diff options
author | Felix Fietkau <nbd@openwrt.org> | 2015-03-27 21:30:37 +0100 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-04-01 20:44:34 +0200 |
commit | ba8c3d6f16a1f9305c23ac1d2fd3992508c5ac03 (patch) | |
tree | c03bbdf0affccbd1f3a4fd0c239e59bb44f28e99 /net/mac80211/iface.c | |
parent | cef2fc1ce4326f7f24c3cf938b94a661fbe773e3 (diff) | |
download | linux-ba8c3d6f16a1f9305c23ac1d2fd3992508c5ac03.tar.bz2 |
mac80211: add an intermediate software queue implementation
This allows drivers to request per-vif and per-sta-tid queues from which
they can pull frames. This makes it easier to keep the hardware queues
short, and to improve fairness between clients and vifs.
The task of scheduling packet transmission is left up to the driver -
queueing is controlled by mac80211. Drivers can only dequeue packets by
calling ieee80211_tx_dequeue. This makes it possible to add active queue
management later without changing drivers using this code.
This can also be used as a starting point to implement A-MSDU
aggregation in a way that does not add artificially induced latency.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
[resolved minor context conflict, minor changes, endian annotations]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a0cd97fd0c49..b4ac596a7cb7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -969,6 +969,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, } spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + if (sdata->vif.txq) { + struct txq_info *txqi = to_txq_info(sdata->vif.txq); + + ieee80211_purge_tx_queue(&local->hw, &txqi->queue); + atomic_set(&sdata->txqs_len[txqi->txq.ac], 0); + } + if (local->open_count == 0) ieee80211_clear_tx_pending(local); @@ -1654,6 +1661,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, { struct net_device *ndev = NULL; struct ieee80211_sub_if_data *sdata = NULL; + struct txq_info *txqi; int ret, i; int txqs = 1; @@ -1673,10 +1681,18 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, ieee80211_assign_perm_addr(local, wdev->address, type); memcpy(sdata->vif.addr, wdev->address, ETH_ALEN); } else { + int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size, + sizeof(void *)); + int txq_size = 0; + + if (local->ops->wake_tx_queue) + txq_size += sizeof(struct txq_info) + + local->hw.txq_data_size; + if (local->hw.queues >= IEEE80211_NUM_ACS) txqs = IEEE80211_NUM_ACS; - ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, + ndev = alloc_netdev_mqs(size + txq_size, name, name_assign_type, ieee80211_if_setup, txqs, 1); if (!ndev) @@ -1711,6 +1727,11 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); memcpy(sdata->name, ndev->name, IFNAMSIZ); + if (txq_size) { + txqi = netdev_priv(ndev) + size; + ieee80211_init_tx_queue(sdata, NULL, txqi, 0); + } + sdata->dev = ndev; } |