aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
authorOleksij Rempel <linux@rempel-privat.de>2015-03-22 14:29:46 -0400
committerKalle Valo <kvalo@codeaurora.org>2015-03-30 04:31:18 -0400
commit8badb50cfab6d433622dbfd5a90b6adf27333107 (patch)
treeb8b6569c7390aaa1a8fb693c5e37a4935d0175bb /drivers/net/wireless/ath/ath9k
parente480e1344873b6a715d06a003e603d86a11a4033 (diff)
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>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c142
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.h16
5 files changed, 172 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 300d3671d0ef..e82a0d4ce23f 100644
--- 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(struct ath9k_htc_priv *priv)
444#define OP_BT_SCAN BIT(4) 444#define OP_BT_SCAN BIT(4)
445#define OP_TSF_RESET BIT(6) 445#define OP_TSF_RESET BIT(6)
446 446
447enum htc_op_flags {
448 HTC_FWFLAG_NO_RMW,
449};
450
447struct ath9k_htc_priv { 451struct ath9k_htc_priv {
448 struct device *dev; 452 struct device *dev;
449 struct ieee80211_hw *hw; 453 struct ieee80211_hw *hw;
@@ -482,6 +486,7 @@ struct ath9k_htc_priv {
482 bool reconfig_beacon; 486 bool reconfig_beacon;
483 unsigned int rxfilter; 487 unsigned int rxfilter;
484 unsigned long op_flags; 488 unsigned long op_flags;
489 unsigned long fw_flags;
485 490
486 struct ath9k_hw_cal_data caldata; 491 struct ath9k_hw_cal_data caldata;
487 struct ath_spec_scan_priv spec_priv; 492 struct ath_spec_scan_priv spec_priv;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index fd229409f676..d7beefe60683 100644
--- 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 *hw_priv)
376 mutex_unlock(&priv->wmi->multi_write_mutex); 376 mutex_unlock(&priv->wmi->multi_write_mutex);
377} 377}
378 378
379static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) 379static void ath9k_reg_rmw_buffer(void *hw_priv,
380 u32 reg_offset, u32 set, u32 clr)
381{
382 struct ath_hw *ah = (struct ath_hw *) hw_priv;
383 struct ath_common *common = ath9k_hw_common(ah);
384 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
385 u32 rsp_status;
386 int r;
387
388 mutex_lock(&priv->wmi->multi_rmw_mutex);
389
390 /* Store the register/value */
391 priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].reg =
392 cpu_to_be32(reg_offset);
393 priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].set =
394 cpu_to_be32(set);
395 priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].clr =
396 cpu_to_be32(clr);
397
398 priv->wmi->multi_rmw_idx++;
399
400 /* If the buffer is full, send it out. */
401 if (priv->wmi->multi_rmw_idx == MAX_RMW_CMD_NUMBER) {
402 r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
403 (u8 *) &priv->wmi->multi_rmw,
404 sizeof(struct register_write) * priv->wmi->multi_rmw_idx,
405 (u8 *) &rsp_status, sizeof(rsp_status),
406 100);
407 if (unlikely(r)) {
408 ath_dbg(common, WMI,
409 "REGISTER RMW FAILED, multi len: %d\n",
410 priv->wmi->multi_rmw_idx);
411 }
412 priv->wmi->multi_rmw_idx = 0;
413 }
414
415 mutex_unlock(&priv->wmi->multi_rmw_mutex);
416}
417
418static void ath9k_reg_rmw_flush(void *hw_priv)
380{ 419{
381 u32 val; 420 struct ath_hw *ah = (struct ath_hw *) hw_priv;
421 struct ath_common *common = ath9k_hw_common(ah);
422 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
423 u32 rsp_status;
424 int r;
425
426 if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
427 return;
428
429 atomic_dec(&priv->wmi->m_rmw_cnt);
382 430
383 val = ath9k_regread(hw_priv, reg_offset); 431 mutex_lock(&priv->wmi->multi_rmw_mutex);
384 val &= ~clr; 432
385 val |= set; 433 if (priv->wmi->multi_rmw_idx) {
386 ath9k_regwrite(hw_priv, val, reg_offset); 434 r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
435 (u8 *) &priv->wmi->multi_rmw,
436 sizeof(struct register_rmw) * priv->wmi->multi_rmw_idx,
437 (u8 *) &rsp_status, sizeof(rsp_status),
438 100);
439 if (unlikely(r)) {
440 ath_dbg(common, WMI,
441 "REGISTER RMW FAILED, multi len: %d\n",
442 priv->wmi->multi_rmw_idx);
443 }
444 priv->wmi->multi_rmw_idx = 0;
445 }
446
447 mutex_unlock(&priv->wmi->multi_rmw_mutex);
448}
449
450static void ath9k_enable_rmw_buffer(void *hw_priv)
451{
452 struct ath_hw *ah = (struct ath_hw *) hw_priv;
453 struct ath_common *common = ath9k_hw_common(ah);
454 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
455
456 if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
457 return;
458
459 atomic_inc(&priv->wmi->m_rmw_cnt);
460}
461
462static u32 ath9k_reg_rmw_single(void *hw_priv,
463 u32 reg_offset, u32 set, u32 clr)
464{
465 struct ath_hw *ah = (struct ath_hw *) hw_priv;
466 struct ath_common *common = ath9k_hw_common(ah);
467 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
468 struct register_rmw buf, buf_ret;
469 int ret;
470 u32 val = 0;
471
472 buf.reg = cpu_to_be32(reg_offset);
473 buf.set = cpu_to_be32(set);
474 buf.clr = cpu_to_be32(clr);
475
476 ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
477 (u8 *) &buf, sizeof(buf),
478 (u8 *) &buf_ret, sizeof(buf_ret),
479 100);
480 if (unlikely(ret)) {
481 ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n",
482 reg_offset, ret);
483 }
387 return val; 484 return val;
388} 485}
389 486
487static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
488{
489 struct ath_hw *ah = (struct ath_hw *) hw_priv;
490 struct ath_common *common = ath9k_hw_common(ah);
491 struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
492
493 if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) {
494 u32 val;
495
496 val = REG_READ(ah, reg_offset);
497 val &= ~clr;
498 val |= set;
499 REG_WRITE(ah, reg_offset, val);
500
501 return 0;
502 }
503
504 if (atomic_read(&priv->wmi->m_rmw_cnt))
505 ath9k_reg_rmw_buffer(hw_priv, reg_offset, set, clr);
506 else
507 ath9k_reg_rmw_single(hw_priv, reg_offset, set, clr);
508
509 return 0;
510}
511
390static void ath_usb_read_cachesize(struct ath_common *common, int *csz) 512static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
391{ 513{
392 *csz = L1_CACHE_BYTES >> 2; 514 *csz = L1_CACHE_BYTES >> 2;
@@ -501,6 +623,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
501 ah->reg_ops.write = ath9k_regwrite; 623 ah->reg_ops.write = ath9k_regwrite;
502 ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; 624 ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
503 ah->reg_ops.write_flush = ath9k_regwrite_flush; 625 ah->reg_ops.write_flush = ath9k_regwrite_flush;
626 ah->reg_ops.enable_rmw_buffer = ath9k_enable_rmw_buffer;
627 ah->reg_ops.rmw_flush = ath9k_reg_rmw_flush;
504 ah->reg_ops.rmw = ath9k_reg_rmw; 628 ah->reg_ops.rmw = ath9k_reg_rmw;
505 priv->ah = ah; 629 priv->ah = ah;
506 630
@@ -686,6 +810,12 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
686 return -EINVAL; 810 return -EINVAL;
687 } 811 }
688 812
813 if (priv->fw_version_major == 1 && priv->fw_version_minor < 4)
814 set_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags);
815
816 dev_info(priv->dev, "FW RMW support: %s\n",
817 test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags) ? "Off" : "On");
818
689 return 0; 819 return 0;
690} 820}
691 821
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index aaec9451de49..7b51d8e3696f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -100,6 +100,18 @@
100 (_ah)->reg_ops.write_flush((_ah)); \ 100 (_ah)->reg_ops.write_flush((_ah)); \
101 } while (0) 101 } while (0)
102 102
103#define ENABLE_REG_RMW_BUFFER(_ah) \
104 do { \
105 if ((_ah)->reg_ops.enable_rmw_buffer) \
106 (_ah)->reg_ops.enable_rmw_buffer((_ah)); \
107 } while (0)
108
109#define REG_RMW_BUFFER_FLUSH(_ah) \
110 do { \
111 if ((_ah)->reg_ops.rmw_flush) \
112 (_ah)->reg_ops.rmw_flush((_ah)); \
113 } while (0)
114
103#define PR_EEP(_s, _val) \ 115#define PR_EEP(_s, _val) \
104 do { \ 116 do { \
105 len += scnprintf(buf + len, size - len, "%20s : %10d\n",\ 117 len += scnprintf(buf + len, size - len, "%20s : %10d\n",\
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 65c8894c5f81..67a2f8c88829 100644
--- 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 wmi_cmd_id wmi_cmd)
61 return "WMI_REG_READ_CMDID"; 61 return "WMI_REG_READ_CMDID";
62 case WMI_REG_WRITE_CMDID: 62 case WMI_REG_WRITE_CMDID:
63 return "WMI_REG_WRITE_CMDID"; 63 return "WMI_REG_WRITE_CMDID";
64 case WMI_REG_RMW_CMDID:
65 return "WMI_REG_RMW_CMDID";
64 case WMI_RC_STATE_CHANGE_CMDID: 66 case WMI_RC_STATE_CHANGE_CMDID:
65 return "WMI_RC_STATE_CHANGE_CMDID"; 67 return "WMI_RC_STATE_CHANGE_CMDID";
66 case WMI_RC_RATE_UPDATE_CMDID: 68 case WMI_RC_RATE_UPDATE_CMDID:
@@ -101,6 +103,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
101 spin_lock_init(&wmi->event_lock); 103 spin_lock_init(&wmi->event_lock);
102 mutex_init(&wmi->op_mutex); 104 mutex_init(&wmi->op_mutex);
103 mutex_init(&wmi->multi_write_mutex); 105 mutex_init(&wmi->multi_write_mutex);
106 mutex_init(&wmi->multi_rmw_mutex);
104 init_completion(&wmi->cmd_wait); 107 init_completion(&wmi->cmd_wait);
105 INIT_LIST_HEAD(&wmi->pending_tx_events); 108 INIT_LIST_HEAD(&wmi->pending_tx_events);
106 tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, 109 tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 0db37f230018..aa84a335289a 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -112,6 +112,7 @@ enum wmi_cmd_id {
112 WMI_TX_STATS_CMDID, 112 WMI_TX_STATS_CMDID,
113 WMI_RX_STATS_CMDID, 113 WMI_RX_STATS_CMDID,
114 WMI_BITRATE_MASK_CMDID, 114 WMI_BITRATE_MASK_CMDID,
115 WMI_REG_RMW_CMDID,
115}; 116};
116 117
117enum wmi_event_id { 118enum wmi_event_id {
@@ -125,12 +126,19 @@ enum wmi_event_id {
125}; 126};
126 127
127#define MAX_CMD_NUMBER 62 128#define MAX_CMD_NUMBER 62
129#define MAX_RMW_CMD_NUMBER 15
128 130
129struct register_write { 131struct register_write {
130 __be32 reg; 132 __be32 reg;
131 __be32 val; 133 __be32 val;
132}; 134};
133 135
136struct register_rmw {
137 __be32 reg;
138 __be32 set;
139 __be32 clr;
140} __packed;
141
134struct ath9k_htc_tx_event { 142struct ath9k_htc_tx_event {
135 int count; 143 int count;
136 struct __wmi_event_txstatus txs; 144 struct __wmi_event_txstatus txs;
@@ -156,10 +164,18 @@ struct wmi {
156 164
157 spinlock_t wmi_lock; 165 spinlock_t wmi_lock;
158 166
167 /* multi write section */
159 atomic_t mwrite_cnt; 168 atomic_t mwrite_cnt;
160 struct register_write multi_write[MAX_CMD_NUMBER]; 169 struct register_write multi_write[MAX_CMD_NUMBER];
161 u32 multi_write_idx; 170 u32 multi_write_idx;
162 struct mutex multi_write_mutex; 171 struct mutex multi_write_mutex;
172
173 /* multi rmw section */
174 atomic_t m_rmw_cnt;
175 struct register_rmw multi_rmw[MAX_RMW_CMD_NUMBER];
176 u32 multi_rmw_idx;
177 struct mutex multi_rmw_mutex;
178
163}; 179};
164 180
165struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv); 181struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);