* Re: [PATCH] Driver-core: Fix bluetooth network device rename regression
From: Kay Sievers @ 2010-07-27 15:32 UTC (permalink / raw)
To: Greg KH
Cc: Johannes Berg, Eric W. Biederman, Greg KH, Andrew Morton,
Rafael J. Wysocki, Maciej W. Rozycki, netdev
In-Reply-To: <20100727150921.GD5803@kroah.com>
On Tue, Jul 27, 2010 at 17:09, Greg KH <greg@kroah.com> wrote:
> On Tue, Jul 27, 2010 at 03:59:50PM +0200, Johannes Berg wrote:
>> On Tue, 2010-07-27 at 06:49 -0700, Greg KH wrote:
>>
>> > And Eric, where are you working on the "real" patches to solve the
>> > problems of the bnet and wireless driver problems so we can remove this
>> > check from the driver core as soon as possible? Any idea when they will
>> > be done?
>>
>> They'll be done as soon as the driver core offers the required
>> functionality, which we discussed elsewhere in this thread.
>
> {sigh}
>
> Kay provided a solution for this a number of times already. What, are
> you really going to make him type it up _again_? That's just completly
> unfair to him.
Sure, I still offer any needed help, if there are new requirements now
that need core changes. But hey, they will not land magically, if
nobody is working on it. And "as soon as the core offers" is not how
we make new features work on Linux. The people who add new features,
which uncover old bugs, need to fix the old bugs instead of papering
them over, like it happened here.
> And note, Eric, this was and is, completely due to your changes, so I am
> holding you responsible for fixing it correctly. Please do so.
I guess faking a 'bluetooth renaming regression', which never existed,
which wasn't even known to the bluetooth maintainers, was just much
easier. :)
Kay
^ permalink raw reply
* Re: [PATCH] Driver-core: Fix bluetooth network device rename regression
From: Greg KH @ 2010-07-27 15:09 UTC (permalink / raw)
To: Johannes Berg
Cc: Kay Sievers, Eric W. Biederman, Greg KH, Andrew Morton,
Rafael J. Wysocki, Maciej W. Rozycki, netdev
In-Reply-To: <1280239190.3755.4.camel@jlt3.sipsolutions.net>
On Tue, Jul 27, 2010 at 03:59:50PM +0200, Johannes Berg wrote:
> On Tue, 2010-07-27 at 06:49 -0700, Greg KH wrote:
>
> > And Eric, where are you working on the "real" patches to solve the
> > problems of the bnet and wireless driver problems so we can remove this
> > check from the driver core as soon as possible? Any idea when they will
> > be done?
>
> They'll be done as soon as the driver core offers the required
> functionality, which we discussed elsewhere in this thread.
{sigh}
Kay provided a solution for this a number of times already. What, are
you really going to make him type it up _again_? That's just completly
unfair to him.
And note, Eric, this was and is, completely due to your changes, so I am
holding you responsible for fixing it correctly. Please do so.
greg k-h
^ permalink raw reply
* Re: ixgbe->bonding->vlan->bridge->ebtables&iptables causes memory corruption
From: Eric Dumazet @ 2010-07-27 14:31 UTC (permalink / raw)
To: Gyorgy Jeney; +Cc: netdev, linux-kernel
In-Reply-To: <AANLkTimEYWiz4d-go6PszKnR0U29FYfjvHeLbPavi-RH@mail.gmail.com>
Le mardi 27 juillet 2010 à 09:15 +0200, Gyorgy Jeney a écrit :
> Hi,
>
> I have a rather interesting network setup here. First I have a dual
> 10Gbit ixgbe ethernet card, being bonded into one link, on which we
> run a number of vlans, which are bridged with various virtual
> machines. Now, to protect the box itself and the virtual machines I
> have a set of iptables and ebtables rules. Whenever one of the
> virtual machines start the kernel, which is 2.6.35-rc6, will reliably
> panic.
>
> This error needs both ebtables and iptables rules, without either one
> or the other, things seem to work quite well.
>
> The errors and backtraces are many and long, so I attached the full
> dmes output, please say if you need more.
>
> nog.
Not related to your crashes, but I wonder how
net/bridge/netfilter/ebt_vlan.c is supposed to work with hw accelerated
vlans...
^ permalink raw reply
* Re: br_forward.c - rcu dereference warning
From: Paul E. McKenney @ 2010-07-27 12:38 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev
In-Reply-To: <1280227553.3755.2.camel@jlt3.sipsolutions.net>
On Tue, Jul 27, 2010 at 12:45:53PM +0200, Johannes Berg wrote:
> I couldn't find this reported yet, apologies if I missed it.
My first guess is that the call to br_multicast_deliver() in
br_dev_xmit() needs to be enclosed in rcu_read_lock(), but I have
to defer to someone who knows the code better. Another possible
fix would be to change the rcu_dereference() in br_multicast_flood()
to rcu_dereference_bh(), for example.
Thanx, Paul
> johannes
>
> [ 60.140433] ===================================================
> [ 60.140437] [ INFO: suspicious rcu_dereference_check() usage. ]
> [ 60.140440] ---------------------------------------------------
> [ 60.140444] /home/johannes/sys/wireless-testing/net/bridge/br_forward.c:215 invoked rcu_dereference_check() without protection!
> [ 60.140447]
> [ 60.140448] other info that might help us debug this:
> [ 60.140449]
> [ 60.140452]
> [ 60.140453] rcu_scheduler_active = 1, debug_locks = 1
> [ 60.140457] 2 locks held by Xorg/3083:
> [ 60.140459] #0: (&im->timer){+.-...}, at: [<ffffffff81058180>] call_timer_fn+0x0/0x2f0
> [ 60.140473] #1: (rcu_read_lock_bh){.+....}, at: [<ffffffff813b6c3a>] dev_queue_xmit+0x5a/0x690
> [ 60.140484]
> [ 60.140484] stack backtrace:
> [ 60.140489] Pid: 3083, comm: Xorg Not tainted 2.6.35-rc6-wl-47665-gc2e2180-dirty #174
> [ 60.140492] Call Trace:
> [ 60.140495] <IRQ> [<ffffffff8107e494>] lockdep_rcu_dereference+0xa4/0xc0
> [ 60.140514] [<ffffffffa07617c3>] br_multicast_flood+0x293/0x310 [bridge]
> [ 60.140531] [<ffffffffa0761877>] br_multicast_deliver+0x17/0x20 [bridge]
> [ 60.140539] [<ffffffffa07607bc>] br_dev_xmit+0x10c/0x170 [bridge]
> [ 60.140550] [<ffffffff813b69ba>] dev_hard_start_xmit+0x21a/0x2e0
> [ 60.140556] [<ffffffff813b708e>] dev_queue_xmit+0x4ae/0x690
> [ 60.140576] [<ffffffff813c0d43>] neigh_resolve_output+0x113/0x250
> [ 60.140582] [<ffffffff813eec46>] ip_finish_output+0x2a6/0x570
> [ 60.140588] [<ffffffff813ef33c>] ip_mc_output+0x1dc/0x320
> [ 60.140593] [<ffffffff813ed7ed>] ip_local_out+0x2d/0x80
> [ 60.140600] [<ffffffff81422236>] igmp_send_report+0x1c6/0x200
> [ 60.140610] [<ffffffff814238f0>] igmp_timer_expire+0x100/0x130
> [ 60.140615] [<ffffffff81058219>] call_timer_fn+0x99/0x2f0
> [ 60.140636] [<ffffffff810585e3>] run_timer_softirq+0x173/0x330
> [ 60.140641] [<ffffffff8104f114>] __do_softirq+0x114/0x3d0
> [ 60.140652] [<ffffffff8100360c>] call_softirq+0x1c/0x50
>
>
> --
> 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] Driver-core: Fix bluetooth network device rename regression
From: Johannes Berg @ 2010-07-27 13:59 UTC (permalink / raw)
To: Greg KH
Cc: Kay Sievers, Eric W. Biederman, Greg KH, Andrew Morton,
Rafael J. Wysocki, Maciej W. Rozycki, netdev
In-Reply-To: <20100727134904.GA4994@kroah.com>
On Tue, 2010-07-27 at 06:49 -0700, Greg KH wrote:
> And Eric, where are you working on the "real" patches to solve the
> problems of the bnet and wireless driver problems so we can remove this
> check from the driver core as soon as possible? Any idea when they will
> be done?
They'll be done as soon as the driver core offers the required
functionality, which we discussed elsewhere in this thread.
johannes
^ permalink raw reply
* Re: [PATCH] Driver-core: Fix bluetooth network device rename regression
From: Greg KH @ 2010-07-27 13:49 UTC (permalink / raw)
To: Kay Sievers
Cc: Eric W. Biederman, Greg KH, Johannes Berg, Andrew Morton,
Rafael J. Wysocki, Maciej W. Rozycki, netdev
In-Reply-To: <AANLkTincg-0-h1aqW4A=z6A+HTbOfkCCWKDD18ZUEGSn@mail.gmail.com>
On Tue, Jul 27, 2010 at 11:10:26AM +0200, Kay Sievers wrote:
> On Mon, Jul 26, 2010 at 20:09, Greg KH <greg@kroah.com> wrote:
> >> Does this version of the change look less bleh worthy? The effect is
> >> the same as my previous patch but the test is more abstract so the
> >> effect is not strictly limited to /sys/class/net.
> >
> > What other class type has a namespace at this point in time?
> > Essentially this is the same exact thing, just in a different format
> > that obfuscates what you are really doing here.
>
> The patch still looks broken, and does not belong into the core the
> way it is done. We denied hacks like this for good reason. But
> out-of-the-blue it was a bluetooth naming regression to fix in the
> driver core? Interesting!
>
> If someone is going to add namespaces to 'block' or 'input', the sysfs
> layout will break, and userspace will be unable to handle the
> resulting changes.
When that happens, I'm sure Eric will be willing to fix up any problems
that are found as he is the one that insisted on pushing it to Linus
around our objections.
Right Eric?
And Eric, where are you working on the "real" patches to solve the
problems of the bnet and wireless driver problems so we can remove this
check from the driver core as soon as possible? Any idea when they will
be done?
thanks,
greg k-h
^ permalink raw reply
* Problem with ARPING broadcasting
From: Gilder @ 2010-07-27 13:34 UTC (permalink / raw)
To: netdev
[-- Attachment #1: Type: TEXT/plain, Size: 547 bytes --]
New version of ARPing commited at 2010-04-12 by YOSHIFUJI Hideaki has a problem with sending proper network packet's - broadcast address isn't ff:ff:ff:ff:ff:ff but ff:XX:ff:XX:00:XX ( where XX is current device MAC fragments ).
That cause a problem, that not all devices respond to that arp-broadcast.
I've attached small patchfile to solving this problem.
------------------------------------------------------------------------ Wakacje na kredyt bez odsetek? Sprawdz mozliwosci kart kredytowych MultiBanku!
http://linkint.pl/f27a7
[-- Attachment #2: arping.patch --]
[-- Type: APPLICATION/octet-stream, Size: 258 bytes --]
337,339c337,340
< for (p = ba, ch = 0; p < ba + balen; p++, ch++) {
< *p = strtoul(brdcast->value + ch * 3, NULL, 16);
< }
---
>
> for (p = ba, ch = 0; p < ba + balen; p++, ch += 3)
> *p++ = strtoul(brdcast->value + ch * 3, NULL, 16);
>
^ permalink raw reply
* [PATCH v4] can: Add driver for esd CAN-USB/2 device
From: Matthias Fuchs @ 2010-07-27 13:42 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 4:
- use WARN_ON instead of BUG_ON
- add more error handling (handle esd_us2_send_msg() return code)
- use single point of return from functions where appropriate
- eliminate race condition during stopping/restarting queue
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 | 1137 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 1144 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..1c06e96
--- /dev/null
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -0,0 +1,1137 @@
+/*
+ * 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);
+
+ WARN_ON(!context);
+
+ priv = context->priv;
+ netdev = priv->netdev;
+ dev = priv->usb2;
+
+ /* free up our allocated buffer */
+ usb_free_coherent(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_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");
+ 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_free_coherent(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_alloc_coherent(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);
+
+ /* Slow down tx path */
+ if (atomic_read(&priv->active_tx_jobs) >= MAX_TX_URBS)
+ netif_stop_queue(netdev);
+
+ 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;
+
+ /*
+ * Release our reference to this URB, the USB core will eventually free
+ * it entirely.
+ */
+ usb_free_urb(urb);
+
+ return NETDEV_TX_OK;
+
+releasebuf:
+ usb_free_coherent(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;
+ if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ dev_err(netdev->dev.parent, "sending idadd message failed\n");
+
+ /* 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);
+ if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ dev_err(netdev->dev.parent, "sending setbaud message failed\n");
+
+ 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 = 0;
+ int i;
+
+ netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "couldn't alloc candev\n");
+ err = -ENOMEM;
+ goto done;
+ }
+
+ 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);
+ err = -ENOMEM;
+ goto done;
+ }
+
+ dev->nets[index] = priv;
+ dev_info(netdev->dev.parent, "device %s registered\n", netdev->name);
+
+done:
+ return err;
+}
+
+/*
+ * 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;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ 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;
+
+ err = esd_usb2_send_msg(dev, &msg);
+ if (err < 0) {
+ dev_err(&intf->dev, "sending version message failed\n");
+ goto free_dev;
+ }
+
+ err = esd_usb2_wait_msg(dev, &msg);
+ if (err < 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);
+done:
+ 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-next] drivers/scsi: Remove warnings after vsprintf %pV introduction
From: James Bottomley @ 2010-07-27 13:12 UTC (permalink / raw)
To: Joe Perches
Cc: David Miller, sfr, netdev, linux-next, linux-kernel, gregkh,
Matthew Wilcox, linux-scsi
In-Reply-To: <1278824921.1501.37.camel@Joe-Laptop.home>
On Sat, 2010-07-10 at 22:08 -0700, Joe Perches wrote:
> On Sat, 2010-07-10 at 19:52 -0700, David Miller wrote:
> > Could you take a stab at this and the other scsi bits that
> > trigger this warning?
>
> Remove warnings introduced by conversions of dev_<level>
> macros to functions.
>
> Compile tested only.
>
> Signed-off-by: Joe Perches <joe@perches.com>
> ---
> drivers/scsi/constants.c | 63 ++++++++++++++++++++---------------
> drivers/scsi/sd.c | 6 ++--
> drivers/scsi/sym53c8xx_2/sym_hipd.c | 10 ++---
> 3 files changed, 43 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
> index cd05e04..f95de51 100644
> --- a/drivers/scsi/constants.c
> +++ b/drivers/scsi/constants.c
> @@ -1226,29 +1226,38 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
> }
> EXPORT_SYMBOL(scsi_extd_sense_format);
>
> +static void scsi_show_extd_sense_args(const char *fmt, ...)
> +{
> + va_list args;
> + struct va_format vaf;
> +
> + va_start(args, fmt);
> +
> + vaf.fmt = fmt;
> + vaf.va = &args;
> +
> + printk(KERN_CONT "Add. Sense: %pV\n", &vaf);
> +
> + va_end(args);
> +}
> +
This doesn't have a place in the patch, it's an unnecessary conversion
> void
> scsi_show_extd_sense(unsigned char asc, unsigned char ascq)
> {
> const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
>
> if (extd_sense_fmt) {
> - if (strstr(extd_sense_fmt, "%x")) {
> - printk("Add. Sense: ");
> - printk(extd_sense_fmt, ascq);
> - } else
> - printk("Add. Sense: %s", extd_sense_fmt);
> + scsi_show_extd_sense_args(extd_sense_fmt, ascq);
> } else {
> if (asc >= 0x80)
> - printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc,
> - ascq);
> + printk(KERN_CONT "<<vendor>> ASC=0x%x ASCQ=0x%x",
> + asc, ascq);
> if (ascq >= 0x80)
> - printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc,
> - ascq);
> + printk(KERN_CONT "ASC=0x%x <<vendor>> ASCQ=0x%x\n",
> + asc, ascq);
> else
> - printk("ASC=0x%x ASCQ=0x%x", asc, ascq);
> + printk(KERN_CONT "ASC=0x%x ASCQ=0x%x\n", asc, ascq);
And half these KERN_CONT additions are spurious since you'd not
otherwise touch the line
> }
> -
> - printk("\n");
> }
> EXPORT_SYMBOL(scsi_show_extd_sense);
>
> @@ -1310,15 +1319,15 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
> if (0 == res) {
> /* this may be SCSI-1 sense data */
> num = (sense_len < 32) ? sense_len : 32;
> - printk("Unrecognized sense data (in hex):");
> + printk(KERN_CONT "Unrecognized sense data (in hex):");
> for (k = 0; k < num; ++k) {
> if (0 == (k % 16)) {
> - printk("\n");
> - printk(KERN_INFO " ");
> + printk(KERN_CONT "\n");
> + printk(KERN_INFO " ");
> }
> - printk("%02x ", sense_buffer[k]);
> + printk(KERN_CONT " %02x", sense_buffer[k]);
> }
> - printk("\n");
> + printk(KERN_CONT "\n");
> return;
> }
> }
> @@ -1364,22 +1373,22 @@ scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
> res += snprintf(buff + res, blen - res, "ILI");
> }
> if (res > 0)
> - printk("%s\n", buff);
> + printk(KERN_CONT "%s\n", buff);
> } else if (sshdr->additional_length > 0) {
> /* descriptor format with sense descriptors */
> num = 8 + sshdr->additional_length;
> num = (sense_len < num) ? sense_len : num;
> - printk("Descriptor sense data with sense descriptors "
> + printk(KERN_CONT "Descriptor sense data with sense descriptors "
> "(in hex):");
> for (k = 0; k < num; ++k) {
> if (0 == (k % 16)) {
> - printk("\n");
> - printk(KERN_INFO " ");
> + printk(KERN_CONT "\n");
> + printk(KERN_INFO " ");
> }
> - printk("%02x ", sense_buffer[k]);
> + printk(KERN_CONT " %02x", sense_buffer[k]);
> }
>
> - printk("\n");
> + printk(KERN_CONT "\n");
> }
>
> }
> @@ -1404,13 +1413,13 @@ void scsi_print_sense(char *name, struct scsi_cmnd *cmd)
> {
> struct scsi_sense_hdr sshdr;
>
> - scmd_printk(KERN_INFO, cmd, "");
> + scmd_printk(KERN_INFO, cmd, " ");
> scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
> &sshdr);
> scsi_show_sense_hdr(&sshdr);
> scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
> &sshdr);
> - scmd_printk(KERN_INFO, cmd, "");
> + scmd_printk(KERN_INFO, cmd, " ");
> scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
> }
> EXPORT_SYMBOL(scsi_print_sense);
> @@ -1443,7 +1452,7 @@ void scsi_show_result(int result)
>
> void scsi_show_result(int result)
> {
> - printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n",
> + printk(KERN_CONT "Result: hostbyte=0x%02x driverbyte=0x%02x\n",
> host_byte(result), driver_byte(result));
> }
>
> @@ -1453,7 +1462,7 @@ EXPORT_SYMBOL(scsi_show_result);
>
> void scsi_print_result(struct scsi_cmnd *cmd)
> {
> - scmd_printk(KERN_INFO, cmd, "");
> + scmd_printk(KERN_INFO, cmd, " ");
> scsi_show_result(cmd->result);
> }
> EXPORT_SYMBOL(scsi_print_result);
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index 829cc37..2fddadd 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -2550,15 +2550,15 @@ module_exit(exit_sd);
> static void sd_print_sense_hdr(struct scsi_disk *sdkp,
> struct scsi_sense_hdr *sshdr)
> {
> - sd_printk(KERN_INFO, sdkp, "");
> + sd_printk(KERN_INFO, sdkp, " ");
> scsi_show_sense_hdr(sshdr);
> - sd_printk(KERN_INFO, sdkp, "");
> + sd_printk(KERN_INFO, sdkp, " ");
> scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
> }
>
> static void sd_print_result(struct scsi_disk *sdkp, int result)
> {
> - sd_printk(KERN_INFO, sdkp, "");
> + sd_printk(KERN_INFO, sdkp, " ");
> scsi_show_result(result);
> }
>
> diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
> index a7bc8b7..d740a5b 100644
> --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
> +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
> @@ -72,10 +72,7 @@ static void sym_printl_hex(u_char *p, int n)
>
> static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg)
> {
> - if (label)
> - sym_print_addr(cp->cmd, "%s: ", label);
> - else
> - sym_print_addr(cp->cmd, "");
> + sym_print_addr(cp->cmd, "%s: ", label);
>
> spi_print_msg(msg);
> printf("\n");
> @@ -4558,7 +4555,8 @@ static void sym_int_sir(struct sym_hcb *np)
> switch (np->msgin [2]) {
> case M_X_MODIFY_DP:
> if (DEBUG_FLAGS & DEBUG_POINTER)
> - sym_print_msg(cp, NULL, np->msgin);
> + sym_print_msg(cp, "extended msg ",
> + np->msgin);
> tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) +
> (np->msgin[5]<<8) + (np->msgin[6]);
> sym_modify_dp(np, tp, cp, tmp);
> @@ -4585,7 +4583,7 @@ static void sym_int_sir(struct sym_hcb *np)
> */
> case M_IGN_RESIDUE:
> if (DEBUG_FLAGS & DEBUG_POINTER)
> - sym_print_msg(cp, NULL, np->msgin);
> + sym_print_msg(cp, "half byte ", np->msgin);
> if (cp->host_flags & HF_SENSE)
> OUTL_DSP(np, SCRIPTA_BA(np, clrack));
> else
OK, so please resend on the necessary bits. That's "" -> " " in the
X_printk() statements. If you remove the space from a continuation
line, then KERN_CONT is appropriate to keep checkpatch quiet.
James
^ permalink raw reply
* Re: nfs client hang
From: Andy Chittenden @ 2010-07-27 12:51 UTC (permalink / raw)
To: Eric Dumazet
Cc: Linux Kernel Mailing List (linux-kernel@vger.kernel.org),
Trond Myklebust, netdev
In-Reply-To: <1280233276.2827.175.camel@edumazet-laptop>
On 2010-07-27 13:21, Eric Dumazet wrote:
> Le mardi 27 juillet 2010 à 11:53 +0100, Andy Chittenden a écrit :
>>>>> IE the client starts a connection and then closes it again without sending data.
>>>> Once this happens, here's some rpcdebug info for the rpc module using 2.6.34.1 kernel:
>>>>
>>>> ... lots of the following nfsv3 WRITE requests:
>>>> [ 7670.026741] 57793 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026759] 57794 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026778] 57795 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026797] 57796 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026815] 57797 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026834] 57798 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026853] 57799 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026871] 57800 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026890] 57801 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7670.026909] 57802 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
>>>> [ 7680.520042] RPC: worker connecting xprt ffff88013e62d800 via tcp to 10.1.6.102 (port 2049)
>>>> [ 7680.520066] RPC: ffff88013e62d800 connect status 99 connected 0 sock state 7
>>>> [ 7680.520074] RPC: 33550 __rpc_wake_up_task (now 4296812426)
>>>> [ 7680.520079] RPC: 33550 disabling timer
>>>> [ 7680.520084] RPC: 33550 removed from queue ffff88013e62db20 "xprt_pending"
>>>> [ 7680.520089] RPC: __rpc_wake_up_task done
>>>> [ 7680.520094] RPC: 33550 __rpc_execute flags=0x1
>>>> [ 7680.520098] RPC: 33550 xprt_connect_status: retrying
>>>> [ 7680.520103] RPC: 33550 call_connect_status (status -11)
>>>> [ 7680.520108] RPC: 33550 call_transmit (status 0)
>>>> [ 7680.520112] RPC: 33550 xprt_prepare_transmit
>>>> [ 7680.520118] RPC: 33550 rpc_xdr_encode (status 0)
>>>> [ 7680.520123] RPC: 33550 marshaling UNIX cred ffff88012e002300
>>>> [ 7680.520130] RPC: 33550 using AUTH_UNIX cred ffff88012e002300 to wrap rpc data
>>>> [ 7680.520136] RPC: 33550 xprt_transmit(32920)
>>>> [ 7680.520145] RPC: xs_tcp_send_request(32920) = -32
>>>> [ 7680.520151] RPC: xs_tcp_state_change client ffff88013e62d800...
>>>> [ 7680.520156] RPC: state 7 conn 0 dead 0 zapped 1
>>> I changed that debug to output sk_shutdown too. That has a value of 2
>>> (IE SEND_SHUTDOWN). Looking at tcp_sendmsg(), I see this:
>>> err = -EPIPE;
>>> if (sk->sk_err || (sk->sk_shutdown& SEND_SHUTDOWN))
>>> goto out_err;
>>> which correlates with the trace "xs_tcp_send_request(32920) = -32". So,
>>> this looks like a problem in the sockets/tcp layer. The rpc layer issues
>>> a shutdown and then reconnects using the same socket. So either
>>> sk_shutdown needs zeroing once the shutdown completes or should be
>>> zeroed on subsequent connect. The latter sounds safer.
>> This patch for 2.6.34.1 fixes the issue:
>>
>> --- /home/company/software/src/linux-2.6.34.1/net/ipv4/tcp_output.c 2010-07-27 08:46:46.917000000 +0100
>> +++ net/ipv4/tcp_output.c 2010-07-27 09:19:16.000000000 +0100
>> @@ -2522,6 +2522,13 @@
>> struct tcp_sock *tp = tcp_sk(sk);
>> __u8 rcv_wscale;
>>
>> + /* clear down any previous shutdown attempts so that
>> + * reconnects on a socket that's been shutdown leave the
>> + * socket in a usable state (otherwise tcp_sendmsg() returns
>> + * -EPIPE).
>> + */
>> + sk->sk_shutdown = 0;
>> +
>> /* We'll fix this up when we get a response from the other end.
>> * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
>> */
>>
>> As I mentioned in my first message, we first saw this issue in 2.6.32 as supplied by debian (linux-image-2.6.32-5-amd64 Version: 2.6.32-17). It looks like the same patch would fix the problem there too.
>>
> CC netdev
>
> This reminds me a similar problem we had in the past, fixed with commit
> 1fdf475a (tcp: tcp_disconnect() should clear window_clamp)
>
> But tcp_disconnect() already clears sk->sk_shutdown
>
> If NFS calls tcp_disconnect(), then shutdown(), there is a problem.
>
> Maybe xs_tcp_shutdown() should make some sanity tests ?
>
> Following sequence is legal, and your patch might break it.
>
> fd = socket(...);
> shutdown(fd, SHUT_WR);
> ...
> connect(fd, ...);
>
>
>
Thanks for the response. From my reading of the RPC code, because
nothing clears the sk_shutdown flag, the RPC code goes into a loop when
recovering from packets being lost:
shutdown
connect
send fails so repeat
My patch stops the NFS client hang that I was seeing but I'm not an
expert on either the socket layer, RPC code or NFS code so I'm happy for
someone else to come up with the alternative, correct fix.
--
Andy, BlueArc Engineering
^ permalink raw reply
* RE: nfs client hang
From: Eric Dumazet @ 2010-07-27 12:21 UTC (permalink / raw)
To: Andy Chittenden
Cc: Linux Kernel Mailing List (linux-kernel@vger.kernel.org),
Trond Myklebust, netdev
In-Reply-To: <ABFC24E4C13D81489F7F624E14891C8607DDF8D1E4@uk-ex-mbx1.terastack.bluearc.com>
Le mardi 27 juillet 2010 à 11:53 +0100, Andy Chittenden a écrit :
> > >> IE the client starts a connection and then closes it again without sending data.
> > > Once this happens, here's some rpcdebug info for the rpc module using 2.6.34.1 kernel:
> > >
> > > ... lots of the following nfsv3 WRITE requests:
> > > [ 7670.026741] 57793 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026759] 57794 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026778] 57795 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026797] 57796 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026815] 57797 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026834] 57798 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026853] 57799 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026871] 57800 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026890] 57801 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7670.026909] 57802 0001 -11 ffff88012e32b000 (null) 0 ffffffffa03beb10 nfsv3 WRITE a:call_reserveresult q:xprt_backlog
> > > [ 7680.520042] RPC: worker connecting xprt ffff88013e62d800 via tcp to 10.1.6.102 (port 2049)
> > > [ 7680.520066] RPC: ffff88013e62d800 connect status 99 connected 0 sock state 7
> > > [ 7680.520074] RPC: 33550 __rpc_wake_up_task (now 4296812426)
> > > [ 7680.520079] RPC: 33550 disabling timer
> > > [ 7680.520084] RPC: 33550 removed from queue ffff88013e62db20 "xprt_pending"
> > > [ 7680.520089] RPC: __rpc_wake_up_task done
> > > [ 7680.520094] RPC: 33550 __rpc_execute flags=0x1
> > > [ 7680.520098] RPC: 33550 xprt_connect_status: retrying
> > > [ 7680.520103] RPC: 33550 call_connect_status (status -11)
> > > [ 7680.520108] RPC: 33550 call_transmit (status 0)
> > > [ 7680.520112] RPC: 33550 xprt_prepare_transmit
> > > [ 7680.520118] RPC: 33550 rpc_xdr_encode (status 0)
> > > [ 7680.520123] RPC: 33550 marshaling UNIX cred ffff88012e002300
> > > [ 7680.520130] RPC: 33550 using AUTH_UNIX cred ffff88012e002300 to wrap rpc data
> > > [ 7680.520136] RPC: 33550 xprt_transmit(32920)
> > > [ 7680.520145] RPC: xs_tcp_send_request(32920) = -32
> > > [ 7680.520151] RPC: xs_tcp_state_change client ffff88013e62d800...
> > > [ 7680.520156] RPC: state 7 conn 0 dead 0 zapped 1
>
> > I changed that debug to output sk_shutdown too. That has a value of 2
> > (IE SEND_SHUTDOWN). Looking at tcp_sendmsg(), I see this:
>
> > err = -EPIPE;
> > if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
> > goto out_err;
>
> > which correlates with the trace "xs_tcp_send_request(32920) = -32". So,
> > this looks like a problem in the sockets/tcp layer. The rpc layer issues
> > a shutdown and then reconnects using the same socket. So either
> > sk_shutdown needs zeroing once the shutdown completes or should be
> > zeroed on subsequent connect. The latter sounds safer.
>
> This patch for 2.6.34.1 fixes the issue:
>
> --- /home/company/software/src/linux-2.6.34.1/net/ipv4/tcp_output.c 2010-07-27 08:46:46.917000000 +0100
> +++ net/ipv4/tcp_output.c 2010-07-27 09:19:16.000000000 +0100
> @@ -2522,6 +2522,13 @@
> struct tcp_sock *tp = tcp_sk(sk);
> __u8 rcv_wscale;
>
> + /* clear down any previous shutdown attempts so that
> + * reconnects on a socket that's been shutdown leave the
> + * socket in a usable state (otherwise tcp_sendmsg() returns
> + * -EPIPE).
> + */
> + sk->sk_shutdown = 0;
> +
> /* We'll fix this up when we get a response from the other end.
> * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
> */
>
> As I mentioned in my first message, we first saw this issue in 2.6.32 as supplied by debian (linux-image-2.6.32-5-amd64 Version: 2.6.32-17). It looks like the same patch would fix the problem there too.
>
CC netdev
This reminds me a similar problem we had in the past, fixed with commit
1fdf475a (tcp: tcp_disconnect() should clear window_clamp)
But tcp_disconnect() already clears sk->sk_shutdown
If NFS calls tcp_disconnect(), then shutdown(), there is a problem.
Maybe xs_tcp_shutdown() should make some sanity tests ?
Following sequence is legal, and your patch might break it.
fd = socket(...);
shutdown(fd, SHUT_WR);
...
connect(fd, ...);
^ permalink raw reply
* Re: Tx queue selection
From: Eric Dumazet @ 2010-07-27 11:57 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: netdev
In-Reply-To: <1280227867.1970.208.camel@pasglop>
Le mardi 27 juillet 2010 à 20:51 +1000, Benjamin Herrenschmidt a écrit :
> Hi folks !
>
> I'm putting my newbie hat on ... :-)
>
> While looking at our ehea driver (and in fact another upcoming driver
> I'm helping with), I noticed it's using the "old style" multiqueue. IE.
> It doesn't use the alloc_netdev_mq() variant, creates one queue on the
> linux side, an makes its own selection of HW queue in start_xmit.
>
> This had many drawbacks, obviously, such as not getting per-queue locks
> etc...
>
> Now, the mechanics of converting that to the new scheme are easy enough
> to figure out by reading the code. However, where my lack of networking
> background fails me is when it comes to the policy of choosing a Tx
> queue.
>
> ehea uses its own hash of the header, different from the "default" queue
> selection in the net core. Looking at other drivers such as ixgbe, I see
> that it can chose to use smp_processor_id() when a flag is set for which
> I don't totally understand the meaning or default to the core algorithm.
>
> Now, while I can understand why it's a good idea to use the current
> processor, in order to limit cache ping pong etc... I'm not really
> confident I understand the pro/cons of using the hashing for tx. I
> understand that the net core can play interesting games with associating
> sockets with queues etc... but I'm a bit at a loss when it comes to
> deciding what's best for this driver. I suppose I could start by
> implementing my own queue selection based on what ehea does today but I
> have the nasty feeling that's going to be sub-optimal :-)
>
> So I would very much appreciate (and reward with free beer at the next
> conference) if somebody could give me a bit of a heads up on how things
> are expected to be done there, pro/cons, perf impact etc...
I am not sure ndo_select_queue() is really needed these days. It was
done before core network was able to use a socket provided hash.
tx queue selection done by default (skb_tx_hash()) should be fine.
bnx2 for example doesnt provide a ndo_select_queue()
^ permalink raw reply
* Re: Tx queue selection
From: Neil Horman @ 2010-07-27 11:50 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: netdev
In-Reply-To: <1280227867.1970.208.camel@pasglop>
On Tue, Jul 27, 2010 at 08:51:07PM +1000, Benjamin Herrenschmidt wrote:
> Hi folks !
>
> I'm putting my newbie hat on ... :-)
>
> While looking at our ehea driver (and in fact another upcoming driver
> I'm helping with), I noticed it's using the "old style" multiqueue. IE.
> It doesn't use the alloc_netdev_mq() variant, creates one queue on the
> linux side, an makes its own selection of HW queue in start_xmit.
>
> This had many drawbacks, obviously, such as not getting per-queue locks
> etc...
>
> Now, the mechanics of converting that to the new scheme are easy enough
> to figure out by reading the code. However, where my lack of networking
> background fails me is when it comes to the policy of choosing a Tx
> queue.
>
> ehea uses its own hash of the header, different from the "default" queue
> selection in the net core. Looking at other drivers such as ixgbe, I see
> that it can chose to use smp_processor_id() when a flag is set for which
> I don't totally understand the meaning or default to the core algorithm.
>
IIRC, that intels Flow Director feature. I've not used it, but from what I
understand flow director is a technology that allows a card to isolate flows to
and from a socket to a single cpu. i.e. the cpu which handles the transmission
of frames will be the cpu that handles frames destined for that flow as well.
To do this they do some additional analysis and steering configuration in the
driver using a user space utility as well. I don't think it makes much sense to
use smp_processor_id in your tx hashing if you don't have some sort of specific
feature like that. The other drivers which implement ndo_select_queue don't do
it, they hash on the skb header like the core does, and make modifications to
that based on hardware capabilities.
HTH
Neil
>
^ permalink raw reply
* Tx queue selection
From: Benjamin Herrenschmidt @ 2010-07-27 10:51 UTC (permalink / raw)
To: netdev
Hi folks !
I'm putting my newbie hat on ... :-)
While looking at our ehea driver (and in fact another upcoming driver
I'm helping with), I noticed it's using the "old style" multiqueue. IE.
It doesn't use the alloc_netdev_mq() variant, creates one queue on the
linux side, an makes its own selection of HW queue in start_xmit.
This had many drawbacks, obviously, such as not getting per-queue locks
etc...
Now, the mechanics of converting that to the new scheme are easy enough
to figure out by reading the code. However, where my lack of networking
background fails me is when it comes to the policy of choosing a Tx
queue.
ehea uses its own hash of the header, different from the "default" queue
selection in the net core. Looking at other drivers such as ixgbe, I see
that it can chose to use smp_processor_id() when a flag is set for which
I don't totally understand the meaning or default to the core algorithm.
Now, while I can understand why it's a good idea to use the current
processor, in order to limit cache ping pong etc... I'm not really
confident I understand the pro/cons of using the hashing for tx. I
understand that the net core can play interesting games with associating
sockets with queues etc... but I'm a bit at a loss when it comes to
deciding what's best for this driver. I suppose I could start by
implementing my own queue selection based on what ehea does today but I
have the nasty feeling that's going to be sub-optimal :-)
So I would very much appreciate (and reward with free beer at the next
conference) if somebody could give me a bit of a heads up on how things
are expected to be done there, pro/cons, perf impact etc...
Thanks in avance !
Cheers,
Ben.
^ permalink raw reply
* br_forward.c - rcu dereference warning
From: Johannes Berg @ 2010-07-27 10:45 UTC (permalink / raw)
To: netdev
I couldn't find this reported yet, apologies if I missed it.
johannes
[ 60.140433] ===================================================
[ 60.140437] [ INFO: suspicious rcu_dereference_check() usage. ]
[ 60.140440] ---------------------------------------------------
[ 60.140444] /home/johannes/sys/wireless-testing/net/bridge/br_forward.c:215 invoked rcu_dereference_check() without protection!
[ 60.140447]
[ 60.140448] other info that might help us debug this:
[ 60.140449]
[ 60.140452]
[ 60.140453] rcu_scheduler_active = 1, debug_locks = 1
[ 60.140457] 2 locks held by Xorg/3083:
[ 60.140459] #0: (&im->timer){+.-...}, at: [<ffffffff81058180>] call_timer_fn+0x0/0x2f0
[ 60.140473] #1: (rcu_read_lock_bh){.+....}, at: [<ffffffff813b6c3a>] dev_queue_xmit+0x5a/0x690
[ 60.140484]
[ 60.140484] stack backtrace:
[ 60.140489] Pid: 3083, comm: Xorg Not tainted 2.6.35-rc6-wl-47665-gc2e2180-dirty #174
[ 60.140492] Call Trace:
[ 60.140495] <IRQ> [<ffffffff8107e494>] lockdep_rcu_dereference+0xa4/0xc0
[ 60.140514] [<ffffffffa07617c3>] br_multicast_flood+0x293/0x310 [bridge]
[ 60.140531] [<ffffffffa0761877>] br_multicast_deliver+0x17/0x20 [bridge]
[ 60.140539] [<ffffffffa07607bc>] br_dev_xmit+0x10c/0x170 [bridge]
[ 60.140550] [<ffffffff813b69ba>] dev_hard_start_xmit+0x21a/0x2e0
[ 60.140556] [<ffffffff813b708e>] dev_queue_xmit+0x4ae/0x690
[ 60.140576] [<ffffffff813c0d43>] neigh_resolve_output+0x113/0x250
[ 60.140582] [<ffffffff813eec46>] ip_finish_output+0x2a6/0x570
[ 60.140588] [<ffffffff813ef33c>] ip_mc_output+0x1dc/0x320
[ 60.140593] [<ffffffff813ed7ed>] ip_local_out+0x2d/0x80
[ 60.140600] [<ffffffff81422236>] igmp_send_report+0x1c6/0x200
[ 60.140610] [<ffffffff814238f0>] igmp_timer_expire+0x100/0x130
[ 60.140615] [<ffffffff81058219>] call_timer_fn+0x99/0x2f0
[ 60.140636] [<ffffffff810585e3>] run_timer_softirq+0x173/0x330
[ 60.140641] [<ffffffff8104f114>] __do_softirq+0x114/0x3d0
[ 60.140652] [<ffffffff8100360c>] call_softirq+0x1c/0x50
^ permalink raw reply
* [net-next 3/3] stmmac: fix automatic PAD/FCS stripping
From: Giuseppe CAVALLARO @ 2010-07-27 10:09 UTC (permalink / raw)
To: netdev; +Cc: Giuseppe Cavallaro
In-Reply-To: <1280225387-26240-2-git-send-email-peppe.cavallaro@st.com>
For Simple Ethernet frames (802.2 and 802.3) the GMAC Core
never strips pad and fcs. This means the ACS has no effect
on IPv4/6 frames.
The FL bits, in the RDES0, include the FCS so the driver
has to remove it in SW.
For 802.3 frame format with LLC or LLC-SNAP, when set the ACS
bit, the HW strips both PAD and FCS.
The FL bits, in the RDES0, actually represents the frame length
already stripped.
This patch fixes this logic within the device driver that
erroneously removed 4byte from 802.3 frames already stripped
corrupting the payload.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/stmmac/common.h | 1 +
drivers/net/stmmac/dwmac1000.h | 2 +-
drivers/net/stmmac/enh_desc.c | 2 +-
drivers/net/stmmac/stmmac_main.c | 8 ++++++--
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h
index 144f76f..66b9da0 100644
--- a/drivers/net/stmmac/common.h
+++ b/drivers/net/stmmac/common.h
@@ -108,6 +108,7 @@ enum rx_frame_status { /* IPC status */
good_frame = 0,
discard_frame = 1,
csum_none = 2,
+ llc_snap = 4,
};
enum tx_dma_irq_status {
diff --git a/drivers/net/stmmac/dwmac1000.h b/drivers/net/stmmac/dwmac1000.h
index d8d0f35..8b20b19 100644
--- a/drivers/net/stmmac/dwmac1000.h
+++ b/drivers/net/stmmac/dwmac1000.h
@@ -93,7 +93,7 @@ enum inter_frame_gap {
#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
-#define GMAC_CONTROL_ACS 0x00000080 /* Automatic Pad Stripping */
+#define GMAC_CONTROL_ACS 0x00000080 /* Automatic Pad/FCS Stripping */
#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
diff --git a/drivers/net/stmmac/enh_desc.c b/drivers/net/stmmac/enh_desc.c
index 3c18ebe..f612f98 100644
--- a/drivers/net/stmmac/enh_desc.c
+++ b/drivers/net/stmmac/enh_desc.c
@@ -123,7 +123,7 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
*/
if (status == 0x0) {
CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
- ret = good_frame;
+ ret = llc_snap;
} else if (status == 0x4) {
CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
ret = good_frame;
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index 1083334..bbb7951 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -1216,9 +1216,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
priv->dev->stats.rx_errors++;
else {
struct sk_buff *skb;
- /* Length should omit the CRC */
- int frame_len = priv->hw->desc->get_rx_frame_len(p) - 4;
+ int frame_len;
+ frame_len = priv->hw->desc->get_rx_frame_len(p);
+ /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
+ * Type frames (LLC/LLC-SNAP) */
+ if (unlikely(status != llc_snap))
+ frame_len -= ETH_FCS_LEN;
#ifdef STMMAC_RX_DEBUG
if (frame_len > ETH_FRAME_LEN)
pr_debug("\tRX frame size %d, COE status: %d\n",
--
1.5.5.6
^ permalink raw reply related
* [net-next 1/3] stmmac: remove the STMMAC_DUAL_MAC option
From: Giuseppe CAVALLARO @ 2010-07-27 10:09 UTC (permalink / raw)
To: netdev; +Cc: Giuseppe Cavallaro
The STMMAC_DUAL_MAC is now removed from the driver's Kconfig.
It will be available from a specific STM boards Kconfig.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/stmmac/Kconfig | 9 ---------
1 files changed, 0 insertions(+), 9 deletions(-)
diff --git a/drivers/net/stmmac/Kconfig b/drivers/net/stmmac/Kconfig
index eb63d44..2513555 100644
--- a/drivers/net/stmmac/Kconfig
+++ b/drivers/net/stmmac/Kconfig
@@ -20,15 +20,6 @@ config STMMAC_DA
By default, the DMA arbitration scheme is based on Round-robin
(rx:tx priority is 1:1).
-config STMMAC_DUAL_MAC
- bool "STMMAC: dual mac support (EXPERIMENTAL)"
- default n
- depends on EXPERIMENTAL && STMMAC_ETH && !STMMAC_TIMER
- help
- Some ST SoCs (for example the stx7141 and stx7200c2) have two
- Ethernet Controllers. This option turns on the second Ethernet
- device on this kind of platforms.
-
config STMMAC_TIMER
bool "STMMAC Timer optimisation"
default n
--
1.5.5.6
^ permalink raw reply related
* [net-next 2/3] stmmac: fix timer setup when use dual mac Kconfig
From: Giuseppe CAVALLARO @ 2010-07-27 10:09 UTC (permalink / raw)
To: netdev; +Cc: Giuseppe Cavallaro
In-Reply-To: <1280225387-26240-1-git-send-email-peppe.cavallaro@st.com>
The driver erroneously sets the tmrate to zero when the
TMU initialisation fails. This actually generates problems
while using the dual GMAC configuration.
With this patch, enabling both the dual gmac and the timer
optimisation, the first interface opened will use the tmu
channel 2, the second one won't be able to use the timer but
will continue to work without mitigating the interrupts by
using the external timer (i.e. TMU channel 2).
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/stmmac/stmmac_main.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index 0bdd332..1083334 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -829,7 +829,6 @@ static int stmmac_open(struct net_device *dev)
* In case of failure continue without timer. */
if (unlikely((stmmac_open_ext_timer(dev, priv->tm)) < 0)) {
pr_warning("stmmaceth: cannot attach the external timer.\n");
- tmrate = 0;
priv->tm->freq = 0;
priv->tm->timer_start = stmmac_no_timer_started;
priv->tm->timer_stop = stmmac_no_timer_stopped;
--
1.5.5.6
^ permalink raw reply related
* [patch -next] ixgbe: potential null dereference
From: Dan Carpenter @ 2010-07-27 10:05 UTC (permalink / raw)
To: Jeff Kirsher
Cc: Jesse Brandeburg, Bruce Allan, Alex Duyck, PJ Waskiewicz,
John Ronciak, David S. Miller, Don Skidmore,
Mallikarjuna R Chilakala, e1000-devel, netdev, kernel-janitors
The e_dev_err() macro dereferences "adapter" which is NULL here.
Signed-off-by: Dan Carpenter <error27@gmail.com>
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 9203759..0360260 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -6549,8 +6549,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
err = dma_set_coherent_mask(&pdev->dev,
DMA_BIT_MASK(32));
if (err) {
- e_dev_err("No usable DMA configuration, "
- "aborting\n");
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting\n");
goto err_dma;
}
}
@@ -6560,7 +6560,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
IORESOURCE_MEM), ixgbe_driver_name);
if (err) {
- e_dev_err("pci_request_selected_regions failed 0x%x\n", err);
+ dev_err(&pdev->dev,
+ "pci_request_selected_regions failed 0x%x\n", err);
goto err_pci_reg;
}
^ permalink raw reply related
* [net-next-2.6 PATCH] igbvf, ixgbevf: use dev_hw_addr_random
From: Stefan Assmann @ 2010-07-27 9:24 UTC (permalink / raw)
To: netdev; +Cc: e1000-devel, jeffrey.t.kirsher, Rose, Gregory V, David Miller
From: Stefan Assmann <sassmann@redhat.com>
Both igbvf and ixgbevf should set addr_assign_type to NET_ADDR_RANDOM
so udev creates persistent net rules by matching the device path.
Do this by using the dev_hw_addr_random helper function.
Signed-off-by: Stefan Assmann <sassmann@redhat.com>
---
drivers/net/igbvf/netdev.c | 2 +-
drivers/net/ixgbevf/ixgbevf_main.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 5e2b2a8..048595b 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -2751,7 +2751,7 @@ static int __devinit igbvf_probe(struct pci_dev *pdev,
dev_info(&pdev->dev,
"PF still in reset state, assigning new address."
" Is the PF interface up?\n");
- random_ether_addr(hw->mac.addr);
+ dev_hw_addr_random(adapter->netdev, hw->mac.addr);
} else {
err = hw->mac.ops.read_mac_addr(hw);
if (err) {
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
index af49135..4867440 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -2229,7 +2229,7 @@ static int __devinit ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
if (err) {
dev_info(&pdev->dev,
"PF still in reset state, assigning new address\n");
- random_ether_addr(hw->mac.addr);
+ dev_hw_addr_random(adapter->netdev, hw->mac.addr);
} else {
err = hw->mac.ops.init_hw(hw);
if (err) {
--
1.6.5.2
^ permalink raw reply related
* [PATCH] ks8842: Support DMA when accessed via timberdale
From: Richard Röjfors @ 2010-07-27 9:18 UTC (permalink / raw)
To: netdev; +Cc: davem
This patch adds support for RX and TX DMA via the DMA API,
this is only supported when the KS8842 is accessed via timberdale.
There is no support for DMA on the generic bus interface it self,
a state machine inside the FPGA is handling RX and TX transfers to/from
buffers in the FPGA. The host CPU can do DMA to and from these buffers.
The FPGA has to handle the RX interrupts, so these must be enabled in
the ks8842 but not in the FPGA. The driver must not disable the RX interrupt
that would mean that the data transfers into the FPGA buffers would stop.
The host shall not enable TX interrupts since TX is handled by the FPGA,
the host is notified by DMA callbacks when transfers are finished.
Which DMA channels to use are added as parameters in the platform data struct.
Signed-off-by: Richard Röjfors <richard.rojfors@pelagicore.com>
---
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 70b98e7..386e283 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1757,6 +1757,16 @@ config KS8842
ethernet switch chip (managed, VLAN, QoS) from Micrel or
Timberdale(FPGA).
+config KS8842_TIMB_DMA
+ bool "Use Timberdale specific DMA engine"
+ depends on KS8842 && MFD_TIMBERDALE
+ select CONFIG_TIMB_DMA
+ help
+ This option enables usage of the timberdale specific DMA engine
+ for the KS8842 driver. Rather than using PIO which results in
+ single accesses over PCIe, the DMA block of the timberdale FPGA
+ will burst data to and from the KS8842.
+
config KS8851
tristate "Micrel KS8851 SPI"
depends on SPI
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c
index 289b0be..c59c8e1 100644
--- a/drivers/net/ks8842.c
+++ b/drivers/net/ks8842.c
@@ -30,6 +30,11 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/ks8842.h>
+#ifdef CONFIG_KS8842_TIMB_DMA
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#endif
#define DRV_NAME "ks8842"
@@ -82,6 +87,17 @@
#define IRQ_RX_ERROR 0x0080
#define ENABLED_IRQS (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \
IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
+#ifdef CONFIG_KS8842_TIMB_DMA
+ /* When running via timberdale in DMA mode, the RX interrupt should be
+ enabled in the KS8842, but not in the FPGA IP, since the IP handles
+ RX DMA internally.
+ TX interrupts are not needed it is handled by the FPGA the driver is
+ notified via DMA callbacks.
+ */
+ #define ENABLED_IRQS_IP (IRQ_LINK_CHANGE | IRQ_RX_STOPPED | \
+ IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
+ #define ENABLED_IRQS_DMA (ENABLED_IRQS_IP | IRQ_RX)
+#endif
#define REG_ISR 0x02
#define REG_RXSR 0x04
#define RXSR_VALID 0x8000
@@ -124,6 +140,31 @@
#define MICREL_KS884X 0x01 /* 0=Timeberdale(FPGA), 1=Micrel */
#define KS884X_16BIT 0x02 /* 1=16bit, 0=32bit */
+#ifdef CONFIG_KS8842_TIMB_DMA
+#define DMA_BUFFER_SIZE 2048
+
+struct ks8842_tx_dma_ctl {
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *adesc;
+ void *buf;
+ struct scatterlist sg;
+ int channel;
+};
+
+struct ks8842_rx_dma_ctl {
+ struct dma_chan *chan;
+ struct dma_async_tx_descriptor *adesc;
+ struct sk_buff *skb;
+ struct scatterlist sg;
+ struct tasklet_struct tasklet;
+ int channel;
+};
+
+#define KS8842_USE_DMA(adapter) (((adapter)->dma_tx.channel != -1) && \
+ ((adapter)->dma_rx.channel != -1))
+
+#endif
+
struct ks8842_adapter {
void __iomem *hw_addr;
int irq;
@@ -132,8 +173,23 @@ struct ks8842_adapter {
spinlock_t lock; /* spinlock to be interrupt safe */
struct work_struct timeout_work;
struct net_device *netdev;
+#ifdef CONFIG_KS8842_TIMB_DMA
+ struct device *dev;
+ struct ks8842_tx_dma_ctl dma_tx;
+ struct ks8842_rx_dma_ctl dma_rx;
+#endif
};
+#ifdef CONFIG_KS8842_TIMB_DMA
+static void ks8842_dma_rx_cb(void *data);
+static void ks8842_dma_tx_cb(void *data);
+
+static inline void ks8842_resume_dma(struct ks8842_adapter *adapter)
+{
+ iowrite32(1, adapter->hw_addr + REQ_TIMB_DMA_RESUME);
+}
+#endif
+
static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank)
{
iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK);
@@ -297,8 +353,23 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter)
ks8842_write16(adapter, 18, 0xffff, REG_ISR);
/* enable interrupts */
- ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
-
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter)) {
+ /* When running in DMA Mode the RX interrupt is not enabled in
+ timberdale because RX data is received by DMA callbacks
+ it must still be enabled in the KS8842 because it indicates
+ to timberdale when there is RX data for it's DMA FIFOs */
+ iowrite16(ENABLED_IRQS_IP, adapter->hw_addr + REG_TIMB_IER);
+ ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
+ } else {
+#endif
+ if (!(adapter->conf_flags & MICREL_KS884X))
+ iowrite16(ENABLED_IRQS,
+ adapter->hw_addr + REG_TIMB_IER);
+ ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ }
+#endif
/* enable the switch */
ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE);
}
@@ -371,6 +442,55 @@ static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter)
return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff;
}
+#ifdef CONFIG_KS8842_TIMB_DMA
+static int ks8842_tx_frame_dma(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_tx_dma_ctl *ctl = &adapter->dma_tx;
+ u8 *buf = ctl->buf;
+
+ if (ctl->adesc) {
+ netdev_dbg(netdev, "%s: TX ongoing\n", __func__);
+ /* transfer ongoing */
+ return NETDEV_TX_BUSY;
+ }
+
+ sg_dma_len(&ctl->sg) = skb->len + sizeof(u32);
+
+ /* copy data to the TX buffer */
+ /* the control word, enable IRQ, port 1 and the length */
+ *buf++ = 0x00;
+ *buf++ = 0x01; /* Port 1 */
+ *buf++ = skb->len & 0xff;
+ *buf++ = (skb->len >> 8) & 0xff;
+ skb_copy_from_linear_data(skb, buf, skb->len);
+
+ dma_sync_single_range_for_device(adapter->dev,
+ sg_dma_address(&ctl->sg), 0, sg_dma_len(&ctl->sg),
+ DMA_TO_DEVICE);
+
+ /* make sure the length is a multiple of 4 */
+ if (sg_dma_len(&ctl->sg) % 4)
+ sg_dma_len(&ctl->sg) += 4 - sg_dma_len(&ctl->sg) % 4;
+
+ ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+ &ctl->sg, 1, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+ if (!ctl->adesc)
+ return NETDEV_TX_BUSY;
+
+ ctl->adesc->callback_param = netdev;
+ ctl->adesc->callback = ks8842_dma_tx_cb;
+ ctl->adesc->tx_submit(ctl->adesc);
+
+ netdev->stats.tx_bytes += skb->len;
+
+ dev_kfree_skb(skb);
+
+ return NETDEV_TX_OK;
+}
+#endif
+
static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct ks8842_adapter *adapter = netdev_priv(netdev);
@@ -422,6 +542,123 @@ static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
}
+static void ks8842_update_rx_err_counters(struct net_device *netdev, u32 status)
+{
+ netdev_dbg(netdev, "RX error, status: %x\n", status);
+
+ netdev->stats.rx_errors++;
+ if (status & RXSR_TOO_LONG)
+ netdev->stats.rx_length_errors++;
+ if (status & RXSR_CRC_ERROR)
+ netdev->stats.rx_crc_errors++;
+ if (status & RXSR_RUNT)
+ netdev->stats.rx_frame_errors++;
+}
+
+static void ks8842_update_rx_counters(struct net_device *netdev, u32 status,
+ int len)
+{
+ netdev_dbg(netdev, "RX packet, len: %d\n", len);
+
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += len;
+ if (status & RXSR_MULTICAST)
+ netdev->stats.multicast++;
+}
+
+#ifdef CONFIG_KS8842_TIMB_DMA
+static int __ks8842_start_new_rx_dma(struct net_device *netdev)
+{
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
+ struct scatterlist *sg = &ctl->sg;
+ int err;
+
+ ctl->skb = netdev_alloc_skb(netdev, DMA_BUFFER_SIZE);
+ if (ctl->skb) {
+ sg_init_table(sg, 1);
+ sg_dma_address(sg) = dma_map_single(adapter->dev,
+ ctl->skb->data, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ err = dma_mapping_error(adapter->dev, sg_dma_address(sg));
+ if (unlikely(err)) {
+ sg_dma_address(sg) = 0;
+ goto out;
+ }
+
+ sg_dma_len(sg) = DMA_BUFFER_SIZE;
+
+ ctl->adesc = ctl->chan->device->device_prep_slave_sg(ctl->chan,
+ sg, 1, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+
+ if (!ctl->adesc)
+ goto out;
+
+ ctl->adesc->callback_param = netdev;
+ ctl->adesc->callback = ks8842_dma_rx_cb;
+ ctl->adesc->tx_submit(ctl->adesc);
+ } else {
+ err = -ENOMEM;
+ sg_dma_address(sg) = 0;
+ goto out;
+ }
+
+ return err;
+out:
+ if (sg_dma_address(sg))
+ dma_unmap_single(adapter->dev, sg_dma_address(sg),
+ DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ sg_dma_address(sg) = 0;
+ if (ctl->skb)
+ dev_kfree_skb(ctl->skb);
+
+ ctl->skb = NULL;
+
+ printk(KERN_ERR DRV_NAME": Failed to start RX DMA: %d\n", err);
+ return err;
+}
+
+static void ks8842_rx_frame_dma_tasklet(unsigned long arg)
+{
+ struct net_device *netdev = (struct net_device *)arg;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_rx_dma_ctl *ctl = &adapter->dma_rx;
+ struct sk_buff *skb = ctl->skb;
+ dma_addr_t addr = sg_dma_address(&ctl->sg);
+ u32 status;
+
+ ctl->adesc = NULL;
+
+ /* kick next transfer going */
+ __ks8842_start_new_rx_dma(netdev);
+
+ /* now handle the data we got */
+ dma_unmap_single(adapter->dev, addr, DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ status = *((u32 *)skb->data);
+
+ netdev_dbg(netdev, "%s - rx_data: status: %x\n",
+ __func__, status & 0xffff);
+
+ /* check the status */
+ if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
+ int len = (status >> 16) & 0x7ff;
+
+ ks8842_update_rx_counters(netdev, status, len);
+
+ /* reserve 4 bytes which is the status word */
+ skb_reserve(skb, 4);
+ skb_put(skb, len);
+
+ skb->protocol = eth_type_trans(skb, netdev);
+ netif_rx(skb);
+ } else {
+ ks8842_update_rx_err_counters(netdev, status);
+ dev_kfree_skb(skb);
+ }
+}
+#endif
+
static void ks8842_rx_frame(struct net_device *netdev,
struct ks8842_adapter *adapter)
{
@@ -445,13 +682,9 @@ static void ks8842_rx_frame(struct net_device *netdev,
if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len);
- netdev_dbg(netdev, "%s, got package, len: %d\n", __func__, len);
if (skb) {
- netdev->stats.rx_packets++;
- netdev->stats.rx_bytes += len;
- if (status & RXSR_MULTICAST)
- netdev->stats.multicast++;
+ ks8842_update_rx_counters(netdev, status, len);
if (adapter->conf_flags & KS884X_16BIT) {
u16 *data16 = (u16 *)skb_put(skb, len);
@@ -477,16 +710,8 @@ static void ks8842_rx_frame(struct net_device *netdev,
netif_rx(skb);
} else
netdev->stats.rx_dropped++;
- } else {
- netdev_dbg(netdev, "RX error, status: %x\n", status);
- netdev->stats.rx_errors++;
- if (status & RXSR_TOO_LONG)
- netdev->stats.rx_length_errors++;
- if (status & RXSR_CRC_ERROR)
- netdev->stats.rx_crc_errors++;
- if (status & RXSR_RUNT)
- netdev->stats.rx_frame_errors++;
- }
+ } else
+ ks8842_update_rx_err_counters(netdev, status);
/* set high watermark to 3K */
ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR);
@@ -541,6 +766,14 @@ void ks8842_tasklet(unsigned long arg)
isr = ks8842_read16(adapter, 18, REG_ISR);
netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ /* when running in DMA mode, do not ack RX interrupts, it is handled
+ internally by timberdale, otherwise it's DMA FIFO:s would stop
+ */
+ if (KS8842_USE_DMA(adapter))
+ isr &= ~IRQ_RX;
+#endif
+
/* Ack */
ks8842_write16(adapter, 18, isr, REG_ISR);
@@ -554,9 +787,14 @@ void ks8842_tasklet(unsigned long arg)
if (isr & IRQ_LINK_CHANGE)
ks8842_update_link_status(netdev, adapter);
+ /* should not get IRQ_RX when running DMA mode */
if (isr & (IRQ_RX | IRQ_RX_ERROR))
- ks8842_handle_rx(netdev, adapter);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (!KS8842_USE_DMA(adapter))
+#endif
+ ks8842_handle_rx(netdev, adapter);
+ /* should only happen when in PIO mode */
if (isr & IRQ_TX)
ks8842_handle_tx(netdev, adapter);
@@ -575,8 +813,19 @@ void ks8842_tasklet(unsigned long arg)
/* re-enable interrupts, put back the bank selection register */
spin_lock_irqsave(&adapter->lock, flags);
- ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter))
+ ks8842_write16(adapter, 18, ENABLED_IRQS_DMA, REG_IER);
+ else
+#endif
+ ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ /* Make sure timberdale continues DMA operations, they are stopped while
+ we are handling the ks8842 because we might change bank */
+ if (KS8842_USE_DMA(adapter))
+ ks8842_resume_dma(adapter);
+#endif
spin_unlock_irqrestore(&adapter->lock, flags);
}
@@ -592,8 +841,14 @@ static irqreturn_t ks8842_irq(int irq, void *devid)
netdev_dbg(netdev, "%s - ISR: 0x%x\n", __func__, isr);
if (isr) {
- /* disable IRQ */
- ks8842_write16(adapter, 18, 0x00, REG_IER);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter))
+ /* disable all but RX IRQ, since the FPGA relies on it*/
+ ks8842_write16(adapter, 18, IRQ_RX, REG_IER);
+ else
+#endif
+ /* disable IRQ */
+ ks8842_write16(adapter, 18, 0x00, REG_IER);
/* schedule tasklet */
tasklet_schedule(&adapter->tasklet);
@@ -602,10 +857,154 @@ static irqreturn_t ks8842_irq(int irq, void *devid)
}
iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
-
+#ifdef CONFIG_KS8842_TIMB_DMA
+ /* After an interrupt, tell timberdale to continue DMA operations.
+ DMA is disabled while we are handling the ks8842 because we might
+ change bank */
+ ks8842_resume_dma(adapter);
+#endif
return ret;
}
+#ifdef CONFIG_KS8842_TIMB_DMA
+static void ks8842_dma_rx_cb(void *data)
+{
+ struct net_device *netdev = data;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+
+ netdev_dbg(netdev, "RX DMA finished\n");
+ /* schedule tasklet */
+ if (adapter->dma_rx.adesc)
+ tasklet_schedule(&adapter->dma_rx.tasklet);
+}
+
+static void ks8842_dma_tx_cb(void *data)
+{
+ struct net_device *netdev = data;
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_tx_dma_ctl *ctl = &adapter->dma_tx;
+
+ netdev_dbg(netdev, "TX DMA finished\n");
+
+ if (!ctl->adesc)
+ return;
+
+ netdev->stats.tx_packets++;
+ ctl->adesc = NULL;
+
+ if (netif_queue_stopped(netdev))
+ netif_wake_queue(netdev);
+}
+
+static void ks8842_stop_dma(struct ks8842_adapter *adapter)
+{
+ struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+ struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+
+ tx_ctl->adesc = NULL;
+ if (tx_ctl->chan)
+ tx_ctl->chan->device->device_control(tx_ctl->chan,
+ DMA_TERMINATE_ALL, 0);
+
+ rx_ctl->adesc = NULL;
+ if (rx_ctl->chan)
+ rx_ctl->chan->device->device_control(rx_ctl->chan,
+ DMA_TERMINATE_ALL, 0);
+
+ if (sg_dma_address(&rx_ctl->sg))
+ dma_unmap_single(adapter->dev, sg_dma_address(&rx_ctl->sg),
+ DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ sg_dma_address(&rx_ctl->sg) = 0;
+
+ dev_kfree_skb(rx_ctl->skb);
+ rx_ctl->skb = NULL;
+}
+
+static void ks8842_dealloc_dma_bufs(struct ks8842_adapter *adapter)
+{
+ struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+ struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+
+ ks8842_stop_dma(adapter);
+
+ if (tx_ctl->chan)
+ dma_release_channel(tx_ctl->chan);
+ tx_ctl->chan = NULL;
+
+ if (rx_ctl->chan)
+ dma_release_channel(rx_ctl->chan);
+ rx_ctl->chan = NULL;
+
+ tasklet_kill(&rx_ctl->tasklet);
+
+ if (sg_dma_address(&tx_ctl->sg))
+ dma_unmap_single(adapter->dev, sg_dma_address(&tx_ctl->sg),
+ DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+ sg_dma_address(&tx_ctl->sg) = 0;
+
+ kfree(tx_ctl->buf);
+ tx_ctl->buf = NULL;
+}
+
+static bool ks8842_dma_filter_fn(struct dma_chan *chan, void *filter_param)
+{
+ return chan->chan_id == (int)filter_param;
+}
+
+static int ks8842_alloc_dma_bufs(struct net_device *netdev)
+{
+ struct ks8842_adapter *adapter = netdev_priv(netdev);
+ struct ks8842_tx_dma_ctl *tx_ctl = &adapter->dma_tx;
+ struct ks8842_rx_dma_ctl *rx_ctl = &adapter->dma_rx;
+ int err;
+
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+
+ sg_init_table(&tx_ctl->sg, 1);
+
+ tx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
+ (void *)tx_ctl->channel);
+ if (!tx_ctl->chan) {
+ err = -ENODEV;
+ goto err;
+ }
+
+ /* allocate DMA buffer */
+ tx_ctl->buf = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL);
+ if (!tx_ctl->buf) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ sg_dma_address(&tx_ctl->sg) = dma_map_single(adapter->dev,
+ tx_ctl->buf, DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+ err = dma_mapping_error(adapter->dev,
+ sg_dma_address(&tx_ctl->sg));
+ if (err) {
+ sg_dma_address(&tx_ctl->sg) = 0;
+ goto err;
+ }
+
+ rx_ctl->chan = dma_request_channel(mask, ks8842_dma_filter_fn,
+ (void *)rx_ctl->channel);
+ if (!rx_ctl->chan) {
+ err = -ENODEV;
+ goto err;
+ }
+
+ tasklet_init(&rx_ctl->tasklet, ks8842_rx_frame_dma_tasklet,
+ (unsigned long)netdev);
+
+ return 0;
+err:
+ ks8842_dealloc_dma_bufs(adapter);
+ return err;
+}
+#endif
/* Netdevice operations */
@@ -616,6 +1015,27 @@ static int ks8842_open(struct net_device *netdev)
netdev_dbg(netdev, "%s - entry\n", __func__);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter)) {
+ err = ks8842_alloc_dma_bufs(netdev);
+
+ if (!err) {
+ /* start RX dma */
+ err = __ks8842_start_new_rx_dma(netdev);
+ if (err)
+ ks8842_dealloc_dma_bufs(adapter);
+ }
+
+ if (err) {
+ printk(KERN_WARNING DRV_NAME
+ ": Failed to initiate DMA, running PIO\n");
+ ks8842_dealloc_dma_bufs(adapter);
+ adapter->dma_rx.channel = -1;
+ adapter->dma_tx.channel = -1;
+ }
+ }
+#endif
+
/* reset the HW */
ks8842_reset_hw(adapter);
@@ -641,6 +1061,11 @@ static int ks8842_close(struct net_device *netdev)
cancel_work_sync(&adapter->timeout_work);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter))
+ ks8842_dealloc_dma_bufs(adapter);
+#endif
+
/* free the irq */
free_irq(adapter->irq, netdev);
@@ -658,6 +1083,19 @@ static netdev_tx_t ks8842_xmit_frame(struct sk_buff *skb,
netdev_dbg(netdev, "%s: entry\n", __func__);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter)) {
+ unsigned long flags;
+ ret = ks8842_tx_frame_dma(skb, netdev);
+ /* for now only allow one transfer at the time */
+ spin_lock_irqsave(&adapter->lock, flags);
+ if (adapter->dma_tx.adesc)
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ return ret;
+ }
+#endif
+
ret = ks8842_tx_frame(skb, netdev);
if (ks8842_tx_fifo_space(adapter) < netdev->mtu + 8)
@@ -693,6 +1131,10 @@ static void ks8842_tx_timeout_work(struct work_struct *work)
netdev_dbg(netdev, "%s: entry\n", __func__);
spin_lock_irqsave(&adapter->lock, flags);
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter))
+ ks8842_stop_dma(adapter);
+#endif
/* disable interrupts */
ks8842_write16(adapter, 18, 0, REG_IER);
ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
@@ -706,6 +1148,11 @@ static void ks8842_tx_timeout_work(struct work_struct *work)
ks8842_write_mac_addr(adapter, netdev->dev_addr);
ks8842_update_link_status(netdev, adapter);
+
+#ifdef CONFIG_KS8842_TIMB_DMA
+ if (KS8842_USE_DMA(adapter))
+ __ks8842_start_new_rx_dma(netdev);
+#endif
}
static void ks8842_tx_timeout(struct net_device *netdev)
@@ -765,6 +1212,20 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
goto err_get_irq;
}
+#ifdef CONFIG_KS8842_TIMB_DMA
+ adapter->dev = (pdev->dev.parent) ? pdev->dev.parent : &pdev->dev;
+
+ /* DMA is only supported when accessed via timberdale */
+ if (!(adapter->conf_flags & MICREL_KS884X) && pdata &&
+ (pdata->tx_dma_channel != -1) &&
+ (pdata->rx_dma_channel != -1)) {
+ adapter->dma_rx.channel = pdata->rx_dma_channel;
+ adapter->dma_tx.channel = pdata->tx_dma_channel;
+ } else {
+ adapter->dma_rx.channel = -1;
+ adapter->dma_tx.channel = -1;
+ }
+#endif
tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev);
spin_lock_init(&adapter->lock);
diff --git a/include/linux/ks8842.h b/include/linux/ks8842.h
index da0341b..953b3fb 100644
--- a/include/linux/ks8842.h
+++ b/include/linux/ks8842.h
@@ -25,10 +25,14 @@
* struct ks8842_platform_data - Platform data of the KS8842 network driver
* @macaddr: The MAC address of the device, set to all 0:s to use the on in
* the chip.
+ * @rx_dma_channel: The DMA channel to use for RX, -1 for none.
+ * @tx_dma_channel: The DMA channel to use for RX, -1 for none.
*
*/
struct ks8842_platform_data {
u8 macaddr[ETH_ALEN];
+ int rx_dma_channel;
+ int tx_dma_channel;
};
#endif
^ permalink raw reply related
* Re: [PATCH] Driver-core: Fix bluetooth network device rename regression
From: Kay Sievers @ 2010-07-27 9:10 UTC (permalink / raw)
To: Greg KH
Cc: Eric W. Biederman, Greg KH, Johannes Berg, Andrew Morton,
Rafael J. Wysocki, Maciej W. Rozycki, netdev
In-Reply-To: <20100726180941.GB4883@kroah.com>
On Mon, Jul 26, 2010 at 20:09, Greg KH <greg@kroah.com> wrote:
>> Does this version of the change look less bleh worthy? The effect is
>> the same as my previous patch but the test is more abstract so the
>> effect is not strictly limited to /sys/class/net.
>
> What other class type has a namespace at this point in time?
> Essentially this is the same exact thing, just in a different format
> that obfuscates what you are really doing here.
The patch still looks broken, and does not belong into the core the
way it is done. We denied hacks like this for good reason. But
out-of-the-blue it was a bluetooth naming regression to fix in the
driver core? Interesting!
If someone is going to add namespaces to 'block' or 'input', the sysfs
layout will break, and userspace will be unable to handle the
resulting changes.
Kay
^ permalink raw reply
* Re: ixgbe->bonding->vlan->bridge->ebtables&iptables causes memory corruption
From: Eric Dumazet @ 2010-07-27 8:55 UTC (permalink / raw)
To: Gyorgy Jeney; +Cc: netdev, linux-kernel
In-Reply-To: <AANLkTimEYWiz4d-go6PszKnR0U29FYfjvHeLbPavi-RH@mail.gmail.com>
Le mardi 27 juillet 2010 à 09:15 +0200, Gyorgy Jeney a écrit :
> Hi,
>
> I have a rather interesting network setup here. First I have a dual
> 10Gbit ixgbe ethernet card, being bonded into one link, on which we
> run a number of vlans, which are bridged with various virtual
> machines. Now, to protect the box itself and the virtual machines I
> have a set of iptables and ebtables rules. Whenever one of the
> virtual machines start the kernel, which is 2.6.35-rc6, will reliably
> panic.
>
> This error needs both ebtables and iptables rules, without either one
> or the other, things seem to work quite well.
>
> The errors and backtraces are many and long, so I attached the full
> dmes output, please say if you need more.
Seems tricky :(
Could you send your {eb/ip}tables rules ?
^ permalink raw reply
* Re: [PATCH UPDATED 1/3] vhost: replace vhost_workqueue with per-vhost kthread
From: Tejun Heo @ 2010-07-27 8:21 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Oleg Nesterov, Sridhar Samudrala, netdev, lkml,
kvm@vger.kernel.org, Andrew Morton, Dmitri Vorobiev, Jiri Kosina,
Thomas Gleixner, Ingo Molnar, Andi Kleen
In-Reply-To: <20100726201907.GF27644@redhat.com>
Hello,
On 07/26/2010 10:19 PM, Michael S. Tsirkin wrote:
> Let's try to define what do we want to achieve then. Do you want
> code that flushes workers not to block when workers are frozen? How
> will we handle work submitted when worker is frozen?
As I wrote earlier, it's not necessarily about correctness but rather
avoiding unnecessary surprises and of course flushing can and should
stall if the queue is frozen but let's not separate execution of a
work and its completion with something which can take undeterminate
amount of time.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH UPDATED 1/3] vhost: replace vhost_workqueue with per-vhost kthread
From: Tejun Heo @ 2010-07-27 8:18 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Oleg Nesterov, Sridhar Samudrala, netdev, lkml,
kvm@vger.kernel.org, Andrew Morton, Dmitri Vorobiev, Jiri Kosina,
Thomas Gleixner, Ingo Molnar, Andi Kleen
In-Reply-To: <20100726195714.GD27644@redhat.com>
Hello,
On 07/26/2010 09:57 PM, Michael S. Tsirkin wrote:
>> For freeze, it probably is okay but for stop, I think it's better to
>> keep the semantics straight forward.
>
> What are the semantics then? What do we want stop followed
> by queue and flush to do?
One scenario I can think of is the following.
kthread_worker allows kthreads to be attached and stopped anytime, so
if the caller stops the current worker while flushing is pending and
attaches a new worker, the flushing which was pending will never
happen.
But, in general, it's nasty to allow execution and its completion to
be separated. Things like that are likely to bite us back in obscure
ways. I think it would be silly to have such oddity in generic code
when it can be avoided without too much trouble.
Thanks.
--
tejun
^ 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