* ipv6: Add GSO support on forwarding path
From: Herbert Xu @ 2010-05-26 10:27 UTC (permalink / raw)
To: Ralf Baechle, David S. Miller, netdev
Hi:
ipv6: Add GSO support on forwarding path
Currently we disallow GSO packets on the IPv6 forward path.
This patch fixes this.
Note that I discovered that our existing GSO MTU checks (e.g.,
IPv4 forwarding) are buggy in that they skip the check altogether,
hen they really should be checking gso_size instead.
I have also been lazy here in that I haven't bothered to segment
the GSO packet by hand before generating an ICMP message. Someone
should add that to be 100% correct.
Reported-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 7cdfb4d..64f9c5a 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2117,6 +2117,13 @@ static inline int skb_is_gso(const struct sk_buff *skb)
return skb_shinfo(skb)->gso_size;
}
+static inline int skb_gso_len(const struct sk_buff *skb)
+{
+ return skb_is_gso(skb) ?
+ skb_shinfo(skb)->gso_size + skb_transport_offset(skb) :
+ skb->len;
+}
+
static inline int skb_is_gso_v6(const struct sk_buff *skb)
{
return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index cd963f6..8904767 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -507,7 +507,7 @@ int ip6_forward(struct sk_buff *skb)
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
- if (skb->len > mtu) {
+ if (skb_gso_len(skb) > mtu) {
/* Again, force OUTPUT device used as source address */
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related
* Re: [PATCH v3] can: Add driver for esd CAN-USB/2 device
From: Wolfgang Grandegger @ 2010-05-26 10:15 UTC (permalink / raw)
To: Matthias Fuchs
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <201005261114.03214.matthias.fuchs-iOnpLzIbIdM@public.gmane.org>
Hi Matthias,
On 05/26/2010 11:14 AM, Matthias Fuchs wrote:
> This patch adds a driver for esd's USB high speed
> CAN interface. The driver supports devices with
> multiple CAN interfaces.
>
> Signed-off-by: Matthias Fuchs <matthias.fuchs-iOnpLzIbIdM@public.gmane.org>
> ---
> version 3:
> - remove bus-error reporting feature because
> it cannot be controlled by user on demand
> with current device's firmware
> - rebased against current net-next-2.6 tree
>
> version 2:
> - use bus-error reporting and counters
> - minor cleanup
> - rebased against current net-next-2.6 tree
> - initial post to linux-usb list for review
I get the following compiler warnings when compiling the kernel:
CC drivers/net/can/usb/esd_usb2.o
drivers/net/can/usb/esd_usb2.c: In function 'esd_usb2_write_bulk_callback':
drivers/net/can/usb/esd_usb2.c:466: error: implicit declaration of function 'usb_buffer_free'
drivers/net/can/usb/esd_usb2.c: In function 'esd_usb2_setup_rx_urbs':
drivers/net/can/usb/esd_usb2.c:562: error: implicit declaration of function 'usb_buffer_alloc'
drivers/net/can/usb/esd_usb2.c:563: warning: assignment makes pointer from integer without a cast
drivers/net/can/usb/esd_usb2.c: In function 'esd_usb2_start_xmit':
drivers/net/can/usb/esd_usb2.c:732: warning: assignment makes pointer from integer without a cast
make[4]: *** [drivers/net/can/usb/esd_usb2.o] Error 1
This is due to commit e26bcf37234c67624f62d9fc95f922b8dbda1363.
You need a similar fix like for ems_usb.c. Are you using a recent
version of the net-next-2.6 tree?
Wolfgang.
^ permalink raw reply
* Re: Warning in net/ipv4/af_inet.c:154
From: Eric Dumazet @ 2010-05-26 10:12 UTC (permalink / raw)
To: David Miller; +Cc: anton, netdev
In-Reply-To: <20100526.005634.48509140.davem@davemloft.net>
Le mercredi 26 mai 2010 à 00:56 -0700, David Miller a écrit :
> From: Anton Blanchard <anton@samba.org>
> Date: Wed, 26 May 2010 13:19:43 +1000
>
> > I notice we update sk_forward_alloc in sk_mem_charge and sk_mem_uncharge.
> > Since it isn't an atomic variable I went looking for a lock somewhere in
> > the call chain (first thought was the socket lock). I couldn't find
> > anything, but I could easily be missing something.
>
> We take the lock properly for all of the skb_queue_rcv_skb() cases
> but this rule isn't followed properly for skb_queue_err_skb().
>
> Eric, look at even things like skb_tstamp_tx(). Nothing locks the
> socket in those cases, yet we dip down into sock_queue_err_skb() and
> thus invoke skb_set_owner_r which goes into sk_mem_charge() and does
> the non-atomic update on ->sk_forward_alloc.
>
> I am sure there are other cases with this problem involving
> sock_queue_err_skb()... ip_icmp_error() (via __udp4_lib_err()),
> ipv6_icmp_error(), etc.
All these points are indeed problematic, since a loooong time, so this
is a stable material.
You are 100% right David, maybe we should add a test when changing
sk_forward_alloc to test if socket is locked (lockdep only test), but
that's for 2.6.36 :)
RAW path is not impacted (yet)
Thanks
[PATCH] net: fix sk_forward_alloc corruptions
As David found out, sock_queue_err_skb() should be called with socket
lock hold, or we risk sk_forward_alloc corruption, since we use non
atomic operations to update this field.
This patch adds bh_lock_sock()/bh_unlock_sock() pair to three spots.
(BH already disabled)
1) skb_tstamp_tx()
2) Before calling ip_icmp_error(), in __udp4_lib_err()
3) Before calling ipv6_icmp_error(), in __udp6_lib_err()
Reported-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/core/skbuff.c | 4 ++++
net/ipv4/udp.c | 2 ++
net/ipv6/udp.c | 6 ++++--
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c543dd2..439e3b9 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2991,7 +2991,11 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
memset(serr, 0, sizeof(*serr));
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+
+ bh_lock_sock(sk);
err = sock_queue_err_skb(sk, skb);
+ bh_unlock_sock(sk);
+
if (err)
kfree_skb(skb);
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 9de6a69..1d70ff0 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -634,7 +634,9 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out;
} else {
+ bh_lock_sock(sk);
ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1));
+ bh_unlock_sock(sk);
}
sk->sk_err = err;
sk->sk_error_report(sk);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3d7a2c0..f441365 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -465,9 +465,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (sk->sk_state != TCP_ESTABLISHED && !np->recverr)
goto out;
- if (np->recverr)
+ if (np->recverr) {
+ bh_lock_sock(sk);
ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
-
+ bh_unlock_sock(sk);
+ }
sk->sk_err = err;
sk->sk_error_report(sk);
out:
^ permalink raw reply related
* [PATCH 2/3] arp_notify: allow drivers to explicitly request a notification event.
From: Ian Campbell @ 2010-05-26 10:09 UTC (permalink / raw)
To: netdev
Cc: Ian Campbell, Stephen Hemminger, Jeremy Fitzhardinge,
David S. Miller, stable
In-Reply-To: <1274868492.24218.7350.camel@zakaz.uk.xensource.com>
Currently such notifications are only generated when the device comes up or the
address changes. However one use case for these notifications is to enable
faster network recovery after a virtual machine migration (by causing switches
to relearn their MAC tables). A migration appears to the network stack as a
temporary loss of carrier and therefore does not trigger either of the current
conditions. Rather than adding carrier up as a trigger (which can cause issues
when interfaces a flapping) simply add an interface which the driver can use
to explicitly trigger the notification.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Stephen Hemminger <shemminger@linux-foundation.org>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Cc: stable@kernel.org
---
include/linux/netdevice.h | 2 ++
include/linux/notifier.h | 1 +
net/ipv4/devinet.c | 1 +
net/sched/sch_generic.c | 18 ++++++++++++++++++
4 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index fa8b476..4737996 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1661,6 +1661,8 @@ extern void netif_carrier_on(struct net_device *dev);
extern void netif_carrier_off(struct net_device *dev);
+extern void netif_notify_peers(struct net_device *dev);
+
/**
* netif_dormant_on - mark device as dormant.
* @dev: network device
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index fee6c2f..45477f2 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -203,6 +203,7 @@ static inline int notifier_to_errno(int ret)
#define NETDEV_BONDING_NEWTYPE 0x000F
#define NETDEV_POST_INIT 0x0010
#define NETDEV_UNREGISTER_BATCH 0x0011
+#define NETDEV_NOTIFY_PEERS 0x0012
#define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 90e3d63..c12777f 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1081,6 +1081,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
}
ip_mc_up(in_dev);
/* fall through */
+ case NETDEV_NOTIFY_PEERS:
case NETDEV_CHANGEADDR:
/* Send gratuitous ARP to notify of link change */
if (IN_DEV_ARP_NOTIFY(in_dev)) {
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index ff4dd53..2d7ca9e 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -325,6 +325,24 @@ void netif_carrier_off(struct net_device *dev)
}
EXPORT_SYMBOL(netif_carrier_off);
+/**
+ * netif_notify_peers - notify network peers about existence of @dev
+ * @dev: network device
+ *
+ * Generate traffic such that interested network peers are aware of
+ * @dev, such as by generating a gratuitous ARP. This may be used when
+ * a device wants to inform the rest of the network about some sort of
+ * reconfiguration such as a failover event or virtual machine
+ * migration.
+ */
+void netif_notify_peers(struct net_device *dev)
+{
+ rtnl_lock();
+ call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev);
+ rtnl_unlock();
+}
+EXPORT_SYMBOL(netif_notify_peers);
+
/* "NOOP" scheduler: the best scheduler, recommended for all interfaces
under all circumstances. It is difficult to invent anything faster or
cheaper.
--
1.5.6.5
^ permalink raw reply related
* [PATCH 3/3] xen: netfront: explicitly generate arp_notify event after migration.
From: Ian Campbell @ 2010-05-26 10:09 UTC (permalink / raw)
To: netdev
Cc: Ian Campbell, Stephen Hemminger, Jeremy Fitzhardinge,
David S. Miller, xen-devel, stable
In-Reply-To: <1274868492.24218.7350.camel@zakaz.uk.xensource.com>
Use newly introduced netif_notify_peers() method to ensure a gratuitous ARP is
generated after a migration.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Stephen Hemminger <shemminger@linux-foundation.org>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Cc: xen-devel@lists.xensource.com
Cc: stable@kernel.org
---
drivers/net/xen-netfront.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d504e2b..b50fedc 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1621,6 +1621,7 @@ static void backend_changed(struct xenbus_device *dev,
if (xennet_connect(netdev) != 0)
break;
xenbus_switch_state(dev, XenbusStateConnected);
+ netif_notify_peers(netdev);
break;
case XenbusStateClosing:
--
1.5.6.5
^ permalink raw reply related
* [PATCH 1/3] arp_notify: document that a gratuitous ARP request is sent when this option is enabled
From: Ian Campbell @ 2010-05-26 10:09 UTC (permalink / raw)
To: netdev
Cc: Ian Campbell, Stephen Hemminger, Jeremy Fitzhardinge,
David S. Miller
In-Reply-To: <1274868492.24218.7350.camel@zakaz.uk.xensource.com>
This option causes a gratuitous ARP request, not a reply as the documentation
currently suggests.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Stephen Hemminger <shemminger@linux-foundation.org>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: netdev@vger.kernel.org
---
Documentation/networking/ip-sysctl.txt | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 8b72c88..bd13884 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -872,7 +872,7 @@ arp_ignore - INTEGER
arp_notify - BOOLEAN
Define mode for notification of address and device changes.
0 - (default): do nothing
- 1 - Generate gratuitous arp replies when device is brought up
+ 1 - Generate gratuitous arp requests when device is brought up
or hardware address changes.
arp_accept - BOOLEAN
--
1.5.6.5
^ permalink raw reply related
* Re: [PATCH 0/2] fixes to arp_notify for virtual machine migration use case
From: Ian Campbell @ 2010-05-26 10:08 UTC (permalink / raw)
To: David Miller
Cc: netdev@vger.kernel.org, shemminger@linux-foundation.org,
Jeremy Fitzhardinge, stable@kernel.org
In-Reply-To: <20100525.230822.71096271.davem@davemloft.net>
On Wed, 2010-05-26 at 07:08 +0100, David Miller wrote:
> From: Ian Campbell <Ian.Campbell@citrix.com>
> Date: Tue, 25 May 2010 10:20:01 +0100
>
> > Anyway, assuming the fact that arp_notify is disabled by default hasn't
> > changed your mind, would adding NETDEV_NOTIFY_PEERS triggered by
> > netif_notify_peers() be appropriate or would it be preferable to simply
> > add netif_notify_peers() which generates the existing NETDEV_CHANGEADDR?
>
> A seperate NETDEV_NOTIFY_PEERS seems the best idea to me.
>
> > I don't think there's any need for a new sysctl so I'll gate the new
> > option on the existing arp_notify one.
>
> Yep, sounds good.
The following changes since commit e40152ee1e1c7a63f4777791863215e3faa37a86:
Linus Torvalds (1):
Linus 2.6.34
are available in the git repository at:
git://xenbits.xensource.com/people/ianc/linux-2.6.git for-netdev/fixes
Ian Campbell (3):
arp_notify: document that a gratuitous ARP request is sent when this option is enabled
arp_notify: allow drivers to explicitly request a notification event.
xen: netfront: explicitly generate arp_notify event after migration.
Documentation/networking/ip-sysctl.txt | 2 +-
drivers/net/xen-netfront.c | 1 +
include/linux/netdevice.h | 2 ++
include/linux/notifier.h | 1 +
net/ipv4/devinet.c | 1 +
net/sched/sch_generic.c | 18 ++++++++++++++++++
6 files changed, 24 insertions(+), 1 deletions(-)
^ permalink raw reply
* [PATCH] net/core: use net_device dev_id to indicate port number
From: Eli Cohen @ 2010-05-26 9:52 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-rdma, rdreier, yevgenyp
Today, there are no means to know which port of a hardware device a netdev
interface uses. struct net_device conatins a field, dev_id, that can be used
for that. This patch adds a new macro, SET_NETDEV_DEV_ID(), to provide a
standard way to set the value of this field.
Also also make use of this feature in the mlx4_en driver to set the port
number; port numbers are zero based.
Signed-off-by: Eli Cohen <eli@mellanox.co.il>
---
drivers/net/mlx4/en_netdev.c | 1 +
include/linux/netdevice.h | 5 +++++
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 6c2b15b..612df1e 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -978,6 +978,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
+ SET_NETDEV_DEV_ID(dev, port - 1);
/*
* Initialize driver private data
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3857517..8d5f2c7 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1080,6 +1080,11 @@ static inline void *netdev_priv(const struct net_device *dev)
*/
#define SET_NETDEV_DEVTYPE(net, devtype) ((net)->dev.type = (devtype))
+/*
+ * Set the port number of the physical device that this port net device uses
+ */
+#define SET_NETDEV_DEV_ID(net, devid) ((net)->dev_id = (devid))
+
/**
* netif_napi_add - initialize a napi context
* @dev: network device
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] net/core: Save the port number a netdevice uses
From: Eli Cohen @ 2010-05-26 9:19 UTC (permalink / raw)
To: David Miller
Cc: eli-VPRAkNaXOzVS1MOuV/RT9w, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-rdma-u79uwXL29TY76Z2rM5mHXA, rdreier-FYB4Gu1CFyUAvxtiuMwx3w,
yevgenyp-VPRAkNaXOzVS1MOuV/RT9w
In-Reply-To: <20100526.021635.179940939.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
On Wed, May 26, 2010 at 02:16:35AM -0700, David Miller wrote:
>
> I actually mean that the value "0" should mean the first port,
> the value "1" should mean the second port, etc.
OK, thanks for clarifying. I'll send a new patch soon.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] net/core: Save the port number a netdevice uses
From: David Miller @ 2010-05-26 9:16 UTC (permalink / raw)
To: eli-LDSdmyG8hGV8YrgS2mwiifqBs+8SCbDb
Cc: eli-VPRAkNaXOzVS1MOuV/RT9w, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-rdma-u79uwXL29TY76Z2rM5mHXA, rdreier-FYB4Gu1CFyUAvxtiuMwx3w,
yevgenyp-VPRAkNaXOzVS1MOuV/RT9w
In-Reply-To: <20100526090850.GB28748-8YAHvHwT2UEvbXDkjdHOrw/a8Rv0c6iv@public.gmane.org>
From: Eli Cohen <eli-LDSdmyG8hGV8YrgS2mwiifqBs+8SCbDb@public.gmane.org>
Date: Wed, 26 May 2010 12:08:52 +0300
> So if I understand you correctly, you think that I should not bother
> to set a default value of 1. Each driver that cares about the value
> of this field, will set it however they want.
I actually mean that the value "0" should mean the first port,
the value "1" should mean the second port, etc.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v3] can: Add driver for esd CAN-USB/2 device
From: Matthias Fuchs @ 2010-05-26 9:14 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
linux-usb-u79uwXL29TY76Z2rM5mHXA
This patch adds a driver for esd's USB high speed
CAN interface. The driver supports devices with
multiple CAN interfaces.
Signed-off-by: Matthias Fuchs <matthias.fuchs-iOnpLzIbIdM@public.gmane.org>
---
version 3:
- remove bus-error reporting feature because
it cannot be controlled by user on demand
with current device's firmware
- rebased against current net-next-2.6 tree
version 2:
- use bus-error reporting and counters
- minor cleanup
- rebased against current net-next-2.6 tree
- initial post to linux-usb list for review
drivers/net/can/usb/Kconfig | 6 +
drivers/net/can/usb/Makefile | 1 +
drivers/net/can/usb/esd_usb2.c | 1125 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 1132 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/usb/esd_usb2.c
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 97ff6fe..0452549 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -7,4 +7,10 @@ config CAN_EMS_USB
This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+config CAN_ESD_USB2
+ tristate "ESD USB/2 CAN/USB interface"
+ ---help---
+ This driver supports the CAN-USB/2 interface
+ from esd electronic system design gmbh (http://www.esd.eu).
+
endmenu
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index 0afd51d..fce3cf1 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -3,5 +3,6 @@
#
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
+obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
new file mode 100644
index 0000000..ff1a5ee
--- /dev/null
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -0,0 +1,1125 @@
+/*
+ * CAN driver for esd CAN-USB/2
+ *
+ * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs-iOnpLzIbIdM@public.gmane.org>, esd gmbh
+ *
+ * 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 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.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>
+
+MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs-iOnpLzIbIdM@public.gmane.org>");
+MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 interfaces");
+MODULE_LICENSE("GPL v2");
+
+/* Define these values to match your devices */
+#define USB_ESDGMBH_VENDOR_ID 0x0ab4
+#define USB_CANUSB2_PRODUCT_ID 0x0010
+
+#define ESD_USB2_CAN_CLOCK 60000000
+#define ESD_USB2_MAX_NETS 2
+
+/* USB2 commands */
+#define CMD_VERSION 1 /* also used for VERSION_REPLY */
+#define CMD_CAN_RX 2 /* device to host only */
+#define CMD_CAN_TX 3 /* also used for TX_DONE */
+#define CMD_SETBAUD 4 /* also used for SETBAUD_REPLY */
+#define CMD_TS 5 /* also used for TS_REPLY */
+#define CMD_IDADD 6 /* also used for IDADD_REPLY */
+
+/* esd CAN message flags - dlc field */
+#define ESD_RTR 0x10
+
+/* esd CAN message flags - id field */
+#define ESD_EXTID 0x20000000
+#define ESD_EVENT 0x40000000
+#define ESD_IDMASK 0x1fffffff
+
+/* esd CAN event ids used by this driver */
+#define ESD_EV_CAN_ERROR_EXT 2
+
+/* baudrate message flags */
+#define ESD_USB2_UBR 0x80000000
+#define ESD_USB2_LOM 0x40000000
+#define ESD_USB2_NO_BAUDRATE 0x7fffffff
+#define ESD_USB2_TSEG1_MIN 1
+#define ESD_USB2_TSEG1_MAX 16
+#define ESD_USB2_TSEG1_SHIFT 16
+#define ESD_USB2_TSEG2_MIN 1
+#define ESD_USB2_TSEG2_MAX 8
+#define ESD_USB2_TSEG2_SHIFT 20
+#define ESD_USB2_SJW_MAX 4
+#define ESD_USB2_SJW_SHIFT 14
+#define ESD_USB2_BRP_MIN 1
+#define ESD_USB2_BRP_MAX 1024
+#define ESD_USB2_BRP_INC 1
+#define ESD_USB2_3_SAMPLES 0x00800000
+
+/* esd IDADD message */
+#define ESD_ID_ENABLE 0x80
+#define ESD_MAX_ID_SEGMENT 64
+
+/* SJA1000 ECC register (emulated by usb2 firmware) */
+#define SJA1000_ECC_SEG 0x1F
+#define SJA1000_ECC_DIR 0x20
+#define SJA1000_ECC_ERR 0x06
+#define SJA1000_ECC_BIT 0x00
+#define SJA1000_ECC_FORM 0x40
+#define SJA1000_ECC_STUFF 0x80
+#define SJA1000_ECC_MASK 0xc0
+
+/* esd bus state event codes */
+#define ESD_BUSSTATE_MASK 0xc0
+#define ESD_BUSSTATE_WARN 0x40
+#define ESD_BUSSTATE_ERRPASSIVE 0x80
+#define ESD_BUSSTATE_BUSOFF 0xc0
+
+#define RX_BUFFER_SIZE 1024
+#define MAX_RX_URBS 4
+#define MAX_TX_URBS 16 /* must be power of 2 */
+
+struct header_msg {
+ u8 len; /* len is always the total message length in 32bit words */
+ u8 cmd;
+ u8 rsvd[2];
+};
+
+struct version_msg {
+ u8 len;
+ u8 cmd;
+ u8 rsvd;
+ u8 flags;
+ __le32 drv_version;
+};
+
+struct version_reply_msg {
+ u8 len;
+ u8 cmd;
+ u8 nets;
+ u8 features;
+ __le32 version;
+ u8 name[16];
+ __le32 rsvd;
+ __le32 ts;
+};
+
+struct rx_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 dlc;
+ __le32 ts;
+ __le32 id; /* upper 3 bits contain flags */
+ u8 data[8];
+};
+
+struct tx_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 dlc;
+ __le32 hnd;
+ __le32 id; /* upper 3 bits contain flags */
+ u8 data[8];
+};
+
+struct tx_done_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 status;
+ __le32 hnd;
+ __le32 ts;
+};
+
+struct id_filter_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 option;
+ __le32 mask[ESD_MAX_ID_SEGMENT + 1];
+};
+
+struct set_baudrate_msg {
+ u8 len;
+ u8 cmd;
+ u8 net;
+ u8 rsvd;
+ __le32 baud;
+};
+
+/* Main message type used between library and application */
+struct __attribute__ ((packed)) esd_usb2_msg {
+ union {
+ struct header_msg hdr;
+ struct version_msg version;
+ struct version_reply_msg version_reply;
+ struct rx_msg rx;
+ struct tx_msg tx;
+ struct tx_done_msg txdone;
+ struct set_baudrate_msg setbaud;
+ struct id_filter_msg filter;
+ } msg;
+};
+
+static struct usb_device_id esd_usb2_table[] = {
+ {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, esd_usb2_table);
+
+struct esd_usb2_net_priv;
+
+struct esd_tx_urb_context {
+ struct esd_usb2_net_priv *priv;
+ u32 echo_index;
+ int dlc;
+};
+
+struct esd_usb2 {
+ struct usb_device *udev;
+ struct esd_usb2_net_priv *nets[ESD_USB2_MAX_NETS];
+
+ struct usb_anchor rx_submitted;
+
+ int net_count;
+ u32 version;
+ int rxinitdone;
+};
+
+struct esd_usb2_net_priv {
+ struct can_priv can; /* must be the first member */
+
+ atomic_t active_tx_jobs;
+ struct usb_anchor tx_submitted;
+ struct esd_tx_urb_context tx_contexts[MAX_TX_URBS];
+
+ int open_time;
+ struct esd_usb2 *usb2;
+ struct net_device *netdev;
+ int index;
+ u8 old_state;
+ struct can_berr_counter bec;
+};
+
+static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
+ struct esd_usb2_msg *msg)
+{
+ struct net_device_stats *stats = &priv->netdev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ u32 id = le32_to_cpu(msg->msg.rx.id) & ESD_IDMASK;
+
+ if (id == ESD_EV_CAN_ERROR_EXT) {
+ u8 state = msg->msg.rx.data[0];
+ u8 ecc = msg->msg.rx.data[1];
+ u8 txerr = msg->msg.rx.data[2];
+ u8 rxerr = msg->msg.rx.data[3];
+
+ skb = alloc_can_err_skb(priv->netdev, &cf);
+ if (skb == NULL) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ if (state != priv->old_state) {
+ priv->old_state = state;
+
+ switch (state & ESD_BUSSTATE_MASK) {
+ case ESD_BUSSTATE_BUSOFF:
+ priv->can.state = CAN_STATE_BUS_OFF;
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(priv->netdev);
+ break;
+ case ESD_BUSSTATE_WARN:
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ priv->can.can_stats.error_warning++;
+ break;
+ case ESD_BUSSTATE_ERRPASSIVE:
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ break;
+ default:
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ break;
+ }
+ } else {
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+
+ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+ switch (ecc & SJA1000_ECC_MASK) {
+ case SJA1000_ECC_BIT:
+ cf->data[2] |= CAN_ERR_PROT_BIT;
+ break;
+ case SJA1000_ECC_FORM:
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case SJA1000_ECC_STUFF:
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ default:
+ cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+ cf->data[3] = ecc & SJA1000_ECC_SEG;
+ break;
+ }
+
+ /* Error occured during transmission? */
+ if (!(ecc & SJA1000_ECC_DIR))
+ cf->data[2] |= CAN_ERR_PROT_TX;
+
+ if (priv->can.state == CAN_STATE_ERROR_WARNING ||
+ priv->can.state == CAN_STATE_ERROR_PASSIVE) {
+ cf->data[1] = (txerr > rxerr) ?
+ CAN_ERR_CRTL_TX_PASSIVE :
+ CAN_ERR_CRTL_RX_PASSIVE;
+ }
+ cf->data[6] = txerr;
+ cf->data[7] = rxerr;
+ }
+
+ netif_rx(skb);
+
+ priv->bec.txerr = txerr;
+ priv->bec.rxerr = rxerr;
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ }
+}
+
+static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
+ struct esd_usb2_msg *msg)
+{
+ struct net_device_stats *stats = &priv->netdev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ int i;
+ u32 id;
+
+ if (!netif_device_present(priv->netdev))
+ return;
+
+ id = le32_to_cpu(msg->msg.rx.id);
+
+ if (id & ESD_EVENT) {
+ esd_usb2_rx_event(priv, msg);
+ } else {
+ skb = alloc_can_skb(priv->netdev, &cf);
+ if (skb == NULL) {
+ stats->rx_dropped++;
+ return;
+ }
+
+ cf->can_id = id & ESD_IDMASK;
+ cf->can_dlc = get_can_dlc(msg->msg.rx.dlc);
+
+ if (id & ESD_EXTID)
+ cf->can_id |= CAN_EFF_FLAG;
+
+ if (msg->msg.rx.dlc & ESD_RTR) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ for (i = 0; i < cf->can_dlc; i++)
+ cf->data[i] = msg->msg.rx.data[i];
+ }
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ }
+
+ return;
+}
+
+static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
+ struct esd_usb2_msg *msg)
+{
+ struct net_device_stats *stats = &priv->netdev->stats;
+ struct net_device *netdev = priv->netdev;
+ struct esd_tx_urb_context *context;
+
+ if (!netif_device_present(netdev))
+ return;
+
+ context = &priv->tx_contexts[msg->msg.txdone.hnd & (MAX_TX_URBS - 1)];
+
+ if (!msg->msg.txdone.status) {
+ stats->tx_packets++;
+ stats->tx_bytes += context->dlc;
+ can_get_echo_skb(netdev, context->echo_index);
+ } else {
+ stats->tx_errors++;
+ can_free_echo_skb(netdev, context->echo_index);
+ }
+
+ /* Release context */
+ context->echo_index = MAX_TX_URBS;
+ atomic_dec(&priv->active_tx_jobs);
+
+ netif_wake_queue(netdev);
+}
+
+static void esd_usb2_read_bulk_callback(struct urb *urb)
+{
+ struct esd_usb2 *dev = urb->context;
+ int retval;
+ int pos = 0;
+ int i;
+
+ switch (urb->status) {
+ case 0: /* success */
+ 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) {
+ struct esd_usb2_msg *msg;
+
+ msg = (struct esd_usb2_msg *)(urb->transfer_buffer + pos);
+
+ switch (msg->msg.hdr.cmd) {
+ case CMD_CAN_RX:
+ esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
+ break;
+
+ case CMD_CAN_TX:
+ esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
+ msg);
+ break;
+ }
+
+ pos += msg->msg.hdr.len << 2;
+
+ if (pos > urb->actual_length) {
+ dev_err(dev->udev->dev.parent, "format error\n");
+ break;
+ }
+ }
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+ urb->transfer_buffer, RX_BUFFER_SIZE,
+ esd_usb2_read_bulk_callback, dev);
+
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval == -ENODEV) {
+ for (i = 0; i < dev->net_count; i++) {
+ if (dev->nets[i])
+ netif_device_detach(dev->nets[i]->netdev);
+ }
+ } else if (retval) {
+ dev_err(dev->udev->dev.parent,
+ "failed resubmitting read bulk urb: %d\n", retval);
+ }
+
+ return;
+}
+
+/*
+ * callback for bulk IN urb
+ */
+static void esd_usb2_write_bulk_callback(struct urb *urb)
+{
+ struct esd_tx_urb_context *context = urb->context;
+ struct esd_usb2_net_priv *priv;
+ struct esd_usb2 *dev;
+ struct net_device *netdev;
+ size_t size = sizeof(struct esd_usb2_msg);
+
+ BUG_ON(!context);
+
+ priv = context->priv;
+ netdev = priv->netdev;
+ dev = priv->usb2;
+
+ /* free up our allocated buffer */
+ usb_buffer_free(urb->dev, size,
+ urb->transfer_buffer, urb->transfer_dma);
+
+ if (!netif_device_present(netdev))
+ return;
+
+ if (urb->status)
+ dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n",
+ urb->status);
+
+ netdev->trans_start = jiffies;
+}
+
+#ifdef CONFIG_SYSFS
+static ssize_t show_firmware(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(d);
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d.%d.%d\n",
+ (dev->version >> 12) & 0xf,
+ (dev->version >> 8) & 0xf,
+ dev->version & 0xff);
+}
+static DEVICE_ATTR(firmware, S_IRUGO, show_firmware, NULL);
+
+static ssize_t show_hardware(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(d);
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d.%d.%d\n",
+ (dev->version >> 28) & 0xf,
+ (dev->version >> 24) & 0xf,
+ (dev->version >> 16) & 0xff);
+}
+static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
+
+static ssize_t show_nets(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(d);
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d", dev->net_count);
+}
+static DEVICE_ATTR(nets, S_IRUGO, show_nets, NULL);
+#endif
+
+static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
+{
+ int actual_length;
+
+ return usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev, 2),
+ msg,
+ msg->msg.hdr.len << 2,
+ &actual_length,
+ 1000);
+}
+
+static int esd_usb2_wait_msg(struct esd_usb2 *dev,
+ struct esd_usb2_msg *msg)
+{
+ int actual_length;
+
+ return usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev, 1),
+ msg,
+ sizeof(*msg),
+ &actual_length,
+ 1000);
+}
+
+static int esd_usb2_setup_rx_urbs(struct esd_usb2 *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;
+
+ /* create a URB, and a buffer for it */
+ 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_buffer_alloc(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");
+ err = -ENOMEM;
+ goto freeurb;
+ }
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev, 1),
+ buf, RX_BUFFER_SIZE,
+ esd_usb2_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_buffer_free(dev->udev, RX_BUFFER_SIZE, buf,
+ urb->transfer_dma);
+ }
+
+freeurb:
+ /* Drop reference, USB core will take care of freeing it */
+ usb_free_urb(urb);
+ if (err)
+ break;
+ }
+
+ /* Did we submit any URBs */
+ if (i == 0) {
+ dev_err(dev->udev->dev.parent, "couldn't setup read URBs\n");
+ return err;
+ }
+
+ /* Warn if we've couldn't transmit all the URBs */
+ if (i < MAX_RX_URBS) {
+ dev_warn(dev->udev->dev.parent,
+ "rx performance may be slow\n");
+ }
+
+ dev->rxinitdone = 1;
+ return 0;
+}
+
+/*
+ * Start interface
+ */
+static int esd_usb2_start(struct esd_usb2_net_priv *priv)
+{
+ struct esd_usb2 *dev = priv->usb2;
+ struct net_device *netdev = priv->netdev;
+ struct esd_usb2_msg msg;
+ int err, i;
+
+ /*
+ * Enable all IDs
+ * The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
+ * Each bit represents one 11 bit CAN identifier. A set bit
+ * enables reception of the corresponding CAN identifier. A cleared
+ * bit disabled this identifier. An additional bitmask value
+ * following the CAN 2.0A bits is used to enable reception of
+ * extended CAN frames. Only the LSB of this final mask is checked
+ * for the complete 29 bit ID range. The IDADD message also allows
+ * filter configuration for an ID subset. In this case you can add
+ * the number of the starting bitmask (0..64) to the filter.option
+ * field followed by only some bitmasks.
+ */
+ msg.msg.hdr.cmd = CMD_IDADD;
+ msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg.msg.filter.net = priv->index;
+ msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ for (i = 0; i < ESD_MAX_ID_SEGMENT; i++)
+ msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff);
+ /* enable 29bit extended IDs */
+ msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
+
+ err = esd_usb2_send_msg(dev, &msg);
+ if (err)
+ goto failed;
+
+ err = esd_usb2_setup_rx_urbs(dev);
+ if (err)
+ goto failed;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+
+failed:
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+
+ dev_err(netdev->dev.parent, "couldn't start device: %d\n", err);
+
+ return err;
+}
+
+static void unlink_all_urbs(struct esd_usb2 *dev)
+{
+ struct esd_usb2_net_priv *priv;
+ int i;
+
+ usb_kill_anchored_urbs(&dev->rx_submitted);
+ for (i = 0; i < dev->net_count; i++) {
+ priv = dev->nets[i];
+ if (priv) {
+ usb_kill_anchored_urbs(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_jobs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+ }
+ }
+}
+
+static int esd_usb2_open(struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ int err;
+
+ /* common open */
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ /* finally start device */
+ err = esd_usb2_start(priv);
+ if (err) {
+ dev_warn(netdev->dev.parent,
+ "couldn't start device: %d\n", err);
+ close_candev(netdev);
+ return err;
+ }
+
+ priv->open_time = jiffies;
+
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ struct esd_usb2 *dev = priv->usb2;
+ struct esd_tx_urb_context *context = NULL;
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ struct esd_usb2_msg *msg;
+ struct urb *urb;
+ u8 *buf;
+ int i, err;
+ int ret = NETDEV_TX_OK;
+ size_t size = sizeof(struct esd_usb2_msg);
+
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
+ /* create a URB, and a buffer for it, and copy the data to the URB */
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ dev_err(netdev->dev.parent, "No memory left for URBs\n");
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ goto nourbmem;
+ }
+
+ buf = usb_buffer_alloc(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);
+ if (!buf) {
+ dev_err(netdev->dev.parent, "No memory left for USB buffer\n");
+ stats->tx_dropped++;
+ dev_kfree_skb(skb);
+ goto nobufmem;
+ }
+
+ msg = (struct esd_usb2_msg *)buf;
+
+ msg->msg.hdr.len = 3; /* minimal length */
+ msg->msg.hdr.cmd = CMD_CAN_TX;
+ msg->msg.tx.net = priv->index;
+ msg->msg.tx.dlc = cf->can_dlc;
+ msg->msg.tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ msg->msg.tx.dlc |= ESD_RTR;
+
+ if (cf->can_id & CAN_EFF_FLAG)
+ msg->msg.tx.id |= cpu_to_le32(ESD_EXTID);
+
+ for (i = 0; i < cf->can_dlc; i++)
+ msg->msg.tx.data[i] = cf->data[i];
+
+ msg->msg.hdr.len += (cf->can_dlc + 3) >> 2;
+
+ for (i = 0; i < MAX_TX_URBS; i++) {
+ if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
+ context = &priv->tx_contexts[i];
+ break;
+ }
+ }
+
+ /*
+ * This may never happen.
+ */
+ if (!context) {
+ dev_warn(netdev->dev.parent, "couldn't find free context\n");
+ ret = NETDEV_TX_BUSY;
+ goto releasebuf;
+ }
+
+ context->priv = priv;
+ context->echo_index = i;
+ context->dlc = cf->can_dlc;
+
+ /* hnd must not be 0 - MSB is stripped in txdone handling */
+ msg->msg.tx.hnd = 0x80000000 | i; /* returned in TX done message */
+
+ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
+ msg->msg.hdr.len << 2,
+ esd_usb2_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_jobs);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ can_free_echo_skb(netdev, context->echo_index);
+
+ atomic_dec(&priv->active_tx_jobs);
+ usb_unanchor_urb(urb);
+
+ stats->tx_dropped++;
+
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+ else
+ dev_warn(netdev->dev.parent, "failed tx_urb %d\n", err);
+
+ goto releasebuf;
+ }
+
+ netdev->trans_start = jiffies;
+
+ /* Slow down tx path */
+ if (atomic_read(&priv->active_tx_jobs) >= MAX_TX_URBS)
+ netif_stop_queue(netdev);
+
+ /*
+ * Release our reference to this URB, the USB core will eventually free
+ * it entirely.
+ */
+ usb_free_urb(urb);
+
+ return NETDEV_TX_OK;
+
+releasebuf:
+ usb_buffer_free(dev->udev, size, buf, urb->transfer_dma);
+
+nobufmem:
+ usb_free_urb(urb);
+
+nourbmem:
+ return ret;
+}
+
+static int esd_usb2_close(struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ struct esd_usb2_msg msg;
+ int i;
+
+ /* Disable all IDs (see esd_usb2_start()) */
+ msg.msg.hdr.cmd = CMD_IDADD;
+ msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg.msg.filter.net = priv->index;
+ msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
+ msg.msg.filter.mask[i] = 0;
+ esd_usb2_send_msg(priv->usb2, &msg);
+
+ /* set CAN controller to reset mode */
+ msg.msg.hdr.len = 2;
+ msg.msg.hdr.cmd = CMD_SETBAUD;
+ msg.msg.setbaud.net = priv->index;
+ msg.msg.setbaud.rsvd = 0;
+ msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
+ esd_usb2_send_msg(priv->usb2, &msg);
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ netif_stop_queue(netdev);
+
+ close_candev(netdev);
+
+ priv->open_time = 0;
+
+ return 0;
+}
+
+static const struct net_device_ops esd_usb2_netdev_ops = {
+ .ndo_open = esd_usb2_open,
+ .ndo_stop = esd_usb2_close,
+ .ndo_start_xmit = esd_usb2_start_xmit,
+};
+
+static struct can_bittiming_const esd_usb2_bittiming_const = {
+ .name = "esd_usb2",
+ .tseg1_min = ESD_USB2_TSEG1_MIN,
+ .tseg1_max = ESD_USB2_TSEG1_MAX,
+ .tseg2_min = ESD_USB2_TSEG2_MIN,
+ .tseg2_max = ESD_USB2_TSEG2_MAX,
+ .sjw_max = ESD_USB2_SJW_MAX,
+ .brp_min = ESD_USB2_BRP_MIN,
+ .brp_max = ESD_USB2_BRP_MAX,
+ .brp_inc = ESD_USB2_BRP_INC,
+};
+
+static int esd_usb2_set_bittiming(struct net_device *netdev)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ struct esd_usb2_msg msg;
+ u32 canbtr;
+
+ canbtr = ESD_USB2_UBR;
+ canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1);
+ canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1))
+ << ESD_USB2_SJW_SHIFT;
+ canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1)
+ & (ESD_USB2_TSEG1_MAX - 1))
+ << ESD_USB2_TSEG1_SHIFT;
+ canbtr |= ((bt->phase_seg2 - 1) & (ESD_USB2_TSEG2_MAX - 1))
+ << ESD_USB2_TSEG2_SHIFT;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ canbtr |= ESD_USB2_3_SAMPLES;
+
+ msg.msg.hdr.len = 2;
+ msg.msg.hdr.cmd = CMD_SETBAUD;
+ msg.msg.setbaud.net = priv->index;
+ msg.msg.setbaud.rsvd = 0;
+ msg.msg.setbaud.baud = cpu_to_le32(canbtr);
+
+ dev_info(netdev->dev.parent, "setting BTR=%#x\n", canbtr);
+
+ return esd_usb2_send_msg(priv->usb2, &msg);
+}
+
+static int esd_usb2_get_berr_counter(const struct net_device *netdev,
+ struct can_berr_counter *bec)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+
+ bec->txerr = priv->bec.txerr;
+ bec->rxerr = priv->bec.rxerr;
+
+ return 0;
+}
+
+static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+ struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+
+ if (!priv->open_time)
+ return -EINVAL;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ netif_wake_queue(netdev);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
+{
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+ struct net_device *netdev;
+ struct esd_usb2_net_priv *priv;
+ int err;
+ int i;
+
+ netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "couldn't alloc candev\n");
+ return -ENOMEM;
+ }
+
+ priv = netdev_priv(netdev);
+
+ init_usb_anchor(&priv->tx_submitted);
+ atomic_set(&priv->active_tx_jobs, 0);
+
+ for (i = 0; i < MAX_TX_URBS; i++)
+ priv->tx_contexts[i].echo_index = MAX_TX_URBS;
+
+ priv->usb2 = dev;
+ priv->netdev = netdev;
+ priv->index = index;
+
+ priv->can.state = CAN_STATE_STOPPED;
+ priv->can.clock.freq = ESD_USB2_CAN_CLOCK;
+ priv->can.bittiming_const = &esd_usb2_bittiming_const;
+ priv->can.do_set_bittiming = esd_usb2_set_bittiming;
+ priv->can.do_set_mode = esd_usb2_set_mode;
+ priv->can.do_get_berr_counter = esd_usb2_get_berr_counter;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+
+ netdev->flags |= IFF_ECHO; /* we support local echo */
+
+ netdev->netdev_ops = &esd_usb2_netdev_ops;
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ err = register_candev(netdev);
+ if (err) {
+ dev_err(&intf->dev,
+ "couldn't register CAN device: %d\n", err);
+ free_candev(netdev);
+ return -ENOMEM;
+ }
+
+ dev->nets[index] = priv;
+ dev_info(netdev->dev.parent, "device %s registered\n", netdev->name);
+ return 0;
+}
+
+/*
+ * probe function for new USB2 devices
+ *
+ * check version information and number of available
+ * CAN interfaces
+ */
+static int esd_usb2_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct esd_usb2 *dev;
+ struct esd_usb2_msg msg;
+ int i, err = -ENOMEM;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->udev = interface_to_usbdev(intf);
+
+ init_usb_anchor(&dev->rx_submitted);
+
+ usb_set_intfdata(intf, dev);
+
+ /* query number of CAN interfaces (nets) */
+ msg.msg.hdr.cmd = CMD_VERSION;
+ msg.msg.hdr.len = 2;
+ msg.msg.version.rsvd = 0;
+ msg.msg.version.flags = 0;
+ msg.msg.version.drv_version = 0;
+
+ if (esd_usb2_send_msg(dev, &msg) < 0) {
+ dev_err(&intf->dev, "sending version message failed\n");
+ goto free_dev;
+ }
+
+ if (esd_usb2_wait_msg(dev, &msg) < 0) {
+ dev_err(&intf->dev, "no version message answer\n");
+ goto free_dev;
+ }
+
+ dev->net_count = (int)msg.msg.version_reply.nets;
+ dev->version = le32_to_cpu(msg.msg.version_reply.version);
+
+#ifdef CONFIG_SYSFS
+ if (device_create_file(&intf->dev, &dev_attr_firmware))
+ dev_err(&intf->dev,
+ "Couldn't create device file for firmware\n");
+
+ if (device_create_file(&intf->dev, &dev_attr_hardware))
+ dev_err(&intf->dev,
+ "Couldn't create device file for hardware\n");
+
+ if (device_create_file(&intf->dev, &dev_attr_nets))
+ dev_err(&intf->dev,
+ "Couldn't create device file for nets\n");
+#endif
+
+ /* do per device probing */
+ for (i = 0; i < dev->net_count; i++)
+ esd_usb2_probe_one_net(intf, i);
+
+ return 0;
+
+free_dev:
+ kfree(dev);
+ return err;
+}
+
+/*
+ * called by the usb core when the device is removed from the system
+ */
+static void esd_usb2_disconnect(struct usb_interface *intf)
+{
+ struct esd_usb2 *dev = usb_get_intfdata(intf);
+ struct net_device *netdev;
+ int i;
+
+#ifdef CONFIG_SYSFS
+ device_remove_file(&intf->dev, &dev_attr_firmware);
+ device_remove_file(&intf->dev, &dev_attr_hardware);
+ device_remove_file(&intf->dev, &dev_attr_nets);
+#endif
+ usb_set_intfdata(intf, NULL);
+
+ if (dev) {
+ for (i = 0; i < dev->net_count; i++) {
+ if (dev->nets[i]) {
+ netdev = dev->nets[i]->netdev;
+ unregister_netdev(netdev);
+ free_candev(netdev);
+ }
+ }
+ unlink_all_urbs(dev);
+ }
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver esd_usb2_driver = {
+ .name = "esd_usb2",
+ .probe = esd_usb2_probe,
+ .disconnect = esd_usb2_disconnect,
+ .id_table = esd_usb2_table,
+};
+
+static int __init esd_usb2_init(void)
+{
+ int err;
+
+ /* register this driver with the USB subsystem */
+ err = usb_register(&esd_usb2_driver);
+
+ if (err) {
+ err("usb_register failed. Error number %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+module_init(esd_usb2_init);
+
+static void __exit esd_usb2_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&esd_usb2_driver);
+}
+module_exit(esd_usb2_exit);
--
1.5.6.3
^ permalink raw reply related
* Re: [PATCH] net/core: Save the port number a netdevice uses
From: Eli Cohen @ 2010-05-26 9:08 UTC (permalink / raw)
To: David Miller; +Cc: eli, netdev, linux-rdma, rdreier, yevgenyp
In-Reply-To: <20100526.015526.102555441.davem@davemloft.net>
On Wed, May 26, 2010 at 01:55:26AM -0700, David Miller wrote:
> From: Eli Cohen <eli@dev.mellanox.co.il>
> Date: Wed, 26 May 2010 11:45:23 +0300
>
>
> What's wrong with using the existing dev_id sysfs file name and saying
> that it means the port number of the card?
>
> Nobody, and I really mean nobody, uses this thing any more.
>
> It used to be a way for devices like the qeth driver to get it's
> IPV6 EUI48 value set properly for local IPV6 addresses assigned
> to the device, but that got fixed in a different way.
>
> So we can use this value however we wish now, and it defaults to zero
> for every single device now, and is propagated across VLAN devices,
> which is perfect.
OK. So if I understand you correctly, you think that I should not
bother to set a default value of 1. Each driver that cares about the
value of this field, will set it however they want.
^ permalink raw reply
* why the number of queue of NIC impact the ping results?
From: Jon Zhou @ 2010-05-26 9:01 UTC (permalink / raw)
To: netdev@vger.kernel.org
broadcom bnx2x netxtreme2-5.2.50,kernel 2.6.27-19
@receiver:
insmod ./bnx2x.ko multi_mode=1 num_queues=12/14/16
@sender:
ping receiver ->response OK
but no response when
insmod ./bnx2x.ko multi_mode=1 num_queues=2/4/8/10
have any idea?
thanks
jon
^ permalink raw reply
* Re: [PATCH] net/core: Save the port number a netdevice uses
From: David Miller @ 2010-05-26 8:55 UTC (permalink / raw)
To: eli-LDSdmyG8hGV8YrgS2mwiifqBs+8SCbDb
Cc: eli-VPRAkNaXOzVS1MOuV/RT9w, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-rdma-u79uwXL29TY76Z2rM5mHXA, rdreier-FYB4Gu1CFyUAvxtiuMwx3w,
yevgenyp-VPRAkNaXOzVS1MOuV/RT9w
In-Reply-To: <20100526084523.GA28748-8YAHvHwT2UEvbXDkjdHOrw/a8Rv0c6iv@public.gmane.org>
From: Eli Cohen <eli-LDSdmyG8hGV8YrgS2mwiifqBs+8SCbDb@public.gmane.org>
Date: Wed, 26 May 2010 11:45:23 +0300
> Do you think we should use dev_id also for the sysfs file name so
> every driver can choose to interpret this field as it chooses to, or
> should I keep the sysfs file name as "port_number"?
What's wrong with using the existing dev_id sysfs file name and saying
that it means the port number of the card?
Nobody, and I really mean nobody, uses this thing any more.
It used to be a way for devices like the qeth driver to get it's
IPV6 EUI48 value set properly for local IPV6 addresses assigned
to the device, but that got fixed in a different way.
So we can use this value however we wish now, and it defaults to zero
for every single device now, and is propagated across VLAN devices,
which is perfect.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [Patch] fix packet loss and massive ping spikes with PPP multi-link
From: Richard Hartmann @ 2010-05-26 8:47 UTC (permalink / raw)
To: wharms, linux-kernel, netdev, linux-ppp; +Cc: erik_list
In-Reply-To: <4BFC0942.2030103@bfs.de>
==It seems LKML & netdev were dropped from the To list, re-adding==
Hi Walter,
> if (ppp->rrsched % ppp->n_channels == i)
>
> since both do not change in that while() loop you can calculate in advance
> perhaps ppp->rrsched %= ppp->n_channels before the while ?
> (that would reduce my bad feels about variables that only increments also :)
rrsched and i do change when appropriate. As they are used as a cheap
way to get round robin, rrsched is not even initialized. One can argue
that this should be done, but as it literally does not matter where the
value starts counting....
> btw: you are doing after loop() if(pch->chan == NULL) continue;
> that means the else in the if below if (pch->chan) should never be reached.
> Or is it likely that some channel will be dropped (?) ?
Channels could be dropped and we need to guard against that.
> btw: this is intentional ? looks strange
>
> if(ppp_ml_noexplode) {
> + }
> + else {
Leftover from various printks for debugging reasons.
Thanks for your feedback,
Richard
^ permalink raw reply
* Re: [PATCH] net/core: Save the port number a netdevice uses
From: Eli Cohen @ 2010-05-26 8:45 UTC (permalink / raw)
To: David Miller
Cc: eli-VPRAkNaXOzVS1MOuV/RT9w, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-rdma-u79uwXL29TY76Z2rM5mHXA, rdreier-FYB4Gu1CFyUAvxtiuMwx3w,
yevgenyp-VPRAkNaXOzVS1MOuV/RT9w
In-Reply-To: <20100526.013926.28807066.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
On Wed, May 26, 2010 at 01:39:26AM -0700, David Miller wrote:
> From: Eli Cohen <eli-VPRAkNaXOzVS1MOuV/RT9w@public.gmane.org>
> Date: Wed, 26 May 2010 11:17:02 +0300
>
> > Today, there are no means to know which port of a hardware device a netdev
> > interface uses. This patch adds a new field to struct net_device that is used
> > to store this value. The network driver should use the SET_NETDEV_PORT_NUM()
> > macro to set the port number for the device it manages. For drivers that do not
> > set a value, a default value of 1 is set at alloc_netdev_mq().
> > This patch also makes use of this feature in the mlx4_en driver.
> >
> > Signed-off-by: Eli Cohen <eli-VPRAkNaXOzVS1MOuV/RT9w@public.gmane.org>
>
> We have an existing dev_id, use it.
Do you think we should use dev_id also for the sysfs file name so
every driver can choose to interpret this field as it chooses to, or
should I keep the sysfs file name as "port_number"?
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* MSI-X resource become less and less
From: Jon Zhou @ 2010-05-26 8:38 UTC (permalink / raw)
To: netdev@vger.kernel.org
let's take Broadcom bnx2x as example:
first of all I can insmod bnx2x.ko multi_mode=1 num_queue=16
but when I do this:
rmmod bnx2x; insmod bnx2x.ko multi_mode=1 num_queue=8 ->OK 8 queues
rmmod bnx2x; insmod bnx2x.ko multi_mode=1 num_queue=4 ->OK 4 queues
...
finally I do this:
rmmod bnx2x; insmod bnx2x.ko multi_mode=1 num_queue=4
I found the driver can only get 1 or 2 queues! it doesn't come back to 4+ queues any longer!
MSI-X resource become less and less, any resource isn't free?
kernel:2.6.27.19
XEON 5500 16 core
thanks
jon
^ permalink raw reply
* Re: [PATCH] net/core: Save the port number a netdevice uses
From: David Miller @ 2010-05-26 8:39 UTC (permalink / raw)
To: eli; +Cc: netdev, linux-rdma, rdreier, yevgenyp
In-Reply-To: <20100526081702.GA17160@mtldesk030.lab.mtl.com>
From: Eli Cohen <eli@mellanox.co.il>
Date: Wed, 26 May 2010 11:17:02 +0300
> Today, there are no means to know which port of a hardware device a netdev
> interface uses. This patch adds a new field to struct net_device that is used
> to store this value. The network driver should use the SET_NETDEV_PORT_NUM()
> macro to set the port number for the device it manages. For drivers that do not
> set a value, a default value of 1 is set at alloc_netdev_mq().
> This patch also makes use of this feature in the mlx4_en driver.
>
> Signed-off-by: Eli Cohen <eli@mellanox.co.il>
We have an existing dev_id, use it.
^ permalink raw reply
* [PATCH] net/core: Save the port number a netdevice uses
From: Eli Cohen @ 2010-05-26 8:17 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-rdma, rdreier, yevgenyp
Today, there are no means to know which port of a hardware device a netdev
interface uses. This patch adds a new field to struct net_device that is used
to store this value. The network driver should use the SET_NETDEV_PORT_NUM()
macro to set the port number for the device it manages. For drivers that do not
set a value, a default value of 1 is set at alloc_netdev_mq().
This patch also makes use of this feature in the mlx4_en driver.
Signed-off-by: Eli Cohen <eli@mellanox.co.il>
---
drivers/net/mlx4/en_netdev.c | 1 +
include/linux/netdevice.h | 6 ++++++
net/core/dev.c | 1 +
net/core/net-sysfs.c | 2 ++
4 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 6c2b15b..d3df609 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -978,6 +978,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
+ SET_NETDEV_PORT_NUM(dev, port);
/*
* Initialize driver private data
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3857517..2a52a6a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -843,6 +843,7 @@ struct net_device {
unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
unsigned char addr_len; /* hardware address length */
unsigned short dev_id; /* for shared network cards */
+ unsigned short port_num; /* for multiport devices */
struct netdev_hw_addr_list uc; /* Secondary unicast
mac addresses */
@@ -1080,6 +1081,11 @@ static inline void *netdev_priv(const struct net_device *dev)
*/
#define SET_NETDEV_DEVTYPE(net, devtype) ((net)->dev.type = (devtype))
+/*
+ * Set the port number of the physical device that this port net device uses
+ */
+#define SET_NETDEV_PORT_NUM(net, portnum) ((net)->port_num = (portnum))
+
/**
* netif_napi_add - initialize a napi context
* @dev: network device
diff --git a/net/core/dev.c b/net/core/dev.c
index 264137f..8e2f5df 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5471,6 +5471,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
dev->_tx = tx;
dev->num_tx_queues = queue_count;
dev->real_num_tx_queues = queue_count;
+ dev->port_num = 1;
dev->gso_max_size = GSO_MAX_SIZE;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 59cfc7d..c3d9b39 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -97,6 +97,7 @@ NETDEVICE_SHOW(ifindex, fmt_dec);
NETDEVICE_SHOW(features, fmt_long_hex);
NETDEVICE_SHOW(type, fmt_dec);
NETDEVICE_SHOW(link_mode, fmt_dec);
+NETDEVICE_SHOW(port_num, fmt_dec);
/* use same locking rules as GIFHWADDR ioctl's */
static ssize_t show_address(struct device *dev, struct device_attribute *attr,
@@ -299,6 +300,7 @@ static struct device_attribute net_class_attributes[] = {
__ATTR(features, S_IRUGO, show_features, NULL),
__ATTR(type, S_IRUGO, show_type, NULL),
__ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
+ __ATTR(port_num, S_IRUGO, show_port_num, NULL),
__ATTR(address, S_IRUGO, show_address, NULL),
__ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
__ATTR(carrier, S_IRUGO, show_carrier, NULL),
--
1.7.1
^ permalink raw reply related
* Re: Warning in net/ipv4/af_inet.c:154
From: David Miller @ 2010-05-26 7:56 UTC (permalink / raw)
To: anton; +Cc: eric.dumazet, netdev
In-Reply-To: <20100526031943.GA28295@kryten>
From: Anton Blanchard <anton@samba.org>
Date: Wed, 26 May 2010 13:19:43 +1000
> I notice we update sk_forward_alloc in sk_mem_charge and sk_mem_uncharge.
> Since it isn't an atomic variable I went looking for a lock somewhere in
> the call chain (first thought was the socket lock). I couldn't find
> anything, but I could easily be missing something.
We take the lock properly for all of the skb_queue_rcv_skb() cases
but this rule isn't followed properly for skb_queue_err_skb().
Eric, look at even things like skb_tstamp_tx(). Nothing locks the
socket in those cases, yet we dip down into sock_queue_err_skb() and
thus invoke skb_set_owner_r which goes into sk_mem_charge() and does
the non-atomic update on ->sk_forward_alloc.
I am sure there are other cases with this problem involving
sock_queue_err_skb()... ip_icmp_error() (via __udp4_lib_err()),
ipv6_icmp_error(), etc.
^ permalink raw reply
* Re: [patch] sctp: dubious bitfields in sctp_transport
From: David Miller @ 2010-05-26 7:40 UTC (permalink / raw)
To: error27; +Cc: vladislav.yasevich, sri, yjwei, linux-sctp, netdev,
kernel-janitors
In-Reply-To: <20100522202024.GL22515@bicker>
From: Dan Carpenter <error27@gmail.com>
Date: Sat, 22 May 2010 22:20:24 +0200
> Sparse complains because these one-bit bitfields are signed.
> include/net/sctp/structs.h:879:24: error: dubious one-bit signed bitfield
> include/net/sctp/structs.h:889:31: error: dubious one-bit signed bitfield
> include/net/sctp/structs.h:895:26: error: dubious one-bit signed bitfield
> include/net/sctp/structs.h:898:31: error: dubious one-bit signed bitfield
> include/net/sctp/structs.h:901:27: error: dubious one-bit signed bitfield
>
> It doesn't cause a problem in the current code, but it would be better
> to clean it up. This was introduced by c0058a35aacc7: "sctp: Save some
> room in the sctp_transport by using bitfields".
>
> Signed-off-by: Dan Carpenter <error27@gmail.com>
Applied, thanks Dan.
^ permalink raw reply
* Re: [patch] ipmr: off by one in __ipmr_fill_mroute()
From: David Miller @ 2010-05-26 7:39 UTC (permalink / raw)
To: error27; +Cc: netdev, kuznet, pekkas, jmorris, yoshfuji, kaber, eric.dumazet
In-Reply-To: <20100522175357.GF22515@bicker>
From: Dan Carpenter <error27@gmail.com>
Date: Sat, 22 May 2010 19:54:48 +0200
> This fixes a smatch warning:
> net/ipv4/ipmr.c +1917 __ipmr_fill_mroute(12) error: buffer overflow
> '(mrt)->vif_table' 32 <= 32
>
> The ipv6 version had the same issue.
>
> Signed-off-by: Dan Carpenter <error27@gmail.com>
Introduced by commit "7438189b".
Applied, thanks Dan.
^ permalink raw reply
* Re: [PATCH] be2net: increase POST timeout for EEH recovery
From: David Miller @ 2010-05-26 7:33 UTC (permalink / raw)
To: sathyap; +Cc: netdev
In-Reply-To: <20100526070048.GA2312@serverengines.com>
From: Sathya Perla <sathyap@serverengines.com>
Date: Wed, 26 May 2010 12:30:48 +0530
> Sometimes BE requires longer time for POST completion after an EEH reset.
> Increasing the timeout value accordingly.
>
> Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] tcp: Socket option to set congestion window
From: David Miller @ 2010-05-26 7:33 UTC (permalink / raw)
To: therbert; +Cc: shemminger, netdev, ycheng
In-Reply-To: <AANLkTinHGMtfw4Oydfgx0w7QLb-HyYSKdI-4smD-BEkq@mail.gmail.com>
From: Tom Herbert <therbert@google.com>
Date: Wed, 26 May 2010 00:06:35 -0700
> It's really not that simple. In the application with multiple
> connections, congestion may only affect some number of connections, so
> more of the aggregate window may be preserved. This is an unfairness
> issue between 1 and N connection scenarios which is a real problem.
If this is true, then by all account your patch allows things to be
even worse.
Because now applications can still open up N connections, but with an
even larger initial CWND, with potentially exponential ramifications
on network congestion.
So yet another reason not to consider this feature seriously. It's
not an application level attribute, it's a network path one. Please
take it seriously because I really mean it.
^ permalink raw reply
* [PATCH] be2net: increase POST timeout for EEH recovery
From: Sathya Perla @ 2010-05-26 7:00 UTC (permalink / raw)
To: netdev
Sometimes BE requires longer time for POST completion after an EEH reset.
Increasing the timeout value accordingly.
Signed-off-by: Sathya Perla <sathyap@serverengines.com>
---
drivers/net/benet/be_cmds.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index c911bfb..9d11dbf 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -294,7 +294,7 @@ int be_cmd_POST(struct be_adapter *adapter)
} else {
return 0;
}
- } while (timeout < 20);
+ } while (timeout < 40);
dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage);
return -1;
--
1.6.5.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox