Skip to content

Commit

Permalink
mac80211: implement fair queueing per txq
Browse files Browse the repository at this point in the history
mac80211's software queues were designed to work
very closely with device tx queues. They are
required to make use of 802.11 packet aggregation
easily and efficiently.

Due to the way 802.11 aggregation is designed it
only makes sense to keep fair queuing as close to
hardware as possible to reduce induced latency and
inertia and provide the best flow responsiveness.

This change doesn't translate directly to
immediate and significant gains. End result
depends on driver's induced latency. Best results
can be achieved if driver keeps its own tx
queue/fifo fill level to a minimum.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
Michal Kazior authored and Johannes Berg committed Jun 9, 2016
1 parent 80a83cf commit fa962b9
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 64 deletions.
8 changes: 6 additions & 2 deletions net/mac80211/agg-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,21 @@ static void
ieee80211_agg_stop_txq(struct sta_info *sta, int tid)
{
struct ieee80211_txq *txq = sta->sta.txq[tid];
struct ieee80211_sub_if_data *sdata;
struct fq *fq;
struct txq_info *txqi;

if (!txq)
return;

txqi = to_txq_info(txq);
sdata = vif_to_sdata(txq->vif);
fq = &sdata->local->fq;

/* Lock here to protect against further seqno updates on dequeue */
spin_lock_bh(&txqi->queue.lock);
spin_lock_bh(&fq->lock);
set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
spin_unlock_bh(&txqi->queue.lock);
spin_unlock_bh(&fq->lock);
}

static void
Expand Down
24 changes: 19 additions & 5 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <net/ieee80211_radiotap.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <net/fq.h>
#include "key.h"
#include "sta_info.h"
#include "debug.h"
Expand Down Expand Up @@ -805,10 +806,17 @@ enum txq_info_flags {
IEEE80211_TXQ_NO_AMSDU,
};

/**
* struct txq_info - per tid queue
*
* @tin: contains packets split into multiple flows
* @def_flow: used as a fallback flow when a packet destined to @tin hashes to
* a fq_flow which is already owned by a different tin
*/
struct txq_info {
struct sk_buff_head queue;
struct fq_tin tin;
struct fq_flow def_flow;
unsigned long flags;
unsigned long byte_cnt;

/* keep last! */
struct ieee80211_txq txq;
Expand Down Expand Up @@ -1099,6 +1107,8 @@ struct ieee80211_local {
* it first anyway so they become a no-op */
struct ieee80211_hw hw;

struct fq fq;

const struct ieee80211_ops *ops;

/*
Expand Down Expand Up @@ -1931,9 +1941,13 @@ static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
return true;
}

void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct txq_info *txq, int tid);
int ieee80211_txq_setup_flows(struct ieee80211_local *local);
void ieee80211_txq_teardown_flows(struct ieee80211_local *local);
void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct txq_info *txq, int tid);
void ieee80211_txq_purge(struct ieee80211_local *local,
struct txq_info *txqi);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
const u8 *extra, size_t extra_len, const u8 *bssid,
Expand Down
12 changes: 5 additions & 7 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
bool going_down)
{
struct ieee80211_local *local = sdata->local;
struct fq *fq = &local->fq;
unsigned long flags;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
Expand Down Expand Up @@ -976,13 +977,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,

if (sdata->vif.txq) {
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
int n = skb_queue_len(&txqi->queue);

spin_lock_bh(&txqi->queue.lock);
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
atomic_sub(n, &sdata->num_tx_queued);
txqi->byte_cnt = 0;
spin_unlock_bh(&txqi->queue.lock);
spin_lock_bh(&fq->lock);
ieee80211_txq_purge(local, txqi);
spin_unlock_bh(&fq->lock);
}

if (local->open_count == 0)
Expand Down Expand Up @@ -1792,7 +1790,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,

if (txq_size) {
txqi = netdev_priv(ndev) + size;
ieee80211_init_tx_queue(sdata, NULL, txqi, 0);
ieee80211_txq_init(sdata, NULL, txqi, 0);
}

sdata->dev = ndev;
Expand Down
7 changes: 7 additions & 0 deletions net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)

rtnl_unlock();

result = ieee80211_txq_setup_flows(local);
if (result)
goto fail_flows;

#ifdef CONFIG_INET
local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
result = register_inetaddr_notifier(&local->ifa_notifier);
Expand All @@ -1111,6 +1115,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
fail_ifa:
#endif
ieee80211_txq_teardown_flows(local);
fail_flows:
rtnl_lock();
rate_control_deinitialize(local);
ieee80211_remove_interfaces(local);
Expand Down Expand Up @@ -1169,6 +1175,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
skb_queue_purge(&local->skb_queue_tdls_chsw);
ieee80211_txq_teardown_flows(local);

destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy);
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info *sta)
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);

if (!skb_queue_len(&txqi->queue))
if (!txqi->tin.backlog_packets)
set_bit(tid, &sta->txq_buffered_tids);
else
clear_bit(tid, &sta->txq_buffered_tids);
Expand Down
14 changes: 7 additions & 7 deletions net/mac80211/sta_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
struct tid_ampdu_tx *tid_tx;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct fq *fq = &local->fq;
struct ps_data *ps;

if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
Expand All @@ -113,11 +114,10 @@ static void __cleanup_single_sta(struct sta_info *sta)
if (sta->sta.txq[0]) {
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
int n = skb_queue_len(&txqi->queue);

ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
atomic_sub(n, &sdata->num_tx_queued);
txqi->byte_cnt = 0;
spin_lock_bh(&fq->lock);
ieee80211_txq_purge(local, txqi);
spin_unlock_bh(&fq->lock);
}
}

Expand Down Expand Up @@ -368,7 +368,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txq = txq_data + i * size;

ieee80211_init_tx_queue(sdata, sta, txq, i);
ieee80211_txq_init(sdata, sta, txq, i);
}
}

Expand Down Expand Up @@ -1211,7 +1211,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);

if (!skb_queue_len(&txqi->queue))
if (!txqi->tin.backlog_packets)
continue;

drv_wake_tx_queue(local, txqi);
Expand Down Expand Up @@ -1648,7 +1648,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);

if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue))
if (!(tids & BIT(tid)) || txqi->tin.backlog_packets)
continue;

sta_info_recalc_tim(sta);
Expand Down
Loading

0 comments on commit fa962b9

Please sign in to comment.