diff mbox

[LEDE-DEV] ath9k: Add airtime fairness scheduler

Message ID 20161125101615.23922-1-toke@toke.dk
State Superseded
Headers show

Commit Message

Toke Høiland-Jørgensen Nov. 25, 2016, 10:16 a.m. UTC
This adds a patch that introduces airtime fairness scheduling to ath9k,
which can significantly improve network efficiency in mixed-rate
environments.

Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
---
 ...h9k-Introduce-airtime-fairness-scheduling.patch | 695 +++++++++++++++++++++
 1 file changed, 695 insertions(+)
 create mode 100644 package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch

Comments

Weedy Nov. 27, 2016, 11:08 a.m. UTC | #1
On Fri, Nov 25, 2016 at 5:16 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
> This adds a patch that introduces airtime fairness scheduling to ath9k,
> which can significantly improve network efficiency in mixed-rate
> environments.
...
> ++      astats = &an->airtime_stats;
> ++
> ++      len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
> ++      len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
> ++      len += scnprintf(buf + len, size - len, "Deficit: ");
> ++      for (i = 0; i < 4; i++)
> ++              len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
> ++      if (len < size)
> ++              buf[len++] = '\n';
> ++
> ++      retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
> ++      kfree(buf);
> ++
> ++      return retval;
> ++}

I'm supposed to have a
/sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/something/airtime
right?
Should I have done anything else besides:
# curl https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v
# make V=s package/mac80211/{clean,install}
Applying ./patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
using plaintext:
patching file drivers/net/wireless/ath/ath9k/ath9k.h
patching file drivers/net/wireless/ath/ath9k/channel.c
patching file drivers/net/wireless/ath/ath9k/debug.c
patching file drivers/net/wireless/ath/ath9k/debug.h
patching file drivers/net/wireless/ath/ath9k/debug_sta.c
patching file drivers/net/wireless/ath/ath9k/init.c
patching file drivers/net/wireless/ath/ath9k/main.c
patching file drivers/net/wireless/ath/ath9k/recv.c
patching file drivers/net/wireless/ath/ath9k/xmit.c

# <the rest of my install stuff>

Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.595812] PCI:
Enabling device 0000:00:11.0 (0000 -> 0002)
Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.606388] ath: phy0:
Ignoring endianness difference in EEPROM magic bytes.
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614943] ath: EEPROM
regdomain: 0x0
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614952] ath: EEPROM
indicates default country code should be used
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614960] ath: doing
EEPROM country->regdmn map search
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614975] ath:
country maps to regdmn code: 0x3a
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614985] ath:
Country alpha2 being used: US
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614993] ath:
Regpair used: 0x3a
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.628327] ieee80211
phy0: Selected rate control algorithm 'minstrel_ht'
Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.632241] ieee80211
phy0: Atheros AR9280 Rev:2 mem=0xb0000000, irq=40
Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.697119] PCI:
Enabling device 0000:00:12.0 (0000 -> 0002)
Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.707690] ath: phy1:
Ignoring endianness difference in EEPROM magic bytes.
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716278] ath: EEPROM
regdomain: 0x0
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716289] ath: EEPROM
indicates default country code should be used
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716297] ath: doing
EEPROM country->regdmn map search
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716313] ath:
country maps to regdmn code: 0x3a
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716322] ath:
Country alpha2 being used: US
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716330] ath:
Regpair used: 0x3a
Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.731825] ieee80211
phy1: Selected rate control algorithm 'minstrel_ht'
Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.735844] ieee80211
phy1: Atheros AR9280 Rev:2 mem=0xb0010000, irq=41

I can't seem to tell if I have the patched driver loaded. Unless
rc_stats counts?
              best   ____________rate__________
________statistics________    ________last_______
______sum-of________
mode guard #  rate  [name   idx airtime  max_tp]  [avg(tp) avg(prob)
sd(prob)]  [prob.|retry|suc|att]  [#success | #attempts]
Toke Høiland-Jørgensen Nov. 27, 2016, 4:01 p.m. UTC | #2
Weedy <weedy2887@gmail.com> writes:

> On Fri, Nov 25, 2016 at 5:16 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
>> This adds a patch that introduces airtime fairness scheduling to ath9k,
>> which can significantly improve network efficiency in mixed-rate
>> environments.
> ...
>> ++      astats = &an->airtime_stats;
>> ++
>> ++      len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
>> ++      len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
>> ++      len += scnprintf(buf + len, size - len, "Deficit: ");
>> ++      for (i = 0; i < 4; i++)
>> ++              len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
>> ++      if (len < size)
>> ++              buf[len++] = '\n';
>> ++
>> ++      retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
>> ++      kfree(buf);
>> ++
>> ++      return retval;
>> ++}
>
> I'm supposed to have a
> /sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/something/airtime
> right?

Yeah, you should. Do you have
/sys/kernel/debug/ieee80211/phy0/ath9k/airtime_flags ?

> Should I have done anything else besides:
> # curl https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v
> # make V=s package/mac80211/{clean,install}

[..]

No, don't think so. Did you reload the right kernel modules after
installing the updated kmod package? You'll need to reload at least the
'ath' and 'ath9k' modules...

-Toke
Weedy Nov. 27, 2016, 11:52 p.m. UTC | #3
On Sun, Nov 27, 2016 at 11:01 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
> Weedy <weedy2887@gmail.com> writes:
>
>> On Fri, Nov 25, 2016 at 5:16 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
>>> This adds a patch that introduces airtime fairness scheduling to ath9k,
>>> which can significantly improve network efficiency in mixed-rate
>>> environments.
>> ...
>>> ++      astats = &an->airtime_stats;
>>> ++
>>> ++      len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
>>> ++      len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
>>> ++      len += scnprintf(buf + len, size - len, "Deficit: ");
>>> ++      for (i = 0; i < 4; i++)
>>> ++              len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
>>> ++      if (len < size)
>>> ++              buf[len++] = '\n';
>>> ++
>>> ++      retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
>>> ++      kfree(buf);
>>> ++
>>> ++      return retval;
>>> ++}
>>
>> I'm supposed to have a
>> /sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/something/airtime
>> right?
>
> Yeah, you should. Do you have
> /sys/kernel/debug/ieee80211/phy0/ath9k/airtime_flags ?

Yes I do. It's set to 7

>> Should I have done anything else besides:
>> # curl https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v
>> # make V=s package/mac80211/{clean,install}
>
> [..]
>
> No, don't think so. Did you reload the right kernel modules after
> installing the updated kmod package? You'll need to reload at least the
> 'ath' and 'ath9k' modules...
>
> -Toke

I flashed the resulting image, so full reboot.
Toke Høiland-Jørgensen Nov. 28, 2016, 9:49 a.m. UTC | #4
Weedy <weedy2887@gmail.com> writes:

> On Sun, Nov 27, 2016 at 11:01 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
>> Weedy <weedy2887@gmail.com> writes:
>>
>>> On Fri, Nov 25, 2016 at 5:16 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
>>>> This adds a patch that introduces airtime fairness scheduling to ath9k,
>>>> which can significantly improve network efficiency in mixed-rate
>>>> environments.
>>> ...
>>>> ++      astats = &an->airtime_stats;
>>>> ++
>>>> ++      len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
>>>> ++      len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
>>>> ++      len += scnprintf(buf + len, size - len, "Deficit: ");
>>>> ++      for (i = 0; i < 4; i++)
>>>> ++              len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
>>>> ++      if (len < size)
>>>> ++              buf[len++] = '\n';
>>>> ++
>>>> ++      retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
>>>> ++      kfree(buf);
>>>> ++
>>>> ++      return retval;
>>>> ++}
>>>
>>> I'm supposed to have a
>>> /sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/something/airtime
>>> right?
>>
>> Yeah, you should. Do you have
>> /sys/kernel/debug/ieee80211/phy0/ath9k/airtime_flags ?
>
> Yes I do. It's set to 7

Right, that means that the patch was applied correctly. That you don't
have the per-station airtime stats file is probably a configuration
issue, then. Did you set CONFIG_PACKAGE_ATH_DEBUG?

What's the output of

grep STATION_STATISTICS build_dir/target-mips_24kc_musl-1.1.15/linux-ar71xx_generic/compat-wireless-2016-10-08/.config


(substitute the right build dir if you are building with a different
musl version).

-Toke
Weedy Nov. 28, 2016, 10:16 a.m. UTC | #5
On Mon, Nov 28, 2016 at 4:49 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
> Right, that means that the patch was applied correctly. That you don't
> have the per-station airtime stats file is probably a configuration
> issue, then. Did you set CONFIG_PACKAGE_ATH_DEBUG?
>
> What's the output of
>
> grep STATION_STATISTICS build_dir/target-mips_24kc_musl-1.1.15/linux-ar71xx_generic/compat-wireless-2016-10-08/.config
>
>
> (substitute the right build dir if you are building with a different
> musl version).

I didn't know I had to change anything.

If this a RFC or a done deal? Should I enable more debugging a post
results, or it the fact my WiFi still works enough to get this merged?
Toke Høiland-Jørgensen Nov. 28, 2016, 10:48 a.m. UTC | #6
Weedy <weedy2887@gmail.com> writes:

> On Mon, Nov 28, 2016 at 4:49 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
>> Right, that means that the patch was applied correctly. That you don't
>> have the per-station airtime stats file is probably a configuration
>> issue, then. Did you set CONFIG_PACKAGE_ATH_DEBUG?
>>
>> What's the output of
>>
>> grep STATION_STATISTICS build_dir/target-mips_24kc_musl-1.1.15/linux-ar71xx_generic/compat-wireless-2016-10-08/.config
>>
>>
>> (substitute the right build dir if you are building with a different
>> musl version).
>
> I didn't know I had to change anything.

You don't for the patch to function. Just for the stats.

> If this a RFC or a done deal? Should I enable more debugging a post
> results, or it the fact my WiFi still works enough to get this merged?

As far as I'm concerned, this is ready for inclusion. Though the people
with merge rights may disagree, of course. :)

I did get a minor issue pointed out to me on linux-wireless, will
re-send the LEDE patch with the fix in a bit...

-Toke
bart van zoest Nov. 28, 2016, 1:58 p.m. UTC | #7
Hi Weedy and Toke,

I am trying to apply the patch using: "curl
https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v". Is the
following output normal?

<stdin>:60: trailing whitespace.
 <stdin>:65: trailing whitespace.
 <stdin>:67: space before tab in indent.
     bool has_queued;
<stdin>:69: trailing whitespace.
 <stdin>:74: space before tab in indent.
     struct ath_softc *sc;
Checking patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch...
Applied patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
cleanly.
warning: squelched 152 whitespace errors
warning: 157 lines add whitespace errors.

On Sun, Nov 27, 2016 at 12:08 PM, Weedy <weedy2887@gmail.com> wrote:
>
> On Fri, Nov 25, 2016 at 5:16 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
> > This adds a patch that introduces airtime fairness scheduling to ath9k,
> > which can significantly improve network efficiency in mixed-rate
> > environments.
> ...
> > ++      astats = &an->airtime_stats;
> > ++
> > ++      len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
> > ++      len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
> > ++      len += scnprintf(buf + len, size - len, "Deficit: ");
> > ++      for (i = 0; i < 4; i++)
> > ++              len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
> > ++      if (len < size)
> > ++              buf[len++] = '\n';
> > ++
> > ++      retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
> > ++      kfree(buf);
> > ++
> > ++      return retval;
> > ++}
>
> I'm supposed to have a
> /sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/something/airtime
> right?
> Should I have done anything else besides:
> # curl https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v
> # make V=s package/mac80211/{clean,install}
> Applying ./patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
> using plaintext:
> patching file drivers/net/wireless/ath/ath9k/ath9k.h
> patching file drivers/net/wireless/ath/ath9k/channel.c
> patching file drivers/net/wireless/ath/ath9k/debug.c
> patching file drivers/net/wireless/ath/ath9k/debug.h
> patching file drivers/net/wireless/ath/ath9k/debug_sta.c
> patching file drivers/net/wireless/ath/ath9k/init.c
> patching file drivers/net/wireless/ath/ath9k/main.c
> patching file drivers/net/wireless/ath/ath9k/recv.c
> patching file drivers/net/wireless/ath/ath9k/xmit.c
>
> # <the rest of my install stuff>
>
> Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.595812] PCI:
> Enabling device 0000:00:11.0 (0000 -> 0002)
> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.606388] ath: phy0:
> Ignoring endianness difference in EEPROM magic bytes.
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614943] ath: EEPROM
> regdomain: 0x0
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614952] ath: EEPROM
> indicates default country code should be used
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614960] ath: doing
> EEPROM country->regdmn map search
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614975] ath:
> country maps to regdmn code: 0x3a
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614985] ath:
> Country alpha2 being used: US
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614993] ath:
> Regpair used: 0x3a
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.628327] ieee80211
> phy0: Selected rate control algorithm 'minstrel_ht'
> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.632241] ieee80211
> phy0: Atheros AR9280 Rev:2 mem=0xb0000000, irq=40
> Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.697119] PCI:
> Enabling device 0000:00:12.0 (0000 -> 0002)
> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.707690] ath: phy1:
> Ignoring endianness difference in EEPROM magic bytes.
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716278] ath: EEPROM
> regdomain: 0x0
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716289] ath: EEPROM
> indicates default country code should be used
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716297] ath: doing
> EEPROM country->regdmn map search
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716313] ath:
> country maps to regdmn code: 0x3a
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716322] ath:
> Country alpha2 being used: US
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716330] ath:
> Regpair used: 0x3a
> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.731825] ieee80211
> phy1: Selected rate control algorithm 'minstrel_ht'
> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.735844] ieee80211
> phy1: Atheros AR9280 Rev:2 mem=0xb0010000, irq=41
>
> I can't seem to tell if I have the patched driver loaded. Unless
> rc_stats counts?
>               best   ____________rate__________
> ________statistics________    ________last_______
> ______sum-of________
> mode guard #  rate  [name   idx airtime  max_tp]  [avg(tp) avg(prob)
> sd(prob)]  [prob.|retry|suc|att]  [#success | #attempts]
>
> _______________________________________________
> Lede-dev mailing list
> Lede-dev@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev
Toke Høiland-Jørgensen Nov. 28, 2016, 2:08 p.m. UTC | #8
bart van zoest <bartvanzoest@gmail.com> writes:

> Hi Weedy and Toke,
>
> I am trying to apply the patch using: "curl https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v". Is the following output normal?
>
> <stdin>:60: trailing whitespace.
>  <stdin>:65: trailing whitespace.
>  <stdin>:67: space before tab in indent.
>      bool has_queued;
> <stdin>:69: trailing whitespace.
>  <stdin>:74: space before tab in indent.
>      struct ath_softc *sc;
> Checking patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch...
> Applied patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch cleanly.
> warning: squelched 152 whitespace errors
> warning: 157 lines add whitespace errors.

Looks like curl is mangling the whitespace. Don't think it matters; if
the mac80211 package still compiles you are probably fine :)

