* Re: linux-next: Tree for Nov 29 (netlabel)
From: Paul Moore @ 2012-11-30 15:31 UTC (permalink / raw)
To: Randy Dunlap
Cc: Stephen Rothwell, linux-next, linux-kernel,
netdev@vger.kernel.org
In-Reply-To: <3694027.VYznNcdp7C@sifl>
On Friday, November 30, 2012 10:19:16 AM Paul Moore wrote:
> On Thursday, November 29, 2012 04:05:26 PM Randy Dunlap wrote:
> > On 11/28/2012 10:40 PM, Stephen Rothwell wrote:
> > > Hi all,
> >
> > > Changes since 20121128:
> > (on i386:)
>
> If I had to guess it looks like CONFIG_NETLABEL needs to be dependent on
> CONFIG_INET. While the net/ Kconfig only pulls in the net/netlabel Kconfig
> if CONFIG_INET is defined, I'm guessing that without the explicit
> dependency there is nothing preventing someone from arriving at a bad
> configuration as we see here.
>
> Let me test this out to make sure my reasoning is right and if it is I'll
> post a patch to netdev later today.
>
> Thanks for catching this.
Hmmm. The existing logic in net/Kconfig seems to disable CONFIG_NETLABEL at
build time whenever CONFIG_INET is disabled in my .config file. The only way
I can recreate what you are seeing here is if I move the NetLabel include
outside of the INET conditional in net/Kconfig.
Regardless, adding an explicit dependency on INET to NETLABEL shouldn't hurt
anything so I'll go ahead and post the patch to netdev. Hopefully someone who
understands Kconfig better than I do can help shed some light on this.
> > net/built-in.o: In function `netlbl_cfg_cipsov4_add':
> > (.text+0x61757): undefined reference to `cipso_v4_doi_add'
> > net/built-in.o: In function `netlbl_cfg_cipsov4_del':
> > (.text+0x6177d): undefined reference to `cipso_v4_doi_remove'
> > net/built-in.o: In function `netlbl_cfg_cipsov4_map_add':
> > (.text+0x617ae): undefined reference to `cipso_v4_doi_getdef'
> > net/built-in.o: In function `netlbl_cfg_cipsov4_map_add':
> > (.text+0x61a49): undefined reference to `cipso_v4_doi_putdef'
> > net/built-in.o: In function `netlbl_sock_setattr':
> > (.text+0x6218c): undefined reference to `cipso_v4_sock_setattr'
> > net/built-in.o: In function `netlbl_sock_delattr':
> > (.text+0x6220b): undefined reference to `cipso_v4_sock_delattr'
> > net/built-in.o: In function `netlbl_sock_getattr':
> > (.text+0x62238): undefined reference to `cipso_v4_sock_getattr'
> > net/built-in.o: In function `netlbl_conn_setattr':
> > (.text+0x622de): undefined reference to `cipso_v4_sock_setattr'
> > net/built-in.o: In function `netlbl_conn_setattr':
> > (.text+0x62303): undefined reference to `cipso_v4_sock_delattr'
> > net/built-in.o: In function `netlbl_req_setattr':
> > (.text+0x62429): undefined reference to `cipso_v4_req_setattr'
> > net/built-in.o: In function `netlbl_req_setattr':
> > (.text+0x6244e): undefined reference to `cipso_v4_req_delattr'
> > net/built-in.o: In function `netlbl_req_delattr':
> > (.text+0x624ba): undefined reference to `cipso_v4_req_delattr'
> > net/built-in.o: In function `netlbl_skbuff_setattr':
> > (.text+0x62551): undefined reference to `cipso_v4_skbuff_setattr'
> > net/built-in.o: In function `netlbl_skbuff_setattr':
> > (.text+0x62576): undefined reference to `cipso_v4_skbuff_delattr'
> > net/built-in.o: In function `netlbl_skbuff_getattr':
> > (.text+0x62619): undefined reference to `cipso_v4_skbuff_getattr'
> > net/built-in.o: In function `netlbl_skbuff_err':
> > (.text+0x62685): undefined reference to `cipso_v4_error'
> > net/built-in.o: In function `netlbl_cache_invalidate':
> > (.text+0x626ab): undefined reference to `cipso_v4_cache_invalidate'
> > net/built-in.o: In function `netlbl_cache_add':
> > (.text+0x626ec): undefined reference to `cipso_v4_cache_add'
> > net/built-in.o: In function `netlbl_domhsh_remove_entry':
> > (.text+0x63294): undefined reference to `cipso_v4_doi_putdef'
> > net/built-in.o: In function `netlbl_domhsh_remove_entry':
> > (.text+0x632eb): undefined reference to `cipso_v4_doi_putdef'
> > net/built-in.o: In function `netlbl_domhsh_remove_af4':
> > (.text+0x6349b): undefined reference to `cipso_v4_doi_putdef'
> > net/built-in.o: In function `netlbl_mgmt_add_common.clone.1':
> > netlabel_mgmt.c:(.text+0x64a87): undefined reference to
> > `cipso_v4_doi_getdef' netlabel_mgmt.c:(.text+0x64c83): undefined reference
> > to `cipso_v4_doi_putdef' net/built-in.o: In function
> > `netlbl_cipsov4_listall':
> > netlabel_cipso_v4.c:(.text+0x66e52): undefined reference to
> > `cipso_v4_doi_walk' net/built-in.o: In function `netlbl_cipsov4_list':
> > netlabel_cipso_v4.c:(.text+0x67199): undefined reference to
> > `cipso_v4_doi_getdef' net/built-in.o: In function `netlbl_cipsov4_remove':
> > netlabel_cipso_v4.c:(.text+0x6771b): undefined reference to
> > `cipso_v4_doi_remove' net/built-in.o: In function
> > `netlbl_cipsov4_add_pass':
> > netlabel_cipso_v4.c:(.text+0x67a4b): undefined reference to
> > `cipso_v4_doi_add' netlabel_cipso_v4.c:(.text+0x67a76): undefined
> > reference
> > to `cipso_v4_doi_free' net/built-in.o: In function
> > `netlbl_cipsov4_add_local':
> > netlabel_cipso_v4.c:(.text+0x67b9a): undefined reference to
> > `cipso_v4_doi_add' netlabel_cipso_v4.c:(.text+0x67bc5): undefined
> > reference
> > to `cipso_v4_doi_free' net/built-in.o: In function
> > `netlbl_cipsov4_add_std':
> > netlabel_cipso_v4.c:(.text+0x68535): undefined reference to
> > `cipso_v4_doi_add' netlabel_cipso_v4.c:(.text+0x68575): undefined
> > reference
> > to `cipso_v4_doi_free'
> >
> >
> > Full randconfig file is attached.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* Re: [PATCH net-next v1 2/2] bridge: export multicast database via netlink
From: Thomas Graf @ 2012-11-30 15:27 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, bridge, Herbert Xu, Stephen Hemminger, David S. Miller,
Jesper Dangaard Brouer
In-Reply-To: <1354287652.19865.10.camel@cr0>
On 11/30/12 at 11:00pm, Cong Wang wrote:
> I don't understand this. nla_put_flag() is used to put a flag (only one
> bit set) into a netlink message, so why should we use it to put
> p->port_no here? And why port_no 0 matters here?
nla_put_flag() will simply add a netlink attribute with no payload,
i.e. just the header. Assuming that port_no == 0 is invalid the
port_no can be used as attribute id as both are 16bit integers.
It will look like this:
MDBA_ROUTERS = {
{
.nla_len = 4,
.nla_type = <port_no_1>,
},
{
.nla_len = 4,
.nla_type = <port_no_2>,
}
[...]
}
If you ever need to extend this you can just add payload to the
per port attribute and nothing will break.
> So I should use net->dev_base_seq + mdb->seq ?
No you can't, mdb->seq is not stable throughout a dump. What you
can do is save mdb->seq in cb->args[] and in case you continue
dumping from the same mdb in the next call to your dump function
you check if it changed and bump cb->seq if it did to trigger an
interrupt.
^ permalink raw reply
* Re: [PATCH] smsc: RFC: Workaround for problems with lan8710 phy auto MDI-X
From: Jiri Kosina @ 2012-11-30 15:23 UTC (permalink / raw)
To: Peter Turczak
Cc: David Miller, Otavio Salvador, Javier Martinez Canillas,
Christian Hohnstaedt, netdev, linux-kernel
In-Reply-To: <8D7E9026-6276-452B-9E0C-AEB8CF38C9FD@netconsequence.de>
On Fri, 30 Nov 2012, Peter Turczak wrote:
> while debugging network outages on a customers hardware I found, that
> the MDI-X function of the lan8710 phy seemed to cause trouble. When
> connecting to almost any kind of 100/1000MBit switch, the link would
> seem to come up and data where sent out to the network. But all incoming
> packets got lost somehow. This is quite bad, as the system runs from
> nfsroot while booting up during development.
>
> When I disabled the auto MDI-X function of the phy the problem went away.
>
> Signed-off-by: Peter Turczak <pt@netconsequence.de>
> ---
> drivers/net/phy/Kconfig | 10 ++++++++++
> drivers/net/phy/smsc.c | 15 +++++++++++++++
> include/linux/smscphy.h | 5 +++++
> 3 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 961f0b2..341f5aa 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -60,6 +60,16 @@ config SMSC_PHY
> ---help---
> Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
>
> +config SMSC_PHY_DISABLE_AUTOX
> + bool "Disable MDI-X upon start"
> + depends on SMSC_PHY
> + ---help---
> + When you experience problems estabishing a stable connection
> + to a network and you have e.g. a LAN8710 ethernet phy
> + this option might help you out.
> +
> + In doubt, say N
> +
I am not sure whether compile-time option for something like this is
appropriate. Kernel module parameter, perhaps?
Of course it'd be far better if faulty hardware can be autodetected in
runtime.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] sctp: fix CONFIG_SCTP_DBG_MSG=y null pointer dereference in sctp_v6_get_dst()
From: Neil Horman @ 2012-11-30 15:20 UTC (permalink / raw)
To: Tommi Rantala
Cc: linux-sctp, netdev, Vlad Yasevich, Sridhar Samudrala,
David S. Miller, Dave Jones
In-Reply-To: <1354267062-15888-1-git-send-email-tt.rantala@gmail.com>
On Fri, Nov 30, 2012 at 11:17:42AM +0200, Tommi Rantala wrote:
> Trinity (the syscall fuzzer) triggered the following BUG, reproducible
> only when the kernel is configured with CONFIG_SCTP_DBG_MSG=y.
>
> When CONFIG_SCTP_DBG_MSG is not set, the null pointer is never
> dereferenced.
>
> ---[ end trace a4de0bfcb38a3642 ]---
> BUG: unable to handle kernel NULL pointer dereference at 0000000000000100
> IP: [<ffffffff8136796e>] ip6_string+0x1e/0xa0
> PGD 4eead067 PUD 4e472067 PMD 0
> Oops: 0000 [#1] PREEMPT SMP
> Modules linked in:
> CPU 3
> Pid: 21324, comm: trinity-child11 Tainted: G W 3.7.0-rc7+ #61 ASUSTeK Computer INC. EB1012/EB1012
> RIP: 0010:[<ffffffff8136796e>] [<ffffffff8136796e>] ip6_string+0x1e/0xa0
> RSP: 0018:ffff88004e4637a0 EFLAGS: 00010046
> RAX: ffff88004e4637da RBX: ffff88004e4637da RCX: 0000000000000000
> RDX: ffffffff8246e92a RSI: 0000000000000100 RDI: ffff88004e4637da
> RBP: ffff88004e4637a8 R08: 000000000000ffff R09: 000000000000ffff
> R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff8289d600
> R13: ffffffff8289d230 R14: ffffffff8246e928 R15: ffffffff8289d600
> FS: 00007fed95153700(0000) GS:ffff88005fd80000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000000000000100 CR3: 000000004eeac000 CR4: 00000000000007e0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> Process trinity-child11 (pid: 21324, threadinfo ffff88004e462000, task ffff8800524b0000)
> Stack:
> ffff88004e4637da ffff88004e463828 ffffffff81368eee 000000004e4637d8
> ffffffff0000ffff ffff88000000ffff 0000000000000000 000000004e4637f8
> ffffffff826285d8 ffff88004e4637f8 0000000000000000 ffff8800524b06b0
> Call Trace:
> [<ffffffff81368eee>] ip6_addr_string.isra.11+0x3e/0xa0
> [<ffffffff81369183>] pointer.isra.12+0x233/0x2d0
> [<ffffffff810a413a>] ? vprintk_emit+0x1ba/0x450
> [<ffffffff8110953d>] ? trace_hardirqs_on_caller+0x10d/0x1a0
> [<ffffffff81369757>] vsnprintf+0x187/0x5d0
> [<ffffffff81369c62>] vscnprintf+0x12/0x30
> [<ffffffff810a4028>] vprintk_emit+0xa8/0x450
> [<ffffffff81e5cb00>] printk+0x49/0x4b
> [<ffffffff81d17221>] sctp_v6_get_dst+0x731/0x780
> [<ffffffff81d16e15>] ? sctp_v6_get_dst+0x325/0x780
> [<ffffffff81d00a96>] sctp_transport_route+0x46/0x120
> [<ffffffff81cff0f1>] sctp_assoc_add_peer+0x161/0x350
> [<ffffffff81d0fd8d>] sctp_sendmsg+0x6cd/0xcb0
> [<ffffffff81b55bf0>] ? inet_create+0x670/0x670
> [<ffffffff81b55cfb>] inet_sendmsg+0x10b/0x220
> [<ffffffff81b55bf0>] ? inet_create+0x670/0x670
> [<ffffffff81a72a64>] ? sock_update_classid+0xa4/0x2b0
> [<ffffffff81a72ab0>] ? sock_update_classid+0xf0/0x2b0
> [<ffffffff81a6ac1c>] sock_sendmsg+0xdc/0xf0
> [<ffffffff8118e9e5>] ? might_fault+0x85/0x90
> [<ffffffff8118e99c>] ? might_fault+0x3c/0x90
> [<ffffffff81a6e12a>] sys_sendto+0xfa/0x130
> [<ffffffff810a9887>] ? do_setitimer+0x197/0x380
> [<ffffffff81e960d5>] ? sysret_check+0x22/0x5d
> [<ffffffff81e960a9>] system_call_fastpath+0x16/0x1b
> Code: 01 eb 89 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 f8 31 c9 48 89 e5 53 eb 12 0f 1f 40 00 48 83 c1 01 48 83 c0 04 48 83 f9 08 74 70 <0f> b6 3c 4e 89 fb 83 e7 0f c0 eb 04 41 89 d8 41 83 e0 0f 0f b6
> RIP [<ffffffff8136796e>] ip6_string+0x1e/0xa0
> RSP <ffff88004e4637a0>
> CR2: 0000000000000100
> ---[ end trace a4de0bfcb38a3643 ]---
>
> Signed-off-by: Tommi Rantala <tt.rantala@gmail.com>
> ---
> net/sctp/ipv6.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
> index ea14cb4..f3f0f4d 100644
> --- a/net/sctp/ipv6.c
> +++ b/net/sctp/ipv6.c
> @@ -345,7 +345,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
> }
>
> out:
> - if (!IS_ERR(dst)) {
> + if (!IS_ERR_OR_NULL(dst)) {
> struct rt6_info *rt;
> rt = (struct rt6_info *)dst;
> t->dst = dst;
> --
> 1.7.9.5
>
>
Acked-by; Neil Horman <nhorman@tuxdriver.com>
^ permalink raw reply
* Re: linux-next: Tree for Nov 29 (netlabel)
From: Paul Moore @ 2012-11-30 15:19 UTC (permalink / raw)
To: Randy Dunlap
Cc: Stephen Rothwell, linux-next, linux-kernel,
netdev@vger.kernel.org
In-Reply-To: <50B7F846.70202@infradead.org>
On Thursday, November 29, 2012 04:05:26 PM Randy Dunlap wrote:
> On 11/28/2012 10:40 PM, Stephen Rothwell wrote:
> > Hi all,
>
> > Changes since 20121128:
> (on i386:)
If I had to guess it looks like CONFIG_NETLABEL needs to be dependent on
CONFIG_INET. While the net/ Kconfig only pulls in the net/netlabel Kconfig if
CONFIG_INET is defined, I'm guessing that without the explicit dependency
there is nothing preventing someone from arriving at a bad configuration as we
see here.
Let me test this out to make sure my reasoning is right and if it is I'll post
a patch to netdev later today.
Thanks for catching this.
> net/built-in.o: In function `netlbl_cfg_cipsov4_add':
> (.text+0x61757): undefined reference to `cipso_v4_doi_add'
> net/built-in.o: In function `netlbl_cfg_cipsov4_del':
> (.text+0x6177d): undefined reference to `cipso_v4_doi_remove'
> net/built-in.o: In function `netlbl_cfg_cipsov4_map_add':
> (.text+0x617ae): undefined reference to `cipso_v4_doi_getdef'
> net/built-in.o: In function `netlbl_cfg_cipsov4_map_add':
> (.text+0x61a49): undefined reference to `cipso_v4_doi_putdef'
> net/built-in.o: In function `netlbl_sock_setattr':
> (.text+0x6218c): undefined reference to `cipso_v4_sock_setattr'
> net/built-in.o: In function `netlbl_sock_delattr':
> (.text+0x6220b): undefined reference to `cipso_v4_sock_delattr'
> net/built-in.o: In function `netlbl_sock_getattr':
> (.text+0x62238): undefined reference to `cipso_v4_sock_getattr'
> net/built-in.o: In function `netlbl_conn_setattr':
> (.text+0x622de): undefined reference to `cipso_v4_sock_setattr'
> net/built-in.o: In function `netlbl_conn_setattr':
> (.text+0x62303): undefined reference to `cipso_v4_sock_delattr'
> net/built-in.o: In function `netlbl_req_setattr':
> (.text+0x62429): undefined reference to `cipso_v4_req_setattr'
> net/built-in.o: In function `netlbl_req_setattr':
> (.text+0x6244e): undefined reference to `cipso_v4_req_delattr'
> net/built-in.o: In function `netlbl_req_delattr':
> (.text+0x624ba): undefined reference to `cipso_v4_req_delattr'
> net/built-in.o: In function `netlbl_skbuff_setattr':
> (.text+0x62551): undefined reference to `cipso_v4_skbuff_setattr'
> net/built-in.o: In function `netlbl_skbuff_setattr':
> (.text+0x62576): undefined reference to `cipso_v4_skbuff_delattr'
> net/built-in.o: In function `netlbl_skbuff_getattr':
> (.text+0x62619): undefined reference to `cipso_v4_skbuff_getattr'
> net/built-in.o: In function `netlbl_skbuff_err':
> (.text+0x62685): undefined reference to `cipso_v4_error'
> net/built-in.o: In function `netlbl_cache_invalidate':
> (.text+0x626ab): undefined reference to `cipso_v4_cache_invalidate'
> net/built-in.o: In function `netlbl_cache_add':
> (.text+0x626ec): undefined reference to `cipso_v4_cache_add'
> net/built-in.o: In function `netlbl_domhsh_remove_entry':
> (.text+0x63294): undefined reference to `cipso_v4_doi_putdef'
> net/built-in.o: In function `netlbl_domhsh_remove_entry':
> (.text+0x632eb): undefined reference to `cipso_v4_doi_putdef'
> net/built-in.o: In function `netlbl_domhsh_remove_af4':
> (.text+0x6349b): undefined reference to `cipso_v4_doi_putdef'
> net/built-in.o: In function `netlbl_mgmt_add_common.clone.1':
> netlabel_mgmt.c:(.text+0x64a87): undefined reference to
> `cipso_v4_doi_getdef' netlabel_mgmt.c:(.text+0x64c83): undefined reference
> to `cipso_v4_doi_putdef' net/built-in.o: In function
> `netlbl_cipsov4_listall':
> netlabel_cipso_v4.c:(.text+0x66e52): undefined reference to
> `cipso_v4_doi_walk' net/built-in.o: In function `netlbl_cipsov4_list':
> netlabel_cipso_v4.c:(.text+0x67199): undefined reference to
> `cipso_v4_doi_getdef' net/built-in.o: In function `netlbl_cipsov4_remove':
> netlabel_cipso_v4.c:(.text+0x6771b): undefined reference to
> `cipso_v4_doi_remove' net/built-in.o: In function
> `netlbl_cipsov4_add_pass':
> netlabel_cipso_v4.c:(.text+0x67a4b): undefined reference to
> `cipso_v4_doi_add' netlabel_cipso_v4.c:(.text+0x67a76): undefined reference
> to `cipso_v4_doi_free' net/built-in.o: In function
> `netlbl_cipsov4_add_local':
> netlabel_cipso_v4.c:(.text+0x67b9a): undefined reference to
> `cipso_v4_doi_add' netlabel_cipso_v4.c:(.text+0x67bc5): undefined reference
> to `cipso_v4_doi_free' net/built-in.o: In function
> `netlbl_cipsov4_add_std':
> netlabel_cipso_v4.c:(.text+0x68535): undefined reference to
> `cipso_v4_doi_add' netlabel_cipso_v4.c:(.text+0x68575): undefined reference
> to `cipso_v4_doi_free'
>
>
> Full randconfig file is attached.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* Re: [PATCH net-next v1 2/2] bridge: export multicast database via netlink
From: Cong Wang @ 2012-11-30 15:00 UTC (permalink / raw)
To: Thomas Graf
Cc: netdev, bridge, Herbert Xu, Stephen Hemminger, David S. Miller,
Jesper Dangaard Brouer
In-Reply-To: <20121130112618.GF30697@casper.infradead.org>
On Fri, 2012-11-30 at 11:26 +0000, Thomas Graf wrote:
> On 11/30/12 at 05:58pm, Cong Wang wrote:
> > +
> > + nest = nla_nest_start(skb, MDBA_ROUTER);
> > + if (nest == NULL)
> > + return -EMSGSIZE;
> > +
> > + hlist_for_each_entry_rcu(p, n, &br->router_list, rlist) {
> > + if (p && nla_put_u16(skb, MDBA_BRPORT_NO, p->port_no))
> > + goto fail;
> > + }
>
> port_no 0 is reserved, right?
>
> We can reduce message size here and make it easier to extend by
> using p->port_no as the attribute id by doing something like this:
>
> hlist_for_each_entry_rcu(p, n, &br->router_list, rlist)
> if (nla_put_flag(skb, p->port_no))
> goto fail;
>
> This will result in an empty attribute body for now and if you ever
> need to include more data you can simply start putting attributes
> insde that empty body and old users will continue to function.
I don't understand this. nla_put_flag() is used to put a flag (only one
bit set) into a netlink message, so why should we use it to put
p->port_no here? And why port_no 0 matters here?
[...]
> > +
> > + cb->seq = mdb->seq;
>
> I'm not sure how this is supposed to worl. cb->seq may not change
> throughout the complete dump process or the dump will be interrupted
> and the user is required to restart.
>
> Each bridge will have its own mdb resulting in a differing seq.
>
So I should use net->dev_base_seq + mdb->seq ?
All of the rest suggestions are taken by me.
Thanks for your detailed review!
^ permalink raw reply
* Re: [net-next PATCH V2 1/9] net: frag evictor, avoid killing warm frag queues
From: Eric Dumazet @ 2012-11-30 14:57 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: David Miller, fw, netdev, pablo, tgraf, amwang, kaber, paulmck,
herbert, David Laight
In-Reply-To: <1354276891.11754.424.camel@localhost>
On Fri, 2012-11-30 at 13:01 +0100, Jesper Dangaard Brouer wrote:
> As the existing entries in the frag queues, are still being allowed
> packets through (even when the memory limit is exceeded). In
> worst-case, as DaveM explained, this can be as much as 100KBytes per
> entry (for 64K fragments).
Some NIC uses a plain page to hold an ethernet frame.
Consider an UDP packet using 512 bytes frags, the resulting packet after
reassembly can use 128 pages. Thats 512 KB of memory on x86.
^ permalink raw reply
* [PATCH 2/2] smsc75xx: expand check_ macros
From: Steve Glendinning @ 2012-11-30 14:52 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1354287164-9884-1-git-send-email-steve.glendinning@shawell.net>
These macros, while reducing the amount of code, hide flow control
and make the code more confusing to follow and review. This patch
expands them. It should have no functional effect on the driver.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc75xx.c | 735 ++++++++++++++++++++++++++++++++++----------
1 file changed, 576 insertions(+), 159 deletions(-)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 86d9249..1cbd936 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -64,15 +64,6 @@
#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
-#define check_warn(ret, fmt, args...) \
- ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
-
-#define check_warn_return(ret, fmt, args...) \
- ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); return ret; } })
-
-#define check_warn_goto_done(ret, fmt, args...) \
- ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); goto done; } })
-
struct smsc75xx_priv {
struct usbnet *dev;
u32 rfe_ctl;
@@ -182,7 +173,10 @@ static __must_check int __smsc75xx_phy_wait_not_busy(struct usbnet *dev,
do {
ret = __smsc75xx_read_reg(dev, MII_ACCESS, &val, in_pm);
- check_warn_return(ret, "Error reading MII_ACCESS\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading MII_ACCESS\n");
+ return ret;
+ }
if (!(val & MII_ACCESS_BUSY))
return 0;
@@ -202,7 +196,10 @@ static int __smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx,
/* confirm MII not busy */
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
- check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_read\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_read\n");
+ goto done;
+ }
/* set the address, index & direction (read from PHY) */
phy_id &= dev->mii.phy_id_mask;
@@ -211,13 +208,22 @@ static int __smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx,
| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
| MII_ACCESS_READ | MII_ACCESS_BUSY;
ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
- check_warn_goto_done(ret, "Error writing MII_ACCESS\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing MII_ACCESS\n");
+ goto done;
+ }
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
- check_warn_goto_done(ret, "Timed out reading MII reg %02X\n", idx);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
+ goto done;
+ }
ret = __smsc75xx_read_reg(dev, MII_DATA, &val, in_pm);
- check_warn_goto_done(ret, "Error reading MII_DATA\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading MII_DATA\n");
+ goto done;
+ }
ret = (u16)(val & 0xFFFF);
@@ -237,11 +243,17 @@ static void __smsc75xx_mdio_write(struct net_device *netdev, int phy_id,
/* confirm MII not busy */
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
- check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_write\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_write\n");
+ goto done;
+ }
val = regval;
ret = __smsc75xx_write_reg(dev, MII_DATA, val, in_pm);
- check_warn_goto_done(ret, "Error writing MII_DATA\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing MII_DATA\n");
+ goto done;
+ }
/* set the address, index & direction (write to PHY) */
phy_id &= dev->mii.phy_id_mask;
@@ -250,10 +262,16 @@ static void __smsc75xx_mdio_write(struct net_device *netdev, int phy_id,
| ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
| MII_ACCESS_WRITE | MII_ACCESS_BUSY;
ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
- check_warn_goto_done(ret, "Error writing MII_ACCESS\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing MII_ACCESS\n");
+ goto done;
+ }
ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
- check_warn_goto_done(ret, "Timed out writing MII reg %02X\n", idx);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
+ goto done;
+ }
done:
mutex_unlock(&dev->phy_mutex);
@@ -290,7 +308,10 @@ static int smsc75xx_wait_eeprom(struct usbnet *dev)
do {
ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
- check_warn_return(ret, "Error reading E2P_CMD\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading E2P_CMD\n");
+ return ret;
+ }
if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT))
break;
@@ -313,7 +334,10 @@ static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev)
do {
ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
- check_warn_return(ret, "Error reading E2P_CMD\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading E2P_CMD\n");
+ return ret;
+ }
if (!(val & E2P_CMD_BUSY))
return 0;
@@ -341,14 +365,20 @@ static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
for (i = 0; i < length; i++) {
val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR);
ret = smsc75xx_write_reg(dev, E2P_CMD, val);
- check_warn_return(ret, "Error writing E2P_CMD\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
+ return ret;
+ }
ret = smsc75xx_wait_eeprom(dev);
if (ret < 0)
return ret;
ret = smsc75xx_read_reg(dev, E2P_DATA, &val);
- check_warn_return(ret, "Error reading E2P_DATA\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading E2P_DATA\n");
+ return ret;
+ }
data[i] = val & 0xFF;
offset++;
@@ -373,7 +403,10 @@ static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
/* Issue write/erase enable command */
val = E2P_CMD_BUSY | E2P_CMD_EWEN;
ret = smsc75xx_write_reg(dev, E2P_CMD, val);
- check_warn_return(ret, "Error writing E2P_CMD\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
+ return ret;
+ }
ret = smsc75xx_wait_eeprom(dev);
if (ret < 0)
@@ -384,12 +417,18 @@ static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
/* Fill data register */
val = data[i];
ret = smsc75xx_write_reg(dev, E2P_DATA, val);
- check_warn_return(ret, "Error writing E2P_DATA\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing E2P_DATA\n");
+ return ret;
+ }
/* Send "write" command */
val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR);
ret = smsc75xx_write_reg(dev, E2P_CMD, val);
- check_warn_return(ret, "Error writing E2P_CMD\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
+ return ret;
+ }
ret = smsc75xx_wait_eeprom(dev);
if (ret < 0)
@@ -408,7 +447,10 @@ static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev)
for (i = 0; i < 100; i++) {
u32 dp_sel;
ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
- check_warn_return(ret, "Error reading DP_SEL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading DP_SEL\n");
+ return ret;
+ }
if (dp_sel & DP_SEL_DPRDY)
return 0;
@@ -431,28 +473,49 @@ static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr,
mutex_lock(&pdata->dataport_mutex);
ret = smsc75xx_dataport_wait_not_busy(dev);
- check_warn_goto_done(ret, "smsc75xx_dataport_write busy on entry\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "smsc75xx_dataport_write busy on entry\n");
+ goto done;
+ }
ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
- check_warn_goto_done(ret, "Error reading DP_SEL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading DP_SEL\n");
+ goto done;
+ }
dp_sel &= ~DP_SEL_RSEL;
dp_sel |= ram_select;
ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel);
- check_warn_goto_done(ret, "Error writing DP_SEL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing DP_SEL\n");
+ goto done;
+ }
for (i = 0; i < length; i++) {
ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i);
- check_warn_goto_done(ret, "Error writing DP_ADDR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing DP_ADDR\n");
+ goto done;
+ }
ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]);
- check_warn_goto_done(ret, "Error writing DP_DATA\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing DP_DATA\n");
+ goto done;
+ }
ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE);
- check_warn_goto_done(ret, "Error writing DP_CMD\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing DP_CMD\n");
+ goto done;
+ }
ret = smsc75xx_dataport_wait_not_busy(dev);
- check_warn_goto_done(ret, "smsc75xx_dataport_write timeout\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "smsc75xx_dataport_write timeout\n");
+ goto done;
+ }
}
done:
@@ -480,7 +543,8 @@ static void smsc75xx_deferred_multicast_write(struct work_struct *param)
DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table);
ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
- check_warn(ret, "Error writing RFE_CRL\n");
+ if (ret < 0)
+ netdev_warn(dev->net, "Error writing RFE_CRL\n");
}
static void smsc75xx_set_multicast(struct net_device *netdev)
@@ -554,10 +618,16 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
}
ret = smsc75xx_write_reg(dev, FLOW, flow);
- check_warn_return(ret, "Error writing FLOW\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing FLOW\n");
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow);
- check_warn_return(ret, "Error writing FCT_FLOW\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing FCT_FLOW\n");
+ return ret;
+ }
return 0;
}
@@ -574,7 +644,10 @@ static int smsc75xx_link_reset(struct usbnet *dev)
PHY_INT_SRC_CLEAR_ALL);
ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
- check_warn_return(ret, "Error writing INT_STS\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing INT_STS\n");
+ return ret;
+ }
mii_check_media(mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
@@ -658,9 +731,10 @@ static int smsc75xx_ethtool_set_wol(struct net_device *net,
pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
- check_warn_return(ret, "device_set_wakeup_enable error %d\n", ret);
+ if (ret < 0)
+ netdev_warn(dev->net, "device_set_wakeup_enable error %d\n", ret);
- return 0;
+ return ret;
}
static const struct ethtool_ops smsc75xx_ethtool_ops = {
@@ -713,19 +787,29 @@ static int smsc75xx_set_mac_address(struct usbnet *dev)
u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi);
- check_warn_return(ret, "Failed to write RX_ADDRH: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write RX_ADDRH: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo);
- check_warn_return(ret, "Failed to write RX_ADDRL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write RX_ADDRL: %d\n", ret);
+ return ret;
+ }
addr_hi |= ADDR_FILTX_FB_VALID;
ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi);
- check_warn_return(ret, "Failed to write ADDR_FILTX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write ADDR_FILTX: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo);
- check_warn_return(ret, "Failed to write ADDR_FILTX+4: %d\n", ret);
+ if (ret < 0)
+ netdev_warn(dev->net, "Failed to write ADDR_FILTX+4: %d\n", ret);
- return 0;
+ return ret;
}
static int smsc75xx_phy_initialize(struct usbnet *dev)
@@ -747,7 +831,10 @@ static int smsc75xx_phy_initialize(struct usbnet *dev)
do {
msleep(10);
bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR);
- check_warn_return(bmcr, "Error reading MII_BMCR\n");
+ if (bmcr < 0) {
+ netdev_warn(dev->net, "Error reading MII_BMCR\n");
+ return bmcr;
+ }
timeout++;
} while ((bmcr & BMCR_RESET) && (timeout < 100));
@@ -764,7 +851,11 @@ static int smsc75xx_phy_initialize(struct usbnet *dev)
/* read and write to clear phy interrupt status */
ret = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
- check_warn_return(ret, "Error reading PHY_INT_SRC\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+ return ret;
+ }
+
smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_SRC, 0xffff);
smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK,
@@ -782,14 +873,20 @@ static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)
bool rxenabled;
ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
- check_warn_return(ret, "Failed to read MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
+ return ret;
+ }
rxenabled = ((buf & MAC_RX_RXEN) != 0);
if (rxenabled) {
buf &= ~MAC_RX_RXEN;
ret = smsc75xx_write_reg(dev, MAC_RX, buf);
- check_warn_return(ret, "Failed to write MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
+ return ret;
+ }
}
/* add 4 to size for FCS */
@@ -797,12 +894,18 @@ static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)
buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE);
ret = smsc75xx_write_reg(dev, MAC_RX, buf);
- check_warn_return(ret, "Failed to write MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
+ return ret;
+ }
if (rxenabled) {
buf |= MAC_RX_RXEN;
ret = smsc75xx_write_reg(dev, MAC_RX, buf);
- check_warn_return(ret, "Failed to write MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
+ return ret;
+ }
}
return 0;
@@ -813,7 +916,10 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
struct usbnet *dev = netdev_priv(netdev);
int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu);
- check_warn_return(ret, "Failed to set mac rx frame length\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to set mac rx frame length\n");
+ return ret;
+ }
return usbnet_change_mtu(netdev, new_mtu);
}
@@ -838,9 +944,10 @@ static int smsc75xx_set_features(struct net_device *netdev,
/* it's racing here! */
ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
- check_warn_return(ret, "Error writing RFE_CTL\n");
+ if (ret < 0)
+ netdev_warn(dev->net, "Error writing RFE_CTL\n");
- return 0;
+ return ret;
}
static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
@@ -853,7 +960,10 @@ static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
ret = __smsc75xx_read_reg(dev, PMT_CTL, &buf, in_pm);
- check_warn_return(ret, "Failed to read PMT_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
+ return ret;
+ }
if (buf & PMT_CTL_DEV_RDY)
return 0;
@@ -875,21 +985,33 @@ static int smsc75xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset\n");
ret = smsc75xx_wait_ready(dev, 0);
- check_warn_return(ret, "device not ready in smsc75xx_reset\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "device not ready in smsc75xx_reset\n");
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
- check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
buf |= HW_CFG_LRST;
ret = smsc75xx_write_reg(dev, HW_CFG, buf);
- check_warn_return(ret, "Failed to write HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
+ return ret;
+ }
timeout = 0;
do {
msleep(10);
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
- check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
timeout++;
} while ((buf & HW_CFG_LRST) && (timeout < 100));
@@ -901,18 +1023,27 @@ static int smsc75xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY\n");
ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
- check_warn_return(ret, "Failed to read PMT_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
+ return ret;
+ }
buf |= PMT_CTL_PHY_RST;
ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
- check_warn_return(ret, "Failed to write PMT_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
+ return ret;
+ }
timeout = 0;
do {
msleep(10);
ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
- check_warn_return(ret, "Failed to read PMT_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
+ return ret;
+ }
timeout++;
} while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
@@ -926,13 +1057,19 @@ static int smsc75xx_reset(struct usbnet *dev)
smsc75xx_init_mac_address(dev);
ret = smsc75xx_set_mac_address(dev);
- check_warn_return(ret, "Failed to set mac address\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to set mac address\n");
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "MAC Address: %pM\n",
dev->net->dev_addr);
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
- check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n",
buf);
@@ -940,10 +1077,16 @@ static int smsc75xx_reset(struct usbnet *dev)
buf |= HW_CFG_BIR;
ret = smsc75xx_write_reg(dev, HW_CFG, buf);
- check_warn_return(ret, "Failed to write HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
- check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after writing HW_CFG_BIR: 0x%08x\n",
buf);
@@ -963,36 +1106,57 @@ static int smsc75xx_reset(struct usbnet *dev)
(ulong)dev->rx_urb_size);
ret = smsc75xx_write_reg(dev, BURST_CAP, buf);
- check_warn_return(ret, "Failed to write BURST_CAP: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, BURST_CAP, &buf);
- check_warn_return(ret, "Failed to read BURST_CAP: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net,
"Read Value from BURST_CAP after writing: 0x%08x\n", buf);
ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
- check_warn_return(ret, "Failed to write BULK_IN_DLY: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write BULK_IN_DLY: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf);
- check_warn_return(ret, "Failed to read BULK_IN_DLY: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net,
"Read Value from BULK_IN_DLY after writing: 0x%08x\n", buf);
if (turbo_mode) {
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
- check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf);
buf |= (HW_CFG_MEF | HW_CFG_BCE);
ret = smsc75xx_write_reg(dev, HW_CFG, buf);
- check_warn_return(ret, "Failed to write HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
- check_warn_return(ret, "Failed to read HW_CFG: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf);
}
@@ -1000,58 +1164,92 @@ static int smsc75xx_reset(struct usbnet *dev)
/* set FIFO sizes */
buf = (MAX_RX_FIFO_SIZE - 512) / 512;
ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf);
- check_warn_return(ret, "Failed to write FCT_RX_FIFO_END: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write FCT_RX_FIFO_END: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x\n", buf);
buf = (MAX_TX_FIFO_SIZE - 512) / 512;
ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf);
- check_warn_return(ret, "Failed to write FCT_TX_FIFO_END: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write FCT_TX_FIFO_END: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x\n", buf);
ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
- check_warn_return(ret, "Failed to write INT_STS: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write INT_STS: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, ID_REV, &buf);
- check_warn_return(ret, "Failed to read ID_REV: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", buf);
ret = smsc75xx_read_reg(dev, E2P_CMD, &buf);
- check_warn_return(ret, "Failed to read E2P_CMD: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read E2P_CMD: %d\n", ret);
+ return ret;
+ }
/* only set default GPIO/LED settings if no EEPROM is detected */
if (!(buf & E2P_CMD_LOADED)) {
ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf);
- check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d\n",
- ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read LED_GPIO_CFG: %d\n", ret);
+ return ret;
+ }
buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL);
buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL;
ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf);
- check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d\n",
- ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write LED_GPIO_CFG: %d\n", ret);
+ return ret;
+ }
}
ret = smsc75xx_write_reg(dev, FLOW, 0);
- check_warn_return(ret, "Failed to write FLOW: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, FCT_FLOW, 0);
- check_warn_return(ret, "Failed to write FCT_FLOW: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write FCT_FLOW: %d\n", ret);
+ return ret;
+ }
/* Don't need rfe_ctl_lock during initialisation */
ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
- check_warn_return(ret, "Failed to read RFE_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret);
+ return ret;
+ }
pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF;
ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
- check_warn_return(ret, "Failed to write RFE_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write RFE_CTL: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
- check_warn_return(ret, "Failed to read RFE_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x\n",
pdata->rfe_ctl);
@@ -1062,65 +1260,107 @@ static int smsc75xx_reset(struct usbnet *dev)
smsc75xx_set_multicast(dev->net);
ret = smsc75xx_phy_initialize(dev);
- check_warn_return(ret, "Failed to initialize PHY: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to initialize PHY: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf);
- check_warn_return(ret, "Failed to read INT_EP_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
+ return ret;
+ }
/* enable PHY interrupts */
buf |= INT_ENP_PHY_INT;
ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf);
- check_warn_return(ret, "Failed to write INT_EP_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
+ return ret;
+ }
/* allow mac to detect speed and duplex from phy */
ret = smsc75xx_read_reg(dev, MAC_CR, &buf);
- check_warn_return(ret, "Failed to read MAC_CR: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
+ return ret;
+ }
buf |= (MAC_CR_ADD | MAC_CR_ASD);
ret = smsc75xx_write_reg(dev, MAC_CR, buf);
- check_warn_return(ret, "Failed to write MAC_CR: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, MAC_TX, &buf);
- check_warn_return(ret, "Failed to read MAC_TX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read MAC_TX: %d\n", ret);
+ return ret;
+ }
buf |= MAC_TX_TXEN;
ret = smsc75xx_write_reg(dev, MAC_TX, buf);
- check_warn_return(ret, "Failed to write MAC_TX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write MAC_TX: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x\n", buf);
ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf);
- check_warn_return(ret, "Failed to read FCT_TX_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read FCT_TX_CTL: %d\n", ret);
+ return ret;
+ }
buf |= FCT_TX_CTL_EN;
ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf);
- check_warn_return(ret, "Failed to write FCT_TX_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write FCT_TX_CTL: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf);
ret = smsc75xx_set_rx_max_frame_length(dev, 1514);
- check_warn_return(ret, "Failed to set max rx frame length\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to set max rx frame length\n");
+ return ret;
+ }
ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
- check_warn_return(ret, "Failed to read MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
+ return ret;
+ }
buf |= MAC_RX_RXEN;
ret = smsc75xx_write_reg(dev, MAC_RX, buf);
- check_warn_return(ret, "Failed to write MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x\n", buf);
ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf);
- check_warn_return(ret, "Failed to read FCT_RX_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read FCT_RX_CTL: %d\n", ret);
+ return ret;
+ }
buf |= FCT_RX_CTL_EN;
ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf);
- check_warn_return(ret, "Failed to write FCT_RX_CTL: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write FCT_RX_CTL: %d\n", ret);
+ return ret;
+ }
netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x\n", buf);
@@ -1149,7 +1389,10 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
ret = usbnet_get_endpoints(dev, intf);
- check_warn_return(ret, "usbnet_get_endpoints failed: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
+ return ret;
+ }
dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv),
GFP_KERNEL);
@@ -1181,7 +1424,10 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
/* Init all registers */
ret = smsc75xx_reset(dev);
- check_warn_return(ret, "smsc75xx_reset error %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "smsc75xx_reset error %d\n", ret);
+ return ret;
+ }
dev->net->netdev_ops = &smsc75xx_netdev_ops;
dev->net->ethtool_ops = &smsc75xx_ethtool_ops;
@@ -1215,19 +1461,34 @@ static int smsc75xx_write_wuff(struct usbnet *dev, int filter, u32 wuf_cfg,
int ret;
ret = smsc75xx_write_reg(dev, cfg_base, wuf_cfg);
- check_warn_return(ret, "Error writing WUF_CFGX\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUF_CFGX\n");
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, mask_base, wuf_mask1);
- check_warn_return(ret, "Error writing WUF_MASKX\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, mask_base + 4, 0);
- check_warn_return(ret, "Error writing WUF_MASKX\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, mask_base + 8, 0);
- check_warn_return(ret, "Error writing WUF_MASKX\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
+ return ret;
+ }
ret = smsc75xx_write_reg(dev, mask_base + 12, 0);
- check_warn_return(ret, "Error writing WUF_MASKX\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
+ return ret;
+ }
return 0;
}
@@ -1239,13 +1500,19 @@ static int smsc75xx_enter_suspend0(struct usbnet *dev)
int ret;
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_return(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ return ret;
+ }
val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_PHY_RST));
val |= PMT_CTL_SUS_MODE_0 | PMT_CTL_WOL_EN | PMT_CTL_WUPS;
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
pdata->suspend_flags |= SUSPEND_SUSPEND0;
@@ -1259,20 +1526,29 @@ static int smsc75xx_enter_suspend1(struct usbnet *dev)
int ret;
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_return(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ return ret;
+ }
val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
val |= PMT_CTL_SUS_MODE_1;
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
/* clear wol status, enable energy detection */
val &= ~PMT_CTL_WUPS;
val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
pdata->suspend_flags |= SUSPEND_SUSPEND1;
@@ -1286,13 +1562,19 @@ static int smsc75xx_enter_suspend2(struct usbnet *dev)
int ret;
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_return(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ return ret;
+ }
val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
val |= PMT_CTL_SUS_MODE_2;
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
pdata->suspend_flags |= SUSPEND_SUSPEND2;
@@ -1306,7 +1588,10 @@ static int smsc75xx_enter_suspend3(struct usbnet *dev)
int ret;
ret = smsc75xx_read_reg_nopm(dev, FCT_RX_CTL, &val);
- check_warn_return(ret, "Error reading FCT_RX_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading FCT_RX_CTL\n");
+ return ret;
+ }
if (val & FCT_RX_CTL_RXUSED) {
netdev_dbg(dev->net, "rx fifo not empty in autosuspend\n");
@@ -1314,20 +1599,29 @@ static int smsc75xx_enter_suspend3(struct usbnet *dev)
}
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_return(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ return ret;
+ }
val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
val |= PMT_CTL_SUS_MODE_3 | PMT_CTL_RES_CLR_WKP_EN;
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
/* clear wol status */
val &= ~PMT_CTL_WUPS;
val |= PMT_CTL_WUPS_WOL;
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
pdata->suspend_flags |= SUSPEND_SUSPEND3;
@@ -1343,11 +1637,17 @@ static int smsc75xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
/* read to clear */
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
- check_warn_return(ret, "Error reading PHY_INT_SRC\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
+ return ret;
+ }
/* enable interrupt source */
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
- check_warn_return(ret, "Error reading PHY_INT_MASK\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PHY_INT_MASK\n");
+ return ret;
+ }
ret |= mask;
@@ -1363,10 +1663,16 @@ static int smsc75xx_link_ok_nopm(struct usbnet *dev)
/* first, a dummy read, needed to latch some MII phys */
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
- check_warn_return(ret, "Error reading MII_BMSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading MII_BMSR\n");
+ return ret;
+ }
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
- check_warn_return(ret, "Error reading MII_BMSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading MII_BMSR\n");
+ return ret;
+ }
return !!(ret & BMSR_LSTATUS);
}
@@ -1388,7 +1694,10 @@ static int smsc75xx_autosuspend(struct usbnet *dev, u32 link_up)
/* enable PHY wakeup events for if cable is attached */
ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
PHY_INT_MASK_ANEG_COMP);
- check_warn_return(ret, "error enabling PHY wakeup ints\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+ return ret;
+ }
netdev_info(dev->net, "entering SUSPEND1 mode\n");
return smsc75xx_enter_suspend1(dev);
@@ -1397,7 +1706,10 @@ static int smsc75xx_autosuspend(struct usbnet *dev, u32 link_up)
/* enable PHY wakeup events so we remote wakeup if cable is pulled */
ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
PHY_INT_MASK_LINK_DOWN);
- check_warn_return(ret, "error enabling PHY wakeup ints\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+ return ret;
+ }
netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
return smsc75xx_enter_suspend3(dev);
@@ -1411,7 +1723,10 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
int ret;
ret = usbnet_suspend(intf, message);
- check_warn_return(ret, "usbnet_suspend error\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "usbnet_suspend error\n");
+ return ret;
+ }
if (pdata->suspend_flags) {
netdev_warn(dev->net, "error during last resume\n");
@@ -1436,20 +1751,32 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
/* disable energy detect (link up) & wake up events */
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
val &= ~(WUCSR_MPEN | WUCSR_WUEN);
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_goto_done(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ goto done;
+ }
val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN);
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_goto_done(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ goto done;
+ }
ret = smsc75xx_enter_suspend2(dev);
goto done;
@@ -1458,7 +1785,10 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
if (pdata->wolopts & WAKE_PHY) {
ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
(PHY_INT_MASK_ANEG_COMP | PHY_INT_MASK_LINK_DOWN));
- check_warn_goto_done(ret, "error enabling PHY wakeup ints\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
+ goto done;
+ }
/* if link is down then configure EDPD and enter SUSPEND1,
* otherwise enter SUSPEND0 below
@@ -1470,7 +1800,10 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
/* enable energy detect power-down mode */
ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id,
PHY_MODE_CTRL_STS);
- check_warn_goto_done(ret, "Error reading PHY_MODE_CTRL_STS\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PHY_MODE_CTRL_STS\n");
+ goto done;
+ }
ret |= MODE_CTRL_STS_EDPWRDOWN;
@@ -1489,7 +1822,10 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
/* disable all filters */
for (i = 0; i < WUF_NUM; i++) {
ret = smsc75xx_write_reg_nopm(dev, WUF_CFGX + i * 4, 0);
- check_warn_goto_done(ret, "Error writing WUF_CFGX\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUF_CFGX\n");
+ goto done;
+ }
}
if (pdata->wolopts & WAKE_MCAST) {
@@ -1499,7 +1835,10 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
val = WUF_CFGX_EN | WUF_CFGX_ATYPE_MULTICAST
| smsc_crc(mcast, 3);
ret = smsc75xx_write_wuff(dev, filter++, val, 0x0007);
- check_warn_goto_done(ret, "Error writing wakeup filter\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing wakeup filter\n");
+ goto done;
+ }
}
if (pdata->wolopts & WAKE_ARP) {
@@ -1509,102 +1848,159 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
val = WUF_CFGX_EN | WUF_CFGX_ATYPE_ALL | (0x0C << 16)
| smsc_crc(arp, 2);
ret = smsc75xx_write_wuff(dev, filter++, val, 0x0003);
- check_warn_goto_done(ret, "Error writing wakeup filter\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing wakeup filter\n");
+ goto done;
+ }
}
/* clear any pending pattern match packet status */
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
val |= WUCSR_WUFR;
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
netdev_info(dev->net, "enabling packet match detection\n");
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
val |= WUCSR_WUEN;
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
} else {
netdev_info(dev->net, "disabling packet match detection\n");
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
val &= ~WUCSR_WUEN;
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
}
/* disable magic, bcast & unicast wakeup sources */
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN);
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
if (pdata->wolopts & WAKE_PHY) {
netdev_info(dev->net, "enabling PHY wakeup\n");
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_goto_done(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ goto done;
+ }
/* clear wol status, enable energy detection */
val &= ~PMT_CTL_WUPS;
val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_goto_done(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ goto done;
+ }
}
if (pdata->wolopts & WAKE_MAGIC) {
netdev_info(dev->net, "enabling magic packet wakeup\n");
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
/* clear any pending magic packet status */
val |= WUCSR_MPR | WUCSR_MPEN;
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
}
if (pdata->wolopts & WAKE_BCAST) {
netdev_info(dev->net, "enabling broadcast detection\n");
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
val |= WUCSR_BCAST_FR | WUCSR_BCST_EN;
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
}
if (pdata->wolopts & WAKE_UCAST) {
netdev_info(dev->net, "enabling unicast detection\n");
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_goto_done(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ goto done;
+ }
val |= WUCSR_WUFR | WUCSR_PFDA_EN;
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_goto_done(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ goto done;
+ }
}
/* enable receiver to enable frame reception */
ret = smsc75xx_read_reg_nopm(dev, MAC_RX, &val);
- check_warn_goto_done(ret, "Failed to read MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
+ goto done;
+ }
val |= MAC_RX_RXEN;
ret = smsc75xx_write_reg_nopm(dev, MAC_RX, val);
- check_warn_goto_done(ret, "Failed to write MAC_RX: %d\n", ret);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
+ goto done;
+ }
/* some wol options are enabled, so enter SUSPEND0 */
netdev_info(dev->net, "entering SUSPEND0 mode\n");
@@ -1632,39 +2028,60 @@ static int smsc75xx_resume(struct usb_interface *intf)
if (suspend_flags & SUSPEND_ALLMODES) {
/* Disable wakeup sources */
ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
- check_warn_return(ret, "Error reading WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading WUCSR\n");
+ return ret;
+ }
val &= ~(WUCSR_WUEN | WUCSR_MPEN | WUCSR_PFDA_EN
| WUCSR_BCST_EN);
ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
- check_warn_return(ret, "Error writing WUCSR\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing WUCSR\n");
+ return ret;
+ }
/* clear wake-up status */
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_return(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ return ret;
+ }
val &= ~PMT_CTL_WOL_EN;
val |= PMT_CTL_WUPS;
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
}
if (suspend_flags & SUSPEND_SUSPEND2) {
netdev_info(dev->net, "resuming from SUSPEND2\n");
ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
- check_warn_return(ret, "Error reading PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
+ return ret;
+ }
val |= PMT_CTL_PHY_PWRUP;
ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
- check_warn_return(ret, "Error writing PMT_CTL\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
+ return ret;
+ }
}
ret = smsc75xx_wait_ready(dev, 1);
- check_warn_return(ret, "device not ready in smsc75xx_resume\n");
+ if (ret < 0) {
+ netdev_warn(dev->net, "device not ready in smsc75xx_resume\n");
+ return ret;
+ }
return usbnet_resume(intf);
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 1/2] smsc75xx: don't call usbnet_resume if usbnet_suspend fails
From: Steve Glendinning @ 2012-11-30 14:52 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
In-Reply-To: <1354287164-9884-1-git-send-email-steve.glendinning@shawell.net>
If usbnet_suspend returns an error we don't want to call
usbnet_resume to clean up, but instead just return the error.
If usbnet_suspend *does* succeed, and we have a problem further
on, the desired behaviour is still to call usbnet_resume
to clean up before returning.
Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net>
---
drivers/net/usb/smsc75xx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 1823806..86d9249 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1411,7 +1411,7 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
int ret;
ret = usbnet_suspend(intf, message);
- check_warn_goto_done(ret, "usbnet_suspend error\n");
+ check_warn_return(ret, "usbnet_suspend error\n");
if (pdata->suspend_flags) {
netdev_warn(dev->net, "error during last resume\n");
--
1.7.10.4
^ permalink raw reply related
* [PATCH 0/2] smsc75xx enhancements
From: Steve Glendinning @ 2012-11-30 14:52 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
This patchset, as requestes, expands the macros used in
smsc75xx to make the flow control clearer.
I've left the fix in a separate patch, so the macro-
expanding patch should have zero functional change.
Steve Glendinning (2):
smsc75xx: don't call usbnet_resume if usbnet_suspend fails
smsc75xx: expand check_ macros
drivers/net/usb/smsc75xx.c | 735 ++++++++++++++++++++++++++++++++++----------
1 file changed, 576 insertions(+), 159 deletions(-)
--
1.7.10.4
^ permalink raw reply
* Re: [net-next PATCH V2 1/9] net: frag evictor, avoid killing warm frag queues
From: Eric Dumazet @ 2012-11-30 14:52 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: David Miller, fw, netdev, pablo, tgraf, amwang, kaber, paulmck,
herbert
In-Reply-To: <1354269846.11754.381.camel@localhost>
On Fri, 2012-11-30 at 11:04 +0100, Jesper Dangaard Brouer wrote:
> So, let me instead show, with tests, that the evictor strategy is
> broken, while keeping the original default thresh settings:
>
> # grep . /proc/sys/net/ipv4/ipfrag_*_thresh
> /proc/sys/net/ipv4/ipfrag_high_thresh:262144
> /proc/sys/net/ipv4/ipfrag_low_thresh:196608
>
> Test purpose, I will on a single 10G link demonstrate, that starting
> several "N" netperf UDP fragmentation flows, will hurt performance, and
> then claim this is caused by the bad evictor strategy.
>
> Test setup:
> - Disable Ethernet flow control
> - netperf packet size 65507
> - Run netserver on one NUMA node
> - Start netperf clients against a NIC on the other NUMA node
> - (The NUMA imbalance helps the effect occur at lower N)
>
> Result: N=1 8040 Mbit/s
> Result: N=2 9584 Mbit/s (4739+4845)
> Result: N=3 4055 Mbit/s (1436+1371+1248)
> Result: N=4 2247 Mbit/s (1538+29+54+626)
> Result: N=5 879 Mbit/s (78+152+226+125+298)
> Result: N=6 293 Mbit/s (85+55+32+57+46+18)
> Result: N=7 354 Mbit/s (70+47+33+80+20+72+32)
>
> Can we, now, agree that the current evictor strategy is broken?!?
Your setup is broken for sure. I dont know how you expect that many
datagrams being correctly reassembled with ipfrag_high_thresh=262144
No matter strategy is implemented, an attacker knows it and can send
frags so that regular workload is denied. Kernel cant decide which
packets are more likely to be completed.
BTW, install fq_codel at the sender side, so that frags are nicely
interleaved. Because on real networks, frags of an UDP datagram rarely
come to destination in a single train with no alien packets inside the
train.
You focus on a particular lab setup and particular workload, you
should consider that if an application _really_ depends on frags, then
the receiver is likely to be a target for various frag attacks.
^ permalink raw reply
* Re: [PATCH net-next v1 1/2] bridge: export port_no and port_id via IFA_INFO_DATA
From: Cong Wang @ 2012-11-30 14:51 UTC (permalink / raw)
To: Thomas Graf
Cc: netdev, bridge, Herbert Xu, Jesper Dangaard Brouer,
Stephen Hemminger, David S. Miller
In-Reply-To: <20121130101814.GD30697@casper.infradead.org>
On Fri, 2012-11-30 at 10:18 +0000, Thomas Graf wrote:
> On 11/30/12 at 05:58pm, Cong Wang wrote:
> > @@ -168,6 +172,8 @@ static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
> > [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
> > [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
> > [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
> > + [IFLA_BRPORT_NO] = { .type = NLA_U16 },
> > + [IFLA_BRPORT_ID] = { .type = NLA_U16 },
> > };
> >
> > /* Change the state of the port and notify spanning tree */
>
> I missed this in the first round. Not much of a point in adding policy
> entries if the attributes are read-only as in this case.
Yeah, remove these lines now.
^ permalink raw reply
* Re: [PATCH iproute2 v1] Add mdb command to bridge
From: Cong Wang @ 2012-11-30 14:50 UTC (permalink / raw)
To: Thomas Graf
Cc: netdev, bridge, Herbert Xu, Stephen Hemminger, David S. Miller,
Jesper Dangaard Brouer
In-Reply-To: <20121130105449.GE30697@casper.infradead.org>
On Fri, 2012-11-30 at 10:54 +0000, Thomas Graf wrote:
>
> You shouldn't need to duplicate the attribute ids and struct br_port_msg
> in iproute2. Just put these definitions in a uapi kernel header and
> include the header from iproute2.
Right, I was confused by include/linux/rtnetlink.h, thought iproute2 has
its own copy of these headers, but they should be exported from kernel.
Thanks!
^ permalink raw reply
* Re: [PATCH] sctp: fix CONFIG_SCTP_DBG_MSG=y null pointer dereference in sctp_v6_get_dst()
From: Vlad Yasevich @ 2012-11-30 14:18 UTC (permalink / raw)
To: Tommi Rantala
Cc: linux-sctp, netdev, Neil Horman, Sridhar Samudrala,
David S. Miller, Dave Jones
In-Reply-To: <1354267062-15888-1-git-send-email-tt.rantala@gmail.com>
On 11/30/2012 04:17 AM, Tommi Rantala wrote:
> Trinity (the syscall fuzzer) triggered the following BUG, reproducible
> only when the kernel is configured with CONFIG_SCTP_DBG_MSG=y.
>
> When CONFIG_SCTP_DBG_MSG is not set, the null pointer is never
> dereferenced.
>
> ---[ end trace a4de0bfcb38a3642 ]---
> BUG: unable to handle kernel NULL pointer dereference at 0000000000000100
> IP: [<ffffffff8136796e>] ip6_string+0x1e/0xa0
> PGD 4eead067 PUD 4e472067 PMD 0
> Oops: 0000 [#1] PREEMPT SMP
> Modules linked in:
> CPU 3
> Pid: 21324, comm: trinity-child11 Tainted: G W 3.7.0-rc7+ #61 ASUSTeK Computer INC. EB1012/EB1012
> RIP: 0010:[<ffffffff8136796e>] [<ffffffff8136796e>] ip6_string+0x1e/0xa0
> RSP: 0018:ffff88004e4637a0 EFLAGS: 00010046
> RAX: ffff88004e4637da RBX: ffff88004e4637da RCX: 0000000000000000
> RDX: ffffffff8246e92a RSI: 0000000000000100 RDI: ffff88004e4637da
> RBP: ffff88004e4637a8 R08: 000000000000ffff R09: 000000000000ffff
> R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff8289d600
> R13: ffffffff8289d230 R14: ffffffff8246e928 R15: ffffffff8289d600
> FS: 00007fed95153700(0000) GS:ffff88005fd80000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000000000000100 CR3: 000000004eeac000 CR4: 00000000000007e0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> Process trinity-child11 (pid: 21324, threadinfo ffff88004e462000, task ffff8800524b0000)
> Stack:
> ffff88004e4637da ffff88004e463828 ffffffff81368eee 000000004e4637d8
> ffffffff0000ffff ffff88000000ffff 0000000000000000 000000004e4637f8
> ffffffff826285d8 ffff88004e4637f8 0000000000000000 ffff8800524b06b0
> Call Trace:
> [<ffffffff81368eee>] ip6_addr_string.isra.11+0x3e/0xa0
> [<ffffffff81369183>] pointer.isra.12+0x233/0x2d0
> [<ffffffff810a413a>] ? vprintk_emit+0x1ba/0x450
> [<ffffffff8110953d>] ? trace_hardirqs_on_caller+0x10d/0x1a0
> [<ffffffff81369757>] vsnprintf+0x187/0x5d0
> [<ffffffff81369c62>] vscnprintf+0x12/0x30
> [<ffffffff810a4028>] vprintk_emit+0xa8/0x450
> [<ffffffff81e5cb00>] printk+0x49/0x4b
> [<ffffffff81d17221>] sctp_v6_get_dst+0x731/0x780
> [<ffffffff81d16e15>] ? sctp_v6_get_dst+0x325/0x780
> [<ffffffff81d00a96>] sctp_transport_route+0x46/0x120
> [<ffffffff81cff0f1>] sctp_assoc_add_peer+0x161/0x350
> [<ffffffff81d0fd8d>] sctp_sendmsg+0x6cd/0xcb0
> [<ffffffff81b55bf0>] ? inet_create+0x670/0x670
> [<ffffffff81b55cfb>] inet_sendmsg+0x10b/0x220
> [<ffffffff81b55bf0>] ? inet_create+0x670/0x670
> [<ffffffff81a72a64>] ? sock_update_classid+0xa4/0x2b0
> [<ffffffff81a72ab0>] ? sock_update_classid+0xf0/0x2b0
> [<ffffffff81a6ac1c>] sock_sendmsg+0xdc/0xf0
> [<ffffffff8118e9e5>] ? might_fault+0x85/0x90
> [<ffffffff8118e99c>] ? might_fault+0x3c/0x90
> [<ffffffff81a6e12a>] sys_sendto+0xfa/0x130
> [<ffffffff810a9887>] ? do_setitimer+0x197/0x380
> [<ffffffff81e960d5>] ? sysret_check+0x22/0x5d
> [<ffffffff81e960a9>] system_call_fastpath+0x16/0x1b
> Code: 01 eb 89 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 f8 31 c9 48 89 e5 53 eb 12 0f 1f 40 00 48 83 c1 01 48 83 c0 04 48 83 f9 08 74 70 <0f> b6 3c 4e 89 fb 83 e7 0f c0 eb 04 41 89 d8 41 83 e0 0f 0f b6
> RIP [<ffffffff8136796e>] ip6_string+0x1e/0xa0
> RSP <ffff88004e4637a0>
> CR2: 0000000000000100
> ---[ end trace a4de0bfcb38a3643 ]---
>
> Signed-off-by: Tommi Rantala <tt.rantala@gmail.com>
Acked-by: Vlad Yasevich <vyasevich@gmail.com>
Thanks
-vlad
> ---
> net/sctp/ipv6.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
> index ea14cb4..f3f0f4d 100644
> --- a/net/sctp/ipv6.c
> +++ b/net/sctp/ipv6.c
> @@ -345,7 +345,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
> }
>
> out:
> - if (!IS_ERR(dst)) {
> + if (!IS_ERR_OR_NULL(dst)) {
> struct rt6_info *rt;
> rt = (struct rt6_info *)dst;
> t->dst = dst;
>
^ permalink raw reply
* [PATCH] smsc: RFC: Workaround for problems with lan8710 phy auto MDI-X
From: Peter Turczak @ 2012-11-30 13:11 UTC (permalink / raw)
To: David Miller, Otavio Salvador, Javier Martinez Canillas,
Jiri Kosina, Christian Hohnstaedt, netdev, linux-kernel
Hi all,
while debugging network outages on a customers hardware I found, that the MDI-X function of the lan8710 phy seemed to cause trouble.
When connecting to almost any kind of 100/1000MBit switch, the link would seem to come up and data where sent out to the network. But all incoming packets got lost somehow. This is quite bad, as the system runs from nfsroot while booting up during development.
When I disabled the auto MDI-X function of the phy the problem went away.
Signed-off-by: Peter Turczak <pt@netconsequence.de>
---
drivers/net/phy/Kconfig | 10 ++++++++++
drivers/net/phy/smsc.c | 15 +++++++++++++++
include/linux/smscphy.h | 5 +++++
3 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 961f0b2..341f5aa 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -60,6 +60,16 @@ config SMSC_PHY
---help---
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
+config SMSC_PHY_DISABLE_AUTOX
+ bool "Disable MDI-X upon start"
+ depends on SMSC_PHY
+ ---help---
+ When you experience problems estabishing a stable connection
+ to a network and you have e.g. a LAN8710 ethernet phy
+ this option might help you out.
+
+ In doubt, say N
+
config BROADCOM_PHY
tristate "Drivers for Broadcom PHYs"
---help---
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 88e3991..651f71e 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -24,6 +24,8 @@
#include <linux/netdevice.h>
#include <linux/smscphy.h>
+static struct phy_driver lan8710_driver;
+
static int smsc_phy_config_intr(struct phy_device *phydev)
{
int rc = phy_write (phydev, MII_LAN83C185_IM,
@@ -53,6 +55,19 @@ static int smsc_phy_config_init(struct phy_device *phydev)
if (rc < 0)
return rc;
+#ifdef CONFIG_SMSC_PHY_DISABLE_AUTOX
+ if (phydev->drv == &lan8710_driver) {
+ rc = phy_read(phydev, MII_LAN8710_SCSI);
+ if (rc < 0)
+ return rc;
+ rc = phy_write(phydev, MII_LAN8710_SCSI,
+ rc | MII_LAN8710_SCSI_AMDIXCTRL);
+
+ if (rc < 0)
+ return rc;
+ }
+#endif
+
return smsc_phy_ack_interrupt (phydev);
}
diff --git a/include/linux/smscphy.h b/include/linux/smscphy.h
index ce718cb..4084b64 100644
--- a/include/linux/smscphy.h
+++ b/include/linux/smscphy.h
@@ -22,4 +22,9 @@
#define MII_LAN83C185_EDPWRDOWN (1 << 13) /* EDPWRDOWN */
#define MII_LAN83C185_ENERGYON (1 << 1) /* ENERGYON */
+#define MII_LAN8710_SCSI 27 /* Special Control/Status register */
+
+#define MII_LAN8710_SCSI_AMDIXCTRL (1<<15) /* Flag to disable Auto-MDIX */
+
+
#endif /* __LINUX_SMSCPHY_H__ */
--
1.7.0.4
^ permalink raw reply related
* [PATCH] [trivial] wireless: mwifiex: Fix typo in wireless/mwifiex driver
From: Masanari Iida @ 2012-11-30 13:08 UTC (permalink / raw)
To: bzhao, linux-wireless, trivial, linux-kernel, netdev; +Cc: Masanari Iida
Correct spelling typo in wireless/mwifiex driver.
Signed-off-by: Masanari Iida <standby24x7@gmail.com>
---
drivers/net/wireless/mwifiex/sta_ioctl.c | 2 +-
drivers/net/wireless/mwifiex/usb.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 552d72e..21035e6 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -463,7 +463,7 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
}
if (adapter->hs_activated) {
- dev_dbg(adapter->dev, "cmd: HS Already actived\n");
+ dev_dbg(adapter->dev, "cmd: HS Already activated\n");
return true;
}
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 22a5916..5eb3b33 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -351,7 +351,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
card->udev = udev;
card->intf = intf;
- pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocl=%#x\n",
+ pr_debug("info: bcdUSB=%#x Device Class=%#x SubClass=%#x Protocol=%#x\n",
udev->descriptor.bcdUSB, udev->descriptor.bDeviceClass,
udev->descriptor.bDeviceSubClass,
udev->descriptor.bDeviceProtocol);
--
1.8.0.1.347.gf94c325
^ permalink raw reply related
* Re: [net-next PATCH V2 8/9] net: frag queue locking per hash bucket
From: Jesper Dangaard Brouer @ 2012-11-30 12:55 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S. Miller, Florian Westphal, netdev, Pablo Neira Ayuso,
Thomas Graf, Cong Wang, Patrick McHardy, Paul E. McKenney,
Herbert Xu
In-Reply-To: <1354208920.14302.1907.camel@edumazet-glaptop>
On Thu, 2012-11-29 at 09:08 -0800, Eric Dumazet wrote:
> So we still have this huge contention on the reader-writer lock cache
> line...
> I would just remove it. (And remove hash rebuild, or make it RCU
> compatible )
I vote for removing the rebuild feature. It really doesn't make sense
to protect a 256Kb memory (using) hash, with very short lived elements,
against hash collision attacks, every 10 minutes. (Especially as we saw
a 7 GBit/s performance improvement)
Making the hash RCU "compatible" is not going to work, because the
elements are too short lived, thus we cannot free them fast enough
(call_rcu stuff). (I actually did the RCU implementation, to realize
this...)
^ permalink raw reply
* Re: [PATCH] net: ICMPv6 packets transmitted on wrong interface if nfmark is mangled
From: Dries De Winter @ 2012-11-30 12:29 UTC (permalink / raw)
To: David Miller; +Cc: pablo, kaber, netdev, netfilter-devel
In-Reply-To: <20121128.183037.1780631404801131036.davem@davemloft.net>
2012/11/29 David Miller <davem@davemloft.net>:
> From: Dries De Winter <dries.dewinter@gmail.com>
> Date: Wed, 28 Nov 2012 10:09:55 +0100 (CET)
>
>> I propose a patch which allows to mark a dst_entry as "non-reroutable".
>> icmp6_dst_alloc() (used by ndisc and MLD implementation) will always mark
>> the
>> allocated dst_entry as such. A check is added to netfilter (IPv6-only) so
>> packets heading for a non-reroutable destination are never rerouted.
>
> What about addrconf_dst_alloc()? Shouldn't it have this new flag set
> as well?
I don't think so. I'm not sure if I understand all of IPv6 routing
correctly, but it looks like dst entries allocated by
addrconf_dst_alloc() are added to the routing table pretty much like
normal routes and skbuffs get assigned such dst entries by normal rule
lookup / route lookup.
If an skbuff got assigned such a dst entry by normal routing in the
first place, and the changes done by the mangle table don't affect
routing (e.g. skb->mark changed but no policy based routing), I guess
that rerouting the packet will get you there too. In the meantime, by
not specifying DST_NOREROUTE for such destinations, you don't lose the
capability to mangle a packet so it should really be routed
differently.
> Regardless of the answer to that question, it should be explained
> in the commit message.
Should I post a new patch email including this comment?
Regards,
Dries.
^ permalink raw reply
* [PATCH] sctp: verify length provided in heartbeat information parameter
From: Thomas Graf @ 2012-11-30 12:16 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-sctp
If the variable parameter length provided in the mandatory
heartbeat information parameter exceeds the calculated payload
length the packet has been corrupted. Reply with a parameter
length protocol violation message.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
---
net/sctp/sm_statefuns.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index b6adef8..e92079d 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1055,6 +1055,7 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net,
void *arg,
sctp_cmd_seq_t *commands)
{
+ sctp_paramhdr_t *param_hdr;
struct sctp_chunk *chunk = arg;
struct sctp_chunk *reply;
size_t paylen = 0;
@@ -1072,12 +1073,17 @@ sctp_disposition_t sctp_sf_beat_8_3(struct net *net,
* Information field copied from the received HEARTBEAT chunk.
*/
chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data;
+ param_hdr = (sctp_paramhdr_t *) chunk->subh.hb_hdr;
paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
+
+ if (ntohs(param_hdr->length) > paylen)
+ return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
+ param_hdr, commands);
+
if (!pskb_pull(chunk->skb, paylen))
goto nomem;
- reply = sctp_make_heartbeat_ack(asoc, chunk,
- chunk->subh.hb_hdr, paylen);
+ reply = sctp_make_heartbeat_ack(asoc, chunk, param_hdr, paylen);
if (!reply)
goto nomem;
^ permalink raw reply related
* Re: [PATCH v2 3/3] pppoatm: protect against freeing of vcc
From: David Woodhouse @ 2012-11-30 12:10 UTC (permalink / raw)
To: Krzysztof Mazur
Cc: Chas Williams (CONTRACTOR), David Laight, davem, netdev,
linux-kernel, nathan
In-Reply-To: <20121130095354.GA15126@shrek.podlesie.net>
[-- Attachment #1: Type: text/plain, Size: 2554 bytes --]
On Fri, 2012-11-30 at 10:53 +0100, Krzysztof Mazur wrote:
> On Fri, Nov 30, 2012 at 08:25:22AM +0000, David Woodhouse wrote:
> > On Fri, 2012-11-30 at 01:57 +0000, David Woodhouse wrote:
> > > I think it's actually fixed for pppoatm by the bh_lock_sock() and the
> > > sock_owned_by_user() check. As soon as vcc_release() calls lock_sock(),
> > > pppoatm stops accepting packets.
> > >
> > > It should be simple enough to do the same in br2684.
> >
> > Um... but now I come to look at it... Krzysztof, doesn't your 'pppoatm:
> > take ATM socket lock in pppoatm_send()' patch actually *break* the case
> > of sending via vcc_sendmsg()?
>
> no,
... oops, sorry. My sleep-deprived brain thought that we were calling
pppoatm_send() *from* vcc_sendmsg() with the lock held. But of course
we're not; we're calling directly into the driver. So that's OK.
In that case I think we're fine. I'll just do the same thing in
br2684_push(), fix up the comment you just corrected, and we're all
good.
> I think that the current order is good, now we have:
>
> 1. stop_sending_fames to protocol
> now TX is shut down
> (currently done by
> set_bit(ATM_VF_CLOSE, &vcc->flags);
> clear_bit(ATM_VF_READY, &vcc->flags);
> )
Right, with the caveat the the socket lock is required for
synchronisation on this. But that's OK. Or we *could* perhaps introduce
an explicit call into the protocol for it, if we really wanted. But I'm
inclined not to.
> 2. close_device to device
> now RX is shut down
> 3. device_was_closed to protocol
> ugly push(NULL), but we can add some other callback.
> we also can do:
>
> 1. disable RX to device
> now RX is shut down
> 2. detach to protocol
> now TX is shut down
> (now protocol can fully detach because RX is disabled)
Careful. You have to flush the TX packets which are currently in-flight.
It's not sufficient just to stop sending any more. And you have to do it
*before* the data structures are torn down.
> 3. close_device to device
> (device is not used anymore)
Really, what we're saying is that *one* of the driver or protocol close
functions needs to be split, and we need to do DPD or PDP. Since the
device driver *can* abort/flush the TX queue and also any pending RX
being handled by a tasklet, I think it makes most sense to keep it in
the middle, with the protocol being handled first and last... which is
the current order, as long as we consider setting ATM_VF_CLOSE to be the
first part.
--
dwmw2
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 6171 bytes --]
^ permalink raw reply
* [PATCH V2 4/5] RDMA/cxgb4: Fix LE hash collision bug for passive open connection
From: Vipul Pandya @ 2012-11-30 12:09 UTC (permalink / raw)
To: linux-rdma-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
Cc: roland-BHEL68pLQRGGvPXPguhicg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
divy-ut6Up61K2wZBDgjK7y7TUQ, dm-ut6Up61K2wZBDgjK7y7TUQ,
kumaras-ut6Up61K2wZBDgjK7y7TUQ,
swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW,
abhishek-ut6Up61K2wZBDgjK7y7TUQ, Vipul Pandya
In-Reply-To: <1354277370-8727-1-git-send-email-vipul-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
It establishes passive open connection through firmware work request. Passive
open connection will go through this path as now instead of listening server we
create a server filter which will redirect the incoming SYN packet to the
offload queue. After this driver tries to establish the connection using
firmware work request.
Signed-off-by: Vipul Pandya <vipul-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
---
V2: Changed commenting style from kernel-doc format('/**') to normal
drivers/infiniband/hw/cxgb4/cm.c | 411 ++++++++++++++++++++---
drivers/infiniband/hw/cxgb4/device.c | 85 +++++-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 9 +
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 46 +++
4 files changed, 496 insertions(+), 55 deletions(-)
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 4878704..2ac6a2c 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -38,10 +38,12 @@
#include <linux/inetdevice.h>
#include <linux/ip.h>
#include <linux/tcp.h>
+#include <linux/if_vlan.h>
#include <net/neighbour.h>
#include <net/netevent.h>
#include <net/route.h>
+#include <net/tcp.h>
#include "iw_cxgb4.h"
@@ -1569,13 +1571,14 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_listen_ep *ep = lookup_stid(t, stid);
if (!ep) {
- printk(KERN_ERR MOD "stid %d lookup failure!\n", stid);
- return 0;
+ PDBG("%s stid %d lookup failure!\n", __func__, stid);
+ goto out;
}
PDBG("%s ep %p status %d error %d\n", __func__, ep,
rpl->status, status2errno(rpl->status));
c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
+out:
return 0;
}
@@ -1779,15 +1782,23 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
unsigned int hwtid = GET_TID(req);
struct dst_entry *dst;
struct rtable *rt;
- __be32 local_ip, peer_ip;
+ __be32 local_ip, peer_ip = 0;
__be16 local_port, peer_port;
int err;
+ u16 peer_mss = ntohs(req->tcpopt.mss);
parent_ep = lookup_stid(t, stid);
- PDBG("%s parent ep %p tid %u\n", __func__, parent_ep, hwtid);
-
+ if (!parent_ep) {
+ PDBG("%s connect request on invalid stid %d\n", __func__, stid);
+ goto reject;
+ }
get_4tuple(req, &local_ip, &peer_ip, &local_port, &peer_port);
+ PDBG("%s parent ep %p hwtid %u laddr 0x%x raddr 0x%x lport %d " \
+ "rport %d peer_mss %d\n", __func__, parent_ep, hwtid,
+ ntohl(local_ip), ntohl(peer_ip), ntohs(local_port),
+ ntohs(peer_port), peer_mss);
+
if (state_read(&parent_ep->com) != LISTEN) {
printk(KERN_ERR "%s - listening ep not in LISTEN\n",
__func__);
@@ -1821,6 +1832,9 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
goto reject;
}
+ if (peer_mss && child_ep->mtu > (peer_mss + 40))
+ child_ep->mtu = peer_mss + 40;
+
state_set(&child_ep->com, CONNECTING);
child_ep->com.dev = dev;
child_ep->com.cm_id = NULL;
@@ -1861,6 +1875,9 @@ static int pass_establish(struct c4iw_dev *dev, struct sk_buff *skb)
ep->snd_seq = be32_to_cpu(req->snd_isn);
ep->rcv_seq = be32_to_cpu(req->rcv_isn);
+ PDBG("%s ep %p hwtid %u tcp_opt 0x%02x\n", __func__, ep, tid,
+ ntohs(req->tcp_opt));
+
set_emss(ep, ntohs(req->tcp_opt));
dst_confirm(ep->dst);
@@ -2478,7 +2495,6 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
struct c4iw_listen_ep *ep;
-
might_sleep();
ep = alloc_ep(sizeof(*ep), GFP_KERNEL);
@@ -2497,30 +2513,49 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
/*
* Allocate a server TID.
*/
- ep->stid = cxgb4_alloc_stid(dev->rdev.lldi.tids, PF_INET, ep);
+ if (dev->rdev.lldi.enable_fw_ofld_conn)
+ ep->stid = cxgb4_alloc_sftid(dev->rdev.lldi.tids, PF_INET, ep);
+ else
+ ep->stid = cxgb4_alloc_stid(dev->rdev.lldi.tids, PF_INET, ep);
+
if (ep->stid == -1) {
printk(KERN_ERR MOD "%s - cannot alloc stid.\n", __func__);
err = -ENOMEM;
goto fail2;
}
-
state_set(&ep->com, LISTEN);
- c4iw_init_wr_wait(&ep->com.wr_wait);
- err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0], ep->stid,
- ep->com.local_addr.sin_addr.s_addr,
- ep->com.local_addr.sin_port,
- ep->com.dev->rdev.lldi.rxq_ids[0]);
- if (err)
- goto fail3;
-
- /* wait for pass_open_rpl */
- err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
- __func__);
+ if (dev->rdev.lldi.enable_fw_ofld_conn) {
+ do {
+ err = cxgb4_create_server_filter(
+ ep->com.dev->rdev.lldi.ports[0], ep->stid,
+ ep->com.local_addr.sin_addr.s_addr,
+ ep->com.local_addr.sin_port,
+ ep->com.dev->rdev.lldi.rxq_ids[0]);
+ if (err == -EBUSY) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(100));
+ }
+ } while (err == -EBUSY);
+ } else {
+ c4iw_init_wr_wait(&ep->com.wr_wait);
+ err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0],
+ ep->stid, ep->com.local_addr.sin_addr.s_addr,
+ ep->com.local_addr.sin_port,
+ ep->com.dev->rdev.lldi.rxq_ids[0]);
+ if (!err)
+ err = c4iw_wait_for_reply(&ep->com.dev->rdev,
+ &ep->com.wr_wait,
+ 0, 0, __func__);
+ }
if (!err) {
cm_id->provider_data = ep;
goto out;
}
-fail3:
+ pr_err("%s cxgb4_create_server/filter failed err %d " \
+ "stid %d laddr %08x lport %d\n", \
+ __func__, err, ep->stid,
+ ntohl(ep->com.local_addr.sin_addr.s_addr),
+ ntohs(ep->com.local_addr.sin_port));
cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
fail2:
cm_id->rem_ref(cm_id);
@@ -2539,12 +2574,18 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id)
might_sleep();
state_set(&ep->com, DEAD);
- c4iw_init_wr_wait(&ep->com.wr_wait);
- err = listen_stop(ep);
- if (err)
- goto done;
- err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
- __func__);
+ if (ep->com.dev->rdev.lldi.enable_fw_ofld_conn) {
+ err = cxgb4_remove_server_filter(
+ ep->com.dev->rdev.lldi.ports[0], ep->stid,
+ ep->com.dev->rdev.lldi.rxq_ids[0], 0);
+ } else {
+ c4iw_init_wr_wait(&ep->com.wr_wait);
+ err = listen_stop(ep);
+ if (err)
+ goto done;
+ err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait,
+ 0, 0, __func__);
+ }
cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
done:
cm_id->rem_ref(cm_id);
@@ -2621,10 +2662,298 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
return ret;
}
-static int async_event(struct c4iw_dev *dev, struct sk_buff *skb)
+static void active_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb,
+ struct cpl_fw6_msg_ofld_connection_wr_rpl *req)
+{
+ struct c4iw_ep *ep;
+
+ ep = (struct c4iw_ep *)lookup_atid(dev->rdev.lldi.tids, req->tid);
+ if (!ep)
+ return;
+
+ switch (req->retval) {
+ case FW_ENOMEM:
+ case FW_EADDRINUSE:
+ PDBG("%s ofld conn wr ret %d\n", __func__, req->retval);
+ break;
+ default:
+ pr_info("%s unexpected ofld conn wr retval %d\n",
+ __func__, req->retval);
+ break;
+ }
+ connect_reply_upcall(ep, status2errno(req->retval));
+}
+
+static void passive_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb,
+ struct cpl_fw6_msg_ofld_connection_wr_rpl *req)
+{
+ struct sk_buff *rpl_skb;
+ struct cpl_pass_accept_req *cpl;
+ int ret;
+
+ rpl_skb = (struct sk_buff *)cpu_to_be64(req->cookie);
+ BUG_ON(!rpl_skb);
+ if (req->retval) {
+ PDBG("%s passive open failure %d\n", __func__, req->retval);
+ kfree_skb(rpl_skb);
+ } else {
+ cpl = (struct cpl_pass_accept_req *)cplhdr(rpl_skb);
+ OPCODE_TID(cpl) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_REQ,
+ htonl(req->tid)));
+ ret = pass_accept_req(dev, rpl_skb);
+ if (!ret)
+ kfree_skb(rpl_skb);
+ }
+ return;
+}
+
+static int deferred_fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
{
struct cpl_fw6_msg *rpl = cplhdr(skb);
- c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+ struct cpl_fw6_msg_ofld_connection_wr_rpl *req;
+
+ switch (rpl->type) {
+ case FW6_TYPE_CQE:
+ c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+ break;
+ case FW6_TYPE_OFLD_CONNECTION_WR_RPL:
+ req = (struct cpl_fw6_msg_ofld_connection_wr_rpl *)rpl->data;
+ switch (req->t_state) {
+ case TCP_SYN_SENT:
+ active_ofld_conn_reply(dev, skb, req);
+ break;
+ case TCP_SYN_RECV:
+ passive_ofld_conn_reply(dev, skb, req);
+ break;
+ default:
+ pr_err("%s unexpected ofld conn wr state %d\n",
+ __func__, req->t_state);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
+{
+ u32 l2info;
+ u16 vlantag, len, hdr_len;
+ u8 intf;
+ struct cpl_rx_pkt *cpl = cplhdr(skb);
+ struct cpl_pass_accept_req *req;
+ struct tcp_options_received tmp_opt;
+
+ /* Store values from cpl_rx_pkt in temporary location. */
+ vlantag = cpl->vlan;
+ len = cpl->len;
+ l2info = cpl->l2info;
+ hdr_len = cpl->hdr_len;
+ intf = cpl->iff;
+
+ __skb_pull(skb, sizeof(*req) + sizeof(struct rss_header));
+
+ /* We need to parse the TCP options from SYN packet.
+ * to generate cpl_pass_accept_req.
+ */
+ memset(&tmp_opt, 0, sizeof(tmp_opt));
+ tcp_clear_options(&tmp_opt);
+ tcp_parse_options(skb, &tmp_opt, 0, 0, NULL);
+
+ req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req));
+ memset(req, 0, sizeof(*req));
+ req->l2info = cpu_to_be16(V_SYN_INTF(intf) |
+ V_SYN_MAC_IDX(G_RX_MACIDX(htonl(l2info))) |
+ F_SYN_XACT_MATCH);
+ req->hdr_len = cpu_to_be32(V_SYN_RX_CHAN(G_RX_CHAN(htonl(l2info))) |
+ V_TCP_HDR_LEN(G_RX_TCPHDR_LEN(htons(hdr_len))) |
+ V_IP_HDR_LEN(G_RX_IPHDR_LEN(htons(hdr_len))) |
+ V_ETH_HDR_LEN(G_RX_ETHHDR_LEN(htonl(l2info))));
+ req->vlan = vlantag;
+ req->len = len;
+ req->tos_stid = cpu_to_be32(PASS_OPEN_TID(stid) |
+ PASS_OPEN_TOS(tos));
+ req->tcpopt.mss = htons(tmp_opt.mss_clamp);
+ if (tmp_opt.wscale_ok)
+ req->tcpopt.wsf = tmp_opt.snd_wscale;
+ req->tcpopt.tstamp = tmp_opt.saw_tstamp;
+ if (tmp_opt.sack_ok)
+ req->tcpopt.sack = 1;
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_REQ, 0));
+ return;
+}
+
+static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
+ __be32 laddr, __be16 lport,
+ __be32 raddr, __be16 rport,
+ u32 rcv_isn, u32 filter, u16 window,
+ u32 rss_qid, u8 port_id)
+{
+ struct sk_buff *req_skb;
+ struct fw_ofld_connection_wr *req;
+ struct cpl_pass_accept_req *cpl = cplhdr(skb);
+
+ req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
+ req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req));
+ memset(req, 0, sizeof(*req));
+ req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL(1));
+ req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16)));
+ req->le.version_cpl = htonl(F_FW_OFLD_CONNECTION_WR_CPL);
+ req->le.filter = filter;
+ req->le.lport = lport;
+ req->le.pport = rport;
+ req->le.u.ipv4.lip = laddr;
+ req->le.u.ipv4.pip = raddr;
+ req->tcb.rcv_nxt = htonl(rcv_isn + 1);
+ req->tcb.rcv_adv = htons(window);
+ req->tcb.t_state_to_astid =
+ htonl(V_FW_OFLD_CONNECTION_WR_T_STATE(TCP_SYN_RECV) |
+ V_FW_OFLD_CONNECTION_WR_RCV_SCALE(cpl->tcpopt.wsf) |
+ V_FW_OFLD_CONNECTION_WR_ASTID(
+ GET_PASS_OPEN_TID(ntohl(cpl->tos_stid))));
+
+ /*
+ * We store the qid in opt2 which will be used by the firmware
+ * to send us the wr response.
+ */
+ req->tcb.opt2 = htonl(V_RSS_QUEUE(rss_qid));
+
+ /*
+ * We initialize the MSS index in TCB to 0xF.
+ * So that when driver sends cpl_pass_accept_rpl
+ * TCB picks up the correct value. If this was 0
+ * TP will ignore any value > 0 for MSS index.
+ */
+ req->tcb.opt0 = cpu_to_be64(V_MSS_IDX(0xF));
+ req->cookie = cpu_to_be64((u64)skb);
+
+ set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id);
+ cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
+}
+
+/*
+ * Handler for CPL_RX_PKT message. Need to handle cpl_rx_pkt
+ * messages when a filter is being used instead of server to
+ * redirect a syn packet. When packets hit filter they are redirected
+ * to the offload queue and driver tries to establish the connection
+ * using firmware work request.
+ */
+static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
+{
+ int stid;
+ unsigned int filter;
+ struct ethhdr *eh = NULL;
+ struct vlan_ethhdr *vlan_eh = NULL;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ struct rss_header *rss = (void *)skb->data;
+ struct cpl_rx_pkt *cpl = (void *)skb->data;
+ struct cpl_pass_accept_req *req = (void *)(rss + 1);
+ struct l2t_entry *e;
+ struct dst_entry *dst;
+ struct rtable *rt;
+ struct c4iw_ep *lep;
+ u16 window;
+ struct port_info *pi;
+ struct net_device *pdev;
+ u16 rss_qid;
+ int step;
+ u32 tx_chan;
+ struct neighbour *neigh;
+
+ /* Drop all non-SYN packets */
+ if (!(cpl->l2info & cpu_to_be32(F_RXF_SYN)))
+ goto reject;
+
+ /*
+ * Drop all packets which did not hit the filter.
+ * Unlikely to happen.
+ */
+ if (!(rss->filter_hit && rss->filter_tid))
+ goto reject;
+
+ /*
+ * Calculate the server tid from filter hit index from cpl_rx_pkt.
+ */
+ stid = cpu_to_be32(rss->hash_val) - dev->rdev.lldi.tids->sftid_base
+ + dev->rdev.lldi.tids->nstids;
+
+ lep = (struct c4iw_ep *)lookup_stid(dev->rdev.lldi.tids, stid);
+ if (!lep) {
+ PDBG("%s connect request on invalid stid %d\n", __func__, stid);
+ goto reject;
+ }
+
+ if (G_RX_ETHHDR_LEN(ntohl(cpl->l2info)) == ETH_HLEN) {
+ eh = (struct ethhdr *)(req + 1);
+ iph = (struct iphdr *)(eh + 1);
+ } else {
+ vlan_eh = (struct vlan_ethhdr *)(req + 1);
+ iph = (struct iphdr *)(vlan_eh + 1);
+ skb->vlan_tci = ntohs(cpl->vlan);
+ }
+
+ if (iph->version != 0x4)
+ goto reject;
+
+ tcph = (struct tcphdr *)(iph + 1);
+ skb_set_network_header(skb, (void *)iph - (void *)rss);
+ skb_set_transport_header(skb, (void *)tcph - (void *)rss);
+ skb_get(skb);
+
+ PDBG("%s lip 0x%x lport %u pip 0x%x pport %u tos %d\n", __func__,
+ ntohl(iph->daddr), ntohs(tcph->dest), ntohl(iph->saddr),
+ ntohs(tcph->source), iph->tos);
+
+ rt = find_route(dev, iph->daddr, iph->saddr, tcph->dest, tcph->source,
+ iph->tos);
+ if (!rt) {
+ pr_err("%s - failed to find dst entry!\n",
+ __func__);
+ goto reject;
+ }
+ dst = &rt->dst;
+ neigh = dst_neigh_lookup_skb(dst, skb);
+
+ if (neigh->dev->flags & IFF_LOOPBACK) {
+ pdev = ip_dev_find(&init_net, iph->daddr);
+ e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
+ pdev, 0);
+ pi = (struct port_info *)netdev_priv(pdev);
+ tx_chan = cxgb4_port_chan(pdev);
+ dev_put(pdev);
+ } else {
+ e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
+ neigh->dev, 0);
+ pi = (struct port_info *)netdev_priv(neigh->dev);
+ tx_chan = cxgb4_port_chan(neigh->dev);
+ }
+ if (!e) {
+ pr_err("%s - failed to allocate l2t entry!\n",
+ __func__);
+ goto free_dst;
+ }
+
+ step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
+ rss_qid = dev->rdev.lldi.rxq_ids[pi->port_id * step];
+ window = htons(tcph->window);
+
+ /* Calcuate filter portion for LE region. */
+ filter = cpu_to_be32(select_ntuple(dev, dst, e));
+
+ /*
+ * Synthesize the cpl_pass_accept_req. We have everything except the
+ * TID. Once firmware sends a reply with TID we update the TID field
+ * in cpl and pass it through the regular cpl_pass_accept_req path.
+ */
+ build_cpl_pass_accept_req(skb, stid, iph->tos);
+ send_fw_pass_open_req(dev, skb, iph->daddr, tcph->dest, iph->saddr,
+ tcph->source, ntohl(tcph->seq), filter, window,
+ rss_qid, pi->port_id);
+ cxgb4_l2t_release(e);
+free_dst:
+ dst_release(dst);
+reject:
return 0;
}
@@ -2647,7 +2976,8 @@ static c4iw_handler_func work_handlers[NUM_CPL_CMDS] = {
[CPL_CLOSE_CON_RPL] = close_con_rpl,
[CPL_RDMA_TERMINATE] = terminate,
[CPL_FW4_ACK] = fw4_ack,
- [CPL_FW6_MSG] = async_event
+ [CPL_FW6_MSG] = deferred_fw6_msg,
+ [CPL_RX_PKT] = rx_pkt
};
static void process_timeout(struct c4iw_ep *ep)
@@ -2774,9 +3104,6 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
struct cpl_fw6_msg *rpl = cplhdr(skb);
struct c4iw_wr_wait *wr_waitp;
int ret;
- u8 opcode;
- struct cpl_fw6_msg_ofld_connection_wr_rpl *req;
- struct c4iw_ep *ep;
PDBG("%s type %u\n", __func__, rpl->type);
@@ -2790,23 +3117,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
kfree_skb(skb);
break;
case FW6_TYPE_CQE:
- sched(dev, skb);
- break;
case FW6_TYPE_OFLD_CONNECTION_WR_RPL:
- opcode = *(const u8 *)rpl->data;
- if (opcode == FW_OFLD_CONNECTION_WR) {
- req =
- (struct cpl_fw6_msg_ofld_connection_wr_rpl *)rpl->data;
- if (req->t_state == TCP_SYN_SENT
- && (req->retval == FW_ENOMEM
- || req->retval == FW_EADDRINUSE)) {
- ep = (struct c4iw_ep *)
- lookup_atid(dev->rdev.lldi.tids,
- req->tid);
- c4iw_l2t_send(&dev->rdev, skb, ep->l2t);
- return 0;
- }
- }
+ sched(dev, skb);
break;
default:
printk(KERN_ERR MOD "%s unexpected fw6 msg type %u\n", __func__,
@@ -2868,7 +3180,8 @@ c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS] = {
[CPL_RDMA_TERMINATE] = sched,
[CPL_FW4_ACK] = sched,
[CPL_SET_TCB_RPL] = set_tcb_rpl,
- [CPL_FW6_MSG] = fw6_msg
+ [CPL_FW6_MSG] = fw6_msg,
+ [CPL_RX_PKT] = sched
};
int __init c4iw_cm_init(void)
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index cb4ecd7..6b5b3d1 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -279,6 +279,7 @@ static int stats_show(struct seq_file *seq, void *v)
seq_printf(seq, " DB State: %s Transitions %llu\n",
db_state_str[dev->db_state],
dev->rdev.stats.db_state_transitions);
+ seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full);
return 0;
}
@@ -577,14 +578,76 @@ out:
return ctx;
}
+static inline struct sk_buff *copy_gl_to_skb_pkt(const struct pkt_gl *gl,
+ const __be64 *rsp,
+ u32 pktshift)
+{
+ struct sk_buff *skb;
+
+ /*
+ * Allocate space for cpl_pass_accept_req which will be synthesized by
+ * driver. Once the driver synthesizes the request the skb will go
+ * through the regular cpl_pass_accept_req processing.
+ * The math here assumes sizeof cpl_pass_accept_req >= sizeof
+ * cpl_rx_pkt.
+ */
+ skb = alloc_skb(gl->tot_len + sizeof(struct cpl_pass_accept_req) +
+ sizeof(struct rss_header) - pktshift, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return NULL;
+
+ __skb_put(skb, gl->tot_len + sizeof(struct cpl_pass_accept_req) +
+ sizeof(struct rss_header) - pktshift);
+
+ /*
+ * This skb will contain:
+ * rss_header from the rspq descriptor (1 flit)
+ * cpl_rx_pkt struct from the rspq descriptor (2 flits)
+ * space for the difference between the size of an
+ * rx_pkt and pass_accept_req cpl (1 flit)
+ * the packet data from the gl
+ */
+ skb_copy_to_linear_data(skb, rsp, sizeof(struct cpl_pass_accept_req) +
+ sizeof(struct rss_header));
+ skb_copy_to_linear_data_offset(skb, sizeof(struct rss_header) +
+ sizeof(struct cpl_pass_accept_req),
+ gl->va + pktshift,
+ gl->tot_len - pktshift);
+ return skb;
+}
+
+static inline int recv_rx_pkt(struct c4iw_dev *dev, const struct pkt_gl *gl,
+ const __be64 *rsp)
+{
+ unsigned int opcode = *(u8 *)rsp;
+ struct sk_buff *skb;
+
+ if (opcode != CPL_RX_PKT)
+ goto out;
+
+ skb = copy_gl_to_skb_pkt(gl , rsp, dev->rdev.lldi.sge_pktshift);
+ if (skb == NULL)
+ goto out;
+
+ if (c4iw_handlers[opcode] == NULL) {
+ pr_info("%s no handler opcode 0x%x...\n", __func__,
+ opcode);
+ kfree_skb(skb);
+ goto out;
+ }
+ c4iw_handlers[opcode](dev, skb);
+ return 1;
+out:
+ return 0;
+}
+
static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
const struct pkt_gl *gl)
{
struct uld_ctx *ctx = handle;
struct c4iw_dev *dev = ctx->dev;
struct sk_buff *skb;
- const struct cpl_act_establish *rpl;
- unsigned int opcode;
+ u8 opcode;
if (gl == NULL) {
/* omit RSS and rsp_ctrl at end of descriptor */
@@ -601,19 +664,29 @@ static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
u32 qid = be32_to_cpu(rc->pldbuflen_qid);
c4iw_ev_handler(dev, qid);
return 0;
+ } else if (unlikely(*(u8 *)rsp != *(u8 *)gl->va)) {
+ if (recv_rx_pkt(dev, gl, rsp))
+ return 0;
+
+ pr_info("%s: unexpected FL contents at %p, " \
+ "RSS %#llx, FL %#llx, len %u\n",
+ pci_name(ctx->lldi.pdev), gl->va,
+ (unsigned long long)be64_to_cpu(*rsp),
+ (unsigned long long)be64_to_cpu(*(u64 *)gl->va),
+ gl->tot_len);
+
+ return 0;
} else {
skb = cxgb4_pktgl_to_skb(gl, 128, 128);
if (unlikely(!skb))
goto nomem;
}
- rpl = cplhdr(skb);
- opcode = rpl->ot.opcode;
-
+ opcode = *(u8 *)rsp;
if (c4iw_handlers[opcode])
c4iw_handlers[opcode](dev, skb);
else
- printk(KERN_INFO "%s no handler opcode 0x%x...\n", __func__,
+ pr_info("%s no handler opcode 0x%x...\n", __func__,
opcode);
return 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index f55386b..1a26e3f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3326,6 +3326,10 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
adap = netdev2adap(dev);
+ /* Adjust stid to correct filter index */
+ stid -= adap->tids.nstids;
+ stid += adap->tids.nftids;
+
/* Check to make sure the filter requested is writable ...
*/
f = &adap->tids.ftid_tab[stid];
@@ -3374,6 +3378,11 @@ int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
struct adapter *adap;
adap = netdev2adap(dev);
+
+ /* Adjust stid to correct filter index */
+ stid -= adap->tids.nstids;
+ stid += adap->tids.nftids;
+
f = &adap->tids.ftid_tab[stid];
/* Unlock the filter */
f->locked = 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index 5b51c01..1179616 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -199,6 +199,18 @@ struct work_request_hdr {
#define WR_HDR struct work_request_hdr wr
+/* option 0 fields */
+#define S_MSS_IDX 60
+#define M_MSS_IDX 0xF
+#define V_MSS_IDX(x) ((__u64)(x) << S_MSS_IDX)
+#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+
+/* option 2 fields */
+#define S_RSS_QUEUE 0
+#define M_RSS_QUEUE 0x3FF
+#define V_RSS_QUEUE(x) ((x) << S_RSS_QUEUE)
+#define G_RSS_QUEUE(x) (((x) >> S_RSS_QUEUE) & M_RSS_QUEUE)
+
struct cpl_pass_open_req {
WR_HDR;
union opcode_tid ot;
@@ -300,6 +312,9 @@ struct cpl_pass_establish {
union opcode_tid ot;
__be32 rsvd;
__be32 tos_stid;
+#define PASS_OPEN_TID(x) ((x) << 0)
+#define PASS_OPEN_TOS(x) ((x) << 24)
+#define GET_PASS_OPEN_TID(x) (((x) >> 0) & 0xFFFFFF)
#define GET_POPEN_TID(x) ((x) & 0xffffff)
#define GET_POPEN_TOS(x) (((x) >> 24) & 0xff)
__be16 mac_idx;
@@ -545,6 +560,37 @@ struct cpl_rx_pkt {
__be16 err_vec;
};
+/* rx_pkt.l2info fields */
+#define S_RX_ETHHDR_LEN 0
+#define M_RX_ETHHDR_LEN 0x1F
+#define V_RX_ETHHDR_LEN(x) ((x) << S_RX_ETHHDR_LEN)
+#define G_RX_ETHHDR_LEN(x) (((x) >> S_RX_ETHHDR_LEN) & M_RX_ETHHDR_LEN)
+
+#define S_RX_MACIDX 8
+#define M_RX_MACIDX 0x1FF
+#define V_RX_MACIDX(x) ((x) << S_RX_MACIDX)
+#define G_RX_MACIDX(x) (((x) >> S_RX_MACIDX) & M_RX_MACIDX)
+
+#define S_RXF_SYN 21
+#define V_RXF_SYN(x) ((x) << S_RXF_SYN)
+#define F_RXF_SYN V_RXF_SYN(1U)
+
+#define S_RX_CHAN 28
+#define M_RX_CHAN 0xF
+#define V_RX_CHAN(x) ((x) << S_RX_CHAN)
+#define G_RX_CHAN(x) (((x) >> S_RX_CHAN) & M_RX_CHAN)
+
+/* rx_pkt.hdr_len fields */
+#define S_RX_TCPHDR_LEN 0
+#define M_RX_TCPHDR_LEN 0x3F
+#define V_RX_TCPHDR_LEN(x) ((x) << S_RX_TCPHDR_LEN)
+#define G_RX_TCPHDR_LEN(x) (((x) >> S_RX_TCPHDR_LEN) & M_RX_TCPHDR_LEN)
+
+#define S_RX_IPHDR_LEN 6
+#define M_RX_IPHDR_LEN 0x3FF
+#define V_RX_IPHDR_LEN(x) ((x) << S_RX_IPHDR_LEN)
+#define G_RX_IPHDR_LEN(x) (((x) >> S_RX_IPHDR_LEN) & M_RX_IPHDR_LEN)
+
struct cpl_trace_pkt {
u8 opcode;
u8 intf;
--
1.7.1
--
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 related
* [PATCH V2 2/5] cxgb4: Add LE hash collision bug fix path in LLD driver
From: Vipul Pandya @ 2012-11-30 12:09 UTC (permalink / raw)
To: linux-rdma-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
Cc: roland-BHEL68pLQRGGvPXPguhicg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
divy-ut6Up61K2wZBDgjK7y7TUQ, dm-ut6Up61K2wZBDgjK7y7TUQ,
kumaras-ut6Up61K2wZBDgjK7y7TUQ,
swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW,
abhishek-ut6Up61K2wZBDgjK7y7TUQ, Vipul Pandya
In-Reply-To: <1354277370-8727-1-git-send-email-vipul-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
It supports establishing passive open connection through firmware filter work
request. Passive open connection will go through this path as now instead of
listening server we create a server filter which will redirect the incoming SYN
packet to the offload queue.
It divides filter region into regular filters and server filter portion. It
introduces new server filter region which will be exclusively used for creating
server filters. This region will not overlap with regular filter region.
It provides new API cxgb4_alloc_sftid in LLD for getting stid in case of LE
hash collision path. This new stid will be used to open server filter in the
filter region.
Signed-off-by: Vipul Pandya <vipul-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
---
V2: Changed commenting style from kernel-doc format('/**') to normal
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 4 +
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 150 +++++++++++++++++++++-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 15 ++-
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 33 +++++
4 files changed, 193 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index b6403d1..868acde 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -35,6 +35,8 @@
#ifndef __CXGB4_H__
#define __CXGB4_H__
+#include "t4_hw.h"
+
#include <linux/bitops.h>
#include <linux/cache.h>
#include <linux/interrupt.h>
@@ -212,6 +214,8 @@ struct tp_err_stats {
struct tp_params {
unsigned int ntxchan; /* # of Tx channels */
unsigned int tre; /* log2 of core clocks per TP tick */
+ unsigned short tx_modq_map; /* TX modulation scheduler queue to */
+ /* channel map */
uint32_t dack_re; /* DACK timer resolution */
unsigned short tx_modq[NCHAN]; /* channel to modulation queue map */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index a678287..f55386b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2489,7 +2489,34 @@ int cxgb4_alloc_stid(struct tid_info *t, int family, void *data)
EXPORT_SYMBOL(cxgb4_alloc_stid);
/*
- * Release a server TID.
+ * Allocate a server filter TID and set it to the supplied value.
+ */
+int cxgb4_alloc_sftid(struct tid_info *t, int family, void *data)
+{
+ int stid;
+
+ spin_lock_bh(&t->stid_lock);
+ if (family == PF_INET) {
+ stid = find_next_zero_bit(t->stid_bmap,
+ t->nstids + t->nsftids, t->nstids);
+ if (stid < (t->nstids + t->nsftids))
+ __set_bit(stid, t->stid_bmap);
+ else
+ stid = -1;
+ } else {
+ stid = -1;
+ }
+ if (stid >= 0) {
+ t->stid_tab[stid].data = data;
+ stid += t->stid_base;
+ t->stids_in_use++;
+ }
+ spin_unlock_bh(&t->stid_lock);
+ return stid;
+}
+EXPORT_SYMBOL(cxgb4_alloc_sftid);
+
+/* Release a server TID.
*/
void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family)
{
@@ -2604,12 +2631,14 @@ static int tid_init(struct tid_info *t)
unsigned int stid_bmap_size;
unsigned int natids = t->natids;
- stid_bmap_size = BITS_TO_LONGS(t->nstids);
+ stid_bmap_size = BITS_TO_LONGS(t->nstids + t->nsftids);
size = t->ntids * sizeof(*t->tid_tab) +
natids * sizeof(*t->atid_tab) +
t->nstids * sizeof(*t->stid_tab) +
+ t->nsftids * sizeof(*t->stid_tab) +
stid_bmap_size * sizeof(long) +
- t->nftids * sizeof(*t->ftid_tab);
+ t->nftids * sizeof(*t->ftid_tab) +
+ t->nsftids * sizeof(*t->ftid_tab);
t->tid_tab = t4_alloc_mem(size);
if (!t->tid_tab)
@@ -2617,7 +2646,7 @@ static int tid_init(struct tid_info *t)
t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids];
t->stid_tab = (struct serv_entry *)&t->atid_tab[natids];
- t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids];
+ t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids + t->nsftids];
t->ftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size];
spin_lock_init(&t->stid_lock);
spin_lock_init(&t->atid_lock);
@@ -2633,7 +2662,7 @@ static int tid_init(struct tid_info *t)
t->atid_tab[natids - 1].next = &t->atid_tab[natids];
t->afree = t->atid_tab;
}
- bitmap_zero(t->stid_bmap, t->nstids);
+ bitmap_zero(t->stid_bmap, t->nstids + t->nsftids);
return 0;
}
@@ -2995,6 +3024,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
{
void *handle;
struct cxgb4_lld_info lli;
+ unsigned short i;
lli.pdev = adap->pdev;
lli.l2t = adap->l2t;
@@ -3021,10 +3051,16 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET(
t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >>
(adap->fn * 4));
+ lli.filt_mode = tp_vlan_pri_map;
+ /* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */
+ for (i = 0; i < NCHAN; i++)
+ lli.tx_modq[i] = i;
lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS);
lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL);
lli.fw_vers = adap->params.fw_vers;
lli.dbfifo_int_thresh = dbfifo_int_thresh;
+ lli.sge_pktshift = adap->sge.pktshift;
+ lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN;
handle = ulds[uld].add(&lli);
if (IS_ERR(handle)) {
@@ -3266,7 +3302,7 @@ static int delete_filter(struct adapter *adapter, unsigned int fidx)
struct filter_entry *f;
int ret;
- if (fidx >= adapter->tids.nftids)
+ if (fidx >= adapter->tids.nftids + adapter->tids.nsftids)
return -EINVAL;
f = &adapter->tids.ftid_tab[fidx];
@@ -3279,6 +3315,77 @@ static int delete_filter(struct adapter *adapter, unsigned int fidx)
return 0;
}
+int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
+ __be32 sip, __be16 sport, unsigned int queue)
+{
+ int ret;
+ struct filter_entry *f;
+ struct adapter *adap;
+ int i;
+ u8 *val;
+
+ adap = netdev2adap(dev);
+
+ /* Check to make sure the filter requested is writable ...
+ */
+ f = &adap->tids.ftid_tab[stid];
+ ret = writable_filter(f);
+ if (ret)
+ return ret;
+
+ /* Clear out any old resources being used by the filter before
+ * we start constructing the new filter.
+ */
+ if (f->valid)
+ clear_filter(adap, f);
+
+ /* Clear out filter specifications */
+ memset(&f->fs, 0, sizeof(struct ch_filter_specification));
+ f->fs.val.lport = cpu_to_be16(sport);
+ f->fs.mask.lport = ~0;
+ val = (u8 *)&sip;
+ if ((val[0] | val[1] | val[2] | val[3]) != 0)
+ for (i = 0; i < 4; i++) {
+ f->fs.val.lip[i] = val[i];
+ f->fs.mask.lip[i] = ~0;
+ }
+
+ f->fs.dirsteer = 1;
+ f->fs.iq = queue;
+ /* Mark filter as locked */
+ f->locked = 1;
+ f->fs.rpttid = 1;
+
+ ret = set_filter_wr(adap, stid);
+ if (ret) {
+ clear_filter(adap, f);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(cxgb4_create_server_filter);
+
+int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
+ unsigned int queue, bool ipv6)
+{
+ int ret;
+ struct filter_entry *f;
+ struct adapter *adap;
+
+ adap = netdev2adap(dev);
+ f = &adap->tids.ftid_tab[stid];
+ /* Unlock the filter */
+ f->locked = 0;
+
+ ret = delete_filter(adap, stid);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(cxgb4_remove_server_filter);
+
static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev,
struct rtnl_link_stats64 *ns)
{
@@ -3525,6 +3632,34 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
v = t4_read_reg(adap, TP_PIO_DATA);
t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR);
+ /* first 4 Tx modulation queues point to consecutive Tx channels */
+ adap->params.tp.tx_modq_map = 0xE4;
+ t4_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
+ V_TX_MOD_QUEUE_REQ_MAP(adap->params.tp.tx_modq_map));
+
+ /* associate each Tx modulation queue with consecutive Tx channels */
+ v = 0x84218421;
+ t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+ &v, 1, A_TP_TX_SCHED_HDR);
+ t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+ &v, 1, A_TP_TX_SCHED_FIFO);
+ t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+ &v, 1, A_TP_TX_SCHED_PCMD);
+
+#define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */
+ if (is_offload(adap)) {
+ t4_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0,
+ V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
+ t4_write_reg(adap, A_TP_TX_MOD_CHANNEL_WEIGHT,
+ V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
+ }
+
/* get basic stuff going */
return t4_early_init(adap, adap->fn);
}
@@ -4948,7 +5083,8 @@ static void __devexit remove_one(struct pci_dev *pdev)
*/
if (adapter->tids.ftid_tab) {
struct filter_entry *f = &adapter->tids.ftid_tab[0];
- for (i = 0; i < adapter->tids.nftids; i++, f++)
+ for (i = 0; i < (adapter->tids.nftids +
+ adapter->tids.nsftids); i++, f++)
if (f->valid)
clear_filter(adapter, f);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 59a6133..065bbd5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -131,7 +131,7 @@ static inline void *lookup_atid(const struct tid_info *t, unsigned int atid)
static inline void *lookup_stid(const struct tid_info *t, unsigned int stid)
{
stid -= t->stid_base;
- return stid < t->nstids ? t->stid_tab[stid].data : NULL;
+ return stid < (t->nstids + t->nsftids) ? t->stid_tab[stid].data : NULL;
}
static inline void cxgb4_insert_tid(struct tid_info *t, void *data,
@@ -143,6 +143,7 @@ static inline void cxgb4_insert_tid(struct tid_info *t, void *data,
int cxgb4_alloc_atid(struct tid_info *t, void *data);
int cxgb4_alloc_stid(struct tid_info *t, int family, void *data);
+int cxgb4_alloc_sftid(struct tid_info *t, int family, void *data);
void cxgb4_free_atid(struct tid_info *t, unsigned int atid);
void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family);
void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid);
@@ -151,7 +152,10 @@ struct in6_addr;
int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
__be32 sip, __be16 sport, unsigned int queue);
-
+int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
+ __be32 sip, __be16 sport, unsigned int queue);
+int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
+ unsigned int queue, bool ipv6);
static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue)
{
skb_set_queue_mapping(skb, (queue << 1) | prio);
@@ -223,9 +227,16 @@ struct cxgb4_lld_info {
unsigned int iscsi_iolen; /* iSCSI max I/O length */
unsigned short udb_density; /* # of user DB/page */
unsigned short ucq_density; /* # of user CQs/page */
+ unsigned short filt_mode; /* filter optional components */
+ unsigned short tx_modq[NCHAN]; /* maps each tx channel to a */
+ /* scheduler queue */
void __iomem *gts_reg; /* address of GTS register */
void __iomem *db_reg; /* address of kernel doorbell */
int dbfifo_int_thresh; /* doorbell fifo int threshold */
+ unsigned int sge_pktshift; /* Padding between CPL and */
+ /* packet data */
+ bool enable_fw_ofld_conn; /* Enable connection through fw */
+ /* WR */
};
struct cxgb4_uld_info {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index a1a8b57..66ab614 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -1032,4 +1032,37 @@
#define ADDRESS(x) ((x) << ADDRESS_SHIFT)
#define XGMAC_PORT_INT_CAUSE 0x10dc
+
+#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x7e28
+
+#define A_TP_TX_MOD_CHANNEL_WEIGHT 0x7e34
+
+#define S_TX_MOD_QUEUE_REQ_MAP 0
+#define M_TX_MOD_QUEUE_REQ_MAP 0xffffU
+#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x7e30
+
+#define S_TX_MODQ_WEIGHT3 24
+#define M_TX_MODQ_WEIGHT3 0xffU
+#define V_TX_MODQ_WEIGHT3(x) ((x) << S_TX_MODQ_WEIGHT3)
+
+#define S_TX_MODQ_WEIGHT2 16
+#define M_TX_MODQ_WEIGHT2 0xffU
+#define V_TX_MODQ_WEIGHT2(x) ((x) << S_TX_MODQ_WEIGHT2)
+
+#define S_TX_MODQ_WEIGHT1 8
+#define M_TX_MODQ_WEIGHT1 0xffU
+#define V_TX_MODQ_WEIGHT1(x) ((x) << S_TX_MODQ_WEIGHT1)
+
+#define S_TX_MODQ_WEIGHT0 0
+#define M_TX_MODQ_WEIGHT0 0xffU
+#define V_TX_MODQ_WEIGHT0(x) ((x) << S_TX_MODQ_WEIGHT0)
+
+#define A_TP_TX_SCHED_HDR 0x23
+
+#define A_TP_TX_SCHED_FIFO 0x24
+
+#define A_TP_TX_SCHED_PCMD 0x25
+
#endif /* __T4_REGS_H */
--
1.7.1
--
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 related
* [PATCH V2 1/5] cxgb4: Add T4 filter support
From: Vipul Pandya @ 2012-11-30 12:09 UTC (permalink / raw)
To: linux-rdma-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
Cc: roland-BHEL68pLQRGGvPXPguhicg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
divy-ut6Up61K2wZBDgjK7y7TUQ, dm-ut6Up61K2wZBDgjK7y7TUQ,
kumaras-ut6Up61K2wZBDgjK7y7TUQ,
swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW,
abhishek-ut6Up61K2wZBDgjK7y7TUQ, Vipul Pandya
The T4 architecture is capable of filtering ingress packets at line rate
using the rule in TCAM. If packet hits a rule in the TCAM then it can be either
dropped or passed to the receive queues based on a rule settings.
This patch adds framework for managing filters and to use T4's filter
capabilities. It constructs a Firmware Filter Work Request which writes the
filter at a specified index to get the work done. It hosts shadow copy of
ingress filter entry to check field size limitations and save memory in the
case where the filter table is large.
Signed-off-by: Vipul Pandya <vipul-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
---
V2: Changed commenting style from kernel-doc format('/**') to normal
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 134 ++++++++++
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 301 ++++++++++++++++++++++-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 2 +
drivers/net/ethernet/chelsio/cxgb4/l2t.c | 33 +++
drivers/net/ethernet/chelsio/cxgb4/l2t.h | 3 +
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 23 ++-
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 1 +
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 279 +++++++++++++++++++++
8 files changed, 770 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 378988b..b6403d1 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -545,6 +545,132 @@ struct adapter {
spinlock_t stats_lock;
};
+/*
+ * Defined bit width of user definable filter tuples
+ */
+#define ETHTYPE_BITWIDTH 16
+#define FRAG_BITWIDTH 1
+#define MACIDX_BITWIDTH 9
+#define FCOE_BITWIDTH 1
+#define IPORT_BITWIDTH 3
+#define MATCHTYPE_BITWIDTH 3
+#define PROTO_BITWIDTH 8
+#define TOS_BITWIDTH 8
+#define PF_BITWIDTH 8
+#define VF_BITWIDTH 8
+#define IVLAN_BITWIDTH 16
+#define OVLAN_BITWIDTH 16
+
+/* Filter matching rules. These consist of a set of ingress packet field
+ * (value, mask) tuples. The associated ingress packet field matches the
+ * tuple when ((field & mask) == value). (Thus a wildcard "don't care" field
+ * rule can be constructed by specifying a tuple of (0, 0).) A filter rule
+ * matches an ingress packet when all of the individual individual field
+ * matching rules are true.
+ *
+ * Partial field masks are always valid, however, while it may be easy to
+ * understand their meanings for some fields (e.g. IP address to match a
+ * subnet), for others making sensible partial masks is less intuitive (e.g.
+ * MPS match type) ...
+ *
+ * Most of the following data structures are modeled on T4 capabilities.
+ * Drivers for earlier chips use the subsets which make sense for those chips.
+ * We really need to come up with a hardware-independent mechanism to
+ * represent hardware filter capabilities ...
+ */
+struct ch_filter_tuple {
+ /*
+ * Compressed header matching field rules. The TP_VLAN_PRI_MAP
+ * register selects which of these fields will participate in the
+ * filter match rules -- up to a maximum of 36 bits. Because
+ * TP_VLAN_PRI_MAP is a global register, all filters must use the same
+ * set of fields.
+ */
+ uint32_t ethtype:ETHTYPE_BITWIDTH; /* Ethernet type */
+ uint32_t frag:FRAG_BITWIDTH; /* IP fragmentation header */
+ uint32_t ivlan_vld:1; /* inner VLAN valid */
+ uint32_t ovlan_vld:1; /* outer VLAN valid */
+ uint32_t pfvf_vld:1; /* PF/VF valid */
+ uint32_t macidx:MACIDX_BITWIDTH; /* exact match MAC index */
+ uint32_t fcoe:FCOE_BITWIDTH; /* FCoE packet */
+ uint32_t iport:IPORT_BITWIDTH; /* ingress port */
+ uint32_t matchtype:MATCHTYPE_BITWIDTH; /* MPS match type */
+ uint32_t proto:PROTO_BITWIDTH; /* protocol type */
+ uint32_t tos:TOS_BITWIDTH; /* TOS/Traffic Type */
+ uint32_t pf:PF_BITWIDTH; /* PCI-E PF ID */
+ uint32_t vf:VF_BITWIDTH; /* PCI-E VF ID */
+ uint32_t ivlan:IVLAN_BITWIDTH; /* inner VLAN */
+ uint32_t ovlan:OVLAN_BITWIDTH; /* outer VLAN */
+
+ /* Uncompressed header matching field rules. These are always
+ * available for field rules.
+ */
+ uint8_t lip[16]; /* local IP address (IPv4 in [3:0]) */
+ uint8_t fip[16]; /* foreign IP address (IPv4 in [3:0]) */
+ uint16_t lport; /* local port */
+ uint16_t fport; /* foreign port */
+};
+
+/* A filter ioctl command.
+ */
+struct ch_filter_specification {
+ /*
+ * Administrative fields for filter.
+ */
+ uint32_t hitcnts:1; /* count filter hits in TCB */
+ uint32_t prio:1; /* filter has priority over active/server */
+
+ /* Fundamental filter typing. This is the one element of filter
+ * matching that doesn't exist as a (value, mask) tuple.
+ */
+ uint32_t type:1; /* 0 => IPv4, 1 => IPv6 */
+
+ /* Packet dispatch information. Ingress packets which match the
+ * filter rules will be dropped, passed to the host or switched back
+ * out as egress packets.
+ */
+ uint32_t action:2; /* drop, pass, switch */
+
+ uint32_t rpttid:1; /* report TID in RSS hash field */
+
+ uint32_t dirsteer:1; /* 0 => RSS, 1 => steer to iq */
+ uint32_t iq:10; /* ingress queue */
+
+ uint32_t maskhash:1; /* dirsteer=0: store RSS hash in TCB */
+ uint32_t dirsteerhash:1;/* dirsteer=1: 0 => TCB contains RSS hash */
+ /* 1 => TCB contains IQ ID */
+
+ /* Switch proxy/rewrite fields. An ingress packet which matches a
+ * filter with "switch" set will be looped back out as an egress
+ * packet -- potentially with some Ethernet header rewriting.
+ */
+ uint32_t eport:2; /* egress port to switch packet out */
+ uint32_t newdmac:1; /* rewrite destination MAC address */
+ uint32_t newsmac:1; /* rewrite source MAC address */
+ uint32_t newvlan:2; /* rewrite VLAN Tag */
+ uint8_t dmac[ETH_ALEN]; /* new destination MAC address */
+ uint8_t smac[ETH_ALEN]; /* new source MAC address */
+ uint16_t vlan; /* VLAN Tag to insert */
+
+ /* Filter rule value/mask pairs.
+ */
+ struct ch_filter_tuple val;
+ struct ch_filter_tuple mask;
+};
+
+enum {
+ FILTER_PASS = 0, /* default */
+ FILTER_DROP,
+ FILTER_SWITCH
+};
+
+enum {
+ VLAN_NOCHANGE = 0, /* default */
+ VLAN_REMOVE,
+ VLAN_INSERT,
+ VLAN_REWRITE
+};
+
static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr)
{
return readl(adap->regs + reg_addr);
@@ -701,6 +827,12 @@ static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd,
void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
unsigned int data_reg, const u32 *vals,
unsigned int nregs, unsigned int start_idx);
+void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
+ unsigned int data_reg, u32 *vals, unsigned int nregs,
+ unsigned int start_idx);
+
+struct fw_filter_wr;
+
void t4_intr_enable(struct adapter *adapter);
void t4_intr_disable(struct adapter *adapter);
int t4_slow_intr_handler(struct adapter *adapter);
@@ -737,6 +869,8 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
const unsigned short *alpha, const unsigned short *beta);
+void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid);
+
void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
const u8 *addr);
int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 0df1284..a678287 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -175,6 +175,32 @@ enum {
MIN_FL_ENTRIES = 16
};
+/*
+ * Host shadow copy of ingress filter entry. This is in host native format
+ * and doesn't match the ordering or bit order, etc. of the hardware of the
+ * firmware command. The use of bit-field structure elements is purely to
+ * remind ourselves of the field size limitations and save memory in the case
+ * where the filter table is large.
+ */
+struct filter_entry {
+ /*
+ * Administrative fields for filter.
+ */
+ u32 valid:1; /* filter allocated and valid */
+ u32 locked:1; /* filter is administratively locked */
+
+ u32 pending:1; /* filter action is pending firmware reply */
+ u32 smtidx:8; /* Source MAC Table index for smac */
+ struct l2t_entry *l2t; /* Layer Two Table entry for dmac */
+
+ /* The filter itself. Most of this is a straight copy of information
+ * provided by the extended ioctl(). Some fields are translated to
+ * internal forms -- for instance the Ingress Queue ID passed in from
+ * the ioctl() is translated into the Absolute Ingress Queue ID.
+ */
+ struct ch_filter_specification fs;
+};
+
#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -325,6 +351,9 @@ enum {
static unsigned int tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT;
+module_param(tp_vlan_pri_map, uint, 0644);
+MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration");
+
static struct dentry *cxgb4_debugfs_root;
static LIST_HEAD(adapter_list);
@@ -507,7 +536,70 @@ static int link_start(struct net_device *dev)
}
/*
- * Response queue handler for the FW event queue.
+ * Clear a filter and release any of its resources that we own. This also
+ * clears the filter's "pending" status.
+ */
+static void clear_filter(struct adapter *adap, struct filter_entry *f)
+{
+ /*
+ * If the new or old filter have loopback rewriteing rules then we'll
+ * need to free any existing Layer Two Table (L2T) entries of the old
+ * filter rule. The firmware will handle freeing up any Source MAC
+ * Table (SMT) entries used for rewriting Source MAC Addresses in
+ * loopback rules.
+ */
+ if (f->l2t)
+ cxgb4_l2t_release(f->l2t);
+
+ /* The zeroing of the filter rule below clears the filter valid,
+ * pending, locked flags, l2t pointer, etc. so it's all we need for
+ * this operation.
+ */
+ memset(f, 0, sizeof(*f));
+}
+
+/* Handle a filter write/deletion reply.
+ */
+static void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
+{
+ unsigned int idx = GET_TID(rpl);
+ unsigned int nidx = idx - adap->tids.ftid_base;
+ unsigned int ret;
+ struct filter_entry *f;
+
+ if (idx >= adap->tids.ftid_base && nidx <
+ (adap->tids.nftids + adap->tids.nsftids)) {
+ idx = nidx;
+ ret = GET_TCB_COOKIE(rpl->cookie);
+ f = &adap->tids.ftid_tab[idx];
+
+ if (ret == FW_FILTER_WR_FLT_DELETED) {
+ /*
+ * Clear the filter when we get confirmation from the
+ * hardware that the filter has been deleted.
+ */
+ clear_filter(adap, f);
+ } else if (ret == FW_FILTER_WR_SMT_TBL_FULL) {
+ dev_err(adap->pdev_dev, "filter %u setup failed due to full SMT\n",
+ idx);
+ clear_filter(adap, f);
+ } else if (ret == FW_FILTER_WR_FLT_ADDED) {
+ f->smtidx = (be64_to_cpu(rpl->oldval) >> 24) & 0xff;
+ f->pending = 0; /* asynchronous setup completed */
+ f->valid = 1;
+ } else {
+ /*
+ * Something went wrong. Issue a warning about the
+ * problem and clear everything out.
+ */
+ dev_err(adap->pdev_dev, "filter %u setup failed with error %u\n",
+ idx, ret);
+ clear_filter(adap, f);
+ }
+ }
+}
+
+/* Response queue handler for the FW event queue.
*/
static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
const struct pkt_gl *gl)
@@ -542,6 +634,10 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
const struct cpl_l2t_write_rpl *p = (void *)rsp;
do_l2t_write_rpl(q->adap, p);
+ } else if (opcode == CPL_SET_TCB_RPL) {
+ const struct cpl_set_tcb_rpl *p = (void *)rsp;
+
+ filter_rpl(q->adap, p);
} else
dev_err(q->adap->pdev_dev,
"unexpected CPL %#x on FW event queue\n", opcode);
@@ -983,6 +1079,149 @@ static void t4_free_mem(void *addr)
kfree(addr);
}
+/*
+ * Send a Work Request to write the filter at a specified index. We construct
+ * a Firmware Filter Work Request to have the work done and put the indicated
+ * filter into "pending" mode which will prevent any further actions against
+ * it till we get a reply from the firmware on the completion status of the
+ * request.
+ */
+static int set_filter_wr(struct adapter *adapter, int fidx)
+{
+ struct filter_entry *f = &adapter->tids.ftid_tab[fidx];
+ struct sk_buff *skb;
+ struct fw_filter_wr *fwr;
+ unsigned int ftid;
+
+ /* If the new filter requires loopback Destination MAC and/or VLAN
+ * rewriting then we need to allocate a Layer 2 Table (L2T) entry for
+ * the filter.
+ */
+ if (f->fs.newdmac || f->fs.newvlan) {
+ /* allocate L2T entry for new filter */
+ f->l2t = t4_l2t_alloc_switching(adapter->l2t);
+ if (f->l2t == NULL)
+ return -EAGAIN;
+ if (t4_l2t_set_switching(adapter, f->l2t, f->fs.vlan,
+ f->fs.eport, f->fs.dmac)) {
+ cxgb4_l2t_release(f->l2t);
+ f->l2t = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ ftid = adapter->tids.ftid_base + fidx;
+
+ skb = alloc_skb(sizeof(*fwr), GFP_KERNEL | __GFP_NOFAIL);
+ fwr = (struct fw_filter_wr *)__skb_put(skb, sizeof(*fwr));
+ memset(fwr, 0, sizeof(*fwr));
+
+ /* It would be nice to put most of the following in t4_hw.c but most
+ * of the work is translating the cxgbtool ch_filter_specification
+ * into the Work Request and the definition of that structure is
+ * currently in cxgbtool.h which isn't appropriate to pull into the
+ * common code. We may eventually try to come up with a more neutral
+ * filter specification structure but for now it's easiest to simply
+ * put this fairly direct code in line ...
+ */
+ fwr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
+ fwr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*fwr)/16));
+ fwr->tid_to_iq =
+ htonl(V_FW_FILTER_WR_TID(ftid) |
+ V_FW_FILTER_WR_RQTYPE(f->fs.type) |
+ V_FW_FILTER_WR_NOREPLY(0) |
+ V_FW_FILTER_WR_IQ(f->fs.iq));
+ fwr->del_filter_to_l2tix =
+ htonl(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) |
+ V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) |
+ V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) |
+ V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) |
+ V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) |
+ V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) |
+ V_FW_FILTER_WR_DMAC(f->fs.newdmac) |
+ V_FW_FILTER_WR_SMAC(f->fs.newsmac) |
+ V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT ||
+ f->fs.newvlan == VLAN_REWRITE) |
+ V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE ||
+ f->fs.newvlan == VLAN_REWRITE) |
+ V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
+ V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
+ V_FW_FILTER_WR_PRIO(f->fs.prio) |
+ V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
+ fwr->ethtype = htons(f->fs.val.ethtype);
+ fwr->ethtypem = htons(f->fs.mask.ethtype);
+ fwr->frag_to_ovlan_vldm =
+ (V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
+ V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
+ V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.ivlan_vld) |
+ V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.ovlan_vld) |
+ V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.ivlan_vld) |
+ V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.ovlan_vld));
+ fwr->smac_sel = 0;
+ fwr->rx_chan_rx_rpl_iq =
+ htons(V_FW_FILTER_WR_RX_CHAN(0) |
+ V_FW_FILTER_WR_RX_RPL_IQ(adapter->sge.fw_evtq.abs_id));
+ fwr->maci_to_matchtypem =
+ htonl(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
+ V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
+ V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) |
+ V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) |
+ V_FW_FILTER_WR_PORT(f->fs.val.iport) |
+ V_FW_FILTER_WR_PORTM(f->fs.mask.iport) |
+ V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) |
+ V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype));
+ fwr->ptcl = f->fs.val.proto;
+ fwr->ptclm = f->fs.mask.proto;
+ fwr->ttyp = f->fs.val.tos;
+ fwr->ttypm = f->fs.mask.tos;
+ fwr->ivlan = htons(f->fs.val.ivlan);
+ fwr->ivlanm = htons(f->fs.mask.ivlan);
+ fwr->ovlan = htons(f->fs.val.ovlan);
+ fwr->ovlanm = htons(f->fs.mask.ovlan);
+ memcpy(fwr->lip, f->fs.val.lip, sizeof(fwr->lip));
+ memcpy(fwr->lipm, f->fs.mask.lip, sizeof(fwr->lipm));
+ memcpy(fwr->fip, f->fs.val.fip, sizeof(fwr->fip));
+ memcpy(fwr->fipm, f->fs.mask.fip, sizeof(fwr->fipm));
+ fwr->lp = htons(f->fs.val.lport);
+ fwr->lpm = htons(f->fs.mask.lport);
+ fwr->fp = htons(f->fs.val.fport);
+ fwr->fpm = htons(f->fs.mask.fport);
+ if (f->fs.newsmac)
+ memcpy(fwr->sma, f->fs.smac, sizeof(fwr->sma));
+
+ /* Mark the filter as "pending" and ship off the Filter Work Request.
+ * When we get the Work Request Reply we'll clear the pending status.
+ */
+ f->pending = 1;
+ set_wr_txq(skb, CPL_PRIORITY_CONTROL, f->fs.val.iport & 0x3);
+ t4_ofld_send(adapter, skb);
+ return 0;
+}
+
+/* Delete the filter at a specified index.
+ */
+static int del_filter_wr(struct adapter *adapter, int fidx)
+{
+ struct filter_entry *f = &adapter->tids.ftid_tab[fidx];
+ struct sk_buff *skb;
+ struct fw_filter_wr *fwr;
+ unsigned int len, ftid;
+
+ len = sizeof(*fwr);
+ ftid = adapter->tids.ftid_base + fidx;
+
+ skb = alloc_skb(len, GFP_KERNEL | __GFP_NOFAIL);
+ fwr = (struct fw_filter_wr *)__skb_put(skb, len);
+ t4_mk_filtdelwr(ftid, fwr, adapter->sge.fw_evtq.abs_id);
+
+ /* Mark the filter as "pending" and ship off the Filter Work Request.
+ * When we get the Work Request Reply we'll clear the pending status.
+ */
+ f->pending = 1;
+ t4_mgmt_tx(adapter, skb);
+ return 0;
+}
+
static inline int is_offload(const struct adapter *adap)
{
return adap->params.offload;
@@ -2195,7 +2434,7 @@ int cxgb4_alloc_atid(struct tid_info *t, void *data)
if (t->afree) {
union aopen_entry *p = t->afree;
- atid = p - t->atid_tab;
+ atid = (p - t->atid_tab) + t->atid_base;
t->afree = p->next;
p->data = data;
t->atids_in_use++;
@@ -2210,7 +2449,7 @@ EXPORT_SYMBOL(cxgb4_alloc_atid);
*/
void cxgb4_free_atid(struct tid_info *t, unsigned int atid)
{
- union aopen_entry *p = &t->atid_tab[atid];
+ union aopen_entry *p = &t->atid_tab[atid - t->atid_base];
spin_lock_bh(&t->atid_lock);
p->next = t->afree;
@@ -2362,11 +2601,16 @@ EXPORT_SYMBOL(cxgb4_remove_tid);
static int tid_init(struct tid_info *t)
{
size_t size;
+ unsigned int stid_bmap_size;
unsigned int natids = t->natids;
- size = t->ntids * sizeof(*t->tid_tab) + natids * sizeof(*t->atid_tab) +
+ stid_bmap_size = BITS_TO_LONGS(t->nstids);
+ size = t->ntids * sizeof(*t->tid_tab) +
+ natids * sizeof(*t->atid_tab) +
t->nstids * sizeof(*t->stid_tab) +
- BITS_TO_LONGS(t->nstids) * sizeof(long);
+ stid_bmap_size * sizeof(long) +
+ t->nftids * sizeof(*t->ftid_tab);
+
t->tid_tab = t4_alloc_mem(size);
if (!t->tid_tab)
return -ENOMEM;
@@ -2374,6 +2618,7 @@ static int tid_init(struct tid_info *t)
t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids];
t->stid_tab = (struct serv_entry *)&t->atid_tab[natids];
t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids];
+ t->ftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size];
spin_lock_init(&t->stid_lock);
spin_lock_init(&t->atid_lock);
@@ -2999,6 +3244,41 @@ static int cxgb_close(struct net_device *dev)
return t4_enable_vi(adapter, adapter->fn, pi->viid, false, false);
}
+/*
+ * Return an error number if the indicated filter isn't writable ...
+ */
+static int writable_filter(struct filter_entry *f)
+{
+ if (f->locked)
+ return -EPERM;
+ if (f->pending)
+ return -EBUSY;
+
+ return 0;
+}
+
+/* Delete the filter at the specified index (if valid). The checks for all
+ * the common problems with doing this like the filter being locked, currently
+ * pending in another operation, etc.
+ */
+static int delete_filter(struct adapter *adapter, unsigned int fidx)
+{
+ struct filter_entry *f;
+ int ret;
+
+ if (fidx >= adapter->tids.nftids)
+ return -EINVAL;
+
+ f = &adapter->tids.ftid_tab[fidx];
+ ret = writable_filter(f);
+ if (ret)
+ return ret;
+ if (f->valid)
+ return del_filter_wr(adapter, fidx);
+
+ return 0;
+}
+
static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev,
struct rtnl_link_stats64 *ns)
{
@@ -4662,6 +4942,17 @@ static void __devexit remove_one(struct pci_dev *pdev)
if (adapter->debugfs_root)
debugfs_remove_recursive(adapter->debugfs_root);
+ /*
+ * If we allocated filters, free up state associated with any
+ * valid filters ...
+ */
+ if (adapter->tids.ftid_tab) {
+ struct filter_entry *f = &adapter->tids.ftid_tab[0];
+ for (i = 0; i < adapter->tids.nftids; i++, f++)
+ if (f->valid)
+ clear_filter(adapter, f);
+ }
+
if (adapter->flags & FULL_INIT_DONE)
cxgb_down(adapter);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 39bec73..59a6133 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -97,7 +97,9 @@ struct tid_info {
union aopen_entry *atid_tab;
unsigned int natids;
+ unsigned int atid_base;
+ struct filter_entry *ftid_tab;
unsigned int nftids;
unsigned int ftid_base;
unsigned int aftid_base;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
index 6ac77a6..18ca67f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
@@ -484,6 +484,39 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
handle_failed_resolution(adap, arpq);
}
+/*
+ * Allocate an L2T entry for use by a switching rule. Such need to be
+ * explicitly freed and while busy they are not on any hash chain, so normal
+ * address resolution updates do not see them.
+ */
+struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d)
+{
+ struct l2t_entry *e;
+
+ write_lock_bh(&d->lock);
+ e = alloc_l2e(d);
+ if (e) {
+ spin_lock(&e->lock); /* avoid race with t4_l2t_free */
+ e->state = L2T_STATE_SWITCHING;
+ atomic_set(&e->refcnt, 1);
+ spin_unlock(&e->lock);
+ }
+ write_unlock_bh(&d->lock);
+ return e;
+}
+
+/* Sets/updates the contents of a switching L2T entry that has been allocated
+ * with an earlier call to @t4_l2t_alloc_switching.
+ */
+int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
+ u8 port, u8 *eth_addr)
+{
+ e->vlan = vlan;
+ e->lport = port;
+ memcpy(e->dmac, eth_addr, ETH_ALEN);
+ return write_l2e(adap, e, 0);
+}
+
struct l2t_data *t4_init_l2t(void)
{
int i;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h
index 02b31d0..108c0f1 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/l2t.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h
@@ -100,6 +100,9 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh,
unsigned int priority);
void t4_l2t_update(struct adapter *adap, struct neighbour *neigh);
+struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d);
+int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
+ u8 port, u8 *eth_addr);
struct l2t_data *t4_init_l2t(void);
void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 730ae2c..7638181 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -109,7 +109,7 @@ void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
* Reads registers that are accessed indirectly through an address/data
* register pair.
*/
-static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
+void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
unsigned int data_reg, u32 *vals,
unsigned int nregs, unsigned int start_idx)
{
@@ -2268,6 +2268,27 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
return 0;
}
+/*
+ * t4_mk_filtdelwr - create a delete filter WR
+ * @ftid: the filter ID
+ * @wr: the filter work request to populate
+ * @qid: ingress queue to receive the delete notification
+ *
+ * Creates a filter work request to delete the supplied filter. If @qid is
+ * negative the delete notification is suppressed.
+ */
+void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
+{
+ memset(wr, 0, sizeof(*wr));
+ wr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
+ wr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*wr) / 16));
+ wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) |
+ V_FW_FILTER_WR_NOREPLY(qid < 0));
+ wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER);
+ if (qid >= 0)
+ wr->rx_chan_rx_rpl_iq = htons(V_FW_FILTER_WR_RX_RPL_IQ(qid));
+}
+
#define INIT_CMD(var, cmd, rd_wr) do { \
(var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \
FW_CMD_REQUEST | FW_CMD_##rd_wr); \
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index eb71b82..480eb43 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -332,6 +332,7 @@ struct cpl_set_tcb_field {
__be16 word_cookie;
#define TCB_WORD(x) ((x) << 0)
#define TCB_COOKIE(x) ((x) << 5)
+#define GET_TCB_COOKIE(x) (((x) >> 5) & 7)
__be64 mask;
__be64 val;
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index a636463..b4dc560 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -35,6 +35,10 @@
#ifndef _T4FW_INTERFACE_H_
#define _T4FW_INTERFACE_H_
+enum fw_ret_val {
+ FW_ENOEXEC = 8, /* Exec format error; inv microcode */
+};
+
#define FW_T4VF_SGE_BASE_ADDR 0x0000
#define FW_T4VF_MPS_BASE_ADDR 0x0100
#define FW_T4VF_PL_BASE_ADDR 0x0200
@@ -81,6 +85,281 @@ struct fw_wr_hdr {
#define HW_TPL_FR_MT_PR_IV_P_FC 0X32B
+/* filter wr reply code in cookie in CPL_SET_TCB_RPL */
+enum fw_filter_wr_cookie {
+ FW_FILTER_WR_SUCCESS,
+ FW_FILTER_WR_FLT_ADDED,
+ FW_FILTER_WR_FLT_DELETED,
+ FW_FILTER_WR_SMT_TBL_FULL,
+ FW_FILTER_WR_EINVAL,
+};
+
+struct fw_filter_wr {
+ __be32 op_pkd;
+ __be32 len16_pkd;
+ __be64 r3;
+ __be32 tid_to_iq;
+ __be32 del_filter_to_l2tix;
+ __be16 ethtype;
+ __be16 ethtypem;
+ __u8 frag_to_ovlan_vldm;
+ __u8 smac_sel;
+ __be16 rx_chan_rx_rpl_iq;
+ __be32 maci_to_matchtypem;
+ __u8 ptcl;
+ __u8 ptclm;
+ __u8 ttyp;
+ __u8 ttypm;
+ __be16 ivlan;
+ __be16 ivlanm;
+ __be16 ovlan;
+ __be16 ovlanm;
+ __u8 lip[16];
+ __u8 lipm[16];
+ __u8 fip[16];
+ __u8 fipm[16];
+ __be16 lp;
+ __be16 lpm;
+ __be16 fp;
+ __be16 fpm;
+ __be16 r7;
+ __u8 sma[6];
+};
+
+#define S_FW_FILTER_WR_TID 12
+#define M_FW_FILTER_WR_TID 0xfffff
+#define V_FW_FILTER_WR_TID(x) ((x) << S_FW_FILTER_WR_TID)
+#define G_FW_FILTER_WR_TID(x) \
+ (((x) >> S_FW_FILTER_WR_TID) & M_FW_FILTER_WR_TID)
+
+#define S_FW_FILTER_WR_RQTYPE 11
+#define M_FW_FILTER_WR_RQTYPE 0x1
+#define V_FW_FILTER_WR_RQTYPE(x) ((x) << S_FW_FILTER_WR_RQTYPE)
+#define G_FW_FILTER_WR_RQTYPE(x) \
+ (((x) >> S_FW_FILTER_WR_RQTYPE) & M_FW_FILTER_WR_RQTYPE)
+#define F_FW_FILTER_WR_RQTYPE V_FW_FILTER_WR_RQTYPE(1U)
+
+#define S_FW_FILTER_WR_NOREPLY 10
+#define M_FW_FILTER_WR_NOREPLY 0x1
+#define V_FW_FILTER_WR_NOREPLY(x) ((x) << S_FW_FILTER_WR_NOREPLY)
+#define G_FW_FILTER_WR_NOREPLY(x) \
+ (((x) >> S_FW_FILTER_WR_NOREPLY) & M_FW_FILTER_WR_NOREPLY)
+#define F_FW_FILTER_WR_NOREPLY V_FW_FILTER_WR_NOREPLY(1U)
+
+#define S_FW_FILTER_WR_IQ 0
+#define M_FW_FILTER_WR_IQ 0x3ff
+#define V_FW_FILTER_WR_IQ(x) ((x) << S_FW_FILTER_WR_IQ)
+#define G_FW_FILTER_WR_IQ(x) \
+ (((x) >> S_FW_FILTER_WR_IQ) & M_FW_FILTER_WR_IQ)
+
+#define S_FW_FILTER_WR_DEL_FILTER 31
+#define M_FW_FILTER_WR_DEL_FILTER 0x1
+#define V_FW_FILTER_WR_DEL_FILTER(x) ((x) << S_FW_FILTER_WR_DEL_FILTER)
+#define G_FW_FILTER_WR_DEL_FILTER(x) \
+ (((x) >> S_FW_FILTER_WR_DEL_FILTER) & M_FW_FILTER_WR_DEL_FILTER)
+#define F_FW_FILTER_WR_DEL_FILTER V_FW_FILTER_WR_DEL_FILTER(1U)
+
+#define S_FW_FILTER_WR_RPTTID 25
+#define M_FW_FILTER_WR_RPTTID 0x1
+#define V_FW_FILTER_WR_RPTTID(x) ((x) << S_FW_FILTER_WR_RPTTID)
+#define G_FW_FILTER_WR_RPTTID(x) \
+ (((x) >> S_FW_FILTER_WR_RPTTID) & M_FW_FILTER_WR_RPTTID)
+#define F_FW_FILTER_WR_RPTTID V_FW_FILTER_WR_RPTTID(1U)
+
+#define S_FW_FILTER_WR_DROP 24
+#define M_FW_FILTER_WR_DROP 0x1
+#define V_FW_FILTER_WR_DROP(x) ((x) << S_FW_FILTER_WR_DROP)
+#define G_FW_FILTER_WR_DROP(x) \
+ (((x) >> S_FW_FILTER_WR_DROP) & M_FW_FILTER_WR_DROP)
+#define F_FW_FILTER_WR_DROP V_FW_FILTER_WR_DROP(1U)
+
+#define S_FW_FILTER_WR_DIRSTEER 23
+#define M_FW_FILTER_WR_DIRSTEER 0x1
+#define V_FW_FILTER_WR_DIRSTEER(x) ((x) << S_FW_FILTER_WR_DIRSTEER)
+#define G_FW_FILTER_WR_DIRSTEER(x) \
+ (((x) >> S_FW_FILTER_WR_DIRSTEER) & M_FW_FILTER_WR_DIRSTEER)
+#define F_FW_FILTER_WR_DIRSTEER V_FW_FILTER_WR_DIRSTEER(1U)
+
+#define S_FW_FILTER_WR_MASKHASH 22
+#define M_FW_FILTER_WR_MASKHASH 0x1
+#define V_FW_FILTER_WR_MASKHASH(x) ((x) << S_FW_FILTER_WR_MASKHASH)
+#define G_FW_FILTER_WR_MASKHASH(x) \
+ (((x) >> S_FW_FILTER_WR_MASKHASH) & M_FW_FILTER_WR_MASKHASH)
+#define F_FW_FILTER_WR_MASKHASH V_FW_FILTER_WR_MASKHASH(1U)
+
+#define S_FW_FILTER_WR_DIRSTEERHASH 21
+#define M_FW_FILTER_WR_DIRSTEERHASH 0x1
+#define V_FW_FILTER_WR_DIRSTEERHASH(x) ((x) << S_FW_FILTER_WR_DIRSTEERHASH)
+#define G_FW_FILTER_WR_DIRSTEERHASH(x) \
+ (((x) >> S_FW_FILTER_WR_DIRSTEERHASH) & M_FW_FILTER_WR_DIRSTEERHASH)
+#define F_FW_FILTER_WR_DIRSTEERHASH V_FW_FILTER_WR_DIRSTEERHASH(1U)
+
+#define S_FW_FILTER_WR_LPBK 20
+#define M_FW_FILTER_WR_LPBK 0x1
+#define V_FW_FILTER_WR_LPBK(x) ((x) << S_FW_FILTER_WR_LPBK)
+#define G_FW_FILTER_WR_LPBK(x) \
+ (((x) >> S_FW_FILTER_WR_LPBK) & M_FW_FILTER_WR_LPBK)
+#define F_FW_FILTER_WR_LPBK V_FW_FILTER_WR_LPBK(1U)
+
+#define S_FW_FILTER_WR_DMAC 19
+#define M_FW_FILTER_WR_DMAC 0x1
+#define V_FW_FILTER_WR_DMAC(x) ((x) << S_FW_FILTER_WR_DMAC)
+#define G_FW_FILTER_WR_DMAC(x) \
+ (((x) >> S_FW_FILTER_WR_DMAC) & M_FW_FILTER_WR_DMAC)
+#define F_FW_FILTER_WR_DMAC V_FW_FILTER_WR_DMAC(1U)
+
+#define S_FW_FILTER_WR_SMAC 18
+#define M_FW_FILTER_WR_SMAC 0x1
+#define V_FW_FILTER_WR_SMAC(x) ((x) << S_FW_FILTER_WR_SMAC)
+#define G_FW_FILTER_WR_SMAC(x) \
+ (((x) >> S_FW_FILTER_WR_SMAC) & M_FW_FILTER_WR_SMAC)
+#define F_FW_FILTER_WR_SMAC V_FW_FILTER_WR_SMAC(1U)
+
+#define S_FW_FILTER_WR_INSVLAN 17
+#define M_FW_FILTER_WR_INSVLAN 0x1
+#define V_FW_FILTER_WR_INSVLAN(x) ((x) << S_FW_FILTER_WR_INSVLAN)
+#define G_FW_FILTER_WR_INSVLAN(x) \
+ (((x) >> S_FW_FILTER_WR_INSVLAN) & M_FW_FILTER_WR_INSVLAN)
+#define F_FW_FILTER_WR_INSVLAN V_FW_FILTER_WR_INSVLAN(1U)
+
+#define S_FW_FILTER_WR_RMVLAN 16
+#define M_FW_FILTER_WR_RMVLAN 0x1
+#define V_FW_FILTER_WR_RMVLAN(x) ((x) << S_FW_FILTER_WR_RMVLAN)
+#define G_FW_FILTER_WR_RMVLAN(x) \
+ (((x) >> S_FW_FILTER_WR_RMVLAN) & M_FW_FILTER_WR_RMVLAN)
+#define F_FW_FILTER_WR_RMVLAN V_FW_FILTER_WR_RMVLAN(1U)
+
+#define S_FW_FILTER_WR_HITCNTS 15
+#define M_FW_FILTER_WR_HITCNTS 0x1
+#define V_FW_FILTER_WR_HITCNTS(x) ((x) << S_FW_FILTER_WR_HITCNTS)
+#define G_FW_FILTER_WR_HITCNTS(x) \
+ (((x) >> S_FW_FILTER_WR_HITCNTS) & M_FW_FILTER_WR_HITCNTS)
+#define F_FW_FILTER_WR_HITCNTS V_FW_FILTER_WR_HITCNTS(1U)
+
+#define S_FW_FILTER_WR_TXCHAN 13
+#define M_FW_FILTER_WR_TXCHAN 0x3
+#define V_FW_FILTER_WR_TXCHAN(x) ((x) << S_FW_FILTER_WR_TXCHAN)
+#define G_FW_FILTER_WR_TXCHAN(x) \
+ (((x) >> S_FW_FILTER_WR_TXCHAN) & M_FW_FILTER_WR_TXCHAN)
+
+#define S_FW_FILTER_WR_PRIO 12
+#define M_FW_FILTER_WR_PRIO 0x1
+#define V_FW_FILTER_WR_PRIO(x) ((x) << S_FW_FILTER_WR_PRIO)
+#define G_FW_FILTER_WR_PRIO(x) \
+ (((x) >> S_FW_FILTER_WR_PRIO) & M_FW_FILTER_WR_PRIO)
+#define F_FW_FILTER_WR_PRIO V_FW_FILTER_WR_PRIO(1U)
+
+#define S_FW_FILTER_WR_L2TIX 0
+#define M_FW_FILTER_WR_L2TIX 0xfff
+#define V_FW_FILTER_WR_L2TIX(x) ((x) << S_FW_FILTER_WR_L2TIX)
+#define G_FW_FILTER_WR_L2TIX(x) \
+ (((x) >> S_FW_FILTER_WR_L2TIX) & M_FW_FILTER_WR_L2TIX)
+
+#define S_FW_FILTER_WR_FRAG 7
+#define M_FW_FILTER_WR_FRAG 0x1
+#define V_FW_FILTER_WR_FRAG(x) ((x) << S_FW_FILTER_WR_FRAG)
+#define G_FW_FILTER_WR_FRAG(x) \
+ (((x) >> S_FW_FILTER_WR_FRAG) & M_FW_FILTER_WR_FRAG)
+#define F_FW_FILTER_WR_FRAG V_FW_FILTER_WR_FRAG(1U)
+
+#define S_FW_FILTER_WR_FRAGM 6
+#define M_FW_FILTER_WR_FRAGM 0x1
+#define V_FW_FILTER_WR_FRAGM(x) ((x) << S_FW_FILTER_WR_FRAGM)
+#define G_FW_FILTER_WR_FRAGM(x) \
+ (((x) >> S_FW_FILTER_WR_FRAGM) & M_FW_FILTER_WR_FRAGM)
+#define F_FW_FILTER_WR_FRAGM V_FW_FILTER_WR_FRAGM(1U)
+
+#define S_FW_FILTER_WR_IVLAN_VLD 5
+#define M_FW_FILTER_WR_IVLAN_VLD 0x1
+#define V_FW_FILTER_WR_IVLAN_VLD(x) ((x) << S_FW_FILTER_WR_IVLAN_VLD)
+#define G_FW_FILTER_WR_IVLAN_VLD(x) \
+ (((x) >> S_FW_FILTER_WR_IVLAN_VLD) & M_FW_FILTER_WR_IVLAN_VLD)
+#define F_FW_FILTER_WR_IVLAN_VLD V_FW_FILTER_WR_IVLAN_VLD(1U)
+
+#define S_FW_FILTER_WR_OVLAN_VLD 4
+#define M_FW_FILTER_WR_OVLAN_VLD 0x1
+#define V_FW_FILTER_WR_OVLAN_VLD(x) ((x) << S_FW_FILTER_WR_OVLAN_VLD)
+#define G_FW_FILTER_WR_OVLAN_VLD(x) \
+ (((x) >> S_FW_FILTER_WR_OVLAN_VLD) & M_FW_FILTER_WR_OVLAN_VLD)
+#define F_FW_FILTER_WR_OVLAN_VLD V_FW_FILTER_WR_OVLAN_VLD(1U)
+
+#define S_FW_FILTER_WR_IVLAN_VLDM 3
+#define M_FW_FILTER_WR_IVLAN_VLDM 0x1
+#define V_FW_FILTER_WR_IVLAN_VLDM(x) ((x) << S_FW_FILTER_WR_IVLAN_VLDM)
+#define G_FW_FILTER_WR_IVLAN_VLDM(x) \
+ (((x) >> S_FW_FILTER_WR_IVLAN_VLDM) & M_FW_FILTER_WR_IVLAN_VLDM)
+#define F_FW_FILTER_WR_IVLAN_VLDM V_FW_FILTER_WR_IVLAN_VLDM(1U)
+
+#define S_FW_FILTER_WR_OVLAN_VLDM 2
+#define M_FW_FILTER_WR_OVLAN_VLDM 0x1
+#define V_FW_FILTER_WR_OVLAN_VLDM(x) ((x) << S_FW_FILTER_WR_OVLAN_VLDM)
+#define G_FW_FILTER_WR_OVLAN_VLDM(x) \
+ (((x) >> S_FW_FILTER_WR_OVLAN_VLDM) & M_FW_FILTER_WR_OVLAN_VLDM)
+#define F_FW_FILTER_WR_OVLAN_VLDM V_FW_FILTER_WR_OVLAN_VLDM(1U)
+
+#define S_FW_FILTER_WR_RX_CHAN 15
+#define M_FW_FILTER_WR_RX_CHAN 0x1
+#define V_FW_FILTER_WR_RX_CHAN(x) ((x) << S_FW_FILTER_WR_RX_CHAN)
+#define G_FW_FILTER_WR_RX_CHAN(x) \
+ (((x) >> S_FW_FILTER_WR_RX_CHAN) & M_FW_FILTER_WR_RX_CHAN)
+#define F_FW_FILTER_WR_RX_CHAN V_FW_FILTER_WR_RX_CHAN(1U)
+
+#define S_FW_FILTER_WR_RX_RPL_IQ 0
+#define M_FW_FILTER_WR_RX_RPL_IQ 0x3ff
+#define V_FW_FILTER_WR_RX_RPL_IQ(x) ((x) << S_FW_FILTER_WR_RX_RPL_IQ)
+#define G_FW_FILTER_WR_RX_RPL_IQ(x) \
+ (((x) >> S_FW_FILTER_WR_RX_RPL_IQ) & M_FW_FILTER_WR_RX_RPL_IQ)
+
+#define S_FW_FILTER_WR_MACI 23
+#define M_FW_FILTER_WR_MACI 0x1ff
+#define V_FW_FILTER_WR_MACI(x) ((x) << S_FW_FILTER_WR_MACI)
+#define G_FW_FILTER_WR_MACI(x) \
+ (((x) >> S_FW_FILTER_WR_MACI) & M_FW_FILTER_WR_MACI)
+
+#define S_FW_FILTER_WR_MACIM 14
+#define M_FW_FILTER_WR_MACIM 0x1ff
+#define V_FW_FILTER_WR_MACIM(x) ((x) << S_FW_FILTER_WR_MACIM)
+#define G_FW_FILTER_WR_MACIM(x) \
+ (((x) >> S_FW_FILTER_WR_MACIM) & M_FW_FILTER_WR_MACIM)
+
+#define S_FW_FILTER_WR_FCOE 13
+#define M_FW_FILTER_WR_FCOE 0x1
+#define V_FW_FILTER_WR_FCOE(x) ((x) << S_FW_FILTER_WR_FCOE)
+#define G_FW_FILTER_WR_FCOE(x) \
+ (((x) >> S_FW_FILTER_WR_FCOE) & M_FW_FILTER_WR_FCOE)
+#define F_FW_FILTER_WR_FCOE V_FW_FILTER_WR_FCOE(1U)
+
+#define S_FW_FILTER_WR_FCOEM 12
+#define M_FW_FILTER_WR_FCOEM 0x1
+#define V_FW_FILTER_WR_FCOEM(x) ((x) << S_FW_FILTER_WR_FCOEM)
+#define G_FW_FILTER_WR_FCOEM(x) \
+ (((x) >> S_FW_FILTER_WR_FCOEM) & M_FW_FILTER_WR_FCOEM)
+#define F_FW_FILTER_WR_FCOEM V_FW_FILTER_WR_FCOEM(1U)
+
+#define S_FW_FILTER_WR_PORT 9
+#define M_FW_FILTER_WR_PORT 0x7
+#define V_FW_FILTER_WR_PORT(x) ((x) << S_FW_FILTER_WR_PORT)
+#define G_FW_FILTER_WR_PORT(x) \
+ (((x) >> S_FW_FILTER_WR_PORT) & M_FW_FILTER_WR_PORT)
+
+#define S_FW_FILTER_WR_PORTM 6
+#define M_FW_FILTER_WR_PORTM 0x7
+#define V_FW_FILTER_WR_PORTM(x) ((x) << S_FW_FILTER_WR_PORTM)
+#define G_FW_FILTER_WR_PORTM(x) \
+ (((x) >> S_FW_FILTER_WR_PORTM) & M_FW_FILTER_WR_PORTM)
+
+#define S_FW_FILTER_WR_MATCHTYPE 3
+#define M_FW_FILTER_WR_MATCHTYPE 0x7
+#define V_FW_FILTER_WR_MATCHTYPE(x) ((x) << S_FW_FILTER_WR_MATCHTYPE)
+#define G_FW_FILTER_WR_MATCHTYPE(x) \
+ (((x) >> S_FW_FILTER_WR_MATCHTYPE) & M_FW_FILTER_WR_MATCHTYPE)
+
+#define S_FW_FILTER_WR_MATCHTYPEM 0
+#define M_FW_FILTER_WR_MATCHTYPEM 0x7
+#define V_FW_FILTER_WR_MATCHTYPEM(x) ((x) << S_FW_FILTER_WR_MATCHTYPEM)
+#define G_FW_FILTER_WR_MATCHTYPEM(x) \
+ (((x) >> S_FW_FILTER_WR_MATCHTYPEM) & M_FW_FILTER_WR_MATCHTYPEM)
+
struct fw_ulptx_wr {
__be32 op_to_compl;
__be32 flowid_len16;
--
1.7.1
--
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 related
* Re: [net-next PATCH V2 1/9] net: frag evictor, avoid killing warm frag queues
From: Jesper Dangaard Brouer @ 2012-11-30 12:01 UTC (permalink / raw)
To: David Miller
Cc: eric.dumazet, fw, netdev, pablo, tgraf, amwang, kaber, paulmck,
herbert, David Laight
In-Reply-To: <1354227470.11754.348.camel@localhost>
On Thu, 2012-11-29 at 23:17 +0100, Jesper Dangaard Brouer wrote:
> On Thu, 2012-11-29 at 12:44 -0500, David Miller wrote:
> >
> > The only way I could see this making sense is if some "probability
> > of fulfillment" was taken into account.
[...]
> This patch/system actually includes a "promise/probability of
> fulfillment". Let me explain.
>
> We allow "warn" entries to complete, by allowing (new) fragments/packets
> for these entries (present in the frag queue). While we don't allow the
> system to create new entries. This creates the selection we interested
> in (as we must drop some packets given the arrival rate bigger than the
> processing rate).
To help reviewers understand; the implications of allowing existing frag
queue to complete/finish.
Let me explain the memory implications:
Remember we only allow (default) 256K mem to be used, (now) per CPU for
fragments (raw memory usage skb->truesize).
Hint: I violate this!!! -- the embedded lynch mob is gathering support
As the existing entries in the frag queues, are still being allowed
packets through (even when the memory limit is exceeded). In
worst-case, as DaveM explained, this can be as much as 100KBytes per
entry (for 64K fragments).
The highest number of frag queue hash entries, I have seen is 308, at
4x10G with two fragments size 2944. (This is of-cause unrealistic to get
this high with 64K frames, due to bw link limit, I would approximate is
max at 77 entries at 4x10G).
Now I'm teasing the embedded lynch mob.
Worst case memory usage:
308 * 100KBytes = 30.8 MBytes (not per CPU, total)
Now the embedded lynch mob is banging at my door, yelling that I'm
opening a remote OOM DoS attack on their small memory boxes.
I'll calm them down, by explaining why we cannot reach this number.
The "warm" fragment code is making sure, this does not get out of hand.
An entry is considered "warn" for only one jiffie (1 HZ), which on
1000HZ systems is 1 ms (and 100HZ = 10 ms). (after-which the fragment
queue is freed)
How much data can we send in 1 ms at 10000 Mbit/s:
10000 Mbit/s div 8bit-per-bytes * 0.001 sec = 1.25 MBytes
And having 4x10G can result in 5 MBytes (and the raw mem usage
skb->truesize is going to get it a bit higher).
Now, the embedded lynch mob is trying find a 4x 10Gbit/s embedded system
with less than 10MBytes of memory... they give up and go home.
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* Re: [PATCH net-next v1 2/2] bridge: export multicast database via netlink
From: Thomas Graf @ 2012-11-30 11:26 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, bridge, Herbert Xu, Stephen Hemminger, David S. Miller,
Jesper Dangaard Brouer
In-Reply-To: <1354269514-1863-2-git-send-email-amwang@redhat.com>
On 11/30/12 at 05:58pm, Cong Wang wrote:
> +enum {
> + MDBA_UNSPEC,
> + MDBA_MDB,
> + MDBA_ROUTER,
> + __MDBA_MAX,
> +};
> +#define MDBA_MAX (__MDBA_MAX - 1)
> +
> +enum {
> + MDBA_MDB_UNSPEC,
> + MDBA_MCADDR,
> + MDBA_BRPORT_NO,
> + __MDBA_MDB_MAX,
> +};
> +#define MDBA_MDB_MAX (__MDBA_MDB_MAX - 1)
So juse use these enums from iproute2 directly instead redefining
them.
> diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
> new file mode 100644
> index 0000000..3751f7d
> --- /dev/null
> +++ b/net/bridge/br_mdb.c
> @@ -0,0 +1,166 @@
> +#include <linux/err.h>
> +#include <linux/if_ether.h>
> +#include <linux/igmp.h>
> +#include <linux/kernel.h>
> +#include <linux/netdevice.h>
> +#include <linux/rculist.h>
> +#include <linux/skbuff.h>
> +#include <linux/slab.h>
> +#include <net/ip.h>
> +#if IS_ENABLED(CONFIG_IPV6)
> +#include <net/ipv6.h>
> +#include <net/mld.h>
> +#include <net/addrconf.h>
> +#include <net/ip6_checksum.h>
> +#endif
> +
> +#include "br_private.h"
> +
> +struct br_port_msg {
> + int ifindex;
> +};
Make that __u32 ifindex and move the definition into if_bridge.h so
you can reuse it in iproute2.
> +static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
> + u32 seq, struct net_device *dev)
> +{
> + struct net_bridge *br = netdev_priv(dev);
> + struct net_bridge_port *p;
> + struct hlist_node *n;
> + struct nlattr *nest;
> +
> + if (!br->multicast_router || hlist_empty(&br->router_list)) {
> + printk(KERN_INFO "no router on bridge\n");
> + return 0;
> + }
> +
> + nest = nla_nest_start(skb, MDBA_ROUTER);
> + if (nest == NULL)
> + return -EMSGSIZE;
> +
> + hlist_for_each_entry_rcu(p, n, &br->router_list, rlist) {
> + if (p && nla_put_u16(skb, MDBA_BRPORT_NO, p->port_no))
> + goto fail;
> + }
port_no 0 is reserved, right?
We can reduce message size here and make it easier to extend by
using p->port_no as the attribute id by doing something like this:
hlist_for_each_entry_rcu(p, n, &br->router_list, rlist)
if (nla_put_flag(skb, p->port_no))
goto fail;
This will result in an empty attribute body for now and if you ever
need to include more data you can simply start putting attributes
insde that empty body and old users will continue to function.
> +static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
> + u32 seq, struct net_device *dev)
> +{
> + struct net_bridge *br = netdev_priv(dev);
> + struct net_bridge_mdb_htable *mdb;
> + struct nlattr *nest;
> + unsigned int i;
> + int s_idx;
> +
> + if (br->multicast_disabled) {
> + printk(KERN_INFO "multicast is disabled on bridge\n");
> + return 0;
> + }
> +
> + mdb = rcu_dereference(br->mdb);
> + if (!mdb) {
> + printk(KERN_INFO "no mdb on bridge\n");
> + return 0;
> + }
> +
> + cb->seq = mdb->seq;
I'm not sure how this is supposed to worl. cb->seq may not change
throughout the complete dump process or the dump will be interrupted
and the user is required to restart.
Each bridge will have its own mdb resulting in a differing seq.
> + s_idx = cb->args[1];
> + if (s_idx >= mdb->max)
> + return 0;
> +
> + nest = nla_nest_start(skb, MDBA_MDB);
> + if (nest == NULL)
> + return -EMSGSIZE;
> +
> + for (i = s_idx; i < mdb->max; i++) {
> + struct hlist_node *h;
> + struct net_bridge_mdb_entry *mp;
> + struct net_bridge_port_group *p, **pp;
> + struct net_bridge_port *port;
> +
> + hlist_for_each_entry_rcu(mp, h, &mdb->mhash[i], hlist[mdb->ver]) {
> + for (pp = &mp->ports;
> + (p = rcu_dereference(*pp)) != NULL;
> + pp = &p->next) {
> + port = p->port;
> + if (port) {
> + printk(KERN_INFO "port %u, mcaddr: %pI4\n", port->port_no, &mp->addr.u.ip4);
> + if (nla_put_u16(skb, MDBA_BRPORT_NO, port->port_no) ||
> + nla_put_be32(skb, MDBA_MCADDR, p->addr.u.ip4))
> + goto fail;
> + }
> + }
> + }
> + }
> +
> + cb->args[1] = i;
> + nla_nest_end(skb, nest);
> + return 0;
> +fail:
> + cb->args[1] = i;
> + nla_nest_cancel(skb, nest);
> + return -EMSGSIZE;
This still relies on the assumption that all of mdb->mhash[] will fit
into a single netlink message. Is that guaranteed? If so that would
simplify this a lot and you wouldn't have to worry about rehashes at
all.
As-is it looks broken, you store an offset into the hash but if you
run out of space you trim away the complete nested attribute again
and thus offseting will actually result in data loss because that
data has never been wired but you will skip over it next time.
You need something like this:
for (i = 0; i < mdb->max; i++) {
[...]
hlist_for_each_entry_rcu(mp, h, &mdb->mhash[i], hlist[mdb->ver]) {
if (idx < s_idx)
goto skip;
hentry = nla_nest_start(...)
if (nla_put_u16(...) ||
nla_put_32(...)) {
nla_nest_cancel(skb, hentry);
err = -EMSGSIZE;
goto out;
}
nla_nest_end(skb, hentry);
skip:
idx++;
}
}
out:
cb->args[1] = idx;
nla_nest_end(skb, nest);
return err;
> +}
> +
> +static int br_mdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> + struct net_device *dev;
> + struct net *net = sock_net(skb->sk);
> + struct nlmsghdr *nlh;
> + u32 seq = cb->nlh->nlmsg_seq;
> + int idx = 0, s_idx;
> +
> + s_idx = cb->args[0];
> +
> + rcu_read_lock();
> +
> + for_each_netdev_rcu(net, dev) {
> + if (dev->priv_flags & IFF_EBRIDGE) {
> + struct br_port_msg *bpm;
> +
> + if (idx < s_idx)
> + goto cont;
> +
> + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid,
> + seq, RTM_GETMDB,
> + sizeof(*bpm), NLM_F_MULTI);
> + if (nlh == NULL)
> + break;
> +
> + bpm = nlmsg_data(nlh);
> + bpm->ifindex = dev->ifindex;
> + if (br_mdb_fill_info(skb, cb, seq, dev) < 0) {
> + printk(KERN_INFO "br_mdb_fill_info failed\n");
> + goto fail;
> + }
> + if (br_rports_fill_info(skb, cb, seq, dev) < 0) {
> + printk(KERN_INFO "br_rports_fill_info failed\n");
> + goto fail;
> + }
> +
> + nlmsg_end(skb, nlh);
> +cont:
> + idx++;
> + }
> + }
> +
> + rcu_read_unlock();
> + cb->args[0] = idx;
> + return skb->len;
> +
> +fail:
> + rcu_read_unlock();
> + nlmsg_cancel(skb, nlh);
> + return skb->len;
Assuming you implement partial messages as proposed above you don't
want to nlmsg_cancel() here. Instead you just want to nlmsg_end() and
send out the message with a partial MDB_MDBA and continue where you
left off.
^ permalink raw reply
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