#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
#define SC_OP_BEACON_SYNC BIT(19)
#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
+#define SC_OP_NULLFUNC_COMPLETED BIT(22)
+#define SC_OP_PS_ENABLED BIT(23)
struct ath_wiphy;
struct ath_rate_table;
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer */
bool bf_stale;
+ bool bf_isnullfunc;
u16 bf_flags;
struct ath_buf_state bf_state;
dma_addr_t bf_dmacontext;
ds->ds_txstat.ts_status = 0;
ds->ds_txstat.ts_flags = 0;
+ if (ads->ds_txstatus1 & AR_FrmXmitOK)
+ ds->ds_txstat.ts_status |= ATH9K_TX_ACKED;
if (ads->ds_txstatus1 & AR_ExcessiveRetries)
ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
if (ads->ds_txstatus1 & AR_Filtered)
}
EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
+/*
+ * This can stop or re-enables RX.
+ *
+ * If bool is set this will kill any frame which is currently being
+ * transferred between the MAC and baseband and also prevent any new
+ * frames from getting started.
+ */
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
{
u32 reg;
#define ATH9K_TXERR_FIFO 0x04
#define ATH9K_TXERR_XTXOP 0x08
#define ATH9K_TXERR_TIMER_EXPIRED 0x10
+#define ATH9K_TX_ACKED 0x20
#define ATH9K_TX_BA 0x01
#define ATH9K_TX_PWRMGMT 0x02
#define AR_TxBaStatus 0x40000000
#define AR_TxStatusRsvd01 0x80000000
+/*
+ * AR_FrmXmitOK - Frame transmission success flag. If set, the frame was
+ * transmitted successfully. If clear, no ACK or BA was received to indicate
+ * successful transmission when we were expecting an ACK or BA.
+ */
#define AR_FrmXmitOK 0x00000001
#define AR_ExcessiveRetries 0x00000002
#define AR_FIFOUnderrun 0x00000004
}
}
+ /*
+ * We just prepare to enable PS. We have to wait until our AP has
+ * ACK'd our null data frame to disable RX otherwise we'll ignore
+ * those ACKs and end up retransmitting the same null data frames.
+ * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode.
+ */
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
+ sc->sc_flags |= SC_OP_PS_ENABLED;
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
ath9k_hw_set_interrupts(sc->sc_ah,
sc->imask);
}
- ath9k_hw_setrxabort(sc->sc_ah, 1);
}
- sc->ps_enabled = true;
+ /*
+ * At this point we know hardware has received an ACK
+ * of a previously sent null data frame.
+ */
+ if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) {
+ sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
+ sc->ps_enabled = true;
+ ath9k_hw_setrxabort(sc->sc_ah, 1);
+ }
} else {
sc->ps_enabled = false;
+ sc->sc_flags &= ~(SC_OP_PS_ENABLED |
+ SC_OP_NULLFUNC_COMPLETED);
ath9k_setpower(sc, ATH9K_PM_AWAKE);
if (!(ah->caps.hw_caps &
ATH9K_HW_CAP_AUTOSLEEP)) {
#define AR_MCAST_FIL0 0x8040
#define AR_MCAST_FIL1 0x8044
+/*
+ * AR_DIAG_SW - Register which can be used for diagnostics and testing purposes.
+ *
+ * The force RX abort (AR_DIAG_RX_ABORT, bit 25) can be used in conjunction with
+ * RX block (AR_DIAG_RX_DIS, bit 5) to help fast channel change to shut down
+ * receive. The force RX abort bit will kill any frame which is currently being
+ * transferred between the MAC and baseband. The RX block bit (AR_DIAG_RX_DIS)
+ * will prevent any new frames from getting started.
+ */
#define AR_DIAG_SW 0x8048
#define AR_DIAG_CACHE_ACK 0x00000001
#define AR_DIAG_ACK_DIS 0x00000002
#define AR_DIAG_CTS_DIS 0x00000004
#define AR_DIAG_ENCRYPT_DIS 0x00000008
#define AR_DIAG_DECRYPT_DIS 0x00000010
-#define AR_DIAG_RX_DIS 0x00000020
+#define AR_DIAG_RX_DIS 0x00000020 /* RX block */
#define AR_DIAG_LOOP_BACK 0x00000040
#define AR_DIAG_CORR_FCS 0x00000080
#define AR_DIAG_CHAN_INFO 0x00000100
#define AR_DIAG_FRAME_NV0 0x00020000
#define AR_DIAG_OBS_PT_SEL1 0x000C0000
#define AR_DIAG_OBS_PT_SEL1_S 18
-#define AR_DIAG_FORCE_RX_CLEAR 0x00100000
+#define AR_DIAG_FORCE_RX_CLEAR 0x00100000 /* force rx_clear high */
#define AR_DIAG_IGNORE_VIRT_CS 0x00200000
#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000
#define AR_DIAG_EIFS_CTRL_ENA 0x00800000
#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000
-#define AR_DIAG_RX_ABORT 0x02000000
+#define AR_DIAG_RX_ABORT 0x02000000 /* Force RX abort */
#define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000
#define AR_DIAG_OBS_PT_SEL2 0x08000000
#define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000
}
bf->bf_buf_addr = bf->bf_dmacontext;
+
+ /* tag if this is a nullfunc frame to enable PS when AP acks it */
+ if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
+ bf->bf_isnullfunc = true;
+ sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
+ } else
+ bf->bf_isnullfunc = false;
+
return 0;
}
}
/*
+ * We now know the nullfunc frame has been ACKed so we
+ * can disable RX.
+ */
+ if (bf->bf_isnullfunc &&
+ (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
+ if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
+ sc->ps_enabled = true;
+ ath9k_hw_setrxabort(sc->sc_ah, 1);
+ } else
+ sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
+ }
+
+ /*
* Remove ath_buf's of the same transmit unit from txq,
* however leave the last descriptor back as the holding
* descriptor for hw.