Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] tcp: Generalized TTL Security Mechanism
From: Stephen Hemminger @ 2010-03-18 17:59 UTC (permalink / raw)
  To: Pekka Savola; +Cc: David Miller, netdev
In-Reply-To: <alpine.LRH.2.00.1003180833420.24946@netcore.fi>

On Thu, 18 Mar 2010 08:36:48 +0200 (EET)
Pekka Savola <pekkas@netcore.fi> wrote:

> Hi,
> 
> On Sun, 10 Jan 2010, Stephen Hemminger wrote:
> > This patch adds the kernel portions needed to implement
> > RFC 5082 Generalized TTL Security Mechanism (GTSM).
> > It is a lightweight security measure against forged
> > packets causing DoS attacks (for BGP).
> ...
> 
> It's nice to see this added.  However, I must add that a compliant RFC 
> 5082 implementation is required to have similar TTL treatment for ICMP 
> errors which relate to the protected session.  AFAIK this does not 
> support that.
> 
> The experimental, earlier spec (GTSH, RFC3682) did not have this 
> requirement.  Most if not all implementations support only GTSH mode. 
> So a backward-compatibility option may be desirable.

The ICMP receive error handling does need to be updated. 

But any application using GTSM should be setting IP_TTL socket option
to set send TTL. But, not sure if Linux TCP ever sends ICMP 
for existing sessions at all.

^ permalink raw reply

* Add PGM protocol support to the IP stack
From: Christoph Lameter @ 2010-03-18 17:58 UTC (permalink / raw)
  To: David Miller, netdev; +Cc: linux-kernel

Is there any work in progress on including PGM support (RFC 3208) in the
kernel?

I know about the openpgm implementation. Openpbm does this at the user
level and requires linking to a library. It is essentially a communication
protocol done in user space. It has privilege issues because it has to
create PGM packets via a raw socket. Which also has implications for the
possible performance. Openpgm seems to be able to interact with major
commercial implementations of PGM.

I am looking at openpgm right now and it seems that there are a number of
useful files and functions in there that could be used to implement PGM
support in the kernel.

There is also an existing socket API for handling PGM available in another
operating system whose name we rather avoid mentioning. That socket API
could be used as the basic. PGM use would then be possible without a
library and without privilege and performance issues.

PGM support would support two different modes of communication


1. Native PGM (allows NAK suppression by Cisco routers to be used)

	socket(AF_INET, SOCK_RDM, IPPROTO_RM)

(SOCK_RDM is defined in the kernel sources but not implemented. PGM
support would implement SOCK_RDM, IPPROTO_RM would need to be defined
according to the IANA protocol number for PGM).


2. PGM over UDP (which is used by many commercial product but not by the
unspeakable OS). No router support for NAK suppression is available. For
this I guess we would have to support

	socket(AF_INET, SOCK_RDM, IPPROTO_UDP)

I would be interested to find others who are interested in such a project
or maybe there is already a project in the works? If not then I will try
to come up with some code to get this going. Any help you could offer
would be appreciated.

^ permalink raw reply

* Re: [PATCH 08/12] netlink: Export genl_lock() API for use by modules
From: James Chapman @ 2010-03-18 17:46 UTC (permalink / raw)
  To: Stephen Hemminger, Thomas Graf; +Cc: netdev
In-Reply-To: <20100318090037.69bcd073@nehalam>

Stephen Hemminger wrote:
> On Thu, 18 Mar 2010 10:22:10 +0000
> James Chapman <jchapman@katalix.com> wrote:
> 
>> This lets kernel modules which use genl netlink APIs serialize netlink
>> processing.
>>
>> Signed-off-by: James Chapman <jchapman@katalix.com>
>> ---
>>  include/linux/genetlink.h |    8 ++++++++
>>  net/netlink/genetlink.c   |    6 ++++--
>>  2 files changed, 12 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h
>> index b834ef6..61549b2 100644
>> --- a/include/linux/genetlink.h
>> +++ b/include/linux/genetlink.h
>> @@ -80,4 +80,12 @@ enum {
>>  
>>  #define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
>>  
>> +#ifdef __KERNEL__
>> +
>> +/* All generic netlink requests are serialized by a global lock.  */
>> +extern void genl_lock(void);
>> +extern void genl_unlock(void);
>> +
>> +#endif /* __KERNEL__ */
>> +
>>  #endif	/* __LINUX_GENERIC_NETLINK_H */
>> diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
>> index a4b6e14..a28fda7 100644
>> --- a/net/netlink/genetlink.c
>> +++ b/net/netlink/genetlink.c
>> @@ -20,15 +20,17 @@
>>  
>>  static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
>>  
>> -static inline void genl_lock(void)
>> +void genl_lock(void)
>>  {
>>  	mutex_lock(&genl_mutex);
>>  }
>> +EXPORT_SYMBOL(genl_lock);
>>  
>> -static inline void genl_unlock(void)
>> +void genl_unlock(void)
>>  {
>>  	mutex_unlock(&genl_mutex);
>>  }
>> +EXPORT_SYMBOL(genl_unlock);
> 
> EXPORT_SYMBOL_GPL() for this?

I chose EXPORT_SYMBOL because other exported symbols in that module
aren't GPL-only. I don't mind which is used. Any preference, Thomas?


-- 
James Chapman
Katalix Systems Ltd
http://www.katalix.com
Catalysts for your Embedded Linux software development


^ permalink raw reply

* Re: [PATCH v2 4/7] drivers/net/wireless: Use STD_IW_HANDLER macro
From: Pavel Roskin @ 2010-03-18 17:25 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, Richard Kennedy, Johannes Berg, Corey Thomas,
	John W. Linville, Arnaldo Carvalho de Melo, linux-wireless,
	netdev
In-Reply-To: <b628c684e970196a7c4c0966ddd599a4c2ce293e.1268892664.git.joe@perches.com>

On Wed, 2010-03-17 at 23:21 -0700, Joe Perches wrote:
> Convert direct uses of [ (foo - SIOCIWFIRST) , fn)
> 
> Signed-off-by: Joe Perches <joe@perches.com>
...
>  static const iw_handler	wl3501_handler[] = {
> -	[SIOCGIWNAME	- SIOCIWFIRST] = wl3501_get_name,
...
> +	STD_IW_HANDLER(SIOCGIWNAME, wl3501_get_name),

You are introducing an unnecessary cast here.  That's bad.

-- 
Regards,
Pavel Roskin

^ permalink raw reply

* Re: [PATCH 1/3] netlink: fix NETLINK_RECV_NO_ENOBUFS in netlink_set_err()
From: Patrick McHardy @ 2010-03-18 17:22 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netdev, davem
In-Reply-To: <4BA25C82.7000301@netfilter.org>

Pablo Neira Ayuso wrote:
> Patrick McHardy wrote:
>>> Currently, no matter if NETLINK_RECV_NO_ENOBUFS is set or not: if we
>>> fail to allocate the netlink message, then ctnetlink_conntrack_event()
>>> returns 0. Thus, we report ENOBUFS to user-space and we lose the event.
>>>
>>> With my patches, if NETLINK_RECV_NO_ENOBUFS is set and we fail to
>>> allocate the message, we don't report ENOBUFS and we don't lose the event.
>> That last part is what keeps confusing me. With your patch, if the
>> ENOBUFS options is set, we don't report the error to userspace
>> and therefore don't return it to conntrack, thus we *do* loose the
>> event. Which is correct however.
> 
> Sorry, I'm being a bit imprecise myself: we do lose the event anyway.
> However, with my patch, if the NO_ENOBUFS option is set, we keep the
> event in the ctevent cache, so we can try to deliver it again with the
> next packet (this is what I initially meant with "we don't lose the
> event", yes, confusing...).

That still doesn't make sense. The NO_ENOBUFS option *surpresses*
errors, so conntrack assumes success and we *don't* keep it in the
cache. Look:

Patch 1:

> @@ -1104,8 +1104,12 @@ static inline int do_one_set_err(struct sock *sk,
>  	    !test_bit(p->group - 1, nlk->groups))
>  		goto out;
>  
> +	if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS)
> +		goto out;
> +
>  	sk->sk_err = p->code;
>  	sk->sk_error_report(sk);
> +	return 1;
>  out:
>  	return 0;
>  }

=> return 0 for NO_ENOBUFS option

Patch 2:

> +	if (nfnetlink_set_err(net, 0, group, -ENOBUFS) > 0)
> +		return -ENOBUFS;
> +
>  	return 0;
>  }

=> return 0 to conntrack. Therefore nf_conntrack_eventmask_report()
assumes success. So if the NO_ENOBUFS option is indeed used for
reliable delivery, this won't work.

Generally the logic seems inverted, you should return an error
to conntrack if userspace wasn't notified of the error.

^ permalink raw reply

* Re: [iproute2] iproute2 question
From: Stephen Hemminger @ 2010-03-18 15:59 UTC (permalink / raw)
  To: thomas yang; +Cc: hadi, netdev
In-Reply-To: <f4f837ab1003180202h6b2d5ed0ledd2a24dfd2627df@mail.gmail.com>

On Thu, 18 Mar 2010 17:02:16 +0800
thomas yang <lampsu@gmail.com> wrote:

> Hi,
> 
> Linux router R (has some interfaces)  use the table "main" as default
> routing table to route packets.  If  some link connected to R failed,
> I want to use another table "backup_tbl" to route packets; if the
> broken link repaired , go back to use table "main"  .  How to do this?

That's now it works. Use a real routing daemon.

-- 

^ permalink raw reply

* Re: [PATCH 08/12] netlink: Export genl_lock() API for use by modules
From: Stephen Hemminger @ 2010-03-18 16:00 UTC (permalink / raw)
  To: James Chapman; +Cc: netdev
In-Reply-To: <20100318102209.14576.61503.stgit@bert.katalix.com>

On Thu, 18 Mar 2010 10:22:10 +0000
James Chapman <jchapman@katalix.com> wrote:

> This lets kernel modules which use genl netlink APIs serialize netlink
> processing.
> 
> Signed-off-by: James Chapman <jchapman@katalix.com>
> ---
>  include/linux/genetlink.h |    8 ++++++++
>  net/netlink/genetlink.c   |    6 ++++--
>  2 files changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h
> index b834ef6..61549b2 100644
> --- a/include/linux/genetlink.h
> +++ b/include/linux/genetlink.h
> @@ -80,4 +80,12 @@ enum {
>  
>  #define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
>  
> +#ifdef __KERNEL__
> +
> +/* All generic netlink requests are serialized by a global lock.  */
> +extern void genl_lock(void);
> +extern void genl_unlock(void);
> +
> +#endif /* __KERNEL__ */
> +
>  #endif	/* __LINUX_GENERIC_NETLINK_H */
> diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
> index a4b6e14..a28fda7 100644
> --- a/net/netlink/genetlink.c
> +++ b/net/netlink/genetlink.c
> @@ -20,15 +20,17 @@
>  
>  static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
>  
> -static inline void genl_lock(void)
> +void genl_lock(void)
>  {
>  	mutex_lock(&genl_mutex);
>  }
> +EXPORT_SYMBOL(genl_lock);
>  
> -static inline void genl_unlock(void)
> +void genl_unlock(void)
>  {
>  	mutex_unlock(&genl_mutex);
>  }
> +EXPORT_SYMBOL(genl_unlock);

EXPORT_SYMBOL_GPL() for this?


-- 

^ permalink raw reply

* [PATCH 2/3] can: add support for Janz VMOD-ICAN3 Intelligent CAN module
From: Ira W. Snyder @ 2010-03-18 16:38 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, sameo, socketcan-core

The Janz VMOD-ICAN3 is a MODULbus daughterboard which fits onto any
MODULbus carrier board. It is an intelligent CAN controller with a
microcontroller and associated firmware.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
Cc: socketcan-core@lists.berlios.de
Cc: netdev@vger.kernel.org
---
 drivers/net/can/Kconfig      |   10 +
 drivers/net/can/Makefile     |    1 +
 drivers/net/can/janz-ican3.c | 1659 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1670 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/janz-ican3.c

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 05b7517..2c5227c 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -63,6 +63,16 @@ config CAN_BFIN
 	  To compile this driver as a module, choose M here: the
 	  module will be called bfin_can.
 
+config CAN_JANZ_ICAN3
+	tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
+	depends on CAN_DEV && MFD_JANZ_CMODIO
+	---help---
+	  Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
+	  connects to a MODULbus carrier board.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called janz-ican3.ko.
+
 source "drivers/net/can/mscan/Kconfig"
 
 source "drivers/net/can/sja1000/Kconfig"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 7a702f2..9047cd0 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -15,5 +15,6 @@ obj-$(CONFIG_CAN_AT91)		+= at91_can.o
 obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
 obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
+obj-$(CONFIG_CAN_JANZ_ICAN3)	+= janz-ican3.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
new file mode 100644
index 0000000..94d4995
--- /dev/null
+++ b/drivers/net/can/janz-ican3.c
@@ -0,0 +1,1659 @@
+/*
+ * Janz MODULbus VMOD-ICAN3 CAN Interface Driver
+ *
+ * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/netdevice.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include <linux/mfd/janz.h>
+
+/* the DPM has 64k of memory, organized into 256x 256 byte pages */
+#define DPM_NUM_PAGES		256
+#define DPM_PAGE_SIZE		256
+#define DPM_PAGE_ADDR(p)	((p) * DPM_PAGE_SIZE)
+
+/* JANZ ICAN3 "old-style" host interface queue page numbers */
+#define QUEUE_OLD_CONTROL	0
+#define QUEUE_OLD_RB0		1
+#define QUEUE_OLD_RB1		2
+#define QUEUE_OLD_WB0		3
+#define QUEUE_OLD_WB1		4
+
+/* Janz ICAN3 "old-style" host interface control registers */
+#define MSYNC_PEER		0x00		/* ICAN only */
+#define MSYNC_LOCL		0x01		/* host only */
+#define TARGET_RUNNING		0x02
+
+#define MSYNC_RB0		0x01
+#define MSYNC_RB1		0x02
+#define MSYNC_RBLW		0x04
+#define MSYNC_RB_MASK		(MSYNC_RB0 | MSYNC_RB1)
+
+#define MSYNC_WB0		0x10
+#define MSYNC_WB1		0x20
+#define MSYNC_WBLW		0x40
+#define MSYNC_WB_MASK		(MSYNC_WB0 | MSYNC_WB1)
+
+/* Janz ICAN3 "new-style" host interface queue page numbers */
+#define QUEUE_TOHOST		5
+#define QUEUE_FROMHOST_MID	6
+#define QUEUE_FROMHOST_HIGH	7
+#define QUEUE_FROMHOST_LOW	8
+
+/* The first free page in the DPM is #9 */
+#define DPM_FREE_START		9
+
+/* Janz ICAN3 "new-style" and "fast" host interface descriptor flags */
+#define DESC_VALID		0x80
+#define DESC_WRAP		0x40
+#define DESC_INTERRUPT		0x20
+#define DESC_IVALID		0x10
+#define DESC_LEN(len)		(len)
+
+/* Janz ICAN3 Firmware Messages */
+#define MSG_CONNECTI		0x02
+#define MSG_DISCONNECT		0x03
+#define MSG_IDVERS		0x04
+#define MSG_MSGLOST		0x05
+#define MSG_NEWHOSTIF		0x08
+#define MSG_SETAFILMASK		0x10
+#define MSG_INITFDPMQUEUE	0x11
+#define MSG_HWCONF		0x12
+#define MSG_FMSGLOST		0x15
+#define MSG_CEVTIND		0x37
+#define MSG_CBTRREQ		0x41
+#define MSG_COFFREQ		0x42
+#define MSG_CONREQ		0x43
+#define MSG_CCONFREQ		0x47
+
+/* Janz ICAN3 CAN Set Acceptance Filter Mask Message Types */
+#define SETAFILMASK_REJECT	0x00
+#define SETAFILMASK_FASTIF	0x02
+
+/* Janz ICAN3 CAN Hardware Configuration Message Types */
+#define HWCONF_TERMINATE_ON	0x01
+#define HWCONF_TERMINATE_OFF	0x00
+
+/* Janz ICAN3 CAN Event Indication Message Types */
+#define CEVTIND_EI		0x01
+#define CEVTIND_DOI		0x02
+#define CEVTIND_LOST		0x04
+#define CEVTIND_FULL		0x08
+#define CEVTIND_BEI		0x10
+
+#define CEVTIND_CHIP_SJA1000	0x02
+
+#define ICAN3_BUSERR_QUOTA_MAX	255
+
+/* Janz ICAN3 CAN Frame Conversion */
+#define ICAN3_ECHO	0x10
+#define ICAN3_EFF_RTR	0x40
+#define ICAN3_SFF_RTR	0x10
+#define ICAN3_EFF	0x80
+
+#define ICAN3_CAN_TYPE_MASK	0x0f
+#define ICAN3_CAN_TYPE_SFF	0x00
+#define ICAN3_CAN_TYPE_EFF	0x01
+
+#define ICAN3_CAN_DLC_MASK	0x0f
+
+/*
+ * SJA1000 Status and Error Register Definitions
+ *
+ * Copied from drivers/net/can/sja1000/sja1000.h
+ */
+
+/* status register content */
+#define SR_BS		0x80
+#define SR_ES		0x40
+#define SR_TS		0x20
+#define SR_RS		0x10
+#define SR_TCS		0x08
+#define SR_TBS		0x04
+#define SR_DOS		0x02
+#define SR_RBS		0x01
+
+#define SR_CRIT (SR_BS|SR_ES)
+
+/* ECC register */
+#define ECC_SEG		0x1F
+#define ECC_DIR		0x20
+#define ECC_ERR		6
+#define ECC_BIT		0x00
+#define ECC_FORM	0x40
+#define ECC_STUFF	0x80
+#define ECC_MASK	0xc0
+
+/* Number of buffers for use in the "new-style" host interface */
+#define ICAN3_NEW_BUFFERS	16
+
+/* Number of buffers for use in the "fast" host interface */
+#define ICAN3_TX_BUFFERS	512
+#define ICAN3_RX_BUFFERS	1024
+
+/* Driver Name */
+#define DRV_NAME "janz-ican3"
+
+/* DPM Control Registers -- starts at offset 0x100 in the MODULbus registers */
+struct ican3_dpm_control {
+	/* window address register */
+	u8 window_address;
+	u8 unused1;
+
+	/*
+	 * Read access: clear interrupt from microcontroller
+	 * Write access: send interrupt to microcontroller
+	 */
+	u8 interrupt;
+	u8 unused2;
+
+	/* write-only: reset all hardware on the module */
+	u8 hwreset;
+	u8 unused3;
+
+	/* write-only: generate an interrupt to the TPU */
+	u8 tpuinterrupt;
+};
+
+struct ican3_dev {
+
+	/* must be the first member */
+	struct can_priv can;
+
+	/* CAN network device */
+	struct net_device *ndev;
+	struct napi_struct napi;
+
+	/* Device for printing */
+	struct device *dev;
+
+	/* module number */
+	unsigned int num;
+
+	/* base address of registers and IRQ */
+	struct janz_cmodio_onboard_regs __iomem *ctrl;
+	struct ican3_dpm_control *dpmctrl;
+	void __iomem *dpm;
+	int irq;
+
+	/* old and new style host interface */
+	unsigned int iftype;
+	spinlock_t lock;
+
+	/* new host interface */
+	unsigned int rx_int;
+	unsigned int rx_num;
+	unsigned int tx_num;
+
+	/* fast host interface */
+	unsigned int fastrx_start;
+	unsigned int fastrx_int;
+	unsigned int fastrx_num;
+	unsigned int fasttx_start;
+	unsigned int fasttx_num;
+
+	/* first free DPM page */
+	unsigned int free_page;
+};
+
+struct ican3_msg {
+	u8 control;
+	u8 spec;
+	__le16 len;
+	u8 data[252];
+};
+
+struct ican3_new_desc {
+	u8 control;
+	u8 pointer;
+};
+
+struct ican3_fast_desc {
+	u8 control;
+	u8 command;
+	u8 data[14];
+};
+
+/* write to the window basic address register */
+static inline void ican3_set_page(struct ican3_dev *mod, unsigned int page)
+{
+	BUG_ON(page >= DPM_NUM_PAGES);
+	iowrite8(page, &mod->dpmctrl->window_address);
+}
+
+/*
+ * ICAN3 "old-style" host interface
+ */
+
+/*
+ * Recieve a message from the ICAN3 "old-style" firmware interface
+ *
+ * LOCKING: must hold mod->lock
+ *
+ * returns 0 on success, -ENOMEM when no message exists
+ */
+static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	unsigned int mbox, mbox_page;
+	u8 locl, peer, xord;
+
+	/* get the MSYNC registers */
+	ican3_set_page(mod, QUEUE_OLD_CONTROL);
+	peer = ioread8(mod->dpm + MSYNC_PEER);
+	locl = ioread8(mod->dpm + MSYNC_LOCL);
+	xord = locl ^ peer;
+
+	if ((xord & MSYNC_RB_MASK) == 0x00) {
+		dev_dbg(mod->dev, "no mbox for reading\n");
+		return -ENOMEM;
+	}
+
+	/* find the first free mbox to read */
+	if ((xord & MSYNC_RB_MASK) == MSYNC_RB_MASK)
+		mbox = (xord & MSYNC_RBLW) ? MSYNC_RB0 : MSYNC_RB1;
+	else
+		mbox = (xord & MSYNC_RB0) ? MSYNC_RB0 : MSYNC_RB1;
+
+	/* copy the message */
+	mbox_page = (mbox == MSYNC_RB0) ? QUEUE_OLD_RB0 : QUEUE_OLD_RB1;
+	ican3_set_page(mod, mbox_page);
+	memcpy_fromio(msg, mod->dpm, sizeof(*msg));
+
+	/*
+	 * notify the firmware that the read buffer is available
+	 * for it to fill again
+	 */
+	locl ^= mbox;
+
+	ican3_set_page(mod, QUEUE_OLD_CONTROL);
+	iowrite8(locl, mod->dpm + MSYNC_LOCL);
+	return 0;
+}
+
+/*
+ * Send a message through the "old-style" firmware interface
+ *
+ * LOCKING: must hold mod->lock
+ *
+ * returns 0 on success, -ENOMEM when no free space exists
+ */
+static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	unsigned int mbox, mbox_page;
+	u8 locl, peer, xord;
+
+	/* get the MSYNC registers */
+	ican3_set_page(mod, QUEUE_OLD_CONTROL);
+	peer = ioread8(mod->dpm + MSYNC_PEER);
+	locl = ioread8(mod->dpm + MSYNC_LOCL);
+	xord = locl ^ peer;
+
+	if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) {
+		dev_err(mod->dev, "no mbox for writing\n");
+		return -ENOMEM;
+	}
+
+	/* calculate a free mbox to use */
+	mbox = (xord & MSYNC_WB0) ? MSYNC_WB1 : MSYNC_WB0;
+
+	/* copy the message to the DPM */
+	mbox_page = (mbox == MSYNC_WB0) ? QUEUE_OLD_WB0 : QUEUE_OLD_WB1;
+	ican3_set_page(mod, mbox_page);
+	memcpy_toio(mod->dpm, msg, sizeof(*msg));
+
+	locl ^= mbox;
+	if (mbox == MSYNC_WB1)
+		locl |= MSYNC_WBLW;
+
+	ican3_set_page(mod, QUEUE_OLD_CONTROL);
+	iowrite8(locl, mod->dpm + MSYNC_LOCL);
+	return 0;
+}
+
+/*
+ * ICAN3 "new-style" Host Interface Setup
+ */
+
+static void __devinit ican3_init_new_host_interface(struct ican3_dev *mod)
+{
+	struct ican3_new_desc desc;
+	unsigned long flags;
+	void __iomem *dst;
+	int i;
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	/* setup the internal datastructures for RX */
+	mod->rx_num = 0;
+	mod->rx_int = 0;
+
+	/* tohost queue descriptors are in page 5 */
+	ican3_set_page(mod, QUEUE_TOHOST);
+	dst = mod->dpm;
+
+	/* initialize the tohost (rx) queue descriptors: pages 9-24 */
+	for (i = 0; i < ICAN3_NEW_BUFFERS; i++) {
+		desc.control = DESC_INTERRUPT | DESC_LEN(1); /* I L=1 */
+		desc.pointer = mod->free_page;
+
+		/* set wrap flag on last buffer */
+		if (i == ICAN3_NEW_BUFFERS - 1)
+			desc.control |= DESC_WRAP;
+
+		memcpy_toio(dst, &desc, sizeof(desc));
+		dst += sizeof(desc);
+		mod->free_page++;
+	}
+
+	/* fromhost (tx) mid queue descriptors are in page 6 */
+	ican3_set_page(mod, QUEUE_FROMHOST_MID);
+	dst = mod->dpm;
+
+	/* setup the internal datastructures for TX */
+	mod->tx_num = 0;
+
+	/* initialize the fromhost mid queue descriptors: pages 25-40 */
+	for (i = 0; i < ICAN3_NEW_BUFFERS; i++) {
+		desc.control = DESC_VALID | DESC_LEN(1); /* V L=1 */
+		desc.pointer = mod->free_page;
+
+		/* set wrap flag on last buffer */
+		if (i == ICAN3_NEW_BUFFERS - 1)
+			desc.control |= DESC_WRAP;
+
+		memcpy_toio(dst, &desc, sizeof(desc));
+		dst += sizeof(desc);
+		mod->free_page++;
+	}
+
+	/* fromhost hi queue descriptors are in page 7 */
+	ican3_set_page(mod, QUEUE_FROMHOST_HIGH);
+	dst = mod->dpm;
+
+	/* initialize only a single buffer in the fromhost hi queue (unused) */
+	desc.control = DESC_VALID | DESC_WRAP | DESC_LEN(1); /* VW L=1 */
+	desc.pointer = mod->free_page;
+	memcpy_toio(dst, &desc, sizeof(desc));
+	mod->free_page++;
+
+	/* fromhost low queue descriptors are in page 8 */
+	ican3_set_page(mod, QUEUE_FROMHOST_LOW);
+	dst = mod->dpm;
+
+	/* initialize only a single buffer in the fromhost low queue (unused) */
+	desc.control = DESC_VALID | DESC_WRAP | DESC_LEN(1); /* VW L=1 */
+	desc.pointer = mod->free_page;
+	memcpy_toio(dst, &desc, sizeof(desc));
+	mod->free_page++;
+
+	spin_unlock_irqrestore(&mod->lock, flags);
+}
+
+/*
+ * ICAN3 Fast Host Interface Setup
+ */
+
+static void __devinit ican3_init_fast_host_interface(struct ican3_dev *mod)
+{
+	struct ican3_fast_desc desc;
+	unsigned long flags;
+	unsigned int addr;
+	void __iomem *dst;
+	int i;
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	/* save the start recv page */
+	mod->fastrx_start = mod->free_page;
+	mod->fastrx_num = 0;
+	mod->fastrx_int = 0;
+
+	/* build a single fast tohost queue descriptor */
+	memset(&desc, 0, sizeof(desc));
+	desc.control = 0x00;
+	desc.command = 1;
+
+	/* build the tohost queue descriptor ring in memory */
+	addr = 0;
+	for (i = 0; i < ICAN3_RX_BUFFERS; i++) {
+
+		/* set the wrap bit on the last buffer */
+		if (i == ICAN3_RX_BUFFERS - 1)
+			desc.control |= DESC_WRAP;
+
+		/* switch to the correct page */
+		ican3_set_page(mod, mod->free_page);
+
+		/* copy the descriptor to the DPM */
+		dst = mod->dpm + addr;
+		memcpy_toio(dst, &desc, sizeof(desc));
+		addr += sizeof(desc);
+
+		/* move to the next page if necessary */
+		if (addr >= DPM_PAGE_SIZE) {
+			addr = 0;
+			mod->free_page++;
+		}
+	}
+
+	/* make sure we page-align the next queue */
+	if (addr != 0)
+		mod->free_page++;
+
+	/* save the start xmit page */
+	mod->fasttx_start = mod->free_page;
+	mod->fasttx_num = 0;
+
+	/* build a single fast fromhost queue descriptor */
+	memset(&desc, 0, sizeof(desc));
+	desc.control = DESC_VALID;
+	desc.command = 1;
+
+	/* build the fromhost queue descriptor ring in memory */
+	addr = 0;
+	for (i = 0; i < ICAN3_TX_BUFFERS; i++) {
+
+		/* set the wrap bit on the last buffer */
+		if (i == ICAN3_TX_BUFFERS - 1)
+			desc.control |= DESC_WRAP;
+
+		/* switch to the correct page */
+		ican3_set_page(mod, mod->free_page);
+
+		/* copy the descriptor to the DPM */
+		dst = mod->dpm + addr;
+		memcpy_toio(dst, &desc, sizeof(desc));
+		addr += sizeof(desc);
+
+		/* move to the next page if necessary */
+		if (addr >= DPM_PAGE_SIZE) {
+			addr = 0;
+			mod->free_page++;
+		}
+	}
+
+	spin_unlock_irqrestore(&mod->lock, flags);
+}
+
+/*
+ * ICAN3 "new-style" Host Interface Message Helpers
+ */
+
+/*
+ * LOCKING: must hold mod->lock
+ */
+static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	struct ican3_new_desc desc;
+	void __iomem *desc_addr = mod->dpm + (mod->tx_num * sizeof(desc));
+
+	/* switch to the fromhost mid queue, and read the buffer descriptor */
+	ican3_set_page(mod, QUEUE_FROMHOST_MID);
+	memcpy_fromio(&desc, desc_addr, sizeof(desc));
+
+	if (!(desc.control & DESC_VALID)) {
+		dev_dbg(mod->dev, "%s: no free buffers\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* switch to the data page, copy the data */
+	ican3_set_page(mod, desc.pointer);
+	memcpy_toio(mod->dpm, msg, sizeof(*msg));
+
+	/* switch back to the descriptor, set the valid bit, write it back */
+	ican3_set_page(mod, QUEUE_FROMHOST_MID);
+	desc.control ^= DESC_VALID;
+	memcpy_toio(desc_addr, &desc, sizeof(desc));
+
+	/* update the tx number */
+	mod->tx_num = (desc.control & DESC_WRAP) ? 0 : (mod->tx_num + 1);
+	return 0;
+}
+
+/*
+ * LOCKING: must hold mod->lock
+ */
+static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	struct ican3_new_desc desc;
+	void __iomem *desc_addr = mod->dpm + (mod->rx_num * sizeof(desc));
+
+	/* switch to the tohost queue, and read the buffer descriptor */
+	ican3_set_page(mod, QUEUE_TOHOST);
+	memcpy_fromio(&desc, desc_addr, sizeof(desc));
+
+	if (!(desc.control & DESC_VALID)) {
+		dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* switch to the data page, copy the data */
+	ican3_set_page(mod, desc.pointer);
+	memcpy_fromio(msg, mod->dpm, sizeof(*msg));
+
+	/* switch back to the descriptor, toggle the valid bit, write it back */
+	ican3_set_page(mod, QUEUE_TOHOST);
+	desc.control ^= DESC_VALID;
+	memcpy_toio(desc_addr, &desc, sizeof(desc));
+
+	/* update the rx number */
+	mod->rx_num = (desc.control & DESC_WRAP) ? 0 : (mod->rx_num + 1);
+	return 0;
+}
+
+/*
+ * Message Send / Recv Helpers
+ */
+
+static int ican3_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	if (mod->iftype == 0)
+		ret = ican3_old_send_msg(mod, msg);
+	else
+		ret = ican3_new_send_msg(mod, msg);
+
+	spin_unlock_irqrestore(&mod->lock, flags);
+	return ret;
+}
+
+static int ican3_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	if (mod->iftype == 0)
+		ret = ican3_old_recv_msg(mod, msg);
+	else
+		ret = ican3_new_recv_msg(mod, msg);
+
+	spin_unlock_irqrestore(&mod->lock, flags);
+	return ret;
+}
+
+/*
+ * Quick Pre-constructed Messages
+ */
+
+static int __devinit ican3_msg_connect(struct ican3_dev *mod)
+{
+	struct ican3_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_CONNECTI;
+	msg.len = cpu_to_le16(0);
+
+	return ican3_send_msg(mod, &msg);
+}
+
+static int __devexit ican3_msg_disconnect(struct ican3_dev *mod)
+{
+	struct ican3_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_DISCONNECT;
+	msg.len = cpu_to_le16(0);
+
+	return ican3_send_msg(mod, &msg);
+}
+
+static int __devinit ican3_msg_newhostif(struct ican3_dev *mod)
+{
+	struct ican3_msg msg;
+	int ret;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_NEWHOSTIF;
+	msg.len = cpu_to_le16(0);
+
+	/* If we're not using the old interface, switching seems bogus */
+	WARN_ON(mod->iftype != 0);
+
+	ret = ican3_send_msg(mod, &msg);
+	if (ret)
+		return ret;
+
+	/* mark the module as using the new host interface */
+	mod->iftype = 1;
+	return 0;
+}
+
+static int __devinit ican3_msg_fasthostif(struct ican3_dev *mod)
+{
+	struct ican3_msg msg;
+	unsigned int addr;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_INITFDPMQUEUE;
+	msg.len = cpu_to_le16(8);
+
+	/* write the tohost queue start address */
+	addr = DPM_PAGE_ADDR(mod->fastrx_start);
+	msg.data[0] = addr & 0xff;
+	msg.data[1] = (addr >> 8) & 0xff;
+	msg.data[2] = (addr >> 16) & 0xff;
+	msg.data[3] = (addr >> 24) & 0xff;
+
+	/* write the fromhost queue start address */
+	addr = DPM_PAGE_ADDR(mod->fasttx_start);
+	msg.data[4] = addr & 0xff;
+	msg.data[5] = (addr >> 8) & 0xff;
+	msg.data[6] = (addr >> 16) & 0xff;
+	msg.data[7] = (addr >> 24) & 0xff;
+
+	/* If we're not using the new interface yet, we cannot do this */
+	WARN_ON(mod->iftype != 1);
+
+	return ican3_send_msg(mod, &msg);
+}
+
+/*
+ * Setup the CAN filter to either accept or reject all
+ * messages from the CAN bus.
+ */
+static int __devinit ican3_set_id_filter(struct ican3_dev *mod, bool accept)
+{
+	struct ican3_msg msg;
+	int ret;
+
+	/* Standard Frame Format */
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_SETAFILMASK;
+	msg.len = cpu_to_le16(5);
+	msg.data[0] = 0x00; /* IDLo LSB */
+	msg.data[1] = 0x00; /* IDLo MSB */
+	msg.data[2] = 0xff; /* IDHi LSB */
+	msg.data[3] = 0x07; /* IDHi MSB */
+
+	/* accept all frames for fast host if, or reject all frames */
+	msg.data[4] = accept ? SETAFILMASK_FASTIF : SETAFILMASK_REJECT;
+
+	ret = ican3_send_msg(mod, &msg);
+	if (ret)
+		return ret;
+
+	/* Extended Frame Format */
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_SETAFILMASK;
+	msg.len = cpu_to_le16(13);
+	msg.data[0] = 0;    /* MUX = 0 */
+	msg.data[1] = 0x00; /* IDLo LSB */
+	msg.data[2] = 0x00;
+	msg.data[3] = 0x00;
+	msg.data[4] = 0x20; /* IDLo MSB */
+	msg.data[5] = 0xff; /* IDHi LSB */
+	msg.data[6] = 0xff;
+	msg.data[7] = 0xff;
+	msg.data[8] = 0x3f; /* IDHi MSB */
+
+	/* accept all frames for fast host if, or reject all frames */
+	msg.data[9] = accept ? SETAFILMASK_FASTIF : SETAFILMASK_REJECT;
+
+	return ican3_send_msg(mod, &msg);
+}
+
+/*
+ * Bring the CAN bus online or offline
+ */
+static int ican3_set_bus_state(struct ican3_dev *mod, bool on)
+{
+	struct ican3_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = on ? MSG_CONREQ : MSG_COFFREQ;
+	msg.len = cpu_to_le16(0);
+
+	return ican3_send_msg(mod, &msg);
+}
+
+static int __devinit ican3_set_termination(struct ican3_dev *mod, bool on)
+{
+	struct ican3_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_HWCONF;
+	msg.len = cpu_to_le16(2);
+	msg.data[0] = 0x00;
+	msg.data[1] = on ? HWCONF_TERMINATE_ON : HWCONF_TERMINATE_OFF;
+
+	return ican3_send_msg(mod, &msg);
+}
+
+static int __devinit ican3_set_buserror(struct ican3_dev *mod, u8 quota)
+{
+	struct ican3_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_CCONFREQ;
+	msg.len = cpu_to_le16(2);
+	msg.data[0] = 0x00;
+	msg.data[1] = quota;
+
+	return ican3_send_msg(mod, &msg);
+}
+
+/*
+ * ICAN3 to Linux CAN Frame Conversion
+ */
+
+static void ican3_to_can_frame(struct ican3_dev *mod,
+			       struct ican3_fast_desc *desc,
+			       struct can_frame *cf)
+{
+	if ((desc->command & ICAN3_CAN_TYPE_MASK) == ICAN3_CAN_TYPE_SFF) {
+		dev_dbg(mod->dev, "%s: old frame format\n", __func__);
+		if (desc->data[1] & ICAN3_SFF_RTR)
+			cf->can_id |= CAN_RTR_FLAG;
+
+		cf->can_id |= desc->data[0] << 3;
+		cf->can_id |= (desc->data[1] & 0xe0) >> 5;
+		cf->can_dlc = desc->data[1] & ICAN3_CAN_DLC_MASK;
+		memcpy(cf->data, &desc->data[2], sizeof(cf->data));
+	} else {
+		dev_dbg(mod->dev, "%s: new frame format\n", __func__);
+		cf->can_dlc = desc->data[0] & ICAN3_CAN_DLC_MASK;
+		if (desc->data[0] & ICAN3_EFF_RTR)
+			cf->can_id |= CAN_RTR_FLAG;
+
+		if (desc->data[0] & ICAN3_EFF) {
+			cf->can_id |= CAN_EFF_FLAG;
+			cf->can_id |= desc->data[2] << 21; /* 28-21 */
+			cf->can_id |= desc->data[3] << 13; /* 20-13 */
+			cf->can_id |= desc->data[4] << 5;  /* 12-5  */
+			cf->can_id |= (desc->data[5] & 0xf8) >> 3;
+		} else {
+			cf->can_id |= desc->data[2] << 3;  /* 10-3  */
+			cf->can_id |= desc->data[3] >> 5;  /* 2-0   */
+		}
+
+		memcpy(cf->data, &desc->data[6], sizeof(cf->data));
+	}
+}
+
+static void can_frame_to_ican3(struct ican3_dev *mod,
+			       struct can_frame *cf,
+			       struct ican3_fast_desc *desc)
+{
+	/* clear out any stale data in the descriptor */
+	memset(desc->data, 0, sizeof(desc->data));
+
+	/* we always use the extended format, with the ECHO flag set */
+	desc->command = ICAN3_CAN_TYPE_EFF;
+	desc->data[0] |= cf->can_dlc;
+	desc->data[1] |= ICAN3_ECHO;
+
+	if (cf->can_id & CAN_RTR_FLAG)
+		desc->data[0] |= ICAN3_EFF_RTR;
+
+	/* pack the id into the correct places */
+	if (cf->can_id & CAN_EFF_FLAG) {
+		dev_dbg(mod->dev, "%s: extended frame\n", __func__);
+		desc->data[0] |= ICAN3_EFF;
+		desc->data[2] = (cf->can_id & 0x1fe00000) >> 21; /* 28-21 */
+		desc->data[3] = (cf->can_id & 0x001fe000) >> 13; /* 20-13 */
+		desc->data[4] = (cf->can_id & 0x00001fe0) >> 5;  /* 12-5  */
+		desc->data[5] = (cf->can_id & 0x0000001f) << 3;  /* 4-0   */
+	} else {
+		dev_dbg(mod->dev, "%s: standard frame\n", __func__);
+		desc->data[2] = (cf->can_id & 0x7F8) >> 3; /* bits 10-3 */
+		desc->data[3] = (cf->can_id & 0x007) << 5; /* bits 2-0  */
+	}
+
+	/* copy the data bits into the descriptor */
+	memcpy(&desc->data[6], cf->data, sizeof(cf->data));
+}
+
+/*
+ * Interrupt Handling
+ */
+
+/*
+ * Handle an ID + Version message response from the firmware. We never generate
+ * this message in production code, but it is very useful when debugging to be
+ * able to display this message.
+ */
+static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data);
+}
+
+static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	struct net_device *dev = mod->ndev;
+	struct net_device_stats *stats = &dev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+
+	/*
+	 * Report that communication messages with the microcontroller firmware
+	 * are being lost. These are never CAN frames, so we do not generate an
+	 * error frame for userspace
+	 */
+	if (msg->spec == MSG_MSGLOST) {
+		dev_err(mod->dev, "lost %d control messages\n", msg->data[0]);
+		return;
+	}
+
+	/*
+	 * Oops, this indicates that we have lost messages in the fast queue,
+	 * which are exclusively CAN messages. Our driver isn't reading CAN
+	 * frames fast enough.
+	 *
+	 * We'll pretend that the SJA1000 told us that it ran out of buffer
+	 * space, because there is not a better message for this.
+	 */
+	skb = alloc_can_err_skb(dev, &cf);
+	if (skb) {
+		cf->can_id |= CAN_ERR_CRTL;
+		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+		stats->rx_errors++;
+		stats->rx_bytes += cf->can_dlc;
+		netif_rx(skb);
+	}
+}
+
+/*
+ * Handle CAN Event Indication Messages from the firmware
+ *
+ * The ICAN3 firmware provides the values of some SJA1000 registers when it
+ * generates this message. The code below is largely copied from the
+ * drivers/net/can/sja1000/sja1000.c file, and adapted as necessary
+ */
+static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	struct net_device *dev = mod->ndev;
+	struct net_device_stats *stats = &dev->stats;
+	enum can_state state = mod->can.state;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	u8 status, isrc;
+
+	/* we can only handle the SJA1000 part */
+	if (msg->data[1] != CEVTIND_CHIP_SJA1000) {
+		dev_err(mod->dev, "unable to handle errors on non-SJA1000\n");
+		return -ENODEV;
+	}
+
+	/* check the message length for sanity */
+	if (msg->len < 6) {
+		dev_err(mod->dev, "error message too short\n");
+		return -EINVAL;
+	}
+
+	skb = alloc_can_err_skb(dev, &cf);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	isrc = msg->data[0];
+	status = msg->data[3];
+
+	/* data overrun interrupt */
+	if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) {
+		cf->can_id |= CAN_ERR_CRTL;
+		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+		stats->rx_over_errors++;
+		stats->rx_errors++;
+		dev_info(mod->dev, "%s: overflow frame generated\n", __func__);
+	}
+
+	/* error warning interrupt */
+	if (isrc == CEVTIND_EI) {
+		if (status & SR_BS) {
+			state = CAN_STATE_BUS_OFF;
+			cf->can_id |= CAN_ERR_BUSOFF;
+			can_bus_off(dev);
+		} else if (status & SR_ES) {
+			state = CAN_STATE_ERROR_WARNING;
+		} else {
+			state = CAN_STATE_ERROR_ACTIVE;
+		}
+	}
+
+	/* bus error interrupt */
+	if (isrc == CEVTIND_BEI) {
+		u8 ecc = msg->data[2];
+		mod->can.can_stats.bus_error++;
+		stats->rx_errors++;
+		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+		switch (ecc & ECC_MASK) {
+		case ECC_BIT:
+			cf->data[2] |= CAN_ERR_PROT_BIT;
+			break;
+		case ECC_FORM:
+			cf->data[2] |= CAN_ERR_PROT_FORM;
+			break;
+		case ECC_STUFF:
+			cf->data[2] |= CAN_ERR_PROT_STUFF;
+			break;
+		default:
+			cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+			cf->data[3] = ecc & ECC_SEG;
+			break;
+		}
+
+		if ((ecc & ECC_DIR) == 0)
+			cf->data[2] |= CAN_ERR_PROT_TX;
+	}
+
+	if (state != mod->can.state && (state == CAN_STATE_ERROR_WARNING ||
+					state == CAN_STATE_ERROR_PASSIVE)) {
+		u8 rxerr = msg->data[4];
+		u8 txerr = msg->data[5];
+		cf->can_id |= CAN_ERR_CRTL;
+		if (state == CAN_STATE_ERROR_WARNING) {
+			mod->can.can_stats.error_warning++;
+			cf->data[1] = (txerr > rxerr) ?
+				CAN_ERR_CRTL_TX_WARNING :
+				CAN_ERR_CRTL_RX_WARNING;
+		} else {
+			mod->can.can_stats.error_passive++;
+			cf->data[1] = (txerr > rxerr) ?
+				CAN_ERR_CRTL_TX_PASSIVE :
+				CAN_ERR_CRTL_RX_PASSIVE;
+		}
+	}
+
+	mod->can.state = state;
+	stats->rx_errors++;
+	stats->rx_bytes += cf->can_dlc;
+	netif_rx(skb);
+	return 0;
+}
+
+static void ican3_handle_unknown_message(struct ican3_dev *mod,
+					struct ican3_msg *msg)
+{
+	dev_warn(mod->dev, "recieved unknown message: spec 0x%.2x length %d\n",
+			   msg->spec, le16_to_cpu(msg->len));
+}
+
+/*
+ * Handle a control message from the firmware
+ */
+static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
+{
+	dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
+			   mod->num, msg->spec, le16_to_cpu(msg->len));
+
+	switch (msg->spec) {
+	case MSG_IDVERS:
+		ican3_handle_idvers(mod, msg);
+		break;
+	case MSG_MSGLOST:
+	case MSG_FMSGLOST:
+		ican3_handle_msglost(mod, msg);
+		break;
+	case MSG_CEVTIND:
+		ican3_handle_cevtind(mod, msg);
+		break;
+	default:
+		ican3_handle_unknown_message(mod, msg);
+		break;
+	}
+}
+
+/*
+ * Check that there is room in the TX ring to transmit another skb
+ *
+ * LOCKING: must hold mod->lock
+ */
+static bool ican3_txok(struct ican3_dev *mod)
+{
+	struct ican3_fast_desc __iomem *desc;
+	u8 control;
+
+	/* copy the control bits of the descriptor */
+	ican3_set_page(mod, mod->fasttx_start + (mod->fasttx_num / 16));
+	desc = mod->dpm + ((mod->fasttx_num % 16) * sizeof(*desc));
+	control = ioread8(&desc->control);
+
+	/* if the control bits are not valid, then we have no more space */
+	if (!(control & DESC_VALID))
+		return false;
+
+	return true;
+}
+
+/*
+ * Recieve one CAN frame from the hardware
+ *
+ * This works like the core of a NAPI function, but is intended to be called
+ * from workqueue context instead. This driver already needs a workqueue to
+ * process control messages, so we use the workqueue instead of using NAPI.
+ * This was done to simplify locking.
+ *
+ * CONTEXT: must be called from user context
+ */
+static int ican3_recv_skb(struct ican3_dev *mod)
+{
+	struct net_device *ndev = mod->ndev;
+	struct net_device_stats *stats = &ndev->stats;
+	struct ican3_fast_desc desc;
+	void __iomem *desc_addr;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	/* copy the whole descriptor */
+	ican3_set_page(mod, mod->fastrx_start + (mod->fastrx_num / 16));
+	desc_addr = mod->dpm + ((mod->fastrx_num % 16) * sizeof(desc));
+	memcpy_fromio(&desc, desc_addr, sizeof(desc));
+
+	spin_unlock_irqrestore(&mod->lock, flags);
+
+	/* check that we actually have a CAN frame */
+	if (!(desc.control & DESC_VALID))
+		return -ENOBUFS;
+
+	/* allocate an skb */
+	skb = alloc_can_skb(ndev, &cf);
+	if (unlikely(skb == NULL)) {
+		stats->rx_dropped++;
+		goto err_noalloc;
+	}
+
+	/* convert the ICAN3 frame into Linux CAN format */
+	ican3_to_can_frame(mod, &desc, cf);
+
+	/* receive the skb, update statistics */
+	netif_receive_skb(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+
+err_noalloc:
+	/* toggle the valid bit and return the descriptor to the ring */
+	desc.control ^= DESC_VALID;
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	ican3_set_page(mod, mod->fastrx_start + (mod->fastrx_num / 16));
+	memcpy_toio(desc_addr, &desc, 1);
+
+	/* update the next buffer pointer */
+	mod->fastrx_num = (desc.control & DESC_WRAP) ? 0
+						     : (mod->fastrx_num + 1);
+
+	/* there are still more buffers to process */
+	spin_unlock_irqrestore(&mod->lock, flags);
+	return 0;
+}
+
+static int ican3_napi(struct napi_struct *napi, int budget)
+{
+	struct ican3_dev *mod = container_of(napi, struct ican3_dev, napi);
+	struct ican3_msg msg;
+	unsigned long flags;
+	int received = 0;
+	int ret;
+
+	/* process all communication messages */
+	while (true) {
+		ret = ican3_recv_msg(mod, &msg);
+		if (ret)
+			break;
+
+		ican3_handle_message(mod, &msg);
+	}
+
+	/* process all CAN frames from the fast interface */
+	while (received < budget) {
+		ret = ican3_recv_skb(mod);
+		if (ret)
+			break;
+
+		received++;
+	}
+
+	/* We have processed all packets that the adapter had, but it
+	 * was less than our budget, stop polling */
+	if (received < budget)
+		napi_complete(napi);
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	/* Wake up the transmit queue if necessary */
+	if (netif_queue_stopped(mod->ndev) && ican3_txok(mod))
+		netif_wake_queue(mod->ndev);
+
+	spin_unlock_irqrestore(&mod->lock, flags);
+
+	/* re-enable interrupt generation */
+	iowrite8(1 << mod->num, &mod->ctrl->int_enable);
+	return received;
+}
+
+static irqreturn_t ican3_irq(int irq, void *dev_id)
+{
+	struct ican3_dev *mod = dev_id;
+	u8 stat;
+
+	/*
+	 * The interrupt status register on this device reports interrupts
+	 * as zeroes instead of using ones like most other devices
+	 */
+	stat = ioread8(&mod->ctrl->int_disable) & (1 << mod->num);
+	if (stat == (1 << mod->num))
+		return IRQ_NONE;
+
+	dev_dbg(mod->dev, "IRQ: module %d\n", mod->num);
+
+	/* clear the MODULbus interrupt from the microcontroller */
+	ioread8(&mod->dpmctrl->interrupt);
+
+	/* disable interrupt generation, schedule the NAPI poller */
+	iowrite8(1 << mod->num, &mod->ctrl->int_disable);
+	napi_schedule(&mod->napi);
+	return IRQ_HANDLED;
+}
+
+/*
+ * Firmware reset, startup, and shutdown
+ */
+
+/*
+ * Reset an ICAN module to its power-on state
+ *
+ * CONTEXT: no network device registered
+ * LOCKING: work function disabled
+ */
+static int ican3_reset_module(struct ican3_dev *mod)
+{
+	u8 val = 1 << mod->num;
+	unsigned long start;
+	u8 runold, runnew;
+
+	/* disable interrupts so no more work is scheduled */
+	iowrite8(1 << mod->num, &mod->ctrl->int_disable);
+
+	/* flush any pending work */
+	flush_scheduled_work();
+
+	/* the first unallocated page in the DPM is #9 */
+	mod->free_page = DPM_FREE_START;
+
+	ican3_set_page(mod, QUEUE_OLD_CONTROL);
+	runold = ioread8(mod->dpm + TARGET_RUNNING);
+
+	/* reset the module */
+	iowrite8(val, &mod->ctrl->reset_assert);
+	iowrite8(val, &mod->ctrl->reset_deassert);
+
+	/* wait until the module has finished resetting and is running */
+	start = jiffies;
+	do {
+		ican3_set_page(mod, QUEUE_OLD_CONTROL);
+		runnew = ioread8(mod->dpm + TARGET_RUNNING);
+		if (runnew == (runold ^ 0xff))
+			return 0;
+
+		msleep(10);
+	} while (time_before(jiffies, start + HZ / 4));
+
+	dev_err(mod->dev, "failed to reset CAN module\n");
+	return -ETIMEDOUT;
+}
+
+static void __devexit ican3_shutdown_module(struct ican3_dev *mod)
+{
+	ican3_msg_disconnect(mod);
+	ican3_reset_module(mod);
+}
+
+/*
+ * Startup an ICAN module, bringing it into fast mode
+ */
+static int __devinit ican3_startup_module(struct ican3_dev *mod)
+{
+	int ret;
+
+	ret = ican3_reset_module(mod);
+	if (ret) {
+		dev_err(mod->dev, "unable to reset module\n");
+		return ret;
+	}
+
+	/* re-enable interrupts so we can send messages */
+	iowrite8(1 << mod->num, &mod->ctrl->int_enable);
+
+	ret = ican3_msg_connect(mod);
+	if (ret) {
+		dev_err(mod->dev, "unable to connect to module\n");
+		return ret;
+	}
+
+	ican3_init_new_host_interface(mod);
+	ret = ican3_msg_newhostif(mod);
+	if (ret) {
+		dev_err(mod->dev, "unable to switch to new-style interface\n");
+		return ret;
+	}
+
+	ret = ican3_set_termination(mod, true);
+	if (ret) {
+		dev_err(mod->dev, "unable to enable termination\n");
+		return ret;
+	}
+
+	ret = ican3_set_buserror(mod, ICAN3_BUSERR_QUOTA_MAX);
+	if (ret) {
+		dev_err(mod->dev, "unable to set bus-error\n");
+		return ret;
+	}
+
+	ican3_init_fast_host_interface(mod);
+	ret = ican3_msg_fasthostif(mod);
+	if (ret) {
+		dev_err(mod->dev, "unable to switch to fast host interface\n");
+		return ret;
+	}
+
+	ret = ican3_set_id_filter(mod, true);
+	if (ret) {
+		dev_err(mod->dev, "unable to set acceptance filter\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * CAN Network Device
+ */
+
+static int ican3_open(struct net_device *ndev)
+{
+	struct ican3_dev *mod = netdev_priv(ndev);
+	int ret;
+
+	/* open the CAN layer */
+	ret = open_candev(ndev);
+	if (ret) {
+		dev_err(mod->dev, "unable to start CAN layer\n");
+		return ret;
+	}
+
+	/* bring the bus online */
+	ret = ican3_set_bus_state(mod, true);
+	if (ret) {
+		dev_err(mod->dev, "unable to set bus-on\n");
+		close_candev(ndev);
+		return ret;
+	}
+
+	/* start up the network device */
+	mod->can.state = CAN_STATE_ERROR_ACTIVE;
+	netif_start_queue(ndev);
+
+	return 0;
+}
+
+static int ican3_stop(struct net_device *ndev)
+{
+	struct ican3_dev *mod = netdev_priv(ndev);
+	int ret;
+
+	/* stop the network device xmit routine */
+	netif_stop_queue(ndev);
+	mod->can.state = CAN_STATE_STOPPED;
+
+	/* bring the bus offline, stop receiving packets */
+	ret = ican3_set_bus_state(mod, false);
+	if (ret) {
+		dev_err(mod->dev, "unable to set bus-off\n");
+		return ret;
+	}
+
+	/* close the CAN layer */
+	close_candev(ndev);
+	return 0;
+}
+
+static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct ican3_dev *mod = netdev_priv(ndev);
+	struct net_device_stats *stats = &ndev->stats;
+	struct can_frame *cf = (struct can_frame *)skb->data;
+	struct ican3_fast_desc desc;
+	void __iomem *desc_addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mod->lock, flags);
+
+	/* check that we can actually transmit */
+	if (!ican3_txok(mod)) {
+		dev_err(mod->dev, "no free descriptors, stopping queue\n");
+		netif_stop_queue(ndev);
+		spin_unlock_irqrestore(&mod->lock, flags);
+		return NETDEV_TX_BUSY;
+	}
+
+	/* copy the control bits of the descriptor */
+	ican3_set_page(mod, mod->fasttx_start + (mod->fasttx_num / 16));
+	desc_addr = mod->dpm + ((mod->fasttx_num % 16) * sizeof(desc));
+	memset(&desc, 0, sizeof(desc));
+	memcpy_fromio(&desc, desc_addr, 1);
+
+	/* convert the Linux CAN frame into ICAN3 format */
+	can_frame_to_ican3(mod, cf, &desc);
+
+	/*
+	 * the programming manual says that you must set the IVALID bit, then
+	 * interrupt, then set the valid bit. Quite weird, but it seems to be
+	 * required for this to work
+	 */
+	desc.control |= DESC_IVALID;
+	memcpy_toio(desc_addr, &desc, sizeof(desc));
+
+	/* generate a MODULbus interrupt to the microcontroller */
+	iowrite8(0x01, &mod->dpmctrl->interrupt);
+
+	desc.control ^= DESC_VALID;
+	memcpy_toio(desc_addr, &desc, sizeof(desc));
+
+	/* update the next buffer pointer */
+	mod->fasttx_num = (desc.control & DESC_WRAP) ? 0
+						     : (mod->fasttx_num + 1);
+
+	/* update statistics */
+	stats->tx_packets++;
+	stats->tx_bytes += cf->can_dlc;
+	kfree_skb(skb);
+
+	/*
+	 * This hardware doesn't have TX-done notifications, so we'll try and
+	 * emulate it the best we can using ECHO skbs. Get the next TX
+	 * descriptor, and see if we have room to send. If not, stop the queue.
+	 * It will be woken when the ECHO skb for the current packet is recv'd.
+	 */
+
+	/* copy the control bits of the descriptor */
+	if (!ican3_txok(mod))
+		netif_stop_queue(ndev);
+
+	spin_unlock_irqrestore(&mod->lock, flags);
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops ican3_netdev_ops = {
+	.ndo_open	= ican3_open,
+	.ndo_stop	= ican3_stop,
+	.ndo_start_xmit	= ican3_xmit,
+};
+
+/*
+ * Low-level CAN Device
+ */
+
+/* This structure was stolen from drivers/net/can/sja1000/sja1000.c */
+static struct can_bittiming_const ican3_bittiming_const = {
+	.name = DRV_NAME,
+	.tseg1_min = 1,
+	.tseg1_max = 16,
+	.tseg2_min = 1,
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 64,
+	.brp_inc = 1,
+};
+
+/*
+ * This routine was stolen from drivers/net/can/sja1000/sja1000.c
+ *
+ * The bittiming register command for the ICAN3 just sets the bit timing
+ * registers on the SJA1000 chip directly
+ */
+static int ican3_set_bittiming(struct net_device *ndev)
+{
+	struct ican3_dev *mod = netdev_priv(ndev);
+	struct can_bittiming *bt = &mod->can.bittiming;
+	struct ican3_msg msg;
+	u8 btr0, btr1;
+
+	btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
+	btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
+		(((bt->phase_seg2 - 1) & 0x7) << 4);
+	if (mod->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+		btr1 |= 0x80;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.spec = MSG_CBTRREQ;
+	msg.len = cpu_to_le16(4);
+	msg.data[0] = 0x00;
+	msg.data[1] = 0x00;
+	msg.data[2] = btr0;
+	msg.data[3] = btr1;
+
+	return ican3_send_msg(mod, &msg);
+}
+
+static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+	struct ican3_dev *mod = netdev_priv(ndev);
+	int ret;
+
+	if (mode != CAN_MODE_START)
+		return -ENOTSUPP;
+
+	/* bring the bus online */
+	ret = ican3_set_bus_state(mod, true);
+	if (ret) {
+		dev_err(mod->dev, "unable to set bus-on\n");
+		return ret;
+	}
+
+	/* start up the network device */
+	mod->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	if (netif_queue_stopped(ndev))
+		netif_wake_queue(ndev);
+
+	return 0;
+}
+
+/*
+ * PCI Subsystem
+ */
+
+static int __devinit ican3_probe(struct platform_device *pdev)
+{
+	struct janz_platform_data *pdata;
+	struct net_device *ndev;
+	struct ican3_dev *mod;
+	struct resource *res;
+	struct device *dev;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -ENXIO;
+
+	dev_dbg(&pdev->dev, "probe: module number %d\n", pdata->modno);
+
+	/* save the struct device for printing */
+	dev = &pdev->dev;
+
+	/* allocate the CAN device and private data */
+	ndev = alloc_candev(sizeof(*mod), 0);
+	if (!ndev) {
+		dev_err(dev, "unable to allocate CANdev\n");
+		ret = -ENOMEM;
+		goto out_return;
+	}
+
+	platform_set_drvdata(pdev, ndev);
+	mod = netdev_priv(ndev);
+	mod->ndev = ndev;
+	mod->dev = &pdev->dev;
+	mod->num = pdata->modno;
+	netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS);
+	spin_lock_init(&mod->lock);
+
+	/* the first unallocated page in the DPM is 9 */
+	mod->free_page = DPM_FREE_START;
+
+	ndev->netdev_ops = &ican3_netdev_ops;
+	ndev->flags |= IFF_ECHO;
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	mod->can.clock.freq = 8000000;
+	mod->can.bittiming_const = &ican3_bittiming_const;
+	mod->can.do_set_bittiming = ican3_set_bittiming;
+	mod->can.do_set_mode = ican3_set_mode;
+
+	/* find our IRQ number */
+	mod->irq = platform_get_irq(pdev, 0);
+	if (mod->irq < 0) {
+		dev_err(dev, "IRQ line not found\n");
+		ret = -ENODEV;
+		goto out_free_ndev;
+	}
+
+	ndev->irq = mod->irq;
+
+	/* get access to the MODULbus registers for this module */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "MODULbus registers not found\n");
+		ret = -ENODEV;
+		goto out_free_ndev;
+	}
+
+	mod->dpm = ioremap(res->start, resource_size(res));
+	if (!mod->dpm) {
+		dev_err(dev, "MODULbus registers not ioremap\n");
+		ret = -ENOMEM;
+		goto out_free_ndev;
+	}
+
+	mod->dpmctrl = mod->dpm + DPM_PAGE_SIZE;
+
+	/* get access to the control registers for this module */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(dev, "CONTROL registers not found\n");
+		ret = -ENODEV;
+		goto out_iounmap_dpm;
+	}
+
+	mod->ctrl = ioremap(res->start, resource_size(res));
+	if (!mod->ctrl) {
+		dev_err(dev, "CONTROL registers not ioremap\n");
+		ret = -ENOMEM;
+		goto out_iounmap_dpm;
+	}
+
+	/* disable our IRQ, then hookup the IRQ handler */
+	iowrite8(1 << mod->num, &mod->ctrl->int_disable);
+	ret = request_irq(mod->irq, ican3_irq, IRQF_SHARED, DRV_NAME, mod);
+	if (ret) {
+		dev_err(dev, "unable to request IRQ\n");
+		goto out_iounmap_ctrl;
+	}
+
+	/* reset and initialize the CAN controller into fast mode */
+	napi_enable(&mod->napi);
+	ret = ican3_startup_module(mod);
+	if (ret) {
+		dev_err(dev, "%s: unable to start CANdev\n", __func__);
+		goto out_free_irq;
+	}
+
+	/* register with the Linux CAN layer */
+	ret = register_candev(ndev);
+	if (ret) {
+		dev_err(dev, "%s: unable to register CANdev\n", __func__);
+		goto out_free_irq;
+	}
+
+	dev_info(dev, "module %d: registered CAN device\n", pdata->modno);
+	return 0;
+
+out_free_irq:
+	napi_disable(&mod->napi);
+	iowrite8(1 << mod->num, &mod->ctrl->int_disable);
+	free_irq(mod->irq, mod);
+out_iounmap_ctrl:
+	iounmap(mod->ctrl);
+out_iounmap_dpm:
+	iounmap(mod->dpm);
+out_free_ndev:
+	free_candev(ndev);
+out_return:
+	return ret;
+}
+
+static int __devexit ican3_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+	struct ican3_dev *mod = netdev_priv(ndev);
+
+	/* unregister the netdevice, stop interrupts */
+	unregister_netdev(ndev);
+	napi_disable(&mod->napi);
+	iowrite8(1 << mod->num, &mod->ctrl->int_disable);
+	free_irq(mod->irq, mod);
+
+	/* put the module into reset */
+	ican3_shutdown_module(mod);
+
+	/* unmap all registers */
+	iounmap(mod->ctrl);
+	iounmap(mod->dpm);
+
+	free_candev(ndev);
+
+	return 0;
+}
+
+static struct platform_driver ican3_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ican3_probe,
+	.remove		= __devexit_p(ican3_remove),
+};
+
+static int __init ican3_init(void)
+{
+	return platform_driver_register(&ican3_driver);
+}
+
+static void __exit ican3_exit(void)
+{
+	platform_driver_unregister(&ican3_driver);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("Janz MODULbus VMOD-ICAN3 Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:janz-ican3");
+
+module_init(ican3_init);
+module_exit(ican3_exit);
-- 
1.5.4.3


^ permalink raw reply related

* Re: [PATCH 1/3] netlink: fix NETLINK_RECV_NO_ENOBUFS in netlink_set_err()
From: Patrick McHardy @ 2010-03-18 16:46 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netdev, davem
In-Reply-To: <4BA25612.3080804@netfilter.org>

Pablo Neira Ayuso wrote:
> Patrick McHardy wrote:
>> Pablo Neira Ayuso wrote:
>>> Yes, allocation is a different situation but we still report ENOBUFS to
>>> user-space. I think that NETLINK_RECV_NO_ENOBUFS is there to a) disable
>>> ENOBUFS reports to user-space and b) disable Netlink congestion.
>>>
>>>> Is there any problem with these errors?
>>> Specifically in ctnetlink, if we fail to allocate a message in ctnetlink
>>> and NETLINK_RECV_NO_ENOBUFS is set, we still lose an event and that
>>> should not happen.
>> I assume you mean "not set"? Otherwise I fail to follow :)
> 
> OK, I'll try again :-)
> 
> Currently, no matter if NETLINK_RECV_NO_ENOBUFS is set or not: if we
> fail to allocate the netlink message, then ctnetlink_conntrack_event()
> returns 0. Thus, we report ENOBUFS to user-space and we lose the event.
> 
> With my patches, if NETLINK_RECV_NO_ENOBUFS is set and we fail to
> allocate the message, we don't report ENOBUFS and we don't lose the event.

That last part is what keeps confusing me. With your patch, if the
ENOBUFS options is set, we don't report the error to userspace
and therefore don't return it to conntrack, thus we *do* loose the
event. Which is correct however.

Did I get it right this time? :)

^ permalink raw reply

* [PATCH 3/3] gpio: add support for Janz VMOD-TTL Digital IO module
From: Ira W. Snyder @ 2010-03-18 16:38 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, sameo, socketcan-core

The Janz VMOD-TTL is a MODULbus daughterboard which fits onto any MODULbus
carrier board. It essentially consists of some various logic and a Zilog
Z8536 CIO Counter/Timer and Parallel IO Unit.

The board must be physically configured with jumpers to enable a user to
drive output signals. I am only interested in outputs, so I have made this
driver as simple as possible. It only supports a very minimal amount of the
features provided by the Z8536 chip.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/gpio/Kconfig    |   10 ++
 drivers/gpio/Makefile   |    1 +
 drivers/gpio/janz-ttl.c |  257 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 268 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/janz-ttl.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 1f1d88a..0da364d 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -255,4 +255,14 @@ config GPIO_UCB1400
 	  To compile this driver as a module, choose M here: the
 	  module will be called ucb1400_gpio.
 
+comment "MODULbus GPIO expanders:"
+
+config GPIO_JANZ_TTL
+	tristate "Janz VMOD-TTL Digital IO Module"
+	depends on MFD_JANZ_CMODIO
+	help
+	  This enables support for the Janz VMOD-TTL Digital IO module.
+	  This driver provides support for driving the pins in output
+	  mode only. Input mode is not supported.
+
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4868723..2263966 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_GPIO_CS5535)	+= cs5535-gpio.o
 obj-$(CONFIG_GPIO_BT8XX)	+= bt8xxgpio.o
 obj-$(CONFIG_GPIO_VR41XX)	+= vr41xx_giu.o
 obj-$(CONFIG_GPIO_WM831X)	+= wm831x-gpio.o
+obj-$(CONFIG_GPIO_JANZ_TTL)	+= janz-ttl.o
diff --git a/drivers/gpio/janz-ttl.c b/drivers/gpio/janz-ttl.c
new file mode 100644
index 0000000..d97eeda
--- /dev/null
+++ b/drivers/gpio/janz-ttl.c
@@ -0,0 +1,257 @@
+/*
+ * Janz MODULbus VMOD-TTL GPIO Driver
+ *
+ * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <linux/mfd/janz.h>
+
+#define DRV_NAME "janz-ttl"
+
+#define PORTA_DIRECTION		0x23
+#define PORTB_DIRECTION		0x2B
+#define PORTC_DIRECTION		0x06
+#define PORTA_IOCTL		0x24
+#define PORTB_IOCTL		0x2C
+#define PORTC_IOCTL		0x07
+
+#define MASTER_INT_CTL		0x00
+#define MASTER_CONF_CTL		0x01
+
+#define CONF_PAE		(1 << 2)
+#define CONF_PBE		(1 << 7)
+#define CONF_PCE		(1 << 4)
+
+struct ttl_control_regs {
+	__be16 portc;
+	__be16 portb;
+	__be16 porta;
+	__be16 control;
+};
+
+struct ttl_module {
+	struct gpio_chip gpio;
+
+	/* base address of registers */
+	struct ttl_control_regs __iomem *regs;
+
+	u8 portc_shadow;
+	u8 portb_shadow;
+	u8 porta_shadow;
+
+	spinlock_t lock;
+};
+
+static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
+{
+	struct ttl_module *mod = dev_get_drvdata(gpio->dev);
+	u8 *shadow;
+	int ret;
+
+	if (offset < 8) {
+		shadow = &mod->porta_shadow;
+	} else if (offset < 16) {
+		shadow = &mod->portb_shadow;
+		offset -= 8;
+	} else {
+		shadow = &mod->portc_shadow;
+		offset -= 16;
+	}
+
+	spin_lock(&mod->lock);
+	ret = *shadow & (1 << offset);
+	spin_unlock(&mod->lock);
+	return ret;
+}
+
+static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
+{
+	struct ttl_module *mod = dev_get_drvdata(gpio->dev);
+	void __iomem *port;
+	u8 *shadow;
+
+	if (offset < 8) {
+		port = &mod->regs->porta;
+		shadow = &mod->porta_shadow;
+	} else if (offset < 16) {
+		port = &mod->regs->portb;
+		shadow = &mod->portb_shadow;
+		offset -= 8;
+	} else {
+		port = &mod->regs->portc;
+		shadow = &mod->portc_shadow;
+		offset -= 16;
+	}
+
+	spin_lock(&mod->lock);
+	if (value)
+		*shadow |= (1 << offset);
+	else
+		*shadow &= ~(1 << offset);
+
+	iowrite16be(*shadow, port);
+	spin_unlock(&mod->lock);
+}
+
+static void __devinit ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val)
+{
+	iowrite16be(reg, &mod->regs->control);
+	iowrite16be(val, &mod->regs->control);
+}
+
+static void __devinit ttl_setup_device(struct ttl_module *mod)
+{
+	/* reset the device to a known state */
+	iowrite16be(0x0000, &mod->regs->control);
+	iowrite16be(0x0001, &mod->regs->control);
+	iowrite16be(0x0000, &mod->regs->control);
+
+	/* put all ports in open-drain mode */
+	ttl_write_reg(mod, PORTA_IOCTL, 0x00ff);
+	ttl_write_reg(mod, PORTB_IOCTL, 0x00ff);
+	ttl_write_reg(mod, PORTC_IOCTL, 0x000f);
+
+	/* set all ports as outputs */
+	ttl_write_reg(mod, PORTA_DIRECTION, 0x0000);
+	ttl_write_reg(mod, PORTB_DIRECTION, 0x0000);
+	ttl_write_reg(mod, PORTC_DIRECTION, 0x0000);
+
+	/* set all ports to drive zeroes */
+	iowrite16be(0x0000, &mod->regs->porta);
+	iowrite16be(0x0000, &mod->regs->portb);
+	iowrite16be(0x0000, &mod->regs->portc);
+
+	/* enable all ports */
+	ttl_write_reg(mod, MASTER_CONF_CTL, CONF_PAE | CONF_PBE | CONF_PCE);
+}
+
+static int __devinit ttl_probe(struct platform_device *pdev)
+{
+	struct janz_platform_data *pdata;
+	struct device *dev = &pdev->dev;
+	struct ttl_module *mod;
+	struct gpio_chip *gpio;
+	struct resource *res;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(dev, "no platform data\n");
+		ret = -ENXIO;
+		goto out_return;
+	}
+
+	mod = kzalloc(sizeof(*mod), GFP_KERNEL);
+	if (!mod) {
+		dev_err(dev, "unable to allocate private data\n");
+		ret = -ENOMEM;
+		goto out_return;
+	}
+
+	platform_set_drvdata(pdev, mod);
+	spin_lock_init(&mod->lock);
+
+	/* get access to the MODULbus registers for this module */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "MODULbus registers not found\n");
+		ret = -ENODEV;
+		goto out_free_mod;
+	}
+
+	mod->regs = ioremap(res->start, resource_size(res));
+	if (!mod->regs) {
+		dev_err(dev, "MODULbus registers not ioremap\n");
+		ret = -ENOMEM;
+		goto out_free_mod;
+	}
+
+	ttl_setup_device(mod);
+
+	/* Initialize the GPIO data structures */
+	gpio = &mod->gpio;
+	gpio->dev = &pdev->dev;
+	gpio->label = pdev->name;
+	gpio->get = ttl_get_value;
+	gpio->set = ttl_set_value;
+	gpio->owner = THIS_MODULE;
+
+	/* request dynamic allocation */
+	gpio->base = -1;
+	gpio->ngpio = 20;
+
+	ret = gpiochip_add(gpio);
+	if (ret) {
+		dev_err(dev, "unable to add GPIO chip\n");
+		goto out_iounmap_regs;
+	}
+
+	dev_info(&pdev->dev, "module %d: registered GPIO device\n",
+			     pdata->modno);
+	return 0;
+
+out_iounmap_regs:
+	iounmap(mod->regs);
+out_free_mod:
+	kfree(mod);
+out_return:
+	return ret;
+}
+
+static int __devexit ttl_remove(struct platform_device *pdev)
+{
+	struct ttl_module *mod = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	ret = gpiochip_remove(&mod->gpio);
+	if (ret) {
+		dev_err(dev, "unable to remove GPIO chip\n");
+		return ret;
+	}
+
+	iounmap(mod->regs);
+	kfree(mod);
+	return 0;
+}
+
+static struct platform_driver ttl_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ttl_probe,
+	.remove		= __devexit_p(ttl_remove),
+};
+
+static int __init ttl_init(void)
+{
+	return platform_driver_register(&ttl_driver);
+}
+
+static void __exit ttl_exit(void)
+{
+	platform_driver_unregister(&ttl_driver);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("Janz MODULbus VMOD-TTL Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:janz-ttl");
+
+module_init(ttl_init);
+module_exit(ttl_exit);
-- 
1.5.4.3

^ permalink raw reply related

* [PATCH 1/3] mfd: add support for Janz CMOD-IO PCI MODULbus Carrier Board
From: Ira W. Snyder @ 2010-03-18 16:38 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, sameo, socketcan-core

The Janz CMOD-IO PCI MODULbus carrier board is a PCI to MODULbus bridge,
which may host many different types of MODULbus daughterboards, including
CAN and GPIO controllers.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/mfd/Kconfig       |    8 +
 drivers/mfd/Makefile      |    1 +
 drivers/mfd/janz-cmodio.c |  339 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/janz.h  |   54 +++++++
 4 files changed, 402 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mfd/janz-cmodio.c
 create mode 100644 include/linux/mfd/janz.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 8782978..f1858d7 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -27,6 +27,14 @@ config MFD_SM501_GPIO
 	 lines on the SM501. The platform data is used to supply the
 	 base number for the first GPIO line to register.
 
+config MFD_JANZ_CMODIO
+	tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board"
+	---help---
+	  This is the core driver for the Janz CMOD-IO PCI MODULbus
+	  carrier board. This device is a PCI to MODULbus bridge which may
+	  host many different types of MODULbus daughterboards, including
+	  CAN and GPIO controllers.
+
 config MFD_ASIC3
 	bool "Support for Compaq ASIC3"
 	depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e09eb48..e8fa905 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_MFD_SM501)		+= sm501.o
+obj-$(CONFIG_MFD_JANZ_CMODIO)	+= janz-cmodio.o
 obj-$(CONFIG_MFD_ASIC3)		+= asic3.o tmio_core.o
 obj-$(CONFIG_MFD_SH_MOBILE_SDHI)		+= sh_mobile_sdhi.o
 
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c
new file mode 100644
index 0000000..914280e
--- /dev/null
+++ b/drivers/mfd/janz-cmodio.c
@@ -0,0 +1,339 @@
+/*
+ * Janz CMOD-IO MODULbus Carrier Board PCI Driver
+ *
+ * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Lots of inspiration and code was copied from drivers/mfd/sm501.c
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/janz.h>
+
+#define DRV_NAME "janz-cmodio"
+
+/* Size of each MODULbus module in PCI BAR4 */
+#define CMODIO_MODULBUS_SIZE	0x200
+
+/* Maximum number of MODULbus modules on a CMOD-IO carrier board */
+#define CMODIO_MAX_MODULES	4
+
+/* Module Parameters */
+static unsigned int num_modules = CMODIO_MAX_MODULES;
+static unsigned char *modules[CMODIO_MAX_MODULES] = {
+	"janz-ican3",
+	"janz-ican3",
+	"",
+	"janz-ttl",
+};
+
+module_param_array(modules, charp, &num_modules, S_IRUGO);
+MODULE_PARM_DESC(modules, "MODULbus modules attached to the carrier board");
+
+struct cmodio_device {
+	/* Parent PCI device */
+	struct pci_dev *pdev;
+
+	/* PLX control registers */
+	struct janz_cmodio_onboard_regs __iomem *ctrl;
+
+	/* hex switch position */
+	u8 hex;
+
+	/* Subdevice ID numbers */
+	unsigned int subdev_id;
+};
+
+/*
+ * Subdevice Support
+ */
+
+static int cmodio_remove_subdev(struct device *dev, void *data)
+{
+	platform_device_unregister(to_platform_device(dev));
+	return 0;
+}
+
+static void cmodio_subdev_release(struct device *dev)
+{
+	kfree(to_platform_device(dev));
+}
+
+static struct platform_device *cmodio_create_subdev(struct cmodio_device *priv,
+						    char *name,
+						    unsigned int res_count,
+						    unsigned int pdata_size)
+{
+	struct platform_device *pdev;
+	size_t res_size;
+
+	res_size = sizeof(struct resource) * res_count;
+	pdev = kzalloc(sizeof(*pdev) + res_size + pdata_size, GFP_KERNEL);
+	if (!pdev)
+		return NULL;
+
+	pdev->dev.release = cmodio_subdev_release;
+	pdev->dev.parent = &priv->pdev->dev;
+	pdev->name = name;
+
+	if (res_count) {
+		pdev->resource = (struct resource *)(pdev + 1);
+		pdev->num_resources = res_count;
+	}
+
+	if (pdata_size)
+		pdev->dev.platform_data = (void *)(pdev + 1) + res_size;
+
+	return pdev;
+}
+
+/* Create a memory resource for a subdevice */
+static void cmodio_create_mem(struct resource *parent, struct resource *res,
+			      resource_size_t offset, resource_size_t size)
+{
+	res->flags = IORESOURCE_MEM;
+	res->parent = parent;
+	res->start = parent->start + offset;
+	res->end = parent->start + offset + size - 1;
+}
+
+/* Create an IRQ resource for a subdevice */
+static void cmodio_create_irq(struct resource *res, unsigned int irq)
+{
+	res->flags = IORESOURCE_IRQ;
+	res->parent = NULL;
+	res->start = irq;
+	res->end = irq;
+}
+
+static int __devinit cmodio_probe_subdevice(struct cmodio_device *priv,
+					    char *name, unsigned int modno)
+{
+	struct janz_platform_data *pdata;
+	struct platform_device *pdev;
+	resource_size_t offset, size;
+	struct pci_dev *pci;
+	int ret;
+
+	pci = priv->pdev;
+	pdev = cmodio_create_subdev(priv, name, 3, sizeof(*pdata));
+	if (!pdev) {
+		dev_err(&pci->dev, "MODULbus slot %d alloc failed\n", modno);
+		ret = -ENOMEM;
+		goto out_return;
+	}
+
+	pdata = pdev->dev.platform_data;
+	pdata->modno = modno;
+	pdev->id = priv->subdev_id++;
+
+	/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
+	offset = CMODIO_MODULBUS_SIZE * modno;
+	size = CMODIO_MODULBUS_SIZE;
+	cmodio_create_mem(&pci->resource[3], &pdev->resource[0], offset, size);
+
+	/* PLX Control Registers -- PCI BAR4 is interrupt and other registers */
+	offset = 0;
+	size = resource_size(&pci->resource[4]);
+	cmodio_create_mem(&pci->resource[4], &pdev->resource[1], offset, size);
+
+	/* IRQ */
+	cmodio_create_irq(&pdev->resource[2], pci->irq);
+
+	/* Register the device */
+	ret = platform_device_register(pdev);
+	if (ret) {
+		dev_err(&pci->dev, "MODULbus slot %d register failed\n", modno);
+		goto out_free;
+	}
+
+	return 0;
+
+out_free:
+	cmodio_subdev_release(&pdev->dev);
+out_return:
+	return ret;
+}
+
+/* Probe each submodule using kernel parameters */
+static int __devinit cmodio_probe_submodules(struct cmodio_device *priv)
+{
+	char *name;
+	int i;
+
+	for (i = 0; i < num_modules; i++) {
+		name = modules[i];
+		if (!strcmp(name, ""))
+			continue;
+
+		dev_dbg(&priv->pdev->dev, "MODULbus %d: name %s\n", i, name);
+		cmodio_probe_subdevice(priv, name, i);
+	}
+
+	return 0;
+}
+
+/*
+ * SYSFS Attributes
+ */
+
+static ssize_t mbus_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct cmodio_device *priv = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", priv->hex);
+}
+
+static DEVICE_ATTR(modulbus_number, S_IRUGO, mbus_show, NULL);
+
+static struct attribute *cmodio_sysfs_attrs[] = {
+	&dev_attr_modulbus_number.attr,
+	NULL,
+};
+
+static const struct attribute_group cmodio_sysfs_attr_group = {
+	.attrs = cmodio_sysfs_attrs,
+};
+
+/*
+ * PCI Driver
+ */
+
+static int __devinit cmodio_pci_probe(struct pci_dev *dev,
+				      const struct pci_device_id *id)
+{
+	struct cmodio_device *priv;
+	int ret;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&dev->dev, "unable to allocate private data\n");
+		ret = -ENOMEM;
+		goto out_return;
+	}
+
+	pci_set_drvdata(dev, priv);
+	priv->pdev = dev;
+
+	/* Hardware Initialization */
+	ret = pci_enable_device(dev);
+	if (ret) {
+		dev_err(&dev->dev, "unable to enable device\n");
+		goto out_free_priv;
+	}
+
+	pci_set_master(dev);
+	ret = pci_request_regions(dev, DRV_NAME);
+	if (ret) {
+		dev_err(&dev->dev, "unable to request regions\n");
+		goto out_pci_disable_device;
+	}
+
+	/* Onboard configuration registers */
+	priv->ctrl = pci_ioremap_bar(dev, 4);
+	if (!priv->ctrl) {
+		dev_err(&dev->dev, "unable to remap onboard regs\n");
+		ret = -ENOMEM;
+		goto out_pci_release_regions;
+	}
+
+	/* Read the hex switch on the carrier board */
+	priv->hex = ioread8(&priv->ctrl->int_enable);
+
+	/* Add the MODULbus number (hex switch value) to the device's sysfs */
+	ret = sysfs_create_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
+	if (ret) {
+		dev_err(&dev->dev, "unable to create sysfs attributes\n");
+		goto out_unmap_ctrl;
+	}
+
+	/*
+	 * Disable all interrupt lines, each submodule will enable its
+	 * own interrupt line if needed
+	 */
+	iowrite8(0xf, &priv->ctrl->int_disable);
+
+	/* Register drivers for all submodules */
+	ret = cmodio_probe_submodules(priv);
+	if (ret) {
+		dev_err(&dev->dev, "unable to probe submodules\n");
+		goto out_sysfs_remove_group;
+	}
+
+	return 0;
+
+out_sysfs_remove_group:
+	sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
+out_unmap_ctrl:
+	iounmap(priv->ctrl);
+out_pci_release_regions:
+	pci_release_regions(dev);
+out_pci_disable_device:
+	pci_disable_device(dev);
+out_free_priv:
+	kfree(priv);
+out_return:
+	return ret;
+}
+
+static void __devexit cmodio_pci_remove(struct pci_dev *dev)
+{
+	struct cmodio_device *priv = pci_get_drvdata(dev);
+
+	device_for_each_child(&dev->dev, NULL, cmodio_remove_subdev);
+	sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
+	iounmap(priv->ctrl);
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	kfree(priv);
+}
+
+#define PCI_VENDOR_ID_JANZ		0x13c3
+
+/* The list of devices that this module will support */
+static DEFINE_PCI_DEVICE_TABLE(cmodio_pci_ids) = {
+	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0101 },
+	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0100 },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);
+
+static struct pci_driver cmodio_pci_driver = {
+	.name     = DRV_NAME,
+	.id_table = cmodio_pci_ids,
+	.probe    = cmodio_pci_probe,
+	.remove   = __devexit_p(cmodio_pci_remove),
+};
+
+/*
+ * Module Init / Exit
+ */
+
+static int __init cmodio_init(void)
+{
+	return pci_register_driver(&cmodio_pci_driver);
+}
+
+static void __exit cmodio_exit(void)
+{
+	pci_unregister_driver(&cmodio_pci_driver);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("Janz CMOD-IO PCI MODULbus Carrier Board Driver");
+MODULE_LICENSE("GPL");
+
+module_init(cmodio_init);
+module_exit(cmodio_exit);
diff --git a/include/linux/mfd/janz.h b/include/linux/mfd/janz.h
new file mode 100644
index 0000000..e9994c4
--- /dev/null
+++ b/include/linux/mfd/janz.h
@@ -0,0 +1,54 @@
+/*
+ * Common Definitions for Janz MODULbus devices
+ *
+ * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef JANZ_H
+#define JANZ_H
+
+struct janz_platform_data {
+	/* MODULbus Module Number */
+	unsigned int modno;
+};
+
+/* PLX bridge chip onboard registers */
+struct janz_cmodio_onboard_regs {
+	u8 unused1;
+
+	/*
+	 * Read access: interrupt status
+	 * Write access: interrupt disable
+	 */
+	u8 int_disable;
+	u8 unused2;
+
+	/*
+	 * Read access: MODULbus number (hex switch)
+	 * Write access: interrupt enable
+	 */
+	u8 int_enable;
+	u8 unused3;
+
+	/* write-only */
+	u8 reset_assert;
+	u8 unused4;
+
+	/* write-only */
+	u8 reset_deassert;
+	u8 unused5;
+
+	/* read-write access to serial EEPROM */
+	u8 eep;
+	u8 unused6;
+
+	/* write-only access to EEPROM chip select */
+	u8 enid;
+};
+
+#endif /* JANZ_H */
-- 
1.5.4.3

^ permalink raw reply related

* [PATCH 0/3] add support for Janz MODULbus devices
From: Ira W. Snyder @ 2010-03-18 16:38 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA, sameo-VuQAYsv1563Yd54FQh9/CA

This patch series adds support for the Janz CMOD-IO carrier board, as well
as the Janz VMOD-ICAN3 Intelligent CAN controller and the Janz VMOD-TTL
Digital IO controller. The CMOD-IO carrier board is a PCI to MODULbus
bridge, into which plug MODULbus daughterboards.  I only have access to two
types of daughtercards, the VMOD-ICAN3 and VMOD-TTL boards mentioned above.

The CAN driver has been tested under high loads. I am able to generate ~60%
bus utilization. With two VMOD-ICAN3 boards looped back to each other,
neither one loses any packets when only a single board is generating
packets at maximum speed. Once both boards start generating packets, one
board will sometimes loose arbitration, and cause some lost packets.

RFCv3 -> RFCv4:
- addressed many review comments
- switch to NAPI
- add TX flow control
- mark functions with __devinit and __devexit
- add sysfs readout of MODULbus number (hex switch)
- implement GPIO driver for VMOD-TTL

RFCv2 -> RFCv3:
- addressed many review comments
- correct CAN bus error handling
- use struct device to track subdevices
- use structures for register layout
- add lots of #defines for register values
- use better function prefixes

RFCv1 -> RFCv2:
- converted to a multi-driver model
- addressed many review comments
- added CAN bus error handling
- use a work function only instead of work + NAPI
- use SJA1000 bittiming calculation code

I apologize if I've CC'd too many people here, but I'm unsure if people
would rather see the whole patch series, or just each part.

I appreciate any review you can offer.

Thanks,
Ira

^ permalink raw reply

* Re: [PATCH v2 0/7] wireless: Use macros from wireless.h
From: Johannes Berg @ 2010-03-18 16:21 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, Richard Kennedy, Geoff Levand, Zhu Yi,
	Reinette Chatre, Intel Linux Wireless, John W. Linville,
	Pavel Roskin, David Gibson, Corey Thomas,
	Arnaldo Carvalho de Melo, David S. Miller, linuxppc-dev,
	cbe-oss-dev, netdev, linux-wireless, orinoco-users, orinoco-devel
In-Reply-To: <cover.1268892663.git.joe@perches.com>

On Wed, 2010-03-17 at 23:21 -0700, Joe Perches wrote:
> Move the STD_IW_HANDLER macro from orinoco to wireless.h
> Use the wireless.h macros in various wireless files
> Remove local #defines of IW_IOCTL

I really don't want to debug any breakage here, but otherwise I don't
care and this is fine with me.

johannes

^ permalink raw reply

* Re: [PATCH 12/12] l2tp: Update documentation
From: Randy Dunlap @ 2010-03-18 15:52 UTC (permalink / raw)
  To: James Chapman; +Cc: netdev
In-Reply-To: <20100318102230.14576.20800.stgit@bert.katalix.com>

On 03/18/10 03:22, James Chapman wrote:
> This patch adds documentation about the L2TPv3 functionality.
> 
> Signed-off-by: James Chapman <jchapman@katalix.com>
> ---
>  Documentation/networking/l2tp.txt |  233 ++++++++++++++++++++++++++++++++-----
>  1 files changed, 199 insertions(+), 34 deletions(-)

Nice job.

Reviewed-by: Randy Dunlap <randy.dunlap@oracle.com>

thanks,
-- 
~Randy

^ permalink raw reply

* Re: Help: the 82577 network driver can't work
From: Allan, Bruce W @ 2010-03-18 15:39 UTC (permalink / raw)
  To: yucheng.wang@windriver.com, netdev@vger.kernel.org
  Cc: Shuo.Kang@windriver.com, Shuo.Liu@windriver.com,
	e1000-devel@lists.sourceforge.net, Bo.Liu@windriver.com,
	Bruce.Ashfield@windriver.com, rongkai.zhan@windriver.com,
	Yang.Shi@windriver.com
In-Reply-To: <4BA1BCC9.1080401@windriver.com>

On Wednesday, March 17, 2010 10:40 PM, yucheng.wang wrote:
> Hi all,
> 
> I need some help for intel 82577 network card driver, named
> CONFIG_E1000E in the kernel config.
> 
> In the kernel 2.6.31 and 2.6.32, the patch works well, but in the
> kernel 
> 2.6.33 and 2.6.34-rc1 the dmesg shows some problem below,and the
> network card can't work.
> **********************************************************************
> e1000e: Intel(R) PRO/1000 Network Driver - 1.0.2-k2
> e1000e: Copyright (c) 1999 - 2009 Intel Corporation.
> e1000e 0000:00:19.0: PCI INT A -> GSI 20 (level, low) -> IRQ 20
> 0000:00:19.0: 0000:00:19.0: Write-protect NVM Disabled
> 0000:00:19.0: 0000:00:19.0: Failed to initialize MSI interrupts.
> Falling back to legacy interrupts.
> ata4: SATA link down (SStatus 0 SControl 300)
> ata3: SATA link down (SStatus 0 SControl 300)
> ata2.00: SATA link down (SStatus 0 SControl 300)
> ata2.01: SATA link down (SStatus 0 SControl 300)
> ata1.00: SATA link down (SStatus 0 SControl 0)
> ata1.01: SATA link down (SStatus 0 SControl 300)
> e1000e 0000:00:19.0: PCI INT A disabled
> e1000e: probe of 0000:00:19.0 failed with error -3
> ********************************************************************
> I read the source code using 2.6.34-rc-1 kernel.
> When calling e1000e_git_phy_id(), the function returns a wrong value
> "-3". The kernel 2.6.31 and 2.6.32 ignores this error, and the kernel
> run well. The function e1000_acquire_swflag_ich8lan( ), called by
> e1000e_get_phy_id(), return "-3".
>   ************************** The code
>        ********************************* extcnf_ctrl |=
>        E1000_EXTCNF_CTRL_SWFLAG; ew32(EXTCNF_CTRL, extcnf_ctrl);
> 
>        while (timeout) {
>            extcnf_ctrl = er32(EXTCNF_CTRL);
>            if (extcnf_ctrl&  E1000_EXTCNF_CTRL_SWFLAG)
>                break;
> 
>            mdelay(1);
>            timeout--;
>        }
> 
>        if (!timeout) {
>            e_dbg("Failed to acquire the semaphore.\n");
>            extcnf_ctrl&= ~E1000_EXTCNF_CTRL_SWFLAG;
>            ew32(EXTCNF_CTRL, extcnf_ctrl);
>            ret_val = -E1000_ERR_CONFIG;
>            goto out;
>        }
>   ************************** The code
> ********************************* The kernel can't set the bit
> E1000_EXTCNF_CTRL_SWFLAG of the register EXTCNF_CTRL.
> 
> We found the information in the 82577 user manual:
> In the Extended Configuration Control Register.
>   Software Semaphore FLAG (SWFLAG). This bit is set by the device
> driver to gain access permission to shared CSR registers with the
> firmware and hardware. The bit is initialized on power up PCI reset
> and software reset. and the default value when Reset is "0b".
> 
> I don't know why the bit E1000_EXTCNF_CTRL_SWFLAG is not right, and
> not find any information about writing the bit. Due to the bit
> returns 0 when reset the controller, we wrote the patch below.
> *****************************The
> patch********************************** diff --git
> a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index
> 8b6ecd1..b3e20f4 100644 --- a/drivers/net/e1000e/ich8lan.c
> +++ b/drivers/net/e1000e/ich8lan.c
> @@ -224,6 +224,7 @@ static void
> e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
>   static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
>   static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool
>   link); static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
> +static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw);
> 
>   static inline u16 __er16flash(struct e1000_hw *hw, unsigned long
>   reg) {
> @@ -276,8 +277,12 @@ static s32 e1000_init_phy_params_pchlan(struct
> e1000_hw *hw)
> 
>       phy->id = e1000_phy_unknown;
>       ret_val = e1000e_get_phy_id(hw);
> -    if (ret_val)
> -        goto out;
> +    if (ret_val) {
> +        e1000_reset_hw_ich8lan(hw);
> +        ret_val = e1000e_get_phy_id(hw);
> +        if (ret_val)
> +            goto out;
> +    }
>       if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) {
>           /*
>            * In case the PHY needs to be in mdio slow mode (eg.
> 82577), 
> ****************************************************************************
> I'm not sure it's right, but using the patch, 82577 network can work
> well.I need more eyes about this, how can I make the patch better?
> Any suggestion would be helped me make the patch better.
> 
> By the way, we find 3 patches make it not well.
> 
>  From 0be8401051c716be4533272e983b7eed3d83946d Mon Sep 17 00:00:00
> 2001 From: Bruce Allan <bruce.w.allan@intel.com>
> Date: Wed, 2 Dec 2009 17:03:18 +0000
> Subject:  e1000e: correct ICH/PCH PHY operations function pointers
> 
>  From fddaa1aff881c98f524221236af98ce70dcd04cf Mon Sep 17 00:00:00
> 2001 
> 
> From: Bruce Allan <bruce.w.allan@intel.com>
> Date: Wed, 13 Jan 2010 01:52:49 +0000
> Subject: e1000e: MDIO slow mode should always be done for 82577
> 
>  From baf86c9d36826fab0160251bbc87dfab3af48a21 Mon Sep 17 00:00:00
> 2001 
> 
> From: Bruce Allan <bruce.w.allan@intel.com>
> Date: Wed, 13 Jan 2010 01:53:08 +0000
> Subject: e1000e: workaround link issues on busy hub in half duplex on
> 82577/82578
> 
> thanks,
> Yucheng.Wang

[Adding e1000-devel@lists.sf.net (the mailing list for Intel wired GbE drivers)]

Thanks for reporting the issue.  The 3 patches you list that appear to break e1000e on 82577 are necessary.  The patch you suggest to resolve the issue is almost exactly the same as one we have been working on in-house here at Intel and will be pushed upstream shortly.  There are still a couple unresolved issues with it however so it will be another couple days.

Thanks again,
Bruce.
------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

^ permalink raw reply

* Re: [PATCH 1/1] NET: netpoll, fix potential NULL ptr dereference
From: Daniel Borkmann @ 2010-03-18 14:55 UTC (permalink / raw)
  To: Matt Mackall
  Cc: Jiri Slaby, Jiri Slaby, davem, netdev, linux-kernel,
	Daniel Borkmann
In-Reply-To: <1268762160.25503.2988.camel@calx>

[-- Attachment #1: Type: text/plain, Size: 1473 bytes --]

Matt Mackall wrote:
> On Tue, 2010-03-16 at 18:22 +0100, Jiri Slaby wrote:
>> On 03/16/2010 06:12 PM, Matt Mackall wrote:
>>> I don't get it. The source of the branch tests for !ndev->npinfo and the
>>> original destination of the branch also tests for !ndev->npinfo. I don't
>>> see how it gets dereferenced.
>> Let's look at more of the context:
>>          if (!ndev->npinfo) {
>>                  npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
>>                  if (!npinfo) {         // npinfo is NULL
>>                          err = -ENOMEM;
>>                          goto release;
>>                  }
>> ...
>> release:                           // npinfo is still NULL
>>          if (!ndev->npinfo) {       // condition is the same (holds)
>>               // dereference below: vvvvvvvvvvvvvvv
>>                  spin_lock_irqsave(&npinfo->rx_lock, flags);
>>                  list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) {
>>                          npe->dev = NULL;
>>                  }
>>                  spin_unlock_irqrestore(&npinfo->rx_lock, flags);
>>
>>                  kfree(npinfo);
>>          }
> 
> Ok, you're correct, I read the second test backwards.
> 
> Acked-by: Matt Mackall <mpm@selenic.com>
> 

Thanks for fixing this and sorry for not being responsive, obviously it
sucks when you have a broken leg and German hospitals do not really have
Internet access ... ;)

Thanks,
Daniel


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 261 bytes --]

^ permalink raw reply

* kernel 2.6.33 kernel panic "kernel BUG at net/core/skbuff.c:147!"
From: Oliver Maurhart @ 2010-03-18 13:45 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 21756 bytes --]

#!/bin/hi *

I'm experiencing a kernel panic with a recent 2.6.33 kernel ... and - frankly 
- don't know what to do.

I've read REPORTING-BUGS and hope I've got all right (and the right target for 
this report).

[1.] Kernel panic when running heavy TUN/TAP I/O between two processes on the 
same machine.

[2.] We have an application scenario where we start 4 processes which are 
interconnected via TCP/IP plus 2 of them via additional TUN/TUP devices. On my 
machine after doing heavy IO the kernel panics (see output [6.]). 
Interestingly, a VM on the very same machine (VirtualBox with Ubuntu 9.10) 
does not with the very same scenery. I don't know where to start looking. The 
bug is very deterministic reproduceable. The kernel stops at the very same 
position in the processing of the application.

[3.] Keywords: skbuff, tun/tap, networking

[4.1.] # cat /proc/version 
Linux version 2.6.33-gentoo (root@lanfear) (gcc version 4.4.3 (Gentoo 4.4.3 
p1.0) ) #3 SMP PREEMPT Tue Mar 16 14:07:33 CET 2010

[4.2.] Kernel config attached from /proc/config.gz

[5.] Within the VM:
$ uname -a
Linux ubuntu-32-clean 2.6.31-20-generic #57-Ubuntu SMP Mon Feb 8 09:05:19 UTC 
2010 i686 GNU/Linux

[6.] Output of kernel panic (got that via netconsole on a remote host):

[ 3485.023866] skb_under_panic: text:ffffffff814dc389 len:46 put:14 
head:ffff880106a73c00 data:ffff880106a73bf2 tail:0x20 end:0x40 dev:q3p1
[ 3485.023932] ------------[ cut here ]------------
[ 3485.023940] kernel BUG at net/core/skbuff.c:147!
[ 3485.023948] invalid opcode: 0000 [#1] PREEMPT SMP 
[ 3485.023963] last sysfs file: 
/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0A:00/power_supply/BAT1/energy_full
[ 3485.023972] CPU 0 
[ 3485.023984] Pid: 26456, comm: link mgr: alice Tainted: P           2.6.33-
gentoo #3 Portable PC/TECRA S10
[ 3485.023993] RIP: 0010:[<ffffffff815c57e4>]  [<ffffffff815c57e4>] 
skb_under_panic+0x54/0x60
[ 3485.024013] RSP: 0018:ffff880028203df8  EFLAGS: 00010296
[ 3485.024015] RAX: 0000000000000092 RBX: ffff8801369cb380 RCX: 
0000000000000000
[ 3485.024015] RDX: ffff880028200000 RSI: 0000000000000092 RDI: 
0000000000000001
[ 3485.024015] RBP: ffff8801369cb380 R08: 0000000002000000 R09: 
0000000000000000
[ 3485.024015] R10: 0000000000000000 R11: 0000000000000000 R12: 
ffff8800bd29a000
[ 3485.024015] R13: ffff8800bd29a000 R14: 0000000000000000 R15: 
000000000000a288
[ 3485.024015] FS:  00007f5f6565a710(0000) GS:ffff880028200000(0000) 
knlGS:0000000000000000
[ 3485.024015] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3485.024015] CR2: 00007f5f65658a08 CR3: 00000000b514b000 CR4: 
00000000000406f0
[ 3485.024015] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 
0000000000000000
[ 3485.024015] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 
0000000000000400
[ 3485.024015] Process link mgr: alice (pid: 26456, threadinfo 
ffff8800b4620000, task ffff8800bd173720)
[ 3485.024015] Stack:
[ 3485.024015]  0000000000000020 0000000000000040 ffff8800bd29a000 
ffff8801369cb380
[ 3485.024015] <0> ffff8801369cb380 ffffffff815c7c6f ffff8801369cb380 
ffffffff814dc389
[ 3485.024015] <0> ffff880180000000 ffffffff81d06380 ffffffff81d063a0 
ffff8801369cb380
[ 3485.024015] Call Trace:
[ 3485.024015]  <IRQ> 
[ 3485.024015]  [<ffffffff815c7c6f>] ? skb_push+0x2f/0x40
[ 3485.024015]  [<ffffffff814dc389>] ? aoenet_rcv+0x99/0x190
[ 3485.024015]  [<ffffffff815d0caa>] ? netif_receive_skb+0x31a/0x450
[ 3485.024015]  [<ffffffff81710971>] ? _raw_spin_unlock_irq+0x11/0x40
[ 3485.024015]  [<ffffffff8104d4e0>] ? run_timer_softirq+0x210/0x270
[ 3485.024015]  [<ffffffff815d0e55>] ? process_backlog+0x75/0xc0
[ 3485.024015]  [<ffffffff815d16b6>] ? net_rx_action+0x116/0x1e0
[ 3485.024015]  [<ffffffff81048244>] ? __do_softirq+0xb4/0x140
[ 3485.024015]  [<ffffffff8100338c>] ? call_softirq+0x1c/0x30
[ 3485.024015]  <EOI> 
[ 3485.024015]  [<ffffffff8100553d>] ? do_softirq+0x4d/0x80
[ 3485.024015]  [<ffffffff815d1a6d>] ? netif_rx_ni+0x4d/0x70
[ 3485.024015]  [<ffffffff8148fb06>] ? tun_chr_aio_write+0x356/0x4e0
[ 3485.024015]  [<ffffffff810bea6f>] ? do_sync_write+0xbf/0x100
[ 3485.024015]  [<ffffffff810a1d0b>] ? handle_mm_fault+0x4bb/0x850
[ 3485.024015]  [<ffffffff81710cde>] ? _raw_spin_lock_irqsave+0x1e/0x50
[ 3485.024015]  [<ffffffff810bf538>] ? vfs_write+0xb8/0x180
[ 3485.024015]  [<ffffffff810bf6ee>] ? sys_write+0x4e/0x90
[ 3485.024015]  [<ffffffff8100256b>] ? system_call_fastpath+0x16/0x1b
[ 3485.024015] Code: 8b 57 68 48 89 44 24 10 8b 87 b8 00 00 00 48 89 44 24 08 
31 c0 8b bf b4 00 00 00 48 89 3c 24 48 c7 c7 b0 1c a9 81 e8 b9 82 14 00 <0f> 
0b eb fe 0f 1f 84 00 00 00 00 00 48 83 ec 28 89 f1 4c 8b 8f 
[ 3485.024015] RIP  [<ffffffff815c57e4>] skb_under_panic+0x54/0x60
[ 3485.024015]  RSP <ffff880028203df8>
[ 3485.024258] ------------[ cut here ]------------
[ 3485.024610] ---[ end trace 30a4557d927b50f9 ]---
[ 3485.024615] Kernel panic - not syncing: Fatal exception in interrupt
[ 3485.024621] Pid: 26456, comm: link mgr: alice Tainted: P      D    2.6.33-
gentoo #3
[ 3485.024625] Call Trace:
[ 3485.024629]  <IRQ>  [<ffffffff8170d9e0>] ? panic+0x84/0x141
[ 3485.024640]  [<ffffffff81710dae>] ? _raw_spin_trylock+0xe/0x70
[ 3485.024647]  [<ffffffff81006b2b>] ? oops_end+0x9b/0xa0
[ 3485.024653]  [<ffffffff810040a4>] ? do_invalid_op+0x84/0xa0
[ 3485.024660]  [<ffffffff815c57e4>] ? skb_under_panic+0x54/0x60
[ 3485.024667]  [<ffffffff81042a03>] ? release_console_sem+0x1a3/0x1f0
[ 3485.024673]  [<ffffffff81042f8e>] ? vprintk+0x27e/0x450
[ 3485.024680]  [<ffffffff81003115>] ? invalid_op+0x15/0x20
[ 3485.024688]  [<ffffffff815c57e4>] ? skb_under_panic+0x54/0x60
[ 3485.024695]  [<ffffffff815c57e4>] ? skb_under_panic+0x54/0x60
[ 3485.024700]  [<ffffffff815c7c6f>] ? skb_push+0x2f/0x40
[ 3485.024707]  [<ffffffff814dc389>] ? aoenet_rcv+0x99/0x190
[ 3485.024714]  [<ffffffff815d0caa>] ? netif_receive_skb+0x31a/0x450
[ 3485.024720]  [<ffffffff81710971>] ? _raw_spin_unlock_irq+0x11/0x40
[ 3485.024726]  [<ffffffff8104d4e0>] ? run_timer_softirq+0x210/0x270
[ 3485.024734]  [<ffffffff815d0e55>] ? process_backlog+0x75/0xc0
[ 3485.024740]  [<ffffffff815d16b6>] ? net_rx_action+0x116/0x1e0
[ 3485.024748]  [<ffffffff81048244>] ? __do_softirq+0xb4/0x140
[ 3485.024755]  [<ffffffff8100338c>] ? call_softirq+0x1c/0x30
[ 3485.024758]  <EOI>  [<ffffffff8100553d>] ? do_softirq+0x4d/0x80
[ 3485.024769]  [<ffffffff815d1a6d>] ? netif_rx_ni+0x4d/0x70
[ 3485.024775]  [<ffffffff8148fb06>] ? tun_chr_aio_write+0x356/0x4e0
[ 3485.024782]  [<ffffffff810bea6f>] ? do_sync_write+0xbf/0x100
[ 3485.024790]  [<ffffffff810a1d0b>] ? handle_mm_fault+0x4bb/0x850
[ 3485.024797]  [<ffffffff81710cde>] ? _raw_spin_lock_irqsave+0x1e/0x50
[ 3485.024804]  [<ffffffff810bf538>] ? vfs_write+0xb8/0x180
[ 3485.024810]  [<ffffffff810bf6ee>] ? sys_write+0x4e/0x90
[ 3485.024817]  [<ffffffff8100256b>] ? system_call_fastpath+0x16/0x1b
[ 3485.024258] kernel BUG at net/core/skbuff.c:147!
[ 3485.024258] invalid opcode: 0000 [#2] PREEMPT SMP 
[ 3485.024258] last sysfs file: 
/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0A:00/power_supply/BAT1/energy_full
[ 3485.024258] CPU 1 
[ 3485.024258] Pid: 26453, comm: link mgr: bob:a Tainted: P      D    2.6.33-
gentoo #3 Portable PC/TECRA S10
[ 3485.024258] RIP: 0010:[<ffffffff815c57e4>]  [<ffffffff815c57e4>] 
skb_under_panic+0x54/0x60
[ 3485.024258] RSP: 0018:ffff880028303df8  EFLAGS: 00010296
[ 3485.024258] RAX: 0000000000000092 RBX: ffff8800b50f33c0 RCX: 
0000000000000000
[ 3485.024258] RDX: 0000000000000001 RSI: 0000000000000092 RDI: 
0000000000000001
[ 3485.024258] RBP: ffff8800b50f33c0 R08: 0000000000000000 R09: 
0000000000000001
[ 3485.024258] R10: 0000000000000000 R11: 0000000000000000 R12: 
ffff8800bf599000
[ 3485.024258] R13: ffff8800bf599000 R14: 0000000000000000 R15: 
000000000000a288
[ 3485.024258] FS:  00007f488bb40710(0000) GS:ffff880028300000(0000) 
knlGS:0000000000000000
[ 3485.024258] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3485.024258] CR2: 00007f488bb3ea08 CR3: 0000000119008000 CR4: 
00000000000406e0
[ 3485.024258] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 
0000000000000000
[ 3485.024258] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 
0000000000000400
[ 3485.024258] Process link mgr: bob:a (pid: 26453, threadinfo 
ffff8800bf6ee000, task ffff8800bd103660)
[ 3485.024258] Stack:
[ 3485.024258]  0000000000000020 0000000000000040 ffff8800bf599000 
ffff8800b50f33c0
[ 3485.024258] <0> ffff8800b50f33c0 ffffffff815c7c6f ffff8800b50f33c0 
ffffffff814dc389
[ 3485.024258] <0> ffff8800bd102fb8 000000000000e240 ffffffff81d063a0 
ffff8800b50f33c0
[ 3485.024258] Call Trace:
[ 3485.024258]  <IRQ> 
[ 3485.024258]  [<ffffffff815c7c6f>] ? skb_push+0x2f/0x40
[ 3485.024258]  [<ffffffff814dc389>] ? aoenet_rcv+0x99/0x190
[ 3485.024258]  [<ffffffff815d0caa>] ? netif_receive_skb+0x31a/0x450
[ 3485.024258]  [<ffffffff81710971>] ? _raw_spin_unlock_irq+0x11/0x40
[ 3485.024258]  [<ffffffff815d0e55>] ? process_backlog+0x75/0xc0
[ 3485.024258]  [<ffffffff8103e8c7>] ? run_rebalance_domains+0x37/0xe0
[ 3485.024258]  [<ffffffff815d16b6>] ? net_rx_action+0x116/0x1e0
[ 3485.024258]  [<ffffffff81048244>] ? __do_softirq+0xb4/0x140
[ 3485.024258]  [<ffffffff8100338c>] ? call_softirq+0x1c/0x30
[ 3485.024258]  <EOI> 
[ 3485.024258]  [<ffffffff8100553d>] ? do_softirq+0x4d/0x80
[ 3485.024258]  [<ffffffff815d1a6d>] ? netif_rx_ni+0x4d/0x70
[ 3485.024258]  [<ffffffff8148fb06>] ? tun_chr_aio_write+0x356/0x4e0
[ 3485.024258]  [<ffffffff8102797c>] ? flush_tlb_page+0x5c/0xe0
[ 3485.024258]  [<ffffffff810bea6f>] ? do_sync_write+0xbf/0x100
[ 3485.024258]  [<ffffffff810a1d0b>] ? handle_mm_fault+0x4bb/0x850
[ 3485.024258]  [<ffffffff81710cde>] ? _raw_spin_lock_irqsave+0x1e/0x50
[ 3485.024258]  [<ffffffff810bf538>] ? vfs_write+0xb8/0x180
[ 3485.024258]  [<ffffffff810bf6ee>] ? sys_write+0x4e/0x90
[ 3485.024258]  [<ffffffff8100256b>] ? system_call_fastpath+0x16/0x1b
[ 3485.024258] Code: 8b 57 68 48 89 44 24 10 8b 87 b8 00 00 00 48 89 44 24 08 
31 c0 8b bf b4 00 00 00 48 89 3c 24 48 c7 c7 b0 1c a9 81 e8 b9 82 14 00 <0f> 
0b eb fe 0f 1f 84 00 00 00 00 00 48 83 ec 28 89 f1 4c 8b 8f 
[ 3485.024258] RIP  [<ffffffff815c57e4>] skb_under_panic+0x54/0x60
[ 3485.024258]  RSP <ffff880028303df8>

[8.1.] # ./ver_linux
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.
 
Linux lanfear 2.6.33-gentoo #3 SMP PREEMPT Tue Mar 16 14:07:33 CET 2010 x86_64 
Intel(R) Core(TM)2 Duo CPU T9550 @ 2.66GHz GenuineIntel GNU/Linux
 
Gnu C                  4.4.3
Gnu make               3.81
binutils               2.20.1.20100303
util-linux             2.17.1
mount                  support
module-init-tools      3.11.1
e2fsprogs              1.41.10
pcmciautils            016
PPP                    2.4.4
Linux C Library        2.11
Dynamic linker (ldd)   2.11
Procps                 3.2.8
Net-tools              1.60_p20100101055920
Kbd                    1.15.1
oprofile               0.9.6
Sh-utils               8.4
wireless-tools         29
Modules Loaded         option snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss 
sco bnep rfcomm l2cap vmmon vmci vmblock vboxnetflt vboxnetadp vboxdrv nvidia 
btusb bluetooth snd_hda_codec_realtek zaurus pl2303 uvcvideo snd_hda_intel 
cdc_ether usbnet iwlagn usbserial snd_hda_codec iwlcore mii usblp cdc_wdm 
cdc_acm snd_hwdep snd_pcm mac80211 video psmouse toshiba_acpi pcspkr cfg80211 
snd_timer backlight serio_raw output snd_page_alloc toshiba_bluetooth rfkill 
libiscsi scsi_wait_scan sl811_hcd


[8.2] # cat /proc/cpuinfo 
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Core(TM)2 Duo CPU     T9550  @ 2.66GHz
stepping        : 10
cpu MHz         : 2661.000
cache size      : 6144 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca 
cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm 
constant_tsc arch_perfmon pebs bts rep_good aperfmperf pni dtes64 monitor 
ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm ida 
tpr_shadow vnmi flexpriority
bogomips        : 5319.97
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

processor       : 1
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Core(TM)2 Duo CPU     T9550  @ 2.66GHz
stepping        : 10
cpu MHz         : 2661.000
cache size      : 6144 KB
physical id     : 0
siblings        : 2
core id         : 1
cpu cores       : 2
apicid          : 1
initial apicid  : 1
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca 
cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm 
constant_tsc arch_perfmon pebs bts rep_good aperfmperf pni dtes64 monitor 
ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm ida 
tpr_shadow vnmi flexpriority
bogomips        : 5317.47
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

[8.3.] # cat /proc/modules 
option 17826 0 - Live 0xffffffffa00ab000
snd_seq 51917 1 - Live 0xffffffffa0e48000
snd_seq_device 6266 1 snd_seq, Live 0xffffffffa0e41000
snd_pcm_oss 37689 0 - Live 0xffffffffa0e30000
snd_mixer_oss 14766 1 snd_pcm_oss, Live 0xffffffffa0e26000
sco 8699 2 - Live 0xffffffffa01af000
bnep 11167 2 - Live 0xffffffffa0130000
rfcomm 36509 4 - Live 0xffffffffa01ec000
l2cap 33696 16 bnep,rfcomm, Live 0xffffffffa0106000
vmmon 70844 0 - Live 0xffffffffa0e12000
vmci 53612 0 - Live 0xffffffffa0e02000
vmblock 11094 0 - Live 0xffffffffa0087000
vboxnetflt 10286 0 - Live 0xffffffffa0036000
vboxnetadp 4246 0 - Live 0xffffffffa000b000
vboxdrv 1723405 3 vboxnetflt,vboxnetadp, Live 0xffffffffa0c5b000
nvidia 9622117 40 - Live 0xffffffffa0254000 (P)
btusb 12243 2 - Live 0xffffffffa0056000
bluetooth 57375 9 sco,bnep,rfcomm,l2cap,btusb, Live 0xffffffffa0243000
snd_hda_codec_realtek 277964 1 - Live 0xffffffffa01fd000
zaurus 3116 0 - Live 0xffffffffa003d000
pl2303 16737 0 - Live 0xffffffffa0080000
uvcvideo 60397 0 - Live 0xffffffffa0172000
snd_hda_intel 22353 14 - Live 0xffffffffa001b000
cdc_ether 4471 1 zaurus, Live 0xffffffffa0005000
usbnet 18998 2 zaurus,cdc_ether, Live 0xffffffffa01f6000
iwlagn 216120 0 - Live 0xffffffffa01b5000
usbserial 37199 2 option,pl2303, Live 0xffffffffa01a3000
snd_hda_codec 81024 2 snd_hda_codec_realtek,snd_hda_intel, Live 
0xffffffffa0182000
iwlcore 214518 1 iwlagn, Live 0xffffffffa013b000
mii 4973 1 usbnet, Live 0xffffffffa0134000
usblp 11258 0 - Live 0xffffffffa012b000
cdc_wdm 9012 0 - Live 0xffffffffa0123000
cdc_acm 16317 2 - Live 0xffffffffa0118000
snd_hwdep 6258 1 snd_hda_codec, Live 0xffffffffa0110000
snd_pcm 80714 7 snd_pcm_oss,snd_hda_intel,snd_hda_codec, Live 
0xffffffffa00f0000
mac80211 146328 2 iwlagn,iwlcore, Live 0xffffffffa00bf000
video 19430 0 - Live 0xffffffffa00b3000
psmouse 57566 0 - Live 0xffffffffa009a000
toshiba_acpi 7734 0 - Live 0xffffffffa0092000
pcspkr 1830 0 - Live 0xffffffffa008c000
cfg80211 143104 3 iwlagn,iwlcore,mac80211, Live 0xffffffffa005b000
snd_timer 20483 6 snd_seq,snd_pcm, Live 0xffffffffa004e000
backlight 4636 2 video,toshiba_acpi, Live 0xffffffffa0047000
serio_raw 4463 0 - Live 0xffffffffa0040000
output 2207 1 video, Live 0xffffffffa003a000
snd_page_alloc 8012 2 snd_hda_intel,snd_pcm, Live 0xffffffffa0032000
toshiba_bluetooth 2031 0 - Live 0xffffffffa002c000
rfkill 12568 4 bluetooth,toshiba_acpi,cfg80211, Live 0xffffffffa0022000
libiscsi 44581 0 - Live 0xffffffffa000e000
scsi_wait_scan 693 0 - Live 0xffffffffa0008000
sl811_hcd 10564 0 - Live 0xffffffffa0000000

[8.4] # cat /proc/ioports 
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0064-0064 : keyboard
0070-0071 : rtc0
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
0170-0177 : ide_generic
01e0-01ef : pnp 00:09
01f0-01f7 : ide_generic
0376-0376 : ide_generic
03c0-03df : vga+
  03c0-03df : uvesafb
03f6-03f6 : ide_generic
03f8-03ff : serial
0480-048f : pnp 00:09
04d0-04d1 : pnp 00:09
0690-06ff : pnp 00:09
0cf8-0cff : PCI conf1
1000-1fff : PCI Bus 0000:06
  1000-10ff : PCI CardBus 0000:07
  1400-14ff : PCI CardBus 0000:07
7f20-7f3f : 0000:00:1f.2
  7f20-7f3f : ahci
7f44-7f47 : 0000:00:1f.2
  7f44-7f47 : ahci
7f48-7f4f : 0000:00:1f.2
  7f48-7f4f : ahci
7f54-7f57 : 0000:00:1f.2
  7f54-7f57 : ahci
7f58-7f5f : 0000:00:1f.2
  7f58-7f5f : ahci
7f60-7f7f : 0000:00:1d.2
  7f60-7f7f : uhci_hcd
7f80-7f9f : 0000:00:1d.1
  7f80-7f9f : uhci_hcd
7fe0-7fff : 0000:00:1d.0
  7fe0-7fff : uhci_hcd
8000-8fff : PCI Bus 0000:05
9000-9fff : PCI Bus 0000:03
a000-afff : PCI Bus 0000:02
bf40-bf5f : 0000:00:1a.2
  bf40-bf5f : uhci_hcd
bf60-bf7f : 0000:00:1a.1
  bf60-bf7f : uhci_hcd
bf80-bf9f : 0000:00:1a.0
  bf80-bf9f : uhci_hcd
bfe0-bfff : 0000:00:19.0
c000-cfff : PCI Bus 0000:01
  cf00-cf7f : 0000:01:00.0
d800-d87f : pnp 00:09
  d800-d803 : ACPI PM1a_EVT_BLK
  d804-d805 : ACPI PM1a_CNT_BLK
  d808-d80b : ACPI PM_TMR
  d810-d815 : ACPI CPU throttle
  d820-d82f : ACPI GPE0_BLK
  d850-d850 : ACPI PM2_CNT_BLK
d880-d89f : pnp 00:09
e000-e07f : pnp 00:09
e080-e0ff : pnp 00:09
e400-e47f : pnp 00:09
e480-e4ff : pnp 00:09
e800-e87f : pnp 00:09
e880-e8ff : pnp 00:09
ec00-ec7f : pnp 00:09
ec80-ecff : pnp 00:09
ee80-eeff : pnp 00:09

# cat /proc/iomem
00000000-0009bbff : System RAM
0009bc00-0009ffff : reserved
000e8000-000eedff : reserved
000eee00-000eefff : ACPI Non-volatile Storage
000ef000-000fffff : reserved
00100000-bfb9ffff : System RAM
  01000000-01713a60 : Kernel code
  01713a61-01d0a627 : Kernel data
  01daf000-01eb50a3 : Kernel bss
bfba0000-bfffffff : reserved
  bfba0000-bfbaffff : pnp 00:00
  bfbb0000-bfefffff : pnp 00:00
  bff00000-bfffffff : pnp 00:00
c0000000-c3ffffff : PCI Bus 0000:06
  c0000000-c3ffffff : PCI CardBus 0000:07
c4000000-c7ffffff : PCI CardBus 0000:07
e0000000-efffffff : PCI Bus 0000:01
  e0000000-efffffff : 0000:01:00.0
f0000000-f3ffffff : PCI MMCONFIG 0000 [bus 00-3f]
  f0000000-f3ffffff : pnp 00:01
f6000000-f7ffffff : PCI Bus 0000:03
f8000000-f9ffffff : PCI Bus 0000:03
fa000000-fdffffff : PCI Bus 0000:01
  fa000000-fbffffff : 0000:01:00.0
    fb000000-fb9fffff : uvesafb
  fc000000-fc01ffff : 0000:01:00.0
  fd000000-fdffffff : 0000:01:00.0
    fd000000-fdffffff : nvidia
fec00000-fec27fff : reserved
  fec00000-fec003ff : IOAPIC 0
fed00000-fed004ff : reserved
  fed00000-fed003ff : HPET 0
  fed00400-fed004ff : pnp 00:00
fed10000-fed19fff : reserved
  fed10000-fed19fff : pnp 00:00
fed1c000-fed93fff : reserved
  fed1c000-fed1ffff : pnp 00:00
  fed20000-fed3ffff : pnp 00:00
  fed45000-fed8ffff : pnp 00:00
  fed90000-fed93fff : pnp 00:00
fee00000-fee00fff : Local APIC
  fee00000-fee00fff : reserved
    fee00000-fee00fff : pnp 00:00
ff200000-ff3fffff : PCI Bus 0000:05
ff400000-ff5fffff : PCI Bus 0000:02
ff600000-ff6fffff : PCI Bus 0000:06
  ff600000-ff600fff : 0000:06:0b.0
    ff600000-ff600fff : yenta_socket
  ff6fb000-ff6fb0ff : 0000:06:0b.5
  ff6fc000-ff6fc0ff : 0000:06:0b.4
  ff6fd000-ff6fd0ff : 0000:06:0b.3
  ff6fe000-ff6fe0ff : 0000:06:0b.2
    ff6fe000-ff6fe0ff : mmc0
  ff6ff000-ff6ff7ff : 0000:06:0b.1
    ff6ff000-ff6ff7ff : firewire_ohci
ff700000-ff8fffff : PCI Bus 0000:05
ff900000-ff9fffff : PCI Bus 0000:02
  ff9fe000-ff9fffff : 0000:02:00.0
    ff9fe000-ff9fffff : iwlagn
ffa00000-ffbfffff : reserved
  ffa00000-ffbfffff : pnp 00:00
ffcc0000-ffcdffff : 0000:00:19.0
  ffcc0000-ffcdffff : e1000e
ffcf7000-ffcf77ff : 0000:00:1f.2
  ffcf7000-ffcf77ff : ahci
ffcf8000-ffcfbfff : 0000:00:1b.0
  ffcf8000-ffcfbfff : ICH HD audio
ffcfc000-ffcfc3ff : 0000:00:1d.7
  ffcfc000-ffcfc3ff : ehci_hcd
ffcfd000-ffcfd3ff : 0000:00:1a.7
  ffcfd000-ffcfd3ff : ehci_hcd
ffcfe000-ffcfefff : 0000:00:19.0
  ffcfe000-ffcfefff : e1000e
ffcff000-ffcff00f : 0000:00:03.0
ffd00000-ffffffff : reserved
  ffd00000-ffffffff : pnp 00:00
100000000-13bffffff : System RAM

[8.5.] lspci.vvv.txt attached

[8.6.] # cat /proc/scsi/scsi 
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: Hitachi HTS72323 Rev: FC4O
  Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi1 Channel: 00 Id: 00 Lun: 00
  Vendor: TEAC     Model: DV-W28S-RT       Rev: 7.0D
  Type:   CD-ROM                           ANSI  SCSI revision: 05
Host: scsi5 Channel: 00 Id: 00 Lun: 00
  Vendor: LITE-ON  Model: DVDRW SOHW-1653S Rev: CS09
  Type:   CD-ROM                           ANSI  SCSI revision: 00


[8.7] -


Hopefully I gathered all what's needed.

Machine works very well besides this kernel bug. No problem at all so far. 
However, I'm still not quite sure 

KR,


Oliver

-- 
DI Oliver Maurhart
Safety & Security Department
Secure Quantum Technologies

AIT Austrian Institute of Technology GmbH
Donau-City-Stra�e 1 | 1220 Vienna | Austria\nT +43(0) 50550-4771 | M +43(0) 
664 8251205\noliver.maurhart@ait.ac.at | http://www.ait.ac.at\n\nFN: 115980 i 
HG Wien | UID: ATU14703506\nRSA2048

[-- Attachment #2: config.gz --]
[-- Type: application/x-gzip, Size: 19891 bytes --]

[-- Attachment #3: lspci.vvv.txt --]
[-- Type: text/plain, Size: 28356 bytes --]

00:00.0 Host bridge: Intel Corporation Mobile 4 Series Chipset Memory Controller Hub (rev 07)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort+ >SERR- <PERR- INTx-
	Latency: 0
	Capabilities: [e0] Vendor Specific Information <?>

00:01.0 PCI bridge: Intel Corporation Mobile 4 Series Chipset PCI Express Graphics Port (rev 07) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
	I/O behind bridge: 0000c000-0000cfff
	Memory behind bridge: fa000000-fdffffff
	Prefetchable memory behind bridge: 00000000e0000000-00000000efffffff
	Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- <SERR- <PERR-
	BridgeCtl: Parity- SERR- NoISA- VGA+ MAbort- >Reset- FastB2B-
		PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
	Capabilities: [88] Subsystem: Toshiba America Info Systems Device 0001
	Capabilities: [80] Power Management version 3
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [90] MSI: Enable+ Count=1/1 Maskable- 64bit-
		Address: fee0300c  Data: 4169
	Capabilities: [a0] Express (v1) Root Port (Slot-), MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
			ExtTag- RBE+ FLReset-
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
			MaxPayload 128 bytes, MaxReadReq 128 bytes
		DevSta:	CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
		LnkCap:	Port #2, Speed 2.5GT/s, Width x16, ASPM L0s L1, Latency L0 <256ns, L1 <4us
			ClockPM- Surprise- LLActRep- BwNot-
		LnkCtl:	ASPM L0s L1 Enabled; RCB 64 bytes Disabled- Retrain- CommClk+
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x16, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
		RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
		RootCap: CRSVisible-
		RootSta: PME ReqID 0000, PMEStatus- PMEPending-
	Capabilities: [100] Virtual Channel <?>
	Capabilities: [140] Root Complex Link <?>
	Kernel driver in use: pcieport

00:03.0 Communication controller: Intel Corporation Mobile 4 Series Chipset MEI Controller (rev 07)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 10
	Region 0: Memory at ffcff000 (64-bit, non-prefetchable) [size=16]
	Capabilities: [50] Power Management version 3
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [8c] MSI: Enable- Count=1/1 Maskable- 64bit+
		Address: 0000000000000000  Data: 0000

00:19.0 Ethernet controller: Intel Corporation 82567LM Gigabit Network Connection (rev 03)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 29
	Region 0: Memory at ffcc0000 (32-bit, non-prefetchable) [size=128K]
	Region 1: Memory at ffcfe000 (32-bit, non-prefetchable) [size=4K]
	Region 2: I/O ports at bfe0 [size=32]
	Capabilities: [c8] Power Management version 2
		Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=1 PME-
	Capabilities: [d0] MSI: Enable+ Count=1/1 Maskable- 64bit+
		Address: 00000000fee0300c  Data: 41d1
	Capabilities: [e0] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: e1000e

00:1a.0 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #4 (rev 03) (prog-if 00 [UHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 16
	Region 4: I/O ports at bf80 [size=32]
	Capabilities: [50] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: uhci_hcd

00:1a.1 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #5 (rev 03) (prog-if 00 [UHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin B routed to IRQ 21
	Region 4: I/O ports at bf60 [size=32]
	Capabilities: [50] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: uhci_hcd

00:1a.2 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #6 (rev 03) (prog-if 00 [UHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin C routed to IRQ 19
	Region 4: I/O ports at bf40 [size=32]
	Capabilities: [50] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: uhci_hcd

00:1a.7 USB Controller: Intel Corporation 82801I (ICH9 Family) USB2 EHCI Controller #2 (rev 03) (prog-if 20 [EHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin C routed to IRQ 19
	Region 0: Memory at ffcfd000 (32-bit, non-prefetchable) [size=1K]
	Capabilities: [50] Power Management version 2
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [58] Debug port: BAR=1 offset=00a0
	Capabilities: [98] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: ehci_hcd

00:1b.0 Audio device: Intel Corporation 82801I (ICH9 Family) HD Audio Controller (rev 03)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Interrupt: pin A routed to IRQ 31
	Region 0: Memory at ffcf8000 (64-bit, non-prefetchable) [size=16K]
	Capabilities: [50] Power Management version 2
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+
		Address: 00000000fee0300c  Data: 41c1
	Capabilities: [70] Express (v1) Root Complex Integrated Endpoint, MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
			ExtTag- RBE- FLReset+
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop+
			MaxPayload 128 bytes, MaxReadReq 128 bytes
		DevSta:	CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
		LnkCap:	Port #0, Speed unknown, Width x0, ASPM unknown, Latency L0 <64ns, L1 <1us
			ClockPM- Surprise- LLActRep- BwNot-
		LnkCtl:	ASPM Disabled; Disabled- Retrain- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed unknown, Width x0, TrErr- Train- SlotClk- DLActive- BWMgmt- ABWMgmt-
	Capabilities: [100] Virtual Channel <?>
	Capabilities: [130] Root Complex Link <?>
	Kernel driver in use: HDA Intel
	Kernel modules: snd-hda-intel

00:1c.0 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 1 (rev 03) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Bus: primary=00, secondary=02, subordinate=02, sec-latency=0
	I/O behind bridge: 0000a000-0000afff
	Memory behind bridge: ff900000-ff9fffff
	Prefetchable memory behind bridge: 00000000ff400000-00000000ff5fffff
	Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- <SERR- <PERR-
	BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
		PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
	Capabilities: [40] Express (v1) Root Port (Slot-), MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
			ExtTag- RBE+ FLReset-
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
			MaxPayload 128 bytes, MaxReadReq 128 bytes
		DevSta:	CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
		LnkCap:	Port #1, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <256ns, L1 <4us
			ClockPM- Surprise- LLActRep+ BwNot-
		LnkCtl:	ASPM L1 Enabled; RCB 64 bytes Disabled- Retrain- CommClk+
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive+ BWMgmt- ABWMgmt-
		RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
		RootCap: CRSVisible-
		RootSta: PME ReqID 0000, PMEStatus- PMEPending-
	Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
		Address: fee0300c  Data: 4171
	Capabilities: [90] Subsystem: Toshiba America Info Systems Device 0001
	Capabilities: [a0] Power Management version 2
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [100] Virtual Channel <?>
	Capabilities: [180] Root Complex Link <?>
	Kernel driver in use: pcieport

00:1c.1 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 2 (rev 03) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Bus: primary=00, secondary=03, subordinate=04, sec-latency=0
	I/O behind bridge: 00009000-00009fff
	Memory behind bridge: f8000000-f9ffffff
	Prefetchable memory behind bridge: 00000000f6000000-00000000f7ffffff
	Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- <SERR- <PERR-
	BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
		PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
	Capabilities: [40] Express (v1) Root Port (Slot+), MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
			ExtTag- RBE+ FLReset-
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
			MaxPayload 128 bytes, MaxReadReq 128 bytes
		DevSta:	CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
		LnkCap:	Port #2, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <1us, L1 <4us
			ClockPM- Surprise- LLActRep+ BwNot-
		LnkCtl:	ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x0, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
		SltCap:	AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surpise+
			Slot #  1, PowerLimit 6.500000; Interlock- NoCompl-
		SltCtl:	Enable: AttnBtn+ PwrFlt- MRL- PresDet+ CmdCplt- HPIrq- LinkChg-
			Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
		SltSta:	Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet- Interlock-
			Changed: MRL- PresDet- LinkState-
		RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
		RootCap: CRSVisible-
		RootSta: PME ReqID 0000, PMEStatus- PMEPending-
	Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
		Address: fee0300c  Data: 4179
	Capabilities: [90] Subsystem: Toshiba America Info Systems Device 0001
	Capabilities: [a0] Power Management version 2
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [100] Virtual Channel <?>
	Capabilities: [180] Root Complex Link <?>
	Kernel driver in use: pcieport

00:1c.2 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 3 (rev 03) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Bus: primary=00, secondary=05, subordinate=05, sec-latency=0
	I/O behind bridge: 00008000-00008fff
	Memory behind bridge: ff700000-ff8fffff
	Prefetchable memory behind bridge: 00000000ff200000-00000000ff3fffff
	Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- <SERR- <PERR-
	BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
		PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
	Capabilities: [40] Express (v1) Root Port (Slot-), MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
			ExtTag- RBE+ FLReset-
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
			MaxPayload 128 bytes, MaxReadReq 128 bytes
		DevSta:	CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
		LnkCap:	Port #3, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <1us, L1 <4us
			ClockPM- Surprise- LLActRep+ BwNot-
		LnkCtl:	ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x0, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
		RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
		RootCap: CRSVisible-
		RootSta: PME ReqID 0000, PMEStatus- PMEPending-
	Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit-
		Address: fee0300c  Data: 4181
	Capabilities: [90] Subsystem: Toshiba America Info Systems Device 0001
	Capabilities: [a0] Power Management version 2
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [100] Virtual Channel <?>
	Capabilities: [180] Root Complex Link <?>
	Kernel driver in use: pcieport

00:1d.0 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #1 (rev 03) (prog-if 00 [UHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 23
	Region 4: I/O ports at 7fe0 [size=32]
	Capabilities: [50] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: uhci_hcd

00:1d.1 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #2 (rev 03) (prog-if 00 [UHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin B routed to IRQ 19
	Region 4: I/O ports at 7f80 [size=32]
	Capabilities: [50] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: uhci_hcd

00:1d.2 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #3 (rev 03) (prog-if 00 [UHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin C routed to IRQ 18
	Region 4: I/O ports at 7f60 [size=32]
	Capabilities: [50] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: uhci_hcd

00:1d.7 USB Controller: Intel Corporation 82801I (ICH9 Family) USB2 EHCI Controller #1 (rev 03) (prog-if 20 [EHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 23
	Region 0: Memory at ffcfc000 (32-bit, non-prefetchable) [size=1K]
	Capabilities: [50] Power Management version 2
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [58] Debug port: BAR=1 offset=00a0
	Capabilities: [98] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: ehci_hcd

00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 93) (prog-if 01 [Subtractive decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Bus: primary=00, secondary=06, subordinate=0a, sec-latency=32
	I/O behind bridge: 00001000-00001fff
	Memory behind bridge: ff600000-ff6fffff
	Prefetchable memory behind bridge: 00000000c0000000-00000000c3ffffff
	Secondary status: 66MHz- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort+ <SERR- <PERR-
	BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
		PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
	Capabilities: [50] Subsystem: Toshiba America Info Systems Device 0001

00:1f.0 ISA bridge: Intel Corporation ICH9M-E LPC Interface Controller (rev 03)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Capabilities: [e0] Vendor Specific Information <?>

00:1f.2 SATA controller: Intel Corporation ICH9M/M-E SATA AHCI Controller (rev 03) (prog-if 01 [AHCI 1.0])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin B routed to IRQ 28
	Region 0: I/O ports at 7f58 [size=8]
	Region 1: I/O ports at 7f54 [size=4]
	Region 2: I/O ports at 7f48 [size=8]
	Region 3: I/O ports at 7f44 [size=4]
	Region 4: I/O ports at 7f20 [size=32]
	Region 5: Memory at ffcf7000 (32-bit, non-prefetchable) [size=2K]
	Capabilities: [80] MSI: Enable+ Count=1/16 Maskable- 64bit-
		Address: fee0300c  Data: 4191
	Capabilities: [70] Power Management version 3
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot+,D3cold-)
		Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [a8] SATA HBA <?>
	Capabilities: [b0] PCI Advanced Features
		AFCap: TP+ FLR+
		AFCtrl: FLR-
		AFStatus: TP-
	Kernel driver in use: ahci

01:00.0 VGA compatible controller: nVidia Corporation G86M [Quadro NVS 150M] (rev a1) (prog-if 00 [VGA controller])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 16
	Region 0: Memory at fd000000 (32-bit, non-prefetchable) [size=16M]
	Region 1: Memory at e0000000 (64-bit, prefetchable) [size=256M]
	Region 3: Memory at fa000000 (64-bit, non-prefetchable) [size=32M]
	Region 5: I/O ports at cf00 [size=128]
	[virtual] Expansion ROM at fc000000 [disabled] [size=128K]
	Capabilities: [60] Power Management version 3
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
		Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [68] MSI: Enable- Count=1/1 Maskable- 64bit+
		Address: 0000000000000000  Data: 0000
	Capabilities: [78] Express (v2) Endpoint, MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <256ns, L1 <4us
			ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd+ ExtTag+ PhantFunc- AuxPwr- NoSnoop+
			MaxPayload 128 bytes, MaxReadReq 512 bytes
		DevSta:	CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
		LnkCap:	Port #0, Speed 5GT/s, Width x16, ASPM L0s L1, Latency L0 <256ns, L1 <1us
			ClockPM- Surprise- LLActRep- BwNot-
		LnkCtl:	ASPM L0s L1 Enabled; RCB 128 bytes Disabled- Retrain- CommClk+
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x16, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
		DevCap2: Completion Timeout: Not Supported, TimeoutDis+
		DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-
		LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-, Selectable De-emphasis: -6dB
			 Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
			 Compliance De-emphasis: -6dB
		LnkSta2: Current De-emphasis Level: -6dB
	Capabilities: [100] Virtual Channel <?>
	Capabilities: [128] Power Budgeting <?>
	Capabilities: [600] Vendor Specific Information <?>
	Kernel driver in use: nvidia
	Kernel modules: nvidia

02:00.0 Network controller: Intel Corporation Wireless WiFi Link 5100
	Subsystem: Intel Corporation PRO/Wireless 5100AGN Network Connection
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Interrupt: pin A routed to IRQ 30
	Region 0: Memory at ff9fe000 (64-bit, non-prefetchable) [size=8K]
	Capabilities: [c8] Power Management version 3
		Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [d0] MSI: Enable+ Count=1/1 Maskable- 64bit+
		Address: 00000000fee0300c  Data: 41b9
	Capabilities: [e0] Express (v1) Endpoint, MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <512ns, L1 unlimited
			ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset+
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+ FLReset-
			MaxPayload 128 bytes, MaxReadReq 128 bytes
		DevSta:	CorrErr+ UncorrErr- FatalErr- UnsuppReq+ AuxPwr+ TransPend-
		LnkCap:	Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0 <128ns, L1 <32us
			ClockPM+ Surprise- LLActRep- BwNot-
		LnkCtl:	ASPM L0s L1 Enabled; RCB 64 bytes Disabled- Retrain- CommClk+
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
	Capabilities: [100] Advanced Error Reporting
		UESta:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UEMsk:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
		UESvrt:	DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
		CESta:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
		CEMsk:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
		AERCap:	First Error Pointer: 00, GenCap- CGenEn- ChkCap- ChkEn-
	Capabilities: [140] Device Serial Number 00-22-fa-ff-ff-3c-77-ae
	Kernel driver in use: iwlagn
	Kernel modules: iwlagn

06:0b.0 CardBus bridge: Ricoh Co Ltd RL5c476 II (rev ba)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 168
	Interrupt: pin A routed to IRQ 22
	Region 0: Memory at ff600000 (32-bit, non-prefetchable) [size=4K]
	Bus: primary=06, secondary=07, subordinate=0a, sec-latency=176
	Memory window 0: c0000000-c3fff000 (prefetchable)
	Memory window 1: c4000000-c7fff000
	I/O window 0: 00001000-000010ff
	I/O window 1: 00001400-000014ff
	BridgeCtl: Parity- SERR- ISA- VGA- MAbort- >Reset- 16bInt+ PostWrite+
	16-bit legacy interface ports at 0001
	Kernel driver in use: yenta_cardbus

06:0b.1 FireWire (IEEE 1394): Ricoh Co Ltd R5C832 IEEE 1394 Controller (rev 04) (prog-if 10 [OHCI])
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 64 (500ns min, 1000ns max), Cache Line Size: 32 bytes
	Interrupt: pin B routed to IRQ 23
	Region 0: Memory at ff6ff000 (32-bit, non-prefetchable) [size=2K]
	Capabilities: [dc] Power Management version 2
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=2 PME+
	Kernel driver in use: firewire_ohci

06:0b.2 SD Host controller: Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter (rev 21)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 64, Cache Line Size: 32 bytes
	Interrupt: pin C routed to IRQ 21
	Region 0: Memory at ff6fe000 (32-bit, non-prefetchable) [size=256]
	Capabilities: [80] Power Management version 2
		Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=2 PME-
	Kernel driver in use: sdhci-pci

06:0b.3 System peripheral: Ricoh Co Ltd R5C843 MMC Host Controller (rev ff) (prog-if ff)
	!!! Unknown header type 7f
	Kernel driver in use: ricoh-mmc

06:0b.4 System peripheral: Ricoh Co Ltd R5C592 Memory Stick Bus Host Adapter (rev 11)
	Subsystem: Toshiba America Info Systems Device 0001
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 64, Cache Line Size: 32 bytes
	Interrupt: pin C routed to IRQ 11
	Region 0: Memory at ff6fc000 (32-bit, non-prefetchable) [size=256]
	Capabilities: [80] Power Management version 2
		Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=2 PME-

06:0b.5 System peripheral: Ricoh Co Ltd xD-Picture Card Controller (rev 11)
	Subsystem: Toshiba America Info Systems Device 0001
	Physical Slot: 0
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 64, Cache Line Size: 32 bytes
	Interrupt: pin C routed to IRQ 11
	Region 0: Memory at ff6fb000 (32-bit, non-prefetchable) [size=256]
	Capabilities: [80] Power Management version 2
		Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
		Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=2 PME-


^ permalink raw reply

* Re: [PATCH] r8169: Fix rtl8169_rx_interrupt()
From: Sergey Senozhatsky @ 2010-03-18 13:31 UTC (permalink / raw)
  To: Francois Romieu; +Cc: Eric Dumazet, Oleg Nesterov, David Miller, netdev
In-Reply-To: <20100317235505.GA6674@electric-eye.fr.zoreil.com>

[-- Attachment #1: Type: text/plain, Size: 6635 bytes --]

Hello,
Patched r8169 (both Eric's and Francois' patches are applied). /*pktgen localhost2localhost*/

[  498.818640] pktgen 2.72: Packet Generator for packet performance testing.
[  568.999957] ------------[ cut here ]------------
[  568.999969] WARNING: at net/sched/sch_generic.c:255 dev_watchdog+0xc1/0x125()
[  568.999973] Hardware name: F3JC                
[  568.999976] NETDEV WATCHDOG: eth0 (r8169): transmit queue 0 timed out
[  568.999979] Modules linked in: pktgen snd_hwdep snd_hda_codec_si3054 snd_hda_codec_realtek asus_laptop sparse_keymap sdhci_pci sdhci snd_hda_intel mmc_core led_class
snd_hda_codec snd_pcm snd_timer psmouse snd soundcore snd_page_alloc sg evdev i2c_i801 rng_core serio_raw r8169 mii uhci_hcd sr_mod ehci_hcd cdrom sd_mod usbcore ata_piix
[  569.000029] Pid: 3350, comm: kpktgend_0 Tainted: G        W  2.6.34-rc1-dbg-git6-r8169 #48
[  569.000033] Call Trace:
[  569.000041]  [<c102e293>] warn_slowpath_common+0x65/0x7c
[  569.000046]  [<c126c024>] ? dev_watchdog+0xc1/0x125
[  569.000051]  [<c102e2de>] warn_slowpath_fmt+0x24/0x27
[  569.000056]  [<c126c024>] dev_watchdog+0xc1/0x125
[  569.000063]  [<c1036afb>] ? run_timer_softirq+0x120/0x1eb
[  569.000069]  [<c1036b51>] run_timer_softirq+0x176/0x1eb
[  569.000074]  [<c1036afb>] ? run_timer_softirq+0x120/0x1eb
[  569.000079]  [<c126bf63>] ? dev_watchdog+0x0/0x125
[  569.000084]  [<c1032d39>] __do_softirq+0x8d/0x117
[  569.000089]  [<c1032dee>] do_softirq+0x2b/0x43
[  569.000097]  [<f809510d>] ? pktgen_xmit+0xdb7/0xe8e [pktgen]
[  569.000102]  [<c1032e9c>] _local_bh_enable_ip+0x88/0xb0
[  569.000107]  [<c1032ecc>] local_bh_enable_ip+0x8/0xa
[  569.000114]  [<c12c83a0>] _raw_spin_unlock_bh+0x2f/0x32
[  569.000120]  [<f809510d>] pktgen_xmit+0xdb7/0xe8e [pktgen]
[  569.000129]  [<f91674a9>] ? rtl8169_start_xmit+0x0/0x304 [r8169]
[  569.000136]  [<c1183940>] ? trace_hardirqs_on_thunk+0xc/0x10
[  569.000143]  [<c105012d>] ? print_lock_contention_bug+0x11/0xb2
[  569.000150]  [<f80935ca>] ? spin_lock+0x8/0xa [pktgen]
[  569.000156]  [<f80954a8>] pktgen_thread_worker+0x18d/0x631 [pktgen]
[  569.000163]  [<c103f931>] ? autoremove_wake_function+0x0/0x2f
[  569.000169]  [<c103f931>] ? autoremove_wake_function+0x0/0x2f
[  569.000175]  [<f809531b>] ? pktgen_thread_worker+0x0/0x631 [pktgen]
[  569.000180]  [<c103f60e>] kthread+0x6a/0x6f
[  569.000185]  [<c103f5a4>] ? kthread+0x0/0x6f
[  569.000191]  [<c1002e42>] kernel_thread_helper+0x6/0x1a
[  569.000195] ---[ end trace a22d306b065d4a68 ]---



	Sergey



On (03/18/10 00:55), Francois Romieu wrote:
> > I suspect lot of work is needed on this driver to make it working, but I
> > dont have a machine with said adapter.
> 
> This one should help too if Sergey owns a (MSI) 8168.
> 
> diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
> index dfc3573..721e7f3 100644
> --- a/drivers/net/r8169.c
> +++ b/drivers/net/r8169.c
> @@ -4532,21 +4532,39 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
>  	return count;
>  }
>  
> +static void rtl_napi_cond_schedule(struct rtl8169_private *tp, u16 status)
> +{
> +	if (status & tp->napi_event) {
> +		void __iomem *ioaddr = tp->mmio_addr;
> +
> +		RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
> +		mmiowb();
> +		napi_schedule(&tp->napi);
> +	}
> +}
> +
>  static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>  {
>  	struct net_device *dev = dev_instance;
>  	struct rtl8169_private *tp = netdev_priv(dev);
>  	void __iomem *ioaddr = tp->mmio_addr;
>  	int handled = 0;
> -	int status;
> +	u16 status;
>  
>  	/* loop handling interrupts until we have no new ones or
>  	 * we hit a invalid/hotplug case.
>  	 */
>  	status = RTL_R16(IntrStatus);
>  	while (status && status != 0xffff) {
> +		u16 acked;
> +
>  		handled = 1;
>  
> +		acked = (status & RxFIFOOver) ? (status | RxOverflow) : status;
> +		acked &= ~tp->napi_event;
> +
> +		RTL_W16(IntrStatus, acked);
> +
>  		/* Handle all of the error cases first. These will reset
>  		 * the chip, so just exit the loop.
>  		 */
> @@ -4557,7 +4575,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>  
>  		/* Work around for rx fifo overflow */
>  		if (unlikely(status & RxFIFOOver) &&
> -		(tp->mac_version == RTL_GIGA_MAC_VER_11)) {
> +		    (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
>  			netif_stop_queue(dev);
>  			rtl8169_tx_timeout(dev);
>  			break;
> @@ -4571,30 +4589,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>  		if (status & LinkChg)
>  			rtl8169_check_link_status(dev, tp, ioaddr);
>  
> -		/* We need to see the lastest version of tp->intr_mask to
> -		 * avoid ignoring an MSI interrupt and having to wait for
> -		 * another event which may never come.
> -		 */
> -		smp_rmb();
> -		if (status & tp->intr_mask & tp->napi_event) {
> -			RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
> -			tp->intr_mask = ~tp->napi_event;
> -
> -			if (likely(napi_schedule_prep(&tp->napi)))
> -				__napi_schedule(&tp->napi);
> -			else
> -				netif_info(tp, intr, dev,
> -					   "interrupt %04x in poll\n", status);
> -		}
> +		rtl_napi_cond_schedule(tp, status);
>  
> -		/* We only get a new MSI interrupt when all active irq
> -		 * sources on the chip have been acknowledged. So, ack
> -		 * everything we've seen and check if new sources have become
> -		 * active to avoid blocking all interrupts from the chip.
> -		 */
> -		RTL_W16(IntrStatus,
> -			(status & RxFIFOOver) ? (status | RxOverflow) : status);
> -		status = RTL_R16(IntrStatus);
> +		break;
>  	}
>  
>  	return IRQ_RETVAL(handled);
> @@ -4607,22 +4604,19 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
>  	void __iomem *ioaddr = tp->mmio_addr;
>  	int work_done;
>  
> +
> +	RTL_W16(IntrStatus, tp->napi_event);
> +
>  	work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
>  	rtl8169_tx_interrupt(dev, tp, ioaddr);
>  
>  	if (work_done < budget) {
>  		napi_complete(napi);
>  
> -		/* We need for force the visibility of tp->intr_mask
> -		 * for other CPUs, as we can loose an MSI interrupt
> -		 * and potentially wait for a retransmit timeout if we don't.
> -		 * The posted write to IntrMask is safe, as it will
> -		 * eventually make it to the chip and we won't loose anything
> -		 * until it does.
> -		 */
> -		tp->intr_mask = 0xffff;
> -		smp_wmb();
>  		RTL_W16(IntrMask, tp->intr_event);
> +		mmiowb();
> +
> +		rtl_napi_cond_schedule(tp, RTL_R16(IntrStatus));
>  	}
>  
>  	return work_done;
> 

[-- Attachment #2: Type: application/pgp-signature, Size: 316 bytes --]

^ permalink raw reply

* Re: [PATCH 1/3] netlink: fix NETLINK_RECV_NO_ENOBUFS in netlink_set_err()
From: Patrick McHardy @ 2010-03-18 13:02 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netdev, davem
In-Reply-To: <4BA10095.2030905@netfilter.org>

Pablo Neira Ayuso wrote:
> Patrick McHardy wrote:
>> Pablo Neira Ayuso wrote:
>>> Currently, ENOBUFS errors are reported to the socket via
>>> netlink_set_err() even if NETLINK_RECV_NO_ENOBUFS is set. However,
>>> that should not happen. This fixes this problem and it changes the
>>> prototype of netlink_set_err() to return the number of sockets whose
>>> error has been set. This allows to know if any error has been set.
>>> This return value is used in the next patch in these bugfix series.
>> But that only happens if we have a message allocate error, which is
>> a different situation than rcvqueue overrun, which I thought the
>> original patch was supposed to handle (disable netlink congestion
>> control).
> 
> Yes, allocation is a different situation but we still report ENOBUFS to
> user-space. I think that NETLINK_RECV_NO_ENOBUFS is there to a) disable
> ENOBUFS reports to user-space and b) disable Netlink congestion.
> 
>> Is there any problem with these errors?
> 
> Specifically in ctnetlink, if we fail to allocate a message in ctnetlink
> and NETLINK_RECV_NO_ENOBUFS is set, we still lose an event and that
> should not happen.

I assume you mean "not set"? Otherwise I fail to follow :)


^ permalink raw reply

* Re: [PATCH] r8169: Fix rtl8169_rx_interrupt()
From: Sergey Senozhatsky @ 2010-03-18 12:32 UTC (permalink / raw)
  To: Francois Romieu; +Cc: Eric Dumazet, Oleg Nesterov, David Miller, netdev
In-Reply-To: <20100317235505.GA6674@electric-eye.fr.zoreil.com>

[-- Attachment #1: Type: text/plain, Size: 5145 bytes --]

Hello,

This hunk is rejected. I suppose I should apply patch against unpatched version (Eric's patch).
Correct? /* Eric's patch does make sense to my mind. */


@@ -4604,22 +4601,19 @@
        void __iomem *ioaddr = tp->mmio_addr;
        int work_done;
 
+
+       RTL_W16(IntrStatus, tp->napi_event);
+
        work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
        rtl8169_tx_interrupt(dev, tp, ioaddr);
 
        if (work_done < budget) {
                napi_complete(napi);
 
-               /* We need for force the visibility of tp->intr_mask
-                * for other CPUs, as we can loose an MSI interrupt
-                * and potentially wait for a retransmit timeout if we don't.
-                * The posted write to IntrMask is safe, as it will
-                * eventually make it to the chip and we won't loose anything
-                * until it does.
-                */
-               tp->intr_mask = 0xffff;
-               smp_wmb();
                RTL_W16(IntrMask, tp->intr_event);
+               mmiowb();
+
+               rtl_napi_cond_schedule(tp, RTL_R16(IntrStatus));
        }



	Sergey



On (03/18/10 00:55), Francois Romieu wrote:
> This one should help too if Sergey owns a (MSI) 8168.
> 
> diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
> index dfc3573..721e7f3 100644
> --- a/drivers/net/r8169.c
> +++ b/drivers/net/r8169.c
> @@ -4532,21 +4532,39 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
>  	return count;
>  }
>  
> +static void rtl_napi_cond_schedule(struct rtl8169_private *tp, u16 status)
> +{
> +	if (status & tp->napi_event) {
> +		void __iomem *ioaddr = tp->mmio_addr;
> +
> +		RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
> +		mmiowb();
> +		napi_schedule(&tp->napi);
> +	}
> +}
> +
>  static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>  {
>  	struct net_device *dev = dev_instance;
>  	struct rtl8169_private *tp = netdev_priv(dev);
>  	void __iomem *ioaddr = tp->mmio_addr;
>  	int handled = 0;
> -	int status;
> +	u16 status;
>  
>  	/* loop handling interrupts until we have no new ones or
>  	 * we hit a invalid/hotplug case.
>  	 */
>  	status = RTL_R16(IntrStatus);
>  	while (status && status != 0xffff) {
> +		u16 acked;
> +
>  		handled = 1;
>  
> +		acked = (status & RxFIFOOver) ? (status | RxOverflow) : status;
> +		acked &= ~tp->napi_event;
> +
> +		RTL_W16(IntrStatus, acked);
> +
>  		/* Handle all of the error cases first. These will reset
>  		 * the chip, so just exit the loop.
>  		 */
> @@ -4557,7 +4575,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>  
>  		/* Work around for rx fifo overflow */
>  		if (unlikely(status & RxFIFOOver) &&
> -		(tp->mac_version == RTL_GIGA_MAC_VER_11)) {
> +		    (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
>  			netif_stop_queue(dev);
>  			rtl8169_tx_timeout(dev);
>  			break;
> @@ -4571,30 +4589,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
>  		if (status & LinkChg)
>  			rtl8169_check_link_status(dev, tp, ioaddr);
>  
> -		/* We need to see the lastest version of tp->intr_mask to
> -		 * avoid ignoring an MSI interrupt and having to wait for
> -		 * another event which may never come.
> -		 */
> -		smp_rmb();
> -		if (status & tp->intr_mask & tp->napi_event) {
> -			RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
> -			tp->intr_mask = ~tp->napi_event;
> -
> -			if (likely(napi_schedule_prep(&tp->napi)))
> -				__napi_schedule(&tp->napi);
> -			else
> -				netif_info(tp, intr, dev,
> -					   "interrupt %04x in poll\n", status);
> -		}
> +		rtl_napi_cond_schedule(tp, status);
>  
> -		/* We only get a new MSI interrupt when all active irq
> -		 * sources on the chip have been acknowledged. So, ack
> -		 * everything we've seen and check if new sources have become
> -		 * active to avoid blocking all interrupts from the chip.
> -		 */
> -		RTL_W16(IntrStatus,
> -			(status & RxFIFOOver) ? (status | RxOverflow) : status);
> -		status = RTL_R16(IntrStatus);
> +		break;
>  	}
>  
>  	return IRQ_RETVAL(handled);
> @@ -4607,22 +4604,19 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
>  	void __iomem *ioaddr = tp->mmio_addr;
>  	int work_done;
>  
> +
> +	RTL_W16(IntrStatus, tp->napi_event);
> +
>  	work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
>  	rtl8169_tx_interrupt(dev, tp, ioaddr);
>  
>  	if (work_done < budget) {
>  		napi_complete(napi);
>  
> -		/* We need for force the visibility of tp->intr_mask
> -		 * for other CPUs, as we can loose an MSI interrupt
> -		 * and potentially wait for a retransmit timeout if we don't.
> -		 * The posted write to IntrMask is safe, as it will
> -		 * eventually make it to the chip and we won't loose anything
> -		 * until it does.
> -		 */
> -		tp->intr_mask = 0xffff;
> -		smp_wmb();
>  		RTL_W16(IntrMask, tp->intr_event);
> +		mmiowb();
> +
> +		rtl_napi_cond_schedule(tp, RTL_R16(IntrStatus));
>  	}
>  
>  	return work_done;
> 

[-- Attachment #2: Type: application/pgp-signature, Size: 316 bytes --]

^ permalink raw reply

* Re: [PATCH] r8169: Fix rtl8169_rx_interrupt()
From: Sergey Senozhatsky @ 2010-03-18 12:28 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Sergey Senozhatsky, Oleg Nesterov, David Miller, Francois Romieu,
	netdev
In-Reply-To: <1268834068.2899.336.camel@edumazet-laptop>

[-- Attachment #1: Type: text/plain, Size: 4276 bytes --]

Hello,

On (03/17/10 14:54), Eric Dumazet wrote:
> Le mercredi 17 mars 2010 à 12:58 +0200, Sergey Senozhatsky a écrit :
> > Hello,
> > 
> > We did pktgen over LAN testing for several hours:
> > 
> > iftop
> >                        19.1Mb                 38.1Mb                  57.2Mb                 76.3Mb            95.4Mb
> > └──────────────────────┴──────────────────────┴───────────────────────┴──────────────────────┴───────────────────────
> > xxxxxxxx0007t2                               => xxxxxxxxxxxxxx.xxxxx.xxxx.xxx                    0b   3.60Kb  4.28Kb
> >                                              <=                                               92.7Mb  92.7Mb  92.5Mb
> > 
> > ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
> > TX:             cumm:  2.50MB   peak:   57.7Kb                                       rates:   7.71Kb  5.97Kb  10.7Kb
> > RX:                    28.0GB           92.9Mb                                                92.7Mb  92.8Mb  92.6Mb
> > TOTAL:                 28.0GB           92.9Mb                                                92.7Mb  92.8Mb  92.6M
> > 
> > Without any problems.
> > 
> > 
> > As soon as I switched back to localhost "pollution":
> > 
> > [ 7343.999279] ------------[ cut here ]------------
> > [ 7343.999292] WARNING: at net/sched/sch_generic.c:255 dev_watchdog+0xc1/0x125()
> > [ 7343.999295] Hardware name: F3JC                
> > [ 7343.999298] NETDEV WATCHDOG: eth0 (r8169): transmit queue 0 timed out
> > [ 7343.999301] Modules linked in: pktgen ppp_async crc_ccitt ipv6 ppp_generic slhc snd_hwdep snd_hda_codec_si3054 snd_hda_codec_realtek sdhci_pci sdhci snd_hda_intel mmc_core
> > asus_laptop sparse_keymap snd_hda_codec led_class snd_pcm rng_core sg psmouse snd_timer snd_page_alloc i2c_i801 evdev snd soundcore serio_raw r8169 mii usbhid hid uhci_hcd
> > ehci_hcd sr_mod cdrom sd_mod usbcore ata_piix
> > [ 7343.999361] Pid: 4801, comm: kpktgend_0 Tainted: G        W  2.6.34-rc1-dbg-git6-r8169 #47
> > [ 7343.999364] Call Trace:
> > [ 7343.999372]  [<c102e293>] warn_slowpath_common+0x65/0x7c
> > [ 7343.999378]  [<c126ac34>] ? dev_watchdog+0xc1/0x125
> > [ 7343.999383]  [<c102e2de>] warn_slowpath_fmt+0x24/0x27
> > [ 7343.999388]  [<c126ac34>] dev_watchdog+0xc1/0x125
> > [ 7343.999395]  [<c1036afb>] ? run_timer_softirq+0x120/0x1eb
> > [ 7343.999401]  [<c1036b51>] run_timer_softirq+0x176/0x1eb
> > [ 7343.999406]  [<c1036afb>] ? run_timer_softirq+0x120/0x1eb
> > [ 7343.999411]  [<c126ab73>] ? dev_watchdog+0x0/0x125
> > [ 7343.999417]  [<c1032d39>] __do_softirq+0x8d/0x117
> > [ 7343.999422]  [<c1032dee>] do_softirq+0x2b/0x43
> > [ 7343.999426]  [<c1032f13>] irq_exit+0x38/0x75
> > [ 7343.999433]  [<c1014e75>] smp_apic_timer_interrupt+0x66/0x74
> > [ 7343.999438]  [<c12c770a>] apic_timer_interrupt+0x36/0x3c
> > [ 7343.999447]  [<f80878df>] ? pktgen_thread_worker+0x5c4/0x631 [pktgen]
> > [ 7343.999454]  [<c103f931>] ? autoremove_wake_function+0x0/0x2f
> > [ 7343.999459]  [<c103f931>] ? autoremove_wake_function+0x0/0x2f
> > [ 7343.999465]  [<f808731b>] ? pktgen_thread_worker+0x0/0x631 [pktgen]
> > [ 7343.999470]  [<c103f60e>] kthread+0x6a/0x6f
> > [ 7343.999476]  [<c103f5a4>] ? kthread+0x0/0x6f
> > [ 7343.999481]  [<c1002e42>] kernel_thread_helper+0x6/0x1a
> > [ 7343.999485] ---[ end trace a22d306b065d4a68 ]---
> > [ 7344.012654] r8169 0000:02:00.0: eth0: link up
> > [ 7356.012657] r8169 0000:02:00.0: eth0: link up
> > [ 7368.013545] r8169 0000:02:00.0: eth0: link up
> > 
> > 
> 
> What do you exactly mean by 'localhost pollution' ?
> 
Sorry. I mean pktgen started on localhost with src set to localhost (not pktgen over LAN from another machine).


	Sergey

[-- Attachment #2: Type: application/pgp-signature, Size: 316 bytes --]

^ permalink raw reply

* Re: [PATCH] ipv4: check rt_genid in dst_check
From: Herbert Xu @ 2010-03-18 12:11 UTC (permalink / raw)
  To: Timo Teras; +Cc: netdev
In-Reply-To: <1268912902-27050-1-git-send-email-timo.teras@iki.fi>

On Thu, Mar 18, 2010 at 01:48:22PM +0200, Timo Teras wrote:
> Xfrm_dst keeps a reference to ipv4 rtable entries on each
> cached bundle. The only we to renew xfrm_dst when the underlying
> route has changed, is to implement dst_check for this. This is
> what ipv6 side does too.
> 
> The problems started after 87c1e12b5eeb7b30b4b41291bef8e0b41fc3dde9
> which fixed a bug causing xfrm_dst to not get reused, until that all
> lookups always generated new xfrm_dst with new route reference
> and path mtu worked. But after the fix, the old routes started
> to get reused even after they were expired causing pmtu to break
> (well it would occationally work if the rtable gc has ran recently
> and marked the route obsolete causing dst_check to get called).
> 
> Signed-off-by: Timo Teras <timo.teras@iki.fi>

I completely agree with your assessment and patch.  The null
dst_check only worked when we purged IPv4 route cache entries
synchronously.  So this should've be done when asynchronous
deletion through genid was introduced.

> @@ -1726,7 +1726,9 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
>  
>  static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
>  {
> -	return NULL;
> +	if (dst && dst->dev && rt_is_expired((struct rtable *) dst))
> +		return NULL;
> +	return dst;
>  }

Can dst->dev ever be NULL? I'm pretty sure that we disallow that
from ever happening through the use of the loopback device.  A
quick grep also fails to find any other dst->dev NULL checks in
this file.

Otherwise

Acked-by: Herbert Xu <herbert@gondor.apana.org.au>

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* [PATCH] ipv4: check rt_genid in dst_check
From: Timo Teras @ 2010-03-18 11:48 UTC (permalink / raw)
  To: netdev; +Cc: Timo Teras, Herbert Xu

Xfrm_dst keeps a reference to ipv4 rtable entries on each
cached bundle. The only we to renew xfrm_dst when the underlying
route has changed, is to implement dst_check for this. This is
what ipv6 side does too.

The problems started after 87c1e12b5eeb7b30b4b41291bef8e0b41fc3dde9
which fixed a bug causing xfrm_dst to not get reused, until that all
lookups always generated new xfrm_dst with new route reference
and path mtu worked. But after the fix, the old routes started
to get reused even after they were expired causing pmtu to break
(well it would occationally work if the rtable gc has ran recently
and marked the route obsolete causing dst_check to get called).

Signed-off-by: Timo Teras <timo.teras@iki.fi>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
---
 net/ipv4/route.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index a770df2..59449a3 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1441,7 +1441,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
 					dev_hold(rt->u.dst.dev);
 				if (rt->idev)
 					in_dev_hold(rt->idev);
-				rt->u.dst.obsolete	= 0;
+				rt->u.dst.obsolete	= -1;
 				rt->u.dst.lastuse	= jiffies;
 				rt->u.dst.path		= &rt->u.dst;
 				rt->u.dst.neighbour	= NULL;
@@ -1506,7 +1506,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 	struct dst_entry *ret = dst;
 
 	if (rt) {
-		if (dst->obsolete) {
+		if (dst->obsolete > 0) {
 			ip_rt_put(rt);
 			ret = NULL;
 		} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
@@ -1726,7 +1726,9 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
 
 static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
 {
-	return NULL;
+	if (dst && dst->dev && rt_is_expired((struct rtable *) dst))
+		return NULL;
+	return dst;
 }
 
 static void ipv4_dst_destroy(struct dst_entry *dst)
@@ -1888,7 +1890,8 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	if (!rth)
 		goto e_nobufs;
 
-	rth->u.dst.output= ip_rt_bug;
+	rth->u.dst.output = ip_rt_bug;
+	rth->u.dst.obsolete = -1;
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
@@ -2054,6 +2057,7 @@ static int __mkroute_input(struct sk_buff *skb,
 	rth->fl.oif 	= 0;
 	rth->rt_spec_dst= spec_dst;
 
+	rth->u.dst.obsolete = -1;
 	rth->u.dst.input = ip_forward;
 	rth->u.dst.output = ip_output;
 	rth->rt_genid = rt_genid(dev_net(rth->u.dst.dev));
@@ -2218,6 +2222,7 @@ local_input:
 		goto e_nobufs;
 
 	rth->u.dst.output= ip_rt_bug;
+	rth->u.dst.obsolete = -1;
 	rth->rt_genid = rt_genid(net);
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
@@ -2444,6 +2449,7 @@ static int __mkroute_output(struct rtable **result,
 	rth->rt_spec_dst= fl->fl4_src;
 
 	rth->u.dst.output=ip_output;
+	rth->u.dst.obsolete = -1;
 	rth->rt_genid = rt_genid(dev_net(dev_out));
 
 	RT_CACHE_STAT_INC(out_slow_tot);
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH 12/12] l2tp: Update documentation
From: James Chapman @ 2010-03-18 10:22 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20100318102127.14576.98388.stgit@bert.katalix.com>

This patch adds documentation about the L2TPv3 functionality.

Signed-off-by: James Chapman <jchapman@katalix.com>
---
 Documentation/networking/l2tp.txt |  233 ++++++++++++++++++++++++++++++++-----
 1 files changed, 199 insertions(+), 34 deletions(-)

diff --git a/Documentation/networking/l2tp.txt b/Documentation/networking/l2tp.txt
index 63214b2..8b5a7b7 100644
--- a/Documentation/networking/l2tp.txt
+++ b/Documentation/networking/l2tp.txt
@@ -1,44 +1,95 @@
-This brief document describes how to use the kernel's PPPoL2TP driver
-to provide L2TP functionality. L2TP is a protocol that tunnels one or
-more PPP sessions over a UDP tunnel. It is commonly used for VPNs
+This document describes how to use the kernel's L2TP drivers to
+provide L2TP functionality. L2TP is a protocol that tunnels one or
+more sessions over an IP tunnel. It is commonly used for VPNs
 (L2TP/IPSec) and by ISPs to tunnel subscriber PPP sessions over an IP
-network infrastructure.
+network infrastructure. With L2TPv3, it is also useful as a Layer-2
+tunneling infrastructure.
+
+Features
+========
+
+L2TPv2 (PPP over L2TP (UDP tunnels)).
+L2TPv3 ethernet pseudowires.
+L2TPv3 PPP pseudowires.
+L2TPv3 IP encapsulation.
+Netlink sockets for L2TPv3 configuration management.
+
+History
+=======
+
+The original pppol2tp driver was introduced in 2.6.23 and provided
+L2TPv2 functionality (rfc2661). L2TPv2 is used to tunnel one or more PPP
+sessions over a UDP tunnel.
+
+L2TPv3 (rfc3931) changes the protocol to allow different frame types
+to be passed over an L2TP tunnel by moving the PPP-specific parts of
+the protocol out of the core L2TP packet headers. Each frame type is
+known as a pseudowire type. Ethernet, PPP, HDLC, Frame Relay and ATM
+pseudowires for L2TP are defined in separate RFC standards. Another
+change for L2TPv3 is that it can be carried directly over IP with no
+UDP header (UDP is optional). It is also possible to create static
+unmanaged L2TPv3 tunnels manually without a control protocol
+(userspace daemon) to manage them.
+
+To support L2TPv3, the original pppol2tp driver was split up to
+separate the L2TP and PPP functionality. Existing L2TPv2 userspace
+apps should be unaffected as the original pppol2tp sockets API is
+retained. L2TPv3, however, uses netlink to manage L2TPv3 tunnels and
+sessions.
 
 Design
 ======
 
-The PPPoL2TP driver, drivers/net/pppol2tp.c, provides a mechanism by
-which PPP frames carried through an L2TP session are passed through
-the kernel's PPP subsystem. The standard PPP daemon, pppd, handles all
-PPP interaction with the peer. PPP network interfaces are created for
-each local PPP endpoint.
-
-The L2TP protocol http://www.faqs.org/rfcs/rfc2661.html defines L2TP
-control and data frames. L2TP control frames carry messages between
-L2TP clients/servers and are used to setup / teardown tunnels and
-sessions. An L2TP client or server is implemented in userspace and
-will use a regular UDP socket per tunnel. L2TP data frames carry PPP
-frames, which may be PPP control or PPP data. The kernel's PPP
+The L2TP protocol separates control and data frames.  The L2TP kernel
+drivers handle only L2TP data frames; control frames are always
+handled by userspace. L2TP control frames carry messages between L2TP
+clients/servers and are used to setup / teardown tunnels and
+sessions. An L2TP client or server is implemented in userspace.
+
+Each L2TP tunnel is implemented using a UDP or L2TPIP socket; L2TPIP
+provides L2TPv3 IP encapsulation (no UDP) and is implemented using a
+new l2tpip socket family. The tunnel socket is typically created by
+userspace, though for unmanaged L2TPv3 tunnels, the socket can also be
+created by the kernel. Each L2TP session (pseudowire) gets a network
+interface instance. In the case of PPP, these interfaces are created
+indirectly by pppd using a pppol2tp socket. In the case of ethernet,
+the netdevice is created upon a netlink request to create an L2TPv3
+ethernet pseudowire.
+
+For PPP, the PPPoL2TP driver, net/l2tp/l2tp_ppp.c, provides a
+mechanism by which PPP frames carried through an L2TP session are
+passed through the kernel's PPP subsystem. The standard PPP daemon,
+pppd, handles all PPP interaction with the peer. PPP network
+interfaces are created for each local PPP endpoint. The kernel's PPP
 subsystem arranges for PPP control frames to be delivered to pppd,
 while data frames are forwarded as usual.
 
+For ethernet, the L2TPETH driver, net/l2tp/l2tp_eth.c, implements a
+netdevice driver, managing virtual ethernet devices, one per
+pseudowire. These interfaces can be managed using standard Linux tools
+such as "ip" and "ifconfig". If only IP frames are passed over the
+tunnel, the interface can be given an IP addresses of itself and its
+peer. If non-IP frames are to be passed over the tunnel, the interface
+can be added to a bridge using brctl. All L2TP datapath protocol
+functions are handled by the L2TP core driver.
+
 Each tunnel and session within a tunnel is assigned a unique tunnel_id
 and session_id. These ids are carried in the L2TP header of every
-control and data packet. The pppol2tp driver uses them to lookup
-internal tunnel and/or session contexts. Zero tunnel / session ids are
-treated specially - zero ids are never assigned to tunnels or sessions
-in the network. In the driver, the tunnel context keeps a pointer to
-the tunnel UDP socket. The session context keeps a pointer to the
-PPPoL2TP socket, as well as other data that lets the driver interface
-to the kernel PPP subsystem.
-
-Note that the pppol2tp kernel driver handles only L2TP data frames;
-L2TP control frames are simply passed up to userspace in the UDP
-tunnel socket. The kernel handles all datapath aspects of the
-protocol, including data packet resequencing (if enabled).
-
-There are a number of requirements on the userspace L2TP daemon in
-order to use the pppol2tp driver.
+control and data packet. (Actually, in L2TPv3, the tunnel_id isn't
+present in data frames - it is inferred from the IP connection on
+which the packet was received.) The L2TP driver uses the ids to lookup
+internal tunnel and/or session contexts to determine how to handle the
+packet. Zero tunnel / session ids are treated specially - zero ids are
+never assigned to tunnels or sessions in the network. In the driver,
+the tunnel context keeps a reference to the tunnel UDP or L2TPIP
+socket. The session context holds data that lets the driver interface
+to the kernel's network frame type subsystems, i.e. PPP, ethernet.
+
+Userspace Programming
+=====================
+
+For L2TPv2, there are a number of requirements on the userspace L2TP
+daemon in order to use the pppol2tp driver.
 
 1. Use a UDP socket per tunnel.
 
@@ -86,6 +137,35 @@ In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided
 to retrieve tunnel and session statistics from the kernel using the
 PPPoX socket of the appropriate tunnel or session.
 
+For L2TPv3, userspace must use the netlink API defined in
+include/linux/l2tp.h to manage tunnel and session contexts. The
+general procedure to create a new L2TP tunnel with one session is:-
+
+1. Open a GENL socket using L2TP_GENL_NAME for configuring the kernel
+   using netlink.
+
+2. Create a UDP or L2TPIP socket for the tunnel.
+
+3. Create a new L2TP tunnel using a L2TP_CMD_TUNNEL_CREATE
+   request. Set attributes according to desired tunnel parameters,
+   referencing the UDP or L2TPIP socket created in the previous step.
+
+4. Create a new L2TP session in the tunnel using a
+   L2TP_CMD_SESSION_CREATE request.
+
+The tunnel and all of its sessions are closed when the tunnel socket
+is closed. The netlink API may also be used to delete sessions and
+tunnels. Configuration and status info may be set or read using netlink.
+
+The L2TP driver also supports static (unmanaged) L2TPv3 tunnels. These
+are where there is no L2TP control message exchange with the peer to
+setup the tunnel; the tunnel is configured manually at each end of the
+tunnel. There is no need for an L2TP userspace application in this
+case -- the tunnel socket is created by the kernel and configured
+using parameters sent in the L2TP_CMD_TUNNEL_CREATE netlink
+request. The "ip" utility of iproute2 has commands for managing static
+L2TPv3 tunnels; do "ip l2tp help" for more information.
+
 Debugging
 =========
 
@@ -102,6 +182,55 @@ PPPOL2TP_MSG_CONTROL  userspace - kernel interface
 PPPOL2TP_MSG_SEQ      sequence numbers handling
 PPPOL2TP_MSG_DATA     data packets
 
+If enabled, /proc/net/l2tp can be used to dump kernel state about L2TP
+tunnels and sessions. However, this should not be used by applications
+to obtain L2TP state because the file format is subject to
+change. Instead, use the netlink API.
+
+Unmanaged L2TPv3 Tunnels
+========================
+
+Some commercial L2TP products support unmanaged L2TPv3 ethernet
+tunnels, where there is no L2TP control protocol; tunnels are
+configured at each side manually. New commands are available in
+iproute2's ip utility to support this.
+
+To create an L2TPv3 ethernet pseudowire between local host 192.168.1.1
+and peer 192.168.1.2, using IP addresses 10.5.1.1 and 10.5.1.2 for the
+tunnel endpoints:-
+
+# modprobe l2tp_eth
+# modprobe l2tp_netlink
+
+# ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 udp_sport 5000 \
+  udp_dport 5000 encap udp local 192.168.1.1 remote 192.168.1.2
+# ip l2tp add session tunnel_id 1 session_id 1 peer_session_id 1
+# ifconfig -a
+# ip addr add 10.5.1.2/32 peer 10.5.1.1/32 dev l2tpeth0
+# ifconfig l2tpeth0 up
+
+Choose IP addresses to be the address of a local IP interface and that
+of the remote system. The IP addresses of the l2tpeth0 interface can be
+anything suitable.
+
+Repeat the above at the peer, with ports, tunnel/session ids and IP
+addresses reversed.  The tunnel and session IDs can be any non-zero
+32-bit number, but the values must be reversed at the peer.
+
+Host 1                         Host2
+udp_sport=5000                 udp_sport=5001
+udp_dport=5001                 udp_dport=5000
+tunnel_id=42                   tunnel_id=45
+peer_tunnel_id=45              peer_tunnel_id=42
+session_id=128                 session_id=5196755
+peer_session_id=5196755        peer_session_id=128
+
+When done at both ends of the tunnel, it should be possible to send
+data over the network. e.g.
+
+# ping 10.5.1.1
+
+
 Sample Userspace Code
 =====================
 
@@ -158,12 +287,48 @@ Sample Userspace Code
         }
         return 0;
 
+Internal Implementation
+=======================
+
+The driver keeps a struct l2tp_tunnel context per L2TP tunnel and a
+struct l2tp_session context for each session. The l2tp_tunnel is
+always associated with a UDP or L2TP/IP socket and keeps a list of
+sessions in the tunnel. The l2tp_session context keeps kernel state
+about the session. It has private data which is used for data specific
+to the session type. With L2TPv2, the session always carried PPP
+traffic. With L2TPv3, the session can also carry ethernet frames
+(ethernet pseudowire) or other data types such as ATM, HDLC or Frame
+Relay.
+
+When a tunnel is first opened, the reference count on the socket is
+increased using sock_hold(). This ensures that the kernel socket
+cannot be removed while L2TP's data structures reference it.
+
+Some L2TP sessions also have a socket (PPP pseudowires) while others
+do not (ethernet pseudowires). We can't use the socket reference count
+as the reference count for session contexts. The L2TP implementation
+therefore has its own internal reference counts on the session
+contexts.
+
+To Do
+=====
+
+Add L2TP tunnel switching support. This would route tunneled traffic
+from one L2TP tunnel into another. Specified in
+http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08
+
+Add L2TPv3 VLAN pseudowire support.
+
+Add L2TPv3 IP pseudowire support.
+
+Add L2TPv3 ATM pseudowire support.
+
 Miscellaneous
-============
+=============
 
-The PPPoL2TP driver was developed as part of the OpenL2TP project by
+The L2TP drivers were developed as part of the OpenL2TP project by
 Katalix Systems Ltd. OpenL2TP is a full-featured L2TP client / server,
 designed from the ground up to have the L2TP datapath in the
 kernel. The project also implemented the pppol2tp plugin for pppd
 which allows pppd to use the kernel driver. Details can be found at
-http://openl2tp.sourceforge.net.
+http://www.openl2tp.org.


^ permalink raw reply related

* [PATCH 11/12] l2tp: Add support for static unmanaged L2TPv3 tunnels
From: James Chapman @ 2010-03-18 10:22 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20100318102127.14576.98388.stgit@bert.katalix.com>

This patch adds support for static (unmanaged) L2TPv3 tunnels, where
the tunnel socket is created by the kernel rather than being created
by userspace. This means L2TP tunnels and sessions can be created
manually, without needing an L2TP control protocol implemented in
userspace. This might be useful where the user wants a simple ethernet
over IP tunnel.

A patch to iproute2 adds a new command set under "ip l2tp" to make use
of this feature. This will be submitted separately.

Signed-off-by: James Chapman <jchapman@katalix.com>
---
 net/l2tp/l2tp_core.c    |  111 +++++++++++++++++++++++++++++++++++++++++++----
 net/l2tp/l2tp_core.h    |    7 +++
 net/l2tp/l2tp_netlink.c |   18 ++++++--
 3 files changed, 122 insertions(+), 14 deletions(-)

diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index c08c859..1431b39 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1259,6 +1259,78 @@ void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
 }
 EXPORT_SYMBOL_GPL(l2tp_tunnel_free);
 
+/* Create a socket for the tunnel, if one isn't set up by
+ * userspace. This is used for static tunnels where there is no
+ * managing L2TP daemon.
+ */
+static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct socket **sockp)
+{
+	int err = -EINVAL;
+	struct sockaddr_in udp_addr;
+	struct sockaddr_l2tpip ip_addr;
+	struct socket *sock;
+
+	switch (cfg->encap) {
+	case L2TP_ENCAPTYPE_UDP:
+		err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp);
+		if (err < 0)
+			goto out;
+
+		sock = *sockp;
+
+		memset(&udp_addr, 0, sizeof(udp_addr));
+		udp_addr.sin_family = AF_INET;
+		udp_addr.sin_addr = cfg->local_ip;
+		udp_addr.sin_port = htons(cfg->local_udp_port);
+		err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
+		if (err < 0)
+			goto out;
+
+		udp_addr.sin_family = AF_INET;
+		udp_addr.sin_addr = cfg->peer_ip;
+		udp_addr.sin_port = htons(cfg->peer_udp_port);
+		err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0);
+		if (err < 0)
+			goto out;
+
+		break;
+	case L2TP_ENCAPTYPE_IP:
+		err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp);
+		if (err < 0)
+			goto out;
+
+		sock = *sockp;
+
+		memset(&ip_addr, 0, sizeof(ip_addr));
+		ip_addr.l2tp_family = AF_INET;
+		ip_addr.l2tp_addr = cfg->local_ip;
+		ip_addr.l2tp_conn_id = tunnel_id;
+		err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr));
+		if (err < 0)
+			goto out;
+
+		ip_addr.l2tp_family = AF_INET;
+		ip_addr.l2tp_addr = cfg->peer_ip;
+		ip_addr.l2tp_conn_id = peer_tunnel_id;
+		err = kernel_connect(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr), 0);
+		if (err < 0)
+			goto out;
+
+		break;
+
+	default:
+		goto out;
+	}
+
+out:
+	if ((err < 0) && sock) {
+		sock_release(sock);
+		*sockp = NULL;
+	}
+
+	return err;
+}
+
 int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
 {
 	struct l2tp_tunnel *tunnel = NULL;
@@ -1269,14 +1341,21 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
 	enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP;
 
 	/* Get the tunnel socket from the fd, which was opened by
-	 * the userspace L2TP daemon.
+	 * the userspace L2TP daemon. If not specified, create a
+	 * kernel socket.
 	 */
-	err = -EBADF;
-	sock = sockfd_lookup(fd, &err);
-	if (!sock) {
-		printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
-		       tunnel_id, fd, err);
-		goto err;
+	if (fd < 0) {
+		err = l2tp_tunnel_sock_create(tunnel_id, peer_tunnel_id, cfg, &sock);
+		if (err < 0)
+			goto err;
+	} else {
+		err = -EBADF;
+		sock = sockfd_lookup(fd, &err);
+		if (!sock) {
+			printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
+			       tunnel_id, fd, err);
+			goto err;
+		}
 	}
 
 	sk = sock->sk;
@@ -1369,7 +1448,10 @@ err:
 	if (tunnelp)
 		*tunnelp = tunnel;
 
-	if (sock)
+	/* If tunnel's socket was created by the kernel, it doesn't
+	 *  have a file.
+	 */
+	if (sock && sock->file)
 		sockfd_put(sock);
 
 	return err;
@@ -1381,13 +1463,22 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
 int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
 {
 	int err = 0;
+	struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL;
 
 	/* Force the tunnel socket to close. This will eventually
 	 * cause the tunnel to be deleted via the normal socket close
 	 * mechanisms when userspace closes the tunnel socket.
 	 */
-	if ((tunnel->sock != NULL) && (tunnel->sock->sk_socket != NULL))
-		err = inet_shutdown(tunnel->sock->sk_socket, 2);
+	if (sock != NULL) {
+		err = inet_shutdown(sock, 2);
+
+		/* If the tunnel's socket was created by the kernel,
+		 * close the socket here since the socket was not
+		 * created by userspace.
+		 */
+		if (sock->file == NULL)
+			err = inet_release(sock);
+	}
 
 	return err;
 }
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index c5f2cc9..7e3387b 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -146,6 +146,13 @@ struct l2tp_tunnel_cfg {
 	int			debug;		/* bitmask of debug message
 						 * categories */
 	enum l2tp_encap_type	encap;
+
+	/* Used only for kernel-created sockets */
+	struct in_addr		local_ip;
+	struct in_addr		peer_ip;
+	u16			local_udp_port;
+	u16			peer_udp_port;
+	int			use_udp_checksums:1;
 };
 
 struct l2tp_tunnel {
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index e051c13..115ea01 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -129,11 +129,21 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info
 	}
 	cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);
 
-	if (!info->attrs[L2TP_ATTR_FD]) {
-		ret = -EINVAL;
-		goto out;
+	fd = -1;
+	if (info->attrs[L2TP_ATTR_FD]) {
+		fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
+	} else {
+		if (info->attrs[L2TP_ATTR_IP_SADDR])
+			cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]);
+		if (info->attrs[L2TP_ATTR_IP_DADDR])
+			cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]);
+		if (info->attrs[L2TP_ATTR_UDP_SPORT])
+			cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);
+		if (info->attrs[L2TP_ATTR_UDP_DPORT])
+			cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
+		if (info->attrs[L2TP_ATTR_UDP_CSUM])
+			cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]);
 	}
-	fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
 
 	if (info->attrs[L2TP_ATTR_DEBUG])
 		cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox