* [RFC][PATCH 5/6] ath9k: check error flags even if rx frame is marked ok
From: Johan Hovold @ 2010-04-16 10:52 UTC (permalink / raw)
To: ath9k-devel, linux-wireless; +Cc: Tor Krill, Johan Hovold
In-Reply-To: <20100416104850.GA13329@lundinova.se>
Check error flags even if frame is marked ok by hardware as this flag
may have been incorrectly set.
Signed-off-by: Johan Hovold <johan.hovold@lundinova.se>
---
00000000: 88 41 30 00 00 80 48 68 08 af 00 b9 49 c3 e1 3f
00000010: 5a 9d 51 71 09 63 00 50 00 00 00 00 ff 54 00 20
00000020: 36 9d 46 02 90 31 2c e8 68 06 84 6e b5 00 29 e8
00000030: ef e3 6f a0 ee 99 7c 7e d8 7d 12 aa de 5c 20 69
00000040: d6 6a ad c4 99 bb c1 e4 c3 ba bd 77 51 7f a2 a5
00000050: 01 e4 81 a0 be 40 54 45 70 e4 cc 11 58 f8 ad 45
00000060: 84 1c 72 36 a1 fd b7 33 ad aa 4f 8b
rxstatus8 = 5994daab
Here AR_RxFrameOK is set even though AR_DecryptCRCErr and AR_MichaelErr are
set.
Note that this also happens for frames with non-corrupt PNs, e.g.:
FrameOK with error: c79e7573
FrameOK with error: 264786bf
FrameOK with error: f3a2446f
FrameOK with error: 2c054c4f
drivers/net/wireless/ath/ath9k/mac.c | 22 ++++++++++------------
1 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 891a294..2b4295b 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -925,18 +925,16 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
if (ads.ds_rxstatus8 & AR_KeyMiss)
rs->rs_flags |= ATH9K_RX_KEY_MISS;
- if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
- if (ads.ds_rxstatus8 & AR_CRCErr)
- rs->rs_status |= ATH9K_RXERR_CRC;
- else if (ads.ds_rxstatus8 & AR_PHYErr) {
- rs->rs_status |= ATH9K_RXERR_PHY;
- phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
- rs->rs_phyerr = phyerr;
- } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
- rs->rs_status |= ATH9K_RXERR_DECRYPT;
- else if (ads.ds_rxstatus8 & AR_MichaelErr)
- rs->rs_status |= ATH9K_RXERR_MIC;
- }
+ if (ads.ds_rxstatus8 & AR_CRCErr)
+ rs->rs_status |= ATH9K_RXERR_CRC;
+ else if (ads.ds_rxstatus8 & AR_PHYErr) {
+ rs->rs_status |= ATH9K_RXERR_PHY;
+ phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
+ rs->rs_phyerr = phyerr;
+ } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+ rs->rs_status |= ATH9K_RXERR_DECRYPT;
+ else if (ads.ds_rxstatus8 & AR_MichaelErr)
+ rs->rs_status |= ATH9K_RXERR_MIC;
return 0;
}
--
1.7.0.3
^ permalink raw reply related
* [RFC][PATCH 4/6] ath9k: do not mark frames with RX_KEY_MISS as decrypted
From: Johan Hovold @ 2010-04-16 10:52 UTC (permalink / raw)
To: ath9k-devel, linux-wireless; +Cc: Tor Krill, Johan Hovold
In-Reply-To: <20100416104850.GA13329@lundinova.se>
Frames tagged by hardware with ATH9K_RX_KEY_MISS should not
incorrectly be marked decrypted.
Signed-off-by: Johan Hovold <johan.hovold@lundinova.se>
---
The frame below has no error flags set besides KeyMiss and would be marked
decrypted by the current code.
00000000: 88 41 30 00 00 80 48 68 08 0f 00 21 6a 56 2c 36
00000010: 00 22 02 00 0b 63 10 a4 00 00 10 00 40 0a 00 20
00000020: 81 62 6d de 46 89 96 96 97 ec cf aa e3 77 73 07
00000030: 17 e8 76 91 73 fd ea a9 29 62 e4 c3 17 46 39 0a
00000040: 52 7f 26 39 2d 4c 22 7c 0e 91 78 95 ff 1d d0 18
00000050: ef 6a af 99 42 74 70 c1 d4 8b 56 16 9b 90 f3 9a
00000060: ff 52 5d 1c 77 ee 83 34 f6 14 1c da
rxstatus8 = b9accfc3
set: AR_RxFrameOK | AR_RxKeyIdxValid | AR_KeyMiss
cleared: AR_CRCErr | AR_DecryptCRCErr | AR_PHYErr | AR_MichaelErr | AR_DecryptBusyErr
drivers/net/wireless/ath/ath9k/common.c | 3 ++-
drivers/net/wireless/ath/ath9k/mac.c | 2 ++
drivers/net/wireless/ath/ath9k/mac.h | 1 +
3 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index dd4be54..1623af1 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -256,7 +256,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
keyix = rx_stats->rs_keyix;
if (ieee80211_has_protected(fc) && !decrypt_error &&
- !(rx_stats->rs_flags & ATH9K_RX_DECRYPT_BUSY)) {
+ !(rx_stats->rs_flags & ATH9K_RX_DECRYPT_BUSY) &&
+ !(rx_stats->rs_flags & ATH9K_RX_KEY_MISS)) {
if (keyix != ATH9K_RXKEYIX_INVALID)
rxs->flag |= RX_FLAG_DECRYPTED;
}
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 4a2060e..891a294 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -922,6 +922,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+ if (ads.ds_rxstatus8 & AR_KeyMiss)
+ rs->rs_flags |= ATH9K_RX_KEY_MISS;
if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
if (ads.ds_rxstatus8 & AR_CRCErr)
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 68dbd7a..ba3c98e 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -189,6 +189,7 @@ struct ath_htc_rx_status {
#define ATH9K_RX_DELIM_CRC_PRE 0x10
#define ATH9K_RX_DELIM_CRC_POST 0x20
#define ATH9K_RX_DECRYPT_BUSY 0x40
+#define ATH9K_RX_KEY_MISS 0x80
#define ATH9K_RXKEYIX_INVALID ((u8)-1)
#define ATH9K_TXKEYIX_INVALID ((u32)-1)
--
1.7.0.3
^ permalink raw reply related
* [RFC][PATCH 3/6] ath9k: do not mark frames with RX_DECRYPT_BUSY as decrypted
From: Johan Hovold @ 2010-04-16 10:52 UTC (permalink / raw)
To: ath9k-devel, linux-wireless; +Cc: Tor Krill, Johan Hovold
In-Reply-To: <20100416104850.GA13329@lundinova.se>
Frames tagged by hardware with ATH9K_RX_DECRYPT_BUSY should not
incorrectly be marked decrypted.
Signed-off-by: Johan Hovold <johan.hovold@lundinova.se>
---
Some corrupt frames such as the one below have DecryptBusyErr flag set even
though frame is marked ok and without DecryptCRCErr set.
00000000: 88 41 30 00 00 80 48 68 08 0f 00 21 6a 56 2c 36
00000010: 00 22 02 00 0b 63 e0 2b 00 00 e0 00 bd 42 00 20
00000020: ef 44 5c a5 45 62 c2 2d af c3 cc ef ec cb d0 83
00000030: a7 7f fd bc 7d f1 c4 5e 72 82 81 fc ff 1a 9d 85
00000040: 63 cd 36 ae a4 12 6e fb b7 6a 77 71 4a 06 e6 ae
00000050: a6 40 ad b1 76 b7 de ff 7c bd cf b1 ef 3d 93 bf
00000060: 68 a0 af c1 a2 14 84 a4 4c 9e 5e 3e
rxstatus8 = de461103
set: AR_RxFrameOK | AR_RxKeyIdxValid | AR_DecryptBusyErr | Ar_KeyMiss
cleared: AR_CRCErr | AR_DecryptCRCErr | AR_PHYErr | AR_MichaelErr
drivers/net/wireless/ath/ath9k/common.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index af22e7a..dd4be54 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -255,7 +255,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
keyix = rx_stats->rs_keyix;
- if (ieee80211_has_protected(fc) && !decrypt_error) {
+ if (ieee80211_has_protected(fc) && !decrypt_error &&
+ !(rx_stats->rs_flags & ATH9K_RX_DECRYPT_BUSY)) {
if (keyix != ATH9K_RXKEYIX_INVALID)
rxs->flag |= RX_FLAG_DECRYPTED;
}
--
1.7.0.3
^ permalink raw reply related
* [RFC][PATCH 2/6] ath9k: do not mark frames with RXKEY_IX_INVALID as decrypted
From: Johan Hovold @ 2010-04-16 10:52 UTC (permalink / raw)
To: ath9k-devel, linux-wireless; +Cc: Tor Krill, Johan Hovold
In-Reply-To: <20100416104850.GA13329@lundinova.se>
Frames tagged by hardware with ATH9K_RXKEYIX_INVALID should not
incorrectly be marked decrypted (even if key index in frame is valid).
Signed-off-by: Johan Hovold <johan.hovold@lundinova.se>
---
The current code overrides the hardware flag indicating that the key index is
invalid and falsely mark this frame as decrypted.
00000000: 88 41 30 00 00 80 48 68 08 0f 00 21 6a 56 2c 36
00000010: 00 22 02 00 0b 63 20 0d 00 00 20 00 d1 20 00 20
00000020: b1 5b a7 c5 96 be cf a3 16 3b 35 a0 bb 59 ea d2
00000030: 17 10 28 b0 07 67 14 ff d7 6f 77 5c f1 01 f0 04
00000040: 8d 03 47 68 9d b2 bd b4 64 bb cd 58 e9 ff 82 d2
00000050: f3 d0 38 b1 75 a2 2f d2 d6 b7 70 ec 95 22 71 32
00000060: 54 c0 c4 6d 1f 0d 19 32 22 e9 c2 9c
rxstatus8 = 3bbc20a3
set: AR_RxFrameOK | AR_MichaelErr
cleared: AR_CRCErr | AR_DecryptCRCErr | AR_PHYErr | AR_RxKeyIdxValid
drivers/net/wireless/ath/ath9k/common.c | 8 +-------
1 files changed, 1 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 0cd10dc..af22e7a 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -256,14 +256,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
keyix = rx_stats->rs_keyix;
if (ieee80211_has_protected(fc) && !decrypt_error) {
- if (keyix != ATH9K_RXKEYIX_INVALID) {
+ if (keyix != ATH9K_RXKEYIX_INVALID)
rxs->flag |= RX_FLAG_DECRYPTED;
- } else if (skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
-
- if (test_bit(keyix, common->keymap))
- rxs->flag |= RX_FLAG_DECRYPTED;
- }
}
if (ah->sw_mgmt_crypto &&
(rxs->flag & RX_FLAG_DECRYPTED) &&
--
1.7.0.3
^ permalink raw reply related
* [RFC][PATCH 1/6] ath9k: clean up rx skb post-process logic
From: Johan Hovold @ 2010-04-16 10:52 UTC (permalink / raw)
To: ath9k-devel, linux-wireless; +Cc: Tor Krill, Johan Hovold
In-Reply-To: <20100416104850.GA13329@lundinova.se>
Refactor IEEE80211_FCTL_PROTECTED and decryption error test.
Signed-off-by: Johan Hovold <johan.hovold@lundinova.se>
---
drivers/net/wireless/ath/ath9k/common.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 09effde..0cd10dc 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -255,15 +255,15 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
keyix = rx_stats->rs_keyix;
- if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
- ieee80211_has_protected(fc)) {
- rxs->flag |= RX_FLAG_DECRYPTED;
- } else if (ieee80211_has_protected(fc)
- && !decrypt_error && skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
-
- if (test_bit(keyix, common->keymap))
+ if (ieee80211_has_protected(fc) && !decrypt_error) {
+ if (keyix != ATH9K_RXKEYIX_INVALID) {
rxs->flag |= RX_FLAG_DECRYPTED;
+ } else if (skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, common->keymap))
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ }
}
if (ah->sw_mgmt_crypto &&
(rxs->flag & RX_FLAG_DECRYPTED) &&
--
1.7.0.3
^ permalink raw reply related
* ath9k: corrupt frames forwarded to mac80211 as decrypted (was: ath9k: receive stops working in AP-mode and 802.11n)
From: Johan Hovold @ 2010-04-16 10:48 UTC (permalink / raw)
To: ath9k-devel, linux-wireless; +Cc: Tor Krill
In-Reply-To: <20100331191058.GD18913@lundinova.se>
Hi,
I now know why 802.11n receive stalls; ath9k is passing corrupt frames to
mac80211.
The corrupt frames are marked as decrypted so the receive PN is updated to a
random number. Later non-corrupt frames with correct PNs are consequently
deemed out-of-sequence and are dropped. Connection is restored at re-keying as
this resets the queue PN.
I noted that some of the corrupt frames may be caught in the driver by closer
inspection of the associated rx status. By modifying the receive processing I
am able to catch most corrupt frames. Unfortunately, there are still some that
seem impossible to identify without actually looking at the actual frames.
An example of such a frame is:
00000000: 88 41 30 00 00 80 48 68 08 0f 00 21 6a 56 2c 36
00000010: 00 22 02 00 0b 63 20 52 00 00 20 21 21 05 00 20
00000020: 8a 39 7b 1f 0f 11 07 9e bd 53 80 33 3b 8c 98 00
00000030: ef 5f da 7c 9a d6 3d d7 59 ac e0 21 44 88 63 d7
00000040: 21 34 b7 9a 89 8e cf 9e 46 1c ee d6 81 56 25 59
00000050: d2 ec ac 33 e6 12 3d c5 02 61 2d 80 8d 30 44 1e
00000060: 79 74 79 79 62 25 ba ec 04 4d 54 dc
with associated status
rxstatus8 = 1e989103
Here nothing in the frame status indicates an error; the frame has no error
flags set, the frame-ok flag is set, and so on. Still the frame is indeed
corrupt; the last four octets of the CCMP-header (bytes 0x20..0x23) should
be {00,00,00,00} rather than {8a,39,7b,1f} as the correct PN is 0x0521 (not
0x1f7b398a0521).
The corrupt frames all seem to have the upper half of the CCMP-header, data
and MIC corrupted, whereas the FCS (last four bytes) seem to be correct in the
sense that they match what I see in the air (and is verified by wireshark).
One explanation for all of this could be that the corrupt packet is what the
hardware is expected to return should it's processing fail (e.g. due to
checksum error). Then the problem is merely that the status field sometimes
get corrupted (some frames with corrupt PN do indeed come with matching
rxstatus). Comments in the code concerning corrupt status fields also point in
this direction.
Another explanation could be that the status is actually correct but for some
reason the returned frame is corrupted. Perhaps it's a combination of both
corrupt status and frame.
Any ideas about what may be going on here?
As I mentioned above I can catch most corrupt frames with the following changes
to the rx processing:
ath9k: clean up rx skb post-process logic
ath9k: do not mark frames with RXKEY_IX_INVALID as decrypted
ath9k: do not mark frames with RX_DECRYPT_BUSY as decrypted
ath9k: do not mark frames with RX_KEY_MISS as decrypted
ath9k: check error flags even if rx frame is marked ok
ath9k: clear mic error flag on encrypted frames
drivers/net/wireless/ath/ath9k/common.c | 16 ++++++++--------
drivers/net/wireless/ath/ath9k/mac.c | 26 +++++++++++++-------------
drivers/net/wireless/ath/ath9k/mac.h | 1 +
3 files changed, 22 insertions(+), 21 deletions(-)
The last change reduces the number of false MIC-errors that leads hostapd to
trigger countermeasures.
I might be violating the semantics of the error flags with some of these
changes, but it does make sense if indeed the status flags are getting
corrupted. For instance, if the FrameOK flag is erroneously set the remaining
error flags would never be checked. My change make sure the error flags are
always checked. Of course this may also, if the error flags get set due to status
corruption, lead to occasional false negatives which would have to be resend,
but this is better than passing false positives to mac80211 which breaks
communication completely.
I'm responding to this mail with the aforementioned patches against linux-next
from 20100413.
I'm still using AR9280.
Thanks,
Johan Hovold
^ permalink raw reply
* [PATCH] wl1251: add support for dedicated IRQ line
From: Grazvydas Ignotas @ 2010-04-16 10:22 UTC (permalink / raw)
To: John W. Linville
Cc: linux-wireless, Kalle Valo, Bob Copeland, Grazvydas Ignotas
wl1251 has WLAN_IRQ pin for generating interrupts to host processor,
which is mandatory in SPI mode and optional in SDIO mode (which can
use SDIO interrupts instead). However TI recommends using deditated
IRQ line for SDIO too.
Add support for using dedicated interrupt line with SDIO, but also leave
ability to switch to SDIO interrupts in case it's needed.
Signed-off-by: Grazvydas Ignotas <notasas@gmail.com>
---
drivers/net/wireless/wl12xx/wl1251_sdio.c | 56 ++++++++++++++++++++++++++---
include/linux/spi/wl12xx.h | 2 +
2 files changed, 53 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index 7409c34..d234285 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -25,6 +25,7 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/platform_device.h>
#include <linux/spi/wl12xx.h>
+#include <linux/irq.h>
#include "wl1251.h"
@@ -134,18 +135,36 @@ static void wl1251_sdio_disable_irq(struct wl1251 *wl)
sdio_release_host(func);
}
+/* Interrupts when using dedicated WLAN_IRQ pin */
+static irqreturn_t wl1251_line_irq(int irq, void *cookie)
+{
+ struct wl1251 *wl = cookie;
+
+ ieee80211_queue_work(wl->hw, &wl->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static void wl1251_enable_line_irq(struct wl1251 *wl)
+{
+ return enable_irq(wl->irq);
+}
+
+static void wl1251_disable_line_irq(struct wl1251 *wl)
+{
+ return disable_irq(wl->irq);
+}
+
static void wl1251_sdio_set_power(bool enable)
{
}
-static const struct wl1251_if_operations wl1251_sdio_ops = {
+static struct wl1251_if_operations wl1251_sdio_ops = {
.read = wl1251_sdio_read,
.write = wl1251_sdio_write,
.write_elp = wl1251_sdio_write_elp,
.read_elp = wl1251_sdio_read_elp,
.reset = wl1251_sdio_reset,
- .enable_irq = wl1251_sdio_enable_irq,
- .disable_irq = wl1251_sdio_disable_irq,
};
static int wl1251_platform_probe(struct platform_device *pdev)
@@ -191,6 +210,7 @@ static int wl1251_sdio_probe(struct sdio_func *func,
goto release;
sdio_set_block_size(func, 512);
+ sdio_release_host(func);
SET_IEEE80211_DEV(hw, &func->dev);
wl->if_priv = func;
@@ -199,17 +219,41 @@ static int wl1251_sdio_probe(struct sdio_func *func,
if (wl12xx_board_data != NULL) {
wl->set_power = wl12xx_board_data->set_power;
+ wl->irq = wl12xx_board_data->irq;
wl->use_eeprom = wl12xx_board_data->use_eeprom;
}
- sdio_release_host(func);
+ if (wl->irq) {
+ ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
+ if (ret < 0) {
+ wl1251_error("request_irq() failed: %d", ret);
+ goto disable;
+ }
+
+ set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+ disable_irq(wl->irq);
+
+ wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq;
+ wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq;
+
+ wl1251_info("using dedicated interrupt line");
+ } else {
+ wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq;
+ wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq;
+
+ wl1251_info("using SDIO interrupt");
+ }
+
ret = wl1251_init_ieee80211(wl);
if (ret)
- goto disable;
+ goto out_free_irq;
sdio_set_drvdata(func, wl);
return ret;
+out_free_irq:
+ if (wl->irq)
+ free_irq(wl->irq, wl);
disable:
sdio_claim_host(func);
sdio_disable_func(func);
@@ -222,6 +266,8 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
{
struct wl1251 *wl = sdio_get_drvdata(func);
+ if (wl->irq)
+ free_irq(wl->irq, wl);
wl1251_free_hw(wl);
sdio_claim_host(func);
diff --git a/include/linux/spi/wl12xx.h b/include/linux/spi/wl12xx.h
index aed64ed..a223ecb 100644
--- a/include/linux/spi/wl12xx.h
+++ b/include/linux/spi/wl12xx.h
@@ -26,6 +26,8 @@
struct wl12xx_platform_data {
void (*set_power)(bool enable);
+ /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
+ int irq;
bool use_eeprom;
};
--
1.6.3.3
^ permalink raw reply related
* [PATCH] wireless: rt2x00: rt2800usb: delete Allwin devices
From: Xose Vazquez Perez @ 2010-04-16 10:16 UTC (permalink / raw)
To: linux-wireless; +Cc: users, linville, IvDoorn, gwingerde, xose.vazquez
Common sense says:
(0x8516, 0x2070) is RT2070
(0x8516, 0x2770) is RT2770
(0x8516, 0x2870) is RT2870
[...]
but Allwin doesn't sell USB dongles nor PCI boards, only voip-routers
http://www.allwin.com.tw/eng/modules/tinyd0/content/index.php?id=1
Signed-off-by: Xose Vazquez Perez <xose.vazquez@gmail.com>
---
drivers/net/wireless/rt2x00/rt2800usb.c | 8 --------
1 files changed, 0 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index df7666f..41de405 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1019,14 +1019,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
* Unclear what kind of devices these are (they aren't supported by the
* vendor driver).
*/
- /* Allwin */
- { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Amigo */
{ USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
--
1.6.6.1
^ permalink raw reply related
* [RFC PATCHv3 0/2] mac80211: cfg80211: dynamic ps timeout based on pm-qos
From: Juuso Oikarinen @ 2010-04-16 9:14 UTC (permalink / raw)
To: linux-wireless
These patches propose a way to adjust the dynamic ps timeout in the mac80211
based on the pm-qos network latency value. This allows user space to influence
the level of power saving performed by the mac80211.
These patches will the current 100ms timeout for the default network
latency value (2000s), so that for non-adjusted pm-qos the functionality will
remain as it is currently. Dynamic ps is disabled for any larger latency
values, and a timeout of 300s is used for latency values smaller than 50ms.
v3 of these patches ad a 50s dynamic ps configuration.
As wext still has an interface to adjust the dynamic ps timeout from userspace,
the wext configuration will override the above, to remain backwards
compatible.
Comments are appreciated.
Juuso Oikarinen (2):
mac80211: Determine dynamic PS timeout based on ps-qos network
latency
cfg80211: Remove default dynamic PS timeout value
include/net/mac80211.h | 5 ++++-
net/mac80211/cfg.c | 4 ++--
net/mac80211/main.c | 2 ++
net/mac80211/mlme.c | 14 ++++++++++++++
net/wireless/core.c | 3 ++-
5 files changed, 24 insertions(+), 4 deletions(-)
^ permalink raw reply
* [RFC PATCHv3 2/2] cfg80211: Remove default dynamic PS timeout value
From: Juuso Oikarinen @ 2010-04-16 9:14 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <1271409274-17162-1-git-send-email-juuso.oikarinen@nokia.com>
Now that the mac80211 is choosing dynamic ps timeouts based on the ps-qos
network latency configuration, configure a default value of -1 as the dynamic
ps timeout in cfg80211. This value allows the mac80211 to determine the value
to be used.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
net/wireless/core.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6ac70c1..37d0e0a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -705,7 +705,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->ps = true;
else
wdev->ps = false;
- wdev->ps_timeout = 100;
+ /* allow mac80211 to determine the timeout */
+ wdev->ps_timeout = -1;
if (rdev->ops->set_power_mgmt)
if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
wdev->ps,
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCHv3 1/2] mac80211: Determine dynamic PS timeout based on ps-qos network latency
From: Juuso Oikarinen @ 2010-04-16 9:14 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <1271409274-17162-1-git-send-email-juuso.oikarinen@nokia.com>
Determine the dynamic PS timeout based on the configured ps-qos network
latency. For backwards wext compatibility, allow the dynamic PS timeout
configured by the cfg80211 to overrule the automatically determined value.
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
include/net/mac80211.h | 5 ++++-
net/mac80211/cfg.c | 4 ++--
net/mac80211/main.c | 2 ++
net/mac80211/mlme.c | 14 ++++++++++++++
4 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index dcf3c5f..243e4ab 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -661,6 +661,9 @@ enum ieee80211_smps_mode {
* @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
* powersave documentation below. This variable is valid only when
* the CONF_PS flag is set.
+ * @dynamic_ps_forced_timeout: The dynamic powersave timeout (in ms) configured
+ * by cfg80211 (essentially, wext) If set, this value overrules the value
+ * chosen by mac80211 based on ps qos network latency.
*
* @power_level: requested transmit power (in dBm)
*
@@ -680,7 +683,7 @@ enum ieee80211_smps_mode {
*/
struct ieee80211_conf {
u32 flags;
- int power_level, dynamic_ps_timeout;
+ int power_level, dynamic_ps_timeout, dynamic_ps_forced_timeout;
int max_sleep_period;
u16 listen_interval;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7dd7cda..9a1a91c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1388,11 +1388,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
return -EOPNOTSUPP;
if (enabled == sdata->u.mgd.powersave &&
- timeout == conf->dynamic_ps_timeout)
+ timeout == conf->dynamic_ps_forced_timeout)
return 0;
sdata->u.mgd.powersave = enabled;
- conf->dynamic_ps_timeout = timeout;
+ conf->dynamic_ps_forced_timeout = timeout;
/* no change, but if automatic follow powersave */
mutex_lock(&sdata->u.mgd.mtx);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 4afe851..ebcca0e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -569,6 +569,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.conf.listen_interval = local->hw.max_listen_interval;
+ local->hw.conf.dynamic_ps_forced_timeout = -1;
+
result = sta_info_start(local);
if (result < 0)
goto fail_sta_info;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 35d8502..6402997 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -476,6 +476,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
{
struct ieee80211_sub_if_data *sdata, *found = NULL;
int count = 0;
+ int timeout;
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
local->ps_sdata = NULL;
@@ -509,6 +510,19 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
beaconint_us = ieee80211_tu_to_usec(
found->vif.bss_conf.beacon_int);
+ timeout = local->hw.conf.dynamic_ps_forced_timeout;
+ if (timeout < 0) {
+ if (latency <= 50000)
+ timeout = 300;
+ else if (latency <= 2000000000)
+ timeout = 100;
+ else if (latency <= 2100000000)
+ timeout = 50;
+ else
+ timeout = 0;
+ }
+ local->hw.conf.dynamic_ps_timeout = timeout;
+
if (beaconint_us > latency) {
local->ps_sdata = NULL;
} else {
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCH] mac80211: Prevent running sta_cleanup timer unnecessarily
From: Juuso Oikarinen @ 2010-04-16 7:35 UTC (permalink / raw)
To: linux-wireless
In-Reply-To: <1271403308-23416-1-git-send-email-juuso.oikarinen@nokia.com>
The sta_cleanup timer is used to periodically expire buffered frames from the
tx buf. The timer is executing periodically, regardless of the need for it.
This is wasting resources.
Fix this simply by not restarting the sta_cleanup timer if the tx buffer was
empty. Restart the timer when there is some more tx-traffic.
Cc: Janne Ylälehto <janne.ylalehto@nokia.com>
Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
---
net/mac80211/sta_info.c | 13 ++++++++++---
net/mac80211/tx.c | 7 +++++++
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ff0eb94..3de7a22 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -575,7 +575,7 @@ static int sta_info_buffer_expired(struct sta_info *sta,
}
-static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
struct sta_info *sta)
{
unsigned long flags;
@@ -583,7 +583,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata;
if (skb_queue_empty(&sta->ps_tx_buf))
- return;
+ return false;
for (;;) {
spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
@@ -608,6 +608,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
if (skb_queue_empty(&sta->ps_tx_buf))
sta_info_clear_tim_bit(sta);
}
+
+ return true;
}
static int __must_check __sta_info_destroy(struct sta_info *sta)
@@ -755,15 +757,20 @@ static void sta_info_cleanup(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sta_info *sta;
+ bool timer_needed = false;
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list)
- sta_info_cleanup_expire_buffered(local, sta);
+ if (sta_info_cleanup_expire_buffered(local, sta))
+ timer_needed = true;
rcu_read_unlock();
if (local->quiescing)
return;
+ if (!timer_needed)
+ return;
+
local->sta_cleanup.expires =
round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
add_timer(&local->sta_cleanup);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2cb7726..e2aa972 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -429,6 +429,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
struct sta_info *sta = tx->sta;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+ struct ieee80211_local *local = tx->local;
u32 staflags;
if (unlikely(!sta ||
@@ -476,6 +477,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+
+ if (!timer_pending(&local->sta_cleanup))
+ mod_timer(&local->sta_cleanup,
+ round_jiffies(jiffies +
+ STA_INFO_CLEANUP_INTERVAL));
+
return TX_QUEUED;
}
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCH] mac80211: sta_cleanup timer handling
From: Juuso Oikarinen @ 2010-04-16 7:35 UTC (permalink / raw)
To: linux-wireless
The sta_cleanup timer is used to expire frames in the sta structure ps_tx_buf
-list. To perform this, the timer is executed periodically.
The timer is executed periodically, regardless if there are frames in the
buffer or not. As a result, the system gets periodically woken up for no
reason at all, wasting precious resources.
This patch proposes a simple fix. It prevent rescheduling the sta_cleanup
timer if on the particular invocation the ps_tx_buf buffers for all sta's
were empty. On the TX path, the timer is restarted upon queueing frames to
those buffers.
Due to the way checking is performed, this approach will "leak" a few
unnecessary invocations of the timer handler, but in the big picture those
do not matter.
Comments are appreciated.
Juuso Oikarinen (1):
mac80211: Prevent running sta_cleanup timer unnecessarily
net/mac80211/sta_info.c | 13 ++++++++++---
net/mac80211/tx.c | 7 +++++++
2 files changed, 17 insertions(+), 3 deletions(-)
^ permalink raw reply
* Re: Survey mode volunteers
From: Holger Schurig @ 2010-04-16 6:47 UTC (permalink / raw)
To: Anton Puolakka; +Cc: Luis Rodriguez, linux-wireless@vger.kernel.org
In-Reply-To: <0290AB2F0A8E124B9FFC144088A1A95609D6097401@EX-MBS04.nbl.local>
> We checked the most recent wireless-testing and saw no related patch on
> mac80211 yet. So, Holger, do You have one for that, too? Or anyone else on
> the mailing-list? Could You please share?
Sure. I thought I already posted that patch. This is a patch that
applied to compat-wireless 2010-03-23:
---------------
Subject: [PATCH] mac80211: sample survey implementation for mac80211_hwsim
This adds the survey function to both mac80211 itself and to mac80211_hwsim.
For the latter driver, we simply invent some noise level.
Signed-off-by: Holger Schurig <holgerschurig@gmail.com>
---
drivers/net/wireless/mac80211_hwsim.c | 28 ++++++++++++++++++++++++++++
include/net/mac80211.h | 3 ++-
net/mac80211/cfg.c | 12 ++++++++++++
net/mac80211/driver-ops.h | 9 +++++++++
4 files changed, 51 insertions(+), 1 deletion(-)
--- compat-wireless-2010-03-15.orig/include/net/mac80211.h
+++ compat-wireless-2010-03-15/include/net/mac80211.h
@@ -1646,7 +1646,8 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
-
+ int (*get_survey)(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey);
void (*rfkill_poll)(struct ieee80211_hw *hw);
void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class);
#ifdef CONFIG_NL80211_TESTMODE
--- compat-wireless-2010-03-15.orig/net/mac80211/cfg.c
+++ compat-wireless-2010-03-15/net/mac80211/cfg.c
@@ -412,6 +412,17 @@ static int ieee80211_dump_station(struct
return ret;
}
+static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
+ int idx, struct survey_info *survey)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (!local->ops->get_survey)
+ return -EOPNOTSUPP;
+
+ return drv_get_survey(local, idx, survey);
+}
+
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_info *sinfo)
{
@@ -1476,6 +1487,7 @@ struct cfg80211_ops mac80211_config_ops
.change_station = ieee80211_change_station,
.get_station = ieee80211_get_station,
.dump_station = ieee80211_dump_station,
+ .dump_survey = ieee80211_dump_survey,
#ifdef CONFIG_MAC80211_MESH
.add_mpath = ieee80211_add_mpath,
.del_mpath = ieee80211_del_mpath,
--- compat-wireless-2010-03-15.orig/net/mac80211/driver-ops.h
+++ compat-wireless-2010-03-15/net/mac80211/driver-ops.h
@@ -346,6 +346,15 @@ static inline int drv_ampdu_action(struc
return ret;
}
+static inline int drv_get_survey(struct ieee80211_local *local, int idx,
+ struct survey_info *survey)
+{
+ int ret = -EOPNOTSUPP;
+ if (local->ops->get_survey)
+ ret = local->ops->get_survey(&local->hw, idx, survey);
+ /* trace_drv_get_survey(local, idx, survey, ret); */
+ return ret;
+}
static inline void drv_rfkill_poll(struct ieee80211_local *local)
{
--- compat-wireless-2010-03-15.orig/drivers/net/wireless/mac80211_hwsim.c
+++ compat-wireless-2010-03-15/drivers/net/wireless/mac80211_hwsim.c
@@ -828,6 +828,33 @@ static int mac80211_hwsim_conf_tx(
return 0;
}
+static int mac80211_hwsim_get_survey(
+ struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct ieee80211_conf *conf = &hw->conf;
+
+ printk(KERN_DEBUG "%s:%s (idx=%d)\n",
+ wiphy_name(hw->wiphy), __func__, idx);
+
+ if (idx != 0)
+ return -ENOENT;
+
+ /* Current channel */
+ survey->channel = conf->channel;
+
+ /*
+ * Magically conjured noise level --- this is only ok for simulated hardware.
+ *
+ * A real driver which cannot determine the real channel noise MUST NOT
+ * report any noise, especially not a magically conjured one :-)
+ */
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ survey->noise = -92;
+
+ return 0;
+}
+
#ifdef CONFIG_NL80211_TESTMODE
/*
* This section contains example code for using netlink
@@ -981,6 +1008,7 @@ static struct ieee80211_ops mac80211_hws
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,
+ .get_survey = mac80211_hwsim_get_survey,
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
.ampdu_action = mac80211_hwsim_ampdu_action,
.flush = mac80211_hwsim_flush,
^ permalink raw reply
* Re: Survey mode volunteers
From: Holger Schurig @ 2010-04-16 6:45 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: Luis Rodriguez, Anton Puolakka, Benoit PAPILLAULT,
linux-wireless@vger.kernel.org
In-Reply-To: <20100414173044.GA2841@tux>
> Nice, it should be very similar for ath9k
... but please be aware that is is only about 20% of survey. Things that need
to be addressed are the reporting of some kind of duty-cycle (how much is this
channel occupied) and logic inside scanning to actually trigger this for
channels other than the current one.
> BTW, one enhancement which we've
> been meanint to address but haven't had the time yet is to split noise
> floor per channel. This can be seen how its done on the legacy HAL with
> the code sprinkled with the ATH_NF_PER_CHAN ifdef.
Nice, knowing the noise-per-channel AND the channel occupation would be quite
helpful to select the "best" channel.
--
http://www.holgerschurig.de
^ permalink raw reply
* [PATCH 10/10] ath9k_htc: Fix sparse endian warnings
From: Sujith @ 2010-04-16 6:26 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
This patch fixes a bunch of endian issues that
were exposed by sparse. It's a miracle that the driver
worked at all till now.
The Lord be praised.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/htc.h | 18 ++++++++--------
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 6 +++-
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 14 +++++++-----
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 11 ++-------
drivers/net/wireless/ath/ath9k/htc_hst.c | 8 +++---
drivers/net/wireless/ath/ath9k/htc_hst.h | 24 +++++++++++-----------
drivers/net/wireless/ath/ath9k/mac.h | 10 ++++----
drivers/net/wireless/ath/ath9k/wmi.c | 2 +-
drivers/net/wireless/ath/ath9k/wmi.h | 10 ++++----
9 files changed, 51 insertions(+), 52 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 6a4614a..c765ff4 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -124,13 +124,13 @@ struct ath9k_htc_cap_target {
struct ath9k_htc_target_vif {
u8 index;
u8 des_bssid[ETH_ALEN];
- enum htc_opmode opmode;
+ __be32 opmode;
u8 myaddr[ETH_ALEN];
u8 bssid[ETH_ALEN];
u32 flags;
u32 flags_ext;
u16 ps_sta;
- u16 rtsthreshold;
+ __be16 rtsthreshold;
u8 ath_cap;
u8 node;
s8 mcast_rate;
@@ -151,7 +151,7 @@ struct ath9k_htc_target_sta {
u8 sta_index;
u8 vif_index;
u8 vif_sta;
- u16 flags; /* ATH_HTC_STA_* */
+ __be16 flags; /* ATH_HTC_STA_* */
u16 htcap;
u8 valid;
u16 capinfo;
@@ -191,16 +191,16 @@ struct ath9k_htc_rate {
struct ath9k_htc_target_rate {
u8 sta_index;
u8 isnew;
- u32 capflags;
+ __be32 capflags;
struct ath9k_htc_rate rates;
};
struct ath9k_htc_target_stats {
- u32 tx_shortretry;
- u32 tx_longretry;
- u32 tx_xretries;
- u32 ht_txunaggr_xretry;
- u32 ht_tx_xretries;
+ __be32 tx_shortretry;
+ __be32 tx_longretry;
+ __be32 tx_xretries;
+ __be32 ht_txunaggr_xretry;
+ __be32 ht_tx_xretries;
} __packed;
struct ath9k_htc_vif {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index d104028..7cb55f5 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -26,7 +26,8 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
enum ath9k_int imask = 0;
int dtimperiod, dtimcount, sleepduration;
int cfpperiod, cfpcount, bmiss_timeout;
- u32 nexttbtt = 0, intval, tsftu, htc_imask = 0;
+ u32 nexttbtt = 0, intval, tsftu;
+ __be32 htc_imask = 0;
u64 tsf;
int num_beacons, offset, dtim_dec_count, cfp_dec_count;
int ret;
@@ -142,7 +143,8 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
{
struct ath_common *common = ath9k_hw_common(priv->ah);
enum ath9k_int imask = 0;
- u32 nexttbtt, intval, htc_imask = 0;
+ u32 nexttbtt, intval;
+ __be32 htc_imask = 0;
int ret;
u8 cmd_rsp;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 081f445..ec7bcc8 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -125,7 +125,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
bool fastcc = true;
struct ieee80211_channel *channel = hw->conf.channel;
enum htc_phymode mode;
- u16 htc_mode;
+ __be16 htc_mode;
u8 cmd_rsp;
int ret;
@@ -378,7 +378,7 @@ static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
priv->tgt_rate.sta_index = ista->index;
priv->tgt_rate.isnew = 1;
trate = priv->tgt_rate;
- priv->tgt_rate.capflags = caps;
+ priv->tgt_rate.capflags = cpu_to_be32(caps);
trate.capflags = cpu_to_be32(caps);
WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
@@ -426,6 +426,7 @@ static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
struct ath9k_htc_target_rate trate;
struct ath_common *common = ath9k_hw_common(priv->ah);
int ret;
+ u32 caps = be32_to_cpu(priv->tgt_rate.capflags);
u8 cmd_rsp;
memset(&trate, 0, sizeof(trate));
@@ -433,11 +434,12 @@ static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
trate = priv->tgt_rate;
if (is_cw40)
- priv->tgt_rate.capflags |= WLAN_RC_40_FLAG;
+ caps |= WLAN_RC_40_FLAG;
else
- priv->tgt_rate.capflags &= ~WLAN_RC_40_FLAG;
+ caps &= ~WLAN_RC_40_FLAG;
- trate.capflags = cpu_to_be32(priv->tgt_rate.capflags);
+ priv->tgt_rate.capflags = cpu_to_be32(caps);
+ trate.capflags = cpu_to_be32(caps);
WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
if (ret) {
@@ -1104,7 +1106,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
struct ath9k_channel *init_channel;
int ret = 0;
enum htc_phymode mode;
- u16 htc_mode;
+ __be16 htc_mode;
u8 cmd_rsp;
ath_print(common, ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 0a7cb30..2c3c510 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -530,7 +530,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
}
- rx_status->mactime = rxbuf->rxstatus.rs_tstamp;
+ rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
@@ -634,13 +634,8 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
rxstatus = (struct ath_htc_rx_status *)skb->data;
- rxstatus->rs_tstamp = be64_to_cpu(rxstatus->rs_tstamp);
- rxstatus->rs_datalen = be16_to_cpu(rxstatus->rs_datalen);
- rxstatus->evm0 = be32_to_cpu(rxstatus->evm0);
- rxstatus->evm1 = be32_to_cpu(rxstatus->evm1);
- rxstatus->evm2 = be32_to_cpu(rxstatus->evm2);
-
- if (rxstatus->rs_datalen - (len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
+ if (be16_to_cpu(rxstatus->rs_datalen) -
+ (len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
ath_print(common, ATH_DBG_FATAL,
"Corrupted RX data len, dropping "
"(epid: %d, dlen: %d, skblen: %d)\n",
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 587d98e..f2dca25 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -368,7 +368,7 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
struct htc_frame_hdr *htc_hdr;
enum htc_endpoint_id epid;
struct htc_endpoint *endpoint;
- u16 *msg_id;
+ __be16 *msg_id;
if (!htc_handle || !skb)
return;
@@ -388,14 +388,14 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle,
/* Handle trailer */
if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
- if (be32_to_cpu(*(u32 *) skb->data) == 0x00C60000)
+ if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
/* Move past the Watchdog pattern */
htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
}
/* Get the message ID */
- msg_id = (u16 *) ((void *) htc_hdr +
- sizeof(struct htc_frame_hdr));
+ msg_id = (__be16 *) ((void *) htc_hdr +
+ sizeof(struct htc_frame_hdr));
/* Now process HTC messages */
switch (be16_to_cpu(*msg_id)) {
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index cd7048f..ea50ab0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -59,20 +59,20 @@ enum htc_endpoint_id {
struct htc_frame_hdr {
u8 endpoint_id;
u8 flags;
- u16 payload_len;
+ __be16 payload_len;
u8 control[4];
} __packed;
struct htc_ready_msg {
- u16 message_id;
- u16 credits;
- u16 credit_size;
+ __be16 message_id;
+ __be16 credits;
+ __be16 credit_size;
u8 max_endpoints;
u8 pad;
} __packed;
struct htc_config_pipe_msg {
- u16 message_id;
+ __be16 message_id;
u8 pipe_id;
u8 credits;
} __packed;
@@ -192,9 +192,9 @@ enum htc_service_group_ids{
#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 8)
struct htc_conn_svc_msg {
- u16 msg_id;
- u16 service_id;
- u16 con_flags;
+ __be16 msg_id;
+ __be16 service_id;
+ __be16 con_flags;
u8 dl_pipeid;
u8 ul_pipeid;
u8 svc_meta_len;
@@ -209,17 +209,17 @@ struct htc_conn_svc_msg {
#define HTC_SERVICE_NO_MORE_EP 4
struct htc_conn_svc_rspmsg {
- u16 msg_id;
- u16 service_id;
+ __be16 msg_id;
+ __be16 service_id;
u8 status;
u8 endpoint_id;
- u16 max_msg_len;
+ __be16 max_msg_len;
u8 svc_meta_len;
u8 pad;
} __packed;
struct htc_comp_msg {
- u16 msg_id;
+ __be16 msg_id;
} __packed;
int htc_init(struct htc_target *target);
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 68eb8d0..66d0d5e 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -155,8 +155,8 @@ struct ath_rx_status {
};
struct ath_htc_rx_status {
- u64 rs_tstamp;
- u16 rs_datalen;
+ __be64 rs_tstamp;
+ __be16 rs_datalen;
u8 rs_status;
u8 rs_phyerr;
int8_t rs_rssi;
@@ -175,9 +175,9 @@ struct ath_htc_rx_status {
u8 rs_num_delims;
u8 rs_flags;
u8 rs_dummy;
- u32 evm0;
- u32 evm1;
- u32 evm2;
+ __be32 evm0;
+ __be32 evm1;
+ __be32 evm2;
};
#define ATH9K_RXERR_CRC 0x01
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index afbf63d..dc6c6fc 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -129,7 +129,7 @@ void ath9k_wmi_tasklet(unsigned long data)
void *wmi_event;
unsigned long flags;
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- u32 txrate;
+ __be32 txrate;
#endif
spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 6113571..167e15c 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -19,7 +19,7 @@
struct wmi_event_txrate {
- u32 txrate;
+ __be32 txrate;
struct {
u8 rssi_thresh;
u8 per;
@@ -27,8 +27,8 @@ struct wmi_event_txrate {
} __packed;
struct wmi_cmd_hdr {
- u16 command_id;
- u16 seq_no;
+ __be16 command_id;
+ __be16 seq_no;
} __packed;
struct wmi_swba {
@@ -87,8 +87,8 @@ enum wmi_event_id {
#define MAX_CMD_NUMBER 62
struct register_write {
- u32 reg;
- u32 val;
+ __be32 reg;
+ __be32 val;
};
struct wmi {
--
1.7.0.5
^ permalink raw reply related
* [PATCH 07/10] ath9k_htc: Remove GPIO set on unload
From: Sujith @ 2010-04-16 6:25 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
There is no point in trying to set the LED pin
when the module is being unloaded. The target
would be reset anyway.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 08a4a58..2cea577 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -960,7 +960,6 @@ void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
ath9k_unregister_led(&priv->tx_led);
ath9k_unregister_led(&priv->rx_led);
ath9k_unregister_led(&priv->radio_led);
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
}
void ath9k_init_leds(struct ath9k_htc_priv *priv)
--
1.7.0.5
^ permalink raw reply related
* [PATCH 09/10] ath9k_htc: Handle WMI timeouts properly
From: Sujith @ 2010-04-16 6:24 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
If a WMI command has timed out for some reason,
a late WMI response would end up updating the
response region of a new WMI request that has been
issued in the meantime.
Fix this race condition by dropping a WMI response
if a new WMI command has been issued.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/wmi.c | 13 +++++++++++++
drivers/net/wireless/ath/ath9k/wmi.h | 1 +
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 355e0db..afbf63d 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -204,6 +204,14 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
return;
}
+ /* Check if there has been a timeout. */
+ spin_lock(&wmi->wmi_lock);
+ if (cmd_id != wmi->last_cmd_id) {
+ spin_unlock(&wmi->wmi_lock);
+ goto free_skb;
+ }
+ spin_unlock(&wmi->wmi_lock);
+
/* WMI command response */
ath9k_wmi_rsp_callback(wmi, skb);
@@ -266,6 +274,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
struct sk_buff *skb;
u8 *data;
int time_left, ret = 0;
+ unsigned long flags;
if (!wmi)
return -EINVAL;
@@ -297,6 +306,10 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
if (ret)
goto out;
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
+ wmi->last_cmd_id = cmd_id;
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
if (!time_left) {
ath_print(common, ATH_DBG_WMI,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index fd8c9c5..6113571 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -97,6 +97,7 @@ struct wmi {
enum htc_endpoint_id ctrl_epid;
struct mutex op_mutex;
struct completion cmd_wait;
+ enum wmi_cmd_id last_cmd_id;
u16 tx_seq_id;
u8 *cmd_rsp_buf;
u32 cmd_rsp_len;
--
1.7.0.5
^ permalink raw reply related
* [PATCH 08/10] ath9k_htc: Add dropped SKB count to debugfs
From: Sujith @ 2010-04-16 6:24 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/hif_usb.c | 13 +++++++++----
drivers/net/wireless/ath/ath9k/htc.h | 1 +
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 +++
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index fe994e2..3091bb3 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -129,6 +129,7 @@ static void hif_usb_tx_cb(struct urb *urb)
TX_STAT_INC(skb_completed);
} else {
dev_kfree_skb_any(skb);
+ TX_STAT_INC(skb_dropped);
}
}
@@ -149,11 +150,15 @@ static void hif_usb_tx_cb(struct urb *urb)
}
}
-static inline void ath9k_skb_queue_purge(struct sk_buff_head *list)
+static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
+ struct sk_buff_head *list)
{
struct sk_buff *skb;
- while ((skb = __skb_dequeue(list)) != NULL)
+
+ while ((skb = __skb_dequeue(list)) != NULL) {
dev_kfree_skb_any(skb);
+ TX_STAT_INC(skb_dropped);
+ }
}
/* TX lock has to be taken */
@@ -214,7 +219,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
if (ret) {
tx_buf->len = tx_buf->offset = 0;
- ath9k_skb_queue_purge(&tx_buf->skb_queue);
+ ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
__skb_queue_head_init(&tx_buf->skb_queue);
list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
hif_dev->tx.tx_buf_cnt++;
@@ -281,7 +286,7 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
- ath9k_skb_queue_purge(&hif_dev->tx.tx_skb_queue);
+ ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue);
hif_dev->tx.tx_skb_cnt = 0;
hif_dev->tx.flags |= HIF_USB_TX_STOP;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 78213fc..6a4614a 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -261,6 +261,7 @@ struct ath_tx_stats {
u32 buf_completed;
u32 skb_queued;
u32 skb_completed;
+ u32 skb_dropped;
};
struct ath_rx_stats {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 2cea577..081f445 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -609,6 +609,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"%20s : %10u\n", "SKBs completed",
priv->debug.tx_stats.skb_completed);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "SKBs dropped",
+ priv->debug.tx_stats.skb_dropped);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
--
1.7.0.5
^ permalink raw reply related
* [PATCH 06/10] ath9k_hw: Use buffered register writes
From: Sujith @ 2010-04-16 6:23 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
This patch adds macros at certain places
which could be optimized for multiple register writes.
The performance of ath9k_htc improves considerably,
especially reducing the latency involved in a scan run.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/ani.c | 23 ++++++++
drivers/net/wireless/ath/ath9k/ar5008_phy.c | 28 ++++++++++
drivers/net/wireless/ath/ath9k/ar9002_calib.c | 5 ++
drivers/net/wireless/ath/ath9k/ar9002_hw.c | 7 ++-
drivers/net/wireless/ath/ath9k/ar9002_phy.c | 5 ++
drivers/net/wireless/ath/ath9k/eeprom_4k.c | 10 ++++
drivers/net/wireless/ath/ath9k/hw.c | 71 +++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/mac.c | 27 +++++++++
8 files changed, 175 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 5a2d867..cec62d3 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -79,11 +79,17 @@ static void ath9k_ani_restart(struct ath_hw *ah)
"Writing ofdmbase=%u cckbase=%u\n",
aniState->ofdmPhyErrBase,
aniState->cckPhyErrBase);
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
aniState->ofdmPhyErrCount = 0;
@@ -357,8 +363,14 @@ void ath9k_ani_reset(struct ath_hw *ah)
ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
~ATH9K_RX_FILTER_PHYERR);
ath9k_ani_restart(ah);
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
void ath9k_hw_ani_monitor(struct ath_hw *ah,
@@ -456,6 +468,8 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_FILT_OFDM, 0);
REG_WRITE(ah, AR_FILT_CCK, 0);
REG_WRITE(ah, AR_MIBC,
@@ -463,6 +477,9 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
& 0x0f);
REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
/* Freeze the MIB counters, get the stats and then clear them */
@@ -626,8 +643,14 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
ah->ani[0].cckPhyErrBase);
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
ath9k_enable_mib_counters(ah);
ah->aniperiod = ATH9K_ANI_PERIOD;
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 94eb069..de8ce12 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -590,10 +590,14 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
rx_chainmask = ah->rxchainmask;
tx_chainmask = ah->txchainmask;
+ ENABLE_REGWRITE_BUFFER(ah);
+
switch (rx_chainmask) {
case 0x5:
+ DISABLE_REGWRITE_BUFFER(ah);
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
AR_PHY_SWAP_ALT_CHAIN);
+ ENABLE_REGWRITE_BUFFER(ah);
case 0x3:
if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
@@ -611,6 +615,10 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
}
REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
if (tx_chainmask == 0x5) {
REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
AR_PHY_SWAP_ALT_CHAIN);
@@ -689,8 +697,13 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
ath9k_hw_set11nmac2040(ah);
+ 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);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
@@ -773,6 +786,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
+ ENABLE_REGWRITE_BUFFER(ah);
+
for (i = 0; i < ah->iniModes.ia_rows; i++) {
u32 reg = INI_RA(&ah->iniModes, i, 0);
u32 val = INI_RA(&ah->iniModes, i, modesIndex);
@@ -790,6 +805,9 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
DO_DELAY(regWrites);
}
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
@@ -801,6 +819,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only,
modesIndex, regWrites);
+ ENABLE_REGWRITE_BUFFER(ah);
+
/* Write common array parameters */
for (i = 0; i < ah->iniCommon.ia_rows; i++) {
u32 reg = INI_RA(&ah->iniCommon, i, 0);
@@ -816,6 +836,9 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
DO_DELAY(regWrites);
}
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
if (AR_SREV_9271(ah)) {
if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1)
REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
@@ -1303,6 +1326,8 @@ static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
udelay(50);
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
val = REG_READ(ah, ar5416_cca_regs[i]);
@@ -1311,6 +1336,9 @@ static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
REG_WRITE(ah, ar5416_cca_regs[i], val);
}
}
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 968529b..5fdbb53 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -527,6 +527,8 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
ah->pacal_info.prev_offset = regVal;
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
regVal = REG_READ(ah, 0x7834);
regVal |= 0x1;
REG_WRITE(ah, 0x7834, regVal);
@@ -536,6 +538,9 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
for (i = 0; i < ARRAY_SIZE(regList); i++)
REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index 17b98a3..adb33b3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -488,10 +488,15 @@ static int ar9002_hw_get_radiorev(struct ath_hw *ah)
u32 val;
int i;
- REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
+ ENABLE_REGWRITE_BUFFER(ah);
+ REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
for (i = 0; i < 8; i++)
REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index a0a2f58..18cfe1a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -236,6 +236,8 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+ ENABLE_REGWRITE_BUFFER(ah);
+
newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
@@ -411,6 +413,9 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
| (mask_p[47] << 2) | (mask_p[46] << 0);
REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
static void ar9002_olc_init(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 2384a9f..41a77d1 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -454,6 +454,8 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
&tMinCalPower, gainBoundaries,
pdadcValues, numXpdGain);
+ ENABLE_REGWRITE_BUFFER(ah);
+
if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
SM(pdGainOverlap_t2,
@@ -494,6 +496,9 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
regOffset += 4;
}
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
}
@@ -759,6 +764,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
/* OFDM power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
ATH9K_POW_SM(ratesArray[rate18mb], 24)
@@ -821,6 +828,9 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
}
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 18cbb19..daca9d3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -275,6 +275,8 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
if (AR_SREV_9100(ah))
return;
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
@@ -286,6 +288,9 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
/* This should work for all families including legacy */
@@ -639,6 +644,8 @@ EXPORT_SYMBOL(ath9k_hw_init);
static void ath9k_hw_init_qos(struct ath_hw *ah)
{
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
@@ -652,6 +659,9 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
static void ath9k_hw_init_pll(struct ath_hw *ah,
@@ -703,6 +713,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
if (opmode == NL80211_IFTYPE_AP)
imr_reg |= AR_IMR_MIB;
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_IMR, imr_reg);
ah->imrs2_reg |= AR_IMR_S2_GTT;
REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
@@ -713,6 +725,9 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
}
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
if (AR_SREV_9300_20_OR_LATER(ah)) {
REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, 0);
@@ -841,6 +856,8 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
u32 regval;
+ ENABLE_REGWRITE_BUFFER(ah);
+
/*
* set AHB_MODE not to do cacheline prefetches
*/
@@ -855,6 +872,9 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
/*
* Restore TX Trigger Level to its pre-reset value.
* The initial value depends on whether aggregation is enabled, and is
@@ -863,6 +883,8 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
if (!AR_SREV_9300_20_OR_LATER(ah))
REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
+ ENABLE_REGWRITE_BUFFER(ah);
+
/*
* let mac dma writes be in 128 byte chunks
*/
@@ -898,6 +920,9 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
AR_PCU_TXBUF_CTRL_USABLE_SIZE);
}
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
if (AR_SREV_9300_20_OR_LATER(ah))
ath9k_hw_reset_txstatus_ring(ah);
}
@@ -957,6 +982,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
(void)REG_READ(ah, AR_RTC_DERIVED_CLK);
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT);
@@ -985,6 +1012,10 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
}
REG_WRITE(ah, AR_RTC_RC, rst_flags);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
udelay(50);
REG_WRITE(ah, AR_RTC_RC, 0);
@@ -1005,6 +1036,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
{
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT);
@@ -1013,6 +1046,9 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
REG_WRITE(ah, AR_RTC_RESET, 0);
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
if (!AR_SREV_9300_20_OR_LATER(ah))
udelay(2);
@@ -1241,6 +1277,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_set_operating_mode(ah, ah->opmode);
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
| macStaId1
@@ -1254,13 +1292,21 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_ISR, ~0);
REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
r = ath9k_hw_rf_set_freq(ah, chan);
if (r)
return r;
+ ENABLE_REGWRITE_BUFFER(ah);
+
for (i = 0; i < AR_NUM_DCU; i++)
REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
ah->intr_txqs = 0;
for (i = 0; i < ah->caps.total_queues; i++)
ath9k_hw_resettxqueue(ah, i);
@@ -1300,9 +1346,14 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (!ath9k_hw_init_cal(ah, chan))
return -EIO;
+ ENABLE_REGWRITE_BUFFER(ah);
+
ath9k_hw_restore_chainmask(ah);
REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
/*
* For big endian systems turn on swapping for descriptors
*/
@@ -1766,6 +1817,8 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
ah->beacon_interval = beacon_period;
+ ENABLE_REGWRITE_BUFFER(ah);
+
switch (ah->opmode) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_MONITOR:
@@ -1809,6 +1862,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
beacon_period &= ~ATH9K_BEACON_ENA;
if (beacon_period & ATH9K_BEACON_RESET_TSF) {
ath9k_hw_reset_tsf(ah);
@@ -1825,6 +1881,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
REG_WRITE(ah, AR_BEACON_PERIOD,
@@ -1832,6 +1890,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
REG_RMW_FIELD(ah, AR_RSSI_THR,
AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
@@ -1854,6 +1915,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_NEXT_DTIM,
TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
@@ -1873,6 +1936,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
REG_SET_BIT(ah, AR_TIMER_MODE,
AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
AR_DTIM_TIMER_EN);
@@ -2330,6 +2396,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
{
u32 phybits;
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_RX_FILTER, bits);
phybits = 0;
@@ -2345,6 +2413,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
else
REG_WRITE(ah, AR_RXCFG,
REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
EXPORT_SYMBOL(ath9k_hw_setrxfilter);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index b54e857..7bbf502 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -25,6 +25,8 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
ah->txurn_interrupt_mask);
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_IMR_S0,
SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
| SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
@@ -35,6 +37,9 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
}
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
@@ -470,6 +475,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
} else
cwMin = qi->tqi_cwmin;
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_DLCL_IFS(q),
SM(cwMin, AR_D_LCL_IFS_CWMIN) |
SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
@@ -484,6 +491,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
REG_WRITE(ah, AR_DMISC(q),
AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+ REGWRITE_BUFFER_FLUSH(ah);
+
if (qi->tqi_cbrPeriod) {
REG_WRITE(ah, AR_QCBRCFG(q),
SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
@@ -499,6 +508,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
AR_Q_RDYTIMECFG_EN);
}
+ REGWRITE_BUFFER_FLUSH(ah);
+
REG_WRITE(ah, AR_DCHNTIME(q),
SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
(qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
@@ -516,6 +527,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
REG_READ(ah, AR_DMISC(q)) |
AR_D_MISC_POST_FR_BKOFF_DIS);
}
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
REG_WRITE(ah, AR_DMISC(q),
REG_READ(ah, AR_DMISC(q)) |
@@ -523,6 +538,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
}
switch (qi->tqi_type) {
case ATH9K_TX_QUEUE_BEACON:
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
| AR_Q_MISC_FSP_DBA_GATED
| AR_Q_MISC_BEACON_USE
@@ -533,6 +550,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
| AR_D_MISC_BEACON_USE
| AR_D_MISC_POST_FR_BKOFF_DIS);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
/* cwmin and cwmax should be 0 for beacon queue */
if (AR_SREV_9300_20_OR_LATER(ah)) {
REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
@@ -541,6 +562,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
}
break;
case ATH9K_TX_QUEUE_CAB:
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
| AR_Q_MISC_FSP_DBA_GATED
| AR_Q_MISC_CBR_INCR_DIS1
@@ -554,6 +577,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
| (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+
+ REGWRITE_BUFFER_FLUSH(ah);
+ DISABLE_REGWRITE_BUFFER(ah);
+
break;
case ATH9K_TX_QUEUE_PSPOLL:
REG_WRITE(ah, AR_QMISC(q),
--
1.7.0.5
^ permalink raw reply related
* [PATCH 05/10] ath9k_hw: Relocate Opmode initialization
From: Sujith @ 2010-04-16 6:23 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
Programming the opmode in the HW can be done
before the assoc_id and STA_ID registers are
setup. This helps ath9k_htc when multiple register
writes are used.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/hw.c | 8 ++------
1 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index b9921e9..18cbb19 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1239,6 +1239,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_spur_mitigate_freq(ah, chan);
ah->eep_ops->set_board_values(ah, chan);
+ ath9k_hw_set_operating_mode(ah, ah->opmode);
+
REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
| macStaId1
@@ -1246,16 +1248,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
| (ah->config.
ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
| ah->sta_id1_defaults);
- ath9k_hw_set_operating_mode(ah, ah->opmode);
-
ath_hw_setbssidmask(common);
-
REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
-
ath9k_hw_write_associd(ah);
-
REG_WRITE(ah, AR_ISR, ~0);
-
REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
r = ath9k_hw_rf_set_freq(ah, chan);
--
1.7.0.5
^ permalink raw reply related
* [PATCH 04/10] ath9k_hw: Add macros for multiple register writes
From: Sujith @ 2010-04-16 6:23 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/hw.h | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 7ce5420..8158e8e 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -68,6 +68,24 @@
#define REG_READ(_ah, _reg) \
ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
+#define ENABLE_REGWRITE_BUFFER(_ah) \
+ do { \
+ if (AR_SREV_9271(_ah)) \
+ ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \
+ } while (0)
+
+#define DISABLE_REGWRITE_BUFFER(_ah) \
+ do { \
+ if (AR_SREV_9271(_ah)) \
+ ath9k_hw_common(_ah)->ops->disable_write_buffer((_ah)); \
+ } while (0)
+
+#define REGWRITE_BUFFER_FLUSH(_ah) \
+ do { \
+ if (AR_SREV_9271(_ah)) \
+ ath9k_hw_common(_ah)->ops->write_flush((_ah)); \
+ } while (0)
+
#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
#define REG_RMW(_a, _r, _set, _clr) \
--
1.7.0.5
^ permalink raw reply related
* [PATCH 03/10] ath9k_htc: Implement multiple register write support
From: Sujith @ 2010-04-16 6:23 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
This patch adds support for writing multiple registers
in a single USB command.
Specific calls from the HW code that performs multiple
register writes would be modified to make use of this
in subsequent patches.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/htc_drv_init.c | 104 ++++++++++++++++++++++++-
drivers/net/wireless/ath/ath9k/wmi.c | 1 +
drivers/net/wireless/ath/ath9k/wmi.h | 12 +++
3 files changed, 113 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index aed5357..a861896 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -213,7 +213,7 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
ath9k_hw_regulatory(priv->ah));
}
-static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
+static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
@@ -235,7 +235,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
return be32_to_cpu(val);
}
-static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = (struct ath_hw *) hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
@@ -257,9 +257,105 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
}
}
+static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
+{
+ 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_write_mutex);
+
+ /* Store the register/value */
+ priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
+ cpu_to_be32(reg_offset);
+ priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
+ cpu_to_be32(val);
+
+ priv->wmi->multi_write_idx++;
+
+ /* If the buffer is full, send it out. */
+ if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
+ r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+ (u8 *) &priv->wmi->multi_write,
+ sizeof(struct register_write) * priv->wmi->multi_write_idx,
+ (u8 *) &rsp_status, sizeof(rsp_status),
+ 100);
+ if (unlikely(r)) {
+ ath_print(common, ATH_DBG_WMI,
+ "REGISTER WRITE FAILED, multi len: %d\n",
+ priv->wmi->multi_write_idx);
+ }
+ priv->wmi->multi_write_idx = 0;
+ }
+
+ mutex_unlock(&priv->wmi->multi_write_mutex);
+}
+
+static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
+{
+ 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 (atomic_read(&priv->wmi->mwrite_cnt))
+ ath9k_regwrite_buffer(hw_priv, val, reg_offset);
+ else
+ ath9k_regwrite_single(hw_priv, val, reg_offset);
+}
+
+static void ath9k_enable_regwrite_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;
+
+ atomic_inc(&priv->wmi->mwrite_cnt);
+}
+
+static void ath9k_disable_regwrite_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;
+
+ atomic_dec(&priv->wmi->mwrite_cnt);
+}
+
+static void ath9k_regwrite_flush(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;
+ u32 rsp_status;
+ int r;
+
+ mutex_lock(&priv->wmi->multi_write_mutex);
+
+ if (priv->wmi->multi_write_idx) {
+ r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+ (u8 *) &priv->wmi->multi_write,
+ sizeof(struct register_write) * priv->wmi->multi_write_idx,
+ (u8 *) &rsp_status, sizeof(rsp_status),
+ 100);
+ if (unlikely(r)) {
+ ath_print(common, ATH_DBG_WMI,
+ "REGISTER WRITE FAILED, multi len: %d\n",
+ priv->wmi->multi_write_idx);
+ }
+ priv->wmi->multi_write_idx = 0;
+ }
+
+ mutex_unlock(&priv->wmi->multi_write_mutex);
+}
+
static const struct ath_ops ath9k_common_ops = {
- .read = ath9k_ioread32,
- .write = ath9k_iowrite32,
+ .read = ath9k_regread,
+ .write = ath9k_regwrite,
+ .enable_write_buffer = ath9k_enable_regwrite_buffer,
+ .disable_write_buffer = ath9k_disable_regwrite_buffer,
+ .write_flush = ath9k_regwrite_flush,
};
static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index f2ff18c..355e0db 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -101,6 +101,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
wmi->drv_priv = priv;
wmi->stopped = false;
mutex_init(&wmi->op_mutex);
+ mutex_init(&wmi->multi_write_mutex);
init_completion(&wmi->cmd_wait);
return wmi;
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 39ef926..fd8c9c5 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -84,6 +84,13 @@ enum wmi_event_id {
WMI_TXRATE_EVENTID,
};
+#define MAX_CMD_NUMBER 62
+
+struct register_write {
+ u32 reg;
+ u32 val;
+};
+
struct wmi {
struct ath9k_htc_priv *drv_priv;
struct htc_target *htc;
@@ -97,6 +104,11 @@ struct wmi {
struct sk_buff *wmi_skb;
spinlock_t wmi_lock;
+
+ atomic_t mwrite_cnt;
+ struct register_write multi_write[MAX_CMD_NUMBER];
+ u32 multi_write_idx;
+ struct mutex multi_write_mutex;
};
struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
--
1.7.0.5
^ permalink raw reply related
* [PATCH 02/10] ath: Add buffered register write operations
From: Sujith @ 2010-04-16 6:23 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
This is required to implement delayed/buffered
register writes in ath9k_htc.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath.h | 14 +++++++++++++-
1 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 1fbf6b1..d32f282 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -71,9 +71,21 @@ struct ath_regulatory {
struct reg_dmn_pair_mapping *regpair;
};
+/**
+ * struct ath_ops - Register read/write operations
+ *
+ * @read: Register read
+ * @write: Register write
+ * @enable_write_buffer: Enable multiple register writes
+ * @disable_write_buffer: Disable multiple register writes
+ * @write_flush: Flush buffered register writes
+ */
struct ath_ops {
unsigned int (*read)(void *, u32 reg_offset);
- void (*write)(void *, u32 val, u32 reg_offset);
+ void (*write)(void *, u32 val, u32 reg_offset);
+ void (*enable_write_buffer)(void *);
+ void (*disable_write_buffer)(void *);
+ void (*write_flush) (void *);
};
struct ath_common;
--
1.7.0.5
^ permalink raw reply related
* [PATCH 01/10] ath9k_htc: Cleanup beacon configuration
From: Sujith @ 2010-04-16 6:23 UTC (permalink / raw)
To: linville; +Cc: linux-wireless
This patch cleans up beacon configuration,
removing a redundant interface type check
and updating beacon interval in the correct place.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 23 +++++++++--------------
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +-
2 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 5e21f4d..d104028 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -244,25 +244,20 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
{
struct ath_common *common = ath9k_hw_common(priv->ah);
- enum nl80211_iftype iftype;
struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
- if (vif) {
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
- iftype = vif->type;
- cur_conf->beacon_interval = bss_conf->beacon_int;
- cur_conf->dtim_period = bss_conf->dtim_period;
- cur_conf->listen_interval = 1;
- cur_conf->dtim_count = 1;
- cur_conf->bmiss_timeout =
- ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
- } else
- iftype = priv->ah->opmode;
-
+ cur_conf->beacon_interval = bss_conf->beacon_int;
if (cur_conf->beacon_interval == 0)
cur_conf->beacon_interval = 100;
- switch (iftype) {
+ cur_conf->dtim_period = bss_conf->dtim_period;
+ cur_conf->listen_interval = 1;
+ cur_conf->dtim_count = 1;
+ cur_conf->bmiss_timeout =
+ ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
+
+ switch (vif->type) {
case NL80211_IFTYPE_STATION:
ath9k_htc_beacon_config_sta(priv, cur_conf);
break;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index eb7722b..08a4a58 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1687,7 +1687,7 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
spin_unlock_bh(&priv->beacon_lock);
priv->op_flags |= OP_FULL_RESET;
if (priv->op_flags & OP_ASSOCIATED)
- ath9k_htc_beacon_config(priv, NULL);
+ ath9k_htc_beacon_config(priv, priv->vif);
ath_start_ani(priv);
mutex_unlock(&priv->mutex);
ath9k_htc_ps_restore(priv);
--
1.7.0.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox