PKG_NAME:=mac80211
-PKG_VERSION:=2015-06-22
+PKG_VERSION:=2015-07-21
PKG_RELEASE:=1
PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
PKG_BACKPORT_VERSION:=
-PKG_MD5SUM:=352b2b46d36a72aadc96161a3cefdb1c
+PKG_MD5SUM:=ec529acfb9c942daf8116e5cff47c999
PKG_SOURCE:=compat-wireless-$(PKG_VERSION)$(PKG_BACKPORT_VERSION).tar.bz2
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
--- a/.local-symbols
+++ b/.local-symbols
-@@ -448,43 +448,6 @@ USB_CDC_PHONET=
+@@ -449,43 +449,6 @@ USB_CDC_PHONET=
USB_IPHETH=
USB_SIERRA_NET=
USB_VL600=
+--- a/net/mac80211/Kconfig
++++ b/net/mac80211/Kconfig
+@@ -5,8 +5,6 @@ config MAC80211
+ depends on CRYPTO
+ depends on CRYPTO_ARC4
+ depends on CRYPTO_AES
+- select BPAUTO_CRYPTO_CCM
+- depends on CRYPTO_GCM
+ depends on CRC32
+ select BPAUTO_AVERAGE
+ ---help---
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -15,9 +15,7 @@ mac80211-y := \
cfg.o \
ethtool.o \
rx.o \
---- a/net/mac80211/aes_gcm.h
-+++ b/net/mac80211/aes_gcm.h
-@@ -11,12 +11,28 @@
-
- #include <linux/crypto.h>
-
--void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
-- u8 *data, size_t data_len, u8 *mic);
--int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
-- u8 *data, size_t data_len, u8 *mic);
--struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
-- size_t key_len);
--void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm);
-+static inline void
-+ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
-+ u8 *data, size_t data_len, u8 *mic)
-+{
-+}
-+
-+static inline int
-+ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
-+ u8 *data, size_t data_len, u8 *mic)
-+{
-+ return -EOPNOTSUPP;
-+}
-+
-+static inline struct crypto_aead *
-+ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], size_t key_len)
-+{
-+ return NULL;
-+}
-+
-+static inline void
-+ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
-+{
-+}
-
- #endif /* AES_GCM_H */
---- a/net/mac80211/aes_gmac.h
-+++ b/net/mac80211/aes_gmac.h
-@@ -11,10 +11,22 @@
-
- #include <linux/crypto.h>
-
--struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
-- size_t key_len);
--int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
-- const u8 *data, size_t data_len, u8 *mic);
--void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm);
-+static inline struct crypto_aead *
-+ieee80211_aes_gmac_key_setup(const u8 key[], size_t key_len)
-+{
-+ return NULL;
-+}
-+
-+static inline int
-+ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
-+ const u8 *data, size_t data_len, u8 *mic)
-+{
-+ return -EOPNOTSUPP;
-+}
-+
-+static inline void
-+ieee80211_aes_gmac_key_free(struct crypto_aead *tfm)
-+{
-+}
-
- #endif /* AES_GMAC_H */
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
-@@ -19,86 +19,126 @@
+@@ -13,89 +13,132 @@
+ #include <linux/types.h>
+ #include <linux/err.h>
+ #include <crypto/aead.h>
++#include <crypto/aes.h>
+
+ #include <net/mac80211.h>
#include "key.h"
#include "aes_ccm.h"
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+- u8 *data, size_t data_len, u8 *mic,
+- size_t mic_len)
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0,
+ u8 *a, u8 *b)
-+{
+ {
+- struct scatterlist sg[3];
+ int i;
+
+ crypto_cipher_encrypt_one(tfm, b, b_0);
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ aad[i] ^= b[i];
+ crypto_cipher_encrypt_one(tfm, a, aad);
-+
+
+- char aead_req_data[sizeof(struct aead_request) +
+- crypto_aead_reqsize(tfm)]
+- __aligned(__alignof__(struct aead_request));
+- struct aead_request *aead_req = (void *) aead_req_data;
+ /* Mask out bits from auth-only-b_0 */
+ b_0[0] &= 0x07;
-+
+
+- memset(aead_req, 0, sizeof(aead_req_data));
+ /* S_0 is used to encrypt T (= MIC) */
+ b_0[14] = 0;
+ b_0[15] = 0;
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
+}
-+
-+
+
+- sg_init_table(sg, 3);
+- sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad));
+- sg_set_buf(&sg[1], data, data_len);
+- sg_set_buf(&sg[2], mic, mic_len);
+
+- aead_request_set_tfm(aead_req, tfm);
+- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
+- aead_request_set_ad(aead_req, sg[0].length);
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
- u8 *data, size_t data_len, u8 *mic,
- size_t mic_len)
- {
-- struct scatterlist assoc, pt, ct[2];
++ u8 *data, size_t data_len, u8 *mic,
++ size_t mic_len)
++{
+ int i, j, last_len, num_blocks;
+ u8 b[AES_BLOCK_SIZE];
+ u8 s_0[AES_BLOCK_SIZE];
+ *cpos++ = *pos++ ^ e[i];
+ }
-- char aead_req_data[sizeof(struct aead_request) +
-- crypto_aead_reqsize(tfm)]
-- __aligned(__alignof__(struct aead_request));
-- struct aead_request *aead_req = (void *) aead_req_data;
--
-- memset(aead_req, 0, sizeof(aead_req_data));
--
-- sg_init_one(&pt, data, data_len);
-- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
-- sg_init_table(ct, 2);
-- sg_set_buf(&ct[0], data, data_len);
-- sg_set_buf(&ct[1], mic, mic_len);
--
-- aead_request_set_tfm(aead_req, tfm);
-- aead_request_set_assoc(aead_req, &assoc, assoc.length);
-- aead_request_set_crypt(aead_req, &pt, ct, data_len, b_0);
--
- crypto_aead_encrypt(aead_req);
+ for (i = 0; i < mic_len; i++)
+ mic[i] = b[i] ^ s_0[i];
u8 *data, size_t data_len, u8 *mic,
size_t mic_len)
{
-- struct scatterlist assoc, pt, ct[2];
+- struct scatterlist sg[3];
- char aead_req_data[sizeof(struct aead_request) +
- crypto_aead_reqsize(tfm)]
- __aligned(__alignof__(struct aead_request));
-
- memset(aead_req, 0, sizeof(aead_req_data));
-
-- sg_init_one(&pt, data, data_len);
-- sg_init_one(&assoc, &aad[2], be16_to_cpup((__be16 *)aad));
-- sg_init_table(ct, 2);
-- sg_set_buf(&ct[0], data, data_len);
-- sg_set_buf(&ct[1], mic, mic_len);
+- 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_assoc(aead_req, &assoc, assoc.length);
-- aead_request_set_crypt(aead_req, ct, &pt, data_len + mic_len, b_0);
+- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
+- aead_request_set_ad(aead_req, sg[0].length);
+ int i, j, last_len, num_blocks;
+ u8 *pos, *cpos;
+ u8 a[AES_BLOCK_SIZE];
- crypto_free_aead(tfm);
+ crypto_free_cipher(tfm);
}
+--- a/net/mac80211/aes_ccm.h
++++ b/net/mac80211/aes_ccm.h
+@@ -12,15 +12,15 @@
+
+ #include <linux/crypto.h>
+
+-struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
+- size_t key_len,
+- size_t mic_len);
+-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
++struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[],
++ size_t key_len,
++ size_t mic_len);
++void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+ u8 *data, size_t data_len, u8 *mic,
+ size_t mic_len);
+-int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
++int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+ u8 *data, size_t data_len, u8 *mic,
+ size_t mic_len);
+-void ieee80211_aes_key_free(struct crypto_aead *tfm);
++void ieee80211_aes_key_free(struct crypto_cipher *tfm);
+
+ #endif /* AES_CCM_H */
+--- a/net/mac80211/aes_gcm.h
++++ b/net/mac80211/aes_gcm.h
+@@ -11,12 +11,28 @@
+
+ #include <linux/crypto.h>
+
+-void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
+- u8 *data, size_t data_len, u8 *mic);
+-int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
+- u8 *data, size_t data_len, u8 *mic);
+-struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
+- size_t key_len);
+-void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm);
++static inline void
++ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
++ u8 *data, size_t data_len, u8 *mic)
++{
++}
++
++static inline int
++ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
++ u8 *data, size_t data_len, u8 *mic)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline struct crypto_aead *
++ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], size_t key_len)
++{
++ return NULL;
++}
++
++static inline void
++ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
++{
++}
+
+ #endif /* AES_GCM_H */
+--- a/net/mac80211/aes_gmac.h
++++ b/net/mac80211/aes_gmac.h
+@@ -11,10 +11,22 @@
+
+ #include <linux/crypto.h>
+
+-struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
+- size_t key_len);
+-int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
+- const u8 *data, size_t data_len, u8 *mic);
+-void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm);
++static inline struct crypto_aead *
++ieee80211_aes_gmac_key_setup(const u8 key[], size_t key_len)
++{
++ return NULL;
++}
++
++static inline int
++ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
++ const u8 *data, size_t data_len, u8 *mic)
++{
++ return -EOPNOTSUPP;
++}
++
++static inline void
++ieee80211_aes_gmac_key_free(struct crypto_aead *tfm)
++{
++}
+
+ #endif /* AES_GMAC_H */
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -84,7 +84,7 @@ struct ieee80211_key {
if (ieee80211_aes_ccm_decrypt(
key->u.ccmp.tfm, b_0, aad,
---- a/net/mac80211/aes_ccm.h
-+++ b/net/mac80211/aes_ccm.h
-@@ -12,15 +12,15 @@
-
- #include <linux/crypto.h>
-
--struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
-- size_t key_len,
-- size_t mic_len);
--void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
-+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[],
-+ size_t key_len,
-+ size_t mic_len);
-+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
- u8 *data, size_t data_len, u8 *mic,
- size_t mic_len);
--int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
-+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
- u8 *data, size_t data_len, u8 *mic,
- size_t mic_len);
--void ieee80211_aes_key_free(struct crypto_aead *tfm);
-+void ieee80211_aes_key_free(struct crypto_cipher *tfm);
-
- #endif /* AES_CCM_H */
---- a/net/mac80211/Kconfig
-+++ b/net/mac80211/Kconfig
-@@ -5,8 +5,6 @@ config MAC80211
- depends on CRYPTO
- depends on CRYPTO_ARC4
- depends on CRYPTO_AES
-- select BPAUTO_CRYPTO_CCM
-- depends on CRYPTO_GCM
- depends on CRC32
- select BPAUTO_AVERAGE
- ---help---
+++ /dev/null
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -2008,7 +2008,7 @@ static int ieee80211_scan(struct wiphy *
- * the frames sent while scanning on other channel will be
- * lost)
- */
-- if (sdata->u.ap.beacon &&
-+ if (0 && sdata->u.ap.beacon &&
- (!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
- !(req->flags & NL80211_SCAN_FLAG_AP)))
- return -EOPNOTSUPP;
--- /dev/null
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Thu, 2 Jul 2015 15:20:56 +0200
+Subject: [PATCH] ath9k: limit retries for powersave response frames
+
+In some cases, the channel might be busy enough that an ath9k AP's
+response to PS-Poll frames might be too slow and the station has already
+gone to sleep. To avoid wasting too much airtime on this, limit the
+number of retries on such frames and ensure that no sample rate gets
+used.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -147,10 +147,25 @@ static void ath_send_bar(struct ath_atx_
+ }
+
+ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+- struct ath_buf *bf)
++ struct ath_buf *bf, bool ps)
+ {
++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
++
++ if (ps) {
++ /* Clear the first rate to avoid using a sample rate for PS frames */
++ info->control.rates[0].idx = -1;
++ info->control.rates[0].count = 0;
++ }
++
+ ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
+ ARRAY_SIZE(bf->rates));
++ if (!ps)
++ return;
++
++ if (bf->rates[0].count > 2)
++ bf->rates[0].count = 2;
++
++ bf->rates[1].idx = -1;
+ }
+
+ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+@@ -1430,7 +1445,7 @@ ath_tx_form_burst(struct ath_softc *sc,
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ break;
+
+- ath_set_rates(tid->an->vif, tid->an->sta, bf);
++ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
+ } while (1);
+ }
+
+@@ -1461,7 +1476,7 @@ static bool ath_tx_sched_aggr(struct ath
+ return false;
+ }
+
+- ath_set_rates(tid->an->vif, tid->an->sta, bf);
++ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
+ if (aggr)
+ last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
+ tid_q, &aggr_len);
+@@ -1653,7 +1668,7 @@ void ath9k_release_buffered_frames(struc
+
+ __skb_unlink(bf->bf_mpdu, tid_q);
+ list_add_tail(&bf->list, &bf_q);
+- ath_set_rates(tid->an->vif, tid->an->sta, bf);
++ ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
+ if (bf_isampdu(bf)) {
+ ath_tx_addto_baw(sc, tid, bf);
+ bf->bf_state.bf_type &= ~BUF_AGGR;
+@@ -2318,7 +2333,7 @@ int ath_tx_start(struct ieee80211_hw *hw
+ struct ath_txq *txq = txctl->txq;
+ struct ath_atx_tid *tid = NULL;
+ struct ath_buf *bf;
+- bool queue, skip_uapsd = false, ps_resp;
++ bool queue, ps_resp;
+ int q, ret;
+
+ if (vif)
+@@ -2365,13 +2380,13 @@ int ath_tx_start(struct ieee80211_hw *hw
+ if (!txctl->an)
+ txctl->an = &avp->mcast_node;
+ queue = true;
+- skip_uapsd = true;
++ ps_resp = false;
+ }
+
+ if (txctl->an && queue)
+ tid = ath_get_skb_tid(sc, txctl->an, skb);
+
+- if (!skip_uapsd && ps_resp) {
++ if (ps_resp) {
+ ath_txq_unlock(sc, txq);
+ txq = sc->tx.uapsdq;
+ ath_txq_lock(sc, txq);
+@@ -2409,7 +2424,7 @@ int ath_tx_start(struct ieee80211_hw *hw
+ if (txctl->paprd)
+ bf->bf_state.bfs_paprd_timestamp = jiffies;
+
+- ath_set_rates(vif, sta, bf);
++ ath_set_rates(vif, sta, bf, ps_resp);
+ ath_tx_send_normal(sc, txq, tid, skb);
+
+ out:
+@@ -2448,7 +2463,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
+ break;
+
+ bf->bf_lastbf = bf;
+- ath_set_rates(vif, NULL, bf);
++ ath_set_rates(vif, NULL, bf, false);
+ ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
+ duration += info.rates[0].PktDuration;
+ if (bf_tail)
+@@ -2968,7 +2983,7 @@ int ath9k_tx99_send(struct ath_softc *sc
+ return -EINVAL;
+ }
+
+- ath_set_rates(sc->tx99_vif, NULL, bf);
++ ath_set_rates(sc->tx99_vif, NULL, bf, false);
+
+ ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
+ ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
+++ /dev/null
-From: Felix Fietkau <nbd@openwrt.org>
-Date: Sun, 21 Jun 2015 19:45:59 +0200
-Subject: [PATCH] ath9k_hw: fix device ID check for AR956x
-
-Because of the missing return, the macVersion value was being
-overwritten with an invalid register read
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -279,6 +279,7 @@ static void ath9k_hw_read_revisions(stru
- return;
- case AR9300_DEVID_QCA956X:
- ah->hw_version.macVersion = AR_SREV_VERSION_9561;
-+ return;
- }
-
- val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
-@@ -3169,6 +3170,7 @@ static struct {
- { AR_SREV_VERSION_9550, "9550" },
- { AR_SREV_VERSION_9565, "9565" },
- { AR_SREV_VERSION_9531, "9531" },
-+ { AR_SREV_VERSION_9561, "956X" },
- };
-
- /* For devices with external radios */
+++ /dev/null
-From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
-Date: Tue, 16 Jun 2015 10:34:03 +0200
-Subject: [PATCH] ath: DFS - limit number of potential PRI sequences
-
-In the PRI detector, after the current radar pulse
-has been checked agains existing PRI sequences, it
-is considered as part of a new potential sequence.
-
-Previously, the condition to accept a new sequence
-was to have at least the same number of pulses as
-the longest matching sequence. This was wrong,
-since it led to duplicates of PRI sequences.
-
-This patch changes the acceptance criteria for new
-potential sequences from 'at least' to 'more than'
-the longest existing.
-
-Detection performance remains unaffected, while
-the number of PRI sequences accounted at runtime
-(and with it CPU load) is reduced by up to 50%.
-
-Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
----
-
---- a/drivers/net/wireless/ath/dfs_pri_detector.c
-+++ b/drivers/net/wireless/ath/dfs_pri_detector.c
-@@ -273,7 +273,7 @@ static bool pseq_handler_create_sequence
- tmp_false_count++;
- }
- }
-- if (ps.count < min_count)
-+ if (ps.count <= min_count)
- /* did not reach minimum count, drop sequence */
- continue;
-
--- /dev/null
+From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
+Date: Fri, 3 Jul 2015 11:45:42 +0530
+Subject: [PATCH] ath10k: Delay device access after cold reset
+
+It is observed that during cold reset pcie access right
+after a write operation to SOC_GLOBAL_RESET_ADDRESS causes
+Data Bus Error and system hard lockup. The reason
+for bus error is that pcie needs some time to get
+back to stable state for any transaction during cold reset. Add
+delay of 20 msecs after write of SOC_GLOBAL_RESET_ADDRESS
+to fix this issue.
+
+Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
+---
+
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -2761,7 +2761,6 @@ static int ath10k_pci_wait_for_target_in
+
+ static int ath10k_pci_cold_reset(struct ath10k *ar)
+ {
+- int i;
+ u32 val;
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
+@@ -2777,23 +2776,18 @@ static int ath10k_pci_cold_reset(struct
+ val |= 1;
+ ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
+
+- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
+- if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
+- RTC_STATE_COLD_RESET_MASK)
+- break;
+- msleep(1);
+- }
++ /* After writing into SOC_GLOBAL_RESET to put device into
++ * reset and pulling out of reset pcie may not be stable
++ * for any immediate pcie register access and cause bus error,
++ * add delay before any pcie access request to fix this issue.
++ */
++ msleep(20);
+
+ /* Pull Target, including PCIe, out of RESET. */
+ val &= ~1;
+ ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
+
+- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
+- if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
+- RTC_STATE_COLD_RESET_MASK))
+- break;
+- msleep(1);
+- }
++ msleep(20);
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
+
+++ /dev/null
-From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
-Date: Tue, 16 Jun 2015 11:46:42 +0200
-Subject: [PATCH] ath9k: DFS - consider ext_channel pulses only in HT40
- mode
-
-The chip reports radar pulses on extension channel
-even if operating in HT20 mode. This patch adds a
-sanity check for HT40 mode before it feeds pulses
-on extension channel to the pattern detector.
-
-Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
----
-
---- a/drivers/net/wireless/ath/ath9k/dfs.c
-+++ b/drivers/net/wireless/ath/ath9k/dfs.c
-@@ -198,7 +198,8 @@ void ath9k_dfs_process_phyerr(struct ath
- sc->dfs_prev_pulse_ts = pe.ts;
- if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND)
- ath9k_dfs_process_radar_pulse(sc, &pe);
-- if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) {
-+ if (IS_CHAN_HT40(ah->curchan) &&
-+ ard.pulse_bw_info & EXT_CH_RADAR_FOUND) {
- pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20;
- ath9k_dfs_process_radar_pulse(sc, &pe);
- }
--- /dev/null
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Mon, 11 May 2015 18:35:20 +0200
+Subject: [PATCH] ath9k: add fast-xmit support
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -826,6 +826,7 @@ static void ath9k_set_hw_capab(struct at
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, RX_INCLUDES_FCS);
+ ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
++ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
+
+ if (ath9k_ps_enable)
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+++ /dev/null
-From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
-Date: Tue, 16 Jun 2015 12:52:16 +0200
-Subject: [PATCH] ath9k: DFS - add pulse chirp detection for FCC
-
-FCC long pulse radar (type 5) requires pulses to be
-checked for chirping. This patch implements chirp
-detection based on the FFT data provided for long
-pulses.
-
-A chirp is detected when a set of criteria defined
-by FCC pulse characteristics is met, including
-* have at least 4 FFT samples
-* max_bin index moves equidistantly between samples
-* the gradient is within defined range
-
-The chirp detection has been tested with reference
-radar generating devices and proved to work reliably.
-
-Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
----
-
---- a/drivers/net/wireless/ath/ath9k/dfs.c
-+++ b/drivers/net/wireless/ath/ath9k/dfs.c
-@@ -30,6 +30,157 @@ struct ath_radar_data {
- u8 pulse_length_pri;
- };
-
-+/**** begin: CHIRP ************************************************************/
-+
-+/* min and max gradients for defined FCC chirping pulses, given by
-+ * - 20MHz chirp width over a pulse width of 50us
-+ * - 5MHz chirp width over a pulse width of 100us
-+ */
-+static const int BIN_DELTA_MIN = 1;
-+static const int BIN_DELTA_MAX = 10;
-+
-+/* we need at least 3 deltas / 4 samples for a reliable chirp detection */
-+#define NUM_DIFFS 3
-+static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1);
-+
-+/* Threshold for difference of delta peaks */
-+static const int MAX_DIFF = 2;
-+
-+/* width range to be checked for chirping */
-+static const int MIN_CHIRP_PULSE_WIDTH = 20;
-+static const int MAX_CHIRP_PULSE_WIDTH = 110;
-+
-+struct ath9k_dfs_fft_20 {
-+ u8 bin[28];
-+ u8 lower_bins[3];
-+} __packed;
-+struct ath9k_dfs_fft_40 {
-+ u8 bin[64];
-+ u8 lower_bins[3];
-+ u8 upper_bins[3];
-+} __packed;
-+
-+static inline int fft_max_index(u8 *bins)
-+{
-+ return (bins[2] & 0xfc) >> 2;
-+}
-+static inline int fft_max_magnitude(u8 *bins)
-+{
-+ return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10;
-+}
-+static inline u8 fft_bitmap_weight(u8 *bins)
-+{
-+ return bins[0] & 0x3f;
-+}
-+
-+static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft,
-+ bool is_ctl, bool is_ext)
-+{
-+ const int DFS_UPPER_BIN_OFFSET = 64;
-+ /* if detected radar on both channels, select the significant one */
-+ if (is_ctl && is_ext) {
-+ /* first check wether channels have 'strong' bins */
-+ is_ctl = fft_bitmap_weight(fft->lower_bins) != 0;
-+ is_ext = fft_bitmap_weight(fft->upper_bins) != 0;
-+
-+ /* if still unclear, take higher magnitude */
-+ if (is_ctl && is_ext) {
-+ int mag_lower = fft_max_magnitude(fft->lower_bins);
-+ int mag_upper = fft_max_magnitude(fft->upper_bins);
-+ if (mag_upper > mag_lower)
-+ is_ctl = false;
-+ else
-+ is_ext = false;
-+ }
-+ }
-+ if (is_ctl)
-+ return fft_max_index(fft->lower_bins);
-+ return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET;
-+}
-+static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
-+ int datalen, bool is_ctl, bool is_ext)
-+{
-+ int i;
-+ int max_bin[FFT_NUM_SAMPLES];
-+ struct ath_hw *ah = sc->sc_ah;
-+ struct ath_common *common = ath9k_hw_common(ah);
-+ int prev_delta;
-+
-+ if (IS_CHAN_HT40(ah->curchan)) {
-+ struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data;
-+ int num_fft_packets = datalen / sizeof(*fft);
-+ if (num_fft_packets == 0)
-+ return false;
-+
-+ ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n",
-+ datalen, num_fft_packets);
-+ if (num_fft_packets < (FFT_NUM_SAMPLES)) {
-+ ath_dbg(common, DFS, "not enough packets for chirp\n");
-+ return false;
-+ }
-+ /* HW sometimes adds 2 garbage bytes in front of FFT samples */
-+ if ((datalen % sizeof(*fft)) == 2) {
-+ fft = (struct ath9k_dfs_fft_40 *) (data + 2);
-+ ath_dbg(common, DFS, "fixing datalen by 2\n");
-+ }
-+ if (IS_CHAN_HT40MINUS(ah->curchan)) {
-+ int temp = is_ctl;
-+ is_ctl = is_ext;
-+ is_ext = temp;
-+ }
-+ for (i = 0; i < FFT_NUM_SAMPLES; i++)
-+ max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
-+ is_ext);
-+ } else {
-+ struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data;
-+ int num_fft_packets = datalen / sizeof(*fft);
-+ if (num_fft_packets == 0)
-+ return false;
-+ ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n",
-+ datalen, num_fft_packets);
-+ if (num_fft_packets < (FFT_NUM_SAMPLES)) {
-+ ath_dbg(common, DFS, "not enough packets for chirp\n");
-+ return false;
-+ }
-+ /* in ht20, this is a 6-bit signed number => shift it to 0 */
-+ for (i = 0; i < FFT_NUM_SAMPLES; i++)
-+ max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20;
-+ }
-+ ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n",
-+ max_bin[0], max_bin[1], max_bin[2], max_bin[3]);
-+
-+ /* Check for chirp attributes within specs
-+ * a) delta of adjacent max_bins is within range
-+ * b) delta of adjacent deltas are within tolerance
-+ */
-+ prev_delta = 0;
-+ for (i = 0; i < NUM_DIFFS; i++) {
-+ int ddelta = -1;
-+ int delta = max_bin[i + 1] - max_bin[i];
-+
-+ /* ensure gradient is within valid range */
-+ if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) {
-+ ath_dbg(common, DFS, "CHIRP: invalid delta %d "
-+ "in sample %d\n", delta, i);
-+ return false;
-+ }
-+ if (i == 0)
-+ goto done;
-+ ddelta = delta - prev_delta;
-+ if (abs(ddelta) > MAX_DIFF) {
-+ ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n",
-+ ddelta);
-+ return false;
-+ }
-+done:
-+ ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n",
-+ i, delta, ddelta);
-+ prev_delta = delta;
-+ }
-+ return true;
-+}
-+/**** end: CHIRP **************************************************************/
-+
- /* convert pulse duration to usecs, considering clock mode */
- static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)
- {
-@@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath
- return false;
- }
-
-- /*
-- * TODO: check chirping pulses
-- * checks for chirping are dependent on the DFS regulatory domain
-- * used, which is yet TBD
-- */
--
- /* convert duration to usecs */
- pe->width = dur_to_usecs(sc->sc_ah, dur);
- pe->rssi = rssi;
-@@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath
- if (!ath9k_postprocess_radar_event(sc, &ard, &pe))
- return;
-
-+ if (pe.width > MIN_CHIRP_PULSE_WIDTH &&
-+ pe.width < MAX_CHIRP_PULSE_WIDTH) {
-+ bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND);
-+ bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND);
-+ int clen = datalen - 3;
-+ pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext);
-+ } else {
-+ pe.chirp = false;
-+ }
-+
- ath_dbg(common, DFS,
- "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "
- "width=%d, rssi=%d, delta_ts=%llu\n",
--- /dev/null
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 4 Apr 2015 18:39:06 +0200
+Subject: [PATCH] ath9k: remove struct ath_atx_ac
+
+struct ath_atx_ac contains a list of active TIDs belonging to one WMM AC.
+This patch changes the code to track active station TIDs in the txq directly.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -173,14 +173,6 @@ struct ath_txq {
+ struct sk_buff_head complete_q;
+ };
+
+-struct ath_atx_ac {
+- struct ath_txq *txq;
+- struct list_head list;
+- struct list_head tid_q;
+- bool clear_ps_filter;
+- bool sched;
+-};
+-
+ struct ath_frame_info {
+ struct ath_buf *bf;
+ u16 framelen;
+@@ -243,7 +235,7 @@ struct ath_atx_tid {
+ struct sk_buff_head buf_q;
+ struct sk_buff_head retry_q;
+ struct ath_node *an;
+- struct ath_atx_ac *ac;
++ struct ath_txq *txq;
+ unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
+ u16 seq_start;
+ u16 seq_next;
+@@ -255,6 +247,7 @@ struct ath_atx_tid {
+ s8 bar_index;
+ bool sched;
+ bool active;
++ bool clear_ps_filter;
+ };
+
+ struct ath_node {
+@@ -262,7 +255,6 @@ struct ath_node {
+ struct ieee80211_sta *sta; /* station struct we're part of */
+ struct ieee80211_vif *vif; /* interface with which we're associated */
+ struct ath_atx_tid tid[IEEE80211_NUM_TIDS];
+- struct ath_atx_ac ac[IEEE80211_NUM_ACS];
+
+ u16 maxampdu;
+ u8 mpdudensity;
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -106,7 +106,6 @@ void ath_txq_unlock_complete(struct ath_
+ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_atx_tid *tid)
+ {
+- struct ath_atx_ac *ac = tid->ac;
+ struct list_head *list;
+ struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
+ struct ath_chanctx *ctx = avp->chanctx;
+@@ -118,15 +117,8 @@ static void ath_tx_queue_tid(struct ath_
+ return;
+
+ tid->sched = true;
+- list_add_tail(&tid->list, &ac->tid_q);
+-
+- if (ac->sched)
+- return;
+-
+- ac->sched = true;
+-
+ list = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
+- list_add_tail(&ac->list, list);
++ list_add_tail(&tid->list, list);
+ }
+
+ static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
+@@ -223,7 +215,7 @@ static struct sk_buff *ath_tid_dequeue(s
+ static void
+ ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
+ {
+- struct ath_txq *txq = tid->ac->txq;
++ struct ath_txq *txq = tid->txq;
+ struct ieee80211_tx_info *tx_info;
+ struct sk_buff *skb, *tskb;
+ struct ath_buf *bf;
+@@ -252,7 +244,7 @@ ath_tx_tid_change_state(struct ath_softc
+
+ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+ {
+- struct ath_txq *txq = tid->ac->txq;
++ struct ath_txq *txq = tid->txq;
+ struct sk_buff *skb;
+ struct ath_buf *bf;
+ struct list_head bf_head;
+@@ -659,7 +651,7 @@ static void ath_tx_complete_aggr(struct
+ ath_tx_queue_tid(sc, txq, tid);
+
+ if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
+- tid->ac->clear_ps_filter = true;
++ tid->clear_ps_filter = true;
+ }
+ }
+
+@@ -749,7 +741,7 @@ static u32 ath_lookup_rate(struct ath_so
+ struct ieee80211_tx_rate *rates;
+ u32 max_4ms_framelen, frmlen;
+ u16 aggr_limit, bt_aggr_limit, legacy = 0;
+- int q = tid->ac->txq->mac80211_qnum;
++ int q = tid->txq->mac80211_qnum;
+ int i;
+
+ skb = bf->bf_mpdu;
+@@ -1486,8 +1478,8 @@ static bool ath_tx_sched_aggr(struct ath
+ if (list_empty(&bf_q))
+ return false;
+
+- if (tid->ac->clear_ps_filter || tid->an->no_ps_filter) {
+- tid->ac->clear_ps_filter = false;
++ if (tid->clear_ps_filter || tid->an->no_ps_filter) {
++ tid->clear_ps_filter = false;
+ tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+ }
+
+@@ -1506,7 +1498,7 @@ int ath_tx_aggr_start(struct ath_softc *
+
+ an = (struct ath_node *)sta->drv_priv;
+ txtid = ATH_AN_2_TID(an, tid);
+- txq = txtid->ac->txq;
++ txq = txtid->txq;
+
+ ath_txq_lock(sc, txq);
+
+@@ -1540,7 +1532,7 @@ void ath_tx_aggr_stop(struct ath_softc *
+ {
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
+ struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
+- struct ath_txq *txq = txtid->ac->txq;
++ struct ath_txq *txq = txtid->txq;
+
+ ath_txq_lock(sc, txq);
+ txtid->active = false;
+@@ -1553,7 +1545,6 @@ void ath_tx_aggr_sleep(struct ieee80211_
+ struct ath_node *an)
+ {
+ struct ath_atx_tid *tid;
+- struct ath_atx_ac *ac;
+ struct ath_txq *txq;
+ bool buffered;
+ int tidno;
+@@ -1561,8 +1552,7 @@ void ath_tx_aggr_sleep(struct ieee80211_
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+
+- ac = tid->ac;
+- txq = ac->txq;
++ txq = tid->txq;
+
+ ath_txq_lock(sc, txq);
+
+@@ -1576,11 +1566,6 @@ void ath_tx_aggr_sleep(struct ieee80211_
+ tid->sched = false;
+ list_del(&tid->list);
+
+- if (ac->sched) {
+- ac->sched = false;
+- list_del(&ac->list);
+- }
+-
+ ath_txq_unlock(sc, txq);
+
+ ieee80211_sta_set_buffered(sta, tidno, buffered);
+@@ -1590,18 +1575,16 @@ void ath_tx_aggr_sleep(struct ieee80211_
+ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
+ {
+ struct ath_atx_tid *tid;
+- struct ath_atx_ac *ac;
+ struct ath_txq *txq;
+ int tidno;
+
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+
+- ac = tid->ac;
+- txq = ac->txq;
++ txq = tid->txq;
+
+ ath_txq_lock(sc, txq);
+- ac->clear_ps_filter = true;
++ tid->clear_ps_filter = true;
+
+ if (ath_tid_has_buffered(tid)) {
+ ath_tx_queue_tid(sc, txq, tid);
+@@ -1621,7 +1604,7 @@ void ath_tx_aggr_resume(struct ath_softc
+
+ an = (struct ath_node *)sta->drv_priv;
+ tid = ATH_AN_2_TID(an, tidno);
+- txq = tid->ac->txq;
++ txq = tid->txq;
+
+ ath_txq_lock(sc, txq);
+
+@@ -1660,7 +1643,7 @@ void ath9k_release_buffered_frames(struc
+
+ tid = ATH_AN_2_TID(an, i);
+
+- ath_txq_lock(sc, tid->ac->txq);
++ ath_txq_lock(sc, tid->txq);
+ while (nframes > 0) {
+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ if (!bf)
+@@ -1684,7 +1667,7 @@ void ath9k_release_buffered_frames(struc
+ if (an->sta && !ath_tid_has_buffered(tid))
+ ieee80211_sta_set_buffered(an->sta, i, false);
+ }
+- ath_txq_unlock_complete(sc, tid->ac->txq);
++ ath_txq_unlock_complete(sc, tid->txq);
+ }
+
+ if (list_empty(&bf_q))
+@@ -1933,9 +1916,8 @@ void ath_tx_cleanupq(struct ath_softc *s
+ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
+ {
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+- struct ath_atx_ac *ac, *last_ac;
+ struct ath_atx_tid *tid, *last_tid;
+- struct list_head *ac_list;
++ struct list_head *tid_list;
+ bool sent = false;
+
+ if (txq->mac80211_qnum < 0)
+@@ -1945,63 +1927,46 @@ void ath_txq_schedule(struct ath_softc *
+ return;
+
+ spin_lock_bh(&sc->chan_lock);
+- ac_list = &sc->cur_chan->acq[txq->mac80211_qnum];
++ tid_list = &sc->cur_chan->acq[txq->mac80211_qnum];
+
+- if (list_empty(ac_list)) {
++ if (list_empty(tid_list)) {
+ spin_unlock_bh(&sc->chan_lock);
+ return;
+ }
+
+ rcu_read_lock();
+
+- last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list);
+- while (!list_empty(ac_list)) {
++ last_tid = list_entry(tid_list->prev, struct ath_atx_tid, list);
++ while (!list_empty(tid_list)) {
+ bool stop = false;
+
+ if (sc->cur_chan->stopped)
+ break;
+
+- ac = list_first_entry(ac_list, struct ath_atx_ac, list);
+- last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
+- list_del(&ac->list);
+- ac->sched = false;
+-
+- while (!list_empty(&ac->tid_q)) {
+-
+- tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
+- list);
+- list_del(&tid->list);
+- tid->sched = false;
+-
+- if (ath_tx_sched_aggr(sc, txq, tid, &stop))
+- sent = true;
+-
+- /*
+- * add tid to round-robin queue if more frames
+- * are pending for the tid
+- */
+- if (ath_tid_has_buffered(tid))
+- ath_tx_queue_tid(sc, txq, tid);
++ tid = list_first_entry(tid_list, struct ath_atx_tid, list);
++ list_del(&tid->list);
++ tid->sched = false;
+
+- if (stop || tid == last_tid)
+- break;
+- }
++ if (ath_tx_sched_aggr(sc, txq, tid, &stop))
++ sent = true;
+
+- if (!list_empty(&ac->tid_q) && !ac->sched) {
+- ac->sched = true;
+- list_add_tail(&ac->list, ac_list);
+- }
++ /*
++ * add tid to round-robin queue if more frames
++ * are pending for the tid
++ */
++ if (ath_tid_has_buffered(tid))
++ ath_tx_queue_tid(sc, txq, tid);
+
+ if (stop)
+ break;
+
+- if (ac == last_ac) {
++ if (tid == last_tid) {
+ if (!sent)
+ break;
+
+ sent = false;
+- last_ac = list_entry(ac_list->prev,
+- struct ath_atx_ac, list);
++ last_tid = list_entry(tid_list->prev,
++ struct ath_atx_tid, list);
+ }
+ }
+
+@@ -2391,10 +2356,10 @@ int ath_tx_start(struct ieee80211_hw *hw
+ txq = sc->tx.uapsdq;
+ ath_txq_lock(sc, txq);
+ } else if (txctl->an && queue) {
+- WARN_ON(tid->ac->txq != txctl->txq);
++ WARN_ON(tid->txq != txctl->txq);
+
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+- tid->ac->clear_ps_filter = true;
++ tid->clear_ps_filter = true;
+
+ /*
+ * Add this frame to software queue for scheduling later
+@@ -2888,7 +2853,6 @@ int ath_tx_init(struct ath_softc *sc, in
+ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
+ {
+ struct ath_atx_tid *tid;
+- struct ath_atx_ac *ac;
+ int tidno, acno;
+
+ for (tidno = 0, tid = &an->tid[tidno];
+@@ -2901,24 +2865,16 @@ void ath_tx_node_init(struct ath_softc *
+ tid->baw_head = tid->baw_tail = 0;
+ tid->sched = false;
+ tid->active = false;
++ tid->clear_ps_filter = true;
+ __skb_queue_head_init(&tid->buf_q);
+ __skb_queue_head_init(&tid->retry_q);
+ acno = TID_TO_WME_AC(tidno);
+- tid->ac = &an->ac[acno];
+- }
+-
+- for (acno = 0, ac = &an->ac[acno];
+- acno < IEEE80211_NUM_ACS; acno++, ac++) {
+- ac->sched = false;
+- ac->clear_ps_filter = true;
+- ac->txq = sc->tx.txq_map[acno];
+- INIT_LIST_HEAD(&ac->tid_q);
++ tid->txq = sc->tx.txq_map[acno];
+ }
+ }
+
+ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
+ {
+- struct ath_atx_ac *ac;
+ struct ath_atx_tid *tid;
+ struct ath_txq *txq;
+ int tidno;
+@@ -2926,8 +2882,7 @@ void ath_tx_node_cleanup(struct ath_soft
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+
+- ac = tid->ac;
+- txq = ac->txq;
++ txq = tid->txq;
+
+ ath_txq_lock(sc, txq);
+
+@@ -2936,11 +2891,6 @@ void ath_tx_node_cleanup(struct ath_soft
+ tid->sched = false;
+ }
+
+- if (ac->sched) {
+- list_del(&ac->list);
+- tid->ac->sched = false;
+- }
+-
+ ath_tid_drain(sc, txq, tid);
+ tid->active = false;
+
+++ /dev/null
-From: Felix Fietkau <nbd@openwrt.org>
-Date: Thu, 2 Jul 2015 13:35:05 +0200
-Subject: [PATCH] ath9k: make DMA stop related messages debug-only
-
-A long time ago, ath9k had issues during reset where the DMA engine
-would stay active and could potentially corrupt memory.
-To debug those issues, the driver would print warnings whenever they
-occur.
-
-Nowadays, these issues are gone and the primary cause of these messages
-is if the MAC is stuck during reset or busy processing a long
-transmission. This is fairly harmless, yet these messages continue to
-worry users.
-
-To reduce the number of bogus bug reports, turn these messages into
-debug messages and count their occurence in the "reset" debugfs file.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -765,6 +765,8 @@ static int read_file_reset(struct seq_fi
- [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
- [RESET_TYPE_MCI] = "MCI Reset",
- [RESET_TYPE_CALIBRATION] = "Calibration error",
-+ [RESET_TX_DMA_ERROR] = "Tx DMA stop error",
-+ [RESET_RX_DMA_ERROR] = "Rx DMA stop error",
- };
- int i;
-
---- a/drivers/net/wireless/ath/ath9k/debug.h
-+++ b/drivers/net/wireless/ath/ath9k/debug.h
-@@ -50,6 +50,8 @@ enum ath_reset_type {
- RESET_TYPE_BEACON_STUCK,
- RESET_TYPE_MCI,
- RESET_TYPE_CALIBRATION,
-+ RESET_TX_DMA_ERROR,
-+ RESET_RX_DMA_ERROR,
- __RESET_TYPE_MAX
- };
-
---- a/drivers/net/wireless/ath/ath9k/recv.c
-+++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -491,10 +491,9 @@ bool ath_stoprecv(struct ath_softc *sc)
-
- if (!(ah->ah_flags & AH_UNPLUGGED) &&
- unlikely(!stopped)) {
-- ath_err(ath9k_hw_common(sc->sc_ah),
-- "Could not stop RX, we could be "
-- "confusing the DMA engine when we start RX up\n");
-- ATH_DBG_WARN_ON_ONCE(!stopped);
-+ ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-+ "Failed to stop Rx DMA\n");
-+ RESET_STAT_INC(sc, RESET_RX_DMA_ERROR);
- }
- return stopped && !reset;
- }
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -1883,8 +1883,11 @@ bool ath_drain_all_txq(struct ath_softc
- npend |= BIT(i);
- }
-
-- if (npend)
-- ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend);
-+ if (npend) {
-+ RESET_STAT_INC(sc, RESET_TX_DMA_ERROR);
-+ ath_dbg(common, RESET,
-+ "Failed to stop TX DMA, queues=0x%03x!\n", npend);
-+ }
-
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
- if (!ATH_TXQ_SETUP(sc, i))
--- /dev/null
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Sat, 4 Apr 2015 18:42:33 +0200
+Subject: [PATCH] ath9k: remove the sched field in struct ath_atx_tid
+
+Use list_empty(&tid->list) instead
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -245,7 +245,6 @@ struct ath_atx_tid {
+ int baw_tail; /* next unused tx buffer slot */
+
+ s8 bar_index;
+- bool sched;
+ bool active;
+ bool clear_ps_filter;
+ };
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -113,12 +113,9 @@ static void ath_tx_queue_tid(struct ath_
+ if (!ctx)
+ return;
+
+- if (tid->sched)
+- return;
+-
+- tid->sched = true;
+ list = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
+- list_add_tail(&tid->list, list);
++ if (list_empty(&tid->list))
++ list_add_tail(&tid->list, list);
+ }
+
+ static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
+@@ -1556,15 +1553,14 @@ void ath_tx_aggr_sleep(struct ieee80211_
+
+ ath_txq_lock(sc, txq);
+
+- if (!tid->sched) {
++ if (list_empty(&tid->list)) {
+ ath_txq_unlock(sc, txq);
+ continue;
+ }
+
+ buffered = ath_tid_has_buffered(tid);
+
+- tid->sched = false;
+- list_del(&tid->list);
++ list_del_init(&tid->list);
+
+ ath_txq_unlock(sc, txq);
+
+@@ -1944,8 +1940,7 @@ void ath_txq_schedule(struct ath_softc *
+ break;
+
+ tid = list_first_entry(tid_list, struct ath_atx_tid, list);
+- list_del(&tid->list);
+- tid->sched = false;
++ list_del_init(&tid->list);
+
+ if (ath_tx_sched_aggr(sc, txq, tid, &stop))
+ sent = true;
+@@ -2863,11 +2858,11 @@ void ath_tx_node_init(struct ath_softc *
+ tid->seq_start = tid->seq_next = 0;
+ tid->baw_size = WME_MAX_BA;
+ tid->baw_head = tid->baw_tail = 0;
+- tid->sched = false;
+ tid->active = false;
+ tid->clear_ps_filter = true;
+ __skb_queue_head_init(&tid->buf_q);
+ __skb_queue_head_init(&tid->retry_q);
++ INIT_LIST_HEAD(&tid->list);
+ acno = TID_TO_WME_AC(tidno);
+ tid->txq = sc->tx.txq_map[acno];
+ }
+@@ -2886,10 +2881,8 @@ void ath_tx_node_cleanup(struct ath_soft
+
+ ath_txq_lock(sc, txq);
+
+- if (tid->sched) {
+- list_del(&tid->list);
+- tid->sched = false;
+- }
++ if (!list_empty(&tid->list))
++ list_del_init(&tid->list);
+
+ ath_tid_drain(sc, txq, tid);
+ tid->active = false;
+++ /dev/null
-From: Felix Fietkau <nbd@openwrt.org>
-Date: Thu, 2 Jul 2015 15:20:56 +0200
-Subject: [PATCH] ath9k: limit retries for powersave response frames
-
-In some cases, the channel might be busy enough that an ath9k AP's
-response to PS-Poll frames might be too slow and the station has already
-gone to sleep. To avoid wasting too much airtime on this, limit the
-number of retries on such frames and ensure that no sample rate gets
-used.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
----
-
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -147,10 +147,25 @@ static void ath_send_bar(struct ath_atx_
- }
-
- static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-- struct ath_buf *bf)
-+ struct ath_buf *bf, bool ps)
- {
-+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu);
-+
-+ if (ps) {
-+ /* Clear the first rate to avoid using a sample rate for PS frames */
-+ info->control.rates[0].idx = -1;
-+ info->control.rates[0].count = 0;
-+ }
-+
- ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
- ARRAY_SIZE(bf->rates));
-+ if (!ps)
-+ return;
-+
-+ if (bf->rates[0].count > 2)
-+ bf->rates[0].count = 2;
-+
-+ bf->rates[1].idx = -1;
- }
-
- static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
-@@ -1430,7 +1445,7 @@ ath_tx_form_burst(struct ath_softc *sc,
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
- break;
-
-- ath_set_rates(tid->an->vif, tid->an->sta, bf);
-+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
- } while (1);
- }
-
-@@ -1461,7 +1476,7 @@ static bool ath_tx_sched_aggr(struct ath
- return false;
- }
-
-- ath_set_rates(tid->an->vif, tid->an->sta, bf);
-+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false);
- if (aggr)
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
-@@ -1653,7 +1668,7 @@ void ath9k_release_buffered_frames(struc
-
- __skb_unlink(bf->bf_mpdu, tid_q);
- list_add_tail(&bf->list, &bf_q);
-- ath_set_rates(tid->an->vif, tid->an->sta, bf);
-+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true);
- if (bf_isampdu(bf)) {
- ath_tx_addto_baw(sc, tid, bf);
- bf->bf_state.bf_type &= ~BUF_AGGR;
-@@ -2318,7 +2333,7 @@ int ath_tx_start(struct ieee80211_hw *hw
- struct ath_txq *txq = txctl->txq;
- struct ath_atx_tid *tid = NULL;
- struct ath_buf *bf;
-- bool queue, skip_uapsd = false, ps_resp;
-+ bool queue, ps_resp;
- int q, ret;
-
- if (vif)
-@@ -2365,13 +2380,13 @@ int ath_tx_start(struct ieee80211_hw *hw
- if (!txctl->an)
- txctl->an = &avp->mcast_node;
- queue = true;
-- skip_uapsd = true;
-+ ps_resp = false;
- }
-
- if (txctl->an && queue)
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
-- if (!skip_uapsd && ps_resp) {
-+ if (ps_resp) {
- ath_txq_unlock(sc, txq);
- txq = sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
-@@ -2409,7 +2424,7 @@ int ath_tx_start(struct ieee80211_hw *hw
- if (txctl->paprd)
- bf->bf_state.bfs_paprd_timestamp = jiffies;
-
-- ath_set_rates(vif, sta, bf);
-+ ath_set_rates(vif, sta, bf, ps_resp);
- ath_tx_send_normal(sc, txq, tid, skb);
-
- out:
-@@ -2448,7 +2463,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
- break;
-
- bf->bf_lastbf = bf;
-- ath_set_rates(vif, NULL, bf);
-+ ath_set_rates(vif, NULL, bf, false);
- ath_buf_set_rate(sc, bf, &info, fi->framelen, false);
- duration += info.rates[0].PktDuration;
- if (bf_tail)
-@@ -2968,7 +2983,7 @@ int ath9k_tx99_send(struct ath_softc *sc
- return -EINVAL;
- }
-
-- ath_set_rates(sc->tx99_vif, NULL, bf);
-+ ath_set_rates(sc->tx99_vif, NULL, bf, false);
-
- ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
- ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);
--- /dev/null
+From: Denys Vlasenko <dvlasenk@redhat.com>
+Date: Wed, 15 Jul 2015 14:56:06 +0200
+Subject: [PATCH] mac80211: Deinline rate_control_rate_init,
+ rate_control_rate_update
+
+With this .config: http://busybox.net/~vda/kernel_config,
+after deinlining these functions have sizes and callsite counts
+as follows:
+
+rate_control_rate_init: 554 bytes, 8 calls
+rate_control_rate_update: 1596 bytes, 5 calls
+
+Total size reduction: about 11 kbytes.
+
+Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
+CC: John Linville <linville@tuxdriver.com>
+CC: Michal Kazior <michal.kazior@tieto.com>
+CC: Johannes Berg <johannes.berg@intel.com>
+Cc: linux-wireless@vger.kernel.org
+Cc: netdev@vger.kernel.org
+CC: linux-kernel@vger.kernel.org
+---
+
+--- a/net/mac80211/rate.c
++++ b/net/mac80211/rate.c
+@@ -29,6 +29,65 @@ module_param(ieee80211_default_rc_algo,
+ MODULE_PARM_DESC(ieee80211_default_rc_algo,
+ "Default rate control algorithm for mac80211 to use");
+
++void rate_control_rate_init(struct sta_info *sta)
++{
++ struct ieee80211_local *local = sta->sdata->local;
++ struct rate_control_ref *ref = sta->rate_ctrl;
++ struct ieee80211_sta *ista = &sta->sta;
++ void *priv_sta = sta->rate_ctrl_priv;
++ struct ieee80211_supported_band *sband;
++ struct ieee80211_chanctx_conf *chanctx_conf;
++
++ ieee80211_sta_set_rx_nss(sta);
++
++ if (!ref)
++ return;
++
++ rcu_read_lock();
++
++ chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
++ if (WARN_ON(!chanctx_conf)) {
++ rcu_read_unlock();
++ return;
++ }
++
++ sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
++
++ spin_lock_bh(&sta->rate_ctrl_lock);
++ ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
++ priv_sta);
++ spin_unlock_bh(&sta->rate_ctrl_lock);
++ rcu_read_unlock();
++ set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
++}
++
++void rate_control_rate_update(struct ieee80211_local *local,
++ struct ieee80211_supported_band *sband,
++ struct sta_info *sta, u32 changed)
++{
++ struct rate_control_ref *ref = local->rate_ctrl;
++ struct ieee80211_sta *ista = &sta->sta;
++ void *priv_sta = sta->rate_ctrl_priv;
++ struct ieee80211_chanctx_conf *chanctx_conf;
++
++ if (ref && ref->ops->rate_update) {
++ rcu_read_lock();
++
++ chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
++ if (WARN_ON(!chanctx_conf)) {
++ rcu_read_unlock();
++ return;
++ }
++
++ spin_lock_bh(&sta->rate_ctrl_lock);
++ ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
++ ista, priv_sta, changed);
++ spin_unlock_bh(&sta->rate_ctrl_lock);
++ rcu_read_unlock();
++ }
++ drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
++}
++
+ int ieee80211_rate_control_register(const struct rate_control_ops *ops)
+ {
+ struct rate_control_alg *alg;
+--- a/net/mac80211/rate.h
++++ b/net/mac80211/rate.h
+@@ -71,64 +71,10 @@ rate_control_tx_status_noskb(struct ieee
+ spin_unlock_bh(&sta->rate_ctrl_lock);
+ }
+
+-static inline void rate_control_rate_init(struct sta_info *sta)
+-{
+- struct ieee80211_local *local = sta->sdata->local;
+- struct rate_control_ref *ref = sta->rate_ctrl;
+- struct ieee80211_sta *ista = &sta->sta;
+- void *priv_sta = sta->rate_ctrl_priv;
+- struct ieee80211_supported_band *sband;
+- struct ieee80211_chanctx_conf *chanctx_conf;
+-
+- ieee80211_sta_set_rx_nss(sta);
+-
+- if (!ref)
+- return;
+-
+- rcu_read_lock();
+-
+- chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
+- if (WARN_ON(!chanctx_conf)) {
+- rcu_read_unlock();
+- return;
+- }
+-
+- sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
+-
+- spin_lock_bh(&sta->rate_ctrl_lock);
+- ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
+- priv_sta);
+- spin_unlock_bh(&sta->rate_ctrl_lock);
+- rcu_read_unlock();
+- set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
+-}
+-
+-static inline void rate_control_rate_update(struct ieee80211_local *local,
++void rate_control_rate_init(struct sta_info *sta);
++void rate_control_rate_update(struct ieee80211_local *local,
+ struct ieee80211_supported_band *sband,
+- struct sta_info *sta, u32 changed)
+-{
+- struct rate_control_ref *ref = local->rate_ctrl;
+- struct ieee80211_sta *ista = &sta->sta;
+- void *priv_sta = sta->rate_ctrl_priv;
+- struct ieee80211_chanctx_conf *chanctx_conf;
+-
+- if (ref && ref->ops->rate_update) {
+- rcu_read_lock();
+-
+- chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf);
+- if (WARN_ON(!chanctx_conf)) {
+- rcu_read_unlock();
+- return;
+- }
+-
+- spin_lock_bh(&sta->rate_ctrl_lock);
+- ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
+- ista, priv_sta, changed);
+- spin_unlock_bh(&sta->rate_ctrl_lock);
+- rcu_read_unlock();
+- }
+- drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
+-}
++ struct sta_info *sta, u32 changed);
+
+ static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
+ struct sta_info *sta, gfp_t gfp)
+++ /dev/null
-From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
-Date: Fri, 3 Jul 2015 11:45:42 +0530
-Subject: [PATCH] ath10k: Delay device access after cold reset
-
-It is observed that during cold reset pcie access right
-after a write operation to SOC_GLOBAL_RESET_ADDRESS causes
-Data Bus Error and system hard lockup. The reason
-for bus error is that pcie needs some time to get
-back to stable state for any transaction during cold reset. Add
-delay of 20 msecs after write of SOC_GLOBAL_RESET_ADDRESS
-to fix this issue.
-
-Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
----
-
---- a/drivers/net/wireless/ath/ath10k/pci.c
-+++ b/drivers/net/wireless/ath/ath10k/pci.c
-@@ -2602,7 +2602,6 @@ static int ath10k_pci_wait_for_target_in
-
- static int ath10k_pci_cold_reset(struct ath10k *ar)
- {
-- int i;
- u32 val;
-
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
-@@ -2618,23 +2617,18 @@ static int ath10k_pci_cold_reset(struct
- val |= 1;
- ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
-
-- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-- if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
-- RTC_STATE_COLD_RESET_MASK)
-- break;
-- msleep(1);
-- }
-+ /* After writing into SOC_GLOBAL_RESET to put device into
-+ * reset and pulling out of reset pcie may not be stable
-+ * for any immediate pcie register access and cause bus error,
-+ * add delay before any pcie access request to fix this issue.
-+ */
-+ msleep(20);
-
- /* Pull Target, including PCIe, out of RESET. */
- val &= ~1;
- ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
-
-- for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-- if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
-- RTC_STATE_COLD_RESET_MASK))
-- break;
-- msleep(1);
-- }
-+ msleep(20);
-
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
-
--- /dev/null
+From: Denys Vlasenko <dvlasenk@redhat.com>
+Date: Wed, 15 Jul 2015 14:56:05 +0200
+Subject: [PATCH] mac80211: Deinline drv_sta_state
+
+With this .config: http://busybox.net/~vda/kernel_config,
+after deinlining the function size is 3132 bytes and there are
+7 callsites.
+
+Total size reduction: about 20 kbytes.
+
+Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
+CC: John Linville <linville@tuxdriver.com>
+CC: Michal Kazior <michal.kazior@tieto.com>
+Cc: Johannes Berg <johannes.berg@intel.com>
+Cc: linux-wireless@vger.kernel.org
+Cc: netdev@vger.kernel.org
+CC: linux-kernel@vger.kernel.org
+---
+ create mode 100644 net/mac80211/driver-ops.c
+
+--- a/net/mac80211/Makefile
++++ b/net/mac80211/Makefile
+@@ -3,6 +3,7 @@ obj-$(CPTCFG_MAC80211) += mac80211.o
+ # mac80211 objects
+ mac80211-y := \
+ main.o status.o \
++ driver-ops.o \
+ sta_info.o \
+ wep.o \
+ wpa.o \
+--- /dev/null
++++ b/net/mac80211/driver-ops.c
+@@ -0,0 +1,41 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <net/mac80211.h>
++#include "ieee80211_i.h"
++#include "trace.h"
++#include "driver-ops.h"
++
++__must_check
++int drv_sta_state(struct ieee80211_local *local,
++ struct ieee80211_sub_if_data *sdata,
++ struct sta_info *sta,
++ enum ieee80211_sta_state old_state,
++ enum ieee80211_sta_state new_state)
++{
++ int ret = 0;
++
++ might_sleep();
++
++ sdata = get_bss_sdata(sdata);
++ if (!check_sdata_in_driver(sdata))
++ return -EIO;
++
++ trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
++ if (local->ops->sta_state) {
++ ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
++ old_state, new_state);
++ } else if (old_state == IEEE80211_STA_AUTH &&
++ new_state == IEEE80211_STA_ASSOC) {
++ ret = drv_sta_add(local, sdata, &sta->sta);
++ if (ret == 0)
++ sta->uploaded = true;
++ } else if (old_state == IEEE80211_STA_ASSOC &&
++ new_state == IEEE80211_STA_AUTH) {
++ drv_sta_remove(local, sdata, &sta->sta);
++ }
++ trace_drv_return_int(local, ret);
++ return ret;
++}
+--- a/net/mac80211/driver-ops.h
++++ b/net/mac80211/driver-ops.h
+@@ -573,37 +573,12 @@ static inline void drv_sta_pre_rcu_remov
+ trace_drv_return_void(local);
+ }
+
+-static inline __must_check
++__must_check
+ int drv_sta_state(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ enum ieee80211_sta_state old_state,
+- enum ieee80211_sta_state new_state)
+-{
+- int ret = 0;
+-
+- might_sleep();
+-
+- sdata = get_bss_sdata(sdata);
+- if (!check_sdata_in_driver(sdata))
+- return -EIO;
+-
+- trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
+- if (local->ops->sta_state) {
+- ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
+- old_state, new_state);
+- } else if (old_state == IEEE80211_STA_AUTH &&
+- new_state == IEEE80211_STA_ASSOC) {
+- ret = drv_sta_add(local, sdata, &sta->sta);
+- if (ret == 0)
+- sta->uploaded = true;
+- } else if (old_state == IEEE80211_STA_ASSOC &&
+- new_state == IEEE80211_STA_AUTH) {
+- drv_sta_remove(local, sdata, &sta->sta);
+- }
+- trace_drv_return_int(local, ret);
+- return ret;
+-}
++ enum ieee80211_sta_state new_state);
+
+ static inline void drv_sta_rc_update(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
--- /dev/null
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Wed, 22 Jul 2015 10:42:43 +0200
+Subject: [PATCH] ath9k: Fix NF CCA limits for AR9287 and AR9227
+
+The FreeBSD driver [0] uses the same 2G values as for the AR9280 chips.
+Using the same values in ath9k results in much better throughput for me.
+
+Before this patch I had a huge amount of packet loss (sometimes up to
+40%) and the max transfer speed was somewhere around 5Mbit/s. With this
+patch applied I have zero packet loss and ten times the throughput.
+My device uses a AR9227 which is the PCI variant of the AR9287.
+
+[0] http://bxr.su/FreeBSD/sys/dev/ath/ath_hal/ar9002/ar9287.h
+
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+@@ -610,8 +610,8 @@
+ #define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ -127
+ #define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ -116
+
+-#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -120
++#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -112
+ #define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ -127
+-#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -110
++#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -97
+
+ #endif
+++ /dev/null
-From: Arik Nemtsov <arik@wizery.com>
-Date: Wed, 8 Jul 2015 15:41:44 +0300
-Subject: [PATCH] cfg80211: use RTNL locked reg_can_beacon for IR-relaxation
-
-The RTNL is required to check for IR-relaxation conditions that allow
-more channels to beacon. Export an RTNL locked version of reg_can_beacon
-and use it where possible in AP/STA interface type flows, where
-IR-relaxation may be applicable.
-
-Fixes: 06f207fc5418 ("cfg80211: change GO_CONCURRENT to IR_CONCURRENT for STA")
-Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
-Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
----
-
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -4871,6 +4871,23 @@ bool cfg80211_reg_can_beacon(struct wiph
- struct cfg80211_chan_def *chandef,
- enum nl80211_iftype iftype);
-
-+/**
-+ * cfg80211_reg_can_beacon_relax - check if beaconing is allowed with relaxation
-+ * @wiphy: the wiphy
-+ * @chandef: the channel definition
-+ * @iftype: interface type
-+ *
-+ * Return: %true if there is no secondary channel or the secondary channel(s)
-+ * can be used for beaconing (i.e. is not a radar channel etc.). This version
-+ * also checks if IR-relaxation conditions apply, to allow beaconing under
-+ * more permissive conditions.
-+ *
-+ * Requires the RTNL to be held.
-+ */
-+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
-+ struct cfg80211_chan_def *chandef,
-+ enum nl80211_iftype iftype);
-+
- /*
- * cfg80211_ch_switch_notify - update wdev channel and notify userspace
- * @dev: the device which switched channels
---- a/net/mac80211/tdls.c
-+++ b/net/mac80211/tdls.c
-@@ -69,6 +69,7 @@ ieee80211_tdls_add_subband(struct ieee80
- struct ieee80211_channel *ch;
- struct cfg80211_chan_def chandef;
- int i, subband_start;
-+ struct wiphy *wiphy = sdata->local->hw.wiphy;
-
- for (i = start; i <= end; i += spacing) {
- if (!ch_cnt)
-@@ -79,9 +80,8 @@ ieee80211_tdls_add_subband(struct ieee80
- /* we will be active on the channel */
- cfg80211_chandef_create(&chandef, ch,
- NL80211_CHAN_NO_HT);
-- if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
-- &chandef,
-- sdata->wdev.iftype)) {
-+ if (cfg80211_reg_can_beacon_relax(wiphy, &chandef,
-+ sdata->wdev.iftype)) {
- ch_cnt++;
- /*
- * check if the next channel is also part of
---- a/net/wireless/chan.c
-+++ b/net/wireless/chan.c
-@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(
- return false;
- }
-
--bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
-- struct cfg80211_chan_def *chandef,
-- enum nl80211_iftype iftype)
-+static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
-+ struct cfg80211_chan_def *chandef,
-+ enum nl80211_iftype iftype,
-+ bool check_no_ir)
- {
- bool res;
- u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_RADAR;
-
-- trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
-+ trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
-
-- /*
-- * Under certain conditions suggested by some regulatory bodies a
-- * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
-- * only if such relaxations are not enabled and the conditions are not
-- * met.
-- */
-- if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
-+ if (check_no_ir)
- prohibited_flags |= IEEE80211_CHAN_NO_IR;
-
- if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
-@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiph
- trace_cfg80211_return_bool(res);
- return res;
- }
-+
-+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
-+ struct cfg80211_chan_def *chandef,
-+ enum nl80211_iftype iftype)
-+{
-+ return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
-+}
- EXPORT_SYMBOL(cfg80211_reg_can_beacon);
-
-+bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
-+ struct cfg80211_chan_def *chandef,
-+ enum nl80211_iftype iftype)
-+{
-+ bool check_no_ir;
-+
-+ ASSERT_RTNL();
-+
-+ /*
-+ * Under certain conditions suggested by some regulatory bodies a
-+ * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
-+ * only if such relaxations are not enabled and the conditions are not
-+ * met.
-+ */
-+ check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
-+ chandef->chan);
-+
-+ return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
-+}
-+EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
-+
- int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
- struct cfg80211_chan_def *chandef)
- {
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -2007,7 +2007,8 @@ static int __nl80211_set_channel(struct
- switch (iftype) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_P2P_GO:
-- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
-+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
-+ iftype)) {
- result = -EINVAL;
- break;
- }
-@@ -3408,8 +3409,8 @@ static int nl80211_start_ap(struct sk_bu
- } else if (!nl80211_get_ap_channel(rdev, ¶ms))
- return -EINVAL;
-
-- if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef,
-- wdev->iftype))
-+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
-+ wdev->iftype))
- return -EINVAL;
-
- if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
-@@ -6500,8 +6501,8 @@ skip_beacons:
- if (err)
- return err;
-
-- if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef,
-- wdev->iftype))
-+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
-+ wdev->iftype))
- return -EINVAL;
-
- err = cfg80211_chandef_dfs_required(wdev->wiphy,
-@@ -10188,7 +10189,8 @@ static int nl80211_tdls_channel_switch(s
- return -EINVAL;
-
- /* we will be active on the TDLS link */
-- if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype))
-+ if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
-+ wdev->iftype))
- return -EINVAL;
-
- /* don't allow switching to DFS channels */
---- a/net/wireless/reg.c
-+++ b/net/wireless/reg.c
-@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct w
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_P2P_GO:
- case NL80211_IFTYPE_ADHOC:
-- return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
-+ return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_P2P_CLIENT:
- return cfg80211_chandef_usable(wiphy, &chandef,
---- a/net/wireless/trace.h
-+++ b/net/wireless/trace.h
-@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
-
- TRACE_EVENT(cfg80211_reg_can_beacon,
- TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
-- enum nl80211_iftype iftype),
-- TP_ARGS(wiphy, chandef, iftype),
-+ enum nl80211_iftype iftype, bool check_no_ir),
-+ TP_ARGS(wiphy, chandef, iftype, check_no_ir),
- TP_STRUCT__entry(
- WIPHY_ENTRY
- CHAN_DEF_ENTRY
- __field(enum nl80211_iftype, iftype)
-+ __field(bool, check_no_ir)
- ),
- TP_fast_assign(
- WIPHY_ASSIGN;
- CHAN_DEF_ASSIGN(chandef);
- __entry->iftype = iftype;
-+ __entry->check_no_ir = check_no_ir;
- ),
-- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
-- WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
-+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s",
-+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype,
-+ BOOL_TO_STR(__entry->check_no_ir))
- );
-
- TRACE_EVENT(cfg80211_chandef_dfs_required,
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
-@@ -2391,6 +2391,8 @@ void regulatory_hint_country_ie(struct w
+@@ -2390,6 +2390,8 @@ void regulatory_hint_country_ie(struct w
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request = NULL, *lr;
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
return;
-@@ -2597,6 +2599,7 @@ static void restore_regulatory_settings(
+@@ -2596,6 +2598,7 @@ static void restore_regulatory_settings(
void regulatory_hint_disconnect(void)
{
--- a/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)
+@@ -1031,23 +1031,23 @@ static int __init ath9k_init(void)
{
int error;
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -87,7 +87,7 @@ int ath_descdma_setup(struct ath_softc *
+@@ -88,7 +88,7 @@ int ath_descdma_setup(struct ath_softc *
(_l) &= ((_sz) - 1); \
} while (0)
*
* @set_wds_peer: set the WDS peer for a WDS interface
*
-@@ -2577,6 +2578,7 @@ struct cfg80211_ops {
+@@ -2576,6 +2577,7 @@ struct cfg80211_ops {
enum nl80211_tx_power_setting type, int mbm);
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
int *dbm);
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -814,6 +814,9 @@ static inline int ath9k_dump_btcoex(stru
+@@ -806,6 +806,9 @@ static inline int ath9k_dump_btcoex(stru
void ath_init_leds(struct ath_softc *sc);
void ath_deinit_leds(struct ath_softc *sc);
void ath_fill_led_pin(struct ath_softc *sc);
#else
static inline void ath_init_leds(struct ath_softc *sc)
{
-@@ -953,6 +956,13 @@ void ath_ant_comb_scan(struct ath_softc
+@@ -945,6 +948,13 @@ void ath_ant_comb_scan(struct ath_softc
#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
-@@ -1004,9 +1014,8 @@ struct ath_softc {
+@@ -996,9 +1006,8 @@ struct ath_softc {
spinlock_t chan_lock;
#ifdef CPTCFG_MAC80211_LEDS
void ath_fill_led_pin(struct ath_softc *sc)
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -942,7 +942,7 @@ int ath9k_init_device(u16 devid, struct
+@@ -943,7 +943,7 @@ int ath9k_init_device(u16 devid, struct
#ifdef CPTCFG_MAC80211_LEDS
/* must be initialized before ieee80211_register_hw */
}
static const struct ieee80211_iface_limit if_limits[] = {
-@@ -902,6 +903,18 @@ static void ath9k_set_hw_capab(struct at
+@@ -903,6 +904,18 @@ static void ath9k_set_hw_capab(struct at
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
int ath9k_init_device(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
-@@ -947,6 +960,8 @@ int ath9k_init_device(u16 devid, struct
+@@ -948,6 +961,8 @@ int ath9k_init_device(u16 devid, struct
ARRAY_SIZE(ath9k_tpt_blink));
#endif
--- a/.local-symbols
+++ b/.local-symbols
-@@ -311,6 +311,7 @@ RT2X00_LIB_FIRMWARE=
+@@ -312,6 +312,7 @@ RT2X00_LIB_FIRMWARE=
RT2X00_LIB_CRYPTO=
RT2X00_LIB_LEDS=
RT2X00_LIB_DEBUGFS=
+++ /dev/null
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
-Date: Thu, 9 Jul 2015 16:53:30 +0200
-Subject: [PATCH] brcmfmac: set wiphy's addresses to provide valid MACs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Broadcom's firmware requires every BSS to use MAC address with unique
-last few bits. The amount of bits may depend on a particular firmware,
-it was verified to be 2 for BCM43602 one.
-If this condition won't be fulfilled firmware will reject such MAC:
-brcmfmac: _brcmf_set_mac_address: Setting cur_etheraddr failed, -52
-
-We don't want to simply set addr_mask as it would also disallow using
-locally administrated bit. Instead let's build a list of addresses
-manually enabling 0x2 bit for extra interfaces.
-
-Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
----
-
---- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -5813,6 +5813,7 @@ static void brcmf_wiphy_wowl_params(stru
-
- static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
- {
-+ struct brcmf_pub *drvr = ifp->drvr;
- struct ieee80211_supported_band *band;
- __le32 bandlist[3];
- u32 n_bands;
-@@ -5826,6 +5827,19 @@ static int brcmf_setup_wiphy(struct wiph
- if (err)
- return err;
-
-+ for (i = 0; i < wiphy->iface_combinations->max_interfaces &&
-+ i < ARRAY_SIZE(drvr->addresses); i++) {
-+ u8 *addr = drvr->addresses[i].addr;
-+
-+ memcpy(addr, drvr->mac, ETH_ALEN);
-+ if (i) {
-+ addr[0] |= BIT(1);
-+ addr[ETH_ALEN - 1] ^= i;
-+ }
-+ }
-+ wiphy->addresses = drvr->addresses;
-+ wiphy->n_addresses = i;
-+
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- wiphy->cipher_suites = __wl_cipher_suites;
- wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
---- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
-+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
-@@ -21,6 +21,7 @@
- #ifndef BRCMFMAC_CORE_H
- #define BRCMFMAC_CORE_H
-
-+#include <net/cfg80211.h>
- #include "fweh.h"
-
- #define TOE_TX_CSUM_OL 0x00000001
-@@ -118,6 +119,8 @@ struct brcmf_pub {
- /* Multicast data packets sent to dongle */
- unsigned long tx_multicast;
-
-+ struct mac_address addresses[BRCMF_MAX_IFS];
-+
- struct brcmf_if *iflist[BRCMF_MAX_IFS];
-
- struct mutex proto_block;
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -1417,6 +1417,16 @@ int ath10k_core_register(struct ath10k *
+@@ -1520,6 +1520,16 @@ int ath10k_core_register(struct ath10k *
ar->chip_id = chip_id;
queue_work(ar->workqueue, &ar->register_work);
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
-@@ -6756,6 +6756,21 @@ struct ath10k_vif *ath10k_get_arvif(stru
+@@ -6804,6 +6804,21 @@ struct ath10k_vif *ath10k_get_arvif(stru
return arvif_iter.arvif;
}
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
-@@ -6971,6 +6986,12 @@ int ath10k_mac_register(struct ath10k *a
+@@ -7025,6 +7040,12 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->wiphy->cipher_suites = cipher_suites;
ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);