mirror of https://github.com/hak5/openwrt-owl.git
mac80211: update to wireless-testing 2016-10-08
Signed-off-by: Felix Fietkau <nbd@nbd.name>owl
parent
4379bcb1b4
commit
ad51e09fd1
|
@ -10,11 +10,11 @@ include $(INCLUDE_DIR)/kernel.mk
|
||||||
|
|
||||||
PKG_NAME:=mac80211
|
PKG_NAME:=mac80211
|
||||||
|
|
||||||
PKG_VERSION:=2016-06-20
|
PKG_VERSION:=2016-10-08
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
|
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
|
||||||
PKG_BACKPORT_VERSION:=
|
PKG_BACKPORT_VERSION:=
|
||||||
PKG_MD5SUM:=29c79bdc3928ef5113b17042ebda9237
|
PKG_MD5SUM:=4f6350e3b75815060bfdf47ef266ad613c7bfea5b7b1dc4552dee69e1bebe4fb
|
||||||
|
|
||||||
PKG_SOURCE:=compat-wireless-$(PKG_VERSION)$(PKG_BACKPORT_VERSION).tar.bz2
|
PKG_SOURCE:=compat-wireless-$(PKG_VERSION)$(PKG_BACKPORT_VERSION).tar.bz2
|
||||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
|
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/compat/Makefile
|
--- a/compat/Makefile
|
||||||
+++ b/compat/Makefile
|
+++ b/compat/Makefile
|
||||||
@@ -35,8 +35,6 @@ compat-$(CPTCFG_KERNEL_4_6) += backport-
|
@@ -36,8 +36,6 @@ compat-$(CPTCFG_KERNEL_4_7) += backport-
|
||||||
|
|
||||||
compat-$(CPTCFG_BPAUTO_BUILD_CRYPTO_CCM) += crypto-ccm.o
|
compat-$(CPTCFG_BPAUTO_BUILD_CRYPTO_CCM) += crypto-ccm.o
|
||||||
compat-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += crypto-skcipher.o
|
compat-$(CPTCFG_BPAUTO_CRYPTO_SKCIPHER) += crypto-skcipher.o
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
From: Jakub Kicinski <jakub.kicinski@netronome.com>
|
|
||||||
Date: Wed, 31 Aug 2016 12:46:44 +0100
|
|
||||||
Subject: [PATCH] add basic register-field manipulation macros
|
|
||||||
|
|
||||||
Common approach to accessing register fields is to define
|
|
||||||
structures or sets of macros containing mask and shift pair.
|
|
||||||
Operations on the register are then performed as follows:
|
|
||||||
|
|
||||||
field = (reg >> shift) & mask;
|
|
||||||
|
|
||||||
reg &= ~(mask << shift);
|
|
||||||
reg |= (field & mask) << shift;
|
|
||||||
|
|
||||||
Defining shift and mask separately is tedious. Ivo van Doorn
|
|
||||||
came up with an idea of computing them at compilation time
|
|
||||||
based on a single shifted mask (later refined by Felix) which
|
|
||||||
can be used like this:
|
|
||||||
|
|
||||||
#define REG_FIELD 0x000ff000
|
|
||||||
|
|
||||||
field = FIELD_GET(REG_FIELD, reg);
|
|
||||||
|
|
||||||
reg &= ~REG_FIELD;
|
|
||||||
reg |= FIELD_PREP(REG_FIELD, field);
|
|
||||||
|
|
||||||
FIELD_{GET,PREP} macros take care of finding out what the
|
|
||||||
appropriate shift is based on compilation time ffs operation.
|
|
||||||
|
|
||||||
GENMASK can be used to define registers (which is usually
|
|
||||||
less error-prone and easier to match with datasheets).
|
|
||||||
|
|
||||||
This approach is the most convenient I've seen so to limit code
|
|
||||||
multiplication let's move the macros to a global header file.
|
|
||||||
Attempts to use static inlines instead of macros failed due
|
|
||||||
to false positive triggering of BUILD_BUG_ON()s, especially with
|
|
||||||
GCC < 6.0.
|
|
||||||
|
|
||||||
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
|
|
||||||
Reviewed-by: Dinan Gunawardena <dinan.gunawardena@netronome.com>
|
|
||||||
---
|
|
||||||
create mode 100644 include/linux/bitfield.h
|
|
||||||
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/include/linux/bitfield.h
|
|
||||||
@@ -0,0 +1,100 @@
|
|
||||||
+/*
|
|
||||||
+ * Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
|
|
||||||
+ * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
|
|
||||||
+ *
|
|
||||||
+ * 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
|
|
||||||
+ *
|
|
||||||
+ * This program is distributed in the hope that it will be useful,
|
|
||||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
+ * GNU General Public License for more details.
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#ifndef _LINUX_BITFIELD_H
|
|
||||||
+#define _LINUX_BITFIELD_H
|
|
||||||
+
|
|
||||||
+#include <linux/bug.h>
|
|
||||||
+
|
|
||||||
+#ifdef __CHECKER__
|
|
||||||
+#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
|
|
||||||
+#else
|
|
||||||
+#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) \
|
|
||||||
+ BUILD_BUG_ON(((n) & ((n) - 1)) != 0)
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Bitfield access macros
|
|
||||||
+ *
|
|
||||||
+ * FIELD_{GET,PREP} macros take as first parameter shifted mask
|
|
||||||
+ * from which they extract the base mask and shift amount.
|
|
||||||
+ * Mask must be a compilation time constant.
|
|
||||||
+ *
|
|
||||||
+ * Example:
|
|
||||||
+ *
|
|
||||||
+ * #define REG_FIELD_A GENMASK(6, 0)
|
|
||||||
+ * #define REG_FIELD_B BIT(7)
|
|
||||||
+ * #define REG_FIELD_C GENMASK(15, 8)
|
|
||||||
+ * #define REG_FIELD_D GENMASK(31, 16)
|
|
||||||
+ *
|
|
||||||
+ * Get:
|
|
||||||
+ * a = FIELD_GET(REG_FIELD_A, reg);
|
|
||||||
+ * b = FIELD_GET(REG_FIELD_B, reg);
|
|
||||||
+ *
|
|
||||||
+ * Set:
|
|
||||||
+ * reg = FIELD_PREP(REG_FIELD_A, 1) |
|
|
||||||
+ * FIELD_PREP(REG_FIELD_B, 0) |
|
|
||||||
+ * FIELD_PREP(REG_FIELD_C, c) |
|
|
||||||
+ * FIELD_PREP(REG_FIELD_D, 0x40);
|
|
||||||
+ *
|
|
||||||
+ * Modify:
|
|
||||||
+ * reg &= ~REG_FIELD_C;
|
|
||||||
+ * reg |= FIELD_PREP(REG_FIELD_C, c);
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#define __bf_shf(x) (__builtin_ffsll(x) - 1)
|
|
||||||
+
|
|
||||||
+#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \
|
|
||||||
+ ({ \
|
|
||||||
+ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
|
|
||||||
+ _pfx "mask is not constant"); \
|
|
||||||
+ BUILD_BUG_ON_MSG(!(_mask), _pfx "mask is zero"); \
|
|
||||||
+ BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
|
|
||||||
+ ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \
|
|
||||||
+ _pfx "value too large for the field"); \
|
|
||||||
+ BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \
|
|
||||||
+ _pfx "type of reg too small for mask"); \
|
|
||||||
+ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
|
|
||||||
+ (1ULL << __bf_shf(_mask))); \
|
|
||||||
+ })
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * FIELD_PREP() - prepare a bitfield element
|
|
||||||
+ * @_mask: shifted mask defining the field's length and position
|
|
||||||
+ * @_val: value to put in the field
|
|
||||||
+ *
|
|
||||||
+ * FIELD_PREP() masks and shifts up the value. The result should
|
|
||||||
+ * be combined with other fields of the bitfield using logical OR.
|
|
||||||
+ */
|
|
||||||
+#define FIELD_PREP(_mask, _val) \
|
|
||||||
+ ({ \
|
|
||||||
+ __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \
|
|
||||||
+ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
|
|
||||||
+ })
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * FIELD_GET() - extract a bitfield element
|
|
||||||
+ * @_mask: shifted mask defining the field's length and position
|
|
||||||
+ * @_reg: 32bit value of entire bitfield
|
|
||||||
+ *
|
|
||||||
+ * FIELD_GET() extracts the field specified by @_mask from the
|
|
||||||
+ * bitfield passed in as @_reg by masking and shifting it down.
|
|
||||||
+ */
|
|
||||||
+#define FIELD_GET(_mask, _reg) \
|
|
||||||
+ ({ \
|
|
||||||
+ __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \
|
|
||||||
+ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
|
|
||||||
+ })
|
|
||||||
+
|
|
||||||
+#endif
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/.local-symbols
|
--- a/.local-symbols
|
||||||
+++ b/.local-symbols
|
+++ b/.local-symbols
|
||||||
@@ -481,45 +481,6 @@ USB_IPHETH=
|
@@ -477,45 +477,6 @@ USB_IPHETH=
|
||||||
USB_SIERRA_NET=
|
USB_SIERRA_NET=
|
||||||
USB_VL600=
|
USB_VL600=
|
||||||
USB_NET_CH9200=
|
USB_NET_CH9200=
|
||||||
|
|
|
@ -34,12 +34,9 @@
|
||||||
#include "aes_ccm.h"
|
#include "aes_ccm.h"
|
||||||
|
|
||||||
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
|
||||||
- u8 *data, size_t data_len, u8 *mic,
|
|
||||||
- size_t mic_len)
|
|
||||||
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0,
|
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0,
|
||||||
+ u8 *a, u8 *b)
|
+ u8 *a, u8 *b)
|
||||||
{
|
+{
|
||||||
- struct scatterlist sg[3];
|
|
||||||
+ int i;
|
+ int i;
|
||||||
+
|
+
|
||||||
+ crypto_cipher_encrypt_one(tfm, b, b_0);
|
+ crypto_cipher_encrypt_one(tfm, b, b_0);
|
||||||
|
@ -54,55 +51,56 @@
|
||||||
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
|
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||||
+ aad[i] ^= b[i];
|
+ aad[i] ^= b[i];
|
||||||
+ crypto_cipher_encrypt_one(tfm, a, aad);
|
+ crypto_cipher_encrypt_one(tfm, a, aad);
|
||||||
|
+
|
||||||
- char aead_req_data[sizeof(struct aead_request) +
|
|
||||||
- crypto_aead_reqsize(tfm)]
|
|
||||||
- __aligned(__alignof__(struct aead_request));
|
|
||||||
- struct aead_request *aead_req = (void *) aead_req_data;
|
|
||||||
+ /* Mask out bits from auth-only-b_0 */
|
+ /* Mask out bits from auth-only-b_0 */
|
||||||
+ b_0[0] &= 0x07;
|
+ b_0[0] &= 0x07;
|
||||||
|
+
|
||||||
- memset(aead_req, 0, sizeof(aead_req_data));
|
|
||||||
+ /* S_0 is used to encrypt T (= MIC) */
|
+ /* S_0 is used to encrypt T (= MIC) */
|
||||||
+ b_0[14] = 0;
|
+ b_0[14] = 0;
|
||||||
+ b_0[15] = 0;
|
+ b_0[15] = 0;
|
||||||
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
|
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
|
||||||
+}
|
+}
|
||||||
|
+
|
||||||
- sg_init_table(sg, 3);
|
+
|
||||||
- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
|
||||||
- sg_set_buf(&sg[1], data, data_len);
|
|
||||||
- sg_set_buf(&sg[2], mic, mic_len);
|
|
||||||
|
|
||||||
- aead_request_set_tfm(aead_req, tfm);
|
|
||||||
- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
|
|
||||||
- aead_request_set_ad(aead_req, sg[0].length);
|
|
||||||
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
||||||
+ u8 *data, size_t data_len, u8 *mic,
|
u8 *data, size_t data_len, u8 *mic,
|
||||||
+ size_t mic_len)
|
size_t mic_len)
|
||||||
+{
|
{
|
||||||
|
- struct scatterlist sg[3];
|
||||||
+ int i, j, last_len, num_blocks;
|
+ int i, j, last_len, num_blocks;
|
||||||
+ u8 b[AES_BLOCK_SIZE];
|
+ u8 b[AES_BLOCK_SIZE];
|
||||||
+ u8 s_0[AES_BLOCK_SIZE];
|
+ u8 s_0[AES_BLOCK_SIZE];
|
||||||
+ u8 e[AES_BLOCK_SIZE];
|
+ u8 e[AES_BLOCK_SIZE];
|
||||||
+ u8 *pos, *cpos;
|
+ u8 *pos, *cpos;
|
||||||
+
|
|
||||||
|
- 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;
|
||||||
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
||||||
+ last_len = data_len % AES_BLOCK_SIZE;
|
+ last_len = data_len % AES_BLOCK_SIZE;
|
||||||
+ aes_ccm_prepare(tfm, b_0, aad, s_0, b, b);
|
+ aes_ccm_prepare(tfm, b_0, aad, s_0, b, b);
|
||||||
+
|
|
||||||
|
- memset(aead_req, 0, sizeof(aead_req_data));
|
||||||
+ /* Process payload blocks */
|
+ /* Process payload blocks */
|
||||||
+ pos = data;
|
+ pos = data;
|
||||||
+ cpos = data;
|
+ cpos = data;
|
||||||
+ for (j = 1; j <= num_blocks; j++) {
|
+ for (j = 1; j <= num_blocks; j++) {
|
||||||
+ int blen = (j == num_blocks && last_len) ?
|
+ int blen = (j == num_blocks && last_len) ?
|
||||||
+ last_len : AES_BLOCK_SIZE;
|
+ last_len : AES_BLOCK_SIZE;
|
||||||
+
|
|
||||||
|
- sg_init_table(sg, 3);
|
||||||
|
- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
||||||
|
- sg_set_buf(&sg[1], data, data_len);
|
||||||
|
- sg_set_buf(&sg[2], mic, mic_len);
|
||||||
+ /* Authentication followed by encryption */
|
+ /* Authentication followed by encryption */
|
||||||
+ for (i = 0; i < blen; i++)
|
+ for (i = 0; i < blen; i++)
|
||||||
+ b[i] ^= pos[i];
|
+ b[i] ^= pos[i];
|
||||||
+ crypto_cipher_encrypt_one(tfm, b, b);
|
+ crypto_cipher_encrypt_one(tfm, b, b);
|
||||||
+
|
|
||||||
|
- aead_request_set_tfm(aead_req, tfm);
|
||||||
|
- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
|
||||||
|
- aead_request_set_ad(aead_req, sg[0].length);
|
||||||
+ b_0[14] = (j >> 8) & 0xff;
|
+ b_0[14] = (j >> 8) & 0xff;
|
||||||
+ b_0[15] = j & 0xff;
|
+ b_0[15] = j & 0xff;
|
||||||
+ crypto_cipher_encrypt_one(tfm, e, b_0);
|
+ crypto_cipher_encrypt_one(tfm, e, b_0);
|
||||||
|
@ -125,37 +123,30 @@
|
||||||
- crypto_aead_reqsize(tfm)]
|
- crypto_aead_reqsize(tfm)]
|
||||||
- __aligned(__alignof__(struct aead_request));
|
- __aligned(__alignof__(struct aead_request));
|
||||||
- struct aead_request *aead_req = (void *) aead_req_data;
|
- struct aead_request *aead_req = (void *) aead_req_data;
|
||||||
-
|
|
||||||
- if (data_len == 0)
|
|
||||||
- return -EINVAL;
|
|
||||||
-
|
|
||||||
- memset(aead_req, 0, sizeof(aead_req_data));
|
|
||||||
-
|
|
||||||
- sg_init_table(sg, 3);
|
|
||||||
- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
|
||||||
- sg_set_buf(&sg[1], data, data_len);
|
|
||||||
- sg_set_buf(&sg[2], mic, mic_len);
|
|
||||||
-
|
|
||||||
- aead_request_set_tfm(aead_req, tfm);
|
|
||||||
- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
|
|
||||||
- aead_request_set_ad(aead_req, sg[0].length);
|
|
||||||
+ int i, j, last_len, num_blocks;
|
+ int i, j, last_len, num_blocks;
|
||||||
+ u8 *pos, *cpos;
|
+ u8 *pos, *cpos;
|
||||||
+ u8 a[AES_BLOCK_SIZE];
|
+ u8 a[AES_BLOCK_SIZE];
|
||||||
+ u8 b[AES_BLOCK_SIZE];
|
+ u8 b[AES_BLOCK_SIZE];
|
||||||
+ u8 s_0[AES_BLOCK_SIZE];
|
+ u8 s_0[AES_BLOCK_SIZE];
|
||||||
+
|
|
||||||
|
- if (data_len == 0)
|
||||||
|
- return -EINVAL;
|
||||||
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
||||||
+ last_len = data_len % AES_BLOCK_SIZE;
|
+ last_len = data_len % AES_BLOCK_SIZE;
|
||||||
+ aes_ccm_prepare(tfm, b_0, aad, s_0, a, b);
|
+ aes_ccm_prepare(tfm, b_0, aad, s_0, a, b);
|
||||||
+
|
|
||||||
|
- memset(aead_req, 0, sizeof(aead_req_data));
|
||||||
+ /* Process payload blocks */
|
+ /* Process payload blocks */
|
||||||
+ cpos = data;
|
+ cpos = data;
|
||||||
+ pos = data;
|
+ pos = data;
|
||||||
+ for (j = 1; j <= num_blocks; j++) {
|
+ for (j = 1; j <= num_blocks; j++) {
|
||||||
+ int blen = (j == num_blocks && last_len) ?
|
+ int blen = (j == num_blocks && last_len) ?
|
||||||
+ last_len : AES_BLOCK_SIZE;
|
+ last_len : AES_BLOCK_SIZE;
|
||||||
+
|
|
||||||
|
- sg_init_table(sg, 3);
|
||||||
|
- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
|
||||||
|
- sg_set_buf(&sg[1], data, data_len);
|
||||||
|
- sg_set_buf(&sg[2], mic, mic_len);
|
||||||
+ /* Decryption followed by authentication */
|
+ /* Decryption followed by authentication */
|
||||||
+ b_0[14] = (j >> 8) & 0xff;
|
+ b_0[14] = (j >> 8) & 0xff;
|
||||||
+ b_0[15] = j & 0xff;
|
+ b_0[15] = j & 0xff;
|
||||||
|
@ -166,7 +157,10 @@
|
||||||
+ }
|
+ }
|
||||||
+ crypto_cipher_encrypt_one(tfm, a, a);
|
+ crypto_cipher_encrypt_one(tfm, a, a);
|
||||||
+ }
|
+ }
|
||||||
+
|
|
||||||
|
- aead_request_set_tfm(aead_req, tfm);
|
||||||
|
- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
|
||||||
|
- aead_request_set_ad(aead_req, sg[0].length);
|
||||||
+ for (i = 0; i < mic_len; i++) {
|
+ for (i = 0; i < mic_len; i++) {
|
||||||
+ if ((mic[i] ^ s_0[i]) != a[i])
|
+ if ((mic[i] ^ s_0[i]) != a[i])
|
||||||
+ return -1;
|
+ return -1;
|
||||||
|
@ -185,12 +179,12 @@
|
||||||
{
|
{
|
||||||
- struct crypto_aead *tfm;
|
- struct crypto_aead *tfm;
|
||||||
- int err;
|
- int err;
|
||||||
+ struct crypto_cipher *tfm;
|
-
|
||||||
|
|
||||||
- tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
|
- tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||||
- if (IS_ERR(tfm))
|
- if (IS_ERR(tfm))
|
||||||
- return tfm;
|
- return tfm;
|
||||||
-
|
+ struct crypto_cipher *tfm;
|
||||||
|
|
||||||
- err = crypto_aead_setkey(tfm, key, key_len);
|
- err = crypto_aead_setkey(tfm, key, key_len);
|
||||||
- if (err)
|
- if (err)
|
||||||
- goto free_aead;
|
- goto free_aead;
|
||||||
|
|
|
@ -2,7 +2,7 @@ Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects
|
||||||
|
|
||||||
--- a/net/mac80211/cfg.c
|
--- a/net/mac80211/cfg.c
|
||||||
+++ b/net/mac80211/cfg.c
|
+++ b/net/mac80211/cfg.c
|
||||||
@@ -850,7 +850,6 @@ static int ieee80211_stop_ap(struct wiph
|
@@ -1016,7 +1016,6 @@ static int ieee80211_stop_ap(struct wiph
|
||||||
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
|
sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF;
|
||||||
|
|
||||||
__sta_info_flush(sdata, true);
|
__sta_info_flush(sdata, true);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/drivers/net/wireless/mac80211_hwsim.c
|
--- a/drivers/net/wireless/mac80211_hwsim.c
|
||||||
+++ b/drivers/net/wireless/mac80211_hwsim.c
|
+++ b/drivers/net/wireless/mac80211_hwsim.c
|
||||||
@@ -2631,7 +2631,7 @@ static int mac80211_hwsim_new_radio(stru
|
@@ -2662,7 +2662,7 @@ static int mac80211_hwsim_new_radio(stru
|
||||||
|
|
||||||
tasklet_hrtimer_init(&data->beacon_timer,
|
tasklet_hrtimer_init(&data->beacon_timer,
|
||||||
mac80211_hwsim_beacon,
|
mac80211_hwsim_beacon,
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
static int ieee80211_ifa6_changed(struct notifier_block *nb,
|
static int ieee80211_ifa6_changed(struct notifier_block *nb,
|
||||||
unsigned long data, void *arg)
|
unsigned long data, void *arg)
|
||||||
{
|
{
|
||||||
@@ -1090,14 +1090,14 @@ int ieee80211_register_hw(struct ieee802
|
@@ -1101,14 +1101,14 @@ int ieee80211_register_hw(struct ieee802
|
||||||
if (result)
|
if (result)
|
||||||
goto fail_flows;
|
goto fail_flows;
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
|
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
|
||||||
result = register_inet6addr_notifier(&local->ifa6_notifier);
|
result = register_inet6addr_notifier(&local->ifa6_notifier);
|
||||||
if (result)
|
if (result)
|
||||||
@@ -1106,13 +1106,13 @@ int ieee80211_register_hw(struct ieee802
|
@@ -1117,13 +1117,13 @@ int ieee80211_register_hw(struct ieee802
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
fail_ifa:
|
fail_ifa:
|
||||||
#endif
|
#endif
|
||||||
ieee80211_txq_teardown_flows(local);
|
ieee80211_txq_teardown_flows(local);
|
||||||
@@ -1142,10 +1142,10 @@ void ieee80211_unregister_hw(struct ieee
|
@@ -1153,10 +1153,10 @@ void ieee80211_unregister_hw(struct ieee
|
||||||
tasklet_kill(&local->tx_pending_tasklet);
|
tasklet_kill(&local->tx_pending_tasklet);
|
||||||
tasklet_kill(&local->tasklet);
|
tasklet_kill(&local->tasklet);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/net/mac80211/cfg.c
|
--- a/net/mac80211/cfg.c
|
||||||
+++ b/net/mac80211/cfg.c
|
+++ b/net/mac80211/cfg.c
|
||||||
@@ -2008,7 +2008,7 @@ static int ieee80211_scan(struct wiphy *
|
@@ -2175,7 +2175,7 @@ static int ieee80211_scan(struct wiphy *
|
||||||
* the frames sent while scanning on other channel will be
|
* the frames sent while scanning on other channel will be
|
||||||
* lost)
|
* lost)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
||||||
Date: Wed, 6 Jul 2016 21:34:17 +0200
|
Date: Fri, 2 Sep 2016 16:00:30 +0200
|
||||||
Subject: [PATCH] ath9k: Switch to using mac80211 intermediate software queues.
|
Subject: [PATCH] ath9k: Switch to using mac80211 intermediate software
|
||||||
|
queues.
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8
|
||||||
Content-Transfer-Encoding: 8bit
|
Content-Transfer-Encoding: 8bit
|
||||||
|
@ -19,7 +20,7 @@ Based on Tim's original patch set, but reworked quite thoroughly.
|
||||||
|
|
||||||
Cc: Tim Shepard <shep@alum.mit.edu>
|
Cc: Tim Shepard <shep@alum.mit.edu>
|
||||||
Cc: Felix Fietkau <nbd@nbd.name>
|
Cc: Felix Fietkau <nbd@nbd.name>
|
||||||
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
---
|
---
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
|
@ -129,7 +130,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
/* VIFs */
|
/* VIFs */
|
||||||
--- a/drivers/net/wireless/ath/ath9k/channel.c
|
--- a/drivers/net/wireless/ath/ath9k/channel.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/channel.c
|
+++ b/drivers/net/wireless/ath/ath9k/channel.c
|
||||||
@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct a
|
@@ -1010,7 +1010,6 @@ static void ath_scan_send_probe(struct a
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
|
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
|
||||||
|
@ -137,7 +138,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
if (ath_tx_start(sc->hw, skb, &txctl))
|
if (ath_tx_start(sc->hw, skb, &txctl))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath
|
@@ -1133,7 +1132,6 @@ ath_chanctx_send_vif_ps_frame(struct ath
|
||||||
memset(&txctl, 0, sizeof(txctl));
|
memset(&txctl, 0, sizeof(txctl));
|
||||||
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
|
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
|
||||||
txctl.sta = sta;
|
txctl.sta = sta;
|
||||||
|
@ -237,7 +238,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -873,6 +872,7 @@ static void ath9k_set_hw_capab(struct at
|
@@ -877,6 +876,7 @@ static void ath9k_set_hw_capab(struct at
|
||||||
hw->max_rate_tries = 10;
|
hw->max_rate_tries = 10;
|
||||||
hw->sta_data_size = sizeof(struct ath_node);
|
hw->sta_data_size = sizeof(struct ath_node);
|
||||||
hw->vif_data_size = sizeof(struct ath_vif);
|
hw->vif_data_size = sizeof(struct ath_vif);
|
||||||
|
@ -247,7 +248,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1;
|
hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1;
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
@@ -1897,9 +1897,11 @@ static int ath9k_ampdu_action(struct iee
|
@@ -1902,9 +1902,11 @@ static int ath9k_ampdu_action(struct iee
|
||||||
bool flush = false;
|
bool flush = false;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct ieee80211_sta *sta = params->sta;
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
@ -259,7 +260,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
mutex_lock(&sc->mutex);
|
||||||
|
|
||||||
@@ -1932,9 +1934,9 @@ static int ath9k_ampdu_action(struct iee
|
@@ -1937,9 +1939,9 @@ static int ath9k_ampdu_action(struct iee
|
||||||
ath9k_ps_restore(sc);
|
ath9k_ps_restore(sc);
|
||||||
break;
|
break;
|
||||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||||
|
@ -272,7 +273,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
|
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
|
||||||
@@ -2696,4 +2698,5 @@ struct ieee80211_ops ath9k_ops = {
|
@@ -2701,4 +2703,5 @@ struct ieee80211_ops ath9k_ops = {
|
||||||
.sw_scan_start = ath9k_sw_scan_start,
|
.sw_scan_start = ath9k_sw_scan_start,
|
||||||
.sw_scan_complete = ath9k_sw_scan_complete,
|
.sw_scan_complete = ath9k_sw_scan_complete,
|
||||||
.get_txpower = ath9k_get_txpower,
|
.get_txpower = ath9k_get_txpower,
|
||||||
|
@ -316,7 +317,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
|
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||||
@@ -179,7 +201,6 @@ static void ath_set_rates(struct ieee802
|
@@ -164,7 +186,6 @@ static void ath_set_rates(struct ieee802
|
||||||
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -324,7 +325,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
struct ath_frame_info *fi = get_frame_info(skb);
|
struct ath_frame_info *fi = get_frame_info(skb);
|
||||||
int q = fi->txq;
|
int q = fi->txq;
|
||||||
|
|
||||||
@@ -190,14 +211,6 @@ static void ath_txq_skb_done(struct ath_
|
@@ -175,14 +196,6 @@ static void ath_txq_skb_done(struct ath_
|
||||||
if (WARN_ON(--txq->pending_frames < 0))
|
if (WARN_ON(--txq->pending_frames < 0))
|
||||||
txq->pending_frames = 0;
|
txq->pending_frames = 0;
|
||||||
|
|
||||||
|
@ -339,7 +340,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ath_atx_tid *
|
static struct ath_atx_tid *
|
||||||
@@ -207,9 +220,48 @@ ath_get_skb_tid(struct ath_softc *sc, st
|
@@ -192,9 +205,48 @@ ath_get_skb_tid(struct ath_softc *sc, st
|
||||||
return ATH_AN_2_TID(an, tidno);
|
return ATH_AN_2_TID(an, tidno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +390,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
|
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
|
||||||
@@ -218,46 +270,11 @@ static struct sk_buff *ath_tid_dequeue(s
|
@@ -203,46 +255,11 @@ static struct sk_buff *ath_tid_dequeue(s
|
||||||
|
|
||||||
skb = __skb_dequeue(&tid->retry_q);
|
skb = __skb_dequeue(&tid->retry_q);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
|
@ -437,7 +438,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
||||||
{
|
{
|
||||||
struct ath_txq *txq = tid->txq;
|
struct ath_txq *txq = tid->txq;
|
||||||
@@ -898,20 +915,16 @@ static int ath_compute_num_delims(struct
|
@@ -883,20 +900,16 @@ static int ath_compute_num_delims(struct
|
||||||
|
|
||||||
static struct ath_buf *
|
static struct ath_buf *
|
||||||
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
|
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
|
||||||
|
@ -461,7 +462,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
if (!skb)
|
if (!skb)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -923,7 +936,6 @@ ath_tx_get_tid_subframe(struct ath_softc
|
@@ -908,7 +921,6 @@ ath_tx_get_tid_subframe(struct ath_softc
|
||||||
bf->bf_state.stale = false;
|
bf->bf_state.stale = false;
|
||||||
|
|
||||||
if (!bf) {
|
if (!bf) {
|
||||||
|
@ -469,7 +470,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
ath_txq_skb_done(sc, txq, skb);
|
ath_txq_skb_done(sc, txq, skb);
|
||||||
ieee80211_free_txskb(sc->hw, skb);
|
ieee80211_free_txskb(sc->hw, skb);
|
||||||
continue;
|
continue;
|
||||||
@@ -952,8 +964,19 @@ ath_tx_get_tid_subframe(struct ath_softc
|
@@ -937,8 +949,20 @@ ath_tx_get_tid_subframe(struct ath_softc
|
||||||
seqno = bf->bf_state.seqno;
|
seqno = bf->bf_state.seqno;
|
||||||
|
|
||||||
/* do not step over block-ack window */
|
/* do not step over block-ack window */
|
||||||
|
@ -480,7 +481,8 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
+ /* If there are other skbs in the retry q, they are
|
+ /* If there are other skbs in the retry q, they are
|
||||||
+ * probably within the BAW, so loop immediately to get
|
+ * probably within the BAW, so loop immediately to get
|
||||||
+ * one of them. Otherwise the queue can get stuck. */
|
+ * one of them. Otherwise the queue can get stuck. */
|
||||||
+ if (!skb_queue_is_first(&tid->retry_q, skb) && skb != first_skb) {
|
+ if (!skb_queue_is_first(&tid->retry_q, skb) &&
|
||||||
|
+ !WARN_ON(skb == first_skb)) {
|
||||||
+ if(!first_skb) /* infinite loop prevention */
|
+ if(!first_skb) /* infinite loop prevention */
|
||||||
+ first_skb = skb;
|
+ first_skb = skb;
|
||||||
+ continue;
|
+ continue;
|
||||||
|
@ -490,7 +492,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
|
|
||||||
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
|
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
|
||||||
struct ath_tx_status ts = {};
|
struct ath_tx_status ts = {};
|
||||||
@@ -961,7 +984,6 @@ ath_tx_get_tid_subframe(struct ath_softc
|
@@ -946,7 +970,6 @@ ath_tx_get_tid_subframe(struct ath_softc
|
||||||
|
|
||||||
INIT_LIST_HEAD(&bf_head);
|
INIT_LIST_HEAD(&bf_head);
|
||||||
list_add(&bf->list, &bf_head);
|
list_add(&bf->list, &bf_head);
|
||||||
|
@ -498,7 +500,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
ath_tx_update_baw(sc, tid, seqno);
|
ath_tx_update_baw(sc, tid, seqno);
|
||||||
ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
|
ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
|
||||||
continue;
|
continue;
|
||||||
@@ -973,11 +995,10 @@ ath_tx_get_tid_subframe(struct ath_softc
|
@@ -958,11 +981,10 @@ ath_tx_get_tid_subframe(struct ath_softc
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +514,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
{
|
{
|
||||||
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
|
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
|
||||||
struct ath_buf *bf = bf_first, *bf_prev = NULL;
|
struct ath_buf *bf = bf_first, *bf_prev = NULL;
|
||||||
@@ -987,12 +1008,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
@@ -972,12 +994,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
||||||
struct ieee80211_tx_info *tx_info;
|
struct ieee80211_tx_info *tx_info;
|
||||||
struct ath_frame_info *fi;
|
struct ath_frame_info *fi;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
@ -528,7 +530,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
skb = bf->bf_mpdu;
|
skb = bf->bf_mpdu;
|
||||||
fi = get_frame_info(skb);
|
fi = get_frame_info(skb);
|
||||||
|
|
||||||
@@ -1001,12 +1023,12 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
@@ -986,12 +1009,12 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
||||||
if (nframes) {
|
if (nframes) {
|
||||||
if (aggr_limit < al + bpad + al_delta ||
|
if (aggr_limit < al + bpad + al_delta ||
|
||||||
ath_lookup_legacy(bf) || nframes >= h_baw)
|
ath_lookup_legacy(bf) || nframes >= h_baw)
|
||||||
|
@ -543,7 +545,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add padding for previous frame to aggregation length */
|
/* add padding for previous frame to aggregation length */
|
||||||
@@ -1028,20 +1050,18 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
@@ -1013,20 +1036,18 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
||||||
ath_tx_addto_baw(sc, tid, bf);
|
ath_tx_addto_baw(sc, tid, bf);
|
||||||
bf->bf_state.ndelim = ndelim;
|
bf->bf_state.ndelim = ndelim;
|
||||||
|
|
||||||
|
@ -570,7 +572,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
bf = bf_first;
|
bf = bf_first;
|
||||||
bf->bf_lastbf = bf_prev;
|
bf->bf_lastbf = bf_prev;
|
||||||
|
|
||||||
@@ -1052,9 +1072,7 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
@@ -1037,9 +1058,7 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
||||||
TX_STAT_INC(txq->axq_qnum, a_aggr);
|
TX_STAT_INC(txq->axq_qnum, a_aggr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,7 +583,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
#undef PADBYTES
|
#undef PADBYTES
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1431,18 +1449,15 @@ static void ath_tx_fill_desc(struct ath_
|
@@ -1416,18 +1435,15 @@ static void ath_tx_fill_desc(struct ath_
|
||||||
static void
|
static void
|
||||||
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
|
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
|
||||||
struct ath_atx_tid *tid, struct list_head *bf_q,
|
struct ath_atx_tid *tid, struct list_head *bf_q,
|
||||||
|
@ -601,7 +603,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
list_add_tail(&bf->list, bf_q);
|
list_add_tail(&bf->list, bf_q);
|
||||||
if (bf_prev)
|
if (bf_prev)
|
||||||
bf_prev->bf_next = bf;
|
bf_prev->bf_next = bf;
|
||||||
@@ -1451,13 +1466,15 @@ ath_tx_form_burst(struct ath_softc *sc,
|
@@ -1436,13 +1452,15 @@ ath_tx_form_burst(struct ath_softc *sc,
|
||||||
if (nframes >= 2)
|
if (nframes >= 2)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -617,9 +619,9 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
break;
|
break;
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||||
} while (1);
|
} while (1);
|
||||||
@@ -1468,34 +1485,33 @@ static bool ath_tx_sched_aggr(struct ath
|
@@ -1453,34 +1471,33 @@ static bool ath_tx_sched_aggr(struct ath
|
||||||
{
|
{
|
||||||
struct ath_buf *bf;
|
struct ath_buf *bf;
|
||||||
struct ieee80211_tx_info *tx_info;
|
struct ieee80211_tx_info *tx_info;
|
||||||
|
@ -649,7 +651,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||||
if (aggr)
|
if (aggr)
|
||||||
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
|
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
|
||||||
- tid_q, &aggr_len);
|
- tid_q, &aggr_len);
|
||||||
|
@ -660,7 +662,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
|
|
||||||
if (list_empty(&bf_q))
|
if (list_empty(&bf_q))
|
||||||
return false;
|
return false;
|
||||||
@@ -1538,9 +1554,6 @@ int ath_tx_aggr_start(struct ath_softc *
|
@@ -1523,9 +1540,6 @@ int ath_tx_aggr_start(struct ath_softc *
|
||||||
an->mpdudensity = density;
|
an->mpdudensity = density;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,7 +672,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
txtid->active = true;
|
txtid->active = true;
|
||||||
*ssn = txtid->seq_start = txtid->seq_next;
|
*ssn = txtid->seq_start = txtid->seq_next;
|
||||||
txtid->bar_index = -1;
|
txtid->bar_index = -1;
|
||||||
@@ -1565,7 +1578,6 @@ void ath_tx_aggr_stop(struct ath_softc *
|
@@ -1550,7 +1564,6 @@ void ath_tx_aggr_stop(struct ath_softc *
|
||||||
ath_txq_lock(sc, txq);
|
ath_txq_lock(sc, txq);
|
||||||
txtid->active = false;
|
txtid->active = false;
|
||||||
ath_tx_flush_tid(sc, txtid);
|
ath_tx_flush_tid(sc, txtid);
|
||||||
|
@ -678,7 +680,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
ath_txq_unlock_complete(sc, txq);
|
ath_txq_unlock_complete(sc, txq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1575,14 +1587,12 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
@@ -1560,14 +1573,12 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
struct ath_atx_tid *tid;
|
struct ath_atx_tid *tid;
|
||||||
struct ath_txq *txq;
|
struct ath_txq *txq;
|
||||||
|
@ -695,7 +697,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
txq = tid->txq;
|
txq = tid->txq;
|
||||||
|
|
||||||
ath_txq_lock(sc, txq);
|
ath_txq_lock(sc, txq);
|
||||||
@@ -1592,13 +1602,12 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
@@ -1577,13 +1588,12 @@ void ath_tx_aggr_sleep(struct ieee80211_
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,7 +713,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1611,49 +1620,20 @@ void ath_tx_aggr_wakeup(struct ath_softc
|
@@ -1596,49 +1606,20 @@ void ath_tx_aggr_wakeup(struct ath_softc
|
||||||
|
|
||||||
ath_dbg(common, XMIT, "%s called\n", __func__);
|
ath_dbg(common, XMIT, "%s called\n", __func__);
|
||||||
|
|
||||||
|
@ -763,7 +765,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
|
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_sta *sta,
|
struct ieee80211_sta *sta,
|
||||||
u16 tids, int nframes,
|
u16 tids, int nframes,
|
||||||
@@ -1666,7 +1646,6 @@ void ath9k_release_buffered_frames(struc
|
@@ -1651,7 +1632,6 @@ void ath9k_release_buffered_frames(struc
|
||||||
struct ieee80211_tx_info *info;
|
struct ieee80211_tx_info *info;
|
||||||
struct list_head bf_q;
|
struct list_head bf_q;
|
||||||
struct ath_buf *bf_tail = NULL, *bf;
|
struct ath_buf *bf_tail = NULL, *bf;
|
||||||
|
@ -771,7 +773,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
int sent = 0;
|
int sent = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1681,11 +1660,10 @@ void ath9k_release_buffered_frames(struc
|
@@ -1666,11 +1646,10 @@ void ath9k_release_buffered_frames(struc
|
||||||
|
|
||||||
ath_txq_lock(sc, tid->txq);
|
ath_txq_lock(sc, tid->txq);
|
||||||
while (nframes > 0) {
|
while (nframes > 0) {
|
||||||
|
@ -782,9 +784,9 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
|
|
||||||
- __skb_unlink(bf->bf_mpdu, tid_q);
|
- __skb_unlink(bf->bf_mpdu, tid_q);
|
||||||
list_add_tail(&bf->list, &bf_q);
|
list_add_tail(&bf->list, &bf_q);
|
||||||
ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||||
if (bf_isampdu(bf)) {
|
if (bf_isampdu(bf)) {
|
||||||
@@ -1700,7 +1678,7 @@ void ath9k_release_buffered_frames(struc
|
@@ -1685,7 +1664,7 @@ void ath9k_release_buffered_frames(struc
|
||||||
sent++;
|
sent++;
|
||||||
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
|
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
|
||||||
|
|
||||||
|
@ -793,7 +795,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
ieee80211_sta_set_buffered(an->sta, i, false);
|
ieee80211_sta_set_buffered(an->sta, i, false);
|
||||||
}
|
}
|
||||||
ath_txq_unlock_complete(sc, tid->txq);
|
ath_txq_unlock_complete(sc, tid->txq);
|
||||||
@@ -1929,13 +1907,7 @@ bool ath_drain_all_txq(struct ath_softc
|
@@ -1914,13 +1893,7 @@ bool ath_drain_all_txq(struct ath_softc
|
||||||
if (!ATH_TXQ_SETUP(sc, i))
|
if (!ATH_TXQ_SETUP(sc, i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -807,13 +809,13 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
ath_draintxq(sc, txq);
|
ath_draintxq(sc, txq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2334,16 +2306,14 @@ int ath_tx_start(struct ieee80211_hw *hw
|
@@ -2319,16 +2292,14 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||||||
struct ath_softc *sc = hw->priv;
|
struct ath_softc *sc = hw->priv;
|
||||||
struct ath_txq *txq = txctl->txq;
|
struct ath_txq *txq = txctl->txq;
|
||||||
struct ath_atx_tid *tid = NULL;
|
struct ath_atx_tid *tid = NULL;
|
||||||
+ struct ath_node *an = NULL;
|
+ struct ath_node *an = NULL;
|
||||||
struct ath_buf *bf;
|
struct ath_buf *bf;
|
||||||
- bool queue, ps_resp;
|
- bool queue, skip_uapsd = false, ps_resp;
|
||||||
+ bool ps_resp;
|
+ bool ps_resp;
|
||||||
int q, ret;
|
int q, ret;
|
||||||
|
|
||||||
|
@ -826,7 +828,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
|
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
|
||||||
|
|
||||||
ret = ath_tx_prepare(hw, skb, txctl);
|
ret = ath_tx_prepare(hw, skb, txctl);
|
||||||
@@ -2358,63 +2328,18 @@ int ath_tx_start(struct ieee80211_hw *hw
|
@@ -2343,63 +2314,18 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||||||
|
|
||||||
q = skb_get_queue_mapping(skb);
|
q = skb_get_queue_mapping(skb);
|
||||||
|
|
||||||
|
@ -860,13 +862,13 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
- if (!txctl->an)
|
- if (!txctl->an)
|
||||||
- txctl->an = &avp->mcast_node;
|
- txctl->an = &avp->mcast_node;
|
||||||
- queue = true;
|
- queue = true;
|
||||||
- ps_resp = false;
|
- skip_uapsd = true;
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- if (txctl->an && queue)
|
- if (txctl->an && queue)
|
||||||
- tid = ath_get_skb_tid(sc, txctl->an, skb);
|
- tid = ath_get_skb_tid(sc, txctl->an, skb);
|
||||||
-
|
-
|
||||||
- if (ps_resp) {
|
- if (!skip_uapsd && ps_resp) {
|
||||||
- ath_txq_unlock(sc, txq);
|
- ath_txq_unlock(sc, txq);
|
||||||
+ if (ps_resp)
|
+ if (ps_resp)
|
||||||
txq = sc->tx.uapsdq;
|
txq = sc->tx.uapsdq;
|
||||||
|
@ -899,7 +901,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
}
|
}
|
||||||
|
|
||||||
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
|
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
|
||||||
@@ -2907,9 +2832,8 @@ void ath_tx_node_init(struct ath_softc *
|
@@ -2892,9 +2818,8 @@ void ath_tx_node_init(struct ath_softc *
|
||||||
struct ath_atx_tid *tid;
|
struct ath_atx_tid *tid;
|
||||||
int tidno, acno;
|
int tidno, acno;
|
||||||
|
|
||||||
|
@ -911,7 +913,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
tid->an = an;
|
tid->an = an;
|
||||||
tid->tidno = tidno;
|
tid->tidno = tidno;
|
||||||
tid->seq_start = tid->seq_next = 0;
|
tid->seq_start = tid->seq_next = 0;
|
||||||
@@ -2917,11 +2841,14 @@ void ath_tx_node_init(struct ath_softc *
|
@@ -2902,11 +2827,14 @@ void ath_tx_node_init(struct ath_softc *
|
||||||
tid->baw_head = tid->baw_tail = 0;
|
tid->baw_head = tid->baw_tail = 0;
|
||||||
tid->active = false;
|
tid->active = false;
|
||||||
tid->clear_ps_filter = true;
|
tid->clear_ps_filter = true;
|
||||||
|
@ -927,7 +929,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2931,9 +2858,8 @@ void ath_tx_node_cleanup(struct ath_soft
|
@@ -2916,9 +2844,8 @@ void ath_tx_node_cleanup(struct ath_soft
|
||||||
struct ath_txq *txq;
|
struct ath_txq *txq;
|
||||||
int tidno;
|
int tidno;
|
||||||
|
|
||||||
|
@ -939,7 +941,7 @@ Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||||
txq = tid->txq;
|
txq = tid->txq;
|
||||||
|
|
||||||
ath_txq_lock(sc, txq);
|
ath_txq_lock(sc, txq);
|
||||||
@@ -2945,6 +2871,9 @@ void ath_tx_node_cleanup(struct ath_soft
|
@@ -2930,6 +2857,9 @@ void ath_tx_node_cleanup(struct ath_soft
|
||||||
tid->active = false;
|
tid->active = false;
|
||||||
|
|
||||||
ath_txq_unlock(sc, txq);
|
ath_txq_unlock(sc, txq);
|
|
@ -13,7 +13,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
@@ -136,10 +136,25 @@ static void ath_send_bar(struct ath_atx_
|
@@ -177,10 +177,25 @@ static void ath_send_bar(struct ath_atx_
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||||
|
@ -40,59 +40,34 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
|
||||||
@@ -1419,7 +1434,7 @@ ath_tx_form_burst(struct ath_softc *sc,
|
@@ -1462,7 +1477,7 @@ ath_tx_form_burst(struct ath_softc *sc,
|
||||||
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||||
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1450,7 +1465,7 @@ static bool ath_tx_sched_aggr(struct ath
|
@@ -1493,7 +1508,7 @@ static bool ath_tx_sched_aggr(struct ath
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||||
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
|
||||||
if (aggr)
|
if (aggr)
|
||||||
last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
|
aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
|
||||||
tid_q, &aggr_len);
|
else
|
||||||
@@ -1647,7 +1662,7 @@ void ath9k_release_buffered_frames(struc
|
@@ -1651,7 +1666,7 @@ void ath9k_release_buffered_frames(struc
|
||||||
|
break;
|
||||||
|
|
||||||
__skb_unlink(bf->bf_mpdu, tid_q);
|
|
||||||
list_add_tail(&bf->list, &bf_q);
|
list_add_tail(&bf->list, &bf_q);
|
||||||
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
- ath_set_rates(tid->an->vif, tid->an->sta, bf);
|
||||||
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
||||||
if (bf_isampdu(bf)) {
|
if (bf_isampdu(bf)) {
|
||||||
ath_tx_addto_baw(sc, tid, bf);
|
ath_tx_addto_baw(sc, tid, bf);
|
||||||
bf->bf_state.bf_type &= ~BUF_AGGR;
|
bf->bf_state.bf_type &= ~BUF_AGGR;
|
||||||
@@ -2293,7 +2308,7 @@ int ath_tx_start(struct ieee80211_hw *hw
|
@@ -2343,7 +2358,7 @@ int ath_tx_start(struct ieee80211_hw *hw
|
||||||
struct ath_txq *txq = txctl->txq;
|
|
||||||
struct ath_atx_tid *tid = NULL;
|
|
||||||
struct ath_buf *bf;
|
|
||||||
- bool queue, skip_uapsd = false, ps_resp;
|
|
||||||
+ bool queue, ps_resp;
|
|
||||||
int q, ret;
|
|
||||||
|
|
||||||
if (vif)
|
|
||||||
@@ -2346,13 +2361,13 @@ int ath_tx_start(struct ieee80211_hw *hw
|
|
||||||
if (!txctl->an)
|
|
||||||
txctl->an = &avp->mcast_node;
|
|
||||||
queue = true;
|
|
||||||
- skip_uapsd = true;
|
|
||||||
+ ps_resp = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txctl->an && queue)
|
|
||||||
tid = ath_get_skb_tid(sc, txctl->an, skb);
|
|
||||||
|
|
||||||
- if (!skip_uapsd && ps_resp) {
|
|
||||||
+ if (ps_resp) {
|
|
||||||
ath_txq_unlock(sc, txq);
|
|
||||||
txq = sc->tx.uapsdq;
|
|
||||||
ath_txq_lock(sc, txq);
|
|
||||||
@@ -2390,7 +2405,7 @@ int ath_tx_start(struct ieee80211_hw *hw
|
|
||||||
if (txctl->paprd)
|
if (txctl->paprd)
|
||||||
bf->bf_state.bfs_paprd_timestamp = jiffies;
|
bf->bf_state.bfs_paprd_timestamp = jiffies;
|
||||||
|
|
||||||
|
@ -101,7 +76,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||||
ath_tx_send_normal(sc, txq, tid, skb);
|
ath_tx_send_normal(sc, txq, tid, skb);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -2429,7 +2444,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
|
@@ -2382,7 +2397,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
|
||||||
break;
|
break;
|
||||||
|
|
||||||
bf->bf_lastbf = bf;
|
bf->bf_lastbf = bf;
|
||||||
|
@ -110,7 +85,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||||
ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
|
ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
|
||||||
duration += info.rates[0].PktDuration;
|
duration += info.rates[0].PktDuration;
|
||||||
if (bf_tail)
|
if (bf_tail)
|
||||||
@@ -2932,7 +2947,7 @@ int ath9k_tx99_send(struct ath_softc *sc
|
@@ -2898,7 +2913,7 @@ int ath9k_tx99_send(struct ath_softc *sc
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411.
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
@@ -2914,7 +2914,8 @@ void ath9k_hw_apply_txpower(struct ath_h
|
@@ -2910,7 +2910,8 @@ void ath9k_hw_apply_txpower(struct ath_h
|
||||||
{
|
{
|
||||||
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
|
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
|
||||||
struct ieee80211_channel *channel;
|
struct ieee80211_channel *channel;
|
||||||
|
@ -18,7 +18,7 @@ This reverts commit 71f5137bf010c6faffab50c0ec15374c59c4a411.
|
||||||
|
|
||||||
if (!chan)
|
if (!chan)
|
||||||
return;
|
return;
|
||||||
@@ -2922,10 +2923,15 @@ void ath9k_hw_apply_txpower(struct ath_h
|
@@ -2918,10 +2919,15 @@ void ath9k_hw_apply_txpower(struct ath_h
|
||||||
channel = chan->chan;
|
channel = chan->chan;
|
||||||
chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
|
chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
|
||||||
new_pwr = min_t(int, chan_pwr, reg->power_limit);
|
new_pwr = min_t(int, chan_pwr, reg->power_limit);
|
|
@ -1,21 +0,0 @@
|
||||||
From: Ben Greear <greearb@candelatech.com>
|
|
||||||
Date: Fri, 1 Apr 2016 14:12:08 -0700
|
|
||||||
Subject: [PATCH] ath10k: Ensure txrx-compl-task is stopped when cleaning
|
|
||||||
htt-tx.
|
|
||||||
|
|
||||||
Otherwise, the txrx-compl-task may access some bad memory?
|
|
||||||
|
|
||||||
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
|
|
||||||
@@ -388,6 +388,8 @@ void ath10k_htt_tx_free(struct ath10k_ht
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
|
|
||||||
+ tasklet_kill(&htt->txrx_compl_task);
|
|
||||||
+
|
|
||||||
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
|
|
||||||
idr_destroy(&htt->pending_tx);
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
From: Ben Greear <greearb@candelatech.com>
|
|
||||||
Date: Fri, 1 Apr 2016 14:12:09 -0700
|
|
||||||
Subject: [PATCH] ath10k: Ensure peer_map references are cleaned up.
|
|
||||||
|
|
||||||
While debugging OS crashes due to firmware crashes, I enabled
|
|
||||||
kasan, and it noticed that peer objects were being used-after-freed.
|
|
||||||
|
|
||||||
Looks like there are two places we could be leaving stale references
|
|
||||||
in the peer-map, so clean that up.
|
|
||||||
|
|
||||||
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
@@ -802,6 +802,7 @@ static void ath10k_peer_cleanup(struct a
|
|
||||||
{
|
|
||||||
struct ath10k_peer *peer, *tmp;
|
|
||||||
int peer_id;
|
|
||||||
+ int i;
|
|
||||||
|
|
||||||
lockdep_assert_held(&ar->conf_mutex);
|
|
||||||
|
|
||||||
@@ -818,6 +819,17 @@ static void ath10k_peer_cleanup(struct a
|
|
||||||
ar->peer_map[peer_id] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* Double check that peer is properly un-referenced from
|
|
||||||
+ * the peer_map
|
|
||||||
+ */
|
|
||||||
+ for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) {
|
|
||||||
+ if (ar->peer_map[i] == peer) {
|
|
||||||
+ ath10k_warn(ar, "removing stale peer_map entry for %pM (ptr %p idx %d)\n",
|
|
||||||
+ peer->addr, peer, i);
|
|
||||||
+ ar->peer_map[i] = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
list_del(&peer->list);
|
|
||||||
kfree(peer);
|
|
||||||
ar->num_peers--;
|
|
||||||
@@ -828,6 +840,7 @@ static void ath10k_peer_cleanup(struct a
|
|
||||||
static void ath10k_peer_cleanup_all(struct ath10k *ar)
|
|
||||||
{
|
|
||||||
struct ath10k_peer *peer, *tmp;
|
|
||||||
+ int i;
|
|
||||||
|
|
||||||
lockdep_assert_held(&ar->conf_mutex);
|
|
||||||
|
|
||||||
@@ -836,6 +849,10 @@ static void ath10k_peer_cleanup_all(stru
|
|
||||||
list_del(&peer->list);
|
|
||||||
kfree(peer);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++)
|
|
||||||
+ ar->peer_map[i] = NULL;
|
|
||||||
+
|
|
||||||
spin_unlock_bh(&ar->data_lock);
|
|
||||||
|
|
||||||
ar->num_peers = 0;
|
|
|
@ -11,7 +11,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
|
|
||||||
--- a/net/mac80211/ieee80211_i.h
|
--- a/net/mac80211/ieee80211_i.h
|
||||||
+++ b/net/mac80211/ieee80211_i.h
|
+++ b/net/mac80211/ieee80211_i.h
|
||||||
@@ -173,6 +173,7 @@ struct ieee80211_tx_data {
|
@@ -175,6 +175,7 @@ struct ieee80211_tx_data {
|
||||||
struct ieee80211_tx_rate rate;
|
struct ieee80211_tx_rate rate;
|
||||||
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
@ -21,7 +21,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
|
|
||||||
--- a/net/mac80211/tx.c
|
--- a/net/mac80211/tx.c
|
||||||
+++ b/net/mac80211/tx.c
|
+++ b/net/mac80211/tx.c
|
||||||
@@ -922,7 +922,7 @@ ieee80211_tx_h_fragment(struct ieee80211
|
@@ -955,7 +955,7 @@ ieee80211_tx_h_fragment(struct ieee80211
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||||
int frag_threshold = tx->local->hw.wiphy->frag_threshold;
|
int frag_threshold = tx->local->hw.wiphy->frag_threshold;
|
||||||
|
@ -30,7 +30,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
int fragnum;
|
int fragnum;
|
||||||
|
|
||||||
/* no matter what happens, tx->skb moves to tx->skbs */
|
/* no matter what happens, tx->skb moves to tx->skbs */
|
||||||
@@ -943,8 +943,6 @@ ieee80211_tx_h_fragment(struct ieee80211
|
@@ -976,8 +976,6 @@ ieee80211_tx_h_fragment(struct ieee80211
|
||||||
if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
|
if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
|
||||||
return TX_DROP;
|
return TX_DROP;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
/* internal error, why isn't DONTFRAG set? */
|
/* internal error, why isn't DONTFRAG set? */
|
||||||
if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
|
if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
|
||||||
return TX_DROP;
|
return TX_DROP;
|
||||||
@@ -1176,6 +1174,8 @@ ieee80211_tx_prepare(struct ieee80211_su
|
@@ -1209,6 +1207,8 @@ ieee80211_tx_prepare(struct ieee80211_su
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *) skb->data;
|
hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
|
|
||||||
|
@ -48,9 +48,25 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
if (likely(sta)) {
|
if (likely(sta)) {
|
||||||
if (!IS_ERR(sta))
|
if (!IS_ERR(sta))
|
||||||
tx->sta = sta;
|
tx->sta = sta;
|
||||||
|
@@ -3414,6 +3414,7 @@ begin:
|
||||||
|
tx.local = local;
|
||||||
|
tx.skb = skb;
|
||||||
|
tx.sdata = vif_to_sdata(info->control.vif);
|
||||||
|
+ tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control);
|
||||||
|
|
||||||
|
if (txq->sta)
|
||||||
|
tx.sta = container_of(txq->sta, struct sta_info, sta);
|
||||||
|
@@ -3584,6 +3585,7 @@ ieee80211_build_data_template(struct iee
|
||||||
|
hdr = (void *)skb->data;
|
||||||
|
tx.sta = sta_info_get(sdata, hdr->addr1);
|
||||||
|
tx.skb = skb;
|
||||||
|
+ tx.hdrlen = ieee80211_padded_hdrlen(&tx.local->hw, hdr->frame_control);
|
||||||
|
|
||||||
|
if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) {
|
||||||
|
rcu_read_unlock();
|
||||||
--- a/net/mac80211/util.c
|
--- a/net/mac80211/util.c
|
||||||
+++ b/net/mac80211/util.c
|
+++ b/net/mac80211/util.c
|
||||||
@@ -1226,6 +1226,7 @@ void ieee80211_send_auth(struct ieee8021
|
@@ -1227,6 +1227,7 @@ void ieee80211_send_auth(struct ieee8021
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ieee80211_mgmt *mgmt;
|
struct ieee80211_mgmt *mgmt;
|
||||||
|
@ -58,7 +74,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* 24 + 6 = header + auth_algo + auth_transaction + status_code */
|
/* 24 + 6 = header + auth_algo + auth_transaction + status_code */
|
||||||
@@ -1250,8 +1251,10 @@ void ieee80211_send_auth(struct ieee8021
|
@@ -1251,8 +1252,10 @@ void ieee80211_send_auth(struct ieee8021
|
||||||
memcpy(skb_put(skb, extra_len), extra, extra_len);
|
memcpy(skb_put(skb, extra_len), extra, extra_len);
|
||||||
|
|
||||||
if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
|
if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
|
|
@ -1,32 +0,0 @@
|
||||||
From: Ben Greear <greearb@candelatech.com>
|
|
||||||
Date: Fri, 1 Apr 2016 14:12:11 -0700
|
|
||||||
Subject: [PATCH] ath10k: Clean up peer when sta goes away.
|
|
||||||
|
|
||||||
If WMI and/or firmware has issues removing the peer object,
|
|
||||||
then we still need to clean up the peer object in the driver.
|
|
||||||
|
|
||||||
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
@@ -5992,9 +5992,17 @@ static int ath10k_sta_state(struct ieee8
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (peer->sta == sta) {
|
|
||||||
- ath10k_warn(ar, "found sta peer %pM entry on vdev %i after it was supposedly removed\n",
|
|
||||||
- sta->addr, arvif->vdev_id);
|
|
||||||
+ ath10k_warn(ar, "found sta peer %pM (ptr %p id %d) entry on vdev %i after it was supposedly removed\n",
|
|
||||||
+ sta->addr, peer, i, arvif->vdev_id);
|
|
||||||
peer->sta = NULL;
|
|
||||||
+
|
|
||||||
+ /* Clean up the peer object as well since we
|
|
||||||
+ * must have failed to do this above.
|
|
||||||
+ */
|
|
||||||
+ list_del(&peer->list);
|
|
||||||
+ ar->peer_map[i] = NULL;
|
|
||||||
+ kfree(peer);
|
|
||||||
+ ar->num_peers--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_bh(&ar->data_lock);
|
|
|
@ -23,9 +23,9 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
|
|
||||||
--- a/include/net/mac80211.h
|
--- a/include/net/mac80211.h
|
||||||
+++ b/include/net/mac80211.h
|
+++ b/include/net/mac80211.h
|
||||||
@@ -2014,6 +2014,9 @@ struct ieee80211_txq {
|
@@ -2025,6 +2025,9 @@ struct ieee80211_txq {
|
||||||
* @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list
|
* drivers, mac80211 packet loss mechanism will not be triggered and driver
|
||||||
* skbs, needed for zero-copy software A-MSDU.
|
* is completely depending on firmware event for station kickout.
|
||||||
*
|
*
|
||||||
+ * @IEEE80211_HW_NEEDS_ALIGNED4_SKBS: Driver need aligned skbs to four-byte.
|
+ * @IEEE80211_HW_NEEDS_ALIGNED4_SKBS: Driver need aligned skbs to four-byte.
|
||||||
+ * Padding will be added after ieee80211_hdr, before IV/LLC.
|
+ * Padding will be added after ieee80211_hdr, before IV/LLC.
|
||||||
|
@ -33,27 +33,27 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||||
*/
|
*/
|
||||||
enum ieee80211_hw_flags {
|
enum ieee80211_hw_flags {
|
||||||
@@ -2054,6 +2057,7 @@ enum ieee80211_hw_flags {
|
@@ -2066,6 +2069,7 @@ enum ieee80211_hw_flags {
|
||||||
IEEE80211_HW_USES_RSS,
|
|
||||||
IEEE80211_HW_TX_AMSDU,
|
IEEE80211_HW_TX_AMSDU,
|
||||||
IEEE80211_HW_TX_FRAG_LIST,
|
IEEE80211_HW_TX_FRAG_LIST,
|
||||||
|
IEEE80211_HW_REPORTS_LOW_ACK,
|
||||||
+ IEEE80211_HW_NEEDS_ALIGNED4_SKBS,
|
+ IEEE80211_HW_NEEDS_ALIGNED4_SKBS,
|
||||||
|
|
||||||
/* keep last, obviously */
|
/* keep last, obviously */
|
||||||
NUM_IEEE80211_HW_FLAGS
|
NUM_IEEE80211_HW_FLAGS
|
||||||
--- a/net/mac80211/debugfs.c
|
--- a/net/mac80211/debugfs.c
|
||||||
+++ b/net/mac80211/debugfs.c
|
+++ b/net/mac80211/debugfs.c
|
||||||
@@ -302,6 +302,7 @@ static const char *hw_flag_names[] = {
|
@@ -210,6 +210,7 @@ static const char *hw_flag_names[] = {
|
||||||
FLAG(USES_RSS),
|
|
||||||
FLAG(TX_AMSDU),
|
FLAG(TX_AMSDU),
|
||||||
FLAG(TX_FRAG_LIST),
|
FLAG(TX_FRAG_LIST),
|
||||||
|
FLAG(REPORTS_LOW_ACK),
|
||||||
+ FLAG(NEEDS_ALIGNED4_SKBS),
|
+ FLAG(NEEDS_ALIGNED4_SKBS),
|
||||||
#undef FLAG
|
#undef FLAG
|
||||||
};
|
};
|
||||||
|
|
||||||
--- a/net/mac80211/ieee80211_i.h
|
--- a/net/mac80211/ieee80211_i.h
|
||||||
+++ b/net/mac80211/ieee80211_i.h
|
+++ b/net/mac80211/ieee80211_i.h
|
||||||
@@ -1497,6 +1497,29 @@ ieee80211_have_rx_timestamp(struct ieee8
|
@@ -1529,6 +1529,29 @@ ieee80211_have_rx_timestamp(struct ieee8
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
unsigned int mpdu_len,
|
unsigned int mpdu_len,
|
||||||
--- a/net/mac80211/sta_info.h
|
--- a/net/mac80211/sta_info.h
|
||||||
+++ b/net/mac80211/sta_info.h
|
+++ b/net/mac80211/sta_info.h
|
||||||
@@ -279,7 +279,7 @@ struct ieee80211_fast_tx {
|
@@ -282,7 +282,7 @@ struct ieee80211_fast_tx {
|
||||||
u8 hdr_len;
|
u8 hdr_len;
|
||||||
u8 sa_offs, da_offs, pn_offs;
|
u8 sa_offs, da_offs, pn_offs;
|
||||||
u8 band;
|
u8 band;
|
||||||
|
@ -96,7 +96,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
struct rcu_head rcu_head;
|
struct rcu_head rcu_head;
|
||||||
--- a/net/mac80211/status.c
|
--- a/net/mac80211/status.c
|
||||||
+++ b/net/mac80211/status.c
|
+++ b/net/mac80211/status.c
|
||||||
@@ -683,9 +683,22 @@ void ieee80211_tx_monitor(struct ieee802
|
@@ -689,9 +689,22 @@ void ieee80211_tx_monitor(struct ieee802
|
||||||
struct sk_buff *skb2;
|
struct sk_buff *skb2;
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
struct ieee80211_sub_if_data *sdata;
|
struct ieee80211_sub_if_data *sdata;
|
||||||
|
@ -137,7 +137,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
|
|
||||||
--- a/net/mac80211/tx.c
|
--- a/net/mac80211/tx.c
|
||||||
+++ b/net/mac80211/tx.c
|
+++ b/net/mac80211/tx.c
|
||||||
@@ -1173,8 +1173,7 @@ ieee80211_tx_prepare(struct ieee80211_su
|
@@ -1206,8 +1206,7 @@ ieee80211_tx_prepare(struct ieee80211_su
|
||||||
info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *) skb->data;
|
hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
|
@ -147,7 +147,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
|
|
||||||
if (likely(sta)) {
|
if (likely(sta)) {
|
||||||
if (!IS_ERR(sta))
|
if (!IS_ERR(sta))
|
||||||
@@ -2108,7 +2107,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
@@ -2158,7 +2157,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
||||||
|
@ -156,7 +156,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
|
|
||||||
if (skb->len < len_rthdr + hdrlen)
|
if (skb->len < len_rthdr + hdrlen)
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -2334,7 +2333,7 @@ static struct sk_buff *ieee80211_build_h
|
@@ -2376,7 +2375,7 @@ static struct sk_buff *ieee80211_build_h
|
||||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||||
struct ieee80211_sub_if_data *ap_sdata;
|
struct ieee80211_sub_if_data *ap_sdata;
|
||||||
enum nl80211_band band;
|
enum nl80211_band band;
|
||||||
|
@ -165,7 +165,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
|
|
||||||
if (IS_ERR(sta))
|
if (IS_ERR(sta))
|
||||||
sta = NULL;
|
sta = NULL;
|
||||||
@@ -2554,6 +2553,9 @@ static struct sk_buff *ieee80211_build_h
|
@@ -2596,6 +2595,9 @@ static struct sk_buff *ieee80211_build_h
|
||||||
hdrlen += 2;
|
hdrlen += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,16 +175,16 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
/*
|
/*
|
||||||
* Drop unicast frames to unauthorised stations unless they are
|
* Drop unicast frames to unauthorised stations unless they are
|
||||||
* EAPOL frames from the local station.
|
* EAPOL frames from the local station.
|
||||||
@@ -2640,6 +2642,7 @@ static struct sk_buff *ieee80211_build_h
|
@@ -2676,6 +2678,7 @@ static struct sk_buff *ieee80211_build_h
|
||||||
h_pos -= skip_header_bytes;
|
|
||||||
|
|
||||||
|
skb_pull(skb, skip_header_bytes);
|
||||||
head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
|
head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
|
||||||
+ head_need += padsize;
|
+ head_need += padsize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* So we need to modify the skb header and hence need a copy of
|
* So we need to modify the skb header and hence need a copy of
|
||||||
@@ -2678,6 +2681,9 @@ static struct sk_buff *ieee80211_build_h
|
@@ -2708,6 +2711,9 @@ static struct sk_buff *ieee80211_build_h
|
||||||
}
|
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
+ if (padsize)
|
+ if (padsize)
|
||||||
|
@ -193,18 +193,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
if (ieee80211_is_data_qos(fc)) {
|
if (ieee80211_is_data_qos(fc)) {
|
||||||
__le16 *qos_control;
|
__le16 *qos_control;
|
||||||
|
|
||||||
@@ -2691,8 +2697,8 @@ static struct sk_buff *ieee80211_build_h
|
@@ -2883,6 +2889,9 @@ void ieee80211_check_fast_xmit(struct st
|
||||||
} else
|
|
||||||
memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
|
|
||||||
|
|
||||||
- nh_pos += hdrlen;
|
|
||||||
- h_pos += hdrlen;
|
|
||||||
+ nh_pos += hdrlen + padsize;
|
|
||||||
+ h_pos += hdrlen + padsize;
|
|
||||||
|
|
||||||
/* Update skb pointers to various headers since this modified frame
|
|
||||||
* is going to go through Linux networking code that may potentially
|
|
||||||
@@ -2861,6 +2867,9 @@ void ieee80211_check_fast_xmit(struct st
|
|
||||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +205,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
* this function after doing so. For a single CPU that would be enough,
|
* this function after doing so. For a single CPU that would be enough,
|
||||||
--- a/net/mac80211/util.c
|
--- a/net/mac80211/util.c
|
||||||
+++ b/net/mac80211/util.c
|
+++ b/net/mac80211/util.c
|
||||||
@@ -1224,6 +1224,7 @@ void ieee80211_send_auth(struct ieee8021
|
@@ -1225,6 +1225,7 @@ void ieee80211_send_auth(struct ieee8021
|
||||||
u32 tx_flags)
|
u32 tx_flags)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
@ -224,7 +213,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ieee80211_mgmt *mgmt;
|
struct ieee80211_mgmt *mgmt;
|
||||||
unsigned int hdrlen;
|
unsigned int hdrlen;
|
||||||
@@ -1251,7 +1252,7 @@ void ieee80211_send_auth(struct ieee8021
|
@@ -1252,7 +1253,7 @@ void ieee80211_send_auth(struct ieee8021
|
||||||
memcpy(skb_put(skb, extra_len), extra, extra_len);
|
memcpy(skb_put(skb, extra_len), extra, extra_len);
|
||||||
|
|
||||||
if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
|
if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
|
|
@ -10,7 +10,7 @@ Signed-off-by: Chaitanya TK <chaitanya.mgit@gmail.com>
|
||||||
|
|
||||||
--- a/include/linux/ieee80211.h
|
--- a/include/linux/ieee80211.h
|
||||||
+++ b/include/linux/ieee80211.h
|
+++ b/include/linux/ieee80211.h
|
||||||
@@ -1550,6 +1550,7 @@ struct ieee80211_vht_operation {
|
@@ -1551,6 +1551,7 @@ struct ieee80211_vht_operation {
|
||||||
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
|
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
|
||||||
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
|
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
|
||||||
#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
|
#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
|
|
@ -7,10 +7,11 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
@@ -1634,6 +1634,21 @@ void ath_tx_aggr_wakeup(struct ath_softc
|
@@ -1635,6 +1635,22 @@ void ath_tx_aggr_wakeup(struct ath_softc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+
|
||||||
+static void
|
+static void
|
||||||
+ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val)
|
+ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val)
|
||||||
+{
|
+{
|
||||||
|
@ -29,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
|
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_sta *sta,
|
struct ieee80211_sta *sta,
|
||||||
u16 tids, int nframes,
|
u16 tids, int nframes,
|
||||||
@@ -1664,6 +1679,7 @@ void ath9k_release_buffered_frames(struc
|
@@ -1665,6 +1681,7 @@ void ath9k_release_buffered_frames(struc
|
||||||
if (!bf)
|
if (!bf)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
list_add_tail(&bf->list, &bf_q);
|
list_add_tail(&bf->list, &bf_q);
|
||||||
ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
||||||
if (bf_isampdu(bf)) {
|
if (bf_isampdu(bf)) {
|
||||||
@@ -1687,6 +1703,9 @@ void ath9k_release_buffered_frames(struc
|
@@ -1688,6 +1705,9 @@ void ath9k_release_buffered_frames(struc
|
||||||
if (list_empty(&bf_q))
|
if (list_empty(&bf_q))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
From: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
|
|
||||||
Date: Thu, 23 Jun 2016 22:10:01 +0530
|
|
||||||
Subject: [PATCH] ath10k: Fix sending NULL/ Qos NULL data frames for
|
|
||||||
QCA99X0 and later
|
|
||||||
|
|
||||||
For chipsets like QCA99X0, IPQ4019 and later we are not getting proper
|
|
||||||
NULL func status (always acked/successs !!) when hostapd does a
|
|
||||||
PROBE_CLIENT via nullfunc frames when the station is powered off
|
|
||||||
abruptly (inactive timer probes client via null func after the inactive
|
|
||||||
time reaches beyond the threshold). Fix this by disabling the workaround
|
|
||||||
(getting the ACK status of NULL func frames by sending via HTT mgmt-tx
|
|
||||||
path) introduced by the change ("ath10k: fix beacon loss handling ")
|
|
||||||
for QCA99X0 and later chipsets. The normal tx path provides the proper
|
|
||||||
ACK status for NULL data frames. As of now disable this workaround for
|
|
||||||
chipsets QCA99X0 and later, once the 10.1 firmware is obselete we can
|
|
||||||
completely get rid of this workaround for all the chipsets
|
|
||||||
|
|
||||||
Signed-off-by: Tamizh chelvam <c_traja@qti.qualcomm.com>
|
|
||||||
Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/core.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/core.c
|
|
||||||
@@ -181,6 +181,7 @@ static const struct ath10k_hw_params ath
|
|
||||||
.board = QCA99X0_HW_2_0_BOARD_DATA_FILE,
|
|
||||||
.board_size = QCA99X0_BOARD_DATA_SZ,
|
|
||||||
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
|
|
||||||
+ .disable_null_func_workaround = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
@@ -204,6 +205,7 @@ static const struct ath10k_hw_params ath
|
|
||||||
.board = QCA9984_HW_1_0_BOARD_DATA_FILE,
|
|
||||||
.board_size = QCA99X0_BOARD_DATA_SZ,
|
|
||||||
.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
|
|
||||||
+ .disable_null_func_workaround = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
@@ -262,6 +264,7 @@ static const struct ath10k_hw_params ath
|
|
||||||
.board = QCA4019_HW_1_0_BOARD_DATA_FILE,
|
|
||||||
.board_size = QCA4019_BOARD_DATA_SZ,
|
|
||||||
.board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,
|
|
||||||
+ .disable_null_func_workaround = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/core.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/core.h
|
|
||||||
@@ -750,6 +750,12 @@ struct ath10k {
|
|
||||||
const char *board;
|
|
||||||
size_t board_size;
|
|
||||||
size_t board_ext_size;
|
|
||||||
+ /* Workaround of sending NULL data frames via
|
|
||||||
+ * HTT mgmt TX and getting the proper ACK status does
|
|
||||||
+ * not works for chipsets QCA99X0 and later, while
|
|
||||||
+ * Tx data path reports the ACK status properly.
|
|
||||||
+ */
|
|
||||||
+ bool disable_null_func_workaround;
|
|
||||||
} fw;
|
|
||||||
} hw_params;
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
@@ -3253,6 +3253,7 @@ ath10k_mac_tx_h_get_txmode(struct ath10k
|
|
||||||
* mode though because AP don't sleep.
|
|
||||||
*/
|
|
||||||
if (ar->htt.target_version_major < 3 &&
|
|
||||||
+ !ar->hw_params.fw.disable_null_func_workaround &&
|
|
||||||
(ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
|
|
||||||
!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
|
||||||
ar->running_fw->fw_file.fw_features))
|
|
|
@ -1,37 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Wed, 29 Jun 2016 10:02:32 +0200
|
|
||||||
Subject: [PATCH] cfg80211: fix proto in ieee80211_data_to_8023 for frames
|
|
||||||
without LLC header
|
|
||||||
|
|
||||||
The PDU length of incoming LLC frames is set to the total skb payload size
|
|
||||||
in __ieee80211_data_to_8023() of net/wireless/util.c which incorrectly
|
|
||||||
includes the length of the IEEE 802.11 header.
|
|
||||||
|
|
||||||
The resulting LLC frame header has a too large PDU length, causing the
|
|
||||||
llc_fixup_skb() function of net/llc/llc_input.c to reject the incoming
|
|
||||||
skb, effectively breaking STP.
|
|
||||||
|
|
||||||
Solve the problem by properly substracting the IEEE 802.11 frame header size
|
|
||||||
from the PDU length, allowing the LLC processor to pick up the incoming
|
|
||||||
control messages.
|
|
||||||
|
|
||||||
Special thanks to Gerry Rozema for tracking down the regression and proposing
|
|
||||||
a suitable patch.
|
|
||||||
|
|
||||||
Fixes: 2d1c304cb2d5 ("cfg80211: add function for 802.3 conversion with separate output buffer")
|
|
||||||
Cc: stable@vger.kernel.org
|
|
||||||
Reported-by: Gerry Rozema <gerryr@rozeware.com>
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/wireless/util.c
|
|
||||||
+++ b/net/wireless/util.c
|
|
||||||
@@ -509,7 +509,7 @@ static int __ieee80211_data_to_8023(stru
|
|
||||||
* replace EtherType */
|
|
||||||
hdrlen += ETH_ALEN + 2;
|
|
||||||
else
|
|
||||||
- tmp.h_proto = htons(skb->len);
|
|
||||||
+ tmp.h_proto = htons(skb->len - hdrlen);
|
|
||||||
|
|
||||||
pskb_pull(skb, hdrlen);
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
ath_tx_complete_buf(sc, bf, txq,
|
ath_tx_complete_buf(sc, bf, txq,
|
||||||
&bf_head, NULL, ts,
|
&bf_head, NULL, ts,
|
||||||
@@ -986,11 +994,14 @@ ath_tx_get_tid_subframe(struct ath_softc
|
@@ -987,11 +995,14 @@ ath_tx_get_tid_subframe(struct ath_softc
|
||||||
|
|
||||||
INIT_LIST_HEAD(&bf_head);
|
INIT_LIST_HEAD(&bf_head);
|
||||||
list_add(&bf->list, &bf_head);
|
list_add(&bf->list, &bf_head);
|
||||||
|
@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
return bf;
|
return bf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1048,8 +1059,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
@@ -1049,8 +1060,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s
|
||||||
bf->bf_next = NULL;
|
bf->bf_next = NULL;
|
||||||
|
|
||||||
/* link buffers of this frame to the aggregate */
|
/* link buffers of this frame to the aggregate */
|
||||||
|
@ -100,7 +100,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
bf->bf_state.ndelim = ndelim;
|
bf->bf_state.ndelim = ndelim;
|
||||||
|
|
||||||
list_add_tail(&bf->list, bf_q);
|
list_add_tail(&bf->list, bf_q);
|
||||||
@@ -1684,10 +1693,8 @@ void ath9k_release_buffered_frames(struc
|
@@ -1686,10 +1695,8 @@ void ath9k_release_buffered_frames(struc
|
||||||
ath9k_set_moredata(sc, bf, true);
|
ath9k_set_moredata(sc, bf, true);
|
||||||
list_add_tail(&bf->list, &bf_q);
|
list_add_tail(&bf->list, &bf_q);
|
||||||
ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
|
|
@ -0,0 +1,285 @@
|
||||||
|
From: Ben Greear <greearb@candelatech.com>
|
||||||
|
Date: Thu, 6 Oct 2016 17:34:14 -0700
|
||||||
|
Subject: [PATCH] ath10k: Add support for 160Mhz.
|
||||||
|
|
||||||
|
This patch was written by Sebastian Gottschall.
|
||||||
|
|
||||||
|
Signed-off-by: Ben Greear <greearb@candelatech.com>
|
||||||
|
Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
|
||||||
|
@@ -702,6 +702,10 @@ static void ath10k_htt_rx_h_rates(struct
|
||||||
|
/* 80MHZ */
|
||||||
|
case 2:
|
||||||
|
status->vht_flag |= RX_VHT_FLAG_80MHZ;
|
||||||
|
+ break;
|
||||||
|
+ case 3:
|
||||||
|
+ status->vht_flag |= RX_VHT_FLAG_160MHZ;
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
|
||||||
|
status->flag |= RX_FLAG_VHT;
|
||||||
|
@@ -926,7 +930,7 @@ static void ath10k_process_rx(struct ath
|
||||||
|
*status = *rx_status;
|
||||||
|
|
||||||
|
ath10k_dbg(ar, ATH10K_DBG_DATA,
|
||||||
|
- "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%llx fcs-err %i mic-err %i amsdu-more %i\n",
|
||||||
|
+ "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%llx fcs-err %i mic-err %i amsdu-more %i\n",
|
||||||
|
skb,
|
||||||
|
skb->len,
|
||||||
|
ieee80211_get_SA(hdr),
|
||||||
|
@@ -940,6 +944,7 @@ static void ath10k_process_rx(struct ath
|
||||||
|
status->flag & RX_FLAG_VHT ? "vht" : "",
|
||||||
|
status->flag & RX_FLAG_40MHZ ? "40" : "",
|
||||||
|
status->vht_flag & RX_VHT_FLAG_80MHZ ? "80" : "",
|
||||||
|
+ status->vht_flag & RX_VHT_FLAG_160MHZ ? "160" : "",
|
||||||
|
status->flag & RX_FLAG_SHORT_GI ? "sgi " : "",
|
||||||
|
status->rate_idx,
|
||||||
|
status->vht_nss,
|
||||||
|
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
||||||
|
@@ -568,10 +568,14 @@ chan_to_phymode(const struct cfg80211_ch
|
||||||
|
case NL80211_CHAN_WIDTH_80:
|
||||||
|
phymode = MODE_11AC_VHT80;
|
||||||
|
break;
|
||||||
|
+ case NL80211_CHAN_WIDTH_160:
|
||||||
|
+ phymode = MODE_11AC_VHT160;
|
||||||
|
+ break;
|
||||||
|
+ case NL80211_CHAN_WIDTH_80P80:
|
||||||
|
+ phymode = MODE_11AC_VHT80_80;
|
||||||
|
+ break;
|
||||||
|
case NL80211_CHAN_WIDTH_5:
|
||||||
|
case NL80211_CHAN_WIDTH_10:
|
||||||
|
- case NL80211_CHAN_WIDTH_80P80:
|
||||||
|
- case NL80211_CHAN_WIDTH_160:
|
||||||
|
phymode = MODE_UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -970,6 +974,7 @@ static int ath10k_monitor_vdev_start(str
|
||||||
|
arg.vdev_id = vdev_id;
|
||||||
|
arg.channel.freq = channel->center_freq;
|
||||||
|
arg.channel.band_center_freq1 = chandef->center_freq1;
|
||||||
|
+ arg.channel.band_center_freq2 = chandef->center_freq2;
|
||||||
|
|
||||||
|
/* TODO setup this dynamically, what in case we
|
||||||
|
don't have any vifs? */
|
||||||
|
@@ -1381,6 +1386,7 @@ static int ath10k_vdev_start_restart(str
|
||||||
|
|
||||||
|
arg.channel.freq = chandef->chan->center_freq;
|
||||||
|
arg.channel.band_center_freq1 = chandef->center_freq1;
|
||||||
|
+ arg.channel.band_center_freq2 = chandef->center_freq2;
|
||||||
|
arg.channel.mode = chan_to_phymode(chandef);
|
||||||
|
|
||||||
|
arg.channel.min_power = 0;
|
||||||
|
@@ -2444,6 +2450,9 @@ static void ath10k_peer_assoc_h_vht(stru
|
||||||
|
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
|
||||||
|
arg->peer_flags |= ar->wmi.peer_flags->bw80;
|
||||||
|
|
||||||
|
+ if (sta->bandwidth == IEEE80211_STA_RX_BW_160)
|
||||||
|
+ arg->peer_flags |= ar->wmi.peer_flags->bw160;
|
||||||
|
+
|
||||||
|
arg->peer_vht_rates.rx_max_rate =
|
||||||
|
__le16_to_cpu(vht_cap->vht_mcs.rx_highest);
|
||||||
|
arg->peer_vht_rates.rx_mcs_set =
|
||||||
|
@@ -2545,7 +2554,17 @@ static void ath10k_peer_assoc_h_phymode(
|
||||||
|
!ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
|
||||||
|
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
|
||||||
|
phymode = MODE_11AC_VHT80;
|
||||||
|
- else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
|
||||||
|
+ else if (sta->bandwidth == IEEE80211_STA_RX_BW_160) {
|
||||||
|
+ phymode = MODE_11AC_VHT160;
|
||||||
|
+ switch (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||||
|
+ case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
||||||
|
+ phymode = MODE_11AC_VHT160;
|
||||||
|
+ break;
|
||||||
|
+ case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
|
||||||
|
+ phymode = MODE_11AC_VHT80_80;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ } else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
|
||||||
|
phymode = MODE_11AC_VHT40;
|
||||||
|
else if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
|
||||||
|
phymode = MODE_11AC_VHT20;
|
||||||
|
@@ -4277,6 +4296,10 @@ static struct ieee80211_sta_vht_cap ath1
|
||||||
|
vht_cap.cap |= val;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) && !(ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
|
||||||
|
+ vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
mcs_map = 0;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
|
||||||
|
@@ -6913,6 +6936,9 @@ static void ath10k_sta_rc_update(struct
|
||||||
|
bw = WMI_PEER_CHWIDTH_80MHZ;
|
||||||
|
break;
|
||||||
|
case IEEE80211_STA_RX_BW_160:
|
||||||
|
+ bw = WMI_PEER_CHWIDTH_160MHZ;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
ath10k_warn(ar, "Invalid bandwidth %d in rc update for %pM\n",
|
||||||
|
sta->bandwidth, sta->addr);
|
||||||
|
bw = WMI_PEER_CHWIDTH_20MHZ;
|
||||||
|
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
|
||||||
|
@@ -3560,6 +3560,7 @@ static const struct wmi_peer_flags_map w
|
||||||
|
.vht = WMI_TLV_PEER_VHT,
|
||||||
|
.bw80 = WMI_TLV_PEER_80MHZ,
|
||||||
|
.pmf = WMI_TLV_PEER_PMF,
|
||||||
|
+ .bw160 = WMI_TLV_PEER_160MHZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
/************/
|
||||||
|
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
|
||||||
|
@@ -543,6 +543,7 @@ enum wmi_tlv_peer_flags {
|
||||||
|
WMI_TLV_PEER_VHT = 0x02000000,
|
||||||
|
WMI_TLV_PEER_80MHZ = 0x04000000,
|
||||||
|
WMI_TLV_PEER_PMF = 0x08000000,
|
||||||
|
+ WMI_TLV_PEER_160MHZ = 0x20000000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_tlv_tag {
|
||||||
|
--- a/drivers/net/wireless/ath/ath10k/wmi.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
|
||||||
|
@@ -1576,6 +1576,7 @@ static const struct wmi_peer_flags_map w
|
||||||
|
.bw80 = WMI_PEER_80MHZ,
|
||||||
|
.vht_2g = WMI_PEER_VHT_2G,
|
||||||
|
.pmf = WMI_PEER_PMF,
|
||||||
|
+ .bw160 = WMI_PEER_160MHZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wmi_peer_flags_map wmi_10x_peer_flags_map = {
|
||||||
|
@@ -1593,6 +1594,7 @@ static const struct wmi_peer_flags_map w
|
||||||
|
.spatial_mux = WMI_10X_PEER_SPATIAL_MUX,
|
||||||
|
.vht = WMI_10X_PEER_VHT,
|
||||||
|
.bw80 = WMI_10X_PEER_80MHZ,
|
||||||
|
+ .bw160 = WMI_10X_PEER_160MHZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wmi_peer_flags_map wmi_10_2_peer_flags_map = {
|
||||||
|
@@ -1612,6 +1614,7 @@ static const struct wmi_peer_flags_map w
|
||||||
|
.bw80 = WMI_10_2_PEER_80MHZ,
|
||||||
|
.vht_2g = WMI_10_2_PEER_VHT_2G,
|
||||||
|
.pmf = WMI_10_2_PEER_PMF,
|
||||||
|
+ .bw160 = WMI_10_2_PEER_160MHZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
|
||||||
|
@@ -1636,7 +1639,10 @@ void ath10k_wmi_put_wmi_channel(struct w
|
||||||
|
|
||||||
|
ch->mhz = __cpu_to_le32(arg->freq);
|
||||||
|
ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
|
||||||
|
- ch->band_center_freq2 = 0;
|
||||||
|
+ if (arg->mode == MODE_11AC_VHT80_80)
|
||||||
|
+ ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq2);
|
||||||
|
+ else
|
||||||
|
+ ch->band_center_freq2 = 0;
|
||||||
|
ch->min_power = arg->min_power;
|
||||||
|
ch->max_power = arg->max_power;
|
||||||
|
ch->reg_power = arg->max_reg_power;
|
||||||
|
--- a/drivers/net/wireless/ath/ath10k/wmi.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
|
||||||
|
@@ -1728,8 +1728,10 @@ enum wmi_phy_mode {
|
||||||
|
MODE_11AC_VHT20_2G = 11,
|
||||||
|
MODE_11AC_VHT40_2G = 12,
|
||||||
|
MODE_11AC_VHT80_2G = 13,
|
||||||
|
- MODE_UNKNOWN = 14,
|
||||||
|
- MODE_MAX = 14
|
||||||
|
+ MODE_11AC_VHT80_80 = 14,
|
||||||
|
+ MODE_11AC_VHT160 = 15,
|
||||||
|
+ MODE_UNKNOWN = 16,
|
||||||
|
+ MODE_MAX = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode)
|
||||||
|
@@ -1757,6 +1759,10 @@ static inline const char *ath10k_wmi_phy
|
||||||
|
return "11ac-vht40";
|
||||||
|
case MODE_11AC_VHT80:
|
||||||
|
return "11ac-vht80";
|
||||||
|
+ case MODE_11AC_VHT160:
|
||||||
|
+ return "11ac-vht160";
|
||||||
|
+ case MODE_11AC_VHT80_80:
|
||||||
|
+ return "11ac-vht80+80";
|
||||||
|
case MODE_11AC_VHT20_2G:
|
||||||
|
return "11ac-vht20-2g";
|
||||||
|
case MODE_11AC_VHT40_2G:
|
||||||
|
@@ -1811,6 +1817,7 @@ struct wmi_channel {
|
||||||
|
struct wmi_channel_arg {
|
||||||
|
u32 freq;
|
||||||
|
u32 band_center_freq1;
|
||||||
|
+ u32 band_center_freq2;
|
||||||
|
bool passive;
|
||||||
|
bool allow_ibss;
|
||||||
|
bool allow_ht;
|
||||||
|
@@ -1875,9 +1882,18 @@ enum wmi_channel_change_cause {
|
||||||
|
#define WMI_VHT_CAP_MAX_MPDU_LEN_MASK 0x00000003
|
||||||
|
#define WMI_VHT_CAP_RX_LDPC 0x00000010
|
||||||
|
#define WMI_VHT_CAP_SGI_80MHZ 0x00000020
|
||||||
|
+#define WMI_VHT_CAP_SGI_160MHZ 0x00000040
|
||||||
|
#define WMI_VHT_CAP_TX_STBC 0x00000080
|
||||||
|
#define WMI_VHT_CAP_RX_STBC_MASK 0x00000300
|
||||||
|
#define WMI_VHT_CAP_RX_STBC_MASK_SHIFT 8
|
||||||
|
+#define WMI_VHT_CAP_SU_BFER 0x00000800
|
||||||
|
+#define WMI_VHT_CAP_SU_BFEE 0x00001000
|
||||||
|
+#define WMI_VHT_CAP_MAX_CS_ANT_MASK 0x0000E000
|
||||||
|
+#define WMI_VHT_CAP_MAX_CS_ANT_MASK_SHIFT 13
|
||||||
|
+#define WMI_VHT_CAP_MAX_SND_DIM_MASK 0x00070000
|
||||||
|
+#define WMI_VHT_CAP_MAX_SND_DIM_MASK_SHIFT 16
|
||||||
|
+#define WMI_VHT_CAP_MU_BFER 0x00080000
|
||||||
|
+#define WMI_VHT_CAP_MU_BFEE 0x00100000
|
||||||
|
#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP 0x03800000
|
||||||
|
#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT 23
|
||||||
|
#define WMI_VHT_CAP_RX_FIXED_ANT 0x10000000
|
||||||
|
@@ -1926,6 +1942,8 @@ enum {
|
||||||
|
REGDMN_MODE_11AC_VHT40PLUS = 0x40000, /* 5Ghz, VHT40 + channels */
|
||||||
|
REGDMN_MODE_11AC_VHT40MINUS = 0x80000, /* 5Ghz VHT40 - channels */
|
||||||
|
REGDMN_MODE_11AC_VHT80 = 0x100000, /* 5Ghz, VHT80 channels */
|
||||||
|
+ REGDMN_MODE_11AC_VHT160 = 0x200000, /* 5Ghz, VHT160 channels */
|
||||||
|
+ REGDMN_MODE_11AC_VHT80_80 = 0x400000, /* 5Ghz, VHT80+80 channels */
|
||||||
|
REGDMN_MODE_ALL = 0xffffffff
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -5769,6 +5787,7 @@ enum wmi_peer_chwidth {
|
||||||
|
WMI_PEER_CHWIDTH_20MHZ = 0,
|
||||||
|
WMI_PEER_CHWIDTH_40MHZ = 1,
|
||||||
|
WMI_PEER_CHWIDTH_80MHZ = 2,
|
||||||
|
+ WMI_PEER_CHWIDTH_160MHZ = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_peer_param {
|
||||||
|
@@ -5859,6 +5878,7 @@ struct wmi_peer_flags_map {
|
||||||
|
u32 bw80;
|
||||||
|
u32 vht_2g;
|
||||||
|
u32 pmf;
|
||||||
|
+ u32 bw160;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_peer_flags {
|
||||||
|
@@ -5878,6 +5898,7 @@ enum wmi_peer_flags {
|
||||||
|
WMI_PEER_80MHZ = 0x04000000,
|
||||||
|
WMI_PEER_VHT_2G = 0x08000000,
|
||||||
|
WMI_PEER_PMF = 0x10000000,
|
||||||
|
+ WMI_PEER_160MHZ = 0x20000000
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_10x_peer_flags {
|
||||||
|
@@ -5895,6 +5916,7 @@ enum wmi_10x_peer_flags {
|
||||||
|
WMI_10X_PEER_SPATIAL_MUX = 0x00200000,
|
||||||
|
WMI_10X_PEER_VHT = 0x02000000,
|
||||||
|
WMI_10X_PEER_80MHZ = 0x04000000,
|
||||||
|
+ WMI_10X_PEER_160MHZ = 0x20000000
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_10_2_peer_flags {
|
||||||
|
@@ -5914,6 +5936,7 @@ enum wmi_10_2_peer_flags {
|
||||||
|
WMI_10_2_PEER_80MHZ = 0x04000000,
|
||||||
|
WMI_10_2_PEER_VHT_2G = 0x08000000,
|
||||||
|
WMI_10_2_PEER_PMF = 0x10000000,
|
||||||
|
+ WMI_10_2_PEER_160MHZ = 0x20000000
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
|
@ -1,73 +0,0 @@
|
||||||
From: Michal Kazior <michal.kazior@tieto.com>
|
|
||||||
Date: Tue, 17 May 2016 14:47:01 +0200
|
|
||||||
Subject: [PATCH] ath10k: disable wake_tx_queue for older devices
|
|
||||||
|
|
||||||
Some setups suffer performance regressions with
|
|
||||||
current wake_tx_queue implementation.
|
|
||||||
|
|
||||||
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/core.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/core.h
|
|
||||||
@@ -667,6 +667,7 @@ struct ath10k_fw_components {
|
|
||||||
struct ath10k {
|
|
||||||
struct ath_common ath_common;
|
|
||||||
struct ieee80211_hw *hw;
|
|
||||||
+ struct ieee80211_ops *ops;
|
|
||||||
struct device *dev;
|
|
||||||
u8 mac_addr[ETH_ALEN];
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/mac.c
|
|
||||||
@@ -7497,21 +7497,32 @@ static const struct ieee80211_channel at
|
|
||||||
struct ath10k *ath10k_mac_create(size_t priv_size)
|
|
||||||
{
|
|
||||||
struct ieee80211_hw *hw;
|
|
||||||
+ struct ieee80211_ops *ops;
|
|
||||||
struct ath10k *ar;
|
|
||||||
|
|
||||||
- hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops);
|
|
||||||
- if (!hw)
|
|
||||||
+ ops = kmemdup(&ath10k_ops, sizeof(ath10k_ops), GFP_KERNEL);
|
|
||||||
+ if (!ops)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, ops);
|
|
||||||
+ if (!hw) {
|
|
||||||
+ kfree(ops);
|
|
||||||
return NULL;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
ar = hw->priv;
|
|
||||||
ar->hw = hw;
|
|
||||||
+ ar->ops = ops;
|
|
||||||
|
|
||||||
return ar;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ath10k_mac_destroy(struct ath10k *ar)
|
|
||||||
{
|
|
||||||
+ struct ieee80211_ops *ops = ar->ops;
|
|
||||||
+
|
|
||||||
ieee80211_free_hw(ar->hw);
|
|
||||||
+ kfree(ops);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct ieee80211_iface_limit ath10k_if_limits[] = {
|
|
||||||
@@ -7945,6 +7956,15 @@ int ath10k_mac_register(struct ath10k *a
|
|
||||||
ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* Current wake_tx_queue implementation imposes a significant
|
|
||||||
+ * performance penalty in some setups. The tx scheduling code needs
|
|
||||||
+ * more work anyway so disable the wake_tx_queue unless firmware
|
|
||||||
+ * supports the pull-push mechanism.
|
|
||||||
+ */
|
|
||||||
+ if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
|
|
||||||
+ ar->running_fw->fw_file.fw_features))
|
|
||||||
+ ar->ops->wake_tx_queue = NULL;
|
|
||||||
+
|
|
||||||
ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
|
|
||||||
ath10k_reg_notifier);
|
|
||||||
if (ret) {
|
|
|
@ -1,45 +0,0 @@
|
||||||
From: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
Date: Mon, 4 Jul 2016 14:37:20 +0200
|
|
||||||
Subject: [PATCH] ath9k: Correct TSF adjustment to align the beacon time
|
|
||||||
correctly
|
|
||||||
|
|
||||||
Beacons were not send out at (timestamp % beacon_time == 0) for interfaces
|
|
||||||
other than the primary one. To send out beacons with the correct timestamp
|
|
||||||
according to 10.1.3.2 of the 802.11 standard the tsf_adjustment has to be
|
|
||||||
set to the negative time difference instead of positive. This way the
|
|
||||||
later beacons get corrected to have a lower (and similar) timestamp with
|
|
||||||
regard to the beacon from slot 0.
|
|
||||||
|
|
||||||
I am not aware about any issues that have been caused by this.
|
|
||||||
|
|
||||||
Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
|
||||||
@@ -279,17 +279,21 @@ static void ath9k_set_tsfadjust(struct a
|
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
struct ath_beacon_config *cur_conf = &avp->chanctx->beacon;
|
|
||||||
- u32 tsfadjust;
|
|
||||||
+ s64 tsfadjust;
|
|
||||||
|
|
||||||
if (avp->av_bslot == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
+ /* tsf_adjust is added to the TSF value. We send out the beacon late,
|
|
||||||
+ * so need to adjust the TSF starting point to be later in time (i.e.
|
|
||||||
+ * the theoretical first beacon has a TSF of 0 after correction).
|
|
||||||
+ */
|
|
||||||
tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
|
|
||||||
- tsfadjust = TU_TO_USEC(tsfadjust) / ATH_BCBUF;
|
|
||||||
+ tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
|
|
||||||
avp->tsf_adjust = cpu_to_le64(tsfadjust);
|
|
||||||
|
|
||||||
- ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n",
|
|
||||||
- (unsigned long long)tsfadjust, avp->av_bslot);
|
|
||||||
+ ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
|
|
||||||
+ (signed long long)tsfadjust, avp->av_bslot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
|
@ -0,0 +1,275 @@
|
||||||
|
From: Herbert Xu <herbert@gondor.apana.org.au>
|
||||||
|
Date: Mon, 19 Sep 2016 19:00:10 +0800
|
||||||
|
Subject: [PATCH] mac80211: Use rhltable instead of rhashtable
|
||||||
|
|
||||||
|
mac80211 currently uses rhashtable with insecure_elasticity set
|
||||||
|
to true. The latter is because of duplicate objects. What's
|
||||||
|
more, mac80211 walks the rhashtable chains by hand which is broken
|
||||||
|
as rhashtable may contain multiple tables due to resizing or
|
||||||
|
rehashing.
|
||||||
|
|
||||||
|
This patch fixes it by converting it to the newly added rhltable
|
||||||
|
interface which is designed for use with duplicate objects.
|
||||||
|
|
||||||
|
With rhltable a lookup returns a list of objects instead of a
|
||||||
|
single one. This is then fed into the existing for_each_sta_info
|
||||||
|
macro.
|
||||||
|
|
||||||
|
This patch also deletes the sta_addr_hash function since rhashtable
|
||||||
|
defaults to jhash.
|
||||||
|
|
||||||
|
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/net/mac80211/ieee80211_i.h
|
||||||
|
+++ b/net/mac80211/ieee80211_i.h
|
||||||
|
@@ -1233,7 +1233,7 @@ struct ieee80211_local {
|
||||||
|
spinlock_t tim_lock;
|
||||||
|
unsigned long num_sta;
|
||||||
|
struct list_head sta_list;
|
||||||
|
- struct rhashtable sta_hash;
|
||||||
|
+ struct rhltable sta_hash;
|
||||||
|
struct timer_list sta_cleanup;
|
||||||
|
int sta_generation;
|
||||||
|
|
||||||
|
--- a/net/mac80211/rx.c
|
||||||
|
+++ b/net/mac80211/rx.c
|
||||||
|
@@ -4004,7 +4004,7 @@ static void __ieee80211_rx_handle_packet
|
||||||
|
__le16 fc;
|
||||||
|
struct ieee80211_rx_data rx;
|
||||||
|
struct ieee80211_sub_if_data *prev;
|
||||||
|
- struct rhash_head *tmp;
|
||||||
|
+ struct rhlist_head *tmp;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
|
||||||
|
@@ -4047,13 +4047,10 @@ static void __ieee80211_rx_handle_packet
|
||||||
|
goto out;
|
||||||
|
} else if (ieee80211_is_data(fc)) {
|
||||||
|
struct sta_info *sta, *prev_sta;
|
||||||
|
- const struct bucket_table *tbl;
|
||||||
|
|
||||||
|
prev_sta = NULL;
|
||||||
|
|
||||||
|
- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
|
||||||
|
-
|
||||||
|
- for_each_sta_info(local, tbl, hdr->addr2, sta, tmp) {
|
||||||
|
+ for_each_sta_info(local, hdr->addr2, sta, tmp) {
|
||||||
|
if (!prev_sta) {
|
||||||
|
prev_sta = sta;
|
||||||
|
continue;
|
||||||
|
--- a/net/mac80211/sta_info.c
|
||||||
|
+++ b/net/mac80211/sta_info.c
|
||||||
|
@@ -67,12 +67,10 @@
|
||||||
|
|
||||||
|
static const struct rhashtable_params sta_rht_params = {
|
||||||
|
.nelem_hint = 3, /* start small */
|
||||||
|
- .insecure_elasticity = true, /* Disable chain-length checks. */
|
||||||
|
.automatic_shrinking = true,
|
||||||
|
.head_offset = offsetof(struct sta_info, hash_node),
|
||||||
|
.key_offset = offsetof(struct sta_info, addr),
|
||||||
|
.key_len = ETH_ALEN,
|
||||||
|
- .hashfn = sta_addr_hash,
|
||||||
|
.max_size = CPTCFG_MAC80211_STA_HASH_MAX_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -80,8 +78,8 @@ static const struct rhashtable_params st
|
||||||
|
static int sta_info_hash_del(struct ieee80211_local *local,
|
||||||
|
struct sta_info *sta)
|
||||||
|
{
|
||||||
|
- return rhashtable_remove_fast(&local->sta_hash, &sta->hash_node,
|
||||||
|
- sta_rht_params);
|
||||||
|
+ return rhltable_remove(&local->sta_hash, &sta->hash_node,
|
||||||
|
+ sta_rht_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __cleanup_single_sta(struct sta_info *sta)
|
||||||
|
@@ -157,19 +155,22 @@ static void cleanup_single_sta(struct st
|
||||||
|
sta_info_free(local, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
+struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
|
||||||
|
+ const u8 *addr)
|
||||||
|
+{
|
||||||
|
+ return rhltable_lookup(&local->sta_hash, addr, sta_rht_params);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* protected by RCU */
|
||||||
|
struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
|
||||||
|
const u8 *addr)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
+ struct rhlist_head *tmp;
|
||||||
|
struct sta_info *sta;
|
||||||
|
- struct rhash_head *tmp;
|
||||||
|
- const struct bucket_table *tbl;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
|
||||||
|
-
|
||||||
|
- for_each_sta_info(local, tbl, addr, sta, tmp) {
|
||||||
|
+ for_each_sta_info(local, addr, sta, tmp) {
|
||||||
|
if (sta->sdata == sdata) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
/* this is safe as the caller must already hold
|
||||||
|
@@ -190,14 +191,11 @@ struct sta_info *sta_info_get_bss(struct
|
||||||
|
const u8 *addr)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local = sdata->local;
|
||||||
|
+ struct rhlist_head *tmp;
|
||||||
|
struct sta_info *sta;
|
||||||
|
- struct rhash_head *tmp;
|
||||||
|
- const struct bucket_table *tbl;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
|
||||||
|
-
|
||||||
|
- for_each_sta_info(local, tbl, addr, sta, tmp) {
|
||||||
|
+ for_each_sta_info(local, addr, sta, tmp) {
|
||||||
|
if (sta->sdata == sdata ||
|
||||||
|
(sta->sdata->bss && sta->sdata->bss == sdata->bss)) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
@@ -263,8 +261,8 @@ void sta_info_free(struct ieee80211_loca
|
||||||
|
static int sta_info_hash_add(struct ieee80211_local *local,
|
||||||
|
struct sta_info *sta)
|
||||||
|
{
|
||||||
|
- return rhashtable_insert_fast(&local->sta_hash, &sta->hash_node,
|
||||||
|
- sta_rht_params);
|
||||||
|
+ return rhltable_insert(&local->sta_hash, &sta->hash_node,
|
||||||
|
+ sta_rht_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sta_deliver_ps_frames(struct work_struct *wk)
|
||||||
|
@@ -453,9 +451,9 @@ static int sta_info_insert_check(struct
|
||||||
|
is_multicast_ether_addr(sta->sta.addr)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
- /* Strictly speaking this isn't necessary as we hold the mutex, but
|
||||||
|
- * the rhashtable code can't really deal with that distinction. We
|
||||||
|
- * do require the mutex for correctness though.
|
||||||
|
+ /* The RCU read lock is required by rhashtable due to
|
||||||
|
+ * asynchronous resize/rehash. We also require the mutex
|
||||||
|
+ * for correctness.
|
||||||
|
*/
|
||||||
|
rcu_read_lock();
|
||||||
|
lockdep_assert_held(&sdata->local->sta_mtx);
|
||||||
|
@@ -1043,16 +1041,11 @@ static void sta_info_cleanup(unsigned lo
|
||||||
|
round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
-u32 sta_addr_hash(const void *key, u32 length, u32 seed)
|
||||||
|
-{
|
||||||
|
- return jhash(key, ETH_ALEN, seed);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
int sta_info_init(struct ieee80211_local *local)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
- err = rhashtable_init(&local->sta_hash, &sta_rht_params);
|
||||||
|
+ err = rhltable_init(&local->sta_hash, &sta_rht_params);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
@@ -1068,7 +1061,7 @@ int sta_info_init(struct ieee80211_local
|
||||||
|
void sta_info_stop(struct ieee80211_local *local)
|
||||||
|
{
|
||||||
|
del_timer_sync(&local->sta_cleanup);
|
||||||
|
- rhashtable_destroy(&local->sta_hash);
|
||||||
|
+ rhltable_destroy(&local->sta_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1138,17 +1131,14 @@ struct ieee80211_sta *ieee80211_find_sta
|
||||||
|
const u8 *localaddr)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local = hw_to_local(hw);
|
||||||
|
+ struct rhlist_head *tmp;
|
||||||
|
struct sta_info *sta;
|
||||||
|
- struct rhash_head *tmp;
|
||||||
|
- const struct bucket_table *tbl;
|
||||||
|
-
|
||||||
|
- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just return a random station if localaddr is NULL
|
||||||
|
* ... first in list.
|
||||||
|
*/
|
||||||
|
- for_each_sta_info(local, tbl, addr, sta, tmp) {
|
||||||
|
+ for_each_sta_info(local, addr, sta, tmp) {
|
||||||
|
if (localaddr &&
|
||||||
|
!ether_addr_equal(sta->sdata->vif.addr, localaddr))
|
||||||
|
continue;
|
||||||
|
--- a/net/mac80211/sta_info.h
|
||||||
|
+++ b/net/mac80211/sta_info.h
|
||||||
|
@@ -455,7 +455,7 @@ struct sta_info {
|
||||||
|
/* General information, mostly static */
|
||||||
|
struct list_head list, free_list;
|
||||||
|
struct rcu_head rcu_head;
|
||||||
|
- struct rhash_head hash_node;
|
||||||
|
+ struct rhlist_head hash_node;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
struct ieee80211_local *local;
|
||||||
|
struct ieee80211_sub_if_data *sdata;
|
||||||
|
@@ -638,6 +638,9 @@ rcu_dereference_protected_tid_tx(struct
|
||||||
|
*/
|
||||||
|
#define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
|
||||||
|
|
||||||
|
+struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
|
||||||
|
+ const u8 *addr);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Get a STA info, must be under RCU read lock.
|
||||||
|
*/
|
||||||
|
@@ -647,17 +650,9 @@ struct sta_info *sta_info_get(struct iee
|
||||||
|
struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
|
||||||
|
const u8 *addr);
|
||||||
|
|
||||||
|
-u32 sta_addr_hash(const void *key, u32 length, u32 seed);
|
||||||
|
-
|
||||||
|
-#define _sta_bucket_idx(_tbl, _a) \
|
||||||
|
- rht_bucket_index(_tbl, sta_addr_hash(_a, ETH_ALEN, (_tbl)->hash_rnd))
|
||||||
|
-
|
||||||
|
-#define for_each_sta_info(local, tbl, _addr, _sta, _tmp) \
|
||||||
|
- rht_for_each_entry_rcu(_sta, _tmp, tbl, \
|
||||||
|
- _sta_bucket_idx(tbl, _addr), \
|
||||||
|
- hash_node) \
|
||||||
|
- /* compare address and run code only if it matches */ \
|
||||||
|
- if (ether_addr_equal(_sta->addr, (_addr)))
|
||||||
|
+#define for_each_sta_info(local, _addr, _sta, _tmp) \
|
||||||
|
+ rhl_for_each_entry_rcu(_sta, _tmp, \
|
||||||
|
+ sta_info_hash_lookup(local, _addr), hash_node)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get STA info by index, BROKEN!
|
||||||
|
--- a/net/mac80211/status.c
|
||||||
|
+++ b/net/mac80211/status.c
|
||||||
|
@@ -759,8 +759,8 @@ void ieee80211_tx_status(struct ieee8021
|
||||||
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
|
__le16 fc;
|
||||||
|
struct ieee80211_supported_band *sband;
|
||||||
|
+ struct rhlist_head *tmp;
|
||||||
|
struct sta_info *sta;
|
||||||
|
- struct rhash_head *tmp;
|
||||||
|
int retry_count;
|
||||||
|
int rates_idx;
|
||||||
|
bool send_to_cooked;
|
||||||
|
@@ -768,7 +768,6 @@ void ieee80211_tx_status(struct ieee8021
|
||||||
|
struct ieee80211_bar *bar;
|
||||||
|
int shift = 0;
|
||||||
|
int tid = IEEE80211_NUM_TIDS;
|
||||||
|
- const struct bucket_table *tbl;
|
||||||
|
|
||||||
|
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
|
||||||
|
|
||||||
|
@@ -777,9 +776,7 @@ void ieee80211_tx_status(struct ieee8021
|
||||||
|
sband = local->hw.wiphy->bands[info->band];
|
||||||
|
fc = hdr->frame_control;
|
||||||
|
|
||||||
|
- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
|
||||||
|
-
|
||||||
|
- for_each_sta_info(local, tbl, hdr->addr1, sta, tmp) {
|
||||||
|
+ for_each_sta_info(local, hdr->addr1, sta, tmp) {
|
||||||
|
/* skip wrong virtual interface */
|
||||||
|
if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
|
||||||
|
continue;
|
|
@ -1,70 +0,0 @@
|
||||||
From: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
Date: Mon, 4 Jul 2016 14:37:21 +0200
|
|
||||||
Subject: [PATCH] ath9k: Handle channel context in get_/set_/reset_tsf
|
|
||||||
|
|
||||||
The ath9k TSF handling routines need to be aware of the channel context that
|
|
||||||
is being modified. With this change the TSF related values that are stored
|
|
||||||
in each channel context will be correctly tracked and the harware will only
|
|
||||||
be updated if the modified context is currently the active one.
|
|
||||||
|
|
||||||
Without this change the TSF modifications done using these routines would
|
|
||||||
for example be lost during a hardware reset as done by ath_complete_reset.
|
|
||||||
|
|
||||||
Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -1823,11 +1823,18 @@ static void ath9k_bss_info_changed(struc
|
|
||||||
static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
||||||
{
|
|
||||||
struct ath_softc *sc = hw->priv;
|
|
||||||
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
u64 tsf;
|
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
- tsf = ath9k_hw_gettsf64(sc->sc_ah);
|
|
||||||
+ /* Get current TSF either from HW or kernel time. */
|
|
||||||
+ if (sc->cur_chan == avp->chanctx) {
|
|
||||||
+ tsf = ath9k_hw_gettsf64(sc->sc_ah);
|
|
||||||
+ } else {
|
|
||||||
+ tsf = sc->cur_chan->tsf_val +
|
|
||||||
+ ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
|
|
||||||
+ }
|
|
||||||
ath9k_ps_restore(sc);
|
|
||||||
mutex_unlock(&sc->mutex);
|
|
||||||
|
|
||||||
@@ -1839,10 +1846,14 @@ static void ath9k_set_tsf(struct ieee802
|
|
||||||
u64 tsf)
|
|
||||||
{
|
|
||||||
struct ath_softc *sc = hw->priv;
|
|
||||||
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
- ath9k_hw_settsf64(sc->sc_ah, tsf);
|
|
||||||
+ getrawmonotonic(&avp->chanctx->tsf_ts);
|
|
||||||
+ if (sc->cur_chan == avp->chanctx)
|
|
||||||
+ ath9k_hw_settsf64(sc->sc_ah, tsf);
|
|
||||||
+ avp->chanctx->tsf_val = tsf;
|
|
||||||
ath9k_ps_restore(sc);
|
|
||||||
mutex_unlock(&sc->mutex);
|
|
||||||
}
|
|
||||||
@@ -1850,11 +1861,15 @@ static void ath9k_set_tsf(struct ieee802
|
|
||||||
static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
||||||
{
|
|
||||||
struct ath_softc *sc = hw->priv;
|
|
||||||
+ struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
|
||||||
|
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
- ath9k_hw_reset_tsf(sc->sc_ah);
|
|
||||||
+ getrawmonotonic(&avp->chanctx->tsf_ts);
|
|
||||||
+ if (sc->cur_chan == avp->chanctx)
|
|
||||||
+ ath9k_hw_reset_tsf(sc->sc_ah);
|
|
||||||
+ avp->chanctx->tsf_val = 0;
|
|
||||||
ath9k_ps_restore(sc);
|
|
||||||
|
|
||||||
mutex_unlock(&sc->mutex);
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Tue, 11 Oct 2016 11:24:07 +0200
|
||||||
|
Subject: [PATCH] mac80211: fix sequence number allocation regression
|
||||||
|
|
||||||
|
The recent commit that moved around TX handlers dropped the sequence
|
||||||
|
number allocation at the end of ieee80211_tx_dequeue and calls
|
||||||
|
ieee80211_tx_h_sequence instead (for the non-fast-xmit case).
|
||||||
|
However, it did not change the fast-xmit sequence allocation condition
|
||||||
|
in ieee80211_xmit_fast_finish, which skipped seqno alloc if intermediate
|
||||||
|
tx queues are being used.
|
||||||
|
|
||||||
|
Drop the now obsolete condition.
|
||||||
|
|
||||||
|
Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue")
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/net/mac80211/tx.c
|
||||||
|
+++ b/net/mac80211/tx.c
|
||||||
|
@@ -3212,7 +3212,6 @@ static void ieee80211_xmit_fast_finish(s
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
|
- struct ieee80211_local *local = sdata->local;
|
||||||
|
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||||
|
u8 tid = IEEE80211_NUM_TIDS;
|
||||||
|
|
||||||
|
@@ -3224,8 +3223,7 @@ static void ieee80211_xmit_fast_finish(s
|
||||||
|
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||||
|
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||||
|
*ieee80211_get_qos_ctl(hdr) = tid;
|
||||||
|
- if (!ieee80211_get_txq(local, &sdata->vif, &sta->sta, skb))
|
||||||
|
- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
||||||
|
+ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
||||||
|
} else {
|
||||||
|
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||||
|
hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
|
|
@ -1,65 +0,0 @@
|
||||||
From: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
Date: Mon, 4 Jul 2016 14:37:22 +0200
|
|
||||||
Subject: [PATCH] ath9k: Use tsf offset helper in ath9k_hw_reset
|
|
||||||
|
|
||||||
These changes make ath9k_hw_reset more consistent with other places that
|
|
||||||
handle the TSF value by using the same helper routine.
|
|
||||||
|
|
||||||
A slight improvement is to not assume that a fixed time of 1.5ms has
|
|
||||||
passed for the initval writes when compared to the first write attempt.
|
|
||||||
Instead the TSF value is re-calculated which will yield a higher accuracy
|
|
||||||
of the restored TSF timer.
|
|
||||||
|
|
||||||
Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
||||||
@@ -1832,8 +1832,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
|
||||||
u32 saveLedState;
|
|
||||||
u32 saveDefAntenna;
|
|
||||||
u32 macStaId1;
|
|
||||||
+ struct timespec tsf_ts;
|
|
||||||
+ u32 tsf_offset;
|
|
||||||
u64 tsf = 0;
|
|
||||||
- s64 usec = 0;
|
|
||||||
int r;
|
|
||||||
bool start_mci_reset = false;
|
|
||||||
bool save_fullsleep = ah->chip_fullsleep;
|
|
||||||
@@ -1877,8 +1878,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
|
||||||
macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
|
|
||||||
|
|
||||||
/* Save TSF before chip reset, a cold reset clears it */
|
|
||||||
+ getrawmonotonic(&tsf_ts);
|
|
||||||
tsf = ath9k_hw_gettsf64(ah);
|
|
||||||
- usec = ktime_to_us(ktime_get_raw());
|
|
||||||
|
|
||||||
saveLedState = REG_READ(ah, AR_CFG_LED) &
|
|
||||||
(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
|
|
||||||
@@ -1911,8 +1912,8 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore TSF */
|
|
||||||
- usec = ktime_to_us(ktime_get_raw()) - usec;
|
|
||||||
- ath9k_hw_settsf64(ah, tsf + usec);
|
|
||||||
+ tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
|
|
||||||
+ ath9k_hw_settsf64(ah, tsf + tsf_offset);
|
|
||||||
|
|
||||||
if (AR_SREV_9280_20_OR_LATER(ah))
|
|
||||||
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
|
|
||||||
@@ -1932,12 +1933,11 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
|
||||||
/*
|
|
||||||
* Some AR91xx SoC devices frequently fail to accept TSF writes
|
|
||||||
* right after the chip reset. When that happens, write a new
|
|
||||||
- * value after the initvals have been applied, with an offset
|
|
||||||
- * based on measured time difference
|
|
||||||
+ * value after the initvals have been applied.
|
|
||||||
*/
|
|
||||||
if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {
|
|
||||||
- tsf += 1500;
|
|
||||||
- ath9k_hw_settsf64(ah, tsf);
|
|
||||||
+ tsf_offset = ath9k_hw_get_tsf_offset(&tsf_ts, NULL);
|
|
||||||
+ ath9k_hw_settsf64(ah, tsf + tsf_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
ath9k_hw_init_mfp(ah);
|
|
|
@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
@@ -1398,8 +1398,12 @@ static bool ath9k_hw_set_reset(struct at
|
@@ -1394,8 +1394,12 @@ static bool ath9k_hw_set_reset(struct at
|
||||||
if (!AR_SREV_9100(ah))
|
if (!AR_SREV_9100(ah))
|
||||||
REG_WRITE(ah, AR_RC, 0);
|
REG_WRITE(ah, AR_RC, 0);
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
From: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
Date: Mon, 4 Jul 2016 14:37:23 +0200
|
|
||||||
Subject: [PATCH] ath9k: Expose tsf_adjustment in mac80211 tsf getters and
|
|
||||||
setters.
|
|
||||||
|
|
||||||
The ath9k driver modifies the TSF for VIFs for the purpose of sending
|
|
||||||
beacons in a staggered fashion. This patch exposes this VIF specific
|
|
||||||
adjustment of the TSF value to mac80211. Without the change the TSF
|
|
||||||
routines handle the hardware TSF value instead of the actual TSF value as
|
|
||||||
seen on the air.
|
|
||||||
|
|
||||||
Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -1835,6 +1835,7 @@ static u64 ath9k_get_tsf(struct ieee8021
|
|
||||||
tsf = sc->cur_chan->tsf_val +
|
|
||||||
ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL);
|
|
||||||
}
|
|
||||||
+ tsf += le64_to_cpu(avp->tsf_adjust);
|
|
||||||
ath9k_ps_restore(sc);
|
|
||||||
mutex_unlock(&sc->mutex);
|
|
||||||
|
|
||||||
@@ -1850,6 +1851,7 @@ static void ath9k_set_tsf(struct ieee802
|
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
|
||||||
ath9k_ps_wakeup(sc);
|
|
||||||
+ tsf -= le64_to_cpu(avp->tsf_adjust);
|
|
||||||
getrawmonotonic(&avp->chanctx->tsf_ts);
|
|
||||||
if (sc->cur_chan == avp->chanctx)
|
|
||||||
ath9k_hw_settsf64(sc->sc_ah, tsf);
|
|
|
@ -1,6 +1,6 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
Date: Sat, 9 Jul 2016 15:26:44 +0200
|
Date: Sat, 9 Jul 2016 15:26:44 +0200
|
||||||
Subject: [PATCH] ath9k_hw: issue external reset for QCA9550
|
Subject: [PATCH] ath9k_hw: issue external reset for QCA955x
|
||||||
|
|
||||||
The RTC interface on the SoC needs to be reset along with the rest of
|
The RTC interface on the SoC needs to be reset along with the rest of
|
||||||
the WMAC.
|
the WMAC.
|
||||||
|
@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
@@ -1275,39 +1275,56 @@ void ath9k_hw_get_delta_slope_vals(struc
|
@@ -1271,39 +1271,56 @@ void ath9k_hw_get_delta_slope_vals(struc
|
||||||
*coef_exponent = coef_exp - 16;
|
*coef_exponent = coef_exp - 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1360,24 +1377,23 @@ static bool ath9k_hw_set_reset(struct at
|
@@ -1356,24 +1373,23 @@ static bool ath9k_hw_set_reset(struct at
|
||||||
rst_flags |= AR_RTC_RC_MAC_COLD;
|
rst_flags |= AR_RTC_RC_MAC_COLD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
From: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
Date: Mon, 4 Jul 2016 14:37:24 +0200
|
|
||||||
Subject: [PATCH] ath9k: Remove some #defined constants to decrease
|
|
||||||
verbosity
|
|
||||||
|
|
||||||
The removed ATH9K_SLOT_TIME_X constants simply map the value in microseconds
|
|
||||||
to the same integer. These constants were not used consistently, so fix the
|
|
||||||
inconsistency issue by replacing all occurances with the integer equivalent.
|
|
||||||
|
|
||||||
Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
|
||||||
@@ -50,7 +50,7 @@ static void ath9k_beaconq_config(struct
|
|
||||||
txq = sc->tx.txq_map[IEEE80211_AC_BE];
|
|
||||||
ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
|
|
||||||
qi.tqi_aifs = qi_be.tqi_aifs;
|
|
||||||
- if (ah->slottime == ATH9K_SLOT_TIME_20)
|
|
||||||
+ if (ah->slottime == 20)
|
|
||||||
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
|
|
||||||
else
|
|
||||||
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/dynack.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
|
|
||||||
@@ -280,7 +280,7 @@ EXPORT_SYMBOL(ath_dynack_sample_ack_ts);
|
|
||||||
void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
|
|
||||||
{
|
|
||||||
/* ackto = slottime + sifs + air delay */
|
|
||||||
- u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
|
|
||||||
+ u32 ackto = 9 + 16 + 64;
|
|
||||||
struct ath_dynack *da = &ah->dynack;
|
|
||||||
|
|
||||||
an->ackto = ackto;
|
|
||||||
@@ -315,7 +315,7 @@ EXPORT_SYMBOL(ath_dynack_node_deinit);
|
|
||||||
void ath_dynack_reset(struct ath_hw *ah)
|
|
||||||
{
|
|
||||||
/* ackto = slottime + sifs + air delay */
|
|
||||||
- u32 ackto = ATH9K_SLOT_TIME_9 + 16 + 64;
|
|
||||||
+ u32 ackto = 9 + 16 + 64;
|
|
||||||
struct ath_dynack *da = &ah->dynack;
|
|
||||||
|
|
||||||
da->lto = jiffies;
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
|
|
||||||
@@ -45,7 +45,7 @@ void ath9k_htc_beaconq_config(struct ath
|
|
||||||
* Long slot time : 2x cwmin
|
|
||||||
* Short slot time : 4x cwmin
|
|
||||||
*/
|
|
||||||
- if (ah->slottime == ATH9K_SLOT_TIME_20)
|
|
||||||
+ if (ah->slottime == 20)
|
|
||||||
qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
|
|
||||||
else
|
|
||||||
qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
|
|
||||||
@@ -678,7 +678,7 @@ static int ath9k_init_priv(struct ath9k_
|
|
||||||
|
|
||||||
for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
|
|
||||||
priv->beacon.bslot[i] = NULL;
|
|
||||||
- priv->beacon.slottime = ATH9K_SLOT_TIME_9;
|
|
||||||
+ priv->beacon.slottime = 9;
|
|
||||||
|
|
||||||
ath9k_cmn_init_channels_rates(common);
|
|
||||||
ath9k_cmn_init_crypto(ah);
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
||||||
@@ -454,7 +454,7 @@ static void ath9k_hw_init_defaults(struc
|
|
||||||
if (AR_SREV_9100(ah))
|
|
||||||
ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
|
|
||||||
|
|
||||||
- ah->slottime = ATH9K_SLOT_TIME_9;
|
|
||||||
+ ah->slottime = 9;
|
|
||||||
ah->globaltxtimeout = (u32) -1;
|
|
||||||
ah->power_mode = ATH9K_PM_UNDEFINED;
|
|
||||||
ah->htc_reset_init = true;
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
|
||||||
@@ -372,7 +372,7 @@ static void ath9k_init_misc(struct ath_s
|
|
||||||
|
|
||||||
common->last_rssi = ATH_RSSI_DUMMY_MARKER;
|
|
||||||
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
|
||||||
- sc->beacon.slottime = ATH9K_SLOT_TIME_9;
|
|
||||||
+ sc->beacon.slottime = 9;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
|
|
||||||
sc->beacon.bslot[i] = NULL;
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/mac.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/mac.h
|
|
||||||
@@ -65,10 +65,6 @@
|
|
||||||
#define INIT_SSH_RETRY 32
|
|
||||||
#define INIT_SLG_RETRY 32
|
|
||||||
|
|
||||||
-#define ATH9K_SLOT_TIME_6 6
|
|
||||||
-#define ATH9K_SLOT_TIME_9 9
|
|
||||||
-#define ATH9K_SLOT_TIME_20 20
|
|
||||||
-
|
|
||||||
#define ATH9K_TXERR_XRETRY 0x01
|
|
||||||
#define ATH9K_TXERR_FILT 0x02
|
|
||||||
#define ATH9K_TXERR_FIFO 0x04
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -926,7 +926,7 @@ static void ath9k_vif_iter(struct ath9k_
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vif->bss_conf.use_short_slot)
|
|
||||||
- iter_data->slottime = ATH9K_SLOT_TIME_20;
|
|
||||||
+ iter_data->slottime = 20;
|
|
||||||
|
|
||||||
switch (vif->type) {
|
|
||||||
case NL80211_IFTYPE_AP:
|
|
||||||
@@ -999,7 +999,7 @@ void ath9k_calculate_iter_data(struct at
|
|
||||||
*/
|
|
||||||
memset(iter_data, 0, sizeof(*iter_data));
|
|
||||||
eth_broadcast_addr(iter_data->mask);
|
|
||||||
- iter_data->slottime = ATH9K_SLOT_TIME_9;
|
|
||||||
+ iter_data->slottime = 9;
|
|
||||||
|
|
||||||
list_for_each_entry(avp, &ctx->vifs, list)
|
|
||||||
ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
|
|
||||||
@@ -1061,7 +1061,7 @@ static void ath9k_set_offchannel_state(s
|
|
||||||
ah->opmode = vif->type;
|
|
||||||
ah->imask &= ~ATH9K_INT_SWBA;
|
|
||||||
ah->imask &= ~ATH9K_INT_TSFOOR;
|
|
||||||
- ah->slottime = ATH9K_SLOT_TIME_9;
|
|
||||||
+ ah->slottime = 9;
|
|
||||||
|
|
||||||
ath_hw_setbssidmask(common);
|
|
||||||
ath9k_hw_setopmode(ah);
|
|
||||||
@@ -1788,6 +1788,7 @@ static void ath9k_bss_info_changed(struc
|
|
||||||
slottime = 9;
|
|
||||||
else
|
|
||||||
slottime = 20;
|
|
||||||
+
|
|
||||||
if (vif->type == NL80211_IFTYPE_AP) {
|
|
||||||
/*
|
|
||||||
* Defer update, so that connected stations can adjust
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Mon, 11 Jul 2016 12:07:40 +0200
|
||||||
|
Subject: [PATCH] ath9k_hw: set spectral scan enable bit on trigger for
|
||||||
|
AR9003+
|
||||||
|
|
||||||
|
AR9002 code and QCA AR9003+ code do the same.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||||
|
@@ -1800,6 +1800,8 @@ static void ar9003_hw_spectral_scan_conf
|
||||||
|
|
||||||
|
static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
|
||||||
|
{
|
||||||
|
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
|
||||||
|
+ AR_PHY_SPECTRAL_SCAN_ENABLE);
|
||||||
|
/* Activate spectral scan */
|
||||||
|
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
|
||||||
|
AR_PHY_SPECTRAL_SCAN_ACTIVE);
|
|
@ -0,0 +1,101 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Tue, 11 Oct 2016 19:45:41 +0200
|
||||||
|
Subject: [PATCH] Revert "ath9k_hw: implement temperature compensation support
|
||||||
|
for AR9003+"
|
||||||
|
|
||||||
|
This reverts commit 171f6402e4aa5cd3b8407f82501f7ea21fa54ccc.
|
||||||
|
Some users report that this commit causes a regression in performance
|
||||||
|
under some conditions.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
||||||
|
@@ -33,7 +33,6 @@ struct coeff {
|
||||||
|
|
||||||
|
enum ar9003_cal_types {
|
||||||
|
IQ_MISMATCH_CAL = BIT(0),
|
||||||
|
- TEMP_COMP_CAL = BIT(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ar9003_hw_setup_calibration(struct ath_hw *ah,
|
||||||
|
@@ -59,12 +58,6 @@ static void ar9003_hw_setup_calibration(
|
||||||
|
/* Kick-off cal */
|
||||||
|
REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
|
||||||
|
break;
|
||||||
|
- case TEMP_COMP_CAL:
|
||||||
|
- ath_dbg(common, CALIBRATE,
|
||||||
|
- "starting Temperature Compensation Calibration\n");
|
||||||
|
- REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL);
|
||||||
|
- REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START);
|
||||||
|
- break;
|
||||||
|
default:
|
||||||
|
ath_err(common, "Invalid calibration type\n");
|
||||||
|
break;
|
||||||
|
@@ -93,8 +86,7 @@ static bool ar9003_hw_per_calibration(st
|
||||||
|
/*
|
||||||
|
* Accumulate cal measures for active chains
|
||||||
|
*/
|
||||||
|
- if (cur_caldata->calCollect)
|
||||||
|
- cur_caldata->calCollect(ah);
|
||||||
|
+ cur_caldata->calCollect(ah);
|
||||||
|
ah->cal_samples++;
|
||||||
|
|
||||||
|
if (ah->cal_samples >= cur_caldata->calNumSamples) {
|
||||||
|
@@ -107,8 +99,7 @@ static bool ar9003_hw_per_calibration(st
|
||||||
|
/*
|
||||||
|
* Process accumulated data
|
||||||
|
*/
|
||||||
|
- if (cur_caldata->calPostProc)
|
||||||
|
- cur_caldata->calPostProc(ah, numChains);
|
||||||
|
+ cur_caldata->calPostProc(ah, numChains);
|
||||||
|
|
||||||
|
/* Calibration has finished. */
|
||||||
|
caldata->CalValid |= cur_caldata->calType;
|
||||||
|
@@ -323,16 +314,9 @@ static const struct ath9k_percal_data iq
|
||||||
|
ar9003_hw_iqcalibrate
|
||||||
|
};
|
||||||
|
|
||||||
|
-static const struct ath9k_percal_data temp_cal_single_sample = {
|
||||||
|
- TEMP_COMP_CAL,
|
||||||
|
- MIN_CAL_SAMPLES,
|
||||||
|
- PER_MAX_LOG_COUNT,
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
|
||||||
|
{
|
||||||
|
ah->iq_caldata.calData = &iq_cal_single_sample;
|
||||||
|
- ah->temp_caldata.calData = &temp_cal_single_sample;
|
||||||
|
|
||||||
|
if (AR_SREV_9300_20_OR_LATER(ah)) {
|
||||||
|
ah->enabled_cals |= TX_IQ_CAL;
|
||||||
|
@@ -340,7 +324,7 @@ static void ar9003_hw_init_cal_settings(
|
||||||
|
ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL;
|
||||||
|
+ ah->supp_cals = IQ_MISMATCH_CAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OFF_UPPER_LT 24
|
||||||
|
@@ -1399,9 +1383,6 @@ static void ar9003_hw_init_cal_common(st
|
||||||
|
INIT_CAL(&ah->iq_caldata);
|
||||||
|
INSERT_CAL(ah, &ah->iq_caldata);
|
||||||
|
|
||||||
|
- INIT_CAL(&ah->temp_caldata);
|
||||||
|
- INSERT_CAL(ah, &ah->temp_caldata);
|
||||||
|
-
|
||||||
|
/* Initialize current pointer to first element in list */
|
||||||
|
ah->cal_list_curr = ah->cal_list;
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||||
|
@@ -830,7 +830,6 @@ struct ath_hw {
|
||||||
|
/* Calibration */
|
||||||
|
u32 supp_cals;
|
||||||
|
struct ath9k_cal_list iq_caldata;
|
||||||
|
- struct ath9k_cal_list temp_caldata;
|
||||||
|
struct ath9k_cal_list adcgain_caldata;
|
||||||
|
struct ath9k_cal_list adcdc_caldata;
|
||||||
|
struct ath9k_cal_list *cal_list;
|
|
@ -1,544 +0,0 @@
|
||||||
From: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
Date: Mon, 4 Jul 2016 14:37:25 +0200
|
|
||||||
Subject: [PATCH] ath9k: Fix beacon configuration for addition/removal of
|
|
||||||
interfaces
|
|
||||||
|
|
||||||
This patch fixes some issues with interface reconfiguration. It could
|
|
||||||
for example happen that an AP interface in beacon slot 0 was removed
|
|
||||||
leaving an IBSS station in one of the other slots. When this happens
|
|
||||||
the driver never sends out the beacon as it only tries to send a beacon
|
|
||||||
from slot 0.
|
|
||||||
|
|
||||||
Appart from that the tracking of required changes to the beacon config is
|
|
||||||
relatively complicated and prone to errors.
|
|
||||||
|
|
||||||
The approach taken here is to solve reconfiguration issues is to
|
|
||||||
reconfigure the beacons when any interface changes. This means that
|
|
||||||
the complexity of deciding whether an interface change may modify the
|
|
||||||
beacon configuration is gone. It also means that the beacon config will
|
|
||||||
be reliably updated when an interface is removed.
|
|
||||||
|
|
||||||
The issue that a single non-AP interface might not be in beacon
|
|
||||||
slot 0 and wouldn't be send out is solved by moving it into the
|
|
||||||
first slot. The TSF value in hardware is adjusted accordingly so
|
|
||||||
that the timestamp of the beacons stay consistent.
|
|
||||||
|
|
||||||
Signed-off-by: Benjamin Berg <benjamin.berg@open-mesh.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
|
||||||
@@ -637,6 +637,8 @@ struct ath9k_vif_iter_data {
|
|
||||||
int nwds; /* number of WDS vifs */
|
|
||||||
int nadhocs; /* number of adhoc vifs */
|
|
||||||
int nocbs; /* number of OCB vifs */
|
|
||||||
+ int nbcnvifs; /* number of beaconing vifs */
|
|
||||||
+ struct ieee80211_vif *primary_beacon_vif;
|
|
||||||
struct ieee80211_vif *primary_sta;
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -685,10 +687,11 @@ struct ath_beacon {
|
|
||||||
};
|
|
||||||
|
|
||||||
void ath9k_beacon_tasklet(unsigned long data);
|
|
||||||
-void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|
||||||
- u32 changed);
|
|
||||||
+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
|
|
||||||
+ bool beacons);
|
|
||||||
void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
||||||
void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
||||||
+void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc);
|
|
||||||
void ath9k_set_beacon(struct ath_softc *sc);
|
|
||||||
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif);
|
|
||||||
void ath9k_csa_update(struct ath_softc *sc);
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
|
||||||
@@ -209,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath
|
|
||||||
}
|
|
||||||
|
|
||||||
sc->beacon.bslot[avp->av_bslot] = vif;
|
|
||||||
- sc->nbcnvifs++;
|
|
||||||
|
|
||||||
ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
|
|
||||||
avp->av_bslot);
|
|
||||||
@@ -220,15 +219,12 @@ void ath9k_beacon_remove_slot(struct ath
|
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
struct ath_buf *bf = avp->av_bcbuf;
|
|
||||||
- struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon;
|
|
||||||
|
|
||||||
ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
|
|
||||||
avp->av_bslot);
|
|
||||||
|
|
||||||
tasklet_disable(&sc->bcon_tasklet);
|
|
||||||
|
|
||||||
- cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
|
|
||||||
-
|
|
||||||
if (bf && bf->bf_mpdu) {
|
|
||||||
struct sk_buff *skb = bf->bf_mpdu;
|
|
||||||
dma_unmap_single(sc->dev, bf->bf_buf_addr,
|
|
||||||
@@ -240,12 +236,73 @@ void ath9k_beacon_remove_slot(struct ath
|
|
||||||
|
|
||||||
avp->av_bcbuf = NULL;
|
|
||||||
sc->beacon.bslot[avp->av_bslot] = NULL;
|
|
||||||
- sc->nbcnvifs--;
|
|
||||||
list_add_tail(&bf->list, &sc->beacon.bbuf);
|
|
||||||
|
|
||||||
tasklet_enable(&sc->bcon_tasklet);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
|
|
||||||
+{
|
|
||||||
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
+ struct ieee80211_vif *vif;
|
|
||||||
+ struct ath_vif *avp;
|
|
||||||
+ s64 tsfadjust;
|
|
||||||
+ u32 offset;
|
|
||||||
+ int first_slot = ATH_BCBUF;
|
|
||||||
+ int slot;
|
|
||||||
+
|
|
||||||
+ tasklet_disable(&sc->bcon_tasklet);
|
|
||||||
+
|
|
||||||
+ /* Find first taken slot. */
|
|
||||||
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
|
|
||||||
+ if (sc->beacon.bslot[slot]) {
|
|
||||||
+ first_slot = slot;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ if (first_slot == 0)
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+ /* Re-enumarate all slots, moving them forward. */
|
|
||||||
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
|
|
||||||
+ if (slot + first_slot < ATH_BCBUF) {
|
|
||||||
+ vif = sc->beacon.bslot[slot + first_slot];
|
|
||||||
+ sc->beacon.bslot[slot] = vif;
|
|
||||||
+
|
|
||||||
+ if (vif) {
|
|
||||||
+ avp = (void *)vif->drv_priv;
|
|
||||||
+ avp->av_bslot = slot;
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ sc->beacon.bslot[slot] = NULL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ vif = sc->beacon.bslot[0];
|
|
||||||
+ if (WARN_ON(!vif))
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+ /* Get the tsf_adjust value for the new first slot. */
|
|
||||||
+ avp = (void *)vif->drv_priv;
|
|
||||||
+ tsfadjust = le64_to_cpu(avp->tsf_adjust);
|
|
||||||
+
|
|
||||||
+ ath_dbg(common, CONFIG,
|
|
||||||
+ "Adjusting global TSF after beacon slot reassignment: %lld\n",
|
|
||||||
+ (signed long long)tsfadjust);
|
|
||||||
+
|
|
||||||
+ /* Modify TSF as required and update the HW. */
|
|
||||||
+ avp->chanctx->tsf_val += tsfadjust;
|
|
||||||
+ if (sc->cur_chan == avp->chanctx) {
|
|
||||||
+ offset = ath9k_hw_get_tsf_offset(&avp->chanctx->tsf_ts, NULL);
|
|
||||||
+ ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* The slots tsf_adjust will be updated by ath9k_beacon_config later. */
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ tasklet_enable(&sc->bcon_tasklet);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int ath9k_beacon_choose_slot(struct ath_softc *sc)
|
|
||||||
{
|
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
@@ -274,26 +331,33 @@ static int ath9k_beacon_choose_slot(stru
|
|
||||||
return slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
||||||
+static void ath9k_set_tsfadjust(struct ath_softc *sc,
|
|
||||||
+ struct ath_beacon_config *cur_conf)
|
|
||||||
{
|
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
- struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
- struct ath_beacon_config *cur_conf = &avp->chanctx->beacon;
|
|
||||||
s64 tsfadjust;
|
|
||||||
+ int slot;
|
|
||||||
|
|
||||||
- if (avp->av_bslot == 0)
|
|
||||||
- return;
|
|
||||||
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
|
|
||||||
+ struct ath_vif *avp;
|
|
||||||
|
|
||||||
- /* tsf_adjust is added to the TSF value. We send out the beacon late,
|
|
||||||
- * so need to adjust the TSF starting point to be later in time (i.e.
|
|
||||||
- * the theoretical first beacon has a TSF of 0 after correction).
|
|
||||||
- */
|
|
||||||
- tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
|
|
||||||
- tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
|
|
||||||
- avp->tsf_adjust = cpu_to_le64(tsfadjust);
|
|
||||||
+ if (!sc->beacon.bslot[slot])
|
|
||||||
+ continue;
|
|
||||||
|
|
||||||
- ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
|
|
||||||
- (signed long long)tsfadjust, avp->av_bslot);
|
|
||||||
+ avp = (void *)sc->beacon.bslot[slot]->drv_priv;
|
|
||||||
+
|
|
||||||
+ /* tsf_adjust is added to the TSF value. We send out the
|
|
||||||
+ * beacon late, so need to adjust the TSF starting point to be
|
|
||||||
+ * later in time (i.e. the theoretical first beacon has a TSF
|
|
||||||
+ * of 0 after correction).
|
|
||||||
+ */
|
|
||||||
+ tsfadjust = cur_conf->beacon_interval * avp->av_bslot;
|
|
||||||
+ tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF;
|
|
||||||
+ avp->tsf_adjust = cpu_to_le64(tsfadjust);
|
|
||||||
+
|
|
||||||
+ ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n",
|
|
||||||
+ (signed long long)tsfadjust, avp->av_bslot);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif)
|
|
||||||
@@ -447,20 +511,28 @@ void ath9k_beacon_tasklet(unsigned long
|
|
||||||
* Both nexttbtt and intval have to be in usecs.
|
|
||||||
*/
|
|
||||||
static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt,
|
|
||||||
- u32 intval, bool reset_tsf)
|
|
||||||
+ u32 intval)
|
|
||||||
{
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
|
||||||
|
|
||||||
ath9k_hw_disable_interrupts(ah);
|
|
||||||
- if (reset_tsf)
|
|
||||||
- ath9k_hw_reset_tsf(ah);
|
|
||||||
ath9k_beaconq_config(sc);
|
|
||||||
ath9k_hw_beaconinit(ah, nexttbtt, intval);
|
|
||||||
+ ah->imask |= ATH9K_INT_SWBA;
|
|
||||||
sc->beacon.bmisscnt = 0;
|
|
||||||
ath9k_hw_set_interrupts(ah);
|
|
||||||
ath9k_hw_enable_interrupts(ah);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void ath9k_beacon_stop(struct ath_softc *sc)
|
|
||||||
+{
|
|
||||||
+ ath9k_hw_disable_interrupts(sc->sc_ah);
|
|
||||||
+ sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
|
|
||||||
+ sc->beacon.bmisscnt = 0;
|
|
||||||
+ ath9k_hw_set_interrupts(sc->sc_ah);
|
|
||||||
+ ath9k_hw_enable_interrupts(sc->sc_ah);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* For multi-bss ap support beacons are either staggered evenly over N slots or
|
|
||||||
* burst together. For the former arrange for the SWBA to be delivered for each
|
|
||||||
@@ -472,7 +544,7 @@ static void ath9k_beacon_config_ap(struc
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
|
||||||
|
|
||||||
ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF);
|
|
||||||
- ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, false);
|
|
||||||
+ ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath9k_beacon_config_sta(struct ath_hw *ah,
|
|
||||||
@@ -501,7 +573,7 @@ static void ath9k_beacon_config_adhoc(st
|
|
||||||
|
|
||||||
ath9k_cmn_beacon_config_adhoc(ah, conf);
|
|
||||||
|
|
||||||
- ath9k_beacon_init(sc, conf->nexttbtt, conf->intval, conf->ibss_creator);
|
|
||||||
+ ath9k_beacon_init(sc, conf->nexttbtt, conf->intval);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the global 'beacon has been configured' flag for the
|
|
||||||
@@ -511,44 +583,6 @@ static void ath9k_beacon_config_adhoc(st
|
|
||||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static bool ath9k_allow_beacon_config(struct ath_softc *sc,
|
|
||||||
- struct ieee80211_vif *vif)
|
|
||||||
-{
|
|
||||||
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
- struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
-
|
|
||||||
- if (ath9k_is_chanctx_enabled()) {
|
|
||||||
- /*
|
|
||||||
- * If the VIF is not present in the current channel context,
|
|
||||||
- * then we can't do the usual opmode checks. Allow the
|
|
||||||
- * beacon config for the VIF to be updated in this case and
|
|
||||||
- * return immediately.
|
|
||||||
- */
|
|
||||||
- if (sc->cur_chan != avp->chanctx)
|
|
||||||
- return true;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
|
|
||||||
- if (vif->type != NL80211_IFTYPE_AP) {
|
|
||||||
- ath_dbg(common, CONFIG,
|
|
||||||
- "An AP interface is already present !\n");
|
|
||||||
- return false;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
|
||||||
- if ((vif->type == NL80211_IFTYPE_STATION) &&
|
|
||||||
- test_bit(ATH_OP_BEACONS, &common->op_flags) &&
|
|
||||||
- vif != sc->cur_chan->primary_sta) {
|
|
||||||
- ath_dbg(common, CONFIG,
|
|
||||||
- "Beacon already configured for a station interface\n");
|
|
||||||
- return false;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- return true;
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
static void ath9k_cache_beacon_config(struct ath_softc *sc,
|
|
||||||
struct ath_chanctx *ctx,
|
|
||||||
struct ieee80211_bss_conf *bss_conf)
|
|
||||||
@@ -584,87 +618,79 @@ static void ath9k_cache_beacon_config(st
|
|
||||||
if (cur_conf->dtim_period == 0)
|
|
||||||
cur_conf->dtim_period = 1;
|
|
||||||
|
|
||||||
+ ath9k_set_tsfadjust(sc, cur_conf);
|
|
||||||
}
|
|
||||||
|
|
||||||
-void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
|
|
||||||
- u32 changed)
|
|
||||||
+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif,
|
|
||||||
+ bool beacons)
|
|
||||||
{
|
|
||||||
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
|
||||||
- struct ath_hw *ah = sc->sc_ah;
|
|
||||||
- struct ath_common *common = ath9k_hw_common(ah);
|
|
||||||
- struct ath_vif *avp = (void *)vif->drv_priv;
|
|
||||||
- struct ath_chanctx *ctx = avp->chanctx;
|
|
||||||
+ struct ath_hw *ah = sc->sc_ah;
|
|
||||||
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
||||||
+ struct ath_vif *avp;
|
|
||||||
+ struct ath_chanctx *ctx;
|
|
||||||
struct ath_beacon_config *cur_conf;
|
|
||||||
unsigned long flags;
|
|
||||||
+ bool enabled;
|
|
||||||
bool skip_beacon = false;
|
|
||||||
|
|
||||||
- if (!ctx)
|
|
||||||
+ if (!beacons) {
|
|
||||||
+ clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
+ ath9k_beacon_stop(sc);
|
|
||||||
return;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- cur_conf = &avp->chanctx->beacon;
|
|
||||||
- if (vif->type == NL80211_IFTYPE_AP)
|
|
||||||
- ath9k_set_tsfadjust(sc, vif);
|
|
||||||
-
|
|
||||||
- if (!ath9k_allow_beacon_config(sc, vif))
|
|
||||||
+ if (WARN_ON(!main_vif))
|
|
||||||
return;
|
|
||||||
|
|
||||||
- if (vif->type == NL80211_IFTYPE_STATION) {
|
|
||||||
- ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
|
||||||
- if (ctx != sc->cur_chan)
|
|
||||||
- return;
|
|
||||||
+ avp = (void *)main_vif->drv_priv;
|
|
||||||
+ ctx = avp->chanctx;
|
|
||||||
+ cur_conf = &ctx->beacon;
|
|
||||||
+ enabled = cur_conf->enable_beacon;
|
|
||||||
+ cur_conf->enable_beacon = beacons;
|
|
||||||
+
|
|
||||||
+ if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
|
|
||||||
+ ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
|
|
||||||
|
|
||||||
ath9k_set_beacon(sc);
|
|
||||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * Take care of multiple interfaces when
|
|
||||||
- * enabling/disabling SWBA.
|
|
||||||
- */
|
|
||||||
- if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
|
||||||
- bool enabled = cur_conf->enable_beacon;
|
|
||||||
-
|
|
||||||
- if (!bss_conf->enable_beacon) {
|
|
||||||
- cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
|
|
||||||
- } else {
|
|
||||||
- cur_conf->enable_beacon |= BIT(avp->av_bslot);
|
|
||||||
- if (!enabled)
|
|
||||||
- ath9k_cache_beacon_config(sc, ctx, bss_conf);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (ctx != sc->cur_chan)
|
|
||||||
- return;
|
|
||||||
+ /* Update the beacon configuration. */
|
|
||||||
+ ath9k_cache_beacon_config(sc, ctx, &main_vif->bss_conf);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Configure the HW beacon registers only when we have a valid
|
|
||||||
* beacon interval.
|
|
||||||
*/
|
|
||||||
if (cur_conf->beacon_interval) {
|
|
||||||
- /*
|
|
||||||
- * If we are joining an existing IBSS network, start beaconing
|
|
||||||
- * only after a TSF-sync has taken place. Ensure that this
|
|
||||||
- * happens by setting the appropriate flags.
|
|
||||||
+ /* Special case to sync the TSF when joining an existing IBSS.
|
|
||||||
+ * This is only done if no AP interface is active.
|
|
||||||
+ * Note that mac80211 always resets the TSF when creating a new
|
|
||||||
+ * IBSS interface.
|
|
||||||
*/
|
|
||||||
- if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator &&
|
|
||||||
- bss_conf->enable_beacon) {
|
|
||||||
+ if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
|
|
||||||
+ !enabled && beacons && !main_vif->bss_conf.ibss_creator) {
|
|
||||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
|
||||||
sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
|
|
||||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
|
||||||
skip_beacon = true;
|
|
||||||
- } else {
|
|
||||||
- ath9k_set_beacon(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do not set the ATH_OP_BEACONS flag for IBSS joiner mode
|
|
||||||
* here, it is done in ath9k_beacon_config_adhoc().
|
|
||||||
*/
|
|
||||||
- if (cur_conf->enable_beacon && !skip_beacon)
|
|
||||||
+ if (beacons && !skip_beacon) {
|
|
||||||
set_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
- else
|
|
||||||
+ ath9k_set_beacon(sc);
|
|
||||||
+ } else {
|
|
||||||
clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
+ ath9k_beacon_stop(sc);
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
+ ath9k_beacon_stop(sc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/common.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/common.h
|
|
||||||
@@ -50,6 +50,7 @@
|
|
||||||
#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
|
|
||||||
|
|
||||||
struct ath_beacon_config {
|
|
||||||
+ struct ieee80211_vif *main_vif;
|
|
||||||
int beacon_interval;
|
|
||||||
u16 dtim_period;
|
|
||||||
u16 bmiss_timeout;
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -910,6 +910,22 @@ static bool ath9k_uses_beacons(int type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void ath9k_vif_iter_set_beacon(struct ath9k_vif_iter_data *iter_data,
|
|
||||||
+ struct ieee80211_vif *vif)
|
|
||||||
+{
|
|
||||||
+ /* Use the first (configured) interface, but prefering AP interfaces. */
|
|
||||||
+ if (!iter_data->primary_beacon_vif) {
|
|
||||||
+ iter_data->primary_beacon_vif = vif;
|
|
||||||
+ } else {
|
|
||||||
+ if (iter_data->primary_beacon_vif->type != NL80211_IFTYPE_AP &&
|
|
||||||
+ vif->type == NL80211_IFTYPE_AP)
|
|
||||||
+ iter_data->primary_beacon_vif = vif;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ iter_data->beacons = true;
|
|
||||||
+ iter_data->nbcnvifs += 1;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
|
|
||||||
u8 *mac, struct ieee80211_vif *vif)
|
|
||||||
{
|
|
||||||
@@ -931,6 +947,8 @@ static void ath9k_vif_iter(struct ath9k_
|
|
||||||
switch (vif->type) {
|
|
||||||
case NL80211_IFTYPE_AP:
|
|
||||||
iter_data->naps++;
|
|
||||||
+ if (vif->bss_conf.enable_beacon)
|
|
||||||
+ ath9k_vif_iter_set_beacon(iter_data, vif);
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_STATION:
|
|
||||||
iter_data->nstations++;
|
|
||||||
@@ -943,12 +961,12 @@ static void ath9k_vif_iter(struct ath9k_
|
|
||||||
case NL80211_IFTYPE_ADHOC:
|
|
||||||
iter_data->nadhocs++;
|
|
||||||
if (vif->bss_conf.enable_beacon)
|
|
||||||
- iter_data->beacons = true;
|
|
||||||
+ ath9k_vif_iter_set_beacon(iter_data, vif);
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
|
||||||
iter_data->nmeshes++;
|
|
||||||
if (vif->bss_conf.enable_beacon)
|
|
||||||
- iter_data->beacons = true;
|
|
||||||
+ ath9k_vif_iter_set_beacon(iter_data, vif);
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_WDS:
|
|
||||||
iter_data->nwds++;
|
|
||||||
@@ -1081,7 +1099,6 @@ void ath9k_calculate_summary_state(struc
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
|
||||||
struct ath9k_vif_iter_data iter_data;
|
|
||||||
- struct ath_beacon_config *cur_conf;
|
|
||||||
|
|
||||||
ath_chanctx_check_active(sc, ctx);
|
|
||||||
|
|
||||||
@@ -1103,13 +1120,12 @@ void ath9k_calculate_summary_state(struc
|
|
||||||
ath_hw_setbssidmask(common);
|
|
||||||
|
|
||||||
if (iter_data.naps > 0) {
|
|
||||||
- cur_conf = &ctx->beacon;
|
|
||||||
ath9k_hw_set_tsfadjust(ah, true);
|
|
||||||
ah->opmode = NL80211_IFTYPE_AP;
|
|
||||||
- if (cur_conf->enable_beacon)
|
|
||||||
- iter_data.beacons = true;
|
|
||||||
} else {
|
|
||||||
ath9k_hw_set_tsfadjust(ah, false);
|
|
||||||
+ if (iter_data.beacons)
|
|
||||||
+ ath9k_beacon_ensure_primary_slot(sc);
|
|
||||||
|
|
||||||
if (iter_data.nmeshes)
|
|
||||||
ah->opmode = NL80211_IFTYPE_MESH_POINT;
|
|
||||||
@@ -1134,7 +1150,6 @@ void ath9k_calculate_summary_state(struc
|
|
||||||
ctx->switch_after_beacon = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
- ah->imask &= ~ATH9K_INT_SWBA;
|
|
||||||
if (ah->opmode == NL80211_IFTYPE_STATION) {
|
|
||||||
bool changed = (iter_data.primary_sta != ctx->primary_sta);
|
|
||||||
|
|
||||||
@@ -1151,16 +1166,12 @@ void ath9k_calculate_summary_state(struc
|
|
||||||
if (ath9k_hw_mci_is_enabled(sc->sc_ah))
|
|
||||||
ath9k_mci_update_wlan_channels(sc, true);
|
|
||||||
}
|
|
||||||
- } else if (iter_data.beacons) {
|
|
||||||
- ah->imask |= ATH9K_INT_SWBA;
|
|
||||||
}
|
|
||||||
+ sc->nbcnvifs = iter_data.nbcnvifs;
|
|
||||||
+ ath9k_beacon_config(sc, iter_data.primary_beacon_vif,
|
|
||||||
+ iter_data.beacons);
|
|
||||||
ath9k_hw_set_interrupts(ah);
|
|
||||||
|
|
||||||
- if (iter_data.beacons)
|
|
||||||
- set_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
- else
|
|
||||||
- clear_bit(ATH_OP_BEACONS, &common->op_flags);
|
|
||||||
-
|
|
||||||
if (ah->slottime != iter_data.slottime) {
|
|
||||||
ah->slottime = iter_data.slottime;
|
|
||||||
ath9k_hw_init_global_settings(ah);
|
|
||||||
@@ -1777,9 +1788,7 @@ static void ath9k_bss_info_changed(struc
|
|
||||||
if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
|
|
||||||
(changed & BSS_CHANGED_BEACON_INT) ||
|
|
||||||
(changed & BSS_CHANGED_BEACON_INFO)) {
|
|
||||||
- ath9k_beacon_config(sc, vif, changed);
|
|
||||||
- if (changed & BSS_CHANGED_BEACON_ENABLED)
|
|
||||||
- ath9k_calculate_summary_state(sc, avp->chanctx);
|
|
||||||
+ ath9k_calculate_summary_state(sc, avp->chanctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((avp->chanctx == sc->cur_chan) &&
|
|
|
@ -1,108 +0,0 @@
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Tue, 7 Jun 2016 21:10:18 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: slightly simplify building interface combinations
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
This change reorders some operations in brcmf_setup_ifmodes in hope to
|
|
||||||
make it simpler:
|
|
||||||
1) It allocates arrays right before filling them. This way it's easier
|
|
||||||
to follow requested array length as it's immediately followed by
|
|
||||||
code filling it. It's easier to check e.g. why we need 4 entries for
|
|
||||||
P2P. Other than that it deduplicates some checks (e.g. for P2P).
|
|
||||||
2) It reorders code to first prepare limits and then define a new combo.
|
|
||||||
Previously this was mixed (e.g. we were setting num of channels
|
|
||||||
before preparing limits).
|
|
||||||
3) It modifies mbss code to use i variable just like other combos do.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -6284,29 +6284,15 @@ static int brcmf_setup_ifmodes(struct wi
|
|
||||||
if (!combo)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
- c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
|
|
||||||
- if (!c0_limits)
|
|
||||||
- goto err;
|
|
||||||
-
|
|
||||||
- if (p2p) {
|
|
||||||
- p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
|
|
||||||
- if (!p2p_limits)
|
|
||||||
- goto err;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (mbss) {
|
|
||||||
- mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
|
|
||||||
- if (!mbss_limits)
|
|
||||||
- goto err;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
|
||||||
BIT(NL80211_IFTYPE_ADHOC) |
|
|
||||||
BIT(NL80211_IFTYPE_AP);
|
|
||||||
|
|
||||||
c = 0;
|
|
||||||
i = 0;
|
|
||||||
- combo[c].num_different_channels = 1;
|
|
||||||
+ c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
|
|
||||||
+ if (!c0_limits)
|
|
||||||
+ goto err;
|
|
||||||
c0_limits[i].max = 1;
|
|
||||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
|
||||||
if (p2p) {
|
|
||||||
@@ -6324,6 +6310,7 @@ static int brcmf_setup_ifmodes(struct wi
|
|
||||||
c0_limits[i].max = 1;
|
|
||||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
|
||||||
}
|
|
||||||
+ combo[c].num_different_channels = 1;
|
|
||||||
combo[c].max_interfaces = i;
|
|
||||||
combo[c].n_limits = i;
|
|
||||||
combo[c].limits = c0_limits;
|
|
||||||
@@ -6331,7 +6318,9 @@ static int brcmf_setup_ifmodes(struct wi
|
|
||||||
if (p2p) {
|
|
||||||
c++;
|
|
||||||
i = 0;
|
|
||||||
- combo[c].num_different_channels = 1;
|
|
||||||
+ p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
|
|
||||||
+ if (!p2p_limits)
|
|
||||||
+ goto err;
|
|
||||||
p2p_limits[i].max = 1;
|
|
||||||
p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
|
||||||
p2p_limits[i].max = 1;
|
|
||||||
@@ -6340,6 +6329,7 @@ static int brcmf_setup_ifmodes(struct wi
|
|
||||||
p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
|
|
||||||
p2p_limits[i].max = 1;
|
|
||||||
p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
|
|
||||||
+ combo[c].num_different_channels = 1;
|
|
||||||
combo[c].max_interfaces = i;
|
|
||||||
combo[c].n_limits = i;
|
|
||||||
combo[c].limits = p2p_limits;
|
|
||||||
@@ -6347,14 +6337,19 @@ static int brcmf_setup_ifmodes(struct wi
|
|
||||||
|
|
||||||
if (mbss) {
|
|
||||||
c++;
|
|
||||||
+ i = 0;
|
|
||||||
+ mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
|
|
||||||
+ if (!mbss_limits)
|
|
||||||
+ goto err;
|
|
||||||
+ mbss_limits[i].max = 4;
|
|
||||||
+ mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
|
||||||
combo[c].beacon_int_infra_match = true;
|
|
||||||
combo[c].num_different_channels = 1;
|
|
||||||
- mbss_limits[0].max = 4;
|
|
||||||
- mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
|
|
||||||
combo[c].max_interfaces = 4;
|
|
||||||
- combo[c].n_limits = 1;
|
|
||||||
+ combo[c].n_limits = i;
|
|
||||||
combo[c].limits = mbss_limits;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
wiphy->n_iface_combinations = n_combos;
|
|
||||||
wiphy->iface_combinations = combo;
|
|
||||||
return 0;
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
From: Bob Copeland <me@bobcopeland.com>
|
||||||
|
Date: Wed, 12 Oct 2016 08:24:54 -0400
|
||||||
|
Subject: [PATCH] mac80211: fix up mismerge of ieee80211_tx_dequeue
|
||||||
|
|
||||||
|
Looks like this spinlock wound up on the wrong side of the
|
||||||
|
linearize, and I also lost the part that re-enters the loop.
|
||||||
|
Fix up to match mac80211-next.
|
||||||
|
|
||||||
|
Signed-off-by: Bob Copeland <me@bobcopeland.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/net/mac80211/tx.c
|
||||||
|
+++ b/net/mac80211/tx.c
|
||||||
|
@@ -3457,17 +3457,17 @@ begin:
|
||||||
|
skb_queue_splice_tail(&tx.skbs, &txqi->frags);
|
||||||
|
}
|
||||||
|
|
||||||
|
-out:
|
||||||
|
- spin_unlock_bh(&fq->lock);
|
||||||
|
-
|
||||||
|
if (skb && skb_has_frag_list(skb) &&
|
||||||
|
!ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) {
|
||||||
|
if (skb_linearize(skb)) {
|
||||||
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
|
- return NULL;
|
||||||
|
+ goto begin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+out:
|
||||||
|
+ spin_unlock_bh(&fq->lock);
|
||||||
|
+
|
||||||
|
return skb;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
|
@ -1,154 +0,0 @@
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Fri, 17 Jun 2016 12:29:21 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: fix lockup when removing P2P interface after
|
|
||||||
event timeout
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Removing P2P interface is handled by sending a proper request to the
|
|
||||||
firmware. On success firmware triggers an event and driver's handler
|
|
||||||
removes a matching interface.
|
|
||||||
|
|
||||||
However on event timeout we remove interface directly from the cfg80211
|
|
||||||
callback. Current code doesn't handle this case correctly as it always
|
|
||||||
assumes rtnl to be unlocked.
|
|
||||||
|
|
||||||
Fix it by adding an extra rtnl_locked parameter to functions and calling
|
|
||||||
unregister_netdevice when needed.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -548,12 +548,16 @@ fail:
|
|
||||||
return -EBADE;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void brcmf_net_detach(struct net_device *ndev)
|
|
||||||
+static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
|
|
||||||
{
|
|
||||||
- if (ndev->reg_state == NETREG_REGISTERED)
|
|
||||||
- unregister_netdev(ndev);
|
|
||||||
- else
|
|
||||||
+ if (ndev->reg_state == NETREG_REGISTERED) {
|
|
||||||
+ if (rtnl_locked)
|
|
||||||
+ unregister_netdevice(ndev);
|
|
||||||
+ else
|
|
||||||
+ unregister_netdev(ndev);
|
|
||||||
+ } else {
|
|
||||||
brcmf_cfg80211_free_netdev(ndev);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
|
|
||||||
@@ -651,7 +655,7 @@ struct brcmf_if *brcmf_add_if(struct brc
|
|
||||||
brcmf_err("ERROR: netdev:%s already exists\n",
|
|
||||||
ifp->ndev->name);
|
|
||||||
netif_stop_queue(ifp->ndev);
|
|
||||||
- brcmf_net_detach(ifp->ndev);
|
|
||||||
+ brcmf_net_detach(ifp->ndev, false);
|
|
||||||
drvr->iflist[bsscfgidx] = NULL;
|
|
||||||
} else {
|
|
||||||
brcmf_dbg(INFO, "netdev:%s ignore IF event\n",
|
|
||||||
@@ -699,7 +703,8 @@ struct brcmf_if *brcmf_add_if(struct brc
|
|
||||||
return ifp;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
|
|
||||||
+static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx,
|
|
||||||
+ bool rtnl_locked)
|
|
||||||
{
|
|
||||||
struct brcmf_if *ifp;
|
|
||||||
|
|
||||||
@@ -729,7 +734,7 @@ static void brcmf_del_if(struct brcmf_pu
|
|
||||||
cancel_work_sync(&ifp->multicast_work);
|
|
||||||
cancel_work_sync(&ifp->ndoffload_work);
|
|
||||||
}
|
|
||||||
- brcmf_net_detach(ifp->ndev);
|
|
||||||
+ brcmf_net_detach(ifp->ndev, rtnl_locked);
|
|
||||||
} else {
|
|
||||||
/* Only p2p device interfaces which get dynamically created
|
|
||||||
* end up here. In this case the p2p module should be informed
|
|
||||||
@@ -743,14 +748,14 @@ static void brcmf_del_if(struct brcmf_pu
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-void brcmf_remove_interface(struct brcmf_if *ifp)
|
|
||||||
+void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
|
|
||||||
{
|
|
||||||
if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp))
|
|
||||||
return;
|
|
||||||
brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx,
|
|
||||||
ifp->ifidx);
|
|
||||||
brcmf_fws_del_interface(ifp);
|
|
||||||
- brcmf_del_if(ifp->drvr, ifp->bsscfgidx);
|
|
||||||
+ brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_INET
|
|
||||||
@@ -1057,9 +1062,9 @@ fail:
|
|
||||||
brcmf_fws_deinit(drvr);
|
|
||||||
}
|
|
||||||
if (ifp)
|
|
||||||
- brcmf_net_detach(ifp->ndev);
|
|
||||||
+ brcmf_net_detach(ifp->ndev, false);
|
|
||||||
if (p2p_ifp)
|
|
||||||
- brcmf_net_detach(p2p_ifp->ndev);
|
|
||||||
+ brcmf_net_detach(p2p_ifp->ndev, false);
|
|
||||||
drvr->iflist[0] = NULL;
|
|
||||||
drvr->iflist[1] = NULL;
|
|
||||||
if (drvr->settings->ignore_probe_fail)
|
|
||||||
@@ -1128,7 +1133,7 @@ void brcmf_detach(struct device *dev)
|
|
||||||
|
|
||||||
/* make sure primary interface removed last */
|
|
||||||
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
|
|
||||||
- brcmf_remove_interface(drvr->iflist[i]);
|
|
||||||
+ brcmf_remove_interface(drvr->iflist[i], false);
|
|
||||||
|
|
||||||
brcmf_cfg80211_detach(drvr->config);
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
@@ -216,7 +216,7 @@ struct brcmf_if *brcmf_get_ifp(struct br
|
|
||||||
int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
|
|
||||||
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
|
|
||||||
bool is_p2pdev, char *name, u8 *mac_addr);
|
|
||||||
-void brcmf_remove_interface(struct brcmf_if *ifp);
|
|
||||||
+void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked);
|
|
||||||
void brcmf_txflowblock_if(struct brcmf_if *ifp,
|
|
||||||
enum brcmf_netif_stop_reason reason, bool state);
|
|
||||||
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
|
|
||||||
@@ -183,7 +183,7 @@ static void brcmf_fweh_handle_if_event(s
|
|
||||||
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
|
|
||||||
|
|
||||||
if (ifp && ifevent->action == BRCMF_E_IF_DEL)
|
|
||||||
- brcmf_remove_interface(ifp);
|
|
||||||
+ brcmf_remove_interface(ifp, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
@@ -2289,7 +2289,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
if (err)
|
|
||||||
- brcmf_remove_interface(vif->ifp);
|
|
||||||
+ brcmf_remove_interface(vif->ifp, true);
|
|
||||||
|
|
||||||
brcmf_cfg80211_arm_vif_event(cfg, NULL);
|
|
||||||
if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
|
|
||||||
@@ -2395,7 +2395,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_i
|
|
||||||
if (vif != NULL) {
|
|
||||||
brcmf_p2p_cancel_remain_on_channel(vif->ifp);
|
|
||||||
brcmf_p2p_deinit_discovery(p2p);
|
|
||||||
- brcmf_remove_interface(vif->ifp);
|
|
||||||
+ brcmf_remove_interface(vif->ifp, false);
|
|
||||||
}
|
|
||||||
/* just set it all to zero */
|
|
||||||
memset(p2p, 0, sizeof(*p2p));
|
|
|
@ -1,40 +0,0 @@
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Fri, 17 Jun 2016 12:48:44 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: use const char * for interface name in
|
|
||||||
brcmf_add_if
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
This function can work just fine with const pointer, it only calls
|
|
||||||
alloc_netdev which take const as well. Moreover it makes this function
|
|
||||||
more flexible as some cfg80211 callback may provide const char * as
|
|
||||||
well, e.g. add_virtual_intf. This will be needed for more advanced
|
|
||||||
interface management.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -638,7 +638,7 @@ fail:
|
|
||||||
}
|
|
||||||
|
|
||||||
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
|
|
||||||
- bool is_p2pdev, char *name, u8 *mac_addr)
|
|
||||||
+ bool is_p2pdev, const char *name, u8 *mac_addr)
|
|
||||||
{
|
|
||||||
struct brcmf_if *ifp;
|
|
||||||
struct net_device *ndev;
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
@@ -215,7 +215,7 @@ char *brcmf_ifname(struct brcmf_if *ifp)
|
|
||||||
struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx);
|
|
||||||
int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
|
|
||||||
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
|
|
||||||
- bool is_p2pdev, char *name, u8 *mac_addr);
|
|
||||||
+ bool is_p2pdev, const char *name, u8 *mac_addr);
|
|
||||||
void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked);
|
|
||||||
void brcmf_txflowblock_if(struct brcmf_if *ifp,
|
|
||||||
enum brcmf_netif_stop_reason reason, bool state);
|
|
|
@ -1,33 +0,0 @@
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Sat, 18 Jun 2016 18:49:38 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: include also core.h header in cfg80211.h
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
This header provides two inline functions using struct brcmf_if so we
|
|
||||||
need core.h to avoid:
|
|
||||||
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h: In function ‘ndev_to_prof’:
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h:368:13: error: dereferencing pointer to incomplete type
|
|
||||||
return &ifp->vif->profile;
|
|
||||||
^
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h: In function ‘ndev_to_vif’:
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h:374:12: error: dereferencing pointer to incomplete type
|
|
||||||
return ifp->vif;
|
|
||||||
^
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
|
|
||||||
@@ -20,6 +20,7 @@
|
|
||||||
/* for brcmu_d11inf */
|
|
||||||
#include <brcmu_d11.h>
|
|
||||||
|
|
||||||
+#include "core.h"
|
|
||||||
#include "fwil_types.h"
|
|
||||||
#include "p2p.h"
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Sun, 19 Jun 2016 01:55:57 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: add missing break when deleting P2P_DEVICE
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
We obviously don't want to fall through in that switch. With this change
|
|
||||||
1) We wait for event (triggered by p2p_disc) as expected
|
|
||||||
2) We remove interface manually on timeout
|
|
||||||
3) We return 0 on success instead of -ENOTSUPP
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
@@ -2263,6 +2263,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
|
|
||||||
return 0;
|
|
||||||
brcmf_p2p_cancel_remain_on_channel(vif->ifp);
|
|
||||||
brcmf_p2p_deinit_discovery(p2p);
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
default:
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Wed, 29 Jun 2016 21:54:26 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: delete interface directly in code that sent fw
|
|
||||||
request
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
So far when receiving event about in-firmware-interface removal our
|
|
||||||
event worker was notifying listener and afterwards it was removing Linux
|
|
||||||
interface.
|
|
||||||
|
|
||||||
First of all it was resulting in slightly unexpected order. The listener
|
|
||||||
(del_virtual_intf callback) was (usually) returning with success before
|
|
||||||
we even called unregister_netdev(ice).
|
|
||||||
|
|
||||||
Please note this couldn't be simply fixed by changing order of calls in
|
|
||||||
brcmf_fweh_handle_if_event as unregistering interface earlier could free
|
|
||||||
struct brcmf_if.
|
|
||||||
|
|
||||||
Another problem of current implementation are possible lockups. Focus on
|
|
||||||
the time slot between calling event handler and removing Linux
|
|
||||||
interface. During that time original caller may leave (unlocking rtnl
|
|
||||||
semaphore) *and* another call to the same code may be done (locking it
|
|
||||||
again). If that happens our event handler will stuck at removing Linux
|
|
||||||
interface, it won't handle another event and will block process holding
|
|
||||||
rtnl lock.
|
|
||||||
|
|
||||||
This can be simply solved by unregistering interface in a proper
|
|
||||||
callback, right after receiving confirmation event from firmware. This
|
|
||||||
only required modifying worker to don't unregister on its own if there
|
|
||||||
is someone waiting for the event.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
|
|
||||||
@@ -18,6 +18,7 @@
|
|
||||||
#include "brcmu_wifi.h"
|
|
||||||
#include "brcmu_utils.h"
|
|
||||||
|
|
||||||
+#include "cfg80211.h"
|
|
||||||
#include "core.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "tracepoint.h"
|
|
||||||
@@ -182,8 +183,13 @@ static void brcmf_fweh_handle_if_event(s
|
|
||||||
|
|
||||||
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
|
|
||||||
|
|
||||||
- if (ifp && ifevent->action == BRCMF_E_IF_DEL)
|
|
||||||
- brcmf_remove_interface(ifp, false);
|
|
||||||
+ if (ifp && ifevent->action == BRCMF_E_IF_DEL) {
|
|
||||||
+ bool armed = brcmf_cfg80211_vif_event_armed(drvr->config);
|
|
||||||
+
|
|
||||||
+ /* Default handling in case no-one waits for this event */
|
|
||||||
+ if (!armed)
|
|
||||||
+ brcmf_remove_interface(ifp, false);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
@@ -2290,8 +2290,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
|
|
||||||
else
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
- if (err)
|
|
||||||
- brcmf_remove_interface(vif->ifp, true);
|
|
||||||
+ brcmf_remove_interface(vif->ifp, true);
|
|
||||||
|
|
||||||
brcmf_cfg80211_arm_vif_event(cfg, NULL);
|
|
||||||
if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
|
|
|
@ -1,84 +0,0 @@
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Wed, 29 Jun 2016 21:54:27 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: support removing AP interfaces with
|
|
||||||
"interface_remove"
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
New firmwares (e.g. 10.10.69.36 for BCM4366) support "interface_remove"
|
|
||||||
for removing interfaces. Try to use this method on cfg80211 request. In
|
|
||||||
case of older firmwares (e.g. 7.35.177.56 for BCM43602 as I tested) this
|
|
||||||
will just result in firmware rejecting command and this won't change any
|
|
||||||
behavior.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -785,12 +785,48 @@ s32 brcmf_notify_escan_complete(struct b
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
|
|
||||||
+ struct wireless_dev *wdev)
|
|
||||||
+{
|
|
||||||
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
|
|
||||||
+ struct net_device *ndev = wdev->netdev;
|
|
||||||
+ struct brcmf_if *ifp = netdev_priv(ndev);
|
|
||||||
+ int ret;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
|
|
||||||
+
|
|
||||||
+ err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
|
|
||||||
+ if (err) {
|
|
||||||
+ brcmf_err("interface_remove failed %d\n", err);
|
|
||||||
+ goto err_unarm;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* wait for firmware event */
|
|
||||||
+ ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
|
|
||||||
+ BRCMF_VIF_EVENT_TIMEOUT);
|
|
||||||
+ if (!ret) {
|
|
||||||
+ brcmf_err("timeout occurred\n");
|
|
||||||
+ err = -EIO;
|
|
||||||
+ goto err_unarm;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ brcmf_remove_interface(ifp, true);
|
|
||||||
+
|
|
||||||
+err_unarm:
|
|
||||||
+ brcmf_cfg80211_arm_vif_event(cfg, NULL);
|
|
||||||
+ return err;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static
|
|
||||||
int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|
||||||
{
|
|
||||||
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
|
|
||||||
struct net_device *ndev = wdev->netdev;
|
|
||||||
|
|
||||||
+ if (ndev && ndev == cfg_to_ndev(cfg))
|
|
||||||
+ return -ENOTSUPP;
|
|
||||||
+
|
|
||||||
/* vif event pending in firmware */
|
|
||||||
if (brcmf_cfg80211_vif_event_armed(cfg))
|
|
||||||
return -EBUSY;
|
|
||||||
@@ -807,12 +843,13 @@ int brcmf_cfg80211_del_iface(struct wiph
|
|
||||||
switch (wdev->iftype) {
|
|
||||||
case NL80211_IFTYPE_ADHOC:
|
|
||||||
case NL80211_IFTYPE_STATION:
|
|
||||||
- case NL80211_IFTYPE_AP:
|
|
||||||
case NL80211_IFTYPE_AP_VLAN:
|
|
||||||
case NL80211_IFTYPE_WDS:
|
|
||||||
case NL80211_IFTYPE_MONITOR:
|
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
+ case NL80211_IFTYPE_AP:
|
|
||||||
+ return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
|
|
||||||
case NL80211_IFTYPE_P2P_CLIENT:
|
|
||||||
case NL80211_IFTYPE_P2P_GO:
|
|
||||||
case NL80211_IFTYPE_P2P_DEVICE:
|
|
|
@ -1,46 +0,0 @@
|
||||||
From c940de10d45efc5664ee993a6da281f45c804e59 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
|
||||||
Date: Wed, 6 Jul 2016 12:22:54 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: respect hidden_ssid for AP interfaces
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
This was succesfully tested with 4366B1. A small workaround is needed
|
|
||||||
for the main interface otherwise it would stuck at the hidden state.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 13 +++++++++++++
|
|
||||||
1 file changed, 13 insertions(+)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -4662,6 +4662,15 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
|
|
||||||
brcmf_err("SET SSID error (%d)\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ if (settings->hidden_ssid) {
|
|
||||||
+ err = brcmf_fil_iovar_int_set(ifp, "closednet", 1);
|
|
||||||
+ if (err) {
|
|
||||||
+ brcmf_err("closednet error (%d)\n", err);
|
|
||||||
+ goto exit;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
brcmf_dbg(TRACE, "AP mode configuration complete\n");
|
|
||||||
} else if (dev_role == NL80211_IFTYPE_P2P_GO) {
|
|
||||||
err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
|
|
||||||
@@ -4720,6 +4729,10 @@ static int brcmf_cfg80211_stop_ap(struct
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* First BSS doesn't get a full reset */
|
|
||||||
+ if (ifp->bsscfgidx == 0)
|
|
||||||
+ brcmf_fil_iovar_int_set(ifp, "closednet", 0);
|
|
||||||
+
|
|
||||||
memset(&join_params, 0, sizeof(join_params));
|
|
||||||
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
|
|
||||||
&join_params, sizeof(join_params));
|
|
|
@ -1,56 +0,0 @@
|
||||||
From 82bc9ab6a8f577d2174a736c33f3d4ecf7d9ef47 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Fri, 15 Jul 2016 12:16:12 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: restore stopping netdev queue when bus clogs up
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
When the host-interface bus has hard time handling transmit packets
|
|
||||||
it informs higher layer about this and it would stop the netdev
|
|
||||||
queue when needed. However, since commit 9cd18359d31e ("brcmfmac:
|
|
||||||
Make FWS queueing configurable.") this was broken. With this patch
|
|
||||||
the behaviour is restored.
|
|
||||||
|
|
||||||
Cc: stable@vger.kernel.org # v4.5, v4.6, v4.7
|
|
||||||
Fixes: 9cd18359d31e ("brcmfmac: Make FWS queueing configurable.")
|
|
||||||
Tested-by: Per Förlin <per.forlin@gmail.com>
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
.../broadcom/brcm80211/brcmfmac/fwsignal.c | 22 +++++++++++++++++-----
|
|
||||||
1 file changed, 17 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
|
||||||
@@ -2469,10 +2469,22 @@ void brcmf_fws_bustxfail(struct brcmf_fw
|
|
||||||
void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
|
|
||||||
{
|
|
||||||
struct brcmf_fws_info *fws = drvr->fws;
|
|
||||||
+ struct brcmf_if *ifp;
|
|
||||||
+ int i;
|
|
||||||
|
|
||||||
- fws->bus_flow_blocked = flow_blocked;
|
|
||||||
- if (!flow_blocked)
|
|
||||||
- brcmf_fws_schedule_deq(fws);
|
|
||||||
- else
|
|
||||||
- fws->stats.bus_flow_block++;
|
|
||||||
+ if (fws->avoid_queueing) {
|
|
||||||
+ for (i = 0; i < BRCMF_MAX_IFS; i++) {
|
|
||||||
+ ifp = drvr->iflist[i];
|
|
||||||
+ if (!ifp || !ifp->ndev)
|
|
||||||
+ continue;
|
|
||||||
+ brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW,
|
|
||||||
+ flow_blocked);
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ fws->bus_flow_blocked = flow_blocked;
|
|
||||||
+ if (!flow_blocked)
|
|
||||||
+ brcmf_fws_schedule_deq(fws);
|
|
||||||
+ else
|
|
||||||
+ fws->stats.bus_flow_block++;
|
|
||||||
+ }
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
From fd3ed33f51c2a586412d35b4f64803f019ab589f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Fri, 15 Jul 2016 12:39:13 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: defer DPC processing during probe
|
|
||||||
|
|
||||||
The sdio dpc starts processing when in SDIOD_STATE_DATA. This state was
|
|
||||||
entered right after firmware download. This patch moves that transition
|
|
||||||
just before enabling sdio interrupt handling thus avoiding watchdog
|
|
||||||
expiry which would put the bus to sleep while probing.
|
|
||||||
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 7 +++----
|
|
||||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
|
||||||
@@ -3305,10 +3305,6 @@ static int brcmf_sdio_download_firmware(
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* Allow full data communication using DPC from now on. */
|
|
||||||
- brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
|
|
||||||
- bcmerror = 0;
|
|
||||||
-
|
|
||||||
err:
|
|
||||||
brcmf_sdio_clkctl(bus, CLK_SDONLY, false);
|
|
||||||
sdio_release_host(bus->sdiodev->func[1]);
|
|
||||||
@@ -4046,6 +4042,9 @@ static void brcmf_sdio_firmware_callback
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == 0) {
|
|
||||||
+ /* Allow full data communication using DPC from now on. */
|
|
||||||
+ brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
|
|
||||||
+
|
|
||||||
err = brcmf_sdiod_intr_register(sdiodev);
|
|
||||||
if (err != 0)
|
|
||||||
brcmf_err("intr register failed:%d\n", err);
|
|
|
@ -1,32 +0,0 @@
|
||||||
From 3bdae810721b33061d2e541bd78a70f86ca42af3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
|
||||||
Date: Mon, 18 Jul 2016 16:24:34 -0700
|
|
||||||
Subject: [PATCH] brcmfmac: Fix glob_skb leak in brcmf_sdiod_recv_chain
|
|
||||||
|
|
||||||
In case brcmf_sdiod_recv_chain() cannot complete a succeful call to
|
|
||||||
brcmf_sdiod_buffrw, we would be leaking glom_skb and not free it as we
|
|
||||||
should, fix this.
|
|
||||||
|
|
||||||
Reported-by: coverity (CID 1164856)
|
|
||||||
Fixes: a413e39a38573 ("brcmfmac: fix brcmf_sdcard_recv_chain() for host without sg support")
|
|
||||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
|
||||||
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 4 +++-
|
|
||||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
|
||||||
@@ -726,8 +726,10 @@ int brcmf_sdiod_recv_chain(struct brcmf_
|
|
||||||
return -ENOMEM;
|
|
||||||
err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
|
|
||||||
glom_skb);
|
|
||||||
- if (err)
|
|
||||||
+ if (err) {
|
|
||||||
+ brcmu_pkt_buf_free_skb(glom_skb);
|
|
||||||
goto done;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
skb_queue_walk(pktq, skb) {
|
|
||||||
memcpy(skb->data, glom_skb->data, skb->len);
|
|
|
@ -1,34 +0,0 @@
|
||||||
From 938f89e50a41c2d56710805fb019ad7618cef84b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Wolfram Sang <wsa-dev@sang-engineering.com>
|
|
||||||
Date: Thu, 11 Aug 2016 23:05:31 +0200
|
|
||||||
Subject: [PATCH] net: wireless: broadcom: brcm80211: brcmfmac: usb: don't
|
|
||||||
print error when allocating urb fails
|
|
||||||
|
|
||||||
kmalloc will print enough information in case of failure.
|
|
||||||
|
|
||||||
Signed-off-by: Wolfram Sang <wsa-dev@sang-engineering.com>
|
|
||||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 8 ++------
|
|
||||||
1 file changed, 2 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
|
||||||
@@ -1099,15 +1099,11 @@ struct brcmf_usbdev *brcmf_usb_attach(st
|
|
||||||
devinfo->tx_freecount = ntxq;
|
|
||||||
|
|
||||||
devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC);
|
|
||||||
- if (!devinfo->ctl_urb) {
|
|
||||||
- brcmf_err("usb_alloc_urb (ctl) failed\n");
|
|
||||||
+ if (!devinfo->ctl_urb)
|
|
||||||
goto error;
|
|
||||||
- }
|
|
||||||
devinfo->bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
|
|
||||||
- if (!devinfo->bulk_urb) {
|
|
||||||
- brcmf_err("usb_alloc_urb (bulk) failed\n");
|
|
||||||
+ if (!devinfo->bulk_urb)
|
|
||||||
goto error;
|
|
||||||
- }
|
|
||||||
|
|
||||||
return &devinfo->bus_pub;
|
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
From 15dacf880e49ce3ecee05eb1a0c6b8e363dbacdc Mon Sep 17 00:00:00 2001
|
|
||||||
From: "mhiramat@kernel.org" <mhiramat@kernel.org>
|
|
||||||
Date: Mon, 15 Aug 2016 18:40:57 +0900
|
|
||||||
Subject: [PATCH] brcmfmac: Check rtnl_lock is locked when removing interface
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Check rtnl_lock is locked in brcmf_p2p_ifp_removed() by passing
|
|
||||||
rtnl_locked flag. Actually the caller brcmf_del_if() checks whether
|
|
||||||
the rtnl_lock is locked, but doesn't pass it to brcmf_p2p_ifp_removed().
|
|
||||||
|
|
||||||
Without this fix, wpa_supplicant goes softlockup with rtnl_lock
|
|
||||||
holding (this means all other process using netlink are locked up too)
|
|
||||||
|
|
||||||
e.g.
|
|
||||||
[ 4495.876627] INFO: task wpa_supplicant:7307 blocked for more than 10 seconds.
|
|
||||||
[ 4495.876632] Tainted: G W 4.8.0-rc1+ #8
|
|
||||||
[ 4495.876635] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
|
|
||||||
[ 4495.876638] wpa_supplicant D ffff974c647b39a0 0 7307 1 0x00000000
|
|
||||||
[ 4495.876644] ffff974c647b39a0 0000000000000000 ffff974c00000000 ffff974c7dc59c58
|
|
||||||
[ 4495.876651] ffff974c6b7417c0 ffff974c645017c0 ffff974c647b4000 ffffffff86f16c08
|
|
||||||
[ 4495.876657] ffff974c645017c0 0000000000000246 00000000ffffffff ffff974c647b39b8
|
|
||||||
[ 4495.876664] Call Trace:
|
|
||||||
[ 4495.876671] [<ffffffff868aeccc>] schedule+0x3c/0x90
|
|
||||||
[ 4495.876676] [<ffffffff868af065>] schedule_preempt_disabled+0x15/0x20
|
|
||||||
[ 4495.876682] [<ffffffff868b0996>] mutex_lock_nested+0x176/0x3b0
|
|
||||||
[ 4495.876686] [<ffffffff867a2067>] ? rtnl_lock+0x17/0x20
|
|
||||||
[ 4495.876690] [<ffffffff867a2067>] rtnl_lock+0x17/0x20
|
|
||||||
[ 4495.876720] [<ffffffffc0ae9a5d>] brcmf_p2p_ifp_removed+0x4d/0x70 [brcmfmac]
|
|
||||||
[ 4495.876741] [<ffffffffc0aebde6>] brcmf_remove_interface+0x196/0x1b0 [brcmfmac]
|
|
||||||
[ 4495.876760] [<ffffffffc0ae9901>] brcmf_p2p_del_vif+0x111/0x220 [brcmfmac]
|
|
||||||
[ 4495.876777] [<ffffffffc0adefab>] brcmf_cfg80211_del_iface+0x21b/0x270 [brcmfmac]
|
|
||||||
[ 4495.876820] [<ffffffffc097b39e>] nl80211_del_interface+0xfe/0x3a0 [cfg80211]
|
|
||||||
[ 4495.876825] [<ffffffff867ca335>] genl_family_rcv_msg+0x1b5/0x370
|
|
||||||
[ 4495.876832] [<ffffffff860e5d8d>] ? trace_hardirqs_on+0xd/0x10
|
|
||||||
[ 4495.876836] [<ffffffff867ca56d>] genl_rcv_msg+0x7d/0xb0
|
|
||||||
[ 4495.876839] [<ffffffff867ca4f0>] ? genl_family_rcv_msg+0x370/0x370
|
|
||||||
[ 4495.876846] [<ffffffff867c9a47>] netlink_rcv_skb+0x97/0xb0
|
|
||||||
[ 4495.876849] [<ffffffff867ca168>] genl_rcv+0x28/0x40
|
|
||||||
[ 4495.876854] [<ffffffff867c93c3>] netlink_unicast+0x1d3/0x2f0
|
|
||||||
[ 4495.876860] [<ffffffff867c933b>] ? netlink_unicast+0x14b/0x2f0
|
|
||||||
[ 4495.876866] [<ffffffff867c97cb>] netlink_sendmsg+0x2eb/0x3a0
|
|
||||||
[ 4495.876870] [<ffffffff8676dad8>] sock_sendmsg+0x38/0x50
|
|
||||||
[ 4495.876874] [<ffffffff8676e4df>] ___sys_sendmsg+0x27f/0x290
|
|
||||||
[ 4495.876882] [<ffffffff8628b935>] ? mntput_no_expire+0x5/0x3f0
|
|
||||||
[ 4495.876888] [<ffffffff8628b9be>] ? mntput_no_expire+0x8e/0x3f0
|
|
||||||
[ 4495.876894] [<ffffffff8628b935>] ? mntput_no_expire+0x5/0x3f0
|
|
||||||
[ 4495.876899] [<ffffffff8628bd44>] ? mntput+0x24/0x40
|
|
||||||
[ 4495.876904] [<ffffffff86267830>] ? __fput+0x190/0x200
|
|
||||||
[ 4495.876909] [<ffffffff8676f125>] __sys_sendmsg+0x45/0x80
|
|
||||||
[ 4495.876914] [<ffffffff8676f172>] SyS_sendmsg+0x12/0x20
|
|
||||||
[ 4495.876918] [<ffffffff868b5680>] entry_SYSCALL_64_fastpath+0x23/0xc1
|
|
||||||
[ 4495.876924] [<ffffffff860e2b8f>] ? trace_hardirqs_off_caller+0x1f/0xc0
|
|
||||||
|
|
||||||
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
|
|
||||||
Acked-by: Rafał Miłecki <rafal@milecki.pl>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 2 +-
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 8 +++++---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h | 2 +-
|
|
||||||
3 files changed, 7 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -743,7 +743,7 @@ static void brcmf_del_if(struct brcmf_pu
|
|
||||||
* serious troublesome side effects. The p2p module will clean
|
|
||||||
* up the ifp if needed.
|
|
||||||
*/
|
|
||||||
- brcmf_p2p_ifp_removed(ifp);
|
|
||||||
+ brcmf_p2p_ifp_removed(ifp, rtnl_locked);
|
|
||||||
kfree(ifp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
|
|
||||||
@@ -2299,7 +2299,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiph
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
-void brcmf_p2p_ifp_removed(struct brcmf_if *ifp)
|
|
||||||
+void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool rtnl_locked)
|
|
||||||
{
|
|
||||||
struct brcmf_cfg80211_info *cfg;
|
|
||||||
struct brcmf_cfg80211_vif *vif;
|
|
||||||
@@ -2308,9 +2308,11 @@ void brcmf_p2p_ifp_removed(struct brcmf_
|
|
||||||
vif = ifp->vif;
|
|
||||||
cfg = wdev_to_cfg(&vif->wdev);
|
|
||||||
cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
|
|
||||||
- rtnl_lock();
|
|
||||||
+ if (!rtnl_locked)
|
|
||||||
+ rtnl_lock();
|
|
||||||
cfg80211_unregister_wdev(&vif->wdev);
|
|
||||||
- rtnl_unlock();
|
|
||||||
+ if (!rtnl_locked)
|
|
||||||
+ rtnl_unlock();
|
|
||||||
brcmf_free_vif(vif);
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.h
|
|
||||||
@@ -155,7 +155,7 @@ struct wireless_dev *brcmf_p2p_add_vif(s
|
|
||||||
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
|
|
||||||
int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
|
|
||||||
enum brcmf_fil_p2p_if_types if_type);
|
|
||||||
-void brcmf_p2p_ifp_removed(struct brcmf_if *ifp);
|
|
||||||
+void brcmf_p2p_ifp_removed(struct brcmf_if *ifp, bool rtnl_locked);
|
|
||||||
int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev);
|
|
||||||
void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev);
|
|
||||||
int brcmf_p2p_scan_prep(struct wiphy *wiphy,
|
|
|
@ -1,175 +0,0 @@
|
||||||
From b64abcb7dae6060c67ab0e548da3ef923c49641d Mon Sep 17 00:00:00 2001
|
|
||||||
From: "mhiramat@kernel.org" <mhiramat@kernel.org>
|
|
||||||
Date: Mon, 15 Aug 2016 18:41:12 +0900
|
|
||||||
Subject: [PATCH] brcmfmac: Change vif_event_lock to spinlock
|
|
||||||
|
|
||||||
Change vif_event_lock to spinlock from mutex, since this lock is
|
|
||||||
used in wait_event_timeout() via vif_event_equals(). This caused
|
|
||||||
a warning report as below.
|
|
||||||
|
|
||||||
As far as I can see, this lock protects regions where updating
|
|
||||||
structure members, not function calls. Also, since those
|
|
||||||
regions are not called from interrupt handlers (of course, it
|
|
||||||
was a mutex), spin_lock is used instead of spin_lock_irqsave.
|
|
||||||
|
|
||||||
[ 186.678550] ------------[ cut here ]------------
|
|
||||||
[ 186.678556] WARNING: CPU: 2 PID: 7140 at /home/mhiramat/ksrc/linux/kernel/sched/core.c:7545 __might_sleep+0x7c/0x80
|
|
||||||
[ 186.678560] do not call blocking ops when !TASK_RUNNING; state=2 set at [<ffffffff980d9090>] prepare_to_wait_event+0x60/0x100
|
|
||||||
[ 186.678560] Modules linked in: brcmfmac xt_CHECKSUM rfcomm ipt_MASQUERADE nf_nat_masquerade_ipv4 xt_addrtype br_netfilter xt_tcpudp ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 ipt_REJECT nf_reject_ipv4 xt_conntrack ip_set nfnetlink ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_raw ip6table_security ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_filter ip6_tables iptable_raw iptable_security iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_filter ip_tables x_tables bnep nls_iso8859_1 i2c_designware_platform i2c_designware_core snd_hda_codec_hdmi snd_hda_codec_realtek dcdbas snd_hda_codec_generic snd_hda_intel snd_hda_codec intel_rapl snd_hda_core x86_pkg_temp_thermal intel_powerclamp coretemp
|
|
||||||
[ 186.678594] snd_pcm crct10dif_pclmul crc32_pclmul aesni_intel aes_x86_64 joydev glue_helper snd_hwdep lrw gf128mul uvcvideo ablk_helper snd_seq_midi cryptd snd_seq_midi_event snd_rawmidi videobuf2_vmalloc videobuf2_memops snd_seq input_leds videobuf2_v4l2 cfg80211 videobuf2_core snd_timer videodev serio_raw btusb snd_seq_device media btrtl rtsx_pci_ms snd mei_me memstick hid_multitouch mei soundcore brcmutil idma64 virt_dma intel_lpss_pci processor_thermal_device intel_soc_dts_iosf hci_uart btbcm btqca btintel bluetooth int3403_thermal dell_smo8800 intel_lpss_acpi intel_lpss int3402_thermal int340x_thermal_zone intel_hid mac_hid int3400_thermal shpchp sparse_keymap acpi_pad acpi_thermal_rel acpi_als kfifo_buf industrialio kvm_intel kvm irqbypass parport_pc ppdev lp parport autofs4 btrfs xor raid6_pq
|
|
||||||
[ 186.678631] usbhid nouveau ttm i915 rtsx_pci_sdmmc mxm_wmi i2c_algo_bit drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops psmouse drm ahci rtsx_pci nvme nvme_core libahci i2c_hid hid pinctrl_sunrisepoint video wmi pinctrl_intel fjes [last unloaded: brcmfmac]
|
|
||||||
[ 186.678646] CPU: 2 PID: 7140 Comm: wpa_supplicant Not tainted 4.8.0-rc1+ #8
|
|
||||||
[ 186.678647] Hardware name: Dell Inc. XPS 15 9550/0N7TVV, BIOS 01.02.00 04/07/2016
|
|
||||||
[ 186.678648] 0000000000000000 ffff9d8c64b5b900 ffffffff98442f23 ffff9d8c64b5b950
|
|
||||||
[ 186.678651] 0000000000000000 ffff9d8c64b5b940 ffffffff9808b22b 00001d790000000d
|
|
||||||
[ 186.678653] ffffffff98c75e78 000000000000026c 0000000000000000 ffff9d8c2706d058
|
|
||||||
[ 186.678655] Call Trace:
|
|
||||||
[ 186.678659] [<ffffffff98442f23>] dump_stack+0x85/0xc2
|
|
||||||
[ 186.678666] [<ffffffff9808b22b>] __warn+0xcb/0xf0
|
|
||||||
[ 186.678668] [<ffffffff9808b29f>] warn_slowpath_fmt+0x4f/0x60
|
|
||||||
[ 186.678671] [<ffffffff980d9090>] ? prepare_to_wait_event+0x60/0x100
|
|
||||||
[ 186.678672] [<ffffffff980d9090>] ? prepare_to_wait_event+0x60/0x100
|
|
||||||
[ 186.678674] [<ffffffff980b922c>] __might_sleep+0x7c/0x80
|
|
||||||
[ 186.678680] [<ffffffff988b0853>] mutex_lock_nested+0x33/0x3b0
|
|
||||||
[ 186.678682] [<ffffffff980e5d8d>] ? trace_hardirqs_on+0xd/0x10
|
|
||||||
[ 186.678689] [<ffffffffc0c57d2d>] brcmf_cfg80211_wait_vif_event+0xcd/0x130 [brcmfmac]
|
|
||||||
[ 186.678691] [<ffffffff980d9190>] ? wake_atomic_t_function+0x60/0x60
|
|
||||||
[ 186.678697] [<ffffffffc0c628e9>] brcmf_p2p_del_vif+0xf9/0x220 [brcmfmac]
|
|
||||||
[ 186.678702] [<ffffffffc0c57fab>] brcmf_cfg80211_del_iface+0x21b/0x270 [brcmfmac]
|
|
||||||
[ 186.678716] [<ffffffffc0b0539e>] nl80211_del_interface+0xfe/0x3a0 [cfg80211]
|
|
||||||
[ 186.678718] [<ffffffff987ca335>] genl_family_rcv_msg+0x1b5/0x370
|
|
||||||
[ 186.678720] [<ffffffff980e5d8d>] ? trace_hardirqs_on+0xd/0x10
|
|
||||||
[ 186.678721] [<ffffffff987ca56d>] genl_rcv_msg+0x7d/0xb0
|
|
||||||
[ 186.678722] [<ffffffff987ca4f0>] ? genl_family_rcv_msg+0x370/0x370
|
|
||||||
[ 186.678724] [<ffffffff987c9a47>] netlink_rcv_skb+0x97/0xb0
|
|
||||||
[ 186.678726] [<ffffffff987ca168>] genl_rcv+0x28/0x40
|
|
||||||
[ 186.678727] [<ffffffff987c93c3>] netlink_unicast+0x1d3/0x2f0
|
|
||||||
[ 186.678729] [<ffffffff987c933b>] ? netlink_unicast+0x14b/0x2f0
|
|
||||||
[ 186.678731] [<ffffffff987c97cb>] netlink_sendmsg+0x2eb/0x3a0
|
|
||||||
[ 186.678733] [<ffffffff9876dad8>] sock_sendmsg+0x38/0x50
|
|
||||||
[ 186.678734] [<ffffffff9876e4df>] ___sys_sendmsg+0x27f/0x290
|
|
||||||
[ 186.678737] [<ffffffff9828b935>] ? mntput_no_expire+0x5/0x3f0
|
|
||||||
[ 186.678739] [<ffffffff9828b9be>] ? mntput_no_expire+0x8e/0x3f0
|
|
||||||
[ 186.678741] [<ffffffff9828b935>] ? mntput_no_expire+0x5/0x3f0
|
|
||||||
[ 186.678743] [<ffffffff9828bd44>] ? mntput+0x24/0x40
|
|
||||||
[ 186.678744] [<ffffffff98267830>] ? __fput+0x190/0x200
|
|
||||||
[ 186.678746] [<ffffffff9876f125>] __sys_sendmsg+0x45/0x80
|
|
||||||
[ 186.678748] [<ffffffff9876f172>] SyS_sendmsg+0x12/0x20
|
|
||||||
[ 186.678749] [<ffffffff988b5680>] entry_SYSCALL_64_fastpath+0x23/0xc1
|
|
||||||
[ 186.678751] [<ffffffff980e2b8f>] ? trace_hardirqs_off_caller+0x1f/0xc0
|
|
||||||
[ 186.678752] ---[ end trace e224d66c5d8408b5 ]---
|
|
||||||
|
|
||||||
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
|
|
||||||
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 26 +++++++++++-----------
|
|
||||||
.../broadcom/brcm80211/brcmfmac/cfg80211.h | 2 +-
|
|
||||||
2 files changed, 14 insertions(+), 14 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -5631,7 +5631,7 @@ static s32 brcmf_notify_vif_event(struct
|
|
||||||
ifevent->action, ifevent->flags, ifevent->ifidx,
|
|
||||||
ifevent->bsscfgidx);
|
|
||||||
|
|
||||||
- mutex_lock(&event->vif_event_lock);
|
|
||||||
+ spin_lock(&event->vif_event_lock);
|
|
||||||
event->action = ifevent->action;
|
|
||||||
vif = event->vif;
|
|
||||||
|
|
||||||
@@ -5639,7 +5639,7 @@ static s32 brcmf_notify_vif_event(struct
|
|
||||||
case BRCMF_E_IF_ADD:
|
|
||||||
/* waiting process may have timed out */
|
|
||||||
if (!cfg->vif_event.vif) {
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
return -EBADF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -5650,24 +5650,24 @@ static s32 brcmf_notify_vif_event(struct
|
|
||||||
ifp->ndev->ieee80211_ptr = &vif->wdev;
|
|
||||||
SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
|
|
||||||
}
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
wake_up(&event->vif_wq);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case BRCMF_E_IF_DEL:
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
/* event may not be upon user request */
|
|
||||||
if (brcmf_cfg80211_vif_event_armed(cfg))
|
|
||||||
wake_up(&event->vif_wq);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case BRCMF_E_IF_CHANGE:
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
wake_up(&event->vif_wq);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
@@ -5788,7 +5788,7 @@ static void wl_deinit_priv(struct brcmf_
|
|
||||||
static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
|
|
||||||
{
|
|
||||||
init_waitqueue_head(&event->vif_wq);
|
|
||||||
- mutex_init(&event->vif_event_lock);
|
|
||||||
+ spin_lock_init(&event->vif_event_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static s32 brcmf_dongle_roam(struct brcmf_if *ifp)
|
|
||||||
@@ -6687,9 +6687,9 @@ static inline bool vif_event_equals(stru
|
|
||||||
{
|
|
||||||
u8 evt_action;
|
|
||||||
|
|
||||||
- mutex_lock(&event->vif_event_lock);
|
|
||||||
+ spin_lock(&event->vif_event_lock);
|
|
||||||
evt_action = event->action;
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
return evt_action == action;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -6698,10 +6698,10 @@ void brcmf_cfg80211_arm_vif_event(struct
|
|
||||||
{
|
|
||||||
struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
|
|
||||||
|
|
||||||
- mutex_lock(&event->vif_event_lock);
|
|
||||||
+ spin_lock(&event->vif_event_lock);
|
|
||||||
event->vif = vif;
|
|
||||||
event->action = 0;
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
|
|
||||||
@@ -6709,9 +6709,9 @@ bool brcmf_cfg80211_vif_event_armed(stru
|
|
||||||
struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
|
|
||||||
bool armed;
|
|
||||||
|
|
||||||
- mutex_lock(&event->vif_event_lock);
|
|
||||||
+ spin_lock(&event->vif_event_lock);
|
|
||||||
armed = event->vif != NULL;
|
|
||||||
- mutex_unlock(&event->vif_event_lock);
|
|
||||||
+ spin_unlock(&event->vif_event_lock);
|
|
||||||
|
|
||||||
return armed;
|
|
||||||
}
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
|
|
||||||
@@ -227,7 +227,7 @@ struct escan_info {
|
|
||||||
*/
|
|
||||||
struct brcmf_cfg80211_vif_event {
|
|
||||||
wait_queue_head_t vif_wq;
|
|
||||||
- struct mutex vif_event_lock;
|
|
||||||
+ spinlock_t vif_event_lock;
|
|
||||||
u8 action;
|
|
||||||
struct brcmf_cfg80211_vif *vif;
|
|
||||||
};
|
|
|
@ -1,29 +0,0 @@
|
||||||
From 8af92af3f2d55db143417a5d401696f4b642009a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Baoyou Xie <baoyou.xie@linaro.org>
|
|
||||||
Date: Mon, 29 Aug 2016 20:39:35 +0800
|
|
||||||
Subject: [PATCH] brcmfmac: add missing header dependencies
|
|
||||||
|
|
||||||
We get 1 warning when building kernel with W=1:
|
|
||||||
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c:23:6: warning: no previous prototype for '__brcmf_err' [-Wmissing-prototypes]
|
|
||||||
|
|
||||||
In fact, this function is declared in brcmfmac/debug.h, so this patch
|
|
||||||
adds missing header dependencies.
|
|
||||||
|
|
||||||
Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
|
|
||||||
Acked-by: Arnd Bergmann <arnd@arndb.de>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.c
|
|
||||||
@@ -19,6 +19,7 @@
|
|
||||||
#ifndef __CHECKER__
|
|
||||||
#define CREATE_TRACE_POINTS
|
|
||||||
#include "tracepoint.h"
|
|
||||||
+#include "debug.h"
|
|
||||||
|
|
||||||
void __brcmf_err(const char *func, const char *fmt, ...)
|
|
||||||
{
|
|
|
@ -1,51 +0,0 @@
|
||||||
From bccf3ffc8c6d8e0251a15541bb4d12b423c4f729 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ismael Luceno <ismael@iodev.co.uk>
|
|
||||||
Date: Mon, 22 Aug 2016 19:40:07 -0300
|
|
||||||
Subject: [PATCH] brcmfmac: Add USB ID for Cisco Linksys AE1200
|
|
||||||
|
|
||||||
The AE1200 comes with different revisions of the BCM43235 chipset,
|
|
||||||
but all have the same USB ID. Only revision 3 can be supported.
|
|
||||||
|
|
||||||
Signed-off-by: Ismael Luceno <ismael@iodev.co.uk>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 4 ++++
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h | 2 ++
|
|
||||||
2 files changed, 6 insertions(+)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
|
|
||||||
@@ -1458,11 +1458,15 @@ static int brcmf_usb_reset_resume(struct
|
|
||||||
#define BRCMF_USB_DEVICE(dev_id) \
|
|
||||||
{ USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id) }
|
|
||||||
|
|
||||||
+#define LINKSYS_USB_DEVICE(dev_id) \
|
|
||||||
+ { USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id) }
|
|
||||||
+
|
|
||||||
static struct usb_device_id brcmf_usb_devid_table[] = {
|
|
||||||
BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID),
|
|
||||||
BRCMF_USB_DEVICE(BRCM_USB_43236_DEVICE_ID),
|
|
||||||
BRCMF_USB_DEVICE(BRCM_USB_43242_DEVICE_ID),
|
|
||||||
BRCMF_USB_DEVICE(BRCM_USB_43569_DEVICE_ID),
|
|
||||||
+ LINKSYS_USB_DEVICE(BRCM_USB_43235_LINKSYS_DEVICE_ID),
|
|
||||||
{ USB_DEVICE(BRCM_USB_VENDOR_ID_LG, BRCM_USB_43242_LG_DEVICE_ID) },
|
|
||||||
/* special entry for device with firmware loaded and running */
|
|
||||||
BRCMF_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID),
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h
|
|
||||||
@@ -22,6 +22,7 @@
|
|
||||||
|
|
||||||
#define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c
|
|
||||||
#define BRCM_USB_VENDOR_ID_LG 0x043e
|
|
||||||
+#define BRCM_USB_VENDOR_ID_LINKSYS 0x13b1
|
|
||||||
#define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
|
|
||||||
|
|
||||||
/* Chipcommon Core Chip IDs */
|
|
||||||
@@ -58,6 +59,7 @@
|
|
||||||
|
|
||||||
/* USB Device IDs */
|
|
||||||
#define BRCM_USB_43143_DEVICE_ID 0xbd1e
|
|
||||||
+#define BRCM_USB_43235_LINKSYS_DEVICE_ID 0x0039
|
|
||||||
#define BRCM_USB_43236_DEVICE_ID 0xbd17
|
|
||||||
#define BRCM_USB_43242_DEVICE_ID 0xbd1f
|
|
||||||
#define BRCM_USB_43242_LG_DEVICE_ID 0x3101
|
|
|
@ -1,51 +0,0 @@
|
||||||
From 7703773ef1d85b40433902a8da20167331597e4a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Nicolas Iooss <nicolas.iooss_linux@m4x.org>
|
|
||||||
Date: Tue, 23 Aug 2016 11:37:17 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: fix pmksa->bssid usage
|
|
||||||
|
|
||||||
The struct cfg80211_pmksa defines its bssid field as:
|
|
||||||
|
|
||||||
const u8 *bssid;
|
|
||||||
|
|
||||||
contrary to struct brcmf_pmksa, which uses:
|
|
||||||
|
|
||||||
u8 bssid[ETH_ALEN];
|
|
||||||
|
|
||||||
Therefore in brcmf_cfg80211_del_pmksa(), &pmksa->bssid takes the address
|
|
||||||
of this field (of type u8**), not the one of its content (which would be
|
|
||||||
u8*). Remove the & operator to make brcmf_dbg("%pM") and memcmp()
|
|
||||||
behave as expected.
|
|
||||||
|
|
||||||
This bug have been found using a custom static checker (which checks the
|
|
||||||
usage of %p... attributes at build time). It has been introduced in
|
|
||||||
commit 6c404f34f2bd ("brcmfmac: Cleanup pmksa cache handling code"),
|
|
||||||
which replaced pmksa->bssid by &pmksa->bssid while refactoring the code,
|
|
||||||
without modifying struct cfg80211_pmksa definition.
|
|
||||||
|
|
||||||
Replace &pmk[i].bssid with pmk[i].bssid too to make the code clearer,
|
|
||||||
this change does not affect the semantic.
|
|
||||||
|
|
||||||
Fixes: 6c404f34f2bd ("brcmfmac: Cleanup pmksa cache handling code")
|
|
||||||
Cc: stable@vger.kernel.org
|
|
||||||
Signed-off-by: Nicolas Iooss <nicolas.iooss_linux@m4x.org>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 ++--
|
|
||||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -3880,11 +3880,11 @@ brcmf_cfg80211_del_pmksa(struct wiphy *w
|
|
||||||
if (!check_vif_up(ifp->vif))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
- brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid);
|
|
||||||
+ brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", pmksa->bssid);
|
|
||||||
|
|
||||||
npmk = le32_to_cpu(cfg->pmk_list.npmk);
|
|
||||||
for (i = 0; i < npmk; i++)
|
|
||||||
- if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
|
|
||||||
+ if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((npmk > 0) && (i < npmk)) {
|
|
|
@ -1,34 +0,0 @@
|
||||||
From ded89912156b1a47d940a0c954c43afbabd0c42c Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Mon, 5 Sep 2016 10:45:47 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: avoid potential stack overflow in
|
|
||||||
brcmf_cfg80211_start_ap()
|
|
||||||
|
|
||||||
User-space can choose to omit NL80211_ATTR_SSID and only provide raw
|
|
||||||
IE TLV data. When doing so it can provide SSID IE with length exceeding
|
|
||||||
the allowed size. The driver further processes this IE copying it
|
|
||||||
into a local variable without checking the length. Hence stack can be
|
|
||||||
corrupted and used as exploit.
|
|
||||||
|
|
||||||
Cc: stable@vger.kernel.org # v4.7
|
|
||||||
Reported-by: Daxing Guo <freener.gdx@gmail.com>
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -4523,7 +4523,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
|
|
||||||
(u8 *)&settings->beacon.head[ie_offset],
|
|
||||||
settings->beacon.head_len - ie_offset,
|
|
||||||
WLAN_EID_SSID);
|
|
||||||
- if (!ssid_ie)
|
|
||||||
+ if (!ssid_ie || ssid_ie->len > IEEE80211_MAX_SSID_LEN)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
|
|
|
@ -1,55 +0,0 @@
|
||||||
From 634faf3686900ccdee87b77e2c56df8b2159912b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Mon, 5 Sep 2016 11:42:12 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: add support for bcm4339 chip with modalias
|
|
||||||
sdio:c00v02D0d4339
|
|
||||||
|
|
||||||
The driver already supports the bcm4339 chipset but only for the variant
|
|
||||||
that shares the same modalias as the bcm4335, ie. sdio:c00v02D0d4335.
|
|
||||||
It turns out that there are also bcm4339 devices out there that have a
|
|
||||||
more distiguishable modalias sdio:c00v02D0d4339.
|
|
||||||
|
|
||||||
Reported-by: Steve deRosier <derosier@gmail.com>
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 +
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 3 ++-
|
|
||||||
include/linux/mmc/sdio_ids.h | 1 +
|
|
||||||
3 files changed, 4 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
|
||||||
@@ -1101,6 +1101,7 @@ static const struct sdio_device_id brcmf
|
|
||||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341),
|
|
||||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362),
|
|
||||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
|
|
||||||
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4339),
|
|
||||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430),
|
|
||||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345),
|
|
||||||
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
|
||||||
@@ -3757,7 +3757,8 @@ static u32 brcmf_sdio_buscore_read32(voi
|
|
||||||
u32 val, rev;
|
|
||||||
|
|
||||||
val = brcmf_sdiod_regrl(sdiodev, addr, NULL);
|
|
||||||
- if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
|
|
||||||
+ if ((sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 ||
|
|
||||||
+ sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4339) &&
|
|
||||||
addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) {
|
|
||||||
rev = (val & CID_REV_MASK) >> CID_REV_SHIFT;
|
|
||||||
if (rev >= 2) {
|
|
||||||
--- a/include/linux/mmc/sdio_ids.h
|
|
||||||
+++ b/include/linux/mmc/sdio_ids.h
|
|
||||||
@@ -32,6 +32,7 @@
|
|
||||||
#define SDIO_DEVICE_ID_BROADCOM_43340 0xa94c
|
|
||||||
#define SDIO_DEVICE_ID_BROADCOM_43341 0xa94d
|
|
||||||
#define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335
|
|
||||||
+#define SDIO_DEVICE_ID_BROADCOM_4339 0x4339
|
|
||||||
#define SDIO_DEVICE_ID_BROADCOM_43362 0xa962
|
|
||||||
#define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6
|
|
||||||
#define SDIO_DEVICE_ID_BROADCOM_4345 0x4345
|
|
|
@ -1,56 +0,0 @@
|
||||||
From 5251b6be8bb5c5675bdf12347c7b83937a5c91e5 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Mon, 5 Sep 2016 11:42:13 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: sdio: shorten retry loop in
|
|
||||||
brcmf_sdio_kso_control()
|
|
||||||
|
|
||||||
In brcmf_sdio_kso_control() there is a retry loop as hardware may take
|
|
||||||
time to settle. However, when the call to brcmf_sdiod_regrb() returns
|
|
||||||
an error it is due to SDIO access failure and it makes no sense to wait
|
|
||||||
for hardware to settle. This patch aborts the loop after a number of
|
|
||||||
subsequent access errors.
|
|
||||||
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 11 +++++++++--
|
|
||||||
1 file changed, 9 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
|
|
||||||
@@ -313,6 +313,7 @@ struct rte_console {
|
|
||||||
|
|
||||||
#define KSO_WAIT_US 50
|
|
||||||
#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
|
|
||||||
+#define BRCMF_SDIO_MAX_ACCESS_ERRORS 5
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Conversion of 802.1D priority to precedence level
|
|
||||||
@@ -677,6 +678,7 @@ brcmf_sdio_kso_control(struct brcmf_sdio
|
|
||||||
{
|
|
||||||
u8 wr_val = 0, rd_val, cmp_val, bmask;
|
|
||||||
int err = 0;
|
|
||||||
+ int err_cnt = 0;
|
|
||||||
int try_cnt = 0;
|
|
||||||
|
|
||||||
brcmf_dbg(TRACE, "Enter: on=%d\n", on);
|
|
||||||
@@ -712,9 +714,14 @@ brcmf_sdio_kso_control(struct brcmf_sdio
|
|
||||||
*/
|
|
||||||
rd_val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
|
|
||||||
&err);
|
|
||||||
- if (((rd_val & bmask) == cmp_val) && !err)
|
|
||||||
+ if (!err) {
|
|
||||||
+ if ((rd_val & bmask) == cmp_val)
|
|
||||||
+ break;
|
|
||||||
+ err_cnt = 0;
|
|
||||||
+ }
|
|
||||||
+ /* bail out upon subsequent access errors */
|
|
||||||
+ if (err && (err_cnt++ > BRCMF_SDIO_MAX_ACCESS_ERRORS))
|
|
||||||
break;
|
|
||||||
-
|
|
||||||
udelay(KSO_WAIT_US);
|
|
||||||
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
|
|
||||||
wr_val, &err);
|
|
|
@ -1,84 +0,0 @@
|
||||||
From b3589dfe02123a0d0ea82076a9f8ef84a46852c0 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:51 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: ignore 11d configuration errors
|
|
||||||
|
|
||||||
802.11d is not always supported by firmware anymore. Currently the
|
|
||||||
AP configuration of 11d will cause an abort if the ioctl set is
|
|
||||||
failing. This behavior is not correct and the error should be
|
|
||||||
ignored.
|
|
||||||
|
|
||||||
Reviewed-by: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 27 ++++++++++++----------
|
|
||||||
1 file changed, 15 insertions(+), 12 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -4498,6 +4498,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
|
|
||||||
u16 chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
|
|
||||||
bool mbss;
|
|
||||||
int is_11d;
|
|
||||||
+ bool supports_11d;
|
|
||||||
|
|
||||||
brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
|
|
||||||
settings->chandef.chan->hw_value,
|
|
||||||
@@ -4510,11 +4511,16 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
|
|
||||||
mbss = ifp->vif->mbss;
|
|
||||||
|
|
||||||
/* store current 11d setting */
|
|
||||||
- brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
|
|
||||||
- country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
|
|
||||||
- settings->beacon.tail_len,
|
|
||||||
- WLAN_EID_COUNTRY);
|
|
||||||
- is_11d = country_ie ? 1 : 0;
|
|
||||||
+ if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
|
|
||||||
+ &ifp->vif->is_11d)) {
|
|
||||||
+ supports_11d = false;
|
|
||||||
+ } else {
|
|
||||||
+ country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
|
|
||||||
+ settings->beacon.tail_len,
|
|
||||||
+ WLAN_EID_COUNTRY);
|
|
||||||
+ is_11d = country_ie ? 1 : 0;
|
|
||||||
+ supports_11d = true;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
memset(&ssid_le, 0, sizeof(ssid_le));
|
|
||||||
if (settings->ssid == NULL || settings->ssid_len == 0) {
|
|
||||||
@@ -4573,7 +4579,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
|
|
||||||
|
|
||||||
/* Parameters shared by all radio interfaces */
|
|
||||||
if (!mbss) {
|
|
||||||
- if (is_11d != ifp->vif->is_11d) {
|
|
||||||
+ if ((supports_11d) && (is_11d != ifp->vif->is_11d)) {
|
|
||||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
|
|
||||||
is_11d);
|
|
||||||
if (err < 0) {
|
|
||||||
@@ -4615,7 +4621,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
|
|
||||||
brcmf_err("SET INFRA error %d\n", err);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
- } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
|
|
||||||
+ } else if (WARN_ON(supports_11d && (is_11d != ifp->vif->is_11d))) {
|
|
||||||
/* Multiple-BSS should use same 11d configuration */
|
|
||||||
err = -EINVAL;
|
|
||||||
goto exit;
|
|
||||||
@@ -4749,11 +4755,8 @@ static int brcmf_cfg80211_stop_ap(struct
|
|
||||||
brcmf_err("setting INFRA mode failed %d\n", err);
|
|
||||||
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
|
|
||||||
brcmf_fil_iovar_int_set(ifp, "mbss", 0);
|
|
||||||
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
|
|
||||||
- ifp->vif->is_11d);
|
|
||||||
- if (err < 0)
|
|
||||||
- brcmf_err("restoring REGULATORY setting failed %d\n",
|
|
||||||
- err);
|
|
||||||
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
|
|
||||||
+ ifp->vif->is_11d);
|
|
||||||
/* Bring device back up so it can be used again */
|
|
||||||
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
|
|
||||||
if (err < 0)
|
|
|
@ -1,32 +0,0 @@
|
||||||
From 704d1c6b56f4ee2ad6a5f012a72a278d17c1a223 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:52 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: rework pointer trickery in
|
|
||||||
brcmf_proto_bcdc_query_dcmd()
|
|
||||||
|
|
||||||
The variable info is assigned to point to bcdc->msg[1], which is the
|
|
||||||
same as pointing to bcdc->buf. As that is what we want to access
|
|
||||||
make it clear by fixing the assignment. This also avoid out-of-bounds
|
|
||||||
errors from static analyzers are bcdc->msg[1] is not in the structure
|
|
||||||
definition.
|
|
||||||
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
|
|
||||||
@@ -194,7 +194,7 @@ retry:
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check info buffer */
|
|
||||||
- info = (void *)&msg[1];
|
|
||||||
+ info = (void *)&bcdc->buf[0];
|
|
||||||
|
|
||||||
/* Copy info buffer */
|
|
||||||
if (buf) {
|
|
|
@ -1,39 +0,0 @@
|
||||||
From bc981641360183990de59da17f9f560f9150b801 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:53 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: fix memory leak in brcmf_flowring_add_tdls_peer()
|
|
||||||
|
|
||||||
In the error paths in brcmf_flowring_add_tdls_peer() the allocated
|
|
||||||
resource should be freed.
|
|
||||||
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c | 8 ++++++--
|
|
||||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
|
|
||||||
@@ -495,14 +495,18 @@ void brcmf_flowring_add_tdls_peer(struct
|
|
||||||
} else {
|
|
||||||
search = flow->tdls_entry;
|
|
||||||
if (memcmp(search->mac, peer, ETH_ALEN) == 0)
|
|
||||||
- return;
|
|
||||||
+ goto free_entry;
|
|
||||||
while (search->next) {
|
|
||||||
search = search->next;
|
|
||||||
if (memcmp(search->mac, peer, ETH_ALEN) == 0)
|
|
||||||
- return;
|
|
||||||
+ goto free_entry;
|
|
||||||
}
|
|
||||||
search->next = tdls_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
flow->tdls_active = true;
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+free_entry:
|
|
||||||
+ kfree(tdls_entry);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
From 26305d3d7298d1ddf8fd4ce95a382aa90534f0a3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:54 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: initialize variable in brcmf_sdiod_regrl()
|
|
||||||
|
|
||||||
In case of an error the variable returned is uninitialized. The caller
|
|
||||||
will probably check the error code before using it, but better assure
|
|
||||||
it is set to zero.
|
|
||||||
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
|
|
||||||
@@ -420,7 +420,7 @@ u8 brcmf_sdiod_regrb(struct brcmf_sdio_d
|
|
||||||
|
|
||||||
u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
|
|
||||||
{
|
|
||||||
- u32 data;
|
|
||||||
+ u32 data = 0;
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
|
|
|
@ -1,107 +0,0 @@
|
||||||
From 8fa5fdec09cd379c9ecb8972f344f8f308e0ccf3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:55 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: remove worker from .ndo_set_mac_address() callback
|
|
||||||
|
|
||||||
As it turns out there is no need to use a worker for the callback
|
|
||||||
because it is not called from atomic context.
|
|
||||||
|
|
||||||
Reported-by: Dan Williams <dcbw@redhat.com>
|
|
||||||
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
.../wireless/broadcom/brcm80211/brcmfmac/core.c | 39 ++++++++--------------
|
|
||||||
.../wireless/broadcom/brcm80211/brcmfmac/core.h | 2 --
|
|
||||||
2 files changed, 13 insertions(+), 28 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -136,27 +136,6 @@ static void _brcmf_set_multicast_list(st
|
|
||||||
err);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void
|
|
||||||
-_brcmf_set_mac_address(struct work_struct *work)
|
|
||||||
-{
|
|
||||||
- struct brcmf_if *ifp;
|
|
||||||
- s32 err;
|
|
||||||
-
|
|
||||||
- ifp = container_of(work, struct brcmf_if, setmacaddr_work);
|
|
||||||
-
|
|
||||||
- brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
|
|
||||||
-
|
|
||||||
- err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
|
|
||||||
- ETH_ALEN);
|
|
||||||
- if (err < 0) {
|
|
||||||
- brcmf_err("Setting cur_etheraddr failed, %d\n", err);
|
|
||||||
- } else {
|
|
||||||
- brcmf_dbg(TRACE, "MAC address updated to %pM\n",
|
|
||||||
- ifp->mac_addr);
|
|
||||||
- memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
|
|
||||||
- }
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
|
||||||
static void _brcmf_update_ndtable(struct work_struct *work)
|
|
||||||
{
|
|
||||||
@@ -190,10 +169,20 @@ static int brcmf_netdev_set_mac_address(
|
|
||||||
{
|
|
||||||
struct brcmf_if *ifp = netdev_priv(ndev);
|
|
||||||
struct sockaddr *sa = (struct sockaddr *)addr;
|
|
||||||
+ int err;
|
|
||||||
|
|
||||||
- memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
|
|
||||||
- schedule_work(&ifp->setmacaddr_work);
|
|
||||||
- return 0;
|
|
||||||
+ brcmf_dbg(TRACE, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);
|
|
||||||
+
|
|
||||||
+ err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", sa->sa_data,
|
|
||||||
+ ETH_ALEN);
|
|
||||||
+ if (err < 0) {
|
|
||||||
+ brcmf_err("Setting cur_etheraddr failed, %d\n", err);
|
|
||||||
+ } else {
|
|
||||||
+ brcmf_dbg(TRACE, "updated to %pM\n", sa->sa_data);
|
|
||||||
+ memcpy(ifp->mac_addr, sa->sa_data, ETH_ALEN);
|
|
||||||
+ memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
|
|
||||||
+ }
|
|
||||||
+ return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
|
|
||||||
@@ -525,7 +514,6 @@ int brcmf_net_attach(struct brcmf_if *if
|
|
||||||
/* set the mac address */
|
|
||||||
memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
|
|
||||||
|
|
||||||
- INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
|
|
||||||
INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
|
|
||||||
INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
|
|
||||||
|
|
||||||
@@ -730,7 +718,6 @@ static void brcmf_del_if(struct brcmf_pu
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
|
|
||||||
- cancel_work_sync(&ifp->setmacaddr_work);
|
|
||||||
cancel_work_sync(&ifp->multicast_work);
|
|
||||||
cancel_work_sync(&ifp->ndoffload_work);
|
|
||||||
}
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
@@ -176,7 +176,6 @@ enum brcmf_netif_stop_reason {
|
|
||||||
* @vif: points to cfg80211 specific interface information.
|
|
||||||
* @ndev: associated network device.
|
|
||||||
* @stats: interface specific network statistics.
|
|
||||||
- * @setmacaddr_work: worker object for setting mac address.
|
|
||||||
* @multicast_work: worker object for multicast provisioning.
|
|
||||||
* @ndoffload_work: worker object for neighbor discovery offload configuration.
|
|
||||||
* @fws_desc: interface specific firmware-signalling descriptor.
|
|
||||||
@@ -193,7 +192,6 @@ struct brcmf_if {
|
|
||||||
struct brcmf_cfg80211_vif *vif;
|
|
||||||
struct net_device *ndev;
|
|
||||||
struct net_device_stats stats;
|
|
||||||
- struct work_struct setmacaddr_work;
|
|
||||||
struct work_struct multicast_work;
|
|
||||||
struct work_struct ndoffload_work;
|
|
||||||
struct brcmf_fws_mac_descriptor *fws_desc;
|
|
|
@ -1,31 +0,0 @@
|
||||||
From 835680b82f029818c813324aed3073cdcf63241f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:56 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: remove unnecessary null pointer check
|
|
||||||
|
|
||||||
in the function brcmf_bus_start() in the exception handling a
|
|
||||||
check is made to dermine whether ifp is null, though this is not
|
|
||||||
possible. Removing the unnessary check.
|
|
||||||
|
|
||||||
Reviewed-by: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 3 +--
|
|
||||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -1048,8 +1048,7 @@ fail:
|
|
||||||
brcmf_fws_del_interface(ifp);
|
|
||||||
brcmf_fws_deinit(drvr);
|
|
||||||
}
|
|
||||||
- if (ifp)
|
|
||||||
- brcmf_net_detach(ifp->ndev, false);
|
|
||||||
+ brcmf_net_detach(ifp->ndev, false);
|
|
||||||
if (p2p_ifp)
|
|
||||||
brcmf_net_detach(p2p_ifp->ndev, false);
|
|
||||||
drvr->iflist[0] = NULL;
|
|
|
@ -1,37 +0,0 @@
|
||||||
From 2b7425f3629b38c438f890c20c5faeca64b144ff Mon Sep 17 00:00:00 2001
|
|
||||||
From: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:57 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: fix clearing entry IPv6 address
|
|
||||||
|
|
||||||
When IPv6 address is to be cleared there is a possible out of
|
|
||||||
bound access. But also the clearing of the last entry and the
|
|
||||||
adjustment of total number of stored IPv6 addresses is not
|
|
||||||
updated. This patch fixes that bug. Bug was found using coverity.
|
|
||||||
|
|
||||||
Reviewed-by: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 7 +++++--
|
|
||||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -873,9 +873,12 @@ static int brcmf_inet6addr_changed(struc
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NETDEV_DOWN:
|
|
||||||
- if (i < NDOL_MAX_ENTRIES)
|
|
||||||
- for (; i < ifp->ipv6addr_idx; i++)
|
|
||||||
+ if (i < NDOL_MAX_ENTRIES) {
|
|
||||||
+ for (; i < ifp->ipv6addr_idx - 1; i++)
|
|
||||||
table[i] = table[i + 1];
|
|
||||||
+ memset(&table[i], 0, sizeof(table[i]));
|
|
||||||
+ ifp->ipv6addr_idx--;
|
|
||||||
+ }
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
|
@ -1,44 +0,0 @@
|
||||||
From a7ed7828ecda0c2b5e0d7f55dedd4230afd4b583 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:58 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: fix out of bound access on clearing wowl wake
|
|
||||||
indicator
|
|
||||||
|
|
||||||
Clearing the wowl wakeindicator happens with a rather odd
|
|
||||||
construction where the string "clear" is used to set the iovar
|
|
||||||
wowl_wakeind. This was implemented incorrectly as it caused an
|
|
||||||
out of bound access. Use an intermediate variable of correct
|
|
||||||
length and copy string in that. Problem was found using coverity.
|
|
||||||
|
|
||||||
Reviewed-by: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 6 ++++--
|
|
||||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -3699,6 +3699,7 @@ static void brcmf_configure_wowl(struct
|
|
||||||
struct cfg80211_wowlan *wowl)
|
|
||||||
{
|
|
||||||
u32 wowl_config;
|
|
||||||
+ struct brcmf_wowl_wakeind_le wowl_wakeind;
|
|
||||||
u32 i;
|
|
||||||
|
|
||||||
brcmf_dbg(TRACE, "Suspend, wowl config.\n");
|
|
||||||
@@ -3740,8 +3741,9 @@ static void brcmf_configure_wowl(struct
|
|
||||||
if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
|
|
||||||
wowl_config |= BRCMF_WOWL_UNASSOC;
|
|
||||||
|
|
||||||
- brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear",
|
|
||||||
- sizeof(struct brcmf_wowl_wakeind_le));
|
|
||||||
+ memcpy(&wowl_wakeind, "clear", 6);
|
|
||||||
+ brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", &wowl_wakeind,
|
|
||||||
+ sizeof(wowl_wakeind));
|
|
||||||
brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
|
|
||||||
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
|
|
||||||
brcmf_bus_wowl_config(cfg->pub->bus_if, true);
|
|
|
@ -1,39 +0,0 @@
|
||||||
From 92c313604711a0976def79dabb9e8da3cc2cc780 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Date: Mon, 19 Sep 2016 12:09:59 +0100
|
|
||||||
Subject: [PATCH] brcmfmac: simplify mapping of auth type
|
|
||||||
|
|
||||||
The 802.11 standard only has four valid auth type configurations of which
|
|
||||||
our firmware only supports two, ie. Open System and Shared Key. Simplify
|
|
||||||
the mapping falling back to automatic for other types specified by
|
|
||||||
user-space.
|
|
||||||
|
|
||||||
Reviewed-by: Arend Van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
|
|
||||||
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
|
|
||||||
Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com>
|
|
||||||
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 8 +-------
|
|
||||||
1 file changed, 1 insertion(+), 7 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -1591,15 +1591,9 @@ static s32 brcmf_set_auth_type(struct ne
|
|
||||||
val = 1;
|
|
||||||
brcmf_dbg(CONN, "shared key\n");
|
|
||||||
break;
|
|
||||||
- case NL80211_AUTHTYPE_AUTOMATIC:
|
|
||||||
- val = 2;
|
|
||||||
- brcmf_dbg(CONN, "automatic\n");
|
|
||||||
- break;
|
|
||||||
- case NL80211_AUTHTYPE_NETWORK_EAP:
|
|
||||||
- brcmf_dbg(CONN, "network eap\n");
|
|
||||||
default:
|
|
||||||
val = 2;
|
|
||||||
- brcmf_err("invalid auth type (%d)\n", sme->auth_type);
|
|
||||||
+ brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
From 23e9c128adb2038c27a424a5f91136e7fa3e0dc6 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
|
||||||
Date: Wed, 21 Sep 2016 08:23:24 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: fix memory leak in brcmf_fill_bss_param
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
This function is called from get_station callback which means that every
|
|
||||||
time user space was getting/dumping station(s) we were leaking 2 KiB.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
|
||||||
Fixes: 1f0dc59a6de ("brcmfmac: rework .get_station() callback")
|
|
||||||
Cc: stable@vger.kernel.org # 4.2+
|
|
||||||
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 5 ++++-
|
|
||||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
|
|
||||||
@@ -2523,7 +2523,7 @@ static void brcmf_fill_bss_param(struct
|
|
||||||
WL_BSS_INFO_MAX);
|
|
||||||
if (err) {
|
|
||||||
brcmf_err("Failed to get bss info (%d)\n", err);
|
|
||||||
- return;
|
|
||||||
+ goto out_kfree;
|
|
||||||
}
|
|
||||||
si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
|
|
||||||
si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period);
|
|
||||||
@@ -2535,6 +2535,9 @@ static void brcmf_fill_bss_param(struct
|
|
||||||
si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
|
|
||||||
if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
|
|
||||||
si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
|
|
||||||
+
|
|
||||||
+out_kfree:
|
|
||||||
+ kfree(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static s32
|
|
|
@ -1,60 +0,0 @@
|
||||||
From 2df86ad959c9d1cdbeb2f23a0801857731156692 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
|
||||||
Date: Fri, 23 Sep 2016 15:27:46 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: drop unused fields from struct brcmf_pub
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
They seem to be there from the first day. We calculate these values but
|
|
||||||
never use them.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 3 ---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h | 4 ----
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c | 2 --
|
|
||||||
3 files changed, 9 deletions(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -508,9 +508,6 @@ int brcmf_net_attach(struct brcmf_if *if
|
|
||||||
ndev->needed_headroom += drvr->hdrlen;
|
|
||||||
ndev->ethtool_ops = &brcmf_ethtool_ops;
|
|
||||||
|
|
||||||
- drvr->rxsz = ndev->mtu + ndev->hard_header_len +
|
|
||||||
- drvr->hdrlen;
|
|
||||||
-
|
|
||||||
/* set the mac address */
|
|
||||||
memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
|
|
||||||
@@ -112,15 +112,11 @@ struct brcmf_pub {
|
|
||||||
|
|
||||||
/* Internal brcmf items */
|
|
||||||
uint hdrlen; /* Total BRCMF header length (proto + bus) */
|
|
||||||
- uint rxsz; /* Rx buffer size bus module should use */
|
|
||||||
|
|
||||||
/* Dongle media info */
|
|
||||||
char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
|
|
||||||
u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
|
|
||||||
|
|
||||||
- /* Multicast data packets sent to dongle */
|
|
||||||
- unsigned long tx_multicast;
|
|
||||||
-
|
|
||||||
struct mac_address addresses[BRCMF_MAX_IFS];
|
|
||||||
|
|
||||||
struct brcmf_if *iflist[BRCMF_MAX_IFS];
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
|
|
||||||
@@ -2104,8 +2104,6 @@ int brcmf_fws_process_skb(struct brcmf_i
|
|
||||||
if ((skb->priority == 0) || (skb->priority > 7))
|
|
||||||
skb->priority = cfg80211_classify8021d(skb, NULL);
|
|
||||||
|
|
||||||
- drvr->tx_multicast += !!multicast;
|
|
||||||
-
|
|
||||||
if (fws->avoid_queueing) {
|
|
||||||
rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb);
|
|
||||||
if (rc < 0)
|
|
|
@ -1,38 +0,0 @@
|
||||||
From 2f0e56fa37cce60a5ac5d451bcadec51cd711436 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
|
||||||
Date: Tue, 27 Sep 2016 12:12:24 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: replace WARNING on timeout with a simple error
|
|
||||||
message
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Even with timeout increased to 950 ms we get WARNINGs from time to time.
|
|
||||||
It mostly happens on A-MPDU stalls (e.g. when station goes out of
|
|
||||||
range). It may take up to 5-10 secods for the firmware to recover and
|
|
||||||
for that time it doesn't process packets.
|
|
||||||
|
|
||||||
It's still useful to have a message on time out as it may indicate some
|
|
||||||
firmware problem and incorrect key update. Raising a WARNING however
|
|
||||||
wasn't really that necessary, it doesn't point to any driver bug anymore
|
|
||||||
and backtrace wasn't much useful.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
|
||||||
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 3 ++-
|
|
||||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
|
|
||||||
@@ -1155,7 +1155,8 @@ int brcmf_netdev_wait_pend8021x(struct b
|
|
||||||
!brcmf_get_pend_8021x_cnt(ifp),
|
|
||||||
MAX_WAIT_FOR_8021X_TX);
|
|
||||||
|
|
||||||
- WARN_ON(!err);
|
|
||||||
+ if (!err)
|
|
||||||
+ brcmf_err("Timed out waiting for no pending 802.1x packets\n");
|
|
||||||
|
|
||||||
return !err;
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
From 7f00ee2bbc630900ba16fc2690473f3e2db0e264 Mon Sep 17 00:00:00 2001
|
|
||||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
|
||||||
Date: Tue, 27 Sep 2016 14:11:04 +0200
|
|
||||||
Subject: [PATCH] brcmfmac: use correct skb freeing helper when deleting
|
|
||||||
flowring
|
|
||||||
MIME-Version: 1.0
|
|
||||||
Content-Type: text/plain; charset=UTF-8
|
|
||||||
Content-Transfer-Encoding: 8bit
|
|
||||||
|
|
||||||
Flowrings contain skbs waiting for transmission that were passed to us
|
|
||||||
by netif. It means we checked every one of them looking for 802.1x
|
|
||||||
Ethernet type. When deleting flowring we have to use freeing function
|
|
||||||
that will check for 802.1x type as well.
|
|
||||||
|
|
||||||
Freeing skbs without a proper check was leading to counter not being
|
|
||||||
properly decreased. This was triggering a WARNING every time
|
|
||||||
brcmf_netdev_wait_pend8021x was called.
|
|
||||||
|
|
||||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
|
||||||
Acked-by: Arend van Spriel <arend@broadcom.com>
|
|
||||||
Cc: stable@vger.kernel.org # 4.5+
|
|
||||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
|
||||||
---
|
|
||||||
drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c | 9 ++++++++-
|
|
||||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
|
|
||||||
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
|
|
||||||
@@ -234,13 +234,20 @@ static void brcmf_flowring_block(struct
|
|
||||||
|
|
||||||
void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
|
|
||||||
{
|
|
||||||
+ struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
|
|
||||||
struct brcmf_flowring_ring *ring;
|
|
||||||
+ struct brcmf_if *ifp;
|
|
||||||
u16 hash_idx;
|
|
||||||
+ u8 ifidx;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
|
|
||||||
ring = flow->rings[flowid];
|
|
||||||
if (!ring)
|
|
||||||
return;
|
|
||||||
+
|
|
||||||
+ ifidx = brcmf_flowring_ifidx_get(flow, flowid);
|
|
||||||
+ ifp = brcmf_get_ifp(bus_if->drvr, ifidx);
|
|
||||||
+
|
|
||||||
brcmf_flowring_block(flow, flowid, false);
|
|
||||||
hash_idx = ring->hash_id;
|
|
||||||
flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
|
|
||||||
@@ -249,7 +256,7 @@ void brcmf_flowring_delete(struct brcmf_
|
|
||||||
|
|
||||||
skb = skb_dequeue(&ring->skblist);
|
|
||||||
while (skb) {
|
|
||||||
- brcmu_pkt_buf_free_skb(skb);
|
|
||||||
+ brcmf_txfinalize(ifp, skb, false);
|
|
||||||
skb = skb_dequeue(&ring->skblist);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Tue, 2 Aug 2016 13:00:01 +0200
|
|
||||||
Subject: [PATCH] ath9k: fix using sta->drv_priv before initializing it
|
|
||||||
|
|
||||||
A station pointer can be passed to the driver on tx, before it has been
|
|
||||||
marked as associated. Since ath9k_sta_state was initializing the entry
|
|
||||||
too late, it resulted in some spurious crashes.
|
|
||||||
|
|
||||||
Fixes: df3c6eb34da5 ("ath9k: Use sta_state() callback")
|
|
||||||
Cc: stable@vger.kernel.org
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -1563,13 +1563,13 @@ static int ath9k_sta_state(struct ieee80
|
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
- if (old_state == IEEE80211_STA_AUTH &&
|
|
||||||
- new_state == IEEE80211_STA_ASSOC) {
|
|
||||||
+ if (old_state == IEEE80211_STA_NOTEXIST &&
|
|
||||||
+ new_state == IEEE80211_STA_NONE) {
|
|
||||||
ret = ath9k_sta_add(hw, vif, sta);
|
|
||||||
ath_dbg(common, CONFIG,
|
|
||||||
"Add station: %pM\n", sta->addr);
|
|
||||||
- } else if (old_state == IEEE80211_STA_ASSOC &&
|
|
||||||
- new_state == IEEE80211_STA_AUTH) {
|
|
||||||
+ } else if (old_state == IEEE80211_STA_NONE &&
|
|
||||||
+ new_state == IEEE80211_STA_NOTEXIST) {
|
|
||||||
ret = ath9k_sta_remove(hw, vif, sta);
|
|
||||||
ath_dbg(common, CONFIG,
|
|
||||||
"Remove station: %pM\n", sta->addr);
|
|
|
@ -1,26 +0,0 @@
|
||||||
From: Sven Eckelmann <sven@narfation.org>
|
|
||||||
Date: Fri, 17 Jun 2016 11:58:20 +0200
|
|
||||||
Subject: [PATCH] ath9k: Fix programming of minCCA power threshold
|
|
||||||
|
|
||||||
The function ar9003_hw_apply_minccapwr_thresh takes as second parameter not
|
|
||||||
a pointer to the channel but a boolean value describing whether the channel
|
|
||||||
is 2.4GHz or not. This broke (according to the origin commit) the ETSI
|
|
||||||
regulatory compliance on 5GHz channels.
|
|
||||||
|
|
||||||
Fixes: 3533bf6b15a0 ("ath9k: Fix regulatory compliance")
|
|
||||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
|
||||||
Cc: Simon Wunderlich <sw@simonwunderlich.de>
|
|
||||||
Cc: Sujith Manoharan <c_manoha@qca.qualcomm.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
|
||||||
@@ -4175,7 +4175,7 @@ static void ath9k_hw_ar9300_set_board_va
|
|
||||||
if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
|
|
||||||
ar9003_hw_internal_regulator_apply(ah);
|
|
||||||
ar9003_hw_apply_tuning_caps(ah);
|
|
||||||
- ar9003_hw_apply_minccapwr_thresh(ah, chan);
|
|
||||||
+ ar9003_hw_apply_minccapwr_thresh(ah, is2ghz);
|
|
||||||
ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz);
|
|
||||||
ar9003_hw_thermometer_apply(ah);
|
|
||||||
ar9003_hw_thermo_cal_apply(ah);
|
|
|
@ -1,86 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 11 Jul 2016 10:34:37 +0200
|
|
||||||
Subject: [PATCH] ath9k_hw: fix spectral scan on AR9285 and newer
|
|
||||||
|
|
||||||
The register layout of AR_PHY_SPECTRAL_SCAN has changed, only AR9280
|
|
||||||
uses the old layout
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
|
|
||||||
@@ -476,6 +476,7 @@ static void ar9002_hw_set_bt_ant_diversi
|
|
||||||
static void ar9002_hw_spectral_scan_config(struct ath_hw *ah,
|
|
||||||
struct ath_spec_scan *param)
|
|
||||||
{
|
|
||||||
+ u32 repeat_bit;
|
|
||||||
u8 count;
|
|
||||||
|
|
||||||
if (!param->enabled) {
|
|
||||||
@@ -486,12 +487,15 @@ static void ar9002_hw_spectral_scan_conf
|
|
||||||
REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
|
|
||||||
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
|
|
||||||
|
|
||||||
+ if (AR_SREV_9280(ah))
|
|
||||||
+ repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
|
|
||||||
+ else
|
|
||||||
+ repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI;
|
|
||||||
+
|
|
||||||
if (param->short_repeat)
|
|
||||||
- REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
- AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
|
|
||||||
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit);
|
|
||||||
else
|
|
||||||
- REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
- AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
|
|
||||||
+ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit);
|
|
||||||
|
|
||||||
/* on AR92xx, the highest bit of count will make the the chip send
|
|
||||||
* spectral samples endlessly. Check if this really was intended,
|
|
||||||
@@ -499,15 +503,25 @@ static void ar9002_hw_spectral_scan_conf
|
|
||||||
*/
|
|
||||||
count = param->count;
|
|
||||||
if (param->endless) {
|
|
||||||
- if (AR_SREV_9271(ah))
|
|
||||||
- count = 0;
|
|
||||||
- else
|
|
||||||
+ if (AR_SREV_9280(ah))
|
|
||||||
count = 0x80;
|
|
||||||
+ else
|
|
||||||
+ count = 0;
|
|
||||||
} else if (count & 0x80)
|
|
||||||
count = 0x7f;
|
|
||||||
+ else if (!count)
|
|
||||||
+ count = 1;
|
|
||||||
+
|
|
||||||
+ if (AR_SREV_9280(ah)) {
|
|
||||||
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
+ AR_PHY_SPECTRAL_SCAN_COUNT, count);
|
|
||||||
+ } else {
|
|
||||||
+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
+ AR_PHY_SPECTRAL_SCAN_COUNT_KIWI, count);
|
|
||||||
+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
+ AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
- AR_PHY_SPECTRAL_SCAN_COUNT, count);
|
|
||||||
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
AR_PHY_SPECTRAL_SCAN_PERIOD, param->period);
|
|
||||||
REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN,
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
|
|
||||||
@@ -177,8 +177,11 @@
|
|
||||||
#define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8
|
|
||||||
#define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/
|
|
||||||
#define AR_PHY_SPECTRAL_SCAN_COUNT_S 16
|
|
||||||
+#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI 0x0FFF0000 /* Number of reports, reg 68, bits 16-27*/
|
|
||||||
+#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI_S 16
|
|
||||||
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/
|
|
||||||
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/
|
|
||||||
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI 0x10000000 /* Short repeat, reg 68, bit 28*/
|
|
||||||
+#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT 0x40000000
|
|
||||||
|
|
||||||
#define AR_PHY_RX_DELAY 0x9914
|
|
||||||
#define AR_PHY_SEARCH_START_DELAY 0x9918
|
|
|
@ -1,57 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 11 Jul 2016 11:31:39 +0200
|
|
||||||
Subject: [PATCH] ath9k_hw: fix duplicate (and partially wrong) definition
|
|
||||||
of AR_CH0_THERM
|
|
||||||
|
|
||||||
AR_PHY_65NM_CH0_THERM and AR_CH0_THERM were supposed to refer to the
|
|
||||||
same register, however they had different SREV checks.
|
|
||||||
|
|
||||||
Remove the duplicate and use the checks. Since there were other SREV
|
|
||||||
checks present in the only place that uses this, this will probaby not
|
|
||||||
affect runtime behavior.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
|
|
||||||
@@ -689,13 +689,6 @@
|
|
||||||
#define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300)
|
|
||||||
#define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8)
|
|
||||||
|
|
||||||
-#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \
|
|
||||||
- ((AR_SREV_9485(ah) ? 0x1628c : 0x16294)))
|
|
||||||
-#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
|
|
||||||
-#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
|
|
||||||
-#define AR_CH0_THERM_XPASHORT2GND 0x4
|
|
||||||
-#define AR_CH0_THERM_XPASHORT2GND_S 2
|
|
||||||
-
|
|
||||||
#define AR_SWITCH_TABLE_COM_ALL (0xffff)
|
|
||||||
#define AR_SWITCH_TABLE_COM_ALL_S (0)
|
|
||||||
#define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff)
|
|
||||||
@@ -712,15 +705,17 @@
|
|
||||||
#define AR_SWITCH_TABLE_ALL (0xfff)
|
|
||||||
#define AR_SWITCH_TABLE_ALL_S (0)
|
|
||||||
|
|
||||||
-#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\
|
|
||||||
- ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c))
|
|
||||||
+#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\
|
|
||||||
+ ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c))
|
|
||||||
+#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
|
|
||||||
+#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
|
|
||||||
+#define AR_CH0_THERM_XPASHORT2GND 0x4
|
|
||||||
+#define AR_CH0_THERM_XPASHORT2GND_S 2
|
|
||||||
|
|
||||||
-#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000
|
|
||||||
-#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
|
|
||||||
-#define AR_PHY_65NM_CH0_THERM_START 0x20000000
|
|
||||||
-#define AR_PHY_65NM_CH0_THERM_START_S 29
|
|
||||||
-#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00
|
|
||||||
-#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8
|
|
||||||
+#define AR_CH0_THERM_LOCAL 0x80000000
|
|
||||||
+#define AR_CH0_THERM_START 0x20000000
|
|
||||||
+#define AR_CH0_THERM_SAR_ADC_OUT 0x0000ff00
|
|
||||||
+#define AR_CH0_THERM_SAR_ADC_OUT_S 8
|
|
||||||
|
|
||||||
#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \
|
|
||||||
(AR_SREV_9462(ah) ? 0x16290 : 0x16284))
|
|
|
@ -1,88 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 11 Jul 2016 11:34:47 +0200
|
|
||||||
Subject: [PATCH] ath9k_hw: simplify ar9003_hw_per_calibration
|
|
||||||
|
|
||||||
Reduce indentation, use a variable to save a few pointer dereferences
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
|
||||||
@@ -75,50 +75,49 @@ static bool ar9003_hw_per_calibration(st
|
|
||||||
struct ath9k_cal_list *currCal)
|
|
||||||
{
|
|
||||||
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
|
||||||
- /* Cal is assumed not done until explicitly set below */
|
|
||||||
- bool iscaldone = false;
|
|
||||||
+ const struct ath9k_percal_data *cur_caldata = currCal->calData;
|
|
||||||
|
|
||||||
/* Calibration in progress. */
|
|
||||||
if (currCal->calState == CAL_RUNNING) {
|
|
||||||
/* Check to see if it has finished. */
|
|
||||||
- if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {
|
|
||||||
- /*
|
|
||||||
- * Accumulate cal measures for active chains
|
|
||||||
- */
|
|
||||||
- currCal->calData->calCollect(ah);
|
|
||||||
- ah->cal_samples++;
|
|
||||||
+ if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)
|
|
||||||
+ return false;
|
|
||||||
|
|
||||||
- if (ah->cal_samples >=
|
|
||||||
- currCal->calData->calNumSamples) {
|
|
||||||
- unsigned int i, numChains = 0;
|
|
||||||
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
|
||||||
- if (rxchainmask & (1 << i))
|
|
||||||
- numChains++;
|
|
||||||
- }
|
|
||||||
+ /*
|
|
||||||
+ * Accumulate cal measures for active chains
|
|
||||||
+ */
|
|
||||||
+ cur_caldata->calCollect(ah);
|
|
||||||
+ ah->cal_samples++;
|
|
||||||
|
|
||||||
- /*
|
|
||||||
- * Process accumulated data
|
|
||||||
- */
|
|
||||||
- currCal->calData->calPostProc(ah, numChains);
|
|
||||||
+ if (ah->cal_samples >= cur_caldata->calNumSamples) {
|
|
||||||
+ unsigned int i, numChains = 0;
|
|
||||||
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
|
|
||||||
+ if (rxchainmask & (1 << i))
|
|
||||||
+ numChains++;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- /* Calibration has finished. */
|
|
||||||
- caldata->CalValid |= currCal->calData->calType;
|
|
||||||
- currCal->calState = CAL_DONE;
|
|
||||||
- iscaldone = true;
|
|
||||||
- } else {
|
|
||||||
+ /*
|
|
||||||
+ * Process accumulated data
|
|
||||||
+ */
|
|
||||||
+ cur_caldata->calPostProc(ah, numChains);
|
|
||||||
+
|
|
||||||
+ /* Calibration has finished. */
|
|
||||||
+ caldata->CalValid |= cur_caldata->calType;
|
|
||||||
+ currCal->calState = CAL_DONE;
|
|
||||||
+ return true;
|
|
||||||
+ } else {
|
|
||||||
/*
|
|
||||||
* Set-up collection of another sub-sample until we
|
|
||||||
* get desired number
|
|
||||||
*/
|
|
||||||
ar9003_hw_setup_calibration(ah, currCal);
|
|
||||||
- }
|
|
||||||
}
|
|
||||||
- } else if (!(caldata->CalValid & currCal->calData->calType)) {
|
|
||||||
+ } else if (!(caldata->CalValid & cur_caldata->calType)) {
|
|
||||||
/* If current cal is marked invalid in channel, kick it off */
|
|
||||||
ath9k_hw_reset_calibration(ah, currCal);
|
|
||||||
}
|
|
||||||
|
|
||||||
- return iscaldone;
|
|
||||||
+ return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
|
|
|
@ -1,94 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 11 Jul 2016 11:35:20 +0200
|
|
||||||
Subject: [PATCH] ath9k_hw: get rid of some duplicate code in calibration
|
|
||||||
init
|
|
||||||
|
|
||||||
Remove a misleading debug message as well
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
|
|
||||||
@@ -1373,6 +1373,26 @@ static void ar9003_hw_cl_cal_post_proc(s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void ar9003_hw_init_cal_common(struct ath_hw *ah)
|
|
||||||
+{
|
|
||||||
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
|
|
||||||
+
|
|
||||||
+ /* Initialize list pointers */
|
|
||||||
+ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
|
|
||||||
+
|
|
||||||
+ INIT_CAL(&ah->iq_caldata);
|
|
||||||
+ INSERT_CAL(ah, &ah->iq_caldata);
|
|
||||||
+
|
|
||||||
+ /* Initialize current pointer to first element in list */
|
|
||||||
+ ah->cal_list_curr = ah->cal_list;
|
|
||||||
+
|
|
||||||
+ if (ah->cal_list_curr)
|
|
||||||
+ ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
|
|
||||||
+
|
|
||||||
+ if (caldata)
|
|
||||||
+ caldata->CalValid = 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
|
|
||||||
struct ath9k_channel *chan)
|
|
||||||
{
|
|
||||||
@@ -1532,21 +1552,7 @@ skip_tx_iqcal:
|
|
||||||
/* Revert chainmask to runtime parameters */
|
|
||||||
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
|
|
||||||
|
|
||||||
- /* Initialize list pointers */
|
|
||||||
- ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
|
|
||||||
-
|
|
||||||
- INIT_CAL(&ah->iq_caldata);
|
|
||||||
- INSERT_CAL(ah, &ah->iq_caldata);
|
|
||||||
- ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
|
|
||||||
-
|
|
||||||
- /* Initialize current pointer to first element in list */
|
|
||||||
- ah->cal_list_curr = ah->cal_list;
|
|
||||||
-
|
|
||||||
- if (ah->cal_list_curr)
|
|
||||||
- ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
|
|
||||||
-
|
|
||||||
- if (caldata)
|
|
||||||
- caldata->CalValid = 0;
|
|
||||||
+ ar9003_hw_init_cal_common(ah);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -1577,8 +1583,6 @@ static bool do_ar9003_agc_cal(struct ath
|
|
||||||
static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
|
|
||||||
struct ath9k_channel *chan)
|
|
||||||
{
|
|
||||||
- struct ath_common *common = ath9k_hw_common(ah);
|
|
||||||
- struct ath9k_hw_cal_data *caldata = ah->caldata;
|
|
||||||
bool txiqcal_done = false;
|
|
||||||
bool status = true;
|
|
||||||
bool run_agc_cal = false, sep_iq_cal = false;
|
|
||||||
@@ -1676,21 +1680,7 @@ skip_tx_iqcal:
|
|
||||||
/* Revert chainmask to runtime parameters */
|
|
||||||
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
|
|
||||||
|
|
||||||
- /* Initialize list pointers */
|
|
||||||
- ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
|
|
||||||
-
|
|
||||||
- INIT_CAL(&ah->iq_caldata);
|
|
||||||
- INSERT_CAL(ah, &ah->iq_caldata);
|
|
||||||
- ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
|
|
||||||
-
|
|
||||||
- /* Initialize current pointer to first element in list */
|
|
||||||
- ah->cal_list_curr = ah->cal_list;
|
|
||||||
-
|
|
||||||
- if (ah->cal_list_curr)
|
|
||||||
- ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
|
|
||||||
-
|
|
||||||
- if (caldata)
|
|
||||||
- caldata->CalValid = 0;
|
|
||||||
+ ar9003_hw_init_cal_common(ah);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Mon, 11 Jul 2016 15:07:06 +0200
|
|
||||||
Subject: [PATCH] mac80211: fix check for buffered powersave frames with txq
|
|
||||||
|
|
||||||
The logic was inverted here, set the bit if frames are pending.
|
|
||||||
|
|
||||||
Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation")
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/mac80211/rx.c
|
|
||||||
+++ b/net/mac80211/rx.c
|
|
||||||
@@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info
|
|
||||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
|
||||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
|
||||||
|
|
||||||
- if (!txqi->tin.backlog_packets)
|
|
||||||
+ if (txqi->tin.backlog_packets)
|
|
||||||
set_bit(tid, &sta->txq_buffered_tids);
|
|
||||||
else
|
|
||||||
clear_bit(tid, &sta->txq_buffered_tids);
|
|
|
@ -1,36 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 17 Jul 2016 12:49:59 +0200
|
|
||||||
Subject: [PATCH] ath10k: fix rx status reporting for A-MSDU subframes
|
|
||||||
|
|
||||||
Patch by Nagarajan, Ashok Raj <arnagara@qti.qualcomm.com>
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
|
|
||||||
@@ -1525,7 +1525,7 @@ static void ath10k_htt_rx_h_filter(struc
|
|
||||||
static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|
||||||
{
|
|
||||||
struct ath10k *ar = htt->ar;
|
|
||||||
- static struct ieee80211_rx_status rx_status;
|
|
||||||
+ struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
|
||||||
struct sk_buff_head amsdu;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
@@ -1549,11 +1549,11 @@ static int ath10k_htt_rx_handle_amsdu(st
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
- ath10k_htt_rx_h_ppdu(ar, &amsdu, &rx_status, 0xffff);
|
|
||||||
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
|
||||||
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
|
|
||||||
- ath10k_htt_rx_h_filter(ar, &amsdu, &rx_status);
|
|
||||||
- ath10k_htt_rx_h_mpdu(ar, &amsdu, &rx_status);
|
|
||||||
- ath10k_htt_rx_h_deliver(ar, &amsdu, &rx_status);
|
|
||||||
+ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
|
||||||
+ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
|
|
||||||
+ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
From: Masashi Honma <masashi.honma@gmail.com>
|
|
||||||
Date: Wed, 13 Jul 2016 16:04:35 +0900
|
|
||||||
Subject: [PATCH] mac80211: End the MPSP even if EOSP frame was not received
|
|
||||||
|
|
||||||
The mesh STA sends QoS frame with EOSP (end of service period)
|
|
||||||
subfiled=1 to end the MPSP(mesh peer service period). Previously, if
|
|
||||||
the frame was not acked by peer, the mesh STA did not end the MPSP.
|
|
||||||
This patch ends the MPSP even if the QoS frame was no acked.
|
|
||||||
|
|
||||||
Signed-off-by: Masashi Honma <masashi.honma@gmail.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/mac80211/status.c
|
|
||||||
+++ b/net/mac80211/status.c
|
|
||||||
@@ -784,6 +784,13 @@ void ieee80211_tx_status(struct ieee8021
|
|
||||||
clear_sta_flag(sta, WLAN_STA_SP);
|
|
||||||
|
|
||||||
acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
|
|
||||||
+
|
|
||||||
+ /* mesh Peer Service Period support */
|
|
||||||
+ if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
|
|
||||||
+ ieee80211_is_data_qos(fc))
|
|
||||||
+ ieee80211_mpsp_trigger_process(
|
|
||||||
+ ieee80211_get_qos_ctl(hdr), sta, true, acked);
|
|
||||||
+
|
|
||||||
if (!acked && test_sta_flag(sta, WLAN_STA_PS_STA)) {
|
|
||||||
/*
|
|
||||||
* The STA is in power save mode, so assume
|
|
||||||
@@ -794,13 +801,6 @@ void ieee80211_tx_status(struct ieee8021
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* mesh Peer Service Period support */
|
|
||||||
- if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
|
|
||||||
- ieee80211_is_data_qos(fc))
|
|
||||||
- ieee80211_mpsp_trigger_process(
|
|
||||||
- ieee80211_get_qos_ctl(hdr),
|
|
||||||
- sta, true, acked);
|
|
||||||
-
|
|
||||||
if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) &&
|
|
||||||
(ieee80211_is_data(hdr->frame_control)) &&
|
|
||||||
(rates_idx != -1))
|
|
|
@ -1,642 +0,0 @@
|
||||||
From: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
|
|
||||||
Date: Thu, 21 Jul 2016 11:50:00 +0530
|
|
||||||
Subject: [PATCH] ath10k: implement NAPI support
|
|
||||||
|
|
||||||
Add NAPI support for rx and tx completion. NAPI poll is scheduled
|
|
||||||
from interrupt handler. The design is as below
|
|
||||||
|
|
||||||
- on interrupt
|
|
||||||
- schedule napi and mask interrupts
|
|
||||||
- on poll
|
|
||||||
- process all pipes (no actual Tx/Rx)
|
|
||||||
- process Rx within budget
|
|
||||||
- if quota exceeds budget reschedule napi poll by returning budget
|
|
||||||
- process Tx completions and update budget if necessary
|
|
||||||
- process Tx fetch indications (pull-push)
|
|
||||||
- push any other pending Tx (if possible)
|
|
||||||
- before resched or napi completion replenish htt rx ring buffer
|
|
||||||
- if work done < budget, complete napi poll and unmask interrupts
|
|
||||||
|
|
||||||
This change also get rid of two tasklets (intr_tq and txrx_compl_task).
|
|
||||||
|
|
||||||
Measured peak throughput with NAPI on IPQ4019 platform in controlled
|
|
||||||
environment. No noticeable reduction in throughput is seen and also
|
|
||||||
observed improvements in CPU usage. Approx. 15% CPU usage got reduced
|
|
||||||
in UDP uplink case.
|
|
||||||
|
|
||||||
DL: AP DUT Tx
|
|
||||||
UL: AP DUT Rx
|
|
||||||
|
|
||||||
IPQ4019 (avg. cpu usage %)
|
|
||||||
========
|
|
||||||
TOT +NAPI
|
|
||||||
=========== =============
|
|
||||||
TCP DL 644 Mbps (42%) 645 Mbps (36%)
|
|
||||||
TCP UL 673 Mbps (30%) 675 Mbps (26%)
|
|
||||||
UDP DL 682 Mbps (49%) 680 Mbps (49%)
|
|
||||||
UDP UL 720 Mbps (28%) 717 Mbps (11%)
|
|
||||||
|
|
||||||
Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/ahb.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
|
|
||||||
@@ -462,13 +462,13 @@ static void ath10k_ahb_halt_chip(struct
|
|
||||||
static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg)
|
|
||||||
{
|
|
||||||
struct ath10k *ar = arg;
|
|
||||||
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
||||||
|
|
||||||
if (!ath10k_pci_irq_pending(ar))
|
|
||||||
return IRQ_NONE;
|
|
||||||
|
|
||||||
ath10k_pci_disable_and_clear_legacy_irq(ar);
|
|
||||||
- tasklet_schedule(&ar_pci->intr_tq);
|
|
||||||
+ ath10k_pci_irq_msi_fw_mask(ar);
|
|
||||||
+ napi_schedule(&ar->napi);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
@@ -831,7 +831,7 @@ static int ath10k_ahb_probe(struct platf
|
|
||||||
goto err_resource_deinit;
|
|
||||||
}
|
|
||||||
|
|
||||||
- ath10k_pci_init_irq_tasklets(ar);
|
|
||||||
+ ath10k_pci_init_napi(ar);
|
|
||||||
|
|
||||||
ret = ath10k_ahb_request_irq_legacy(ar);
|
|
||||||
if (ret)
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/core.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/core.c
|
|
||||||
@@ -2226,6 +2226,8 @@ struct ath10k *ath10k_core_create(size_t
|
|
||||||
INIT_WORK(&ar->register_work, ath10k_core_register_work);
|
|
||||||
INIT_WORK(&ar->restart_work, ath10k_core_restart);
|
|
||||||
|
|
||||||
+ init_dummy_netdev(&ar->napi_dev);
|
|
||||||
+
|
|
||||||
ret = ath10k_debug_create(ar);
|
|
||||||
if (ret)
|
|
||||||
goto err_free_aux_wq;
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/core.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/core.h
|
|
||||||
@@ -65,6 +65,10 @@
|
|
||||||
#define ATH10K_KEEPALIVE_MAX_IDLE 3895
|
|
||||||
#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
|
|
||||||
|
|
||||||
+/* NAPI poll budget */
|
|
||||||
+#define ATH10K_NAPI_BUDGET 64
|
|
||||||
+#define ATH10K_NAPI_QUOTA_LIMIT 60
|
|
||||||
+
|
|
||||||
struct ath10k;
|
|
||||||
|
|
||||||
enum ath10k_bus {
|
|
||||||
@@ -933,6 +937,10 @@ struct ath10k {
|
|
||||||
struct ath10k_thermal thermal;
|
|
||||||
struct ath10k_wow wow;
|
|
||||||
|
|
||||||
+ /* NAPI */
|
|
||||||
+ struct net_device napi_dev;
|
|
||||||
+ struct napi_struct napi;
|
|
||||||
+
|
|
||||||
/* must be last */
|
|
||||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
|
||||||
};
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/htt.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/htt.h
|
|
||||||
@@ -1666,7 +1666,6 @@ struct ath10k_htt {
|
|
||||||
|
|
||||||
/* This is used to group tx/rx completions separately and process them
|
|
||||||
* in batches to reduce cache stalls */
|
|
||||||
- struct tasklet_struct txrx_compl_task;
|
|
||||||
struct sk_buff_head rx_compl_q;
|
|
||||||
struct sk_buff_head rx_in_ord_compl_q;
|
|
||||||
struct sk_buff_head tx_fetch_ind_q;
|
|
||||||
@@ -1799,5 +1798,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt
|
|
||||||
struct sk_buff *msdu);
|
|
||||||
void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
|
|
||||||
struct sk_buff *skb);
|
|
||||||
+int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
|
|
||||||
@@ -34,7 +34,6 @@
|
|
||||||
#define HTT_RX_RING_REFILL_RESCHED_MS 5
|
|
||||||
|
|
||||||
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
|
|
||||||
-static void ath10k_htt_txrx_compl_task(unsigned long ptr);
|
|
||||||
|
|
||||||
static struct sk_buff *
|
|
||||||
ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr)
|
|
||||||
@@ -226,7 +225,6 @@ int ath10k_htt_rx_ring_refill(struct ath
|
|
||||||
void ath10k_htt_rx_free(struct ath10k_htt *htt)
|
|
||||||
{
|
|
||||||
del_timer_sync(&htt->rx_ring.refill_retry_timer);
|
|
||||||
- tasklet_kill(&htt->txrx_compl_task);
|
|
||||||
|
|
||||||
skb_queue_purge(&htt->rx_compl_q);
|
|
||||||
skb_queue_purge(&htt->rx_in_ord_compl_q);
|
|
||||||
@@ -520,9 +518,6 @@ int ath10k_htt_rx_alloc(struct ath10k_ht
|
|
||||||
skb_queue_head_init(&htt->tx_fetch_ind_q);
|
|
||||||
atomic_set(&htt->num_mpdus_ready, 0);
|
|
||||||
|
|
||||||
- tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
|
|
||||||
- (unsigned long)htt);
|
|
||||||
-
|
|
||||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
|
|
||||||
htt->rx_ring.size, htt->rx_ring.fill_level);
|
|
||||||
return 0;
|
|
||||||
@@ -958,7 +953,7 @@ static void ath10k_process_rx(struct ath
|
|
||||||
trace_ath10k_rx_hdr(ar, skb->data, skb->len);
|
|
||||||
trace_ath10k_rx_payload(ar, skb->data, skb->len);
|
|
||||||
|
|
||||||
- ieee80211_rx(ar->hw, skb);
|
|
||||||
+ ieee80211_rx_napi(ar->hw, NULL, skb, &ar->napi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar,
|
|
||||||
@@ -1527,7 +1522,7 @@ static int ath10k_htt_rx_handle_amsdu(st
|
|
||||||
struct ath10k *ar = htt->ar;
|
|
||||||
struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
|
||||||
struct sk_buff_head amsdu;
|
|
||||||
- int ret;
|
|
||||||
+ int ret, num_msdus;
|
|
||||||
|
|
||||||
__skb_queue_head_init(&amsdu);
|
|
||||||
|
|
||||||
@@ -1549,13 +1544,14 @@ static int ath10k_htt_rx_handle_amsdu(st
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ num_msdus = skb_queue_len(&amsdu);
|
|
||||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
|
||||||
ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
|
|
||||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
|
||||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
|
|
||||||
ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
|
|
||||||
|
|
||||||
- return 0;
|
|
||||||
+ return num_msdus;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
|
|
||||||
@@ -1579,15 +1575,6 @@ static void ath10k_htt_rx_proc_rx_ind(st
|
|
||||||
mpdu_count += mpdu_ranges[i].mpdu_count;
|
|
||||||
|
|
||||||
atomic_add(mpdu_count, &htt->num_mpdus_ready);
|
|
||||||
-
|
|
||||||
- tasklet_schedule(&htt->txrx_compl_task);
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
-static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt)
|
|
||||||
-{
|
|
||||||
- atomic_inc(&htt->num_mpdus_ready);
|
|
||||||
-
|
|
||||||
- tasklet_schedule(&htt->txrx_compl_task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
|
|
||||||
@@ -1772,14 +1759,15 @@ static void ath10k_htt_rx_h_rx_offload_p
|
|
||||||
RX_FLAG_MMIC_STRIPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
|
||||||
- struct sk_buff_head *list)
|
|
||||||
+static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
|
|
||||||
+ struct sk_buff_head *list)
|
|
||||||
{
|
|
||||||
struct ath10k_htt *htt = &ar->htt;
|
|
||||||
struct ieee80211_rx_status *status = &htt->rx_status;
|
|
||||||
struct htt_rx_offload_msdu *rx;
|
|
||||||
struct sk_buff *msdu;
|
|
||||||
size_t offset;
|
|
||||||
+ int num_msdu = 0;
|
|
||||||
|
|
||||||
while ((msdu = __skb_dequeue(list))) {
|
|
||||||
/* Offloaded frames don't have Rx descriptor. Instead they have
|
|
||||||
@@ -1819,10 +1807,12 @@ static void ath10k_htt_rx_h_rx_offload(s
|
|
||||||
ath10k_htt_rx_h_rx_offload_prot(status, msdu);
|
|
||||||
ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id);
|
|
||||||
ath10k_process_rx(ar, status, msdu);
|
|
||||||
+ num_msdu++;
|
|
||||||
}
|
|
||||||
+ return num_msdu;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|
||||||
+static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct ath10k_htt *htt = &ar->htt;
|
|
||||||
struct htt_resp *resp = (void *)skb->data;
|
|
||||||
@@ -1835,12 +1825,12 @@ static void ath10k_htt_rx_in_ord_ind(str
|
|
||||||
u8 tid;
|
|
||||||
bool offload;
|
|
||||||
bool frag;
|
|
||||||
- int ret;
|
|
||||||
+ int ret, num_msdus = 0;
|
|
||||||
|
|
||||||
lockdep_assert_held(&htt->rx_ring.lock);
|
|
||||||
|
|
||||||
if (htt->rx_confused)
|
|
||||||
- return;
|
|
||||||
+ return -EIO;
|
|
||||||
|
|
||||||
skb_pull(skb, sizeof(resp->hdr));
|
|
||||||
skb_pull(skb, sizeof(resp->rx_in_ord_ind));
|
|
||||||
@@ -1859,7 +1849,7 @@ static void ath10k_htt_rx_in_ord_ind(str
|
|
||||||
|
|
||||||
if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) {
|
|
||||||
ath10k_warn(ar, "dropping invalid in order rx indication\n");
|
|
||||||
- return;
|
|
||||||
+ return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The event can deliver more than 1 A-MSDU. Each A-MSDU is later
|
|
||||||
@@ -1870,14 +1860,14 @@ static void ath10k_htt_rx_in_ord_ind(str
|
|
||||||
if (ret < 0) {
|
|
||||||
ath10k_warn(ar, "failed to pop paddr list: %d\n", ret);
|
|
||||||
htt->rx_confused = true;
|
|
||||||
- return;
|
|
||||||
+ return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Offloaded frames are very different and need to be handled
|
|
||||||
* separately.
|
|
||||||
*/
|
|
||||||
if (offload)
|
|
||||||
- ath10k_htt_rx_h_rx_offload(ar, &list);
|
|
||||||
+ num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list);
|
|
||||||
|
|
||||||
while (!skb_queue_empty(&list)) {
|
|
||||||
__skb_queue_head_init(&amsdu);
|
|
||||||
@@ -1890,6 +1880,7 @@ static void ath10k_htt_rx_in_ord_ind(str
|
|
||||||
* better to report something than nothing though. This
|
|
||||||
* should still give an idea about rx rate to the user.
|
|
||||||
*/
|
|
||||||
+ num_msdus += skb_queue_len(&amsdu);
|
|
||||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
|
|
||||||
ath10k_htt_rx_h_filter(ar, &amsdu, status);
|
|
||||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
|
|
||||||
@@ -1902,9 +1893,10 @@ static void ath10k_htt_rx_in_ord_ind(str
|
|
||||||
ath10k_warn(ar, "failed to extract amsdu: %d\n", ret);
|
|
||||||
htt->rx_confused = true;
|
|
||||||
__skb_queue_purge(&list);
|
|
||||||
- return;
|
|
||||||
+ return -EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ return num_msdus;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar,
|
|
||||||
@@ -2267,7 +2259,6 @@ bool ath10k_htt_t2h_msg_handler(struct a
|
|
||||||
}
|
|
||||||
case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
|
|
||||||
ath10k_htt_rx_tx_compl_ind(htt->ar, skb);
|
|
||||||
- tasklet_schedule(&htt->txrx_compl_task);
|
|
||||||
break;
|
|
||||||
case HTT_T2H_MSG_TYPE_SEC_IND: {
|
|
||||||
struct ath10k *ar = htt->ar;
|
|
||||||
@@ -2284,7 +2275,7 @@ bool ath10k_htt_t2h_msg_handler(struct a
|
|
||||||
case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
|
|
||||||
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
|
|
||||||
skb->data, skb->len);
|
|
||||||
- ath10k_htt_rx_frag_handler(htt);
|
|
||||||
+ atomic_inc(&htt->num_mpdus_ready);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HTT_T2H_MSG_TYPE_TEST:
|
|
||||||
@@ -2322,8 +2313,7 @@ bool ath10k_htt_t2h_msg_handler(struct a
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
|
|
||||||
- skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
|
|
||||||
- tasklet_schedule(&htt->txrx_compl_task);
|
|
||||||
+ __skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
|
|
||||||
@@ -2349,7 +2339,6 @@ bool ath10k_htt_t2h_msg_handler(struct a
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
skb_queue_tail(&htt->tx_fetch_ind_q, tx_fetch_ind);
|
|
||||||
- tasklet_schedule(&htt->txrx_compl_task);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM:
|
|
||||||
@@ -2378,27 +2367,77 @@ void ath10k_htt_rx_pktlog_completion_han
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
|
|
||||||
|
|
||||||
-static void ath10k_htt_txrx_compl_task(unsigned long ptr)
|
|
||||||
+int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget)
|
|
||||||
{
|
|
||||||
- struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
|
|
||||||
- struct ath10k *ar = htt->ar;
|
|
||||||
+ struct ath10k_htt *htt = &ar->htt;
|
|
||||||
struct htt_tx_done tx_done = {};
|
|
||||||
- struct sk_buff_head rx_ind_q;
|
|
||||||
struct sk_buff_head tx_ind_q;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
unsigned long flags;
|
|
||||||
- int num_mpdus;
|
|
||||||
+ int quota = 0, done, num_rx_msdus;
|
|
||||||
+ bool resched_napi = false;
|
|
||||||
|
|
||||||
- __skb_queue_head_init(&rx_ind_q);
|
|
||||||
__skb_queue_head_init(&tx_ind_q);
|
|
||||||
|
|
||||||
- spin_lock_irqsave(&htt->rx_in_ord_compl_q.lock, flags);
|
|
||||||
- skb_queue_splice_init(&htt->rx_in_ord_compl_q, &rx_ind_q);
|
|
||||||
- spin_unlock_irqrestore(&htt->rx_in_ord_compl_q.lock, flags);
|
|
||||||
+ /* Since in-ord-ind can deliver more than 1 A-MSDU in single event,
|
|
||||||
+ * process it first to utilize full available quota.
|
|
||||||
+ */
|
|
||||||
+ while (quota < budget) {
|
|
||||||
+ if (skb_queue_empty(&htt->rx_in_ord_compl_q))
|
|
||||||
+ break;
|
|
||||||
|
|
||||||
- spin_lock_irqsave(&htt->tx_fetch_ind_q.lock, flags);
|
|
||||||
- skb_queue_splice_init(&htt->tx_fetch_ind_q, &tx_ind_q);
|
|
||||||
- spin_unlock_irqrestore(&htt->tx_fetch_ind_q.lock, flags);
|
|
||||||
+ skb = __skb_dequeue(&htt->rx_in_ord_compl_q);
|
|
||||||
+ if (!skb) {
|
|
||||||
+ resched_napi = true;
|
|
||||||
+ goto exit;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ spin_lock_bh(&htt->rx_ring.lock);
|
|
||||||
+ num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb);
|
|
||||||
+ spin_unlock_bh(&htt->rx_ring.lock);
|
|
||||||
+ if (num_rx_msdus < 0) {
|
|
||||||
+ resched_napi = true;
|
|
||||||
+ goto exit;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ dev_kfree_skb_any(skb);
|
|
||||||
+ if (num_rx_msdus > 0)
|
|
||||||
+ quota += num_rx_msdus;
|
|
||||||
+
|
|
||||||
+ if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
|
|
||||||
+ !skb_queue_empty(&htt->rx_in_ord_compl_q)) {
|
|
||||||
+ resched_napi = true;
|
|
||||||
+ goto exit;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ while (quota < budget) {
|
|
||||||
+ /* no more data to receive */
|
|
||||||
+ if (!atomic_read(&htt->num_mpdus_ready))
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
+ num_rx_msdus = ath10k_htt_rx_handle_amsdu(htt);
|
|
||||||
+ if (num_rx_msdus < 0) {
|
|
||||||
+ resched_napi = true;
|
|
||||||
+ goto exit;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ quota += num_rx_msdus;
|
|
||||||
+ atomic_dec(&htt->num_mpdus_ready);
|
|
||||||
+ if ((quota > ATH10K_NAPI_QUOTA_LIMIT) &&
|
|
||||||
+ atomic_read(&htt->num_mpdus_ready)) {
|
|
||||||
+ resched_napi = true;
|
|
||||||
+ goto exit;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* From NAPI documentation:
|
|
||||||
+ * The napi poll() function may also process TX completions, in which
|
|
||||||
+ * case if it processes the entire TX ring then it should count that
|
|
||||||
+ * work as the rest of the budget.
|
|
||||||
+ */
|
|
||||||
+ if ((quota < budget) && !kfifo_is_empty(&htt->txdone_fifo))
|
|
||||||
+ quota = budget;
|
|
||||||
|
|
||||||
/* kfifo_get: called only within txrx_tasklet so it's neatly serialized.
|
|
||||||
* From kfifo_get() documentation:
|
|
||||||
@@ -2408,27 +2447,22 @@ static void ath10k_htt_txrx_compl_task(u
|
|
||||||
while (kfifo_get(&htt->txdone_fifo, &tx_done))
|
|
||||||
ath10k_txrx_tx_unref(htt, &tx_done);
|
|
||||||
|
|
||||||
+ spin_lock_irqsave(&htt->tx_fetch_ind_q.lock, flags);
|
|
||||||
+ skb_queue_splice_init(&htt->tx_fetch_ind_q, &tx_ind_q);
|
|
||||||
+ spin_unlock_irqrestore(&htt->tx_fetch_ind_q.lock, flags);
|
|
||||||
+
|
|
||||||
while ((skb = __skb_dequeue(&tx_ind_q))) {
|
|
||||||
ath10k_htt_rx_tx_fetch_ind(ar, skb);
|
|
||||||
dev_kfree_skb_any(skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
- num_mpdus = atomic_read(&htt->num_mpdus_ready);
|
|
||||||
-
|
|
||||||
- while (num_mpdus) {
|
|
||||||
- if (ath10k_htt_rx_handle_amsdu(htt))
|
|
||||||
- break;
|
|
||||||
-
|
|
||||||
- num_mpdus--;
|
|
||||||
- atomic_dec(&htt->num_mpdus_ready);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- while ((skb = __skb_dequeue(&rx_ind_q))) {
|
|
||||||
- spin_lock_bh(&htt->rx_ring.lock);
|
|
||||||
- ath10k_htt_rx_in_ord_ind(ar, skb);
|
|
||||||
- spin_unlock_bh(&htt->rx_ring.lock);
|
|
||||||
- dev_kfree_skb_any(skb);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
+exit:
|
|
||||||
ath10k_htt_rx_msdu_buff_replenish(htt);
|
|
||||||
+ /* In case of rx failure or more data to read, report budget
|
|
||||||
+ * to reschedule NAPI poll
|
|
||||||
+ */
|
|
||||||
+ done = resched_napi ? budget : quota;
|
|
||||||
+
|
|
||||||
+ return done;
|
|
||||||
}
|
|
||||||
+EXPORT_SYMBOL(ath10k_htt_txrx_compl_task);
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
|
|
||||||
@@ -388,8 +388,6 @@ void ath10k_htt_tx_free(struct ath10k_ht
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
|
|
||||||
- tasklet_kill(&htt->txrx_compl_task);
|
|
||||||
-
|
|
||||||
idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
|
|
||||||
idr_destroy(&htt->pending_tx);
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/pci.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/pci.c
|
|
||||||
@@ -1502,12 +1502,10 @@ void ath10k_pci_hif_send_complete_check(
|
|
||||||
ath10k_ce_per_engine_service(ar, pipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
-void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
|
||||||
+static void ath10k_pci_rx_retry_sync(struct ath10k *ar)
|
|
||||||
{
|
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
||||||
|
|
||||||
- tasklet_kill(&ar_pci->intr_tq);
|
|
||||||
-
|
|
||||||
del_timer_sync(&ar_pci->rx_post_retry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1566,7 +1564,7 @@ void ath10k_pci_hif_get_default_pipe(str
|
|
||||||
ul_pipe, dl_pipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
|
|
||||||
+void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
|
|
||||||
{
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
@@ -1747,7 +1745,7 @@ void ath10k_pci_ce_deinit(struct ath10k
|
|
||||||
|
|
||||||
void ath10k_pci_flush(struct ath10k *ar)
|
|
||||||
{
|
|
||||||
- ath10k_pci_kill_tasklet(ar);
|
|
||||||
+ ath10k_pci_rx_retry_sync(ar);
|
|
||||||
ath10k_pci_buffer_cleanup(ar);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2754,35 +2752,53 @@ static irqreturn_t ath10k_pci_interrupt_
|
|
||||||
return IRQ_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) {
|
|
||||||
- if (!ath10k_pci_irq_pending(ar))
|
|
||||||
- return IRQ_NONE;
|
|
||||||
-
|
|
||||||
- ath10k_pci_disable_and_clear_legacy_irq(ar);
|
|
||||||
- }
|
|
||||||
+ if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) &&
|
|
||||||
+ !ath10k_pci_irq_pending(ar))
|
|
||||||
+ return IRQ_NONE;
|
|
||||||
|
|
||||||
- tasklet_schedule(&ar_pci->intr_tq);
|
|
||||||
+ ath10k_pci_disable_and_clear_legacy_irq(ar);
|
|
||||||
+ ath10k_pci_irq_msi_fw_mask(ar);
|
|
||||||
+ napi_schedule(&ar->napi);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static void ath10k_pci_tasklet(unsigned long data)
|
|
||||||
+static int ath10k_pci_napi_poll(struct napi_struct *ctx, int budget)
|
|
||||||
{
|
|
||||||
- struct ath10k *ar = (struct ath10k *)data;
|
|
||||||
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
||||||
+ struct ath10k *ar = container_of(ctx, struct ath10k, napi);
|
|
||||||
+ int done = 0;
|
|
||||||
|
|
||||||
if (ath10k_pci_has_fw_crashed(ar)) {
|
|
||||||
- ath10k_pci_irq_disable(ar);
|
|
||||||
ath10k_pci_fw_crashed_clear(ar);
|
|
||||||
ath10k_pci_fw_crashed_dump(ar);
|
|
||||||
- return;
|
|
||||||
+ napi_complete(ctx);
|
|
||||||
+ return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
ath10k_ce_per_engine_service_any(ar);
|
|
||||||
|
|
||||||
- /* Re-enable legacy irq that was disabled in the irq handler */
|
|
||||||
- if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
|
|
||||||
+ done = ath10k_htt_txrx_compl_task(ar, budget);
|
|
||||||
+
|
|
||||||
+ if (done < budget) {
|
|
||||||
+ napi_complete(ctx);
|
|
||||||
+ /* In case of MSI, it is possible that interrupts are received
|
|
||||||
+ * while NAPI poll is inprogress. So pending interrupts that are
|
|
||||||
+ * received after processing all copy engine pipes by NAPI poll
|
|
||||||
+ * will not be handled again. This is causing failure to
|
|
||||||
+ * complete boot sequence in x86 platform. So before enabling
|
|
||||||
+ * interrupts safer to check for pending interrupts for
|
|
||||||
+ * immediate servicing.
|
|
||||||
+ */
|
|
||||||
+ if (CE_INTERRUPT_SUMMARY(ar)) {
|
|
||||||
+ napi_reschedule(&ar->napi);
|
|
||||||
+ goto out;
|
|
||||||
+ }
|
|
||||||
ath10k_pci_enable_legacy_irq(ar);
|
|
||||||
+ ath10k_pci_irq_msi_fw_unmask(ar);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+out:
|
|
||||||
+ return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ath10k_pci_request_irq_msi(struct ath10k *ar)
|
|
||||||
@@ -2840,11 +2856,11 @@ static void ath10k_pci_free_irq(struct a
|
|
||||||
free_irq(ar_pci->pdev->irq, ar);
|
|
||||||
}
|
|
||||||
|
|
||||||
-void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
|
|
||||||
+void ath10k_pci_init_napi(struct ath10k *ar)
|
|
||||||
{
|
|
||||||
- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
||||||
-
|
|
||||||
- tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
|
|
||||||
+ netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_pci_napi_poll,
|
|
||||||
+ ATH10K_NAPI_BUDGET);
|
|
||||||
+ napi_enable(&ar->napi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ath10k_pci_init_irq(struct ath10k *ar)
|
|
||||||
@@ -2852,7 +2868,7 @@ static int ath10k_pci_init_irq(struct at
|
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
- ath10k_pci_init_irq_tasklets(ar);
|
|
||||||
+ ath10k_pci_init_napi(ar);
|
|
||||||
|
|
||||||
if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO)
|
|
||||||
ath10k_info(ar, "limiting irq mode to: %d\n",
|
|
||||||
@@ -3113,7 +3129,8 @@ int ath10k_pci_setup_resource(struct ath
|
|
||||||
|
|
||||||
void ath10k_pci_release_resource(struct ath10k *ar)
|
|
||||||
{
|
|
||||||
- ath10k_pci_kill_tasklet(ar);
|
|
||||||
+ ath10k_pci_rx_retry_sync(ar);
|
|
||||||
+ netif_napi_del(&ar->napi);
|
|
||||||
ath10k_pci_ce_deinit(ar);
|
|
||||||
ath10k_pci_free_pipes(ar);
|
|
||||||
}
|
|
||||||
@@ -3274,7 +3291,7 @@ static int ath10k_pci_probe(struct pci_d
|
|
||||||
|
|
||||||
err_free_irq:
|
|
||||||
ath10k_pci_free_irq(ar);
|
|
||||||
- ath10k_pci_kill_tasklet(ar);
|
|
||||||
+ ath10k_pci_rx_retry_sync(ar);
|
|
||||||
|
|
||||||
err_deinit_irq:
|
|
||||||
ath10k_pci_deinit_irq(ar);
|
|
||||||
--- a/drivers/net/wireless/ath/ath10k/pci.h
|
|
||||||
+++ b/drivers/net/wireless/ath/ath10k/pci.h
|
|
||||||
@@ -177,8 +177,6 @@ struct ath10k_pci {
|
|
||||||
/* Operating interrupt mode */
|
|
||||||
enum ath10k_pci_irq_mode oper_irq_mode;
|
|
||||||
|
|
||||||
- struct tasklet_struct intr_tq;
|
|
||||||
-
|
|
||||||
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
|
|
||||||
|
|
||||||
/* Copy Engine used for Diagnostic Accesses */
|
|
||||||
@@ -294,8 +292,7 @@ void ath10k_pci_free_pipes(struct ath10k
|
|
||||||
void ath10k_pci_free_pipes(struct ath10k *ar);
|
|
||||||
void ath10k_pci_rx_replenish_retry(unsigned long ptr);
|
|
||||||
void ath10k_pci_ce_deinit(struct ath10k *ar);
|
|
||||||
-void ath10k_pci_init_irq_tasklets(struct ath10k *ar);
|
|
||||||
-void ath10k_pci_kill_tasklet(struct ath10k *ar);
|
|
||||||
+void ath10k_pci_init_napi(struct ath10k *ar);
|
|
||||||
int ath10k_pci_init_pipes(struct ath10k *ar);
|
|
||||||
int ath10k_pci_init_config(struct ath10k *ar);
|
|
||||||
void ath10k_pci_rx_post(struct ath10k *ar);
|
|
||||||
@@ -303,6 +300,7 @@ void ath10k_pci_flush(struct ath10k *ar)
|
|
||||||
void ath10k_pci_enable_legacy_irq(struct ath10k *ar);
|
|
||||||
bool ath10k_pci_irq_pending(struct ath10k *ar);
|
|
||||||
void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar);
|
|
||||||
+void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar);
|
|
||||||
int ath10k_pci_wait_for_target_init(struct ath10k *ar);
|
|
||||||
int ath10k_pci_setup_resource(struct ath10k *ar);
|
|
||||||
void ath10k_pci_release_resource(struct ath10k *ar);
|
|
|
@ -1,69 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Tue, 26 Jul 2016 08:05:10 +0200
|
|
||||||
Subject: [PATCH] ath9k: fix client mode beacon configuration
|
|
||||||
|
|
||||||
For pure station mode, iter_data.primary_beacon_vif was used and passed
|
|
||||||
to ath_beacon_config, but not set to the station vif.
|
|
||||||
This was causing the following warning:
|
|
||||||
|
|
||||||
[ 100.310919] ------------[ cut here ]------------
|
|
||||||
[ 100.315683] WARNING: CPU: 0 PID: 7 at compat-wireless-2016-06-20/drivers/net/wireless/ath/ath9k/beacon.c:642 ath9k_calculate_summary_state+0x250/0x60c [ath9k]()
|
|
||||||
[ 100.402028] CPU: 0 PID: 7 Comm: kworker/u2:1 Tainted: G W 4.4.15 #5
|
|
||||||
[ 100.409676] Workqueue: phy0 ieee80211_ibss_leave [mac80211]
|
|
||||||
[ 100.415351] Stack : 8736e98c 870b4b20 87a25b54 800a6800 8782a080 80400d63 8039b96c 00000007
|
|
||||||
[ 100.415351] 803c5edc 87875914 80400000 800a47cc 87a25b54 800a6800 803a0fd8 80400000
|
|
||||||
[ 100.415351] 00000003 87875914 80400000 80094ae0 87a25b54 8787594c 00000000 801ef308
|
|
||||||
[ 100.415351] 803ffe70 801ef300 87193d58 87b3a400 87b3ad00 70687930 00000000 00000000
|
|
||||||
[ 100.415351] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
|
||||||
[ 100.415351] ...
|
|
||||||
[ 100.451703] Call Trace:
|
|
||||||
[ 100.454235] [<800a6800>] vprintk_default+0x24/0x30
|
|
||||||
[ 100.459110] [<800a47cc>] printk+0x2c/0x38
|
|
||||||
[ 100.463190] [<800a6800>] vprintk_default+0x24/0x30
|
|
||||||
[ 100.468072] [<80094ae0>] print_worker_info+0x148/0x174
|
|
||||||
[ 100.473378] [<801ef308>] serial8250_console_putchar+0x0/0x44
|
|
||||||
[ 100.479122] [<801ef300>] wait_for_xmitr+0xc4/0xcc
|
|
||||||
[ 100.484014] [<87193d58>] ieee80211_ibss_leave+0xb90/0x1900 [mac80211]
|
|
||||||
[ 100.490590] [<80081604>] warn_slowpath_common+0xa0/0xd0
|
|
||||||
[ 100.495922] [<801a359c>] dump_stack+0x14/0x28
|
|
||||||
[ 100.500350] [<80071a00>] show_stack+0x50/0x84
|
|
||||||
[ 100.504784] [<80081604>] warn_slowpath_common+0xa0/0xd0
|
|
||||||
[ 100.510106] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k]
|
|
||||||
[ 100.517105] [<800816b8>] warn_slowpath_null+0x18/0x24
|
|
||||||
[ 100.522256] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k]
|
|
||||||
[ 100.529273] [<87025418>] ath9k_set_txpower+0x148/0x498 [ath9k]
|
|
||||||
[ 100.535302] [<871d2c64>] cleanup_module+0xa74/0xd4c [mac80211]
|
|
||||||
[ 100.541237] [<801ef308>] serial8250_console_putchar+0x0/0x44
|
|
||||||
[ 100.547042] [<800a5d18>] wake_up_klogd+0x54/0x68
|
|
||||||
[ 100.551730] [<800a6650>] vprintk_emit+0x404/0x43c
|
|
||||||
[ 100.556623] [<871b9db8>] ieee80211_sta_rx_notify+0x258/0x32c [mac80211]
|
|
||||||
[ 100.563475] [<871ba6a4>] ieee80211_sta_rx_queued_mgmt+0x63c/0x734 [mac80211]
|
|
||||||
[ 100.570693] [<871aa49c>] ieee80211_tx_prepare_skb+0x210/0x230 [mac80211]
|
|
||||||
[ 100.577609] [<800af5d4>] mod_timer+0x15c/0x190
|
|
||||||
[ 100.582220] [<871ba8b8>] ieee80211_sta_work+0xfc/0xe1c [mac80211]
|
|
||||||
[ 100.588539] [<871940b4>] ieee80211_ibss_leave+0xeec/0x1900 [mac80211]
|
|
||||||
[ 100.595122] [<8009ec84>] dequeue_task_fair+0x44/0x130
|
|
||||||
[ 100.600281] [<80092a34>] process_one_work+0x1f8/0x334
|
|
||||||
[ 100.605454] [<80093830>] worker_thread+0x2b4/0x408
|
|
||||||
[ 100.610317] [<8009357c>] worker_thread+0x0/0x408
|
|
||||||
[ 100.615019] [<8009357c>] worker_thread+0x0/0x408
|
|
||||||
[ 100.619705] [<80097b68>] kthread+0xdc/0xe8
|
|
||||||
[ 100.623886] [<80097a8c>] kthread+0x0/0xe8
|
|
||||||
[ 100.627961] [<80060878>] ret_from_kernel_thread+0x14/0x1c
|
|
||||||
[ 100.633448]
|
|
||||||
[ 100.634956] ---[ end trace aafbe57e9ae6862f ]---
|
|
||||||
|
|
||||||
Fixes: cfda2d8e2314 ("ath9k: Fix beacon configuration for addition/removal of interfaces")
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
|
||||||
@@ -1154,6 +1154,7 @@ void ath9k_calculate_summary_state(struc
|
|
||||||
bool changed = (iter_data.primary_sta != ctx->primary_sta);
|
|
||||||
|
|
||||||
if (iter_data.primary_sta) {
|
|
||||||
+ iter_data.primary_beacon_vif = iter_data.primary_sta;
|
|
||||||
iter_data.beacons = true;
|
|
||||||
ath9k_set_assoc_state(sc, iter_data.primary_sta,
|
|
||||||
changed);
|
|
|
@ -1,54 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Tue, 2 Aug 2016 11:11:13 +0200
|
|
||||||
Subject: [PATCH] mac80211: fix purging multicast PS buffer queue
|
|
||||||
|
|
||||||
The code currently assumes that buffered multicast PS frames don't have
|
|
||||||
a pending ACK frame for tx status reporting.
|
|
||||||
However, hostapd sends a broadcast deauth frame on teardown for which tx
|
|
||||||
status is requested. This can lead to the "Have pending ack frames"
|
|
||||||
warning on module reload.
|
|
||||||
Fix this by using ieee80211_free_txskb/ieee80211_purge_tx_queue.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/mac80211/cfg.c
|
|
||||||
+++ b/net/mac80211/cfg.c
|
|
||||||
@@ -868,7 +868,7 @@ static int ieee80211_stop_ap(struct wiph
|
|
||||||
|
|
||||||
/* free all potentially still buffered bcast frames */
|
|
||||||
local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
|
|
||||||
- skb_queue_purge(&sdata->u.ap.ps.bc_buf);
|
|
||||||
+ ieee80211_purge_tx_queue(&local->hw, &sdata->u.ap.ps.bc_buf);
|
|
||||||
|
|
||||||
mutex_lock(&local->mtx);
|
|
||||||
ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
|
|
||||||
--- a/net/mac80211/tx.c
|
|
||||||
+++ b/net/mac80211/tx.c
|
|
||||||
@@ -368,7 +368,7 @@ static void purge_old_ps_buffers(struct
|
|
||||||
skb = skb_dequeue(&ps->bc_buf);
|
|
||||||
if (skb) {
|
|
||||||
purged++;
|
|
||||||
- dev_kfree_skb(skb);
|
|
||||||
+ ieee80211_free_txskb(&local->hw, skb);
|
|
||||||
}
|
|
||||||
total += skb_queue_len(&ps->bc_buf);
|
|
||||||
}
|
|
||||||
@@ -451,7 +451,7 @@ ieee80211_tx_h_multicast_ps_buf(struct i
|
|
||||||
if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) {
|
|
||||||
ps_dbg(tx->sdata,
|
|
||||||
"BC TX buffer full - dropping the oldest frame\n");
|
|
||||||
- dev_kfree_skb(skb_dequeue(&ps->bc_buf));
|
|
||||||
+ ieee80211_free_txskb(&tx->local->hw, skb_dequeue(&ps->bc_buf));
|
|
||||||
} else
|
|
||||||
tx->local->total_ps_buffered++;
|
|
||||||
|
|
||||||
@@ -4276,7 +4276,7 @@ ieee80211_get_buffered_bc(struct ieee802
|
|
||||||
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
|
|
||||||
if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
|
|
||||||
break;
|
|
||||||
- dev_kfree_skb_any(skb);
|
|
||||||
+ ieee80211_free_txskb(hw, skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
info = IEEE80211_SKB_CB(skb);
|
|
|
@ -1,305 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Tue, 2 Aug 2016 12:12:18 +0200
|
|
||||||
Subject: [PATCH] ath9k: use ieee80211_tx_status_noskb where possible
|
|
||||||
|
|
||||||
It removes the need for undoing the padding changes to skb->data and it
|
|
||||||
improves performance by eliminating one tx status lookup per MPDU in the
|
|
||||||
status path. It is also useful for preparing a follow-up fix to better
|
|
||||||
handle powersave filtering.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
|
||||||
@@ -50,9 +50,11 @@ static u16 bits_per_symbol[][2] = {
|
|
||||||
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
|
|
||||||
struct ath_atx_tid *tid, struct sk_buff *skb);
|
|
||||||
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|
||||||
- int tx_flags, struct ath_txq *txq);
|
|
||||||
+ int tx_flags, struct ath_txq *txq,
|
|
||||||
+ struct ieee80211_sta *sta);
|
|
||||||
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
|
||||||
struct ath_txq *txq, struct list_head *bf_q,
|
|
||||||
+ struct ieee80211_sta *sta,
|
|
||||||
struct ath_tx_status *ts, int txok);
|
|
||||||
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
|
|
||||||
struct list_head *head, bool internal);
|
|
||||||
@@ -77,6 +79,22 @@ enum {
|
|
||||||
/* Aggregation logic */
|
|
||||||
/*********************/
|
|
||||||
|
|
||||||
+static void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|
||||||
+{
|
|
||||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
+ struct ieee80211_sta *sta = info->status.status_driver_data[0];
|
|
||||||
+
|
|
||||||
+ if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
|
|
||||||
+ ieee80211_tx_status(hw, skb);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (sta)
|
|
||||||
+ ieee80211_tx_status_noskb(hw, sta, info);
|
|
||||||
+
|
|
||||||
+ dev_kfree_skb(skb);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
|
|
||||||
__acquires(&txq->axq_lock)
|
|
||||||
{
|
|
||||||
@@ -92,6 +110,7 @@ void ath_txq_unlock(struct ath_softc *sc
|
|
||||||
void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
|
|
||||||
__releases(&txq->axq_lock)
|
|
||||||
{
|
|
||||||
+ struct ieee80211_hw *hw = sc->hw;
|
|
||||||
struct sk_buff_head q;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
|
|
||||||
@@ -100,7 +119,7 @@ void ath_txq_unlock_complete(struct ath_
|
|
||||||
spin_unlock_bh(&txq->axq_lock);
|
|
||||||
|
|
||||||
while ((skb = __skb_dequeue(&q)))
|
|
||||||
- ieee80211_tx_status(sc->hw, skb);
|
|
||||||
+ ath_tx_status(hw, skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
|
|
||||||
@@ -268,7 +287,7 @@ static void ath_tx_flush_tid(struct ath_
|
|
||||||
}
|
|
||||||
|
|
||||||
list_add_tail(&bf->list, &bf_head);
|
|
||||||
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
|
|
||||||
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sendbar) {
|
|
||||||
@@ -333,12 +352,12 @@ static void ath_tid_drain(struct ath_sof
|
|
||||||
bf = fi->bf;
|
|
||||||
|
|
||||||
if (!bf) {
|
|
||||||
- ath_tx_complete(sc, skb, ATH_TX_ERROR, txq);
|
|
||||||
+ ath_tx_complete(sc, skb, ATH_TX_ERROR, txq, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_add_tail(&bf->list, &bf_head);
|
|
||||||
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
|
|
||||||
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -441,12 +460,11 @@ static void ath_tx_count_frames(struct a
|
|
||||||
|
|
||||||
static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|
||||||
struct ath_buf *bf, struct list_head *bf_q,
|
|
||||||
+ struct ieee80211_sta *sta,
|
|
||||||
struct ath_tx_status *ts, int txok)
|
|
||||||
{
|
|
||||||
struct ath_node *an = NULL;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
- struct ieee80211_sta *sta;
|
|
||||||
- struct ieee80211_hw *hw = sc->hw;
|
|
||||||
struct ieee80211_hdr *hdr;
|
|
||||||
struct ieee80211_tx_info *tx_info;
|
|
||||||
struct ath_atx_tid *tid = NULL;
|
|
||||||
@@ -475,12 +493,7 @@ static void ath_tx_complete_aggr(struct
|
|
||||||
for (i = 0; i < ts->ts_rateindex; i++)
|
|
||||||
retries += rates[i].count;
|
|
||||||
|
|
||||||
- rcu_read_lock();
|
|
||||||
-
|
|
||||||
- sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
|
|
||||||
if (!sta) {
|
|
||||||
- rcu_read_unlock();
|
|
||||||
-
|
|
||||||
INIT_LIST_HEAD(&bf_head);
|
|
||||||
while (bf) {
|
|
||||||
bf_next = bf->bf_next;
|
|
||||||
@@ -488,7 +501,7 @@ static void ath_tx_complete_aggr(struct
|
|
||||||
if (!bf->bf_state.stale || bf_next != NULL)
|
|
||||||
list_move_tail(&bf->list, &bf_head);
|
|
||||||
|
|
||||||
- ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0);
|
|
||||||
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, ts, 0);
|
|
||||||
|
|
||||||
bf = bf_next;
|
|
||||||
}
|
|
||||||
@@ -598,7 +611,7 @@ static void ath_tx_complete_aggr(struct
|
|
||||||
ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
- ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
|
|
||||||
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts,
|
|
||||||
!txfail);
|
|
||||||
} else {
|
|
||||||
if (tx_info->flags & IEEE80211_TX_STATUS_EOSP) {
|
|
||||||
@@ -619,7 +632,8 @@ static void ath_tx_complete_aggr(struct
|
|
||||||
ath_tx_update_baw(sc, tid, seqno);
|
|
||||||
|
|
||||||
ath_tx_complete_buf(sc, bf, txq,
|
|
||||||
- &bf_head, ts, 0);
|
|
||||||
+ &bf_head, NULL, ts,
|
|
||||||
+ 0);
|
|
||||||
bar_index = max_t(int, bar_index,
|
|
||||||
ATH_BA_INDEX(seq_first, seqno));
|
|
||||||
break;
|
|
||||||
@@ -663,8 +677,6 @@ static void ath_tx_complete_aggr(struct
|
|
||||||
ath_txq_lock(sc, txq);
|
|
||||||
}
|
|
||||||
|
|
||||||
- rcu_read_unlock();
|
|
||||||
-
|
|
||||||
if (needreset)
|
|
||||||
ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR);
|
|
||||||
}
|
|
||||||
@@ -679,7 +691,10 @@ static void ath_tx_process_buffer(struct
|
|
||||||
struct ath_tx_status *ts, struct ath_buf *bf,
|
|
||||||
struct list_head *bf_head)
|
|
||||||
{
|
|
||||||
+ struct ieee80211_hw *hw = sc->hw;
|
|
||||||
struct ieee80211_tx_info *info;
|
|
||||||
+ struct ieee80211_sta *sta;
|
|
||||||
+ struct ieee80211_hdr *hdr;
|
|
||||||
bool txok, flush;
|
|
||||||
|
|
||||||
txok = !(ts->ts_status & ATH9K_TXERR_MASK);
|
|
||||||
@@ -692,6 +707,10 @@ static void ath_tx_process_buffer(struct
|
|
||||||
|
|
||||||
ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc,
|
|
||||||
ts->ts_rateindex);
|
|
||||||
+
|
|
||||||
+ hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
|
|
||||||
+ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
|
|
||||||
+
|
|
||||||
if (!bf_isampdu(bf)) {
|
|
||||||
if (!flush) {
|
|
||||||
info = IEEE80211_SKB_CB(bf->bf_mpdu);
|
|
||||||
@@ -700,9 +719,9 @@ static void ath_tx_process_buffer(struct
|
|
||||||
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
|
|
||||||
ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts);
|
|
||||||
}
|
|
||||||
- ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
|
|
||||||
+ ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok);
|
|
||||||
} else
|
|
||||||
- ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
|
|
||||||
+ ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, ts, txok);
|
|
||||||
|
|
||||||
if (!flush)
|
|
||||||
ath_txq_schedule(sc, txq);
|
|
||||||
@@ -938,7 +957,7 @@ ath_tx_get_tid_subframe(struct ath_softc
|
|
||||||
list_add(&bf->list, &bf_head);
|
|
||||||
__skb_unlink(skb, *q);
|
|
||||||
ath_tx_update_baw(sc, tid, seqno);
|
|
||||||
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
|
|
||||||
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1847,6 +1866,7 @@ static void ath_drain_txq_list(struct at
|
|
||||||
*/
|
|
||||||
void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq)
|
|
||||||
{
|
|
||||||
+ rcu_read_lock();
|
|
||||||
ath_txq_lock(sc, txq);
|
|
||||||
|
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
|
||||||
@@ -1865,6 +1885,7 @@ void ath_draintxq(struct ath_softc *sc,
|
|
||||||
ath_drain_txq_list(sc, txq, &txq->axq_q);
|
|
||||||
|
|
||||||
ath_txq_unlock_complete(sc, txq);
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ath_drain_all_txq(struct ath_softc *sc)
|
|
||||||
@@ -2487,7 +2508,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw
|
|
||||||
/*****************/
|
|
||||||
|
|
||||||
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
|
||||||
- int tx_flags, struct ath_txq *txq)
|
|
||||||
+ int tx_flags, struct ath_txq *txq,
|
|
||||||
+ struct ieee80211_sta *sta)
|
|
||||||
{
|
|
||||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
|
||||||
@@ -2507,15 +2529,17 @@ static void ath_tx_complete(struct ath_s
|
|
||||||
tx_info->flags |= IEEE80211_TX_STAT_ACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
- padpos = ieee80211_hdrlen(hdr->frame_control);
|
|
||||||
- padsize = padpos & 3;
|
|
||||||
- if (padsize && skb->len>padpos+padsize) {
|
|
||||||
- /*
|
|
||||||
- * Remove MAC header padding before giving the frame back to
|
|
||||||
- * mac80211.
|
|
||||||
- */
|
|
||||||
- memmove(skb->data + padsize, skb->data, padpos);
|
|
||||||
- skb_pull(skb, padsize);
|
|
||||||
+ if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
|
|
||||||
+ padpos = ieee80211_hdrlen(hdr->frame_control);
|
|
||||||
+ padsize = padpos & 3;
|
|
||||||
+ if (padsize && skb->len>padpos+padsize) {
|
|
||||||
+ /*
|
|
||||||
+ * Remove MAC header padding before giving the frame back to
|
|
||||||
+ * mac80211.
|
|
||||||
+ */
|
|
||||||
+ memmove(skb->data + padsize, skb->data, padpos);
|
|
||||||
+ skb_pull(skb, padsize);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&sc->sc_pm_lock, flags);
|
|
||||||
@@ -2530,12 +2554,14 @@ static void ath_tx_complete(struct ath_s
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
|
||||||
|
|
||||||
- __skb_queue_tail(&txq->complete_q, skb);
|
|
||||||
ath_txq_skb_done(sc, txq, skb);
|
|
||||||
+ tx_info->status.status_driver_data[0] = sta;
|
|
||||||
+ __skb_queue_tail(&txq->complete_q, skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
|
||||||
struct ath_txq *txq, struct list_head *bf_q,
|
|
||||||
+ struct ieee80211_sta *sta,
|
|
||||||
struct ath_tx_status *ts, int txok)
|
|
||||||
{
|
|
||||||
struct sk_buff *skb = bf->bf_mpdu;
|
|
||||||
@@ -2563,7 +2589,7 @@ static void ath_tx_complete_buf(struct a
|
|
||||||
complete(&sc->paprd_complete);
|
|
||||||
} else {
|
|
||||||
ath_debug_stat_tx(sc, bf, ts, txq, tx_flags);
|
|
||||||
- ath_tx_complete(sc, skb, tx_flags, txq);
|
|
||||||
+ ath_tx_complete(sc, skb, tx_flags, txq, sta);
|
|
||||||
}
|
|
||||||
skip_tx_complete:
|
|
||||||
/* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
|
|
||||||
@@ -2715,10 +2741,12 @@ void ath_tx_tasklet(struct ath_softc *sc
|
|
||||||
u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
+ rcu_read_lock();
|
|
||||||
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
|
|
||||||
if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
|
|
||||||
ath_tx_processq(sc, &sc->tx.txq[i]);
|
|
||||||
}
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ath_tx_edma_tasklet(struct ath_softc *sc)
|
|
||||||
@@ -2732,6 +2760,7 @@ void ath_tx_edma_tasklet(struct ath_soft
|
|
||||||
struct list_head *fifo_list;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
+ rcu_read_lock();
|
|
||||||
for (;;) {
|
|
||||||
if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
|
|
||||||
break;
|
|
||||||
@@ -2802,6 +2831,7 @@ void ath_tx_edma_tasklet(struct ath_soft
|
|
||||||
ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
|
|
||||||
ath_txq_unlock_complete(sc, txq);
|
|
||||||
}
|
|
||||||
+ rcu_read_unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************/
|
|
|
@ -1,70 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Tue, 2 Aug 2016 12:13:35 +0200
|
|
||||||
Subject: [PATCH] ath9k: improve powersave filter handling
|
|
||||||
|
|
||||||
For non-aggregated frames, ath9k was leaving handling of powersave
|
|
||||||
filtered packets to mac80211. This can be too slow if the intermediate
|
|
||||||
queue is already filled with packets and mac80211 does not immediately
|
|
||||||
send a new packet via drv_tx().
|
|
||||||
|
|
||||||
Improve response time with filtered frames by triggering clearing the
|
|
||||||
powersave filter internally.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
|
||||||
@@ -461,13 +461,13 @@ static void ath_tx_count_frames(struct a
|
|
||||||
static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|
||||||
struct ath_buf *bf, struct list_head *bf_q,
|
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
+ struct ath_atx_tid *tid,
|
|
||||||
struct ath_tx_status *ts, int txok)
|
|
||||||
{
|
|
||||||
struct ath_node *an = NULL;
|
|
||||||
struct sk_buff *skb;
|
|
||||||
struct ieee80211_hdr *hdr;
|
|
||||||
struct ieee80211_tx_info *tx_info;
|
|
||||||
- struct ath_atx_tid *tid = NULL;
|
|
||||||
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
|
|
||||||
struct list_head bf_head;
|
|
||||||
struct sk_buff_head bf_pending;
|
|
||||||
@@ -509,7 +509,6 @@ static void ath_tx_complete_aggr(struct
|
|
||||||
}
|
|
||||||
|
|
||||||
an = (struct ath_node *)sta->drv_priv;
|
|
||||||
- tid = ath_get_skb_tid(sc, an, skb);
|
|
||||||
seq_first = tid->seq_start;
|
|
||||||
isba = ts->ts_flags & ATH9K_TX_BA;
|
|
||||||
|
|
||||||
@@ -695,6 +694,7 @@ static void ath_tx_process_buffer(struct
|
|
||||||
struct ieee80211_tx_info *info;
|
|
||||||
struct ieee80211_sta *sta;
|
|
||||||
struct ieee80211_hdr *hdr;
|
|
||||||
+ struct ath_atx_tid *tid = NULL;
|
|
||||||
bool txok, flush;
|
|
||||||
|
|
||||||
txok = !(ts->ts_status & ATH9K_TXERR_MASK);
|
|
||||||
@@ -710,6 +710,12 @@ static void ath_tx_process_buffer(struct
|
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
|
|
||||||
sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
|
|
||||||
+ if (sta) {
|
|
||||||
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
|
|
||||||
+ tid = ath_get_skb_tid(sc, an, bf->bf_mpdu);
|
|
||||||
+ if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
|
|
||||||
+ tid->clear_ps_filter = true;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
if (!bf_isampdu(bf)) {
|
|
||||||
if (!flush) {
|
|
||||||
@@ -721,7 +727,7 @@ static void ath_tx_process_buffer(struct
|
|
||||||
}
|
|
||||||
ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok);
|
|
||||||
} else
|
|
||||||
- ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, ts, txok);
|
|
||||||
+ ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok);
|
|
||||||
|
|
||||||
if (!flush)
|
|
||||||
ath_txq_schedule(sc, txq);
|
|
|
@ -1,31 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Fri, 26 Aug 2016 21:57:16 +0200
|
|
||||||
Subject: [PATCH] mac80211: fix tim recalculation after PS response
|
|
||||||
|
|
||||||
Handle the case where the mac80211 intermediate queues are empty and the
|
|
||||||
driver has buffered frames
|
|
||||||
|
|
||||||
Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation")
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/mac80211/sta_info.c
|
|
||||||
+++ b/net/mac80211/sta_info.c
|
|
||||||
@@ -1616,7 +1616,6 @@ ieee80211_sta_ps_deliver_response(struct
|
|
||||||
|
|
||||||
sta_info_recalc_tim(sta);
|
|
||||||
} else {
|
|
||||||
- unsigned long tids = sta->txq_buffered_tids & driver_release_tids;
|
|
||||||
int tid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -1648,7 +1647,8 @@ ieee80211_sta_ps_deliver_response(struct
|
|
||||||
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
|
|
||||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
|
|
||||||
|
|
||||||
- if (!(tids & BIT(tid)) || txqi->tin.backlog_packets)
|
|
||||||
+ if (!(driver_release_tids & BIT(tid)) ||
|
|
||||||
+ txqi->tin.backlog_packets)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
sta_info_recalc_tim(sta);
|
|
|
@ -1,64 +0,0 @@
|
||||||
From: Johannes Berg <johannes.berg@intel.com>
|
|
||||||
Date: Mon, 29 Aug 2016 23:25:18 +0300
|
|
||||||
Subject: [PATCH] mac80211: send delBA on unexpected BlockAck data frames
|
|
||||||
|
|
||||||
When we receive data frames with ACK policy BlockAck, send
|
|
||||||
delBA as requested by the 802.11 spec. Since this would be
|
|
||||||
happening for every frame inside an A-MPDU if it's really
|
|
||||||
received outside a session, limit it to a single attempt.
|
|
||||||
|
|
||||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/mac80211/agg-rx.c
|
|
||||||
+++ b/net/mac80211/agg-rx.c
|
|
||||||
@@ -388,8 +388,10 @@ void __ieee80211_start_rx_ba_session(str
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
- if (status == WLAN_STATUS_SUCCESS)
|
|
||||||
+ if (status == WLAN_STATUS_SUCCESS) {
|
|
||||||
__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
|
|
||||||
+ __clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
|
|
||||||
+ }
|
|
||||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
|
||||||
|
|
||||||
end_no_lock:
|
|
||||||
--- a/net/mac80211/rx.c
|
|
||||||
+++ b/net/mac80211/rx.c
|
|
||||||
@@ -1072,8 +1072,15 @@ static void ieee80211_rx_reorder_ampdu(s
|
|
||||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
|
||||||
|
|
||||||
tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
|
|
||||||
- if (!tid_agg_rx)
|
|
||||||
+ if (!tid_agg_rx) {
|
|
||||||
+ if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
|
|
||||||
+ !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
|
|
||||||
+ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
|
|
||||||
+ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
|
|
||||||
+ WLAN_BACK_RECIPIENT,
|
|
||||||
+ WLAN_REASON_QSTA_REQUIRE_SETUP);
|
|
||||||
goto dont_reorder;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* qos null data frames are excluded */
|
|
||||||
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
|
|
||||||
--- a/net/mac80211/sta_info.h
|
|
||||||
+++ b/net/mac80211/sta_info.h
|
|
||||||
@@ -230,6 +230,8 @@ struct tid_ampdu_rx {
|
|
||||||
* @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the
|
|
||||||
* driver requested to close until the work for it runs
|
|
||||||
* @agg_session_valid: bitmap indicating which TID has a rx BA session open on
|
|
||||||
+ * @unexpected_agg: bitmap indicating which TID already sent a delBA due to
|
|
||||||
+ * unexpected aggregation related frames outside a session
|
|
||||||
* @work: work struct for starting/stopping aggregation
|
|
||||||
* @tid_tx: aggregation info for Tx per TID
|
|
||||||
* @tid_start_tx: sessions where start was requested
|
|
||||||
@@ -244,6 +246,7 @@ struct sta_ampdu_mlme {
|
|
||||||
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
|
||||||
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
|
||||||
unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
|
||||||
+ unsigned long unexpected_agg[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
|
||||||
/* tx */
|
|
||||||
struct work_struct work;
|
|
||||||
struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
|
|
|
@ -1,26 +0,0 @@
|
||||||
From: Johannes Berg <johannes.berg@intel.com>
|
|
||||||
Date: Mon, 29 Aug 2016 23:25:19 +0300
|
|
||||||
Subject: [PATCH] mac80211: send delBA on unexpected BlockAck Request
|
|
||||||
|
|
||||||
If we don't have a BA session, send delBA, as requested by the
|
|
||||||
IEEE 802.11 spec. Apply the same limit of sending such a delBA
|
|
||||||
only once as in the previous patch.
|
|
||||||
|
|
||||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/mac80211/rx.c
|
|
||||||
+++ b/net/mac80211/rx.c
|
|
||||||
@@ -2537,6 +2537,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_
|
|
||||||
|
|
||||||
tid = le16_to_cpu(bar_data.control) >> 12;
|
|
||||||
|
|
||||||
+ if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
|
|
||||||
+ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
|
|
||||||
+ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
|
|
||||||
+ WLAN_BACK_RECIPIENT,
|
|
||||||
+ WLAN_REASON_QSTA_REQUIRE_SETUP);
|
|
||||||
+
|
|
||||||
tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
|
|
||||||
if (!tid_agg_rx)
|
|
||||||
return RX_DROP_MONITOR;
|
|
|
@ -1,478 +0,0 @@
|
||||||
From: Felix Fietkau <nbd@nbd.name>
|
|
||||||
Date: Sun, 4 Sep 2016 17:46:24 +0200
|
|
||||||
Subject: [PATCH] mac80211: fix sequence number assignment for PS response
|
|
||||||
frames
|
|
||||||
|
|
||||||
When using intermediate queues, sequence number allocation is deferred
|
|
||||||
until dequeue. This doesn't work for PS response frames, which bypass
|
|
||||||
those queues.
|
|
||||||
|
|
||||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
||||||
---
|
|
||||||
|
|
||||||
--- a/net/mac80211/tx.c
|
|
||||||
+++ b/net/mac80211/tx.c
|
|
||||||
@@ -38,6 +38,12 @@
|
|
||||||
#include "wme.h"
|
|
||||||
#include "rate.h"
|
|
||||||
|
|
||||||
+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx);
|
|
||||||
+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
|
|
||||||
+ struct sta_info *sta, u8 pn_offs,
|
|
||||||
+ struct ieee80211_key_conf *key_conf,
|
|
||||||
+ struct sk_buff *skb);
|
|
||||||
+
|
|
||||||
/* misc utils */
|
|
||||||
|
|
||||||
static inline void ieee80211_tx_stats(struct net_device *dev, u32 len)
|
|
||||||
@@ -849,8 +855,7 @@ ieee80211_tx_h_sequence(struct ieee80211
|
|
||||||
tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
|
||||||
tx->sta->tx_stats.msdu[tid]++;
|
|
||||||
|
|
||||||
- if (!tx->sta->sta.txq[0])
|
|
||||||
- hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);
|
|
||||||
+ hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);
|
|
||||||
|
|
||||||
return TX_CONTINUE;
|
|
||||||
}
|
|
||||||
@@ -1398,6 +1403,7 @@ void ieee80211_txq_init(struct ieee80211
|
|
||||||
fq_tin_init(&txqi->tin);
|
|
||||||
fq_flow_init(&txqi->def_flow);
|
|
||||||
codel_vars_init(&txqi->def_cvars);
|
|
||||||
+ __skb_queue_head_init(&txqi->frags);
|
|
||||||
|
|
||||||
txqi->txq.vif = &sdata->vif;
|
|
||||||
|
|
||||||
@@ -1420,6 +1426,7 @@ void ieee80211_txq_purge(struct ieee8021
|
|
||||||
struct fq_tin *tin = &txqi->tin;
|
|
||||||
|
|
||||||
fq_tin_reset(fq, tin, fq_skb_free_func);
|
|
||||||
+ ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ieee80211_txq_setup_flows(struct ieee80211_local *local)
|
|
||||||
@@ -1476,12 +1483,19 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
|
||||||
struct sk_buff *skb = NULL;
|
|
||||||
struct fq *fq = &local->fq;
|
|
||||||
struct fq_tin *tin = &txqi->tin;
|
|
||||||
+ struct ieee80211_tx_info *info;
|
|
||||||
|
|
||||||
spin_lock_bh(&fq->lock);
|
|
||||||
|
|
||||||
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
+ /* Make sure fragments stay together. */
|
|
||||||
+ skb = __skb_dequeue(&txqi->frags);
|
|
||||||
+ if (skb)
|
|
||||||
+ goto out;
|
|
||||||
+
|
|
||||||
+begin:
|
|
||||||
skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
|
|
||||||
if (!skb)
|
|
||||||
goto out;
|
|
||||||
@@ -1489,16 +1503,38 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
|
||||||
ieee80211_set_skb_vif(skb, txqi);
|
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *)skb->data;
|
|
||||||
- if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
|
|
||||||
+ info = IEEE80211_SKB_CB(skb);
|
|
||||||
+ if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
|
|
||||||
struct sta_info *sta = container_of(txq->sta, struct sta_info,
|
|
||||||
sta);
|
|
||||||
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
+ u8 pn_offs = 0;
|
|
||||||
|
|
||||||
- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid);
|
|
||||||
- if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
|
|
||||||
- info->flags |= IEEE80211_TX_CTL_AMPDU;
|
|
||||||
- else
|
|
||||||
- info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
|
||||||
+ if (info->control.hw_key)
|
|
||||||
+ pn_offs = ieee80211_padded_hdrlen(hw, hdr->frame_control);
|
|
||||||
+
|
|
||||||
+ ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
|
|
||||||
+ info->control.hw_key, skb);
|
|
||||||
+ } else {
|
|
||||||
+ struct ieee80211_tx_data tx = { };
|
|
||||||
+
|
|
||||||
+ __skb_queue_head_init(&tx.skbs);
|
|
||||||
+ tx.local = local;
|
|
||||||
+ tx.skb = skb;
|
|
||||||
+ tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control);
|
|
||||||
+ if (txq->sta) {
|
|
||||||
+ tx.sta = container_of(txq->sta, struct sta_info, sta);
|
|
||||||
+ tx.sdata = tx.sta->sdata;
|
|
||||||
+ } else {
|
|
||||||
+ tx.sdata = vif_to_sdata(info->control.vif);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (invoke_tx_handlers_late(&tx))
|
|
||||||
+ goto begin;
|
|
||||||
+
|
|
||||||
+ skb = __skb_dequeue(&tx.skbs);
|
|
||||||
+
|
|
||||||
+ if (!skb_queue_empty(&tx.skbs))
|
|
||||||
+ skb_queue_splice_tail(&tx.skbs, &txqi->frags);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
@@ -1512,6 +1548,47 @@ out:
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
|
||||||
|
|
||||||
+static bool ieee80211_queue_skb(struct ieee80211_local *local,
|
|
||||||
+ struct ieee80211_sub_if_data *sdata,
|
|
||||||
+ struct sta_info *sta,
|
|
||||||
+ struct sk_buff *skb)
|
|
||||||
+{
|
|
||||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
+ struct fq *fq = &local->fq;
|
|
||||||
+ struct ieee80211_vif *vif;
|
|
||||||
+ struct txq_info *txqi;
|
|
||||||
+ struct ieee80211_sta *pubsta;
|
|
||||||
+
|
|
||||||
+ if (!local->ops->wake_tx_queue ||
|
|
||||||
+ sdata->vif.type == NL80211_IFTYPE_MONITOR)
|
|
||||||
+ return false;
|
|
||||||
+
|
|
||||||
+ if (sta && sta->uploaded)
|
|
||||||
+ pubsta = &sta->sta;
|
|
||||||
+ else
|
|
||||||
+ pubsta = NULL;
|
|
||||||
+
|
|
||||||
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
|
||||||
+ sdata = container_of(sdata->bss,
|
|
||||||
+ struct ieee80211_sub_if_data, u.ap);
|
|
||||||
+
|
|
||||||
+ vif = &sdata->vif;
|
|
||||||
+ txqi = ieee80211_get_txq(local, vif, pubsta, skb);
|
|
||||||
+
|
|
||||||
+ if (!txqi)
|
|
||||||
+ return false;
|
|
||||||
+
|
|
||||||
+ info->control.vif = vif;
|
|
||||||
+
|
|
||||||
+ spin_lock_bh(&fq->lock);
|
|
||||||
+ ieee80211_txq_enqueue(local, txqi, skb);
|
|
||||||
+ spin_unlock_bh(&fq->lock);
|
|
||||||
+
|
|
||||||
+ drv_wake_tx_queue(local, txqi);
|
|
||||||
+
|
|
||||||
+ return true;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
|
||||||
struct ieee80211_vif *vif,
|
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
@@ -1519,9 +1596,7 @@ static bool ieee80211_tx_frags(struct ie
|
|
||||||
bool txpending)
|
|
||||||
{
|
|
||||||
struct ieee80211_tx_control control = {};
|
|
||||||
- struct fq *fq = &local->fq;
|
|
||||||
struct sk_buff *skb, *tmp;
|
|
||||||
- struct txq_info *txqi;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
skb_queue_walk_safe(skbs, skb, tmp) {
|
|
||||||
@@ -1536,21 +1611,6 @@ static bool ieee80211_tx_frags(struct ie
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
- txqi = ieee80211_get_txq(local, vif, sta, skb);
|
|
||||||
- if (txqi) {
|
|
||||||
- info->control.vif = vif;
|
|
||||||
-
|
|
||||||
- __skb_unlink(skb, skbs);
|
|
||||||
-
|
|
||||||
- spin_lock_bh(&fq->lock);
|
|
||||||
- ieee80211_txq_enqueue(local, txqi, skb);
|
|
||||||
- spin_unlock_bh(&fq->lock);
|
|
||||||
-
|
|
||||||
- drv_wake_tx_queue(local, txqi);
|
|
||||||
-
|
|
||||||
- continue;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
|
||||||
if (local->queue_stop_reasons[q] ||
|
|
||||||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
|
|
||||||
@@ -1671,10 +1731,13 @@ static bool __ieee80211_tx(struct ieee80
|
|
||||||
/*
|
|
||||||
* Invoke TX handlers, return 0 on success and non-zero if the
|
|
||||||
* frame was dropped or queued.
|
|
||||||
+ *
|
|
||||||
+ * The handlers are split into an early and late part. The latter is everything
|
|
||||||
+ * that can be sensitive to reordering, and will be deferred to after packets
|
|
||||||
+ * are dequeued from the intermediate queues (when they are enabled).
|
|
||||||
*/
|
|
||||||
-static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
|
||||||
+static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
|
|
||||||
{
|
|
||||||
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
||||||
ieee80211_tx_result res = TX_DROP;
|
|
||||||
|
|
||||||
#define CALL_TXH(txh) \
|
|
||||||
@@ -1688,16 +1751,42 @@ static int invoke_tx_handlers(struct iee
|
|
||||||
CALL_TXH(ieee80211_tx_h_check_assoc);
|
|
||||||
CALL_TXH(ieee80211_tx_h_ps_buf);
|
|
||||||
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
|
|
||||||
- CALL_TXH(ieee80211_tx_h_select_key);
|
|
||||||
+
|
|
||||||
if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
|
|
||||||
CALL_TXH(ieee80211_tx_h_rate_ctrl);
|
|
||||||
|
|
||||||
+ txh_done:
|
|
||||||
+ if (unlikely(res == TX_DROP)) {
|
|
||||||
+ I802_DEBUG_INC(tx->local->tx_handlers_drop);
|
|
||||||
+ if (tx->skb)
|
|
||||||
+ ieee80211_free_txskb(&tx->local->hw, tx->skb);
|
|
||||||
+ else
|
|
||||||
+ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
|
|
||||||
+ return -1;
|
|
||||||
+ } else if (unlikely(res == TX_QUEUED)) {
|
|
||||||
+ I802_DEBUG_INC(tx->local->tx_handlers_queued);
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Late handlers can be called while the sta lock is held. Handlers that can
|
|
||||||
+ * cause packets to be generated will cause deadlock!
|
|
||||||
+ */
|
|
||||||
+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
|
|
||||||
+{
|
|
||||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
||||||
+ ieee80211_tx_result res = TX_CONTINUE;
|
|
||||||
+
|
|
||||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
|
|
||||||
__skb_queue_tail(&tx->skbs, tx->skb);
|
|
||||||
tx->skb = NULL;
|
|
||||||
goto txh_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ CALL_TXH(ieee80211_tx_h_select_key);
|
|
||||||
CALL_TXH(ieee80211_tx_h_michael_mic_add);
|
|
||||||
CALL_TXH(ieee80211_tx_h_sequence);
|
|
||||||
CALL_TXH(ieee80211_tx_h_fragment);
|
|
||||||
@@ -1724,6 +1813,15 @@ static int invoke_tx_handlers(struct iee
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
|
||||||
+{
|
|
||||||
+ int r = invoke_tx_handlers_early(tx);
|
|
||||||
+ if (r)
|
|
||||||
+ return r;
|
|
||||||
+
|
|
||||||
+ return invoke_tx_handlers_late(tx);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
|
||||||
struct ieee80211_vif *vif, struct sk_buff *skb,
|
|
||||||
int band, struct ieee80211_sta **sta)
|
|
||||||
@@ -1798,7 +1896,13 @@ static bool ieee80211_tx(struct ieee8021
|
|
||||||
info->hw_queue =
|
|
||||||
sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
|
|
||||||
|
|
||||||
- if (!invoke_tx_handlers(&tx))
|
|
||||||
+ if (invoke_tx_handlers_early(&tx))
|
|
||||||
+ return false;
|
|
||||||
+
|
|
||||||
+ if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
|
|
||||||
+ return true;
|
|
||||||
+
|
|
||||||
+ if (!invoke_tx_handlers_late(&tx))
|
|
||||||
result = __ieee80211_tx(local, &tx.skbs, led_len,
|
|
||||||
tx.sta, txpending);
|
|
||||||
|
|
||||||
@@ -3181,7 +3285,7 @@ out:
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|
||||||
- struct net_device *dev, struct sta_info *sta,
|
|
||||||
+ struct sta_info *sta,
|
|
||||||
struct ieee80211_fast_tx *fast_tx,
|
|
||||||
struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
@@ -3192,9 +3296,9 @@ static bool ieee80211_xmit_fast(struct i
|
|
||||||
struct ethhdr eth;
|
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
|
|
||||||
- struct ieee80211_tx_data tx;
|
|
||||||
- ieee80211_tx_result r;
|
|
||||||
struct tid_ampdu_tx *tid_tx = NULL;
|
|
||||||
+ ieee80211_tx_result r;
|
|
||||||
+ struct ieee80211_tx_data tx;
|
|
||||||
u8 tid = IEEE80211_NUM_TIDS;
|
|
||||||
|
|
||||||
/* control port protocol needs a lot of special handling */
|
|
||||||
@@ -3232,8 +3336,6 @@ static bool ieee80211_xmit_fast(struct i
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
- ieee80211_tx_stats(dev, skb->len + extra_head);
|
|
||||||
-
|
|
||||||
if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
|
|
||||||
ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
|
|
||||||
return true;
|
|
||||||
@@ -3262,24 +3364,7 @@ static bool ieee80211_xmit_fast(struct i
|
|
||||||
info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
|
|
||||||
IEEE80211_TX_CTL_DONTFRAG |
|
|
||||||
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
|
|
||||||
-
|
|
||||||
- if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
|
||||||
- *ieee80211_get_qos_ctl(hdr) = tid;
|
|
||||||
- if (!sta->sta.txq[0])
|
|
||||||
- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
|
||||||
- } else {
|
|
||||||
- info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
|
||||||
- hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
|
|
||||||
- sdata->sequence_number += 0x10;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (skb_shinfo(skb)->gso_size)
|
|
||||||
- sta->tx_stats.msdu[tid] +=
|
|
||||||
- DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
|
|
||||||
- else
|
|
||||||
- sta->tx_stats.msdu[tid]++;
|
|
||||||
-
|
|
||||||
- info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
|
|
||||||
+ info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
|
|
||||||
|
|
||||||
__skb_queue_head_init(&tx.skbs);
|
|
||||||
|
|
||||||
@@ -3305,22 +3390,71 @@ static bool ieee80211_xmit_fast(struct i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (ieee80211_queue_skb(local, sdata, sta, skb))
|
|
||||||
+ return true;
|
|
||||||
+
|
|
||||||
+ ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
|
|
||||||
+ &fast_tx->key->conf, skb);
|
|
||||||
+
|
|
||||||
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
|
||||||
+ sdata = container_of(sdata->bss,
|
|
||||||
+ struct ieee80211_sub_if_data, u.ap);
|
|
||||||
+
|
|
||||||
+ __skb_queue_tail(&tx.skbs, skb);
|
|
||||||
+ ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
|
|
||||||
+
|
|
||||||
+ return true;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Can be called while the sta lock is held. Anything that can cause packets to
|
|
||||||
+ * be generated will cause deadlock!
|
|
||||||
+ */
|
|
||||||
+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
|
|
||||||
+ struct sta_info *sta, u8 pn_offs,
|
|
||||||
+ struct ieee80211_key_conf *key_conf,
|
|
||||||
+ struct sk_buff *skb)
|
|
||||||
+{
|
|
||||||
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
+ struct ieee80211_hdr *hdr = (void *)skb->data;
|
|
||||||
+ u8 tid = IEEE80211_NUM_TIDS;
|
|
||||||
+
|
|
||||||
+ ieee80211_tx_stats(skb->dev, skb->len);
|
|
||||||
+
|
|
||||||
+ if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
|
||||||
+ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
|
||||||
+ *ieee80211_get_qos_ctl(hdr) = tid;
|
|
||||||
+ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
|
||||||
+ } else {
|
|
||||||
+ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
|
||||||
+ hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number);
|
|
||||||
+ sdata->sequence_number += 0x10;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (skb_shinfo(skb)->gso_size)
|
|
||||||
+ sta->tx_stats.msdu[tid] +=
|
|
||||||
+ DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size);
|
|
||||||
+ else
|
|
||||||
+ sta->tx_stats.msdu[tid]++;
|
|
||||||
+
|
|
||||||
+ info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
|
|
||||||
+
|
|
||||||
/* statistics normally done by ieee80211_tx_h_stats (but that
|
|
||||||
* has to consider fragmentation, so is more complex)
|
|
||||||
*/
|
|
||||||
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
|
|
||||||
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
|
|
||||||
|
|
||||||
- if (fast_tx->pn_offs) {
|
|
||||||
+ if (pn_offs && (key_conf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
|
||||||
u64 pn;
|
|
||||||
- u8 *crypto_hdr = skb->data + fast_tx->pn_offs;
|
|
||||||
+ u8 *crypto_hdr = skb->data + pn_offs;
|
|
||||||
|
|
||||||
- switch (fast_tx->key->conf.cipher) {
|
|
||||||
+ switch (key_conf->cipher) {
|
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
|
||||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
|
||||||
case WLAN_CIPHER_SUITE_GCMP:
|
|
||||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
|
||||||
- pn = atomic64_inc_return(&fast_tx->key->conf.tx_pn);
|
|
||||||
+ pn = atomic64_inc_return(&key_conf->tx_pn);
|
|
||||||
crypto_hdr[0] = pn;
|
|
||||||
crypto_hdr[1] = pn >> 8;
|
|
||||||
crypto_hdr[4] = pn >> 16;
|
|
||||||
@@ -3331,12 +3465,6 @@ static bool ieee80211_xmit_fast(struct i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
|
||||||
- sdata = container_of(sdata->bss,
|
|
||||||
- struct ieee80211_sub_if_data, u.ap);
|
|
||||||
-
|
|
||||||
- __skb_queue_tail(&tx.skbs, skb);
|
|
||||||
- ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -3364,7 +3492,7 @@ void __ieee80211_subif_start_xmit(struct
|
|
||||||
fast_tx = rcu_dereference(sta->fast_tx);
|
|
||||||
|
|
||||||
if (fast_tx &&
|
|
||||||
- ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb))
|
|
||||||
+ ieee80211_xmit_fast(sdata, sta, fast_tx, skb))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
--- a/include/net/mac80211.h
|
|
||||||
+++ b/include/net/mac80211.h
|
|
||||||
@@ -715,6 +715,7 @@ enum mac80211_tx_info_flags {
|
|
||||||
* frame (PS-Poll or uAPSD).
|
|
||||||
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
|
|
||||||
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
|
|
||||||
+ * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path
|
|
||||||
*
|
|
||||||
* These flags are used in tx_info->control.flags.
|
|
||||||
*/
|
|
||||||
@@ -723,6 +724,7 @@ enum mac80211_tx_control_flags {
|
|
||||||
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
|
|
||||||
IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
|
|
||||||
IEEE80211_TX_CTRL_AMSDU = BIT(3),
|
|
||||||
+ IEEE80211_TX_CTRL_FAST_XMIT = BIT(4),
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
--- a/net/mac80211/ieee80211_i.h
|
|
||||||
+++ b/net/mac80211/ieee80211_i.h
|
|
||||||
@@ -814,11 +814,13 @@ enum txq_info_flags {
|
|
||||||
* @def_flow: used as a fallback flow when a packet destined to @tin hashes to
|
|
||||||
* a fq_flow which is already owned by a different tin
|
|
||||||
* @def_cvars: codel vars for @def_flow
|
|
||||||
+ * @frags: used to keep fragments created after dequeue
|
|
||||||
*/
|
|
||||||
struct txq_info {
|
|
||||||
struct fq_tin tin;
|
|
||||||
struct fq_flow def_flow;
|
|
||||||
struct codel_vars def_cvars;
|
|
||||||
+ struct sk_buff_head frags;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/* keep last! */
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/drivers/net/wireless/ath/regd.c
|
--- a/drivers/net/wireless/ath/regd.c
|
||||||
+++ b/drivers/net/wireless/ath/regd.c
|
+++ b/drivers/net/wireless/ath/regd.c
|
||||||
@@ -114,10 +114,22 @@ static const struct ieee80211_regdomain
|
@@ -114,11 +114,24 @@ static const struct ieee80211_regdomain
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,14 +16,16 @@
|
||||||
+
|
+
|
||||||
static bool dynamic_country_user_possible(struct ath_regulatory *reg)
|
static bool dynamic_country_user_possible(struct ath_regulatory *reg)
|
||||||
{
|
{
|
||||||
if (config_enabled(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
|
if (IS_ENABLED(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
+ if (is_default_regd(reg))
|
+ if (is_default_regd(reg))
|
||||||
+ return true;
|
+ return true;
|
||||||
|
+
|
||||||
switch (reg->country_code) {
|
switch (reg->country_code) {
|
||||||
case CTRY_UNITED_STATES:
|
case CTRY_UNITED_STATES:
|
||||||
@@ -202,11 +214,6 @@ static inline bool is_wwr_sku(u16 regd)
|
case CTRY_JAPAN1:
|
||||||
|
@@ -202,11 +215,6 @@ static inline bool is_wwr_sku(u16 regd)
|
||||||
(regd == WORLD));
|
(regd == WORLD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +37,7 @@
|
||||||
bool ath_is_world_regd(struct ath_regulatory *reg)
|
bool ath_is_world_regd(struct ath_regulatory *reg)
|
||||||
{
|
{
|
||||||
return is_wwr_sku(ath_regd_get_eepromRD(reg));
|
return is_wwr_sku(ath_regd_get_eepromRD(reg));
|
||||||
@@ -650,6 +657,9 @@ ath_regd_init_wiphy(struct ath_regulator
|
@@ -650,6 +658,9 @@ ath_regd_init_wiphy(struct ath_regulator
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||||
@@ -727,6 +727,7 @@ static const struct ieee80211_iface_limi
|
@@ -731,6 +731,7 @@ static const struct ieee80211_iface_limi
|
||||||
BIT(NL80211_IFTYPE_AP) },
|
BIT(NL80211_IFTYPE_AP) },
|
||||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||||
BIT(NL80211_IFTYPE_P2P_GO) },
|
BIT(NL80211_IFTYPE_P2P_GO) },
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||||
@@ -1030,23 +1030,23 @@ static int __init ath9k_init(void)
|
@@ -1034,23 +1034,23 @@ static int __init ath9k_init(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
@@ -651,6 +651,7 @@ int ath9k_hw_init(struct ath_hw *ah)
|
@@ -647,6 +647,7 @@ int ath9k_hw_init(struct ath_hw *ah)
|
||||||
|
|
||||||
/* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */
|
/* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */
|
||||||
switch (ah->hw_version.devid) {
|
switch (ah->hw_version.devid) {
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
#define AR9160_DEVID_PCI 0x0027
|
#define AR9160_DEVID_PCI 0x0027
|
||||||
--- a/drivers/net/wireless/ath/ath9k/pci.c
|
--- a/drivers/net/wireless/ath/ath9k/pci.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/pci.c
|
+++ b/drivers/net/wireless/ath/ath9k/pci.c
|
||||||
@@ -761,6 +761,7 @@ static const struct pci_device_id ath_pc
|
@@ -760,6 +760,7 @@ static const struct pci_device_id ath_pc
|
||||||
.driver_data = ATH9K_PCI_BT_ANT_DIV },
|
.driver_data = ATH9K_PCI_BT_ANT_DIV },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/include/net/cfg80211.h
|
--- a/include/net/cfg80211.h
|
||||||
+++ b/include/net/cfg80211.h
|
+++ b/include/net/cfg80211.h
|
||||||
@@ -2410,6 +2410,7 @@ struct cfg80211_qos_map {
|
@@ -2562,6 +2562,7 @@ struct cfg80211_nan_func {
|
||||||
* (as advertised by the nl80211 feature flag.)
|
* (as advertised by the nl80211 feature flag.)
|
||||||
* @get_tx_power: store the current TX power into the dbm variable;
|
* @get_tx_power: store the current TX power into the dbm variable;
|
||||||
* return 0 if successful
|
* return 0 if successful
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
* @set_wds_peer: set the WDS peer for a WDS interface
|
* @set_wds_peer: set the WDS peer for a WDS interface
|
||||||
*
|
*
|
||||||
@@ -2671,6 +2672,7 @@ struct cfg80211_ops {
|
@@ -2836,6 +2837,7 @@ struct cfg80211_ops {
|
||||||
enum nl80211_tx_power_setting type, int mbm);
|
enum nl80211_tx_power_setting type, int mbm);
|
||||||
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||||
int *dbm);
|
int *dbm);
|
||||||
|
@ -36,9 +36,9 @@
|
||||||
u8 ps_dtim_period;
|
u8 ps_dtim_period;
|
||||||
--- a/include/uapi/linux/nl80211.h
|
--- a/include/uapi/linux/nl80211.h
|
||||||
+++ b/include/uapi/linux/nl80211.h
|
+++ b/include/uapi/linux/nl80211.h
|
||||||
@@ -1829,6 +1829,9 @@ enum nl80211_commands {
|
@@ -1937,6 +1937,9 @@ enum nl80211_commands {
|
||||||
* %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
|
* @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
|
||||||
* interface type.
|
* See &enum nl80211_nan_match_attributes.
|
||||||
*
|
*
|
||||||
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
|
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
|
||||||
+ * transmit power to stay within regulatory limits. u32, dBi.
|
+ * transmit power to stay within regulatory limits. u32, dBi.
|
||||||
|
@ -46,9 +46,9 @@
|
||||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||||
@@ -2213,6 +2216,8 @@ enum nl80211_attrs {
|
@@ -2336,6 +2339,8 @@ enum nl80211_attrs {
|
||||||
|
NL80211_ATTR_NAN_FUNC,
|
||||||
NL80211_ATTR_IFTYPE_EXT_CAPA,
|
NL80211_ATTR_NAN_MATCH,
|
||||||
|
|
||||||
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
|
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
|
||||||
+
|
+
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
__NL80211_ATTR_AFTER_LAST,
|
__NL80211_ATTR_AFTER_LAST,
|
||||||
--- a/net/mac80211/cfg.c
|
--- a/net/mac80211/cfg.c
|
||||||
+++ b/net/mac80211/cfg.c
|
+++ b/net/mac80211/cfg.c
|
||||||
@@ -2238,6 +2238,19 @@ static int ieee80211_get_tx_power(struct
|
@@ -2406,6 +2406,19 @@ static int ieee80211_get_tx_power(struct
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||||
const u8 *addr)
|
const u8 *addr)
|
||||||
{
|
{
|
||||||
@@ -3412,6 +3425,7 @@ const struct cfg80211_ops mac80211_confi
|
@@ -3633,6 +3646,7 @@ const struct cfg80211_ops mac80211_confi
|
||||||
.set_wiphy_params = ieee80211_set_wiphy_params,
|
.set_wiphy_params = ieee80211_set_wiphy_params,
|
||||||
.set_tx_power = ieee80211_set_tx_power,
|
.set_tx_power = ieee80211_set_tx_power,
|
||||||
.get_tx_power = ieee80211_get_tx_power,
|
.get_tx_power = ieee80211_get_tx_power,
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
|
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
|
||||||
--- a/net/mac80211/ieee80211_i.h
|
--- a/net/mac80211/ieee80211_i.h
|
||||||
+++ b/net/mac80211/ieee80211_i.h
|
+++ b/net/mac80211/ieee80211_i.h
|
||||||
@@ -1340,6 +1340,7 @@ struct ieee80211_local {
|
@@ -1363,6 +1363,7 @@ struct ieee80211_local {
|
||||||
int dynamic_ps_forced_timeout;
|
int dynamic_ps_forced_timeout;
|
||||||
|
|
||||||
int user_power_level; /* in dBm, for all interfaces */
|
int user_power_level; /* in dBm, for all interfaces */
|
||||||
|
@ -129,15 +129,15 @@
|
||||||
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||||
--- a/net/wireless/nl80211.c
|
--- a/net/wireless/nl80211.c
|
||||||
+++ b/net/wireless/nl80211.c
|
+++ b/net/wireless/nl80211.c
|
||||||
@@ -407,6 +407,7 @@ static const struct nla_policy nl80211_p
|
@@ -416,6 +416,7 @@ static const struct nla_policy nl80211_p
|
||||||
[NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
|
[NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
|
||||||
[NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
|
[NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
|
||||||
[NL80211_ATTR_STA_SUPPORT_P2P_PS] = { .type = NLA_U8 },
|
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
|
||||||
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
|
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* policy for the key attributes */
|
/* policy for the key attributes */
|
||||||
@@ -2294,6 +2295,20 @@ static int nl80211_set_wiphy(struct sk_b
|
@@ -2353,6 +2354,20 @@ static int nl80211_set_wiphy(struct sk_b
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,16 +38,7 @@
|
||||||
#ifdef CPTCFG_ATH9K_DEBUGFS
|
#ifdef CPTCFG_ATH9K_DEBUGFS
|
||||||
--- a/drivers/net/wireless/ath/ath9k/gpio.c
|
--- a/drivers/net/wireless/ath/ath9k/gpio.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
|
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
|
||||||
@@ -22,7 +22,7 @@
|
@@ -39,61 +39,111 @@ static void ath_fill_led_pin(struct ath_
|
||||||
|
|
||||||
#ifdef CPTCFG_MAC80211_LEDS
|
|
||||||
|
|
||||||
-void ath_fill_led_pin(struct ath_softc *sc)
|
|
||||||
+static void ath_fill_led_pin(struct ath_softc *sc)
|
|
||||||
{
|
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
|
||||||
|
|
||||||
@@ -39,61 +39,111 @@ void ath_fill_led_pin(struct ath_softc *
|
|
||||||
else
|
else
|
||||||
ah->led_pin = ATH_LED_PIN_DEF;
|
ah->led_pin = ATH_LED_PIN_DEF;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +181,7 @@
|
||||||
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||||
@@ -942,7 +942,7 @@ int ath9k_init_device(u16 devid, struct
|
@@ -946,7 +946,7 @@ int ath9k_init_device(u16 devid, struct
|
||||||
|
|
||||||
#ifdef CPTCFG_MAC80211_LEDS
|
#ifdef CPTCFG_MAC80211_LEDS
|
||||||
/* must be initialized before ieee80211_register_hw */
|
/* must be initialized before ieee80211_register_hw */
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/include/linux/ath9k_platform.h
|
--- a/include/linux/ath9k_platform.h
|
||||||
+++ b/include/linux/ath9k_platform.h
|
+++ b/include/linux/ath9k_platform.h
|
||||||
@@ -45,6 +45,9 @@ struct ath9k_platform_data {
|
@@ -46,6 +46,9 @@ struct ath9k_platform_data {
|
||||||
int (*external_reset)(void);
|
int (*external_reset)(void);
|
||||||
|
|
||||||
bool use_eeprom;
|
bool use_eeprom;
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
--- a/include/linux/ath9k_platform.h
|
|
||||||
+++ b/include/linux/ath9k_platform.h
|
|
||||||
@@ -40,6 +40,7 @@ struct ath9k_platform_data {
|
|
||||||
bool tx_gain_buffalo;
|
|
||||||
bool disable_2ghz;
|
|
||||||
bool disable_5ghz;
|
|
||||||
+ bool led_active_high;
|
|
||||||
|
|
||||||
int (*get_mac_revision)(void);
|
|
||||||
int (*external_reset)(void);
|
|
||||||
--- a/drivers/net/wireless/ath/ath9k/init.c
|
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
|
||||||
@@ -580,6 +580,7 @@ static int ath9k_init_softc(u16 devid, s
|
|
||||||
ah->external_reset = pdata->external_reset;
|
|
||||||
ah->disable_2ghz = pdata->disable_2ghz;
|
|
||||||
ah->disable_5ghz = pdata->disable_5ghz;
|
|
||||||
+ ah->config.led_active_high = pdata->led_active_high;
|
|
||||||
if (!pdata->endian_check)
|
|
||||||
ah->ah_flags |= AH_NO_EEP_SWAP;
|
|
||||||
}
|
|
|
@ -94,7 +94,7 @@
|
||||||
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
|
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
|
||||||
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
@@ -1841,6 +1841,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
|
@@ -1837,6 +1837,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
|
EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
|
||||||
struct ath9k_hw_cal_data *caldata, bool fastcc)
|
struct ath9k_hw_cal_data *caldata, bool fastcc)
|
||||||
{
|
{
|
||||||
@@ -2049,6 +2063,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
@@ -2045,6 +2059,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
||||||
ar9003_hw_disable_phy_restart(ah);
|
ar9003_hw_disable_phy_restart(ah);
|
||||||
|
|
||||||
ath9k_hw_apply_gpio_override(ah);
|
ath9k_hw_apply_gpio_override(ah);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue