Netdev List
 help / color / mirror / Atom feed
* [PATCH 1/1] myri10ge: Add support for PCI device id 9
From: Brice Goglin @ 2007-09-13 22:40 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev
In-Reply-To: <46E9BC1A.5020105@myri.com>

Add support for new Myri-10G boards with PCI device id 9.

Signed-off-by: Brice Goglin <brice@myri.com>
---
 drivers/net/myri10ge/myri10ge.c |    3 +++
 1 file changed, 3 insertions(+)

Index: linux-rc/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-rc.orig/drivers/net/myri10ge/myri10ge.c	2007-09-11 20:27:17.000000000 +0200
+++ linux-rc/drivers/net/myri10ge/myri10ge.c	2007-09-14 00:36:36.000000000 +0200
@@ -3094,9 +3094,12 @@
 }
 
 #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 	0x0008
+#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9	0x0009
 
 static struct pci_device_id myri10ge_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
+	{PCI_DEVICE
+	 (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)},
 	{0},
 };
 



^ permalink raw reply

* Re: [ofa-general] InfiniBand/RDMA merge plans for 2.6.24
From: Michael Chan @ 2007-09-13 22:59 UTC (permalink / raw)
  To: Roland Dreier; +Cc: general, netdev, linux-kernel, anilgv, uri
In-Reply-To: <adaps0ml18e.fsf@cisco.com>

On Thu, 2007-09-13 at 14:11 -0700, Roland Dreier wrote:

> 
> I've been meaning to track down the bnx2 iscsi offload patch to look
> and see if this issue is addressed, since the same problem seems to
> exist: it seems an iscsi connection and a main stack tcp connection
> might share the same 4-tuple unless something is done to avoid that
> happening.
> 

iSCSI does not do passive listens, only active connections to the
target.  But you're right, the port space is still shared between iSCSI
and the main stack.  We currently rely on user apps binding to the main
stack to reserve certain ephemeral ports, and telling the iSCSI driver
which ports to use.

^ permalink raw reply

* [PATCH] Add IP1000A Driver into Kernel (2007/09/12)
From: Jesse Huang @ 2007-09-14 13:02 UTC (permalink / raw)
  To: "Jeff Garzik [jeff", akpm, netdev, romieu, shemminger,
	jesse


From: Jesse Huang <jesse@icplus.com.tw>

Change Logs: Add IP1000A Driver to kernel tree.

Signed-off-by: Jesse Huang <jesse@icplus.com.tw>
---

 MAINTAINERS       |   10 
 drivers/net/ipg.c | 2329 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ipg.h |  856 +++++++++++++++++++
 3 files changed, 3195 insertions(+), 0 deletions(-)
 create mode 100755 drivers/net/ipg.c
 create mode 100755 drivers/net/ipg.h

339cdb53f4106d822dcda34b12bd10f0ba965de1
diff --git a/MAINTAINERS b/MAINTAINERS
index df40a4e..a1ff6fe 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1988,6 +1988,16 @@ P:	Juanjo Ciarlante
 M:	jjciarla@raiz.uncu.edu.ar
 S:	Maintained
 
+IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER
+P:	Francois Romieu
+M:	romieu@fr.zoreil.com
+P:	Sorbica Shieh 
+M:	sorbica@icplus.com.tw
+P:	Jesse Huang
+M:	jesse@icplus.com.tw
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 IPATH DRIVER:
 P:	Bryan O'Sullivan
 M:	support@pathscale.com
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
new file mode 100755
index 0000000..e7a23e5
--- /dev/null
+++ b/drivers/net/ipg.c
@@ -0,0 +1,2329 @@
+/*
+ * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter
+ *
+ * Copyright (C) 2003, 2006  IC Plus Corp.
+ *
+ * Original Author:
+ *
+ *   Craig Rich
+ *   Sundance Technology, Inc.
+ *   www.sundanceti.com
+ *   craig_rich@sundanceti.com
+ *
+ * Current Maintainer:
+ *
+ *   Sorbica Shieh.
+ *   http://www.icplus.com.tw
+ *   sorbica@icplus.com.tw
+ *   
+ *   Jesse Huang
+ *   http://www.icplus.com.tw
+ *   jesse@icplus.com.tw
+ */
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/mutex.h>
+
+#define IPG_RX_RING_BYTES	(sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH)
+#define IPG_TX_RING_BYTES	(sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH)
+#define IPG_RESET_MASK \
+	(IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \
+	 IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
+	 IPG_AC_AUTO_INIT)
+
+#define ipg_w32(val32,reg)	iowrite32((val32), ioaddr + (reg))
+#define ipg_w16(val16,reg)	iowrite16((val16), ioaddr + (reg))
+#define ipg_w8(val8,reg)	iowrite8((val8), ioaddr + (reg))
+
+#define ipg_r32(reg)		ioread32(ioaddr + (reg))
+#define ipg_r16(reg)		ioread16(ioaddr + (reg))
+#define ipg_r8(reg)		ioread8(ioaddr + (reg))
+
+#define JUMBO_FRAME_4k_ONLY
+enum {
+	netdev_io_size = 128
+};
+
+#include "ipg.h"
+#define DRV_NAME	"ipg"
+
+MODULE_AUTHOR("IC Plus Corp. 2003");
+MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver "
+		   DrvVer);
+MODULE_LICENSE("GPL");
+
+static const char *ipg_brand_name[] = {
+	"IC PLUS IP1000 1000/100/10 based NIC",
+	"Sundance Technology ST2021 based NIC",
+	"Tamarack Microelectronics TC9020/9021 based NIC",
+	"Tamarack Microelectronics TC9020/9021 based NIC",
+	"D-Link NIC",
+	"D-Link NIC IP1000A"
+};
+
+static struct pci_device_id ipg_pci_tbl[] __devinitdata = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SUNDANCE,	0x1023), 0, 0, 0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SUNDANCE,	0x2021), 0, 0, 1 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SUNDANCE,	0x1021), 0, 0, 2 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK,	0x9021), 0, 0, 3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK,	0x4000), 0, 0, 4 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK,	0x4020), 0, 0, 5 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ipg_pci_tbl);
+
+static inline void __iomem *ipg_ioaddr(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	return sp->ioaddr;
+}
+
+#ifdef IPG_DEBUG
+static void ipg_dump_rfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+	u32 offset;
+
+	IPG_DEBUG_MSG("_dump_rfdlist\n");
+
+	printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current);
+	printk(KERN_INFO "rx_dirty   = %2.2x\n", sp->rx_dirty);
+	printk(KERN_INFO "RFDList start address = %16.16lx\n",
+	       (unsigned long) sp->rxd_map);
+	printk(KERN_INFO "RFDListPtr register   = %8.8x%8.8x\n",
+	       ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
+
+	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+		offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
+		printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i,
+		       offset, (unsigned long) sp->rxd[i].next_desc);
+		offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
+		printk(KERN_INFO "%2.2x %4.4x RFS        = %16.16lx\n", i,
+		       offset, (unsigned long) sp->rxd[i].rfs);
+		offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
+		printk(KERN_INFO "%2.2x %4.4x frag_info   = %16.16lx\n", i,
+		       offset, (unsigned long) sp->rxd[i].frag_info);
+	}
+}
+
+static void ipg_dump_tfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+	u32 offset;
+
+	IPG_DEBUG_MSG("_dump_tfdlist\n");
+
+	printk(KERN_INFO "tx_current         = %2.2x\n", sp->tx_current);
+	printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
+	printk(KERN_INFO "TFDList start address = %16.16lx\n",
+	       (unsigned long) sp->txd_map);
+	printk(KERN_INFO "TFDListPtr register   = %8.8x%8.8x\n",
+	       ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].next_desc);
+
+		offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x TFC        = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].tfc);
+		offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x frag_info   = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].frag_info);
+	}
+}
+#endif
+
+static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data)
+{
+	ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL);
+	ndelay(IPG_PC_PHYCTRLWAIT_NS);
+}
+
+static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data)
+{
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data);
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data);
+}
+
+static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+	phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR;
+
+	ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity);
+}
+
+static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+	ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR |
+		phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
+}
+
+static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity)
+{
+	u16 bit_data;
+
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity);
+
+	bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1;
+
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity);
+
+	return bit_data;
+}
+
+/*
+ * Read a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static int mdio_read(struct net_device * dev, int phy_id, int phy_reg)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	/*
+	 * The GMII mangement frame structure for a read is as follows:
+	 *
+	 * |Preamble|st|op|phyad|regad|ta|      data      |idle|
+	 * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
+	 *
+	 * <32 1s> = 32 consecutive logic 1 values
+	 * A = bit of Physical Layer device address (MSB first)
+	 * R = bit of register address (MSB first)
+	 * z = High impedance state
+	 * D = bit of read data (MSB first)
+	 *
+	 * Transmission order is 'Preamble' field first, bits transmitted
+	 * left to right (first to last).
+	 */
+	struct {
+		u32 field;
+		unsigned int len;
+	} p[] = {
+		{ GMII_PREAMBLE,	32 },	/* Preamble */
+		{ GMII_ST,		2  },	/* ST */
+		{ GMII_READ,		2  },	/* OP */
+		{ phy_id,		5  },	/* PHYAD */
+		{ phy_reg,		5  },	/* REGAD */
+		{ 0x0000,		2  },	/* TA */
+		{ 0x0000,		16 },	/* DATA */
+		{ 0x0000,		1  }	/* IDLE */
+	};
+	unsigned int i, j;
+	u8 polarity, data;
+
+	polarity  = ipg_r8(PHY_CTRL);
+	polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+	/* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+	for (j = 0; j < 5; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			/* For each variable length field, the MSB must be
+			 * transmitted first. Rotate through the field bits,
+			 * starting with the MSB, and move each bit into the
+			 * the 1st (2^1) bit position (this is the bit position
+			 * corresponding to the MgmtData bit of the PhyCtrl
+			 * register for the IPG).
+			 *
+			 * Example: ST = 01;
+			 *
+			 *          First write a '0' to bit 1 of the PhyCtrl
+			 *          register, then write a '1' to bit 1 of the
+			 *          PhyCtrl register.
+			 *
+			 * To do this, right shift the MSB of ST by the value:
+			 * [field length - 1 - #ST bits already written]
+			 * then left shift this result by 1.
+			 */
+			data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
+			data &= IPG_PC_MGMTDATA;
+			data |= polarity | IPG_PC_MGMTDIR;
+
+			ipg_drive_phy_ctl_low_high(ioaddr, data);
+		}
+	}
+
+	send_three_state(ioaddr, polarity);
+
+	read_phy_bit(ioaddr, polarity);
+
+	/*
+	 * For a read cycle, the bits for the next two fields (TA and
+	 * DATA) are driven by the PHY (the IPG reads these bits).
+	 */
+	for (i = 0; i < p[6].len; i++) {
+		p[6].field |=
+		    (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
+	}
+
+	send_three_state(ioaddr, polarity);
+	send_three_state(ioaddr, polarity);
+	send_three_state(ioaddr, polarity);
+	send_end(ioaddr, polarity);
+
+	/* Return the value of the DATA field. */
+	return p[6].field;
+}
+
+/*
+ * Write to a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	/*
+	 * The GMII mangement frame structure for a read is as follows:
+	 *
+	 * |Preamble|st|op|phyad|regad|ta|      data      |idle|
+	 * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
+	 *
+	 * <32 1s> = 32 consecutive logic 1 values
+	 * A = bit of Physical Layer device address (MSB first)
+	 * R = bit of register address (MSB first)
+	 * z = High impedance state
+	 * D = bit of write data (MSB first)
+	 *
+	 * Transmission order is 'Preamble' field first, bits transmitted
+	 * left to right (first to last).
+	 */
+	struct {
+		u32 field;
+		unsigned int len;
+	} p[] = {
+		{ GMII_PREAMBLE,	32 },	/* Preamble */
+		{ GMII_ST,		2  },	/* ST */
+		{ GMII_WRITE,		2  },	/* OP */
+		{ phy_id,		5  },	/* PHYAD */
+		{ phy_reg,		5  },	/* REGAD */
+		{ 0x0002,		2  },	/* TA */
+		{ val & 0xffff,		16 },	/* DATA */
+		{ 0x0000,		1  }	/* IDLE */
+	};
+	unsigned int i, j;
+	u8 polarity, data;
+
+	polarity  = ipg_r8(PHY_CTRL);
+	polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+	/* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+	for (j = 0; j < 7; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			/* For each variable length field, the MSB must be
+			 * transmitted first. Rotate through the field bits,
+			 * starting with the MSB, and move each bit into the
+			 * the 1st (2^1) bit position (this is the bit position
+			 * corresponding to the MgmtData bit of the PhyCtrl
+			 * register for the IPG).
+			 *
+			 * Example: ST = 01;
+			 *
+			 *          First write a '0' to bit 1 of the PhyCtrl
+			 *          register, then write a '1' to bit 1 of the
+			 *          PhyCtrl register.
+			 *
+			 * To do this, right shift the MSB of ST by the value:
+			 * [field length - 1 - #ST bits already written]
+			 * then left shift this result by 1.
+			 */
+			data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
+			data &= IPG_PC_MGMTDATA;
+			data |= polarity | IPG_PC_MGMTDIR;
+
+			ipg_drive_phy_ctl_low_high(ioaddr, data);
+		}
+	}
+
+	/* The last cycle is a tri-state, so read from the PHY. */
+	for (j = 7; j < 8; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
+
+			p[j].field |= ((ipg_r8(PHY_CTRL) &
+				IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i);
+
+			ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
+		}
+	}
+}
+
+/* Set LED_Mode JES20040127EEPROM */
+static void ipg_set_led_mode(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	u32 mode;
+
+	mode = ipg_r32(ASIC_CTRL);
+	mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
+
+	if ((sp->LED_Mode & 0x03) > 1)
+		mode |= IPG_AC_LED_MODE_BIT_1;	/* Write Asic Control Bit 29 */
+
+	if ((sp->LED_Mode & 0x01) == 1)
+		mode |= IPG_AC_LED_MODE;	/* Write Asic Control Bit 14 */
+
+	if ((sp->LED_Mode & 0x08) == 8)
+		mode |= IPG_AC_LED_SPEED;	/* Write Asic Control Bit 27 */
+
+	ipg_w32(mode, ASIC_CTRL);
+}
+
+/* Set PHYSet JES20040127EEPROM */
+static void ipg_set_phy_set(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	int physet;
+
+	physet = ipg_r8(PHY_SET);
+	physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET);
+	physet |= ((sp->LED_Mode & 0x70) >> 4);
+	ipg_w8(physet, PHY_SET);
+}
+
+static int ipg_reset(struct net_device *dev, u32 resetflags)
+{
+	/* Assert functional resets via the IPG AsicCtrl
+	 * register as specified by the 'resetflags' input
+	 * parameter.
+	 */
+	void __iomem *ioaddr = ipg_ioaddr(dev);	//JES20040127EEPROM:
+	unsigned int timeout_count = 0;
+
+	IPG_DEBUG_MSG("_reset\n");
+
+	ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
+
+	/* Delay added to account for problem with 10Mbps reset. */
+	mdelay(IPG_AC_RESETWAIT);
+
+	while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
+		mdelay(IPG_AC_RESETWAIT);
+		if (++timeout_count > IPG_AC_RESET_TIMEOUT)
+			return -ETIME;
+	}
+	/* Set LED Mode in Asic Control JES20040127EEPROM */
+	ipg_set_led_mode(dev);
+
+	/* Set PHYSet Register Value JES20040127EEPROM */
+	ipg_set_phy_set(dev);
+	return 0;
+}
+
+/* Find the GMII PHY address. */
+static int ipg_find_phyaddr(struct net_device *dev)
+{
+	unsigned int phyaddr, i;
+
+	for (i = 0; i < 32; i++) {
+		u32 status;
+
+		/* Search for the correct PHY address among 32 possible. */
+		phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32;
+
+		/* 10/22/03 Grace change verify from GMII_PHY_STATUS to
+		   GMII_PHY_ID1
+		 */
+
+		status = mdio_read(dev, phyaddr, MII_BMSR);
+
+		if ((status != 0xFFFF) && (status != 0))
+			return phyaddr;
+	}
+
+	return 0x1f;
+}
+
+/*
+ * Configure IPG based on result of IEEE 802.3 PHY
+ * auto-negotiation.
+ */
+static int ipg_config_autoneg(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int txflowcontrol;
+	unsigned int rxflowcontrol;
+	unsigned int fullduplex;
+	unsigned int gig;
+	u32 mac_ctrl_val;
+	u32 asicctrl;
+	u8 phyctrl;
+
+	IPG_DEBUG_MSG("_config_autoneg\n");
+
+	asicctrl = ipg_r32(ASIC_CTRL);
+	phyctrl = ipg_r8(PHY_CTRL);
+	mac_ctrl_val = ipg_r32(MAC_CTRL);
+
+	/* Set flags for use in resolving auto-negotation, assuming
+	 * non-1000Mbps, half duplex, no flow control.
+	 */
+	fullduplex = 0;
+	txflowcontrol = 0;
+	rxflowcontrol = 0;
+	gig = 0;
+
+	/* To accomodate a problem in 10Mbps operation,
+	 * set a global flag if PHY running in 10Mbps mode.
+	 */
+	sp->tenmbpsmode = 0;
+
+	printk(KERN_INFO "%s: Link speed = ", dev->name);
+
+	/* Determine actual speed of operation. */
+	switch (phyctrl & IPG_PC_LINK_SPEED) {
+	case IPG_PC_LINK_SPEED_10MBPS:
+		printk("10Mbps.\n");
+		printk(KERN_INFO "%s: 10Mbps operational mode enabled.\n",
+		       dev->name);
+		sp->tenmbpsmode = 1;
+		break;
+	case IPG_PC_LINK_SPEED_100MBPS:
+		printk("100Mbps.\n");
+		break;
+	case IPG_PC_LINK_SPEED_1000MBPS:
+		printk("1000Mbps.\n");
+		gig = 1;
+		break;
+	default:
+		printk("undefined!\n");
+		return 0;
+	}
+
+	if (phyctrl & IPG_PC_DUPLEX_STATUS) {
+		fullduplex = 1;
+		txflowcontrol = 1;
+		rxflowcontrol = 1;
+	}
+
+	/* Configure full duplex, and flow control. */
+	if (fullduplex == 1) {
+		/* Configure IPG for full duplex operation. */
+		printk(KERN_INFO "%s: setting full duplex, ", dev->name);
+
+		mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD;
+
+		if (txflowcontrol == 1) {
+			printk("TX flow control");
+			mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE;
+		} else {
+			printk("no TX flow control");
+			mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE;
+		}
+
+		if (rxflowcontrol == 1) {
+			printk(", RX flow control.");
+			mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE;
+		} else {
+			printk(", no RX flow control.");
+			mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+		}
+
+		printk("\n");
+	} else {
+		/* Configure IPG for half duplex operation. */
+	        printk(KERN_INFO "%s: setting half duplex, "
+		       "no TX flow control, no RX flow control.\n", dev->name);
+
+		mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD &
+			~IPG_MC_TX_FLOW_CONTROL_ENABLE &
+			~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+	}
+	ipg_w32(mac_ctrl_val, MAC_CTRL);
+	return 0;
+}
+
+/* Determine and configure multicast operation and set
+ * receive mode for IPG.
+ */
+static void ipg_nic_set_multicast_list(struct net_device *dev)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	struct dev_mc_list *mc_list_ptr;
+	unsigned int hashindex;
+	u32 hashtable[2];
+	u8 receivemode;
+
+	IPG_DEBUG_MSG("_nic_set_multicast_list\n");
+
+	receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* NIC to be configured in promiscuous mode. */
+		receivemode = IPG_RM_RECEIVEALLFRAMES;
+	} else if ((dev->flags & IFF_ALLMULTI) ||
+		   (dev->flags & IFF_MULTICAST &
+		    (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) {
+		/* NIC to be configured to receive all multicast
+		 * frames. */
+		receivemode |= IPG_RM_RECEIVEMULTICAST;
+	} else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) {
+		/* NIC to be configured to receive selected
+		 * multicast addresses. */
+		receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
+	}
+
+	/* Calculate the bits to set for the 64 bit, IPG HASHTABLE.
+	 * The IPG applies a cyclic-redundancy-check (the same CRC
+	 * used to calculate the frame data FCS) to the destination
+	 * address all incoming multicast frames whose destination
+	 * address has the multicast bit set. The least significant
+	 * 6 bits of the CRC result are used as an addressing index
+	 * into the hash table. If the value of the bit addressed by
+	 * this index is a 1, the frame is passed to the host system.
+	 */
+
+	/* Clear hashtable. */
+	hashtable[0] = 0x00000000;
+	hashtable[1] = 0x00000000;
+
+	/* Cycle through all multicast addresses to filter. */
+	for (mc_list_ptr = dev->mc_list;
+	     mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) {
+		/* Calculate CRC result for each multicast address. */
+		hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr,
+				     ETH_ALEN);
+
+		/* Use only the least significant 6 bits. */
+		hashindex = hashindex & 0x3F;
+
+		/* Within "hashtable", set bit number "hashindex"
+		 * to a logic 1.
+		 */
+		set_bit(hashindex, (void *)hashtable);
+	}
+
+	/* Write the value of the hashtable, to the 4, 16 bit
+	 * HASHTABLE IPG registers.
+	 */
+	ipg_w32(hashtable[0], HASHTABLE_0);
+	ipg_w32(hashtable[1], HASHTABLE_1);
+
+	ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE);
+
+	IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE));
+}
+
+static int ipg_io_config(struct net_device *dev)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	u32 origmacctrl;
+	u32 restoremacctrl;
+
+	IPG_DEBUG_MSG("_io_config\n");
+
+	origmacctrl = ipg_r32(MAC_CTRL);
+
+	restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE;
+
+	/* Based on compilation option, determine if FCS is to be
+	 * stripped on receive frames by IPG.
+	 */
+	if (!IPG_STRIP_FCS_ON_RX)
+		restoremacctrl |= IPG_MC_RCV_FCS;
+
+	/* Determine if transmitter and/or receiver are
+	 * enabled so we may restore MACCTRL correctly.
+	 */
+	if (origmacctrl & IPG_MC_TX_ENABLED)
+		restoremacctrl |= IPG_MC_TX_ENABLE;
+
+	if (origmacctrl & IPG_MC_RX_ENABLED)
+		restoremacctrl |= IPG_MC_RX_ENABLE;
+
+	/* Transmitter and receiver must be disabled before setting
+	 * IFSSelect.
+	 */
+	ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) &
+		IPG_MC_RSVD_MASK, MAC_CTRL);
+
+	/* Now that transmitter and receiver are disabled, write
+	 * to IFSSelect.
+	 */
+	ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL);
+
+	/* Set RECEIVEMODE register. */
+	ipg_nic_set_multicast_list(dev);
+
+	ipg_w16(IPG_MAX_RXFRAME_SIZE, MAX_FRAME_SIZE);
+
+	ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE,   RX_DMA_POLL_PERIOD);
+	ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH);
+	ipg_w8(IPG_RXDMABURSTTHRESH_VALUE,  RX_DMA_BURST_THRESH);
+	ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE,   TX_DMA_POLL_PERIOD);
+	ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH);
+	ipg_w8(IPG_TXDMABURSTTHRESH_VALUE,  TX_DMA_BURST_THRESH);
+	ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE |
+		 IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED |
+		 IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT |
+		 IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE);
+	ipg_w16(IPG_FLOWONTHRESH_VALUE,  FLOW_ON_THRESH);
+	ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH);
+
+	/* IPG multi-frag frame bug workaround.
+	 * Per silicon revision B3 eratta.
+	 */
+	ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL);
+
+	/* IPG TX poll now bug workaround.
+	 * Per silicon revision B3 eratta.
+	 */
+	ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL);
+
+	/* IPG RX poll now bug workaround.
+	 * Per silicon revision B3 eratta.
+	 */
+	ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL);
+
+	/* Now restore MACCTRL to original setting. */
+	ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL);
+
+	/* Disable unused RMON statistics. */
+	ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK);
+
+	/* Disable unused MIB statistics. */
+	ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD |
+		IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES |
+		IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES |
+		IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK |
+		IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS |
+		IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK);
+
+	return 0;
+}
+
+/*
+ * Create a receive buffer within system memory and update
+ * NIC private structure appropriately.
+ */
+static int ipg_get_rxbuff(struct net_device *dev, int entry)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	struct ipg_rx *rxfd = sp->rxd + entry;
+	struct sk_buff *skb;
+	u64 rxfragsize;
+
+	IPG_DEBUG_MSG("_get_rxbuff\n");
+
+	skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN);
+	if (!skb) {
+		sp->RxBuff[entry] = NULL;
+		return -ENOMEM;
+	}
+
+	/* Adjust the data start location within the buffer to
+	 * align IP address field to a 16 byte boundary.
+	 */
+	skb_reserve(skb, NET_IP_ALIGN);
+
+	/* Associate the receive buffer with the IPG NIC. */
+	skb->dev = dev;
+
+	/* Save the address of the sk_buff structure. */
+	sp->RxBuff[entry] = skb;
+
+	rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+		sp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+
+	/* Set the RFD fragment length. */
+	rxfragsize = IPG_RXFRAG_SIZE;
+	rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN);
+
+	return 0;
+}
+
+static int init_rfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_init_rfdlist\n");
+
+	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+		struct ipg_rx *rxfd = sp->rxd + i;
+
+		if (sp->RxBuff[i]) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+			sp->RxBuff[i] = NULL;
+		}
+
+		/* Clear out the RFS field. */
+		rxfd->rfs = 0x0000000000000000;
+
+		if (ipg_get_rxbuff(dev, i) < 0) {
+			/*
+			 * A receive buffer was not ready, break the
+			 * RFD list here.
+			 */
+			IPG_DEBUG_MSG("Cannot allocate Rx buffer.\n");
+
+			/* Just in case we cannot allocate a single RFD.
+			 * Should not occur.
+			 */
+			if (i == 0) {
+				printk(KERN_ERR "%s: No memory available"
+					" for RFD list.\n", dev->name);
+				return -ENOMEM;
+			}
+		}
+
+		rxfd->next_desc = cpu_to_le64(sp->rxd_map +
+			sizeof(struct ipg_rx)*(i + 1));
+	}
+	sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map);
+
+	sp->rx_current = 0;
+	sp->rx_dirty = 0;
+
+	/* Write the location of the RFDList to the IPG. */
+	ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0);
+	ipg_w32(0x00000000, RFD_LIST_PTR_1);
+
+	return 0;
+}
+
+static void init_tfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_init_tfdlist\n");
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		struct ipg_tx *txfd = sp->txd + i;
+
+		txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+		if (sp->TxBuff[i]) {
+			IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+			sp->TxBuff[i] = NULL;
+		}
+
+		txfd->next_desc = cpu_to_le64(sp->txd_map +
+			sizeof(struct ipg_tx)*(i + 1));
+	}
+	sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map);
+
+	sp->tx_current = 0;
+	sp->tx_dirty = 0;
+
+	/* Write the location of the TFDList to the IPG. */
+	IPG_DDEBUG_MSG("Starting TFDListPtr = %8.8x\n",
+		       (u32) sp->txd_map);
+	ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
+	ipg_w32(0x00000000, TFD_LIST_PTR_1);
+
+	sp->ResetCurrentTFD = 1;
+}
+
+/*
+ * Free all transmit buffers which have already been transfered
+ * via DMA to the IPG.
+ */
+static void ipg_nic_txfree(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	const unsigned int curr = ipg_r32(TFD_LIST_PTR_0) -
+		(sp->txd_map / sizeof(struct ipg_tx)) - 1;
+	unsigned int released, pending;
+
+	IPG_DEBUG_MSG("_nic_txfree\n");
+
+	pending = sp->tx_current - sp->tx_dirty;
+
+	for (released = 0; released < pending; released++) {
+		unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
+		struct sk_buff *skb = sp->TxBuff[dirty];
+		struct ipg_tx *txfd = sp->txd + dirty;
+
+		IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc);
+
+		/* Look at each TFD's TFC field beginning
+		 * at the last freed TFD up to the current TFD.
+		 * If the TFDDone bit is set, free the associated
+		 * buffer.
+		 */
+		if (dirty == curr)
+			break;
+
+		/* Setup TFDDONE for compatible issue. */
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE);
+
+		/* Free the transmit buffer. */
+		if (skb) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+				skb->len, PCI_DMA_TODEVICE);
+
+			IPG_DEV_KFREE_SKB(skb);
+
+			sp->TxBuff[dirty] = NULL;
+		}
+	}
+
+	sp->tx_dirty += released;
+
+	if (netif_queue_stopped(dev) &&
+	    (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) {
+		netif_wake_queue(dev);
+	}
+}
+
+static void ipg_tx_timeout(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+
+	ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK |
+		  IPG_AC_FIFO);
+
+	spin_lock_irq(&sp->lock);
+
+	/* Re-configure after DMA reset. */
+	if (ipg_io_config(dev) < 0) {
+		printk(KERN_INFO "%s: Error during re-configuration.\n",
+		       dev->name);
+	}
+
+	init_tfdlist(dev);
+
+	spin_unlock_irq(&sp->lock);
+
+	ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK,
+		MAC_CTRL);
+}
+
+/*
+ * For TxComplete interrupts, free all transmit
+ * buffers which have already been transfered via DMA
+ * to the IPG.
+ */
+static void ipg_nic_txcleanup(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_nic_txcleanup\n");
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		/* Reading the TXSTATUS register clears the
+		 * TX_COMPLETE interrupt.
+		 */
+		u32 txstatusdword = ipg_r32(TX_STATUS);
+
+		IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword);
+
+		/* Check for Transmit errors. Error bits only valid if
+		 * TX_COMPLETE bit in the TXSTATUS register is a 1.
+		 */
+		if (!(txstatusdword & IPG_TS_TX_COMPLETE))
+			break;
+
+		/* If in 10Mbps mode, indicate transmit is ready. */
+		if (sp->tenmbpsmode) {
+			netif_wake_queue(dev);
+		}
+
+		/* Transmit error, increment stat counters. */
+		if (txstatusdword & IPG_TS_TX_ERROR) {
+			IPG_DEBUG_MSG("Transmit error.\n");
+			sp->stats.tx_errors++;
+		}
+
+		/* Late collision, re-enable transmitter. */
+		if (txstatusdword & IPG_TS_LATE_COLLISION) {
+			IPG_DEBUG_MSG("Late collision on transmit.\n");
+			ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+				IPG_MC_RSVD_MASK, MAC_CTRL);
+		}
+
+		/* Maximum collisions, re-enable transmitter. */
+		if (txstatusdword & IPG_TS_TX_MAX_COLL) {
+			IPG_DEBUG_MSG("Maximum collisions on transmit.\n");
+			ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+				IPG_MC_RSVD_MASK, MAC_CTRL);
+		}
+
+		/* Transmit underrun, reset and re-enable
+		 * transmitter.
+		 */
+		if (txstatusdword & IPG_TS_TX_UNDERRUN) {
+			IPG_DEBUG_MSG("Transmitter underrun.\n");
+			sp->stats.tx_fifo_errors++;
+			ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA |
+				  IPG_AC_NETWORK | IPG_AC_FIFO);
+
+			/* Re-configure after DMA reset. */
+			if (ipg_io_config(dev) < 0) {
+				printk(KERN_INFO
+				       "%s: Error during re-configuration.\n",
+				       dev->name);
+			}
+			init_tfdlist(dev);
+
+			ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+				IPG_MC_RSVD_MASK, MAC_CTRL);
+		}
+	}
+
+	ipg_nic_txfree(dev);
+}
+
+/* Provides statistical information about the IPG NIC. */
+struct net_device_stats *ipg_nic_get_stats(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	u16 temp1;
+	u16 temp2;
+
+	IPG_DEBUG_MSG("_nic_get_stats\n");
+
+	/* Check to see if the NIC has been initialized via nic_open,
+	 * before trying to read statistic registers.
+	 */
+	if (!test_bit(__LINK_STATE_START, &dev->state))
+		return &sp->stats;
+
+	sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK);
+	sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK);
+	sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK);
+	sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK);
+	temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS);
+	sp->stats.rx_errors += temp1;
+	sp->stats.rx_missed_errors += temp1;
+	temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) +
+		ipg_r32(IPG_LATECOLLISIONS);
+	temp2 = ipg_r16(IPG_CARRIERSENSEERRORS);
+	sp->stats.collisions += temp1;
+	sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS);
+	sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) +
+		ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2;
+	sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK);
+
+	/* detailed tx_errors */
+	sp->stats.tx_carrier_errors += temp2;
+
+	/* detailed rx_errors */
+	sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) +
+		ipg_r16(IPG_FRAMETOOLONGERRRORS);
+	sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS);
+
+	/* Unutilized IPG statistic registers. */
+	ipg_r32(IPG_MCSTFRAMESRCVDOK);
+
+	return &sp->stats;
+}
+
+/* Restore used receive buffers. */
+static int ipg_nic_rxrestore(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	const unsigned int curr = sp->rx_current;
+	unsigned int dirty = sp->rx_dirty;
+
+	IPG_DEBUG_MSG("_nic_rxrestore\n");
+
+	for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) {
+		unsigned int entry = dirty % IPG_RFDLIST_LENGTH;
+
+		/* rx_copybreak may poke hole here and there. */
+		if (sp->RxBuff[entry])
+			continue;
+
+		/* Generate a new receive buffer to replace the
+		 * current buffer (which will be released by the
+		 * Linux system).
+		 */
+		if (ipg_get_rxbuff(dev, entry) < 0) {
+			IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n");
+
+			break;
+		}
+
+		/* Reset the RFS field. */
+		sp->rxd[entry].rfs = 0x0000000000000000;
+	}
+	sp->rx_dirty = dirty;
+
+	return 0;
+}
+
+#ifdef JUMBO_FRAME
+
+/* use jumboindex and jumbosize to control jumbo frame status
+   initial status is jumboindex=-1 and jumbosize=0
+   1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
+   2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
+   3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
+                previous receiving and need to continue dumping the current one
+*/
+enum {
+	NormalPacket,
+	ErrorPacket
+};
+
+enum {
+	Frame_NoStart_NoEnd	= 0,
+	Frame_WithStart		= 1,
+	Frame_WithEnd		= 10,
+	Frame_WithStart_WithEnd = 11
+};
+
+inline void ipg_nic_rx_free_skb(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+
+	if (sp->RxBuff[entry]) {
+		struct ipg_rx *rxfd = sp->rxd + entry;
+
+		pci_unmap_single(sp->pdev,
+			le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+			sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+		sp->RxBuff[entry] = NULL;
+	}
+}
+
+inline int ipg_nic_rx_check_frame_type(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH);
+	int type = Frame_NoStart_NoEnd;
+
+	if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART)
+		type += Frame_WithStart;
+	if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND)
+		type += Frame_WithEnd;
+	return type;
+}
+
+inline int ipg_nic_rx_check_error(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+	struct ipg_rx *rxfd = sp->rxd + entry;
+
+	if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
+	     (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+	      IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+	      IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) {
+		IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+			      (unsigned long) rxfd->rfs);
+
+		/* Increment general receive error statistic. */
+		sp->stats.rx_errors++;
+
+		/* Increment detailed receive error statistics. */
+		if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
+			IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+
+			sp->stats.rx_fifo_errors++;
+		}
+
+		if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
+			IPG_DEBUG_MSG("RX runt occured.\n");
+			sp->stats.rx_length_errors++;
+		}
+
+		/* Do nothing for IPG_RFS_RXOVERSIZEDFRAME,
+		 * error count handled by a IPG statistic register.
+		 */
+
+		if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
+			IPG_DEBUG_MSG("RX alignment error occured.\n");
+			sp->stats.rx_frame_errors++;
+		}
+
+		/* Do nothing for IPG_RFS_RXFCSERROR, error count
+		 * handled by a IPG statistic register.
+		 */
+
+		/* Free the memory associated with the RX
+		 * buffer since it is erroneous and we will
+		 * not pass it to higher layer processes.
+		 */
+		if (sp->RxBuff[entry]) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+			IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+			sp->RxBuff[entry] = NULL;
+		}
+		return ErrorPacket;
+	}
+	return NormalPacket;
+}
+
+static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
+					  struct ipg_nic_private *sp,
+					  struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+	struct sk_buff *skb;
+	int framelen;
+
+	if (jumbo->FoundStart) {
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+	}
+
+	// 1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) != NormalPacket)
+		return;
+
+	skb = sp->RxBuff[entry];
+	if (!skb)
+		return;
+
+	// accept this frame and send to upper layer
+	framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+	if (framelen > IPG_RXFRAG_SIZE)
+		framelen = IPG_RXFRAG_SIZE;
+
+	skb_put(skb, framelen);
+	skb->protocol = eth_type_trans(skb, dev);
+	skb->ip_summed = CHECKSUM_NONE;
+	netif_rx(skb);
+	dev->last_rx = jiffies;
+	sp->RxBuff[entry] = NULL;
+}
+
+static void ipg_nic_rx_with_start(struct net_device *dev,
+				  struct ipg_nic_private *sp,
+				  struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+	struct pci_dev *pdev = sp->pdev;
+	struct sk_buff *skb;
+
+	// 1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) != NormalPacket)
+		return;
+
+	// accept this frame and send to upper layer
+	skb = sp->RxBuff[entry];
+	if (!skb)
+		return;
+
+	if (jumbo->FoundStart)
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+
+	pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+			 sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+	skb_put(skb, IPG_RXFRAG_SIZE);
+
+	jumbo->FoundStart = 1;
+	jumbo->CurrentSize = IPG_RXFRAG_SIZE;
+	jumbo->skb = skb;
+
+	sp->RxBuff[entry] = NULL;
+	dev->last_rx = jiffies;
+}
+
+static void ipg_nic_rx_with_end(struct net_device *dev,
+				struct ipg_nic_private *sp,
+				struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+
+	//1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+		struct sk_buff *skb = sp->RxBuff[entry];
+
+		if (!skb)
+			return;
+
+		if (jumbo->FoundStart) {
+			int framelen, endframelen;
+
+			framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+			endframeLen = framelen - jumbo->CurrentSize;
+			/*
+			if (framelen > IPG_RXFRAG_SIZE)
+				framelen=IPG_RXFRAG_SIZE;
+			 */
+			if (framelen > IPG_RXSUPPORT_SIZE)
+				IPG_DEV_KFREE_SKB(jumbo->skb);
+			else {
+				memcpy(skb_put(jumbo->skb, endframeLen),
+				       skb->data, endframeLen);
+
+				jumbo->skb->protocol =
+				    eth_type_trans(jumbo->skb, dev);
+
+				jumbo->skb->ip_summed = CHECKSUM_NONE;
+				netif_rx(jumbo->skb);
+			}
+		}
+
+		dev->last_rx = jiffies;
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+
+		ipg_nic_rx_free_skb(dev);
+	} else {
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+	}
+}
+
+static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
+				       struct ipg_nic_private *sp,
+				       struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+
+	//1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+		struct sk_buff *skb = sp->RxBuff[entry];
+
+		if (skb) {
+			if (jumbo->FoundStart) {
+				jumbo->CurrentSize += IPG_RXFRAG_SIZE;
+				if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) {
+					memcpy(skb_put(jumbo->skb,
+						       IPG_RXFRAG_SIZE),
+					       skb->data, IPG_RXFRAG_SIZE);
+				}
+			}
+			dev->last_rx = jiffies;
+			ipg_nic_rx_free_skb(dev);
+		}
+	} else {
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+	}
+}
+
+static int ipg_nic_rx(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int curr = sp->rx_current;
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_nic_rx\n");
+
+	for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+		unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+		struct ipg_rx *rxfd = sp->rxd + entry;
+
+		if (!(rxfd->rfs & le64_to_cpu(IPG_RFS_RFDDONE)))
+			break;
+
+		switch (ipg_nic_rx_check_frame_type(dev)) {
+		case Frame_WithStart_WithEnd:
+			ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+			break;
+		case Frame_WithStart:
+			ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+			break;
+		case Frame_WithEnd:
+			ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+			break;
+		case Frame_NoStart_NoEnd:
+			ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+			break;
+		}
+	}
+
+	sp->rx_current = curr;
+
+	if (i == IPG_MAXRFDPROCESS_COUNT) {
+		/* There are more RFDs to process, however the
+		 * allocated amount of RFD processing time has
+		 * expired. Assert Interrupt Requested to make
+		 * sure we come back to process the remaining RFDs.
+		 */
+		ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+	}
+
+	ipg_nic_rxrestore(dev);
+
+	return 0;
+}
+
+#else
+static int ipg_nic_rx(struct net_device *dev)
+{
+	/* Transfer received Ethernet frames to higher network layers. */
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int curr = sp->rx_current;
+	void __iomem *ioaddr = sp->ioaddr;
+	struct ipg_rx *rxfd;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_nic_rx\n");
+
+#define __RFS_MASK \
+	cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND)
+
+	for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+		unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+		struct sk_buff *skb = sp->RxBuff[entry];
+		unsigned int framelen;
+
+		rxfd = sp->rxd + entry;
+
+		if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb)
+			break;
+
+		/* Get received frame length. */
+		framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+		/* Check for jumbo frame arrival with too small
+		 * RXFRAG_SIZE.
+		 */
+		if (framelen > IPG_RXFRAG_SIZE) {
+			IPG_DEBUG_MSG
+			    ("RFS FrameLen > allocated fragment size.\n");
+
+			framelen = IPG_RXFRAG_SIZE;
+		}
+
+		if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs &
+		       (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+			IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+			IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) {
+
+			IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+				      (unsigned long int) rxfd->rfs);
+
+			/* Increment general receive error statistic. */
+			sp->stats.rx_errors++;
+
+			/* Increment detailed receive error statistics. */
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) {
+				IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+				sp->stats.rx_fifo_errors++;
+			}
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) {
+				IPG_DEBUG_MSG("RX runt occured.\n");
+				sp->stats.rx_length_errors++;
+			}
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ;
+			/* Do nothing, error count handled by a IPG
+			 * statistic register.
+			 */
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) {
+				IPG_DEBUG_MSG("RX alignment error occured.\n");
+				sp->stats.rx_frame_errors++;
+			}
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ;
+			/* Do nothing, error count handled by a IPG
+			 * statistic register.
+			 */
+
+			/* Free the memory associated with the RX
+			 * buffer since it is erroneous and we will
+			 * not pass it to higher layer processes.
+			 */
+			if (skb) {
+				u64 info = rxfd->frag_info;
+
+				pci_unmap_single(sp->pdev,
+					le64_to_cpu(info & ~IPG_RFI_FRAGLEN),
+					sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+				IPG_DEV_KFREE_SKB(skb);
+			}
+		} else {
+
+			/* Adjust the new buffer length to accomodate the size
+			 * of the received frame.
+			 */
+			skb_put(skb, framelen);
+
+			/* Set the buffer's protocol field to Ethernet. */
+			skb->protocol = eth_type_trans(skb, dev);
+
+			/* If the frame contains an IP/TCP/UDP frame,
+			 * determine if upper layer must check IP/TCP/UDP
+			 * checksums.
+			 *
+			 * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM
+			 *       VERIFICATION FOR SILICON REVISIONS B3
+			 *       AND EARLIER!
+			 *
+			 if ((le64_to_cpu(rxfd->rfs &
+			 (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED |
+			 IPG_RFS_IPDETECTED))) &&
+			 !(le64_to_cpu(rxfd->rfs &
+			 (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR |
+			 IPG_RFS_IPERROR))))
+			 {
+			 * Indicate IP checksums were performed
+			 * by the IPG.
+			 *
+			 skb->ip_summed = CHECKSUM_UNNECESSARY;
+			 }
+			 else
+			 */
+			if (1 == 1) {
+				/* The IPG encountered an error with (or
+				 * there were no) IP/TCP/UDP checksums.
+				 * This may or may not indicate an invalid
+				 * IP/TCP/UDP frame was received. Let the
+				 * upper layer decide.
+				 */
+				skb->ip_summed = CHECKSUM_NONE;
+			}
+
+			/* Hand off frame for higher layer processing.
+			 * The function netif_rx() releases the sk_buff
+			 * when processing completes.
+			 */
+			netif_rx(skb);
+
+			/* Record frame receive time (jiffies = Linux
+			 * kernel current time stamp).
+			 */
+			dev->last_rx = jiffies;
+		}
+
+		/* Assure RX buffer is not reused by IPG. */
+		sp->RxBuff[entry] = NULL;
+	}
+
+	/*
+	 * If there are more RFDs to proces and the allocated amount of RFD
+	 * processing time has expired, assert Interrupt Requested to make
+	 * sure we come back to process the remaining RFDs.
+	 */
+	if (i == IPG_MAXRFDPROCESS_COUNT)
+		ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+
+#ifdef IPG_DEBUG
+	/* Check if the RFD list contained no receive frame data. */
+	if (!i)
+		sp->EmptyRFDListCount++;
+#endif
+	while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) &&
+	       !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) &&
+		 (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) {
+		unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
+
+		rxfd = sp->rxd + entry;
+
+		IPG_DEBUG_MSG("Frame requires multiple RFDs.\n");
+
+		/* An unexpected event, additional code needed to handle
+		 * properly. So for the time being, just disregard the
+		 * frame.
+		 */
+
+		/* Free the memory associated with the RX
+		 * buffer since it is erroneous and we will
+		 * not pass it to higher layer processes.
+		 */
+		if (sp->RxBuff[entry]) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+		}
+
+		/* Assure RX buffer is not reused by IPG. */
+		sp->RxBuff[entry] = NULL;
+	}
+
+	sp->rx_current = curr;
+
+	/* Check to see if there are a minimum number of used
+	 * RFDs before restoring any (should improve performance.)
+	 */
+	if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE)
+		ipg_nic_rxrestore(dev);
+
+	return 0;
+}
+#endif
+
+static void ipg_reset_after_host_error(struct work_struct *work)
+{
+	struct ipg_nic_private *sp =
+		container_of(work, struct ipg_nic_private, task.work);
+	struct net_device *dev = sp->dev;
+
+	IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL));
+
+	/*
+	 * Acknowledge HostError interrupt by resetting
+	 * IPG DMA and HOST.
+	 */
+	ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+	init_rfdlist(dev);
+	init_tfdlist(dev);
+
+	if (ipg_io_config(dev) < 0) {
+		printk(KERN_INFO "%s: Cannot recover from PCI error.\n",
+		       dev->name);
+		schedule_delayed_work(&sp->task, HZ);
+	}
+}
+
+static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
+{
+	struct net_device *dev = dev_inst;
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int handled = 0;
+	u16 status;
+
+	IPG_DEBUG_MSG("_interrupt_handler\n");
+
+#ifdef JUMBO_FRAME
+	ipg_nic_rxrestore(dev);
+#endif
+	/* Get interrupt source information, and acknowledge
+	 * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly,
+	 * IntRequested, MacControlFrame, LinkEvent) interrupts
+	 * if issued. Also, all IPG interrupts are disabled by
+	 * reading IntStatusAck.
+	 */
+	status = ipg_r16(INT_STATUS_ACK);
+
+	IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status);
+
+	/* Shared IRQ of remove event. */
+	if (!(status & IPG_IS_RSVD_MASK))
+		goto out_enable;
+
+	handled = 1;
+
+	if (unlikely(!netif_running(dev)))
+		goto out;
+
+	spin_lock(&sp->lock);
+
+	/* If RFDListEnd interrupt, restore all used RFDs. */
+	if (status & IPG_IS_RFD_LIST_END) {
+		IPG_DEBUG_MSG("RFDListEnd Interrupt.\n");
+
+		/* The RFD list end indicates an RFD was encountered
+		 * with a 0 NextPtr, or with an RFDDone bit set to 1
+		 * (indicating the RFD is not read for use by the
+		 * IPG.) Try to restore all RFDs.
+		 */
+		ipg_nic_rxrestore(dev);
+
+#ifdef IPG_DEBUG
+		/* Increment the RFDlistendCount counter. */
+		sp->RFDlistendCount++;
+#endif
+	}
+
+	/* If RFDListEnd, RxDMAPriority, RxDMAComplete, or
+	 * IntRequested interrupt, process received frames. */
+	if ((status & IPG_IS_RX_DMA_PRIORITY) ||
+	    (status & IPG_IS_RFD_LIST_END) ||
+	    (status & IPG_IS_RX_DMA_COMPLETE) ||
+	    (status & IPG_IS_INT_REQUESTED)) {
+#ifdef IPG_DEBUG
+		/* Increment the RFD list checked counter if interrupted
+		 * only to check the RFD list. */
+		if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END |
+				IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) &
+			       (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE |
+				IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE |
+				IPG_IS_UPDATE_STATS)))
+			sp->RFDListCheckedCount++;
+#endif
+
+		ipg_nic_rx(dev);
+	}
+
+	/* If TxDMAComplete interrupt, free used TFDs. */
+	if (status & IPG_IS_TX_DMA_COMPLETE)
+		ipg_nic_txfree(dev);
+
+	/* TxComplete interrupts indicate one of numerous actions.
+	 * Determine what action to take based on TXSTATUS register.
+	 */
+	if (status & IPG_IS_TX_COMPLETE)
+		ipg_nic_txcleanup(dev);
+
+	/* If UpdateStats interrupt, update Linux Ethernet statistics */
+	if (status & IPG_IS_UPDATE_STATS)
+		ipg_nic_get_stats(dev);
+
+	/* If HostError interrupt, reset IPG. */
+	if (status & IPG_IS_HOST_ERROR) {
+		IPG_DDEBUG_MSG("HostError Interrupt\n");
+
+		schedule_delayed_work(&sp->task, 0);
+	}
+
+	/* If LinkEvent interrupt, resolve autonegotiation. */
+	if (status & IPG_IS_LINK_EVENT) {
+		if (ipg_config_autoneg(dev) < 0)
+			printk(KERN_INFO "%s: Auto-negotiation error.\n",
+			       dev->name);
+	}
+
+	/* If MACCtrlFrame interrupt, do nothing. */
+	if (status & IPG_IS_MAC_CTRL_FRAME)
+		IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n");
+
+	/* If RxComplete interrupt, do nothing. */
+	if (status & IPG_IS_RX_COMPLETE)
+		IPG_DEBUG_MSG("RxComplete interrupt.\n");
+
+	/* If RxEarly interrupt, do nothing. */
+	if (status & IPG_IS_RX_EARLY)
+		IPG_DEBUG_MSG("RxEarly interrupt.\n");
+
+out_enable:
+	/* Re-enable IPG interrupts. */
+	ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE |
+		IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE |
+		IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);
+
+	spin_unlock(&sp->lock);
+out:
+	return IRQ_RETVAL(handled);
+}
+
+static void ipg_rx_clear(struct ipg_nic_private *sp)
+{
+	unsigned int i;
+
+	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+		if (sp->RxBuff[i]) {
+			struct ipg_rx *rxfd = sp->rxd + i;
+
+			IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+			sp->RxBuff[i] = NULL;
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		}
+	}
+}
+
+static void ipg_tx_clear(struct ipg_nic_private *sp)
+{
+	unsigned int i;
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		if (sp->TxBuff[i]) {
+			struct ipg_tx *txfd = sp->txd + i;
+
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+				sp->TxBuff[i]->len, PCI_DMA_TODEVICE);
+
+			IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+
+			sp->TxBuff[i] = NULL;
+		}
+	}
+}
+
+static int ipg_nic_open(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	struct pci_dev *pdev = sp->pdev;
+	int rc;
+
+	IPG_DEBUG_MSG("_nic_open\n");
+
+	sp->rx_buf_sz = IPG_RXSUPPORT_SIZE;
+
+	/* Check for interrupt line conflicts, and request interrupt
+	 * line for IPG.
+	 *
+	 * IMPORTANT: Disable IPG interrupts prior to registering
+	 *            IRQ.
+	 */
+	ipg_w16(0x0000, INT_ENABLE);
+
+	/* Register the interrupt line to be used by the IPG within
+	 * the Linux system.
+	 */
+	rc = request_irq(pdev->irq, &ipg_interrupt_handler, IRQF_SHARED,
+			 dev->name, dev);
+	if (rc < 0) {
+		printk(KERN_INFO "%s: Error when requesting interrupt.\n",
+		       dev->name);
+		goto out;
+	}
+
+	dev->irq = pdev->irq;
+
+	rc = -ENOMEM;
+
+	sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES,
+				     &sp->rxd_map, GFP_KERNEL);
+	if (!sp->rxd)
+		goto err_free_irq_0;
+
+	sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES,
+				     &sp->txd_map, GFP_KERNEL);
+	if (!sp->txd)
+		goto err_free_rx_1;
+
+	rc = init_rfdlist(dev);
+	if (rc < 0) {
+		printk(KERN_INFO "%s: Error during configuration.\n",
+		       dev->name);
+		goto err_free_tx_2;
+	}
+
+	init_tfdlist(dev);
+
+	rc = ipg_io_config(dev);
+	if (rc < 0) {
+		printk(KERN_INFO "%s: Error during configuration.\n",
+		       dev->name);
+		goto err_release_tfdlist_3;
+	}
+
+	/* Resolve autonegotiation. */
+	if (ipg_config_autoneg(dev) < 0)
+		printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name);
+
+#ifdef JUMBO_FRAME
+	/* initialize JUMBO Frame control variable */
+	sp->Jumbo.FoundStart = 0;
+	sp->Jumbo.CurrentSize = 0;
+	sp->Jumbo.skb = 0;
+	dev->mtu = IPG_TXFRAG_SIZE;
+#endif
+
+	/* Enable transmit and receive operation of the IPG. */
+	ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) &
+		 IPG_MC_RSVD_MASK, MAC_CTRL);
+
+	netif_start_queue(dev);
+out:
+	return rc;
+
+err_release_tfdlist_3:
+	ipg_tx_clear(sp);
+	ipg_rx_clear(sp);
+err_free_tx_2:
+	dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+err_free_rx_1:
+	dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+err_free_irq_0:
+	free_irq(pdev->irq, dev);
+	goto out;
+}
+
+static int ipg_nic_stop(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	struct pci_dev *pdev = sp->pdev;
+
+	IPG_DEBUG_MSG("_nic_stop\n");
+
+	netif_stop_queue(dev);
+
+	IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount);
+	IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount);
+	IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount);
+	IPG_DUMPTFDLIST(dev);
+
+	do {
+		(void) ipg_r16(INT_STATUS_ACK);
+
+		ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+		synchronize_irq(pdev->irq);
+	} while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK);
+
+	ipg_rx_clear(sp);
+
+	ipg_tx_clear(sp);
+
+	pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+	pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+
+	free_irq(pdev->irq, dev);
+
+	return 0;
+}
+
+static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH;
+	unsigned long flags;
+	struct ipg_tx *txfd;
+
+	IPG_DDEBUG_MSG("_nic_hard_start_xmit\n");
+
+	/* If in 10Mbps mode, stop the transmit queue so
+	 * no more transmit frames are accepted.
+	 */
+	if (sp->tenmbpsmode)
+		netif_stop_queue(dev);
+
+	if (sp->ResetCurrentTFD) {
+		sp->ResetCurrentTFD = 0;
+		entry = 0;
+	}
+
+	txfd = sp->txd + entry;
+
+	sp->TxBuff[entry] = skb;
+
+	/* Clear all TFC fields, except TFDDONE. */
+	txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+	/* Specify the TFC field within the TFD. */
+	txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED |
+		(IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) |
+		(IPG_TFC_FRAGCOUNT & (1 << 24)));
+
+	/* Request TxComplete interrupts at an interval defined
+	 * by the constant IPG_FRAMESBETWEENTXCOMPLETES.
+	 * Request TxComplete interrupt for every frame
+	 * if in 10Mbps mode to accomodate problem with 10Mbps
+	 * processing.
+	 */
+	if (sp->tenmbpsmode)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);
+	else if (!((sp->tx_current - sp->tx_dirty + 1) >
+	    IPG_FRAMESBETWEENTXDMACOMPLETES)) {
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
+	}
+	/* Based on compilation option, determine if FCS is to be
+	 * appended to transmit frame by IPG.
+	 */
+	if (!(IPG_APPEND_FCS_ON_TX))
+		txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE);
+
+	/* Based on compilation option, determine if IP, TCP and/or
+	 * UDP checksums are to be added to transmit frame by IPG.
+	 */
+	if (IPG_ADD_IPCHECKSUM_ON_TX)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE);
+
+	if (IPG_ADD_TCPCHECKSUM_ON_TX)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE);
+
+	if (IPG_ADD_UDPCHECKSUM_ON_TX)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE);
+
+	/* Based on compilation option, determine if VLAN tag info is to be
+	 * inserted into transmit frame by IPG.
+	 */
+	if (IPG_INSERT_MANUAL_VLAN_TAG) {
+		txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT |
+			((u64) IPG_MANUAL_VLAN_VID << 32) |
+			((u64) IPG_MANUAL_VLAN_CFI << 44) |
+			((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45));
+	}
+
+	/* The fragment start location within system memory is defined
+	 * by the sk_buff structure's data field. The physical address
+	 * of this location within the system's virtual memory space
+	 * is determined using the IPG_HOST2BUS_MAP function.
+	 */
+	txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+		skb->len, PCI_DMA_TODEVICE));
+
+	/* The length of the fragment within system memory is defined by
+	 * the sk_buff structure's len field.
+	 */
+	txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN &
+		((u64) (skb->len & 0xffff) << 48));
+
+	/* Clear the TFDDone bit last to indicate the TFD is ready
+	 * for transfer to the IPG.
+	 */
+	txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE);
+
+	spin_lock_irqsave(&sp->lock, flags);
+
+	sp->tx_current++;
+
+	mmiowb();
+
+	ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);
+
+	if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))
+		netif_wake_queue(dev);
+
+	spin_unlock_irqrestore(&sp->lock, flags);
+
+	return NETDEV_TX_OK;
+}
+
+static void ipg_set_phy_default_param(unsigned char rev,
+				      struct net_device *dev, int phy_address)
+{
+	unsigned short length;
+	unsigned char revision;
+	unsigned short *phy_param;
+	unsigned short address, value;
+
+	phy_param = &DefaultPhyParam[0];
+	length = *phy_param & 0x00FF;
+	revision = (unsigned char)((*phy_param) >> 8);
+	phy_param++;
+	while (length != 0) {
+		if (rev == revision) {
+			while (length > 1) {
+				address = *phy_param;
+				value = *(phy_param + 1);
+				phy_param += 2;
+				mdio_write(dev, phy_address, address, value);
+				length -= 4;
+			}
+			break;
+		} else {
+			phy_param += length / 2;
+			length = *phy_param & 0x00FF;
+			revision = (unsigned char)((*phy_param) >> 8);
+			phy_param++;
+		}
+	}
+}
+
+/* JES20040127EEPROM */
+static int read_eeprom(struct net_device *dev, int eep_addr)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	unsigned int i;
+	int ret = 0;
+	u16 value;
+
+	value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff);
+	ipg_w16(value, EEPROM_CTRL);
+
+	for (i = 0; i < 1000; i++) {
+		u16 data;
+
+		mdelay(10);
+		data = ipg_r16(EEPROM_CTRL);
+		if (!(data & IPG_EC_EEPROM_BUSY)) {
+			ret = ipg_r16(EEPROM_DATA);
+			break;
+		}
+	}
+	return ret;
+}
+
+static void ipg_init_mii(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	struct mii_if_info *mii_if = &sp->mii_if;
+	int phyaddr;
+
+	mii_if->dev          = dev;
+	mii_if->mdio_read    = mdio_read;
+	mii_if->mdio_write   = mdio_write;
+	mii_if->phy_id_mask  = 0x1f;
+	mii_if->reg_num_mask = 0x1f;
+
+	mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev);
+
+	if (phyaddr != 0x1f) {
+		u16 mii_phyctrl, mii_1000cr;
+		u8 revisionid = 0;
+
+		mii_1000cr  = mdio_read(dev, phyaddr, MII_CTRL1000);
+		mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF |
+			GMII_PHY_1000BASETCONTROL_PreferMaster;
+		mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr);
+
+		mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR);
+
+		/* Set default phyparam */
+		pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid);
+		ipg_set_phy_default_param(revisionid, dev, phyaddr);
+
+		/* Reset PHY */
+		mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART;
+		mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl);
+
+	}
+}
+
+static int ipg_hw_init(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+	int rc;
+
+	/* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */
+	/* Read LED Mode Configuration from EEPROM */
+	sp->LED_Mode = read_eeprom(dev, 6);
+
+	/* Reset all functions within the IPG. Do not assert
+	 * RST_OUT as not compatible with some PHYs.
+	 */
+	rc = ipg_reset(dev, IPG_RESET_MASK);
+	if (rc < 0)
+		goto out;
+
+	ipg_init_mii(dev);
+
+	/* Read MAC Address from EEPROM */
+	for (i = 0; i < 3; i++)
+		sp->station_addr[i] = read_eeprom(dev, 16 + i);
+
+	for (i = 0; i < 3; i++)
+		ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i);
+
+	/* Set station address in ethernet_device structure. */
+	dev->dev_addr[0] =  ipg_r16(STATION_ADDRESS_0) & 0x00ff;
+	dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8;
+	dev->dev_addr[2] =  ipg_r16(STATION_ADDRESS_1) & 0x00ff;
+	dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8;
+	dev->dev_addr[4] =  ipg_r16(STATION_ADDRESS_2) & 0x00ff;
+	dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8;
+out:
+	return rc;
+}
+
+static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* Function to accomodate changes to Maximum Transfer Unit
+	 * (or MTU) of IPG NIC. Cannot use default function since
+	 * the default will not allow for MTU > 1500 bytes.
+	 */
+
+	IPG_DEBUG_MSG("_nic_change_mtu\n");
+
+	/* Check that the new MTU value is between 68 (14 byte header, 46
+	 * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which
+	 * corresponds to the MAXFRAMESIZE register in the IPG.
+	 */
+	if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE))
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = mii_ethtool_gset(&sp->mii_if, cmd);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = mii_ethtool_sset(&sp->mii_if, cmd);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static int ipg_nway_reset(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = mii_nway_restart(&sp->mii_if);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static struct ethtool_ops ipg_ethtool_ops = {
+	.get_settings = ipg_get_settings,
+	.set_settings = ipg_set_settings,
+	.nway_reset   = ipg_nway_reset,
+};
+
+static void ipg_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct ipg_nic_private *sp = netdev_priv(dev);
+
+	IPG_DEBUG_MSG("_remove\n");
+
+	/* Un-register Ethernet device. */
+	unregister_netdev(dev);
+
+	pci_iounmap(pdev, sp->ioaddr);
+
+	pci_release_regions(pdev);
+
+	free_netdev(dev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int __devinit ipg_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	unsigned int i = id->driver_data;
+	struct ipg_nic_private *sp;
+	struct net_device *dev;
+	void __iomem *ioaddr;
+	int rc;
+
+	rc = pci_enable_device(pdev);
+	if (rc < 0)
+		goto out;
+
+	printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
+
+	pci_set_master(pdev);
+
+	rc = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+	if (rc < 0) {
+		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: DMA config failed.\n",
+			       pci_name(pdev));
+			goto err_disable_0;
+		}
+	}
+
+	/*
+	 * Initialize net device.
+	 */
+	dev = alloc_etherdev(sizeof(struct ipg_nic_private));
+	if (!dev) {
+		printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_disable_0;
+	}
+
+	sp = netdev_priv(dev);
+	spin_lock_init(&sp->lock);
+	mutex_init(&sp->mii_mutex);
+
+	/* Declare IPG NIC functions for Ethernet device methods.
+	 */
+	dev->open = &ipg_nic_open;
+	dev->stop = &ipg_nic_stop;
+	dev->hard_start_xmit = &ipg_nic_hard_start_xmit;
+	dev->get_stats = &ipg_nic_get_stats;
+	dev->set_multicast_list = &ipg_nic_set_multicast_list;
+	dev->do_ioctl = ipg_ioctl;
+	dev->tx_timeout = ipg_tx_timeout;
+	dev->change_mtu = &ipg_nic_change_mtu;
+
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops);
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_free_dev_1;
+
+	ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
+	if (!ioaddr) {
+		printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev));
+		rc = -EIO;
+		goto err_release_regions_2;
+	}
+
+	/* Save the pointer to the PCI device information. */
+	sp->ioaddr = ioaddr;
+	sp->pdev = pdev;
+	sp->dev = dev;
+
+	INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error);
+
+	pci_set_drvdata(pdev, dev);
+
+	rc = ipg_hw_init(dev);
+	if (rc < 0)
+		goto err_unmap_3;
+
+	rc = register_netdev(dev);
+	if (rc < 0)
+		goto err_unmap_3;
+
+	printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name);
+out:
+	return rc;
+
+err_unmap_3:
+	pci_iounmap(pdev, ioaddr);
+err_release_regions_2:
+	pci_release_regions(pdev);
+err_free_dev_1:
+	free_netdev(dev);
+err_disable_0:
+	pci_disable_device(pdev);
+	goto out;
+}
+
+static struct pci_driver ipg_pci_driver = {
+	.name		= IPG_DRIVER_NAME,
+	.id_table	= ipg_pci_tbl,
+	.probe		= ipg_probe,
+	.remove		= __devexit_p(ipg_remove),
+};
+
+static int __init ipg_init_module(void)
+{
+	return pci_register_driver(&ipg_pci_driver);
+}
+
+static void __exit ipg_exit_module(void)
+{
+	pci_unregister_driver(&ipg_pci_driver);
+}
+
+module_init(ipg_init_module);
+module_exit(ipg_exit_module);
diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h
new file mode 100755
index 0000000..9b8e3bb
--- /dev/null
+++ b/drivers/net/ipg.h
@@ -0,0 +1,856 @@
+/*
+ *
+ * ipg.h
+ *
+ * Include file for Gigabit Ethernet device driver for Network
+ * Interface Cards (NICs) utilizing the Tamarack Microelectronics
+ * Inc. IPG Gigabit or Triple Speed Ethernet Media Access
+ * Controller.
+ *
+ * Craig Rich
+ * Sundance Technology, Inc.
+ * 1485 Saratoga Avenue
+ * Suite 200
+ * San Jose, CA 95129
+ * 408 873 4117
+ * www.sundanceti.com
+ * craig_rich@sundanceti.com
+ */
+#ifndef __LINUX_IPG_H
+#define __LINUX_IPG_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/version.h>
+#include <asm/bitops.h>
+/*#include <asm/spinlock.h>*/
+
+#define DrvVer "2.09d"
+
+#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb)
+
+/*
+ *	Constants
+ */
+
+/* GMII based PHY IDs */
+#define		NS				0x2000
+#define		MARVELL				0x0141
+#define		ICPLUS_PHY		0x243
+
+/* NIC Physical Layer Device MII register fields. */
+#define         MII_PHY_SELECTOR_IEEE8023       0x0001
+#define         MII_PHY_TECHABILITYFIELD        0x1FE0
+
+/* GMII_PHY_1000 need to set to prefer master */
+#define         GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400
+
+/* NIC Physical Layer Device GMII constants. */
+#define         GMII_PREAMBLE                    0xFFFFFFFF
+#define         GMII_ST                          0x1
+#define         GMII_READ                        0x2
+#define         GMII_WRITE                       0x1
+#define         GMII_TA_READ_MASK                0x1
+#define         GMII_TA_WRITE                    0x2
+
+/* I/O register offsets. */
+enum ipg_regs {
+	DMA_CTRL		= 0x00,
+	RX_DMA_STATUS		= 0x08, // Unused + reserved
+	TFD_LIST_PTR_0		= 0x10,
+	TFD_LIST_PTR_1		= 0x14,
+	TX_DMA_BURST_THRESH	= 0x18,
+	TX_DMA_URGENT_THRESH	= 0x19,
+	TX_DMA_POLL_PERIOD	= 0x1a,
+	RFD_LIST_PTR_0		= 0x1c,
+	RFD_LIST_PTR_1		= 0x20,
+	RX_DMA_BURST_THRESH	= 0x24,
+	RX_DMA_URGENT_THRESH	= 0x25,
+	RX_DMA_POLL_PERIOD	= 0x26,
+	DEBUG_CTRL		= 0x2c,
+	ASIC_CTRL		= 0x30,
+	FIFO_CTRL		= 0x38, // Unused
+	FLOW_OFF_THRESH		= 0x3c,
+	FLOW_ON_THRESH		= 0x3e,
+	EEPROM_DATA		= 0x48,
+	EEPROM_CTRL		= 0x4a,
+	EXPROM_ADDR		= 0x4c, // Unused
+	EXPROM_DATA		= 0x50, // Unused
+	WAKE_EVENT		= 0x51, // Unused
+	COUNTDOWN		= 0x54, // Unused
+	INT_STATUS_ACK		= 0x5a,
+	INT_ENABLE		= 0x5c,
+	INT_STATUS		= 0x5e, // Unused
+	TX_STATUS		= 0x60,
+	MAC_CTRL		= 0x6c,
+	VLAN_TAG		= 0x70, // Unused
+	PHY_SET			= 0x75,	// JES20040127EEPROM
+	PHY_CTRL		= 0x76,
+	STATION_ADDRESS_0	= 0x78,
+	STATION_ADDRESS_1	= 0x7a,
+	STATION_ADDRESS_2	= 0x7c,
+	MAX_FRAME_SIZE		= 0x86,
+	RECEIVE_MODE		= 0x88,
+	HASHTABLE_0		= 0x8c,
+	HASHTABLE_1		= 0x90,
+	RMON_STATISTICS_MASK	= 0x98,
+	STATISTICS_MASK		= 0x9c,
+	RX_JUMBO_FRAMES		= 0xbc, // Unused
+	TCP_CHECKSUM_ERRORS	= 0xc0, // Unused
+	IP_CHECKSUM_ERRORS	= 0xc2, // Unused
+	UDP_CHECKSUM_ERRORS	= 0xc4, // Unused
+	TX_JUMBO_FRAMES		= 0xf4  // Unused
+};
+
+/* Ethernet MIB statistic register offsets. */
+#define	IPG_OCTETRCVOK		0xA8
+#define	IPG_MCSTOCTETRCVDOK		0xAC
+#define	IPG_BCSTOCTETRCVOK		0xB0
+#define	IPG_FRAMESRCVDOK		0xB4
+#define	IPG_MCSTFRAMESRCVDOK		0xB8
+#define	IPG_BCSTFRAMESRCVDOK		0xBE
+#define	IPG_MACCONTROLFRAMESRCVD	0xC6
+#define	IPG_FRAMETOOLONGERRRORS	0xC8
+#define	IPG_INRANGELENGTHERRORS	0xCA
+#define	IPG_FRAMECHECKSEQERRORS	0xCC
+#define	IPG_FRAMESLOSTRXERRORS	0xCE
+#define	IPG_OCTETXMTOK		0xD0
+#define	IPG_MCSTOCTETXMTOK		0xD4
+#define	IPG_BCSTOCTETXMTOK		0xD8
+#define	IPG_FRAMESXMTDOK		0xDC
+#define	IPG_MCSTFRAMESXMTDOK		0xE0
+#define	IPG_FRAMESWDEFERREDXMT	0xE4
+#define	IPG_LATECOLLISIONS		0xE8
+#define	IPG_MULTICOLFRAMES		0xEC
+#define	IPG_SINGLECOLFRAMES		0xF0
+#define	IPG_BCSTFRAMESXMTDOK		0xF6
+#define	IPG_CARRIERSENSEERRORS	0xF8
+#define	IPG_MACCONTROLFRAMESXMTDOK	0xFA
+#define	IPG_FRAMESABORTXSCOLLS	0xFC
+#define	IPG_FRAMESWEXDEFERRAL	0xFE
+
+/* RMON statistic register offsets. */
+#define	IPG_ETHERSTATSCOLLISIONS			0x100
+#define	IPG_ETHERSTATSOCTETSTRANSMIT			0x104
+#define	IPG_ETHERSTATSPKTSTRANSMIT			0x108
+#define	IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT		0x10C
+#define	IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT	0x110
+#define	IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT	0x114
+#define	IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT	0x118
+#define	IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT	0x11C
+#define	IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT	0x120
+#define	IPG_ETHERSTATSCRCALIGNERRORS			0x124
+#define	IPG_ETHERSTATSUNDERSIZEPKTS			0x128
+#define	IPG_ETHERSTATSFRAGMENTS			0x12C
+#define	IPG_ETHERSTATSJABBERS			0x130
+#define	IPG_ETHERSTATSOCTETS				0x134
+#define	IPG_ETHERSTATSPKTS				0x138
+#define	IPG_ETHERSTATSPKTS64OCTESTS			0x13C
+#define	IPG_ETHERSTATSPKTS65TO127OCTESTS		0x140
+#define	IPG_ETHERSTATSPKTS128TO255OCTESTS		0x144
+#define	IPG_ETHERSTATSPKTS256TO511OCTESTS		0x148
+#define	IPG_ETHERSTATSPKTS512TO1023OCTESTS		0x14C
+#define	IPG_ETHERSTATSPKTS1024TO1518OCTESTS		0x150
+
+/* RMON statistic register equivalents. */
+#define	IPG_ETHERSTATSMULTICASTPKTSTRANSMIT		0xE0
+#define	IPG_ETHERSTATSBROADCASTPKTSTRANSMIT		0xF6
+#define	IPG_ETHERSTATSMULTICASTPKTS			0xB8
+#define	IPG_ETHERSTATSBROADCASTPKTS			0xBE
+#define	IPG_ETHERSTATSOVERSIZEPKTS			0xC8
+#define	IPG_ETHERSTATSDROPEVENTS			0xCE
+
+/* Serial EEPROM offsets */
+#define	IPG_EEPROM_CONFIGPARAM	0x00
+#define	IPG_EEPROM_ASICCTRL		0x01
+#define	IPG_EEPROM_SUBSYSTEMVENDORID	0x02
+#define	IPG_EEPROM_SUBSYSTEMID	0x03
+#define	IPG_EEPROM_STATIONADDRESS0	0x10
+#define	IPG_EEPROM_STATIONADDRESS1	0x11
+#define	IPG_EEPROM_STATIONADDRESS2	0x12
+
+/* Register & data structure bit masks */
+
+/* PCI register masks. */
+
+/* IOBaseAddress */
+#define         IPG_PIB_RSVD_MASK		0xFFFFFE01
+#define         IPG_PIB_IOBASEADDRESS	0xFFFFFF00
+#define         IPG_PIB_IOBASEADDRIND	0x00000001
+
+/* MemBaseAddress */
+#define         IPG_PMB_RSVD_MASK		0xFFFFFE07
+#define         IPG_PMB_MEMBASEADDRIND	0x00000001
+#define         IPG_PMB_MEMMAPTYPE		0x00000006
+#define         IPG_PMB_MEMMAPTYPE0		0x00000002
+#define         IPG_PMB_MEMMAPTYPE1		0x00000004
+#define         IPG_PMB_MEMBASEADDRESS	0xFFFFFE00
+
+/* ConfigStatus */
+#define IPG_CS_RSVD_MASK                0xFFB0
+#define IPG_CS_CAPABILITIES             0x0010
+#define IPG_CS_66MHZCAPABLE             0x0020
+#define IPG_CS_FASTBACK2BACK            0x0080
+#define IPG_CS_DATAPARITYREPORTED       0x0100
+#define IPG_CS_DEVSELTIMING             0x0600
+#define IPG_CS_SIGNALEDTARGETABORT      0x0800
+#define IPG_CS_RECEIVEDTARGETABORT      0x1000
+#define IPG_CS_RECEIVEDMASTERABORT      0x2000
+#define IPG_CS_SIGNALEDSYSTEMERROR      0x4000
+#define IPG_CS_DETECTEDPARITYERROR      0x8000
+
+/* TFD data structure masks. */
+
+/* TFDList, TFC */
+#define	IPG_TFC_RSVD_MASK			0x0000FFFF9FFFFFFF
+#define	IPG_TFC_FRAMEID			0x000000000000FFFF
+#define	IPG_TFC_WORDALIGN			0x0000000000030000
+#define	IPG_TFC_WORDALIGNTODWORD		0x0000000000000000
+#define	IPG_TFC_WORDALIGNTOWORD		0x0000000000020000
+#define	IPG_TFC_WORDALIGNDISABLED		0x0000000000030000
+#define	IPG_TFC_TCPCHECKSUMENABLE		0x0000000000040000
+#define	IPG_TFC_UDPCHECKSUMENABLE		0x0000000000080000
+#define	IPG_TFC_IPCHECKSUMENABLE		0x0000000000100000
+#define	IPG_TFC_FCSAPPENDDISABLE		0x0000000000200000
+#define	IPG_TFC_TXINDICATE			0x0000000000400000
+#define	IPG_TFC_TXDMAINDICATE		0x0000000000800000
+#define	IPG_TFC_FRAGCOUNT			0x000000000F000000
+#define	IPG_TFC_VLANTAGINSERT		0x0000000010000000
+#define	IPG_TFC_TFDDONE			0x0000000080000000
+#define	IPG_TFC_VID				0x00000FFF00000000
+#define	IPG_TFC_CFI				0x0000100000000000
+#define	IPG_TFC_USERPRIORITY			0x0000E00000000000
+
+/* TFDList, FragInfo */
+#define	IPG_TFI_RSVD_MASK			0xFFFF00FFFFFFFFFF
+#define	IPG_TFI_FRAGADDR			0x000000FFFFFFFFFF
+#define	IPG_TFI_FRAGLEN			0xFFFF000000000000LL
+
+/* RFD data structure masks. */
+
+/* RFDList, RFS */
+#define	IPG_RFS_RSVD_MASK			0x0000FFFFFFFFFFFF
+#define	IPG_RFS_RXFRAMELEN			0x000000000000FFFF
+#define	IPG_RFS_RXFIFOOVERRUN		0x0000000000010000
+#define	IPG_RFS_RXRUNTFRAME			0x0000000000020000
+#define	IPG_RFS_RXALIGNMENTERROR		0x0000000000040000
+#define	IPG_RFS_RXFCSERROR			0x0000000000080000
+#define	IPG_RFS_RXOVERSIZEDFRAME		0x0000000000100000
+#define	IPG_RFS_RXLENGTHERROR		0x0000000000200000
+#define	IPG_RFS_VLANDETECTED			0x0000000000400000
+#define	IPG_RFS_TCPDETECTED			0x0000000000800000
+#define	IPG_RFS_TCPERROR			0x0000000001000000
+#define	IPG_RFS_UDPDETECTED			0x0000000002000000
+#define	IPG_RFS_UDPERROR			0x0000000004000000
+#define	IPG_RFS_IPDETECTED			0x0000000008000000
+#define	IPG_RFS_IPERROR			0x0000000010000000
+#define	IPG_RFS_FRAMESTART			0x0000000020000000
+#define	IPG_RFS_FRAMEEND			0x0000000040000000
+#define	IPG_RFS_RFDDONE			0x0000000080000000
+#define	IPG_RFS_TCI				0x0000FFFF00000000
+
+/* RFDList, FragInfo */
+#define	IPG_RFI_RSVD_MASK			0xFFFF00FFFFFFFFFF
+#define	IPG_RFI_FRAGADDR			0x000000FFFFFFFFFF
+#define	IPG_RFI_FRAGLEN			0xFFFF000000000000LL
+
+/* I/O Register masks. */
+
+/* RMON Statistics Mask */
+#define	IPG_RZ_ALL					0x0FFFFFFF
+
+/* Statistics Mask */
+#define	IPG_SM_ALL					0x0FFFFFFF
+#define	IPG_SM_OCTETRCVOK_FRAMESRCVDOK		0x00000001
+#define	IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK	0x00000002
+#define	IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK	0x00000004
+#define	IPG_SM_RXJUMBOFRAMES				0x00000008
+#define	IPG_SM_TCPCHECKSUMERRORS			0x00000010
+#define	IPG_SM_IPCHECKSUMERRORS			0x00000020
+#define	IPG_SM_UDPCHECKSUMERRORS			0x00000040
+#define	IPG_SM_MACCONTROLFRAMESRCVD			0x00000080
+#define	IPG_SM_FRAMESTOOLONGERRORS			0x00000100
+#define	IPG_SM_INRANGELENGTHERRORS			0x00000200
+#define	IPG_SM_FRAMECHECKSEQERRORS			0x00000400
+#define	IPG_SM_FRAMESLOSTRXERRORS			0x00000800
+#define	IPG_SM_OCTETXMTOK_FRAMESXMTOK		0x00001000
+#define	IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK	0x00002000
+#define	IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK	0x00004000
+#define	IPG_SM_FRAMESWDEFERREDXMT			0x00008000
+#define	IPG_SM_LATECOLLISIONS			0x00010000
+#define	IPG_SM_MULTICOLFRAMES			0x00020000
+#define	IPG_SM_SINGLECOLFRAMES			0x00040000
+#define	IPG_SM_TXJUMBOFRAMES				0x00080000
+#define	IPG_SM_CARRIERSENSEERRORS			0x00100000
+#define	IPG_SM_MACCONTROLFRAMESXMTD			0x00200000
+#define	IPG_SM_FRAMESABORTXSCOLLS			0x00400000
+#define	IPG_SM_FRAMESWEXDEFERAL			0x00800000
+
+/* Countdown */
+#define	IPG_CD_RSVD_MASK		0x0700FFFF
+#define	IPG_CD_COUNT			0x0000FFFF
+#define	IPG_CD_COUNTDOWNSPEED	0x01000000
+#define	IPG_CD_COUNTDOWNMODE		0x02000000
+#define	IPG_CD_COUNTINTENABLED	0x04000000
+
+/* TxDMABurstThresh */
+#define IPG_TB_RSVD_MASK                0xFF
+
+/* TxDMAUrgentThresh */
+#define IPG_TU_RSVD_MASK                0xFF
+
+/* TxDMAPollPeriod */
+#define IPG_TP_RSVD_MASK                0xFF
+
+/* RxDMAUrgentThresh */
+#define IPG_RU_RSVD_MASK                0xFF
+
+/* RxDMAPollPeriod */
+#define IPG_RP_RSVD_MASK                0xFF
+
+/* ReceiveMode */
+#define IPG_RM_RSVD_MASK                0x3F
+#define IPG_RM_RECEIVEUNICAST           0x01
+#define IPG_RM_RECEIVEMULTICAST         0x02
+#define IPG_RM_RECEIVEBROADCAST         0x04
+#define IPG_RM_RECEIVEALLFRAMES         0x08
+#define IPG_RM_RECEIVEMULTICASTHASH     0x10
+#define IPG_RM_RECEIVEIPMULTICAST       0x20
+
+/* PhySet JES20040127EEPROM*/
+#define IPG_PS_MEM_LENB9B               0x01
+#define IPG_PS_MEM_LEN9                 0x02
+#define IPG_PS_NON_COMPDET              0x04
+
+/* PhyCtrl */
+#define IPG_PC_RSVD_MASK                0xFF
+#define IPG_PC_MGMTCLK_LO               0x00
+#define IPG_PC_MGMTCLK_HI               0x01
+#define IPG_PC_MGMTCLK                  0x01
+#define IPG_PC_MGMTDATA                 0x02
+#define IPG_PC_MGMTDIR                  0x04
+#define IPG_PC_DUPLEX_POLARITY          0x08
+#define IPG_PC_DUPLEX_STATUS            0x10
+#define IPG_PC_LINK_POLARITY            0x20
+#define IPG_PC_LINK_SPEED               0xC0
+#define IPG_PC_LINK_SPEED_10MBPS        0x40
+#define IPG_PC_LINK_SPEED_100MBPS       0x80
+#define IPG_PC_LINK_SPEED_1000MBPS      0xC0
+
+/* DMACtrl */
+#define IPG_DC_RSVD_MASK                0xC07D9818
+#define IPG_DC_RX_DMA_COMPLETE          0x00000008
+#define IPG_DC_RX_DMA_POLL_NOW          0x00000010
+#define IPG_DC_TX_DMA_COMPLETE          0x00000800
+#define IPG_DC_TX_DMA_POLL_NOW          0x00001000
+#define IPG_DC_TX_DMA_IN_PROG           0x00008000
+#define IPG_DC_RX_EARLY_DISABLE         0x00010000
+#define IPG_DC_MWI_DISABLE              0x00040000
+#define IPG_DC_TX_WRITE_BACK_DISABLE    0x00080000
+#define IPG_DC_TX_BURST_LIMIT           0x00700000
+#define IPG_DC_TARGET_ABORT             0x40000000
+#define IPG_DC_MASTER_ABORT             0x80000000
+
+/* ASICCtrl */
+#define IPG_AC_RSVD_MASK                0x07FFEFF2
+#define IPG_AC_EXP_ROM_SIZE             0x00000002
+#define IPG_AC_PHY_SPEED10              0x00000010
+#define IPG_AC_PHY_SPEED100             0x00000020
+#define IPG_AC_PHY_SPEED1000            0x00000040
+#define IPG_AC_PHY_MEDIA                0x00000080
+#define IPG_AC_FORCED_CFG               0x00000700
+#define IPG_AC_D3RESETDISABLE           0x00000800
+#define IPG_AC_SPEED_UP_MODE            0x00002000
+#define IPG_AC_LED_MODE                 0x00004000
+#define IPG_AC_RST_OUT_POLARITY         0x00008000
+#define IPG_AC_GLOBAL_RESET             0x00010000
+#define IPG_AC_RX_RESET                 0x00020000
+#define IPG_AC_TX_RESET                 0x00040000
+#define IPG_AC_DMA                      0x00080000
+#define IPG_AC_FIFO                     0x00100000
+#define IPG_AC_NETWORK                  0x00200000
+#define IPG_AC_HOST                     0x00400000
+#define IPG_AC_AUTO_INIT                0x00800000
+#define IPG_AC_RST_OUT                  0x01000000
+#define IPG_AC_INT_REQUEST              0x02000000
+#define IPG_AC_RESET_BUSY               0x04000000
+#define IPG_AC_LED_SPEED                0x08000000	//JES20040127EEPROM
+#define IPG_AC_LED_MODE_BIT_1           0x20000000	//JES20040127EEPROM
+
+/* EepromCtrl */
+#define IPG_EC_RSVD_MASK                0x83FF
+#define IPG_EC_EEPROM_ADDR              0x00FF
+#define IPG_EC_EEPROM_OPCODE            0x0300
+#define IPG_EC_EEPROM_SUBCOMMAD         0x0000
+#define IPG_EC_EEPROM_WRITEOPCODE       0x0100
+#define IPG_EC_EEPROM_READOPCODE        0x0200
+#define IPG_EC_EEPROM_ERASEOPCODE       0x0300
+#define IPG_EC_EEPROM_BUSY              0x8000
+
+/* FIFOCtrl */
+#define IPG_FC_RSVD_MASK                0xC001
+#define IPG_FC_RAM_TEST_MODE            0x0001
+#define IPG_FC_TRANSMITTING             0x4000
+#define IPG_FC_RECEIVING                0x8000
+
+/* TxStatus */
+#define IPG_TS_RSVD_MASK                0xFFFF00DD
+#define IPG_TS_TX_ERROR                 0x00000001
+#define IPG_TS_LATE_COLLISION           0x00000004
+#define IPG_TS_TX_MAX_COLL              0x00000008
+#define IPG_TS_TX_UNDERRUN              0x00000010
+#define IPG_TS_TX_IND_REQD              0x00000040
+#define IPG_TS_TX_COMPLETE              0x00000080
+#define IPG_TS_TX_FRAMEID               0xFFFF0000
+
+/* WakeEvent */
+#define IPG_WE_WAKE_PKT_ENABLE          0x01
+#define IPG_WE_MAGIC_PKT_ENABLE         0x02
+#define IPG_WE_LINK_EVT_ENABLE          0x04
+#define IPG_WE_WAKE_POLARITY            0x08
+#define IPG_WE_WAKE_PKT_EVT             0x10
+#define IPG_WE_MAGIC_PKT_EVT            0x20
+#define IPG_WE_LINK_EVT                 0x40
+#define IPG_WE_WOL_ENABLE               0x80
+
+/* IntEnable */
+#define IPG_IE_RSVD_MASK                0x1FFE
+#define IPG_IE_HOST_ERROR               0x0002
+#define IPG_IE_TX_COMPLETE              0x0004
+#define IPG_IE_MAC_CTRL_FRAME           0x0008
+#define IPG_IE_RX_COMPLETE              0x0010
+#define IPG_IE_RX_EARLY                 0x0020
+#define IPG_IE_INT_REQUESTED            0x0040
+#define IPG_IE_UPDATE_STATS             0x0080
+#define IPG_IE_LINK_EVENT               0x0100
+#define IPG_IE_TX_DMA_COMPLETE          0x0200
+#define IPG_IE_RX_DMA_COMPLETE          0x0400
+#define IPG_IE_RFD_LIST_END             0x0800
+#define IPG_IE_RX_DMA_PRIORITY          0x1000
+
+/* IntStatus */
+#define IPG_IS_RSVD_MASK                0x1FFF
+#define IPG_IS_INTERRUPT_STATUS         0x0001
+#define IPG_IS_HOST_ERROR               0x0002
+#define IPG_IS_TX_COMPLETE              0x0004
+#define IPG_IS_MAC_CTRL_FRAME           0x0008
+#define IPG_IS_RX_COMPLETE              0x0010
+#define IPG_IS_RX_EARLY                 0x0020
+#define IPG_IS_INT_REQUESTED            0x0040
+#define IPG_IS_UPDATE_STATS             0x0080
+#define IPG_IS_LINK_EVENT               0x0100
+#define IPG_IS_TX_DMA_COMPLETE          0x0200
+#define IPG_IS_RX_DMA_COMPLETE          0x0400
+#define IPG_IS_RFD_LIST_END             0x0800
+#define IPG_IS_RX_DMA_PRIORITY          0x1000
+
+/* MACCtrl */
+#define IPG_MC_RSVD_MASK                0x7FE33FA3
+#define IPG_MC_IFS_SELECT               0x00000003
+#define IPG_MC_IFS_4352BIT              0x00000003
+#define IPG_MC_IFS_1792BIT              0x00000002
+#define IPG_MC_IFS_1024BIT              0x00000001
+#define IPG_MC_IFS_96BIT                0x00000000
+#define IPG_MC_DUPLEX_SELECT            0x00000020
+#define IPG_MC_DUPLEX_SELECT_FD         0x00000020
+#define IPG_MC_DUPLEX_SELECT_HD         0x00000000
+#define IPG_MC_TX_FLOW_CONTROL_ENABLE   0x00000080
+#define IPG_MC_RX_FLOW_CONTROL_ENABLE   0x00000100
+#define IPG_MC_RCV_FCS                  0x00000200
+#define IPG_MC_FIFO_LOOPBACK            0x00000400
+#define IPG_MC_MAC_LOOPBACK             0x00000800
+#define IPG_MC_AUTO_VLAN_TAGGING        0x00001000
+#define IPG_MC_AUTO_VLAN_UNTAGGING      0x00002000
+#define IPG_MC_COLLISION_DETECT         0x00010000
+#define IPG_MC_CARRIER_SENSE            0x00020000
+#define IPG_MC_STATISTICS_ENABLE        0x00200000
+#define IPG_MC_STATISTICS_DISABLE       0x00400000
+#define IPG_MC_STATISTICS_ENABLED       0x00800000
+#define IPG_MC_TX_ENABLE                0x01000000
+#define IPG_MC_TX_DISABLE               0x02000000
+#define IPG_MC_TX_ENABLED               0x04000000
+#define IPG_MC_RX_ENABLE                0x08000000
+#define IPG_MC_RX_DISABLE               0x10000000
+#define IPG_MC_RX_ENABLED               0x20000000
+#define IPG_MC_PAUSED                   0x40000000
+
+/*
+ *	Tune
+ */
+
+/* Miscellaneous Constants. */
+#define   TRUE  1
+#define   FALSE 0
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */
+#define         IPG_APPEND_FCS_ON_TX         TRUE
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */
+#define         IPG_STRIP_FCS_ON_RX          TRUE
+
+/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with
+ * Ethernet errors.
+ */
+#define         IPG_DROP_ON_RX_ETH_ERRORS    TRUE
+
+/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually
+ * (via TFC).
+ */
+#define		IPG_INSERT_MANUAL_VLAN_TAG   FALSE
+
+/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */
+#define         IPG_ADD_IPCHECKSUM_ON_TX     FALSE
+
+/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define         IPG_ADD_TCPCHECKSUM_ON_TX    FALSE
+
+/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define         IPG_ADD_UDPCHECKSUM_ON_TX    FALSE
+
+/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx
+ * constants as desired.
+ */
+#define		IPG_MANUAL_VLAN_VID		0xABC
+#define		IPG_MANUAL_VLAN_CFI		0x1
+#define		IPG_MANUAL_VLAN_USERPRIORITY 0x5
+
+#define         IPG_IO_REG_RANGE		0xFF
+#define         IPG_MEM_REG_RANGE		0x154
+#define         IPG_DRIVER_NAME		"Sundance Technology IPG Triple-Speed Ethernet"
+#define         IPG_NIC_PHY_ADDRESS          0x01
+#define		IPG_DMALIST_ALIGN_PAD	0x07
+#define		IPG_MULTICAST_HASHTABLE_SIZE	0x40
+
+/* Number of miliseconds to wait after issuing a software reset.
+ * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation.
+ */
+#define         IPG_AC_RESETWAIT             0x05
+
+/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */
+#define         IPG_AC_RESET_TIMEOUT         0x0A
+
+/* Minimum number of nanoseconds used to toggle MDC clock during
+ * MII/GMII register access.
+ */
+#define		IPG_PC_PHYCTRLWAIT_NS		200
+
+#define		IPG_TFDLIST_LENGTH		0x100
+
+/* Number of frames between TxDMAComplete interrupt.
+ * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH
+ */
+#define		IPG_FRAMESBETWEENTXDMACOMPLETES 0x1
+
+#ifdef JUMBO_FRAME
+
+# ifdef JUMBO_FRAME_SIZE_2K
+# define JUMBO_FRAME_SIZE 2048
+# define __IPG_RXFRAG_SIZE 2048
+# else
+#  ifdef JUMBO_FRAME_SIZE_3K
+#  define JUMBO_FRAME_SIZE 3072
+#  define __IPG_RXFRAG_SIZE 3072
+#  else
+#   ifdef JUMBO_FRAME_SIZE_4K
+#   define JUMBO_FRAME_SIZE 4096
+#   define __IPG_RXFRAG_SIZE 4088
+#   else
+#    ifdef JUMBO_FRAME_SIZE_5K
+#    define JUMBO_FRAME_SIZE 5120
+#    define __IPG_RXFRAG_SIZE 4088
+#    else
+#     ifdef JUMBO_FRAME_SIZE_6K
+#     define JUMBO_FRAME_SIZE 6144
+#     define __IPG_RXFRAG_SIZE 4088
+#     else
+#      ifdef JUMBO_FRAME_SIZE_7K
+#      define JUMBO_FRAME_SIZE 7168
+#      define __IPG_RXFRAG_SIZE 4088
+#      else
+#       ifdef JUMBO_FRAME_SIZE_8K
+#       define JUMBO_FRAME_SIZE 8192
+#       define __IPG_RXFRAG_SIZE 4088
+#       else
+#        ifdef JUMBO_FRAME_SIZE_9K
+#        define JUMBO_FRAME_SIZE 9216
+#        define __IPG_RXFRAG_SIZE 4088
+#        else
+#         ifdef JUMBO_FRAME_SIZE_10K
+#         define JUMBO_FRAME_SIZE 10240
+#         define __IPG_RXFRAG_SIZE 4088
+#         else
+#         define JUMBO_FRAME_SIZE 4096
+#         endif
+#        endif
+#       endif
+#      endif
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash
+#define		IPG_TXFRAG_SIZE		JUMBO_FRAME_SIZE
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//4088=4096-8
+#define		IPG_RXFRAG_SIZE		__IPG_RXFRAG_SIZE
+#define     IPG_RXSUPPORT_SIZE   IPG_MAX_RXFRAME_SIZE
+#else
+#define		IPG_RXFRAG_SIZE		0x0600
+#define     IPG_RXSUPPORT_SIZE   IPG_RXFRAG_SIZE
+#endif
+
+/* IPG_MAX_RXFRAME_SIZE <= IPG_RXFRAG_SIZE */
+#ifdef JUMBO_FRAME
+#define		IPG_MAX_RXFRAME_SIZE		JUMBO_FRAME_SIZE
+#else
+#define		IPG_MAX_RXFRAME_SIZE		0x0600
+#endif
+
+#define		IPG_RFDLIST_LENGTH		0x100
+
+/* Maximum number of RFDs to process per interrupt.
+ * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH
+ */
+#define		IPG_MAXRFDPROCESS_COUNT	0x80
+
+/* Minimum margin between last freed RFD, and current RFD.
+ * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH
+ */
+#define		IPG_MINUSEDRFDSTOFREE	0x80
+
+/* specify the jumbo frame maximum size
+ * per unit is 0x600 (the RxBuffer size that one RFD can carry)
+ */
+#define     MAX_JUMBOSIZE	        0x8	// max is 12K
+
+/* Key register values loaded at driver start up. */
+
+/* TXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value	Time
+ * ---------------------
+ * 0x00-0x01	320ns
+ * 0x03		~1us
+ * 0x1F		~10us
+ * 0xFF		~82us
+ */
+#define		IPG_TXDMAPOLLPERIOD_VALUE	0x26
+
+/* TxDMAUrgentThresh specifies the minimum amount of
+ * data in the transmit FIFO before asserting an
+ * urgent transmit DMA request.
+ *
+ * Value	Min TxFIFO occupied space before urgent TX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04	128 bytes (1024 bits)
+ * 0x27		1248 bytes (~10000 bits)
+ * 0x30		1536 bytes (12288 bits)
+ * 0xFF		8192 bytes (65535 bits)
+ */
+#define		IPG_TXDMAURGENTTHRESH_VALUE	0x04
+
+/* TxDMABurstThresh specifies the minimum amount of
+ * free space in the transmit FIFO before asserting an
+ * transmit DMA request.
+ *
+ * Value	Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08	256 bytes
+ * 0x30		1536 bytes
+ * 0xFF		8192 bytes
+ */
+#define		IPG_TXDMABURSTTHRESH_VALUE	0x30
+
+/* RXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value	Time
+ * ---------------------
+ * 0x00-0x01	320ns
+ * 0x03		~1us
+ * 0x1F		~10us
+ * 0xFF		~82us
+ */
+#define		IPG_RXDMAPOLLPERIOD_VALUE	0x01
+
+/* RxDMAUrgentThresh specifies the minimum amount of
+ * free space within the receive FIFO before asserting
+ * a urgent receive DMA request.
+ *
+ * Value	Min RxFIFO free space before urgent RX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04	128 bytes (1024 bits)
+ * 0x27		1248 bytes (~10000 bits)
+ * 0x30		1536 bytes (12288 bits)
+ * 0xFF		8192 bytes (65535 bits)
+ */
+#define		IPG_RXDMAURGENTTHRESH_VALUE	0x30
+
+/* RxDMABurstThresh specifies the minimum amount of
+ * occupied space within the receive FIFO before asserting
+ * a receive DMA request.
+ *
+ * Value	Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08	256 bytes
+ * 0x30		1536 bytes
+ * 0xFF		8192 bytes
+ */
+#define		IPG_RXDMABURSTTHRESH_VALUE	0x30
+
+/* FlowOnThresh specifies the maximum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * maximum pause time transmitted.
+ *
+ * Value	Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000	0 bytes
+ * 0x0740	29,696 bytes
+ * 0x07FF	32,752 bytes
+ */
+#define		IPG_FLOWONTHRESH_VALUE	0x0740
+
+/* FlowOffThresh specifies the minimum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * zero pause time is transmitted.
+ *
+ * Value	Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000	0 bytes
+ * 0x00BF	3056 bytes
+ * 0x07FF	32,752 bytes
+ */
+#define		IPG_FLOWOFFTHRESH_VALUE	0x00BF
+
+/*
+ * Miscellaneous macros.
+ */
+
+/* Marco for printing debug statements.
+#  define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */
+#ifdef IPG_DEBUG
+#  define IPG_DEBUG_MSG(args...)
+#  define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args)
+#  define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args)
+#  define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args)
+#else
+#  define IPG_DEBUG_MSG(args...)
+#  define IPG_DDEBUG_MSG(args...)
+#  define IPG_DUMPRFDLIST(args)
+#  define IPG_DUMPTFDLIST(args)
+#endif
+
+/*
+ * End miscellaneous macros.
+ */
+
+/* Transmit Frame Descriptor. The IPG supports 15 fragments,
+ * however Linux requires only a single fragment. Note, each
+ * TFD field is 64 bits wide.
+ */
+struct ipg_tx {
+	u64 next_desc;
+	u64 tfc;
+	u64 frag_info;
+};
+
+/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
+ */
+struct ipg_rx {
+	u64 next_desc;
+	u64 rfs;
+	u64 frag_info;
+};
+
+struct SJumbo {
+	int FoundStart;
+	int CurrentSize;
+	struct sk_buff *skb;
+};
+/* Structure of IPG NIC specific data. */
+struct ipg_nic_private {
+	void __iomem *ioaddr;
+	struct ipg_tx *txd;
+	struct ipg_rx *rxd;
+	dma_addr_t txd_map;
+	dma_addr_t rxd_map;
+	struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH];
+	struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH];
+	unsigned int tx_current;
+	unsigned int tx_dirty;
+	unsigned int rx_current;
+	unsigned int rx_dirty;
+// Add by Grace 2005/05/19
+#ifdef JUMBO_FRAME
+	struct SJumbo Jumbo;
+#endif
+	unsigned int rx_buf_sz;
+	struct pci_dev *pdev;
+	struct net_device *dev;
+	struct net_device_stats stats;
+	spinlock_t lock;
+	int tenmbpsmode;
+
+	/*Jesse20040128EEPROM_VALUE */
+	u16 LED_Mode;
+	u16 station_addr[3];	/* Station Address in EEPROM Reg 0x10..0x12 */
+
+	struct mutex		mii_mutex;
+	struct mii_if_info	mii_if;
+	int ResetCurrentTFD;
+#ifdef IPG_DEBUG
+	int RFDlistendCount;
+	int RFDListCheckedCount;
+	int EmptyRFDListCount;
+#endif
+	struct delayed_work task;
+};
+
+//variable record -- index by leading revision/length
+//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
+unsigned short DefaultPhyParam[] = {
+	// 11/12/03 IP1000A v1-3 rev=0x40
+	/*--------------------------------------------------------------------------
+	(0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
+		    		 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
+		    		 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7,  9, 0x0700,
+	  --------------------------------------------------------------------------*/
+	// 12/17/03 IP1000A v1-4 rev=0x40
+	(0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+	    0x0000,
+	30, 0x005e, 9, 0x0700,
+	// 01/09/04 IP1000A v1-5 rev=0x41
+	(0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+	    0x0000,
+	30, 0x005e, 9, 0x0700,
+	0x0000
+};
+
+#endif				/* __LINUX_IPG_H */
-- 
1.3.GIT



^ permalink raw reply related

* Re: r8169: slow samba performance
From: David Madsen @ 2007-09-14  1:31 UTC (permalink / raw)
  To: Francois Romieu; +Cc: netdev
In-Reply-To: <20070909153312.GA29586@electric-eye.fr.zoreil.com>

> > I noticed a somewhat significant difference between patch #0002 and a
> > busy wait loop with ndelay(10). Write performance was equivalent in
> > both cases as should be the case.  Read perfomance for me maxed out
>
> Do you have some (gross) figure for the write performance ?

Write performance was quite high, around 650-700 megabit no doubt due
to caching behavior on the server, and it was similar in both cases.
I believe the machine with the r8169 was CPU bound at this point or it
probably would have been even higher.

Sorry for the slow response, your reply ended up buried in a deluge of
email and I just dug it out.  I'll give these other patches a spin in
the next couple days when I get a chance and see if things improve.

--David Madsen

^ permalink raw reply

* e1000 driver and samba
From: L F @ 2007-09-14  2:04 UTC (permalink / raw)
  To: netdev

Folks,
I've been playing with multiple gigabit ethernet drivers to get samba
3.0.25+ to work reliably. The situation is as follows.
I have a network, one of the machines on the network is a
server/firewall. It contains an Intel PRO1000 dual port PCI Express
card and runs Debian-testing.
The machine is running shorewall 3.4.5 and at present, one port of the
PRO1000 is configured as the WAN port, the other is bridged to a tap
device for virtualbox and is running as the LAN port.
Samba 3.0.25+ will either lose connection or - more worrisomely -
corrupt data in files upon sustained traffic.
One of the tests that consistently fails is mounting a samba share
onto any WinXP client, then trying to unzip a file from the
mounted/mapped drive into the drive itself (i.e. unzipping
Z:\Stuff\qqq.zip to Z:\Stuff\qqq\* ).
If the zip file is of any significant size, one of two things will
happen. Either the client will complain about losing connection to the
share - with a corrisponding error in the samba logs - or everything
will be fine.. except the files will be corrupt.
The unusual thing is that going through the TAP interface from a
Virtualbox machine yields no problems even when transferring tens of
GBs of data.
Copying a large file (500MB+) also has the same effect.
Now, the machine worked when it was using an onboard Realtek 8169
chipset on a 945G board from ASUS, but it worked slowly. I upgraded to
a P965 chipset, started using the realtek driver for the 8110B on that
board.. and started getting consistent samba errors. I therefore
killed the onboard LAN, switched to the Intel board, tried both the
7.6.5 driver on the Intel website AND the driver in the 2.6.20+
kernels - 7.2.x IIRC - and it fails, less than it did with the
realtek, but it fails. Switching back and forth between 2.6.18,
2.6.20.x and 2.6.22.x yielded no improvements. I could use some help,
because I refuse to believe that there isn't a reliable PCIexpress
gigeth/samba combo available.
For further reference, the kernel versions are those mentioned above,
compiled with gcc-3.4.6 and gcc-4.1.2 (current on debian-testing),
with no improvement between the two.
Any and all indications appreciated.

Regards,
Luigi Fabio

^ permalink raw reply

* Re: 2.6.23-rc4-mm1 OOPS in forcedeth?
From: Andrew James Wade @ 2007-09-14  3:51 UTC (permalink / raw)
  To: Satyam Sharma
  Cc: thunder7, Jeff Garzik, Andrew Morton, Linux Kernel Mailing List,
	netdev
In-Reply-To: <alpine.LFD.0.999.0709021504550.22654@enigma.security.iitk.ac.in>

I have an Oops that may be related:

BUG: unable to handle kernel NULL pointer dereference at virtual address 00000025
printing eip: c037d81b *pde = 00000000
Oops: 0000 [#1]
last sysfs file: /devices/pci0000:00/0000:00:01.0/0000:01:00.0/class

Pid: 0, comm: swapper Not tainted (2.6.23-rc4-mm1-config2 #2)
EIP: 0060:[<c037d81b>] EFLAGS: 00010246 CPU: 0
EIP is at tcp_rto_min+0xb/0x15
EAX: 00000032 EBX: c4c98b68 ECX: fffffffe EDX: 00000000
ESI: c4c98b68 EDI: c055f600 EBP: c4432e40 ESP: c0596dec
 DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
Process swapper (pid: 0, ti=c0596000 task=c052a340 task.ti=c0568000)
Stack: c037d8de c4c98b68 c4c98b68 c037e0ec 00000001 c037f879 c052a8b4 c052a340
       00000000 00000001 c25e1e60 00000000 00000000 00000001 8c176265 8c17678a
       00000000 00000001 00000001 00000000 8c17678a 86000000 ffffffff 007d8b21
Call Trace:
 [<c037d8de>] tcp_rtt_estimator+0xb9/0xfe
 [<c037e0ec>] tcp_ack_saw_tstamp+0x14/0x43
 [<c037f879>] tcp_ack+0x6b8/0x17b8
 [<c03833cc>] tcp_rcv_established+0x519/0x5f1
 [<c038838d>] tcp_v4_do_rcv+0x28/0x2f8
 [<c038a4ce>] tcp_v4_rcv+0x7df/0x83d
 [<c0372542>] ip_local_deliver+0xcc/0x148
 [<c0372975>] ip_rcv+0x3b7/0x3de
 [<c035fa0e>] netif_receive_skb+0x17a/0x1c2
 [<c02cc121>] rtl8139_poll+0x2d9/0x425
 [<c03616d7>] net_rx_action+0xa8/0xc8
 [<c011e8e0>] __do_softirq+0x40/0x90
 [<c010635d>] do_softirq+0x4d/0xb6
 =======================
INFO: lockdep is turned off.
Code: 24 8b 82 88 03 00 00 89 82 40 05 00 00 a1 a0 23 53 c0 89 82 44 05 00 00 83 c4 0c 5b 5e 5f 5d c3 8b 90 88 00 00 00 b8 32 00 00 00 <f6> 42 25 20 74 03 8b 42 54 c3 56
 85 d2 b9 01 00 00 00 0f 45 ca
EIP: [<c037d81b>] tcp_rto_min+0xb/0x15 SS:ESP 0068:c0596dec
Kernel panic - not syncing: Fatal exception in interrupt

config:
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.23-rc4-mm1
# Wed Sep 12 19:53:26 2007
#
CONFIG_X86_32=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_SEMAPHORE_SLEEPERS=y
CONFIG_X86=y
CONFIG_MMU=y
CONFIG_ZONE_DMA=y
CONFIG_QUICKLIST=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_DMI=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"

#
# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION="-config2"
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=18
# CONFIG_CONTAINERS is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
CONFIG_UID16=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_KPAGEMAP=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_MODULES is not set
CONFIG_BLOCK=y
CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
# CONFIG_BLK_DEV_BSG is not set

#
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_DEADLINE is not set
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"

#
# Processor type and features
#
# CONFIG_TICK_ONESHOT is not set
# CONFIG_NO_HZ is not set
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_SMP is not set
CONFIG_X86_PC=y
# CONFIG_X86_ELAN is not set
# CONFIG_X86_VOYAGER is not set
# CONFIG_X86_NUMAQ is not set
# CONFIG_X86_SUMMIT is not set
# CONFIG_X86_BIGSMP is not set
# CONFIG_X86_VISWS is not set
# CONFIG_X86_GENERICARCH is not set
# CONFIG_X86_ES7000 is not set
# CONFIG_PARAVIRT is not set
# CONFIG_M386 is not set
# CONFIG_M486 is not set
# CONFIG_M586 is not set
# CONFIG_M586TSC is not set
# CONFIG_M586MMX is not set
# CONFIG_M686 is not set
# CONFIG_MPENTIUMII is not set
# CONFIG_MPENTIUMIII is not set
# CONFIG_MPENTIUMM is not set
# CONFIG_MPENTIUM4 is not set
# CONFIG_MCORE2 is not set
# CONFIG_MK6 is not set
CONFIG_MK7=y
# CONFIG_MK8 is not set
# CONFIG_MCRUSOE is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MWINCHIPC6 is not set
# CONFIG_MWINCHIP2 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MGEODE_LX is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
# CONFIG_MVIAC7 is not set
# CONFIG_X86_GENERIC is not set
CONFIG_X86_CMPXCHG=y
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_X86_XADD=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
CONFIG_X86_USE_3DNOW=y
CONFIG_X86_TSC=y
CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=4
CONFIG_HPET_TIMER=y
CONFIG_HPET_EMULATE_RTC=y
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
CONFIG_X86_UP_APIC=y
CONFIG_X86_UP_IOAPIC=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_X86_IO_APIC=y
CONFIG_X86_MCE=y
CONFIG_X86_MCE_NONFATAL=y
# CONFIG_X86_MCE_P4THERMAL is not set
CONFIG_VM86=y
# CONFIG_TOSHIBA is not set
# CONFIG_I8K is not set
# CONFIG_X86_REBOOTFIXUPS is not set
# CONFIG_MICROCODE is not set
CONFIG_X86_MSR=y
CONFIG_X86_CPUID=y

#
# Firmware Drivers
#
# CONFIG_EDD is not set
# CONFIG_DELL_RBU is not set
# CONFIG_DCDBAS is not set
CONFIG_DMIID=y
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_X86_PAE is not set
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_SPARSEMEM_STATIC=y
# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
CONFIG_BOUNCE=y
CONFIG_NR_QUICK=1
CONFIG_VIRT_TO_BUS=y
# CONFIG_MATH_EMULATION is not set
CONFIG_MTRR=y
# CONFIG_EFI is not set
CONFIG_SECCOMP=y
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
# CONFIG_KEXEC is not set
CONFIG_PHYSICAL_START=0x100000
# CONFIG_RELOCATABLE is not set
CONFIG_PHYSICAL_ALIGN=0x100000
# CONFIG_COMPAT_VDSO is not set

#
# Power management options (ACPI, APM)
#
CONFIG_PM=y
# CONFIG_PM_LEGACY is not set
# CONFIG_PM_DEBUG is not set
CONFIG_PM_SLEEP=y
CONFIG_SUSPEND_UP_POSSIBLE=y
CONFIG_SUSPEND=y
CONFIG_HIBERNATION_UP_POSSIBLE=y
# CONFIG_HIBERNATION is not set
CONFIG_ACPI=y
CONFIG_ACPI_SLEEP=y
# CONFIG_ACPI_PROCFS is not set
CONFIG_ACPI_PROC_EVENT=y
# CONFIG_ACPI_AC is not set
# CONFIG_ACPI_BATTERY is not set
CONFIG_ACPI_BUTTON=y
# CONFIG_ACPI_VIDEO is not set
# CONFIG_ACPI_FAN is not set
# CONFIG_ACPI_DOCK is not set
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_THERMAL=y
# CONFIG_ACPI_ASUS is not set
# CONFIG_ACPI_TOSHIBA is not set
CONFIG_ACPI_BLACKLIST_YEAR=2001
# CONFIG_ACPI_DEBUG is not set
CONFIG_ACPI_EC=y
CONFIG_ACPI_POWER=y
CONFIG_ACPI_SYSTEM=y
CONFIG_X86_PM_TIMER=y
# CONFIG_ACPI_CONTAINER is not set
# CONFIG_ACPI_SBS is not set
# CONFIG_APM is not set

#
# CPU Frequency scaling
#
# CONFIG_CPU_FREQ is not set

#
# CPU idle PM support
#
# CONFIG_CPU_IDLE is not set

#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
#
CONFIG_PCI=y
# CONFIG_PCI_GOBIOS is not set
# CONFIG_PCI_GOMMCONFIG is not set
# CONFIG_PCI_GODIRECT is not set
CONFIG_PCI_GOANY=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
# CONFIG_PCIEPORTBUS is not set
CONFIG_ARCH_SUPPORTS_MSI=y
CONFIG_PCI_MSI=y
# CONFIG_PCI_DEBUG is not set
# CONFIG_HT_IRQ is not set
CONFIG_ISA_DMA_API=y
# CONFIG_ISA is not set
# CONFIG_MCA is not set
# CONFIG_SCx200 is not set
# CONFIG_PCCARD is not set
# CONFIG_HOTPLUG_PCI is not set

#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_AOUT is not set
CONFIG_BINFMT_MISC=y

#
# Networking
#
CONFIG_NET=y

#
# Networking options
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
# CONFIG_IPV6_OPTIMISTIC_DAD is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
# CONFIG_IPV6_MIP6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
CONFIG_INET6_XFRM_MODE_TRANSPORT=y
CONFIG_INET6_XFRM_MODE_TUNNEL=y
# CONFIG_INET6_XFRM_MODE_BEET is not set
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
CONFIG_IPV6_SIT=y
# CONFIG_IPV6_TUNNEL is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set

#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set

#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set

#
# Wireless
#
# CONFIG_CFG80211 is not set
# CONFIG_WIRELESS_EXT is not set
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set

#
# Device Drivers
#

#
# Generic Driver Options
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
# CONFIG_PARPORT is not set
CONFIG_PNP=y
# CONFIG_PNP_DEBUG is not set

#
# Protocols
#
CONFIG_PNPACPI=y
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_UB is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_MISC_DEVICES=y
# CONFIG_IBM_ASM is not set
# CONFIG_PHANTOM is not set
# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
# CONFIG_MSI_LAPTOP is not set
# CONFIG_SONY_LAPTOP is not set
# CONFIG_THINKPAD_ACPI is not set
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y

#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_IDE_SATA is not set
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_IDEDISK_MULTI_MODE=y
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
CONFIG_BLK_DEV_IDEACPI=y
# CONFIG_IDE_TASK_IOCTL is not set
CONFIG_IDE_PROC_FS=y

#
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
# CONFIG_BLK_DEV_PLATFORM is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_IDEPNP is not set

#
# PCI IDE chipsets support
#
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_IDEPCI_PCIBUS_ORDER=y
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_GENERIC is not set
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
# CONFIG_BLK_DEV_ATIIXP is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_TRIFLEX is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5520 is not set
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_CS5535 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_IT8213 is not set
# CONFIG_BLK_DEV_IT821X is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
# CONFIG_BLK_DEV_SVWKS is not set
# CONFIG_BLK_DEV_SIIMAGE is not set
# CONFIG_BLK_DEV_SIS5513 is not set
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
CONFIG_BLK_DEV_VIA82CXXX=y
# CONFIG_BLK_DEV_TC86C001 is not set
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_BLK_DEV_HD is not set

#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
# CONFIG_SCSI_PROC_FS is not set

#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set

#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set

#
# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
CONFIG_ATA_ACPI=y
# CONFIG_SATA_AHCI is not set
# CONFIG_SATA_SVW is not set
# CONFIG_ATA_PIIX is not set
# CONFIG_SATA_MV is not set
# CONFIG_SATA_NV is not set
# CONFIG_PDC_ADMA is not set
# CONFIG_SATA_QSTOR is not set
# CONFIG_SATA_PROMISE is not set
# CONFIG_SATA_SX4 is not set
# CONFIG_SATA_SIL is not set
# CONFIG_SATA_SIL24 is not set
# CONFIG_SATA_SIS is not set
# CONFIG_SATA_ULI is not set
# CONFIG_SATA_VIA is not set
# CONFIG_SATA_VITESSE is not set
# CONFIG_SATA_INIC162X is not set
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CS5520 is not set
# CONFIG_PATA_CS5530 is not set
# CONFIG_PATA_CS5535 is not set
# CONFIG_PATA_CYPRESS is not set
# CONFIG_PATA_EFAR is not set
# CONFIG_ATA_GENERIC is not set
# CONFIG_PATA_HPT366 is not set
# CONFIG_PATA_HPT37X is not set
# CONFIG_PATA_HPT3X2N is not set
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_IT8213 is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_MARVELL is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_OLDPIIX is not set
# CONFIG_PATA_NETCELL is not set
# CONFIG_PATA_NS87410 is not set
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RZ1000 is not set
# CONFIG_PATA_SC1200 is not set
# CONFIG_PATA_SERVERWORKS is not set
# CONFIG_PATA_PDC2027X is not set
# CONFIG_PATA_SIL680 is not set
# CONFIG_PATA_SIS is not set
CONFIG_PATA_VIA=y
# CONFIG_PATA_WINBOND is not set
# CONFIG_MD is not set
# CONFIG_FUSION is not set

#
# IEEE 1394 (FireWire) support
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
# CONFIG_I2O is not set
CONFIG_MACINTOSH_DRIVERS=y
# CONFIG_MAC_EMUMOUSEBTN is not set
CONFIG_NETDEVICES=y
# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_VETH is not set
# CONFIG_NET_SB1000 is not set
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
CONFIG_NET_TULIP=y
# CONFIG_DE2104X is not set
CONFIG_TULIP=y
# CONFIG_TULIP_MWI is not set
# CONFIG_TULIP_MMIO is not set
# CONFIG_TULIP_NAPI is not set
# CONFIG_DE4X5 is not set
# CONFIG_WINBOND_840 is not set
# CONFIG_DM9102 is not set
# CONFIG_ULI526X is not set
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
# CONFIG_FORCEDETH is not set
# CONFIG_DGRS is not set
# CONFIG_EEPRO100 is not set
# CONFIG_E100 is not set
# CONFIG_FEALNX is not set
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_8139CP is not set
CONFIG_8139TOO=y
# CONFIG_8139TOO_PIO is not set
# CONFIG_8139TOO_TUNE_TWISTER is not set
# CONFIG_8139TOO_8129 is not set
# CONFIG_8139_OLD_RX_RESET is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
# CONFIG_E1000E is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_MLX4_CORE is not set
# CONFIG_TR is not set

#
# Wireless LAN
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set

#
# USB Network Adapters
#
# CONFIG_USB_CATC is not set
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_ISDN is not set
# CONFIG_PHONE is not set

#
# Input device support
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set

#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1280
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=1024
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set

#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set

#
# Hardware I/O ports
#
CONFIG_SERIO=y
CONFIG_SERIO_I8042=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_SERIO_CT82C710 is not set
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set

#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_NOZOMI is not set

#
# Serial drivers
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_PNP=y
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set

#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_IPMI_HANDLER is not set
CONFIG_HW_RANDOM=y
# CONFIG_HW_RANDOM_INTEL is not set
# CONFIG_HW_RANDOM_AMD is not set
# CONFIG_HW_RANDOM_GEODE is not set
CONFIG_HW_RANDOM_VIA=y
# CONFIG_NVRAM is not set
CONFIG_RTC=y
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_SONYPI is not set
CONFIG_AGP=y
# CONFIG_AGP_ALI is not set
# CONFIG_AGP_ATI is not set
# CONFIG_AGP_AMD is not set
# CONFIG_AGP_AMD64 is not set
# CONFIG_AGP_INTEL is not set
# CONFIG_AGP_NVIDIA is not set
# CONFIG_AGP_SIS is not set
# CONFIG_AGP_SWORKS is not set
CONFIG_AGP_VIA=y
# CONFIG_AGP_EFFICEON is not set
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
# CONFIG_PC8736x_GPIO is not set
# CONFIG_NSC_GPIO is not set
# CONFIG_CS5535_GPIO is not set
# CONFIG_RAW_DRIVER is not set
CONFIG_HPET=y
# CONFIG_HPET_RTC_IRQ is not set
CONFIG_HPET_MMAP=y
# CONFIG_HANGCHECK_TIMER is not set
# CONFIG_TCG_TPM is not set
# CONFIG_TELCLOCK is not set
CONFIG_DEVPORT=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
# CONFIG_I2C_CHARDEV is not set

#
# I2C Algorithms
#
CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_ALGOPCF is not set
# CONFIG_I2C_ALGOPCA is not set

#
# I2C Hardware Bus support
#
# CONFIG_I2C_ALI1535 is not set
# CONFIG_I2C_ALI1563 is not set
# CONFIG_I2C_ALI15X3 is not set
# CONFIG_I2C_AMD756 is not set
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_I2C_SIMTEC is not set
# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_TINY_USB is not set
CONFIG_I2C_VIA=y
CONFIG_I2C_VIAPRO=y
# CONFIG_I2C_VOODOO3 is not set

#
# Miscellaneous I2C Chip support
#
# CONFIG_SENSORS_DS1337 is not set
# CONFIG_SENSORS_DS1374 is not set
# CONFIG_DS1682 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set

#
# SPI support
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
CONFIG_HWMON_VID=y
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ABITUGURU3 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1029 is not set
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ADT7470 is not set
# CONFIG_SENSORS_K8TEMP is not set
CONFIG_SENSORS_ASB100=y
# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_F71882FG is not set
# CONFIG_SENSORS_F75375S is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
# CONFIG_SENSORS_GL518SM is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_CORETEMP is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM75 is not set
# CONFIG_SENSORS_LM77 is not set
# CONFIG_SENSORS_LM78 is not set
# CONFIG_SENSORS_LM80 is not set
# CONFIG_SENSORS_LM83 is not set
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_LM93 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_DME1737 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_SENSORS_HDAPS is not set
# CONFIG_SENSORS_APPLESMC is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
# CONFIG_WATCHDOG is not set

#
# Sonics Silicon Backplane
#
CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set

#
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set

#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
# CONFIG_DVB_CORE is not set
CONFIG_DAB=y
# CONFIG_USB_DABUSB is not set

#
# Graphics support
#
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_PROGEAR is not set

#
# Display device support
#
# CONFIG_DISPLAY_SUPPORT is not set
# CONFIG_VGASTATE is not set
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
CONFIG_FB_DDC=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
# CONFIG_FB_SYS_IMAGEBLIT is not set
# CONFIG_FB_SYS_FOPS is not set
CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
CONFIG_FB_BACKLIGHT=y
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set

#
# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
# CONFIG_FB_VESA is not set
# CONFIG_FB_EFI is not set
# CONFIG_FB_HECUBA is not set
# CONFIG_FB_HGA is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_I810 is not set
# CONFIG_FB_LE80578 is not set
# CONFIG_FB_INTEL is not set
# CONFIG_FB_MATROX is not set
CONFIG_FB_RADEON=y
CONFIG_FB_RADEON_I2C=y
CONFIG_FB_RADEON_BACKLIGHT=y
# CONFIG_FB_RADEON_DEBUG is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_VT8623 is not set
# CONFIG_FB_CYBLA is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_ARK is not set
# CONFIG_FB_PM3 is not set
# CONFIG_FB_GEODE is not set
# CONFIG_FB_VIRTUAL is not set

#
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
# CONFIG_VGACON_SOFT_SCROLLBACK is not set
# CONFIG_VIDEO_SELECT is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
# CONFIG_FONT_8x8 is not set
CONFIG_FONT_8x16=y
# CONFIG_FONT_6x11 is not set
# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_10x18 is not set
# CONFIG_LOGO is not set

#
# Sound
#
CONFIG_SOUND=y

#
# Advanced Linux Sound Architecture
#
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
CONFIG_SND_HWDEP=y
CONFIG_SND_RAWMIDI=y
CONFIG_SND_SEQUENCER=y
# CONFIG_SND_SEQ_DUMMY is not set
# CONFIG_SND_MIXER_OSS is not set
# CONFIG_SND_PCM_OSS is not set
# CONFIG_SND_SEQUENCER_OSS is not set
CONFIG_SND_RTCTIMER=y
CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y
# CONFIG_SND_DYNAMIC_MINORS is not set
CONFIG_SND_SUPPORT_OLD_API=y
# CONFIG_SND_VERBOSE_PROCFS is not set
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set

#
# Generic devices
#
CONFIG_SND_MPU401_UART=y
CONFIG_SND_OPL3_LIB=y
# CONFIG_SND_DUMMY is not set
# CONFIG_SND_VIRMIDI is not set
# CONFIG_SND_MTPAV is not set
# CONFIG_SND_SERIAL_U16550 is not set
# CONFIG_SND_MPU401 is not set

#
# PCI devices
#
# CONFIG_SND_AD1889 is not set
# CONFIG_SND_ALS300 is not set
# CONFIG_SND_ALS4000 is not set
# CONFIG_SND_ALI5451 is not set
# CONFIG_SND_ATIIXP is not set
# CONFIG_SND_ATIIXP_MODEM is not set
# CONFIG_SND_AU8810 is not set
# CONFIG_SND_AU8820 is not set
# CONFIG_SND_AU8830 is not set
# CONFIG_SND_AZT3328 is not set
# CONFIG_SND_BT87X is not set
# CONFIG_SND_CA0106 is not set
CONFIG_SND_CMIPCI=y
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS5530 is not set
# CONFIG_SND_CS5535AUDIO is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
# CONFIG_SND_DARLA24 is not set
# CONFIG_SND_GINA24 is not set
# CONFIG_SND_LAYLA24 is not set
# CONFIG_SND_MONA is not set
# CONFIG_SND_MIA is not set
# CONFIG_SND_ECHO3G is not set
# CONFIG_SND_INDIGO is not set
# CONFIG_SND_INDIGOIO is not set
# CONFIG_SND_INDIGODJ is not set
# CONFIG_SND_EMU10K1 is not set
# CONFIG_SND_EMU10K1X is not set
# CONFIG_SND_ENS1370 is not set
# CONFIG_SND_ENS1371 is not set
# CONFIG_SND_ES1938 is not set
# CONFIG_SND_ES1968 is not set
# CONFIG_SND_FM801 is not set
# CONFIG_SND_HDA_INTEL is not set
# CONFIG_SND_HDSP is not set
# CONFIG_SND_HDSPM is not set
# CONFIG_SND_ICE1712 is not set
# CONFIG_SND_ICE1724 is not set
# CONFIG_SND_INTEL8X0 is not set
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_KORG1212 is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
# CONFIG_SND_PCXHR is not set
# CONFIG_SND_RIPTIDE is not set
# CONFIG_SND_RME32 is not set
# CONFIG_SND_RME96 is not set
# CONFIG_SND_RME9652 is not set
# CONFIG_SND_SONICVIBES is not set
# CONFIG_SND_TRIDENT is not set
# CONFIG_SND_VIA82XX is not set
# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VX222 is not set
# CONFIG_SND_YMFPCI is not set

#
# USB devices
#
# CONFIG_SND_USB_AUDIO is not set
# CONFIG_SND_USB_USX2Y is not set
# CONFIG_SND_USB_CAIAQ is not set

#
# System on Chip audio support
#
# CONFIG_SND_SOC is not set

#
# SoC Audio support for SuperH
#

#
# Open Sound System
#
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set

#
# USB Input Devices
#
CONFIG_USB_HID=y
# CONFIG_USB_HIDINPUT_POWERBOOK is not set
# CONFIG_HID_FF is not set
# CONFIG_USB_HIDDEV is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set

#
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
# CONFIG_USB_PERSIST is not set
# CONFIG_USB_OTG is not set

#
# USB Host Controller Drivers
#
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
# CONFIG_USB_OHCI_HCD is not set
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
# CONFIG_USB_R8A66597_HCD is not set

#
# USB Device Class drivers
#
# CONFIG_USB_ACM is not set
CONFIG_USB_PRINTER=y

#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#

#
# may also be needed; see USB_STORAGE Help for more information
#
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_ISD200 is not set
# CONFIG_USB_STORAGE_DPCM is not set
# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
# CONFIG_USB_STORAGE_ALAUDA is not set
# CONFIG_USB_STORAGE_KARMA is not set
# CONFIG_USB_LIBUSUAL is not set

#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
# CONFIG_USB_MON is not set

#
# USB port drivers
#

#
# USB Serial Converter support
#
# CONFIG_USB_SERIAL is not set

#
# USB Miscellaneous drivers
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_BERRY_CHARGE is not set
# CONFIG_USB_IPHONE is not set
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
# CONFIG_USB_GOTEMP is not set

#
# USB DSL modem support
#

#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
# CONFIG_MMC is not set
# CONFIG_NEW_LEDS is not set
# CONFIG_INFINIBAND is not set
# CONFIG_EDAC is not set
# CONFIG_RTC_CLASS is not set
# CONFIG_DMADEVICES is not set
CONFIG_VIRTUALIZATION=y
# CONFIG_KVM is not set

#
# Userspace I/O
#
# CONFIG_UIO is not set

#
# File systems
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_EXT4DEV_FS is not set
CONFIG_REISER4_FS=y
# CONFIG_REISER4_DEBUG is not set
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
# CONFIG_REISERFS_FS_XATTR is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_FUSE_FS is not set

#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
# CONFIG_ZISOFS is not set
CONFIG_UDF_FS=y
CONFIG_UDF_NLS=y

#
# DOS/FAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
CONFIG_NTFS_FS=y
# CONFIG_NTFS_DEBUG is not set
CONFIG_NTFS_RW=y

#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
# CONFIG_CONFIGFS_FS is not set

#
# Layered filesystems
#
# CONFIG_UNION_FS is not set

#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set

#
# Network File Systems
#
# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
# CONFIG_SMB_FS is not set
CONFIG_CIFS=y
# CONFIG_CIFS_STATS is not set
# CONFIG_CIFS_WEAK_PW_HASH is not set
# CONFIG_CIFS_XATTR is not set
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_EXPERIMENTAL is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set

#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y

#
# Native Language Support
#
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
CONFIG_NLS_ISO8859_15=y
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
CONFIG_NLS_UTF8=y

#
# Distributed Lock Manager
#
# CONFIG_DLM is not set
CONFIG_INSTRUMENTATION=y
# CONFIG_PROFILING is not set

#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_UNUSED_SYMBOLS=y
# CONFIG_PAGE_OWNER is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
CONFIG_DEBUG_SLAB=y
# CONFIG_DEBUG_SLAB_LEAK is not set
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_PI_LIST=y
# CONFIG_RT_MUTEX_TESTER is not set
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
CONFIG_LOCKDEP=y
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_LOCKDEP is not set
CONFIG_TRACE_IRQFLAGS=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_VM=y
CONFIG_DEBUG_LIST=y
# CONFIG_FRAME_POINTER is not set
CONFIG_UNWIND_INFO=y
CONFIG_STACK_UNWIND=y
# CONFIG_PROFILE_LIKELY is not set
# CONFIG_FORCED_INLINING is not set
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_DEBUG_SYNCHRO_TEST is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_WANT_EXTRA_DEBUG_INFORMATION is not set
# CONFIG_KGDB is not set
# CONFIG_KGDB_ATTACH_WAIT is not set
CONFIG_EARLY_PRINTK=y
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
CONFIG_DEBUG_RODATA=y
CONFIG_4KSTACKS=y
CONFIG_X86_FIND_SMP_CONFIG=y
CONFIG_X86_MPPARSE=y
CONFIG_DOUBLEFAULT=y

#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_ECB is not set
# CONFIG_CRYPTO_CBC is not set
# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_CRYPTD is not set
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_TWOFISH_586 is not set
# CONFIG_CRYPTO_SERPENT is not set
# CONFIG_CRYPTO_AES is not set
# CONFIG_CRYPTO_AES_586 is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_KHAZAD is not set
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_AUTHENC is not set
CONFIG_CRYPTO_HW=y
# CONFIG_CRYPTO_DEV_PADLOCK is not set
# CONFIG_CRYPTO_DEV_GEODE is not set

#
# Library routines
#
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_X86_BIOS_REBOOT=y
CONFIG_KTIME_SCALAR=y

^ permalink raw reply

* Re: Network Namespace status
From: Oliver Hartkopp @ 2007-09-14  6:03 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linux Containers, netdev, David Miller, Tejun Heo,
	Greg Kroah-Hartman, Andrew Morton, Thomas Gleixner, Urs Thuermann
In-Reply-To: <m18x7a5qif.fsf@ebiederm.dsl.xmission.com>

Eric W. Biederman wrote:
> Looking into my patch queue I have:
> 5 patches for cleaning up and making a per network namespace loopback device.
> 4 patches for making rtnetlink message processing per network namespace
> 1 patch for making AF_UNIX per network namespace
> 1 patch for making AF_PACKET per network namespace
>
> The ipv4 part of my patchset is currently working but it needs some
> more cleanup and reordering of patches before it is ready to go anywhere.
> Nothing has been done for ipv6, but the changes should very much parallel
> ipv4.
>
> The other protocols I haven't even looked at yet.
>   

Hi Eric,

can you send me your current AF_PACKET patch? I just want to update our
recent post of the CAN (controller area network) subsystem (AF_CAN)
which is (in some parts) similar to AF_PACKET. So i can take a look on
it to provide the latest technique in the next post ...

Thanks,
Oliver



^ permalink raw reply

* [ofa-general] Re: [PATCH 0/9 Rev3] Implement batching skb API and support in IPoIB
From: Bill Fink @ 2007-09-14  7:20 UTC (permalink / raw)
  To: hadi
  Cc: jagana, peter.p.waskiewicz.jr, herbert, gaagaan, Robert.Olsson,
	netdev, rdreier, mcarlson, kaber, jeff, general, mchan, tgraf,
	johnpol, shemminger, David Miller, jheffner, sri
In-Reply-To: <1188257019.4250.55.camel@localhost>

On Mon, 27 Aug 2007, jamal wrote:

> On Sun, 2007-26-08 at 19:04 -0700, David Miller wrote:
> 
> > The transfer is much better behaved if we ACK every two full sized
> > frames we copy into the receiver, and therefore don't stretch ACK, but
> > at the cost of cpu utilization.
> 
> The rx coalescing in theory should help by accumulating more ACKs on the
> rx side of the sender. But it doesnt seem to do that i.e For the 9K MTU,
> you are better off to turn off the coalescing if you want higher
> numbers. Also some of the TOE vendors (chelsio?) claim to have fixed
> this by reducing bursts on outgoing packets.
>  
> Bill:
> who suggested (as per your email) the 75usec value and what was it based
> on measurement-wise? 

Belatedly getting back to this thread.  There was a recent myri10ge
patch that changed the default value for tx/rx interrupt coalescing
to 75 usec claiming it was an optimum value for maximum throughput
(and is also mentioned in their external README documentation).

I also did some empirical testing to determine the effect of different
values of TX/RX interrupt coalescing on 10-GigE network performance,
both with TSO enabled and with TSO disabled.  The actual test runs
are attached at the end of this message, but the results are summarized
in the following table (network performance in Mbps).

		        TX/RX interrupt coalescing in usec (both sides)
		   0	  15	  30	  45	  60	  75	  90	 105

TSO enabled	8909	9682	9716	9725	9739	9745	9688	9648
TSO disabled	9113	9910	9910	9910	9910	9910	9910	9910

TSO disabled performance is always better than equivalent TSO enabled
performance.  With TSO enabled, the optimum performance is indeed at
a TX/RX interrupt coalescing value of 75 usec.  With TSO disabled,
performance is the full 10-GigE line rate of 9910 Mbps for any value
of TX/RX interrupt coalescing from 15 usec to 105 usec.

> BTW, thanks for the finding the energy to run those tests and a very
> refreshing perspective. I dont mean to add more work, but i had some
> queries;
> On your earlier tests, i think that Reno showed some significant
> differences on the lower MTU case over BIC. I wonder if this is
> consistent? 

Here's a retest (5 tests each):

TSO enabled:

TCP Cubic (initial_ssthresh set to 0):

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5007.6295 MB /  10.06 sec = 4176.1807 Mbps 36 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4950.9279 MB /  10.06 sec = 4130.2528 Mbps 36 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4917.1742 MB /  10.05 sec = 4102.5772 Mbps 35 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4948.7920 MB /  10.05 sec = 4128.7990 Mbps 36 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4937.5765 MB /  10.05 sec = 4120.6460 Mbps 35 %TX 99 %RX

TCP Bic (initial_ssthresh set to 0):

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5005.5335 MB /  10.06 sec = 4172.9571 Mbps 36 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5001.0625 MB /  10.06 sec = 4169.2960 Mbps 36 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4957.7500 MB /  10.06 sec = 4135.7355 Mbps 36 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4957.3777 MB /  10.06 sec = 4135.6252 Mbps 36 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5059.1815 MB /  10.05 sec = 4221.3546 Mbps 37 %TX 99 %RX

TCP Reno:

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4973.3532 MB /  10.06 sec = 4147.3589 Mbps 36 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4984.4375 MB /  10.06 sec = 4155.2131 Mbps 36 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4995.6841 MB /  10.06 sec = 4166.2734 Mbps 36 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4982.2500 MB /  10.05 sec = 4156.7586 Mbps 36 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4989.9796 MB /  10.05 sec = 4163.0949 Mbps 36 %TX 99 %RX

TSO disabled:

TCP Cubic (initial_ssthresh set to 0):

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5075.8125 MB /  10.02 sec = 4247.3408 Mbps 99 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5056.0000 MB /  10.03 sec = 4229.9621 Mbps 100 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5047.4375 MB /  10.03 sec = 4223.1203 Mbps 99 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5066.1875 MB /  10.03 sec = 4239.1659 Mbps 100 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4986.3750 MB /  10.03 sec = 4171.9906 Mbps 99 %TX 100 %RX

TCP Bic (initial_ssthresh set to 0):

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5040.5625 MB /  10.03 sec = 4217.3521 Mbps 100 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5049.7500 MB /  10.03 sec = 4225.4585 Mbps 99 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5076.5000 MB /  10.03 sec = 4247.6632 Mbps 100 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5017.2500 MB /  10.03 sec = 4197.4990 Mbps 100 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5013.3125 MB /  10.03 sec = 4194.8851 Mbps 100 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5036.0625 MB /  10.03 sec = 4213.9195 Mbps 100 %TX 100 %RX

TCP Reno:

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5006.8750 MB /  10.02 sec = 4189.6051 Mbps 99 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5028.1250 MB /  10.02 sec = 4207.4553 Mbps 100 %TX 99 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5021.9375 MB /  10.02 sec = 4202.2668 Mbps 99 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5000.5625 MB /  10.03 sec = 4184.3109 Mbps 99 %TX 100 %RX
[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5025.1250 MB /  10.03 sec = 4204.7378 Mbps 99 %TX 100 %RX

Not too much variation here, and not quite as high results
as previously.  Some further testing reveals that while this
time I mainly get results like (here for TCP Bic with TSO
disabled):

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 4958.0625 MB /  10.02 sec = 4148.9361 Mbps 100 %TX 99 %RX

I also sometimes get results like:

[root@lang2 ~]# nuttcp -M1460 -w10m 192.168.88.16
 5882.1875 MB /  10.00 sec = 4932.5549 Mbps 100 %TX 90 %RX

The higher performing results seem to correspond to when there's a
somewhat lower receiver CPU utilization.  I'm not sure but there
could also have been an effect from running the "-M1460" test after
the 9000 byte jumbo frame test (no jumbo tests were done at all prior
to running the above sets of 5 tests, although I did always discard
an initial "warmup" test, and now that I think about it some of
those initial discarded "warmup" tests did have somewhat anomalously
high results).

> A side note: Although the experimentation reduces the variables (eg
> tying all to CPU0), it would be more exciting to see multi-cpu and
> multi-flow sender effect (which IMO is more real world). 

These systems are intended as test systems for 10-GigE networks,
and as such it's important to get as consistently close to full
10-GigE line rate as possible, and that's why the interrupts and
nuttcp application are tied to CPU0, with almost all other system
applications tied to CPU1.

Now on another system that's intended as a 10-GigE firewall system,
it has 2 Myricom 10-GigE NICs with the interrupts for eth2 tied to
CPU0 and the interrupts for CPU1 tied to CPU1.  In IP forwarding
tests of this system, I have basically achieved full bidirectional
10-GigE line rate IP forwarding with 9000 byte jumbo frames.

chance4 -> chance6 -> chance9 4.85 Gbps rate limited TCP stream
chance5 -> chance6 -> chance9 4.85 Gbps rate limited TCP stream
chance7 <- chance6 <- chance8 10.0 Gbps non-rate limited TCP stream

[root@chance7 ~]# nuttcp -Ic4tc9 -Ri4.85g -w10m 192.168.88.8 192.168.89.16 & \
    nuttcp -Ic5tc9 -Ri4.85g -w10m -P5100 -p5101 192.168.88.9 192.168.89.16 & \
    nuttcp -Ic7rc8 -r -w10m 192.168.89.15
c4tc9:  5778.6875 MB /  10.01 sec = 4842.7158 Mbps 100 %TX 42 %RX
c5tc9:  5778.9375 MB /  10.01 sec = 4843.1595 Mbps 100 %TX 40 %RX
c7rc8: 11509.1875 MB /  10.00 sec = 9650.8009 Mbps 99 %TX 74 %RX

If there's some other specific test you'd like to see, and it's not
too difficult to set up and I have some spare time, I'll see what I
can do.

						-Bill



Testing of effect of RX/TX interrupt coalescing on 10-GigE network performance
(both with TSO enabled and with TSO disabled):
--------------------------------------------------------------------------------

No RX/TX interrupt coalescing (either side):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
10649.8750 MB /  10.03 sec = 8908.9806 Mbps 97 %TX 100 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
10879.5000 MB /  10.02 sec = 9112.5141 Mbps 99 %TX 99 %RX

RX/TX interrupt coalescing set to 15 usec (both sides):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11546.7500 MB /  10.00 sec = 9682.0785 Mbps 99 %TX 90 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.9375 MB /  10.00 sec = 9910.3702 Mbps 100 %TX 92 %RX

RX/TX interrupt coalescing set to 30 usec (both sides):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11587.1250 MB /  10.00 sec = 9715.9489 Mbps 99 %TX 81 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.8125 MB /  10.00 sec = 9910.3040 Mbps 100 %TX 81 %RX

RX/TX interrupt coalescing set to 45 usec (both sides):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11597.8750 MB /  10.00 sec = 9724.9902 Mbps 99 %TX 76 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.6250 MB /  10.00 sec = 9910.0933 Mbps 100 %TX 77 %RX

RX/TX interrupt coalescing set to 60 usec (both sides):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11614.7500 MB /  10.00 sec = 9739.1323 Mbps 100 %TX 74 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.4375 MB /  10.00 sec = 9909.9995 Mbps 100 %TX 76 %RX

RX/TX interrupt coalescing set to 75 usec (both sides):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11621.7500 MB /  10.00 sec = 9745.0993 Mbps 100 %TX 72 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.0625 MB /  10.00 sec = 9909.7881 Mbps 100 %TX 75 %RX

RX/TX interrupt coalescing set to 90 usec (both sides):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11553.1250 MB /  10.00 sec = 9687.6458 Mbps 100 %TX 71 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.4375 MB /  10.00 sec = 9910.0837 Mbps 100 %TX 73 %RX

RX/TX interrupt coalescing set to 105 usec (both sides):

TSO enabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11505.7500 MB /  10.00 sec = 9647.8558 Mbps 99 %TX 69 %RX

TSO disabled:

[root@lang2 ~]# nuttcp -w10m 192.168.88.16
11818.4375 MB /  10.00 sec = 9910.0530 Mbps 100 %TX 74 %RX

^ permalink raw reply

* [PATCH][NETNS] Use list_for_each_entry_continue_reverse in setup_net
From: Pavel Emelyanov @ 2007-09-14  7:39 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linux Netdev List, Linux Containers, devel, Daniel Lezcano

I proposed introducing a list_for_each_entry_continue_reverse
macro to be used in setup_net() when unrolling the failed
->init callback.

Here is the macro and some more cleanup in the setup_net() itself
to remove one variable from the stack :) Minor, but the code
looks nicer.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

I have problems with cloning repos from git.openvz.org, so
this patch comes to the yesterdays net-2.6.24 David's tree.

diff --git a/include/linux/list.h b/include/linux/list.h
index f29fc9c..ad9dcb9 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -525,6 +525,20 @@ static inline void list_splice_init_rcu(
 	     pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)		\
+	for (pos = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     prefetch(pos->member.prev), &pos->member != (head);	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
  * list_for_each_entry_from - iterate over list of given type from the current point
  * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 1fc513c..a9dd261 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -102,7 +102,6 @@ static int setup_net(struct net *net)
 {
 	/* Must be called with net_mutex held */
 	struct pernet_operations *ops;
-	struct list_head *ptr;
 	int error;
 
 	memset(net, 0, sizeof(struct net));
@@ -110,8 +109,7 @@ static int setup_net(struct net *net)
 	atomic_set(&net->use_count, 0);
 
 	error = 0;
-	list_for_each(ptr, &pernet_list) {
-		ops = list_entry(ptr, struct pernet_operations, list);
+	list_for_each_entry(ops, &pernet_list, list) {
 		if (ops->init) {
 			error = ops->init(net);
 			if (error < 0)
@@ -120,12 +118,12 @@ static int setup_net(struct net *net)
 	}
 out:
 	return error;
+
 out_undo:
 	/* Walk through the list backwards calling the exit functions
 	 * for the pernet modules whose init functions did not fail.
 	 */
-	for (ptr = ptr->prev; ptr != &pernet_list; ptr = ptr->prev) {
-		ops = list_entry(ptr, struct pernet_operations, list);
+	list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
 		if (ops->exit)
 			ops->exit(net);
 	}

^ permalink raw reply related

* [PATCH][NETNS] Consolidate hashes creation in netdev_init()
From: Pavel Emelyanov @ 2007-09-14  8:40 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linux Netdev List, Linux Containers, devel, Daniel Lezcano

The dev_name_hash and the dev_index_hash are now booth kmalloc-ed
(and each element is properly initialized as usually) so I think
it's worth consolidating this code making it look nicer (and 
saving 28 bytes of .text section ;) )

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/net/core/dev.c b/net/core/dev.c
index a22a95d..1a60ed2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4258,32 +4258,39 @@ int netdev_compute_features(unsigned lon
 }
 EXPORT_SYMBOL(netdev_compute_features);
 
+static struct hlist_head *netdev_create_hash(void)
+{
+	int i;
+	struct hlist_head *hash;
+
+	hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL);
+	if (hash != NULL)
+		for (i = 0; i < NETDEV_HASHENTRIES; i++)
+			INIT_HLIST_HEAD(&hash[i]);
+
+	return hash;
+}
+
 /* Initialize per network namespace state */
 static int netdev_init(struct net *net)
 {
-	int i;
 	INIT_LIST_HEAD(&net->dev_base_head);
 	rwlock_init(&dev_base_lock);
 
-	net->dev_name_head = kmalloc(
-		sizeof(*net->dev_name_head)*NETDEV_HASHENTRIES, GFP_KERNEL);
-	if (!net->dev_name_head)
-		return -ENOMEM;
-
-	net->dev_index_head = kmalloc(
-		sizeof(*net->dev_index_head)*NETDEV_HASHENTRIES, GFP_KERNEL);
-	if (!net->dev_index_head) {
-		kfree(net->dev_name_head);
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < NETDEV_HASHENTRIES; i++)
-		INIT_HLIST_HEAD(&net->dev_name_head[i]);
-
-	for (i = 0; i < NETDEV_HASHENTRIES; i++)
-		INIT_HLIST_HEAD(&net->dev_index_head[i]);
+	net->dev_name_head = netdev_create_hash();
+	if (net->dev_name_head == NULL)
+		goto err_name;
+
+	net->dev_index_head = netdev_create_hash();
+	if (net->dev_index_head == NULL)
+		goto err_idx;
 
 	return 0;
+
+err_idx:
+	kfree(net->dev_name_head);
+err_name:
+	return -ENOMEM;
 }
 
 static void netdev_exit(struct net *net)

^ permalink raw reply related

* Re: [BUG] tg3 cannot do PXE (loses MAC address) after soft reboot
From: Ingo Oeser @ 2007-09-14  8:14 UTC (permalink / raw)
  To: Michael Chan; +Cc: Lucas Nussbaum, netdev
In-Reply-To: <1189716472.9540.106.camel@dell>

Michael Chan schrieb:
> On Thu, 2007-09-13 at 21:28 +0200, Lucas Nussbaum wrote:
> > Erm, Wouldn't it be possible to print a warning when the driver loads,
> > saying that the firmware is outdated ?
> 
> It's possible, but would require the driver to parse the version string.
> The driver currently reports the version string for information and for
> the human to parse it.

Yes, but most humans don't know all valid firmware versions of their 
components.

Is it enough to parse the first number in the firmware via simple_strtoul()?

Then we could do this (pseudo-kernel-code :-)):


firmare_version = simple_strtoul(version_string, NULL, 0);

if (firmware_version < oldest_supported) {
	printk(KERN_WARNING "Please upgrade the firmware (you have %s, we need at least %d)\n", 
		version_string, oldest_supported);
} else if (firmware_version > newest_supported) {
	printk(KERN_INFO "Firmware version %s (latest supported: %d). You might need a newer driver.\n", 
		version_string, oldest_supported);
} else if (firmware_version != newest_supported) {
	dprintk("Firmware version %s (latest supported: %d). You might consider a firmware upgrade.\n", 
		version_string, oldest_supported);
}

Maybe that mechanism should be global somewhere? Having this kind of information available
would help system maintenance in heterogenous hardware environments.

Best regards

Ingo Oeser

^ permalink raw reply

* [RESEND] Implement batching skb API and support in IPoIB
From: Krishna Kumar2 @ 2007-09-14  8:52 UTC (permalink / raw)
  To: David Miller
  Cc: gaagaan, general, hadi, herbert, jagana, jeff, johnpol, kaber,
	kumarkr, mcarlson, mchan, netdev, peter.p.waskiewicz.jr, rdreier,
	rick.jones2, Robert.Olsson, shemminger, sri, tgraf, xma


Hi Dave,

I am re-sending in case you didn't get this earlier. Also sending REV5 of
the patch.
I will send patch for e1000e on monday or tuesday after making the changes
and
testing over the weekend.

thanks,

- KK

__________________

Hi Dave,

David Miller <davem@davemloft.net> wrote on 08/29/2007 10:21:50 AM:

> From: Krishna Kumar2 <krkumar2@in.ibm.com>
> Date: Wed, 29 Aug 2007 08:53:30 +0530
>
> > I am scp'ng from 192.168.1.1 to 192.168.1.2 and captured at the send
> > side.
>
> Bad choice of test, this is cpu limited since the scp
> has to encrypt and MAC hash all the data it sends.
>
> Use something like straight ftp or "bw_tcp" from lmbench.

I used bw_tcp from lmbench-3. I transfered 500MB and captured
the tcpdump, and analysis at various points gave pipeline sizes:

26064, 27792, 22888, 23168, 23448, 20272, 23168, 4344, 10136,
164792, 35920, 26344, 24336, 24336, 23168, 25784, 23168,

There was one huge 164K, otherwise most were in smaller ranges
like 20-30K. I ran the following test script:

SERVER=192.168.1.2
BYTES=100m
BUFFERSIZES="4096 16384 65536 131072 262144"
PROCS="1 8"
ITERATIONS=5

for m in $BUFFERSIZES
do
      for procs in $PROCS
      do
            echo TEST: Size:$m Procs:$procs
            bw_tcp -N $ITERATIONS -m $m -M $BYTES -P $procs $SERVER
      done
done

Result is:
Test without batching:
#       Size       Procs     BW (MB/s)
1       4096       1         117.39
2       16384      1         117.49
3       65536      1         117.55
4       131072     1         117.55
5       262144     1         117.58

6       4096       8         117.18
7       16384      8         117.47
8       65536      8         117.54
9       131072     8         117.59
10      262144     8         117.55

Test with batching:
#       Size       Procs     BW (MB/s)
1       4096       1         117.39
2       16384      1         117.48
3       65536      1         117.55
4       131072     1         117.58
5       262144     1         117.58

6       4096       8         117.19
7       16384      8         117.46
8       65536      8         117.53
9       131072     8         117.55
10      262144     8         117.60

So it doesn't seem to harm e1000.

Can someone give a link to the E1000E driver? I couldn't find it
after downloading Jeff's netdev-2.6 tree.

Thanks,

- KK


^ permalink raw reply

* [PATCH 0/10 REV5] Implement skb batching and support in IPoIB/E1000
From: Krishna Kumar @ 2007-09-14  9:00 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, rick.jones2, xma, gaagaan, netdev, rdreier,
	peter.p.waskiewicz.jr, mcarlson, jeff, mchan, general, kumarkr,
	tgraf, randy.dunlap, Krishna Kumar, sri

This set of patches implements the batching xmit capability, and adds support
for batching in IPoIB and E1000 (E1000 driver changes is ported, thanks to
changes taken from Jamal's code from an old kernel).

List of changes from previous revision:
----------------------------------------
1. [Dave] Enable batching as default (change in register_netdev).
2. [Randy] Update documentation (however ethtool cmd to get/set batching is
	not implemented, hence I am guessing the usage).
3. [KK] When changing tx_batch_skb, qdisc xmits need to be blocked since
	qdisc_restart() drops queue_lock before calling driver xmit, and
	driver could find blist change under it.
4. [KK] sched: requeue could wrongly requeue skb already put in the batching
	list (in case a single skb was sent to the device but not sent as the
	device was full, resulting in the skb getting added to blist). This
	also results in slight optimization of batching behavior where for
	getting skbs #2 onwards don't require to check for gso_skb as that
	is the first skb that is processed.
4. [KK] Change documentation to explain this behavior.
5. [KK] sched: Fix panic when GSO is enabled in driver.
6. [KK] IPoIB: Small optimization in ipoib_ib_handle_tx_wc
7. [KK] netdevice: Needed to change NETIF_F_GSO_SHIFT/NETIF_F_GSO_MASK as
	BATCH_SKBS is now defined as 65536 (earlier it was using 8192 which
	was taken up by NETIF_F_NETNS_LOCAL).


Will submit in the next 1-2 days:
---------------------------------
1. [Auke] Enable batching in e1000e.


Extras that I can do later:
---------------------------
1. [Patrick] Use skb_blist statically in netdevice. This could also be used
	to integrate GSO and batching.
2. [Evgeniy] Useful to splice lists dev_add_skb_to_blist (and this can be
	done for regular xmit's of GSO skbs too for #1 above).

Patches are described as:
		 Mail 0/10:  This mail
		 Mail 1/10:  HOWTO documentation
		 Mail 2/10:  Introduce skb_blist, NETIF_F_BATCH_SKBS, use
		 	     single API for batching/no-batching, etc.
		 Mail 3/10:  Modify qdisc_run() to support batching
		 Mail 4/10:  Add ethtool support to enable/disable batching
		 Mail 5/10:  IPoIB: Header file changes to use batching
		 Mail 6/10:  IPoIB: CM & Multicast changes
		 Mail 7/10:  IPoIB: Verbs changes to use batching
		 Mail 8/10:  IPoIB: Internal post and work completion handler
		 Mail 9/10:  IPoIB: Implement the new batching capability
		 Mail 10/10: E1000: Implement the new batching capability

Issues:
--------
The retransmission problem reported earlier seems to happen when mthca is
used as the underlying device, but when I tested ehca the retransmissions
dropped to normal levels (around 2 times the regular code). The performance
improvement is around 55% for TCP.

Please review and provide feedback; and consider for inclusion.

Thanks,

- KK

----------------------------------------------------
			TCP
			----
Size:32 Procs:1		2728	3544	29.91
Size:128 Procs:1	11803	13679	15.89
Size:512 Procs:1	43279	49665	14.75
Size:4096 Procs:1	147952	101246	-31.56
Size:16384 Procs:1	149852	141897	-5.30

Size:32 Procs:4		10562	11349	7.45
Size:128 Procs:4	41010	40832	-.43
Size:512 Procs:4	75374	130943	73.72
Size:4096 Procs:4	167996	368218	119.18
Size:16384 Procs:4	123176	379524	208.11

Size:32 Procs:8		21125	21990	4.09
Size:128 Procs:8	77419	78605	1.53
Size:512 Procs:8	234678	265047	12.94
Size:4096 Procs:8	218063	367604	68.57
Size:16384 Procs:8	184283	370972	101.30

Average:	1509300 -> 2345115 = 55.38%
----------------------------------------------------

^ permalink raw reply

* [PATCH 1/10 REV5] [Doc] HOWTO Documentation for batching
From: Krishna Kumar @ 2007-09-14  9:01 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, peter.p.waskiewicz.jr, kumarkr, xma,
	gaagaan, netdev, rdreier, rick.jones2, mcarlson, jeff, general,
	mchan, tgraf, randy.dunlap, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

Add Documentation describing batching skb xmit capability.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 batching_skb_xmit.txt |  107 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 107 insertions(+)

diff -ruNp org/Documentation/networking/batching_skb_xmit.txt new/Documentation/networking/batching_skb_xmit.txt
--- org/Documentation/networking/batching_skb_xmit.txt	1970-01-01 05:30:00.000000000 +0530
+++ new/Documentation/networking/batching_skb_xmit.txt	2007-09-14 10:25:36.000000000 +0530
@@ -0,0 +1,107 @@
+		 HOWTO for batching skb xmit support
+		 -----------------------------------
+
+Section 1: What is batching skb xmit
+Section 2: How batching xmit works vs the regular xmit
+Section 3: How drivers can support batching
+Section 4: Nitty gritty details for drivers
+Section 5: How users can work with batching
+
+
+Introduction: Kernel support for batching skb
+----------------------------------------------
+
+A new capability to support xmit of multiple skbs is provided in the netdevice
+layer. Drivers which enable this capability should be able to process multiple
+skbs in a single call to their xmit handler.
+
+
+Section 1: What is batching skb xmit
+-------------------------------------
+
+	This capability is optionally enabled by a driver by setting the
+	NETIF_F_BATCH_SKBS bit in dev->features. The prerequisite for a
+	driver to use this capability is that it should have a reasonably-
+	sized hardware queue that can process multiple skbs.
+
+
+Section 2: How batching xmit works vs the regular xmit
+-------------------------------------------------------
+
+	The network stack gets called from upper layer protocols with a single
+	skb to transmit. This skb is first enqueued and an attempt is made to
+	transmit it immediately (via qdisc_run). However, events like tx lock
+	contention, tx queue stopped, etc., can result in the skb not getting
+	sent out and it remains in the queue. When the next xmit is called or
+	when the queue is re-enabled, qdisc_run could potentially find
+	multiple packets in the queue, and iteratively send them all out
+	one-by-one.
+
+	Batching skb xmit is a mechanism to exploit this situation where all
+	skbs can be passed in one shot to the device. This reduces driver
+	processing, locking at the driver (or in stack for ~LLTX drivers)
+	gets amortized over multiple skbs, and in case of specific drivers
+	where every xmit results in a completion processing (like IPoIB) -
+	optimizations can be made in the driver to request a completion for
+	only the last skb that was sent which results in saving interrupts
+	for every (but the last) skb that was sent in the same batch.
+
+	Batching can result in significant performance gains for systems that
+	have multiple data stream paths over the same network interface card.
+
+
+Section 3: How drivers can support batching
+---------------------------------------------
+
+	Batching requires the driver to set the NETIF_F_BATCH_SKBS bit in
+	dev->features.
+
+	The driver's xmit handler should be modified to process multiple skbs
+	instead of one skb. The driver's xmit handler is called either with
+	an skb to transmit or NULL skb, where the latter case should be
+	handled as a call to xmit multiple skbs. This is done by sending out
+	all skbs in the dev->skb_blist list (where it was added by the core
+	stack).
+
+
+Section 4: Nitty gritty details for driver writers
+--------------------------------------------------
+
+	Batching is enabled from core networking stack only from softirq
+	context (NET_TX_SOFTIRQ), and dev_queue_xmit() doesn't use batching.
+
+	This leads to the following situation:
+		A skb was not sent out as either driver lock was contested or
+		the device was blocked. When the softirq handler runs, it
+		moves all skbs from the device queue to the batch list, but
+		then it too could fail to send due to lock contention. The
+		next xmit (of a single skb) called from dev_queue_xmit() will
+		not use batching and try to xmit skb, while previous skbs are
+		still present in the batch list. This results in the receiver
+		getting out-of-order packets, and in case of TCP the sender
+		would have unnecessary retransmissions.
+
+	To fix this problem, error cases where driver xmit gets called with a
+	skb must code as follows:
+		1. If driver xmit cannot get tx lock, return NETDEV_TX_LOCKED
+		   as usual. This allows qdisc to requeue the skb.
+		2. If driver xmit got the lock but failed to send the skb, it
+		   should return NETDEV_TX_BUSY but before that it should have
+		   queue'd the skb to the batch list. In this case, the qdisc
+		   does not requeue the skb.
+
+
+Section 5: How users can work with batching
+--------------------------------------------
+
+	Batching can be disabled for a particular device, e.g. on desktop
+	systems if only one stream of network activity for that device is
+	taking place, since performance could be slightly affected due to
+	extra processing that batching adds (unless packets are getting
+	sent fast resulting in queue getting stopped). Batching can be enabled
+	if more than one stream of network activity per device is being done,
+	e.g. on servers; or even desktop usage with multiple browser, chat,
+	file transfer sessions, etc.
+
+	Per device batching can be enabled/disabled by:
+		ethtool <dev> batching on/off

^ permalink raw reply

* [PATCH 2/10 REV5] [core] Add skb_blist & support for batching
From: Krishna Kumar @ 2007-09-14  9:01 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, rick.jones2, xma, gaagaan, kumarkr,
	rdreier, peter.p.waskiewicz.jr, mcarlson, jeff, Krishna Kumar,
	general, netdev, tgraf, randy.dunlap, mchan, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

Introduce skb_blist, NETIF_F_BATCH_SKBS, use single API for
batching/no-batching, etc.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 include/linux/netdevice.h |    8 ++++++--
 net/core/dev.c            |   29 ++++++++++++++++++++++++++---
 2 files changed, 32 insertions(+), 5 deletions(-)

diff -ruNp org/include/linux/netdevice.h new/include/linux/netdevice.h
--- org/include/linux/netdevice.h	2007-09-13 09:11:09.000000000 +0530
+++ new/include/linux/netdevice.h	2007-09-14 10:26:21.000000000 +0530
@@ -439,10 +439,11 @@ struct net_device
 #define NETIF_F_NETNS_LOCAL	8192	/* Does not change network namespaces */
 #define NETIF_F_MULTI_QUEUE	16384	/* Has multiple TX/RX queues */
 #define NETIF_F_LRO		32768	/* large receive offload */
+#define NETIF_F_BATCH_SKBS	65536	/* Driver supports multiple skbs/xmit */
 
 	/* Segmentation offload features */
-#define NETIF_F_GSO_SHIFT	16
-#define NETIF_F_GSO_MASK	0xffff0000
+#define NETIF_F_GSO_SHIFT	17
+#define NETIF_F_GSO_MASK	0xfffe0000
 #define NETIF_F_TSO		(SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
 #define NETIF_F_UFO		(SKB_GSO_UDP << NETIF_F_GSO_SHIFT)
 #define NETIF_F_GSO_ROBUST	(SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
@@ -548,6 +549,9 @@ struct net_device
 	/* Partially transmitted GSO packet. */
 	struct sk_buff		*gso_skb;
 
+	/* List of batch skbs (optional, used if driver supports skb batching */
+	struct sk_buff_head	*skb_blist;
+
 	/* ingress path synchronizer */
 	spinlock_t		ingress_lock;
 	struct Qdisc		*qdisc_ingress;
diff -ruNp org/net/core/dev.c new/net/core/dev.c
--- org/net/core/dev.c	2007-09-14 10:24:27.000000000 +0530
+++ new/net/core/dev.c	2007-09-14 10:25:36.000000000 +0530
@@ -953,6 +953,16 @@ void netdev_state_change(struct net_devi
 	}
 }
 
+static void free_batching(struct net_device *dev)
+{
+	if (dev->skb_blist) {
+		if (!skb_queue_empty(dev->skb_blist))
+			skb_queue_purge(dev->skb_blist);
+		kfree(dev->skb_blist);
+		dev->skb_blist = NULL;
+	}
+}
+
 /**
  *	dev_load 	- load a network module
  *	@name: name of interface
@@ -1534,7 +1544,10 @@ static int dev_gso_segment(struct sk_buf
 
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	if (likely(!skb->next)) {
+	if (likely(skb)) {
+		if (unlikely(skb->next))
+			goto gso;
+
 		if (!list_empty(&ptype_all))
 			dev_queue_xmit_nit(skb, dev);
 
@@ -1544,10 +1557,10 @@ int dev_hard_start_xmit(struct sk_buff *
 			if (skb->next)
 				goto gso;
 		}
-
-		return dev->hard_start_xmit(skb, dev);
 	}
 
+	return dev->hard_start_xmit(skb, dev);
+
 gso:
 	do {
 		struct sk_buff *nskb = skb->next;
@@ -3566,6 +3579,13 @@ int register_netdevice(struct net_device
 		}
 	}
 
+	if (dev->features & NETIF_F_BATCH_SKBS) {
+		/* Driver supports batching skb */
+		dev->skb_blist = kmalloc(sizeof *dev->skb_blist, GFP_KERNEL);
+		if (dev->skb_blist)
+			skb_queue_head_init(dev->skb_blist);
+	}
+
 	/*
 	 *	nil rebuild_header routine,
 	 *	that should be never called and used as just bug trap.
@@ -3901,6 +3921,9 @@ void unregister_netdevice(struct net_dev
 
 	synchronize_net();
 
+	/* Deallocate batching structure */
+	free_batching(dev);
+
 	/* Shutdown queueing discipline. */
 	dev_shutdown(dev);
 

^ permalink raw reply

* [PATCH 3/10 REV5] [sched] Modify qdisc_run to support batching
From: Krishna Kumar @ 2007-09-14  9:01 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, peter.p.waskiewicz.jr, xma, gaagaan,
	kumarkr, rdreier, rick.jones2, mcarlson, jeff, mchan, general,
	netdev, tgraf, randy.dunlap, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

Modify qdisc_run() to support batching. Modify callers of qdisc_run to
use batching, modify qdisc_restart to implement batching.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 include/linux/netdevice.h |    2 
 include/net/pkt_sched.h   |   17 +++++--
 net/core/dev.c            |   45 ++++++++++++++++++
 net/sched/sch_generic.c   |  109 ++++++++++++++++++++++++++++++++++++----------
 4 files changed, 145 insertions(+), 28 deletions(-)

diff -ruNp org/include/net/pkt_sched.h new/include/net/pkt_sched.h
--- org/include/net/pkt_sched.h	2007-09-13 09:11:09.000000000 +0530
+++ new/include/net/pkt_sched.h	2007-09-14 10:25:36.000000000 +0530
@@ -80,13 +80,24 @@ extern struct qdisc_rate_table *qdisc_ge
 		struct rtattr *tab);
 extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
 
-extern void __qdisc_run(struct net_device *dev);
+static inline void qdisc_block(struct net_device *dev)
+{
+	while (test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
+		yield();
+}
+
+static inline void qdisc_unblock(struct net_device *dev)
+{
+	clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
+}
+
+extern void __qdisc_run(struct net_device *dev, struct sk_buff_head *blist);
 
-static inline void qdisc_run(struct net_device *dev)
+static inline void qdisc_run(struct net_device *dev, struct sk_buff_head *blist)
 {
 	if (!netif_queue_stopped(dev) &&
 	    !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
-		__qdisc_run(dev);
+		__qdisc_run(dev, blist);
 }
 
 extern int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp,
diff -ruNp org/include/linux/netdevice.h new/include/linux/netdevice.h
--- org/include/linux/netdevice.h	2007-09-13 09:11:09.000000000 +0530
+++ new/include/linux/netdevice.h	2007-09-14 10:26:21.000000000 +0530
@@ -1013,6 +1013,8 @@ extern int		dev_set_mac_address(struct n
 					    struct sockaddr *);
 extern int		dev_hard_start_xmit(struct sk_buff *skb,
 					    struct net_device *dev);
+extern int		dev_add_skb_to_blist(struct sk_buff *skb,
+					     struct net_device *dev);
 
 extern int		netdev_budget;
 
diff -ruNp org/net/sched/sch_generic.c new/net/sched/sch_generic.c
--- org/net/sched/sch_generic.c	2007-09-13 09:11:10.000000000 +0530
+++ new/net/sched/sch_generic.c	2007-09-14 10:25:36.000000000 +0530
@@ -59,26 +59,30 @@ static inline int qdisc_qlen(struct Qdis
 static inline int dev_requeue_skb(struct sk_buff *skb, struct net_device *dev,
 				  struct Qdisc *q)
 {
-	if (unlikely(skb->next))
-		dev->gso_skb = skb;
-	else
-		q->ops->requeue(skb, q);
+	if (skb) {
+		if (unlikely(skb->next))
+			dev->gso_skb = skb;
+		else
+			q->ops->requeue(skb, q);
+	}
 
 	netif_schedule(dev);
 	return 0;
 }
 
-static inline struct sk_buff *dev_dequeue_skb(struct net_device *dev,
-					      struct Qdisc *q)
+static inline int dev_requeue_skb_wrapper(struct sk_buff *skb,
+					  struct net_device *dev,
+					  struct Qdisc *q)
 {
-	struct sk_buff *skb;
-
-	if ((skb = dev->gso_skb))
-		dev->gso_skb = NULL;
-	else
-		skb = q->dequeue(q);
+	if (dev->skb_blist) {
+		/*
+		 * In case of tx full, batching drivers would have put all
+		 * skbs into skb_blist so there is no skb to requeue.
+		 */
+		skb = NULL;
+	}
 
-	return skb;
+	return dev_requeue_skb(skb, dev, q);
 }
 
 static inline int handle_dev_cpu_collision(struct sk_buff *skb,
@@ -91,10 +95,15 @@ static inline int handle_dev_cpu_collisi
 		/*
 		 * Same CPU holding the lock. It may be a transient
 		 * configuration error, when hard_start_xmit() recurses. We
-		 * detect it by checking xmit owner and drop the packet when
-		 * deadloop is detected. Return OK to try the next skb.
+		 * detect it by checking xmit owner and drop the packet (or
+		 * all packets in batching case) when deadloop is detected.
+		 * Return OK to try the next skb.
 		 */
-		kfree_skb(skb);
+		if (likely(skb))
+			kfree_skb(skb);
+		else if (!skb_queue_empty(dev->skb_blist))
+			skb_queue_purge(dev->skb_blist);
+
 		if (net_ratelimit())
 			printk(KERN_WARNING "Dead loop on netdevice %s, "
 			       "fix it urgently!\n", dev->name);
@@ -111,6 +120,53 @@ static inline int handle_dev_cpu_collisi
 	return ret;
 }
 
+#define DEQUEUE_SKB(q)		(q->dequeue(q))
+
+static inline struct sk_buff *get_gso_skb(struct net_device *dev)
+{
+	struct sk_buff *skb;
+
+	if ((skb = dev->gso_skb))
+		dev->gso_skb = NULL;
+
+	return skb;
+}
+
+/*
+ * Algorithm to get skb(s) is:
+ *	- If gso skb present, return it.
+ *	- Non batching drivers, or if the batch list is empty and there is
+ *	  1 skb in the queue - dequeue skb and put it in *skbp to tell the
+ *	  caller to use the single xmit API.
+ *	- Batching drivers where the batch list already contains atleast one
+ *	  skb, or if there are multiple skbs in the queue: keep dequeue'ing
+ *	  skb's upto a limit and set *skbp to NULL to tell the caller to use
+ *	  the multiple xmit API.
+ *
+ * Returns:
+ *	1 - atleast one skb is to be sent out, *skbp contains skb or NULL
+ *	    (in case >1 skbs present in blist for batching)
+ *	0 - no skbs to be sent.
+ */
+static inline int get_skb(struct net_device *dev, struct Qdisc *q,
+			  struct sk_buff_head *blist, struct sk_buff **skbp)
+{
+	if ((*skbp = get_gso_skb(dev)) != NULL)
+		return 1;
+
+	if (!blist || (!skb_queue_len(blist) && qdisc_qlen(q) <= 1)) {
+		return likely((*skbp = DEQUEUE_SKB(q)) != NULL);
+	} else {
+		struct sk_buff *skb;
+		int max = dev->tx_queue_len - skb_queue_len(blist);
+
+		while (max > 0 && (skb = DEQUEUE_SKB(q)) != NULL)
+			max -= dev_add_skb_to_blist(skb, dev);
+
+		return 1;	/* there is atleast one skb in skb_blist */
+	}
+}
+
 /*
  * NOTE: Called under dev->queue_lock with locally disabled BH.
  *
@@ -130,7 +186,8 @@ static inline int handle_dev_cpu_collisi
  *				>0 - queue is not empty.
  *
  */
-static inline int qdisc_restart(struct net_device *dev)
+static inline int qdisc_restart(struct net_device *dev,
+				struct sk_buff_head *blist)
 {
 	struct Qdisc *q = dev->qdisc;
 	struct sk_buff *skb;
@@ -138,7 +195,7 @@ static inline int qdisc_restart(struct n
 	int ret;
 
 	/* Dequeue packet */
-	if (unlikely((skb = dev_dequeue_skb(dev, q)) == NULL))
+	if (unlikely(get_skb(dev, q, blist, &skb) == 0))
 		return 0;
 
 	/*
@@ -168,7 +225,7 @@ static inline int qdisc_restart(struct n
 
 	switch (ret) {
 	case NETDEV_TX_OK:
-		/* Driver sent out skb successfully */
+		/* Driver sent out skb (or entire skb_blist) successfully */
 		ret = qdisc_qlen(q);
 		break;
 
@@ -183,21 +240,21 @@ static inline int qdisc_restart(struct n
 			printk(KERN_WARNING "BUG %s code %d qlen %d\n",
 			       dev->name, ret, q->q.qlen);
 
-		ret = dev_requeue_skb(skb, dev, q);
+		ret = dev_requeue_skb_wrapper(skb, dev, q);
 		break;
 	}
 
 	return ret;
 }
 
-void __qdisc_run(struct net_device *dev)
+void __qdisc_run(struct net_device *dev, struct sk_buff_head *blist)
 {
 	do {
-		if (!qdisc_restart(dev))
+		if (!qdisc_restart(dev, blist))
 			break;
 	} while (!netif_queue_stopped(dev));
 
-	clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
+	qdisc_unblock(dev);
 }
 
 static void dev_watchdog(unsigned long arg)
@@ -575,6 +632,12 @@ void dev_deactivate(struct net_device *d
 	qdisc = dev->qdisc;
 	dev->qdisc = &noop_qdisc;
 
+	if (dev->skb_blist) {
+		/* Release skbs on batch list */
+		if (!skb_queue_empty(dev->skb_blist))
+			skb_queue_purge(dev->skb_blist);
+	}
+
 	qdisc_reset(qdisc);
 
 	skb = dev->gso_skb;
diff -ruNp org/net/core/dev.c new/net/core/dev.c
--- org/net/core/dev.c	2007-09-14 10:24:27.000000000 +0530
+++ new/net/core/dev.c	2007-09-14 10:25:36.000000000 +0530
@@ -1542,6 +1542,46 @@ static int dev_gso_segment(struct sk_buf
 	return 0;
 }
 
+/*
+ * Add skb (skbs in case segmentation is required) to dev->skb_blist. No one
+ * can add to this list simultaneously since we are holding QDISC RUNNING
+ * bit. Also list is safe from simultaneous deletes too since skbs are
+ * dequeued only when the driver is invoked.
+ *
+ * Returns count of successful skb(s) added to skb_blist.
+ */
+int dev_add_skb_to_blist(struct sk_buff *skb, struct net_device *dev)
+{
+	if (!list_empty(&ptype_all))
+		dev_queue_xmit_nit(skb, dev);
+
+	if (netif_needs_gso(dev, skb)) {
+		if (unlikely(dev_gso_segment(skb))) {
+			kfree_skb(skb);
+			return 0;
+		}
+
+		if (skb->next) {
+			int count = 0;
+
+			do {
+				struct sk_buff *nskb = skb->next;
+
+				skb->next = nskb->next;
+				__skb_queue_tail(dev->skb_blist, nskb);
+				count++;
+			} while (skb->next);
+
+			/* Reset destructor for kfree_skb to work */
+			skb->destructor = DEV_GSO_CB(skb)->destructor;
+			kfree_skb(skb);
+			return count;
+		}
+	}
+	__skb_queue_tail(dev->skb_blist, skb);
+	return 1;
+}
+
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	if (likely(skb)) {
@@ -1697,7 +1737,7 @@ gso:
 			/* reset queue_mapping to zero */
 			skb->queue_mapping = 0;
 			rc = q->enqueue(skb, q);
-			qdisc_run(dev);
+			qdisc_run(dev, NULL);
 			spin_unlock(&dev->queue_lock);
 
 			rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
@@ -1895,7 +1935,8 @@ static void net_tx_action(struct softirq
 			clear_bit(__LINK_STATE_SCHED, &dev->state);
 
 			if (spin_trylock(&dev->queue_lock)) {
-				qdisc_run(dev);
+				/* Send all skbs if driver supports batching */
+				qdisc_run(dev, dev->skb_blist);
 				spin_unlock(&dev->queue_lock);
 			} else {
 				netif_schedule(dev);

^ permalink raw reply

* [PATCH 4/10 REV5] [ethtool] Add ethtool support
From: Krishna Kumar @ 2007-09-14  9:02 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, rick.jones2, xma, gaagaan, kumarkr,
	rdreier, peter.p.waskiewicz.jr, mcarlson, jeff, general, mchan,
	tgraf, randy.dunlap, netdev, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

Add ethtool support to enable/disable batching.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 include/linux/ethtool.h   |    2 ++
 include/linux/netdevice.h |    2 ++
 net/core/dev.c            |   44 ++++++++++++++++++++++++++++++++++++++++++++
 net/core/ethtool.c        |   27 +++++++++++++++++++++++++++
 4 files changed, 75 insertions(+)

diff -ruNp org/include/linux/ethtool.h new/include/linux/ethtool.h
--- org/include/linux/ethtool.h	2007-09-13 09:11:09.000000000 +0530
+++ new/include/linux/ethtool.h	2007-09-14 10:25:36.000000000 +0530
@@ -440,6 +440,8 @@ struct ethtool_ops {
 #define ETHTOOL_SFLAGS		0x00000026 /* Set flags bitmap(ethtool_value) */
 #define ETHTOOL_GPFLAGS		0x00000027 /* Get driver-private flags bitmap */
 #define ETHTOOL_SPFLAGS		0x00000028 /* Set driver-private flags bitmap */
+#define ETHTOOL_GBATCH		0x00000029 /* Get Batching (ethtool_value) */
+#define ETHTOOL_SBATCH		0x00000030 /* Set Batching (ethtool_value) */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
diff -ruNp org/include/linux/netdevice.h new/include/linux/netdevice.h
--- org/include/linux/netdevice.h	2007-09-13 09:11:09.000000000 +0530
+++ new/include/linux/netdevice.h	2007-09-14 10:26:21.000000000 +0530
@@ -1331,6 +1331,8 @@ extern void		dev_set_promiscuity(struct 
 extern void		dev_set_allmulti(struct net_device *dev, int inc);
 extern void		netdev_state_change(struct net_device *dev);
 extern void		netdev_features_change(struct net_device *dev);
+extern int		dev_change_tx_batch_skb(struct net_device *dev,
+						unsigned long new_batch_skb);
 /* Load a device via the kmod */
 extern void		dev_load(struct net *net, const char *name);
 extern void		dev_mcast_init(void);
diff -ruNp org/net/core/dev.c new/net/core/dev.c
--- org/net/core/dev.c	2007-09-14 10:24:27.000000000 +0530
+++ new/net/core/dev.c	2007-09-14 10:25:36.000000000 +0530
@@ -963,6 +963,50 @@ void free_batching(struct net_dev
 	}
 }
 
+int dev_change_tx_batch_skb(struct net_device *dev, unsigned long new_batch_skb)
+{
+	int ret = 0;
+	struct sk_buff_head *blist = NULL;
+
+	if (!(dev->features & NETIF_F_BATCH_SKBS)) {
+		/* Driver doesn't support batching skb API */
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/*
+	 * Check if new value is same as the current (paranoia to use !! for
+	 * new_batch_skb as that will be boolean via ethtool).
+	 */
+	if (!!dev->skb_blist == !!new_batch_skb)
+		goto out;
+
+	if (new_batch_skb &&
+	    (blist = kmalloc(sizeof *blist, GFP_KERNEL)) == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * Block xmit as qdisc_restart() drops queue_lock before calling
+	 * driver xmit, and driver could find blist change under it.
+	 */
+	qdisc_block(dev);
+
+	spin_lock_bh(&dev->queue_lock);
+	if (new_batch_skb) {
+		skb_queue_head_init(blist);
+		dev->skb_blist = blist;
+	} else
+		free_batching(dev);
+	spin_unlock_bh(&dev->queue_lock);
+
+	qdisc_unblock(dev);
+
+out:
+	return ret;
+}
+
 /**
  *	dev_load 	- load a network module
  *	@name: name of interface
diff -ruNp org/net/core/ethtool.c new/net/core/ethtool.c
--- org/net/core/ethtool.c	2007-09-13 09:11:10.000000000 +0530
+++ new/net/core/ethtool.c	2007-09-14 10:25:36.000000000 +0530
@@ -556,6 +556,26 @@ static int ethtool_set_gso(struct net_de
 	return 0;
 }
 
+static int ethtool_get_batch(struct net_device *dev, char __user *useraddr)
+{
+	struct ethtool_value edata = { ETHTOOL_GBATCH };
+
+	edata.data = dev->skb_blist != NULL;
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+		 return -EFAULT;
+	return 0;
+}
+
+static int ethtool_set_batch(struct net_device *dev, char __user *useraddr)
+{
+	struct ethtool_value edata;
+
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+		return -EFAULT;
+
+	return dev_change_tx_batch_skb(dev, edata.data);
+}
+
 static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
 {
 	struct ethtool_test test;
@@ -813,6 +833,7 @@ int dev_ethtool(struct net *net, struct 
 	case ETHTOOL_GGSO:
 	case ETHTOOL_GFLAGS:
 	case ETHTOOL_GPFLAGS:
+	case ETHTOOL_GBATCH:
 		break;
 	default:
 		if (!capable(CAP_NET_ADMIN))
@@ -956,6 +977,12 @@ int dev_ethtool(struct net *net, struct 
 		rc = ethtool_set_value(dev, useraddr,
 				       dev->ethtool_ops->set_priv_flags);
 		break;
+	case ETHTOOL_GBATCH:
+		rc = ethtool_get_batch(dev, useraddr);
+		break;
+	case ETHTOOL_SBATCH:
+		rc = ethtool_set_batch(dev, useraddr);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}

^ permalink raw reply

* [PATCH 5/10 REV5] [IPoIB] Header file changes
From: Krishna Kumar @ 2007-09-14  9:02 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, peter.p.waskiewicz.jr, xma, gaagaan,
	kumarkr, rdreier, rick.jones2, mcarlson, jeff, general, mchan,
	tgraf, randy.dunlap, netdev, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

IPoIB header file changes to use batching.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 ipoib.h |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib.h new/drivers/infiniband/ulp/ipoib/ipoib.h
--- org/drivers/infiniband/ulp/ipoib/ipoib.h	2007-09-13 09:10:58.000000000 +0530
+++ new/drivers/infiniband/ulp/ipoib/ipoib.h	2007-09-14 10:25:36.000000000 +0530
@@ -271,8 +271,8 @@ struct ipoib_dev_priv {
 	struct ipoib_tx_buf *tx_ring;
 	unsigned             tx_head;
 	unsigned             tx_tail;
-	struct ib_sge        tx_sge;
-	struct ib_send_wr    tx_wr;
+	struct ib_sge        *tx_sge;
+	struct ib_send_wr    *tx_wr;
 
 	struct ib_wc ibwc[IPOIB_NUM_WC];
 
@@ -367,8 +367,11 @@ static inline void ipoib_put_ah(struct i
 int ipoib_open(struct net_device *dev);
 int ipoib_add_pkey_attr(struct net_device *dev);
 
+int ipoib_process_skb(struct net_device *dev, struct sk_buff *skb,
+		      struct ipoib_dev_priv *priv, struct ipoib_ah *address,
+		      u32 qpn, int wr_num);
 void ipoib_send(struct net_device *dev, struct sk_buff *skb,
-		struct ipoib_ah *address, u32 qpn);
+		struct ipoib_ah *address, u32 qpn, int num_skbs);
 void ipoib_reap_ah(struct work_struct *work);
 
 void ipoib_flush_paths(struct net_device *dev);

^ permalink raw reply

* [PATCH 6/10 REV5] [IPoIB] CM & Multicast changes
From: Krishna Kumar @ 2007-09-14  9:03 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, rick.jones2, xma, gaagaan, kumarkr,
	rdreier, peter.p.waskiewicz.jr, mcarlson, jeff, general, mchan,
	tgraf, randy.dunlap, netdev, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

IPoIB CM & Multicast changes based on header file changes.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 ipoib_cm.c        |   13 +++++++++----
 ipoib_multicast.c |    4 ++--
 2 files changed, 11 insertions(+), 6 deletions(-)

diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_cm.c new/drivers/infiniband/ulp/ipoib/ipoib_cm.c
--- org/drivers/infiniband/ulp/ipoib/ipoib_cm.c	2007-09-13 09:10:58.000000000 +0530
+++ new/drivers/infiniband/ulp/ipoib/ipoib_cm.c	2007-09-14 10:25:36.000000000 +0530
@@ -493,14 +493,19 @@ static inline int post_send(struct ipoib
 			    unsigned int wr_id,
 			    u64 addr, int len)
 {
+	int ret;
 	struct ib_send_wr *bad_wr;
 
-	priv->tx_sge.addr             = addr;
-	priv->tx_sge.length           = len;
+	priv->tx_sge[0].addr          = addr;
+	priv->tx_sge[0].length        = len;
+
+	priv->tx_wr[0].wr_id 	      = wr_id;
 
-	priv->tx_wr.wr_id 	      = wr_id;
+	priv->tx_wr[0].next = NULL;
+	ret = ib_post_send(tx->qp, priv->tx_wr, &bad_wr);
+	priv->tx_wr[0].next = &priv->tx_wr[1];
 
-	return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
+	return ret;
 }
 
 void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_multicast.c new/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
--- org/drivers/infiniband/ulp/ipoib/ipoib_multicast.c	2007-09-13 09:10:58.000000000 +0530
+++ new/drivers/infiniband/ulp/ipoib/ipoib_multicast.c	2007-09-14 10:25:36.000000000 +0530
@@ -217,7 +217,7 @@ static int ipoib_mcast_join_finish(struc
 	if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4,
 		    sizeof (union ib_gid))) {
 		priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey);
-		priv->tx_wr.wr.ud.remote_qkey = priv->qkey;
+		priv->tx_wr[0].wr.ud.remote_qkey = priv->qkey;
 	}
 
 	if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
@@ -736,7 +736,7 @@ out:
 			}
 		}
 
-		ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN);
+		ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN, 1);
 	}
 
 unlock:

^ permalink raw reply

* [PATCH 7/10 REV5] [IPoIB] Verbs changes
From: Krishna Kumar @ 2007-09-14  9:03 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, peter.p.waskiewicz.jr, xma, gaagaan,
	kumarkr, rdreier, rick.jones2, mcarlson, jeff, general, mchan,
	tgraf, randy.dunlap, netdev, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

IPoIB verb changes to use batching.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 ipoib_verbs.c |   23 ++++++++++++++---------
 1 files changed, 14 insertions(+), 9 deletions(-)

diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_verbs.c new/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
--- org/drivers/infiniband/ulp/ipoib/ipoib_verbs.c	2007-09-13 09:10:58.000000000 +0530
+++ new/drivers/infiniband/ulp/ipoib/ipoib_verbs.c	2007-09-14 10:25:36.000000000 +0530
@@ -152,11 +152,11 @@ int ipoib_transport_dev_init(struct net_
 			.max_send_sge = 1,
 			.max_recv_sge = 1
 		},
-		.sq_sig_type = IB_SIGNAL_ALL_WR,
+		.sq_sig_type = IB_SIGNAL_REQ_WR,	/* 11.2.4.1 */
 		.qp_type     = IB_QPT_UD
 	};
-
-	int ret, size;
+	struct ib_send_wr *next_wr = NULL;
+	int i, ret, size;
 
 	priv->pd = ib_alloc_pd(priv->ca);
 	if (IS_ERR(priv->pd)) {
@@ -197,12 +197,17 @@ int ipoib_transport_dev_init(struct net_
 	priv->dev->dev_addr[2] = (priv->qp->qp_num >>  8) & 0xff;
 	priv->dev->dev_addr[3] = (priv->qp->qp_num      ) & 0xff;
 
-	priv->tx_sge.lkey 	= priv->mr->lkey;
-
-	priv->tx_wr.opcode 	= IB_WR_SEND;
-	priv->tx_wr.sg_list 	= &priv->tx_sge;
-	priv->tx_wr.num_sge 	= 1;
-	priv->tx_wr.send_flags 	= IB_SEND_SIGNALED;
+	for (i = ipoib_sendq_size - 1; i >= 0; i--) {
+		priv->tx_sge[i].lkey		= priv->mr->lkey;
+		priv->tx_wr[i].opcode		= IB_WR_SEND;
+		priv->tx_wr[i].sg_list		= &priv->tx_sge[i];
+		priv->tx_wr[i].num_sge		= 1;
+		priv->tx_wr[i].send_flags	= 0;
+
+		/* Link the list properly for provider to use */
+		priv->tx_wr[i].next		= next_wr;
+		next_wr				= &priv->tx_wr[i];
+	}
 
 	return 0;
 

^ permalink raw reply

* [PATCH 8/10 REV5] [IPoIB] Post and work completion handler changes
From: Krishna Kumar @ 2007-09-14  9:03 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, rick.jones2, xma, gaagaan, kumarkr,
	rdreier, peter.p.waskiewicz.jr, mcarlson, jeff, general, mchan,
	tgraf, randy.dunlap, netdev, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

IPoIB internal post and work completion handler changes.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 ipoib_ib.c |  212 ++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 168 insertions(+), 44 deletions(-)

diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_ib.c new/drivers/infiniband/ulp/ipoib/ipoib_ib.c
--- org/drivers/infiniband/ulp/ipoib/ipoib_ib.c	2007-09-13 09:10:58.000000000 +0530
+++ new/drivers/infiniband/ulp/ipoib/ipoib_ib.c	2007-09-14 10:25:36.000000000 +0530
@@ -242,6 +242,8 @@ repost:
 static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int num_completions, to_process;
+	unsigned int tx_ring_index;
 	unsigned int wr_id = wc->wr_id;
 	struct ipoib_tx_buf *tx_req;
 	unsigned long flags;
@@ -255,18 +257,51 @@ static void ipoib_ib_handle_tx_wc(struct
 		return;
 	}
 
-	tx_req = &priv->tx_ring[wr_id];
+	/* Get first WC to process (no one can update tx_tail at this time) */
+	tx_ring_index = priv->tx_tail & (ipoib_sendq_size - 1);
 
-	ib_dma_unmap_single(priv->ca, tx_req->mapping,
-			    tx_req->skb->len, DMA_TO_DEVICE);
+	/* Find number of WC's to process */
+	num_completions = wr_id - tx_ring_index + 1;
+	if (unlikely(num_completions <= 0))
+		num_completions += ipoib_sendq_size;
+	to_process = num_completions;
 
-	++priv->stats.tx_packets;
-	priv->stats.tx_bytes += tx_req->skb->len;
+	/*
+	 * Handle WC's from earlier (possibly multiple) post_sends in this
+	 * iteration as we move from tx_tail to wr_id, since if the last WR
+	 * (which is the one which requested completion notification) failed
+	 * to be sent for any of those earlier request(s), no completion
+	 * notification is generated for successful WR's of those earlier
+	 * request(s). Use a infinite loop to handle the regular case of
+	 * one skb processing faster.
+	 */
+	tx_req = &priv->tx_ring[tx_ring_index];
+	while (1) {
+		if (likely(tx_req->skb)) {
+			ib_dma_unmap_single(priv->ca, tx_req->mapping,
+					    tx_req->skb->len, DMA_TO_DEVICE);
+
+			++priv->stats.tx_packets;
+			priv->stats.tx_bytes += tx_req->skb->len;
+
+			dev_kfree_skb_any(tx_req->skb);
+		}
+		/*
+		 * else this skb failed synchronously when posted and was
+		 * freed immediately.
+		 */
+
+		if (--to_process == 0)
+			break;
 
-	dev_kfree_skb_any(tx_req->skb);
+		if (likely(++tx_ring_index != ipoib_sendq_size))
+			tx_req++;
+		else
+			tx_req = &priv->tx_ring[0];
+	}
 
 	spin_lock_irqsave(&priv->tx_lock, flags);
-	++priv->tx_tail;
+	priv->tx_tail += num_completions;
 	if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags)) &&
 	    priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) {
 		clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
@@ -335,29 +370,57 @@ void ipoib_ib_completion(struct ib_cq *c
 	netif_rx_schedule(dev, &priv->napi);
 }
 
-static inline int post_send(struct ipoib_dev_priv *priv,
-			    unsigned int wr_id,
-			    struct ib_ah *address, u32 qpn,
-			    u64 addr, int len)
+/*
+ * post_send : Post WR(s) to the device.
+ *
+ * num_skbs is the number of WR's, first_wr is the first slot in tx_wr[] (or
+ * tx_sge[]). first_wr is normally zero unless a previous post_send returned
+ * error and we are trying to post the untried WR's, in which case first_wr
+ * is the index to the first untried WR.
+ *
+ * Break the WR link before posting so that provider knows how many WR's to
+ * process, and this is set back after the post.
+ */
+static inline int post_send(struct ipoib_dev_priv *priv, u32 qpn,
+			    int first_wr, int num_skbs,
+			    struct ib_send_wr **bad_wr)
 {
-	struct ib_send_wr *bad_wr;
+	int ret;
+	struct ib_send_wr *last_wr, *next_wr;
+
+	last_wr = &priv->tx_wr[first_wr + num_skbs - 1];
+
+	/* Set Completion Notification for last WR */
+	last_wr->send_flags = IB_SEND_SIGNALED;
 
-	priv->tx_sge.addr             = addr;
-	priv->tx_sge.length           = len;
+	/* Terminate the last WR */
+	next_wr = last_wr->next;
+	last_wr->next = NULL;
 
-	priv->tx_wr.wr_id 	      = wr_id;
-	priv->tx_wr.wr.ud.remote_qpn  = qpn;
-	priv->tx_wr.wr.ud.ah 	      = address;
+	/* Send all the WR's in one doorbell */
+	ret = ib_post_send(priv->qp, &priv->tx_wr[first_wr], bad_wr);
 
-	return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr);
+	/* Restore send_flags & WR chain */
+	last_wr->send_flags = 0;
+	last_wr->next = next_wr;
+
+	return ret;
 }
 
-void ipoib_send(struct net_device *dev, struct sk_buff *skb,
-		struct ipoib_ah *address, u32 qpn)
+/*
+ * Map skb & store skb/mapping in tx_ring; and details of the WR in tx_wr
+ * to pass to the provider.
+ *
+ * Returns:
+ *	1: Error and the skb is freed.
+ *	0 skb processed successfully.
+ */
+int ipoib_process_skb(struct net_device *dev, struct sk_buff *skb,
+		      struct ipoib_dev_priv *priv, struct ipoib_ah *address,
+		      u32 qpn, int wr_num)
 {
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	struct ipoib_tx_buf *tx_req;
 	u64 addr;
+	unsigned int tx_ring_index;
 
 	if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) {
 		ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
@@ -365,7 +428,7 @@ void ipoib_send(struct net_device *dev, 
 		++priv->stats.tx_dropped;
 		++priv->stats.tx_errors;
 		ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu);
-		return;
+		return 1;
 	}
 
 	ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n",
@@ -378,35 +441,96 @@ void ipoib_send(struct net_device *dev, 
 	 * means we have to make sure everything is properly recorded and
 	 * our state is consistent before we call post_send().
 	 */
-	tx_req = &priv->tx_ring[priv->tx_head & (ipoib_sendq_size - 1)];
-	tx_req->skb = skb;
-	addr = ib_dma_map_single(priv->ca, skb->data, skb->len,
-				 DMA_TO_DEVICE);
+	addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE);
 	if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
 		++priv->stats.tx_errors;
 		dev_kfree_skb_any(skb);
-		return;
+		return 1;
 	}
-	tx_req->mapping = addr;
 
-	if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
-			       address->ah, qpn, addr, skb->len))) {
-		ipoib_warn(priv, "post_send failed\n");
-		++priv->stats.tx_errors;
-		ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
-		dev_kfree_skb_any(skb);
-	} else {
-		dev->trans_start = jiffies;
+	tx_ring_index = priv->tx_head & (ipoib_sendq_size - 1);
+
+	/* Save till completion handler executes */
+	priv->tx_ring[tx_ring_index].skb = skb;
+	priv->tx_ring[tx_ring_index].mapping = addr;
+
+	/* Set WR values for the provider to use */
+	priv->tx_sge[wr_num].addr = addr;
+	priv->tx_sge[wr_num].length = skb->len;
+
+	priv->tx_wr[wr_num].wr_id = tx_ring_index;
+	priv->tx_wr[wr_num].wr.ud.remote_qpn = qpn;
+	priv->tx_wr[wr_num].wr.ud.ah = address->ah;
+
+	priv->tx_head++;
+
+	if (unlikely(priv->tx_head - priv->tx_tail == ipoib_sendq_size)) {
+		ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
+		netif_stop_queue(dev);
+		set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
+	}
 
-		address->last_send = priv->tx_head;
-		++priv->tx_head;
+	return 0;
+}
 
-		if (priv->tx_head - priv->tx_tail == ipoib_sendq_size) {
-			ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
-			netif_stop_queue(dev);
-			set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
+/*
+ * Send num_skbs to the device. If an skb is passed to this function, it is
+ * single, unprocessed skb send case; otherwise it means that all skbs are
+ * already processed and put on priv->tx_wr,tx_sge,tx_ring, etc.
+ */
+void ipoib_send(struct net_device *dev, struct sk_buff *skb,
+		struct ipoib_ah *address, u32 qpn, int num_skbs)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int first_wr = 0;
+
+	if (skb && ipoib_process_skb(dev, skb, priv, address, qpn, 0))
+		return;
+
+	/* Send all skb's in one post */
+	do {
+		struct ib_send_wr *bad_wr;
+
+		if (unlikely((post_send(priv, qpn, first_wr, num_skbs,
+					&bad_wr)))) {
+			int done;
+
+			ipoib_warn(priv, "post_send failed\n");
+
+			/* Get number of WR's that finished successfully */
+			done = bad_wr - &priv->tx_wr[first_wr];
+
+			/* Handle 1 error */
+			priv->stats.tx_errors++;
+			ib_dma_unmap_single(priv->ca,
+				priv->tx_sge[first_wr + done].addr,
+				priv->tx_sge[first_wr + done].length,
+				DMA_TO_DEVICE);
+
+			/* Free failed WR & reset for WC handler to recognize */
+			dev_kfree_skb_any(priv->tx_ring[bad_wr->wr_id].skb);
+			priv->tx_ring[bad_wr->wr_id].skb = NULL;
+
+			/* Handle 'n' successes */
+			if (done) {
+				dev->trans_start = jiffies;
+				address->last_send = priv->tx_head - (num_skbs -
+								      done) - 1;
+			}
+
+			/* Get count of skbs that were not tried */
+			num_skbs -= (done + 1);
+				/* + 1 for WR that was tried & failed */
+
+			/* Get start index for next iteration */
+			first_wr += (done + 1);
+		} else {
+			dev->trans_start = jiffies;
+
+			address->last_send = priv->tx_head - 1;
+			num_skbs = 0;
 		}
-	}
+	} while (num_skbs);
 }
 
 static void __ipoib_reap_ah(struct net_device *dev)

^ permalink raw reply

* [PATCH 9/10 REV5] [IPoIB] Implement batching
From: Krishna Kumar @ 2007-09-14  9:04 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, peter.p.waskiewicz.jr, xma, gaagaan,
	kumarkr, rdreier, rick.jones2, mcarlson, jeff, general, mchan,
	tgraf, randy.dunlap, netdev, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

IPoIB: implement the new batching API.

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 ipoib_main.c |  248 +++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 168 insertions(+), 80 deletions(-)

diff -ruNp org/drivers/infiniband/ulp/ipoib/ipoib_main.c new/drivers/infiniband/ulp/ipoib/ipoib_main.c
--- org/drivers/infiniband/ulp/ipoib/ipoib_main.c	2007-09-13 09:10:58.000000000 +0530
+++ new/drivers/infiniband/ulp/ipoib/ipoib_main.c	2007-09-14 10:25:36.000000000 +0530
@@ -563,7 +563,8 @@ static void neigh_add_path(struct sk_buf
 				goto err_drop;
 			}
 		} else
-			ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha));
+			ipoib_send(dev, skb, path->ah,
+				   IPOIB_QPN(skb->dst->neighbour->ha), 1);
 	} else {
 		neigh->ah  = NULL;
 
@@ -643,7 +644,7 @@ static void unicast_arp_send(struct sk_b
 		ipoib_dbg(priv, "Send unicast ARP to %04x\n",
 			  be16_to_cpu(path->pathrec.dlid));
 
-		ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr));
+		ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr), 1);
 	} else if ((path->query || !path_rec_start(dev, path)) &&
 		   skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
 		/* put pseudoheader back on for next time */
@@ -657,105 +658,163 @@ static void unicast_arp_send(struct sk_b
 	spin_unlock(&priv->lock);
 }
 
+#define	XMIT_PROCESSED_SKBS()						\
+	do {								\
+		if (wr_num) {						\
+			ipoib_send(dev, NULL, old_neigh->ah, old_qpn,	\
+				   wr_num);				\
+			wr_num = 0;					\
+		}							\
+	} while (0)
+
 static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	struct ipoib_neigh *neigh;
+	struct sk_buff_head *blist;
+	int max_skbs, wr_num = 0;
+	u32 qpn, old_qpn = 0;
+	struct ipoib_neigh *neigh, *old_neigh = NULL;
 	unsigned long flags;
 
 	if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
 		return NETDEV_TX_LOCKED;
 
-	/*
-	 * Check if our queue is stopped.  Since we have the LLTX bit
-	 * set, we can't rely on netif_stop_queue() preventing our
-	 * xmit function from being called with a full queue.
-	 */
-	if (unlikely(netif_queue_stopped(dev))) {
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
-		return NETDEV_TX_BUSY;
+	blist = dev->skb_blist;
+	if (!skb || (blist && skb_queue_len(blist))) {
+		/*
+		 * Either batching xmit call, or single skb case but there are
+		 * skbs already in the batch list from previous failure to
+		 * xmit - send the earlier skbs first to avoid out of order.
+		 */
+
+		if (skb)
+			__skb_queue_tail(blist, skb);
+
+		/*
+		 * Figure out how many skbs can be sent. This prevents the
+		 * device getting full and avoids checking for stopped queue
+		 * after each iteration. Now the queue can get stopped atmost
+		 * after xmit of the last skb.
+		 */
+		max_skbs = ipoib_sendq_size - (priv->tx_head - priv->tx_tail);
+		skb = __skb_dequeue(blist);
+	} else {
+		blist = NULL;
+		max_skbs = 1;
 	}
 
-	if (likely(skb->dst && skb->dst->neighbour)) {
-		if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
-			ipoib_path_lookup(skb, dev);
-			goto out;
-		}
-
-		neigh = *to_ipoib_neigh(skb->dst->neighbour);
-
-		if (ipoib_cm_get(neigh)) {
-			if (ipoib_cm_up(neigh)) {
-				ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
-				goto out;
-			}
-		} else if (neigh->ah) {
-			if (unlikely(memcmp(&neigh->dgid.raw,
-					    skb->dst->neighbour->ha + 4,
-					    sizeof(union ib_gid)))) {
-				spin_lock(&priv->lock);
-				/*
-				 * It's safe to call ipoib_put_ah() inside
-				 * priv->lock here, because we know that
-				 * path->ah will always hold one more reference,
-				 * so ipoib_put_ah() will never do more than
-				 * decrement the ref count.
-				 */
-				ipoib_put_ah(neigh->ah);
-				list_del(&neigh->list);
-				ipoib_neigh_free(dev, neigh);
-				spin_unlock(&priv->lock);
+	do {
+		if (likely(skb->dst && skb->dst->neighbour)) {
+			if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
+				XMIT_PROCESSED_SKBS();
 				ipoib_path_lookup(skb, dev);
-				goto out;
+				continue;
 			}
 
-			ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
-			goto out;
-		}
-
-		if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
-			spin_lock(&priv->lock);
-			__skb_queue_tail(&neigh->queue, skb);
-			spin_unlock(&priv->lock);
-		} else {
-			++priv->stats.tx_dropped;
-			dev_kfree_skb_any(skb);
-		}
-	} else {
-		struct ipoib_pseudoheader *phdr =
-			(struct ipoib_pseudoheader *) skb->data;
-		skb_pull(skb, sizeof *phdr);
+			neigh = *to_ipoib_neigh(skb->dst->neighbour);
 
-		if (phdr->hwaddr[4] == 0xff) {
-			/* Add in the P_Key for multicast*/
-			phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
-			phdr->hwaddr[9] = priv->pkey & 0xff;
+			if (ipoib_cm_get(neigh)) {
+				if (ipoib_cm_up(neigh)) {
+					XMIT_PROCESSED_SKBS();
+					ipoib_cm_send(dev, skb,
+						      ipoib_cm_get(neigh));
+					continue;
+				}
+			} else if (neigh->ah) {
+				if (unlikely(memcmp(&neigh->dgid.raw,
+						    skb->dst->neighbour->ha + 4,
+						    sizeof(union ib_gid)))) {
+					spin_lock(&priv->lock);
+					/*
+					 * It's safe to call ipoib_put_ah()
+					 * inside priv->lock here, because we
+					 * know that path->ah will always hold
+					 * one more reference, so ipoib_put_ah()
+					 * will never do more than decrement
+					 * the ref count.
+					 */
+					ipoib_put_ah(neigh->ah);
+					list_del(&neigh->list);
+					ipoib_neigh_free(dev, neigh);
+					spin_unlock(&priv->lock);
+					XMIT_PROCESSED_SKBS();
+					ipoib_path_lookup(skb, dev);
+					continue;
+				}
+
+				qpn = IPOIB_QPN(skb->dst->neighbour->ha);
+				if (neigh != old_neigh || qpn != old_qpn) {
+					/*
+					 * Sending to a different destination
+					 * from earlier skb's (or this is the
+					 * first skb) - send all existing skbs.
+					 */
+					XMIT_PROCESSED_SKBS();
+					old_neigh = neigh;
+					old_qpn = qpn;
+				}
+
+				if (likely(!ipoib_process_skb(dev, skb, priv,
+							      neigh->ah, qpn,
+							      wr_num)))
+					wr_num++;
 
-			ipoib_mcast_send(dev, phdr->hwaddr + 4, skb);
-		} else {
-			/* unicast GID -- should be ARP or RARP reply */
+				continue;
+			}
 
-			if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) &&
-			    (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) {
-				ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x "
-					   IPOIB_GID_FMT "\n",
-					   skb->dst ? "neigh" : "dst",
-					   be16_to_cpup((__be16 *) skb->data),
-					   IPOIB_QPN(phdr->hwaddr),
-					   IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
+			if (skb_queue_len(&neigh->queue) <
+			    IPOIB_MAX_PATH_REC_QUEUE) {
+				spin_lock(&priv->lock);
+				__skb_queue_tail(&neigh->queue, skb);
+				spin_unlock(&priv->lock);
+			} else {
 				dev_kfree_skb_any(skb);
 				++priv->stats.tx_dropped;
-				goto out;
 			}
-
-			unicast_arp_send(skb, dev, phdr);
+		} else {
+			struct ipoib_pseudoheader *phdr =
+				(struct ipoib_pseudoheader *) skb->data;
+			skb_pull(skb, sizeof *phdr);
+
+			if (phdr->hwaddr[4] == 0xff) {
+				/* Add in the P_Key for multicast*/
+				phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
+				phdr->hwaddr[9] = priv->pkey & 0xff;
+
+				XMIT_PROCESSED_SKBS();
+				ipoib_mcast_send(dev, phdr->hwaddr + 4, skb);
+			} else {
+				/* unicast GID -- should be ARP or RARP reply */
+
+				if ((be16_to_cpup((__be16 *) skb->data) !=
+				    ETH_P_ARP) &&
+				    (be16_to_cpup((__be16 *) skb->data) !=
+				    ETH_P_RARP)) {
+					ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x "
+						IPOIB_GID_FMT "\n",
+						skb->dst ? "neigh" : "dst",
+						be16_to_cpup((__be16 *)
+						skb->data),
+						IPOIB_QPN(phdr->hwaddr),
+						IPOIB_GID_RAW_ARG(phdr->hwaddr
+								  + 4));
+					dev_kfree_skb_any(skb);
+					++priv->stats.tx_dropped;
+					continue;
+				}
+				XMIT_PROCESSED_SKBS();
+				unicast_arp_send(skb, dev, phdr);
+			}
 		}
-	}
+	} while (--max_skbs > 0 && (skb = __skb_dequeue(blist)) != NULL);
+
+	/* Send out last packets (if any) */
+	XMIT_PROCESSED_SKBS();
 
-out:
 	spin_unlock_irqrestore(&priv->tx_lock, flags);
 
-	return NETDEV_TX_OK;
+	return (!blist || !skb_queue_len(blist)) ? NETDEV_TX_OK :
+						   NETDEV_TX_BUSY;
 }
 
 static struct net_device_stats *ipoib_get_stats(struct net_device *dev)
@@ -903,11 +962,35 @@ int ipoib_dev_init(struct net_device *de
 
 	/* priv->tx_head & tx_tail are already 0 */
 
-	if (ipoib_ib_dev_init(dev, ca, port))
+	/* Allocate tx_sge */
+	priv->tx_sge = kmalloc(ipoib_sendq_size * sizeof *priv->tx_sge,
+			       GFP_KERNEL);
+	if (!priv->tx_sge) {
+		printk(KERN_WARNING "%s: failed to allocate TX sge (%d entries)\n",
+		       ca->name, ipoib_sendq_size);
 		goto out_tx_ring_cleanup;
+	}
+
+	/* Allocate tx_wr */
+	priv->tx_wr = kmalloc(ipoib_sendq_size * sizeof *priv->tx_wr,
+			      GFP_KERNEL);
+	if (!priv->tx_wr) {
+		printk(KERN_WARNING "%s: failed to allocate TX wr (%d entries)\n",
+		       ca->name, ipoib_sendq_size);
+		goto out_tx_sge_cleanup;
+	}
+
+	if (ipoib_ib_dev_init(dev, ca, port))
+		goto out_tx_wr_cleanup;
 
 	return 0;
 
+out_tx_wr_cleanup:
+	kfree(priv->tx_wr);
+
+out_tx_sge_cleanup:
+	kfree(priv->tx_sge);
+
 out_tx_ring_cleanup:
 	kfree(priv->tx_ring);
 
@@ -935,9 +1018,13 @@ void ipoib_dev_cleanup(struct net_device
 
 	kfree(priv->rx_ring);
 	kfree(priv->tx_ring);
+	kfree(priv->tx_sge);
+	kfree(priv->tx_wr);
 
 	priv->rx_ring = NULL;
 	priv->tx_ring = NULL;
+	priv->tx_sge = NULL;
+	priv->tx_wr = NULL;
 }
 
 static void ipoib_setup(struct net_device *dev)
@@ -968,7 +1055,8 @@ static void ipoib_setup(struct net_devic
 	dev->addr_len 		 = INFINIBAND_ALEN;
 	dev->type 		 = ARPHRD_INFINIBAND;
 	dev->tx_queue_len 	 = ipoib_sendq_size * 2;
-	dev->features            = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
+	dev->features            = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX |
+				   NETIF_F_BATCH_SKBS;
 
 	/* MTU will be reset when mcast join happens */
 	dev->mtu 		 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;

^ permalink raw reply

* [PATCH 10/10 REV5] [E1000] Implement batching
From: Krishna Kumar @ 2007-09-14  9:04 UTC (permalink / raw)
  To: johnpol, herbert, hadi, kaber, shemminger, davem
  Cc: jagana, Robert.Olsson, rick.jones2, xma, gaagaan, kumarkr,
	rdreier, peter.p.waskiewicz.jr, mcarlson, jeff, general, mchan,
	tgraf, randy.dunlap, netdev, Krishna Kumar, sri
In-Reply-To: <20070914090058.17589.80352.sendpatchset@K50wks273871wss.in.ibm.com>

E1000: Implement batching capability (ported thanks to changes taken from
	Jamal).

Signed-off-by: Krishna Kumar <krkumar2@in.ibm.com>
---
 e1000_main.c |  104 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 75 insertions(+), 29 deletions(-)

diff -ruNp org/drivers/net/e1000/e1000_main.c new/drivers/net/e1000/e1000_main.c
--- org/drivers/net/e1000/e1000_main.c	2007-09-14 10:30:57.000000000 +0530
+++ new/drivers/net/e1000/e1000_main.c	2007-09-14 10:31:02.000000000 +0530
@@ -990,7 +990,7 @@ e1000_probe(struct pci_dev *pdev,
 	if (pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
-	netdev->features |= NETIF_F_LLTX;
+	netdev->features |= NETIF_F_LLTX | NETIF_F_BATCH_SKBS;
 
 	adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
 
@@ -3092,6 +3092,17 @@ e1000_tx_map(struct e1000_adapter *adapt
 	return count;
 }
 
+static void e1000_kick_DMA(struct e1000_adapter *adapter,
+			   struct e1000_tx_ring *tx_ring, int i)
+{
+	wmb();
+
+	writel(i, adapter->hw.hw_addr + tx_ring->tdt);
+	/* we need this if more than one processor can write to our tail
+	 * at a time, it syncronizes IO on IA64/Altix systems */
+	mmiowb();
+}
+
 static void
 e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
                int tx_flags, int count)
@@ -3138,13 +3149,7 @@ e1000_tx_queue(struct e1000_adapter *ada
 	 * know there are new descriptors to fetch.  (Only
 	 * applicable for weak-ordered memory model archs,
 	 * such as IA-64). */
-	wmb();
-
 	tx_ring->next_to_use = i;
-	writel(i, adapter->hw.hw_addr + tx_ring->tdt);
-	/* we need this if more than one processor can write to our tail
-	 * at a time, it syncronizes IO on IA64/Altix systems */
-	mmiowb();
 }
 
 /**
@@ -3251,22 +3256,23 @@ static int e1000_maybe_stop_tx(struct ne
 }
 
 #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
+
+#define NETDEV_TX_DROPPED	-5
+
 static int
-e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+e1000_prep_queue_frame(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_tx_ring *tx_ring;
 	unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
 	unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
 	unsigned int tx_flags = 0;
-	unsigned int len = skb->len;
-	unsigned long flags;
-	unsigned int nr_frags = 0;
-	unsigned int mss = 0;
+	unsigned int len = skb->len - skb->data_len;
+	unsigned int nr_frags;
+	unsigned int mss;
 	int count = 0;
 	int tso;
 	unsigned int f;
-	len -= skb->data_len;
 
 	/* This goes back to the question of how to logically map a tx queue
 	 * to a flow.  Right now, performance is impacted slightly negatively
@@ -3276,7 +3282,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 
 	if (unlikely(skb->len <= 0)) {
 		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
+		return NETDEV_TX_DROPPED;
 	}
 
 	/* 82571 and newer doesn't need the workaround that limited descriptor
@@ -3322,7 +3328,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 					DPRINTK(DRV, ERR,
 						"__pskb_pull_tail failed.\n");
 					dev_kfree_skb_any(skb);
-					return NETDEV_TX_OK;
+					return NETDEV_TX_DROPPED;
 				}
 				len = skb->len - skb->data_len;
 				break;
@@ -3366,22 +3372,15 @@ e1000_xmit_frame(struct sk_buff *skb, st
 	    (adapter->hw.mac_type == e1000_82573))
 		e1000_transfer_dhcp_info(adapter, skb);
 
-	if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags))
-		/* Collision - tell upper layer to requeue */
-		return NETDEV_TX_LOCKED;
-
 	/* need: count + 2 desc gap to keep tail from touching
 	 * head, otherwise try next time */
-	if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2))) {
-		spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+	if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2)))
 		return NETDEV_TX_BUSY;
-	}
 
 	if (unlikely(adapter->hw.mac_type == e1000_82547)) {
 		if (unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
 			netif_stop_queue(netdev);
 			mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1);
-			spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
 			return NETDEV_TX_BUSY;
 		}
 	}
@@ -3396,8 +3395,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 	tso = e1000_tso(adapter, tx_ring, skb);
 	if (tso < 0) {
 		dev_kfree_skb_any(skb);
-		spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
-		return NETDEV_TX_OK;
+		return NETDEV_TX_DROPPED;
 	}
 
 	if (likely(tso)) {
@@ -3416,13 +3414,61 @@ e1000_xmit_frame(struct sk_buff *skb, st
 	               e1000_tx_map(adapter, tx_ring, skb, first,
 	                            max_per_txd, nr_frags, mss));
 
-	netdev->trans_start = jiffies;
+	return NETDEV_TX_OK;
+}
+
+static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_tx_ring *tx_ring = adapter->tx_ring;
+	struct sk_buff_head *blist;
+	int ret, skbs_done = 0;
+	unsigned long flags;
+
+	if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags)) {
+		/* Collision - tell upper layer to requeue */
+		return NETDEV_TX_LOCKED;
+	}
 
-	/* Make sure there is space in the ring for the next send. */
-	e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
+	blist = netdev->skb_blist;
+
+	if (!skb || (blist && skb_queue_len(blist))) {
+		/*
+		 * Either batching xmit call, or single skb case but there are
+		 * skbs already in the batch list from previous failure to
+		 * xmit - send the earlier skbs first to avoid out of order.
+		 */
+		if (skb)
+			__skb_queue_tail(blist, skb);
+		skb = __skb_dequeue(blist);
+	} else {
+		blist = NULL;
+	}
+
+	do {
+		ret = e1000_prep_queue_frame(skb, netdev);
+		if (likely(ret == NETDEV_TX_OK))
+			skbs_done++;
+		else {
+			if (ret == NETDEV_TX_BUSY) {
+				if (blist)
+					__skb_queue_head(blist, skb);
+				break;
+			}
+			/* skb dropped, not a TX error */
+			ret = NETDEV_TX_OK;
+		}
+	} while (blist && (skb = __skb_dequeue(blist)) != NULL);
+
+	if (skbs_done) {
+		e1000_kick_DMA(adapter, tx_ring, adapter->tx_ring->next_to_use);
+		netdev->trans_start = jiffies;
+		/* Make sure there is space in the ring for the next send. */
+		e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
+	}
 
 	spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
