* Re: [PATCH] USB: qmi_wwan: add Dell Wireless 5809e Gobi 4G HSPA+ (rev3)
From: Bjørn Mork @ 2016-03-16 11:26 UTC (permalink / raw)
To: Patrik Halfar; +Cc: netdev, linux-usb
In-Reply-To: <1458126825-15753-1-git-send-email-patrik_halfar@halfarit.cz>
Patrik Halfar <patrik_halfar@halfarit.cz> writes:
> --- a/drivers/net/usb/qmi_wwan.c
> +++ b/drivers/net/usb/qmi_wwan.c
> @@ -884,6 +884,7 @@ static const struct usb_device_id products[] = {
> {QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
> {QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
> {QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
> + {QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
> {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
> {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
> {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */
Huh? This is already applied AFAICS:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/net/usb/qmi_wwan.c?id=fb5eb24cdd5cdb83be77d3e4b2f16e92e06bd9e9
Bjørn
^ permalink raw reply
* [PATCH] USB: qmi_wwan: add Dell Wireless 5809e Gobi 4G HSPA+ (rev3)
From: Patrik Halfar @ 2016-03-16 11:13 UTC (permalink / raw)
To: Bjørn Mork; +Cc: Patrik Halfar, netdev, linux-usb
New revison of Dell Wireless 5809e Gobi 4G HSPA+ Mobile Broadband Card has new idProduct
Bus 002 Device 006: ID 413c:81b3 Dell Computer Corp.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x413c Dell Computer Corp.
idProduct 0x81b3
bcdDevice 0.06
iManufacturer 1 Sierra Wireless, Incorporated
iProduct 2 Dell Wireless 5809e Gobi™ 4G HSPA+ Mobile Broadband Card
iSerial 3
bNumConfigurations 2
Signed-off-by: Patrik Halfar <patrik_halfar@halfarit.cz>
---
drivers/net/usb/qmi_wwan.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 23e9880791fc..5ef413305895 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -884,6 +884,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+ {QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
{QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
{QMI_FIXED_INTF(0x1e0e, 0x9001, 5)}, /* SIMCom 7230E */
--
2.4.10
^ permalink raw reply related
* Re: [PATCH net-next v3 1/2] RDS: TCP: Add sysctl tunables for sndbuf/rcvbuf on rds-tcp socket
From: Sowmini Varadhan @ 2016-03-16 11:10 UTC (permalink / raw)
To: Hannes Frederic Sowa; +Cc: netdev, davem, santosh.shilimkar, eric.dumazet
In-Reply-To: <56E93596.90503@stressinduktion.org>
On (03/16/16 11:29), Hannes Frederic Sowa wrote:
> Normally we kmemdup a table per netns and update its data pointer,
> so we can reuse the proc_doint_minmax functions.
I remembered one more thing.. in this particular case, I need to
have my one ->proc_handler, because I need to rds_tcp_sysctl_reset()
existing connections to make them use the new tunable.
--Sowmini
^ permalink raw reply
* Re: [PATCH net-next v3 1/2] RDS: TCP: Add sysctl tunables for sndbuf/rcvbuf on rds-tcp socket
From: Sowmini Varadhan @ 2016-03-16 11:06 UTC (permalink / raw)
To: Hannes Frederic Sowa; +Cc: netdev, davem, santosh.shilimkar, eric.dumazet
In-Reply-To: <56E93596.90503@stressinduktion.org>
On (03/16/16 11:29), Hannes Frederic Sowa wrote:
>
> Normally we kmemdup a table per netns and update its data pointer,
> so we can reuse the proc_doint_minmax functions.
I actually thought of doing a separate kzalloc per netns,
but it seemed like it would be a lot of memory bloat, when really,
all I want is just the per-netns data.
I could go and duplicate the whole table, but is there a significant
benefit to that, or some bad bug with this approach?
One dubious (yes, I know, "solution looking for problem" category)
benefit is that this hack allows me to have both global, and per netns,
tunables... plus the reduced memory footprint (latter is probably
more interesting than former?)
> >+ rtn->rds_tcp_sysctl = register_net_sysctl(net, "net/rds/tcp",
> >+ rds_tcp_sysctl_table);
>
> You should add proper error handling here?
Agree, I will send this out in the next rev.
> >+ rtn->sndbuf_size = max_t(u32, user_atoi(buffer, *lenp) * 2,
> >+ SOCK_MIN_SNDBUF);
>
> user_atoi does return negative error values (as you implemented it),
> I think you should check before, otherwise the signed to unsigned
> conversion can cause huge memory allocations.
yes, good catch, that will have to be split into two lines. Shall
be fixing this in v4.
> Why actually implement user_atoi?
errhm. cut/paste from other drivers that do this. I needed to
do the copy_from_user() + kstrtoul, and user_atoi had some
additional checks that seemed useful.
--Sowmini
^ permalink raw reply
* Re: [PATCH (net-next.git) 2/2] stmmac: fix MDIO settings
From: Andreas Färber @ 2016-03-16 11:03 UTC (permalink / raw)
To: Gabriel Fernandez, Giuseppe Cavallaro
Cc: netdev, fschaefer.oss, Dinh Nguyen, David S. Miller, Phil Reid
In-Reply-To: <CAG374jDJS7TUSx0Ob38x4aRYHyrA+OWeCDm+f-Ytq8YZhwkEqg@mail.gmail.com>
Am 16.03.2016 um 12:01 schrieb Gabriel Fernandez:
> Hi Pepe,
>
> i have a kernel crash
>
> [ 2.714097] Unable to handle kernel NULL pointer dereference at
> virtual address 000001d6
> [ 2.722188] pgd = c0204000
> [ 2.724886] [000001d6] *pgd=00000000
> [ 2.728452] Internal error: Oops: 5 [#1] SMP ARM
> [ 2.733054] Modules linked in:
> [ 2.736095] CPU: 1 PID: 1 Comm: swapper/0 Not tainted
> 4.5.0-rc7-01768-g3407893 #36
> [ 2.743649] Hardware name: STiH415/416 SoC with Flattened Device Tree
> [ 2.750074] task: ee070000 ti: ee05e000 task.ti: ee05e000
> [ 2.755467] PC is at stmmac_open+0xcc/0xc40
> [ 2.759641] LR is at of_phy_connect+0x44/0x5c
>
>
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> index 4c5ce98..943500b 100644
>> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> @@ -278,7 +278,6 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
>> */
>> bool stmmac_eee_init(struct stmmac_priv *priv)
>> {
>> - char *phy_bus_name = priv->plat->phy_bus_name;
>> unsigned long flags;
>> bool ret = false;
>>
>> @@ -290,7 +289,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
>> goto out;
>>
>> /* Never init EEE in case of a switch is attached */
>> - if (phy_bus_name && (!strcmp(phy_bus_name, "fixed")))
>> + if (priv->phydev->is_pseudo_fixed_link)
>
> priv->phydev is not yet affected
> replace by if (phydev->is_pseudo_fixed_link) instead ?
Indeed that's how I had it in my own patch before. Thanks for spotting.
Regards,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg)
^ permalink raw reply
* Re: [PATCH (net-next.git) 2/2] stmmac: fix MDIO settings
From: Gabriel Fernandez @ 2016-03-16 11:01 UTC (permalink / raw)
To: Giuseppe Cavallaro
Cc: netdev, Andreas Färber, fschaefer.oss, Dinh Nguyen,
David S. Miller, Phil Reid
In-Reply-To: <1458121942-5537-3-git-send-email-peppe.cavallaro@st.com>
Hi Pepe,
i have a kernel crash
[ 2.714097] Unable to handle kernel NULL pointer dereference at
virtual address 000001d6
[ 2.722188] pgd = c0204000
[ 2.724886] [000001d6] *pgd=00000000
[ 2.728452] Internal error: Oops: 5 [#1] SMP ARM
[ 2.733054] Modules linked in:
[ 2.736095] CPU: 1 PID: 1 Comm: swapper/0 Not tainted
4.5.0-rc7-01768-g3407893 #36
[ 2.743649] Hardware name: STiH415/416 SoC with Flattened Device Tree
[ 2.750074] task: ee070000 ti: ee05e000 task.ti: ee05e000
[ 2.755467] PC is at stmmac_open+0xcc/0xc40
[ 2.759641] LR is at of_phy_connect+0x44/0x5c
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 4c5ce98..943500b 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -278,7 +278,6 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
> */
> bool stmmac_eee_init(struct stmmac_priv *priv)
> {
> - char *phy_bus_name = priv->plat->phy_bus_name;
> unsigned long flags;
> bool ret = false;
>
> @@ -290,7 +289,7 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
> goto out;
>
> /* Never init EEE in case of a switch is attached */
> - if (phy_bus_name && (!strcmp(phy_bus_name, "fixed")))
> + if (priv->phydev->is_pseudo_fixed_link)
priv->phydev is not yet affected
replace by if (phydev->is_pseudo_fixed_link) instead ?
Best Regard
Gabriel
^ permalink raw reply
* Re: [PATCH net-next 7/7] vxlan: allow setting ipv6 traffic class
From: Jiri Benc @ 2016-03-16 10:59 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: davem, alexei.starovoitov, tgraf, netdev
In-Reply-To: <c50f1e302411f7e4fe73ec469e0683f3e14fe830.1457099834.git.daniel@iogearbox.net>
On Fri, 4 Mar 2016 15:15:08 +0100, Daniel Borkmann wrote:
> We can already do that for IPv4, but IPv6 support was missing. Add
> it for vxlan, so it can be used with collect metadata frontends.
>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> ---
> drivers/net/vxlan.c | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
> index 366a858..d33a434 100644
> --- a/drivers/net/vxlan.c
> +++ b/drivers/net/vxlan.c
> @@ -1788,7 +1788,7 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
>
> #if IS_ENABLED(CONFIG_IPV6)
> static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
> - struct sk_buff *skb, int oif,
> + struct sk_buff *skb, int oif, u8 tos,
> const struct in6_addr *daddr,
> struct in6_addr *saddr,
> struct dst_cache *dst_cache,
> @@ -1799,6 +1799,8 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
> struct flowi6 fl6;
> int err;
>
> + if (tos && !info)
> + use_cache = false;
> if (use_cache) {
> ndst = dst_cache_get_ip6(dst_cache, saddr);
> if (ndst)
> @@ -1807,6 +1809,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
>
> memset(&fl6, 0, sizeof(fl6));
> fl6.flowi6_oif = oif;
> + fl6.flowi6_tos = RT_TOS(tos);
Nothing against this but the reason it was missing was that it's never
used. Unless I'm missing something the IPv6 code does not use this
field at all for lookups.
This patch is not wrong but it's effectively dead code right now.
I'll be happy to be proven wrong, though.
(Sorry for answering after such long time, I'm catching up after a
vacation.)
Jiri
^ permalink raw reply
* Re: [PATCH (net-next.git) 0/2] STMMAC: MDIO settings
From: Andreas Färber @ 2016-03-16 10:47 UTC (permalink / raw)
To: Giuseppe Cavallaro
Cc: netdev, gabriel.fernandez, fschaefer.oss, dinh.linux, davem,
preid
In-Reply-To: <1458121942-5537-1-git-send-email-peppe.cavallaro@st.com>
Am 16.03.2016 um 10:52 schrieb Giuseppe Cavallaro:
> These two patches are to fix the recent regressions raised
> when test the stmmac on some platforms due to broken MDIO/PHY
> management.
>
> NOTE:
>
> these are the same reviewed patches sent for net.git (version 4).
> The patch #2 has been modified to solve a build problem on net-next;
> inside the stmmac_init_phy where there is:
>
> 869 if (priv->plat->is_fixed_link)
> 870 phydev->irq = PHY_IGNORE_INTERRUPT;
On next-20160316 plus the other previously tested normal desc fix with
this series I now get:
Starting wicked managed network interfaces...
eth0: device MAC address e6:6f:12:1b:8f:24
Unable to handle kernel NULL pointer dereference at virtual address 00000322
pgd = ffffffc074e76000
[00000322] *pgd=00000000765d5003, *pud=00000000765d5003,
*pmd=0000000000000000
Internal error: Oops: 96000006 [#1] PREEMPT SMP
Modules linked in:
CPU: 5 PID: 1600 Comm: wickedd Not tainted 4.5.0-next-20160316+ #40
Hardware name: GeekBox on Landingship (DT)
task: ffffffc0787ce000 ti: ffffffc0765f4000 task.ti: ffffffc0765f4000
PC is at stmmac_open+0xcc/0xc20
LR is at stmmac_open+0x6a8/0xc20
pc : [<ffffff800856a58c>] lr : [<ffffff800856ab68>] pstate: a0000145
sp : ffffffc0765f7670
x29: ffffffc0765f7670 x28: 0000000000000000
x27: ffffff800889bb40 x26: ffffffc076610100
x25: ffffffc077593810 x24: ffffff8008878898
x23: 00000000fffffffe x22: 0000000000000007
x21: ffffffc0784e4000 x20: ffffffc077e15800
x19: ffffffc0784e4800 x18: 0000000000000002
x17: 0000000000000007 x16: 0000000000000001
x15: ffffffc0765f7703 x14: 0000000000000001
x13: 0000000000000001 x12: ffffffc0770d2000
x11: 0000000000000021 x10: 0000000000001140
x9 : ffffff8008c60014 x8 : ffffffc077e15bb0
x7 : ffffffc07ef8eb80 x6 : ffffffc077e15b98
x5 : 00000000fffee416 x4 : 00000000000000f9
x3 : 0000000000000000 x2 : 00000000000009ba
x1 : ffffffc0765f4000 x0 : 0000000000000000
Process wickedd (pid: 1600, stack limit = 0xffffffc0765f4020)
Stack: (0xffffffc0765f7670 to 0xffffffc0765f8000)
7660: ffffffc0765f7710 ffffff800869bb38
7680: ffffffc0784e4000 0000000000001003 ffffff8008878898 ffffffc0784e4048
76a0: 0000000000001002 ffffff8008878898 ffffffc077593810 ffffffc076610100
76c0: ffffff800889bb40 0000000000000000 ffffffc0765f76e0 ffffff8008693610
76e0: 302d63616d6d7473 ffffff800869ba00 ffffffc0784e4000 302d63616d6d7473
7700: ffffff800030303a ffffff80080dcb58 ffffffc0765f7750 ffffff800869bdfc
7720: ffffffc0784e4000 0000000000001003 0000000000000001 0000000000000000
7740: ffffffc0784e4000 ffffffc0784e4000 ffffffc0765f7790 ffffff800869bee8
7760: ffffffc0784e4000 0000000000000000 0000000000000000 0000000000001002
7780: ffffffc0765f7958 ffffff80080ef7fc ffffffc0765f77c0 ffffff80086abf48
77a0: 0000000000000000 0000000000000000 ffffffc0784e4000 ffffffc0765f79e0
77c0: ffffffc0765f78d0 ffffff80086aca00 0000000000000000 ffffffc0784e4000
77e0: ffffffc077593800 0000000000000000 0000000000000000 0000000000000000
7800: ffffffc0765f78d0 ffffffc077593810 ffffff800889bb40 0000000000000000
7820: ffffffc0787ce000 0000000000000000 0000000000000000 ffffffc0774b0000
7840: ffffffc0765f7880 ffffff800815b0f0 ffffff80087eb63c ffffffc07ef93180
7860: ffffffc07748bdc0 ffffffc07851bc00 ffffffc0765f78c0 ffffff80080b623c
7880: 0000000000000004 ffffffc07748c070 ffffffc0765f78d0 ffffff80086ac6e8
78a0: ffffffc0765f78d0 ffffff80086ac72c 0000000000000000 ffffffc0784e4000
78c0: ffffffc077593800 0000000000000000 ffffffc0765f7b20 ffffff80086ab5dc
78e0: 0000000000000000 ffffffc077593800 ffffffc076610100 0000000000000000
7900: 0000000000000000 0000000000000020 0000000000000000 0000000000000008
7920: ffffff80087fb000 ffffffc0765f4000 ffffffc076610100 ffffff800889ba98
7940: ffffffc077593820 ffffff8008b71100 ffffffc0765f4000 0000000000000000
7960: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7980: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
79a0: 0000000000000000 ffffff80080daf00 ffffffc0765f7ac0 ffffff80081a8d9c
79c0: ffffffbdc1ddaa00 ffffffc0765f4000 0000000000008145 ffffffc0776aac00
79e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7a00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7a20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7a40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7a60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7a80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7aa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7ac0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7ae0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7b00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7b20: ffffffc0765f7b90 ffffff80086be524 ffffffc077593800 ffffffc076610100
7b40: ffffff80086ab4f8 ffffffc076610100 0000000000000000 ffffffc0765f7c2f
7b60: 00000000024000c0 ffffff80086878d4 ffffffc0765f7b90 ffffff80086bba04
7b80: ffffffc077c6af90 0000000000000008 ffffffc0765f7bc0 ffffff80086ab4e4
7ba0: ffffffc076610100 ffffffc077c17800 0000000000000020 ffffff80086bdcac
7bc0: ffffffc0765f7be0 ffffff80086bddc0 ffffffc077c6ac00 ffffffc077c17800
7be0: ffffffc0765f7c30 ffffff80086be290 ffffffc0765f7e68 0000000000000000
7c00: ffffffc076610100 ffffffc077c17800 0000000000000000 00000000ffffffa6
7c20: ffffffc076610100 7fffffffffffffff ffffffc0765f7ca0 ffffff800867d208
7c40: ffffffc0765f7e68 0000000000000000 0000000000000000 0000000000000000
7c60: ffffffc078106300 0000000000000000 0000000000000000 ffffffc0765f7d08
7c80: ffffffc077f4b700 0000000000000000 0000000000000640 0000000000000000
7ca0: ffffffc0765f7cb0 ffffff800867f364 ffffffc0765f7e30 ffffff8008680244
7cc0: ffffffc078106300 0000007fe0a23730 0000000000000000 0000007fb07b9898
7ce0: 0000000060000000 0000000000000015 000000000000011e 00000000000000d3
7d00: 0000000000000000 00000000000000d4 ffffff80087fb000 ffffff8008094964
7d20: 0000000000000000 0000000000000000 0000000000000010 0000000000000000
7d40: 000000009200004f 0000000000000055 0000000000000002 ffffffc0777ea630
7d60: ffffffc0776eb468 0000000000020000 ffffffc0765f7db0 0000000007fb09b3
7d80: ffffffc076f173f8 ffffffc076f17480 ffffffc0765f7dc0 ffffff80080947c0
7da0: ffffffc0765f7ed0 ffffffc0776eb400 000000002571bf40 0000000000000020
7dc0: 0000000025736bf0 0000000000000000 000000009200004f ffffff8008b146f8
7de0: 0000007fb09b3ec0 ffffffc0765f7ed0 0000000080000000 0000000000000024
7e00: ffffffc0765f7e10 ffffff800867cde0 ffffffc0765f7e30 ffffff8008680224
7e20: 0000000000000200 0000007fe0a23730 ffffffc0765f7ec0 ffffff8008680298
7e40: 0000000000000200 00000000256d2920 ffffffffffffffff ffffffc0765f7ed0
7e60: fffffff700000000 ffffffc0765f7d30 000000000000000c 0000000000000001
7e80: 0000000000000000 0000000000000000 ffffffc0765f7dc0 0000000000000000
7ea0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
7ec0: 0000000000000000 ffffff8008084d8c 0000000000000006 0000007fe0a23730
7ee0: 0000000000000000 0000000000000001 0000007fb09e3c68 0000000000000000
7f00: 000000002571bf60 0000000200000000 00000000000000d3 0000000000000004
7f20: 0000000000000076 0000000000000030 6e65706f2e67726f 74654e2e65737573
7f40: 746e492e6b726f77 00315fd0a7af2c02 0000000000000000 0000007fb07b98b0
7f60: 0000000000000001 0000007fb0676000 00000000256d2920 0000000025720910
7f80: 00000000256a5980 0000007fe0a23730 000000002571daa0 00000000256a2810
7fa0: 00000000256a1f50 0000007fe0a239e0 0000000000000003 0000007fe0a23670
7fc0: 0000007fb06593d4 0000007fe0a23660 0000007fb07b9898 0000000060000000
7fe0: 0000000000000006 00000000000000d3 00000000004c944d 0000000000000000
Call trace:
Exception stack(0xffffffc0765f74b0 to 0xffffffc0765f75d0)
74a0: ffffffc0784e4800 ffffffc077e15800
74c0: ffffffc0765f7670 ffffff800856a58c 0000000000000000 0000000000000000
74e0: ffffffc077593810 ffffffc076610100 ffffff800889bb40 0000000000000000
7500: ffffffc0765f7550 ffffff800810b95c ffffffc077e15bb0 00000000fffee50f
7520: ffffff8008ae2b80 ffffffc07ef2ab80 ffffffc0765f7540 ffffff80087ef268
7540: ffffffc0765f7550 ffffff800810b8fc 0000000000000000 ffffffc0765f4000
7560: 00000000000009ba 0000000000000000 00000000000000f9 00000000fffee416
7580: ffffffc077e15b98 ffffffc07ef8eb80 ffffffc077e15bb0 ffffff8008c60014
75a0: 0000000000001140 0000000000000021 ffffffc0770d2000 0000000000000001
75c0: 0000000000000001 ffffffc0765f7703
[<ffffff800856a58c>] stmmac_open+0xcc/0xc20
[<ffffff800869bb38>] __dev_open+0xb8/0x128
[<ffffff800869bdfc>] __dev_change_flags+0x8c/0x158
[<ffffff800869bee8>] dev_change_flags+0x20/0x60
[<ffffff80086abf48>] do_setlink+0x288/0x8a0
[<ffffff80086aca00>] rtnl_newlink+0x398/0x6a8
[<ffffff80086ab5dc>] rtnetlink_rcv_msg+0xe4/0x220
[<ffffff80086be524>] netlink_rcv_skb+0xc4/0xf8
[<ffffff80086ab4e4>] rtnetlink_rcv+0x2c/0x40
[<ffffff80086bddc0>] netlink_unicast+0x160/0x238
[<ffffff80086be290>] netlink_sendmsg+0x2f0/0x358
[<ffffff800867d208>] sock_sendmsg+0x18/0x30
[<ffffff800867f364>] ___sys_sendmsg+0x26c/0x280
[<ffffff8008680244>] __sys_sendmsg+0x44/0x88
[<ffffff8008680298>] SyS_sendmsg+0x10/0x20
[<ffffff8008084d8c>] __sys_trace_return+0x0/0x4
Code: f9434260 f9400c00 b4004840 f9410260 (394c8800)
---[ end trace 20896b27fa45a738 ]---
[ OK ] Started wicked managed network interfaces.
ping did not work (no eth0 I assume) and doing `ip a` got the system
stuck with Ctrl+C not working. Reproducible.
Regards,
Andreas
>
> Note: still on-going for net-next a debug session to solve a recent
> regression when use normal descriptors.
> This will be sent in a new patch set.
>
> Giuseppe Cavallaro (2):
> Revert "stmmac: Fix 'eth0: No PHY found' regression"
> stmmac: fix MDIO settings
>
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 16 +---
> drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 10 +--
> .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 91 ++++++++++++++------
> include/linux/stmmac.h | 1 -
> 4 files changed, 72 insertions(+), 46 deletions(-)
>
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton; HRB 21284 (AG Nürnberg)
^ permalink raw reply
* Re: [PATCH 1/3] infiniband: IB/hns: add Hisilicon RoCE support
From: Jiri Pirko @ 2016-03-16 10:36 UTC (permalink / raw)
To: oulijun
Cc: dledford-H+wXaHxf7aLQT0dZR+AlfA,
sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
davem-fT/PcQaiUtIeIZ0/mPfg9Q,
jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w,
jiri-VPRAkNaXOzVWk0Htik3J/w, ogerlitz-VPRAkNaXOzVWk0Htik3J/w,
linux-rdma-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
gongyangming-hv44wF8Li93QT0dZR+AlfA,
xiaokun-hv44wF8Li93QT0dZR+AlfA,
tangchaofei-hv44wF8Li93QT0dZR+AlfA,
haifeng.wei-hv44wF8Li93QT0dZR+AlfA,
yisen.zhuang-hv44wF8Li93QT0dZR+AlfA,
yankejian-hv44wF8Li93QT0dZR+AlfA,
lisheng011-hv44wF8Li93QT0dZR+AlfA,
charles.chenxin-hv44wF8Li93QT0dZR+AlfA,
linuxarm-hv44wF8Li93QT0dZR+AlfA
In-Reply-To: <56E9340E.3040207-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Wed, Mar 16, 2016 at 11:23:10AM CET, oulijun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org wrote:
>Hi Jiri Pirko, thanks your reviewing.
>sorry, I will send a new patch according to your reviews.
>
>On 2016/3/11 18:42, Jiri Pirko wrote:
>> Fri, Mar 11, 2016 at 11:37:09AM CET, oulijun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org wrote:
>>> The driver for Hisilicon RoCE is a platform driver.
>>> The driver will support mulitple versions of hardware. Currently only "v1"
>>> for hip06 SOC is supported.
>>> The driver includes two parts: common driver and hardware-specific
>>> operations. hns_roce_v1_hw.c and hns_roce_v1_hw.h are files for
>>> hardware-specific operations only for v1 engine, and other files(.c and .h)
>>> for common algorithm and common hardware operations
>>>
>>> Signed-off-by: Lijun Ou <oulijun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>>> Signed-off-by: Wei Hu(Xavier) <xavier.huwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>>> Signed-off-by: Znlong <zhaonenglong-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>>
>> <snip>
>>
>> I'm sorry to be nitpicking, but you still have style issues in your
>> code. I believe that for newly submitted code, this should be avoided. I
>> already pointed that out as a comment to your last version, but you
>> ignored it. So again, couple of examples:
>>
>>> +struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd,
>>> + struct ib_ah_attr *ah_attr)
>>
>> <snip>
>>
>>> + ret = ib_get_cached_gid(ibpd->device, ah_attr->port_num,
>>> + ah_attr->grh.sgid_index, &sgid, &gid_attr);
>>
>> <snip>
>>
>>> +int hns_roce_bitmap_alloc_range(
>>> + struct hns_roce_bitmap *bitmap,
>>> + int cnt, int align, u32 *obj)
>>
>> <snip>
>>
>>> + pages =
>>> + kmalloc(sizeof(*pages) * buf->nbufs,
>>> + GFP_KERNEL);
>>
>In v2, I consider that it will violate checkpatch if write as follows
> pages = kmalloc(sizeof(*pages) * buf->nbufs,
> GFP_KERNEL);
Why it would be problem for checkpatch? I bet it won't.
>so, I continue to have it.
I will continue to bash on your odd codingstyle. Please fix it!
>Now, I have used kmalloc_array instead of it. I will send new patch at soon.
>Again, i am sorry for my incorrect plan.
>
>> <snip>
>>
>>> + dev_err(dev,
>>> + "CQ alloc.Failed to find cq buf addr.\n");
>>
>> <snip>
>>
>>> + resp.qp_tab_size = hr_dev->caps.num_qps;
>>
>> <snip>
>>
>>> + buddy->bits[i] =
>>> + kmalloc(s * sizeof(long), GFP_KERNEL);
>>
>>
>> and many, many others similar to this. Please fix this.
>>
>>
>> Also, I don't understand why you have "_" prefix for labels:
>>
>>> +
>>> +_error_failed_register_device:
>>> + hns_roce_engine_uninit(hr_dev);
>>> +
>>> +_error_failed_engine_init:
>>> + hns_roce_cleanup_bitmap(hr_dev);
>>> +
>>> +_error_failed_setup_hca:
>>> + hns_roce_cleanup_icm(hr_dev);
>>> +
>>> +_error_failed_init_icm:
>>> + if (hr_dev->cmd_mod)
>>> + hns_roce_cmd_use_polling(hr_dev);
>>> +
>>> +_error_failed_use_event:
>>> + hns_roce_cleanup_eq_table(hr_dev);
>>> +
>>> +_error_failed_eq_tabel:
>>> + hns_roce_cmd_cleanup(hr_dev);
>>> +
>>> +_error_failed_cmd_init:
>>> + (void)hns_roce_engine_reset(hr_dev, 0);
>>> +
>>> +_error_failed_reset_engine:
>>> + hns_roce_free_cfg(hr_dev);
>>> +
>>> +_error_failed_get_cfg:
>>> + ib_dealloc_device(&hr_dev->ib_dev);
>>> +
>>> + return ret;
>>> +}
>>
>> .
>>
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" 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
* Re: [PATCH net-next v3 1/2] RDS: TCP: Add sysctl tunables for sndbuf/rcvbuf on rds-tcp socket
From: Hannes Frederic Sowa @ 2016-03-16 10:29 UTC (permalink / raw)
To: Sowmini Varadhan, netdev; +Cc: davem, santosh.shilimkar, eric.dumazet
In-Reply-To: <5c18f6bdde99628e486d63a071c256d1be036c28.1458064902.git.sowmini.varadhan@oracle.com>
Hello,
some feedback.
On 15.03.2016 19:53, Sowmini Varadhan wrote:
> Add per-net sysctl tunables to set the size of sndbuf and
> rcvbuf on the kernel tcp socket.
>
> The tunables are added at /proc/sys/net/rds/tcp/rds_tcp_sndbuf
> and /proc/sys/net/rds/tcp/rds_tcp_rcvbuf.
>
> Since these values must be set before accept() or connect(),
> and there may be an arbitrary number of existing rds-tcp
> sockets when the tunable is modified. To make sure that all
> connections in the netns pick up the same value for the tunable,
> we reset existing rds-tcp connections in the netns, so that
> they can reconnect with the new parameters.
>
> Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
> ---
> v2; use sysctl instead of module param. Tunabes are now per netns,
> and can be dynamically modified without restarting all namespaces.
> v3: review comments from Santosh Shilimkar, Eric Dumazet
>
> net/rds/tcp.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
> 1 files changed, 134 insertions(+), 9 deletions(-)
>
> diff --git a/net/rds/tcp.c b/net/rds/tcp.c
> index ad60299..b720b25 100644
> --- a/net/rds/tcp.c
> +++ b/net/rds/tcp.c
> @@ -54,6 +54,28 @@ static struct kmem_cache *rds_tcp_conn_slab;
>
> #define RDS_TCP_DEFAULT_BUFSIZE (128 * 1024)
>
> +static int sndbuf_handler(struct ctl_table *ctl, int write,
> + void __user *buffer, size_t *lenp, loff_t *fpos);
> +static int rcvbuf_handler(struct ctl_table *ctl, int write,
> + void __user *buffer, size_t *lenp, loff_t *fpos);
> +static struct ctl_table rds_tcp_sysctl_table[] = {
> + {
> + .procname = "rds_tcp_sndbuf",
> + /* data is per-net pointer */
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = sndbuf_handler,
> + },
> + {
> + .procname = "rds_tcp_rcvbuf",
> + /* data is per-net pointer */
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = rcvbuf_handler,
> + },
> + { }
> +};
Normally we kmemdup a table per netns and update its data pointer, so we
can reuse the proc_doint_minmax functions.
> /* doing it this way avoids calling tcp_sk() */
> void rds_tcp_nonagle(struct socket *sock)
> {
> @@ -66,15 +88,6 @@ void rds_tcp_nonagle(struct socket *sock)
> set_fs(oldfs);
> }
>
> -/* All module specific customizations to the RDS-TCP socket should be done in
> - * rds_tcp_tune() and applied after socket creation. In general these
> - * customizations should be tunable via module_param()
> - */
> -void rds_tcp_tune(struct socket *sock)
> -{
> - rds_tcp_nonagle(sock);
> -}
> -
> u32 rds_tcp_snd_nxt(struct rds_tcp_connection *tc)
> {
> return tcp_sk(tc->t_sock->sk)->snd_nxt;
> @@ -272,8 +285,33 @@ static int rds_tcp_netid;
> struct rds_tcp_net {
> struct socket *rds_tcp_listen_sock;
> struct work_struct rds_tcp_accept_w;
> + struct ctl_table_header *rds_tcp_sysctl;
> + int sndbuf_size;
> + int rcvbuf_size;
> };
>
> +/* All module specific customizations to the RDS-TCP socket should be done in
> + * rds_tcp_tune() and applied after socket creation.
> + */
> +void rds_tcp_tune(struct socket *sock)
> +{
> + struct sock *sk = sock->sk;
> + struct net *net = sock_net(sk);
> + struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
> +
> + rds_tcp_nonagle(sock);
> + lock_sock(sk);
> + if (rtn->sndbuf_size > 0) {
> + sk->sk_sndbuf = rtn->sndbuf_size;
> + sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
> + }
> + if (rtn->rcvbuf_size > 0) {
> + sk->sk_sndbuf = rtn->rcvbuf_size;
> + sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
> + }
> + release_sock(sk);
> +}
> +
> static void rds_tcp_accept_worker(struct work_struct *work)
> {
> struct rds_tcp_net *rtn = container_of(work,
> @@ -296,9 +334,17 @@ static __net_init int rds_tcp_init_net(struct net *net)
> {
> struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
>
> + /* 0 value for {snd, rcv}buf_size implies we let the stack
> + * pick the default, and permit auto-tuning of buffer size.
> + */
> + rtn->sndbuf_size = 0;
> + rtn->rcvbuf_size = 0;
> + rtn->rds_tcp_sysctl = register_net_sysctl(net, "net/rds/tcp",
> + rds_tcp_sysctl_table);
You should add proper error handling here?
> rtn->rds_tcp_listen_sock = rds_tcp_listen_init(net);
> if (!rtn->rds_tcp_listen_sock) {
> pr_warn("could not set up listen sock\n");
> + unregister_net_sysctl_table(rtn->rds_tcp_sysctl);
> return -EAFNOSUPPORT;
> }
> INIT_WORK(&rtn->rds_tcp_accept_w, rds_tcp_accept_worker);
> @@ -309,6 +355,7 @@ static void __net_exit rds_tcp_exit_net(struct net *net)
> {
> struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
>
> + unregister_net_sysctl_table(rtn->rds_tcp_sysctl);
> /* If rds_tcp_exit_net() is called as a result of netns deletion,
> * the rds_tcp_kill_sock() device notifier would already have cleaned
> * up the listen socket, thus there is no work to do in this function.
> @@ -383,6 +430,84 @@ static struct notifier_block rds_tcp_dev_notifier = {
> .priority = -10, /* must be called after other network notifiers */
> };
>
> +static int user_atoi(char __user *ubuf, size_t len)
> +{
> + char buf[16];
> + unsigned long ret;
> + int err;
> +
> + if (len > 15)
> + return -EINVAL;
> +
> + if (copy_from_user(buf, ubuf, len))
> + return -EFAULT;
> +
> + buf[len] = 0;
> + err = kstrtoul(buf, 0, &ret);
> + if (err != 0)
> + return -ERANGE;
> + return ret;
> +}
> +
> +/* when sysctl is used to modify some kernel socket parameters,this
> + * function resets the RDS connections in that netns so that we can
> + * restart with new parameters. The assumption is that such reset
> + * events are few and far-between.
> + */
> +static void rds_tcp_sysctl_reset(struct net *net)
> +{
> + struct rds_tcp_connection *tc, *_tc;
> +
> + spin_lock_irq(&rds_tcp_conn_lock);
> + list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) {
> + struct net *c_net = read_pnet(&tc->conn->c_net);
> +
> + if (net != c_net || !tc->t_sock)
> + continue;
> +
> + rds_conn_drop(tc->conn); /* reconnect with new parameters */
> + }
> + spin_unlock_irq(&rds_tcp_conn_lock);
> +}
> +
> +static int sndbuf_handler(struct ctl_table *ctl, int write,
> + void __user *buffer, size_t *lenp, loff_t *fpos)
> +{
> + struct net *net = current->nsproxy->net_ns;
> + struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
> + struct ctl_table tmp;
> +
> + tmp = *ctl;
> + tmp.data = &rtn->sndbuf_size;
> + if (!write)
> + return proc_dointvec(&tmp, write, buffer, lenp, fpos);
> +
> + rtn->sndbuf_size = max_t(u32, user_atoi(buffer, *lenp) * 2,
> + SOCK_MIN_SNDBUF);
user_atoi does return negative error values (as you implemented it), I
think you should check before, otherwise the signed to unsigned
conversion can cause huge memory allocations.
Why actually implement user_atoi?
> + rds_tcp_sysctl_reset(net);
> +
> + return 0;
> +}
> +
> +static int rcvbuf_handler(struct ctl_table *ctl, int write,
> + void __user *buffer, size_t *lenp, loff_t *fpos)
> +{
> + struct net *net = current->nsproxy->net_ns;
> + struct rds_tcp_net *rtn = net_generic(net, rds_tcp_netid);
> + struct ctl_table tmp;
> +
> + tmp = *ctl;
> + tmp.data = &rtn->rcvbuf_size;
> + if (!write)
> + return proc_dointvec(&tmp, write, buffer, lenp, fpos);
> +
> + rtn->rcvbuf_size = max_t(u32, user_atoi(buffer, *lenp) * 2,
> + SOCK_MIN_RCVBUF);
> + rds_tcp_sysctl_reset(net);
> +
> + return 0;
> +}
> +
> static void rds_tcp_exit(void)
> {
> rds_info_deregister_func(RDS_INFO_TCP_SOCKETS, rds_tcp_tc_info);
>
^ permalink raw reply
* Re: [PATCH 1/3] infiniband: IB/hns: add Hisilicon RoCE support
From: oulijun @ 2016-03-16 10:26 UTC (permalink / raw)
To: dledford-H+wXaHxf7aLQT0dZR+AlfA,
sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
davem-fT/PcQaiUtIeIZ0/mPfg9Q,
jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w,
jiri-VPRAkNaXOzVWk0Htik3J/w, ogerlitz-VPRAkNaXOzVWk0Htik3J/w,
linux-rdma-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
gongyangming-hv44wF8Li93QT0dZR+AlfA,
xiaokun-hv44wF8Li93QT0dZR+AlfA,
tangchaofei-hv44wF8Li93QT0dZR+AlfA,
haifeng.wei-hv44wF8Li93QT0dZR+AlfA,
yisen.zhuang-hv44wF8Li93QT0dZR+AlfA,
yankejian-hv44wF8Li93QT0dZR+AlfA,
lisheng011-hv44wF8Li93QT0dZR+AlfA,
charles.chenxin-hv44wF8Li93QT0dZR+AlfA,
linuxarm-hv44wF8Li93QT0dZR+AlfA
In-Reply-To: <20160312103940.GA15703-2ukJVAZIZ/Y@public.gmane.org>
Hi dledford, thanks for reviewing.
I have modified according to your reivews. I will send a new patch
at soon.
thanks
Lijun Ou
On 2016/3/12 18:39, Leon Romanovsky wrote:
> On Fri, Mar 11, 2016 at 06:37:09PM +0800, Lijun Ou wrote:
>> The driver for Hisilicon RoCE is a platform driver.
>> The driver will support mulitple versions of hardware. Currently only "v1"
>> for hip06 SOC is supported.
>> The driver includes two parts: common driver and hardware-specific
>> operations. hns_roce_v1_hw.c and hns_roce_v1_hw.h are files for
>> hardware-specific operations only for v1 engine, and other files(.c and .h)
>> for common algorithm and common hardware operations
>>
>> Signed-off-by: Lijun Ou <oulijun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>> Signed-off-by: Wei Hu(Xavier) <xavier.huwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>> Signed-off-by: Znlong <zhaonenglong-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>> ---
>> drivers/infiniband/Kconfig | 2 +-
>> drivers/infiniband/hw/Makefile | 1 +
>> drivers/infiniband/hw/hisilicon/hns/Kconfig | 10 +
>> drivers/infiniband/hw/hisilicon/hns/Makefile | 9 +
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_ah.c | 114 +
>> .../infiniband/hw/hisilicon/hns/hns_roce_alloc.c | 253 ++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.c | 354 +++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.h | 163 ++
>> .../infiniband/hw/hisilicon/hns/hns_roce_common.h | 704 +++++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_cq.c | 454 +++
>> .../infiniband/hw/hisilicon/hns/hns_roce_device.h | 840 ++++++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.c | 798 ++++++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.h | 138 +
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.c | 608 ++++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.h | 121 +
>> .../infiniband/hw/hisilicon/hns/hns_roce_main.c | 1124 ++++++++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_mr.c | 637 +++++
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_pd.c | 129 +
>> drivers/infiniband/hw/hisilicon/hns/hns_roce_qp.c | 890 ++++++
>> .../infiniband/hw/hisilicon/hns/hns_roce_user.h | 31 +
>> .../infiniband/hw/hisilicon/hns/hns_roce_v1_hw.c | 2992 ++++++++++++++++++++
>> .../infiniband/hw/hisilicon/hns/hns_roce_v1_hw.h | 1068 +++++++
>> 22 files changed, 11439 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/Kconfig
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/Makefile
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_ah.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_alloc.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_cmd.h
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_common.h
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_cq.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_device.h
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_eq.h
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_icm.h
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_main.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_mr.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_pd.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_qp.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_user.h
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_v1_hw.c
>> create mode 100644 drivers/infiniband/hw/hisilicon/hns/hns_roce_v1_hw.h
>>
>> diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
>> index 8a8440c..c7a24bb 100644
>> --- a/drivers/infiniband/Kconfig
>> +++ b/drivers/infiniband/Kconfig
>> @@ -73,7 +73,7 @@ source "drivers/infiniband/hw/mlx5/Kconfig"
>> source "drivers/infiniband/hw/nes/Kconfig"
>> source "drivers/infiniband/hw/ocrdma/Kconfig"
>> source "drivers/infiniband/hw/usnic/Kconfig"
>> -
>
> No need to remove this line. It separates HW from ULPs.
>
>> +source "drivers/infiniband/hw/hisilicon/hns/Kconfig"
>> source "drivers/infiniband/ulp/ipoib/Kconfig"
>>
>> source "drivers/infiniband/ulp/srp/Kconfig"
>
> <snip>
>
>> +int hns_roce_bitmap_alloc_range(
>> + struct hns_roce_bitmap *bitmap,
>> + int cnt, int align, u32 *obj)
>
> You have indentation issues.
>
>> +{
>> + int i;
>> + int ret = 0;
>> +
>> + if (likely(cnt == 1 && align == 1))
>> + return hns_roce_bitmap_alloc(bitmap, obj);
>> +
>> + spin_lock(&bitmap->lock);
>> +
>> + *obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max,
>> + bitmap->last, cnt, align - 1);
>> + if (*obj >= bitmap->max) {
>> + bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
>> + & bitmap->mask;
>> + *obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, 0,
>> + cnt, align - 1);
>> + }
>> +
>> + if (*obj < bitmap->max) {
>> + for (i = 0; i < cnt; i++)
>> + set_bit(*obj + i, bitmap->table);
>> +
>> + if (*obj == bitmap->last) {
>> + bitmap->last = (*obj + cnt);
>> + if (bitmap->last >= bitmap->max)
>> + bitmap->last = 0;
>> + }
>> + *obj |= bitmap->top;
>> + } else {
>> + ret = -1;
>> + }
>> +
>> + spin_unlock(&bitmap->lock);
>> +
>> + return ret;
>> +}
>> +
>> +void hns_roce_bitmap_free_range(
>> + struct hns_roce_bitmap *bitmap,
>> + u32 obj,
>> + int cnt)
>> +{
>> + int i;
>> +
>> + obj &= bitmap->max + bitmap->reserved_top - 1;
>> +
>> + spin_lock(&bitmap->lock);
>> + for (i = 0; i < cnt; i++)
>> + clear_bit(obj + i, bitmap->table);
>> +
>> + bitmap->last = min(bitmap->last, obj);
>> + bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
>> + & bitmap->mask;
>> + spin_unlock(&bitmap->lock);
>> +}
>> +
>> +int hns_roce_bitmap_init(struct hns_roce_bitmap *bitmap, u32 num,
>> + u32 mask, u32 reserved_bot,
>> + u32 reserved_top)
>> +{
>> + u32 i;
>> +
>> + if (num != roundup_pow_of_two(num))
>> + return -EINVAL;
>> +
>> + bitmap->last = 0;
>> + bitmap->top = 0;
>> + bitmap->max = num - reserved_top;
>> + bitmap->mask = mask;
>> + bitmap->reserved_top = reserved_top;
>> + spin_lock_init(&bitmap->lock);
>> + bitmap->table =
>> + kzalloc(BITS_TO_LONGS(bitmap->max) * sizeof(long), GFP_KERNEL);
>
> Here and below, please consider to use kcalloc.
>
>> + if (!bitmap->table)
>> + return -ENOMEM;
>> +
>> + for (i = 0; i < reserved_bot; ++i)
>
> .
>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" 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
* Re: [RFCv2 0/3] mac80211: implement fq codel
From: Michal Kazior @ 2016-03-16 10:26 UTC (permalink / raw)
To: linux-wireless
Cc: ath10k@lists.infradead.org, Johannes Berg, Network Development,
Dave Taht, Emmanuel Grumbach, Felix Fietkau, Tim Shepard,
make-wifi-fast, codel, Michal Kazior
In-Reply-To: <1458123478-1795-1-git-send-email-michal.kazior@tieto.com>
[-- Attachment #1: Type: text/plain, Size: 1041 bytes --]
On 16 March 2016 at 11:17, Michal Kazior <michal.kazior@tieto.com> wrote:
> Hi,
>
> Most notable changes:
[...]
> * ath10k proof-of-concept that uses the new tx
> scheduling (will post results in separate
> email)
I'm attaching a bunch of tests I've done using flent. They are all
"burst" tests with burst-ports=1 and burst-length=2. The testing
topology is:
AP ----> STA
AP )) (( STA
[veth]--[br]--[wlan] )) (( [wlan]
You can notice that in some tests plot data gets cut-off. There are 2
problems I've identified:
- excess drops (not a problem with the patchset and can be seen when
there's no codel-in-mac or scheduling isn't used)
- UDP_RR hangs (apparently QCA99X0 I have hangs for a few hundred ms
sometimes at times and doesn't Rx frames causing UDP_RR to stop
mid-way; confirmed with logs and sniffer; I haven't figured out *why*
exactly, could be some hw/fw quirk)
Let me know if you have questions or comments regarding my testing/results.
Michał
[-- Attachment #2: fq.tar.gz --]
[-- Type: application/x-gzip, Size: 63753 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] infiniband: IB/hns: add Hisilicon RoCE support
From: oulijun @ 2016-03-16 10:23 UTC (permalink / raw)
To: Jiri Pirko
Cc: dledford-H+wXaHxf7aLQT0dZR+AlfA,
sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
davem-fT/PcQaiUtIeIZ0/mPfg9Q,
jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w,
jiri-VPRAkNaXOzVWk0Htik3J/w, ogerlitz-VPRAkNaXOzVWk0Htik3J/w,
linux-rdma-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
gongyangming-hv44wF8Li93QT0dZR+AlfA,
xiaokun-hv44wF8Li93QT0dZR+AlfA,
tangchaofei-hv44wF8Li93QT0dZR+AlfA,
haifeng.wei-hv44wF8Li93QT0dZR+AlfA,
yisen.zhuang-hv44wF8Li93QT0dZR+AlfA,
yankejian-hv44wF8Li93QT0dZR+AlfA,
lisheng011-hv44wF8Li93QT0dZR+AlfA,
charles.chenxin-hv44wF8Li93QT0dZR+AlfA,
linuxarm-hv44wF8Li93QT0dZR+AlfA
In-Reply-To: <20160311104239.GD3931-6KJVSR23iU488b5SBfVpbw@public.gmane.org>
Hi Jiri Pirko, thanks your reviewing.
sorry, I will send a new patch according to your reviews.
On 2016/3/11 18:42, Jiri Pirko wrote:
> Fri, Mar 11, 2016 at 11:37:09AM CET, oulijun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org wrote:
>> The driver for Hisilicon RoCE is a platform driver.
>> The driver will support mulitple versions of hardware. Currently only "v1"
>> for hip06 SOC is supported.
>> The driver includes two parts: common driver and hardware-specific
>> operations. hns_roce_v1_hw.c and hns_roce_v1_hw.h are files for
>> hardware-specific operations only for v1 engine, and other files(.c and .h)
>> for common algorithm and common hardware operations
>>
>> Signed-off-by: Lijun Ou <oulijun-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>> Signed-off-by: Wei Hu(Xavier) <xavier.huwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>> Signed-off-by: Znlong <zhaonenglong-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>
> <snip>
>
> I'm sorry to be nitpicking, but you still have style issues in your
> code. I believe that for newly submitted code, this should be avoided. I
> already pointed that out as a comment to your last version, but you
> ignored it. So again, couple of examples:
>
>> +struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd,
>> + struct ib_ah_attr *ah_attr)
>
> <snip>
>
>> + ret = ib_get_cached_gid(ibpd->device, ah_attr->port_num,
>> + ah_attr->grh.sgid_index, &sgid, &gid_attr);
>
> <snip>
>
>> +int hns_roce_bitmap_alloc_range(
>> + struct hns_roce_bitmap *bitmap,
>> + int cnt, int align, u32 *obj)
>
> <snip>
>
>> + pages =
>> + kmalloc(sizeof(*pages) * buf->nbufs,
>> + GFP_KERNEL);
>
In v2, I consider that it will violate checkpatch if write as follows
pages = kmalloc(sizeof(*pages) * buf->nbufs,
GFP_KERNEL);
so, I continue to have it.
Now, I have used kmalloc_array instead of it. I will send new patch at soon.
Again, i am sorry for my incorrect plan.
> <snip>
>
>> + dev_err(dev,
>> + "CQ alloc.Failed to find cq buf addr.\n");
>
> <snip>
>
>> + resp.qp_tab_size = hr_dev->caps.num_qps;
>
> <snip>
>
>> + buddy->bits[i] =
>> + kmalloc(s * sizeof(long), GFP_KERNEL);
>
>
> and many, many others similar to this. Please fix this.
>
>
> Also, I don't understand why you have "_" prefix for labels:
>
>> +
>> +_error_failed_register_device:
>> + hns_roce_engine_uninit(hr_dev);
>> +
>> +_error_failed_engine_init:
>> + hns_roce_cleanup_bitmap(hr_dev);
>> +
>> +_error_failed_setup_hca:
>> + hns_roce_cleanup_icm(hr_dev);
>> +
>> +_error_failed_init_icm:
>> + if (hr_dev->cmd_mod)
>> + hns_roce_cmd_use_polling(hr_dev);
>> +
>> +_error_failed_use_event:
>> + hns_roce_cleanup_eq_table(hr_dev);
>> +
>> +_error_failed_eq_tabel:
>> + hns_roce_cmd_cleanup(hr_dev);
>> +
>> +_error_failed_cmd_init:
>> + (void)hns_roce_engine_reset(hr_dev, 0);
>> +
>> +_error_failed_reset_engine:
>> + hns_roce_free_cfg(hr_dev);
>> +
>> +_error_failed_get_cfg:
>> + ib_dealloc_device(&hr_dev->ib_dev);
>> +
>> + return ret;
>> +}
>
> .
>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" 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
* Re: [PATCHv3 (net.git) 2/2] stmmac: fix MDIO settings
From: Giuseppe CAVALLARO @ 2016-03-16 10:18 UTC (permalink / raw)
To: Andreas Färber
Cc: netdev, gabriel.fernandez, fschaefer.oss, dinh.linux, davem,
preid, Tomeu Vizoso
In-Reply-To: <56E92BAF.3020001@suse.de>
Hi Andreas
On 3/16/2016 10:47 AM, Andreas Färber wrote:
> Hi Peppe,
>
> Am 15.03.2016 um 16:53 schrieb Giuseppe CAVALLARO:
>> On 3/15/2016 1:54 AM, Andreas Färber wrote:
>>> The connectivity issue still remains. Kernel log snippet:
>>>
>>> [ +0.001117] rk_gmac-dwmac ff290000.ethernet: Looking up phy-supply
>>> from device tree
>>> [ +0.000028] rk808 0-001b: Looking up vcc12-supply from device tree
>>> [ +0.000014] vcc_lan: supplied by vcc_io
>>> [ +0.000101] rk_gmac-dwmac ff290000.ethernet: clock input or output?
>>> (input).
>>> [ +0.000009] rk_gmac-dwmac ff290000.ethernet: TX delay(0x30).
>>> [ +0.000008] rk_gmac-dwmac ff290000.ethernet: RX delay(0x10).
>>> [ +0.000014] rk_gmac-dwmac ff290000.ethernet: init for RGMII
>>> [ +0.000104] rk_gmac-dwmac ff290000.ethernet: clock input from PHY
>>> [ +0.005063] rk_gmac-dwmac ff290000.ethernet: no reset control found
>>> [ +0.000007] stmmac - user ID: 0x10, Synopsys ID: 0x35
>>> [ +0.000002] Ring mode enabled
>>> [ +0.000006] DMA HW capability register supported
>>> [ +0.000000] Normal descriptors
>>
>> ^^^^^^^^^^^^^^^^^^
>>
>>> [ +0.000003] RX Checksum Offload Engine supported (type 2)
>>> [ +0.000002] TX Checksum insertion supported
>>> [ +0.000002] Wake-Up On Lan supported
>>> [ +0.000053] Enable RX Mitigation via HW Watchdog Timer
>>> [ +0.000771] of_get_named_gpiod_flags: can't parse 'snps,reset-gpio'
>>> property of node '/ethernet@ff290000[0]'
>>> [ +0.004250] libphy: stmmac: probed
>>> [ +0.000009] eth0: PHY ID 001cc915 at 0 IRQ POLL (stmmac-0:00) active
>>> [ +0.000005] eth0: PHY ID 001cc915 at 1 IRQ POLL (stmmac-0:01)
>>>
>>> As before, reverting "stmmac: first frame prep at the end of xmit
>>> routine" fixes it. My test cases are `ping 192.168.1.1` and `zypper up`.
>>
>> so on your side, this revert fixes the issue and you do not see any
>> tx watchdog as Tomeu's raised.
>
> Confirmed, the system ran stable over night. I don't use NFS on that
> system myself, having GMAC working only since v2.
>
>> I have fixed some problems on top of
>> "stmmac: first frame prep at the end of xmit ..." please
>> see patch attached for net-next.
>>
>> Indeed, the normal tx descriptors are well filled w/o
>> "stmmac: first frame prep at the end of xmit ..."
>>
>> I wonder if you could try the attachment in order to understand if we
>> have to actually revert the patch (I ask you to not revert the
>> patch "stmmac: first frame...").
>
> Works great on top of next-20160314 with i2c plus this series, please
> add my Tested-by. Thanks a lot for investigating!
you are welcome, I have just sent the patch
"[PATCH (net-next.git)] stmmac: fix TX normal DESC"
do not hesitate to contact me for further checks
and if I have missed something.
Cheers
peppe
>
> Cheers,
> Andreas
>
^ permalink raw reply
* [RFCv2 3/3] ath10k: use ieee80211_tx_schedule()
From: Michal Kazior @ 2016-03-16 10:17 UTC (permalink / raw)
To: linux-wireless
Cc: nbd, emmanuel.grumbach, netdev, ath10k, codel, make-wifi-fast,
johannes, Tim Shepard
In-Reply-To: <1458123478-1795-1-git-send-email-michal.kazior@tieto.com>
The wake_tx_queue() scheduling for non-pull-push
(or threshold based pull-push) wasn't really smart
nor fair.
Instead use the new mac80211 Tx scheduling helper
which is part of the fq-codel-in-mac80211 proof of
concept.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/core.c | 2 -
drivers/net/wireless/ath/ath10k/core.h | 3 -
drivers/net/wireless/ath/ath10k/mac.c | 100 ++++++++++++++++-----------------
3 files changed, 50 insertions(+), 55 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 2389c0713c13..1848e0b6206a 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -2049,9 +2049,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
mutex_init(&ar->conf_mutex);
spin_lock_init(&ar->data_lock);
- spin_lock_init(&ar->txqs_lock);
- INIT_LIST_HEAD(&ar->txqs);
INIT_LIST_HEAD(&ar->peers);
init_waitqueue_head(&ar->peer_mapping_wq);
init_waitqueue_head(&ar->htt.empty_tx_wq);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 3f76669d44cf..1f94af046f79 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -801,10 +801,7 @@ struct ath10k {
/* protects shared structure data */
spinlock_t data_lock;
- /* protects: ar->txqs, artxq->list */
- spinlock_t txqs_lock;
- struct list_head txqs;
struct list_head arvifs;
struct list_head peers;
struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS];
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index addef9179dbe..5b8becb30b62 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3624,17 +3624,14 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
static void ath10k_mac_txq_init(struct ieee80211_txq *txq)
{
- struct ath10k_txq *artxq = (void *)txq->drv_priv;
-
if (!txq)
return;
- INIT_LIST_HEAD(&artxq->list);
+ /* It's useful to keep this even though it doesn't do anything now */
}
static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
{
- struct ath10k_txq *artxq = (void *)txq->drv_priv;
struct ath10k_skb_cb *cb;
struct sk_buff *msdu;
int msdu_id;
@@ -3642,11 +3639,6 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
if (!txq)
return;
- spin_lock_bh(&ar->txqs_lock);
- if (!list_empty(&artxq->list))
- list_del_init(&artxq->list);
- spin_unlock_bh(&ar->txqs_lock);
-
spin_lock_bh(&ar->htt.tx_lock);
idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) {
cb = ATH10K_SKB_CB(msdu);
@@ -3725,7 +3717,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
ath10k_htt_tx_dec_pending(htt, is_mgmt);
spin_unlock_bh(&ar->htt.tx_lock);
- return -ENOENT;
+ return 0;
}
ath10k_mac_tx_h_fill_cb(ar, vif, txq, skb);
@@ -3752,44 +3744,59 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
return skb_len;
}
+#define MIN_TX_SLOTS 42
+
+static int ath10k_mac_tx_wake(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq,
+ int budget)
+{
+ struct ath10k *ar = hw->priv;
+ int sent = 0;
+ int ret;
+ int slots;
+
+ if (!ath10k_mac_tx_can_push(hw, txq))
+ return 0;
+
+ /* This gives more opportunity to form longer bursts when there's a lot
+ * of stations active
+ */
+ slots = ar->htt.max_num_pending_tx - ar->htt.num_pending_tx;
+ if (slots < MIN_TX_SLOTS)
+ return -1;
+
+ while (budget > 0) {
+ ret = ath10k_mac_tx_push_txq(hw, txq);
+ if (ret <= 0)
+ break;
+
+ sent++;
+ budget -= ret;
+ }
+
+ if (ret >= 0)
+ return sent;
+ else
+ return -1;
+}
+
void ath10k_mac_tx_push_pending(struct ath10k *ar)
{
struct ieee80211_hw *hw = ar->hw;
- struct ieee80211_txq *txq;
- struct ath10k_txq *artxq;
- struct ath10k_txq *last;
int ret;
- int max;
- spin_lock_bh(&ar->txqs_lock);
- rcu_read_lock();
-
- last = list_last_entry(&ar->txqs, struct ath10k_txq, list);
- while (!list_empty(&ar->txqs)) {
- artxq = list_first_entry(&ar->txqs, struct ath10k_txq, list);
- txq = container_of((void *)artxq, struct ieee80211_txq,
- drv_priv);
-
- /* Prevent aggressive sta/tid taking over tx queue */
- max = 16;
- while (max--) {
- ret = ath10k_mac_tx_push_txq(hw, txq);
- if (ret < 0)
- break;
- }
-
- list_del_init(&artxq->list);
- ath10k_htt_tx_txq_update(hw, txq);
-
- if (artxq == last || (ret < 0 && ret != -ENOENT)) {
- if (ret != -ENOENT)
- list_add_tail(&artxq->list, &ar->txqs);
- break;
- }
+ ieee80211_recalc_fq_period(hw);
+
+ ret = ieee80211_tx_schedule(hw, ath10k_mac_tx_wake);
+ switch (ret) {
+ default:
+ ath10k_warn(ar, "unexpected tx schedul retval: %d\n",
+ ret);
+ /* pass through */
+ case -EBUSY:
+ case -ENOENT:
+ break;
}
-
- rcu_read_unlock();
- spin_unlock_bh(&ar->txqs_lock);
}
/************/
@@ -4013,16 +4020,9 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
struct ath10k *ar = hw->priv;
- struct ath10k_txq *artxq = (void *)txq->drv_priv;
-
- if (ath10k_mac_tx_can_push(hw, txq)) {
- spin_lock_bh(&ar->txqs_lock);
- if (list_empty(&artxq->list))
- list_add_tail(&artxq->list, &ar->txqs);
- spin_unlock_bh(&ar->txqs_lock);
+ if (ath10k_mac_tx_can_push(hw, txq))
tasklet_schedule(&ar->htt.txrx_compl_task);
- }
ath10k_htt_tx_txq_update(hw, txq);
}
--
2.1.4
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel
^ permalink raw reply related
* [RFCv2 2/3] ath10k: report per-station tx/rate rates to mac80211
From: Michal Kazior @ 2016-03-16 10:17 UTC (permalink / raw)
To: linux-wireless
Cc: nbd, emmanuel.grumbach, netdev, ath10k, codel, make-wifi-fast,
johannes, Tim Shepard
In-Reply-To: <1458123478-1795-1-git-send-email-michal.kazior@tieto.com>
The rate control is offloaded by firmware so it's
challanging to provide expected throughput value
for given station.
This approach is naive as it reports last tx rate
used for given station as provided by firmware
stat event.
This should be sufficient for airtime estimation
used for fq-codel-in-mac80211 tx scheduling
purposes now.
This patch uses a very hacky way to get the stats.
This is sufficient for proof-of-concept but must
be cleaned up properly eventually.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
drivers/net/wireless/ath/ath10k/core.h | 5 +++
drivers/net/wireless/ath/ath10k/debug.c | 61 +++++++++++++++++++++++++++++----
drivers/net/wireless/ath/ath10k/mac.c | 26 ++++++++------
drivers/net/wireless/ath/ath10k/wmi.h | 2 +-
4 files changed, 76 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 23ba03fb7a5f..3f76669d44cf 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -331,6 +331,9 @@ struct ath10k_sta {
/* protected by conf_mutex */
bool aggr_mode;
u64 rx_duration;
+
+ u32 tx_rate_kbps;
+ u32 rx_rate_kbps;
#endif
};
@@ -372,6 +375,8 @@ struct ath10k_vif {
s8 def_wep_key_idx;
u16 tx_seq_no;
+ u32 tx_rate_kbps;
+ u32 rx_rate_kbps;
union {
struct {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 076d29b53ddf..cc7ebf04ae00 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -316,6 +316,58 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
spin_unlock_bh(&ar->data_lock);
}
+static void ath10k_mac_update_txrx_rate_iter(void *data,
+ u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct ath10k_fw_stats_peer *peer = data;
+ struct ath10k_vif *arvif;
+
+ if (memcmp(vif->addr, peer->peer_macaddr, ETH_ALEN))
+ return;
+
+ arvif = (void *)vif->drv_priv;
+ arvif->tx_rate_kbps = peer->peer_tx_rate;
+ arvif->rx_rate_kbps = peer->peer_rx_rate;
+}
+
+static void ath10k_mac_update_txrx_rate(struct ath10k *ar,
+ struct ath10k_fw_stats *stats)
+{
+ struct ieee80211_hw *hw = ar->hw;
+ struct ath10k_fw_stats_peer *peer;
+ struct ath10k_sta *arsta;
+ struct ieee80211_sta *sta;
+ const u8 *localaddr = NULL;
+
+ rcu_read_lock();
+
+ list_for_each_entry(peer, &stats->peers, list) {
+ /* This doesn't account for multiple STA connected on different
+ * vifs. Unfortunately there's no way to derive that from the available
+ * information.
+ */
+ sta = ieee80211_find_sta_by_ifaddr(hw,
+ peer->peer_macaddr,
+ localaddr);
+ if (!sta) {
+ /* This tries to update multicast rates */
+ ieee80211_iterate_active_interfaces_atomic(
+ hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ ath10k_mac_update_txrx_rate_iter,
+ peer);
+ continue;
+ }
+
+ arsta = (void *)sta->drv_priv;
+ arsta->tx_rate_kbps = peer->peer_tx_rate;
+ arsta->rx_rate_kbps = peer->peer_rx_rate;
+ }
+
+ rcu_read_unlock();
+}
+
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_fw_stats stats = {};
@@ -335,6 +387,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
goto free;
}
+ ath10k_mac_update_txrx_rate(ar, &stats);
+
/* Stat data may exceed htc-wmi buffer limit. In such case firmware
* splits the stats data and delivers it in a ping-pong fashion of
* request cmd-update event.
@@ -351,13 +405,6 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
if (peer_stats_svc)
ath10k_sta_update_rx_duration(ar, &stats.peers);
- if (ar->debug.fw_stats_done) {
- if (!peer_stats_svc)
- ath10k_warn(ar, "received unsolicited stats update event\n");
-
- goto free;
- }
-
num_peers = ath10k_wmi_fw_stats_num_peers(&ar->debug.fw_stats.peers);
num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs);
is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index ebff9c0a0784..addef9179dbe 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4427,16 +4427,14 @@ static int ath10k_start(struct ieee80211_hw *hw)
ar->ani_enabled = true;
- if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
- param = ar->wmi.pdev_param->peer_stats_update_period;
- ret = ath10k_wmi_pdev_set_param(ar, param,
- PEER_DEFAULT_STATS_UPDATE_PERIOD);
- if (ret) {
- ath10k_warn(ar,
- "failed to set peer stats period : %d\n",
- ret);
- goto err_core_stop;
- }
+ param = ar->wmi.pdev_param->peer_stats_update_period;
+ ret = ath10k_wmi_pdev_set_param(ar, param,
+ PEER_DEFAULT_STATS_UPDATE_PERIOD);
+ if (ret) {
+ ath10k_warn(ar,
+ "failed to set peer stats period : %d\n",
+ ret);
+ goto err_core_stop;
}
ar->num_started_vdevs = 0;
@@ -7215,6 +7213,13 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
return 0;
}
+static u32
+ath10k_mac_op_get_expected_throughput(struct ieee80211_sta *sta)
+{
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ return arsta->tx_rate_kbps;
+}
+
static const struct ieee80211_ops ath10k_ops = {
.tx = ath10k_mac_op_tx,
.wake_tx_queue = ath10k_mac_op_wake_tx_queue,
@@ -7254,6 +7259,7 @@ static const struct ieee80211_ops ath10k_ops = {
.assign_vif_chanctx = ath10k_mac_op_assign_vif_chanctx,
.unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx,
.switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx,
+ .get_expected_throughput = ath10k_mac_op_get_expected_throughput,
CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 4d3cbc44fcd2..2877a3a27b95 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -3296,7 +3296,7 @@ struct wmi_csa_event {
/* the definition of different PDEV parameters */
#define PDEV_DEFAULT_STATS_UPDATE_PERIOD 500
#define VDEV_DEFAULT_STATS_UPDATE_PERIOD 500
-#define PEER_DEFAULT_STATS_UPDATE_PERIOD 500
+#define PEER_DEFAULT_STATS_UPDATE_PERIOD 100
struct wmi_pdev_param_map {
u32 tx_chain_mask;
--
2.1.4
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel
^ permalink raw reply related
* [RFCv2 1/3] mac80211: implement fq_codel for software queuing
From: Michal Kazior @ 2016-03-16 10:17 UTC (permalink / raw)
To: linux-wireless
Cc: nbd, emmanuel.grumbach, netdev, ath10k, codel, make-wifi-fast,
johannes, Tim Shepard
In-Reply-To: <1458123478-1795-1-git-send-email-michal.kazior@tieto.com>
Since 11n aggregation become important to get the
best out of txops. However aggregation inherently
requires buffering and queuing. Once variable
medium conditions to different associated stations
is considered it became apparent that bufferbloat
can't be simply fought with qdiscs for wireless
drivers.
This bases on codel5 and sch_fq_codel.c. It may
not be the Right Thing yet but it should at least
provide a framework for more improvements.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
---
include/net/mac80211.h | 96 ++++++-
net/mac80211/agg-tx.c | 8 +-
net/mac80211/cfg.c | 2 +-
net/mac80211/codel.h | 264 ++++++++++++++++++
net/mac80211/codel_i.h | 89 ++++++
net/mac80211/debugfs.c | 267 ++++++++++++++++++
net/mac80211/ieee80211_i.h | 45 +++-
net/mac80211/iface.c | 25 +-
net/mac80211/main.c | 9 +-
net/mac80211/rx.c | 2 +-
net/mac80211/sta_info.c | 10 +-
net/mac80211/sta_info.h | 27 ++
net/mac80211/status.c | 64 +++++
net/mac80211/tx.c | 658 ++++++++++++++++++++++++++++++++++++++++++---
net/mac80211/util.c | 21 +-
15 files changed, 1503 insertions(+), 84 deletions(-)
create mode 100644 net/mac80211/codel.h
create mode 100644 net/mac80211/codel_i.h
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a53333cb1528..947d827f254b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -565,6 +565,16 @@ struct ieee80211_bss_conf {
struct ieee80211_p2p_noa_attr p2p_noa_attr;
};
+/*
+ * struct codel_params - contains codel parameters
+ * @interval: initial drop rate
+ * @target: maximum persistent sojourn time
+ */
+struct codel_params {
+ u64 interval;
+ u64 target;
+};
+
/**
* enum mac80211_tx_info_flags - flags to describe transmission information/status
*
@@ -853,6 +863,8 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
* @band: the band to transmit on (use for checking for races)
* @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
* @ack_frame_id: internal frame ID for TX status, used internally
+ * @expected_duration: number of microseconds the stack expects this frame to
+ * take to tx. Used for fair queuing.
* @control: union for control data
* @status: union for status data
* @driver_data: array of driver_data pointers
@@ -865,11 +877,10 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
struct ieee80211_tx_info {
/* common information */
u32 flags;
- u8 band;
-
- u8 hw_queue;
-
- u16 ack_frame_id;
+ u32 band:2,
+ hw_queue:5,
+ ack_frame_id:15,
+ expected_duration:10;
union {
struct {
@@ -888,8 +899,18 @@ struct ieee80211_tx_info {
/* only needed before rate control */
unsigned long jiffies;
};
- /* NB: vif can be NULL for injected frames */
- struct ieee80211_vif *vif;
+ union {
+ /* NB: vif can be NULL for injected frames */
+ struct ieee80211_vif *vif;
+
+ /* When packets are enqueued on txq it's easy
+ * to re-construct the vif pointer. There's no
+ * more space in tx_info so it can be used to
+ * store the necessary enqueue time for packet
+ * sojourn time computation.
+ */
+ u64 enqueue_time;
+ };
struct ieee80211_key_conf *hw_key;
u32 flags;
/* 4 bytes free */
@@ -2114,8 +2135,8 @@ enum ieee80211_hw_flags {
* @cipher_schemes: a pointer to an array of cipher scheme definitions
* supported by HW.
*
- * @txq_ac_max_pending: maximum number of frames per AC pending in all txq
- * entries for a vif.
+ * @txq_cparams: codel parameters to control tx queueing dropping behavior
+ * @txq_limit: maximum number of frames queuesd
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
@@ -2145,7 +2166,8 @@ struct ieee80211_hw {
u8 uapsd_max_sp_len;
u8 n_cipher_schemes;
const struct ieee80211_cipher_scheme *cipher_schemes;
- int txq_ac_max_pending;
+ struct codel_params txq_cparams;
+ u32 txq_limit;
};
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
@@ -5633,6 +5655,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
* txq state can change half-way of this function and the caller may end up
* with "new" frame_cnt and "old" byte_cnt or vice-versa.
*
+ * Moreover returned values are best-case, i.e. assuming queueing algorithm
+ * will not drop frames due to excess latency.
+ *
* @txq: pointer obtained from station or virtual interface
* @frame_cnt: pointer to store frame count
* @byte_cnt: pointer to store byte count
@@ -5640,4 +5665,55 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
unsigned long *frame_cnt,
unsigned long *byte_cnt);
+
+/**
+ * ieee80211_recalc_fq_period - recalculate fair-queuing period
+ *
+ * This is used to alter the dropping rate to react to possibly changing
+ * (active) station-tid service period and air conditions.
+ *
+ * Driver which implement wake_tx_queue() but don't use ieee80211_tx_schedule()
+ * are encouraged to call this function periodically.
+ *
+* @hw: pointer as obtained from ieee80211_alloc_hw()
+ */
+void ieee80211_recalc_fq_period(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_tx_schedule - schedule next transmission burst
+ *
+ * This function can be (and should be, preferably) called by drivers that use
+ * wake_tx_queue op. It uses fq-codel like algorithm to maintain fairness.
+ *
+ * This function may call in back to driver (get_expected_throughput op) so
+ * be careful with locking.
+ *
+ * Driver should take care of serializing calls to this functions. Otherwise
+ * fairness can't be guaranteed.
+ *
+ * This function returns the following values:
+ * -EBUSY Software queues are not empty yet. The function should
+ * not be called until after driver's next tx completion.
+ * -ENOENT Software queues are empty.
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @wake: callback to driver to handle burst for given txq within given (byte)
+ * budget. The driver is expected to either call ieee80211_tx_dequeue() or
+ * use its internal queues (if any). The budget should be respected only
+ * for frames comming from ieee80211_tx_dequeue(). On termination it is
+ * expected to return number of frames put onto hw queue that were taken
+ * via ieee80211_tx_dequeue(). Frames from internal retry queues shall not
+ * be included in the returned count. If hw queues become/are busy/full
+ * the driver shall return a negative value which will prompt
+ * ieee80211_tx_schedule() to terminate. If hw queues become full after at
+ * least 1 frame dequeued via ieee80211_tx_dequeue() was sent the driver
+ * is free to report either number of sent frames up until that point or a
+ * negative value. The driver may return 0 if it wants to skip the txq
+ * (e.g. target station is in powersave).
+ */
+int ieee80211_tx_schedule(struct ieee80211_hw *hw,
+ int (*wake)(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq,
+ int budget));
+
#endif /* MAC80211_H */
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 4932e9f243a2..b9d0cee2a786 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -194,17 +194,21 @@ static void
ieee80211_agg_stop_txq(struct sta_info *sta, int tid)
{
struct ieee80211_txq *txq = sta->sta.txq[tid];
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_fq *fq;
struct txq_info *txqi;
if (!txq)
return;
txqi = to_txq_info(txq);
+ sdata = vif_to_sdata(txq->vif);
+ fq = &sdata->local->fq;
/* Lock here to protect against further seqno updates on dequeue */
- spin_lock_bh(&txqi->queue.lock);
+ spin_lock_bh(&fq->lock);
set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
- spin_unlock_bh(&txqi->queue.lock);
+ spin_unlock_bh(&fq->lock);
}
static void
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b37adb60c9cb..238d7bbd275e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3029,7 +3029,7 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
spin_lock_irqsave(&local->ack_status_lock, spin_flags);
id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
+ 1, 0x8000, GFP_ATOMIC);
spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
if (id < 0) {
diff --git a/net/mac80211/codel.h b/net/mac80211/codel.h
new file mode 100644
index 000000000000..e6470dbe5b0b
--- /dev/null
+++ b/net/mac80211/codel.h
@@ -0,0 +1,264 @@
+#ifndef __NET_MAC80211_CODEL_H
+#define __NET_MAC80211_CODEL_H
+
+/*
+ * Codel - The Controlled-Delay Active Queue Management algorithm
+ *
+ * Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
+ * Copyright (C) 2011-2012 Van Jacobson <van@pollere.net>
+ * Copyright (C) 2016 Michael D. Taht <dave.taht@bufferbloat.net>
+ * Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ * Copyright (C) 2015 Jonathan Morton <chromatix99@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/ktime.h>
+#include <linux/skbuff.h>
+#include <net/pkt_sched.h>
+#include <net/inet_ecn.h>
+#include <linux/reciprocal_div.h>
+
+#include "codel_i.h"
+
+/* Controlling Queue Delay (CoDel) algorithm
+ * =========================================
+ * Source : Kathleen Nichols and Van Jacobson
+ * http://queue.acm.org/detail.cfm?id=2209336
+ *
+ * Implemented on linux by Dave Taht and Eric Dumazet
+ */
+
+/* CoDel5 uses a real clock, unlike codel */
+
+static inline u64 codel_get_time(void)
+{
+ return ktime_get_ns();
+}
+
+static inline u32 codel_time_to_us(u64 val)
+{
+ do_div(val, NSEC_PER_USEC);
+ return (u32)val;
+}
+
+/* sizeof_in_bits(rec_inv_sqrt) */
+#define REC_INV_SQRT_BITS (8 * sizeof(u16))
+/* needed shift to get a Q0.32 number from rec_inv_sqrt */
+#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
+
+/* Newton approximation method needs more iterations at small inputs,
+ * so cache them.
+ */
+
+static void codel_vars_init(struct codel_vars *vars)
+{
+ memset(vars, 0, sizeof(*vars));
+}
+
+/*
+ * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots
+ * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2)
+ *
+ * Here, invsqrt is a fixed point number (< 1.0), 32bit mantissa, aka Q0.32
+ */
+static inline void codel_Newton_step(struct codel_vars *vars)
+{
+ u32 invsqrt = ((u32)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
+ u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 32;
+ u64 val = (3LL << 32) - ((u64)vars->count * invsqrt2);
+
+ val >>= 2; /* avoid overflow in following multiply */
+ val = (val * invsqrt) >> (32 - 2 + 1);
+
+ vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT;
+}
+
+/*
+ * CoDel control_law is t + interval/sqrt(count)
+ * We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid
+ * both sqrt() and divide operation.
+ */
+static u64 codel_control_law(u64 t,
+ u64 interval,
+ u32 rec_inv_sqrt)
+{
+ return t + reciprocal_scale(interval, rec_inv_sqrt <<
+ REC_INV_SQRT_SHIFT);
+}
+
+/* Forward declaration of this for use elsewhere */
+
+static inline u64
+custom_codel_get_enqueue_time(struct sk_buff *skb);
+
+static inline struct sk_buff *
+custom_dequeue(struct codel_vars *vars, void *ptr);
+
+static inline void
+custom_drop(struct sk_buff *skb, void *ptr);
+
+static bool codel_should_drop(struct sk_buff *skb,
+ __u32 *backlog,
+ __u32 backlog_thr,
+ struct codel_vars *vars,
+ const struct codel_params *p,
+ u64 now)
+{
+ if (!skb) {
+ vars->first_above_time = 0;
+ return false;
+ }
+
+ if (now - custom_codel_get_enqueue_time(skb) < p->target ||
+ *backlog <= backlog_thr) {
+ /* went below - stay below for at least interval */
+ vars->first_above_time = 0;
+ return false;
+ }
+
+ if (vars->first_above_time == 0) {
+ /* just went above from below; mark the time */
+ vars->first_above_time = now + p->interval;
+
+ } else if (now > vars->first_above_time) {
+ return true;
+ }
+
+ return false;
+}
+
+static struct sk_buff *codel_dequeue(void *ptr,
+ __u32 *backlog,
+ __u32 backlog_thr,
+ struct codel_vars *vars,
+ struct codel_params *p,
+ u64 now,
+ bool overloaded)
+{
+ struct sk_buff *skb = custom_dequeue(vars, ptr);
+ bool drop;
+
+ if (!skb) {
+ vars->dropping = false;
+ return skb;
+ }
+ drop = codel_should_drop(skb, backlog, backlog_thr, vars, p, now);
+ if (vars->dropping) {
+ if (!drop) {
+ /* sojourn time below target - leave dropping state */
+ vars->dropping = false;
+ } else if (now >= vars->drop_next) {
+ /* It's time for the next drop. Drop the current
+ * packet and dequeue the next. The dequeue might
+ * take us out of dropping state.
+ * If not, schedule the next drop.
+ * A large backlog might result in drop rates so high
+ * that the next drop should happen now,
+ * hence the while loop.
+ */
+
+ /* saturating increment */
+ vars->count++;
+ if (!vars->count)
+ vars->count--;
+
+ codel_Newton_step(vars);
+ vars->drop_next = codel_control_law(vars->drop_next,
+ p->interval,
+ vars->rec_inv_sqrt);
+ do {
+ if (INET_ECN_set_ce(skb) && !overloaded) {
+ vars->ecn_mark++;
+ /* and schedule the next drop */
+ vars->drop_next = codel_control_law(
+ vars->drop_next, p->interval,
+ vars->rec_inv_sqrt);
+ goto end;
+ }
+ custom_drop(skb, ptr);
+ vars->drop_count++;
+ skb = custom_dequeue(vars, ptr);
+ if (skb && !codel_should_drop(skb, backlog,
+ backlog_thr,
+ vars, p, now)) {
+ /* leave dropping state */
+ vars->dropping = false;
+ } else {
+ /* schedule the next drop */
+ vars->drop_next = codel_control_law(
+ vars->drop_next, p->interval,
+ vars->rec_inv_sqrt);
+ }
+ } while (skb && vars->dropping && now >=
+ vars->drop_next);
+
+ /* Mark the packet regardless */
+ if (skb && INET_ECN_set_ce(skb))
+ vars->ecn_mark++;
+ }
+ } else if (drop) {
+ if (INET_ECN_set_ce(skb) && !overloaded) {
+ vars->ecn_mark++;
+ } else {
+ custom_drop(skb, ptr);
+ vars->drop_count++;
+
+ skb = custom_dequeue(vars, ptr);
+ drop = codel_should_drop(skb, backlog, backlog_thr,
+ vars, p, now);
+ if (skb && INET_ECN_set_ce(skb))
+ vars->ecn_mark++;
+ }
+ vars->dropping = true;
+ /* if min went above target close to when we last went below
+ * assume that the drop rate that controlled the queue on the
+ * last cycle is a good starting point to control it now.
+ */
+ if (vars->count > 2 &&
+ now - vars->drop_next < 8 * p->interval) {
+ vars->count -= 2;
+ codel_Newton_step(vars);
+ } else {
+ vars->count = 1;
+ vars->rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT;
+ }
+ codel_Newton_step(vars);
+ vars->drop_next = codel_control_law(now, p->interval,
+ vars->rec_inv_sqrt);
+ }
+end:
+ return skb;
+}
+#endif
diff --git a/net/mac80211/codel_i.h b/net/mac80211/codel_i.h
new file mode 100644
index 000000000000..a7d23e45dee9
--- /dev/null
+++ b/net/mac80211/codel_i.h
@@ -0,0 +1,89 @@
+#ifndef __NET_MAC80211_CODEL_I_H
+#define __NET_MAC80211_CODEL_I_H
+
+/*
+ * Codel - The Controlled-Delay Active Queue Management algorithm
+ *
+ * Copyright (C) 2011-2012 Kathleen Nichols <nichols@pollere.com>
+ * Copyright (C) 2011-2012 Van Jacobson <van@pollere.net>
+ * Copyright (C) 2016 Michael D. Taht <dave.taht@bufferbloat.net>
+ * Copyright (C) 2012 Eric Dumazet <edumazet@google.com>
+ * Copyright (C) 2015 Jonathan Morton <chromatix99@gmail.com>
+ * Copyright (C) 2016 Michal Kazior <michal.kazior@tieto.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/ktime.h>
+#include <linux/skbuff.h>
+#include <net/pkt_sched.h>
+#include <net/inet_ecn.h>
+#include <linux/reciprocal_div.h>
+
+/* Controlling Queue Delay (CoDel) algorithm
+ * =========================================
+ * Source : Kathleen Nichols and Van Jacobson
+ * http://queue.acm.org/detail.cfm?id=2209336
+ *
+ * Implemented on linux by Dave Taht and Eric Dumazet
+ */
+
+/* CoDel5 uses a real clock, unlike codel */
+
+#define MS2TIME(a) (a * (u64) NSEC_PER_MSEC)
+#define US2TIME(a) (a * (u64) NSEC_PER_USEC)
+
+/**
+ * struct codel_vars - contains codel variables
+ * @count: how many drops we've done since the last time we
+ * entered dropping state
+ * @dropping: set to > 0 if in dropping state
+ * @rec_inv_sqrt: reciprocal value of sqrt(count) >> 1
+ * @first_above_time: when we went (or will go) continuously above target
+ * for interval
+ * @drop_next: time to drop next packet, or when we dropped last
+ * @drop_count: temp count of dropped packets in dequeue()
+ * @ecn_mark: number of packets we ECN marked instead of dropping
+ */
+
+struct codel_vars {
+ u32 count;
+ u16 dropping;
+ u16 rec_inv_sqrt;
+ u64 first_above_time;
+ u64 drop_next;
+ u16 drop_count;
+ u16 ecn_mark;
+};
+#endif
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 4ab5c522ceee..9b0b8c3d23cd 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -31,6 +31,30 @@ int mac80211_format_buffer(char __user *userbuf, size_t count,
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
+static int mac80211_parse_buffer(const char __user *userbuf,
+ size_t count,
+ loff_t *ppos,
+ char *fmt, ...)
+{
+ va_list args;
+ char buf[DEBUGFS_FORMAT_BUFFER_SIZE] = {};
+ int res;
+
+ if (count > sizeof(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, userbuf, count))
+ return -EFAULT;
+
+ buf[sizeof(buf) - 1] = '\0';
+
+ va_start(args, fmt);
+ res = vsscanf(buf, fmt, args);
+ va_end(args);
+
+ return count;
+}
+
#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
@@ -70,6 +94,62 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
+DEBUGFS_READONLY_FILE(fq_drop_overlimit, "%d",
+ local->fq.drop_overlimit);
+DEBUGFS_READONLY_FILE(fq_drop_codel, "%d",
+ local->fq.drop_codel);
+DEBUGFS_READONLY_FILE(fq_backlog, "%d",
+ local->fq.backlog);
+DEBUGFS_READONLY_FILE(fq_in_flight_usec, "%d",
+ atomic_read(&local->fq.in_flight_usec));
+DEBUGFS_READONLY_FILE(fq_txq_limit, "%d",
+ local->hw.txq_limit);
+DEBUGFS_READONLY_FILE(fq_txq_interval, "%llu",
+ local->hw.txq_cparams.interval);
+DEBUGFS_READONLY_FILE(fq_txq_target, "%llu",
+ local->hw.txq_cparams.target);
+DEBUGFS_READONLY_FILE(fq_ave_period, "%d",
+ (int)ewma_fq_period_read(&local->fq.ave_period));
+
+#define DEBUGFS_RW_FILE_FN(name, expr) \
+static ssize_t name## _write(struct file *file, \
+ const char __user *userbuf, \
+ size_t count, \
+ loff_t *ppos) \
+{ \
+ struct ieee80211_local *local = file->private_data; \
+ return expr; \
+}
+
+#define DEBUGFS_RW_FILE(name, expr, fmt, value...) \
+ DEBUGFS_READONLY_FILE_FN(name, fmt, value) \
+ DEBUGFS_RW_FILE_FN(name, expr) \
+ DEBUGFS_RW_FILE_OPS(name)
+
+#define DEBUGFS_RW_FILE_OPS(name) \
+static const struct file_operations name## _ops = { \
+ .read = name## _read, \
+ .write = name## _write, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+};
+
+#define DEBUGFS_RW_EXPR_FQ(name) \
+({ \
+ int res; \
+ res = mac80211_parse_buffer(userbuf, count, ppos, "%d", &name); \
+ ieee80211_recalc_fq_period(&local->hw); \
+ res; \
+})
+
+DEBUGFS_RW_FILE(fq_min_txops_target, DEBUGFS_RW_EXPR_FQ(local->fq.min_txops_target), "%d", local->fq.min_txops_target);
+DEBUGFS_RW_FILE(fq_max_txops_per_txq, DEBUGFS_RW_EXPR_FQ(local->fq.max_txops_per_txq), "%d", local->fq.max_txops_per_txq);
+DEBUGFS_RW_FILE(fq_min_txops_per_hw, DEBUGFS_RW_EXPR_FQ(local->fq.min_txops_per_hw), "%d", local->fq.min_txops_per_hw);
+DEBUGFS_RW_FILE(fq_max_txops_per_hw, DEBUGFS_RW_EXPR_FQ(local->fq.max_txops_per_hw), "%d", local->fq.max_txops_per_hw);
+DEBUGFS_RW_FILE(fq_txop_mixed_usec, DEBUGFS_RW_EXPR_FQ(local->fq.txop_mixed_usec), "%d", local->fq.txop_mixed_usec);
+DEBUGFS_RW_FILE(fq_txop_green_usec, DEBUGFS_RW_EXPR_FQ(local->fq.txop_green_usec), "%d", local->fq.txop_green_usec);
+
+
#ifdef CONFIG_PM
static ssize_t reset_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -177,8 +257,178 @@ static ssize_t queues_read(struct file *file, char __user *user_buf,
return simple_read_from_buffer(user_buf, count, ppos, buf, res);
}
+static ssize_t fq_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+ struct txq_flow *flow;
+ struct txq_info *txqi;
+ void *buf;
+ int new_flows;
+ int old_flows;
+ int len;
+ int i;
+ int rv;
+ int res = 0;
+ static const u8 zeroaddr[ETH_ALEN];
+
+ len = 32 * 1024;
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ spin_lock_bh(&local->fq.lock);
+ rcu_read_lock();
+
+ list_for_each_entry(txqi, &local->fq.new_flows, flowchain) {
+ res += scnprintf(buf + res, len - res,
+ "sched new txqi vif %s sta %pM tid %d deficit %d\n",
+ container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif)->name,
+ txqi->txq.sta ? txqi->txq.sta->addr : zeroaddr,
+ txqi->txq.tid,
+ txqi->deficit);
+ }
+
+ list_for_each_entry(txqi, &local->fq.old_flows, flowchain) {
+ res += scnprintf(buf + res, len - res,
+ "sched old txqi vif %s sta %pM tid %d deficit %d\n",
+ container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif)->name,
+ txqi->txq.sta ? txqi->txq.sta->addr : zeroaddr,
+ txqi->txq.tid,
+ txqi->deficit);
+ }
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+ if (!sta->sta.txq[i])
+ continue;
+
+ txqi = container_of(sta->sta.txq[i], struct txq_info, txq);
+ if (!txqi->backlog_bytes)
+ continue;
+
+ new_flows = 0;
+ old_flows = 0;
+
+ list_for_each_entry(flow, &txqi->new_flows, flowchain)
+ new_flows++;
+ list_for_each_entry(flow, &txqi->old_flows, flowchain)
+ old_flows++;
+
+ res += scnprintf(buf + res, len - res,
+ "sta %pM tid %d backlog (%db %dp) flows (%d new %d old) burst %d bpu %d in-flight %d\n",
+ sta->sta.addr,
+ i,
+ txqi->backlog_bytes,
+ txqi->backlog_packets,
+ new_flows,
+ old_flows,
+ txqi->bytes_per_burst,
+ txqi->bytes_per_usec,
+ atomic_read(&txqi->in_flight_usec)
+ );
+
+ flow = &txqi->flow;
+ res += scnprintf(buf + res, len - res,
+ "sta %pM def flow %p backlog (%db %dp)\n",
+ sta->sta.addr,
+ flow,
+ flow->backlog,
+ flow->queue.qlen
+ );
+
+ list_for_each_entry(flow, &txqi->new_flows, flowchain)
+ res += scnprintf(buf + res, len - res,
+ "sta %pM tid %d new flow %p backlog (%db %dp)\n",
+ sta->sta.addr,
+ i,
+ flow,
+ flow->backlog,
+ flow->queue.qlen
+ );
+
+ list_for_each_entry(flow, &txqi->old_flows, flowchain)
+ res += scnprintf(buf + res, len - res,
+ "sta %pM tid %d old flow %p backlog (%db %dp)\n",
+ sta->sta.addr,
+ i,
+ flow,
+ flow->backlog,
+ flow->queue.qlen
+ );
+ }
+ }
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!sdata->vif.txq)
+ continue;
+
+ txqi = container_of(sdata->vif.txq, struct txq_info, txq);
+ if (!txqi->backlog_bytes)
+ continue;
+
+ new_flows = 0;
+ old_flows = 0;
+
+ list_for_each_entry(flow, &txqi->new_flows, flowchain)
+ new_flows++;
+ list_for_each_entry(flow, &txqi->old_flows, flowchain)
+ old_flows++;
+
+ res += scnprintf(buf + res, len - res,
+ "vif %s backlog (%db %dp) flows (%d new %d old) burst %d bpu %d in-flight %d\n",
+ sdata->name,
+ txqi->backlog_bytes,
+ txqi->backlog_packets,
+ new_flows,
+ old_flows,
+ txqi->bytes_per_burst,
+ txqi->bytes_per_usec,
+ atomic_read(&txqi->in_flight_usec)
+ );
+
+ flow = &txqi->flow;
+ res += scnprintf(buf + res, len - res,
+ "vif %s def flow %p backlog (%db %dp)\n",
+ sdata->name,
+ flow,
+ flow->backlog,
+ flow->queue.qlen
+ );
+
+ list_for_each_entry(flow, &txqi->new_flows, flowchain)
+ res += scnprintf(buf + res, len - res,
+ "vif %s new flow %p backlog (%db %dp)\n",
+ sdata->name,
+ flow,
+ flow->backlog,
+ flow->queue.qlen
+ );
+
+ list_for_each_entry(flow, &txqi->old_flows, flowchain)
+ res += scnprintf(buf + res, len - res,
+ "vif %s old flow %p backlog (%db %dp)\n",
+ sdata->name,
+ flow,
+ flow->backlog,
+ flow->queue.qlen
+ );
+ }
+
+ rcu_read_unlock();
+ spin_unlock_bh(&local->fq.lock);
+
+ rv = simple_read_from_buffer(user_buf, count, ppos, buf, res);
+ kfree(buf);
+
+ return rv;
+}
+
DEBUGFS_READONLY_FILE_OPS(hwflags);
DEBUGFS_READONLY_FILE_OPS(queues);
+DEBUGFS_READONLY_FILE_OPS(fq);
/* statistics stuff */
@@ -247,6 +497,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(queues);
+ DEBUGFS_ADD(fq);
#ifdef CONFIG_PM
DEBUGFS_ADD_MODE(reset, 0200);
#endif
@@ -254,6 +505,22 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power);
+ DEBUGFS_ADD(fq_drop_overlimit);
+ DEBUGFS_ADD(fq_drop_codel);
+ DEBUGFS_ADD(fq_backlog);
+ DEBUGFS_ADD(fq_in_flight_usec);
+ DEBUGFS_ADD(fq_txq_limit);
+ DEBUGFS_ADD(fq_txq_interval);
+ DEBUGFS_ADD(fq_txq_target);
+ DEBUGFS_ADD(fq_ave_period);
+
+ DEBUGFS_ADD(fq_min_txops_target);
+ DEBUGFS_ADD(fq_max_txops_per_txq);
+ DEBUGFS_ADD(fq_min_txops_per_hw);
+ DEBUGFS_ADD(fq_max_txops_per_hw);
+ DEBUGFS_ADD(fq_txop_mixed_usec);
+ DEBUGFS_ADD(fq_txop_green_usec);
+
statsd = debugfs_create_dir("statistics", phyd);
/* if the dir failed, don't put all the other things into the root! */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f1565ce35273..443c941d5917 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -805,9 +805,18 @@ enum txq_info_flags {
};
struct txq_info {
- struct sk_buff_head queue;
+ struct txq_flow flow;
+ struct list_head flowchain;
+ struct list_head new_flows;
+ struct list_head old_flows;
+ int backlog_bytes;
+ int backlog_packets;
+ int bytes_per_burst;
+ int bytes_per_usec;
+ int deficit;
+ int in_flight_delta_usec;
+ atomic_t in_flight_usec;
unsigned long flags;
- unsigned long byte_cnt;
/* keep last! */
struct ieee80211_txq txq;
@@ -855,7 +864,6 @@ struct ieee80211_sub_if_data {
bool control_port_no_encrypt;
int encrypt_headroom;
- atomic_t txqs_len[IEEE80211_NUM_ACS];
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
struct mac80211_qos_map __rcu *qos_map;
@@ -1092,11 +1100,37 @@ enum mac80211_scan_state {
SCAN_ABORT,
};
+DECLARE_EWMA(fq_period, 16, 4)
+
+struct ieee80211_fq {
+ struct txq_flow *flows;
+ struct list_head backlogs;
+ struct list_head old_flows;
+ struct list_head new_flows;
+ struct ewma_fq_period ave_period;
+ spinlock_t lock;
+ atomic_t in_flight_usec;
+ int flows_cnt;
+ int perturbation;
+ int quantum;
+ int backlog;
+ int min_txops_target;
+ int max_txops_per_txq;
+ int min_txops_per_hw;
+ int max_txops_per_hw;
+ int txop_mixed_usec;
+ int txop_green_usec;
+
+ int drop_overlimit;
+ int drop_codel;
+};
+
struct ieee80211_local {
/* embed the driver visible part.
* don't cast (use the static inlines below), but we keep
* it first anyway so they become a no-op */
struct ieee80211_hw hw;
+ struct ieee80211_fq fq;
const struct ieee80211_ops *ops;
@@ -1928,6 +1962,11 @@ static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct txq_info *txq, int tid);
+void ieee80211_purge_txq(struct ieee80211_local *local, struct txq_info *txqi);
+void ieee80211_init_flow(struct txq_flow *flow);
+int ieee80211_setup_flows(struct ieee80211_local *local);
+void ieee80211_teardown_flows(struct ieee80211_local *local);
+
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
const u8 *extra, size_t extra_len, const u8 *bssid,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 453b4e741780..d1063b50f12c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -779,6 +779,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
bool going_down)
{
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_fq *fq = &local->fq;
unsigned long flags;
struct sk_buff *skb, *tmp;
u32 hw_reconf_flags = 0;
@@ -977,12 +978,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.txq) {
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
- spin_lock_bh(&txqi->queue.lock);
- ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
- txqi->byte_cnt = 0;
- spin_unlock_bh(&txqi->queue.lock);
-
- atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
+ spin_lock_bh(&fq->lock);
+ ieee80211_purge_txq(local, txqi);
+ spin_unlock_bh(&fq->lock);
}
if (local->open_count == 0)
@@ -1198,6 +1196,13 @@ static void ieee80211_if_setup(struct net_device *dev)
dev->destructor = ieee80211_if_free;
}
+static void ieee80211_if_setup_no_queue(struct net_device *dev)
+{
+ ieee80211_if_setup(dev);
+ dev->priv_flags |= IFF_NO_QUEUE;
+ /* Note for backporters: use dev->tx_queue_len = 0 instead of IFF_ */
+}
+
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -1707,6 +1712,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device *ndev = NULL;
struct ieee80211_sub_if_data *sdata = NULL;
struct txq_info *txqi;
+ void (*if_setup)(struct net_device *dev);
int ret, i;
int txqs = 1;
@@ -1734,12 +1740,17 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
txq_size += sizeof(struct txq_info) +
local->hw.txq_data_size;
+ if (local->ops->wake_tx_queue)
+ if_setup = ieee80211_if_setup_no_queue;
+ else
+ if_setup = ieee80211_if_setup;
+
if (local->hw.queues >= IEEE80211_NUM_ACS)
txqs = IEEE80211_NUM_ACS;
ndev = alloc_netdev_mqs(size + txq_size,
name, name_assign_type,
- ieee80211_if_setup, txqs, 1);
+ if_setup, txqs, 1);
if (!ndev)
return -ENOMEM;
dev_net_set(ndev, wiphy_net(local->hw.wiphy));
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 8190bf27ebff..9fd3b10ae52b 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1053,9 +1053,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->dynamic_ps_forced_timeout = -1;
- if (!local->hw.txq_ac_max_pending)
- local->hw.txq_ac_max_pending = 64;
-
result = ieee80211_wep_init(local);
if (result < 0)
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
@@ -1087,6 +1084,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
rtnl_unlock();
+ result = ieee80211_setup_flows(local);
+ if (result)
+ goto fail_flows;
+
#ifdef CONFIG_INET
local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
result = register_inetaddr_notifier(&local->ifa_notifier);
@@ -1112,6 +1113,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
fail_ifa:
#endif
+ ieee80211_teardown_flows(local);
+ fail_flows:
rtnl_lock();
rate_control_deinitialize(local);
ieee80211_remove_interfaces(local);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index dc27becb9b71..70f8f7949bf2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info *sta)
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
- if (!skb_queue_len(&txqi->queue))
+ if (!txqi->backlog_packets)
set_bit(tid, &sta->txq_buffered_tids);
else
clear_bit(tid, &sta->txq_buffered_tids);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 00c82fb152c0..0729046a0144 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -112,11 +112,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
if (sta->sta.txq[0]) {
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
- int n = skb_queue_len(&txqi->queue);
-
- ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
- atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
- txqi->byte_cnt = 0;
+ ieee80211_purge_txq(local, txqi);
}
}
@@ -1193,7 +1189,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
- if (!skb_queue_len(&txqi->queue))
+ if (!txqi->backlog_packets)
continue;
drv_wake_tx_queue(local, txqi);
@@ -1630,7 +1626,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
- if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue))
+ if (!(tids & BIT(tid)) || txqi->backlog_packets)
continue;
sta_info_recalc_tim(sta);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 053f5c4fa495..dd9d5f754c57 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -19,6 +19,7 @@
#include <linux/etherdevice.h>
#include <linux/rhashtable.h>
#include "key.h"
+#include "codel_i.h"
/**
* enum ieee80211_sta_info_flags - Stations flags
@@ -330,6 +331,32 @@ struct mesh_sta {
DECLARE_EWMA(signal, 1024, 8)
+struct txq_info;
+
+/**
+ * struct txq_flow - per traffic flow queue
+ *
+ * This structure is used to distinguish and queue different traffic flows
+ * separately for fair queueing/AQM purposes.
+ *
+ * @txqi: txq_info structure it is associated at given time
+ * @flowchain: can be linked to other flows for RR purposes
+ * @backlogchain: can be linked to other flows for backlog sorting purposes
+ * @queue: sk_buff queue
+ * @cvars: codel state vars
+ * @backlog: number of bytes pending in the queue
+ * @deficit: used for fair queueing balancing
+ */
+struct txq_flow {
+ struct txq_info *txqi;
+ struct list_head flowchain;
+ struct list_head backlogchain;
+ struct sk_buff_head queue;
+ struct codel_vars cvars;
+ int backlog;
+ int deficit;
+};
+
/**
* struct sta_info - STA information
*
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 8b1b2ea03eb5..2cd898f8a658 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -502,6 +502,67 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
}
}
+static void ieee80211_report_txq_skb(struct ieee80211_local *local,
+ struct ieee80211_hdr *hdr,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_fq *fq = &local->fq;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_txq *txq = NULL;
+ struct sta_info *sta;
+ struct txq_info *txqi;
+ struct rhash_head *tmp;
+ const struct bucket_table *tbl;
+ int tid;
+ __le16 fc = hdr->frame_control;
+ u8 *addr;
+ static const u8 zeroaddr[ETH_ALEN];
+
+ if (!ieee80211_is_data(fc))
+ return;
+
+ rcu_read_lock();
+
+ tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+ for_each_sta_info(local, tbl, hdr->addr1, sta, tmp) {
+ /* skip wrong virtual interface */
+ if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
+ continue;
+
+ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+ txq = sta->sta.txq[tid];
+
+ break;
+ }
+
+ if (!txq) {
+ addr = ieee80211_get_DA(hdr);
+ if (is_multicast_ether_addr(addr)) {
+ sdata = ieee80211_sdata_from_skb(local, skb);
+ txq = sdata->vif.txq;
+ }
+ }
+
+ if (txq) {
+ txqi = container_of(txq, struct txq_info, txq);
+ atomic_sub(info->expected_duration, &txqi->in_flight_usec);
+ if (atomic_read(&txqi->in_flight_usec) < 0) {
+ WARN_ON_ONCE(1);
+ print_hex_dump(KERN_DEBUG, "skb: ", DUMP_PREFIX_OFFSET, 16, 1,
+ skb->data, skb->len, 0);
+ printk("underflow: txq tid %d sta %pM vif %s\n",
+ txq->tid,
+ txq->sta ? txq->sta->addr : zeroaddr,
+ container_of(txq->vif, struct ieee80211_sub_if_data, vif)->name);
+ }
+ }
+
+ atomic_sub(info->expected_duration, &fq->in_flight_usec);
+
+ rcu_read_unlock();
+}
+
static void ieee80211_report_used_skb(struct ieee80211_local *local,
struct sk_buff *skb, bool dropped)
{
@@ -512,6 +573,9 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
if (dropped)
acked = false;
+ if (local->ops->wake_tx_queue)
+ ieee80211_report_txq_skb(local, hdr, skb);
+
if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
struct ieee80211_sub_if_data *sdata;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 6040c29a9e17..3072e460e82a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -34,6 +34,7 @@
#include "wpa.h"
#include "wme.h"
#include "rate.h"
+#include "codel.h"
/* misc utils */
@@ -1232,27 +1233,335 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
return TX_CONTINUE;
}
-static void ieee80211_drv_tx(struct ieee80211_local *local,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *pubsta,
- struct sk_buff *skb)
+static inline u64
+custom_codel_get_enqueue_time(struct sk_buff *skb)
+{
+ return IEEE80211_SKB_CB(skb)->control.enqueue_time;
+}
+
+static inline struct sk_buff *
+flow_dequeue(struct ieee80211_local *local, struct txq_flow *flow)
+{
+ struct ieee80211_fq *fq = &local->fq;
+ struct txq_info *txqi = flow->txqi;
+ struct txq_flow *i;
+ struct sk_buff *skb;
+
+ skb = __skb_dequeue(&flow->queue);
+ if (!skb)
+ return NULL;
+
+ txqi->backlog_bytes -= skb->len;
+ txqi->backlog_packets--;
+ flow->backlog -= skb->len;
+ fq->backlog--;
+
+ if (flow->backlog == 0) {
+ list_del_init(&flow->backlogchain);
+ } else {
+ i = flow;
+
+ list_for_each_entry_continue(i, &fq->backlogs, backlogchain)
+ if (i->backlog < flow->backlog)
+ break;
+
+ list_move_tail(&flow->backlogchain, &i->backlogchain);
+ }
+
+ return skb;
+}
+
+static inline struct sk_buff *
+custom_dequeue(struct codel_vars *vars, void *ptr)
+{
+ struct txq_flow *flow = ptr;
+ struct txq_info *txqi = flow->txqi;
+ struct ieee80211_vif *vif = txqi->txq.vif;
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+
+ return flow_dequeue(local, flow);
+}
+
+static inline void
+custom_drop(struct sk_buff *skb, void *ptr)
+{
+ struct txq_flow *flow = ptr;
+ struct txq_info *txqi = flow->txqi;
+ struct ieee80211_vif *vif = txqi->txq.vif;
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_hw *hw = &local->hw;
+
+ ieee80211_free_txskb(hw, skb);
+ local->fq.drop_codel++;
+}
+
+static u32 fq_hash(struct ieee80211_fq *fq, struct sk_buff *skb)
+{
+ u32 hash = skb_get_hash_perturb(skb, fq->perturbation);
+ return reciprocal_scale(hash, fq->flows_cnt);
+}
+
+static void fq_drop(struct ieee80211_local *local)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ struct ieee80211_fq *fq = &local->fq;
+ struct txq_flow *flow;
+ struct sk_buff *skb;
+
+ flow = list_first_entry_or_null(&fq->backlogs, struct txq_flow,
+ backlogchain);
+ if (WARN_ON_ONCE(!flow))
+ return;
+
+ skb = flow_dequeue(local, flow);
+ if (WARN_ON_ONCE(!skb))
+ return;
+
+ ieee80211_free_txskb(hw, skb);
+ fq->drop_overlimit++;
+}
+
+void ieee80211_init_flow(struct txq_flow *flow)
+{
+ INIT_LIST_HEAD(&flow->flowchain);
+ INIT_LIST_HEAD(&flow->backlogchain);
+ __skb_queue_head_init(&flow->queue);
+ codel_vars_init(&flow->cvars);
+}
+
+#define MIN_FQ_TARGET_USEC(fq) ((fq)->min_txops_target * (fq)->txop_mixed_usec)
+
+int ieee80211_setup_flows(struct ieee80211_local *local)
+{
+ struct ieee80211_fq *fq = &local->fq;
+ int i;
+
+ if (!local->ops->wake_tx_queue)
+ return 0;
+
+ if (!local->hw.txq_limit)
+ local->hw.txq_limit = 8192;
+
+ memset(fq, 0, sizeof(fq[0]));
+ INIT_LIST_HEAD(&fq->backlogs);
+ INIT_LIST_HEAD(&fq->old_flows);
+ INIT_LIST_HEAD(&fq->new_flows);
+ ewma_fq_period_init(&fq->ave_period);
+ atomic_set(&fq->in_flight_usec, 0);
+ spin_lock_init(&fq->lock);
+ fq->flows_cnt = 4096;
+ fq->perturbation = prandom_u32();
+ fq->quantum = 300;
+ fq->txop_mixed_usec = 5484;
+ fq->txop_green_usec = 10000;
+ fq->min_txops_target = 2;
+ fq->max_txops_per_txq = 1;
+ fq->min_txops_per_hw = 3;
+ fq->max_txops_per_hw = 4;
+
+ if (!local->hw.txq_cparams.target)
+ local->hw.txq_cparams.target = US2TIME(MIN_FQ_TARGET_USEC(fq));
+
+ if (!local->hw.txq_cparams.interval)
+ local->hw.txq_cparams.interval = MS2TIME(100);
+
+ fq->flows = kzalloc(fq->flows_cnt * sizeof(fq->flows[0]), GFP_KERNEL);
+ if (!fq->flows)
+ return -ENOMEM;
+
+ for (i = 0; i < fq->flows_cnt; i++)
+ ieee80211_init_flow(&fq->flows[i]);
+
+ return 0;
+}
+
+static void ieee80211_reset_flow(struct ieee80211_local *local,
+ struct txq_flow *flow)
+{
+ if (!list_empty(&flow->flowchain))
+ list_del_init(&flow->flowchain);
+
+ if (!list_empty(&flow->backlogchain))
+ list_del_init(&flow->backlogchain);
+
+ ieee80211_purge_tx_queue(&local->hw, &flow->queue);
+
+ flow->deficit = 0;
+ flow->txqi = NULL;
+}
+
+void ieee80211_purge_txq(struct ieee80211_local *local, struct txq_info *txqi)
+{
+ struct txq_flow *flow;
+ int i;
+
+ for (i = 0; i < local->fq.flows_cnt; i++) {
+ flow = &local->fq.flows[i];
+
+ if (flow->txqi != txqi)
+ continue;
+
+ ieee80211_reset_flow(local, flow);
+ }
+
+ ieee80211_reset_flow(local, &txqi->flow);
+
+ txqi->backlog_bytes = 0;
+ txqi->backlog_packets = 0;
+}
+
+void ieee80211_teardown_flows(struct ieee80211_local *local)
+{
+ struct ieee80211_fq *fq = &local->fq;
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+ int i;
+
+ if (!local->ops->wake_tx_queue)
+ return;
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list)
+ for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+ ieee80211_purge_txq(local,
+ to_txq_info(sta->sta.txq[i]));
+
+ list_for_each_entry_rcu(sdata, &local->interfaces, list)
+ ieee80211_purge_txq(local, to_txq_info(sdata->vif.txq));
+
+ for (i = 0; i < fq->flows_cnt; i++)
+ ieee80211_reset_flow(local, &fq->flows[i]);
+
+ kfree(fq->flows);
+
+ fq->flows = NULL;
+ fq->flows_cnt = 0;
+}
+
+static void ieee80211_txq_enqueue(struct ieee80211_local *local,
+ struct txq_info *txqi,
+ struct sk_buff *skb)
+{
+ struct ieee80211_fq *fq = &local->fq;
+ struct ieee80211_hw *hw = &local->hw;
+ struct txq_flow *flow;
+ struct txq_flow *i;
+ size_t idx = fq_hash(fq, skb);
+
+ lockdep_assert_held(&fq->lock);
+
+ flow = &fq->flows[idx];
+
+ if (flow->txqi && flow->txqi != txqi)
+ flow = &txqi->flow;
+
+ /* The following overwrites `vif` pointer effectively. It is later
+ * restored using txq structure.
+ */
+ IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
+
+ flow->txqi = txqi;
+ flow->backlog += skb->len;
+ txqi->backlog_bytes += skb->len;
+ txqi->backlog_packets++;
+ fq->backlog++;
+
+ if (list_empty(&flow->backlogchain))
+ list_add_tail(&flow->backlogchain, &fq->backlogs);
+
+ i = flow;
+ list_for_each_entry_continue_reverse(i, &fq->backlogs, backlogchain)
+ if (i->backlog > flow->backlog)
+ break;
+
+ list_move(&flow->backlogchain, &i->backlogchain);
+
+ if (list_empty(&flow->flowchain)) {
+ flow->deficit = fq->quantum;
+ list_add_tail(&flow->flowchain, &txqi->new_flows);
+ }
+
+ if (list_empty(&txqi->flowchain)) {
+ txqi->deficit = fq->quantum;
+ list_add_tail(&txqi->flowchain, &fq->new_flows);
+ }
+
+ __skb_queue_tail(&flow->queue, skb);
+
+ if (fq->backlog > hw->txq_limit)
+ fq_drop(local);
+}
+
+static struct sk_buff *ieee80211_txq_dequeue(struct ieee80211_local *local,
+ struct txq_info *txqi)
+{
+ struct ieee80211_fq *fq = &local->fq;
+ struct ieee80211_hw *hw = &local->hw;
+ struct txq_flow *flow;
+ struct list_head *head;
+ struct sk_buff *skb;
+
+begin:
+ head = &txqi->new_flows;
+ if (list_empty(head)) {
+ head = &txqi->old_flows;
+ if (list_empty(head))
+ return NULL;
+ }
+
+ flow = list_first_entry(head, struct txq_flow, flowchain);
+
+ if (flow->deficit <= 0) {
+ flow->deficit += fq->quantum;
+ list_move_tail(&flow->flowchain, &txqi->old_flows);
+ goto begin;
+ }
+
+ skb = codel_dequeue(flow,
+ &flow->backlog,
+ txqi->bytes_per_burst,
+ &flow->cvars,
+ &hw->txq_cparams,
+ codel_get_time(),
+ false);
+ if (!skb) {
+ if ((head == &txqi->new_flows) &&
+ !list_empty(&txqi->old_flows)) {
+ list_move_tail(&flow->flowchain, &txqi->old_flows);
+ } else {
+ list_del_init(&flow->flowchain);
+ flow->txqi = NULL;
+ }
+ goto begin;
+ }
+
+ flow->deficit -= skb->len;
+
+ /* The `vif` pointer was overwritten with enqueue time during
+ * enqueuing. Restore it before handing to driver.
+ */
+ IEEE80211_SKB_CB(skb)->control.vif = flow->txqi->txq.vif;
+
+ return skb;
+}
+
+static struct txq_info *
+ieee80211_get_txq(struct ieee80211_local *local,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *pubsta,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_control control = {
- .sta = pubsta,
- };
struct ieee80211_txq *txq = NULL;
- struct txq_info *txqi;
- u8 ac;
if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
- goto tx_normal;
+ return NULL;
if (!ieee80211_is_data(hdr->frame_control))
- goto tx_normal;
+ return NULL;
if (pubsta) {
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@@ -1263,57 +1572,48 @@ static void ieee80211_drv_tx(struct ieee80211_local *local,
}
if (!txq)
- goto tx_normal;
+ return NULL;
- ac = txq->ac;
- txqi = to_txq_info(txq);
- atomic_inc(&sdata->txqs_len[ac]);
- if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending)
- netif_stop_subqueue(sdata->dev, ac);
-
- spin_lock_bh(&txqi->queue.lock);
- txqi->byte_cnt += skb->len;
- __skb_queue_tail(&txqi->queue, skb);
- spin_unlock_bh(&txqi->queue.lock);
-
- drv_wake_tx_queue(local, txqi);
-
- return;
-
-tx_normal:
- drv_tx(local, &control, skb);
+ return to_txq_info(txq);
}
+#define TXQI_BYTES_TO_USEC(txqi, bytes) \
+ DIV_ROUND_UP((bytes), max_t(int, 1, (txqi)->bytes_per_usec))
+
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
+ struct ieee80211_fq *fq = &local->fq;
+ struct ieee80211_tx_info *info;
struct txq_info *txqi = container_of(txq, struct txq_info, txq);
struct ieee80211_hdr *hdr;
struct sk_buff *skb = NULL;
- u8 ac = txq->ac;
+ int duration_usec;
- spin_lock_bh(&txqi->queue.lock);
+ spin_lock_bh(&fq->lock);
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
goto out;
- skb = __skb_dequeue(&txqi->queue);
+ skb = ieee80211_txq_dequeue(local, txqi);
if (!skb)
goto out;
- txqi->byte_cnt -= skb->len;
+ duration_usec = TXQI_BYTES_TO_USEC(txqi, skb->len);
+ duration_usec = min_t(int, BIT(10) - 1, duration_usec);
- atomic_dec(&sdata->txqs_len[ac]);
- if (__netif_subqueue_stopped(sdata->dev, ac))
- ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
+ info = IEEE80211_SKB_CB(skb);
+ info->expected_duration = duration_usec;
+
+ txqi->in_flight_delta_usec += duration_usec;
+ atomic_add(duration_usec, &txqi->in_flight_usec);
+ atomic_add(duration_usec, &fq->in_flight_usec);
hdr = (struct ieee80211_hdr *)skb->data;
if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
struct sta_info *sta = container_of(txq->sta, struct sta_info,
sta);
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid);
if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
@@ -1323,19 +1623,274 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
}
out:
- spin_unlock_bh(&txqi->queue.lock);
+ spin_unlock_bh(&fq->lock);
return skb;
}
EXPORT_SYMBOL(ieee80211_tx_dequeue);
+static u16 ieee80211_get_txop_usec(struct ieee80211_local *local,
+ struct txq_info *txqi)
+{
+ struct ieee80211_sub_if_data *sdata;
+ u16 txop_usec;
+
+ sdata = container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif);
+ txop_usec = sdata->tx_conf[txqi->txq.ac].txop * 32;
+
+ /* How to pick between mixed/greenfield txops? */
+ if (txop_usec == 0)
+ txop_usec = local->fq.txop_mixed_usec;
+
+ return txop_usec;
+}
+
+static u32 ieee80211_get_tput_kbps(struct ieee80211_local *local,
+ struct txq_info *txqi)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ enum ieee80211_band band;
+ struct rate_control_ref *ref = NULL;
+ struct sta_info *sta;
+ int idx;
+ u32 tput;
+
+ if (txqi->txq.sta) {
+ sta = container_of(txqi->txq.sta, struct sta_info, sta);
+
+ if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
+ ref = local->rate_ctrl;
+
+ if (ref)
+ tput = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
+ else if (local->ops->get_expected_throughput)
+ tput = drv_get_expected_throughput(local, &sta->sta);
+ else
+ tput = 0;
+ } else {
+ sdata = container_of(txqi->txq.vif, struct ieee80211_sub_if_data, vif);
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ band = chanctx_conf->def.chan->band;
+ rcu_read_unlock();
+
+ sband = local->hw.wiphy->bands[band];
+ idx = sdata->vif.bss_conf.mcast_rate[band];
+ if (idx > 0) {
+ /* Convert units from 100Kbps and assume 20% MAC
+ * overhead, i.e. 80% efficiency.
+ */
+ tput = sband[band].bitrates[idx].bitrate * 100;
+ tput = (tput * 8) / 10;
+ } else {
+ tput = 1000;
+ }
+ }
+
+ return tput;
+}
+
+static void ieee80211_recalc_txqi_tput(struct ieee80211_local *local,
+ struct txq_info *txqi)
+{
+ struct ieee80211_fq *fq = &local->fq;
+ int tput_kbps;
+ int txop_usec;
+
+ lockdep_assert_held(&fq->lock);
+
+ tput_kbps = ieee80211_get_tput_kbps(local, txqi);
+ txop_usec = ieee80211_get_txop_usec(local, txqi);
+ txqi->bytes_per_usec = max_t(int, 1, DIV_ROUND_UP(1024 * (tput_kbps/8),
+ USEC_PER_SEC));
+ txqi->bytes_per_burst = max_t(int, 1, txop_usec * txqi->bytes_per_usec);
+}
+
+void ieee80211_recalc_fq_period(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_fq *fq = &local->fq;
+ struct txq_info *txqi;
+ int period = 0;
+ int target_usec;
+
+ spin_lock_bh(&fq->lock);
+
+ list_for_each_entry(txqi, &fq->new_flows, flowchain) {
+ ieee80211_recalc_txqi_tput(local, txqi);
+
+ period += TXQI_BYTES_TO_USEC(txqi, min(txqi->backlog_bytes,
+ txqi->bytes_per_burst));
+ }
+
+ list_for_each_entry(txqi, &fq->old_flows, flowchain) {
+ ieee80211_recalc_txqi_tput(local, txqi);
+
+ period += TXQI_BYTES_TO_USEC(txqi, min(txqi->backlog_bytes,
+ txqi->bytes_per_burst));
+ }
+
+ ewma_fq_period_add(&fq->ave_period, period);
+
+ target_usec = ewma_fq_period_read(&fq->ave_period);
+ target_usec = max_t(u64, target_usec, MIN_FQ_TARGET_USEC(fq));
+ hw->txq_cparams.target = US2TIME(target_usec);
+
+ spin_unlock_bh(&fq->lock);
+}
+EXPORT_SYMBOL(ieee80211_recalc_fq_period);
+
+static int ieee80211_tx_sched_budget(struct ieee80211_local *local,
+ struct txq_info *txqi)
+{
+ int txop_usec;
+ int budget;
+
+ /* XXX: Should this consider per-txq or per-sta in flight duration? */
+ txop_usec = ieee80211_get_txop_usec(local, txqi);
+ budget = local->fq.max_txops_per_txq * txop_usec;
+ budget -= atomic_read(&txqi->in_flight_usec);
+ budget = min(budget, txop_usec);
+ budget *= min_t(int, 1, txqi->bytes_per_usec);
+
+ return budget;
+}
+
+static void ieee80211_tx_sched_next_txqi(struct ieee80211_local *local,
+ struct list_head **list,
+ struct list_head **head)
+{
+ struct ieee80211_fq *fq = &local->fq;
+
+ if (!*list) {
+ *head = &fq->new_flows;
+ *list = *head;
+ }
+
+ *list = (*list)->next;
+
+ if (*list != *head)
+ return;
+
+ if (*head == &fq->new_flows) {
+ *head = &fq->old_flows;
+ *list = *head;
+ ieee80211_tx_sched_next_txqi(local, list, head);
+ return;
+ }
+
+ *head = NULL;
+ *list = NULL;
+}
+
+int ieee80211_tx_schedule(struct ieee80211_hw *hw,
+ int (*wake)(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq,
+ int budget))
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_fq *fq = &local->fq;
+ struct list_head *list = NULL;
+ struct list_head *head = NULL;
+ struct txq_info *txqi = NULL;
+ int min_in_flight_usec;
+ int max_in_flight_usec;
+ int in_flight_usec;
+ int ret = 0;
+ int budget;
+
+ rcu_read_lock();
+ spin_lock_bh(&fq->lock);
+
+ min_in_flight_usec = fq->min_txops_per_hw * fq->txop_mixed_usec;
+ max_in_flight_usec = fq->max_txops_per_hw * fq->txop_mixed_usec;
+ in_flight_usec = atomic_read(&fq->in_flight_usec);
+
+ if (in_flight_usec >= min_in_flight_usec) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ for (;;) {
+ if (in_flight_usec >= max_in_flight_usec) {
+ ret = -EBUSY;
+ break;
+ }
+
+ if (list && list_is_last(list, &fq->old_flows)) {
+ ret = -EBUSY;
+ break;
+ }
+
+ ieee80211_tx_sched_next_txqi(local, &list, &head);
+ if (!list) {
+ ret = -ENOENT;
+ break;
+ }
+
+ txqi = list_entry(list, struct txq_info, flowchain);
+
+ if (txqi->deficit < 0) {
+ txqi->deficit += fq->quantum;
+ list_move_tail(&txqi->flowchain, &fq->old_flows);
+ list = NULL;
+ continue;
+ }
+
+ budget = ieee80211_tx_sched_budget(local, txqi);
+ txqi->in_flight_delta_usec = 0;
+
+ spin_unlock_bh(&fq->lock);
+ ret = wake(hw, &txqi->txq, budget);
+ spin_lock_bh(&fq->lock);
+
+ if (ret > 0) {
+ txqi->deficit -= txqi->in_flight_delta_usec;
+ in_flight_usec += txqi->in_flight_delta_usec;
+ }
+
+ if (!txqi->backlog_bytes) {
+ if (head == &fq->new_flows && !list_empty(&fq->old_flows)) {
+ list_move_tail(&txqi->flowchain, &fq->old_flows);
+ } else {
+ list_del_init(&txqi->flowchain);
+ }
+
+ list = NULL;
+ }
+
+ if (ret < 0) {
+ ret = -EBUSY;
+ break;
+ } else if (ret == 0 && txqi) {
+ /* `list` is not reset to skip over */
+ continue;
+ }
+
+ list = NULL;
+ }
+
+unlock:
+ spin_unlock_bh(&fq->lock);
+ rcu_read_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL(ieee80211_tx_schedule);
+
static bool ieee80211_tx_frags(struct ieee80211_local *local,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct sk_buff_head *skbs,
bool txpending)
{
+ struct ieee80211_fq *fq = &local->fq;
+ struct ieee80211_tx_control control = {};
struct sk_buff *skb, *tmp;
+ struct txq_info *txqi;
unsigned long flags;
skb_queue_walk_safe(skbs, skb, tmp) {
@@ -1350,6 +1905,24 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
}
#endif
+ /* XXX: This changes behavior for offchan-tx. Is this really a
+ * problem with per-sta-tid queueing now?
+ */
+ txqi = ieee80211_get_txq(local, vif, sta, skb);
+ if (txqi) {
+ info->control.vif = vif;
+
+ __skb_unlink(skb, skbs);
+
+ spin_lock_bh(&fq->lock);
+ ieee80211_txq_enqueue(local, txqi, skb);
+ spin_unlock_bh(&fq->lock);
+
+ drv_wake_tx_queue(local, txqi);
+
+ continue;
+ }
+
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
if (local->queue_stop_reasons[q] ||
(!txpending && !skb_queue_empty(&local->pending[q]))) {
@@ -1392,9 +1965,10 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
info->control.vif = vif;
+ control.sta = sta;
__skb_unlink(skb, skbs);
- ieee80211_drv_tx(local, vif, sta, skb);
+ drv_tx(local, &control, skb);
}
return true;
@@ -2381,7 +2955,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
spin_lock_irqsave(&local->ack_status_lock, flags);
id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
+ 1, 0x8000, GFP_ATOMIC);
spin_unlock_irqrestore(&local->ack_status_lock, flags);
if (id >= 0) {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0319d6d4f863..afb1bbf9b3f4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -244,6 +244,9 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
struct ieee80211_sub_if_data *sdata;
int n_acs = IEEE80211_NUM_ACS;
+ if (local->ops->wake_tx_queue)
+ return;
+
if (local->hw.queues < IEEE80211_NUM_ACS)
n_acs = 1;
@@ -260,11 +263,6 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
for (ac = 0; ac < n_acs; ac++) {
int ac_queue = sdata->vif.hw_queue[ac];
- if (local->ops->wake_tx_queue &&
- (atomic_read(&sdata->txqs_len[ac]) >
- local->hw.txq_ac_max_pending))
- continue;
-
if (ac_queue == queue ||
(sdata->vif.cab_queue == queue &&
local->queue_stop_reasons[ac_queue] == 0 &&
@@ -352,6 +350,9 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
return;
+ if (local->ops->wake_tx_queue)
+ return;
+
if (local->hw.queues < IEEE80211_NUM_ACS)
n_acs = 1;
@@ -3392,8 +3393,12 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct txq_info *txqi, int tid)
{
- skb_queue_head_init(&txqi->queue);
+ INIT_LIST_HEAD(&txqi->flowchain);
+ INIT_LIST_HEAD(&txqi->old_flows);
+ INIT_LIST_HEAD(&txqi->new_flows);
+ ieee80211_init_flow(&txqi->flow);
txqi->txq.vif = &sdata->vif;
+ txqi->flow.txqi = txqi;
if (sta) {
txqi->txq.sta = &sta->sta;
@@ -3414,9 +3419,9 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
struct txq_info *txqi = to_txq_info(txq);
if (frame_cnt)
- *frame_cnt = txqi->queue.qlen;
+ *frame_cnt = txqi->backlog_packets;
if (byte_cnt)
- *byte_cnt = txqi->byte_cnt;
+ *byte_cnt = txqi->backlog_bytes;
}
EXPORT_SYMBOL(ieee80211_txq_get_depth);
--
2.1.4
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel
^ permalink raw reply related
* [PATCH (net-next.git)] stmmac: fix TX normal DESC
From: Giuseppe Cavallaro @ 2016-03-16 10:21 UTC (permalink / raw)
To: netdev
Cc: gabriel.fernandez, afaerber, fschaefer.oss, dinh.linux, davem,
preid, tomeu, fabrice.gasnier, alexandre.torgue,
Giuseppe Cavallaro
In-Reply-To: <1458123709-19692-1-git-send-email-peppe.cavallaro@st.com>
This patch fixs a regression raised when test on chips that use
the normal descriptor layout. In fact, no len bits were set for
the TDES1 and no OWN bit inside the TDES0.
Signed-off-by: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
Tested-by: Andreas Färber <afaerber@suse.de>
Cc: Fabrice Gasnier <fabrice.gasnier@st.com>
---
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index e13228f..011386f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -199,11 +199,6 @@ static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
{
unsigned int tdes1 = p->des1;
- if (mode == STMMAC_CHAIN_MODE)
- norm_set_tx_desc_len_on_chain(p, len);
- else
- norm_set_tx_desc_len_on_ring(p, len);
-
if (is_fs)
tdes1 |= TDES1_FIRST_SEGMENT;
else
@@ -217,10 +212,15 @@ static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
if (ls)
tdes1 |= TDES1_LAST_SEGMENT;
- if (tx_own)
- tdes1 |= TDES0_OWN;
-
p->des1 = tdes1;
+
+ if (mode == STMMAC_CHAIN_MODE)
+ norm_set_tx_desc_len_on_chain(p, len);
+ else
+ norm_set_tx_desc_len_on_ring(p, len);
+
+ if (tx_own)
+ p->des0 |= TDES0_OWN;
}
static void ndesc_set_tx_ic(struct dma_desc *p)
--
1.7.4.4
^ permalink raw reply related
* [PATCH (net-next.git)] STMMAC: fix TX Normal descriptor
From: Giuseppe Cavallaro @ 2016-03-16 10:21 UTC (permalink / raw)
To: netdev
Cc: gabriel.fernandez, afaerber, fschaefer.oss, dinh.linux, davem,
preid, tomeu, fabrice.gasnier, alexandre.torgue,
Giuseppe Cavallaro
On top of the Oct_2015 driver version committed into net-next, this patch
fixes a problem for the HW where the normal descriptor are used at runtime
instead of the Enhanced/Alternate descriptors.
In the beginning, it was suggested to revert the patch:
"stmmac: first frame prep at the end of xmit routine"
and it has been noticed that w/o it the normal TDES 0 and 1 were good filled.
Then has been proposed this new fix (w/o reverting the patch above).
Giuseppe Cavallaro (1):
stmmac: fix TX normal DESC
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
--
1.7.4.4
^ permalink raw reply
* [RFCv2 0/3] mac80211: implement fq codel
From: Michal Kazior @ 2016-03-16 10:17 UTC (permalink / raw)
To: linux-wireless
Cc: ath10k, johannes, netdev, dave.taht, emmanuel.grumbach, nbd,
Tim Shepard, make-wifi-fast, codel, Michal Kazior
Hi,
Most notable changes:
* fixes (duh); fairness should work better now,
* EWMA codel target based on estimated service
time,
* new tx scheduling helper with in-flight
duration limiting (same idea Emmanuel
had for iwlwifi),
* added a few debugfs hooks.
* ath10k proof-of-concept that uses the new tx
scheduling (will post results in separate
email)
The patch grew pretty big and I plan on splitting
it before next submission. Any suggestions?
The tx scheduling probably needs more work and
testing. I didn't evaluate how CPU intensive it is
nor how it influences things like peak throughput
(lab conditions et al) yet.
I've uploaded a branch for convenience:
https://github.com/kazikcz/linux/tree/fqmac-rfc-v2
This is based on Kalle's ath tree.
Michal Kazior (3):
mac80211: implement fq_codel for software queuing
ath10k: report per-station tx/rate rates to mac80211
ath10k: use ieee80211_tx_schedule()
drivers/net/wireless/ath/ath10k/core.c | 2 -
drivers/net/wireless/ath/ath10k/core.h | 8 +-
drivers/net/wireless/ath/ath10k/debug.c | 61 ++-
drivers/net/wireless/ath/ath10k/mac.c | 126 +++---
drivers/net/wireless/ath/ath10k/wmi.h | 2 +-
include/net/mac80211.h | 96 ++++-
net/mac80211/agg-tx.c | 8 +-
net/mac80211/cfg.c | 2 +-
net/mac80211/codel.h | 264 +++++++++++++
net/mac80211/codel_i.h | 89 +++++
net/mac80211/debugfs.c | 267 +++++++++++++
net/mac80211/ieee80211_i.h | 45 ++-
net/mac80211/iface.c | 25 +-
net/mac80211/main.c | 9 +-
net/mac80211/rx.c | 2 +-
net/mac80211/sta_info.c | 10 +-
net/mac80211/sta_info.h | 27 ++
net/mac80211/status.c | 64 ++++
net/mac80211/tx.c | 658 ++++++++++++++++++++++++++++++--
net/mac80211/util.c | 21 +-
20 files changed, 1629 insertions(+), 157 deletions(-)
create mode 100644 net/mac80211/codel.h
create mode 100644 net/mac80211/codel_i.h
--
2.1.4
^ permalink raw reply
* Re: [net-next 1/2] bonding: remove duplicate set of flag IFF_MULTICAST
From: Nikolay Aleksandrov @ 2016-03-16 10:06 UTC (permalink / raw)
To: Zhang Shengju, davem, j.vosburgh, jiri; +Cc: netdev, gospo, Veaceslav Falico
In-Reply-To: <1458122356-25021-2-git-send-email-zhangshengju@cmss.chinamobile.com>
On 03/16/2016 10:59 AM, Zhang Shengju wrote:
> Remove unnecessary set of flag IFF_MULTICAST, since ether_setup
> already does this.
>
> Signed-off-by: Zhang Shengju <zhangshengju@cmss.chinamobile.com>
> ---
> drivers/net/bonding/bond_main.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
There're a few more bonding maintainers, I've added them to the CC list.
Reviewed-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
^ permalink raw reply
* Re: [net-next 2/2] team: remove duplicate set of flag IFF_MULTICAST
From: Jiri Pirko @ 2016-03-16 10:00 UTC (permalink / raw)
To: Zhang Shengju; +Cc: davem, j.vosburgh, netdev
In-Reply-To: <1458122356-25021-3-git-send-email-zhangshengju@cmss.chinamobile.com>
Wed, Mar 16, 2016 at 10:59:16AM CET, zhangshengju@cmss.chinamobile.com wrote:
>Remove unnecessary set of flag IFF_MULTICAST, since ether_setup
>already does this.
>
>Signed-off-by: Zhang Shengju <zhangshengju@cmss.chinamobile.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply
* [net-next 2/2] team: remove duplicate set of flag IFF_MULTICAST
From: Zhang Shengju @ 2016-03-16 9:59 UTC (permalink / raw)
To: davem, j.vosburgh, jiri; +Cc: netdev
In-Reply-To: <1458122356-25021-1-git-send-email-zhangshengju@cmss.chinamobile.com>
Remove unnecessary set of flag IFF_MULTICAST, since ether_setup
already does this.
Signed-off-by: Zhang Shengju <zhangshengju@cmss.chinamobile.com>
---
drivers/net/team/team.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 2769835..26c64d2 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2082,7 +2082,6 @@ static void team_setup(struct net_device *dev)
dev->netdev_ops = &team_netdev_ops;
dev->ethtool_ops = &team_ethtool_ops;
dev->destructor = team_destructor;
- dev->flags |= IFF_MULTICAST;
dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
dev->priv_flags |= IFF_NO_QUEUE;
dev->priv_flags |= IFF_TEAM;
--
1.8.3.1
^ permalink raw reply related
* [net-next 0/2] remove duplicate set of flag IFF_MULTICAST
From: Zhang Shengju @ 2016-03-16 9:59 UTC (permalink / raw)
To: davem, j.vosburgh, jiri; +Cc: netdev
This patch series remove duplicate set of flag IFF_MULTICAST.
Zhang Shengju (2):
bonding: remove duplicate set of flag IFF_MULTICAST
team: remove duplicate set of flag IFF_MULTICAST
drivers/net/bonding/bond_main.c | 2 +-
drivers/net/team/team.c | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
--
1.8.3.1
^ permalink raw reply
* [net-next 1/2] bonding: remove duplicate set of flag IFF_MULTICAST
From: Zhang Shengju @ 2016-03-16 9:59 UTC (permalink / raw)
To: davem, j.vosburgh, jiri; +Cc: netdev
In-Reply-To: <1458122356-25021-1-git-send-email-zhangshengju@cmss.chinamobile.com>
Remove unnecessary set of flag IFF_MULTICAST, since ether_setup
already does this.
Signed-off-by: Zhang Shengju <zhangshengju@cmss.chinamobile.com>
---
drivers/net/bonding/bond_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b6236ff..270b39c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4175,7 +4175,7 @@ void bond_setup(struct net_device *bond_dev)
SET_NETDEV_DEVTYPE(bond_dev, &bond_type);
/* Initialize the device options */
- bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
+ bond_dev->flags |= IFF_MASTER;
bond_dev->priv_flags |= IFF_BONDING | IFF_UNICAST_FLT | IFF_NO_QUEUE;
bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
--
1.8.3.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox