* Re: [PATCH 5/5] net: Loopback ifindex is constant now
From: Eric Dumazet @ 2012-08-06 11:54 UTC (permalink / raw)
To: Pavel Emelyanov; +Cc: David Miller, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501F9D2B.8000504@parallels.com>
On Mon, 2012-08-06 at 14:32 +0400, Pavel Emelyanov wrote:
> As pointed out, there are places, that access net->loopback_dev->ifindex
> and after ifindex generation is made per-net this value becomes constant
> equals 1. So go ahead and introduce the LOOPBACK_IFINDEX constant and use
> it where appropriate.
>
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
What guarantee do we have that loopback is the first device per net ?
You should add this to the changelog because its not that obvious.
^ permalink raw reply
* Re: [PATCH 1/5] net: Don't use ifindices in hash fns
From: Eric Dumazet @ 2012-08-06 11:51 UTC (permalink / raw)
To: Pavel Emelyanov; +Cc: David Miller, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501FA3FA.9010107@parallels.com>
On Mon, 2012-08-06 at 15:01 +0400, Pavel Emelyanov wrote:
> Damn :( You're right.
>
> > This returns 0 as is
>
> Well, on 64-bit no, but what it does is also not what it was supposed to.
>
Here, my L1_CACHE_BYTES is 64, but whatever
> > I would define a generic pointer hash mix instead of a 'net_device
> > thing'
> >
> > static inline u32 ptr_hash_mix(void *ptr)
> > {
> > #if BITS_PER_LONG==32
> > return (u32)(unsigned long)ptr;
> > #else
> > return (u32)((unsigned long)ptr >> L1_CACHE_SHIFT);
> > #endif
> > }
>
> OK. It will also obsolete the net_hash_mix then. Any suggestions where to put
> the new one?
Not obsolete net_hash_mix(), since this one can return 0 if
CONFIG_NET_NS is not set.
static inline unsigned int net_hash_mix(struct net *net)
{
#ifdef CONFIG_NET_NS
return ptr_hash_mix(net);
#else
return 0;
#endif
}
I dont know, you could add this to include/linux/hash.h
^ permalink raw reply
* [BUG] af_packet: tpacket_destruct_skb throws BUG under high tx load
From: Daniel Borkmann @ 2012-08-06 11:21 UTC (permalink / raw)
To: Johann Baudy; +Cc: netdev, Eric Dumazet, David S. Miller
Under high tx load from mmap()ed PF_PACKET sockets the statement in
tpacket_destruct_skb():
BUG_ON(__packet_get_status(po, ph) != TP_STATUS_SENDING);
is being thrown, where __packet_get_status(po, ph) has the value
TP_STATUS_SEND_REQUEST instead of TP_STATUS_SENDING.
The send(2) system call was invoked with the flag MSG_DONTWAIT. The
BUG occurred even with having dev_queue_xmit() returned successfully
in tpacket_snd().
By simply removing this BUG statement, the system seemed stable, but
this might not be the proper solution. It's reproducible and I tested
it on a multi-core system under the latest net/net-next kernel on x86
and x86_64.
On my system, this BUG was triggered in the following cases:
* Multiple processes allocate and use a TX_RING on one device
* A single process allocates a TX_RING on one device and
/proc/sys/net/core/wmem_default, /proc/sys/net/core/wmem_max were
increased
Cheers,
Daniel
^ permalink raw reply
* Re: [PATCH 1/5] net: Don't use ifindices in hash fns
From: Pavel Emelyanov @ 2012-08-06 11:01 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, Eric W. Biederman, Linux Netdev List
In-Reply-To: <1344249789.26674.8.camel@edumazet-glaptop>
On 08/06/2012 02:43 PM, Eric Dumazet wrote:
> On Mon, 2012-08-06 at 14:30 +0400, Pavel Emelyanov wrote:
>> Eric noticed, that when there will be devices with equal indices, some
>> hash functions that use them will become less effective as they could.
>>
>> Fix this in advance by taking the net_device address into calculations
>> instead of the device index. Since the net_device is always aligned in
>> memory, shift the pointer to eliminate always zero bits (like we do it
>> in net_hash_mix).
>>
>> This is true for arp and ndisc hash fns. The netlabel, can and llc ones
>> are also ifindex-based, but that three are init_net-only, thus will not
>> be affected.
>>
>> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
>>
>> ---
>> include/linux/netdevice.h | 6 ++++++
>> include/net/arp.h | 2 +-
>> include/net/ndisc.h | 2 +-
>> 3 files changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>> index a9db4f3..6010b37 100644
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -1330,6 +1330,12 @@ struct net_device {
>>
>> #define NETDEV_ALIGN 32
>>
>> +static inline unsigned int netdev_hash_mix(const struct net_device *dev)
>> +{
>> + return (unsigned int)(((unsigned long)dev) >>
>> + max(L1_CACHE_BYTES, NETDEV_ALIGN));
>> +}
>> +
>
> I guess you didnt test this patch very well ...
Damn :( You're right.
> This returns 0 as is
Well, on 64-bit no, but what it does is also not what it was supposed to.
> I would define a generic pointer hash mix instead of a 'net_device
> thing'
>
> static inline u32 ptr_hash_mix(void *ptr)
> {
> #if BITS_PER_LONG==32
> return (u32)(unsigned long)ptr;
> #else
> return (u32)((unsigned long)ptr >> L1_CACHE_SHIFT);
> #endif
> }
OK. It will also obsolete the net_hash_mix then. Any suggestions where to put
the new one?
Thanks,
Pavel
^ permalink raw reply
* Re: skb_warn_bad_offload with kernel 3.5 (maybe gso/bridge related ?)
From: Eric Dumazet @ 2012-08-06 10:57 UTC (permalink / raw)
To: Herbert Xu; +Cc: Ben Hutchings, Yann Dupont, netdev@vger.kernel.org
In-Reply-To: <20120806091846.GA18581@gondor.apana.org.au>
On Mon, 2012-08-06 at 17:18 +0800, Herbert Xu wrote:
> On Fri, Aug 03, 2012 at 04:40:08PM +0100, Ben Hutchings wrote:
> >
> > I think GRO is doing the right thing, and I can't think why we should
> > see ip_summed = CHECKSUM_PARTIAL if the skb is forwarded by a bridge. I
>
> If it is was created by GRO then it should always be CHECKSUM_PARTIAL,
> even if it came through a bridge.
Not sure where in GRO we set ip_summed to CHECKSUM_PARTIAL ?
^ permalink raw reply
* Re: skb_warn_bad_offload with kernel 3.5 (maybe gso/bridge related ?)
From: Dmitry Kravkov @ 2012-08-06 10:50 UTC (permalink / raw)
To: Herbert Xu
Cc: Ben Hutchings, Eric Dumazet, Yann Dupont, netdev@vger.kernel.org
In-Reply-To: <20120806091846.GA18581@gondor.apana.org.au>
On Mon, 2012-08-06 at 17:18 +0800, Herbert Xu wrote:
> On Fri, Aug 03, 2012 at 04:40:08PM +0100, Ben Hutchings wrote:
> >
> > I think GRO is doing the right thing, and I can't think why we should
> > see ip_summed = CHECKSUM_PARTIAL if the skb is forwarded by a bridge. I
>
> If it is was created by GRO then it should always be CHECKSUM_PARTIAL,
> even if it came through a bridge.
>
> Cheers,
Is LRO on for bnx2x device? It should be off when forwarding is enabled.
^ permalink raw reply
* Re: [PATCH 1/5] net: Don't use ifindices in hash fns
From: Eric Dumazet @ 2012-08-06 10:43 UTC (permalink / raw)
To: Pavel Emelyanov; +Cc: David Miller, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501F9CDA.6040403@parallels.com>
On Mon, 2012-08-06 at 14:30 +0400, Pavel Emelyanov wrote:
> Eric noticed, that when there will be devices with equal indices, some
> hash functions that use them will become less effective as they could.
>
> Fix this in advance by taking the net_device address into calculations
> instead of the device index. Since the net_device is always aligned in
> memory, shift the pointer to eliminate always zero bits (like we do it
> in net_hash_mix).
>
> This is true for arp and ndisc hash fns. The netlabel, can and llc ones
> are also ifindex-based, but that three are init_net-only, thus will not
> be affected.
>
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
>
> ---
> include/linux/netdevice.h | 6 ++++++
> include/net/arp.h | 2 +-
> include/net/ndisc.h | 2 +-
> 3 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index a9db4f3..6010b37 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1330,6 +1330,12 @@ struct net_device {
>
> #define NETDEV_ALIGN 32
>
> +static inline unsigned int netdev_hash_mix(const struct net_device *dev)
> +{
> + return (unsigned int)(((unsigned long)dev) >>
> + max(L1_CACHE_BYTES, NETDEV_ALIGN));
> +}
> +
I guess you didnt test this patch very well ...
This returns 0 as is
I would define a generic pointer hash mix instead of a 'net_device
thing'
static inline u32 ptr_hash_mix(void *ptr)
{
#if BITS_PER_LONG==32
return (u32)(unsigned long)ptr;
#else
return (u32)((unsigned long)ptr >> L1_CACHE_SHIFT);
#endif
}
^ permalink raw reply
* [PATCH 5/5] net: Loopback ifindex is constant now
From: Pavel Emelyanov @ 2012-08-06 10:32 UTC (permalink / raw)
To: David Miller, Eric Dumazet, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501F9CAF.3030605@parallels.com>
As pointed out, there are places, that access net->loopback_dev->ifindex
and after ifindex generation is made per-net this value becomes constant
equals 1. So go ahead and introduce the LOOPBACK_IFINDEX constant and use
it where appropriate.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
drivers/net/loopback.c | 1 +
include/net/net_namespace.h | 6 ++++++
net/decnet/dn_route.c | 6 +++---
net/ipv4/fib_frontend.c | 2 +-
net/ipv4/ipmr.c | 2 +-
net/ipv4/netfilter/ipt_rpfilter.c | 2 +-
net/ipv4/route.c | 6 +++---
net/ipv6/route.c | 2 +-
8 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index e2a06fd..4a075ba 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -197,6 +197,7 @@ static __net_init int loopback_net_init(struct net *net)
if (err)
goto out_free_netdev;
+ BUG_ON(dev->ifindex != LOOPBACK_IFINDEX);
net->loopback_dev = dev;
return 0;
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index c5fbebf..841581b 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -105,6 +105,12 @@ struct net {
struct sock *diag_nlsk;
};
+/*
+ * ifindex generation is per-net namespace, thus any loopback
+ * device should get ifindex 1
+ */
+
+#define LOOPBACK_IFINDEX 1
#include <linux/seq_file_net.h>
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 85a3604..c855e8d 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -961,7 +961,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o
.saddr = oldflp->saddr,
.flowidn_scope = RT_SCOPE_UNIVERSE,
.flowidn_mark = oldflp->flowidn_mark,
- .flowidn_iif = init_net.loopback_dev->ifindex,
+ .flowidn_iif = LOOPBACK_IFINDEX,
.flowidn_oif = oldflp->flowidn_oif,
};
struct dn_route *rt = NULL;
@@ -979,7 +979,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o
"dn_route_output_slow: dst=%04x src=%04x mark=%d"
" iif=%d oif=%d\n", le16_to_cpu(oldflp->daddr),
le16_to_cpu(oldflp->saddr),
- oldflp->flowidn_mark, init_net.loopback_dev->ifindex,
+ oldflp->flowidn_mark, LOOPBACK_IFINDEX,
oldflp->flowidn_oif);
/* If we have an output interface, verify its a DECnet device */
@@ -1042,7 +1042,7 @@ source_ok:
if (!fld.daddr)
goto out;
}
- fld.flowidn_oif = init_net.loopback_dev->ifindex;
+ fld.flowidn_oif = LOOPBACK_IFINDEX;
res.type = RTN_LOCAL;
goto make_route;
}
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index c43ae3f..7f073a3 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -218,7 +218,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
scope = RT_SCOPE_UNIVERSE;
if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) {
fl4.flowi4_oif = 0;
- fl4.flowi4_iif = net->loopback_dev->ifindex;
+ fl4.flowi4_iif = LOOPBACK_IFINDEX;
fl4.daddr = ip_hdr(skb)->saddr;
fl4.saddr = 0;
fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 8eec8f4..3a57570 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1798,7 +1798,7 @@ static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
.flowi4_oif = (rt_is_output_route(rt) ?
skb->dev->ifindex : 0),
.flowi4_iif = (rt_is_output_route(rt) ?
- net->loopback_dev->ifindex :
+ LOOPBACK_IFINDEX :
skb->dev->ifindex),
.flowi4_mark = skb->mark,
};
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
index 31371be..24eb18c 100644
--- a/net/ipv4/netfilter/ipt_rpfilter.c
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -85,7 +85,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
return ipv4_is_local_multicast(iph->daddr) ^ invert;
flow.flowi4_iif = 0;
} else {
- flow.flowi4_iif = dev_net(par->in)->loopback_dev->ifindex;
+ flow.flowi4_iif = LOOPBACK_IFINDEX;
}
flow.daddr = iph->saddr;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 21ad369..c581373 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1619,7 +1619,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
if (res.type == RTN_LOCAL) {
err = fib_validate_source(skb, saddr, daddr, tos,
- net->loopback_dev->ifindex,
+ LOOPBACK_IFINDEX,
dev, in_dev, &itag);
if (err < 0)
goto martian_source_keep_err;
@@ -1895,7 +1895,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
orig_oif = fl4->flowi4_oif;
- fl4->flowi4_iif = net->loopback_dev->ifindex;
+ fl4->flowi4_iif = LOOPBACK_IFINDEX;
fl4->flowi4_tos = tos & IPTOS_RT_MASK;
fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
@@ -1984,7 +1984,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
if (!fl4->daddr)
fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
dev_out = net->loopback_dev;
- fl4->flowi4_oif = net->loopback_dev->ifindex;
+ fl4->flowi4_oif = LOOPBACK_IFINDEX;
res.type = RTN_LOCAL;
flags |= RTCF_LOCAL;
goto make_route;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 8e80fd2..0ddf2d1 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -965,7 +965,7 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
{
int flags = 0;
- fl6->flowi6_iif = net->loopback_dev->ifindex;
+ fl6->flowi6_iif = LOOPBACK_IFINDEX;
if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
flags |= RT6_LOOKUP_F_IFACE;
--
1.7.6.5
^ permalink raw reply related
* [PATCH 3/5] veth: Allow to create peer link with given ifindex
From: Pavel Emelyanov @ 2012-08-06 10:31 UTC (permalink / raw)
To: David Miller, Eric Dumazet, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501F9CAF.3030605@parallels.com>
The ifinfomsg is in there (thanks kaber@ for foreseeing this long time ago),
so take the given ifidex and register netdev with it.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
drivers/net/veth.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 5852361..496c026 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -348,6 +348,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
if (tbp[IFLA_ADDRESS] == NULL)
eth_hw_addr_random(peer);
+ if (ifmp)
+ peer->ifindex = ifmp->ifi_index;
+
err = register_netdevice(peer);
put_net(net);
net = NULL;
--
1.7.6.5
^ permalink raw reply related
* [PATCH 4/5] net: Make ifindex generation per-net namespace
From: Pavel Emelyanov @ 2012-08-06 10:31 UTC (permalink / raw)
To: David Miller, Eric Dumazet, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501F9CAF.3030605@parallels.com>
Strictly speaking this is only _really_ required for checkpoint-restore to
make loopback device always have the same index.
This change appears to be safe wrt "ifindex should be unique per-system"
concept, as all the ifindex usage is either already made per net namespace
of is explicitly limited with init_net only.
There are two cool side effects of this. The first one -- ifindices of
devices in container are always small, regardless of how many containers
we've started (and re-started) so far. The second one is -- we can speed
up the loopback ifidex access as shown in the next patch.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
include/net/net_namespace.h | 1 +
net/core/dev.c | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index ae1cd6c..c5fbebf 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -62,6 +62,7 @@ struct net {
struct sock *rtnl; /* rtnetlink socket */
struct sock *genl_sock;
+ int ifindex;
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
diff --git a/net/core/dev.c b/net/core/dev.c
index 3ca300d..1f06df8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5221,12 +5221,12 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
*/
static int dev_new_index(struct net *net)
{
- static int ifindex;
+ int ifindex = net->ifindex;
for (;;) {
if (++ifindex <= 0)
ifindex = 1;
if (!__dev_get_by_index(net, ifindex))
- return ifindex;
+ return net->ifindex = ifindex;
}
}
--
1.7.6.5
^ permalink raw reply related
* [PATCH 2/5] net: Allow to create links with given ifindex
From: Pavel Emelyanov @ 2012-08-06 10:31 UTC (permalink / raw)
To: David Miller, Eric Dumazet, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501F9CAF.3030605@parallels.com>
Currently the RTM_NEWLINK results in -EOPNOTSUPP if the ifinfomsg->ifi_index
is not zero. I propose to allow requesting ifindices on link creation. This
is required by the checkpoint-restore to correctly restore a net namespace
(i.e. -- a container).
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
net/core/dev.c | 7 ++++++-
net/core/rtnetlink.c | 12 +++++++-----
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index f91abf8..3ca300d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5579,7 +5579,12 @@ int register_netdevice(struct net_device *dev)
}
}
- dev->ifindex = dev_new_index(net);
+ ret = -EBUSY;
+ if (!dev->ifindex)
+ dev->ifindex = dev_new_index(net);
+ else if (__dev_get_by_index(net, dev->ifindex))
+ goto err_uninit;
+
if (dev->iflink == -1)
dev->iflink = dev->ifindex;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 2c5a0a0..1aa1456 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1812,8 +1812,6 @@ replay:
return -ENODEV;
}
- if (ifm->ifi_index)
- return -EOPNOTSUPP;
if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO])
return -EOPNOTSUPP;
@@ -1839,10 +1837,14 @@ replay:
return PTR_ERR(dest_net);
dev = rtnl_create_link(net, dest_net, ifname, ops, tb);
-
- if (IS_ERR(dev))
+ if (IS_ERR(dev)) {
err = PTR_ERR(dev);
- else if (ops->newlink)
+ goto out;
+ }
+
+ dev->ifindex = ifm->ifi_index;
+
+ if (ops->newlink)
err = ops->newlink(net, dev, tb, data);
else
err = register_netdevice(dev);
--
1.7.6.5
^ permalink raw reply related
* [PATCH 1/5] net: Don't use ifindices in hash fns
From: Pavel Emelyanov @ 2012-08-06 10:30 UTC (permalink / raw)
To: David Miller, Eric Dumazet, Eric W. Biederman, Linux Netdev List
In-Reply-To: <501F9CAF.3030605@parallels.com>
Eric noticed, that when there will be devices with equal indices, some
hash functions that use them will become less effective as they could.
Fix this in advance by taking the net_device address into calculations
instead of the device index. Since the net_device is always aligned in
memory, shift the pointer to eliminate always zero bits (like we do it
in net_hash_mix).
This is true for arp and ndisc hash fns. The netlabel, can and llc ones
are also ifindex-based, but that three are init_net-only, thus will not
be affected.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
include/linux/netdevice.h | 6 ++++++
include/net/arp.h | 2 +-
include/net/ndisc.h | 2 +-
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a9db4f3..6010b37 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1330,6 +1330,12 @@ struct net_device {
#define NETDEV_ALIGN 32
+static inline unsigned int netdev_hash_mix(const struct net_device *dev)
+{
+ return (unsigned int)(((unsigned long)dev) >>
+ max(L1_CACHE_BYTES, NETDEV_ALIGN));
+}
+
static inline
int netdev_get_prio_tc_map(const struct net_device *dev, u32 prio)
{
diff --git a/include/net/arp.h b/include/net/arp.h
index 7f7df93..0305a38 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -10,7 +10,7 @@ extern struct neigh_table arp_tbl;
static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd)
{
- u32 val = key ^ dev->ifindex;
+ u32 val = key ^ netdev_hash_mix(dev);
return val * hash_rnd;
}
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 96a3b5c..ae7c1fd 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -134,7 +134,7 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _
{
const u32 *p32 = pkey;
- return (((p32[0] ^ dev->ifindex) * hash_rnd[0]) +
+ return (((p32[0] ^ netdev_hash_mix(dev)) * hash_rnd[0]) +
(p32[1] * hash_rnd[1]) +
(p32[2] * hash_rnd[2]) +
(p32[3] * hash_rnd[3]));
--
1.7.6.5
^ permalink raw reply related
* [PATCH net-next 0/5] Per-net and on-demand link indices (and related)
From: Pavel Emelyanov @ 2012-08-06 10:30 UTC (permalink / raw)
To: David Miller, Eric Dumazet, Eric W. Biederman, Linux Netdev List
Hi!
This set tries to summarize the recent discussion of making ifindices friendly
to checkpoint-restore and consists of:
1. Prepare hash function to non-unique ifindices
2. Allow for specifying the desired ifindex on net link creation
3. Make ifindex generation per-net
4. Simplify loopback device ifindex access
Thanks,
Pavel
^ permalink raw reply
* Re: [PATCH 1/7] netpoll: use GFP_ATOMIC in slave_enable_netpoll() and __netpoll_setup()
From: Eric Dumazet @ 2012-08-06 9:44 UTC (permalink / raw)
To: Cong Wang
Cc: netdev, David S. Miller, Jay Vosburgh, Andy Gospodarek,
Eric Dumazet, Cong Wang, Joe Perches, Neil Horman, linux-kernel
In-Reply-To: <1344244118.14728.28.camel@cr0>
On Mon, 2012-08-06 at 17:08 +0800, Cong Wang wrote:
> On Fri, 2012-08-03 at 12:10 +0200, Eric Dumazet wrote:
> >
> > I did this , just take it ;)
>
> Do we have to pass gfp to ->ndo_netpoll_setup() too? It seems no, so far
> I don't think we have to do that.
>
> Thanks.
>
It is needed.
->ndo_netpoll_setup() is called from __netpoll_setup()
So it would make no sense to allow GFP_KERNEL allocations in
ndo_netpoll_setup() hgandlers if we called __netpoll_setup() with
GFP_ATOMIC gfp
^ permalink raw reply
* Re: Huge performance degradation for UDP between 2.4.17 and 2.6
From: leroy christophe @ 2012-08-06 9:27 UTC (permalink / raw)
To: Eric Dumazet; +Cc: linux-kernel, netdev
In-Reply-To: <1344155331.9299.1573.camel@edumazet-glaptop>
[-- Attachment #1: Type: text/plain, Size: 1649 bytes --]
Le 05/08/2012 10:28, Eric Dumazet a écrit :
> On Sun, 2012-08-05 at 10:16 +0200, LEROY christophe wrote:
>> Le 02/08/2012 16:13, Eric Dumazet a écrit :
>>> On Thu, 2012-08-02 at 14:27 +0200, leroy christophe wrote:
>>>> Hi
>>>>
>>>> I'm having a big issue with UDP. Using a powerpc board (MPC860).
>>>>
>>>> With our board running kernel 2.4.17, I'm able to send 160000 voice
>>>> packets (UDP, 96 bytes per packet) in 11 seconds.
>>>> With the same board running either Kernel 2.6.35.14 or Kernel 3.4.7, I
>>>> need 55 seconds to send the same amount of packets.
>>>>
>>>>
>>>> Is there anything to tune in order to get same output rate as with
>>>> Kernel 2.4 ?
>>> kernel size is probably too big for your old / slow cpu.
>>>
>>> Maybe you added too many features on your 3.4.7 kernel. (netfilter ?
>>> SLUB debugging ...)
>>>
>>> Its hard to say, 2.4.17 had less features and was faster.
>>>
>> Thanks for your answer.
>> Yes I have netfilter as I need it. However, I tried without it and still
>> need about 37 seconds to send the 160000 packets I was sending in 11
>> seconds with 2.4.17
>>
>> I don't think there is any problem with size of the kernel. I still have
>> plenty of memory available.
>>
> I believe you misunderstood me.
>
> I was referring to cpu caches ( dcache & icache )
>
>> All debugging is turned off, and I'm not using SLUB but SLOB.
>> I have 32Mbytes of RAM. Would SLUB be more performant than SLOB ?
> I never used SLOB I cannot comment
>
> Please provide (on 3.4.7)
>
> cat /proc/cpuinfo
> lsmod
> dmesg
>
Ok, I have recompiled with SLUB.
Find attached cpuinfo, lsmod and dmesg. I do not have any modules loaded.
[-- Attachment #2: lsmod.txt --]
[-- Type: text/plain, Size: 54 bytes --]
Module Size Used by Not tainted
[-- Attachment #3: cpuinfo.txt --]
[-- Type: text/plain, Size: 174 bytes --]
processor : 0
cpu : 8xx
clock : 132.000000MHz
revision : 0.0 (pvr 0050 0000)
bogomips : 16.50
timebase : 8250000
platform : CMPC885
model : MIAE
Memory : 128 MB
[-- Attachment #4: dmesg.txt --]
[-- Type: text/plain, Size: 29225 bytes --]
[ 0.000000] Using CMPC885 machine description
[ 0.000000] Linux version 3.4.7-s3k-3.8.3+-svn2796 (root@localhost.localdomain) (gcc version 4.4.4 (GCC) ) #19 PREEMPT Sun Aug 5 06:43:31 CEST 2012
[ 0.000000] Top of RAM: 0x8000000, Total RAM: 0x8000000
[ 0.000000] Memory hole size: 0MB
[ 0.000000] Zone PFN ranges:
[ 0.000000] DMA 0x00000000 -> 0x00008000
[ 0.000000] Normal empty
[ 0.000000] Movable zone start PFN for each node
[ 0.000000] Early memory PFN ranges
[ 0.000000] 0: 0x00000000 -> 0x00008000
[ 0.000000] On node 0 totalpages: 32768
[ 0.000000] free_area_init_node: node 0, pgdat c03f4be8, node_mem_map c0433000
[ 0.000000] DMA zone: 256 pages used for memmap
[ 0.000000] DMA zone: 0 pages reserved
[ 0.000000] DMA zone: 32512 pages, LIFO batch:7
[ 0.000000] MMU: Allocated 72 bytes of context maps for 16 contexts
[ 0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[ 0.000000] pcpu-alloc: [0] 0
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 32512
[ 0.000000] Kernel command line: console=ttyCPM0,115200N8 ip=172.25.231.39:172.25.231.59::255.0.0.0:miae:eth0:off
[ 0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
[ 0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
[ 0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[ 0.000000] Memory: 125432k/131072k available (3972k kernel code, 5640k reserved, 140k data, 178k bss, 488k init)
[ 0.000000] Kernel virtual memory layout:
[ 0.000000] * 0xfffdf000..0xfffff000 : fixmap
[ 0.000000] * 0xfde00000..0xfe000000 : consistent mem
[ 0.000000] * 0xfddf6000..0xfde00000 : early ioremap
[ 0.000000] * 0xc9000000..0xfddf6000 : vmalloc & ioremap
[ 0.000000] SLUB: Genslabs=14, HWalign=16, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[ 0.000000] NR_IRQS:512 nr_irqs:512 16
[ 0.000000] Decrementer Frequency = 0x7de290
[ 0.000000] time_init: decrementer frequency = 8.250000 MHz
[ 0.000000] time_init: processor frequency = 132.000000 MHz
[ 0.000000] clocksource: timebase mult[79364d93] shift[24] registered
[ 0.000000] clockevent: decrementer mult[21cac08] shift[32] cpu[0]
[ 0.000000] console [ttyCPM0] enabled
[ 0.144102] pid_max: default: 32768 minimum: 301
[ 0.149489] Mount-cache hash table entries: 512
[ 0.175086] devtmpfs: initialized
[ 0.178575] device: 'platform': device_add
[ 0.179079] bus: 'platform': registered
[ 0.179451] bus: 'cpu': registered
[ 0.179551] device: 'cpu': device_add
[ 0.181718] NET: Registered protocol family 16
[ 0.186374] device class 'bdi': registering
[ 0.188054] device class 'gpio': registering
[ 0.189423] device class 'tty': registering
[ 0.191855] bus: 'spi': registered
[ 0.191932] device class 'spi_master': registering
[ 0.193842] gpiochip_find_base: found new base at 1008
[ 0.193974] device: 'gpiochip1008': device_add
[ 0.195387] gpiochip_add: registered GPIOs 1008 to 1023 on device: /soc@ff000000/cpm@9c0/gpio-controller@950
[ 0.205830] gpiochip_find_base: found new base at 976
[ 0.205962] device: 'gpiochip976': device_add
[ 0.207142] gpiochip_add: registered GPIOs 976 to 1007 on device: /soc@ff000000/cpm@9c0/gpio-controller@ab8
[ 0.221332] gpiochip_find_base: found new base at 960
[ 0.221466] device: 'gpiochip960': device_add
[ 0.222639] gpiochip_add: registered GPIOs 960 to 975 on device: /soc@ff000000/cpm@9c0/gpio-controller@960
[ 0.232869] gpiochip_find_base: found new base at 944
[ 0.232999] device: 'gpiochip944': device_add
[ 0.234181] gpiochip_add: registered GPIOs 944 to 959 on device: /soc@ff000000/cpm@9c0/gpio-controller@970
[ 0.244378] gpiochip_find_base: found new base at 912
[ 0.244508] device: 'gpiochip912': device_add
[ 0.245744] gpiochip_add: registered GPIOs 912 to 943 on device: /soc@ff000000/cpm@9c0/gpio-controller@ac8
[ 0.255606] bus: 'platform': add driver mpc8xxx_wdt
[ 0.256898] device: 'cpu0': device_add
[ 0.257044] bus: 'cpu': add device cpu0
[ 0.330377] device: 'default': device_add
[ 0.332266] device class 'misc': registering
[ 0.333402] device class 'mdio_bus': registering
[ 0.336232] bus: 'mdio_bus': registered
[ 0.336318] bus: 'mdio_bus': add driver Generic PHY
[ 0.337607] device class 'hwmon': registering
[ 0.338929] device class 'leds': registering
[ 0.340236] device class 'net': registering
[ 0.341620] device: 'lo': device_add
[ 0.345289] Switching to clocksource timebase
[ 0.350674] FS-Cache: Loaded
[ 0.353317] device class 'mem': registering
[ 0.354397] device: 'mem': device_add
[ 0.356110] device: 'kmem': device_add
[ 0.357737] device: 'null': device_add
[ 0.359373] device: 'zero': device_add
[ 0.361445] device: 'full': device_add
[ 0.363081] device: 'random': device_add
[ 0.364738] device: 'urandom': device_add
[ 0.366391] device: 'kmsg': device_add
[ 0.368042] device: 'tty': device_add
[ 0.369797] device: 'console': device_add
[ 0.371798] device class 'firmware': registering
[ 0.373031] device class 'thermal': registering
[ 0.375174] NET: Registered protocol family 2
[ 0.380793] IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.389420] TCP established hash table entries: 4096 (order: 3, 32768 bytes)
[ 0.397191] TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
[ 0.403931] TCP: Hash tables configured (established 4096 bind 4096)
[ 0.410141] TCP: reno registered
[ 0.413212] UDP hash table entries: 256 (order: 0, 4096 bytes)
[ 0.419057] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[ 0.426463] NET: Registered protocol family 1
[ 0.432619] RPC: Registered named UNIX socket transport module.
[ 0.438291] RPC: Registered udp transport module.
[ 0.443459] RPC: Registered tcp transport module.
[ 0.447931] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 0.493551] Registering platform device 'rtc-generic'. Parent at platform
[ 0.493649] device: 'rtc-generic': device_add
[ 0.493788] bus: 'platform': add device rtc-generic
[ 0.494880] MIAE declare_of_platform_devices()
[ 0.499330] device: 'ff000100.localbus': device_add
[ 0.499487] bus: 'platform': add device ff000100.localbus
[ 0.501396] device: '40000000.flash': device_add
[ 0.501549] bus: 'platform': add device 40000000.flash
[ 0.502899] device: 'c0000000.nand': device_add
[ 0.503051] bus: 'platform': add device c0000000.nand
[ 0.504625] device: 'c8000000.cpld-cmpc': device_add
[ 0.504781] bus: 'platform': add device c8000000.cpld-cmpc
[ 0.506303] device: 'c8000000.cpld-mpc': device_add
[ 0.506464] bus: 'platform': add device c8000000.cpld-mpc
[ 0.507966] device: 'd0000000.fpga-m': device_add
[ 0.508126] bus: 'platform': add device d0000000.fpga-m
[ 0.510502] device: 'd2000000.e1': device_add
[ 0.510654] bus: 'platform': add device d2000000.e1
[ 0.512758] device: 'e0000000.dpram': device_add
[ 0.512913] bus: 'platform': add device e0000000.dpram
[ 0.514469] device: 'f0000000.dsp': device_add
[ 0.514620] bus: 'platform': add device f0000000.dsp
[ 0.516116] device: 'd0000042.GPIO': device_add
[ 0.516270] bus: 'platform': add device d0000042.GPIO
[ 0.517683] device: 'soc.0': device_add
[ 0.517834] bus: 'platform': add device soc.0
[ 0.519352] device: 'ff000000.watchdog': device_add
[ 0.519510] bus: 'platform': add device ff000000.watchdog
[ 0.521164] bus: 'platform': driver_probe_device: matched device ff000000.watchdog with driver mpc8xxx_wdt
[ 0.521279] bus: 'platform': really_probe: probing driver mpc8xxx_wdt with device ff000000.watchdog
[ 0.521572] mpc8xxx_wdt: could not be enabled in software
[ 0.526748] mpc8xxx_wdt: probe of ff000000.watchdog failed with error -38
[ 0.534033] device: 'ff000e00.mdio': device_add
[ 0.534183] bus: 'platform': add device ff000e00.mdio
[ 0.536047] device: 'ff000e00.ethernet': device_add
[ 0.536201] bus: 'platform': add device ff000e00.ethernet
[ 0.538220] device: 'ff001e00.ethernet': device_add
[ 0.538376] bus: 'platform': add device ff001e00.ethernet
[ 0.540262] device: 'ff000000.pic': device_add
[ 0.540413] bus: 'platform': add device ff000000.pic
[ 0.542495] device: 'ff000200.sit': device_add
[ 0.542646] bus: 'platform': add device ff000200.sit
[ 0.544347] device: 'ff0009c0.cpm': device_add
[ 0.544503] bus: 'platform': add device ff0009c0.cpm
[ 0.545955] device: 'muram.1': device_add
[ 0.546105] bus: 'platform': add device muram.1
[ 0.547601] device: 'ff0009f0.brg': device_add
[ 0.547754] bus: 'platform': add device ff0009f0.brg
[ 0.549874] device: 'ff000930.pic': device_add
[ 0.550348] bus: 'platform': add device ff000930.pic
[ 0.551936] device: 'ff000950.gpio-controller': device_add
[ 0.552097] bus: 'platform': add device ff000950.gpio-controller
[ 0.553636] device: 'ff000ab8.gpio-controller': device_add
[ 0.553798] bus: 'platform': add device ff000ab8.gpio-controller
[ 0.556578] device: 'ff000960.gpio-controller': device_add
[ 0.556743] bus: 'platform': add device ff000960.gpio-controller
[ 0.558297] device: 'ff000970.gpio-controller': device_add
[ 0.558458] bus: 'platform': add device ff000970.gpio-controller
[ 0.560395] device: 'ff000ac8.gpio-controller': device_add
[ 0.560556] bus: 'platform': add device ff000ac8.gpio-controller
[ 0.562169] device: 'ff0009c0.tsa': device_add
[ 0.562320] bus: 'platform': add device ff0009c0.tsa
[ 0.564072] device: 'ff000a80.serial': device_add
[ 0.564230] bus: 'platform': add device ff000a80.serial
[ 0.566300] device: 'ff000a20.serial': device_add
[ 0.566458] bus: 'platform': add device ff000a20.serial
[ 0.568565] device: 'ff000a40.tdm': device_add
[ 0.568724] bus: 'platform': add device ff000a40.tdm
[ 0.571169] device: 'ff000a60.tdm': device_add
[ 0.571328] bus: 'platform': add device ff000a60.tdm
[ 0.573531] device: 'ff000a90.tdm_smc': device_add
[ 0.573689] bus: 'platform': add device ff000a90.tdm_smc
[ 0.575816] device: 'ff000a80.spi': device_add
[ 0.575977] bus: 'platform': add device ff000a80.spi
[ 0.577542] device: 'ff00a980.dummy_pio': device_add
[ 0.577704] bus: 'platform': add device ff00a980.dummy_pio
[ 0.579225] device: 'ff000002.gpio-controller': device_add
[ 0.579394] bus: 'platform': add device ff000002.gpio-controller
[ 0.581054] CTS2 and CTS3 temporarily deactivated (FEV170)
[ 0.586510] gpiochip_find_base: found new base at 896
[ 0.586636] device: 'gpiochip896': device_add
[ 0.588093] gpiochip_add: registered GPIOs 896 to 911 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@00
[ 0.599034] gpiochip_find_base: found new base at 880
[ 0.599165] device: 'gpiochip880': device_add
[ 0.600516] gpiochip_add: registered GPIOs 880 to 895 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@02
[ 0.611617] gpiochip_find_base: found new base at 864
[ 0.611807] device: 'gpiochip864': device_add
[ 0.613003] gpiochip_add: registered GPIOs 864 to 879 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@04
[ 0.624149] gpiochip_find_base: found new base at 848
[ 0.624279] device: 'gpiochip848': device_add
[ 0.625456] gpiochip_add: registered GPIOs 848 to 863 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@10
[ 0.636625] gpiochip_find_base: found new base at 832
[ 0.636752] device: 'gpiochip832': device_add
[ 0.637993] gpiochip_add: registered GPIOs 832 to 847 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@20
[ 0.649112] gpiochip_find_base: found new base at 816
[ 0.649241] device: 'gpiochip816': device_add
[ 0.650637] gpiochip_add: registered GPIOs 816 to 831 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@22
[ 0.661713] gpiochip_find_base: found new base at 800
[ 0.661840] device: 'gpiochip800': device_add
[ 0.663101] gpiochip_add: registered GPIOs 800 to 815 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@24
[ 0.674239] gpiochip_find_base: found new base at 784
[ 0.674369] device: 'gpiochip784': device_add
[ 0.675551] gpiochip_add: registered GPIOs 784 to 799 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@26
[ 0.686714] gpiochip_find_base: found new base at 768
[ 0.686844] device: 'gpiochip768': device_add
[ 0.688026] gpiochip_add: registered GPIOs 768 to 783 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@28
[ 0.699202] gpiochip_find_base: found new base at 752
[ 0.699332] device: 'gpiochip752': device_add
[ 0.700721] gpiochip_add: registered GPIOs 752 to 767 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@2A
[ 0.711803] gpiochip_find_base: found new base at 736
[ 0.711931] device: 'gpiochip736': device_add
[ 0.713252] gpiochip_add: registered GPIOs 736 to 751 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@2C
[ 0.728958] gpiochip_find_base: found new base at 720
[ 0.729088] device: 'gpiochip720': device_add
[ 0.730524] gpiochip_add: registered GPIOs 720 to 735 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@30
[ 0.741588] gpiochip_find_base: found new base at 704
[ 0.741718] device: 'gpiochip704': device_add
[ 0.742907] gpiochip_add: registered GPIOs 704 to 719 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@32
[ 0.754062] gpiochip_find_base: found new base at 688
[ 0.754192] device: 'gpiochip688': device_add
[ 0.755386] gpiochip_add: registered GPIOs 688 to 703 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@40
[ 0.768695] gpiochip_find_base: found new base at 672
[ 0.768823] device: 'gpiochip672': device_add
[ 0.770226] gpiochip_add: registered GPIOs 672 to 687 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@42
[ 0.784715] gpiochip_find_base: found new base at 656
[ 0.784844] device: 'gpiochip656': device_add
[ 0.786031] gpiochip_add: registered GPIOs 656 to 671 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@44
[ 0.797136] gpiochip_find_base: found new base at 640
[ 0.797265] device: 'gpiochip640': device_add
[ 0.798449] gpiochip_add: registered GPIOs 640 to 655 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@50
[ 0.809624] gpiochip_find_base: found new base at 624
[ 0.809754] device: 'gpiochip624': device_add
[ 0.811165] gpiochip_add: registered GPIOs 624 to 639 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@52
[ 0.822229] gpiochip_find_base: found new base at 608
[ 0.822359] device: 'gpiochip608': device_add
[ 0.823636] gpiochip_add: registered GPIOs 608 to 623 on device: /localbus@ff000100/fpga-m@4,0000000/gpio-controller@54
[ 0.834743] Number of GPIO found = 0
[ 0.839274] bus: 'clocksource': registered
[ 0.839398] device: 'clocksource': device_add
[ 0.839573] device: 'clocksource0': device_add
[ 0.839708] bus: 'clocksource': add device clocksource0
[ 0.841307] bus: 'platform': add driver alarmtimer
[ 0.842717] Registering platform device 'alarmtimer'. Parent at platform
[ 0.842816] device: 'alarmtimer': device_add
[ 0.842957] bus: 'platform': add device alarmtimer
[ 0.844218] bus: 'platform': driver_probe_device: matched device alarmtimer with driver alarmtimer
[ 0.844329] bus: 'platform': really_probe: probing driver alarmtimer with device alarmtimer
[ 0.844484] driver: 'alarmtimer': driver_bound: bound to device 'alarmtimer'
[ 0.844581] bus: 'platform': really_probe: bound device alarmtimer to driver alarmtimer
[ 0.946411] msgmni has been set to 244
[ 0.952742] device: 'ptyp0': device_add
[ 0.954595] device: 'ptyp1': device_add
[ 0.956281] device: 'ptyp2': device_add
[ 0.957965] device: 'ptyp3': device_add
[ 0.959777] device: 'ptyp4': device_add
[ 0.961841] device: 'ttyp0': device_add
[ 0.963542] device: 'ttyp1': device_add
[ 0.965243] device: 'ttyp2': device_add
[ 0.967064] device: 'ttyp3': device_add
[ 0.968758] device: 'ttyp4': device_add
[ 0.970845] device: 'ptmx': device_add
[ 0.972612] bus: 'platform': add driver cpm_uart
[ 0.973307] bus: 'platform': driver_probe_device: matched device ff000a80.serial with driver cpm_uart
[ 0.973416] bus: 'platform': really_probe: probing driver cpm_uart with device ff000a80.serial
[ 0.973925] ff000a80.serial: ttyCPM0 at MMIO 0xc9048a80 (irq = 20) is a CPM UART
[ 0.981598] device: 'ttyCPM0': device_add
[ 0.983183] driver: 'ff000a80.serial': driver_bound: bound to device 'cpm_uart'
[ 0.983290] bus: 'platform': really_probe: bound device ff000a80.serial to driver cpm_uart
[ 0.983421] bus: 'platform': driver_probe_device: matched device ff000a20.serial with driver cpm_uart
[ 0.983520] bus: 'platform': really_probe: probing driver cpm_uart with device ff000a20.serial
[ 0.984208] ff000a20.serial: ttyCPM1 at MMIO 0xc904ca20 (irq = 39) is a CPM UART
[ 0.991793] device: 'ttyCPM1': device_add
[ 0.993465] driver: 'ff000a20.serial': driver_bound: bound to device 'cpm_uart'
[ 0.993572] bus: 'platform': really_probe: bound device ff000a20.serial to driver cpm_uart
[ 0.995444] Generic RTC Driver v1.07
[ 0.998755] device: 'rtc': device_add
[ 1.000927] bus: 'spi': add driver at25
[ 1.002200] device class 'mtd': registering
[ 1.003448] device: 'mtd-unmap': device_add
[ 1.004812] device: 'mtd-romap': device_add
[ 1.006189] device: 'mtd-rwmap': device_add
[ 1.007718] bus: 'platform': add driver of-flash
[ 1.007938] bus: 'platform': driver_probe_device: matched device 40000000.flash with driver of-flash
[ 1.008046] bus: 'platform': really_probe: probing driver of-flash with device 40000000.flash
[ 1.009123] 40000000.flash: Found 1 x16 devices at 0x0 in 16-bit bank. Manufacturer ID 0x000020 Chip ID 0x002257
[ 1.019662] Amd/Fujitsu Extended Query Table at 0x0040
[ 1.024787] Amd/Fujitsu Extended Query version 1.1.
[ 1.029546] number of CFI chips: 1
[ 1.034403] 4 ofpart partitions found on MTD device 40000000.flash
[ 1.040614] Creating 4 MTD partitions on "40000000.flash":
[ 1.045835] 0x000000000000-0x000000050000 : "boot"
[ 1.050810] device: 'mtd0': device_add
[ 1.052636] device: 'mtd0ro': device_add
[ 1.054362] 0x000000050000-0x000000060000 : "env"
[ 1.058855] device: 'mtd1': device_add
[ 1.060941] device: 'mtd1ro': device_add
[ 1.062670] 0x000000060000-0x000000090000 : "blob"
[ 1.067283] device: 'mtd2': device_add
[ 1.069226] device: 'mtd2ro': device_add
[ 1.071290] 0x000000090000-0x000000400000 : "kernel"
[ 1.076064] device: 'mtd3': device_add
[ 1.077916] device: 'mtd3ro': device_add
[ 1.079619] driver: '40000000.flash': driver_bound: bound to device 'of-flash'
[ 1.079728] bus: 'platform': really_probe: bound device 40000000.flash to driver of-flash
[ 1.081833] bus: 'platform': add driver cmpc885-nand
[ 1.082059] bus: 'platform': driver_probe_device: matched device c0000000.nand with driver cmpc885-nand
[ 1.082169] bus: 'platform': really_probe: probing driver cmpc885-nand with device c0000000.nand
[ 1.083191] NAND device: Manufacturer ID: 0xad, Chip ID: 0x76 (Hynix NAND 64MiB 3,3V 8-bit)
[ 1.091734] Scanning device for bad blocks
[ 1.431745] device: 'mtd4': device_add
[ 1.433479] device: 'mtd4ro': device_add
[ 1.435182] driver: 'c0000000.nand': driver_bound: bound to device 'cmpc885-nand'
[ 1.435292] bus: 'platform': really_probe: bound device c0000000.nand to driver cmpc885-nand
[ 1.436826] bus: 'platform': add driver gen_nand
[ 1.438182] device class 'ubi': registering
[ 1.439458] device: 'ubi_ctrl': device_add
[ 1.441662] bus: 'platform': add driver fsl_spi
[ 1.442087] bus: 'platform': driver_probe_device: matched device ff000a80.spi with driver fsl_spi
[ 1.442194] bus: 'platform': really_probe: probing driver fsl_spi with device ff000a80.spi
[ 1.445117] device: 'spi32766': device_add
[ 1.446456] fsl_spi ff000a80.spi: master is unqueued, this is deprecated
[ 1.454691] device: 'spi32766.0': device_add
[ 1.454853] bus: 'spi': add device spi32766.0
[ 1.457526] device: 'spi32766.1': device_add
[ 1.457689] bus: 'spi': add device spi32766.1
[ 1.460862] device: 'spi32766.2': device_add
[ 1.461025] bus: 'spi': add device spi32766.2
[ 1.463718] device: 'spi32766.3': device_add
[ 1.463882] bus: 'spi': add device spi32766.3
[ 1.465083] bus: 'spi': driver_probe_device: matched device spi32766.3 with driver at25
[ 1.465188] bus: 'spi': really_probe: probing driver at25 with device spi32766.3
[ 1.465956] at25 spi32766.3: 1 KByte at25080 eeprom, pagesize 32
[ 1.472245] driver: 'spi32766.3': driver_bound: bound to device 'at25'
[ 1.472349] bus: 'spi': really_probe: bound device spi32766.3 to driver at25
[ 1.473868] device: 'spi32766.4': device_add
[ 1.474033] bus: 'spi': add device spi32766.4
[ 1.476755] device: 'spi32766.5': device_add
[ 1.476919] bus: 'spi': add device spi32766.5
[ 1.479626] device: 'spi32766.6': device_add
[ 1.479791] bus: 'spi': add device spi32766.6
[ 1.481491] bus: 'spi': driver_probe_device: matched device spi32766.6 with driver at25
[ 1.481596] bus: 'spi': really_probe: probing driver at25 with device spi32766.6
[ 1.482316] at25 spi32766.6: 1 KByte at25080 eeprom, pagesize 32
[ 1.488067] driver: 'spi32766.6': driver_bound: bound to device 'at25'
[ 1.488158] bus: 'spi': really_probe: bound device spi32766.6 to driver at25
[ 1.488294] fsl_spi ff000a80.spi: at 0xc9056a80 (irq = 43), CPM1 mode
[ 1.494846] driver: 'ff000a80.spi': driver_bound: bound to device 'fsl_spi'
[ 1.494953] bus: 'platform': really_probe: bound device ff000a80.spi to driver fsl_spi
[ 1.496083] bonding: Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
[ 1.504285] device: 'bond0': device_add
[ 1.528580] bus: 'mdio_bus': add driver LXT970
[ 1.530367] bus: 'mdio_bus': add driver LXT971
[ 1.531640] bus: 'mdio_bus': add driver LXT973
[ 1.532923] bus: 'mdio_bus': add driver Micrel KS8001 or KS8721
[ 1.534223] bus: 'mdio_bus': add driver Micrel KSZ9021 Gigabit PHY
[ 1.535526] bus: 'mdio_bus': add driver Micrel KS8737
[ 1.536813] bus: 'mdio_bus': add driver Micrel KS8041
[ 1.538118] bus: 'mdio_bus': add driver Micrel KS8051
[ 1.539420] bus: 'platform': add driver fs_enet
[ 1.539726] bus: 'platform': driver_probe_device: matched device ff000e00.ethernet with driver fs_enet
[ 1.539836] bus: 'platform': really_probe: probing driver fs_enet with device ff000e00.ethernet
[ 1.540997] device: 'eth0': device_add
[ 1.545222] eth0: fs_enet: 08:00:51:20:44:23
[ 1.549360] driver: 'ff000e00.ethernet': driver_bound: bound to device 'fs_enet'
[ 1.549463] bus: 'platform': really_probe: bound device ff000e00.ethernet to driver fs_enet
[ 1.549589] bus: 'platform': driver_probe_device: matched device ff001e00.ethernet with driver fs_enet
[ 1.549691] bus: 'platform': really_probe: probing driver fs_enet with device ff001e00.ethernet
[ 1.550767] PHY-disable = isolate
[ 1.554310] device: 'eth1': device_add
[ 1.558272] eth1: fs_enet: 08:00:51:20:44:24
[ 1.562840] driver: 'ff001e00.ethernet': driver_bound: bound to device 'fs_enet'
[ 1.562949] bus: 'platform': really_probe: bound device ff001e00.ethernet to driver fs_enet
[ 1.564230] bus: 'platform': add driver fsl-fec-mdio
[ 1.564521] bus: 'platform': driver_probe_device: matched device ff000e00.mdio with driver fsl-fec-mdio
[ 1.564631] bus: 'platform': really_probe: probing driver fsl-fec-mdio with device ff000e00.mdio
[ 1.564972] device: 'ff000e00': device_add
[ 1.566333] FEC MII Bus: probed
[ 1.571618] device: 'ff000e00:01': device_add
[ 1.571785] bus: 'mdio_bus': add device ff000e00:01
[ 1.572929] bus: 'mdio_bus': driver_probe_device: matched device ff000e00:01 with driver Micrel KS8041
[ 1.573041] bus: 'mdio_bus': really_probe: probing driver Micrel KS8041 with device ff000e00:01
[ 1.573215] driver: 'ff000e00:01': driver_bound: bound to device 'Micrel KS8041'
[ 1.573317] bus: 'mdio_bus': really_probe: bound device ff000e00:01 to driver Micrel KS8041
[ 1.575186] device: 'ff000e00:02': device_add
[ 1.575354] bus: 'mdio_bus': add device ff000e00:02
[ 1.576498] bus: 'mdio_bus': driver_probe_device: matched device ff000e00:02 with driver Micrel KS8041
[ 1.576610] bus: 'mdio_bus': really_probe: probing driver Micrel KS8041 with device ff000e00:02
[ 1.576784] driver: 'ff000e00:02': driver_bound: bound to device 'Micrel KS8041'
[ 1.576886] bus: 'mdio_bus': really_probe: bound device ff000e00:02 to driver Micrel KS8041
[ 1.578760] device: 'ff000e00:03': device_add
[ 1.578929] bus: 'mdio_bus': add device ff000e00:03
[ 1.580484] bus: 'mdio_bus': driver_probe_device: matched device ff000e00:03 with driver Micrel KS8041
[ 1.580597] bus: 'mdio_bus': really_probe: probing driver Micrel KS8041 with device ff000e00:03
[ 1.580771] driver: 'ff000e00:03': driver_bound: bound to device 'Micrel KS8041'
[ 1.580872] bus: 'mdio_bus': really_probe: bound device ff000e00:03 to driver Micrel KS8041
[ 1.580990] driver: 'ff000e00.mdio': driver_bound: bound to device 'fsl-fec-mdio'
[ 1.581084] bus: 'platform': really_probe: bound device ff000e00.mdio to driver fsl-fec-mdio
[ 1.582511] bus: 'spi': add driver lm70
[ 1.582694] bus: 'spi': driver_probe_device: matched device spi32766.1 with driver lm70
[ 1.582795] bus: 'spi': really_probe: probing driver lm70 with device spi32766.1
[ 1.583147] device: 'hwmon0': device_add
[ 1.584544] driver: 'spi32766.1': driver_bound: bound to device 'lm70'
[ 1.584650] bus: 'spi': really_probe: bound device spi32766.1 to driver lm70
[ 1.584762] bus: 'spi': driver_probe_device: matched device spi32766.5 with driver lm70
[ 1.584852] bus: 'spi': really_probe: probing driver lm70 with device spi32766.5
[ 1.585124] device: 'hwmon1': device_add
[ 1.586574] driver: 'spi32766.5': driver_bound: bound to device 'lm70'
[ 1.586679] bus: 'spi': really_probe: bound device spi32766.5 to driver lm70
[ 1.587942] bus: 'platform': add driver talitos
[ 1.589613] nf_conntrack version 0.5.0 (1959 buckets, 7836 max)
[ 1.601203] ip_tables: (C) 2000-2006 Netfilter Core Team
[ 1.606999] TCP: cubic registered
[ 1.610492] NET: Registered protocol family 17
[ 1.614758] 8021q: 802.1Q VLAN Support v1.8
[ 1.619247] device: 'cpu_dma_latency': device_add
[ 1.621013] device: 'network_latency': device_add
[ 1.622734] device: 'network_throughput': device_add
[ 1.638486] Freeing unused kernel memory: 488k freed
[ 1.745200] UBI: attaching mtd4 to ubi0
[ 1.752891] UBI: physical eraseblock size: 16384 bytes (16 KiB)
[ 1.758719] UBI: logical eraseblock size: 15872 bytes
[ 1.764104] UBI: smallest flash I/O unit: 512
[ 1.768529] UBI: sub-page size: 256
[ 1.773225] UBI: VID header offset: 256 (aligned 256)
[ 1.778856] UBI: data offset: 512
[ 2.707154] UBI: max. sequence number: 3567
[ 2.755007] device: 'ubi0': device_add
[ 2.756808] device: 'ubi0_0': device_add
[ 2.759183] UBI: attached mtd4 to ubi0
[ 2.763020] UBI: MTD device name: "cmpc885-nand"
[ 2.768298] UBI: MTD device size: 64 MiB
[ 2.773283] UBI: number of good PEBs: 4096
[ 2.777761] UBI: number of bad PEBs: 0
[ 2.782282] UBI: number of corrupted PEBs: 0
[ 2.786540] UBI: max. allowed volumes: 92
[ 2.791145] UBI: wear-leveling threshold: 4096
[ 2.795662] UBI: number of internal volumes: 1
[ 2.800180] UBI: number of user volumes: 1
[ 2.804440] UBI: available PEBs: 0
[ 2.808829] UBI: total number of reserved PEBs: 4096
[ 2.813866] UBI: number of PEBs reserved for bad PEB handling: 40
[ 2.819763] UBI: max/mean erase counter: 13/8
[ 2.824195] UBI: image sequence number: 1870984234
[ 2.828961] UBI: background thread "ubi_bgt0d" started, PID 356
[ 2.851633] device: 'ubifs_0_0': device_add
[ 2.913328] UBIFS: mounted UBI device 0, volume 0, name "rootfs"
[ 2.919092] UBIFS: file system size: 63837184 bytes (62341 KiB, 60 MiB, 4022 LEBs)
[ 2.926908] UBIFS: journal size: 8428032 bytes (8230 KiB, 8 MiB, 531 LEBs)
[ 2.934191] UBIFS: media format: w4/r0 (latest is w4/r0)
[ 2.939814] UBIFS: default compressor: lzo
[ 2.943991] UBIFS: reserved for root: 0 bytes (0 KiB)
^ permalink raw reply
* если хош подружиться
From: Эльзонька Фильченкова @ 2012-08-06 3:53 UTC (permalink / raw)
To: netdev
http://translate.yandex.net/ya.ru/../tr-url/ya.ru/../en-ru.ru/www.burghleycourt.com/privat.php/ya.ru/../
^ permalink raw reply
* Re: skb_warn_bad_offload with kernel 3.5 (maybe gso/bridge related ?)
From: Herbert Xu @ 2012-08-06 9:18 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Eric Dumazet, Yann Dupont, netdev@vger.kernel.org
In-Reply-To: <1344008408.4642.160.camel@deadeye.wl.decadent.org.uk>
On Fri, Aug 03, 2012 at 04:40:08PM +0100, Ben Hutchings wrote:
>
> I think GRO is doing the right thing, and I can't think why we should
> see ip_summed = CHECKSUM_PARTIAL if the skb is forwarded by a bridge. I
If it is was created by GRO then it should always be CHECKSUM_PARTIAL,
even if it came through a bridge.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH 1/7] netpoll: use GFP_ATOMIC in slave_enable_netpoll() and __netpoll_setup()
From: Cong Wang @ 2012-08-06 9:08 UTC (permalink / raw)
To: Eric Dumazet
Cc: netdev, David S. Miller, Jay Vosburgh, Andy Gospodarek,
Eric Dumazet, Cong Wang, Joe Perches, Neil Horman, linux-kernel
In-Reply-To: <1343988623.9299.932.camel@edumazet-glaptop>
On Fri, 2012-08-03 at 12:10 +0200, Eric Dumazet wrote:
>
> I did this , just take it ;)
Do we have to pass gfp to ->ndo_netpoll_setup() too? It seems no, so far
I don't think we have to do that.
Thanks.
^ permalink raw reply
* Re: [PATCH RFC] net: tcp: GRO should be ECN friendly
From: Herbert Xu @ 2012-08-06 9:01 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1344242090.9299.1656.camel@edumazet-glaptop>
On Mon, Aug 06, 2012 at 10:34:50AM +0200, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> While doing TCP ECN tests, I discovered GRO was reordering packets if it
> receives one packet with CE set, while previous packets in same NAPI run
> have ECT(0) for the same flow :
>
> 09:25:25.857620 IP (tos 0x2,ECT(0), ttl 64, id 27893, offset 0, flags
> [DF], proto TCP (6), length 4396)
> 172.30.42.19.54550 > 172.30.42.13.44139: Flags [.], seq
> 233801:238145, ack 1, win 115, options [nop,nop,TS val 3397779 ecr
> 1990627], length 4344
>
> 09:25:25.857626 IP (tos 0x3,CE, ttl 64, id 27892, offset 0, flags [DF],
> proto TCP (6), length 1500)
> 172.30.42.19.54550 > 172.30.42.13.44139: Flags [.], seq
> 232353:233801, ack 1, win 115, options [nop,nop,TS val 3397779 ecr
> 1990627], length 1448
>
> 09:25:25.857638 IP (tos 0x0, ttl 64, id 34581, offset 0, flags [DF],
> proto TCP (6), length 64)
> 172.30.42.13.44139 > 172.30.42.19.54550: Flags [.], cksum 0xac8f
> (incorrect -> 0xca69), ack 232353, win 1271, options [nop,nop,TS val
> 1990627 ecr 3397779,nop,nop,sack 1 {233801:238145}], length 0
>
> We have two problems here :
>
> 1) GRO reorders packets
>
> If NIC gave packet1, then packet2, which happen to be from "different
> flows" GRO feeds stack with packet2, then packet1. I have yet to
> understand how to solve this problem.
>
> 2) GRO is not ECN friendly
>
> Delivering packets out of order makes TCP stack not as fast as it could
> be.
>
> In this patch I suggest we make the tos test not part of the 'same_flow'
> determination, but part of the 'should flush' logic
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Good catch, thanks Eric!
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH RFC] net: tcp: GRO should be ECN friendly
From: Eric Dumazet @ 2012-08-06 8:34 UTC (permalink / raw)
To: David Miller, Herbert Xu; +Cc: netdev
From: Eric Dumazet <edumazet@google.com>
While doing TCP ECN tests, I discovered GRO was reordering packets if it
receives one packet with CE set, while previous packets in same NAPI run
have ECT(0) for the same flow :
09:25:25.857620 IP (tos 0x2,ECT(0), ttl 64, id 27893, offset 0, flags
[DF], proto TCP (6), length 4396)
172.30.42.19.54550 > 172.30.42.13.44139: Flags [.], seq
233801:238145, ack 1, win 115, options [nop,nop,TS val 3397779 ecr
1990627], length 4344
09:25:25.857626 IP (tos 0x3,CE, ttl 64, id 27892, offset 0, flags [DF],
proto TCP (6), length 1500)
172.30.42.19.54550 > 172.30.42.13.44139: Flags [.], seq
232353:233801, ack 1, win 115, options [nop,nop,TS val 3397779 ecr
1990627], length 1448
09:25:25.857638 IP (tos 0x0, ttl 64, id 34581, offset 0, flags [DF],
proto TCP (6), length 64)
172.30.42.13.44139 > 172.30.42.19.54550: Flags [.], cksum 0xac8f
(incorrect -> 0xca69), ack 232353, win 1271, options [nop,nop,TS val
1990627 ecr 3397779,nop,nop,sack 1 {233801:238145}], length 0
We have two problems here :
1) GRO reorders packets
If NIC gave packet1, then packet2, which happen to be from "different
flows" GRO feeds stack with packet2, then packet1. I have yet to
understand how to solve this problem.
2) GRO is not ECN friendly
Delivering packets out of order makes TCP stack not as fast as it could
be.
In this patch I suggest we make the tos test not part of the 'same_flow'
determination, but part of the 'should flush' logic
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/af_inet.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index fe4582c..6681ccf 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1364,7 +1364,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
if (*(u8 *)iph != 0x45)
goto out_unlock;
- if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
+ if (unlikely(ip_fast_csum((u8 *)iph, 5)))
goto out_unlock;
id = ntohl(*(__be32 *)&iph->id);
@@ -1380,7 +1380,6 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
iph2 = ip_hdr(p);
if ((iph->protocol ^ iph2->protocol) |
- (iph->tos ^ iph2->tos) |
((__force u32)iph->saddr ^ (__force u32)iph2->saddr) |
((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) {
NAPI_GRO_CB(p)->same_flow = 0;
@@ -1390,6 +1389,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
/* All fields must match except length and checksum. */
NAPI_GRO_CB(p)->flush |=
(iph->ttl ^ iph2->ttl) |
+ (iph->tos ^ iph2->tos) |
((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
NAPI_GRO_CB(p)->flush |= flush;
^ permalink raw reply related
* Re: [PATCH v2] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Oliver Neukum @ 2012-08-06 8:10 UTC (permalink / raw)
To: Olivier Sobrie
Cc: Wolfgang Grandegger, Marc Kleine-Budde, linux-can, linux-usb,
netdev
In-Reply-To: <1344230489-16595-1-git-send-email-olivier@sobrie.be>
On Monday 06 August 2012 07:21:29 Olivier Sobrie wrote:
> This driver provides support for several Kvaser CAN/USB devices.
> Such kind of devices supports up to three can network interfaces.
>
> It has been tested with a Kvaser USB Leaf Light (one network interface)
> connected to a pch_can interface.
> The firmware version of the Kvaser device was 2.5.205.
> +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
> + struct net_device *netdev)
> +{
> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> + struct kvaser_usb *dev = priv->dev;
> + struct net_device_stats *stats = &netdev->stats;
> + struct can_frame *cf = (struct can_frame *)skb->data;
> + struct kvaser_usb_tx_urb_context *context = NULL;
> + struct urb *urb;
> + void *buf;
> + struct kvaser_msg *msg;
> + int i, err;
> + int ret = NETDEV_TX_OK;
> +
> + if (can_dropped_invalid_skb(netdev, skb))
> + return NETDEV_TX_OK;
> +
> + urb = usb_alloc_urb(0, GFP_ATOMIC);
> + if (!urb) {
> + netdev_err(netdev, "No memory left for URBs\n");
> + stats->tx_dropped++;
> + dev_kfree_skb(skb);
> + return NETDEV_TX_OK;
> + }
> +
> + buf = usb_alloc_coherent(dev->udev, sizeof(struct kvaser_msg),
> + GFP_ATOMIC, &urb->transfer_dma);
usb_alloc_coherent() as a rule only makes sense if you reuse the buffer
and in some cases not even then. Please use a simple kmalloc()
> + if (!buf) {
> + netdev_err(netdev, "No memory left for USB buffer\n");
> + stats->tx_dropped++;
> + dev_kfree_skb(skb);
> + goto nobufmem;
> + }
> +
> + msg = (struct kvaser_msg *)buf;
> + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
> + msg->u.tx_can.flags = 0;
> + msg->u.tx_can.channel = priv->channel;
> +
> + if (cf->can_id & CAN_EFF_FLAG) {
> + msg->id = CMD_TX_EXT_MESSAGE;
> + msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
> + msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
> + msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
> + msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
> + msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
> + } else {
> + msg->id = CMD_TX_STD_MESSAGE;
> + msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
> + msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
> + }
> +
> + msg->u.tx_can.msg[5] = cf->can_dlc;
> + memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
> +
> + if (cf->can_id & CAN_RTR_FLAG)
> + msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
> +
> + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
> + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
> + context = &priv->tx_contexts[i];
> + break;
> + }
> + }
> +
> + if (!context) {
> + netdev_warn(netdev, "cannot find free context\n");
> + ret = NETDEV_TX_BUSY;
> + goto releasebuf;
> + }
> +
> + context->priv = priv;
> + context->echo_index = i;
> + context->dlc = cf->can_dlc;
> +
> + msg->u.tx_can.tid = context->echo_index;
> +
> + usb_fill_bulk_urb(urb, dev->udev,
> + usb_sndbulkpipe(dev->udev,
> + dev->bulk_out->bEndpointAddress),
> + buf, msg->len,
> + kvaser_usb_write_bulk_callback, context);
> + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
> + usb_anchor_urb(urb, &priv->tx_submitted);
> +
> + can_put_echo_skb(skb, netdev, context->echo_index);
> +
> + atomic_inc(&priv->active_tx_urbs);
> +
> + if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
> + netif_stop_queue(netdev);
> +
> + err = usb_submit_urb(urb, GFP_ATOMIC);
> + if (unlikely(err)) {
> + can_free_echo_skb(netdev, context->echo_index);
> +
> + atomic_dec(&priv->active_tx_urbs);
> + usb_unanchor_urb(urb);
> +
> + stats->tx_dropped++;
> +
> + if (err == -ENODEV)
> + netif_device_detach(netdev);
> + else
> + netdev_warn(netdev, "Failed tx_urb %d\n", err);
> +
> + goto releasebuf;
> + }
> +
> + netdev->trans_start = jiffies;
> +
> + usb_free_urb(urb);
> +
> + return NETDEV_TX_OK;
> +
> +releasebuf:
> + usb_free_coherent(dev->udev, sizeof(struct kvaser_msg),
> + buf, urb->transfer_dma);
> +nobufmem:
> + usb_free_urb(urb);
> + return ret;
> +}
> +static int kvaser_usb_init_one(struct usb_interface *intf,
> + const struct usb_device_id *id, int channel)
> +{
> + struct kvaser_usb *dev = usb_get_intfdata(intf);
> + struct net_device *netdev;
> + struct kvaser_usb_net_priv *priv;
> + int i, err;
> +
> + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
> + if (!netdev) {
> + dev_err(&intf->dev, "Cannot alloc candev\n");
> + return -ENOMEM;
> + }
> +
> + priv = netdev_priv(netdev);
> +
> + init_completion(&priv->start_comp);
> + init_completion(&priv->stop_comp);
> +
> + init_usb_anchor(&priv->tx_submitted);
> + atomic_set(&priv->active_tx_urbs, 0);
> +
> + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
> +
> + priv->dev = dev;
> + priv->netdev = netdev;
> + priv->channel = channel;
> +
> + priv->can.state = CAN_STATE_STOPPED;
> + priv->can.clock.freq = CAN_USB_CLOCK;
> + priv->can.bittiming_const = &kvaser_usb_bittiming_const;
> + priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
> + priv->can.do_set_mode = kvaser_usb_set_mode;
> + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
> + if (id->driver_info & KVASER_HAS_SILENT_MODE)
> + priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
> +
> + netdev->flags |= IFF_ECHO;
> +
> + netdev->netdev_ops = &kvaser_usb_netdev_ops;
> +
> + SET_NETDEV_DEV(netdev, &intf->dev);
> +
> + err = register_candev(netdev);
> + if (err) {
> + dev_err(&intf->dev, "Failed to register can device\n");
> + free_candev(netdev);
> + return err;
> + }
> +
Here the device is usable.
> + dev->nets[channel] = priv;
And only know you init this field. Looks like a race condition.
> + netdev_dbg(netdev, "device registered\n");
> +
> + return 0;
> +}
> +
> +static void kvaser_usb_disconnect(struct usb_interface *intf)
> +{
> + struct kvaser_usb *dev = usb_get_intfdata(intf);
> + int i;
> +
> + usb_set_intfdata(intf, NULL);
> +
> + if (!dev)
> + return;
> +
> + for (i = 0; i < dev->nchannels; i++) {
> + if (!dev->nets[i])
> + continue;
> +
> + unregister_netdev(dev->nets[i]->netdev);
> + free_candev(dev->nets[i]->netdev);
> + }
> +
> + kvaser_usb_unlink_all_urbs(dev);
So what happens if an URB completes between freeing the candev
and unlinking and proceeds to push data to upper layers?
Regards
Oliver
^ permalink raw reply
* Re: [patch 1/1] ixp4xx_eth: fix ptp_ixp46x build failure
From: Richard Cochran @ 2012-08-06 6:23 UTC (permalink / raw)
To: Arnaud Patard; +Cc: netdev, Krzysztof Halasa
In-Reply-To: <20120805203042.509148064@rtp-net.org>
On Sun, Aug 05, 2012 at 10:30:11PM +0200, Arnaud Patard wrote:
> When building with ixp4xx_eth and ptp_ixp46x as module, one is getting the
> following error:
>
> ERROR: "ixp46x_phc_index" [drivers/ptp/ptp_ixp46x.ko] undefined!
>
> This has been introduced by commit 509a7c25729feab353502e1b544c614772a1d49a.
Thanks for patching this.
Acked-by: Richard Cochran <richardcochran@gmail.com>
> Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
> Index: efika/drivers/net/ethernet/xscale/ixp4xx_eth.c
> ===================================================================
> --- efika.orig/drivers/net/ethernet/xscale/ixp4xx_eth.c 2012-07-29 14:03:12.710197591 +0200
> +++ efika/drivers/net/ethernet/xscale/ixp4xx_eth.c 2012-08-05 11:13:13.188037295 +0200
> @@ -1003,6 +1003,7 @@ static int ixp4xx_nway_reset(struct net_
> }
>
> int ixp46x_phc_index = -1;
> +EXPORT_SYMBOL_GPL(ixp46x_phc_index);
>
> static int ixp4xx_get_ts_info(struct net_device *dev,
> struct ethtool_ts_info *info)
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Olivier Sobrie @ 2012-08-06 5:27 UTC (permalink / raw)
To: Wolfgang Grandegger; +Cc: Marc Kleine-Budde, linux-can, netdev
In-Reply-To: <501EDB0B.5040204@grandegger.com>
On Sun, Aug 05, 2012 at 10:43:55PM +0200, Wolfgang Grandegger wrote:
> On 08/02/2012 01:56 PM, Marc Kleine-Budde wrote:
> > On 08/02/2012 12:53 PM, Olivier Sobrie wrote:
> ...
> >> I actually implemeted it as you said and here is what I observed in
> >> candump output with restart_ms set to 100 ms:
> >>
> >> t0: Short circuit between CAN-H and CAN-L + cansend can1 123#1122
> >> can1 2000008C [8] 00 04 90 00 00 00 00 00 ERRORFRAME
> >> controller-problem{rx-error-warning}
> >> protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
> >> bus-error
> >> can1 2000008C [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> >> controller-problem{rx-error-passive}
> >> protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
> >> bus-error
> >> can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME
> >> protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
> >> bus-off
> >> bus-error
> >> ...
>
> FYI, the option "-td" nicely shows the timing. I assume that the
> "warning->passive->bus-off" sequence repeats because automatic bus-off
> is active via ip option "restart-ms xx ms". What I'm missing is the
> message "restarted-after-bus-off". Maybe it's not listed here...
Indeed it's missing. Please look at the patch I just sent if it is now
correct or not.
>
> >> can1 2000008C [8] 00 04 90 00 00 00 00 00 ERRORFRAME
> >> controller-problem{rx-error-warning}
> >> protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
> >> bus-error
> >> can1 2000008C [8] 00 10 90 00 00 00 00 00 ERRORFRAME
> >> controller-problem{rx-error-passive}
> >> protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
> >> bus-error
> >> can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME
> >> protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
> >> bus-off
> >> bus-error
> >>
> >> t1: short circuit removed
> >> can1 123 [2] 11 22
> >> can1 20000100 [8] 00 00 00 00 00 00 00 00 ERRORFRAME
> >> restarted-after-bus-of
> >>
> >> The echo coming before the restart looks weird? No?
>
> Yes. It should come later.
Ok I've to change this.
>
> >> Shouldn't we drop the frame once BUF-OFF is reached?
>
> No.
Ok.
>
> > No, I don't think so. But wait for Wolfgang, here's more into error
> > handling then me.
>
> Looking to your code it's not clear to me how you do recovery from
> bus-off (called "restart"). This is usually done via
> do_set_mode(CAN_MODE_START), either manually (restart-ms==0) or
> automatically (restart-ms>0). Could you please explain how the device
> does bus-off recovery? Does the hardware do it automatically? This
> should be suppressed if if restart-ms==0 (as Marc already pointed out).
The hardware automatically recovers from BUS-OFF if it isn't stopped.
In the second version of the patch I just sent, I put the device off if
restart-ms == 0.
Thanks,
--
Olivier
^ permalink raw reply
* [PATCH v2] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Olivier Sobrie @ 2012-08-06 5:21 UTC (permalink / raw)
To: Wolfgang Grandegger, Marc Kleine-Budde, linux-can, linux-usb
Cc: netdev, Olivier Sobrie
In-Reply-To: <1343626352-24760-1-git-send-email-olivier@sobrie.be>
This driver provides support for several Kvaser CAN/USB devices.
Such kind of devices supports up to three can network interfaces.
It has been tested with a Kvaser USB Leaf Light (one network interface)
connected to a pch_can interface.
The firmware version of the Kvaser device was 2.5.205.
List of Kvaser devices supported by the driver:
- Kvaser Leaf prototype (P010v2 and v3)
- Kvaser Leaf Light (P010v3)
- Kvaser Leaf Professional HS
- Kvaser Leaf SemiPro HS
- Kvaser Leaf Professional LS
- Kvaser Leaf Professional SWC
- Kvaser Leaf Professional LIN
- Kvaser Leaf SemiPro LS
- Kvaser Leaf SemiPro SWC
- Kvaser Memorator II, Prototype
- Kvaser Memorator II HS/HS
- Kvaser USBcan Professional HS/HS
- Kvaser Leaf Light GI
- Kvaser Leaf Professional HS (OBD-II connector)
- Kvaser Memorator Professional HS/LS
- Kvaser Leaf Light "China"
- Kvaser BlackBird SemiPro
- Kvaser OEM Mercury
- Kvaser OEM Leaf
- Kvaser USBcan R
Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
---
Changes since v1:
- added copyrights
- kvaser_usb.h merged into kvaser.c
- added kvaser_usb_get_endpoints to find eindpoints instead of
hardcoding their address
- some cleanup and comestic changes
- fixed issues with errors handling
- fixed restart-ms == 0 case
- removed do_get_berr_counter method since the hardware doens't return
good values for txerr and rxerr.
If someone in the linux-usb mailing can review it, it would be nice.
Concerning the errors, it behaves like that now:
1) Short-circuit CAN-H and CAN-L and restart-ms = 0
t0: short-circuit + 'cansend can1 123#112233'
can1 2000008C [8] 00 0C 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-warning,tx-error-warning}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
can1 2000008C [8] 00 30 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-passive,tx-error-passive}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-off
bus-error
t1: remove short-circuit + 'ip link set can1 type can restart'
can1 20000100 [8] 00 00 00 00 00 00 00 00 ERRORFRAME
restarted-after-bus-off
can1 20000004 [8] 00 0C 00 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-warning,tx-error-warning}
2) Short-circuit CAN-H and CAN-L and restart-ms = 100
t0: short-circuit + cansend can1 123#112233
can1 2000008C [8] 00 0C 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-warning,tx-error-warning}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
can1 2000008C [8] 00 30 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-passive,tx-error-passive}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-off
bus-error
can1 2000018C [8] 00 0C 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-warning,tx-error-warning}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
restarted-after-bus-off
can1 2000008C [8] 00 0C 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-warning,tx-error-warning}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
can1 2000008C [8] 00 30 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-passive,tx-error-passive}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
can1 200000C8 [8] 00 00 90 00 00 00 00 00 ERRORFRAME
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-off
bus-error
...
can1 2000018C [8] 00 0C 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-warning,tx-error-warning}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
restarted-after-bus-off
can1 2000008C [8] 00 0C 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-warning,tx-error-warning}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
can1 2000008C [8] 00 30 90 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-passive,tx-error-passive}
protocol-violation{{tx-recessive-bit-error,error-on-tx}{}}
bus-error
t1: remove short-circuit
can1 123 [3] 11 22 33
can1 20000008 [8] 00 00 40 00 00 00 00 00 ERRORFRAME
protocol-violation{{back-to-error-active}{}}
3) CAN-H and CAN-L disconnected
t0: CAN-H and CAN-L disconnected + cansend can1 123#112233
can1 20000004 [8] 00 30 00 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-passive,tx-error-passive}
can1 2000008C [8] 00 30 80 1B 00 00 00 00 ERRORFRAME
controller-problem{rx-error-passive,tx-error-passive}
protocol-violation{{error-on-tx}{acknowledge-delimiter}}
bus-error
t1: CAN-H and CAN-L reconnected
can1 123 [3] 11 22 33
can1 20000004 [8] 00 30 00 00 00 00 00 00 ERRORFRAME
controller-problem{rx-error-passive,tx-error-passive}
Let me know if it is correct.
Thanks,
Olivier
drivers/net/can/usb/Kconfig | 33 +
drivers/net/can/usb/Makefile | 1 +
drivers/net/can/usb/kvaser_usb.c | 1437 ++++++++++++++++++++++++++++++++++++++
3 files changed, 1471 insertions(+)
create mode 100644 drivers/net/can/usb/kvaser_usb.c
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 0a68768..578955f 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -13,6 +13,39 @@ config CAN_ESD_USB2
This driver supports the CAN-USB/2 interface
from esd electronic system design gmbh (http://www.esd.eu).
+config CAN_KVASER_USB
+ tristate "Kvaser CAN/USB interface"
+ ---help---
+ This driver adds support for Kvaser CAN/USB devices like Kvaser
+ Leaf Light.
+
+ The driver gives support for the following devices:
+ - Kvaser Leaf prototype (P010v2 and v3)
+ - Kvaser Leaf Light (P010v3)
+ - Kvaser Leaf Professional HS
+ - Kvaser Leaf SemiPro HS
+ - Kvaser Leaf Professional LS
+ - Kvaser Leaf Professional SWC
+ - Kvaser Leaf Professional LIN
+ - Kvaser Leaf SemiPro LS
+ - Kvaser Leaf SemiPro SWC
+ - Kvaser Memorator II, Prototype
+ - Kvaser Memorator II HS/HS
+ - Kvaser USBcan Professional HS/HS
+ - Kvaser Leaf Light GI
+ - Kvaser Leaf Professional HS (OBD-II connector)
+ - Kvaser Memorator Professional HS/LS
+ - Kvaser Leaf Light "China"
+ - Kvaser BlackBird SemiPro
+ - Kvaser OEM Mercury
+ - Kvaser OEM Leaf
+ - Kvaser USBcan R
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called kvaser_usb.
+
config CAN_PEAK_USB
tristate "PEAK PCAN-USB/USB Pro interfaces"
---help---
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index da6d1d3..80a2ee4 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
+obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
new file mode 100644
index 0000000..eea0655
--- /dev/null
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -0,0 +1,1437 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * Parts of this driver are based on the following:
+ * - Kvaser linux leaf driver (version 4.78)
+ * - CAN driver for esd CAN-USB/2
+ *
+ * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
+ * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ */
+
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#define MAX_TX_URBS 16
+#define MAX_RX_URBS 4
+#define START_TIMEOUT 1000
+#define STOP_TIMEOUT 1000
+#define USB_SEND_TIMEOUT 1000
+#define USB_RECV_TIMEOUT 1000
+#define RX_BUFFER_SIZE 3072
+#define CAN_USB_CLOCK 8000000
+#define MAX_NET_DEVICES 3
+
+/* Kvaser USB devices */
+#define KVASER_VENDOR_ID 0x0bfd
+#define USB_LEAF_DEVEL_PRODUCT_ID 10
+#define USB_LEAF_LITE_PRODUCT_ID 11
+#define USB_LEAF_PRO_PRODUCT_ID 12
+#define USB_LEAF_SPRO_PRODUCT_ID 14
+#define USB_LEAF_PRO_LS_PRODUCT_ID 15
+#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
+#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
+#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
+#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
+#define USB_MEMO2_DEVEL_PRODUCT_ID 22
+#define USB_MEMO2_HSHS_PRODUCT_ID 23
+#define USB_UPRO_HSHS_PRODUCT_ID 24
+#define USB_LEAF_LITE_GI_PRODUCT_ID 25
+#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
+#define USB_MEMO2_HSLS_PRODUCT_ID 27
+#define USB_LEAF_LITE_CH_PRODUCT_ID 28
+#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
+#define USB_OEM_MERCURY_PRODUCT_ID 34
+#define USB_OEM_LEAF_PRODUCT_ID 35
+#define USB_CAN_R_PRODUCT_ID 39
+
+/* USB devices features */
+#define KVASER_HAS_SILENT_MODE BIT(0)
+
+/* Message header size */
+#define MSG_HEADER_LEN 2
+
+/* Can message flags */
+#define MSG_FLAG_ERROR_FRAME BIT(0)
+#define MSG_FLAG_OVERRUN BIT(1)
+#define MSG_FLAG_NERR BIT(2)
+#define MSG_FLAG_WAKEUP BIT(3)
+#define MSG_FLAG_REMOTE_FRAME BIT(4)
+#define MSG_FLAG_RESERVED BIT(5)
+#define MSG_FLAG_TX_ACK BIT(6)
+#define MSG_FLAG_TX_REQUEST BIT(7)
+
+/* Can states */
+#define M16C_STATE_BUS_RESET BIT(0)
+#define M16C_STATE_BUS_ERROR BIT(4)
+#define M16C_STATE_BUS_PASSIVE BIT(5)
+#define M16C_STATE_BUS_OFF BIT(6)
+
+/* Can msg ids */
+#define CMD_RX_STD_MESSAGE 12
+#define CMD_TX_STD_MESSAGE 13
+#define CMD_RX_EXT_MESSAGE 14
+#define CMD_TX_EXT_MESSAGE 15
+#define CMD_SET_BUS_PARAMS 16
+#define CMD_GET_BUS_PARAMS 17
+#define CMD_GET_BUS_PARAMS_REPLY 18
+#define CMD_GET_CHIP_STATE 19
+#define CMD_CHIP_STATE_EVENT 20
+#define CMD_SET_CTRL_MODE 21
+#define CMD_GET_CTRL_MODE 22
+#define CMD_GET_CTRL_MODE_REPLY 23
+#define CMD_RESET_CHIP 24
+#define CMD_RESET_CARD 25
+#define CMD_START_CHIP 26
+#define CMD_START_CHIP_REPLY 27
+#define CMD_STOP_CHIP 28
+#define CMD_STOP_CHIP_REPLY 29
+#define CMD_GET_CARD_INFO2 32
+#define CMD_GET_CARD_INFO 34
+#define CMD_GET_CARD_INFO_REPLY 35
+#define CMD_GET_SOFTWARE_INFO 38
+#define CMD_GET_SOFTWARE_INFO_REPLY 39
+#define CMD_ERROR_EVENT 45
+#define CMD_FLUSH_QUEUE 48
+#define CMD_RESET_ERROR_COUNTER 49
+#define CMD_TX_ACKNOWLEDGE 50
+#define CMD_CAN_ERROR_EVENT 51
+#define CMD_USB_THROTTLE 77
+
+/* error factors */
+#define M16C_EF_ACKE BIT(0)
+#define M16C_EF_CRCE BIT(1)
+#define M16C_EF_FORME BIT(2)
+#define M16C_EF_STFE BIT(3)
+#define M16C_EF_BITE0 BIT(4)
+#define M16C_EF_BITE1 BIT(5)
+#define M16C_EF_RCVE BIT(6)
+#define M16C_EF_TRE BIT(7)
+
+/* bittiming parameters */
+#define KVASER_USB_TSEG1_MIN 1
+#define KVASER_USB_TSEG1_MAX 16
+#define KVASER_USB_TSEG2_MIN 1
+#define KVASER_USB_TSEG2_MAX 8
+#define KVASER_USB_SJW_MAX 4
+#define KVASER_USB_BRP_MIN 1
+#define KVASER_USB_BRP_MAX 64
+#define KVASER_USB_BRP_INC 1
+
+/* ctrl modes */
+#define KVASER_CTRL_MODE_NORMAL 1
+#define KVASER_CTRL_MODE_SILENT 2
+#define KVASER_CTRL_MODE_SELFRECEPTION 3
+#define KVASER_CTRL_MODE_OFF 4
+
+struct kvaser_msg_simple {
+ u8 tid;
+ u8 channel;
+} __packed;
+
+struct kvaser_msg_cardinfo {
+ u8 tid;
+ u8 nchannels;
+ __le32 serial_number;
+ __le32 padding;
+ __le32 clock_resolution;
+ __le32 mfgdate;
+ u8 ean[8];
+ u8 hw_revision;
+ u8 usb_hs_mode;
+ __le16 padding2;
+} __packed;
+
+struct kvaser_msg_cardinfo2 {
+ u8 tid;
+ u8 channel;
+ u8 pcb_id[24];
+ __le32 oem_unlock_code;
+} __packed;
+
+struct kvaser_msg_softinfo {
+ u8 tid;
+ u8 channel;
+ __le32 sw_options;
+ __le32 fw_version;
+ __le16 max_outstanding_tx;
+ __le16 padding[9];
+} __packed;
+
+struct kvaser_msg_busparams {
+ u8 tid;
+ u8 channel;
+ __le32 bitrate;
+ u8 tseg1;
+ u8 tseg2;
+ u8 sjw;
+ u8 no_samp;
+} __packed;
+
+struct kvaser_msg_tx_can {
+ u8 channel;
+ u8 tid;
+ u8 msg[14];
+ u8 padding;
+ u8 flags;
+} __packed;
+
+struct kvaser_msg_rx_can {
+ u8 channel;
+ u8 flag;
+ __le16 time[3];
+ u8 msg[14];
+} __packed;
+
+struct kvaser_msg_chip_state_event {
+ u8 tid;
+ u8 channel;
+ __le16 time[3];
+ u8 tx_errors_count;
+ u8 rx_errors_count;
+ u8 status;
+ u8 padding[3];
+} __packed;
+
+struct kvaser_msg_tx_acknowledge {
+ u8 channel;
+ u8 tid;
+ __le16 time[3];
+ u8 flags;
+ u8 time_offset;
+} __packed;
+
+struct kvaser_msg_error_event {
+ u8 tid;
+ u8 flags;
+ __le16 time[3];
+ u8 channel;
+ u8 padding;
+ u8 tx_errors_count;
+ u8 rx_errors_count;
+ u8 status;
+ u8 error_factor;
+} __packed;
+
+struct kvaser_msg_ctrl_mode {
+ u8 tid;
+ u8 channel;
+ u8 ctrl_mode;
+ u8 padding[3];
+} __packed;
+
+struct kvaser_msg_flush_queue {
+ u8 tid;
+ u8 channel;
+ u8 flags;
+ u8 padding[3];
+} __packed;
+
+struct kvaser_msg {
+ u8 len;
+ u8 id;
+ union {
+ struct kvaser_msg_simple simple;
+ struct kvaser_msg_cardinfo cardinfo;
+ struct kvaser_msg_cardinfo2 cardinfo2;
+ struct kvaser_msg_softinfo softinfo;
+ struct kvaser_msg_busparams busparams;
+ struct kvaser_msg_tx_can tx_can;
+ struct kvaser_msg_rx_can rx_can;
+ struct kvaser_msg_chip_state_event chip_state_event;
+ struct kvaser_msg_tx_acknowledge tx_acknowledge;
+ struct kvaser_msg_error_event error_event;
+ struct kvaser_msg_ctrl_mode ctrl_mode;
+ struct kvaser_msg_flush_queue flush_queue;
+ } u;
+} __packed;
+
+struct kvaser_usb_tx_urb_context {
+ struct kvaser_usb_net_priv *priv;
+ u32 echo_index;
+ int dlc;
+};
+
+struct kvaser_usb {
+ struct usb_device *udev;
+ struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
+
+ struct usb_endpoint_descriptor *bulk_in, *bulk_out;
+ struct usb_anchor rx_submitted;
+
+ u32 fw_version;
+ unsigned int nchannels;
+
+ bool rxinitdone;
+};
+
+struct kvaser_usb_net_priv {
+ struct can_priv can;
+
+ atomic_t active_tx_urbs;
+ struct usb_anchor tx_submitted;
+ struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+ struct completion start_comp, stop_comp;
+
+ struct kvaser_usb *dev;
+ struct net_device *netdev;
+ int channel;
+
+ struct can_frame cf_err_old;
+};
+
+static struct usb_device_id kvaser_usb_table[] = {
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
+ .driver_info = KVASER_HAS_SILENT_MODE },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
+
+static inline int kvaser_usb_send_msg(const struct kvaser_usb *dev,
+ struct kvaser_msg *msg)
+{
+ int actual_len;
+
+ return usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out->bEndpointAddress),
+ msg, msg->len, &actual_len,
+ USB_SEND_TIMEOUT);
+}
+
+static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
+ struct kvaser_msg *msg)
+{
+ struct kvaser_msg *tmp;
+ void *buf;
+ int actual_len;
+ int err;
+ int pos = 0;
+
+ buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ err = usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in->bEndpointAddress),
+ buf, RX_BUFFER_SIZE, &actual_len,
+ USB_RECV_TIMEOUT);
+ if (err < 0) {
+ kfree(buf);
+ return err;
+ }
+
+ while (pos <= actual_len - MSG_HEADER_LEN) {
+ tmp = buf + pos;
+
+ if (!tmp->len)
+ break;
+
+ if (pos + tmp->len > actual_len) {
+ dev_err(dev->udev->dev.parent, "Format error\n");
+ break;
+ }
+
+ if (tmp->id == id) {
+ memcpy(msg, tmp, tmp->len);
+ kfree(buf);
+ return 0;
+ }
+
+ pos += tmp->len;
+ }
+
+ kfree(buf);
+
+ return -EINVAL;
+}
+
+static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev,
+ u8 msg_id, int channel)
+{
+ struct kvaser_msg msg = {
+ .len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple),
+ .id = msg_id,
+ .u.simple.channel = channel,
+ .u.simple.tid = 0xff,
+ };
+
+ return kvaser_usb_send_msg(dev, &msg);
+}
+
+static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
+{
+ struct kvaser_msg msg;
+ int err;
+
+ err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0);
+ if (err)
+ return err;
+
+ err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg);
+ if (err)
+ return err;
+
+ dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
+
+ return 0;
+}
+
+static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
+{
+ struct kvaser_msg msg;
+ int err;
+
+ err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0);
+ if (err)
+ return err;
+
+ err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg);
+ if (err)
+ return err;
+
+ dev->nchannels = msg.u.cardinfo.nchannels;
+
+ return 0;
+}
+
+static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct net_device_stats *stats;
+ struct kvaser_usb_tx_urb_context *context;
+ struct kvaser_usb_net_priv *priv;
+ u8 channel = msg->u.tx_acknowledge.channel;
+ u8 tid = msg->u.tx_acknowledge.tid;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+
+ if (!netif_device_present(priv->netdev))
+ return;
+
+ stats = &priv->netdev->stats;
+
+ context = &priv->tx_contexts[tid % MAX_TX_URBS];
+
+ /*
+ * It looks like the firmware never sets the flags field of the
+ * tx_acknowledge frame and never reports a transmit failure.
+ * If the can message can't be transmited (e.g. incompatible
+ * bitrates), a frame CMD_CAN_ERROR_EVENT is sent (with a null
+ * tid) and the firmware tries to transmit again the packet until
+ * it succeeds. Once the packet is successfully transmitted, then
+ * the tx_acknowledge frame is sent.
+ */
+
+ stats->tx_packets++;
+ stats->tx_bytes += context->dlc;
+ can_get_echo_skb(priv->netdev, context->echo_index);
+
+ context->echo_index = MAX_TX_URBS;
+ atomic_dec(&priv->active_tx_urbs);
+
+ netif_wake_queue(priv->netdev);
+}
+
+static void kvaser_usb_simple_msg_callback(struct urb *urb)
+{
+ struct net_device *netdev = urb->context;
+
+ if (urb->status)
+ netdev_warn(netdev, "urb status received: %d\n",
+ urb->status);
+}
+
+static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
+ u8 msg_id)
+{
+ struct kvaser_usb *dev = priv->dev;
+ struct net_device *netdev = priv->netdev;
+ struct kvaser_msg *msg;
+ struct urb *urb;
+ void *buf;
+ int err;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ return -ENOMEM;
+ }
+
+ buf = usb_alloc_coherent(dev->udev, sizeof(struct kvaser_msg),
+ GFP_ATOMIC, &urb->transfer_dma);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ return -ENOMEM;
+ }
+
+ msg = (struct kvaser_msg *)buf;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
+ msg->id = msg_id;
+ msg->u.simple.channel = priv->channel;
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out->bEndpointAddress),
+ buf, msg->len,
+ kvaser_usb_simple_msg_callback, priv);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &priv->tx_submitted);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ netdev_err(netdev, "Error transmitting URB\n");
+ usb_unanchor_urb(urb);
+ return err;
+ }
+
+ return 0;
+}
+
+static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
+{
+ int i;
+
+ usb_kill_anchored_urbs(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+}
+
+static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats;
+ struct kvaser_usb_net_priv *priv;
+ unsigned int new_state;
+ u8 channel, status;
+
+ if (msg->id == CMD_CAN_ERROR_EVENT) {
+ channel = msg->u.error_event.channel;
+ status = msg->u.error_event.status;
+ } else {
+ channel = msg->u.chip_state_event.channel;
+ status = msg->u.chip_state_event.status;
+ }
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+ stats = &priv->netdev->stats;
+
+ if (status & M16C_STATE_BUS_RESET) {
+ kvaser_usb_unlink_tx_urbs(priv);
+ return;
+ }
+
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (!skb) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ if (status & M16C_STATE_BUS_OFF) {
+ cf->can_id |= CAN_ERR_BUSOFF;
+
+ if (!priv->can.restart_ms)
+ kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP);
+
+ if (!priv->can.state != CAN_ERR_BUSOFF) {
+ priv->can.can_stats.bus_off++;
+ netif_carrier_off(priv->netdev);
+ }
+
+ new_state = CAN_STATE_BUS_OFF;
+ } else if (status & M16C_STATE_BUS_PASSIVE) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE |
+ CAN_ERR_CRTL_RX_PASSIVE;
+
+ if (priv->can.state != CAN_STATE_ERROR_PASSIVE)
+ priv->can.can_stats.error_passive++;
+
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ } else if (status & M16C_STATE_BUS_ERROR) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] = CAN_ERR_CRTL_TX_WARNING |
+ CAN_ERR_CRTL_RX_WARNING;
+
+ if (priv->can.state != CAN_STATE_ERROR_WARNING)
+ priv->can.can_stats.error_warning++;
+
+ new_state = CAN_STATE_ERROR_WARNING;
+ } else {
+ cf->can_id |= CAN_ERR_PROT;
+ cf->data[2] = CAN_ERR_PROT_ACTIVE;
+
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ if (priv->can.restart_ms &&
+ (priv->can.state >= CAN_STATE_BUS_OFF) &&
+ (new_state < CAN_STATE_BUS_OFF)) {
+ cf->can_id |= CAN_ERR_RESTARTED;
+ priv->can.can_stats.restarts++;
+ netif_carrier_on(priv->netdev);
+ }
+
+ if (msg->id == CMD_CAN_ERROR_EVENT) {
+ u8 error_factor = msg->u.error_event.error_factor;
+
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+ if (error_factor & M16C_EF_ACKE)
+ cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
+ CAN_ERR_PROT_LOC_ACK_DEL);
+ if (error_factor & M16C_EF_CRCE)
+ cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL);
+ if (error_factor & M16C_EF_FORME)
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ if (error_factor & M16C_EF_STFE)
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ if (error_factor & M16C_EF_BITE0)
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ if (error_factor & M16C_EF_BITE1)
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ if (error_factor & M16C_EF_TRE)
+ cf->data[2] |= CAN_ERR_PROT_TX;
+ }
+
+ priv->can.state = new_state;
+
+ if (!memcmp(cf, &priv->cf_err_old, sizeof(*cf))) {
+ kfree_skb(skb);
+ return;
+ }
+
+ netif_rx(skb);
+
+ priv->cf_err_old = *cf;
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_net_priv *priv;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device_stats *stats;
+ u8 channel = msg->u.rx_can.channel;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+ stats = &priv->netdev->stats;
+
+ skb = alloc_can_skb(priv->netdev, &cf);
+ if (skb == NULL) {
+ stats->tx_dropped++;
+ return;
+ }
+
+ cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
+ (msg->u.rx_can.msg[1] & 0x3f);
+ cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+
+ if (msg->id == CMD_RX_EXT_MESSAGE) {
+ cf->can_id <<= 18;
+ cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
+ ((msg->u.rx_can.msg[3] & 0xff) << 6) |
+ (msg->u.rx_can.msg[4] & 0x3f);
+ cf->can_id |= CAN_EFF_FLAG;
+ }
+
+ if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+ MSG_FLAG_NERR)) {
+ cf->can_id |= CAN_ERR_FLAG;
+ cf->can_dlc = CAN_ERR_DLC;
+ cf->data[1] = CAN_ERR_CRTL_UNSPEC;
+
+ stats->rx_errors++;
+ } else if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+ cf->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
+ cf->can_dlc = CAN_ERR_DLC;
+ cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+ } else if (!msg->u.rx_can.flag) {
+ memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc);
+ } else {
+ kfree_skb(skb);
+ return;
+ }
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_net_priv *priv;
+ u8 channel = msg->u.simple.channel;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+
+ if (completion_done(&priv->start_comp) &&
+ netif_queue_stopped(priv->netdev)) {
+ netif_wake_queue(priv->netdev);
+ } else {
+ netif_start_queue(priv->netdev);
+ complete(&priv->start_comp);
+ }
+}
+
+static void kvaser_usb_stop_chip_reply(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_net_priv *priv;
+ u8 channel = msg->u.simple.channel;
+
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ priv = dev->nets[channel];
+
+ complete(&priv->stop_comp);
+}
+
+static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ switch (msg->id) {
+ case CMD_START_CHIP_REPLY:
+ kvaser_usb_start_chip_reply(dev, msg);
+ break;
+
+ case CMD_STOP_CHIP_REPLY:
+ kvaser_usb_stop_chip_reply(dev, msg);
+ break;
+
+ case CMD_RX_STD_MESSAGE:
+ case CMD_RX_EXT_MESSAGE:
+ kvaser_usb_rx_can_msg(dev, msg);
+ break;
+
+ case CMD_CHIP_STATE_EVENT:
+ case CMD_CAN_ERROR_EVENT:
+ kvaser_usb_rx_error(dev, msg);
+ break;
+
+ case CMD_TX_ACKNOWLEDGE:
+ kvaser_usb_tx_acknowledge(dev, msg);
+ break;
+
+ default:
+ dev_warn(dev->udev->dev.parent,
+ "Unhandled message (%d)\n", msg->id);
+ break;
+ }
+}
+
+static void kvaser_usb_read_bulk_callback(struct urb *urb)
+{
+ struct kvaser_usb *dev = urb->context;
+ struct kvaser_msg *msg;
+ int pos = 0;
+ int err, i;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default:
+ dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n",
+ urb->status);
+ goto resubmit_urb;
+ }
+
+ while (pos <= urb->actual_length - MSG_HEADER_LEN) {
+ msg = urb->transfer_buffer + pos;
+
+ if (!msg->len)
+ break;
+
+ if (pos + msg->len > urb->actual_length) {
+ dev_err(dev->udev->dev.parent, "Format error\n");
+ break;
+ }
+
+ kvaser_usb_handle_message(dev, msg);
+
+ pos += msg->len;
+ }
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in->bEndpointAddress),
+ urb->transfer_buffer, RX_BUFFER_SIZE,
+ kvaser_usb_read_bulk_callback, dev);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err == -ENODEV) {
+ for (i = 0; i < dev->nchannels; i++) {
+ if (!dev->nets[i])
+ continue;
+
+ netif_device_detach(dev->nets[i]->netdev);
+ }
+ } else if (err) {
+ dev_err(dev->udev->dev.parent,
+ "Failed resubmitting read bulk urb: %d\n", err);
+ }
+
+ return;
+}
+
+static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
+{
+ int i, err = 0;
+
+ if (dev->rxinitdone)
+ return 0;
+
+ for (i = 0; i < MAX_RX_URBS; i++) {
+ struct urb *urb = NULL;
+ u8 *buf = NULL;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_warn(dev->udev->dev.parent,
+ "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE,
+ GFP_KERNEL, &urb->transfer_dma);
+ if (!buf) {
+ dev_warn(dev->udev->dev.parent,
+ "No memory left for USB buffer\n");
+ usb_free_urb(urb);
+ err = -ENOMEM;
+ break;
+ }
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+ dev->bulk_in->bEndpointAddress),
+ buf, RX_BUFFER_SIZE,
+ kvaser_usb_read_bulk_callback,
+ dev);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &dev->rx_submitted);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ usb_unanchor_urb(urb);
+ usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
+ urb->transfer_dma);
+ break;
+ }
+
+ usb_free_urb(urb);
+ }
+
+ if (i == 0) {
+ dev_warn(dev->udev->dev.parent,
+ "Cannot setup read URBs, error %d\n", err);
+ return err;
+ } else if (i < MAX_RX_URBS) {
+ dev_warn(dev->udev->dev.parent,
+ "RX performances may be slow\n");
+ }
+
+ dev->rxinitdone = true;
+
+ return 0;
+}
+
+static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv)
+{
+ struct kvaser_msg msg = {
+ .id = CMD_SET_CTRL_MODE,
+ .len = MSG_HEADER_LEN +
+ sizeof(struct kvaser_msg_ctrl_mode),
+ .u.ctrl_mode.tid = 0xff,
+ .u.ctrl_mode.channel = priv->channel,
+ };
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+ msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
+ else
+ msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
+
+ return kvaser_usb_send_msg(priv->dev, &msg);
+}
+
+static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv)
+{
+ int err;
+
+ init_completion(&priv->start_comp);
+
+ err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP,
+ priv->channel);
+ if (err)
+ return err;
+
+ if (!wait_for_completion_timeout(&priv->start_comp,
+ msecs_to_jiffies(START_TIMEOUT)))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int kvaser_usb_open(struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
+ int err;
+
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ err = kvaser_usb_setup_rx_urbs(dev);
+ if (err)
+ return err;
+
+ err = kvaser_usb_set_opt_mode(priv);
+ if (err)
+ return err;
+
+ err = kvaser_usb_start_chip(priv);
+ if (err) {
+ netdev_warn(netdev, "Cannot start device, error %d\n", err);
+ close_candev(netdev);
+ return err;
+ }
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+}
+
+static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
+{
+ int i;
+
+ usb_kill_anchored_urbs(&dev->rx_submitted);
+
+ for (i = 0; i < MAX_NET_DEVICES; i++) {
+ struct kvaser_usb_net_priv *priv = dev->nets[i];
+
+ if (priv)
+ kvaser_usb_unlink_tx_urbs(priv);
+ }
+}
+
+static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv)
+{
+ int err;
+
+ init_completion(&priv->stop_comp);
+
+ err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP,
+ priv->channel);
+ if (err)
+ return err;
+
+ if (!wait_for_completion_timeout(&priv->stop_comp,
+ msecs_to_jiffies(STOP_TIMEOUT)))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv)
+{
+ struct kvaser_msg msg = {
+ .id = CMD_FLUSH_QUEUE,
+ .len = MSG_HEADER_LEN +
+ sizeof(struct kvaser_msg_flush_queue),
+ .u.flush_queue.channel = priv->channel,
+ .u.flush_queue.flags = 0x00,
+ };
+
+ return kvaser_usb_send_msg(priv->dev, &msg);
+}
+
+static int kvaser_usb_close(struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
+ int err;
+
+ netif_stop_queue(netdev);
+
+ err = kvaser_usb_flush_queue(priv);
+ if (err)
+ netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
+
+ if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel))
+ netdev_warn(netdev, "Cannot reset card, error %d\n", err);
+
+ err = kvaser_usb_stop_chip(priv);
+ if (err) {
+ netdev_warn(netdev, "Cannot stop device, error %d\n", err);
+ return err;
+ }
+
+ priv->can.state = CAN_STATE_STOPPED;
+ close_candev(priv->netdev);
+
+ return 0;
+}
+
+static void kvaser_usb_write_bulk_callback(struct urb *urb)
+{
+ struct kvaser_usb_tx_urb_context *context = urb->context;
+ struct kvaser_usb_net_priv *priv;
+ struct net_device *netdev;
+
+ if (WARN_ON(!context))
+ return;
+
+ priv = context->priv;
+ netdev = priv->netdev;
+
+ usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+
+ if (!netif_device_present(netdev))
+ return;
+
+ if (urb->status)
+ netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
+}
+
+static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb *dev = priv->dev;
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ struct kvaser_usb_tx_urb_context *context = NULL;
+ struct urb *urb;
+ void *buf;
+ struct kvaser_msg *msg;
+ int i, err;
+ int ret = NETDEV_TX_OK;
+
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ buf = usb_alloc_coherent(dev->udev, sizeof(struct kvaser_msg),
+ GFP_ATOMIC, &urb->transfer_dma);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ goto nobufmem;
+ }
+
+ msg = (struct kvaser_msg *)buf;
+ msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
+ msg->u.tx_can.flags = 0;
+ msg->u.tx_can.channel = priv->channel;
+
+ if (cf->can_id & CAN_EFF_FLAG) {
+ msg->id = CMD_TX_EXT_MESSAGE;
+ msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
+ msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
+ msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
+ msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
+ msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
+ } else {
+ msg->id = CMD_TX_STD_MESSAGE;
+ msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
+ msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
+ }
+
+ msg->u.tx_can.msg[5] = cf->can_dlc;
+ memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
+
+ for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
+ if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+ context = &priv->tx_contexts[i];
+ break;
+ }
+ }
+
+ if (!context) {
+ netdev_warn(netdev, "cannot find free context\n");
+ ret = NETDEV_TX_BUSY;
+ goto releasebuf;
+ }
+
+ context->priv = priv;
+ context->echo_index = i;
+ context->dlc = cf->can_dlc;
+
+ msg->u.tx_can.tid = context->echo_index;
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out->bEndpointAddress),
+ buf, msg->len,
+ kvaser_usb_write_bulk_callback, context);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &priv->tx_submitted);
+
+ can_put_echo_skb(skb, netdev, context->echo_index);
+
+ atomic_inc(&priv->active_tx_urbs);
+
+ if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
+ netif_stop_queue(netdev);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (unlikely(err)) {
+ can_free_echo_skb(netdev, context->echo_index);
+
+ atomic_dec(&priv->active_tx_urbs);
+ usb_unanchor_urb(urb);
+
+ stats->tx_dropped++;
+
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+ else
+ netdev_warn(netdev, "Failed tx_urb %d\n", err);
+
+ goto releasebuf;
+ }
+
+ netdev->trans_start = jiffies;
+
+ usb_free_urb(urb);
+
+ return NETDEV_TX_OK;
+
+releasebuf:
+ usb_free_coherent(dev->udev, sizeof(struct kvaser_msg),
+ buf, urb->transfer_dma);
+nobufmem:
+ usb_free_urb(urb);
+ return ret;
+}
+
+static const struct net_device_ops kvaser_usb_netdev_ops = {
+ .ndo_open = kvaser_usb_open,
+ .ndo_stop = kvaser_usb_close,
+ .ndo_start_xmit = kvaser_usb_start_xmit,
+};
+
+static struct can_bittiming_const kvaser_usb_bittiming_const = {
+ .name = "kvaser_usb",
+ .tseg1_min = KVASER_USB_TSEG1_MIN,
+ .tseg1_max = KVASER_USB_TSEG1_MAX,
+ .tseg2_min = KVASER_USB_TSEG2_MIN,
+ .tseg2_max = KVASER_USB_TSEG2_MAX,
+ .sjw_max = KVASER_USB_SJW_MAX,
+ .brp_min = KVASER_USB_BRP_MIN,
+ .brp_max = KVASER_USB_BRP_MAX,
+ .brp_inc = KVASER_USB_BRP_INC,
+};
+
+static int kvaser_usb_set_bittiming(struct net_device *netdev)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct kvaser_usb *dev = priv->dev;
+ struct kvaser_msg msg = {
+ .id = CMD_SET_BUS_PARAMS,
+ .len = MSG_HEADER_LEN +
+ sizeof(struct kvaser_msg_busparams),
+ .u.busparams.channel = priv->channel,
+ .u.busparams.tid = 0xff,
+ .u.busparams.bitrate = cpu_to_le32(bt->bitrate),
+ .u.busparams.sjw = bt->sjw,
+ .u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1,
+ .u.busparams.tseg2 = bt->phase_seg2,
+ };
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ msg.u.busparams.no_samp = 3;
+ else
+ msg.u.busparams.no_samp = 1;
+
+ return kvaser_usb_send_msg(dev, &msg);
+}
+
+static int kvaser_usb_set_mode(struct net_device *netdev,
+ enum can_mode mode)
+{
+ struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ int err;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ err = kvaser_usb_simple_msg_async(priv, CMD_START_CHIP);
+ if (err)
+ return err;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int kvaser_usb_init_one(struct usb_interface *intf,
+ const struct usb_device_id *id, int channel)
+{
+ struct kvaser_usb *dev = usb_get_intfdata(intf);
+ struct net_device *netdev;
+ struct kvaser_usb_net_priv *priv;
+ int i, err;
+
+ netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "Cannot alloc candev\n");
+ return -ENOMEM;
+ }
+
+ priv = netdev_priv(netdev);
+
+ init_completion(&priv->start_comp);
+ init_completion(&priv->stop_comp);
+
+ init_usb_anchor(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_urbs, 0);
+
+ for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+ priv->dev = dev;
+ priv->netdev = netdev;
+ priv->channel = channel;
+
+ priv->can.state = CAN_STATE_STOPPED;
+ priv->can.clock.freq = CAN_USB_CLOCK;
+ priv->can.bittiming_const = &kvaser_usb_bittiming_const;
+ priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
+ priv->can.do_set_mode = kvaser_usb_set_mode;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+ if (id->driver_info & KVASER_HAS_SILENT_MODE)
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
+
+ netdev->flags |= IFF_ECHO;
+
+ netdev->netdev_ops = &kvaser_usb_netdev_ops;
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ err = register_candev(netdev);
+ if (err) {
+ dev_err(&intf->dev, "Failed to register can device\n");
+ free_candev(netdev);
+ return err;
+ }
+
+ dev->nets[channel] = priv;
+ netdev_dbg(netdev, "device registered\n");
+
+ return 0;
+}
+
+static void kvaser_usb_get_endpoints(const struct usb_interface *intf,
+ struct usb_endpoint_descriptor **in,
+ struct usb_endpoint_descriptor **out)
+{
+ const struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+
+ iface_desc = &intf->altsetting[0];
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(endpoint))
+ *in = endpoint;
+
+ if (usb_endpoint_is_bulk_out(endpoint))
+ *out = endpoint;
+ }
+}
+
+static int kvaser_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct kvaser_usb *dev;
+ int err = -ENOMEM;
+ int i;
+
+ dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
+ if (!dev->bulk_in || !dev->bulk_out) {
+ dev_err(&intf->dev, "Cannot get usb endpoint(s)");
+ return err;
+ }
+
+ dev->udev = interface_to_usbdev(intf);
+
+ init_usb_anchor(&dev->rx_submitted);
+
+ usb_set_intfdata(intf, dev);
+
+ for (i = 0; i < MAX_NET_DEVICES; i++)
+ kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
+
+ err = kvaser_usb_get_software_info(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Cannot get software infos, error %d\n", err);
+ return err;
+ }
+
+ err = kvaser_usb_get_card_info(dev);
+ if (err) {
+ dev_err(&intf->dev,
+ "Cannot get card infos, error %d\n", err);
+ return err;
+ }
+
+ dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
+ ((dev->fw_version >> 24) & 0xff),
+ ((dev->fw_version >> 16) & 0xff),
+ (dev->fw_version & 0xffff));
+
+ for (i = 0; i < dev->nchannels; i++)
+ kvaser_usb_init_one(intf, id, i);
+
+ return 0;
+}
+
+static void kvaser_usb_disconnect(struct usb_interface *intf)
+{
+ struct kvaser_usb *dev = usb_get_intfdata(intf);
+ int i;
+
+ usb_set_intfdata(intf, NULL);
+
+ if (!dev)
+ return;
+
+ for (i = 0; i < dev->nchannels; i++) {
+ if (!dev->nets[i])
+ continue;
+
+ unregister_netdev(dev->nets[i]->netdev);
+ free_candev(dev->nets[i]->netdev);
+ }
+
+ kvaser_usb_unlink_all_urbs(dev);
+}
+
+static struct usb_driver kvaser_usb_driver = {
+ .name = "kvaser_usb",
+ .probe = kvaser_usb_probe,
+ .disconnect = kvaser_usb_disconnect,
+ .id_table = kvaser_usb_table
+};
+
+module_usb_driver(kvaser_usb_driver);
+
+MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
+MODULE_DESCRIPTION("Can driver for Kvaser CAN/USB devices");
+MODULE_LICENSE("GPL v2");
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH iproute2] Install the bridge command under the same name we build it.
From: Li Wei @ 2012-08-06 1:51 UTC (permalink / raw)
To: Nick Alcock; +Cc: netdev, Stephen Hemminger
In-Reply-To: <87ehnmiv1m.fsf@spindle.srvr.nix>
On 08/04/2012 10:36 PM, Nick Alcock wrote:
>
> Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
> ---
> bridge/Makefile | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/bridge/Makefile b/bridge/Makefile
> index 0c333bf..9a6743e 100644
> --- a/bridge/Makefile
> +++ b/bridge/Makefile
> @@ -7,8 +7,8 @@ all: bridge
> bridge: $(BROBJ) $(LIBNETLINK)
>
> install: all
> - install -m 0755 br $(DESTDIR)$(SBINDIR)
> + install -m 0755 bridge $(DESTDIR)$(SBINDIR)
>
> clean:
> - rm -f $(BROBJ) br
> + rm -f $(BROBJ) bridge
>
Hi Nick,
To post a patch for iproute2, you should send it to
Stephen Hemminger <shemminger@vyatta.com> who is the maintainer of iproute2.
Stephen, I also noticed this problem and thought should ask you for the final
name of the brige extension. Personally I prefer br, it is short and
distingushable enough.
Thanks.
^ 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