--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Fri, 6 Mar 2015 18:40:41 +0100
+Subject: [PATCH] brcmfmac: Fix race condition in msgbuf ioctl processing.
+
+Msgbuf is using a wait_event_timeout to wait for the response on
+an ioctl. The wakeup routine uses waitqueue_active to see if
+wait_event_timeout has been called. There is a chance that the
+response arrives before wait_event_timeout is called, this
+will result in situation that wait_event_timeout never gets
+woken again and assumed result will be a timeout. This patch
+removes that errornous situation by always setting the
+ctl_completed var before checking for queue active.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -481,10 +481,9 @@ static int brcmf_msgbuf_ioctl_resp_wait(
+
+ static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf)
+ {
+- if (waitqueue_active(&msgbuf->ioctl_resp_wait)) {
+- msgbuf->ctl_completed = true;
++ msgbuf->ctl_completed = true;
++ if (waitqueue_active(&msgbuf->ioctl_resp_wait))
+ wake_up(&msgbuf->ioctl_resp_wait);
+- }
+ }
+
+
--- /dev/null
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Wed, 18 Mar 2015 13:25:23 +0100
+Subject: [PATCH] brcmfmac: Update msgbuf commonring size for improved
+ throughput.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h
+@@ -17,11 +17,11 @@
+
+ #ifdef CPTCFG_BRCMFMAC_PROTO_MSGBUF
+
+-#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 20
+-#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 256
+-#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 20
++#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 64
++#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 512
++#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 64
+ #define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024
+-#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 256
++#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 512
+ #define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512
+
+ #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:46 +0100
+Subject: [PATCH] ath9k_htc: add new WMI_REG_RMW_CMDID command
+
+Since usb bus add extra delay on each request, a command
+with read + write requests is too expensive. We can dramtically
+reduce usb load by moving this command to firmware.
+
+In my tests, this patch will reduce channel scan time
+for about 5-10 seconds.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath.h
++++ b/drivers/net/wireless/ath/ath.h
+@@ -131,6 +131,9 @@ struct ath_ops {
+ void (*enable_write_buffer)(void *);
+ void (*write_flush) (void *);
+ u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr);
++ void (*enable_rmw_buffer)(void *);
++ void (*rmw_flush) (void *);
++
+ };
+
+ struct ath_common;
+--- a/drivers/net/wireless/ath/ath9k/htc.h
++++ b/drivers/net/wireless/ath/ath9k/htc.h
+@@ -444,6 +444,10 @@ static inline void ath9k_htc_stop_btcoex
+ #define OP_BT_SCAN BIT(4)
+ #define OP_TSF_RESET BIT(6)
+
++enum htc_op_flags {
++ HTC_FWFLAG_NO_RMW,
++};
++
+ struct ath9k_htc_priv {
+ struct device *dev;
+ struct ieee80211_hw *hw;
+@@ -482,6 +486,7 @@ struct ath9k_htc_priv {
+ bool reconfig_beacon;
+ unsigned int rxfilter;
+ unsigned long op_flags;
++ unsigned long fw_flags;
+
+ struct ath9k_hw_cal_data caldata;
+ struct ath_spec_scan_priv spec_priv;
+--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
++++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+@@ -376,17 +376,139 @@ static void ath9k_regwrite_flush(void *h
+ mutex_unlock(&priv->wmi->multi_write_mutex);
+ }
+
+-static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
++static void ath9k_reg_rmw_buffer(void *hw_priv,
++ u32 reg_offset, u32 set, u32 clr)
++{
++ struct ath_hw *ah = (struct ath_hw *) hw_priv;
++ struct ath_common *common = ath9k_hw_common(ah);
++ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
++ u32 rsp_status;
++ int r;
++
++ mutex_lock(&priv->wmi->multi_rmw_mutex);
++
++ /* Store the register/value */
++ priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].reg =
++ cpu_to_be32(reg_offset);
++ priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].set =
++ cpu_to_be32(set);
++ priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].clr =
++ cpu_to_be32(clr);
++
++ priv->wmi->multi_rmw_idx++;
++
++ /* If the buffer is full, send it out. */
++ if (priv->wmi->multi_rmw_idx == MAX_RMW_CMD_NUMBER) {
++ r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
++ (u8 *) &priv->wmi->multi_rmw,
++ sizeof(struct register_write) * priv->wmi->multi_rmw_idx,
++ (u8 *) &rsp_status, sizeof(rsp_status),
++ 100);
++ if (unlikely(r)) {
++ ath_dbg(common, WMI,
++ "REGISTER RMW FAILED, multi len: %d\n",
++ priv->wmi->multi_rmw_idx);
++ }
++ priv->wmi->multi_rmw_idx = 0;
++ }
++
++ mutex_unlock(&priv->wmi->multi_rmw_mutex);
++}
++
++static void ath9k_reg_rmw_flush(void *hw_priv)
+ {
+- u32 val;
++ struct ath_hw *ah = (struct ath_hw *) hw_priv;
++ struct ath_common *common = ath9k_hw_common(ah);
++ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
++ u32 rsp_status;
++ int r;
++
++ if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
++ return;
++
++ atomic_dec(&priv->wmi->m_rmw_cnt);
++
++ mutex_lock(&priv->wmi->multi_rmw_mutex);
++
++ if (priv->wmi->multi_rmw_idx) {
++ r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
++ (u8 *) &priv->wmi->multi_rmw,
++ sizeof(struct register_rmw) * priv->wmi->multi_rmw_idx,
++ (u8 *) &rsp_status, sizeof(rsp_status),
++ 100);
++ if (unlikely(r)) {
++ ath_dbg(common, WMI,
++ "REGISTER RMW FAILED, multi len: %d\n",
++ priv->wmi->multi_rmw_idx);
++ }
++ priv->wmi->multi_rmw_idx = 0;
++ }
++
++ mutex_unlock(&priv->wmi->multi_rmw_mutex);
++}
++
++static void ath9k_enable_rmw_buffer(void *hw_priv)
++{
++ struct ath_hw *ah = (struct ath_hw *) hw_priv;
++ struct ath_common *common = ath9k_hw_common(ah);
++ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
++
++ if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
++ return;
+
+- val = ath9k_regread(hw_priv, reg_offset);
+- val &= ~clr;
+- val |= set;
+- ath9k_regwrite(hw_priv, val, reg_offset);
++ atomic_inc(&priv->wmi->m_rmw_cnt);
++}
++
++static u32 ath9k_reg_rmw_single(void *hw_priv,
++ u32 reg_offset, u32 set, u32 clr)
++{
++ struct ath_hw *ah = (struct ath_hw *) hw_priv;
++ struct ath_common *common = ath9k_hw_common(ah);
++ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
++ struct register_rmw buf, buf_ret;
++ int ret;
++ u32 val = 0;
++
++ buf.reg = cpu_to_be32(reg_offset);
++ buf.set = cpu_to_be32(set);
++ buf.clr = cpu_to_be32(clr);
++
++ ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
++ (u8 *) &buf, sizeof(buf),
++ (u8 *) &buf_ret, sizeof(buf_ret),
++ 100);
++ if (unlikely(ret)) {
++ ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n",
++ reg_offset, ret);
++ }
+ return val;
+ }
+
++static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
++{
++ struct ath_hw *ah = (struct ath_hw *) hw_priv;
++ struct ath_common *common = ath9k_hw_common(ah);
++ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
++
++ if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) {
++ u32 val;
++
++ val = REG_READ(ah, reg_offset);
++ val &= ~clr;
++ val |= set;
++ REG_WRITE(ah, reg_offset, val);
++
++ return 0;
++ }
++
++ if (atomic_read(&priv->wmi->m_rmw_cnt))
++ ath9k_reg_rmw_buffer(hw_priv, reg_offset, set, clr);
++ else
++ ath9k_reg_rmw_single(hw_priv, reg_offset, set, clr);
++
++ return 0;
++}
++
+ static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
+ {
+ *csz = L1_CACHE_BYTES >> 2;
+@@ -501,6 +623,8 @@ static int ath9k_init_priv(struct ath9k_
+ ah->reg_ops.write = ath9k_regwrite;
+ ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
+ ah->reg_ops.write_flush = ath9k_regwrite_flush;
++ ah->reg_ops.enable_rmw_buffer = ath9k_enable_rmw_buffer;
++ ah->reg_ops.rmw_flush = ath9k_reg_rmw_flush;
+ ah->reg_ops.rmw = ath9k_reg_rmw;
+ priv->ah = ah;
+
+@@ -686,6 +810,12 @@ static int ath9k_init_firmware_version(s
+ return -EINVAL;
+ }
+
++ if (priv->fw_version_major == 1 && priv->fw_version_minor < 4)
++ set_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags);
++
++ dev_info(priv->dev, "FW RMW support: %s\n",
++ test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags) ? "Off" : "On");
++
+ return 0;
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -100,6 +100,18 @@
+ (_ah)->reg_ops.write_flush((_ah)); \
+ } while (0)
+
++#define ENABLE_REG_RMW_BUFFER(_ah) \
++ do { \
++ if ((_ah)->reg_ops.enable_rmw_buffer) \
++ (_ah)->reg_ops.enable_rmw_buffer((_ah)); \
++ } while (0)
++
++#define REG_RMW_BUFFER_FLUSH(_ah) \
++ do { \
++ if ((_ah)->reg_ops.rmw_flush) \
++ (_ah)->reg_ops.rmw_flush((_ah)); \
++ } while (0)
++
+ #define PR_EEP(_s, _val) \
+ do { \
+ len += scnprintf(buf + len, size - len, "%20s : %10d\n",\
+--- a/drivers/net/wireless/ath/ath9k/wmi.c
++++ b/drivers/net/wireless/ath/ath9k/wmi.c
+@@ -61,6 +61,8 @@ static const char *wmi_cmd_to_name(enum
+ return "WMI_REG_READ_CMDID";
+ case WMI_REG_WRITE_CMDID:
+ return "WMI_REG_WRITE_CMDID";
++ case WMI_REG_RMW_CMDID:
++ return "WMI_REG_RMW_CMDID";
+ case WMI_RC_STATE_CHANGE_CMDID:
+ return "WMI_RC_STATE_CHANGE_CMDID";
+ case WMI_RC_RATE_UPDATE_CMDID:
+@@ -101,6 +103,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_
+ spin_lock_init(&wmi->event_lock);
+ mutex_init(&wmi->op_mutex);
+ mutex_init(&wmi->multi_write_mutex);
++ mutex_init(&wmi->multi_rmw_mutex);
+ init_completion(&wmi->cmd_wait);
+ INIT_LIST_HEAD(&wmi->pending_tx_events);
+ tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
+--- a/drivers/net/wireless/ath/ath9k/wmi.h
++++ b/drivers/net/wireless/ath/ath9k/wmi.h
+@@ -112,6 +112,7 @@ enum wmi_cmd_id {
+ WMI_TX_STATS_CMDID,
+ WMI_RX_STATS_CMDID,
+ WMI_BITRATE_MASK_CMDID,
++ WMI_REG_RMW_CMDID,
+ };
+
+ enum wmi_event_id {
+@@ -125,12 +126,19 @@ enum wmi_event_id {
+ };
+
+ #define MAX_CMD_NUMBER 62
++#define MAX_RMW_CMD_NUMBER 15
+
+ struct register_write {
+ __be32 reg;
+ __be32 val;
+ };
+
++struct register_rmw {
++ __be32 reg;
++ __be32 set;
++ __be32 clr;
++} __packed;
++
+ struct ath9k_htc_tx_event {
+ int count;
+ struct __wmi_event_txstatus txs;
+@@ -156,10 +164,18 @@ struct wmi {
+
+ spinlock_t wmi_lock;
+
++ /* multi write section */
+ atomic_t mwrite_cnt;
+ struct register_write multi_write[MAX_CMD_NUMBER];
+ u32 multi_write_idx;
+ struct mutex multi_write_mutex;
++
++ /* multi rmw section */
++ atomic_t m_rmw_cnt;
++ struct register_rmw multi_rmw[MAX_RMW_CMD_NUMBER];
++ u32 multi_rmw_idx;
++ struct mutex multi_rmw_mutex;
++
+ };
+
+ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:47 +0100
+Subject: [PATCH] ath9k: ar9271_hw_pa_cal - use defs instead of magin
+ numbers
+
+This function uses mixed styles for register names/numbers which
+is make harder reading and optimisation.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+@@ -430,22 +430,22 @@ static void ar9271_hw_pa_cal(struct ath_
+ u32 regVal;
+ unsigned int i;
+ u32 regList[][2] = {
+- { 0x786c, 0 },
+- { 0x7854, 0 },
+- { 0x7820, 0 },
+- { 0x7824, 0 },
+- { 0x7868, 0 },
+- { 0x783c, 0 },
+- { 0x7838, 0 } ,
+- { 0x7828, 0 } ,
++ { AR9285_AN_TOP3, 0 },
++ { AR9285_AN_RXTXBB1, 0 },
++ { AR9285_AN_RF2G1, 0 },
++ { AR9285_AN_RF2G2, 0 },
++ { AR9285_AN_TOP2, 0 },
++ { AR9285_AN_RF2G8, 0 },
++ { AR9285_AN_RF2G7, 0 } ,
++ { AR9285_AN_RF2G3, 0 } ,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ regList[i][1] = REG_READ(ah, regList[i][0]);
+
+- regVal = REG_READ(ah, 0x7834);
++ regVal = REG_READ(ah, AR9285_AN_RF2G6);
+ regVal &= (~(0x1));
+- REG_WRITE(ah, 0x7834, regVal);
++ REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal |= (0x1 << 27);
+ REG_WRITE(ah, 0x9808, regVal);
+@@ -477,7 +477,7 @@ static void ar9271_hw_pa_cal(struct ath_
+ * does not matter since we turn it off
+ */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+-
++ /* 7828, b0-11, ccom=fff */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
+
+ /* Set:
+@@ -490,15 +490,16 @@ static void ar9271_hw_pa_cal(struct ath_
+
+ /* find off_6_1; */
+ for (i = 6; i > 0; i--) {
+- regVal = REG_READ(ah, 0x7834);
++ regVal = REG_READ(ah, AR9285_AN_RF2G6);
+ regVal |= (1 << (20 + i));
+- REG_WRITE(ah, 0x7834, regVal);
++ REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
+ udelay(1);
+ /* regVal = REG_READ(ah, 0x7834); */
+ regVal &= (~(0x1 << (20 + i)));
+- regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
++ regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9),
++ AR9285_AN_RXTXBB1_SPARE9)
+ << (20 + i));
+- REG_WRITE(ah, 0x7834, regVal);
++ REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
+ }
+
+ regVal = (regVal >> 20) & 0x7f;
+@@ -517,9 +518,9 @@ static void ar9271_hw_pa_cal(struct ath_
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
+- regVal = REG_READ(ah, 0x7834);
++ regVal = REG_READ(ah, AR_AN_RF2G1_CH1);
+ regVal |= 0x1;
+- REG_WRITE(ah, 0x7834, regVal);
++ REG_WRITE(ah, AR_AN_RF2G1_CH1, regVal);
+ regVal = REG_READ(ah, 0x9808);
+ regVal &= (~(0x1 << 27));
+ REG_WRITE(ah, 0x9808, regVal);
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:48 +0100
+Subject: [PATCH] ath9k: ar9271_hw_pa_cal: use proper makroses.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+@@ -443,33 +443,30 @@ static void ar9271_hw_pa_cal(struct ath_
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ regList[i][1] = REG_READ(ah, regList[i][0]);
+
+- regVal = REG_READ(ah, AR9285_AN_RF2G6);
+- regVal &= (~(0x1));
+- REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
+- regVal = REG_READ(ah, 0x9808);
+- regVal |= (0x1 << 27);
+- REG_WRITE(ah, 0x9808, regVal);
+-
++ /* 7834, b1=0 */
++ REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
++ /* 9808, b27=1 */
++ REG_SET_BIT(ah, 0x9808, 1 << 27);
+ /* 786c,b23,1, pwddac=1 */
+- REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
++ REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC);
+ /* 7854, b5,1, pdrxtxbb=1 */
+- REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
++ REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1);
+ /* 7854, b7,1, pdv2i=1 */
+- REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
++ REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I);
+ /* 7854, b8,1, pddacinterface=1 */
+- REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
++ REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF);
+ /* 7824,b12,0, offcal=0 */
+- REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
++ REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL);
+ /* 7838, b1,0, pwddb=0 */
+- REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
++ REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB);
+ /* 7820,b11,0, enpacal=0 */
+- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
++ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL);
+ /* 7820,b25,1, pdpadrv1=0 */
+- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
++ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1);
+ /* 7820,b24,0, pdpadrv2=0 */
+- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
++ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2);
+ /* 7820,b23,0, pdpaout=0 */
+- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
++ REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT);
+ /* 783c,b14-16,7, padrvgn2tab_0=7 */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+ /*
+@@ -516,15 +513,13 @@ static void ar9271_hw_pa_cal(struct ath_
+ ah->pacal_info.prev_offset = regVal;
+ }
+
+- ENABLE_REGWRITE_BUFFER(ah);
+
+- regVal = REG_READ(ah, AR_AN_RF2G1_CH1);
+- regVal |= 0x1;
+- REG_WRITE(ah, AR_AN_RF2G1_CH1, regVal);
+- regVal = REG_READ(ah, 0x9808);
+- regVal &= (~(0x1 << 27));
+- REG_WRITE(ah, 0x9808, regVal);
++ /* 7834, b1=1 */
++ REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
++ /* 9808, b27=0 */
++ REG_CLR_BIT(ah, 0x9808, 1 << 27);
+
++ ENABLE_REGWRITE_BUFFER(ah);
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ REG_WRITE(ah, regList[i][0], regList[i][1]);
+
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:49 +0100
+Subject: [PATCH] ath9k: ar9271_hw_pa_cal: use RMW buffer
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+@@ -436,13 +436,14 @@ static void ar9271_hw_pa_cal(struct ath_
+ { AR9285_AN_RF2G2, 0 },
+ { AR9285_AN_TOP2, 0 },
+ { AR9285_AN_RF2G8, 0 },
+- { AR9285_AN_RF2G7, 0 } ,
+- { AR9285_AN_RF2G3, 0 } ,
++ { AR9285_AN_RF2G7, 0 },
++ { AR9285_AN_RF2G3, 0 },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
+ regList[i][1] = REG_READ(ah, regList[i][0]);
+
++ ENABLE_REG_RMW_BUFFER(ah);
+ /* 7834, b1=0 */
+ REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
+ /* 9808, b27=1 */
+@@ -476,6 +477,7 @@ static void ar9271_hw_pa_cal(struct ath_
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+ /* 7828, b0-11, ccom=fff */
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
++ REG_RMW_BUFFER_FLUSH(ah);
+
+ /* Set:
+ * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
+@@ -514,10 +516,12 @@ static void ar9271_hw_pa_cal(struct ath_
+ }
+
+
++ ENABLE_REG_RMW_BUFFER(ah);
+ /* 7834, b1=1 */
+ REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
+ /* 9808, b27=0 */
+ REG_CLR_BIT(ah, 0x9808, 1 << 27);
++ REG_RMW_BUFFER_FLUSH(ah);
+
+ ENABLE_REGWRITE_BUFFER(ah);
+ for (i = 0; i < ARRAY_SIZE(regList); i++)
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:50 +0100
+Subject: [PATCH] ath9k: add multi_read to be compatible with ath9k_htc
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -141,6 +141,16 @@ static unsigned int ath9k_ioread32(void
+ return val;
+ }
+
++static void ath9k_multi_ioread32(void *hw_priv, u32 *addr,
++ u32 *val, u16 count)
++{
++ int i;
++
++ for (i = 0; i < count; i++)
++ val[i] = ath9k_ioread32(hw_priv, addr[i]);
++}
++
++
+ static unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset,
+ u32 set, u32 clr)
+ {
+@@ -530,6 +540,7 @@ static int ath9k_init_softc(u16 devid, s
+ ah->hw = sc->hw;
+ ah->hw_version.devid = devid;
+ ah->reg_ops.read = ath9k_ioread32;
++ ah->reg_ops.multi_read = ath9k_multi_ioread32;
+ ah->reg_ops.write = ath9k_iowrite32;
+ ah->reg_ops.rmw = ath9k_reg_rmw;
+ pCap = &ah->caps;
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:51 +0100
+Subject: [PATCH] ath9k: add new function ath9k_hw_read_array
+
+REG_READ generate most overhead on usb bus. It send and read micro packages
+and reduce usb bandwidth. To reduce this overhead we should read in batches.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -121,6 +121,36 @@ void ath9k_hw_write_array(struct ath_hw
+ REGWRITE_BUFFER_FLUSH(ah);
+ }
+
++void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size)
++{
++ u32 *tmp_reg_list, *tmp_data;
++ int i;
++
++ tmp_reg_list = kmalloc(size * sizeof(u32), GFP_KERNEL);
++ if (!tmp_reg_list) {
++ dev_err(ah->dev, "%s: tmp_reg_list: alloc filed\n", __func__);
++ return;
++ }
++
++ tmp_data = kmalloc(size * sizeof(u32), GFP_KERNEL);
++ if (!tmp_data) {
++ dev_err(ah->dev, "%s tmp_data: alloc filed\n", __func__);
++ goto error_tmp_data;
++ }
++
++ for (i = 0; i < size; i++)
++ tmp_reg_list[i] = array[i][0];
++
++ REG_READ_MULTI(ah, tmp_reg_list, tmp_data, size);
++
++ for (i = 0; i < size; i++)
++ array[i][1] = tmp_data[i];
++
++ kfree(tmp_data);
++error_tmp_data:
++ kfree(tmp_reg_list);
++}
++
+ u32 ath9k_hw_reverse_bits(u32 val, u32 n)
+ {
+ u32 retval;
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -138,6 +138,8 @@
+
+ #define REG_WRITE_ARRAY(iniarray, column, regWr) \
+ ath9k_hw_write_array(ah, iniarray, column, &(regWr))
++#define REG_READ_ARRAY(ah, array, size) \
++ ath9k_hw_read_array(ah, array, size)
+
+ #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
+ #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
+@@ -1020,6 +1022,7 @@ void ath9k_hw_synth_delay(struct ath_hw
+ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
+ void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array,
+ int column, unsigned int *writecnt);
++void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size);
+ u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
+ u8 phy, int kbps,
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:52 +0100
+Subject: [PATCH] ath9k: ar9271_hw_pa_cal: use REG_READ_ARRAY
+
+insted of reading each register separatly
+and waste 4ms on each operation, we can
+use one shot read.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+@@ -440,8 +440,7 @@ static void ar9271_hw_pa_cal(struct ath_
+ { AR9285_AN_RF2G3, 0 },
+ };
+
+- for (i = 0; i < ARRAY_SIZE(regList); i++)
+- regList[i][1] = REG_READ(ah, regList[i][0]);
++ REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList));
+
+ ENABLE_REG_RMW_BUFFER(ah);
+ /* 7834, b1=0 */
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:53 +0100
+Subject: [PATCH] ath9k: use one shot read in ath9k_hw_update_mibstats
+
+this will reduce some overhead on usb bus.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ani.c
++++ b/drivers/net/wireless/ath/ath9k/ani.c
+@@ -107,11 +107,21 @@ static const struct ani_cck_level_entry
+ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
+ struct ath9k_mib_stats *stats)
+ {
+- stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
+- stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
+- stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
+- stats->rts_good += REG_READ(ah, AR_RTS_OK);
+- stats->beacons += REG_READ(ah, AR_BEACON_CNT);
++ u32 addr[5] = {AR_RTS_OK, AR_RTS_FAIL, AR_ACK_FAIL,
++ AR_FCS_FAIL, AR_BEACON_CNT};
++ u32 data[5];
++
++ REG_READ_MULTI(ah, &addr[0], &data[0], 5);
++ /* AR_RTS_OK */
++ stats->rts_good += data[0];
++ /* AR_RTS_FAIL */
++ stats->rts_bad += data[1];
++ /* AR_ACK_FAIL */
++ stats->ackrcv_bad += data[2];
++ /* AR_FCS_FAIL */
++ stats->fcs_bad += data[3];
++ /* AR_BEACON_CNT */
++ stats->beacons += data[4];
+ }
+
+ static void ath9k_ani_restart(struct ath_hw *ah)
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:54 +0100
+Subject: [PATCH] ath9k: ath9k_hw_loadnf: use REG_RMW
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/calib.c
++++ b/drivers/net/wireless/ath/ath9k/calib.c
+@@ -238,7 +238,6 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
+ {
+ struct ath9k_nfcal_hist *h = NULL;
+ unsigned i, j;
+- int32_t val;
+ u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+ struct ath_common *common = ath9k_hw_common(ah);
+ s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
+@@ -246,6 +245,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
+ if (ah->caldata)
+ h = ah->caldata->nfCalHist;
+
++ ENABLE_REG_RMW_BUFFER(ah);
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ s16 nfval;
+@@ -258,10 +258,8 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
+ else
+ nfval = default_nf;
+
+- val = REG_READ(ah, ah->nf_regs[i]);
+- val &= 0xFFFFFE00;
+- val |= (((u32) nfval << 1) & 0x1ff);
+- REG_WRITE(ah, ah->nf_regs[i], val);
++ REG_RMW(ah, ah->nf_regs[i],
++ (((u32) nfval << 1) & 0x1ff), 0x1ff);
+ }
+ }
+
+@@ -274,6 +272,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
++ REG_RMW_BUFFER_FLUSH(ah);
+
+ /*
+ * Wait for load to complete, should be fast, a few 10s of us.
+@@ -309,19 +308,17 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s
+ * by the median we just loaded. This will be initial (and max) value
+ * of next noise floor calibration the baseband does.
+ */
+- ENABLE_REGWRITE_BUFFER(ah);
++ ENABLE_REG_RMW_BUFFER(ah);
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
+ continue;
+
+- val = REG_READ(ah, ah->nf_regs[i]);
+- val &= 0xFFFFFE00;
+- val |= (((u32) (-50) << 1) & 0x1ff);
+- REG_WRITE(ah, ah->nf_regs[i], val);
++ REG_RMW(ah, ah->nf_regs[i],
++ (((u32) (-50) << 1) & 0x1ff), 0x1ff);
+ }
+ }
+- REGWRITE_BUFFER_FLUSH(ah);
++ REG_RMW_BUFFER_FLUSH(ah);
+
+ return 0;
+ }
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:55 +0100
+Subject: [PATCH] ath9k: write buffer related optimisation in
+ ar5008_hw_set_channel_regs
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -681,12 +681,13 @@ static void ar5008_hw_set_channel_regs(s
+ phymode |= AR_PHY_FC_DYN2040_PRI_CH;
+
+ }
++ ENABLE_REGWRITE_BUFFER(ah);
+ REG_WRITE(ah, AR_PHY_TURBO, phymode);
+
++ /* This function do only REG_WRITE, so
++ * we can include it to REGWRITE_BUFFER. */
+ ath9k_hw_set11nmac2040(ah, chan);
+
+- ENABLE_REGWRITE_BUFFER(ah);
+-
+ REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+ REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:56 +0100
+Subject: [PATCH] ath9k: ath9k_hw_set_4k_power_cal_tabl: use rmw buffer
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -389,6 +389,7 @@ static void ath9k_hw_set_4k_power_cal_ta
+ }
+ }
+
++ ENABLE_REG_RMW_BUFFER(ah);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+@@ -396,6 +397,7 @@ static void ath9k_hw_set_4k_power_cal_ta
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
++ REG_RMW_BUFFER_FLUSH(ah);
+
+ for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+ regChainOffset = i * 0x1000;
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:57 +0100
+Subject: [PATCH] ath9k: use rmw buffer in ath9k_hw_set_operating_mode
+ and ath9k_hw_reset
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1227,6 +1227,7 @@ static void ath9k_hw_set_operating_mode(
+ u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC;
+ u32 set = AR_STA_ID1_KSRCH_MODE;
+
++ ENABLE_REG_RMW_BUFFER(ah);
+ switch (opmode) {
+ case NL80211_IFTYPE_ADHOC:
+ if (!AR_SREV_9340_13(ah)) {
+@@ -1248,6 +1249,7 @@ static void ath9k_hw_set_operating_mode(
+ break;
+ }
+ REG_RMW(ah, AR_STA_ID1, set, mask);
++ REG_RMW_BUFFER_FLUSH(ah);
+ }
+
+ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
+@@ -1960,6 +1962,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ if (!ath9k_hw_mci_is_enabled(ah))
+ REG_WRITE(ah, AR_OBS, 8);
+
++ ENABLE_REG_RMW_BUFFER(ah);
+ if (ah->config.rx_intr_mitigation) {
+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, ah->config.rimt_last);
+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, ah->config.rimt_first);
+@@ -1969,6 +1972,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+ REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300);
+ REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750);
+ }
++ REG_RMW_BUFFER_FLUSH(ah);
+
+ ath9k_hw_init_bb(ah, chan);
+
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:58 +0100
+Subject: [PATCH] ath9k: ath9k_hw_4k_set_board_values: use rmw buffer
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -1082,6 +1082,7 @@ static void ath9k_hw_4k_set_board_values
+ mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
++ ENABLE_REG_RMW_BUFFER(ah);
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
+@@ -1096,6 +1097,7 @@ static void ath9k_hw_4k_set_board_values
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
++ REG_RMW_BUFFER_FLUSH(ah);
+ }
+ }
+
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:29:59 +0100
+Subject: [PATCH] ath9k: ath9k_hw_analog_shift_rmw: use REG_RMW
+
+use REG_RMW in ath9k_hw_analog_shift_rmw.
+It will double execution speed on usb bus.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom.c
+@@ -27,12 +27,7 @@ void ath9k_hw_analog_shift_regwrite(stru
+ void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
+ u32 shift, u32 val)
+ {
+- u32 regVal;
+-
+- regVal = REG_READ(ah, reg) & ~mask;
+- regVal |= (val << shift) & mask;
+-
+- REG_WRITE(ah, reg, regVal);
++ REG_RMW(ah, reg, ((val << shift) & mask), mask);
+
+ if (ah->config.analog_shiftreg)
+ udelay(100);
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:30:01 +0100
+Subject: [PATCH] ath9k: use REG_RMW and rmw buffer in
+ ath9k_hw_4k_set_gain
+
+it is possible to reduce time needed for this function
+by rplacing REG_WRITE with REG_RMW (plus dummy 0) and putt all commands
+in same buffer.
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+@@ -772,15 +772,14 @@ static void ath9k_hw_4k_set_gain(struct
+ struct ar5416_eeprom_4k *eep,
+ u8 txRxAttenLocal)
+ {
+- REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0,
+- pModal->antCtrlChain[0]);
+-
+- REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0),
+- (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+- ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+- AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+- SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+- SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
++ ENABLE_REG_RMW_BUFFER(ah);
++ REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0,
++ pModal->antCtrlChain[0], 0);
++
++ REG_RMW(ah, AR_PHY_TIMING_CTRL4(0),
++ SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
++ SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF),
++ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF);
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+@@ -819,6 +818,7 @@ static void ath9k_hw_4k_set_gain(struct
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
++ REG_RMW_BUFFER_FLUSH(ah);
+ }
+
+ /*
--- /dev/null
+From: Oleksij Rempel <linux@rempel-privat.de>
+Date: Sun, 22 Mar 2015 19:30:03 +0100
+Subject: [PATCH] ath9k: use REG_RMW and rmw buffer in
+ ath9k_hw_def_set_gain
+
+Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
+@@ -466,6 +466,7 @@ static void ath9k_hw_def_set_gain(struct
+ struct ar5416_eeprom_def *eep,
+ u8 txRxAttenLocal, int regChainOffset, int i)
+ {
++ ENABLE_REG_RMW_BUFFER(ah);
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
+ txRxAttenLocal = pModal->txRxAttenCh[i];
+
+@@ -483,16 +484,12 @@ static void ath9k_hw_def_set_gain(struct
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->xatten2Db[i]);
+ } else {
+- REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+- ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+- | SM(pModal-> bswMargin[i],
+- AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+- REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+- ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+- | SM(pModal->bswAtten[i],
+- AR_PHY_GAIN_2GHZ_BSW_ATTEN));
++ REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
++ SM(pModal-> bswMargin[i], AR_PHY_GAIN_2GHZ_BSW_MARGIN),
++ AR_PHY_GAIN_2GHZ_BSW_MARGIN);
++ REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
++ SM(pModal->bswAtten[i], AR_PHY_GAIN_2GHZ_BSW_ATTEN),
++ AR_PHY_GAIN_2GHZ_BSW_ATTEN);
+ }
+ }
+
+@@ -504,17 +501,14 @@ static void ath9k_hw_def_set_gain(struct
+ AR_PHY_RXGAIN + regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]);
+ } else {
+- REG_WRITE(ah,
+- AR_PHY_RXGAIN + regChainOffset,
+- (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) &
+- ~AR_PHY_RXGAIN_TXRX_ATTEN)
+- | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN));
+- REG_WRITE(ah,
+- AR_PHY_GAIN_2GHZ + regChainOffset,
+- (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+- ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+- SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
++ REG_RMW(ah, AR_PHY_RXGAIN + regChainOffset,
++ SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN),
++ AR_PHY_RXGAIN_TXRX_ATTEN);
++ REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
++ SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN),
++ AR_PHY_GAIN_2GHZ_RXTX_MARGIN);
+ }
++ REG_RMW_BUFFER_FLUSH(ah);
+ }
+
+ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
ccflags-y += -D__CHECK_ENDIAN__
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
-@@ -313,13 +313,6 @@ void _ath_dbg(struct ath_common *common,
+@@ -316,13 +316,6 @@ void _ath_dbg(struct ath_common *common,
#endif /* CPTCFG_ATH_DEBUG */
/** Returns string describing opmode, or NULL if unknown mode. */
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -704,6 +704,7 @@ static const struct ieee80211_iface_limi
+@@ -715,6 +715,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_AP) },
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -1012,23 +1012,23 @@ static int __init ath9k_init(void)
+@@ -1023,23 +1023,23 @@ static int __init ath9k_init(void)
{
int error;
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -358,13 +358,8 @@ static void ath9k_hw_init_config(struct
+@@ -388,13 +388,8 @@ static void ath9k_hw_init_config(struct
ah->config.rx_intr_mitigation = true;
debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
-@@ -148,6 +148,7 @@ struct ath_common {
+@@ -151,6 +151,7 @@ struct ath_common {
int debug_mask;
enum ath_device_state state;
unsigned long op_flags;
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -616,6 +616,7 @@ int ath9k_hw_init(struct ath_hw *ah)
+@@ -646,6 +646,7 @@ int ath9k_hw_init(struct ath_hw *ah)
/* These are all the AR5008/AR9001/AR9002/AR9003 hardware family of chipsets */
switch (ah->hw_version.devid) {
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
-@@ -924,7 +924,7 @@ int ath9k_init_device(u16 devid, struct
+@@ -935,7 +935,7 @@ int ath9k_init_device(u16 devid, struct
#ifdef CPTCFG_MAC80211_LEDS
/* must be initialized before ieee80211_register_hw */
debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -499,6 +499,12 @@ enum {
+@@ -513,6 +513,12 @@ enum {
ATH9K_RESET_COLD,
};
struct ath9k_hw_version {
u32 magic;
u16 devid;
-@@ -780,6 +786,8 @@ struct ath_hw {
+@@ -794,6 +800,8 @@ struct ath_hw {
u32 rfkill_polarity;
u32 ah_flags;
bool reset_power_on;
bool htc_reset_init;
-@@ -1040,6 +1048,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
+@@ -1055,6 +1063,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
bool ath9k_hw_check_alive(struct ath_hw *ah);
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1771,6 +1771,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
+@@ -1803,6 +1803,20 @@ u32 ath9k_hw_get_tsf_offset(struct times
}
EXPORT_SYMBOL(ath9k_hw_get_tsf_offset);
int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath9k_hw_cal_data *caldata, bool fastcc)
{
-@@ -1977,6 +1991,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2011,6 +2025,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st
ar9003_hw_disable_phy_restart(ah);
ath9k_hw_apply_gpio_override(ah);
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -696,6 +696,7 @@ struct ath_spec_scan {
+@@ -710,6 +710,7 @@ struct ath_spec_scan {
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
*
* @spectral_scan_config: set parameters for spectral scan and enable/disable it
* @spectral_scan_trigger: trigger a spectral scan run
* @spectral_scan_wait: wait for a spectral scan run to finish
-@@ -718,6 +719,7 @@ struct ath_hw_ops {
+@@ -732,6 +733,7 @@ struct ath_hw_ops {
struct ath_hw_antcomb_conf *antconf);
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
-@@ -692,7 +692,8 @@ static void ath9k_init_txpower_limits(st
+@@ -703,7 +703,8 @@ static void ath9k_init_txpower_limits(st
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ);
}
static const struct ieee80211_iface_limit if_limits[] = {
-@@ -884,6 +885,18 @@ static void ath9k_set_hw_capab(struct at
+@@ -895,6 +896,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)
{
-@@ -929,6 +942,8 @@ int ath9k_init_device(u16 devid, struct
+@@ -940,6 +953,8 @@ int ath9k_init_device(u16 devid, struct
ARRAY_SIZE(ath9k_tpt_blink));
#endif
static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
-@@ -1315,9 +1315,30 @@ void ar5008_hw_init_rate_txpower(struct
+@@ -1316,9 +1316,30 @@ void ar5008_hw_init_rate_txpower(struct
}
}
static const u32 ar5416_cca_regs[6] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
-@@ -1332,6 +1353,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
+@@ -1333,6 +1354,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
if (ret)
return ret;
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -215,6 +215,19 @@ void ath9k_hw_get_channel_centers(struct
+@@ -245,6 +245,19 @@ void ath9k_hw_get_channel_centers(struct
centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
}
/******************/
/* Chip Revisions */
/******************/
-@@ -1349,6 +1362,9 @@ static bool ath9k_hw_set_reset(struct at
+@@ -1381,6 +1394,9 @@ static bool ath9k_hw_set_reset(struct at
if (AR_SREV_9100(ah))
udelay(50);
return true;
}
-@@ -1448,6 +1464,9 @@ static bool ath9k_hw_chip_reset(struct a
+@@ -1480,6 +1496,9 @@ static bool ath9k_hw_chip_reset(struct a
ar9003_hw_internal_regulator_apply(ah);
ath9k_hw_init_pll(ah, chan);
return true;
}
-@@ -1749,8 +1768,14 @@ static int ath9k_hw_do_fastcc(struct ath
+@@ -1781,8 +1800,14 @@ static int ath9k_hw_do_fastcc(struct ath
if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan);
return -EINVAL;
}
-@@ -2002,6 +2027,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+@@ -2036,6 +2061,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st
ath9k_hw_set_radar_params(ah);
}
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
-@@ -944,55 +944,6 @@ static bool ar5008_hw_ani_control_new(st
+@@ -945,55 +945,6 @@ static bool ar5008_hw_ani_control_new(st
* on == 0 means more noise imm
*/
u32 on = param ? 1 : 0;