mac80211: merge a number of upstream driver fixes/improvements
[openwrt.git] / package / kernel / mac80211 / patches / 319-ath9k_htc-add-new-WMI_REG_RMW_CMDID-command.patch
1 From: Oleksij Rempel <linux@rempel-privat.de>
2 Date: Sun, 22 Mar 2015 19:29:46 +0100
3 Subject: [PATCH] ath9k_htc: add new WMI_REG_RMW_CMDID command
4
5 Since usb bus add extra delay on each request, a command
6 with read + write requests is too expensive. We can dramtically
7 reduce usb load by moving this command to firmware.
8
9 In my tests, this patch will reduce channel scan time
10 for about 5-10 seconds.
11
12 Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
13 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
14 ---
15
16 --- a/drivers/net/wireless/ath/ath.h
17 +++ b/drivers/net/wireless/ath/ath.h
18 @@ -131,6 +131,9 @@ struct ath_ops {
19         void (*enable_write_buffer)(void *);
20         void (*write_flush) (void *);
21         u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr);
22 +       void (*enable_rmw_buffer)(void *);
23 +       void (*rmw_flush) (void *);
24 +
25  };
26  
27  struct ath_common;
28 --- a/drivers/net/wireless/ath/ath9k/htc.h
29 +++ b/drivers/net/wireless/ath/ath9k/htc.h
30 @@ -444,6 +444,10 @@ static inline void ath9k_htc_stop_btcoex
31  #define OP_BT_SCAN                 BIT(4)
32  #define OP_TSF_RESET               BIT(6)
33  
34 +enum htc_op_flags {
35 +       HTC_FWFLAG_NO_RMW,
36 +};
37 +
38  struct ath9k_htc_priv {
39         struct device *dev;
40         struct ieee80211_hw *hw;
41 @@ -482,6 +486,7 @@ struct ath9k_htc_priv {
42         bool reconfig_beacon;
43         unsigned int rxfilter;
44         unsigned long op_flags;
45 +       unsigned long fw_flags;
46  
47         struct ath9k_hw_cal_data caldata;
48         struct ath_spec_scan_priv spec_priv;
49 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
50 +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
51 @@ -376,17 +376,139 @@ static void ath9k_regwrite_flush(void *h
52         mutex_unlock(&priv->wmi->multi_write_mutex);
53  }
54  
55 -static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
56 +static void ath9k_reg_rmw_buffer(void *hw_priv,
57 +                                u32 reg_offset, u32 set, u32 clr)
58 +{
59 +       struct ath_hw *ah = (struct ath_hw *) hw_priv;
60 +       struct ath_common *common = ath9k_hw_common(ah);
61 +       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
62 +       u32 rsp_status;
63 +       int r;
64 +
65 +       mutex_lock(&priv->wmi->multi_rmw_mutex);
66 +
67 +       /* Store the register/value */
68 +       priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].reg =
69 +               cpu_to_be32(reg_offset);
70 +       priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].set =
71 +               cpu_to_be32(set);
72 +       priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].clr =
73 +               cpu_to_be32(clr);
74 +
75 +       priv->wmi->multi_rmw_idx++;
76 +
77 +       /* If the buffer is full, send it out. */
78 +       if (priv->wmi->multi_rmw_idx == MAX_RMW_CMD_NUMBER) {
79 +               r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
80 +                         (u8 *) &priv->wmi->multi_rmw,
81 +                         sizeof(struct register_write) * priv->wmi->multi_rmw_idx,
82 +                         (u8 *) &rsp_status, sizeof(rsp_status),
83 +                         100);
84 +               if (unlikely(r)) {
85 +                       ath_dbg(common, WMI,
86 +                               "REGISTER RMW FAILED, multi len: %d\n",
87 +                               priv->wmi->multi_rmw_idx);
88 +               }
89 +               priv->wmi->multi_rmw_idx = 0;
90 +       }
91 +
92 +       mutex_unlock(&priv->wmi->multi_rmw_mutex);
93 +}
94 +
95 +static void ath9k_reg_rmw_flush(void *hw_priv)
96  {
97 -       u32 val;
98 +       struct ath_hw *ah = (struct ath_hw *) hw_priv;
99 +       struct ath_common *common = ath9k_hw_common(ah);
100 +       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
101 +       u32 rsp_status;
102 +       int r;
103 +
104 +       if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
105 +               return;
106 +
107 +       atomic_dec(&priv->wmi->m_rmw_cnt);
108 +
109 +       mutex_lock(&priv->wmi->multi_rmw_mutex);
110 +
111 +       if (priv->wmi->multi_rmw_idx) {
112 +               r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
113 +                         (u8 *) &priv->wmi->multi_rmw,
114 +                         sizeof(struct register_rmw) * priv->wmi->multi_rmw_idx,
115 +                         (u8 *) &rsp_status, sizeof(rsp_status),
116 +                         100);
117 +               if (unlikely(r)) {
118 +                       ath_dbg(common, WMI,
119 +                               "REGISTER RMW FAILED, multi len: %d\n",
120 +                               priv->wmi->multi_rmw_idx);
121 +               }
122 +               priv->wmi->multi_rmw_idx = 0;
123 +       }
124 +
125 +       mutex_unlock(&priv->wmi->multi_rmw_mutex);
126 +}
127 +
128 +static void ath9k_enable_rmw_buffer(void *hw_priv)
129 +{
130 +       struct ath_hw *ah = (struct ath_hw *) hw_priv;
131 +       struct ath_common *common = ath9k_hw_common(ah);
132 +       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
133 +
134 +       if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
135 +               return;
136  
137 -       val = ath9k_regread(hw_priv, reg_offset);
138 -       val &= ~clr;
139 -       val |= set;
140 -       ath9k_regwrite(hw_priv, val, reg_offset);
141 +       atomic_inc(&priv->wmi->m_rmw_cnt);
142 +}
143 +
144 +static u32 ath9k_reg_rmw_single(void *hw_priv,
145 +                                u32 reg_offset, u32 set, u32 clr)
146 +{
147 +       struct ath_hw *ah = (struct ath_hw *) hw_priv;
148 +       struct ath_common *common = ath9k_hw_common(ah);
149 +       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
150 +       struct register_rmw buf, buf_ret;
151 +       int ret;
152 +       u32 val = 0;
153 +
154 +       buf.reg = cpu_to_be32(reg_offset);
155 +       buf.set = cpu_to_be32(set);
156 +       buf.clr = cpu_to_be32(clr);
157 +
158 +       ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
159 +                         (u8 *) &buf, sizeof(buf),
160 +                         (u8 *) &buf_ret, sizeof(buf_ret),
161 +                         100);
162 +       if (unlikely(ret)) {
163 +               ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n",
164 +                       reg_offset, ret);
165 +       }
166         return val;
167  }
168  
169 +static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
170 +{
171 +       struct ath_hw *ah = (struct ath_hw *) hw_priv;
172 +       struct ath_common *common = ath9k_hw_common(ah);
173 +       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
174 +
175 +       if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) {
176 +               u32 val;
177 +
178 +               val = REG_READ(ah, reg_offset);
179 +               val &= ~clr;
180 +               val |= set;
181 +               REG_WRITE(ah, reg_offset, val);
182 +
183 +               return 0;
184 +       }
185 +
186 +       if (atomic_read(&priv->wmi->m_rmw_cnt))
187 +               ath9k_reg_rmw_buffer(hw_priv, reg_offset, set, clr);
188 +       else
189 +               ath9k_reg_rmw_single(hw_priv, reg_offset, set, clr);
190 +
191 +       return 0;
192 +}
193 +
194  static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
195  {
196         *csz = L1_CACHE_BYTES >> 2;
197 @@ -501,6 +623,8 @@ static int ath9k_init_priv(struct ath9k_
198         ah->reg_ops.write = ath9k_regwrite;
199         ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
200         ah->reg_ops.write_flush = ath9k_regwrite_flush;
201 +       ah->reg_ops.enable_rmw_buffer = ath9k_enable_rmw_buffer;
202 +       ah->reg_ops.rmw_flush = ath9k_reg_rmw_flush;
203         ah->reg_ops.rmw = ath9k_reg_rmw;
204         priv->ah = ah;
205  
206 @@ -686,6 +810,12 @@ static int ath9k_init_firmware_version(s
207                 return -EINVAL;
208         }
209  
210 +       if (priv->fw_version_major == 1 && priv->fw_version_minor < 4)
211 +               set_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags);
212 +
213 +       dev_info(priv->dev, "FW RMW support: %s\n",
214 +               test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags) ? "Off" : "On");
215 +
216         return 0;
217  }
218  
219 --- a/drivers/net/wireless/ath/ath9k/hw.h
220 +++ b/drivers/net/wireless/ath/ath9k/hw.h
221 @@ -100,6 +100,18 @@
222                         (_ah)->reg_ops.write_flush((_ah));      \
223         } while (0)
224  
225 +#define ENABLE_REG_RMW_BUFFER(_ah)                                     \
226 +       do {                                                            \
227 +               if ((_ah)->reg_ops.enable_rmw_buffer)   \
228 +                       (_ah)->reg_ops.enable_rmw_buffer((_ah)); \
229 +       } while (0)
230 +
231 +#define REG_RMW_BUFFER_FLUSH(_ah)                                      \
232 +       do {                                                            \
233 +               if ((_ah)->reg_ops.rmw_flush)           \
234 +                       (_ah)->reg_ops.rmw_flush((_ah));        \
235 +       } while (0)
236 +
237  #define PR_EEP(_s, _val)                                               \
238         do {                                                            \
239                 len += scnprintf(buf + len, size - len, "%20s : %10d\n",\
240 --- a/drivers/net/wireless/ath/ath9k/wmi.c
241 +++ b/drivers/net/wireless/ath/ath9k/wmi.c
242 @@ -61,6 +61,8 @@ static const char *wmi_cmd_to_name(enum 
243                 return "WMI_REG_READ_CMDID";
244         case WMI_REG_WRITE_CMDID:
245                 return "WMI_REG_WRITE_CMDID";
246 +       case WMI_REG_RMW_CMDID:
247 +               return "WMI_REG_RMW_CMDID";
248         case WMI_RC_STATE_CHANGE_CMDID:
249                 return "WMI_RC_STATE_CHANGE_CMDID";
250         case WMI_RC_RATE_UPDATE_CMDID:
251 @@ -101,6 +103,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_
252         spin_lock_init(&wmi->event_lock);
253         mutex_init(&wmi->op_mutex);
254         mutex_init(&wmi->multi_write_mutex);
255 +       mutex_init(&wmi->multi_rmw_mutex);
256         init_completion(&wmi->cmd_wait);
257         INIT_LIST_HEAD(&wmi->pending_tx_events);
258         tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
259 --- a/drivers/net/wireless/ath/ath9k/wmi.h
260 +++ b/drivers/net/wireless/ath/ath9k/wmi.h
261 @@ -112,6 +112,7 @@ enum wmi_cmd_id {
262         WMI_TX_STATS_CMDID,
263         WMI_RX_STATS_CMDID,
264         WMI_BITRATE_MASK_CMDID,
265 +       WMI_REG_RMW_CMDID,
266  };
267  
268  enum wmi_event_id {
269 @@ -125,12 +126,19 @@ enum wmi_event_id {
270  };
271  
272  #define MAX_CMD_NUMBER 62
273 +#define MAX_RMW_CMD_NUMBER 15
274  
275  struct register_write {
276         __be32 reg;
277         __be32 val;
278  };
279  
280 +struct register_rmw {
281 +       __be32 reg;
282 +       __be32 set;
283 +       __be32 clr;
284 +} __packed;
285 +
286  struct ath9k_htc_tx_event {
287         int count;
288         struct __wmi_event_txstatus txs;
289 @@ -156,10 +164,18 @@ struct wmi {
290  
291         spinlock_t wmi_lock;
292  
293 +       /* multi write section */
294         atomic_t mwrite_cnt;
295         struct register_write multi_write[MAX_CMD_NUMBER];
296         u32 multi_write_idx;
297         struct mutex multi_write_mutex;
298 +
299 +       /* multi rmw section */
300 +       atomic_t m_rmw_cnt;
301 +       struct register_rmw multi_rmw[MAX_RMW_CMD_NUMBER];
302 +       u32 multi_rmw_idx;
303 +       struct mutex multi_rmw_mutex;
304 +
305  };
306  
307  struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);