-	return NETDEV_TX_OK;
+	return ret;
 }
 
 /**

^ permalink raw reply

* Re: [patch] sunrpc: make closing of old temporary sockets work (was: problems with lockd in 2.6.22.6)
From: Wolfgang Walter @ 2007-09-14  9:12 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: Neil Brown, trond.myklebust, netdev, nfs, linux-kernel
In-Reply-To: <20070912195512.GC13792@fieldses.org>

Am Mittwoch, 12. September 2007 21:55 schrieb J. Bruce Fields:
> On Wed, Sep 12, 2007 at 09:40:57PM +0200, Wolfgang Walter wrote:
> > On Wednesday 12 September 2007, J. Bruce Fields wrote:
> > > On Wed, Sep 12, 2007 at 04:14:06PM +0200, Neil Brown wrote:
> > > > So it is in 2.6.21 and later and should probably go to .stable for
> > > > .21 and .22.
> > > >
> > > > Bruce:  for you :-)
> > >
> > > OK, thanks!  But, (as is alas often the case) I'm still confused:
> > > >  		if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
> > > >  			continue;
> > > > -		if (atomic_read(&svsk->sk_inuse) || test_bit(SK_BUSY,
> > > > &svsk->sk_flags)) +		if (atomic_read(&svsk->sk_inuse) > 1
> > > > +		    || test_bit(SK_BUSY, &svsk->sk_flags))
> > > >  			continue;
> > > >  		atomic_inc(&svsk->sk_inuse);
> > > >  		list_move(le, &to_be_aged);
> > >
> > > What is it that ensures svsk->sk_inuse isn't incremented or SK_BUSY set
> > > after that test?  Not all the code that does either of those is under
> > > the same serv->sv_lock lock that this code is.
> >
> > This should not matter - SK_CLOSED may be set at any time.
> >
> > svc_age_temp_sockets only detaches the socket, sets SK_CLOSED and then
> > enqueues it. If SK_BUSY is set its already enqueued and svc_sock_enqueue
> > ensures that it is not enqueued twice.
>
> Oh, got it.  And the list manipulation is safe thanks to sv_lock.  Neat,
> thanks.  Can you verify that this solves your problem?

Patch works fine here.

Regards,
-- 
Wolfgang Walter
Studentenwerk München
Anstalt des öffentlichen Rechts

^ permalink raw reply

* Re: Network Namespace status
From: Eric W. Biederman @ 2007-09-14  9:33 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: Linux Containers, netdev, David Miller, Tejun Heo,
	Greg Kroah-Hartman, Andrew Morton, Thomas Gleixner, Urs Thuermann
In-Reply-To: <46EA244C.1050702@hartkopp.net>

Oliver Hartkopp <oliver@hartkopp.net> writes:

> can you send me your current AF_PACKET patch? I just want to update our
> recent post of the CAN (controller area network) subsystem (AF_CAN)
> which is (in some parts) similar to AF_PACKET. So i can take a look on
> it to provide the latest technique in the next post ...

Ok the last snapshot of my tree is at:

git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/linux-2.6-netns.git
And tagged as: netns/v2.6.23-rc5netns45

Although that is the same as the default HEAD until I rebase my tree
again.

Eric

^ permalink raw reply


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