aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-09-29 10:04:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-30 15:57:10 -0400
commit042ec4533720122e6cb93dd9f3b6a75fe2fcff16 (patch)
treeed8fad40c171ab54155ce316496f68d79b438b01
parent941c93cd039852b7ab02c74f4698c99d82bd6cfe (diff)
mac80211: let drivers inform it about per TID buffered frames
For uAPSD implementation, it is necessary to know on which ACs frames are buffered. mac80211 obviously knows about the frames it has buffered itself, but with aggregation many drivers buffer frames. Thus, mac80211 needs to be informed about this. For now, since we don't have APSD in any form, this will unconditionally set the TIM bit for the station but later with uAPSD only some ACs might cause the TIM bit to be set. ath9k is the only driver using this API and I only modify it in the most basic way, it won't be able to implement uAPSD with this yet. But it can't do that anyway since there's no way to selectively release frames to the peer yet. Since drivers will buffer frames per TID, let them inform mac80211 on a per TID basis, mac80211 will then sort out the AC mapping itself. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c14
-rw-r--r--include/net/mac80211.h34
-rw-r--r--net/mac80211/sta_info.c8
5 files changed, 42 insertions, 20 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 94d887b65e69..1e8614783181 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -340,7 +340,8 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
340void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); 340void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
341 341
342void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); 342void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
343bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); 343void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
344 struct ath_node *an);
344 345
345/********/ 346/********/
346/* VIFs */ 347/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index edaa7843bf4c..0ebf7321df12 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1833,8 +1833,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
1833 switch (cmd) { 1833 switch (cmd) {
1834 case STA_NOTIFY_SLEEP: 1834 case STA_NOTIFY_SLEEP:
1835 an->sleeping = true; 1835 an->sleeping = true;
1836 if (ath_tx_aggr_sleep(sc, an)) 1836 ath_tx_aggr_sleep(sta, sc, an);
1837 ieee80211_sta_set_tim(sta);
1838 break; 1837 break;
1839 case STA_NOTIFY_AWAKE: 1838 case STA_NOTIFY_AWAKE:
1840 an->sleeping = false; 1839 an->sleeping = false;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index f5d4764888b9..c2bfc57958d8 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -542,7 +542,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
542 /* prepend un-acked frames to the beginning of the pending frame queue */ 542 /* prepend un-acked frames to the beginning of the pending frame queue */
543 if (!skb_queue_empty(&bf_pending)) { 543 if (!skb_queue_empty(&bf_pending)) {
544 if (an->sleeping) 544 if (an->sleeping)
545 ieee80211_sta_set_tim(sta); 545 ieee80211_sta_set_buffered(sta, tid->tidno, true);
546 546
547 spin_lock_bh(&txq->axq_lock); 547 spin_lock_bh(&txq->axq_lock);
548 if (clear_filter) 548 if (clear_filter)
@@ -1153,12 +1153,13 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
1153 ath_tx_flush_tid(sc, txtid); 1153 ath_tx_flush_tid(sc, txtid);
1154} 1154}
1155 1155
1156bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) 1156void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
1157 struct ath_node *an)
1157{ 1158{
1158 struct ath_atx_tid *tid; 1159 struct ath_atx_tid *tid;
1159 struct ath_atx_ac *ac; 1160 struct ath_atx_ac *ac;
1160 struct ath_txq *txq; 1161 struct ath_txq *txq;
1161 bool buffered = false; 1162 bool buffered;
1162 int tidno; 1163 int tidno;
1163 1164
1164 for (tidno = 0, tid = &an->tid[tidno]; 1165 for (tidno = 0, tid = &an->tid[tidno];
@@ -1172,8 +1173,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
1172 1173
1173 spin_lock_bh(&txq->axq_lock); 1174 spin_lock_bh(&txq->axq_lock);
1174 1175
1175 if (!skb_queue_empty(&tid->buf_q)) 1176 buffered = !skb_queue_empty(&tid->buf_q);
1176 buffered = true;
1177 1177
1178 tid->sched = false; 1178 tid->sched = false;
1179 list_del(&tid->list); 1179 list_del(&tid->list);
@@ -1184,9 +1184,9 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
1184 } 1184 }
1185 1185
1186 spin_unlock_bh(&txq->axq_lock); 1186 spin_unlock_bh(&txq->axq_lock);
1187 }
1188 1187
1189 return buffered; 1188 ieee80211_sta_set_buffered(sta, tidno, buffered);
1189 }
1190} 1190}
1191 1191
1192void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) 1192void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b5f7ada2f87b..e66638e749c6 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2361,17 +2361,35 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
2361#define IEEE80211_TX_STATUS_HEADROOM 13 2361#define IEEE80211_TX_STATUS_HEADROOM 13
2362 2362
2363/** 2363/**
2364 * ieee80211_sta_set_tim - set the TIM bit for a sleeping station 2364 * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
2365 * @sta: &struct ieee80211_sta pointer for the sleeping station 2365 * @sta: &struct ieee80211_sta pointer for the sleeping station
2366 * @tid: the TID that has buffered frames
2367 * @buffered: indicates whether or not frames are buffered for this TID
2366 * 2368 *
2367 * If a driver buffers frames for a powersave station instead of passing 2369 * If a driver buffers frames for a powersave station instead of passing
2368 * them back to mac80211 for retransmission, the station needs to be told 2370 * them back to mac80211 for retransmission, the station may still need
2369 * to wake up using the TIM bitmap in the beacon. 2371 * to be told that there are buffered frames via the TIM bit.
2370 * 2372 *
2371 * This function sets the station's TIM bit - it will be cleared when the 2373 * This function informs mac80211 whether or not there are frames that are
2372 * station wakes up. 2374 * buffered in the driver for a given TID; mac80211 can then use this data
2373 */ 2375 * to set the TIM bit (NOTE: This may call back into the driver's set_tim
2374void ieee80211_sta_set_tim(struct ieee80211_sta *sta); 2376 * call! Beware of the locking!)
2377 *
2378 * If all frames are released to the station (due to PS-poll or uAPSD)
2379 * then the driver needs to inform mac80211 that there no longer are
2380 * frames buffered. However, when the station wakes up mac80211 assumes
2381 * that all buffered frames will be transmitted and clears this data,
2382 * drivers need to make sure they inform mac80211 about all buffered
2383 * frames on the sleep transition (sta_notify() with %STA_NOTIFY_SLEEP).
2384 *
2385 * Note that technically mac80211 only needs to know this per AC, not per
2386 * TID, but since driver buffering will inevitably happen per TID (since
2387 * it is related to aggregation) it is easier to make mac80211 map the
2388 * TID to the AC as required instead of keeping track in all drivers that
2389 * use this API.
2390 */
2391void ieee80211_sta_set_buffered(struct ieee80211_sta *sta,
2392 u8 tid, bool buffered);
2375 2393
2376/** 2394/**
2377 * ieee80211_tx_status - transmit status callback 2395 * ieee80211_tx_status - transmit status callback
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index c52e58c0a979..016742d4c48e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1117,11 +1117,15 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
1117} 1117}
1118EXPORT_SYMBOL(ieee80211_sta_block_awake); 1118EXPORT_SYMBOL(ieee80211_sta_block_awake);
1119 1119
1120void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta) 1120void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
1121 u8 tid, bool buffered)
1121{ 1122{
1122 struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 1123 struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
1123 1124
1125 if (!buffered)
1126 return;
1127
1124 set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF); 1128 set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
1125 sta_info_set_tim_bit(sta); 1129 sta_info_set_tim_bit(sta);
1126} 1130}
1127EXPORT_SYMBOL(ieee80211_sta_set_tim); 1131EXPORT_SYMBOL(ieee80211_sta_set_buffered);