* [RFC/RFT 0/4] mac80211 QoS-related enhancements
@ 2008-04-30 12:40 Johannes Berg
2008-04-30 12:40 ` [RFC/RFT 1/4] mac80211: use rate index in TX control Johannes Berg
` (3 more replies)
0 siblings, 4 replies; 41+ messages in thread
From: Johannes Berg @ 2008-04-30 12:40 UTC (permalink / raw)
To: linux-wireless
Cc: netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn,
Peter P Waskiewicz Jr
Note: This patch series requires a number of other patches, notably Ivo's
rt2x00 update and Ivo's mac80211 patch
"mac80211: Replace ieee80211_tx_control->key_idx with ieee80211_key_conf"
Any testing of this series is welcome, even just the first patch by itself
(especially with drivers other than b43), it doesn't make sense to test with
patch 2 and not 3 though, so if you're going to test one by one treat 2/3 as
a set.
This series of patches reworks mac80211 step-by-step to use more generic
code instead of having implementations of everything built-in.
The first patch (mac80211: use rate index in TX control) is just preparation
(but I'm not entirely sure about the iwlwifi changes, haven't tested them yet.)
The second patch I want input from netdev from, what do people think about
using the GSO code that way? It does seem like a bit of an abuse to fill the
skb->next pointer from within ->hard_start_xmit() but it works and allows
me to get rid of all the weird retry logic in mac80211 (patch three). Finally,
the fourth patch converts mac80211 and drivers to be multiqueue aware.
There are still a number of things missing in this series:
* we need to rework the classification function to be a real classifier
that we install on our wme qdisc
* we should allow tuning the medium access parameters via the wme qdisc
johannes
^ permalink raw reply [flat|nested] 41+ messages in thread* [RFC/RFT 1/4] mac80211: use rate index in TX control 2008-04-30 12:40 [RFC/RFT 0/4] mac80211 QoS-related enhancements Johannes Berg @ 2008-04-30 12:40 ` Johannes Berg 2008-04-30 12:40 ` [RFC/RFT 2/4] GSO: generalize for mac80211 Johannes Berg ` (2 subsequent siblings) 3 siblings, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-04-30 12:40 UTC (permalink / raw) To: linux-wireless-u79uwXL29TY76Z2rM5mHXA Cc: netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr [-- Attachment #1: 036-mac80211-tx-rate-idx.patch --] [-- Type: text/plain, Size: 40019 bytes --] This patch modifies struct ieee80211_tx_control to give band info and the rate index (instead of rate pointers) to drivers. This mostly serves to reduce the TX control structure size to make it fit into skb->cb so that the fragmentation code can put it there and we can think about passing it to drivers that way in the future. Signed-off-by: Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> --- drivers/net/wireless/adm8211.c | 6 - drivers/net/wireless/at76_usb.c | 2 drivers/net/wireless/ath5k/base.c | 8 +- drivers/net/wireless/b43/main.c | 2 drivers/net/wireless/b43/xmit.c | 13 ++- drivers/net/wireless/b43legacy/xmit.c | 9 +- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 6 - drivers/net/wireless/iwlwifi/iwl-3945.c | 7 + drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 12 +-- drivers/net/wireless/iwlwifi/iwl-4965.c | 13 +-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 - drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 - drivers/net/wireless/p54/p54common.c | 2 drivers/net/wireless/rt2x00/rt2x00dev.c | 6 - drivers/net/wireless/rtl8180_dev.c | 19 ++--- drivers/net/wireless/rtl8187_dev.c | 10 -- drivers/net/wireless/zd1211rw/zd_mac.c | 7 + include/net/mac80211.h | 51 ++++++++++--- net/mac80211/ieee80211_i.h | 8 +- net/mac80211/mlme.c | 6 - net/mac80211/rate.c | 12 ++- net/mac80211/rate.h | 25 ++---- net/mac80211/rc80211_pid_algo.c | 6 - net/mac80211/tx.c | 104 +++++++++++++++------------- net/mac80211/util.c | 10 ++ 25 files changed, 200 insertions(+), 152 deletions(-) --- everything.orig/include/net/mac80211.h 2008-04-29 22:49:27.000000000 +0200 +++ everything/include/net/mac80211.h 2008-04-29 23:56:43.000000000 +0200 @@ -266,27 +266,26 @@ enum mac80211_tx_control_flags { * ieee80211_ops->remove_interface() callback funtion. * The hw_key pointer is valid until it has been removed with the * ieee80211_ops->set_key() callback function. - * The tx_rate and alt_retry_rate pointers are valid until the phy is - * deregistered. */ struct ieee80211_tx_control { - struct ieee80211_vif *vif; - struct ieee80211_rate *tx_rate; + u32 flags; /* tx control flags defined above */ + + s8 tx_rate_idx, /* Transmit rate (indexes registered rates) */ + rts_cts_rate_idx, /* Transmit rate for RTS/CTS frame */ + alt_retry_rate_idx; /* retry rate for the last retries */ - /* Transmit rate for RTS/CTS frame */ - struct ieee80211_rate *rts_cts_rate; + s8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. + * This could be used when set_retry_limit + * is not implemented by the driver */ - /* retry rate for the last retries */ - struct ieee80211_rate *alt_retry_rate; + struct ieee80211_vif *vif; /* Key used for hardware encryption * NULL if IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */ struct ieee80211_key_conf *hw_key; - u32 flags; /* tx control flags defined above */ - u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. - * This could be used when set_retry_limit - * is not implemented by the driver */ + enum ieee80211_band band; + u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit * position represents antenna number used */ u8 icv_len; /* length of the ICV/MIC field in octets */ @@ -298,6 +297,7 @@ struct ieee80211_tx_control { }; + /** * enum mac80211_rx_flags - receive flags * @@ -799,6 +799,33 @@ static inline void SET_IEEE80211_PERM_AD memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +static inline struct ieee80211_rate * +ieee80211_get_tx_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (WARN_ON(c->tx_rate_idx < 0)) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (c->rts_cts_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->rts_cts_rate_idx]; +} + +static inline struct ieee80211_rate * +ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, + const struct ieee80211_tx_control *c) +{ + if (c->alt_retry_rate_idx < 0) + return NULL; + return &hw->wiphy->bands[c->band]->bitrates[c->alt_retry_rate_idx]; +} + /** * DOC: Hardware crypto acceleration * --- everything.orig/net/mac80211/rate.h 2008-04-29 22:56:34.000000000 +0200 +++ everything/net/mac80211/rate.h 2008-04-29 23:15:36.000000000 +0200 @@ -19,14 +19,15 @@ #include "ieee80211_i.h" #include "sta_info.h" -/* TODO: kdoc */ +/** + * struct rate_selection - rate selection for rate control algos + * @rate: selected transmission rate index + * @nonerp: Non-ERP rate to use instead if ERP cannot be used + * @probe: rate for probing (or -1) + * + */ struct rate_selection { - /* Selected transmission rate */ - struct ieee80211_rate *rate; - /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */ - struct ieee80211_rate *nonerp; - /* probe with this rate, or NULL for no probing */ - struct ieee80211_rate *probe; + s8 rate_idx, nonerp_idx, probe_idx; }; struct rate_control_ops { @@ -138,7 +139,7 @@ static inline int rate_supported(struct return (sta == NULL || sta->supp_rates[band] & BIT(index)); } -static inline int +static inline s8 rate_lowest_index(struct ieee80211_local *local, struct ieee80211_supported_band *sband, struct sta_info *sta) @@ -155,14 +156,6 @@ rate_lowest_index(struct ieee80211_local return 0; } -static inline struct ieee80211_rate * -rate_lowest(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta) -{ - return &sband->bitrates[rate_lowest_index(local, sband, sta)]; -} - /* functions for rate control related to a device */ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, --- everything.orig/net/mac80211/mlme.c 2008-04-29 22:56:00.000000000 +0200 +++ everything/net/mac80211/mlme.c 2008-04-29 23:20:08.000000000 +0200 @@ -2371,15 +2371,15 @@ static int ieee80211_sta_join_ibss(struc memset(&control, 0, sizeof(control)); rate_control_get_rate(dev, sband, skb, &ratesel); - if (!ratesel.rate) { + if (ratesel.rate_idx < 0) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } control.vif = &sdata->vif; - control.tx_rate = ratesel.rate; + control.tx_rate_idx = ratesel.rate_idx; if (sdata->bss_conf.use_short_preamble && - ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.flags |= IEEE80211_TXCTL_NO_ACK; --- everything.orig/net/mac80211/rate.c 2008-04-29 22:59:56.000000000 +0200 +++ everything/net/mac80211/rate.c 2008-04-29 23:16:53.000000000 +0200 @@ -176,20 +176,24 @@ void rate_control_get_rate(struct net_de rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); - memset(sel, 0, sizeof(struct rate_selection)); + sel->rate_idx = -1; + sel->nonerp_idx = -1; + sel->probe_idx = -1; ref->ops->get_rate(ref->priv, dev, sband, skb, sel); + BUG_ON(sel->rate_idx < 0); + /* Select a non-ERP backup rate. */ - if (!sel->nonerp) { + if (sel->nonerp_idx < 0) { for (i = 0; i < sband->n_bitrates; i++) { struct ieee80211_rate *rate = &sband->bitrates[i]; - if (sel->rate->bitrate < rate->bitrate) + if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate) break; if (rate_supported(sta, sband->band, i) && !(rate->flags & IEEE80211_RATE_ERP_G)) - sel->nonerp = rate; + sel->nonerp_idx = i; } } --- everything.orig/net/mac80211/ieee80211_i.h 2008-04-29 22:55:37.000000000 +0200 +++ everything/net/mac80211/ieee80211_i.h 2008-04-29 23:33:09.000000000 +0200 @@ -159,11 +159,11 @@ struct ieee80211_tx_data { struct ieee80211_tx_control *control; struct ieee80211_channel *channel; - struct ieee80211_rate *rate; + s8 rate_idx; /* use this rate (if set) for last fragment; rate can * be set to lower rate for the first fragments, e.g., * when using CTS protection with IEEE 802.11g. */ - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -225,9 +225,9 @@ struct ieee80211_tx_stored_packet { struct ieee80211_tx_control control; struct sk_buff *skb; struct sk_buff **extra_frag; - struct ieee80211_rate *last_frag_rate; + s8 last_frag_rate_idx; int num_extra_frag; - unsigned int last_frag_rate_ctrl_probe; + bool last_frag_rate_ctrl_probe; }; struct beacon_data { --- everything.orig/net/mac80211/rc80211_pid_algo.c 2008-04-29 23:11:25.000000000 +0200 +++ everything/net/mac80211/rc80211_pid_algo.c 2008-04-29 23:26:07.000000000 +0200 @@ -266,7 +266,7 @@ static void rate_control_pid_tx_status(v /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) + if (status->control.tx_rate_idx != sta->txrate_idx) goto unlock; spinfo = sta->rate_ctrl_priv; @@ -330,7 +330,7 @@ static void rate_control_pid_get_rate(vo fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } @@ -349,7 +349,7 @@ static void rate_control_pid_get_rate(vo rcu_read_unlock(); - sel->rate = &sband->bitrates[rateidx]; + sel->rate_idx = rateidx; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate( --- everything.orig/net/mac80211/tx.c 2008-04-29 23:00:43.000000000 +0200 +++ everything/net/mac80211/tx.c 2008-04-29 23:38:40.000000000 +0200 @@ -91,11 +91,12 @@ static u16 ieee80211_duration(struct iee int next_frag_len) { int rate, mrate, erp, dur, i; - struct ieee80211_rate *txrate = tx->rate; + struct ieee80211_rate *txrate; struct ieee80211_local *local = tx->local; struct ieee80211_supported_band *sband; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[tx->channel->band]; + txrate = &sband->bitrates[tx->rate_idx]; erp = 0; if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -610,40 +611,40 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 struct rate_selection rsel; struct ieee80211_supported_band *sband; - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; - if (likely(!tx->rate)) { + if (likely(tx->rate_idx < 0)) { rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); - tx->rate = rsel.rate; - if (unlikely(rsel.probe)) { + tx->rate_idx = rsel.rate_idx; + if (unlikely(rsel.probe_idx >= 0)) { tx->control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->control->alt_retry_rate = tx->rate; - tx->rate = rsel.probe; + tx->control->alt_retry_rate_idx = tx->rate_idx; + tx->rate_idx = rsel.probe_idx; } else - tx->control->alt_retry_rate = NULL; + tx->control->alt_retry_rate_idx = -1; - if (!tx->rate) + if (unlikely(tx->rate_idx < 0)) return TX_DROP; } else - tx->control->alt_retry_rate = NULL; + tx->control->alt_retry_rate_idx = -1; if (tx->sdata->bss_conf.use_cts_prot && - (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) { - tx->last_frag_rate = tx->rate; - if (rsel.probe) + (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { + tx->last_frag_rate_idx = tx->rate_idx; + if (rsel.probe_idx >= 0) tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; else tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->rate = rsel.nonerp; - tx->control->tx_rate = rsel.nonerp; + tx->rate_idx = rsel.nonerp_idx; + tx->control->tx_rate_idx = rsel.nonerp_idx; tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { - tx->last_frag_rate = tx->rate; - tx->control->tx_rate = tx->rate; + tx->last_frag_rate_idx = tx->rate_idx; + tx->control->tx_rate_idx = tx->rate_idx; } - tx->control->tx_rate = tx->rate; + tx->control->tx_rate_idx = tx->rate_idx; return TX_CONTINUE; } @@ -655,6 +656,9 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->control; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -681,14 +685,14 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate = NULL; + control->alt_retry_rate_idx = -1; } /* Use CTS protection for unicast frames sent using extended rates if * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && - (tx->rate->flags & IEEE80211_RATE_ERP_G) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TX_UNICAST) && tx->sdata->bss_conf.use_cts_prot && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) @@ -698,7 +702,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && + (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; @@ -715,32 +719,32 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate, *baserate; + struct ieee80211_rate *rate; + s8 baserate = -1; int idx; - sband = tx->local->hw.wiphy->bands[ - tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = NULL; + control->alt_retry_rate_idx = -1; /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = tx->rate; - baserate = NULL; + rate = &sband->bitrates[tx->rate_idx]; for (idx = 0; idx < sband->n_bitrates; idx++) { if (sband->bitrates[idx].bitrate > rate->bitrate) continue; if (tx->sdata->basic_rates & BIT(idx) && - (!baserate || - (baserate->bitrate < sband->bitrates[idx].bitrate))) - baserate = &sband->bitrates[idx]; + (baserate < 0 || + (sband->bitrates[baserate].bitrate + < sband->bitrates[idx].bitrate))) + baserate = idx; } - if (baserate) - control->rts_cts_rate = baserate; + if (baserate >= 0) + control->rts_cts_rate_idx = baserate; else - control->rts_cts_rate = &sband->bitrates[0]; + control->rts_cts_rate_idx = 0; } if (tx->sta) { @@ -768,7 +772,11 @@ ieee80211_tx_h_load_stats(struct ieee802 struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; - struct ieee80211_rate *rate = tx->rate; + struct ieee80211_rate *rate; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->channel->band]; + rate = &sband->bitrates[tx->rate_idx]; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored @@ -803,7 +811,7 @@ ieee80211_tx_h_load_stats(struct ieee802 for (i = 0; i < tx->num_extra_frag; i++) { load += 2 * hdrtime; load += tx->extra_frag[i]->len * - tx->rate->bitrate; + rate->bitrate; } } @@ -859,7 +867,7 @@ __ieee80211_parse_tx_radiotap(struct iee int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); struct ieee80211_tx_control *control = tx->control; - sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; tx->flags |= IEEE80211_TX_INJECTED; @@ -899,7 +907,7 @@ __ieee80211_parse_tx_radiotap(struct iee r = &sband->bitrates[i]; if (r->bitrate == target_rate) { - tx->rate = r; + tx->rate_idx = i; break; } } @@ -1098,7 +1106,7 @@ static int __ieee80211_tx(struct ieee802 if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->num_extra_frag) { - control->tx_rate = tx->last_frag_rate; + control->tx_rate_idx = tx->last_frag_rate_idx; if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) control->flags |= @@ -1156,6 +1164,7 @@ static int ieee80211_tx(struct net_devic sta = tx.sta; tx.channel = local->hw.conf.channel; + control->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { @@ -1188,7 +1197,7 @@ static int ieee80211_tx(struct net_devic next_len = tx.extra_frag[i + 1]->len; } else { next_len = 0; - tx.rate = tx.last_frag_rate; + tx.rate_idx = tx.last_frag_rate_idx; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1225,7 +1234,7 @@ retry: store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate = tx.last_frag_rate; + store->last_frag_rate_idx = tx.last_frag_rate_idx; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); } @@ -1681,7 +1690,7 @@ void ieee80211_tx_pending(unsigned long tx.control = &store->control; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate = store->last_frag_rate; + tx.last_frag_rate_idx = store->last_frag_rate_idx; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; @@ -1785,9 +1794,10 @@ struct sk_buff *ieee80211_beacon_get(str struct ieee80211_mgmt *mgmt; int *num_beacons; bool err = true; + enum ieee80211_band band = local->hw.conf.channel->band; u8 *pos; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[band]; rcu_read_lock(); @@ -1881,8 +1891,9 @@ struct sk_buff *ieee80211_beacon_get(str } if (control) { + control->band = band; rate_control_get_rate(local->mdev, sband, skb, &rsel); - if (!rsel.rate) { + if (unlikely(rsel.rate_idx < 0)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: ieee80211_beacon_get: " "no rate found\n", @@ -1894,9 +1905,9 @@ struct sk_buff *ieee80211_beacon_get(str } control->vif = vif; - control->tx_rate = rsel.rate; + control->tx_rate_idx = rsel.rate_idx; if (sdata->bss_conf.use_short_preamble && - rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; control->flags |= IEEE80211_TXCTL_NO_ACK; @@ -2001,6 +2012,7 @@ ieee80211_get_buffered_bc(struct ieee802 sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; + control->band = tx.channel->band; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); --- everything.orig/net/mac80211/util.c 2008-04-29 23:13:24.000000000 +0200 +++ everything/net/mac80211/util.c 2008-04-29 23:25:15.000000000 +0200 @@ -266,10 +266,13 @@ __le16 ieee80211_rts_duration(struct iee bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) @@ -300,10 +303,13 @@ __le16 ieee80211_ctstoself_duration(stru bool short_preamble; int erp; u16 dur; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_cts_rate; + rate = &sband->bitrates[frame_txctl->rts_cts_rate_idx]; erp = 0; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; --- everything.orig/drivers/net/wireless/adm8211.c 2008-04-29 23:49:15.000000000 +0200 +++ everything/drivers/net/wireless/adm8211.c 2008-04-29 23:50:11.000000000 +0200 @@ -1693,10 +1693,10 @@ static int adm8211_tx(struct ieee80211_h size_t payload_len, hdrlen; int plcp, dur, len, plcp_signal, short_preamble; struct ieee80211_hdr *hdr; + struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, control); - short_preamble = !!(control->tx_rate->flags & - IEEE80211_TXCTL_SHORT_PREAMBLE); - plcp_signal = control->tx_rate->bitrate; + short_preamble = !!(txrate->flags & IEEE80211_TXCTL_SHORT_PREAMBLE); + plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED; --- everything.orig/drivers/net/wireless/at76_usb.c 2008-04-29 23:44:22.000000000 +0200 +++ everything/drivers/net/wireless/at76_usb.c 2008-04-29 23:44:48.000000000 +0200 @@ -1753,7 +1753,7 @@ static int at76_mac80211_tx(struct ieee8 memset(tx_buffer, 0, sizeof(*tx_buffer)); tx_buffer->padding = padding; tx_buffer->wlength = cpu_to_le16(skb->len); - tx_buffer->tx_rate = control->tx_rate->hw_value; + tx_buffer->tx_rate = ieee80211_get_tx_rate(hw, control)->hw_value; memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved)); memcpy(tx_buffer->packet, skb->data, skb->len); --- everything.orig/drivers/net/wireless/ath5k/base.c 2008-04-29 23:50:17.000000000 +0200 +++ everything/drivers/net/wireless/ath5k/base.c 2008-04-29 23:52:29.000000000 +0200 @@ -1329,7 +1329,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc ret = ah->ah_setup_tx_desc(ah, ds, pktlen, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, - (sc->power_level * 2), ctl->tx_rate->hw_value, + (sc->power_level * 2), + ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, ctl->retry_limit, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -2061,7 +2062,8 @@ ath5k_beacon_setup(struct ath5k_softc *s ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (sc->power_level * 2), - ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID, + ieee80211_get_tx_rate(sc->hw, ctl)->hw_value, + 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); if (ret) goto err_unmap; @@ -2669,7 +2671,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct memmove(skb->data, skb->data+pad, hdrlen); } - sc->led_txrate = ctl->tx_rate->hw_value; + sc->led_txrate = ieee80211_get_tx_rate(hw, ctl)->hw_value; spin_lock_irqsave(&sc->txbuflock, flags); if (list_empty(&sc->txbuf)) { --- everything.orig/drivers/net/wireless/b43/main.c 2008-04-29 23:52:44.000000000 +0200 +++ everything/drivers/net/wireless/b43/main.c 2008-04-29 23:53:58.000000000 +0200 @@ -1365,7 +1365,7 @@ static void b43_write_beacon_template(st bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - rate = dev->wl->beacon_txctl.tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev->wl->hw, &dev->wl->beacon_txctl)->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); --- everything.orig/drivers/net/wireless/b43/xmit.c 2008-04-29 23:54:15.000000000 +0200 +++ everything/drivers/net/wireless/b43/xmit.c 2008-04-29 23:58:24.000000000 +0200 @@ -201,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev u32 mac_ctl = 0; u16 phy_ctl = 0; u8 extra_ft = 0; + struct ieee80211_rate *txrate; memset(txhdr, 0, sizeof(*txhdr)); - WARN_ON(!txctl->tx_rate); - rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; + txrate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -336,9 +337,11 @@ int b43_generate_txhdr(struct b43_wldev int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; struct b43_plcp_hdr6 *plcp; + struct ieee80211_rate *rts_cts_rate; - WARN_ON(!txctl->rts_cts_rate); - rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; + rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl); + + rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); --- everything.orig/drivers/net/wireless/b43legacy/xmit.c 2008-04-29 23:58:40.000000000 +0200 +++ everything/drivers/net/wireless/b43legacy/xmit.c 2008-04-30 00:00:33.000000000 +0200 @@ -201,15 +201,18 @@ static int generate_txhdr_fw3(struct b43 unsigned int plcp_fragment_len; u32 mac_ctl = 0; u16 phy_ctl = 0; + struct ieee80211_rate *tx_rate; wlhdr = (const struct ieee80211_hdr *)fragment_data; fctl = le16_to_cpu(wlhdr->frame_control); memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate->hw_value; + tx_rate = ieee80211_get_tx_rate(dev->wl->hw, txctl); + + rate = tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, txctl) ? : tx_rate; rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; @@ -312,7 +315,7 @@ static int generate_txhdr_fw3(struct b43 int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = txctl->rts_cts_rate->hw_value; + rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, txctl)->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); --- everything.orig/drivers/net/wireless/iwlwifi/iwl-3945-rs.c 2008-04-30 00:05:11.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl-3945-rs.c 2008-04-30 00:08:12.000000000 +0200 @@ -465,7 +465,7 @@ static void rs_tx_status(void *priv_rate retries = tx_resp->retry_count; - first_index = tx_resp->control.tx_rate->hw_value; + first_index = sband->bitrates[tx_resp->control.tx_rate_idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -670,7 +670,7 @@ static void rs_get_rate(void *priv_rate, is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); rcu_read_unlock(); return; } @@ -814,7 +814,7 @@ static void rs_get_rate(void *priv_rate, IWL_DEBUG_RATE("leave: %d\n", index); - sel->rate = &sband->bitrates[sta->txrate_idx]; + sel->rate_idx = sta->txrate_idx; } static struct rate_control_ops rs_ops = { --- everything.orig/drivers/net/wireless/iwlwifi/iwl-3945.c 2008-04-30 00:02:07.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl-3945.c 2008-04-30 00:13:39.000000000 +0200 @@ -331,7 +331,9 @@ static void iwl3945_rx_reply_tx(struct i tx_resp->rate, tx_resp->failure_frame); rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); - tx_status->control.tx_rate = &priv->ieee_rates[rate_idx]; + if (tx_status->control.band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + tx_status->control.tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -966,7 +968,8 @@ void iwl3945_hw_build_tx_cmd_rate(struct struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + u16 hw_value = ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value; + u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; u8 rts_retry_limit; --- everything.orig/drivers/net/wireless/iwlwifi/iwl-4965-rs.c 2008-04-30 00:13:48.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl-4965-rs.c 2008-04-30 00:17:28.000000000 +0200 @@ -851,7 +851,7 @@ static void rs_tx_status(void *priv_rate if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((tx_resp->control.tx_rate == NULL) || + if ((tx_resp->control.tx_rate_idx < 0) || (tbl_type.is_SGI ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) || (tbl_type.is_fat ^ @@ -865,7 +865,7 @@ static void rs_tx_status(void *priv_rate (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^ !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - tx_resp->control.tx_rate->bitrate)) { + hw->wiphy->bands[tx_resp->control.band]->bitrates[tx_resp->control.tx_rate_idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_mcs.rate_n_flags); goto out; @@ -2181,7 +2181,7 @@ static void rs_get_rate(void *priv_rate, fc = le16_to_cpu(hdr->frame_control); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } @@ -2211,11 +2211,13 @@ static void rs_get_rate(void *priv_rate, done: if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate = rate_lowest(local, sband, sta); + sel->rate_idx = rate_lowest_index(local, sband, sta); goto out; } - sel->rate = &priv->ieee_rates[i]; + if (sband->band == IEEE80211_BAND_5GHZ) + i -= IWL_FIRST_OFDM_RATE; + sel->rate_idx = i; out: rcu_read_unlock(); } --- everything.orig/drivers/net/wireless/iwlwifi/iwl-4965.c 2008-04-30 00:09:05.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl-4965.c 2008-04-30 00:12:01.000000000 +0200 @@ -421,14 +421,10 @@ void iwl4965_hwrate_to_tx_control(struct control->flags |= IEEE80211_TXCTL_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) control->flags |= IEEE80211_TXCTL_SHORT_GI; - /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use - * IEEE80211_BAND_2GHZ band as it contains all the rates */ rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags); - if (rate_index == -1) - control->tx_rate = NULL; - else - control->tx_rate = - &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index]; + if (control->band == IEEE80211_BAND_5GHZ) + rate_index -= IWL_FIRST_OFDM_RATE; + control->tx_rate_idx = rate_index; } /* @@ -2980,7 +2976,8 @@ void iwl4965_hw_build_tx_cmd_rate(struct u16 fc = le16_to_cpu(hdr->frame_control); u8 rate_plcp; u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); + u16 hw_value = ieee80211_get_tx_rate(priv->hw, ctrl)->hw_value; + int rate_idx = min(hw_value & 0xffff, IWL_RATE_COUNT - 1); rate_plcp = iwl4965_rates[rate_idx].plcp; --- everything.orig/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 00:00:59.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 00:01:52.000000000 +0200 @@ -2589,7 +2589,7 @@ static int iwl3945_tx_skb(struct iwl3945 goto drop_unlock; } - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -6700,7 +6700,7 @@ static int iwl3945_mac_tx(struct ieee802 } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, ctl)->bitrate); if (iwl3945_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); --- everything.orig/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 00:08:23.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 00:08:51.000000000 +0200 @@ -2154,7 +2154,7 @@ static int iwl4965_tx_skb(struct iwl_pri goto drop_unlock; } - if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { + if ((ieee80211_get_tx_rate(priv->hw, ctl)->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -6243,7 +6243,7 @@ static int iwl4965_mac_tx(struct ieee802 } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate->bitrate); + ieee80211_get_tx_rate(hw, ctl)->bitrate); if (iwl4965_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); --- everything.orig/drivers/net/wireless/p54/p54common.c 2008-04-30 00:17:46.000000000 +0200 +++ everything/drivers/net/wireless/p54/p54common.c 2008-04-30 00:18:05.000000000 +0200 @@ -595,7 +595,7 @@ static int p54_tx(struct ieee80211_hw *d txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = control->tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev, control)->hw_value; if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) rate |= 0x10; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) --- everything.orig/drivers/net/wireless/rt2x00/rt2x00dev.c 2008-04-30 00:18:16.000000000 +0200 +++ everything/drivers/net/wireless/rt2x00/rt2x00dev.c 2008-04-30 00:19:14.000000000 +0200 @@ -648,7 +648,7 @@ void rt2x00lib_write_tx_desc(struct rt2x frame_control = le16_to_cpu(hdr->frame_control); seq_ctrl = le16_to_cpu(hdr->seq_ctrl); - tx_rate = control->tx_rate->hw_value; + tx_rate = ieee80211_get_tx_rate(rt2x00dev->hw, control)->hw_value; /* * Check whether this frame is to be acked @@ -666,8 +666,8 @@ void rt2x00lib_write_tx_desc(struct rt2x __set_bit(ENTRY_TXD_ACK, &txdesc.flags); } else __clear_bit(ENTRY_TXD_ACK, &txdesc.flags); - if (control->rts_cts_rate) - tx_rate = control->rts_cts_rate->hw_value; + if (control->rts_cts_rate_idx >= 0) + tx_rate = ieee80211_get_rts_cts_rate(rt2x00dev->hw, control)->hw_value; } rate = rt2x00_get_rate(tx_rate); --- everything.orig/drivers/net/wireless/rtl8180_dev.c 2008-04-29 23:45:07.000000000 +0200 +++ everything/drivers/net/wireless/rtl8180_dev.c 2008-04-29 23:48:00.000000000 +0200 @@ -257,24 +257,21 @@ static int rtl8180_tx(struct ieee80211_h mapping = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - BUG_ON(!control->tx_rate); - tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | RTL8180_TX_DESC_FLAG_LS | - (control->tx_rate->hw_value << 24) | skb->len; + (ieee80211_get_tx_rate(dev, control)->hw_value << 24) | + skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | RTL8180_TX_DESC_FLAG_NO_ENC; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_RTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); tx_flags |= RTL8180_TX_DESC_FLAG_CTS; - tx_flags |= control->rts_cts_rate->hw_value << 19; + tx_flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } *((struct ieee80211_tx_control **) skb->cb) = @@ -288,9 +285,9 @@ static int rtl8180_tx(struct ieee80211_h unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (control->tx_rate->bitrate * 2) / 10); + (ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((control->tx_rate->bitrate * 2) / 10); + ((ieee80211_get_tx_rate(dev, control)->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -303,8 +300,8 @@ static int rtl8180_tx(struct ieee80211_h entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate != NULL ? - control->alt_retry_rate->bitrate << 4 : 0; + entry->flags2 = control->alt_retry_rate_idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, control)->bitrate << 4 : 0; entry->retry_limit = control->retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); --- everything.orig/drivers/net/wireless/rtl8187_dev.c 2008-04-29 23:48:15.000000000 +0200 +++ everything/drivers/net/wireless/rtl8187_dev.c 2008-04-29 23:49:04.000000000 +0200 @@ -179,21 +179,17 @@ static int rtl8187_tx(struct ieee80211_h flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - BUG_ON(!control->tx_rate); - - flags |= control->tx_rate->hw_value << 24; + flags |= ieee80211_get_tx_rate(dev, control)->hw_value << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { - BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_RTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, control); } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - BUG_ON(!control->rts_cts_rate); flags |= RTL8187_TX_FLAG_CTS; - flags |= control->rts_cts_rate->hw_value << 19; + flags |= ieee80211_get_rts_cts_rate(dev, control)->hw_value << 19; } hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); --- everything.orig/drivers/net/wireless/zd1211rw/zd_mac.c 2008-04-30 00:19:42.000000000 +0200 +++ everything/drivers/net/wireless/zd1211rw/zd_mac.c 2008-04-30 00:21:03.000000000 +0200 @@ -523,14 +523,17 @@ static int fill_ctrlset(struct zd_mac *m struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; + struct ieee80211_rate *txrate; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); ZD_ASSERT(frag_len <= 0xffff); - cs->modulation = control->tx_rate->hw_value; + txrate = ieee80211_get_tx_rate(mac->hw, control); + + cs->modulation = txrate->hw_value; if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) - cs->modulation = control->tx_rate->hw_value_short; + cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); -- -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* [RFC/RFT 2/4] GSO: generalize for mac80211 2008-04-30 12:40 [RFC/RFT 0/4] mac80211 QoS-related enhancements Johannes Berg 2008-04-30 12:40 ` [RFC/RFT 1/4] mac80211: use rate index in TX control Johannes Berg @ 2008-04-30 12:40 ` Johannes Berg [not found] ` <20080430130049.359549000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> 2008-04-30 12:40 ` [RFC/RFT 3/4] mac80211: use GSO for fragmentation Johannes Berg 2008-04-30 12:40 ` [RFC/RFT 4/4] mac80211: use multi-queue master netdevice Johannes Berg 3 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-04-30 12:40 UTC (permalink / raw) To: linux-wireless Cc: netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr, Herbert Xu [-- Attachment #1: 037-generalize-gso-functions.patch --] [-- Type: text/plain, Size: 3793 bytes --] This patch adds a new function dev_skb_segment() that generalises the existing dev_gso_segment() by allowing to give a segmentation function. mac80211 will use that function using the segmentation function skb_segment(). This patch also changes dev_gso_skb_destructor() to be safe when the skb no longer has any segments, this will happen when mac80211 has internally passed off all the fragments to the driver instead of asking dev_hard_start_xmit() to do it (which protects against this by resetting the destructor if it has sent all fragments.) Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Cc: Herbert Xu <herbert@gondor.apana.org.au> --- include/linux/netdevice.h | 1 + net/core/dev.c | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 8 deletions(-) --- everything.orig/net/core/dev.c 2008-04-30 01:52:23.000000000 +0200 +++ everything/net/core/dev.c 2008-04-30 03:46:33.000000000 +0200 @@ -1491,13 +1491,13 @@ static void dev_gso_skb_destructor(struc { struct dev_gso_cb *cb; - do { + while (skb->next) { struct sk_buff *nskb = skb->next; skb->next = nskb->next; nskb->next = NULL; kfree_skb(nskb); - } while (skb->next); + } cb = DEV_GSO_CB(skb); if (cb->destructor) @@ -1505,22 +1505,31 @@ static void dev_gso_skb_destructor(struc } /** - * dev_gso_segment - Perform emulated hardware segmentation on skb. + * dev_skb_segment - Perform segmentation on skb. * @skb: buffer to segment + * @segmfn: function that does the actual segmentation * - * This function segments the given skb and stores the list of segments - * in skb->next. + * This function segments the given skb and stores the list + * of segments in skb->next. The segmentation function is + * used to do the actual segmentation, it must return the + * list of segments as chained via the returned skb's @next + * pointer. The segmentation function is given the skb to + * segment and the features of the device the skb is going + * to. The segmentation function needs to return an ERR_PTR + * or a valid sk_buff pointer (or NULL for no segments.) + * + * Note that segmentation needs the skbs @cb data. */ -static int dev_gso_segment(struct sk_buff *skb) +int dev_skb_segment(struct sk_buff *skb, struct sk_buff *(segmfn)(struct sk_buff *skb, int feat)) { struct net_device *dev = skb->dev; struct sk_buff *segs; int features = dev->features & ~(illegal_highdma(dev, skb) ? NETIF_F_SG : 0); - segs = skb_gso_segment(skb, features); + segs = segmfn(skb, features); - /* Verifying header integrity only. */ + /* Verifying header integrity only/no segments required. */ if (!segs) return 0; @@ -1533,6 +1542,19 @@ static int dev_gso_segment(struct sk_buf return 0; } +EXPORT_SYMBOL_GPL(dev_skb_segment); + +/** + * dev_gso_segment - Perform emulated hardware segmentation on skb. + * @skb: buffer to segment + * + * This function segments the given skb and stores the list of segments + * in skb->next. + */ +static int dev_gso_segment(struct sk_buff *skb) +{ + return dev_skb_segment(skb, skb_gso_segment); +} int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { --- everything.orig/include/linux/netdevice.h 2008-04-30 01:52:23.000000000 +0200 +++ everything/include/linux/netdevice.h 2008-04-30 01:52:26.000000000 +0200 @@ -1454,6 +1454,7 @@ extern int weight_p; extern int netdev_set_master(struct net_device *dev, struct net_device *master); extern int skb_checksum_help(struct sk_buff *skb); extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features); +extern int dev_skb_segment(struct sk_buff *skb, struct sk_buff *(segmfn)(struct sk_buff *skb, int feat)); #ifdef CONFIG_BUG extern void netdev_rx_csum_fault(struct net_device *dev); #else -- ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080430130049.359549000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org>]
* Re: [RFC/RFT 2/4] GSO: generalize for mac80211 [not found] ` <20080430130049.359549000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> @ 2008-05-06 16:12 ` Johannes Berg 0 siblings, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-05-06 16:12 UTC (permalink / raw) To: linux-wireless-u79uwXL29TY76Z2rM5mHXA Cc: netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr, Herbert Xu, David S. Miller [-- Attachment #1: Type: text/plain, Size: 1076 bytes --] On Wed, 2008-04-30 at 14:40 +0200, Johannes Berg wrote: > plain text document attachment (037-generalize-gso-functions.patch) > This patch adds a new function dev_skb_segment() that generalises > the existing dev_gso_segment() by allowing to give a segmentation > function. mac80211 will use that function using the segmentation > function skb_segment(). > > This patch also changes dev_gso_skb_destructor() to be safe when > the skb no longer has any segments, this will happen when mac80211 > has internally passed off all the fragments to the driver instead > of asking dev_hard_start_xmit() to do it (which protects against > this by resetting the destructor if it has sent all fragments.) Any comments on this? I'd like to include this (well, more importantly the mac80211 patch that needs it) for testing for 2.6.27, should I send it via John or directly to you, Dave? Also, I'm not sure, should I allow for a segmentation function at all? I'm only going to use the generic skb_segment and the code there only uses skb_gso_segment. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* [RFC/RFT 3/4] mac80211: use GSO for fragmentation 2008-04-30 12:40 [RFC/RFT 0/4] mac80211 QoS-related enhancements Johannes Berg 2008-04-30 12:40 ` [RFC/RFT 1/4] mac80211: use rate index in TX control Johannes Berg 2008-04-30 12:40 ` [RFC/RFT 2/4] GSO: generalize for mac80211 Johannes Berg @ 2008-04-30 12:40 ` Johannes Berg 2008-05-07 7:10 ` Herbert Xu 2008-04-30 12:40 ` [RFC/RFT 4/4] mac80211: use multi-queue master netdevice Johannes Berg 3 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-04-30 12:40 UTC (permalink / raw) To: linux-wireless Cc: netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr, Herbert Xu [-- Attachment #1: 038-mac80211-use-gso-infrastructure.patch --] [-- Type: text/plain, Size: 39519 bytes --] This patch makes mac80211 use the GSO infrastructure for segmentation, but not really all of it because we do not register a protocol handler (nor can do that easily since a lot of functions need to be done before segmentation and another bunch afterwards, and we need to keep rcu- protected structures for both.) Hence, the way it works is that if a packet is to be fragmented then we call dev_skb_segment() on it and get a fragment list in skb->next. We then go to pass this fragment list to the driver one by one but if at any point the driver is unable to handle more data on its queues we reject the skb (with the remaining fragments) which will cause it to be stored into dev->gso_skb and handed to us (once the queue is woken again) fragment by fragment which we detect and hand on to the driver. This has the benefit of removing a lot of code that is rarely used (since fragmentation in IEEE 802.11 isn't all that common any more) and is rather complex. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Cc: Herbert Xu <herbert@gondor.apana.org.au> --- Herbert, would you mind taking a look at ieee80211_tx_h_fragment and __ieee80211_tx? The diffstat is negative despite adding lots of comments :) include/net/mac80211.h | 11 net/mac80211/ieee80211_i.h | 19 - net/mac80211/main.c | 33 +- net/mac80211/mlme.c | 1 net/mac80211/tx.c | 589 +++++++++++++++++++++------------------------ net/mac80211/util.c | 30 -- net/mac80211/wep.c | 28 +- net/mac80211/wme.c | 9 net/mac80211/wpa.c | 46 ++- 9 files changed, 370 insertions(+), 396 deletions(-) --- everything.orig/net/mac80211/ieee80211_i.h 2008-04-30 03:44:52.000000000 +0200 +++ everything/net/mac80211/ieee80211_i.h 2008-04-30 13:37:40.000000000 +0200 @@ -147,7 +147,6 @@ typedef unsigned __bitwise__ ieee80211_t #define IEEE80211_TX_UNICAST BIT(1) #define IEEE80211_TX_PS_BUFFERED BIT(2) #define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) -#define IEEE80211_TX_INJECTED BIT(4) struct ieee80211_tx_data { struct sk_buff *skb; @@ -165,11 +164,6 @@ struct ieee80211_tx_data { * when using CTS protection with IEEE 802.11g. */ s8 last_frag_rate_idx; - /* Extra fragments (in addition to the first fragment - * in skb) */ - struct sk_buff **extra_frag; - int num_extra_frag; - u16 fc, ethertype; unsigned int flags; }; @@ -213,20 +207,20 @@ struct ieee80211_rx_data { #define IEEE80211_TXPD_REQUEUE BIT(2) #define IEEE80211_TXPD_EAPOL_FRAME BIT(3) #define IEEE80211_TXPD_AMPDU BIT(4) +/* ALWAYS(!) set the _PRESENT bit */ +#define IEEE80211_TXPD_PRESENT BIT(19) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { + u32 flags; int ifindex; + u16 queue; unsigned long jiffies; - unsigned int flags; - u8 queue; }; struct ieee80211_tx_stored_packet { struct ieee80211_tx_control control; struct sk_buff *skb; - struct sk_buff **extra_frag; s8 last_frag_rate_idx; - int num_extra_frag; bool last_frag_rate_ctrl_probe; }; @@ -612,8 +606,6 @@ struct ieee80211_local { struct timer_list sta_cleanup; unsigned long state[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; - struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; - struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ atomic_t iff_allmultis, iff_promiscs; @@ -846,7 +838,6 @@ static inline struct ieee80211_hw *local enum ieee80211_link_state_t { IEEE80211_LINK_STATE_XOFF = 0, - IEEE80211_LINK_STATE_PENDING, }; struct sta_attribute { @@ -968,8 +959,6 @@ void ieee80211_if_free(struct net_device void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); /* tx handling */ -void ieee80211_clear_tx_pending(struct ieee80211_local *local); -void ieee80211_tx_pending(unsigned long data); int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); --- everything.orig/net/mac80211/tx.c 2008-04-30 03:44:52.000000000 +0200 +++ everything/net/mac80211/tx.c 2008-04-30 13:55:23.000000000 +0200 @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> - * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,9 +32,6 @@ #include "wme.h" #include "rate.h" -#define IEEE80211_TX_OK 0 -#define IEEE80211_TX_AGAIN 1 -#define IEEE80211_TX_FRAG_AGAIN 2 /* misc utils */ @@ -219,12 +216,6 @@ static inline int __ieee80211_queue_stop return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); } -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); -} - static int inline is_ieee80211_device(struct net_device *dev, struct net_device *master) { @@ -243,7 +234,7 @@ ieee80211_tx_h_check_assoc(struct ieee80 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ u32 sta_flags; - if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) + if (unlikely(tx->control->flags & IEEE80211_TXCTL_INJECTED)) return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && @@ -457,46 +448,66 @@ ieee80211_tx_h_ps_buf(struct ieee80211_t return ieee80211_tx_h_multicast_ps_buf(tx); } +static struct ieee80211_key * +ieee80211_select_key(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + struct ieee80211_tx_control *control, + u16 fc) +{ + struct ieee80211_key *key, *result; + u16 ftype, stype; + + if (unlikely(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + result = NULL; + else if (sta && (key = rcu_dereference(sta->key))) + result = key; + else if ((key = rcu_dereference(sdata->default_key))) + result = key; + else + result = NULL; + + if (!result) + return NULL; + + switch (result->conf.alg) { + case ALG_WEP: + ftype = fc & IEEE80211_FCTL_FTYPE; + stype = fc & IEEE80211_FCTL_STYPE; + + if (ftype == IEEE80211_FTYPE_MGMT && + stype == IEEE80211_STYPE_AUTH) + break; + case ALG_TKIP: + case ALG_CCMP: + if (!WLAN_FC_DATA_PRESENT(fc)) + result = NULL; + break; + } + + return result; +} + static ieee80211_tx_result ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { - struct ieee80211_key *key; u16 fc = tx->fc; if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - tx->key = NULL; - else if (tx->sta && (key = rcu_dereference(tx->sta->key))) - tx->key = key; - else if ((key = rcu_dereference(tx->sdata->default_key))) - tx->key = key; - else if (tx->sdata->drop_unencrypted && - !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && - !(tx->flags & IEEE80211_TX_INJECTED)) { + return TX_CONTINUE; + + tx->key = ieee80211_select_key(tx->sdata, tx->sta, tx->control, fc); + + if (!tx->key && + tx->sdata->drop_unencrypted && + !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && + !(tx->control->flags & IEEE80211_TXCTL_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; - } else - tx->key = NULL; + } if (tx->key) { - u16 ftype, stype; - tx->key->tx_rx_count++; /* TODO: add threshold stuff again */ - - switch (tx->key->conf.alg) { - case ALG_WEP: - ftype = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - - if (ftype == IEEE80211_FTYPE_MGMT && - stype == IEEE80211_STYPE_AUTH) - break; - case ALG_TKIP: - case ALG_CCMP: - if (!WLAN_FC_DATA_PRESENT(fc)) - tx->key = NULL; - break; - } } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) @@ -508,81 +519,40 @@ ieee80211_tx_h_select_key(struct ieee802 static ieee80211_tx_result ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - size_t hdrlen, per_fragm, num_fragm, payload_len, left; - struct sk_buff **frags, *first, *frag; - int i; - u16 seq; - u8 *pos; int frag_threshold = tx->local->fragmentation_threshold; + int hdrlen, payload_len, per_fragm, num_fragm; if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) return TX_CONTINUE; - first = tx->skb; - hdrlen = ieee80211_get_hdrlen(tx->fc); - payload_len = first->len - hdrlen; + payload_len = tx->skb->len - hdrlen; per_fragm = frag_threshold - hdrlen - FCS_LEN; num_fragm = DIV_ROUND_UP(payload_len, per_fragm); - frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); - if (!frags) - goto fail; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); - seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; - pos = first->data + hdrlen + per_fragm; - left = payload_len - per_fragm; - for (i = 0; i < num_fragm - 1; i++) { - struct ieee80211_hdr *fhdr; - size_t copylen; - - if (left <= 0) - goto fail; + WARN_ON(num_fragm <= 1); - /* reserve enough extra head and tail room for possible - * encryption */ - frag = frags[i] = - dev_alloc_skb(tx->local->tx_headroom + - frag_threshold + - IEEE80211_ENCRYPT_HEADROOM + - IEEE80211_ENCRYPT_TAILROOM); - if (!frag) - goto fail; - /* Make sure that all fragments use the same priority so - * that they end up using the same TX queue */ - frag->priority = first->priority; - skb_reserve(frag, tx->local->tx_headroom + - IEEE80211_ENCRYPT_HEADROOM); - fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); - memcpy(fhdr, first->data, hdrlen); - if (i == num_fragm - 2) - fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); - fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); - copylen = left > per_fragm ? per_fragm : left; - memcpy(skb_put(frag, copylen), pos, copylen); + /* skb_segment will push the mac header back in */ + skb_reset_mac_header(tx->skb); + __skb_pull(tx->skb, hdrlen); - pos += copylen; - left -= copylen; - } - skb_trim(first, hdrlen + per_fragm); + skb_shinfo(tx->skb)->gso_size = per_fragm; + skb_shinfo(tx->skb)->nr_frags = 0; - tx->num_extra_frag = num_fragm - 1; - tx->extra_frag = frags; + /* + * Now segment (fragment) the frame. This will allocate all the + * segments and assign them to the tx->skb->next pointer. During + * transmission, we will remove the successfully transmitted + * fragments from this list. Iff the low-level driver rejects one + * of the fragments then we will simply reject the skb completely + * (with the remaining fragments still in it) which will make the + * upper layer code store it away specially and try to retransmit + * the fragments one by one. + */ + if (dev_skb_segment(tx->skb, skb_segment)) + return TX_DROP; return TX_CONTINUE; - - fail: - printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); - if (frags) { - for (i = 0; i < num_fragm - 1; i++) - if (frags[i]) - dev_kfree_skb(frags[i]); - kfree(frags); - } - I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TX_DROP; } static ieee80211_tx_result @@ -712,8 +682,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ * for remaining fragments will be updated when they are being sent * to low-level driver in ieee80211_tx(). */ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), - (tx->flags & IEEE80211_TX_FRAGMENTED) ? - tx->extra_frag[0]->len : 0); + tx->skb->next ? tx->skb->next->len : 0); hdr->duration_id = cpu_to_le16(dur); if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -748,17 +717,17 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ } if (tx->sta) { + struct sk_buff *skb; control->aid = tx->sta->aid; tx->sta->tx_packets++; - tx->sta->tx_fragments++; - tx->sta->tx_bytes += tx->skb->len; - if (tx->extra_frag) { - int i; - tx->sta->tx_fragments += tx->num_extra_frag; - for (i = 0; i < tx->num_extra_frag; i++) { - tx->sta->tx_bytes += - tx->extra_frag[i]->len; - } + skb = tx->skb; + if (!skb->next) { + tx->sta->tx_fragments++; + tx->sta->tx_bytes += skb->len; + } + while ((skb = skb->next)) { + tx->sta->tx_fragments++; + tx->sta->tx_bytes += skb->len; } } @@ -804,15 +773,12 @@ ieee80211_tx_h_load_stats(struct ieee802 load += hdrtime; /* TODO: optimise again */ - load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; + if (!skb->next) + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - load += 2 * hdrtime; - load += tx->extra_frag[i]->len * - rate->bitrate; - } + while ((skb = skb->next)) { + load += 2 * hdrtime; + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; } /* Divide channel_use by 8 to avoid wrapping around the counter */ @@ -870,7 +836,7 @@ __ieee80211_parse_tx_radiotap(struct iee sband = tx->local->hw.wiphy->bands[tx->channel->band]; control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - tx->flags |= IEEE80211_TX_INJECTED; + control->flags |= IEEE80211_TXCTL_INJECTED; tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* @@ -1075,63 +1041,123 @@ static int ieee80211_tx_prepare(struct i return 0; } +#ifdef DEBUG_PRINT_CONTROL_TX +static void print_control(struct ieee80211_tx_control *c, struct sk_buff *skb) +{ + printk(KERN_DEBUG "skb: %p (%d) fl: 0x%x / rates: %d,%d,%d / retr: %d / vif: %p / key: %p / band: %d / ant: %d / iv,icv: %d,%d / aid: %d, type: %d\n", + skb, skb->len, c->flags, c->tx_rate_idx, c->rts_cts_rate_idx, c->alt_retry_rate_idx, + c->retry_limit, c->vif, c->hw_key, c->band, c->antenna_sel_tx, c->iv_len, c->icv_len, c->aid, c->type); + print_hex_dump(KERN_DEBUG, "skb: ", DUMP_PREFIX_OFFSET, 32, 1, skb->data, skb->len, 1); +} +#else +static inline void +print_control(struct ieee80211_tx_control *c, struct sk_buff *skb) {} +#endif + +static int ___ieee80211_tx(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + int ret; + + if (unlikely(!skb)) + return NETDEV_TX_OK; + + print_control(control, skb); + + if (unlikely(netif_queue_stopped(local->mdev) || + __ieee80211_queue_stopped(local, control->queue))) + return NETDEV_TX_BUSY; + + ieee80211_dump_frame(wiphy_name(local->hw.wiphy), + "TX to low-level driver", skb); + ret = local->ops->tx(local_to_hw(local), skb, control); + if (ret) + return NETDEV_TX_BUSY; + + local->mdev->trans_start = jiffies; + ieee80211_led_tx(local, 1); + + return NETDEV_TX_OK; +} + static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_tx_data *tx) + struct ieee80211_tx_control *control) { - struct ieee80211_tx_control *control = tx->control; - int ret, i; + struct sk_buff *origskb = NULL, *next; + int unsetflags = 0, ret; - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); - return IEEE80211_TX_AGAIN; - } - if (skb) { - ieee80211_dump_frame(wiphy_name(local->hw.wiphy), - "TX to low-level driver", skb); - ret = local->ops->tx(local_to_hw(local), skb, control); - if (ret) - return IEEE80211_TX_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - } - if (tx->extra_frag) { - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_PS_FILT | - IEEE80211_TXCTL_FIRST_FRAGMENT); - for (i = 0; i < tx->num_extra_frag; i++) { - if (!tx->extra_frag[i]) - continue; - if (__ieee80211_queue_stopped(local, control->queue)) - return IEEE80211_TX_FRAG_AGAIN; - if (i == tx->num_extra_frag) { - control->tx_rate_idx = tx->last_frag_rate_idx; - - if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) - control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; - else - control->flags &= - ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + /* + * Send skb (or fragments if any.) + * + * Functionally, we could reject the frame here if it has segments + * and wait for the upper layer to hand us each of the fragments + * again, but in the common case we can simply enqueue all of the + * fragments to the hardware right away so optimise for that. + */ + + if (skb->next) { + origskb = skb; + skb = skb->next; + } + + while (1) { + control->flags &= ~unsetflags; + + /* Try to transmit this fragment */ + + next = skb->next; + /* + * skb->next must be NULL so the driver (or mac80211 in status + * handling) is able to put it onto a queue + */ + skb->next = NULL; + ret = ___ieee80211_tx(local, skb, control); + + /* + * If we return here, and the skb has fragments, then we're + * never going to see the skb itself (origskb) again since + * the generic xmit code will then just hand us the segments + * one by one. + */ + if (unlikely(ret != NETDEV_TX_OK)) { + /* important: restore skb->next on errors */ + skb->next = next; + BUG_ON(control->flags & IEEE80211_TXCTL_TXPD_PRESENT); + /* put control data into skb->cb for all fragments */ + while (skb) { + control->flags &= ~unsetflags; + memcpy(skb->cb, control, sizeof(*control)); + skb = skb->next; + unsetflags = IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT | + IEEE80211_TXCTL_CLEAR_PS_FILT | + IEEE80211_TXCTL_FIRST_FRAGMENT; } + return ret; + } - ieee80211_dump_frame(wiphy_name(local->hw.wiphy), - "TX to low-level driver", - tx->extra_frag[i]); - ret = local->ops->tx(local_to_hw(local), - tx->extra_frag[i], - control); - if (ret) - return IEEE80211_TX_FRAG_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - tx->extra_frag[i] = NULL; + /* successfully transmitted this (only) fragment */ + + unsetflags = IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT | + IEEE80211_TXCTL_CLEAR_PS_FILT | + IEEE80211_TXCTL_FIRST_FRAGMENT; + + /* remove this one from the segment list */ + skb = next; + if (origskb) + origskb->next = skb; + + /* all ok if this was the last */ + if (!skb) { + if (origskb) + kfree_skb(origskb); + return NETDEV_TX_OK; } - kfree(tx->extra_frag); - tx->extra_frag = NULL; } - return IEEE80211_TX_OK; + + return NETDEV_TX_OK; } static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, @@ -1139,12 +1165,11 @@ static int ieee80211_tx(struct net_devic { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; + struct sk_buff *frag; ieee80211_tx_handler *handler; struct ieee80211_tx_data tx; ieee80211_tx_result res = TX_DROP, res_prepare; - int ret, i; - - WARN_ON(__ieee80211_queue_pending(local, control->queue)); + int ret, num = 0; if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); @@ -1186,74 +1211,70 @@ static int ieee80211_tx(struct net_devic return 0; } - if (tx.extra_frag) { - for (i = 0; i < tx.num_extra_frag; i++) { - int next_len, dur; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) - tx.extra_frag[i]->data; - - if (i + 1 < tx.num_extra_frag) { - next_len = tx.extra_frag[i + 1]->len; - } else { - next_len = 0; - tx.rate_idx = tx.last_frag_rate_idx; - } - dur = ieee80211_duration(&tx, 0, next_len); - hdr->duration_id = cpu_to_le16(dur); + /* fragmented: update duration/seq/flags of fragments */ + frag = skb; + while ((frag = frag->next)) { + struct ieee80211_hdr *hdr = (void *)frag->data; + int next_len, dur; + __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); + + if (frag->next) { + hdr->frame_control |= morefrags; + next_len = frag->next->len; + } else { + hdr->frame_control &= ~morefrags; + next_len = 0; + tx.rate_idx = tx.last_frag_rate_idx; } + dur = ieee80211_duration(&tx, 0, next_len); + hdr->duration_id = cpu_to_le16(dur); + hdr->seq_ctrl |= cpu_to_le16(num & IEEE80211_SCTL_FRAG); + num++; } -retry: - ret = __ieee80211_tx(local, skb, &tx); - if (ret) { - struct ieee80211_tx_stored_packet *store = - &local->pending_packet[control->queue]; - - if (ret == IEEE80211_TX_FRAG_AGAIN) - skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer - * gets available in that window (i.e. driver calls - * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by - * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, control->queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - goto retry; - } - memcpy(&store->control, control, - sizeof(struct ieee80211_tx_control)); - store->skb = skb; - store->extra_frag = tx.extra_frag; - store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate_idx = tx.last_frag_rate_idx; - store->last_frag_rate_ctrl_probe = - !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); - } + ret = __ieee80211_tx(local, skb, tx.control); rcu_read_unlock(); - return 0; + return ret; drop: if (skb) dev_kfree_skb(skb); - for (i = 0; i < tx.num_extra_frag; i++) - if (tx.extra_frag[i]) - dev_kfree_skb(tx.extra_frag[i]); - kfree(tx.extra_frag); rcu_read_unlock(); return 0; } /* device xmit handlers */ +/* + * validate_control verifies that the control pointers are + * still valid after the requeue. If they are not then we'll + * simply drop the packet. + */ +static bool validate_control(struct ieee80211_local *local, + struct ieee80211_tx_control *ctl, + struct sk_buff *skb) +{ + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + struct ieee80211_key *key; + struct ieee80211_hdr *hdr = (void *)skb->data; + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (ctl->vif != &sdata->vif) + continue; + + sta = sta_info_get(local, ieee80211_get_DA(hdr)); + key = ieee80211_select_key(sdata, sta, ctl, + le16_to_cpu(hdr->frame_control)); + + if (!ctl->hw_key && !key) + return true; + return &key->conf == ctl->hw_key; + } + + return false; +} + int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1264,11 +1285,38 @@ int ieee80211_master_start_xmit(struct s int headroom; int ret; - /* - * copy control out of the skb so other people can use skb->cb - */ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(&control, 0, sizeof(struct ieee80211_tx_control)); + + if (!(pkt_data->flags & IEEE80211_TXPD_PRESENT)) { + /* + * Not a frame with pkt_data, it has tx_control instead! + * We set the TXPD_PRESENT bit in all tx_packet_data + * instances so we know that we got this frame from the + * subif and not because of fragment requeuing. This here + * is the fragment requeuing path (although it may also + * be entered if somebody injects a packet on the master + * interface... which will be dropped right away because + * it has no useful control data in skb->cb.) + */ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + rcu_read_lock(); + if (!validate_control(local, (void *)skb->cb, skb)) { + if (net_ratelimit()) + printk(KERN_DEBUG "dropped re-queued skb %p\n", skb); + dev_kfree_skb(skb); + rcu_read_unlock(); + return NETDEV_TX_OK; + } + memcpy(&control, skb->cb, sizeof(control)); + memset(skb->cb, 0, sizeof(skb->cb)); + ret = ___ieee80211_tx(local, skb, &control); + if (ret != NETDEV_TX_OK) + memcpy(skb->cb, &control, sizeof(control)); + rcu_read_unlock(); + return ret; + } + + memset(&control, 0, sizeof(control)); if (pkt_data->ifindex) odev = dev_get_by_index(&init_net, pkt_data->ifindex); @@ -1296,7 +1344,6 @@ int ieee80211_master_start_xmit(struct s } control.vif = &osdata->vif; - control.type = osdata->vif.type; if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) @@ -1309,6 +1356,7 @@ int ieee80211_master_start_xmit(struct s control.flags |= IEEE80211_TXCTL_AMPDU; control.queue = pkt_data->queue; + memset(skb->cb, 0, sizeof(skb->cb)); ret = ieee80211_tx(odev, skb, &control); dev_put(odev); @@ -1553,19 +1601,6 @@ int ieee80211_subif_start_xmit(struct sk nh_pos -= skip_header_bytes; h_pos -= skip_header_bytes; - /* TODO: implement support for fragments so that there is no need to - * reallocate and copy payload; it might be enough to support one - * extra fragment that would be copied in the beginning of the frame - * data.. anyway, it would be nice to include this into skb structure - * somehow - * - * There are few options for this: - * use skb->cb as an extra space for 802.11 header - * allocate new buffer if not enough headroom - * make sure that there is enough headroom in every skb by increasing - * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and - * alloc_skb() (net/core/skbuff.c) - */ head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; head_need -= skb_headroom(skb); @@ -1625,6 +1660,7 @@ int ieee80211_subif_start_xmit(struct sk pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = dev->ifindex; + pkt_data->flags = IEEE80211_TXPD_PRESENT; if (ethertype == ETH_P_PAE) pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; @@ -1651,69 +1687,6 @@ int ieee80211_subif_start_xmit(struct sk return ret; } -/* helper functions for pending packets for when queues are stopped */ - -void ieee80211_clear_tx_pending(struct ieee80211_local *local) -{ - int i, j; - struct ieee80211_tx_stored_packet *store; - - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) - continue; - store = &local->pending_packet[i]; - kfree_skb(store->skb); - for (j = 0; j < store->num_extra_frag; j++) - kfree_skb(store->extra_frag[j]); - kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); - } -} - -void ieee80211_tx_pending(unsigned long data) -{ - struct ieee80211_local *local = (struct ieee80211_local *)data; - struct net_device *dev = local->mdev; - struct ieee80211_tx_stored_packet *store; - struct ieee80211_tx_data tx; - int i, ret, reschedule = 0; - - netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) - continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; - continue; - } - store = &local->pending_packet[i]; - tx.control = &store->control; - tx.extra_frag = store->extra_frag; - tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate_idx = store->last_frag_rate_idx; - tx.flags = 0; - if (store->last_frag_rate_ctrl_probe) - tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; - ret = __ieee80211_tx(local, store->skb, &tx); - if (ret) { - if (ret == IEEE80211_TX_FRAG_AGAIN) - store->skb = NULL; - } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; - } - } - netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } -} - /* functions for drivers to get certain frames */ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, --- everything.orig/net/mac80211/wep.c 2008-04-30 03:44:52.000000000 +0200 +++ everything/net/mac80211/wep.c 2008-04-30 03:46:39.000000000 +0200 @@ -349,23 +349,29 @@ static int wep_encrypt_skb(struct ieee80 ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) { + struct sk_buff *skb; + tx->control->iv_len = WEP_IV_LEN; tx->control->icv_len = WEP_ICV_LEN; ieee80211_tx_set_protected(tx); - if (wep_encrypt_skb(tx, tx->skb) < 0) { - I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); - return TX_DROP; + /* not fragmented */ + if (!tx->skb->next) { + if (wep_encrypt_skb(tx, tx->skb) < 0) { + I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); + return TX_DROP; + } + return TX_CONTINUE; } - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) { - I802_DEBUG_INC(tx->local-> - tx_handlers_drop_wep); - return TX_DROP; - } + /* fragmented, encrypt fragments */ + + skb = tx->skb; + /* tx->skb is the non-fragmented one */ + while ((skb = skb->next)) { + if (wep_encrypt_skb(tx, skb) < 0) { + I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); + return TX_DROP; } } --- everything.orig/net/mac80211/wpa.c 2008-04-30 03:44:52.000000000 +0200 +++ everything/net/mac80211/wpa.c 2008-04-30 03:46:39.000000000 +0200 @@ -260,16 +260,19 @@ ieee80211_crypto_tkip_encrypt(struct iee return TX_CONTINUE; } - if (tkip_encrypt_skb(tx, skb, test) < 0) - return TX_DROP; + /* not fragmented */ + if (!skb->next) { + if (tkip_encrypt_skb(tx, skb, test) < 0) + return TX_DROP; + return TX_CONTINUE; + } - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) - return TX_DROP; - } + /* fragmented, encrypt fragments */ + + /* tx->skb is the non-fragmented one */ + while ((skb = skb->next)) { + if (tkip_encrypt_skb(tx, skb, test) < 0) + return TX_DROP; } return TX_CONTINUE; @@ -509,16 +512,23 @@ ieee80211_crypto_ccmp_encrypt(struct iee return TX_CONTINUE; } - if (ccmp_encrypt_skb(tx, skb, test) < 0) - return TX_DROP; + tx->control->iv_len = WEP_IV_LEN; + tx->control->icv_len = WEP_ICV_LEN; + ieee80211_tx_set_protected(tx); + + /* not fragmented */ + if (!skb->next) { + if (ccmp_encrypt_skb(tx, skb, test) < 0) + return TX_DROP; + return TX_CONTINUE; + } + + /* fragmented, encrypt fragments */ - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) - return TX_DROP; - } + /* tx->skb is the non-fragmented one */ + while ((skb = skb->next)) { + if (ccmp_encrypt_skb(tx, skb, test) < 0) + return TX_DROP; } return TX_CONTINUE; --- everything.orig/net/mac80211/util.c 2008-04-30 03:44:52.000000000 +0200 +++ everything/net/mac80211/util.c 2008-04-30 13:37:40.000000000 +0200 @@ -167,17 +167,13 @@ int ieee80211_get_mesh_hdrlen(struct iee void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + struct sk_buff *skb = tx->skb; + struct ieee80211_hdr *hdr; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - if (tx->extra_frag) { - struct ieee80211_hdr *fhdr; - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - fhdr = (struct ieee80211_hdr *) - tx->extra_frag[i]->data; - fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - } + while (skb) { + hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + skb = skb->next; } } @@ -333,15 +329,11 @@ void ieee80211_wake_queue(struct ieee802 if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); + if (!ieee80211_qdisc_installed(local->mdev)) { + if (queue == 0) + netif_wake_queue(local->mdev); + } else + __netif_schedule(local->mdev); } } EXPORT_SYMBOL(ieee80211_wake_queue); --- everything.orig/net/mac80211/wme.c 2008-04-30 03:44:52.000000000 +0200 +++ everything/net/mac80211/wme.c 2008-04-30 13:40:09.000000000 +0200 @@ -236,9 +236,6 @@ static int wme_qdiscop_enqueue(struct sk } -/* TODO: clean up the cases where master_hard_start_xmit - * returns non 0 - it shouldn't ever do that. Once done we - * can remove this function */ static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); @@ -247,7 +244,7 @@ static int wme_qdiscop_requeue(struct sk struct Qdisc *qdisc; int err; - /* we recorded which queue to use earlier! */ + /* We recorded which queue to use earlier. */ qdisc = q->queues[pkt_data->queue]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { @@ -274,9 +271,7 @@ static struct sk_buff *wme_qdiscop_deque /* see if there is room in this hardware queue */ if ((test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue])) || - (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) + (!test_bit(queue, q->qdisc_pool))) continue; /* there is space - try and get a frame */ --- everything.orig/net/mac80211/main.c 2008-04-30 03:44:52.000000000 +0200 +++ everything/net/mac80211/main.c 2008-04-30 13:40:19.000000000 +0200 @@ -408,7 +408,6 @@ static int ieee80211_open(struct net_dev WARN_ON(res); if (res) goto err_del_interface; - tasklet_enable(&local->tx_pending_tasklet); tasklet_enable(&local->tasklet); } @@ -602,7 +601,6 @@ static int ieee80211_stop(struct net_dev ieee80211_led_radio(local, 0); - tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); } @@ -1204,8 +1202,16 @@ void ieee80211_tx_status_irqsafe(struct struct ieee80211_tx_status *saved; int tmp; + if (WARN_ON(!skb)) + return; + + if (WARN_ON(!status)) { + dev_kfree_skb(skb); + return; + } + skb->dev = local->mdev; - saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC); + saved = kmemdup(status, sizeof(struct ieee80211_tx_status), GFP_ATOMIC); if (unlikely(!saved)) { if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " @@ -1216,7 +1222,6 @@ void ieee80211_tx_status_irqsafe(struct dev_kfree_skb_any(skb); return; } - memcpy(saved, status, sizeof(struct ieee80211_tx_status)); /* copy pointer to saved status into skb->cb for use by tasklet */ memcpy(skb->cb, &saved, sizeof(saved)); @@ -1299,7 +1304,7 @@ static void ieee80211_remove_tx_extra(st pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex; - pkt_data->flags = 0; + pkt_data->flags = IEEE80211_TXPD_PRESENT; if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) @@ -1435,10 +1440,10 @@ void ieee80211_tx_status(struct ieee8021 struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - if (!status) { - printk(KERN_ERR - "%s: ieee80211_tx_status called with NULL status\n", - wiphy_name(local->hw.wiphy)); + if (WARN_ON(!skb)) + return; + + if (WARN_ON(!status)) { dev_kfree_skb(skb); return; } @@ -1665,10 +1670,6 @@ struct ieee80211_hw *ieee80211_alloc_hw( sta_info_init(local); - tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, - (unsigned long)local); - tasklet_disable(&local->tx_pending_tasklet); - tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); @@ -1852,7 +1853,6 @@ void ieee80211_unregister_hw(struct ieee struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; - tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); rtnl_lock(); @@ -1886,7 +1886,6 @@ void ieee80211_unregister_hw(struct ieee rtnl_unlock(); ieee80211_rx_bss_list_deinit(local->mdev); - ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); debugfs_hw_del(local); @@ -1921,6 +1920,10 @@ static int __init ieee80211_init(void) int ret; BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); + BUILD_BUG_ON(sizeof(struct ieee80211_tx_control) > sizeof(skb->cb)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_control, flags) != 0); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_packet_data, flags) != 0); + BUILD_BUG_ON(IEEE80211_TXPD_PRESENT != IEEE80211_TXCTL_TXPD_PRESENT); ret = rc80211_pid_init(); if (ret) --- everything.orig/include/net/mac80211.h 2008-04-30 03:44:52.000000000 +0200 +++ everything/include/net/mac80211.h 2008-04-30 13:37:40.000000000 +0200 @@ -3,7 +3,7 @@ * * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> - * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -233,6 +233,8 @@ struct ieee80211_bss_conf { * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval + * @IEEE80211_TXCTL_TXPD_PRESENT: Reserved, must never be set. + * @IEEE80211_TXCTL_INJECTED: Frame was injected (NOT for driver use!) */ enum mac80211_tx_control_flags { IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0), @@ -254,6 +256,8 @@ enum mac80211_tx_control_flags { IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16), IEEE80211_TXCTL_DUP_DATA = (1<<17), IEEE80211_TXCTL_SHORT_GI = (1<<18), + IEEE80211_TXCTL_TXPD_PRESENT = (1<<19), + IEEE80211_TXCTL_INJECTED = (1<<20), }; /* Transmit control fields. This data structure is passed to low-level driver @@ -278,6 +282,9 @@ struct ieee80211_tx_control { * This could be used when set_retry_limit * is not implemented by the driver */ + u16 queue; /* hardware queue to use for this frame; + * 0 = highest, hw->queues-1 = lowest */ + struct ieee80211_vif *vif; /* Key used for hardware encryption @@ -290,8 +297,6 @@ struct ieee80211_tx_control { * position represents antenna number used */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ - u16 queue; /* hardware queue to use for this frame; - * 0 = highest, hw->queues-1 = lowest */ u16 aid; /* Station AID */ int type; /* internal */ }; --- everything.orig/net/mac80211/mlme.c 2008-04-30 03:44:49.000000000 +0200 +++ everything/net/mac80211/mlme.c 2008-04-30 13:37:38.000000000 +0200 @@ -587,6 +587,7 @@ void ieee80211_sta_tx(struct net_device pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; + pkt_data->flags = IEEE80211_TXPD_PRESENT; if (!encrypt) pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; -- ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC/RFT 3/4] mac80211: use GSO for fragmentation 2008-04-30 12:40 ` [RFC/RFT 3/4] mac80211: use GSO for fragmentation Johannes Berg @ 2008-05-07 7:10 ` Herbert Xu 2008-05-07 8:50 ` Johannes Berg 0 siblings, 1 reply; 41+ messages in thread From: Herbert Xu @ 2008-05-07 7:10 UTC (permalink / raw) To: Johannes Berg Cc: linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Wed, Apr 30, 2008 at 02:40:58PM +0200, Johannes Berg wrote: > This patch makes mac80211 use the GSO infrastructure for segmentation, > but not really all of it because we do not register a protocol handler > (nor can do that easily since a lot of functions need to be done before > segmentation and another bunch afterwards, and we need to keep rcu- > protected structures for both.) Your idea of using skb_segment to remove duplicate code is great. However, using skb->gso_skb for the push-back doesn't work. For example, what is going to happen when I enable software GSO on a wireless device and then send a real GSO packet to it where each GSO fragment also required wireless fragmentation? I suggest that you just use skb_segment for the actual fragmentation but keep the original infrastructure for handling the fragments. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC/RFT 3/4] mac80211: use GSO for fragmentation 2008-05-07 7:10 ` Herbert Xu @ 2008-05-07 8:50 ` Johannes Berg 2008-05-07 9:00 ` Herbert Xu 0 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-05-07 8:50 UTC (permalink / raw) To: Herbert Xu Cc: linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr [-- Attachment #1: Type: text/plain, Size: 2147 bytes --] On Wed, 2008-05-07 at 15:10 +0800, Herbert Xu wrote: > On Wed, Apr 30, 2008 at 02:40:58PM +0200, Johannes Berg wrote: > > This patch makes mac80211 use the GSO infrastructure for segmentation, > > but not really all of it because we do not register a protocol handler > > (nor can do that easily since a lot of functions need to be done before > > segmentation and another bunch afterwards, and we need to keep rcu- > > protected structures for both.) > > Your idea of using skb_segment to remove duplicate code is great. > > However, using skb->gso_skb for the push-back doesn't work. For > example, what is going to happen when I enable software GSO on a > wireless device and then send a real GSO packet to it where each > GSO fragment also required wireless fragmentation? Good point. Somehow I thought this couldn't happen but of course it can since we don't do hw GSO. > I suggest that you just use skb_segment for the actual fragmentation > but keep the original infrastructure for handling the fragments. But I want to get rid of that much more than I want to get rid of the fragmentation code :/ Also, if I need to keep that code, I will absolutely not use skb_segment either as it's more efficient to just trim the existing skb to make the first segment out of it (like the code does now) rather than reallocate that too. However, I'm sure it's buggy under certain circumstances we never understood (as indicated by a WARN_ON triggering that shouldn't and lots of reports about that) and I don't like the extra tasklet. I guess I could remove it and copy the existing code into the wireless qdisc, but that would be weird. But you're right, it doesn't work this way. I'll have to think of something. Maybe I can rip out all the retry logic and just store an skb myself (like dev->gso_skb) and return NETDEV_TX_BUSY when I used that one and the queue got full because of it. That'll requeue a lot when non-gso skbs are coming in, but mind you this is not a common case, most of the time fragmentation will not be enabled and even when it is device queues should be long enough. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC/RFT 3/4] mac80211: use GSO for fragmentation 2008-05-07 8:50 ` Johannes Berg @ 2008-05-07 9:00 ` Herbert Xu [not found] ` <20080507090040.GA25186-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> 0 siblings, 1 reply; 41+ messages in thread From: Herbert Xu @ 2008-05-07 9:00 UTC (permalink / raw) To: Johannes Berg Cc: linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Wed, May 07, 2008 at 10:50:17AM +0200, Johannes Berg wrote: > > But you're right, it doesn't work this way. I'll have to think of > something. Maybe I can rip out all the retry logic and just store an skb > myself (like dev->gso_skb) and return NETDEV_TX_BUSY when I used that > one and the queue got full because of it. That'll requeue a lot when > non-gso skbs are coming in, but mind you this is not a common case, most > of the time fragmentation will not be enabled and even when it is device > queues should be long enough. Yes keeping your own gso_skb sounds like a good solution. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080507090040.GA25186-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>]
* [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080507090040.GA25186-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> @ 2008-05-07 11:22 ` Johannes Berg [not found] ` <1210159339.5642.13.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> 0 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-05-07 11:22 UTC (permalink / raw) To: Herbert Xu Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr This patch rewrites mac80211's fragmentation handling to (a) use skb_segment (b) get rid of the tasklet etc. and just push responsibility to the qdisc/core code This can result in excessive requeues when the device only accepts a fragment at a time or so then we'll always ask the generic code to try again but then won't accept the skb. However, devices that only accept a single skb at a time won't get good performance anyhow so it doesn't matter. Signed-off-by: Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> --- John, this has no more dependencies on other patches except ones I submitted earlier, please merge unless somebody objects. include/net/mac80211.h | 10 net/mac80211/ieee80211_i.h | 32 -- net/mac80211/main.c | 46 ++- net/mac80211/tx.c | 629 ++++++++++++++++++++++----------------------- net/mac80211/util.c | 30 -- net/mac80211/wep.c | 26 - net/mac80211/wme.c | 9 net/mac80211/wpa.c | 44 +-- 8 files changed, 395 insertions(+), 431 deletions(-) --- everything.orig/net/mac80211/ieee80211_i.h 2008-05-07 11:13:00.000000000 +0200 +++ everything/net/mac80211/ieee80211_i.h 2008-05-07 11:49:11.000000000 +0200 @@ -147,7 +147,6 @@ typedef unsigned __bitwise__ ieee80211_t #define IEEE80211_TX_UNICAST BIT(1) #define IEEE80211_TX_PS_BUFFERED BIT(2) #define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) -#define IEEE80211_TX_INJECTED BIT(4) struct ieee80211_tx_data { struct sk_buff *skb; @@ -165,11 +164,6 @@ struct ieee80211_tx_data { * when using CTS protection with IEEE 802.11g. */ s8 last_frag_rate_idx; - /* Extra fragments (in addition to the first fragment - * in skb) */ - struct sk_buff **extra_frag; - int num_extra_frag; - u16 fc, ethertype; unsigned int flags; }; @@ -215,19 +209,10 @@ struct ieee80211_rx_data { #define IEEE80211_TXPD_AMPDU BIT(4) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { + u32 flags; int ifindex; + u16 queue; unsigned long jiffies; - unsigned int flags; - u8 queue; -}; - -struct ieee80211_tx_stored_packet { - struct ieee80211_tx_control control; - struct sk_buff *skb; - struct sk_buff **extra_frag; - s8 last_frag_rate_idx; - int num_extra_frag; - bool last_frag_rate_ctrl_probe; }; struct beacon_data { @@ -612,8 +597,7 @@ struct ieee80211_local { struct timer_list sta_cleanup; unsigned long state[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; - struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; - struct tasklet_struct tx_pending_tasklet; + struct sk_buff *pending_packet[IEEE80211_MAX_QUEUES]; /* number of interfaces with corresponding IFF_ flags */ atomic_t iff_allmultis, iff_promiscs; @@ -846,7 +830,6 @@ static inline struct ieee80211_hw *local enum ieee80211_link_state_t { IEEE80211_LINK_STATE_XOFF = 0, - IEEE80211_LINK_STATE_PENDING, }; struct sta_attribute { @@ -866,7 +849,6 @@ static inline int ieee80211_bssid_match( int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_if_setup(struct net_device *dev); u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_info *req_ht_cap, @@ -967,8 +949,6 @@ void ieee80211_if_free(struct net_device void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); /* tx handling */ -void ieee80211_clear_tx_pending(struct ieee80211_local *local); -void ieee80211_tx_pending(unsigned long data); int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -984,4 +964,10 @@ int ieee80211_frame_duration(struct ieee void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, struct ieee80211_hdr *hdr); +static inline void ieee80211_skb_set_protected(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); +} + #endif /* IEEE80211_I_H */ --- everything.orig/net/mac80211/tx.c 2008-05-07 11:13:00.000000000 +0200 +++ everything/net/mac80211/tx.c 2008-05-07 13:02:02.000000000 +0200 @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc <jbenc-AlSwsSmVLrQ@public.gmane.org> - * Copyright 2007 Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> + * Copyright 2007-2008 Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -32,9 +32,6 @@ #include "wme.h" #include "rate.h" -#define IEEE80211_TX_OK 0 -#define IEEE80211_TX_AGAIN 1 -#define IEEE80211_TX_FRAG_AGAIN 2 /* misc utils */ @@ -219,12 +216,6 @@ static inline int __ieee80211_queue_stop return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); } -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); -} - static int inline is_ieee80211_device(struct net_device *dev, struct net_device *master) { @@ -243,7 +234,7 @@ ieee80211_tx_h_check_assoc(struct ieee80 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ u32 sta_flags; - if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) + if (unlikely(tx->control->flags & IEEE80211_TXCTL_INJECTED)) return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && @@ -457,46 +448,66 @@ ieee80211_tx_h_ps_buf(struct ieee80211_t return ieee80211_tx_h_multicast_ps_buf(tx); } +static struct ieee80211_key * +ieee80211_select_key(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + struct ieee80211_tx_control *control, + u16 fc) +{ + struct ieee80211_key *key, *result; + u16 ftype, stype; + + if (unlikely(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + result = NULL; + else if (sta && (key = rcu_dereference(sta->key))) + result = key; + else if ((key = rcu_dereference(sdata->default_key))) + result = key; + else + result = NULL; + + if (!result) + return NULL; + + switch (result->conf.alg) { + case ALG_WEP: + ftype = fc & IEEE80211_FCTL_FTYPE; + stype = fc & IEEE80211_FCTL_STYPE; + + if (ftype == IEEE80211_FTYPE_MGMT && + stype == IEEE80211_STYPE_AUTH) + break; + case ALG_TKIP: + case ALG_CCMP: + if (!WLAN_FC_DATA_PRESENT(fc)) + result = NULL; + break; + } + + return result; +} + static ieee80211_tx_result ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { - struct ieee80211_key *key; u16 fc = tx->fc; if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - tx->key = NULL; - else if (tx->sta && (key = rcu_dereference(tx->sta->key))) - tx->key = key; - else if ((key = rcu_dereference(tx->sdata->default_key))) - tx->key = key; - else if (tx->sdata->drop_unencrypted && - !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && - !(tx->flags & IEEE80211_TX_INJECTED)) { + return TX_CONTINUE; + + tx->key = ieee80211_select_key(tx->sdata, tx->sta, tx->control, fc); + + if (!tx->key && + tx->sdata->drop_unencrypted && + !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && + !(tx->control->flags & IEEE80211_TXCTL_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; - } else - tx->key = NULL; + } if (tx->key) { - u16 ftype, stype; - tx->key->tx_rx_count++; /* TODO: add threshold stuff again */ - - switch (tx->key->conf.alg) { - case ALG_WEP: - ftype = fc & IEEE80211_FCTL_FTYPE; - stype = fc & IEEE80211_FCTL_STYPE; - - if (ftype == IEEE80211_FTYPE_MGMT && - stype == IEEE80211_STYPE_AUTH) - break; - case ALG_TKIP: - case ALG_CCMP: - if (!WLAN_FC_DATA_PRESENT(fc)) - tx->key = NULL; - break; - } } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) @@ -508,81 +519,69 @@ ieee80211_tx_h_select_key(struct ieee802 static ieee80211_tx_result ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - size_t hdrlen, per_fragm, num_fragm, payload_len, left; - struct sk_buff **frags, *first, *frag; - int i; - u16 seq; - u8 *pos; int frag_threshold = tx->local->fragmentation_threshold; + int hdrlen, payload_len, per_fragm, num_fragm; + struct sk_buff *skb = tx->skb, *frags; + int fragnum = 0; if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) return TX_CONTINUE; - first = tx->skb; + if (WARN_ON(tx->control->flags & IEEE80211_TXCTL_AMPDU || + tx->control->queue >= tx->local->hw.queues)) + return TX_DROP; hdrlen = ieee80211_get_hdrlen(tx->fc); - payload_len = first->len - hdrlen; + payload_len = skb->len - hdrlen; per_fragm = frag_threshold - hdrlen - FCS_LEN; num_fragm = DIV_ROUND_UP(payload_len, per_fragm); - frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); - if (!frags) - goto fail; + if (WARN_ON(num_fragm <= 1)) + return TX_DROP; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); - seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; - pos = first->data + hdrlen + per_fragm; - left = payload_len - per_fragm; - for (i = 0; i < num_fragm - 1; i++) { - struct ieee80211_hdr *fhdr; - size_t copylen; + /* skb_segment will push the mac header back in */ + skb_reset_mac_header(skb); + __skb_pull(skb, hdrlen); - if (left <= 0) - goto fail; + skb_shinfo(skb)->gso_size = per_fragm; + skb_shinfo(skb)->nr_frags = 0; - /* reserve enough extra head and tail room for possible - * encryption */ - frag = frags[i] = - dev_alloc_skb(tx->local->tx_headroom + - frag_threshold + - IEEE80211_ENCRYPT_HEADROOM + - IEEE80211_ENCRYPT_TAILROOM); - if (!frag) - goto fail; - /* Make sure that all fragments use the same priority so - * that they end up using the same TX queue */ - frag->priority = first->priority; - skb_reserve(frag, tx->local->tx_headroom + - IEEE80211_ENCRYPT_HEADROOM); - fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); - memcpy(fhdr, first->data, hdrlen); - if (i == num_fragm - 2) - fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); - fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); - copylen = left > per_fragm ? per_fragm : left; - memcpy(skb_put(frag, copylen), pos, copylen); + /* + * Now segment (fragment) the frame. This will allocate all the + * segments, we then assign them to the tx->skb->next pointer. + * During transmission, we will remove the successfully transmitted + * fragments from this list. Iff the low-level driver rejects one + * of the fragments then we will simply pretend to accept the skb + * but store it away in our fragment list and use it preferentially + * when the next skb comes in. + */ + frags = skb_segment(skb, 0); + if (IS_ERR(frags)) + return TX_DROP; - pos += copylen; - left -= copylen; - } - skb_trim(first, hdrlen + per_fragm); + skb->next = frags; - tx->num_extra_frag = num_fragm - 1; - tx->extra_frag = frags; + /* update duration/seq/flags of fragments, not on original */ + while ((skb = skb->next)) { + struct ieee80211_hdr *hdr = (void *)skb->data; + int next_len, dur; + __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); + + if (skb->next) { + hdr->frame_control |= morefrags; + next_len = skb->next->len; + } else { + hdr->frame_control &= ~morefrags; + next_len = 0; + tx->rate_idx = tx->last_frag_rate_idx; + } + dur = ieee80211_duration(tx, 0, next_len); + hdr->duration_id = cpu_to_le16(dur); + hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); + fragnum++; + } return TX_CONTINUE; - - fail: - printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); - if (frags) { - for (i = 0; i < num_fragm - 1; i++) - if (frags[i]) - dev_kfree_skb(frags[i]); - kfree(frags); - } - I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TX_DROP; } static ieee80211_tx_result @@ -712,8 +711,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ * for remaining fragments will be updated when they are being sent * to low-level driver in ieee80211_tx(). */ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), - (tx->flags & IEEE80211_TX_FRAGMENTED) ? - tx->extra_frag[0]->len : 0); + tx->skb->next ? tx->skb->next->len : 0); hdr->duration_id = cpu_to_le16(dur); if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -748,18 +746,16 @@ ieee80211_tx_h_misc(struct ieee80211_tx_ } if (tx->sta) { + struct sk_buff *skb = tx->skb; + control->aid = tx->sta->aid; tx->sta->tx_packets++; - tx->sta->tx_fragments++; - tx->sta->tx_bytes += tx->skb->len; - if (tx->extra_frag) { - int i; - tx->sta->tx_fragments += tx->num_extra_frag; - for (i = 0; i < tx->num_extra_frag; i++) { - tx->sta->tx_bytes += - tx->extra_frag[i]->len; - } - } + if (skb->next) + skb = skb->next; + do { + tx->sta->tx_fragments++; + tx->sta->tx_bytes += skb->len; + } while ((skb = skb->next)); } return TX_CONTINUE; @@ -804,15 +800,12 @@ ieee80211_tx_h_load_stats(struct ieee802 load += hdrtime; /* TODO: optimise again */ - load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; + if (!skb->next) + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - load += 2 * hdrtime; - load += tx->extra_frag[i]->len * - rate->bitrate; - } + while ((skb = skb->next)) { + load += 2 * hdrtime; + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; } /* Divide channel_use by 8 to avoid wrapping around the counter */ @@ -870,7 +863,7 @@ __ieee80211_parse_tx_radiotap(struct iee sband = tx->local->hw.wiphy->bands[tx->channel->band]; control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - tx->flags |= IEEE80211_TX_INJECTED; + control->flags |= IEEE80211_TXCTL_INJECTED; tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* @@ -1074,63 +1067,106 @@ static int ieee80211_tx_prepare(struct i return 0; } +static int ___ieee80211_tx(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + int ret; + + if (unlikely(!skb)) + return NETDEV_TX_OK; + + if (unlikely(netif_queue_stopped(local->mdev) || + __ieee80211_queue_stopped(local, control->queue))) + return NETDEV_TX_BUSY; + + ieee80211_dump_frame(wiphy_name(local->hw.wiphy), + "TX to low-level driver", skb); + ret = local->ops->tx(local_to_hw(local), skb, control); + if (ret) + return NETDEV_TX_BUSY; + + local->mdev->trans_start = jiffies; + ieee80211_led_tx(local, 1); + + return NETDEV_TX_OK; +} + static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_tx_data *tx) + struct ieee80211_tx_control *control) { - struct ieee80211_tx_control *control = tx->control; - int ret, i; + struct sk_buff *origskb = NULL, *next; + int unsetflags = 0, ret; - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); - return IEEE80211_TX_AGAIN; - } - if (skb) { - ieee80211_dump_frame(wiphy_name(local->hw.wiphy), - "TX to low-level driver", skb); - ret = local->ops->tx(local_to_hw(local), skb, control); - if (ret) - return IEEE80211_TX_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - } - if (tx->extra_frag) { - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_PS_FILT | - IEEE80211_TXCTL_FIRST_FRAGMENT); - for (i = 0; i < tx->num_extra_frag; i++) { - if (!tx->extra_frag[i]) - continue; - if (__ieee80211_queue_stopped(local, control->queue)) - return IEEE80211_TX_FRAG_AGAIN; - if (i == tx->num_extra_frag) { - control->tx_rate_idx = tx->last_frag_rate_idx; - - if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) - control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; - else - control->flags &= - ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + /* + * Send skb (or fragments if any.) + */ + + if (skb->next) { + origskb = skb; + skb = skb->next; + } + + do { + control->flags &= ~unsetflags; + + /* Try to transmit this fragment */ + + next = skb->next; + /* + * skb->next must be NULL so the driver (or more likely + * mac80211 in status handling) is able to put it onto a + * queue. + */ + skb->next = NULL; + ret = ___ieee80211_tx(local, skb, control); + + if (unlikely(ret != NETDEV_TX_OK)) { + /* important: restore skb->next on errors */ + skb->next = next; + /* put control data into skb->cb for all fragments */ + while (skb) { + control->flags &= ~unsetflags; + memcpy(skb->cb, control, sizeof(*control)); + skb = skb->next; + unsetflags = IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT | + IEEE80211_TXCTL_CLEAR_PS_FILT | + IEEE80211_TXCTL_FIRST_FRAGMENT; } - ieee80211_dump_frame(wiphy_name(local->hw.wiphy), - "TX to low-level driver", - tx->extra_frag[i]); - ret = local->ops->tx(local_to_hw(local), - tx->extra_frag[i], - control); - if (ret) - return IEEE80211_TX_FRAG_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - tx->extra_frag[i] = NULL; + /* + * If this is not fragmented, simply reject it and have + * it requeued at the upper layer. + */ + if (!origskb) + return ret; + + BUG_ON(local->pending_packet[control->queue]); + local->pending_packet[control->queue] = origskb; + /* + * We stored it locally, pretend all is well, + * let's hope the driver turned off the queue. + */ + return NETDEV_TX_OK; } - kfree(tx->extra_frag); - tx->extra_frag = NULL; - } - return IEEE80211_TX_OK; + + /* successfully transmitted this (only) fragment */ + + unsetflags = IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT | + IEEE80211_TXCTL_CLEAR_PS_FILT | + IEEE80211_TXCTL_FIRST_FRAGMENT; + + /* remove this one from the segment list */ + skb = next; + if (origskb) + origskb->next = skb; + } while (skb); + + kfree_skb(origskb); + + return NETDEV_TX_OK; } static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, @@ -1141,13 +1177,11 @@ static int ieee80211_tx(struct net_devic ieee80211_tx_handler *handler; struct ieee80211_tx_data tx; ieee80211_tx_result res = TX_DROP, res_prepare; - int ret, i; - - WARN_ON(__ieee80211_queue_pending(local, control->queue)); + int ret; if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); - return 0; + return NETDEV_TX_OK; } rcu_read_lock(); @@ -1155,11 +1189,8 @@ static int ieee80211_tx(struct net_devic /* initialises tx */ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); - if (res_prepare == TX_DROP) { - dev_kfree_skb(skb); - rcu_read_unlock(); - return 0; - } + if (res_prepare == TX_DROP) + goto drop; sta = tx.sta; tx.channel = local->hw.conf.channel; @@ -1181,78 +1212,107 @@ static int ieee80211_tx(struct net_devic if (unlikely(res == TX_QUEUED)) { I802_DEBUG_INC(local->tx_handlers_queued); - rcu_read_unlock(); - return 0; + goto unlock; } - if (tx.extra_frag) { - for (i = 0; i < tx.num_extra_frag; i++) { - int next_len, dur; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) - tx.extra_frag[i]->data; - - if (i + 1 < tx.num_extra_frag) { - next_len = tx.extra_frag[i + 1]->len; - } else { - next_len = 0; - tx.rate_idx = tx.last_frag_rate_idx; - } - dur = ieee80211_duration(&tx, 0, next_len); - hdr->duration_id = cpu_to_le16(dur); - } - } - -retry: - ret = __ieee80211_tx(local, skb, &tx); - if (ret) { - struct ieee80211_tx_stored_packet *store = - &local->pending_packet[control->queue]; - - if (ret == IEEE80211_TX_FRAG_AGAIN) - skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer - * gets available in that window (i.e. driver calls - * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by - * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, control->queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - goto retry; - } - memcpy(&store->control, control, - sizeof(struct ieee80211_tx_control)); - store->skb = skb; - store->extra_frag = tx.extra_frag; - store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate_idx = tx.last_frag_rate_idx; - store->last_frag_rate_ctrl_probe = - !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); - } + ret = __ieee80211_tx(local, skb, tx.control); rcu_read_unlock(); - return 0; + return ret; drop: if (skb) dev_kfree_skb(skb); - for (i = 0; i < tx.num_extra_frag; i++) - if (tx.extra_frag[i]) - dev_kfree_skb(tx.extra_frag[i]); - kfree(tx.extra_frag); + unlock: rcu_read_unlock(); - return 0; + return NETDEV_TX_OK; } /* device xmit handlers */ +/* + * validate_control verifies that the control pointers are + * still valid after the requeue. If they are not then we'll + * simply drop the packet. + */ +static bool validate_control(struct ieee80211_local *local, + struct ieee80211_tx_control *ctl, + struct sk_buff *skb) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_key *key; + struct ieee80211_hdr *hdr = (void *)skb->data; + struct sta_info *sta; + u8 *da; + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (ctl->vif != &sdata->vif) + continue; + + da = ieee80211_get_DA(hdr); + if (!is_multicast_ether_addr(da)) + sta = sta_info_get(local, da); + + key = ieee80211_select_key(sdata, sta, ctl, + le16_to_cpu(hdr->frame_control)); + + if (!ctl->hw_key && !key) + return true; + return &key->conf == ctl->hw_key; + } + + return false; +} + +static int ieee80211_send_pending_fragments(struct ieee80211_local *local, + struct ieee80211_tx_control *ctl, + int queue) +{ + struct sk_buff *orig, *frag, *next; + int ret; + + orig = local->pending_packet[queue]; + + if (!orig) + return NETDEV_TX_OK; + + frag = orig->next; + + /* need RCU protection for key/vif pointers */ + rcu_read_lock(); + + do { + next = frag->next; + frag->next = NULL; + + /* The interface could have been removed, or the key, or ... */ + if (!validate_control(local, (void *)frag->cb, frag)) { + dev_kfree_skb(frag); + /* most likely we'll drop all others, but let's see */ + orig->next = frag = next; + continue; + } + memcpy(ctl, frag->cb, sizeof(*ctl)); + memset(frag->cb, 0, sizeof(frag->cb)); + ret = ___ieee80211_tx(local, frag, ctl); + if (ret != NETDEV_TX_OK) { + frag->next = next; + memcpy(frag->cb, ctl, sizeof(*ctl)); + rcu_read_unlock(); + return ret; + } + /* fragment sent fine, remove from list */ + orig->next = frag = next; + } while (next); + + rcu_read_unlock(); + + /* yay, all fragments queued to hw successfully */ + dev_kfree_skb(local->pending_packet[queue]); + local->pending_packet[queue] = NULL; + + return NETDEV_TX_OK; +} + int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1263,11 +1323,16 @@ int ieee80211_master_start_xmit(struct s int headroom; int ret; - /* - * copy control out of the skb so other people can use skb->cb - */ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(&control, 0, sizeof(struct ieee80211_tx_control)); + + ret = ieee80211_send_pending_fragments(wdev_priv(dev->ieee80211_ptr), + &control, pkt_data->queue); + + /* Not all pending fragments queued to hw so reject this skb */ + if (ret != NETDEV_TX_OK) + return ret; + + memset(&control, 0, sizeof(control)); if (pkt_data->ifindex) odev = dev_get_by_index(&init_net, pkt_data->ifindex); @@ -1290,12 +1355,11 @@ int ieee80211_master_start_xmit(struct s if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { dev_kfree_skb(skb); dev_put(odev); - return 0; + return NETDEV_TX_OK; } } control.vif = &osdata->vif; - control.type = osdata->vif.type; if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) @@ -1308,6 +1372,7 @@ int ieee80211_master_start_xmit(struct s control.flags |= IEEE80211_TXCTL_AMPDU; control.queue = pkt_data->queue; + memset(skb->cb, 0, sizeof(skb->cb)); ret = ieee80211_tx(odev, skb, &control); dev_put(odev); @@ -1552,19 +1617,6 @@ int ieee80211_subif_start_xmit(struct sk nh_pos -= skip_header_bytes; h_pos -= skip_header_bytes; - /* TODO: implement support for fragments so that there is no need to - * reallocate and copy payload; it might be enough to support one - * extra fragment that would be copied in the beginning of the frame - * data.. anyway, it would be nice to include this into skb structure - * somehow - * - * There are few options for this: - * use skb->cb as an extra space for 802.11 header - * allocate new buffer if not enough headroom - * make sure that there is enough headroom in every skb by increasing - * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and - * alloc_skb() (net/core/skbuff.c) - */ head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; head_need -= skb_headroom(skb); @@ -1650,69 +1702,6 @@ int ieee80211_subif_start_xmit(struct sk return ret; } -/* helper functions for pending packets for when queues are stopped */ - -void ieee80211_clear_tx_pending(struct ieee80211_local *local) -{ - int i, j; - struct ieee80211_tx_stored_packet *store; - - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) - continue; - store = &local->pending_packet[i]; - kfree_skb(store->skb); - for (j = 0; j < store->num_extra_frag; j++) - kfree_skb(store->extra_frag[j]); - kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); - } -} - -void ieee80211_tx_pending(unsigned long data) -{ - struct ieee80211_local *local = (struct ieee80211_local *)data; - struct net_device *dev = local->mdev; - struct ieee80211_tx_stored_packet *store; - struct ieee80211_tx_data tx; - int i, ret, reschedule = 0; - - netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) - continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; - continue; - } - store = &local->pending_packet[i]; - tx.control = &store->control; - tx.extra_frag = store->extra_frag; - tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate_idx = store->last_frag_rate_idx; - tx.flags = 0; - if (store->last_frag_rate_ctrl_probe) - tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; - ret = __ieee80211_tx(local, store->skb, &tx); - if (ret) { - if (ret == IEEE80211_TX_FRAG_AGAIN) - store->skb = NULL; - } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; - } - } - netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } -} - /* functions for drivers to get certain frames */ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, --- everything.orig/net/mac80211/wep.c 2008-05-07 11:09:12.000000000 +0200 +++ everything/net/mac80211/wep.c 2008-05-07 11:13:19.000000000 +0200 @@ -333,6 +333,8 @@ ieee80211_crypto_wep_decrypt(struct ieee static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { + ieee80211_skb_set_protected(skb); + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; @@ -349,25 +351,21 @@ static int wep_encrypt_skb(struct ieee80 ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) { + struct sk_buff *skb = tx->skb; + tx->control->iv_len = WEP_IV_LEN; tx->control->icv_len = WEP_ICV_LEN; - ieee80211_tx_set_protected(tx); - if (wep_encrypt_skb(tx, tx->skb) < 0) { + /* skip original if fragmented */ + if (skb->next) + skb = skb->next; + + do { + if (wep_encrypt_skb(tx, tx->skb) == 0) + continue; I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); return TX_DROP; - } - - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) { - I802_DEBUG_INC(tx->local-> - tx_handlers_drop_wep); - return TX_DROP; - } - } - } + } while ((skb = skb->next)); return TX_CONTINUE; } --- everything.orig/net/mac80211/wpa.c 2008-05-07 11:09:13.000000000 +0200 +++ everything/net/mac80211/wpa.c 2008-05-07 11:13:19.000000000 +0200 @@ -192,6 +192,8 @@ static int tkip_encrypt_skb(struct ieee8 u16 fc; u8 *pos; + ieee80211_skb_set_protected(skb); + fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; @@ -250,7 +252,6 @@ ieee80211_crypto_tkip_encrypt(struct iee tx->control->icv_len = TKIP_ICV_LEN; tx->control->iv_len = TKIP_IV_LEN; - ieee80211_tx_set_protected(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && @@ -260,17 +261,14 @@ ieee80211_crypto_tkip_encrypt(struct iee return TX_CONTINUE; } - if (tkip_encrypt_skb(tx, skb, test) < 0) - return TX_DROP; - - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) - return TX_DROP; - } - } + /* skip original if segmented */ + if (skb->next) + skb = skb->next; + + do { + if (tkip_encrypt_skb(tx, skb, test) < 0) + return TX_DROP; + } while ((skb = skb->next)); return TX_CONTINUE; } @@ -439,6 +437,8 @@ static int ccmp_encrypt_skb(struct ieee8 u8 *pos, *pn, *b_0, *aad, *scratch; int i; + ieee80211_skb_set_protected(skb); + scratch = key->u.ccmp.tx_crypto_buf; b_0 = scratch + 3 * AES_BLOCK_LEN; aad = scratch + 4 * AES_BLOCK_LEN; @@ -499,7 +499,6 @@ ieee80211_crypto_ccmp_encrypt(struct iee tx->control->icv_len = CCMP_MIC_LEN; tx->control->iv_len = CCMP_HDR_LEN; - ieee80211_tx_set_protected(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { @@ -509,17 +508,14 @@ ieee80211_crypto_ccmp_encrypt(struct iee return TX_CONTINUE; } - if (ccmp_encrypt_skb(tx, skb, test) < 0) - return TX_DROP; - - if (tx->extra_frag) { - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test) - < 0) - return TX_DROP; - } - } + /* skip original if fragmented */ + if (skb->next) + skb = skb->next; + + do { + if (ccmp_encrypt_skb(tx, skb, test) < 0) + return TX_DROP; + } while ((skb = skb->next)); return TX_CONTINUE; } --- everything.orig/net/mac80211/util.c 2008-05-07 11:13:00.000000000 +0200 +++ everything/net/mac80211/util.c 2008-05-07 11:13:19.000000000 +0200 @@ -165,22 +165,6 @@ int ieee80211_get_mesh_hdrlen(struct iee } } -void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - if (tx->extra_frag) { - struct ieee80211_hdr *fhdr; - int i; - for (i = 0; i < tx->num_extra_frag; i++) { - fhdr = (struct ieee80211_hdr *) - tx->extra_frag[i]->data; - fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - } - } -} - int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int rate, int erp, int short_preamble) { @@ -333,15 +317,11 @@ void ieee80211_wake_queue(struct ieee802 if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); + if (!ieee80211_qdisc_installed(local->mdev)) { + if (queue == 0) + netif_wake_queue(local->mdev); + } else + __netif_schedule(local->mdev); } } EXPORT_SYMBOL(ieee80211_wake_queue); --- everything.orig/net/mac80211/wme.c 2008-05-07 11:12:48.000000000 +0200 +++ everything/net/mac80211/wme.c 2008-05-07 11:13:19.000000000 +0200 @@ -235,9 +235,6 @@ static int wme_qdiscop_enqueue(struct sk } -/* TODO: clean up the cases where master_hard_start_xmit - * returns non 0 - it shouldn't ever do that. Once done we - * can remove this function */ static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); @@ -246,7 +243,7 @@ static int wme_qdiscop_requeue(struct sk struct Qdisc *qdisc; int err; - /* we recorded which queue to use earlier! */ + /* We recorded which queue to use earlier. */ qdisc = q->queues[pkt_data->queue]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { @@ -273,9 +270,7 @@ static struct sk_buff *wme_qdiscop_deque /* see if there is room in this hardware queue */ if ((test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue])) || - (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) + (!test_bit(queue, q->qdisc_pool))) continue; /* there is space - try and get a frame */ --- everything.orig/net/mac80211/main.c 2008-05-07 11:12:57.000000000 +0200 +++ everything/net/mac80211/main.c 2008-05-07 12:43:17.000000000 +0200 @@ -408,7 +408,6 @@ static int ieee80211_open(struct net_dev WARN_ON(res); if (res) goto err_del_interface; - tasklet_enable(&local->tx_pending_tasklet); tasklet_enable(&local->tasklet); } @@ -602,7 +601,6 @@ static int ieee80211_stop(struct net_dev ieee80211_led_radio(local, 0); - tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); } @@ -1204,8 +1202,16 @@ void ieee80211_tx_status_irqsafe(struct struct ieee80211_tx_status *saved; int tmp; + if (WARN_ON(!skb)) + return; + + if (WARN_ON(!status)) { + dev_kfree_skb(skb); + return; + } + skb->dev = local->mdev; - saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC); + saved = kmemdup(status, sizeof(struct ieee80211_tx_status), GFP_ATOMIC); if (unlikely(!saved)) { if (net_ratelimit()) printk(KERN_WARNING "%s: Not enough memory, " @@ -1216,7 +1222,6 @@ void ieee80211_tx_status_irqsafe(struct dev_kfree_skb_any(skb); return; } - memcpy(saved, status, sizeof(struct ieee80211_tx_status)); /* copy pointer to saved status into skb->cb for use by tasklet */ memcpy(skb->cb, &saved, sizeof(saved)); @@ -1435,10 +1440,10 @@ void ieee80211_tx_status(struct ieee8021 struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; - if (!status) { - printk(KERN_ERR - "%s: ieee80211_tx_status called with NULL status\n", - wiphy_name(local->hw.wiphy)); + if (WARN_ON(!skb)) + return; + + if (WARN_ON(!status)) { dev_kfree_skb(skb); return; } @@ -1665,10 +1670,6 @@ struct ieee80211_hw *ieee80211_alloc_hw( sta_info_init(local); - tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, - (unsigned long)local); - tasklet_disable(&local->tx_pending_tasklet); - tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); @@ -1851,8 +1852,8 @@ void ieee80211_unregister_hw(struct ieee { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; + int queue; - tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); rtnl_lock(); @@ -1886,7 +1887,6 @@ void ieee80211_unregister_hw(struct ieee rtnl_unlock(); ieee80211_rx_bss_list_deinit(local->mdev); - ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); debugfs_hw_del(local); @@ -1898,6 +1898,21 @@ void ieee80211_unregister_hw(struct ieee skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); + /* free possibly queued fragmented skbs */ + for (queue = 0; queue < hw->queues; queue++) { + struct sk_buff *skb = local->pending_packet[queue]; + struct sk_buff *frag; + if (!skb) + continue; + frag = skb->next; + while (frag) { + skb->next = frag->next; + dev_kfree_skb(frag); + frag = skb->next; + } + dev_kfree_skb(skb); + } + destroy_workqueue(local->hw.workqueue); wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); @@ -1921,6 +1936,9 @@ static int __init ieee80211_init(void) int ret; BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); + BUILD_BUG_ON(sizeof(struct ieee80211_tx_control) > sizeof(skb->cb)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_control, flags) != 0); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_packet_data, flags) != 0); ret = rc80211_pid_init(); if (ret) --- everything.orig/include/net/mac80211.h 2008-05-07 11:13:00.000000000 +0200 +++ everything/include/net/mac80211.h 2008-05-07 12:01:25.000000000 +0200 @@ -3,7 +3,7 @@ * * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc <jbenc-AlSwsSmVLrQ@public.gmane.org> - * Copyright 2007 Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> + * Copyright 2007-2008 Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -233,6 +233,7 @@ struct ieee80211_bss_conf { * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval + * @IEEE80211_TXCTL_INJECTED: Frame was injected (NOT for driver use!) */ enum mac80211_tx_control_flags { IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0), @@ -254,6 +255,7 @@ enum mac80211_tx_control_flags { IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16), IEEE80211_TXCTL_DUP_DATA = (1<<17), IEEE80211_TXCTL_SHORT_GI = (1<<18), + IEEE80211_TXCTL_INJECTED = (1<<19), }; /* Transmit control fields. This data structure is passed to low-level driver @@ -278,6 +280,9 @@ struct ieee80211_tx_control { * This could be used when set_retry_limit * is not implemented by the driver */ + u16 queue; /* hardware queue to use for this frame; + * 0 = highest, hw->queues-1 = lowest */ + struct ieee80211_vif *vif; /* Key used for hardware encryption @@ -290,10 +295,7 @@ struct ieee80211_tx_control { * position represents antenna number used */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ - u16 queue; /* hardware queue to use for this frame; - * 0 = highest, hw->queues-1 = lowest */ u16 aid; /* Station AID */ - int type; /* internal */ }; -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <1210159339.5642.13.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <1210159339.5642.13.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> @ 2008-05-07 11:41 ` Herbert Xu 2008-05-07 11:52 ` Johannes Berg 0 siblings, 1 reply; 41+ messages in thread From: Herbert Xu @ 2008-05-07 11:41 UTC (permalink / raw) To: Johannes Berg Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Wed, May 07, 2008 at 01:22:19PM +0200, Johannes Berg wrote: > > + if (unlikely(netif_queue_stopped(local->mdev) || > + __ieee80211_queue_stopped(local, control->queue))) > + return NETDEV_TX_BUSY; Returning busy should be avoided because not everything expects it. For example, this can cause tcpdump to see the same packet twice. Besides, I'm not sure if this will even work if you're fiddling with skb->next. Perhaps you can stash it in a pointer local to your device. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-07 11:41 ` Herbert Xu @ 2008-05-07 11:52 ` Johannes Berg [not found] ` <1210161133.5642.19.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> 0 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-05-07 11:52 UTC (permalink / raw) To: Herbert Xu Cc: linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr [-- Attachment #1: Type: text/plain, Size: 1132 bytes --] On Wed, 2008-05-07 at 19:41 +0800, Herbert Xu wrote: > On Wed, May 07, 2008 at 01:22:19PM +0200, Johannes Berg wrote: > > > > + if (unlikely(netif_queue_stopped(local->mdev) || > > + __ieee80211_queue_stopped(local, control->queue))) > > + return NETDEV_TX_BUSY; > > Returning busy should be avoided because not everything expects it. Hmm. Why does busy exist then? Historical accident? I really really don't want to keep all that logic that does "if device enables queue then first check if maybe we have pending packets and try to send them and then go back to the regular queues and see if ..." > Besides, I'm not sure if this will even work if you're fiddling > with skb->next. Perhaps you can stash it in a pointer local to > your device. You're looking at an internal helper function that is never called with skb->next assigned; if it returns BUSY for a fragmented skb then later in __ieee80211_tx() I will store the fragmented frame away and return OK. But if I really need to avoid returning busy I need to hook into all the queue management stuff which I'd like to avoid. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <1210161133.5642.19.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <1210161133.5642.19.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> @ 2008-05-07 13:05 ` Herbert Xu [not found] ` <20080507130548.GA26977-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> 0 siblings, 1 reply; 41+ messages in thread From: Herbert Xu @ 2008-05-07 13:05 UTC (permalink / raw) To: Johannes Berg Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Wed, May 07, 2008 at 01:52:13PM +0200, Johannes Berg wrote: > > Hmm. Why does busy exist then? Historical accident? I really really Yes it's historical baggage. These days the biggest users would be LLTX drivers which should all be converted to non-LLTX and drivers that don't keep track of queue status properly. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080507130548.GA26977-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080507130548.GA26977-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> @ 2008-05-07 13:48 ` Michael Buesch 2008-05-08 3:22 ` Herbert Xu 2008-05-07 19:19 ` Johannes Berg 1 sibling, 1 reply; 41+ messages in thread From: Michael Buesch @ 2008-05-07 13:48 UTC (permalink / raw) To: Herbert Xu Cc: Johannes Berg, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Wednesday 07 May 2008 15:05:48 Herbert Xu wrote: > On Wed, May 07, 2008 at 01:52:13PM +0200, Johannes Berg wrote: > > > > Hmm. Why does busy exist then? Historical accident? I really really > > Yes it's historical baggage. These days the biggest users would > be LLTX drivers which should all be converted to non-LLTX and > drivers that don't keep track of queue status properly. So there's no way to actually fail in a TX handler? Drivers are doomed to drop the packet, if they cannot handle it due to ring overflow? -- Greetings Michael. -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-07 13:48 ` Michael Buesch @ 2008-05-08 3:22 ` Herbert Xu [not found] ` <20080508032208.GA401-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> 2008-05-08 13:00 ` Michael Buesch 0 siblings, 2 replies; 41+ messages in thread From: Herbert Xu @ 2008-05-08 3:22 UTC (permalink / raw) To: Michael Buesch Cc: Johannes Berg, linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Wed, May 07, 2008 at 03:48:06PM +0200, Michael Buesch wrote: > > So there's no way to actually fail in a TX handler? Drivers > are doomed to drop the packet, if they cannot handle it due to > ring overflow? You're supposed to stop the queue before the ring overflows. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080508032208.GA401-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080508032208.GA401-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> @ 2008-05-08 3:26 ` David Miller [not found] ` <20080507.202606.242037993.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 0 siblings, 1 reply; 41+ messages in thread From: David Miller @ 2008-05-08 3:26 UTC (permalink / raw) To: herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q Cc: mb-fseUSCV1ubazQB+pC5nmwQ, johannes-cdvu00un1VgdHxzADdlk8Q, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, ron.rindjunsky-ral2JQCrhuEAvxtiuMwx3w, tomasw-Re5JQEeQqe8AvxtiuMwx3w, ivdoorn-Re5JQEeQqe8AvxtiuMwx3w, peter.p.waskiewicz.jr-ral2JQCrhuEAvxtiuMwx3w From: Herbert Xu <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> Date: Thu, 8 May 2008 11:22:08 +0800 > On Wed, May 07, 2008 at 03:48:06PM +0200, Michael Buesch wrote: > > > > So there's no way to actually fail in a TX handler? Drivers > > are doomed to drop the packet, if they cannot handle it due to > > ring overflow? > > You're supposed to stop the queue before the ring overflows. Right, and this is why drivers choose a TX wakeup threshold such that they can accept an arbitrarily sized TSO frame. For example, from drivers/net/tg3.c's ->hard_start_xmit(): if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) netif_wake_queue(tp->dev); } The driver is responsible for stopping the queue _before_ it enters a state where there is not enough space in the queue to accept a packet. This is why most drivers make the following kind of BUG check at the start of their ->hard_start_xmit() if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); /* This is a hard error, log it. */ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when " "queue awake!\n", dev->name); } return NETDEV_TX_BUSY; } -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080507.202606.242037993.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080507.202606.242037993.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> @ 2008-05-08 9:00 ` Johannes Berg 2008-05-16 2:01 ` Rusty Russell 1 sibling, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-05-08 9:00 UTC (permalink / raw) To: David Miller Cc: herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q, mb-fseUSCV1ubazQB+pC5nmwQ, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, ron.rindjunsky-ral2JQCrhuEAvxtiuMwx3w, tomasw-Re5JQEeQqe8AvxtiuMwx3w, ivdoorn-Re5JQEeQqe8AvxtiuMwx3w, peter.p.waskiewicz.jr-ral2JQCrhuEAvxtiuMwx3w [-- Attachment #1: Type: text/plain, Size: 1033 bytes --] On Wed, 2008-05-07 at 20:26 -0700, David Miller wrote: > > You're supposed to stop the queue before the ring overflows. > > Right, and this is why drivers choose a TX wakeup threshold such > that they can accept an arbitrarily sized TSO frame. > > For example, from drivers/net/tg3.c's ->hard_start_xmit(): > > if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) { > netif_stop_queue(dev); > if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)) > netif_wake_queue(tp->dev); > } > > The driver is responsible for stopping the queue _before_ it > enters a state where there is not enough space in the queue > to accept a packet. Yes yes yes I know :) It's just quite awkward to handle when your hard_start_xmit() actually increases the number of packets, you don't really know how deep the queue is etc. I'll add an assertion like that to mac80211 for the non-fragmented case and clean up the fragmented case to retry by itself without upper layer involvement after the tx->cb patch. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080507.202606.242037993.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 2008-05-08 9:00 ` Johannes Berg @ 2008-05-16 2:01 ` Rusty Russell 2008-05-16 3:28 ` Herbert Xu 2008-05-16 4:58 ` David Miller 1 sibling, 2 replies; 41+ messages in thread From: Rusty Russell @ 2008-05-16 2:01 UTC (permalink / raw) To: David Miller Cc: herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q, mb-fseUSCV1ubazQB+pC5nmwQ, johannes-cdvu00un1VgdHxzADdlk8Q, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, ron.rindjunsky-ral2JQCrhuEAvxtiuMwx3w, tomasw-Re5JQEeQqe8AvxtiuMwx3w, ivdoorn-Re5JQEeQqe8AvxtiuMwx3w, peter.p.waskiewicz.jr-ral2JQCrhuEAvxtiuMwx3w On Thursday 08 May 2008 13:26:06 David Miller wrote: > From: Herbert Xu <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> > Date: Thu, 8 May 2008 11:22:08 +0800 > > > On Wed, May 07, 2008 at 03:48:06PM +0200, Michael Buesch wrote: > > > So there's no way to actually fail in a TX handler? Drivers > > > are doomed to drop the packet, if they cannot handle it due to > > > ring overflow? > > > > You're supposed to stop the queue before the ring overflows. > > Right, and this is why drivers choose a TX wakeup threshold such > that they can accept an arbitrarily sized TSO frame. Dave, please allow me to ask a heretical question. Returning TX_BUSY has some appeal for virtio_net: is it fundamentally a flawed idea, or simply a matter of coding? Currently we have no virtio interface to ask how many descriptors are left; it's not clear that it's a fair question to ask, since for Xen it's depends on the actual buffers we're trying to put in the descirptors. Thanks, Rusty. -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-16 2:01 ` Rusty Russell @ 2008-05-16 3:28 ` Herbert Xu 2008-05-16 4:58 ` David Miller 1 sibling, 0 replies; 41+ messages in thread From: Herbert Xu @ 2008-05-16 3:28 UTC (permalink / raw) To: Rusty Russell Cc: David Miller, mb, johannes, linux-wireless, netdev, ron.rindjunsky, tomasw, ivdoorn, peter.p.waskiewicz.jr On Fri, May 16, 2008 at 12:01:48PM +1000, Rusty Russell wrote: > > Dave, please allow me to ask a heretical question. Returning TX_BUSY has some > appeal for virtio_net: is it fundamentally a flawed idea, or simply a matter > of coding? I don't think returning TX_BUSY is fundamentally flawed (unlike LLTX which is). However, until somebody (i.e., you :) writes the code to handle it properly, i.e., not making the requeued packet go through AF_PCAKET twice, it's something that shouldn't be encouraged. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-16 2:01 ` Rusty Russell 2008-05-16 3:28 ` Herbert Xu @ 2008-05-16 4:58 ` David Miller [not found] ` <20080515.215823.28841530.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 1 sibling, 1 reply; 41+ messages in thread From: David Miller @ 2008-05-16 4:58 UTC (permalink / raw) To: rusty Cc: herbert, mb, johannes, linux-wireless, netdev, ron.rindjunsky, tomasw, ivdoorn, peter.p.waskiewicz.jr From: Rusty Russell <rusty@rustcorp.com.au> Date: Fri, 16 May 2008 12:01:48 +1000 > Dave, please allow me to ask a heretical question. Returning > TX_BUSY has some appeal for virtio_net: is it fundamentally a flawed > idea, or simply a matter of coding? Allowing TX_BUSY adds a special case to the caller which we'd like to remove at some point. > Currently we have no virtio interface to ask how many descriptors are left; > it's not clear that it's a fair question to ask, since for Xen it's depends > on the actual buffers we're trying to put in the descirptors. Two things: 1) You can always make sure that you have enough space for a TSO frame, with arbitrary page boundaries and thus buffer chopping. It can even be estimated, and if violated by some corner case you can punt and drop. 2) You can queue inside of the driver one packet when you hit the limits unexpectedly, netif_stop_queue(), and return success. Spit this packet out right before waking the queue again. Really, there are no hard reasons to ever return TX_BUSY, it's always a bug. In fact, I want to move things more and more towards the driver queueing TX packets internally instead of the networking mid-layer. That will ahve benefits for things like TX multiqueue, we won't need any locking at all, nor have any knowledge about multiple queues at all, if the driver takes care of providing the buffer between what the kernel gives it and what the device can handle at the moment. ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080515.215823.28841530.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080515.215823.28841530.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> @ 2008-05-16 10:32 ` Rusty Russell [not found] ` <200805162032.48469.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org> ` (2 more replies) 0 siblings, 3 replies; 41+ messages in thread From: Rusty Russell @ 2008-05-16 10:32 UTC (permalink / raw) To: David Miller Cc: herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q, mb-fseUSCV1ubazQB+pC5nmwQ, johannes-cdvu00un1VgdHxzADdlk8Q, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, ron.rindjunsky-ral2JQCrhuEAvxtiuMwx3w, tomasw-Re5JQEeQqe8AvxtiuMwx3w, ivdoorn-Re5JQEeQqe8AvxtiuMwx3w, peter.p.waskiewicz.jr-ral2JQCrhuEAvxtiuMwx3w On Friday 16 May 2008 14:58:23 David Miller wrote: > From: Rusty Russell <rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org> > Date: Fri, 16 May 2008 12:01:48 +1000 > > > Dave, please allow me to ask a heretical question. Returning > > TX_BUSY has some appeal for virtio_net: is it fundamentally a flawed > > idea, or simply a matter of coding? > > Allowing TX_BUSY adds a special case to the caller which we'd > like to remove at some point. > > > Currently we have no virtio interface to ask how many descriptors are > > left; it's not clear that it's a fair question to ask, since for Xen it's > > depends on the actual buffers we're trying to put in the descirptors. > > Two things: > > 1) You can always make sure that you have enough space for a > TSO frame, with arbitrary page boundaries and thus buffer > chopping. > > It can even be estimated, and if violated by some corner case > you can punt and drop. Yes, this is what we'd have to do. Wasting room in the ring feels wrong though. > 2) You can queue inside of the driver one packet when you hit > the limits unexpectedly, netif_stop_queue(), and return > success. Spit this packet out right before waking the > queue again. I put a patch in to do exactly that at Herbert's prompting, for 2.6.26, but it's buggy in (at least) two ways. I have a fix for this, which adds a new tasklet to xmit the packet. There's still some subtle race, however, since I'm still seeing a stuck packet. I'll have to revert to TX_BUSY for 2.6.26 if I can't find it (unlikely). And I haven't measured what it does to performance (should be OK, but still). > Really, there are no hard reasons to ever return TX_BUSY, > it's always a bug. But it's *simple*, and seems like a common thing to want. Why not change everything to use TX_BUSY and rip out the guestimate/buffering hacks? > In fact, I want to move things more and more towards the driver > queueing TX packets internally instead of the networking mid-layer. > > That will ahve benefits for things like TX multiqueue, we won't > need any locking at all, nor have any knowledge about multiple > queues at all, if the driver takes care of providing the buffer > between what the kernel gives it and what the device can handle > at the moment. That would be great: then I could shove the packet back on the queue myself and not have to ask you about it. It's adding a *second* queue inside the driver which feels terribly ugly... Cheers, Rusty. -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <200805162032.48469.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <200805162032.48469.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org> @ 2008-05-16 10:38 ` Johannes Berg 0 siblings, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-05-16 10:38 UTC (permalink / raw) To: Rusty Russell Cc: David Miller, herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q, mb-fseUSCV1ubazQB+pC5nmwQ, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, ron.rindjunsky-ral2JQCrhuEAvxtiuMwx3w, tomasw-Re5JQEeQqe8AvxtiuMwx3w, ivdoorn-Re5JQEeQqe8AvxtiuMwx3w, peter.p.waskiewicz.jr-ral2JQCrhuEAvxtiuMwx3w [-- Attachment #1: Type: text/plain, Size: 523 bytes --] > I put a patch in to do exactly that at Herbert's prompting, for 2.6.26, but > it's buggy in (at least) two ways. I have a fix for this, which adds a new > tasklet to xmit the packet. There's still some subtle race, however, since > I'm still seeing a stuck packet. I'll have to revert to TX_BUSY for 2.6.26 > if I can't find it (unlikely). Incidentally, mac80211 has a tasklet for this as well, and I'm pretty sure it's also buggy in the corner cases (rather than inefficient or something) johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-16 10:32 ` Rusty Russell [not found] ` <200805162032.48469.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org> @ 2008-05-16 12:15 ` Herbert Xu 2008-05-16 19:40 ` David Miller 2 siblings, 0 replies; 41+ messages in thread From: Herbert Xu @ 2008-05-16 12:15 UTC (permalink / raw) To: Rusty Russell Cc: David Miller, mb, johannes, linux-wireless, netdev, ron.rindjunsky, tomasw, ivdoorn, peter.p.waskiewicz.jr On Fri, May 16, 2008 at 08:32:48PM +1000, Rusty Russell wrote: > > But it's *simple*, and seems like a common thing to want. Why not change > everything to use TX_BUSY and rip out the guestimate/buffering hacks? I think this sounds quite reasonable. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-16 10:32 ` Rusty Russell [not found] ` <200805162032.48469.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org> 2008-05-16 12:15 ` Herbert Xu @ 2008-05-16 19:40 ` David Miller [not found] ` <20080516.124039.253626477.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 2 siblings, 1 reply; 41+ messages in thread From: David Miller @ 2008-05-16 19:40 UTC (permalink / raw) To: rusty Cc: herbert, mb, johannes, linux-wireless, netdev, ron.rindjunsky, tomasw, ivdoorn, peter.p.waskiewicz.jr From: Rusty Russell <rusty@rustcorp.com.au> Date: Fri, 16 May 2008 20:32:48 +1000 > On Friday 16 May 2008 14:58:23 David Miller wrote: > > In fact, I want to move things more and more towards the driver > > queueing TX packets internally instead of the networking mid-layer. > > > > That will ahve benefits for things like TX multiqueue, we won't > > need any locking at all, nor have any knowledge about multiple > > queues at all, if the driver takes care of providing the buffer > > between what the kernel gives it and what the device can handle > > at the moment. > > That would be great: then I could shove the packet back on the queue myself > and not have to ask you about it. It's adding a *second* queue inside the > driver which feels terribly ugly... My description describes how I want the mid-layer queue to disappear entirely. Queueing would be done by the driver only. Only the driver knows all of these details about how much space there is, what packet chopping has to take place and what effects that has on queue space, multiqueue configurations, how one wants to hash to multiple queues, how to lock this stuff the most efficiently. The kernel should just get out of the way and let the driver take care of everything. Sure, we can have some standard helpers to deal with the most common cases. But anything non-trivial right now is painful because the mid-layer model tries to be too helpful when it should just get out of the way. ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080516.124039.253626477.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080516.124039.253626477.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> @ 2008-05-19 3:08 ` Rusty Russell 2008-05-19 7:03 ` David Miller 0 siblings, 1 reply; 41+ messages in thread From: Rusty Russell @ 2008-05-19 3:08 UTC (permalink / raw) To: David Miller Cc: herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q, mb-fseUSCV1ubazQB+pC5nmwQ, johannes-cdvu00un1VgdHxzADdlk8Q, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, ron.rindjunsky-ral2JQCrhuEAvxtiuMwx3w, tomasw-Re5JQEeQqe8AvxtiuMwx3w, ivdoorn-Re5JQEeQqe8AvxtiuMwx3w, peter.p.waskiewicz.jr-ral2JQCrhuEAvxtiuMwx3w On Saturday 17 May 2008 05:40:39 David Miller wrote: > My description describes how I want the mid-layer queue to disappear > entirely. Queueing would be done by the driver only. Ok, the more I ponder this, the more I like it. It has a very nice side benefit for virtio_net: we can xmit a whole bunch of packets before notifying the host. Real NICs might gain similarly. The bit I can't see is what to do about qdisc if the driver manages its own queue(s). Leave the qdisc as currently in place and have the driver call dev_dequeue_skb() (or some wrapper) directly? Modulo locking issues, that should be a fairly simple change. Thanks, Rusty. -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-19 3:08 ` Rusty Russell @ 2008-05-19 7:03 ` David Miller 0 siblings, 0 replies; 41+ messages in thread From: David Miller @ 2008-05-19 7:03 UTC (permalink / raw) To: rusty Cc: herbert, mb, johannes, linux-wireless, netdev, ron.rindjunsky, tomasw, ivdoorn, peter.p.waskiewicz.jr From: Rusty Russell <rusty@rustcorp.com.au> Date: Mon, 19 May 2008 13:08:13 +1000 > The bit I can't see is what to do about qdisc if the driver manages its own > queue(s). Leave the qdisc as currently in place and have the driver call > dev_dequeue_skb() (or some wrapper) directly? Modulo locking issues, that > should be a fairly simple change. I'd like to approach a state where the device is just a black hole that the qdisc injects packets into. At least theoretically, that's what the network is once the packet leaves the device anyways. Nobody really notices as long as flows don't get reordered. I realize it isn't feasible to retain many of the qualities that some qdiscs want (rates, qfull handling, etc.), so we'll have to provide some handling for that, ideally in some cheap slowpath test. But for things like tx queue backlog overflow the behavior would be essentially the same. The only change is that the txqueuelen parameter is handled inside of the driver (again, perhaps via helpers). Our TX path is way too complicated and, frankly, restrictive. This is why we don't have real parallel TX multiqueue support as a simple patch to some drivers. We have fundamental restrictions that keep that from happening. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-08 3:22 ` Herbert Xu [not found] ` <20080508032208.GA401-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> @ 2008-05-08 13:00 ` Michael Buesch [not found] ` <200805081500.00682.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org> 1 sibling, 1 reply; 41+ messages in thread From: Michael Buesch @ 2008-05-08 13:00 UTC (permalink / raw) To: Herbert Xu Cc: Johannes Berg, linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Thursday 08 May 2008 05:22:08 Herbert Xu wrote: > On Wed, May 07, 2008 at 03:48:06PM +0200, Michael Buesch wrote: > > > > So there's no way to actually fail in a TX handler? Drivers > > are doomed to drop the packet, if they cannot handle it due to > > ring overflow? > > You're supposed to stop the queue before the ring overflows. Ok, what about DMA error. kmalloc error or something else? ring overflow was a bad example, of course. -- Greetings Michael. ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <200805081500.00682.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <200805081500.00682.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org> @ 2008-05-08 13:08 ` Herbert Xu 2008-05-08 13:13 ` Michael Buesch 0 siblings, 1 reply; 41+ messages in thread From: Herbert Xu @ 2008-05-08 13:08 UTC (permalink / raw) To: Michael Buesch Cc: Johannes Berg, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Thu, May 08, 2008 at 03:00:00PM +0200, Michael Buesch wrote: > > Ok, what about DMA error. kmalloc error or something else? > ring overflow was a bad example, of course. If your NIC gets DMA errors all the time then I suggest you invest in some new hardware. Ditto if you fail to kmalloc all the time. If they're rare as they should be then dropping the packet is perfectly reasonable. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-08 13:08 ` Herbert Xu @ 2008-05-08 13:13 ` Michael Buesch 2008-05-08 13:15 ` Michael Buesch [not found] ` <200805081513.56521.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org> 0 siblings, 2 replies; 41+ messages in thread From: Michael Buesch @ 2008-05-08 13:13 UTC (permalink / raw) To: Herbert Xu Cc: Johannes Berg, linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Thursday 08 May 2008 15:08:46 Herbert Xu wrote: > On Thu, May 08, 2008 at 03:00:00PM +0200, Michael Buesch wrote: > > > > Ok, what about DMA error. kmalloc error or something else? > > ring overflow was a bad example, of course. > > If your NIC gets DMA errors all the time then I suggest you > invest in some new hardware. Ditto if you fail to kmalloc all > the time. > > If they're rare as they should be then dropping the packet is > perfectly reasonable. Ok, why is nobody actually answering my _question_? :) So I'll try to answer it by myself: the hard_start_xmit callback is actually supposed to return "void", but it returns "int" just for historical reasons. So there is no way to fail in a TX handler. If a failure happens, the driver must free and drop the skb. How likely errors are is a completely different story. One could argue that errors are unlikely for any part of the kernel, except for very sone special cases. So does that also apply to the wireless stack? Should we change drivers to always return 0. later we can change the function prototype to return void. -- Greetings Michael. ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code 2008-05-08 13:13 ` Michael Buesch @ 2008-05-08 13:15 ` Michael Buesch [not found] ` <200805081513.56521.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org> 1 sibling, 0 replies; 41+ messages in thread From: Michael Buesch @ 2008-05-08 13:15 UTC (permalink / raw) To: Herbert Xu Cc: Johannes Berg, linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Thursday 08 May 2008 15:13:56 Michael Buesch wrote: > that errors are unlikely for any part of the kernel, except for very > sone special cases. "..., except for some very special cases." -- Greetings Michael. ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <200805081513.56521.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>]
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <200805081513.56521.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org> @ 2008-05-08 13:32 ` Herbert Xu 0 siblings, 0 replies; 41+ messages in thread From: Herbert Xu @ 2008-05-08 13:32 UTC (permalink / raw) To: Michael Buesch Cc: Johannes Berg, linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr On Thu, May 08, 2008 at 03:13:56PM +0200, Michael Buesch wrote: > > Ok, why is nobody actually answering my _question_? :) > So I'll try to answer it by myself: the hard_start_xmit callback > is actually supposed to return "void", but it returns "int" just > for historical reasons. So there is no way to fail in a TX handler. Pretty much. When lockless drivers were the vogue the return value was useful but as we've since found better ways to scale NICs in an SMP environment (first the tg3 model, and then multi- queue TX) that don't have the problems associated with requeueing the packet, any non-zero return value should only be used by existing code. Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH] mac80211: rewrite fragmentation code [not found] ` <20080507130548.GA26977-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org> 2008-05-07 13:48 ` Michael Buesch @ 2008-05-07 19:19 ` Johannes Berg 1 sibling, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-05-07 19:19 UTC (permalink / raw) To: Herbert Xu Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr [-- Attachment #1: Type: text/plain, Size: 677 bytes --] On Wed, 2008-05-07 at 21:05 +0800, Herbert Xu wrote: > On Wed, May 07, 2008 at 01:52:13PM +0200, Johannes Berg wrote: > > > > Hmm. Why does busy exist then? Historical accident? I really really > > Yes it's historical baggage. These days the biggest users would > be LLTX drivers which should all be converted to non-LLTX and > drivers that don't keep track of queue status properly. Hmmm mmmm. I'll clean it up later, it gets easier with my patch that puts the control info into skb->cb so I'll do that later in a separate patch. The way I see it, this is actually *correct* from a "what hits the air" point of view and the current code is crappy. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* [RFC/RFT 4/4] mac80211: use multi-queue master netdevice 2008-04-30 12:40 [RFC/RFT 0/4] mac80211 QoS-related enhancements Johannes Berg ` (2 preceding siblings ...) 2008-04-30 12:40 ` [RFC/RFT 3/4] mac80211: use GSO for fragmentation Johannes Berg @ 2008-04-30 12:40 ` Johannes Berg [not found] ` <20080430130051.397094000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> 3 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-04-30 12:40 UTC (permalink / raw) To: linux-wireless-u79uwXL29TY76Z2rM5mHXA Cc: netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Ivo van Doorn, Peter P Waskiewicz Jr [-- Attachment #1: 039-mac80211-mq.patch --] [-- Type: text/plain, Size: 23314 bytes --] This patch updates mac80211 and drivers to be multi-queue aware and use that instead of the internal queue mapping. Signed-off-by: Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> --- This is just ground-work. We'll be able to play with Qos much more now. drivers/net/wireless/ath5k/base.c | 2 - drivers/net/wireless/b43/dma.c | 7 ++- drivers/net/wireless/b43/pio.c | 8 ++-- drivers/net/wireless/b43legacy/dma.c | 2 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 +- drivers/net/wireless/p54/p54common.c | 10 ++--- drivers/net/wireless/rt2x00/rt2x00mac.c | 12 +++--- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 - drivers/net/wireless/rt2x00/rt2x00queue.h | 13 ------ drivers/net/wireless/rtl8180_dev.c | 4 +- include/net/mac80211.h | 12 ++++-- net/mac80211/Kconfig | 14 ++++++- net/mac80211/Makefile | 2 - net/mac80211/ieee80211_i.h | 7 --- net/mac80211/main.c | 21 ++++++---- net/mac80211/tx.c | 9 ---- net/mac80211/util.c | 54 +++++++++++++++++++--------- net/mac80211/wme.c | 13 ++---- net/mac80211/wme.h | 2 - 20 files changed, 109 insertions(+), 93 deletions(-) --- everything.orig/drivers/net/wireless/ath5k/base.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/ath5k/base.c 2008-04-30 14:02:34.000000000 +0200 @@ -2677,7 +2677,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, ctl->queue); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); --- everything.orig/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 14:02:34.000000000 +0200 @@ -2562,7 +2562,7 @@ static int iwl3945_tx_skb(struct iwl3945 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2776,7 +2776,7 @@ static int iwl3945_tx_skb(struct iwl3945 spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; --- everything.orig/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 14:02:34.000000000 +0200 @@ -2126,7 +2126,7 @@ static int iwl4965_tx_skb(struct iwl_pri struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl4965_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl4965_tx_queue *txq = NULL; struct iwl4965_queue *q = NULL; dma_addr_t phys_addr; @@ -2350,7 +2350,7 @@ static int iwl4965_tx_skb(struct iwl_pri spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; --- everything.orig/drivers/net/wireless/p54/p54common.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/p54/p54common.c 2008-04-30 14:02:34.000000000 +0200 @@ -417,7 +417,7 @@ static void p54_rx_frame_sent(struct iee memcpy(&status.control, range->control, sizeof(status.control)); kfree(range->control); - priv->tx_stats[status.control.queue].len--; + priv->tx_stats[skb_get_queue_mapping(skb)].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -562,13 +562,13 @@ static int p54_tx(struct ieee80211_hw *d size_t padding, len; u8 rate; - current_queue = &priv->tx_stats[control->queue]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; @@ -605,7 +605,7 @@ static int p54_tx(struct ieee80211_hw *d memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(control->queue + 4); + txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4); txhdr->magic4 = 0; txhdr->antenna = (control->antenna_sel_tx == 0) ? 2 : control->antenna_sel_tx - 1; @@ -944,7 +944,7 @@ static int p54_conf_tx(struct ieee80211_ vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); - if ((params) && !((queue < 0) || (queue > 4))) { + if (params && queue < dev->queues) { P54_SET_QUEUE(vdcf->queue[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else --- everything.orig/drivers/net/wireless/rtl8180_dev.c 2008-04-30 14:02:31.000000000 +0200 +++ everything/drivers/net/wireless/rtl8180_dev.c 2008-04-30 14:02:34.000000000 +0200 @@ -251,7 +251,7 @@ static int rtl8180_tx(struct ieee80211_h u16 plcp_len = 0; __le16 rts_duration = 0; - prio = control->queue; + prio = skb_get_queue_mapping(skb); ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, @@ -306,7 +306,7 @@ static int rtl8180_tx(struct ieee80211_h entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); --- everything.orig/include/net/mac80211.h 2008-04-30 14:02:31.000000000 +0200 +++ everything/include/net/mac80211.h 2008-04-30 14:02:34.000000000 +0200 @@ -282,9 +282,6 @@ struct ieee80211_tx_control { * This could be used when set_retry_limit * is not implemented by the driver */ - u16 queue; /* hardware queue to use for this frame; - * 0 = highest, hw->queues-1 = lowest */ - struct ieee80211_vif *vif; /* Key used for hardware encryption @@ -1575,6 +1572,15 @@ void ieee80211_wake_queue(struct ieee802 void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); /** + * ieee80211_start_queue - start specific queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_start_queue. + */ +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue); + +/** * ieee80211_start_queues - start all queues * @hw: pointer to as obtained from ieee80211_alloc_hw(). * --- everything.orig/net/mac80211/Kconfig 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/Kconfig 2008-04-30 14:25:39.000000000 +0200 @@ -7,11 +7,23 @@ config MAC80211 select CRC32 select WIRELESS_EXT select CFG80211 - select NET_SCH_FIFO ---help--- This option enables the hardware independent IEEE 802.11 networking stack. +config MAC80211_QOS + def_bool y + depends on MAC80211 + depends on NET_SCHED + depends on NETDEVICES_MULTIQUEUE + +comment "QoS/HT support disabled" + depends on !MAC80211_QOS +comment "QoS/HT support needs CONFIG_NET_SCHED" + depends on MAC80211 && !NET_SCHED +comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE" + depends on MAC80211 && !NETDEVICES_MULTIQUEUE + menu "Rate control algorithm selection" depends on MAC80211 != n --- everything.orig/net/mac80211/Makefile 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/Makefile 2008-04-30 14:02:34.000000000 +0200 @@ -29,7 +29,7 @@ mac80211-y := \ event.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o -mac80211-$(CONFIG_NET_SCHED) += wme.o +mac80211-$(CONFIG_MAC80211_QOS) += wme.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs.o \ debugfs_sta.o \ --- everything.orig/net/mac80211/ieee80211_i.h 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/ieee80211_i.h 2008-04-30 14:02:34.000000000 +0200 @@ -213,7 +213,6 @@ struct ieee80211_rx_data { struct ieee80211_tx_packet_data { u32 flags; int ifindex; - u16 queue; unsigned long jiffies; }; @@ -605,8 +604,6 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; - /* number of interfaces with corresponding IFF_ flags */ atomic_t iff_allmultis, iff_promiscs; @@ -836,10 +833,6 @@ static inline struct ieee80211_hw *local return &local->hw; } -enum ieee80211_link_state_t { - IEEE80211_LINK_STATE_XOFF = 0, -}; - struct sta_attribute { struct attribute attr; ssize_t (*show)(const struct sta_info *, char *buf); --- everything.orig/net/mac80211/main.c 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/main.c 2008-04-30 14:18:53.000000000 +0200 @@ -1313,7 +1313,6 @@ static void ieee80211_remove_tx_extra(st pkt_data->flags |= IEEE80211_TXPD_REQUEUE; if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; - pkt_data->queue = control->queue; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -1713,9 +1712,20 @@ int ieee80211_register_hw(struct ieee802 if (result < 0) return result; +#ifdef CONFIG_MAC80211_QOS + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; +#else + hw->queues = 1; + hw->ampdu_queues = 0; +#endif + /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); + mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup, + hw->queues + hw->ampdu_queues); if (!mdev) goto fail_mdev_alloc; @@ -1807,11 +1817,6 @@ int ieee80211_register_hw(struct ieee802 goto fail_wep; } - if (hw->queues > IEEE80211_MAX_QUEUES) - hw->queues = IEEE80211_MAX_QUEUES; - if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) - hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; - ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ --- everything.orig/net/mac80211/tx.c 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/tx.c 2008-04-30 14:02:34.000000000 +0200 @@ -210,12 +210,6 @@ static u16 ieee80211_duration(struct iee return dur; } -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - static int inline is_ieee80211_device(struct net_device *dev, struct net_device *master) { @@ -1066,7 +1060,7 @@ static int ___ieee80211_tx(struct ieee80 print_control(control, skb); if (unlikely(netif_queue_stopped(local->mdev) || - __ieee80211_queue_stopped(local, control->queue))) + netif_subqueue_stopped(local->mdev, skb))) return NETDEV_TX_BUSY; ieee80211_dump_frame(wiphy_name(local->hw.wiphy), @@ -1354,7 +1348,6 @@ int ieee80211_master_start_xmit(struct s control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; if (pkt_data->flags & IEEE80211_TXPD_AMPDU) control.flags |= IEEE80211_TXCTL_AMPDU; - control.queue = pkt_data->queue; memset(skb->cb, 0, sizeof(skb->cb)); ret = ieee80211_tx(odev, skb, &control); --- everything.orig/net/mac80211/util.c 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/util.c 2008-04-30 14:20:06.000000000 +0200 @@ -323,18 +323,28 @@ __le16 ieee80211_ctstoself_duration(stru } EXPORT_SYMBOL(ieee80211_ctstoself_duration); +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue) +{ + struct ieee80211_local *local = hw_to_local(hw); +#ifdef CONFIG_MAC80211_QOS + netif_start_subqueue(local->mdev, queue); +#else + WARN_ON(queue != 0); + netif_start_queue(local->mdev); +#endif +} +EXPORT_SYMBOL(ieee80211_start_queue); + void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); - } +#ifdef CONFIG_MAC80211_QOS + netif_wake_subqueue(local->mdev, queue); +#else + WARN_ON(queue != 0); + netif_wake_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_wake_queue); @@ -342,39 +352,51 @@ void ieee80211_stop_queue(struct ieee802 { struct ieee80211_local *local = hw_to_local(hw); - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) - netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); +#ifdef CONFIG_MAC80211_QOS + netif_stop_subqueue(local->mdev, queue); +#else + WARN_ON(queue != 0); + netif_stop_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_stop_queue); void ieee80211_start_queues(struct ieee80211_hw *hw) { - struct ieee80211_local *local = hw_to_local(hw); +#ifdef CONFIG_MAC80211_QOS int i; - for (i = 0; i < local->hw.queues; i++) - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); - if (!ieee80211_qdisc_installed(local->mdev)) - netif_start_queue(local->mdev); + for (i = 0; i < hw->queues; i++) + ieee80211_start_queue(hw, i); +#else + netif_start_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_start_queues); void ieee80211_stop_queues(struct ieee80211_hw *hw) { +#ifdef CONFIG_MAC80211_QOS int i; for (i = 0; i < hw->queues; i++) ieee80211_stop_queue(hw, i); +#else + netif_stop_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_stop_queues); void ieee80211_wake_queues(struct ieee80211_hw *hw) { +#ifdef CONFIG_MAC80211_QOS int i; for (i = 0; i < hw->queues; i++) ieee80211_wake_queue(hw, i); +#else + netif_wake_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_wake_queues); --- everything.orig/net/mac80211/wme.c 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/wme.c 2008-04-30 14:35:44.000000000 +0200 @@ -160,7 +160,7 @@ static int wme_qdiscop_enqueue(struct sk u8 tid; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - queue = pkt_data->queue; + queue = skb_get_queue_mapping(skb); rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; @@ -221,7 +221,7 @@ static int wme_qdiscop_enqueue(struct sk err = NET_XMIT_DROP; } else { tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - pkt_data->queue = (unsigned int) queue; + skb_set_queue_mapping(skb, queue); qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); if (err == NET_XMIT_SUCCESS) { @@ -239,13 +239,10 @@ static int wme_qdiscop_enqueue(struct sk static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; struct Qdisc *qdisc; int err; - /* We recorded which queue to use earlier. */ - qdisc = q->queues[pkt_data->queue]; + qdisc = q->queues[skb_get_queue_mapping(skb)]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { qd->q.qlen++; @@ -269,9 +266,7 @@ static struct sk_buff *wme_qdiscop_deque /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < QD_NUM(hw); queue++) { /* see if there is room in this hardware queue */ - if ((test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) + if (__netif_subqueue_stopped(local->mdev, queue)) continue; /* there is space - try and get a frame */ --- everything.orig/net/mac80211/wme.h 2008-04-30 14:02:31.000000000 +0200 +++ everything/net/mac80211/wme.h 2008-04-30 14:02:34.000000000 +0200 @@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u1 return (fc & 0x8C) == 0x88; } -#ifdef CONFIG_NET_SCHED +#ifdef CONFIG_MAC80211_QOS void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, --- everything.orig/drivers/net/wireless/b43/dma.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/b43/dma.c 2008-04-30 14:02:34.000000000 +0200 @@ -1298,7 +1298,8 @@ int b43_dma_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, ctl->queue); + ring = select_ring_by_priority( + dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&ring->lock, flags); @@ -1316,7 +1317,7 @@ int b43_dma_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = ctl->queue; + ring->queue_prio = skb_get_queue_mapping(skb); err = dma_tx_fragment(ring, skb, ctl); if (unlikely(err == -ENOKEY)) { @@ -1334,7 +1335,7 @@ int b43_dma_tx(struct b43_wldev *dev, if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); --- everything.orig/drivers/net/wireless/b43/pio.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/b43/pio.c 2008-04-30 14:02:34.000000000 +0200 @@ -510,7 +510,7 @@ int b43_pio_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, ctl->queue); + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&q->lock, flags); @@ -533,7 +533,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out_unlock; } @@ -541,7 +541,7 @@ int b43_pio_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = ctl->queue; + q->queue_prio = skb_get_queue_mapping(skb); err = pio_tx_frame(q, skb, ctl); if (unlikely(err == -ENOKEY)) { @@ -561,7 +561,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } --- everything.orig/drivers/net/wireless/b43legacy/dma.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/b43legacy/dma.c 2008-04-30 14:02:34.000000000 +0200 @@ -1330,7 +1330,7 @@ int b43legacy_dma_tx(struct b43legacy_wl int err = 0; unsigned long flags; - ring = priority_to_txring(dev, ctl->queue); + ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { --- everything.orig/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 14:02:34.000000000 +0200 @@ -81,7 +81,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); + enum data_queue_qid qid = skb_get_queue_mapping(skb); struct data_queue *queue; struct skb_frame_desc *skbdesc; u16 frame_control; @@ -129,12 +129,14 @@ int rt2x00mac_tx(struct ieee80211_hw *hw IEEE80211_TXCTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue( + rt2x00dev->hw, skb_get_queue_mapping(skb)); return NETDEV_TX_BUSY; } if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue( + rt2x00dev->hw, skb_get_queue_mapping(skb)); return NETDEV_TX_BUSY; } } @@ -146,12 +148,12 @@ int rt2x00mac_tx(struct ieee80211_hw *hw memset(skbdesc, 0, sizeof(*skbdesc)); if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, skb_get_queue_mapping(skb)); return NETDEV_TX_BUSY; } if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, skb_get_queue_mapping(skb)); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); --- everything.orig/drivers/net/wireless/rt2x00/rt2x00pci.c 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/rt2x00/rt2x00pci.c 2008-04-30 14:02:34.000000000 +0200 @@ -178,7 +178,7 @@ void rt2x00pci_txdone(struct rt2x00_dev * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, entry->queue->qid); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); --- everything.orig/drivers/net/wireless/rt2x00/rt2x00queue.h 2008-04-30 14:02:32.000000000 +0200 +++ everything/drivers/net/wireless/rt2x00/rt2x00queue.h 2008-04-30 14:02:34.000000000 +0200 @@ -80,19 +80,6 @@ enum data_queue_qid { }; /** - * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid - * @queue: mac80211 queue. - */ -static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) -{ - /* Regular TX queues are mapped directly */ - if (queue < 4) - return queue; - WARN_ON(1); - return QID_OTHER; -} ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <20080430130051.397094000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org>]
* Re: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <20080430130051.397094000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> @ 2008-04-30 14:37 ` Ivo van Doorn [not found] ` <200804301637.35170.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2008-04-30 19:39 ` Waskiewicz Jr, Peter P 1 sibling, 1 reply; 41+ messages in thread From: Ivo van Doorn @ 2008-04-30 14:37 UTC (permalink / raw) To: Johannes Berg Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Peter P Waskiewicz Jr Hi, Overall the rt2x00 changes are good, but I have a few suggestions :) > --- everything.orig/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 14:02:32.000000000 +0200 > +++ everything/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 14:02:34.000000000 +0200 > @@ -81,7 +81,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw > { > struct rt2x00_dev *rt2x00dev = hw->priv; > struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; > - enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); > + enum data_queue_qid qid = skb_get_queue_mapping(skb); > struct data_queue *queue; > struct skb_frame_desc *skbdesc; > u16 frame_control; > @@ -129,12 +129,14 @@ int rt2x00mac_tx(struct ieee80211_hw *hw > IEEE80211_TXCTL_USE_CTS_PROTECT)) && > !rt2x00dev->ops->hw->set_rts_threshold) { > if (rt2x00queue_available(queue) <= 1) { > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue( > + rt2x00dev->hw, skb_get_queue_mapping(skb)); ieee80211_stop_queue(rt2x00dev->hw, qid); The result of skb_get_queue_mapping(skb) was already stored in the 'qid' variable at the start of the function. And since this is a 1-1 mapping from skb queue to rt2x00 queue, it is safe to use 'qid' directly in all instances. > return NETDEV_TX_BUSY; > } > > if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue( > + rt2x00dev->hw, skb_get_queue_mapping(skb)); ieee80211_stop_queue(rt2x00dev->hw, qid); > return NETDEV_TX_BUSY; > } > } > @@ -146,12 +148,12 @@ int rt2x00mac_tx(struct ieee80211_hw *hw > memset(skbdesc, 0, sizeof(*skbdesc)); > > if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue(rt2x00dev->hw, skb_get_queue_mapping(skb)); ieee80211_stop_queue(rt2x00dev->hw, qid); > return NETDEV_TX_BUSY; > } > > if (rt2x00queue_full(queue)) > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue(rt2x00dev->hw, skb_get_queue_mapping(skb)); ieee80211_stop_queue(rt2x00dev->hw, qid); > if (rt2x00dev->ops->lib->kick_tx_queue) > rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); Thanks, Ivo -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <200804301637.35170.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <200804301637.35170.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2008-04-30 14:45 ` Johannes Berg [not found] ` <1209566743.18659.30.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> 0 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-04-30 14:45 UTC (permalink / raw) To: Ivo van Doorn Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Peter P Waskiewicz Jr [-- Attachment #1: Type: text/plain, Size: 1030 bytes --] Hi Ivo, > Overall the rt2x00 changes are good, but I have a few suggestions :) > > struct rt2x00_dev *rt2x00dev = hw->priv; > > struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; > > - enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); > > + enum data_queue_qid qid = skb_get_queue_mapping(skb); > > struct data_queue *queue; > > if (rt2x00queue_available(queue) <= 1) { > > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > > + ieee80211_stop_queue( > > + rt2x00dev->hw, skb_get_queue_mapping(skb)); > > ieee80211_stop_queue(rt2x00dev->hw, qid); > The result of skb_get_queue_mapping(skb) was already stored in the > 'qid' variable at the start of the function. And since this is a 1-1 mapping > from skb queue to rt2x00 queue, it is safe to use 'qid' directly in all instances. Heh, good point, changed that. Will probably generate the same code since get_queue_mapping is a static inline, but hey, much nicer to read that way :) johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <1209566743.18659.30.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>]
* Re: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <1209566743.18659.30.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> @ 2008-04-30 15:00 ` Johannes Berg [not found] ` <1209567609.18659.33.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> 0 siblings, 1 reply; 41+ messages in thread From: Johannes Berg @ 2008-04-30 15:00 UTC (permalink / raw) To: Ivo van Doorn Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Peter P Waskiewicz Jr Turns out there was something missing (last hunk of this updated version) from the rt2x00 part of the patch that I accidentally didn't quilt edit, here's an updated version if anybody wants to test on rt2x00 hw. johannes Subject: mac80211: use multi-queue master netdevice This patch updates mac80211 and drivers to be multi-queue aware and use that instead of the internal queue mapping. Signed-off-by: Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> --- This is just ground-work. We'll be able to play with Qos much more now. drivers/net/wireless/ath5k/base.c | 2 - drivers/net/wireless/b43/dma.c | 7 ++- drivers/net/wireless/b43/pio.c | 8 ++-- drivers/net/wireless/b43legacy/dma.c | 2 - drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 +- drivers/net/wireless/p54/p54common.c | 10 ++--- drivers/net/wireless/rt2x00/rt2x00mac.c | 10 ++--- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 - drivers/net/wireless/rt2x00/rt2x00queue.h | 13 ------ drivers/net/wireless/rt2x00/rt2x00usb.c | 2 - drivers/net/wireless/rtl8180_dev.c | 4 +- include/net/mac80211.h | 12 ++++-- net/mac80211/Kconfig | 14 ++++++- net/mac80211/Makefile | 2 - net/mac80211/ieee80211_i.h | 7 --- net/mac80211/main.c | 21 ++++++---- net/mac80211/tx.c | 9 ---- net/mac80211/util.c | 54 +++++++++++++++++++--------- net/mac80211/wme.c | 13 ++---- net/mac80211/wme.h | 2 - 21 files changed, 108 insertions(+), 94 deletions(-) --- everything.orig/drivers/net/wireless/ath5k/base.c 2008-04-30 16:55:36.000000000 +0200 +++ everything/drivers/net/wireless/ath5k/base.c 2008-04-30 16:55:37.000000000 +0200 @@ -2677,7 +2677,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct if (list_empty(&sc->txbuf)) { ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); spin_unlock_irqrestore(&sc->txbuflock, flags); - ieee80211_stop_queue(hw, ctl->queue); + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); return -1; } bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); --- everything.orig/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 16:55:36.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 16:55:37.000000000 +0200 @@ -2562,7 +2562,7 @@ static int iwl3945_tx_skb(struct iwl3945 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl3945_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl3945_tx_queue *txq = NULL; struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; @@ -2776,7 +2776,7 @@ static int iwl3945_tx_skb(struct iwl3945 spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; --- everything.orig/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 16:55:36.000000000 +0200 +++ everything/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 16:55:37.000000000 +0200 @@ -2126,7 +2126,7 @@ static int iwl4965_tx_skb(struct iwl_pri struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl4965_tfd_frame *tfd; u32 *control_flags; - int txq_id = ctl->queue; + int txq_id = skb_get_queue_mapping(skb); struct iwl4965_tx_queue *txq = NULL; struct iwl4965_queue *q = NULL; dma_addr_t phys_addr; @@ -2350,7 +2350,7 @@ static int iwl4965_tx_skb(struct iwl_pri spin_unlock_irqrestore(&priv->lock, flags); } - ieee80211_stop_queue(priv->hw, ctl->queue); + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); } return 0; --- everything.orig/drivers/net/wireless/p54/p54common.c 2008-04-30 16:55:36.000000000 +0200 +++ everything/drivers/net/wireless/p54/p54common.c 2008-04-30 16:55:37.000000000 +0200 @@ -417,7 +417,7 @@ static void p54_rx_frame_sent(struct iee memcpy(&status.control, range->control, sizeof(status.control)); kfree(range->control); - priv->tx_stats[status.control.queue].len--; + priv->tx_stats[skb_get_queue_mapping(skb)].len--; entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) @@ -562,13 +562,13 @@ static int p54_tx(struct ieee80211_hw *d size_t padding, len; u8 rate; - current_queue = &priv->tx_stats[control->queue]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; if (current_queue->len == current_queue->limit) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; @@ -605,7 +605,7 @@ static int p54_tx(struct ieee80211_hw *d memset(txhdr->rateset, rate, 8); txhdr->wep_key_present = 0; txhdr->wep_key_len = 0; - txhdr->frame_type = cpu_to_le32(control->queue + 4); + txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4); txhdr->magic4 = 0; txhdr->antenna = (control->antenna_sel_tx == 0) ? 2 : control->antenna_sel_tx - 1; @@ -944,7 +944,7 @@ static int p54_conf_tx(struct ieee80211_ vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); - if ((params) && !((queue < 0) || (queue > 4))) { + if (params && queue < dev->queues) { P54_SET_QUEUE(vdcf->queue[queue], params->aifs, params->cw_min, params->cw_max, params->txop); } else --- everything.orig/drivers/net/wireless/rtl8180_dev.c 2008-04-30 16:55:36.000000000 +0200 +++ everything/drivers/net/wireless/rtl8180_dev.c 2008-04-30 16:55:37.000000000 +0200 @@ -251,7 +251,7 @@ static int rtl8180_tx(struct ieee80211_h u16 plcp_len = 0; __le16 rts_duration = 0; - prio = control->queue; + prio = skb_get_queue_mapping(skb); ring = &priv->tx_ring[prio]; mapping = pci_map_single(priv->pdev, skb->data, @@ -306,7 +306,7 @@ static int rtl8180_tx(struct ieee80211_h entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, control->queue); + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); spin_unlock_irqrestore(&priv->lock, flags); rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); --- everything.orig/include/net/mac80211.h 2008-04-30 16:55:37.000000000 +0200 +++ everything/include/net/mac80211.h 2008-04-30 16:55:37.000000000 +0200 @@ -282,9 +282,6 @@ struct ieee80211_tx_control { * This could be used when set_retry_limit * is not implemented by the driver */ - u16 queue; /* hardware queue to use for this frame; - * 0 = highest, hw->queues-1 = lowest */ - struct ieee80211_vif *vif; /* Key used for hardware encryption @@ -1575,6 +1572,15 @@ void ieee80211_wake_queue(struct ieee802 void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); /** + * ieee80211_start_queue - start specific queue + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @queue: queue number (counted from zero). + * + * Drivers should use this function instead of netif_start_queue. + */ +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue); + +/** * ieee80211_start_queues - start all queues * @hw: pointer to as obtained from ieee80211_alloc_hw(). * --- everything.orig/net/mac80211/Kconfig 2008-04-30 16:53:47.000000000 +0200 +++ everything/net/mac80211/Kconfig 2008-04-30 16:55:37.000000000 +0200 @@ -7,11 +7,23 @@ config MAC80211 select CRC32 select WIRELESS_EXT select CFG80211 - select NET_SCH_FIFO ---help--- This option enables the hardware independent IEEE 802.11 networking stack. +config MAC80211_QOS + def_bool y + depends on MAC80211 + depends on NET_SCHED + depends on NETDEVICES_MULTIQUEUE + +comment "QoS/HT support disabled" + depends on !MAC80211_QOS +comment "QoS/HT support needs CONFIG_NET_SCHED" + depends on MAC80211 && !NET_SCHED +comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE" + depends on MAC80211 && !NETDEVICES_MULTIQUEUE + menu "Rate control algorithm selection" depends on MAC80211 != n --- everything.orig/net/mac80211/Makefile 2008-04-30 16:55:30.000000000 +0200 +++ everything/net/mac80211/Makefile 2008-04-30 16:55:37.000000000 +0200 @@ -29,7 +29,7 @@ mac80211-y := \ event.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o -mac80211-$(CONFIG_NET_SCHED) += wme.o +mac80211-$(CONFIG_MAC80211_QOS) += wme.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs.o \ debugfs_sta.o \ --- everything.orig/net/mac80211/ieee80211_i.h 2008-04-30 16:55:37.000000000 +0200 +++ everything/net/mac80211/ieee80211_i.h 2008-04-30 16:55:37.000000000 +0200 @@ -213,7 +213,6 @@ struct ieee80211_rx_data { struct ieee80211_tx_packet_data { u32 flags; int ifindex; - u16 queue; unsigned long jiffies; }; @@ -605,8 +604,6 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; - /* number of interfaces with corresponding IFF_ flags */ atomic_t iff_allmultis, iff_promiscs; @@ -836,10 +833,6 @@ static inline struct ieee80211_hw *local return &local->hw; } -enum ieee80211_link_state_t { - IEEE80211_LINK_STATE_XOFF = 0, -}; - struct sta_attribute { struct attribute attr; ssize_t (*show)(const struct sta_info *, char *buf); --- everything.orig/net/mac80211/main.c 2008-04-30 16:55:37.000000000 +0200 +++ everything/net/mac80211/main.c 2008-04-30 16:55:37.000000000 +0200 @@ -1313,7 +1313,6 @@ static void ieee80211_remove_tx_extra(st pkt_data->flags |= IEEE80211_TXPD_REQUEUE; if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; - pkt_data->queue = control->queue; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -1713,9 +1712,20 @@ int ieee80211_register_hw(struct ieee802 if (result < 0) return result; +#ifdef CONFIG_MAC80211_QOS + if (hw->queues > IEEE80211_MAX_QUEUES) + hw->queues = IEEE80211_MAX_QUEUES; + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; +#else + hw->queues = 1; + hw->ampdu_queues = 0; +#endif + /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); + mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup, + hw->queues + hw->ampdu_queues); if (!mdev) goto fail_mdev_alloc; @@ -1807,11 +1817,6 @@ int ieee80211_register_hw(struct ieee802 goto fail_wep; } - if (hw->queues > IEEE80211_MAX_QUEUES) - hw->queues = IEEE80211_MAX_QUEUES; - if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) - hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; - ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ --- everything.orig/net/mac80211/tx.c 2008-04-30 16:55:37.000000000 +0200 +++ everything/net/mac80211/tx.c 2008-04-30 16:55:37.000000000 +0200 @@ -210,12 +210,6 @@ static u16 ieee80211_duration(struct iee return dur; } -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - static int inline is_ieee80211_device(struct net_device *dev, struct net_device *master) { @@ -1066,7 +1060,7 @@ static int ___ieee80211_tx(struct ieee80 print_control(control, skb); if (unlikely(netif_queue_stopped(local->mdev) || - __ieee80211_queue_stopped(local, control->queue))) + netif_subqueue_stopped(local->mdev, skb))) return NETDEV_TX_BUSY; ieee80211_dump_frame(wiphy_name(local->hw.wiphy), @@ -1354,7 +1348,6 @@ int ieee80211_master_start_xmit(struct s control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; if (pkt_data->flags & IEEE80211_TXPD_AMPDU) control.flags |= IEEE80211_TXCTL_AMPDU; - control.queue = pkt_data->queue; memset(skb->cb, 0, sizeof(skb->cb)); ret = ieee80211_tx(odev, skb, &control); --- everything.orig/net/mac80211/util.c 2008-04-30 16:55:37.000000000 +0200 +++ everything/net/mac80211/util.c 2008-04-30 16:55:37.000000000 +0200 @@ -323,18 +323,28 @@ __le16 ieee80211_ctstoself_duration(stru } EXPORT_SYMBOL(ieee80211_ctstoself_duration); +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue) +{ + struct ieee80211_local *local = hw_to_local(hw); +#ifdef CONFIG_MAC80211_QOS + netif_start_subqueue(local->mdev, queue); +#else + WARN_ON(queue != 0); + netif_start_queue(local->mdev); +#endif +} +EXPORT_SYMBOL(ieee80211_start_queue); + void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); - } +#ifdef CONFIG_MAC80211_QOS + netif_wake_subqueue(local->mdev, queue); +#else + WARN_ON(queue != 0); + netif_wake_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_wake_queue); @@ -342,39 +352,51 @@ void ieee80211_stop_queue(struct ieee802 { struct ieee80211_local *local = hw_to_local(hw); - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) - netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); +#ifdef CONFIG_MAC80211_QOS + netif_stop_subqueue(local->mdev, queue); +#else + WARN_ON(queue != 0); + netif_stop_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_stop_queue); void ieee80211_start_queues(struct ieee80211_hw *hw) { - struct ieee80211_local *local = hw_to_local(hw); +#ifdef CONFIG_MAC80211_QOS int i; - for (i = 0; i < local->hw.queues; i++) - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); - if (!ieee80211_qdisc_installed(local->mdev)) - netif_start_queue(local->mdev); + for (i = 0; i < hw->queues; i++) + ieee80211_start_queue(hw, i); +#else + netif_start_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_start_queues); void ieee80211_stop_queues(struct ieee80211_hw *hw) { +#ifdef CONFIG_MAC80211_QOS int i; for (i = 0; i < hw->queues; i++) ieee80211_stop_queue(hw, i); +#else + netif_stop_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_stop_queues); void ieee80211_wake_queues(struct ieee80211_hw *hw) { +#ifdef CONFIG_MAC80211_QOS int i; for (i = 0; i < hw->queues; i++) ieee80211_wake_queue(hw, i); +#else + netif_wake_queue(local->mdev); +#endif } EXPORT_SYMBOL(ieee80211_wake_queues); --- everything.orig/net/mac80211/wme.c 2008-04-30 16:55:37.000000000 +0200 +++ everything/net/mac80211/wme.c 2008-04-30 16:55:37.000000000 +0200 @@ -160,7 +160,7 @@ static int wme_qdiscop_enqueue(struct sk u8 tid; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - queue = pkt_data->queue; + queue = skb_get_queue_mapping(skb); rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; @@ -221,7 +221,7 @@ static int wme_qdiscop_enqueue(struct sk err = NET_XMIT_DROP; } else { tid = skb->priority & QOS_CONTROL_TAG1D_MASK; - pkt_data->queue = (unsigned int) queue; + skb_set_queue_mapping(skb, queue); qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); if (err == NET_XMIT_SUCCESS) { @@ -239,13 +239,10 @@ static int wme_qdiscop_enqueue(struct sk static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) { struct ieee80211_sched_data *q = qdisc_priv(qd); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; struct Qdisc *qdisc; int err; - /* We recorded which queue to use earlier. */ - qdisc = q->queues[pkt_data->queue]; + qdisc = q->queues[skb_get_queue_mapping(skb)]; if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { qd->q.qlen++; @@ -269,9 +266,7 @@ static struct sk_buff *wme_qdiscop_deque /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < QD_NUM(hw); queue++) { /* see if there is room in this hardware queue */ - if ((test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) || - (!test_bit(queue, q->qdisc_pool))) + if (__netif_subqueue_stopped(local->mdev, queue)) continue; /* there is space - try and get a frame */ --- everything.orig/net/mac80211/wme.h 2008-04-30 16:53:47.000000000 +0200 +++ everything/net/mac80211/wme.h 2008-04-30 16:55:37.000000000 +0200 @@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u1 return (fc & 0x8C) == 0x88; } -#ifdef CONFIG_NET_SCHED +#ifdef CONFIG_MAC80211_QOS void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, --- everything.orig/drivers/net/wireless/b43/dma.c 2008-04-30 16:55:34.000000000 +0200 +++ everything/drivers/net/wireless/b43/dma.c 2008-04-30 16:55:37.000000000 +0200 @@ -1298,7 +1298,8 @@ int b43_dma_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, ctl->queue); + ring = select_ring_by_priority( + dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&ring->lock, flags); @@ -1316,7 +1317,7 @@ int b43_dma_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = ctl->queue; + ring->queue_prio = skb_get_queue_mapping(skb); err = dma_tx_fragment(ring, skb, ctl); if (unlikely(err == -ENOKEY)) { @@ -1334,7 +1335,7 @@ int b43_dma_tx(struct b43_wldev *dev, if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); --- everything.orig/drivers/net/wireless/b43/pio.c 2008-04-30 16:55:34.000000000 +0200 +++ everything/drivers/net/wireless/b43/pio.c 2008-04-30 16:55:37.000000000 +0200 @@ -510,7 +510,7 @@ int b43_pio_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, ctl->queue); + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&q->lock, flags); @@ -533,7 +533,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out_unlock; } @@ -541,7 +541,7 @@ int b43_pio_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = ctl->queue; + q->queue_prio = skb_get_queue_mapping(skb); err = pio_tx_frame(q, skb, ctl); if (unlikely(err == -ENOKEY)) { @@ -561,7 +561,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } --- everything.orig/drivers/net/wireless/b43legacy/dma.c 2008-04-30 16:55:34.000000000 +0200 +++ everything/drivers/net/wireless/b43legacy/dma.c 2008-04-30 16:55:37.000000000 +0200 @@ -1330,7 +1330,7 @@ int b43legacy_dma_tx(struct b43legacy_wl int err = 0; unsigned long flags; - ring = priority_to_txring(dev, ctl->queue); + ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { --- everything.orig/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 16:55:35.000000000 +0200 +++ everything/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 16:55:37.000000000 +0200 @@ -81,7 +81,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); + enum data_queue_qid qid = skb_get_queue_mapping(skb); struct data_queue *queue; struct skb_frame_desc *skbdesc; u16 frame_control; @@ -129,12 +129,12 @@ int rt2x00mac_tx(struct ieee80211_hw *hw IEEE80211_TXCTL_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } } @@ -146,12 +146,12 @@ int rt2x00mac_tx(struct ieee80211_hw *hw memset(skbdesc, 0, sizeof(*skbdesc)); if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); return NETDEV_TX_BUSY; } if (rt2x00queue_full(queue)) - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + ieee80211_stop_queue(rt2x00dev->hw, qid); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); --- everything.orig/drivers/net/wireless/rt2x00/rt2x00pci.c 2008-04-30 16:55:33.000000000 +0200 +++ everything/drivers/net/wireless/rt2x00/rt2x00pci.c 2008-04-30 16:55:37.000000000 +0200 @@ -178,7 +178,7 @@ void rt2x00pci_txdone(struct rt2x00_dev * is reenabled when the txdone handler has finished. */ if (!rt2x00queue_full(entry->queue)) - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); + ieee80211_wake_queue(rt2x00dev->hw, entry->queue->qid); } EXPORT_SYMBOL_GPL(rt2x00pci_txdone); --- everything.orig/drivers/net/wireless/rt2x00/rt2x00queue.h 2008-04-30 16:55:35.000000000 +0200 +++ everything/drivers/net/wireless/rt2x00/rt2x00queue.h 2008-04-30 16:55:37.000000000 +0200 @@ -80,19 +80,6 @@ enum data_queue_qid { }; /** - * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid - * @queue: mac80211 queue. - */ -static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) -{ - /* Regular TX queues are mapped directly */ - if (queue < 4) - return queue; - WARN_ON(1); - return QID_OTHER; -} ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <1209567609.18659.33.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>]
* Re: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <1209567609.18659.33.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> @ 2008-04-30 15:34 ` Ivo van Doorn 2008-04-30 15:38 ` Johannes Berg 2008-05-01 8:21 ` Ivo van Doorn 1 sibling, 1 reply; 41+ messages in thread From: Ivo van Doorn @ 2008-04-30 15:34 UTC (permalink / raw) To: Johannes Berg Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Peter P Waskiewicz Jr Hi, Don't want to spoil the fun, but the following part doesn't compile when CONFIG_MAC80211_QOS is not set. In the following occurences struct ieee80211_local *local needs to be defined. > void ieee80211_start_queues(struct ieee80211_hw *hw) > { > - struct ieee80211_local *local = hw_to_local(hw); > +#ifdef CONFIG_MAC80211_QOS > int i; > > - for (i = 0; i < local->hw.queues; i++) > - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); > - if (!ieee80211_qdisc_installed(local->mdev)) > - netif_start_queue(local->mdev); > + for (i = 0; i < hw->queues; i++) > + ieee80211_start_queue(hw, i); > +#else struct ieee80211_local *local = hw_to_local(hw); > + netif_start_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_start_queues); > > void ieee80211_stop_queues(struct ieee80211_hw *hw) > { > +#ifdef CONFIG_MAC80211_QOS > int i; > > for (i = 0; i < hw->queues; i++) > ieee80211_stop_queue(hw, i); > +#else struct ieee80211_local *local = hw_to_local(hw); > + netif_stop_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_stop_queues); > > void ieee80211_wake_queues(struct ieee80211_hw *hw) > { > +#ifdef CONFIG_MAC80211_QOS > int i; > > for (i = 0; i < hw->queues; i++) > ieee80211_wake_queue(hw, i); > +#else struct ieee80211_local *local = hw_to_local(hw); > + netif_wake_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_wake_queues); Ivo -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice 2008-04-30 15:34 ` Ivo van Doorn @ 2008-04-30 15:38 ` Johannes Berg 0 siblings, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-04-30 15:38 UTC (permalink / raw) To: Ivo van Doorn Cc: linux-wireless, netdev, Ron Rindjunsky, Tomas Winkler, Peter P Waskiewicz Jr [-- Attachment #1: Type: text/plain, Size: 323 bytes --] On Wed, 2008-04-30 at 17:34 +0200, Ivo van Doorn wrote: > Hi, > > Don't want to spoil the fun, but the following part doesn't compile > when CONFIG_MAC80211_QOS is not set. Oh! I hadn't tried that yet, thanks. I had tried not configuring it and tested the Kconfig for it, but evidently not compiling. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <1209567609.18659.33.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org> 2008-04-30 15:34 ` Ivo van Doorn @ 2008-05-01 8:21 ` Ivo van Doorn [not found] ` <200805011021.04435.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 1 sibling, 1 reply; 41+ messages in thread From: Ivo van Doorn @ 2008-05-01 8:21 UTC (permalink / raw) To: Johannes Berg Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Peter P Waskiewicz Jr On Wednesday 30 April 2008, Johannes Berg wrote: > Turns out there was something missing (last hunk of this updated > version) from the rt2x00 part of the patch that I accidentally didn't > quilt edit, here's an updated version if anybody wants to test on rt2x00 > hw. I've tested the following patch series: mac80211: clean up get_tx_stats callback mac80211: remove queue info from ieee80211_tx_status mac80211: QoS related cleanups mac80211: use rate index in TX control GSO: generalize for mac80211 mac80211: use GSO for fragmentation mac80211: use multi-queue master netdevice My rt61 card (4 TX queues) seems to work correctly, it uses queue 3 as default queue, and a few packets seem to go over queue 1. Ivo > johannes > > Subject: mac80211: use multi-queue master netdevice > > This patch updates mac80211 and drivers to be multi-queue aware and > use that instead of the internal queue mapping. > > Signed-off-by: Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> > --- > This is just ground-work. We'll be able to play with Qos much more now. > > drivers/net/wireless/ath5k/base.c | 2 - > drivers/net/wireless/b43/dma.c | 7 ++- > drivers/net/wireless/b43/pio.c | 8 ++-- > drivers/net/wireless/b43legacy/dma.c | 2 - > drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 +- > drivers/net/wireless/iwlwifi/iwl4965-base.c | 4 +- > drivers/net/wireless/p54/p54common.c | 10 ++--- > drivers/net/wireless/rt2x00/rt2x00mac.c | 10 ++--- > drivers/net/wireless/rt2x00/rt2x00pci.c | 2 - > drivers/net/wireless/rt2x00/rt2x00queue.h | 13 ------ > drivers/net/wireless/rt2x00/rt2x00usb.c | 2 - > drivers/net/wireless/rtl8180_dev.c | 4 +- > include/net/mac80211.h | 12 ++++-- > net/mac80211/Kconfig | 14 ++++++- > net/mac80211/Makefile | 2 - > net/mac80211/ieee80211_i.h | 7 --- > net/mac80211/main.c | 21 ++++++---- > net/mac80211/tx.c | 9 ---- > net/mac80211/util.c | 54 +++++++++++++++++++--------- > net/mac80211/wme.c | 13 ++---- > net/mac80211/wme.h | 2 - > 21 files changed, 108 insertions(+), 94 deletions(-) > > --- everything.orig/drivers/net/wireless/ath5k/base.c 2008-04-30 16:55:36.000000000 +0200 > +++ everything/drivers/net/wireless/ath5k/base.c 2008-04-30 16:55:37.000000000 +0200 > @@ -2677,7 +2677,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct > if (list_empty(&sc->txbuf)) { > ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); > spin_unlock_irqrestore(&sc->txbuflock, flags); > - ieee80211_stop_queue(hw, ctl->queue); > + ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); > return -1; > } > bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); > --- everything.orig/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 16:55:36.000000000 +0200 > +++ everything/drivers/net/wireless/iwlwifi/iwl3945-base.c 2008-04-30 16:55:37.000000000 +0200 > @@ -2562,7 +2562,7 @@ static int iwl3945_tx_skb(struct iwl3945 > struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; > struct iwl3945_tfd_frame *tfd; > u32 *control_flags; > - int txq_id = ctl->queue; > + int txq_id = skb_get_queue_mapping(skb); > struct iwl3945_tx_queue *txq = NULL; > struct iwl3945_queue *q = NULL; > dma_addr_t phys_addr; > @@ -2776,7 +2776,7 @@ static int iwl3945_tx_skb(struct iwl3945 > spin_unlock_irqrestore(&priv->lock, flags); > } > > - ieee80211_stop_queue(priv->hw, ctl->queue); > + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); > } > > return 0; > --- everything.orig/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 16:55:36.000000000 +0200 > +++ everything/drivers/net/wireless/iwlwifi/iwl4965-base.c 2008-04-30 16:55:37.000000000 +0200 > @@ -2126,7 +2126,7 @@ static int iwl4965_tx_skb(struct iwl_pri > struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; > struct iwl4965_tfd_frame *tfd; > u32 *control_flags; > - int txq_id = ctl->queue; > + int txq_id = skb_get_queue_mapping(skb); > struct iwl4965_tx_queue *txq = NULL; > struct iwl4965_queue *q = NULL; > dma_addr_t phys_addr; > @@ -2350,7 +2350,7 @@ static int iwl4965_tx_skb(struct iwl_pri > spin_unlock_irqrestore(&priv->lock, flags); > } > > - ieee80211_stop_queue(priv->hw, ctl->queue); > + ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); > } > > return 0; > --- everything.orig/drivers/net/wireless/p54/p54common.c 2008-04-30 16:55:36.000000000 +0200 > +++ everything/drivers/net/wireless/p54/p54common.c 2008-04-30 16:55:37.000000000 +0200 > @@ -417,7 +417,7 @@ static void p54_rx_frame_sent(struct iee > memcpy(&status.control, range->control, > sizeof(status.control)); > kfree(range->control); > - priv->tx_stats[status.control.queue].len--; > + priv->tx_stats[skb_get_queue_mapping(skb)].len--; > entry_hdr = (struct p54_control_hdr *) entry->data; > entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; > if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) > @@ -562,13 +562,13 @@ static int p54_tx(struct ieee80211_hw *d > size_t padding, len; > u8 rate; > > - current_queue = &priv->tx_stats[control->queue]; > + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; > if (unlikely(current_queue->len > current_queue->limit)) > return NETDEV_TX_BUSY; > current_queue->len++; > current_queue->count++; > if (current_queue->len == current_queue->limit) > - ieee80211_stop_queue(dev, control->queue); > + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); > > padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; > len = skb->len; > @@ -605,7 +605,7 @@ static int p54_tx(struct ieee80211_hw *d > memset(txhdr->rateset, rate, 8); > txhdr->wep_key_present = 0; > txhdr->wep_key_len = 0; > - txhdr->frame_type = cpu_to_le32(control->queue + 4); > + txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4); > txhdr->magic4 = 0; > txhdr->antenna = (control->antenna_sel_tx == 0) ? > 2 : control->antenna_sel_tx - 1; > @@ -944,7 +944,7 @@ static int p54_conf_tx(struct ieee80211_ > vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) > ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); > > - if ((params) && !((queue < 0) || (queue > 4))) { > + if (params && queue < dev->queues) { > P54_SET_QUEUE(vdcf->queue[queue], params->aifs, > params->cw_min, params->cw_max, params->txop); > } else > --- everything.orig/drivers/net/wireless/rtl8180_dev.c 2008-04-30 16:55:36.000000000 +0200 > +++ everything/drivers/net/wireless/rtl8180_dev.c 2008-04-30 16:55:37.000000000 +0200 > @@ -251,7 +251,7 @@ static int rtl8180_tx(struct ieee80211_h > u16 plcp_len = 0; > __le16 rts_duration = 0; > > - prio = control->queue; > + prio = skb_get_queue_mapping(skb); > ring = &priv->tx_ring[prio]; > > mapping = pci_map_single(priv->pdev, skb->data, > @@ -306,7 +306,7 @@ static int rtl8180_tx(struct ieee80211_h > entry->flags = cpu_to_le32(tx_flags); > __skb_queue_tail(&ring->queue, skb); > if (ring->entries - skb_queue_len(&ring->queue) < 2) > - ieee80211_stop_queue(dev, control->queue); > + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); > spin_unlock_irqrestore(&priv->lock, flags); > > rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); > --- everything.orig/include/net/mac80211.h 2008-04-30 16:55:37.000000000 +0200 > +++ everything/include/net/mac80211.h 2008-04-30 16:55:37.000000000 +0200 > @@ -282,9 +282,6 @@ struct ieee80211_tx_control { > * This could be used when set_retry_limit > * is not implemented by the driver */ > > - u16 queue; /* hardware queue to use for this frame; > - * 0 = highest, hw->queues-1 = lowest */ > - > struct ieee80211_vif *vif; > > /* Key used for hardware encryption > @@ -1575,6 +1572,15 @@ void ieee80211_wake_queue(struct ieee802 > void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue); > > /** > + * ieee80211_start_queue - start specific queue > + * @hw: pointer as obtained from ieee80211_alloc_hw(). > + * @queue: queue number (counted from zero). > + * > + * Drivers should use this function instead of netif_start_queue. > + */ > +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue); > + > +/** > * ieee80211_start_queues - start all queues > * @hw: pointer to as obtained from ieee80211_alloc_hw(). > * > --- everything.orig/net/mac80211/Kconfig 2008-04-30 16:53:47.000000000 +0200 > +++ everything/net/mac80211/Kconfig 2008-04-30 16:55:37.000000000 +0200 > @@ -7,11 +7,23 @@ config MAC80211 > select CRC32 > select WIRELESS_EXT > select CFG80211 > - select NET_SCH_FIFO > ---help--- > This option enables the hardware independent IEEE 802.11 > networking stack. > > +config MAC80211_QOS > + def_bool y > + depends on MAC80211 > + depends on NET_SCHED > + depends on NETDEVICES_MULTIQUEUE > + > +comment "QoS/HT support disabled" > + depends on !MAC80211_QOS > +comment "QoS/HT support needs CONFIG_NET_SCHED" > + depends on MAC80211 && !NET_SCHED > +comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE" > + depends on MAC80211 && !NETDEVICES_MULTIQUEUE > + > menu "Rate control algorithm selection" > depends on MAC80211 != n > > --- everything.orig/net/mac80211/Makefile 2008-04-30 16:55:30.000000000 +0200 > +++ everything/net/mac80211/Makefile 2008-04-30 16:55:37.000000000 +0200 > @@ -29,7 +29,7 @@ mac80211-y := \ > event.o > > mac80211-$(CONFIG_MAC80211_LEDS) += led.o > -mac80211-$(CONFIG_NET_SCHED) += wme.o > +mac80211-$(CONFIG_MAC80211_QOS) += wme.o > mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ > debugfs.o \ > debugfs_sta.o \ > --- everything.orig/net/mac80211/ieee80211_i.h 2008-04-30 16:55:37.000000000 +0200 > +++ everything/net/mac80211/ieee80211_i.h 2008-04-30 16:55:37.000000000 +0200 > @@ -213,7 +213,6 @@ struct ieee80211_rx_data { > struct ieee80211_tx_packet_data { > u32 flags; > int ifindex; > - u16 queue; > unsigned long jiffies; > }; > > @@ -605,8 +604,6 @@ struct ieee80211_local { > struct sta_info *sta_hash[STA_HASH_SIZE]; > struct timer_list sta_cleanup; > > - unsigned long state[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; > - > /* number of interfaces with corresponding IFF_ flags */ > atomic_t iff_allmultis, iff_promiscs; > > @@ -836,10 +833,6 @@ static inline struct ieee80211_hw *local > return &local->hw; > } > > -enum ieee80211_link_state_t { > - IEEE80211_LINK_STATE_XOFF = 0, > -}; > - > struct sta_attribute { > struct attribute attr; > ssize_t (*show)(const struct sta_info *, char *buf); > --- everything.orig/net/mac80211/main.c 2008-04-30 16:55:37.000000000 +0200 > +++ everything/net/mac80211/main.c 2008-04-30 16:55:37.000000000 +0200 > @@ -1313,7 +1313,6 @@ static void ieee80211_remove_tx_extra(st > pkt_data->flags |= IEEE80211_TXPD_REQUEUE; > if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) > pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; > - pkt_data->queue = control->queue; > > hdrlen = ieee80211_get_hdrlen_from_skb(skb); > > @@ -1713,9 +1712,20 @@ int ieee80211_register_hw(struct ieee802 > if (result < 0) > return result; > > +#ifdef CONFIG_MAC80211_QOS > + if (hw->queues > IEEE80211_MAX_QUEUES) > + hw->queues = IEEE80211_MAX_QUEUES; > + if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) > + hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; > +#else > + hw->queues = 1; > + hw->ampdu_queues = 0; > +#endif > + > /* for now, mdev needs sub_if_data :/ */ > - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), > - "wmaster%d", ether_setup); > + mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data), > + "wmaster%d", ether_setup, > + hw->queues + hw->ampdu_queues); > if (!mdev) > goto fail_mdev_alloc; > > @@ -1807,11 +1817,6 @@ int ieee80211_register_hw(struct ieee802 > goto fail_wep; > } > > - if (hw->queues > IEEE80211_MAX_QUEUES) > - hw->queues = IEEE80211_MAX_QUEUES; > - if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) > - hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; > - > ieee80211_install_qdisc(local->mdev); > > /* add one default STA interface */ > --- everything.orig/net/mac80211/tx.c 2008-04-30 16:55:37.000000000 +0200 > +++ everything/net/mac80211/tx.c 2008-04-30 16:55:37.000000000 +0200 > @@ -210,12 +210,6 @@ static u16 ieee80211_duration(struct iee > return dur; > } > > -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, > - int queue) > -{ > - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); > -} > - > static int inline is_ieee80211_device(struct net_device *dev, > struct net_device *master) > { > @@ -1066,7 +1060,7 @@ static int ___ieee80211_tx(struct ieee80 > print_control(control, skb); > > if (unlikely(netif_queue_stopped(local->mdev) || > - __ieee80211_queue_stopped(local, control->queue))) > + netif_subqueue_stopped(local->mdev, skb))) > return NETDEV_TX_BUSY; > > ieee80211_dump_frame(wiphy_name(local->hw.wiphy), > @@ -1354,7 +1348,6 @@ int ieee80211_master_start_xmit(struct s > control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; > if (pkt_data->flags & IEEE80211_TXPD_AMPDU) > control.flags |= IEEE80211_TXCTL_AMPDU; > - control.queue = pkt_data->queue; > > memset(skb->cb, 0, sizeof(skb->cb)); > ret = ieee80211_tx(odev, skb, &control); > --- everything.orig/net/mac80211/util.c 2008-04-30 16:55:37.000000000 +0200 > +++ everything/net/mac80211/util.c 2008-04-30 16:55:37.000000000 +0200 > @@ -323,18 +323,28 @@ __le16 ieee80211_ctstoself_duration(stru > } > EXPORT_SYMBOL(ieee80211_ctstoself_duration); > > +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue) > +{ > + struct ieee80211_local *local = hw_to_local(hw); > +#ifdef CONFIG_MAC80211_QOS > + netif_start_subqueue(local->mdev, queue); > +#else > + WARN_ON(queue != 0); > + netif_start_queue(local->mdev); > +#endif > +} > +EXPORT_SYMBOL(ieee80211_start_queue); > + > void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) > { > struct ieee80211_local *local = hw_to_local(hw); > > - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, > - &local->state[queue])) { > - if (!ieee80211_qdisc_installed(local->mdev)) { > - if (queue == 0) > - netif_wake_queue(local->mdev); > - } else > - __netif_schedule(local->mdev); > - } > +#ifdef CONFIG_MAC80211_QOS > + netif_wake_subqueue(local->mdev, queue); > +#else > + WARN_ON(queue != 0); > + netif_wake_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_wake_queue); > > @@ -342,39 +352,51 @@ void ieee80211_stop_queue(struct ieee802 > { > struct ieee80211_local *local = hw_to_local(hw); > > - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) > - netif_stop_queue(local->mdev); > - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); > +#ifdef CONFIG_MAC80211_QOS > + netif_stop_subqueue(local->mdev, queue); > +#else > + WARN_ON(queue != 0); > + netif_stop_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_stop_queue); > > void ieee80211_start_queues(struct ieee80211_hw *hw) > { > - struct ieee80211_local *local = hw_to_local(hw); > +#ifdef CONFIG_MAC80211_QOS > int i; > > - for (i = 0; i < local->hw.queues; i++) > - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); > - if (!ieee80211_qdisc_installed(local->mdev)) > - netif_start_queue(local->mdev); > + for (i = 0; i < hw->queues; i++) > + ieee80211_start_queue(hw, i); > +#else > + netif_start_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_start_queues); > > void ieee80211_stop_queues(struct ieee80211_hw *hw) > { > +#ifdef CONFIG_MAC80211_QOS > int i; > > for (i = 0; i < hw->queues; i++) > ieee80211_stop_queue(hw, i); > +#else > + netif_stop_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_stop_queues); > > void ieee80211_wake_queues(struct ieee80211_hw *hw) > { > +#ifdef CONFIG_MAC80211_QOS > int i; > > for (i = 0; i < hw->queues; i++) > ieee80211_wake_queue(hw, i); > +#else > + netif_wake_queue(local->mdev); > +#endif > } > EXPORT_SYMBOL(ieee80211_wake_queues); > > --- everything.orig/net/mac80211/wme.c 2008-04-30 16:55:37.000000000 +0200 > +++ everything/net/mac80211/wme.c 2008-04-30 16:55:37.000000000 +0200 > @@ -160,7 +160,7 @@ static int wme_qdiscop_enqueue(struct sk > u8 tid; > > if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { > - queue = pkt_data->queue; > + queue = skb_get_queue_mapping(skb); > rcu_read_lock(); > sta = sta_info_get(local, hdr->addr1); > tid = skb->priority & QOS_CONTROL_TAG1D_MASK; > @@ -221,7 +221,7 @@ static int wme_qdiscop_enqueue(struct sk > err = NET_XMIT_DROP; > } else { > tid = skb->priority & QOS_CONTROL_TAG1D_MASK; > - pkt_data->queue = (unsigned int) queue; > + skb_set_queue_mapping(skb, queue); > qdisc = q->queues[queue]; > err = qdisc->enqueue(skb, qdisc); > if (err == NET_XMIT_SUCCESS) { > @@ -239,13 +239,10 @@ static int wme_qdiscop_enqueue(struct sk > static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) > { > struct ieee80211_sched_data *q = qdisc_priv(qd); > - struct ieee80211_tx_packet_data *pkt_data = > - (struct ieee80211_tx_packet_data *) skb->cb; > struct Qdisc *qdisc; > int err; > > - /* We recorded which queue to use earlier. */ > - qdisc = q->queues[pkt_data->queue]; > + qdisc = q->queues[skb_get_queue_mapping(skb)]; > > if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) { > qd->q.qlen++; > @@ -269,9 +266,7 @@ static struct sk_buff *wme_qdiscop_deque > /* check all the h/w queues in numeric/priority order */ > for (queue = 0; queue < QD_NUM(hw); queue++) { > /* see if there is room in this hardware queue */ > - if ((test_bit(IEEE80211_LINK_STATE_XOFF, > - &local->state[queue])) || > - (!test_bit(queue, q->qdisc_pool))) > + if (__netif_subqueue_stopped(local->mdev, queue)) > continue; > > /* there is space - try and get a frame */ > --- everything.orig/net/mac80211/wme.h 2008-04-30 16:53:47.000000000 +0200 > +++ everything/net/mac80211/wme.h 2008-04-30 16:55:37.000000000 +0200 > @@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u1 > return (fc & 0x8C) == 0x88; > } > > -#ifdef CONFIG_NET_SCHED > +#ifdef CONFIG_MAC80211_QOS > void ieee80211_install_qdisc(struct net_device *dev); > int ieee80211_qdisc_installed(struct net_device *dev); > int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, > --- everything.orig/drivers/net/wireless/b43/dma.c 2008-04-30 16:55:34.000000000 +0200 > +++ everything/drivers/net/wireless/b43/dma.c 2008-04-30 16:55:37.000000000 +0200 > @@ -1298,7 +1298,8 @@ int b43_dma_tx(struct b43_wldev *dev, > hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); > } else { > /* Decide by priority where to put this frame. */ > - ring = select_ring_by_priority(dev, ctl->queue); > + ring = select_ring_by_priority( > + dev, skb_get_queue_mapping(skb)); > } > > spin_lock_irqsave(&ring->lock, flags); > @@ -1316,7 +1317,7 @@ int b43_dma_tx(struct b43_wldev *dev, > /* Assign the queue number to the ring (if not already done before) > * so TX status handling can use it. The queue to ring mapping is > * static, so we don't need to store it per frame. */ > - ring->queue_prio = ctl->queue; > + ring->queue_prio = skb_get_queue_mapping(skb); > > err = dma_tx_fragment(ring, skb, ctl); > if (unlikely(err == -ENOKEY)) { > @@ -1334,7 +1335,7 @@ int b43_dma_tx(struct b43_wldev *dev, > if ((free_slots(ring) < SLOTS_PER_PACKET) || > should_inject_overflow(ring)) { > /* This TX ring is full. */ > - ieee80211_stop_queue(dev->wl->hw, ctl->queue); > + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); > ring->stopped = 1; > if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { > b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); > --- everything.orig/drivers/net/wireless/b43/pio.c 2008-04-30 16:55:34.000000000 +0200 > +++ everything/drivers/net/wireless/b43/pio.c 2008-04-30 16:55:37.000000000 +0200 > @@ -510,7 +510,7 @@ int b43_pio_tx(struct b43_wldev *dev, > hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); > } else { > /* Decide by priority where to put this frame. */ > - q = select_queue_by_priority(dev, ctl->queue); > + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); > } > > spin_lock_irqsave(&q->lock, flags); > @@ -533,7 +533,7 @@ int b43_pio_tx(struct b43_wldev *dev, > if (total_len > (q->buffer_size - q->buffer_used)) { > /* Not enough memory on the queue. */ > err = -EBUSY; > - ieee80211_stop_queue(dev->wl->hw, ctl->queue); > + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); > q->stopped = 1; > goto out_unlock; > } > @@ -541,7 +541,7 @@ int b43_pio_tx(struct b43_wldev *dev, > /* Assign the queue number to the ring (if not already done before) > * so TX status handling can use it. The mac80211-queue to b43-queue > * mapping is static, so we don't need to store it per frame. */ > - q->queue_prio = ctl->queue; > + q->queue_prio = skb_get_queue_mapping(skb); > > err = pio_tx_frame(q, skb, ctl); > if (unlikely(err == -ENOKEY)) { > @@ -561,7 +561,7 @@ int b43_pio_tx(struct b43_wldev *dev, > if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || > (q->free_packet_slots == 0)) { > /* The queue is full. */ > - ieee80211_stop_queue(dev->wl->hw, ctl->queue); > + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); > q->stopped = 1; > } > > --- everything.orig/drivers/net/wireless/b43legacy/dma.c 2008-04-30 16:55:34.000000000 +0200 > +++ everything/drivers/net/wireless/b43legacy/dma.c 2008-04-30 16:55:37.000000000 +0200 > @@ -1330,7 +1330,7 @@ int b43legacy_dma_tx(struct b43legacy_wl > int err = 0; > unsigned long flags; > > - ring = priority_to_txring(dev, ctl->queue); > + ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); > spin_lock_irqsave(&ring->lock, flags); > B43legacy_WARN_ON(!ring->tx); > if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { > --- everything.orig/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 16:55:35.000000000 +0200 > +++ everything/drivers/net/wireless/rt2x00/rt2x00mac.c 2008-04-30 16:55:37.000000000 +0200 > @@ -81,7 +81,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw > { > struct rt2x00_dev *rt2x00dev = hw->priv; > struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; > - enum data_queue_qid qid = mac80211_queue_to_qid(control->queue); > + enum data_queue_qid qid = skb_get_queue_mapping(skb); > struct data_queue *queue; > struct skb_frame_desc *skbdesc; > u16 frame_control; > @@ -129,12 +129,12 @@ int rt2x00mac_tx(struct ieee80211_hw *hw > IEEE80211_TXCTL_USE_CTS_PROTECT)) && > !rt2x00dev->ops->hw->set_rts_threshold) { > if (rt2x00queue_available(queue) <= 1) { > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue(rt2x00dev->hw, qid); > return NETDEV_TX_BUSY; > } > > if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) { > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue(rt2x00dev->hw, qid); > return NETDEV_TX_BUSY; > } > } > @@ -146,12 +146,12 @@ int rt2x00mac_tx(struct ieee80211_hw *hw > memset(skbdesc, 0, sizeof(*skbdesc)); > > if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) { > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue(rt2x00dev->hw, qid); > return NETDEV_TX_BUSY; > } > > if (rt2x00queue_full(queue)) > - ieee80211_stop_queue(rt2x00dev->hw, control->queue); > + ieee80211_stop_queue(rt2x00dev->hw, qid); > > if (rt2x00dev->ops->lib->kick_tx_queue) > rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid); > --- everything.orig/drivers/net/wireless/rt2x00/rt2x00pci.c 2008-04-30 16:55:33.000000000 +0200 > +++ everything/drivers/net/wireless/rt2x00/rt2x00pci.c 2008-04-30 16:55:37.000000000 +0200 > @@ -178,7 +178,7 @@ void rt2x00pci_txdone(struct rt2x00_dev > * is reenabled when the txdone handler has finished. > */ > if (!rt2x00queue_full(entry->queue)) > - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); > + ieee80211_wake_queue(rt2x00dev->hw, entry->queue->qid); > > } > EXPORT_SYMBOL_GPL(rt2x00pci_txdone); > --- everything.orig/drivers/net/wireless/rt2x00/rt2x00queue.h 2008-04-30 16:55:35.000000000 +0200 > +++ everything/drivers/net/wireless/rt2x00/rt2x00queue.h 2008-04-30 16:55:37.000000000 +0200 > @@ -80,19 +80,6 @@ enum data_queue_qid { > }; > > /** > - * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid > - * @queue: mac80211 queue. > - */ > -static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue) > -{ > - /* Regular TX queues are mapped directly */ > - if (queue < 4) > - return queue; > - WARN_ON(1); > - return QID_OTHER; > -} > - > -/** > * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc > * > * @FRAME_DESC_DRIVER_GENERATED: Frame was generated inside driver > --- everything.orig/drivers/net/wireless/rt2x00/rt2x00usb.c 2008-04-30 16:56:02.000000000 +0200 > +++ everything/drivers/net/wireless/rt2x00/rt2x00usb.c 2008-04-30 16:56:16.000000000 +0200 > @@ -166,7 +166,7 @@ static void rt2x00usb_interrupt_txdone(s > * is reenabled when the txdone handler has finished. > */ > if (!rt2x00queue_full(entry->queue)) > - ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue); > + ieee80211_wake_queue(rt2x00dev->hw, entry->queue->qid); > } > > int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, > > > -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <200805011021.04435.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <200805011021.04435.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2008-05-01 8:54 ` Johannes Berg 0 siblings, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-05-01 8:54 UTC (permalink / raw) To: Ivo van Doorn Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Ron Rindjunsky, Tomas Winkler, Peter P Waskiewicz Jr [-- Attachment #1: Type: text/plain, Size: 525 bytes --] > I've tested the following patch series: > > mac80211: clean up get_tx_stats callback > mac80211: remove queue info from ieee80211_tx_status > mac80211: QoS related cleanups > mac80211: use rate index in TX control > GSO: generalize for mac80211 > mac80211: use GSO for fragmentation > mac80211: use multi-queue master netdevice > > My rt61 card (4 TX queues) seems to work correctly, it uses > queue 3 as default queue, and a few packets seem to go > over queue 1. Nice, thanks for testing! johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <20080430130051.397094000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org> 2008-04-30 14:37 ` Ivo van Doorn @ 2008-04-30 19:39 ` Waskiewicz Jr, Peter P [not found] ` <D5C1322C3E673F459512FB59E0DDC32904FE144F-O6kdQIuPh0Q64kNsxIetb7fspsVTdybXVpNB7YpNyf8@public.gmane.org> 1 sibling, 1 reply; 41+ messages in thread From: Waskiewicz Jr, Peter P @ 2008-04-30 19:39 UTC (permalink / raw) To: Johannes Berg, linux-wireless-u79uwXL29TY76Z2rM5mHXA Cc: netdev-u79uwXL29TY76Z2rM5mHXA, Rindjunsky, Ron, Tomas Winkler, Ivo van Doorn > --- everything.orig/net/mac80211/util.c 2008-04-30 > 14:02:31.000000000 +0200 > +++ everything/net/mac80211/util.c 2008-04-30 > 14:20:06.000000000 +0200 > @@ -323,18 +323,28 @@ __le16 ieee80211_ctstoself_duration(stru > } > EXPORT_SYMBOL(ieee80211_ctstoself_duration); > > +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue) > +{ > + struct ieee80211_local *local = hw_to_local(hw); > +#ifdef CONFIG_MAC80211_QOS > + netif_start_subqueue(local->mdev, queue); > +#else > + WARN_ON(queue != 0); > + netif_start_queue(local->mdev); > +#endif > +} > +EXPORT_SYMBOL(ieee80211_start_queue); > + I would suggest that you enable the netdev feature flag for NETIF_F_MULTI_QUEUE on devices when you create them. That way you can have things like ieee80211_start_queue() key on that instead of a compile-time option, in case wireless devices come along that won't support multiple queues, if that's possible. So something like this: +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue) +{ + struct ieee80211_local *local = hw_to_local(hw); + if (netif_is_multiqueue(local->mdev) { + netif_start_subqueue(local->mdev, queue); + } else { + WARN_ON(queue != 0); + netif_start_queue(local->mdev); + } +} +EXPORT_SYMBOL(ieee80211_start_queue); + If you think this is a decent idea, I'd suggest that any function that has a compile-time check for multiqueue being changed to use the runtime check. Then in your device setup, where you call netdev_alloc_mq(), there you set the flag NETIF_F_MULTI_QUEUE based on the device features. Other than that, this patch looks great. Exciting to see this starting to take flight. Cheers, -PJ Waskiewicz -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 41+ messages in thread
[parent not found: <D5C1322C3E673F459512FB59E0DDC32904FE144F-O6kdQIuPh0Q64kNsxIetb7fspsVTdybXVpNB7YpNyf8@public.gmane.org>]
* RE: [RFC/RFT 4/4] mac80211: use multi-queue master netdevice [not found] ` <D5C1322C3E673F459512FB59E0DDC32904FE144F-O6kdQIuPh0Q64kNsxIetb7fspsVTdybXVpNB7YpNyf8@public.gmane.org> @ 2008-04-30 20:07 ` Johannes Berg 0 siblings, 0 replies; 41+ messages in thread From: Johannes Berg @ 2008-04-30 20:07 UTC (permalink / raw) To: Waskiewicz Jr, Peter P Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, Rindjunsky, Ron, Tomas Winkler, Ivo van Doorn [-- Attachment #1: Type: text/plain, Size: 1288 bytes --] > > +void ieee80211_start_queue(struct ieee80211_hw *hw, int queue) > > +{ > > + struct ieee80211_local *local = hw_to_local(hw); > > +#ifdef CONFIG_MAC80211_QOS > > + netif_start_subqueue(local->mdev, queue); > > +#else > > + WARN_ON(queue != 0); > > + netif_start_queue(local->mdev); > > +#endif > > +} > > +EXPORT_SYMBOL(ieee80211_start_queue); > > + > > I would suggest that you enable the netdev feature flag for > NETIF_F_MULTI_QUEUE on devices when you create them. That way you can > have things like ieee80211_start_queue() key on that instead of a > compile-time option, in case wireless devices come along that won't > support multiple queues, if that's possible. Ah. I thought that then I'd just create a device with alloc_mq with a single queue. > If you think this is a decent idea, I'd suggest that any function that > has a compile-time check for multiqueue being changed to use the runtime > check. Then in your device setup, where you call netdev_alloc_mq(), > there you set the flag NETIF_F_MULTI_QUEUE based on the device features. Hah, indeed, I don't currently set it at all. Yes, I guess I should do it that way. > Other than that, this patch looks great. Exciting to see this starting > to take flight. :) johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 828 bytes --] ^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2008-05-19 7:03 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-30 12:40 [RFC/RFT 0/4] mac80211 QoS-related enhancements Johannes Berg
2008-04-30 12:40 ` [RFC/RFT 1/4] mac80211: use rate index in TX control Johannes Berg
2008-04-30 12:40 ` [RFC/RFT 2/4] GSO: generalize for mac80211 Johannes Berg
[not found] ` <20080430130049.359549000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org>
2008-05-06 16:12 ` Johannes Berg
2008-04-30 12:40 ` [RFC/RFT 3/4] mac80211: use GSO for fragmentation Johannes Berg
2008-05-07 7:10 ` Herbert Xu
2008-05-07 8:50 ` Johannes Berg
2008-05-07 9:00 ` Herbert Xu
[not found] ` <20080507090040.GA25186-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>
2008-05-07 11:22 ` [PATCH] mac80211: rewrite fragmentation code Johannes Berg
[not found] ` <1210159339.5642.13.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>
2008-05-07 11:41 ` Herbert Xu
2008-05-07 11:52 ` Johannes Berg
[not found] ` <1210161133.5642.19.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>
2008-05-07 13:05 ` Herbert Xu
[not found] ` <20080507130548.GA26977-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>
2008-05-07 13:48 ` Michael Buesch
2008-05-08 3:22 ` Herbert Xu
[not found] ` <20080508032208.GA401-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>
2008-05-08 3:26 ` David Miller
[not found] ` <20080507.202606.242037993.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2008-05-08 9:00 ` Johannes Berg
2008-05-16 2:01 ` Rusty Russell
2008-05-16 3:28 ` Herbert Xu
2008-05-16 4:58 ` David Miller
[not found] ` <20080515.215823.28841530.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2008-05-16 10:32 ` Rusty Russell
[not found] ` <200805162032.48469.rusty-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>
2008-05-16 10:38 ` Johannes Berg
2008-05-16 12:15 ` Herbert Xu
2008-05-16 19:40 ` David Miller
[not found] ` <20080516.124039.253626477.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2008-05-19 3:08 ` Rusty Russell
2008-05-19 7:03 ` David Miller
2008-05-08 13:00 ` Michael Buesch
[not found] ` <200805081500.00682.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>
2008-05-08 13:08 ` Herbert Xu
2008-05-08 13:13 ` Michael Buesch
2008-05-08 13:15 ` Michael Buesch
[not found] ` <200805081513.56521.mb-fseUSCV1ubazQB+pC5nmwQ@public.gmane.org>
2008-05-08 13:32 ` Herbert Xu
2008-05-07 19:19 ` Johannes Berg
2008-04-30 12:40 ` [RFC/RFT 4/4] mac80211: use multi-queue master netdevice Johannes Berg
[not found] ` <20080430130051.397094000-cdvu00un1VgdHxzADdlk8Q@public.gmane.org>
2008-04-30 14:37 ` Ivo van Doorn
[not found] ` <200804301637.35170.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2008-04-30 14:45 ` Johannes Berg
[not found] ` <1209566743.18659.30.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>
2008-04-30 15:00 ` Johannes Berg
[not found] ` <1209567609.18659.33.camel-YfaajirXv214zXjbi5bjpg@public.gmane.org>
2008-04-30 15:34 ` Ivo van Doorn
2008-04-30 15:38 ` Johannes Berg
2008-05-01 8:21 ` Ivo van Doorn
[not found] ` <200805011021.04435.IvDoorn-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2008-05-01 8:54 ` Johannes Berg
2008-04-30 19:39 ` Waskiewicz Jr, Peter P
[not found] ` <D5C1322C3E673F459512FB59E0DDC32904FE144F-O6kdQIuPh0Q64kNsxIetb7fspsVTdybXVpNB7YpNyf8@public.gmane.org>
2008-04-30 20:07 ` Johannes Berg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).