Commit 948d887d authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: split PS buffers into ACs

For uAPSD support we'll need to have per-AC PS
buffers. As this is a major undertaking, split
the buffers before really adding support for
uAPSD. This already makes some reference to the
uapsd_queues variable, but for now that will
never be non-zero.

Since book-keeping is complicated, also change
the logic for keeping a maximum of frames only
and allow 64 frames per AC (up from 128 for a
station).
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 60750397
...@@ -109,6 +109,7 @@ enum ieee80211_ac_numbers { ...@@ -109,6 +109,7 @@ enum ieee80211_ac_numbers {
IEEE80211_AC_BE = 2, IEEE80211_AC_BE = 2,
IEEE80211_AC_BK = 3, IEEE80211_AC_BK = 3,
}; };
#define IEEE80211_NUM_ACS 4
/** /**
* struct ieee80211_tx_queue_params - transmit queue configuration * struct ieee80211_tx_queue_params - transmit queue configuration
......
...@@ -78,8 +78,14 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file, ...@@ -78,8 +78,14 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct sta_info *sta = file->private_data; struct sta_info *sta = file->private_data;
return mac80211_format_buffer(userbuf, count, ppos, "%u\n", char buf[17*IEEE80211_NUM_ACS], *p = buf;
skb_queue_len(&sta->ps_tx_buf)); int ac;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
p += scnprintf(p, sizeof(buf)+buf-p, "AC%d: %d\n", ac,
skb_queue_len(&sta->ps_tx_buf[ac]) +
skb_queue_len(&sta->tx_filtered[ac]));
return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
} }
STA_OPS(num_ps_buf_frames); STA_OPS(num_ps_buf_frames);
......
This diff is collapsed.
...@@ -43,8 +43,6 @@ ...@@ -43,8 +43,6 @@
* be in the queues * be in the queues
* @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping
* station in power-save mode, reply when the driver unblocks. * station in power-save mode, reply when the driver unblocks.
* @WLAN_STA_PS_DRIVER_BUF: Station has frames pending in driver internal
* buffers. Automatically cleared on station wake-up.
* @WLAN_STA_TDLS_PEER: Station is a TDLS peer. * @WLAN_STA_TDLS_PEER: Station is a TDLS peer.
* @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct * @WLAN_STA_TDLS_PEER_AUTH: This TDLS peer is authorized to send direct
* packets. This means the link is enabled. * packets. This means the link is enabled.
...@@ -63,7 +61,6 @@ enum ieee80211_sta_info_flags { ...@@ -63,7 +61,6 @@ enum ieee80211_sta_info_flags {
WLAN_STA_BLOCK_BA = 1<<11, WLAN_STA_BLOCK_BA = 1<<11,
WLAN_STA_PS_DRIVER = 1<<12, WLAN_STA_PS_DRIVER = 1<<12,
WLAN_STA_PSPOLL = 1<<13, WLAN_STA_PSPOLL = 1<<13,
WLAN_STA_PS_DRIVER_BUF = 1<<14,
WLAN_STA_TDLS_PEER = 1<<15, WLAN_STA_TDLS_PEER = 1<<15,
WLAN_STA_TDLS_PEER_AUTH = 1<<16, WLAN_STA_TDLS_PEER_AUTH = 1<<16,
}; };
...@@ -212,11 +209,13 @@ struct sta_ampdu_mlme { ...@@ -212,11 +209,13 @@ struct sta_ampdu_mlme {
* @drv_unblock_wk: used for driver PS unblocking * @drv_unblock_wk: used for driver PS unblocking
* @listen_interval: listen interval of this station, when we're acting as AP * @listen_interval: listen interval of this station, when we're acting as AP
* @flags: STA flags, see &enum ieee80211_sta_info_flags * @flags: STA flags, see &enum ieee80211_sta_info_flags
* @ps_tx_buf: buffer of frames to transmit to this station * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
* when it leaves power saving state * when it leaves power saving state or polls
* @tx_filtered: buffer of frames we already tried to transmit * @tx_filtered: buffers (per AC) of frames we already tried to
* but were filtered by hardware due to STA having entered * transmit but were filtered by hardware due to STA having
* power saving state * entered power saving state, these are also delivered to
* the station when it leaves powersave or polls for frames
* @driver_buffered_tids: bitmap of TIDs the driver has data buffered on
* @rx_packets: Number of MSDUs received from this STA * @rx_packets: Number of MSDUs received from this STA
* @rx_bytes: Number of bytes received from this STA * @rx_bytes: Number of bytes received from this STA
* @wep_weak_iv_count: number of weak WEP IVs received from this station * @wep_weak_iv_count: number of weak WEP IVs received from this station
...@@ -286,8 +285,9 @@ struct sta_info { ...@@ -286,8 +285,9 @@ struct sta_info {
* STA powersave frame queues, no more than the internal * STA powersave frame queues, no more than the internal
* locking required. * locking required.
*/ */
struct sk_buff_head ps_tx_buf; struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
struct sk_buff_head tx_filtered; struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
unsigned long driver_buffered_tids;
/* Updated from RX path only, no locking requirements */ /* Updated from RX path only, no locking requirements */
unsigned long rx_packets, rx_bytes; unsigned long rx_packets, rx_bytes;
...@@ -434,8 +434,8 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) ...@@ -434,8 +434,8 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
#define STA_HASH(sta) (sta[5]) #define STA_HASH(sta) (sta[5])
/* Maximum number of frames to buffer per power saving station */ /* Maximum number of frames to buffer per power saving station per AC */
#define STA_MAX_TX_BUFFER 128 #define STA_MAX_TX_BUFFER 64
/* Minimum buffered frame expiry time. If STA uses listen interval that is /* Minimum buffered frame expiry time. If STA uses listen interval that is
* smaller than this value, the minimum value here is used instead. */ * smaller than this value, the minimum value here is used instead. */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "rate.h" #include "rate.h"
#include "mesh.h" #include "mesh.h"
#include "led.h" #include "led.h"
#include "wme.h"
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
...@@ -43,6 +44,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, ...@@ -43,6 +44,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *)skb->data;
int ac;
/* /*
* This skb 'survived' a round-trip through the driver, and * This skb 'survived' a round-trip through the driver, and
...@@ -62,6 +65,14 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, ...@@ -62,6 +65,14 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
sta->tx_filtered_count++; sta->tx_filtered_count++;
if (ieee80211_is_data_qos(hdr->frame_control)) {
int tid = *ieee80211_get_qos_ctl(hdr) &
IEEE80211_QOS_CTL_TID_MASK;
ac = ieee802_1d_to_ac[tid & 7];
} else {
ac = IEEE80211_AC_BE;
}
/* /*
* Clear the TX filter mask for this STA when sending the next * Clear the TX filter mask for this STA when sending the next
* packet. If the STA went to power save mode, this will happen * packet. If the STA went to power save mode, this will happen
...@@ -104,8 +115,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, ...@@ -104,8 +115,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
* unknown. * unknown.
*/ */
if (test_sta_flags(sta, WLAN_STA_PS_STA) && if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) {
skb_queue_tail(&sta->tx_filtered, skb); skb_queue_tail(&sta->tx_filtered[ac], skb);
sta_info_recalc_tim(sta); sta_info_recalc_tim(sta);
if (!timer_pending(&local->sta_cleanup)) if (!timer_pending(&local->sta_cleanup))
...@@ -127,7 +138,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, ...@@ -127,7 +138,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
if (net_ratelimit()) if (net_ratelimit())
wiphy_debug(local->hw.wiphy, wiphy_debug(local->hw.wiphy,
"dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
skb_queue_len(&sta->tx_filtered), skb_queue_len(&sta->tx_filtered[ac]),
!!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies); !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
#endif #endif
dev_kfree_skb(skb); dev_kfree_skb(skb);
......
...@@ -343,13 +343,22 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) ...@@ -343,13 +343,22 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
total += skb_queue_len(&ap->ps_bc_buf); total += skb_queue_len(&ap->ps_bc_buf);
} }
/*
* Drop one frame from each station from the lowest-priority
* AC that has frames at all.
*/
list_for_each_entry_rcu(sta, &local->sta_list, list) { list_for_each_entry_rcu(sta, &local->sta_list, list) {
skb = skb_dequeue(&sta->ps_tx_buf); int ac;
for (ac = IEEE80211_AC_BK; ac >= IEEE80211_AC_VO; ac--) {
skb = skb_dequeue(&sta->ps_tx_buf[ac]);
total += skb_queue_len(&sta->ps_tx_buf[ac]);
if (skb) { if (skb) {
purged++; purged++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
break;
}
} }
total += skb_queue_len(&sta->ps_tx_buf);
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -448,22 +457,21 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -448,22 +457,21 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) && if (unlikely((staflags & (WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) &&
!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) {
int ac = skb_get_queue_mapping(tx->skb);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n",
"before %d)\n", sta->sta.addr, sta->sta.aid, ac);
sta->sta.addr, sta->sta.aid,
skb_queue_len(&sta->ps_tx_buf));
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local); purge_old_ps_buffers(tx->local);
if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
if (net_ratelimit()) { if (net_ratelimit())
printk(KERN_DEBUG "%s: STA %pM TX " printk(KERN_DEBUG "%s: STA %pM TX buffer for "
"buffer full - dropping oldest frame\n", "AC %d full - dropping oldest frame\n",
tx->sdata->name, sta->sta.addr); tx->sdata->name, sta->sta.addr, ac);
}
#endif #endif
dev_kfree_skb(old); dev_kfree_skb(old);
} else } else
...@@ -472,7 +480,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -472,7 +480,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
info->control.jiffies = jiffies; info->control.jiffies = jiffies;
info->control.vif = &tx->sdata->vif; info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&sta->ps_tx_buf, tx->skb); skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
if (!timer_pending(&local->sta_cleanup)) if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup, mod_timer(&local->sta_cleanup,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment