mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-27 17:15:00 +02:00
ath9k: add fixes for AP side powersave frame buffering
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@25426 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
88bf917365
commit
22ecf6d623
37
package/mac80211/patches/530-mac80211_drv_tim_override.patch
Normal file
37
package/mac80211/patches/530-mac80211_drv_tim_override.patch
Normal file
@ -0,0 +1,37 @@
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2198,6 +2198,20 @@ static inline int ieee80211_sta_ps_trans
|
||||
#define IEEE80211_TX_STATUS_HEADROOM 13
|
||||
|
||||
/**
|
||||
+ * ieee80211_sta_set_tim - set the TIM bit for a sleeping station
|
||||
+ *
|
||||
+ * If a driver buffers frames for a powersave station instead of passing
|
||||
+ * them back to mac80211 for retransmission, the station needs to be told
|
||||
+ * to wake up using the TIM bitmap in the beacon.
|
||||
+ *
|
||||
+ * This function sets the station's TIM bit - it will be cleared automatically
|
||||
+ * either when the station wakes up (and mac80211 has flushed out its
|
||||
+ * buffered frames), or if all remaining buffered frames in mac80211 have
|
||||
+ * timed out.
|
||||
+ */
|
||||
+void ieee80211_sta_set_tim(struct ieee80211_sta *sta);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_tx_status - transmit status callback
|
||||
*
|
||||
* Call this function for all transmitted frames after they have been
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -991,3 +991,11 @@ void ieee80211_sta_block_awake(struct ie
|
||||
ieee80211_queue_work(hw, &sta->drv_unblock_wk);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_block_awake);
|
||||
+
|
||||
+void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
|
||||
+{
|
||||
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
+
|
||||
+ sta_info_set_tim_bit(sta);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_sta_set_tim);
|
307
package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch
Normal file
307
package/mac80211/patches/531-ath9k_fix_ap_ps_buffering.patch
Normal file
@ -0,0 +1,307 @@
|
||||
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||
@@ -205,6 +205,7 @@ struct ath_atx_ac {
|
||||
int sched;
|
||||
struct list_head list;
|
||||
struct list_head tid_q;
|
||||
+ bool clear_ps_filter;
|
||||
};
|
||||
|
||||
struct ath_frame_info {
|
||||
@@ -262,6 +263,8 @@ struct ath_node {
|
||||
struct ath_atx_ac ac[WME_NUM_AC];
|
||||
u16 maxampdu;
|
||||
u8 mpdudensity;
|
||||
+
|
||||
+ bool sleeping;
|
||||
};
|
||||
|
||||
#define AGGR_CLEANUP BIT(1)
|
||||
@@ -343,6 +346,9 @@ int ath_tx_aggr_start(struct ath_softc *
|
||||
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
|
||||
|
||||
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
|
||||
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
|
||||
+
|
||||
/********/
|
||||
/* VIFs */
|
||||
/********/
|
||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||
@@ -1791,6 +1791,27 @@ static int ath9k_sta_remove(struct ieee8
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_vif *vif,
|
||||
+ enum sta_notify_cmd cmd,
|
||||
+ struct ieee80211_sta *sta)
|
||||
+{
|
||||
+ struct ath_softc *sc = hw->priv;
|
||||
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case STA_NOTIFY_SLEEP:
|
||||
+ an->sleeping = true;
|
||||
+ if (ath_tx_aggr_sleep(sc, an))
|
||||
+ ieee80211_sta_set_tim(sta);
|
||||
+ break;
|
||||
+ case STA_NOTIFY_AWAKE:
|
||||
+ an->sleeping = false;
|
||||
+ ath_tx_aggr_wakeup(sc, an);
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params)
|
||||
{
|
||||
@@ -2130,6 +2151,7 @@ struct ieee80211_ops ath9k_ops = {
|
||||
.configure_filter = ath9k_configure_filter,
|
||||
.sta_add = ath9k_sta_add,
|
||||
.sta_remove = ath9k_sta_remove,
|
||||
+ .sta_notify = ath9k_sta_notify,
|
||||
.conf_tx = ath9k_conf_tx,
|
||||
.bss_info_changed = ath9k_bss_info_changed,
|
||||
.set_key = ath9k_set_key,
|
||||
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||
@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct
|
||||
struct ath_frame_info *fi;
|
||||
int nframes;
|
||||
u8 tidno;
|
||||
+ bool clear_filter;
|
||||
|
||||
skb = bf->bf_mpdu;
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
@@ -442,7 +443,11 @@ static void ath_tx_complete_aggr(struct
|
||||
acked_cnt++;
|
||||
} else {
|
||||
if (!(tid->state & AGGR_CLEANUP) && retry) {
|
||||
- if (fi->retries < ATH_MAX_SW_RETRIES) {
|
||||
+ if (ts->ts_status & ATH9K_TXERR_FILT) {
|
||||
+ if (!an->sleeping)
|
||||
+ clear_filter = true;
|
||||
+ txpending = 1;
|
||||
+ } else if (fi->retries < ATH_MAX_SW_RETRIES) {
|
||||
ath_tx_set_retry(sc, txq, bf->bf_mpdu);
|
||||
txpending = 1;
|
||||
} else {
|
||||
@@ -496,6 +501,7 @@ static void ath_tx_complete_aggr(struct
|
||||
!txfail, sendbar);
|
||||
} else {
|
||||
/* retry the un-acked ones */
|
||||
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
|
||||
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
|
||||
if (bf->bf_next == NULL && bf_last->bf_stale) {
|
||||
struct ath_buf *tbf;
|
||||
@@ -547,6 +553,8 @@ static void ath_tx_complete_aggr(struct
|
||||
/* prepend un-acked frames to the beginning of the pending frame queue */
|
||||
if (!list_empty(&bf_pending)) {
|
||||
spin_lock_bh(&txq->axq_lock);
|
||||
+ if (clear_filter)
|
||||
+ tid->ac->clear_ps_filter = true;
|
||||
list_splice(&bf_pending, &tid->buf_q);
|
||||
ath_tx_queue_tid(txq, tid);
|
||||
spin_unlock_bh(&txq->axq_lock);
|
||||
@@ -816,6 +824,11 @@ static void ath_tx_sched_aggr(struct ath
|
||||
bf = list_first_entry(&bf_q, struct ath_buf, list);
|
||||
bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
|
||||
|
||||
+ if (tid->ac->clear_ps_filter) {
|
||||
+ tid->ac->clear_ps_filter = false;
|
||||
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
|
||||
+ }
|
||||
+
|
||||
/* if only one frame, send as non-aggregate */
|
||||
if (bf == bf->bf_lastbf) {
|
||||
fi = get_frame_info(bf->bf_mpdu);
|
||||
@@ -896,6 +909,67 @@ void ath_tx_aggr_stop(struct ath_softc *
|
||||
ath_tx_flush_tid(sc, txtid);
|
||||
}
|
||||
|
||||
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
|
||||
+{
|
||||
+ struct ath_atx_tid *tid;
|
||||
+ struct ath_atx_ac *ac;
|
||||
+ struct ath_txq *txq;
|
||||
+ bool buffered = false;
|
||||
+ int tidno;
|
||||
+
|
||||
+ for (tidno = 0, tid = &an->tid[tidno];
|
||||
+ tidno < WME_NUM_TID; tidno++, tid++) {
|
||||
+
|
||||
+ if (!tid->sched)
|
||||
+ continue;
|
||||
+
|
||||
+ ac = tid->ac;
|
||||
+ txq = ac->txq;
|
||||
+
|
||||
+ spin_lock_bh(&txq->axq_lock);
|
||||
+
|
||||
+ if (!list_empty(&tid->buf_q))
|
||||
+ buffered = true;
|
||||
+
|
||||
+ tid->sched = false;
|
||||
+ list_del(&tid->list);
|
||||
+
|
||||
+ if (ac->sched) {
|
||||
+ ac->sched = false;
|
||||
+ list_del(&ac->list);
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_bh(&txq->axq_lock);
|
||||
+ }
|
||||
+
|
||||
+ return buffered;
|
||||
+}
|
||||
+
|
||||
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
|
||||
+{
|
||||
+ struct ath_atx_tid *tid;
|
||||
+ struct ath_atx_ac *ac;
|
||||
+ struct ath_txq *txq;
|
||||
+ int tidno;
|
||||
+
|
||||
+ for (tidno = 0, tid = &an->tid[tidno];
|
||||
+ tidno < WME_NUM_TID; tidno++, tid++) {
|
||||
+
|
||||
+ ac = tid->ac;
|
||||
+ txq = ac->txq;
|
||||
+
|
||||
+ spin_lock_bh(&txq->axq_lock);
|
||||
+ ac->clear_ps_filter = true;
|
||||
+
|
||||
+ if (!list_empty(&tid->buf_q) && !tid->paused) {
|
||||
+ ath_tx_queue_tid(txq, tid);
|
||||
+ ath_txq_schedule(sc, txq);
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_bh(&txq->axq_lock);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
||||
{
|
||||
struct ath_atx_tid *txtid;
|
||||
@@ -1492,7 +1566,6 @@ static int setup_tx_flags(struct sk_buff
|
||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||
int flags = 0;
|
||||
|
||||
- flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
|
||||
flags |= ATH9K_TXDESC_INTREQ;
|
||||
|
||||
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
@@ -1755,6 +1828,9 @@ static void ath_tx_start_dma(struct ath_
|
||||
if (txctl->paprd)
|
||||
bf->bf_state.bfs_paprd_timestamp = jiffies;
|
||||
|
||||
+ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
|
||||
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
|
||||
+
|
||||
ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
|
||||
}
|
||||
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
|
||||
@@ -128,6 +128,11 @@ static inline void ath9k_hw_set11n_virtu
|
||||
ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
|
||||
}
|
||||
|
||||
+static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
|
||||
+{
|
||||
+ ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
|
||||
+}
|
||||
+
|
||||
/* Private hardware call ops */
|
||||
|
||||
/* PHY ops */
|
||||
--- a/drivers/net/wireless/ath/ath9k/hw.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/hw.h
|
||||
@@ -642,6 +642,7 @@ struct ath_hw_ops {
|
||||
u32 burstDuration);
|
||||
void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
|
||||
u32 vmf);
|
||||
+ void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
|
||||
};
|
||||
|
||||
struct ath_nf_limits {
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
|
||||
@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(stru
|
||||
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
|
||||
| SM(txPower, AR_XmitPower)
|
||||
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
|
||||
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
|
||||
| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
|
||||
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
|
||||
|
||||
@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(stru
|
||||
}
|
||||
}
|
||||
|
||||
+static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
|
||||
+{
|
||||
+ struct ar5416_desc *ads = AR5416DESC(ds);
|
||||
+
|
||||
+ if (val)
|
||||
+ ads->ds_ctl0 |= AR_ClrDestMask;
|
||||
+ else
|
||||
+ ads->ds_ctl0 &= ~AR_ClrDestMask;
|
||||
+}
|
||||
+
|
||||
static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
|
||||
void *lastds,
|
||||
u32 durUpdateEn, u32 rtsctsRate,
|
||||
@@ -460,4 +469,5 @@ void ar9002_hw_attach_mac_ops(struct ath
|
||||
ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
|
||||
ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
|
||||
ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag;
|
||||
+ ops->set_clrdmask = ar9002_hw_set_clrdmask;
|
||||
}
|
||||
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
|
||||
@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(stru
|
||||
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
|
||||
| SM(txpower, AR_XmitPower)
|
||||
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
|
||||
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
|
||||
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
|
||||
| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
|
||||
|
||||
@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(stru
|
||||
ads->ctl22 = 0;
|
||||
}
|
||||
|
||||
+static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
|
||||
+{
|
||||
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
|
||||
+
|
||||
+ if (val)
|
||||
+ ads->ctl11 |= AR_ClrDestMask;
|
||||
+ else
|
||||
+ ads->ctl11 &= ~AR_ClrDestMask;
|
||||
+}
|
||||
+
|
||||
static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
|
||||
void *lastds,
|
||||
u32 durUpdateEn, u32 rtsctsRate,
|
||||
@@ -522,6 +531,7 @@ void ar9003_hw_attach_mac_ops(struct ath
|
||||
ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
|
||||
ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
|
||||
ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag;
|
||||
+ ops->set_clrdmask = ar9003_hw_set_clrdmask;
|
||||
}
|
||||
|
||||
void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
|
||||
--- a/drivers/net/wireless/ath/ath9k/mac.h
|
||||
+++ b/drivers/net/wireless/ath/ath9k/mac.h
|
||||
@@ -239,7 +239,6 @@ struct ath_desc {
|
||||
void *ds_vdata;
|
||||
} __packed __aligned(4);
|
||||
|
||||
-#define ATH9K_TXDESC_CLRDMASK 0x0001
|
||||
#define ATH9K_TXDESC_NOACK 0x0002
|
||||
#define ATH9K_TXDESC_RTSENA 0x0004
|
||||
#define ATH9K_TXDESC_CTSENA 0x0008
|
Loading…
Reference in New Issue
Block a user