-Toke
John Crispin Nov. 28, 2016, 2:09 p.m. UTC | #9
On 28/11/2016 14:58, bart van zoest wrote:
> Hi Weedy and Toke,
> 
> I am trying to apply the patch using: "curl
> https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v". Is the
> following output normal?
> 
> <stdin>:60: trailing whitespace.
>  <stdin>:65: trailing whitespace.
>  <stdin>:67: space before tab in indent.
>      bool has_queued;
> <stdin>:69: trailing whitespace.
>  <stdin>:74: space before tab in indent.
>      struct ath_softc *sc;
> Checking patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch...
> Applied patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
> cleanly.
> warning: squelched 152 whitespace errors
> warning: 157 lines add whitespace errors.

these types of messages are nortmal as you are applying a patch that
adds a patch which will be applied during build.

	John

> 
> On Sun, Nov 27, 2016 at 12:08 PM, Weedy <weedy2887@gmail.com> wrote:
>>
>> On Fri, Nov 25, 2016 at 5:16 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
>>> This adds a patch that introduces airtime fairness scheduling to ath9k,
>>> which can significantly improve network efficiency in mixed-rate
>>> environments.
>> ...
>>> ++      astats = &an->airtime_stats;
>>> ++
>>> ++      len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
>>> ++      len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
>>> ++      len += scnprintf(buf + len, size - len, "Deficit: ");
>>> ++      for (i = 0; i < 4; i++)
>>> ++              len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
>>> ++      if (len < size)
>>> ++              buf[len++] = '\n';
>>> ++
>>> ++      retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
>>> ++      kfree(buf);
>>> ++
>>> ++      return retval;
>>> ++}
>>
>> I'm supposed to have a
>> /sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/something/airtime
>> right?
>> Should I have done anything else besides:
>> # curl https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v
>> # make V=s package/mac80211/{clean,install}
>> Applying ./patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
>> using plaintext:
>> patching file drivers/net/wireless/ath/ath9k/ath9k.h
>> patching file drivers/net/wireless/ath/ath9k/channel.c
>> patching file drivers/net/wireless/ath/ath9k/debug.c
>> patching file drivers/net/wireless/ath/ath9k/debug.h
>> patching file drivers/net/wireless/ath/ath9k/debug_sta.c
>> patching file drivers/net/wireless/ath/ath9k/init.c
>> patching file drivers/net/wireless/ath/ath9k/main.c
>> patching file drivers/net/wireless/ath/ath9k/recv.c
>> patching file drivers/net/wireless/ath/ath9k/xmit.c
>>
>> # <the rest of my install stuff>
>>
>> Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.595812] PCI:
>> Enabling device 0000:00:11.0 (0000 -> 0002)
>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.606388] ath: phy0:
>> Ignoring endianness difference in EEPROM magic bytes.
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614943] ath: EEPROM
>> regdomain: 0x0
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614952] ath: EEPROM
>> indicates default country code should be used
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614960] ath: doing
>> EEPROM country->regdmn map search
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614975] ath:
>> country maps to regdmn code: 0x3a
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614985] ath:
>> Country alpha2 being used: US
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614993] ath:
>> Regpair used: 0x3a
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.628327] ieee80211
>> phy0: Selected rate control algorithm 'minstrel_ht'
>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.632241] ieee80211
>> phy0: Atheros AR9280 Rev:2 mem=0xb0000000, irq=40
>> Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.697119] PCI:
>> Enabling device 0000:00:12.0 (0000 -> 0002)
>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.707690] ath: phy1:
>> Ignoring endianness difference in EEPROM magic bytes.
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716278] ath: EEPROM
>> regdomain: 0x0
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716289] ath: EEPROM
>> indicates default country code should be used
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716297] ath: doing
>> EEPROM country->regdmn map search
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716313] ath:
>> country maps to regdmn code: 0x3a
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716322] ath:
>> Country alpha2 being used: US
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716330] ath:
>> Regpair used: 0x3a
>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.731825] ieee80211
>> phy1: Selected rate control algorithm 'minstrel_ht'
>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.735844] ieee80211
>> phy1: Atheros AR9280 Rev:2 mem=0xb0010000, irq=41
>>
>> I can't seem to tell if I have the patched driver loaded. Unless
>> rc_stats counts?
>>               best   ____________rate__________
>> ________statistics________    ________last_______
>> ______sum-of________
>> mode guard #  rate  [name   idx airtime  max_tp]  [avg(tp) avg(prob)
>> sd(prob)]  [prob.|retry|suc|att]  [#success | #attempts]
>>
>> _______________________________________________
>> Lede-dev mailing list
>> Lede-dev@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/lede-dev
> 
> _______________________________________________
> Lede-dev mailing list
> Lede-dev@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev
>
bart van zoest Nov. 28, 2016, 6:35 p.m. UTC | #10
Thanks John and Toke,

The build compiled fine however I am not able to test it (atm no
access to router).
Also saw that Toke released v2 of the patch so my box is compiling again

On Mon, Nov 28, 2016 at 3:09 PM, John Crispin <john@phrozen.org> wrote:
>
>
> On 28/11/2016 14:58, bart van zoest wrote:
>> Hi Weedy and Toke,
>>
>> I am trying to apply the patch using: "curl
>> https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v". Is the
>> following output normal?
>>
>> <stdin>:60: trailing whitespace.
>>  <stdin>:65: trailing whitespace.
>>  <stdin>:67: space before tab in indent.
>>      bool has_queued;
>> <stdin>:69: trailing whitespace.
>>  <stdin>:74: space before tab in indent.
>>      struct ath_softc *sc;
>> Checking patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch...
>> Applied patch package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
>> cleanly.
>> warning: squelched 152 whitespace errors
>> warning: 157 lines add whitespace errors.
>
> these types of messages are nortmal as you are applying a patch that
> adds a patch which will be applied during build.
>
>         John
>
>>
>> On Sun, Nov 27, 2016 at 12:08 PM, Weedy <weedy2887@gmail.com> wrote:
>>>
>>> On Fri, Nov 25, 2016 at 5:16 AM, Toke Høiland-Jørgensen <toke@toke.dk> wrote:
>>>> This adds a patch that introduces airtime fairness scheduling to ath9k,
>>>> which can significantly improve network efficiency in mixed-rate
>>>> environments.
>>> ...
>>>> ++      astats = &an->airtime_stats;
>>>> ++
>>>> ++      len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
>>>> ++      len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
>>>> ++      len += scnprintf(buf + len, size - len, "Deficit: ");
>>>> ++      for (i = 0; i < 4; i++)
>>>> ++              len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
>>>> ++      if (len < size)
>>>> ++              buf[len++] = '\n';
>>>> ++
>>>> ++      retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
>>>> ++      kfree(buf);
>>>> ++
>>>> ++      return retval;
>>>> ++}
>>>
>>> I'm supposed to have a
>>> /sys/kernel/debug/ieee80211/phy0/netdev\:wlan0/stations/something/airtime
>>> right?
>>> Should I have done anything else besides:
>>> # curl https://patchwork.ozlabs.org/patch/699159/raw/ | git apply -v
>>> # make V=s package/mac80211/{clean,install}
>>> Applying ./patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
>>> using plaintext:
>>> patching file drivers/net/wireless/ath/ath9k/ath9k.h
>>> patching file drivers/net/wireless/ath/ath9k/channel.c
>>> patching file drivers/net/wireless/ath/ath9k/debug.c
>>> patching file drivers/net/wireless/ath/ath9k/debug.h
>>> patching file drivers/net/wireless/ath/ath9k/debug_sta.c
>>> patching file drivers/net/wireless/ath/ath9k/init.c
>>> patching file drivers/net/wireless/ath/ath9k/main.c
>>> patching file drivers/net/wireless/ath/ath9k/recv.c
>>> patching file drivers/net/wireless/ath/ath9k/xmit.c
>>>
>>> # <the rest of my install stuff>
>>>
>>> Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.595812] PCI:
>>> Enabling device 0000:00:11.0 (0000 -> 0002)
>>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.606388] ath: phy0:
>>> Ignoring endianness difference in EEPROM magic bytes.
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614943] ath: EEPROM
>>> regdomain: 0x0
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614952] ath: EEPROM
>>> indicates default country code should be used
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614960] ath: doing
>>> EEPROM country->regdmn map search
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614975] ath:
>>> country maps to regdmn code: 0x3a
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614985] ath:
>>> Country alpha2 being used: US
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.614993] ath:
>>> Regpair used: 0x3a
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.628327] ieee80211
>>> phy0: Selected rate control algorithm 'minstrel_ht'
>>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.632241] ieee80211
>>> phy0: Atheros AR9280 Rev:2 mem=0xb0000000, irq=40
>>> Sat Nov 26 16:39:31 2016 kern.warn kernel: [   11.697119] PCI:
>>> Enabling device 0000:00:12.0 (0000 -> 0002)
>>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.707690] ath: phy1:
>>> Ignoring endianness difference in EEPROM magic bytes.
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716278] ath: EEPROM
>>> regdomain: 0x0
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716289] ath: EEPROM
>>> indicates default country code should be used
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716297] ath: doing
>>> EEPROM country->regdmn map search
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716313] ath:
>>> country maps to regdmn code: 0x3a
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716322] ath:
>>> Country alpha2 being used: US
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.716330] ath:
>>> Regpair used: 0x3a
>>> Sat Nov 26 16:39:31 2016 kern.debug kernel: [   11.731825] ieee80211
>>> phy1: Selected rate control algorithm 'minstrel_ht'
>>> Sat Nov 26 16:39:31 2016 kern.info kernel: [   11.735844] ieee80211
>>> phy1: Atheros AR9280 Rev:2 mem=0xb0010000, irq=41
>>>
>>> I can't seem to tell if I have the patched driver loaded. Unless
>>> rc_stats counts?
>>>               best   ____________rate__________
>>> ________statistics________    ________last_______
>>> ______sum-of________
>>> mode guard #  rate  [name   idx airtime  max_tp]  [avg(tp) avg(prob)
>>> sd(prob)]  [prob.|retry|suc|att]  [#success | #attempts]
>>>
>>> _______________________________________________
>>> Lede-dev mailing list
>>> Lede-dev@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/lede-dev
>>
>> _______________________________________________
>> Lede-dev mailing list
>> Lede-dev@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/lede-dev
>>
>
> _______________________________________________
> Lede-dev mailing list
> Lede-dev@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev
diff mbox

Patch

diff --git a/package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch b/package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
new file mode 100644
index 0000000..52d0d69
--- /dev/null
+++ b/package/kernel/mac80211/patches/326-ath9k-Introduce-airtime-fairness-scheduling.patch
@@ -0,0 +1,695 @@ 
+From 11c70d8df13d0f3d18852df4cf5a0365cf7c82b3 Mon Sep 17 00:00:00 2001
+In-Reply-To: <20160617090929.31606-1-toke@toke.dk>
+References: <20160617090929.31606-1-toke@toke.dk>
+From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
+Date: Wed, 22 Jun 2016 13:48:14 +0200
+Subject: [PATCH v2] ath9k: Introduce airtime fairness scheduling between
+ stations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reworks the ath9k driver to schedule transmissions to connected
+stations in a way that enforces airtime fairness between them. It
+accomplishes this by measuring the time spent transmitting to or
+receiving from a station at TX and RX completion, and accounting this to
+a per-station, per-QoS level airtime deficit. Then, an FQ-CoDel based
+deficit scheduler is employed at packet dequeue time, to control which
+station gets the next transmission opportunity.
+
+Airtime fairness can significantly improve the efficiency of the network
+when station rates vary. The following throughput values are from a
+simple three-station test scenario, where two stations operate at the
+highest HT20 rate, and one station at the lowest, and the scheduler is
+employed at the access point:
+
+                  Before   /   After
+Fast station 1:    19.17   /   25.09 Mbps
+Fast station 2:    19.83   /   25.21 Mbps
+Slow station:       2.58   /    1.77 Mbps
+Total:             41.58   /   52.07 Mbps
+
+The benefit of airtime fairness goes up the more stations are present.
+In a 30-station test with one station artificially limited to 1 Mbps,
+we have seen aggregate throughput go from 2.14 to 17.76 Mbps.
+
+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
+---
+ drivers/net/wireless/ath/ath9k/ath9k.h     |  28 ++++-
+ drivers/net/wireless/ath/ath9k/channel.c   |  26 ++++-
+ drivers/net/wireless/ath/ath9k/debug.c     |   3 +
+ drivers/net/wireless/ath/ath9k/debug.h     |  13 +++
+ drivers/net/wireless/ath/ath9k/debug_sta.c |  54 +++++++++
+ drivers/net/wireless/ath/ath9k/init.c      |   2 +
+ drivers/net/wireless/ath/ath9k/main.c      |   6 +-
+ drivers/net/wireless/ath/ath9k/recv.c      |  65 +++++++++++
+ drivers/net/wireless/ath/ath9k/xmit.c      | 177 +++++++++++++++++++++--------
+ 9 files changed, 318 insertions(+), 56 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -112,6 +112,8 @@ int ath_descdma_setup(struct ath_softc *
+ #define ATH_TXFIFO_DEPTH           8
+ #define ATH_TX_ERROR               0x01
+ 
++#define ATH_AIRTIME_QUANTUM        300 /* usec */
++
+ /* Stop tx traffic 1ms before the GO goes away */
+ #define ATH_P2P_PS_STOP_TIME       1000
+ 
+@@ -247,6 +249,9 @@ struct ath_atx_tid {
+ 	bool has_queued;
+ };
+ 
++void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
++void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid);
++
+ struct ath_node {
+ 	struct ath_softc *sc;
+ 	struct ieee80211_sta *sta; /* station struct we're part of */
+@@ -258,9 +263,12 @@ struct ath_node {
+ 
+ 	bool sleeping;
+ 	bool no_ps_filter;
++	s64 airtime_deficit[IEEE80211_NUM_ACS];
++	u32 airtime_rx_start;
+ 
+ #ifdef CPTCFG_ATH9K_STATION_STATISTICS
+ 	struct ath_rx_rate_stats rx_rate_stats;
++	struct ath_airtime_stats airtime_stats;
+ #endif
+ 	u8 key_idx[4];
+ 
+@@ -317,10 +325,16 @@ struct ath_rx {
+ /* Channel Context */
+ /*******************/
+ 
++struct ath_acq {
++	struct list_head acq_new;
++	struct list_head acq_old;
++	spinlock_t lock;
++};
++
+ struct ath_chanctx {
+ 	struct cfg80211_chan_def chandef;
+ 	struct list_head vifs;
+-	struct list_head acq[IEEE80211_NUM_ACS];
++	struct ath_acq acq[IEEE80211_NUM_ACS];
+ 	int hw_queue_base;
+ 
+ 	/* do not dereference, use for comparison only */
+@@ -443,6 +457,9 @@ void ath_chanctx_init(struct ath_softc *
+ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+ 			     struct cfg80211_chan_def *chandef);
+ 
++void ath_acq_lock(struct ath_softc *sc, struct ath_acq *acq);
++void ath_acq_unlock(struct ath_softc *sc, struct ath_acq *acq);
++
+ #ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+ 
+ static inline struct ath_chanctx *
+@@ -575,6 +592,8 @@ void ath_txq_schedule_all(struct ath_sof
+ int ath_tx_init(struct ath_softc *sc, int nbufs);
+ int ath_txq_update(struct ath_softc *sc, int qnum,
+ 		   struct ath9k_tx_queue_info *q);
++u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
++		     int width, int half_gi, bool shortPreamble);
+ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
+ void ath_assign_seq(struct ath_common *common, struct sk_buff *skb);
+ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -963,6 +982,11 @@ void ath_ant_comb_scan(struct ath_softc
+ 
+ #define ATH9K_NUM_CHANCTX  2 /* supports 2 operating channels */
+ 
++#define AIRTIME_USE_TX		BIT(0)
++#define AIRTIME_USE_RX		BIT(1)
++#define AIRTIME_USE_NEW_QUEUES	BIT(2)
++#define AIRTIME_ACTIVE(flags) (!!(flags & (AIRTIME_USE_TX|AIRTIME_USE_RX)))
++
+ struct ath_softc {
+ 	struct ieee80211_hw *hw;
+ 	struct device *dev;
+@@ -1005,6 +1029,8 @@ struct ath_softc {
+ 	short nbcnvifs;
+ 	unsigned long ps_usecount;
+ 
++	u16 airtime_flags; /* AIRTIME_* */
++
+ 	struct ath_rx rx;
+ 	struct ath_tx tx;
+ 	struct ath_beacon beacon;
+--- a/drivers/net/wireless/ath/ath9k/channel.c
++++ b/drivers/net/wireless/ath/ath9k/channel.c
+@@ -118,8 +118,11 @@ void ath_chanctx_init(struct ath_softc *
+ 		INIT_LIST_HEAD(&ctx->vifs);
+ 		ctx->txpower = ATH_TXPOWER_MAX;
+ 		ctx->flush_timeout = HZ / 5; /* 200ms */
+-		for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
+-			INIT_LIST_HEAD(&ctx->acq[j]);
++		for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) {
++			INIT_LIST_HEAD(&ctx->acq[j].acq_new);
++			INIT_LIST_HEAD(&ctx->acq[j].acq_old);
++			spin_lock_init(&ctx->acq[j].lock);
++		}
+ 	}
+ }
+ 
+@@ -144,6 +147,18 @@ void ath_chanctx_set_channel(struct ath_
+ 	ath_set_channel(sc);
+ }
+ 
++void ath_acq_lock(struct ath_softc *sc, struct ath_acq *acq)
++	__acquires(&acq->lock)
++{
++	spin_lock_bh(&acq->lock);
++}
++
++void ath_acq_unlock(struct ath_softc *sc, struct ath_acq *acq)
++	__releases(&acq->lock)
++{
++	spin_unlock_bh(&acq->lock);
++}
++
+ #ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT
+ 
+ /*************/
+@@ -1345,8 +1360,11 @@ void ath9k_offchannel_init(struct ath_so
+ 	ctx->txpower = ATH_TXPOWER_MAX;
+ 	cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+ 
+-	for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
+-		INIT_LIST_HEAD(&ctx->acq[i]);
++	for (i = 0; i < ARRAY_SIZE(ctx->acq); i++) {
++		INIT_LIST_HEAD(&ctx->acq[i].acq_new);
++		INIT_LIST_HEAD(&ctx->acq[i].acq_old);
++		spin_lock_init(&ctx->acq[i].lock);
++	}
+ 
+ 	sc->offchannel.chan.offchannel = true;
+ }
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -1399,5 +1399,8 @@ int ath9k_init_debug(struct ath_hw *ah)
+ 	debugfs_create_file("tpc", S_IRUSR | S_IWUSR,
+ 			    sc->debug.debugfs_phy, sc, &fops_tpc);
+ 
++	debugfs_create_u16("airtime_flags", S_IRUSR | S_IWUSR,
++			   sc->debug.debugfs_phy, &sc->airtime_flags);
++
+ 	return 0;
+ }
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -221,6 +221,11 @@ struct ath_rx_rate_stats {
+ 	} cck_stats[4];
+ };
+ 
++struct ath_airtime_stats {
++	u32 rx_airtime;
++	u32 tx_airtime;
++};
++
+ #define ANT_MAIN 0
+ #define ANT_ALT  1
+ 
+@@ -314,12 +319,20 @@ ath9k_debug_sync_cause(struct ath_softc
+ void ath_debug_rate_stats(struct ath_softc *sc,
+ 			  struct ath_rx_status *rs,
+ 			  struct sk_buff *skb);
++void ath_debug_airtime(struct ath_softc *sc,
++		       struct ath_node *an,
++		       u32 rx, u32 tx);
+ #else
+ static inline void ath_debug_rate_stats(struct ath_softc *sc,
+ 					struct ath_rx_status *rs,
+ 					struct sk_buff *skb)
+ {
+ }
++static inline void ath_debug_airtime(struct ath_softc *sc,
++			      struct ath_node *an,
++			      u32 rx, u32 tx)
++{
++}
+ #endif /* CPTCFG_ATH9K_STATION_STATISTICS */
+ 
+ #endif /* DEBUG_H */
+--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
++++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
+@@ -242,6 +242,59 @@ static const struct file_operations fops
+ 	.llseek = default_llseek,
+ };
+ 
++void ath_debug_airtime(struct ath_softc *sc,
++		struct ath_node *an,
++		u32 rx,
++		u32 tx)
++{
++	struct ath_airtime_stats *astats = &an->airtime_stats;
++
++	astats->rx_airtime += rx;
++	astats->tx_airtime += tx;
++}
++
++static ssize_t read_airtime(struct file *file, char __user *user_buf,
++			size_t count, loff_t *ppos)
++{
++	struct ath_node *an = file->private_data;
++	struct ath_airtime_stats *astats;
++	static const char *qname[4] = {
++		"VO", "VI", "BE", "BK"
++	};
++	u32 len = 0, size = 256;
++	char *buf;
++	size_t retval;
++	int i;
++
++	buf = kzalloc(size, GFP_KERNEL);
++	if (buf == NULL)
++		return -ENOMEM;
++
++	astats = &an->airtime_stats;
++
++	len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
++	len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
++	len += scnprintf(buf + len, size - len, "Deficit: ");
++	for (i = 0; i < 4; i++)
++		len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
++	if (len < size)
++		buf[len++] = '\n';
++
++	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++	kfree(buf);
++
++	return retval;
++}
++
++
++static const struct file_operations fops_airtime = {
++	.read = read_airtime,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
++
+ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
+ 			   struct ieee80211_vif *vif,
+ 			   struct ieee80211_sta *sta,
+@@ -251,4 +304,5 @@ void ath9k_sta_add_debugfs(struct ieee80
+ 
+ 	debugfs_create_file("node_aggr", S_IRUGO, dir, an, &fops_node_aggr);
+ 	debugfs_create_file("node_recv", S_IRUGO, dir, an, &fops_node_recv);
++	debugfs_create_file("airtime", S_IRUGO, dir, an, &fops_airtime);
+ }
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -582,6 +582,8 @@ static int ath9k_init_softc(u16 devid, s
+ 
+ 	/* Will be cleared in ath9k_start() */
+ 	set_bit(ATH_OP_INVALID, &common->op_flags);
++	sc->airtime_flags = (AIRTIME_USE_TX | AIRTIME_USE_RX |
++			     AIRTIME_USE_NEW_QUEUES);
+ 
+ 	sc->sc_ah = ah;
+ 	sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET);
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -70,10 +70,10 @@ static bool ath9k_has_pending_frames(str
+ 		goto out;
+ 
+ 	if (txq->mac80211_qnum >= 0) {
+-		struct list_head *list;
++		struct ath_acq *acq;
+ 
+-		list = &sc->cur_chan->acq[txq->mac80211_qnum];
+-		if (!list_empty(list))
++		acq = &sc->cur_chan->acq[txq->mac80211_qnum];
++		if (!list_empty(&acq->acq_new) || !list_empty(&acq->acq_old))
+ 			pending = true;
+ 	}
+ out:
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -991,6 +991,70 @@ static void ath9k_apply_ampdu_details(st
+ 	}
+ }
+ 
++static void ath_rx_count_airtime(struct ath_softc *sc,
++				 struct ath_rx_status *rs,
++				 struct sk_buff *skb)
++{
++	struct ath_node *an;
++	struct ath_acq *acq;
++	struct ath_vif *avp;
++	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
++	struct ath_hw *ah = sc->sc_ah;
++	struct ath_common *common = ath9k_hw_common(ah);
++	struct ieee80211_sta *sta;
++	struct ieee80211_rx_status *rxs;
++	const struct ieee80211_rate *rate;
++	bool is_sgi, is_40, is_sp;
++	int phy;
++	u16 len = rs->rs_datalen;
++	u32 airtime = 0;
++	u8 tidno, acno;
++
++	if (!ieee80211_is_data(hdr->frame_control))
++		return;
++
++	rcu_read_lock();
++
++	sta = ieee80211_find_sta_by_ifaddr(sc->hw, hdr->addr2, NULL);
++	if (!sta)
++		goto exit;
++	an = (struct ath_node *) sta->drv_priv;
++	avp = (struct ath_vif *) an->vif->drv_priv;
++	tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
++	acno = TID_TO_WME_AC(tidno);
++	acq = &avp->chanctx->acq[acno];
++
++	rxs = IEEE80211_SKB_RXCB(skb);
++
++	is_sgi = !!(rxs->flag & RX_FLAG_SHORT_GI);
++	is_40 = !!(rxs->flag & RX_FLAG_40MHZ);
++	is_sp = !!(rxs->flag & RX_FLAG_SHORTPRE);
++
++	if (!!(rxs->flag & RX_FLAG_HT)) {
++		/* MCS rates */
++
++		airtime += ath_pkt_duration(sc, rxs->rate_idx, len,
++					is_40, is_sgi, is_sp);
++	} else {
++
++		phy = IS_CCK_RATE(rs->rs_rate) ? WLAN_RC_PHY_CCK : WLAN_RC_PHY_OFDM;
++		rate = &common->sbands[rxs->band].bitrates[rxs->rate_idx];
++		airtime += ath9k_hw_computetxtime(ah, phy, rate->bitrate * 100,
++						len, rxs->rate_idx, is_sp);
++	}
++
++ 	if (!!(sc->airtime_flags & AIRTIME_USE_RX)) {
++		ath_acq_lock(sc, acq);
++		an->airtime_deficit[acno] -= airtime;
++		if (an->airtime_deficit[acno] <= 0)
++			__ath_tx_queue_tid(sc, ATH_AN_2_TID(an, tidno));
++		ath_acq_unlock(sc, acq);
++	}
++	ath_debug_airtime(sc, an, airtime, 0);
++exit:
++	rcu_read_unlock();
++}
++
+ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
+ {
+ 	struct ath_rxbuf *bf;
+@@ -1137,6 +1201,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
+ 		ath9k_antenna_check(sc, &rs);
+ 		ath9k_apply_ampdu_details(sc, &rs, rxs);
+ 		ath_debug_rate_stats(sc, &rs, skb);
++		ath_rx_count_airtime(sc, &rs, skb);
+ 
+ 		hdr = (struct ieee80211_hdr *)skb->data;
+ 		if (ieee80211_is_ack(hdr->frame_control))
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -125,21 +125,44 @@ void ath_txq_unlock_complete(struct ath_
+ 		ath_tx_status(hw, skb);
+ }
+ 
+-static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
+-			     struct ath_atx_tid *tid)
++void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+ {
+-	struct list_head *list;
+ 	struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
+ 	struct ath_chanctx *ctx = avp->chanctx;
++	struct ath_acq *acq;
++	struct list_head *tid_list;
++	u8 acno = TID_TO_WME_AC(tid->tidno);
+ 
+-	if (!ctx)
++	if (!ctx || !list_empty(&tid->list))
+ 		return;
+ 
+-	list = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
+-	if (list_empty(&tid->list))
+-		list_add_tail(&tid->list, list);
++
++	acq = &ctx->acq[acno];
++	if ((sc->airtime_flags & AIRTIME_USE_NEW_QUEUES) &&
++	    tid->an->airtime_deficit[acno] > 0)
++		tid_list = &acq->acq_new;
++	else
++		tid_list = &acq->acq_old;
++
++	list_add_tail(&tid->list, tid_list);
+ }
+ 
++void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
++{
++	struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
++	struct ath_chanctx *ctx = avp->chanctx;
++	struct ath_acq *acq;
++
++	if (!ctx || !list_empty(&tid->list))
++		return;
++
++	acq = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
++	ath_acq_lock(sc, acq);
++	__ath_tx_queue_tid(sc, tid);
++	ath_acq_unlock(sc, acq);
++}
++
++
+ void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+ {
+ 	struct ath_softc *sc = hw->priv;
+@@ -154,7 +177,7 @@ void ath9k_wake_tx_queue(struct ieee8021
+ 	ath_txq_lock(sc, txq);
+ 
+ 	tid->has_queued = true;
+-	ath_tx_queue_tid(sc, txq, tid);
++	ath_tx_queue_tid(sc, tid);
+ 	ath_txq_schedule(sc, txq);
+ 
+ 	ath_txq_unlock(sc, txq);
+@@ -684,7 +707,7 @@ static void ath_tx_complete_aggr(struct
+ 
+ 		skb_queue_splice_tail(&bf_pending, &tid->retry_q);
+ 		if (!an->sleeping) {
+-			ath_tx_queue_tid(sc, txq, tid);
++			ath_tx_queue_tid(sc, tid);
+ 
+ 			if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
+ 				tid->clear_ps_filter = true;
+@@ -712,6 +735,53 @@ static bool bf_is_ampdu_not_probing(stru
+     return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+ }
+ 
++static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_txq *txq,
++				 struct ath_buf *bf, struct ath_tx_status *ts)
++{
++	struct ath_node *an;
++	struct ath_acq *acq = &sc->cur_chan->acq[txq->mac80211_qnum];
++	struct sk_buff *skb;
++	struct ieee80211_hdr *hdr;
++	struct ieee80211_hw *hw = sc->hw;
++	struct ieee80211_tx_rate rates[4];
++	struct ieee80211_sta *sta;
++	int i;
++	u32 airtime = 0;
++
++	skb = bf->bf_mpdu;
++	if(!skb)
++		return;
++
++	hdr = (struct ieee80211_hdr *)skb->data;
++	memcpy(rates, bf->rates, sizeof(rates));
++
++	rcu_read_lock();
++
++	sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
++	if(!sta)
++		goto exit;
++
++
++	an = (struct ath_node *) sta->drv_priv;
++
++	airtime += ts->duration * (ts->ts_longretry + 1);
++
++	for(i=0; i < ts->ts_rateindex; i++)
++		airtime += ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, i) * rates[i].count;
++
++	if (!!(sc->airtime_flags & AIRTIME_USE_TX)) {
++		ath_acq_lock(sc, acq);
++		an->airtime_deficit[txq->mac80211_qnum] -= airtime;
++		if (an->airtime_deficit[txq->mac80211_qnum] <= 0)
++			__ath_tx_queue_tid(sc, ath_get_skb_tid(sc, an, skb));
++		ath_acq_unlock(sc, acq);
++	}
++	ath_debug_airtime(sc, an, 0, airtime);
++
++exit:
++	rcu_read_unlock();
++}
++
+ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
+ 				  struct ath_tx_status *ts, struct ath_buf *bf,
+ 				  struct list_head *bf_head)
+@@ -733,6 +803,7 @@ static void ath_tx_process_buffer(struct
+ 
+ 	ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc,
+ 					     ts->ts_rateindex);
++	ath_tx_count_airtime(sc, txq, bf, ts);
+ 
+ 	hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
+ 	sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2);
+@@ -1094,8 +1165,8 @@ finish:
+  * width  - 0 for 20 MHz, 1 for 40 MHz
+  * half_gi - to use 4us v/s 3.6 us for symbol time
+  */
+-static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
+-			    int width, int half_gi, bool shortPreamble)
++u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
++		     int width, int half_gi, bool shortPreamble)
+ {
+ 	u32 nbits, nsymbits, duration, nsymbols;
+ 	int streams;
+@@ -1493,7 +1564,7 @@ ath_tx_form_burst(struct ath_softc *sc,
+ }
+ 
+ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
+-			      struct ath_atx_tid *tid, bool *stop)
++			      struct ath_atx_tid *tid)
+ {
+ 	struct ath_buf *bf;
+ 	struct ieee80211_tx_info *tx_info;
+@@ -1515,7 +1586,6 @@ static bool ath_tx_sched_aggr(struct ath
+ 	if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
+ 	    (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ 		__skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+-		*stop = true;
+ 		return false;
+ 	}
+ 
+@@ -1639,7 +1709,7 @@ void ath_tx_aggr_wakeup(struct ath_softc
+ 		ath_txq_lock(sc, txq);
+ 		tid->clear_ps_filter = true;
+ 		if (ath_tid_has_buffered(tid)) {
+-			ath_tx_queue_tid(sc, txq, tid);
++			ath_tx_queue_tid(sc, tid);
+ 			ath_txq_schedule(sc, txq);
+ 		}
+ 		ath_txq_unlock_complete(sc, txq);
+@@ -1956,9 +2026,10 @@ void ath_tx_cleanupq(struct ath_softc *s
+ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
+ {
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+-	struct ath_atx_tid *tid, *last_tid;
++	struct ath_atx_tid *tid;
+ 	struct list_head *tid_list;
+-	bool sent = false;
++	struct ath_acq *acq;
++	bool active = AIRTIME_ACTIVE(sc->airtime_flags);
+ 
+ 	if (txq->mac80211_qnum < 0)
+ 		return;
+@@ -1967,48 +2038,55 @@ void ath_txq_schedule(struct ath_softc *
+ 		return;
+ 
+ 	spin_lock_bh(&sc->chan_lock);
+-	tid_list = &sc->cur_chan->acq[txq->mac80211_qnum];
+-
+-	if (list_empty(tid_list)) {
+-		spin_unlock_bh(&sc->chan_lock);
+-		return;
+-	}
+-
+ 	rcu_read_lock();
++	acq = &sc->cur_chan->acq[txq->mac80211_qnum];
+ 
+-	last_tid = list_entry(tid_list->prev, struct ath_atx_tid, list);
+-	while (!list_empty(tid_list)) {
+-		bool stop = false;
+-
+-		if (sc->cur_chan->stopped)
+-			break;
+-
+-		tid = list_first_entry(tid_list, struct ath_atx_tid, list);
+-		list_del_init(&tid->list);
+-
+-		if (ath_tx_sched_aggr(sc, txq, tid, &stop))
+-			sent = true;
+-
+-		/*
+-		 * add tid to round-robin queue if more frames
+-		 * are pending for the tid
+-		 */
+-		if (ath_tid_has_buffered(tid))
+-			ath_tx_queue_tid(sc, txq, tid);
++	if (sc->cur_chan->stopped)
++		goto out;
+ 
+-		if (stop)
+-			break;
++begin:
++	tid_list = &acq->acq_new;
++	if (list_empty(tid_list)) {
++		tid_list = &acq->acq_old;
++		if (list_empty(tid_list))
++			goto out;
++	}
++	tid = list_first_entry(tid_list, struct ath_atx_tid, list);
++
++	if (active && tid->an->airtime_deficit[txq->mac80211_qnum] <= 0) {
++		ath_acq_lock(sc, acq);
++		tid->an->airtime_deficit[txq->mac80211_qnum] += ATH_AIRTIME_QUANTUM;
++		list_move_tail(&tid->list, &acq->acq_old);
++		ath_acq_unlock(sc, acq);
++		goto begin;
++	}
++
++	if (!ath_tid_has_buffered(tid)) {
++		ath_acq_lock(sc, acq);
++		if ((tid_list == &acq->acq_new) && !list_empty(&acq->acq_old))
++			list_move_tail(&tid->list, &acq->acq_old);
++		else {
++			list_del_init(&tid->list);
++		}
++		ath_acq_unlock(sc, acq);
++		goto begin;
++	}
+ 
+-		if (tid == last_tid) {
+-			if (!sent)
+-				break;
+ 
+-			sent = false;
+-			last_tid = list_entry(tid_list->prev,
+-					      struct ath_atx_tid, list);
++	/*
++	 * If we succeed in scheduling something, immediately restart to make
++	 * sure we keep the HW busy.
++	 */
++	if(ath_tx_sched_aggr(sc, txq, tid)) {
++		if (!active) {
++			ath_acq_lock(sc, acq);
++			list_move_tail(&tid->list, &acq->acq_old);
++			ath_acq_unlock(sc, acq);
+ 		}
++		goto begin;
+ 	}
+ 
++out:
+ 	rcu_read_unlock();
+ 	spin_unlock_bh(&sc->chan_lock);
+ }
+@@ -2862,6 +2940,9 @@ void ath_tx_node_init(struct ath_softc *
+ 	struct ath_atx_tid *tid;
+ 	int tidno, acno;
+ 
++	for (acno = 0; acno < IEEE80211_NUM_ACS; acno++)
++		an->airtime_deficit[acno] = ATH_AIRTIME_QUANTUM;
++
+ 	for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ 		tid = ath_node_to_tid(an, tidno);
+ 		tid->an        = an;