aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2009-11-24 02:53:25 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-28 15:04:49 -0500
commite7824a50662f7f79b1a739f705b4d906c31cf221 (patch)
tree20f92622698f9f07524db55691e0322b298031db
parent6b65b6ad016f048547127946d1afe4ba41c74296 (diff)
ath9k: fix processing of TX PS null data frames
When mac80211 was telling us to go into Powersave we listened and immediately turned RX off. This meant hardware would not see the ACKs from the AP we're associated with and hardware we'd end up retransmiting the null data frame in a loop helplessly. Fix this by keeping track of the transmitted nullfunc frames and only when we are sure the AP has sent back an ACK do we go ahead and shut RX off. Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com> Signed-off-by: Vivek Natarajan <Vivek.Natarajan@atheros.com> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h15
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c21
7 files changed, 69 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 9ff53c9c4119..3eb9677b2dfe 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -420,6 +420,8 @@ struct ath_led {
420#define SC_OP_WAIT_FOR_TX_ACK BIT(18) 420#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
421#define SC_OP_BEACON_SYNC BIT(19) 421#define SC_OP_BEACON_SYNC BIT(19)
422#define SC_OP_BT_PRIORITY_DETECTED BIT(21) 422#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
423#define SC_OP_NULLFUNC_COMPLETED BIT(22)
424#define SC_OP_PS_ENABLED BIT(23)
423 425
424struct ath_wiphy; 426struct ath_wiphy;
425struct ath_rate_table; 427struct ath_rate_table;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index 4e1176029356..b230bb15279e 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -78,6 +78,7 @@ struct ath_buf {
78 dma_addr_t bf_daddr; /* physical addr of desc */ 78 dma_addr_t bf_daddr; /* physical addr of desc */
79 dma_addr_t bf_buf_addr; /* physical addr of data buffer */ 79 dma_addr_t bf_buf_addr; /* physical addr of data buffer */
80 bool bf_stale; 80 bool bf_stale;
81 bool bf_isnullfunc;
81 u16 bf_flags; 82 u16 bf_flags;
82 struct ath_buf_state bf_state; 83 struct ath_buf_state bf_state;
83 dma_addr_t bf_dmacontext; 84 dma_addr_t bf_dmacontext;
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 46466ffebcb0..09ed441eb6ba 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -231,6 +231,8 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
231 ds->ds_txstat.ts_status = 0; 231 ds->ds_txstat.ts_status = 0;
232 ds->ds_txstat.ts_flags = 0; 232 ds->ds_txstat.ts_flags = 0;
233 233
234 if (ads->ds_txstatus1 & AR_FrmXmitOK)
235 ds->ds_txstat.ts_status |= ATH9K_TX_ACKED;
234 if (ads->ds_txstatus1 & AR_ExcessiveRetries) 236 if (ads->ds_txstatus1 & AR_ExcessiveRetries)
235 ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; 237 ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
236 if (ads->ds_txstatus1 & AR_Filtered) 238 if (ads->ds_txstatus1 & AR_Filtered)
@@ -926,6 +928,13 @@ void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
926} 928}
927EXPORT_SYMBOL(ath9k_hw_setuprxdesc); 929EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
928 930
931/*
932 * This can stop or re-enables RX.
933 *
934 * If bool is set this will kill any frame which is currently being
935 * transferred between the MAC and baseband and also prevent any new
936 * frames from getting started.
937 */
929bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) 938bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
930{ 939{
931 u32 reg; 940 u32 reg;
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 29dfe14751a7..6cc04951a051 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -76,6 +76,7 @@
76#define ATH9K_TXERR_FIFO 0x04 76#define ATH9K_TXERR_FIFO 0x04
77#define ATH9K_TXERR_XTXOP 0x08 77#define ATH9K_TXERR_XTXOP 0x08
78#define ATH9K_TXERR_TIMER_EXPIRED 0x10 78#define ATH9K_TXERR_TIMER_EXPIRED 0x10
79#define ATH9K_TX_ACKED 0x20
79 80
80#define ATH9K_TX_BA 0x01 81#define ATH9K_TX_BA 0x01
81#define ATH9K_TX_PWRMGMT 0x02 82#define ATH9K_TX_PWRMGMT 0x02
@@ -380,6 +381,11 @@ struct ar5416_desc {
380#define AR_TxBaStatus 0x40000000 381#define AR_TxBaStatus 0x40000000
381#define AR_TxStatusRsvd01 0x80000000 382#define AR_TxStatusRsvd01 0x80000000
382 383
384/*
385 * AR_FrmXmitOK - Frame transmission success flag. If set, the frame was
386 * transmitted successfully. If clear, no ACK or BA was received to indicate
387 * successful transmission when we were expecting an ACK or BA.
388 */
383#define AR_FrmXmitOK 0x00000001 389#define AR_FrmXmitOK 0x00000001
384#define AR_ExcessiveRetries 0x00000002 390#define AR_ExcessiveRetries 0x00000002
385#define AR_FIFOUnderrun 0x00000004 391#define AR_FIFOUnderrun 0x00000004
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index bd1e2de3a1f9..55c669648bd6 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2701,8 +2701,15 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
2701 } 2701 }
2702 } 2702 }
2703 2703
2704 /*
2705 * We just prepare to enable PS. We have to wait until our AP has
2706 * ACK'd our null data frame to disable RX otherwise we'll ignore
2707 * those ACKs and end up retransmitting the same null data frames.
2708 * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
2709 */
2704 if (changed & IEEE80211_CONF_CHANGE_PS) { 2710 if (changed & IEEE80211_CONF_CHANGE_PS) {
2705 if (conf->flags & IEEE80211_CONF_PS) { 2711 if (conf->flags & IEEE80211_CONF_PS) {
2712 sc->sc_flags |= SC_OP_PS_ENABLED;
2706 if (!(ah->caps.hw_caps & 2713 if (!(ah->caps.hw_caps &
2707 ATH9K_HW_CAP_AUTOSLEEP)) { 2714 ATH9K_HW_CAP_AUTOSLEEP)) {
2708 if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { 2715 if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
@@ -2710,11 +2717,20 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
2710 ath9k_hw_set_interrupts(sc->sc_ah, 2717 ath9k_hw_set_interrupts(sc->sc_ah,
2711 sc->imask); 2718 sc->imask);
2712 } 2719 }
2713 ath9k_hw_setrxabort(sc->sc_ah, 1);
2714 } 2720 }
2715 sc->ps_enabled = true; 2721 /*
2722 * At this point we know hardware has received an ACK
2723 * of a previously sent null data frame.
2724 */
2725 if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) {
2726 sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
2727 sc->ps_enabled = true;
2728 ath9k_hw_setrxabort(sc->sc_ah, 1);
2729 }
2716 } else { 2730 } else {
2717 sc->ps_enabled = false; 2731 sc->ps_enabled = false;
2732 sc->sc_flags &= ~(SC_OP_PS_ENABLED |
2733 SC_OP_NULLFUNC_COMPLETED);
2718 ath9k_setpower(sc, ATH9K_PM_AWAKE); 2734 ath9k_setpower(sc, ATH9K_PM_AWAKE);
2719 if (!(ah->caps.hw_caps & 2735 if (!(ah->caps.hw_caps &
2720 ATH9K_HW_CAP_AUTOSLEEP)) { 2736 ATH9K_HW_CAP_AUTOSLEEP)) {
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 49ec25f020f0..8e653fb937a1 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -1332,13 +1332,22 @@ enum {
1332#define AR_MCAST_FIL0 0x8040 1332#define AR_MCAST_FIL0 0x8040
1333#define AR_MCAST_FIL1 0x8044 1333#define AR_MCAST_FIL1 0x8044
1334 1334
1335/*
1336 * AR_DIAG_SW - Register which can be used for diagnostics and testing purposes.
1337 *
1338 * The force RX abort (AR_DIAG_RX_ABORT, bit 25) can be used in conjunction with
1339 * RX block (AR_DIAG_RX_DIS, bit 5) to help fast channel change to shut down
1340 * receive. The force RX abort bit will kill any frame which is currently being
1341 * transferred between the MAC and baseband. The RX block bit (AR_DIAG_RX_DIS)
1342 * will prevent any new frames from getting started.
1343 */
1335#define AR_DIAG_SW 0x8048 1344#define AR_DIAG_SW 0x8048
1336#define AR_DIAG_CACHE_ACK 0x00000001 1345#define AR_DIAG_CACHE_ACK 0x00000001
1337#define AR_DIAG_ACK_DIS 0x00000002 1346#define AR_DIAG_ACK_DIS 0x00000002
1338#define AR_DIAG_CTS_DIS 0x00000004 1347#define AR_DIAG_CTS_DIS 0x00000004
1339#define AR_DIAG_ENCRYPT_DIS 0x00000008 1348#define AR_DIAG_ENCRYPT_DIS 0x00000008
1340#define AR_DIAG_DECRYPT_DIS 0x00000010 1349#define AR_DIAG_DECRYPT_DIS 0x00000010
1341#define AR_DIAG_RX_DIS 0x00000020 1350#define AR_DIAG_RX_DIS 0x00000020 /* RX block */
1342#define AR_DIAG_LOOP_BACK 0x00000040 1351#define AR_DIAG_LOOP_BACK 0x00000040
1343#define AR_DIAG_CORR_FCS 0x00000080 1352#define AR_DIAG_CORR_FCS 0x00000080
1344#define AR_DIAG_CHAN_INFO 0x00000100 1353#define AR_DIAG_CHAN_INFO 0x00000100
@@ -1347,12 +1356,12 @@ enum {
1347#define AR_DIAG_FRAME_NV0 0x00020000 1356#define AR_DIAG_FRAME_NV0 0x00020000
1348#define AR_DIAG_OBS_PT_SEL1 0x000C0000 1357#define AR_DIAG_OBS_PT_SEL1 0x000C0000
1349#define AR_DIAG_OBS_PT_SEL1_S 18 1358#define AR_DIAG_OBS_PT_SEL1_S 18
1350#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 1359#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */
1351#define AR_DIAG_IGNORE_VIRT_CS 0x00200000 1360#define AR_DIAG_IGNORE_VIRT_CS 0x00200000
1352#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000 1361#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000
1353#define AR_DIAG_EIFS_CTRL_ENA 0x00800000 1362#define AR_DIAG_EIFS_CTRL_ENA 0x00800000
1354#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000 1363#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000
1355#define AR_DIAG_RX_ABORT 0x02000000 1364#define AR_DIAG_RX_ABORT 0x02000000 /* Force RX abort */
1356#define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000 1365#define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000
1357#define AR_DIAG_OBS_PT_SEL2 0x08000000 1366#define AR_DIAG_OBS_PT_SEL2 0x08000000
1358#define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000 1367#define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 2bb8c91bf4f9..6f91a8ae616f 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1644,6 +1644,14 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
1644 } 1644 }
1645 1645
1646 bf->bf_buf_addr = bf->bf_dmacontext; 1646 bf->bf_buf_addr = bf->bf_dmacontext;
1647
1648 /* tag if this is a nullfunc frame to enable PS when AP acks it */
1649 if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
1650 bf->bf_isnullfunc = true;
1651 sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
1652 } else
1653 bf->bf_isnullfunc = false;
1654
1647 return 0; 1655 return 0;
1648} 1656}
1649 1657
@@ -2039,6 +2047,19 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
2039 } 2047 }
2040 2048
2041 /* 2049 /*
2050 * We now know the nullfunc frame has been ACKed so we
2051 * can disable RX.
2052 */
2053 if (bf->bf_isnullfunc &&
2054 (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
2055 if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
2056 sc->ps_enabled = true;
2057 ath9k_hw_setrxabort(sc->sc_ah, 1);
2058 } else
2059 sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
2060 }
2061
2062 /*
2042 * Remove ath_buf's of the same transmit unit from txq, 2063 * Remove ath_buf's of the same transmit unit from txq,
2043 * however leave the last descriptor back as the holding 2064 * however leave the last descriptor back as the holding
2044 * descriptor for hw. 2065 * descriptor for hw.