* [PATCH] pcnet32 driver NAPI support
@ 2006-06-07 16:52 Lennart Sorensen
2006-06-07 18:20 ` Don Fry
2006-06-08 8:03 ` Pavel Machek
0 siblings, 2 replies; 5+ messages in thread
From: Lennart Sorensen @ 2006-06-07 16:52 UTC (permalink / raw)
To: linux-kernel; +Cc: Len Sorensen, linux-net
[-- Attachment #1: Type: text/plain, Size: 1242 bytes --]
I have added NAPI support to the pcnet32 driver. This has greatly
improved the responsiveness on my systems (geode GX1 266MHz) when under
heavy network load. Without this change the system would become
unresponsive due to interrupts when flooded with traffic, and eventually
the watchdog would reboot the system due to the watchdog daemon being
starved for cpu time. With the patch the system is still useable on a
serial console, although very slow. Network throughput is also higher
since more time is spend processing packets and getting them sent out,
instead of only spending time acknowledging interrupts from incoming
packets.
Now having never actually done a patch submission to the kernel before,
I will try and see if I can do it right.
The patch adds a PCNET32_NAPI config option to drivers/net/Kconfig, and
the appropriate code to support the option to drivers/net/pcnet32.c and
has been tested on many of my systems (allthough they are allmost all
identical, and require some extra patches to pcnet32 due to not having
an EEPROM installed), and on an AT-2700TX.
I have made a diff against 2.6.16.20 and 2.6.17-rc6.
Comments would be very welcome.
Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
Len Sorensen
[-- Attachment #2: pcnet32napi.2.6.16.20.diff --]
[-- Type: text/plain, Size: 12270 bytes --]
diff -ruN linux-2.6.16.20/drivers/net/Kconfig linux-2.6.16.20.pcnet32napi/drivers/net/Kconfig
--- linux-2.6.16.20/drivers/net/Kconfig 2006-06-05 13:18:23.000000000 -0400
+++ linux-2.6.16.20.pcnet32napi/drivers/net/Kconfig 2006-06-07 11:19:54.000000000 -0400
@@ -1272,6 +1272,23 @@
<file:Documentation/networking/net-modules.txt>. The module
will be called pcnet32.
+config PCNET32_NAPI
+ bool "Use NAPI RX polling "
+ depends on PCNET32
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
+
config AMD8111_ETH
tristate "AMD 8111 (new PCI lance) support"
depends on NET_PCI && PCI
diff -ruN linux-2.6.16.20/drivers/net/pcnet32.c linux-2.6.16.20.pcnet32napi/drivers/net/pcnet32.c
--- linux-2.6.16.20/drivers/net/pcnet32.c 2006-06-05 13:18:23.000000000 -0400
+++ linux-2.6.16.20.pcnet32napi/drivers/net/pcnet32.c 2006-06-07 12:00:36.000000000 -0400
@@ -21,9 +21,15 @@
*
*************************************************************************/
+#include <linux/config.h>
+
+#ifdef CONFIG_PCNET32_NAPI
+#define DRV_NAME "pcnet32napi"
+#else
#define DRV_NAME "pcnet32"
-#define DRV_VERSION "1.31c"
-#define DRV_RELDATE "01.Nov.2005"
+#endif
+#define DRV_VERSION "1.31d"
+#define DRV_RELDATE "06.Jun.2006"
#define PFX DRV_NAME ": "
static const char *version =
@@ -265,6 +271,7 @@
* v1.31c 01 Nov 2005 Don Fry Allied Telesyn 2700/2701 FX are 100Mbit only.
* Force 100Mbit FD if Auto (ASEL) is selected.
* See Bugzilla 2669 and 4551.
+ * v1.31d 06 Jun 2006 Len Sorensen added NAPI support.
*/
@@ -383,6 +390,7 @@
struct mii_if_info mii_if;
struct timer_list watchdog_timer;
struct timer_list blink_timer;
+ struct timer_list oom_timer;
u32 msg_enable; /* debug message level */
};
@@ -392,7 +400,13 @@
static int pcnet32_open(struct net_device *);
static int pcnet32_init_ring(struct net_device *);
static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
+#ifdef CONFIG_PCNET32_NAPI
+void disable_rx_and_norxbuff_ints(struct net_device *dev);
+void enable_rx_and_norxbuff_ints(struct net_device *dev);
+static int pcnet32_poll(struct net_device *, int *budget);
+#else
static int pcnet32_rx(struct net_device *);
+#endif
static void pcnet32_tx_timeout (struct net_device *dev);
static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
static int pcnet32_close(struct net_device *);
@@ -422,6 +436,174 @@
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
+#ifdef CONFIG_PCNET32_NAPI
+void oom_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct pcnet32_private *lp = dev->priv;
+ lp->rl_active = 0;
+ netif_rx_schedule(dev);
+}
+
+static
+int pcnet32_poll(struct net_device *dev, int *budget)
+{
+ struct pcnet32_private *lp = dev->priv;
+ ulong ioaddr = dev->base_addr;
+
+ int entry = lp->cur_rx & lp->rx_mod_mask;
+ int rx_work_limit = dev->quota;
+ int received = 0;
+
+ if (!netif_running(dev))
+ goto done;
+
+ do {
+ // Clear RX interrupts
+ lp->a.write_csr (ioaddr, 0, 0x1400);
+
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
+ int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
+
+ if (status != 0x03) { /* There was an error. */
+ /*
+ * There is a tricky error noted by John Murphy,
+ * <murf@perftech.com> to Russ Nelson: Even with full-sized
+ * buffers it's possible for a jabber packet to use two
+ * buffers, with only the last correctly noting the error.
+ */
+ if (status & 0x01) /* Only count a general error at the */
+ lp->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x20) lp->stats.rx_frame_errors++;
+ if (status & 0x10) lp->stats.rx_over_errors++;
+ if (status & 0x08) lp->stats.rx_crc_errors++;
+ if (status & 0x04) lp->stats.rx_fifo_errors++;
+ lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+ } else {
+ /* Malloc up new buffer, compatible with net-2e. */
+ short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
+ struct sk_buff *skb;
+
+ /* Discard oversize frames. */
+ if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR "%s: Impossible packet size %d!\n",
+ dev->name, pkt_len);
+ lp->stats.rx_errors++;
+ } else if (pkt_len < 60) {
+ if (netif_msg_rx_err(lp))
+ printk(KERN_ERR "%s: Runt packet!\n", dev->name);
+ lp->stats.rx_errors++;
+ } else {
+ int rx_in_place = 0;
+ if (--rx_work_limit < 0) {
+ goto not_done;
+ }
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+ if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) {
+ skb_reserve (newskb, 2);
+ skb = lp->rx_skbuff[entry];
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry],
+ PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
+ skb_put (skb, pkt_len);
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ lp->rx_dma_addr[entry] =
+ pci_map_single(lp->pci_dev, newskb->data,
+ PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
+ lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
+ rx_in_place = 1;
+ } else
+ skb = NULL;
+ } else {
+ skb = dev_alloc_skb(pkt_len+2);
+ }
+ if (skb == NULL) {
+ int i;
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ for (i = 0; i < lp->rx_ring_size; i++)
+ if ((short)le16_to_cpu(lp->rx_ring[(entry+i)
+ & lp->rx_mod_mask].status) < 0)
+ break;
+
+ if (i > lp->rx_ring_size -2) {
+ lp->stats.rx_dropped++;
+ lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+ wmb(); /* Make sure adapter sees owner change */
+ lp->cur_rx++;
+ }
+ goto oom;
+ }
+ skb->dev = dev;
+ if (!rx_in_place) {
+ skb_reserve(skb,2); /* 16 byte align */
+ skb_put(skb,pkt_len); /* Make room */
+ pci_dma_sync_single_for_cpu(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ-2,
+ PCI_DMA_FROMDEVICE);
+ eth_copy_and_sum(skb,
+ (unsigned char *)(lp->rx_skbuff[entry]->data),
+ pkt_len,0);
+ pci_dma_sync_single_for_device(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ-2,
+ PCI_DMA_FROMDEVICE);
+ }
+ lp->stats.rx_bytes += skb->len;
+ skb->protocol=eth_type_trans(skb,dev);
+ dev->last_rx = jiffies;
+ netif_receive_skb(skb);
+ lp->stats.rx_packets++;
+ }
+ }
+ /*
+ * The docs say that the buffer length isn't touched, but Andrew Boyd
+ * of QNX reports that some revs of the 79C965 clear it.
+ */
+ lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
+ wmb(); /* Make sure owner changes after all others are visible */
+ lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+ entry = (++lp->cur_rx) & lp->rx_mod_mask;
+ received++;
+ }
+ } while(lp->a.read_csr (ioaddr, 0) & 0x1400);
+
+done:
+
+ dev->quota -= received;
+ *budget -= received;
+
+ /* Remove us from polling list and enable RX intr. */
+ netif_rx_complete(dev);
+ enable_rx_and_norxbuff_ints(dev);
+
+ return 0;
+
+not_done:
+ if (!received) {
+ received = dev->quota; /* Not to happen */
+ }
+ dev->quota -= received;
+ *budget -= received;
+
+ return 1;
+
+oom: /* Executed with RX ints disabled */
+
+ /* Start timer, stop polling, but do not enable rx interrupts. */
+ mod_timer(&lp->oom_timer, jiffies+1);
+
+ /* remove ourselves from the polling list */
+ netif_rx_complete(dev);
+
+ return 0;
+}
+#endif
static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
{
@@ -775,7 +957,7 @@
lp->tx_ring[x].length = le16_to_cpu(-skb->len);
lp->tx_ring[x].misc = 0;
- /* put DA and SA into the skb */
+ /* put DA and SA into the skb */
for (i=0; i<6; i++)
*packet++ = dev->dev_addr[i];
for (i=0; i<6; i++)
@@ -1334,6 +1516,12 @@
lp->mii_if.mdio_read = mdio_read;
lp->mii_if.mdio_write = mdio_write;
+#ifdef CONFIG_PCNET32_NAPI
+ init_timer(&lp->oom_timer);
+ lp->oom_timer.data = (unsigned long)dev;
+ lp->oom_timer.function = oom_timer;
+#endif
+
if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&
((cards_found>=MAX_UNITS) || full_duplex[cards_found]))
lp->options |= PCNET32_PORT_FD;
@@ -1418,6 +1606,10 @@
dev->ethtool_ops = &pcnet32_ethtool_ops;
dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5*HZ);
+#ifdef CONFIG_PCNET32_NAPI
+ dev->poll = pcnet32_poll;
+ dev->weight = 16;
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = pcnet32_poll_controller;
@@ -1949,6 +2141,38 @@
return 0;
}
+void
+disable_rx_and_norxbuff_ints(struct net_device *dev)
+{
+ u16 csr3,rap;
+ unsigned long ioaddr;
+ struct pcnet32_private *lp;
+
+ ioaddr = dev->base_addr;
+ lp = dev->priv;
+ rap = lp->a.read_rap(ioaddr);
+ csr3 = lp->a.read_csr (ioaddr, 3);
+ lp->a.write_csr (ioaddr, 3, csr3 | 0x1400); // Set the MISSM and RINTM bits
+ lp->a.write_rap (ioaddr,rap);
+}
+
+void
+enable_rx_and_norxbuff_ints(struct net_device *dev)
+{
+ u16 csr3,rap;
+ unsigned long ioaddr;
+ struct pcnet32_private *lp;
+
+ ioaddr = dev->base_addr;
+ lp = dev->priv;
+ rap = lp->a.read_rap(ioaddr);
+ csr3 = lp->a.read_csr (ioaddr, 3);
+ lp->a.write_csr (ioaddr, 3, csr3 & ~0x1400); // Clear the MISSM and RINTM bits
+ /* Set interrupt enable. */
+ lp->a.write_csr (ioaddr, 0, 0x0040);
+ lp->a.write_rap (ioaddr,rap);
+}
+
/* The PCNET32 interrupt handler. */
static irqreturn_t
pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
@@ -1978,7 +2202,11 @@
break; /* PCMCIA remove happened */
}
/* Acknowledge all of the current interrupt sources ASAP. */
+#ifdef CONFIG_PCNET32_NAPI
+ lp->a.write_csr (ioaddr, 0, csr0 & ~0x144f);
+#else
lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f);
+#endif
must_restart = 0;
@@ -1986,8 +2214,18 @@
printk(KERN_DEBUG "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
dev->name, csr0, lp->a.read_csr (ioaddr, 0));
- if (csr0 & 0x0400) /* Rx interrupt */
+ if (csr0 & 0x0400) { /* Rx interrupt */
+#ifdef CONFIG_PCNET32_NAPI
+ if(!lp->rl_active) {
+ disable_rx_and_norxbuff_ints(dev);
+ netif_rx_schedule(dev);
+ } else {
+ lp->a.write_csr (ioaddr, 0, 0x0400);
+ }
+#else
pcnet32_rx(dev);
+#endif
+ }
if (csr0 & 0x0200) { /* Tx-done interrupt */
unsigned int dirty_tx = lp->dirty_tx;
@@ -2084,7 +2322,16 @@
* interrupt, but a missed frame interrupt sooner or later.
* So we try to clean up our receive ring here.
*/
+#ifdef CONFIG_PCNET32_NAPI
+ if(!lp->rl_active) {
+ disable_rx_and_norxbuff_ints(dev);
+ netif_rx_schedule(dev);
+ } else {
+ lp->a.write_csr (ioaddr, 0, 0x1000);
+ }
+#else
pcnet32_rx(dev);
+#endif
lp->stats.rx_errors++; /* Missed a Rx frame. */
}
if (csr0 & 0x0800) {
@@ -2116,6 +2363,7 @@
return IRQ_HANDLED;
}
+#ifndef CONFIG_PCNET32_NAPI
static int
pcnet32_rx(struct net_device *dev)
{
@@ -2235,6 +2483,7 @@
return 0;
}
+#endif
static int
pcnet32_close(struct net_device *dev)
@@ -2245,6 +2494,9 @@
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
+#ifdef CONFIG_PCNET32_NAPI
+ del_timer_sync(&lp->oom_timer);
+#endif
netif_stop_queue(dev);
[-- Attachment #3: pcnet32napi.2.6.17-rc6.diff --]
[-- Type: text/plain, Size: 11865 bytes --]
diff -ruN linux-2.6.17-rc6/drivers/net/Kconfig linux-2.6.17-rc6.pcnet32napi/drivers/net/Kconfig
--- linux-2.6.17-rc6/drivers/net/Kconfig 2006-06-05 13:18:23.000000000 -0400
+++ linux-2.6.17-rc6.pcnet32napi/drivers/net/Kconfig 2006-06-07 11:19:54.000000000 -0400
@@ -1272,6 +1272,23 @@
<file:Documentation/networking/net-modules.txt>. The module
will be called pcnet32.
+config PCNET32_NAPI
+ bool "Use NAPI RX polling "
+ depends on PCNET32
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
+
config AMD8111_ETH
tristate "AMD 8111 (new PCI lance) support"
depends on NET_PCI && PCI
diff -ruN linux-2.6.17-rc6/drivers/net/pcnet32.c linux-2.6.17-rc6.pcnet32napi/drivers/net/pcnet32.c
--- linux-2.6.17-rc6/drivers/net/pcnet32.c 2006-06-05 13:18:23.000000000 -0400
+++ linux-2.6.17-rc6.pcnet32napi/drivers/net/pcnet32.c 2006-06-07 12:00:36.000000000 -0400
@@ -21,9 +21,15 @@
*
*************************************************************************/
+#include <linux/config.h>
+
+#ifdef CONFIG_PCNET32_NAPI
+#define DRV_NAME "pcnet32napi"
+#else
#define DRV_NAME "pcnet32"
-#define DRV_VERSION "1.32"
-#define DRV_RELDATE "18.Mar.2006"
+#endif
+#define DRV_VERSION "1.32a"
+#define DRV_RELDATE "06.Jun.2006"
#define PFX DRV_NAME ": "
static const char *const version =
@@ -271,6 +277,7 @@
struct mii_if_info mii_if;
struct timer_list watchdog_timer;
struct timer_list blink_timer;
+ struct timer_list oom_timer;
u32 msg_enable; /* debug message level */
/* each bit indicates an available PHY */
@@ -283,7 +290,13 @@
static int pcnet32_open(struct net_device *);
static int pcnet32_init_ring(struct net_device *);
static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
+#ifdef CONFIG_PCNET32_NAPI
+void disable_rx_and_norxbuff_ints(struct net_device *dev);
+void enable_rx_and_norxbuff_ints(struct net_device *dev);
+static int pcnet32_poll(struct net_device *, int *budget);
+#else
static int pcnet32_rx(struct net_device *);
+#endif
static void pcnet32_tx_timeout(struct net_device *dev);
static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
static int pcnet32_close(struct net_device *);
@@ -315,6 +328,213 @@
0x10 << 2, PCI_ADDR3 = 0x10 << 3,
};
+#ifdef CONFIG_PCNET32_NAPI
+void oom_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct pcnet32_private *lp = dev->priv;
+ lp->rl_active = 0;
+ netif_rx_schedule(dev);
+}
+
+static
+int pcnet32_poll(struct net_device *dev, int *budget)
+{
+ struct pcnet32_private *lp = dev->priv;
+ ulong ioaddr = dev->base_addr;
+
+ int entry = lp->cur_rx & lp->rx_mod_mask;
+ int rx_work_limit = dev->quota;
+ int received = 0;
+
+ if (!netif_running(dev))
+ goto done;
+
+ do {
+ // Clear RX interrupts
+ lp->a.write_csr (ioaddr, 0, 0x1400);
+
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
+ int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
+
+ if (status != 0x03) { /* There was an error. */
+ /*
+ * There is a tricky error noted by John Murphy,
+ * <murf@perftech.com> to Russ Nelson: Even with full-sized
+ * buffers it's possible for a jabber packet to use two
+ * buffers, with only the last correctly noting the error.
+ */
+ if (status & 0x01) /* Only count a general error at the */
+ lp->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x20)
+ lp->stats.rx_frame_errors++;
+ if (status & 0x10)
+ lp->stats.rx_over_errors++;
+ if (status & 0x08)
+ lp->stats.rx_crc_errors++;
+ if (status & 0x04)
+ lp->stats.rx_fifo_errors++;
+ lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+ } else {
+ /* Malloc up new buffer, compatible with net-2e. */
+ short pkt_len =
+ (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)
+ - 4;
+ struct sk_buff *skb;
+
+ /* Discard oversize frames. */
+ if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: Impossible packet size %d!\n",
+ dev->name, pkt_len);
+ lp->stats.rx_errors++;
+ } else if (pkt_len < 60) {
+ if (netif_msg_rx_err(lp))
+ printk(KERN_ERR "%s: Runt packet!\n",
+ dev->name);
+ lp->stats.rx_errors++;
+ } else {
+ int rx_in_place = 0;
+ if (--rx_work_limit < 0) {
+ goto not_done;
+ }
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+
+ if ((newskb =
+ dev_alloc_skb(PKT_BUF_SZ))) {
+ skb_reserve (newskb, 2);
+ skb = lp->rx_skbuff[entry];
+ pci_unmap_single(lp->pci_dev,
+ lp->
+ rx_dma_addr
+ [entry],
+ PKT_BUF_SZ-2,
+ PCI_DMA_FROMDEVICE);
+ skb_put (skb, pkt_len);
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ lp->rx_dma_addr[entry] =
+ pci_map_single(lp->pci_dev,
+ newskb->data,
+ PKT_BUF_SZ -
+ 2,
+ PCI_DMA_FROMDEVICE);
+ lp->rx_ring[entry].base =
+ le32_to_cpu(lp->
+ rx_dma_addr
+ [entry]);
+ rx_in_place = 1;
+ } else
+ skb = NULL;
+ } else {
+ skb = dev_alloc_skb(pkt_len+2);
+ }
+
+ if (skb == NULL) {
+ int i;
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: Memory squeeze, deferring packet.\n",
+ dev->name);
+ for (i = 0; i < lp->rx_ring_size; i++)
+ if ((short)
+ le16_to_cpu(lp->
+ rx_ring[(entry +
+ i)
+ & lp->
+ rx_mod_mask].
+ status) < 0)
+ break;
+
+ if (i > lp->rx_ring_size -2) {
+ lp->stats.rx_dropped++;
+ lp->rx_ring[entry].status |=
+ le16_to_cpu(0x8000);
+ wmb(); /* Make sure adapter sees owner change */
+ lp->cur_rx++;
+ }
+ goto oom;
+ }
+ skb->dev = dev;
+ if (!rx_in_place) {
+ skb_reserve(skb,2); /* 16 byte align */
+ skb_put(skb,pkt_len); /* Make room */
+ pci_dma_sync_single_for_cpu(lp->pci_dev,
+ lp->
+ rx_dma_addr
+ [entry],
+ PKT_BUF_SZ -
+ 2,
+ PCI_DMA_FROMDEVICE);
+ eth_copy_and_sum(skb,
+ (unsigned char *)(lp->
+ rx_skbuff
+ [entry]->
+ data),
+ pkt_len,0);
+ pci_dma_sync_single_for_device(lp->
+ pci_dev,
+ lp->
+ rx_dma_addr
+ [entry],
+ PKT_BUF_SZ
+ - 2,
+ PCI_DMA_FROMDEVICE);
+ }
+ lp->stats.rx_bytes += skb->len;
+ skb->protocol=eth_type_trans(skb,dev);
+ dev->last_rx = jiffies;
+ netif_receive_skb(skb);
+ lp->stats.rx_packets++;
+ }
+ }
+ /*
+ * The docs say that the buffer length isn't touched, but Andrew Boyd
+ * of QNX reports that some revs of the 79C965 clear it.
+ */
+ lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
+ wmb(); /* Make sure owner changes after all others are visible */
+ lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+ entry = (++lp->cur_rx) & lp->rx_mod_mask;
+ received++;
+ }
+ } while(lp->a.read_csr (ioaddr, 0) & 0x1400);
+
+done:
+
+ dev->quota -= received;
+ *budget -= received;
+
+ /* Remove us from polling list and enable RX intr. */
+ netif_rx_complete(dev);
+ enable_rx_and_norxbuff_ints(dev);
+
+ return 0;
+
+not_done:
+ if (!received) {
+ received = dev->quota; /* Not to happen */
+ }
+ dev->quota -= received;
+ *budget -= received;
+
+ return 1;
+
+oom: /* Executed with RX ints disabled */
+
+ /* Start timer, stop polling, but do not enable rx interrupts. */
+ mod_timer(&lp->oom_timer, jiffies+1);
+
+ /* remove ourselves from the polling list */
+ netif_rx_complete(dev);
+
+ return 0;
+}
+#endif
+
static u16 pcnet32_wio_read_csr(unsigned long addr, int index)
{
outw(index, addr + PCNET32_WIO_RAP);
@@ -1284,6 +1504,12 @@
lp->mii_if.mdio_read = mdio_read;
lp->mii_if.mdio_write = mdio_write;
+#ifdef CONFIG_PCNET32_NAPI
+ init_timer(&lp->oom_timer);
+ lp->oom_timer.data = (unsigned long)dev;
+ lp->oom_timer.function = oom_timer;
+#endif
+
if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&
((cards_found >= MAX_UNITS) || full_duplex[cards_found]))
lp->options |= PCNET32_PORT_FD;
@@ -1396,6 +1622,10 @@
dev->ethtool_ops = &pcnet32_ethtool_ops;
dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5 * HZ);
+#ifdef CONFIG_PCNET32_NAPI
+ dev->poll = pcnet32_poll;
+ dev->weight = 16;
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = pcnet32_poll_controller;
@@ -2004,6 +2234,38 @@
return 0;
}
+void
+disable_rx_and_norxbuff_ints(struct net_device *dev)
+{
+ u16 csr3,rap;
+ unsigned long ioaddr;
+ struct pcnet32_private *lp;
+
+ ioaddr = dev->base_addr;
+ lp = dev->priv;
+ rap = lp->a.read_rap(ioaddr);
+ csr3 = lp->a.read_csr (ioaddr, 3);
+ lp->a.write_csr (ioaddr, 3, csr3 | 0x1400); // Set the MISSM and RINTM bits
+ lp->a.write_rap (ioaddr,rap);
+}
+
+void
+enable_rx_and_norxbuff_ints(struct net_device *dev)
+{
+ u16 csr3,rap;
+ unsigned long ioaddr;
+ struct pcnet32_private *lp;
+
+ ioaddr = dev->base_addr;
+ lp = dev->priv;
+ rap = lp->a.read_rap(ioaddr);
+ csr3 = lp->a.read_csr (ioaddr, 3);
+ lp->a.write_csr (ioaddr, 3, csr3 & ~0x1400); // Clear the MISSM and RINTM bits
+ /* Set interrupt enable. */
+ lp->a.write_csr (ioaddr, 0, 0x0040);
+ lp->a.write_rap (ioaddr,rap);
+}
+
/* The PCNET32 interrupt handler. */
static irqreturn_t
pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -2033,7 +2295,11 @@
break; /* PCMCIA remove happened */
}
/* Acknowledge all of the current interrupt sources ASAP. */
+#ifdef CONFIG_PCNET32_NAPI
+ lp->a.write_csr (ioaddr, 0, csr0 & ~0x144f);
+#else
lp->a.write_csr(ioaddr, 0, csr0 & ~0x004f);
+#endif
must_restart = 0;
@@ -2042,8 +2308,18 @@
"%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
dev->name, csr0, lp->a.read_csr(ioaddr, 0));
- if (csr0 & 0x0400) /* Rx interrupt */
+ if (csr0 & 0x0400) { /* Rx interrupt */
+#ifdef CONFIG_PCNET32_NAPI
+ if(!lp->rl_active) {
+ disable_rx_and_norxbuff_ints(dev);
+ netif_rx_schedule(dev);
+ } else {
+ lp->a.write_csr (ioaddr, 0, 0x0400);
+ }
+#else
pcnet32_rx(dev);
+#endif
+ }
if (csr0 & 0x0200) { /* Tx-done interrupt */
unsigned int dirty_tx = lp->dirty_tx;
@@ -2161,7 +2437,16 @@
* interrupt, but a missed frame interrupt sooner or later.
* So we try to clean up our receive ring here.
*/
+#ifdef CONFIG_PCNET32_NAPI
+ if(!lp->rl_active) {
+ disable_rx_and_norxbuff_ints(dev);
+ netif_rx_schedule(dev);
+ } else {
+ lp->a.write_csr (ioaddr, 0, 0x1000);
+ }
+#else
pcnet32_rx(dev);
+#endif
lp->stats.rx_errors++; /* Missed a Rx frame. */
}
if (csr0 & 0x0800) {
@@ -2194,6 +2479,7 @@
return IRQ_HANDLED;
}
+#ifndef CONFIG_PCNET32_NAPI
static int pcnet32_rx(struct net_device *dev)
{
struct pcnet32_private *lp = dev->priv;
@@ -2349,6 +2635,7 @@
return 0;
}
+#endif
static int pcnet32_close(struct net_device *dev)
{
@@ -2358,6 +2645,9 @@
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
+#ifdef CONFIG_PCNET32_NAPI
+ del_timer_sync(&lp->oom_timer);
+#endif
netif_stop_queue(dev);
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] pcnet32 driver NAPI support
2006-06-07 16:52 [PATCH] pcnet32 driver NAPI support Lennart Sorensen
@ 2006-06-07 18:20 ` Don Fry
2006-06-07 19:34 ` Lennart Sorensen
2006-06-08 8:03 ` Pavel Machek
1 sibling, 1 reply; 5+ messages in thread
From: Don Fry @ 2006-06-07 18:20 UTC (permalink / raw)
To: Lennart Sorensen; +Cc: linux-kernel, linux-net, netdev
On Wed, Jun 07, 2006 at 12:52:25PM -0400, Lennart Sorensen wrote:
> I have added NAPI support to the pcnet32 driver. This has greatly
> improved the responsiveness on my systems (geode GX1 266MHz) when under
> heavy network load. Without this change the system would become
> unresponsive due to interrupts when flooded with traffic, and eventually
> the watchdog would reboot the system due to the watchdog daemon being
> starved for cpu time. With the patch the system is still useable on a
> serial console, although very slow. Network throughput is also higher
> since more time is spend processing packets and getting them sent out,
> instead of only spending time acknowledging interrupts from incoming
> packets.
>
> Now having never actually done a patch submission to the kernel before,
> I will try and see if I can do it right.
>
> The patch adds a PCNET32_NAPI config option to drivers/net/Kconfig, and
> the appropriate code to support the option to drivers/net/pcnet32.c and
> has been tested on many of my systems (allthough they are allmost all
> identical, and require some extra patches to pcnet32 due to not having
> an EEPROM installed), and on an AT-2700TX.
>
> I have made a diff against 2.6.16.20 and 2.6.17-rc6.
>
> Comments would be very welcome.
I am also working on a NAPI version of the pcnet32 driver for many of
the same reasons, and will compare what you have with my own
implementation. I probably won't be able to do much until Friday.
Just a couple of comments. I am adding netdev@vger.kernel.org to the cc
list, as most network driver discussion is done here rather than lkml.
linux-kernel (and linux-net) should be deleted in future replies.
The 2.6.17-rc6 would be the correct source to patch against. Since this
is an enhancement it will not come out till 2.6.18.
I would not change the driver name from pcnet32 to pcnet32napi, but I
would changes the version from 1.32 to 1.33NAPI or something like that.
Some areas of concern that you may have addressed already, I have not
scanned your changes yet, are what happens if the ring size is changed
without bringing down the interface (via ethtool), or if the loopback
test is run in a similar fashion, or a tx timeout occurs.
The lp->lock MUST be held whenever accessing the csr or bcr registers as
this is a multi-step process, and has been the source of problems in the
past. Even on UP systems.
>
> Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
>
> Len Sorensen
--
Don Fry
brazilnut@us.ibm.com
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] pcnet32 driver NAPI support
2006-06-07 18:20 ` Don Fry
@ 2006-06-07 19:34 ` Lennart Sorensen
0 siblings, 0 replies; 5+ messages in thread
From: Lennart Sorensen @ 2006-06-07 19:34 UTC (permalink / raw)
To: Don Fry; +Cc: linux-kernel, linux-net, netdev
On Wed, Jun 07, 2006 at 11:20:40AM -0700, Don Fry wrote:
> I am also working on a NAPI version of the pcnet32 driver for many of
> the same reasons, and will compare what you have with my own
> implementation. I probably won't be able to do much until Friday.
>
> Just a couple of comments. I am adding netdev@vger.kernel.org to the cc
> list, as most network driver discussion is done here rather than lkml.
> linux-kernel (and linux-net) should be deleted in future replies.
I must have picked the wrong place to cc.
> The 2.6.17-rc6 would be the correct source to patch against. Since this
> is an enhancement it will not come out till 2.6.18.
I thought so. That is why I did it against both 2.6.17-rc6 and 2.6.16
(since I use it with 2.6.16).
> I would not change the driver name from pcnet32 to pcnet32napi, but I
> would changes the version from 1.32 to 1.33NAPI or something like that.
Hmm, perhaps. I just wanted something that made it obvious in dmesg
which driver I was running. I see tulip actually does put it in the
version instead. I don't remember where I got the driver name change
idea from.
> Some areas of concern that you may have addressed already, I have not
> scanned your changes yet, are what happens if the ring size is changed
> without bringing down the interface (via ethtool), or if the loopback
> test is run in a similar fashion, or a tx timeout occurs.
The same thing as if it was done before enabling napi. From a few
messages I have seen, it doesn't work right now, and it won't work any
better with my changes. I have never tried changing the ring size on
the fly, so I don't know.
It appears that the port is stopped before the ring size change is done,
although I can't really tell how it handles things if the queue is not
empty when it stops the port. Does it try to handle anything left in
the ring first or does it just toss those packets? (That I would
consider wrong).
> The lp->lock MUST be held whenever accessing the csr or bcr registers as
> this is a multi-step process, and has been the source of problems in the
> past. Even on UP systems.
Hmm, I just followed what appeared to be in pcnet32_rx and how tulip and
a few other drivers had done their napi conversions. It certainly works
for me the way I did it. Haven't seen any lockups yet. I do see that I
am not holding the lock when I acknowledge IRQs in pcnet32_poll, which
pcnet32_rx doesn't need to worry about since it is called from the
interrupt handler which already holds the lock. That should be fixed
then.
So I can do:
// Clear RX interrupts
spin_lock(&lp->lock);
lp->a.write_csr (ioaddr, 0, 0x1400);
spin_unlock(&lp->lock);
That part seems simple enough to protect.
Is this safe without holding the lock?
} while(lp->a.read_csr (ioaddr, 0) & 0x1400);
Not sure how to wrap a lock around that one without holding the lock for
way too long.
perhaps:
spin_lock(&lp->lock);
state=lp->a.read_csr (ioaddr, 0) & 0x1400;
spin_unlock(&lp->lock);
} while(state);
Does that seem more reasonable?
Len Sorensen
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] pcnet32 driver NAPI support
2006-06-07 16:52 [PATCH] pcnet32 driver NAPI support Lennart Sorensen
2006-06-07 18:20 ` Don Fry
@ 2006-06-08 8:03 ` Pavel Machek
2006-06-08 15:46 ` Lennart Sorensen
1 sibling, 1 reply; 5+ messages in thread
From: Pavel Machek @ 2006-06-08 8:03 UTC (permalink / raw)
To: Lennart Sorensen; +Cc: linux-kernel, linux-net
Hi!
> I have made a diff against 2.6.16.20 and 2.6.17-rc6.
>
> Comments would be very welcome.
>
> Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
>
> Len Sorensen
> diff -ruN linux-2.6.16.20/drivers/net/Kconfig linux-2.6.16.20.pcnet32napi/drivers/net/Kconfig
> --- linux-2.6.16.20/drivers/net/Kconfig 2006-06-05 13:18:23.000000000 -0400
> +++ linux-2.6.16.20.pcnet32napi/drivers/net/Kconfig 2006-06-07 11:19:54.000000000 -0400
> @@ -1272,6 +1272,23 @@
> <file:Documentation/networking/net-modules.txt>. The module
> will be called pcnet32.
>
> +config PCNET32_NAPI
> + bool "Use NAPI RX polling "
> + depends on PCNET32
> + help
> + NAPI is a new driver API designed to reduce CPU and interrupt load
> + when the driver is receiving lots of packets from the card. It is
> + still somewhat experimental and thus not yet enabled by default.
> +
> + If your estimated Rx load is 10kpps or more, or if the card will be
> + deployed on potentially unfriendly networks (e.g. in a firewall),
> + then say Y here.
> +
> + See <file:Documentation/networking/NAPI_HOWTO.txt> for more
> + information.
> +
> + If in doubt, say N.
> +
> config AMD8111_ETH
> tristate "AMD 8111 (new PCI lance) support"
> depends on NET_PCI && PCI
> diff -ruN linux-2.6.16.20/drivers/net/pcnet32.c linux-2.6.16.20.pcnet32napi/drivers/net/pcnet32.c
> --- linux-2.6.16.20/drivers/net/pcnet32.c 2006-06-05 13:18:23.000000000 -0400
> +++ linux-2.6.16.20.pcnet32napi/drivers/net/pcnet32.c 2006-06-07 12:00:36.000000000 -0400
> @@ -21,9 +21,15 @@
> *
> *************************************************************************/
>
> +#include <linux/config.h>
> +
> +#ifdef CONFIG_PCNET32_NAPI
> +#define DRV_NAME "pcnet32napi"
> +#else
> #define DRV_NAME "pcnet32"
> -#define DRV_VERSION "1.31c"
> -#define DRV_RELDATE "01.Nov.2005"
> +#endif
> +#define DRV_VERSION "1.31d"
> +#define DRV_RELDATE "06.Jun.2006"
> #define PFX DRV_NAME ": "
>
> static const char *version =
> @@ -265,6 +271,7 @@
> * v1.31c 01 Nov 2005 Don Fry Allied Telesyn 2700/2701 FX are 100Mbit only.
> * Force 100Mbit FD if Auto (ASEL) is selected.
> * See Bugzilla 2669 and 4551.
> + * v1.31d 06 Jun 2006 Len Sorensen added NAPI support.
> */
>
>
> @@ -383,6 +390,7 @@
> struct mii_if_info mii_if;
> struct timer_list watchdog_timer;
> struct timer_list blink_timer;
> + struct timer_list oom_timer;
> u32 msg_enable; /* debug message level */
> };
>
> @@ -392,7 +400,13 @@
> static int pcnet32_open(struct net_device *);
> static int pcnet32_init_ring(struct net_device *);
> static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
> +#ifdef CONFIG_PCNET32_NAPI
> +void disable_rx_and_norxbuff_ints(struct net_device *dev);
> +void enable_rx_and_norxbuff_ints(struct net_device *dev);
> +static int pcnet32_poll(struct net_device *, int *budget);
> +#else
> static int pcnet32_rx(struct net_device *);
> +#endif
> static void pcnet32_tx_timeout (struct net_device *dev);
> static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
> static int pcnet32_close(struct net_device *);
> @@ -422,6 +436,174 @@
> PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
> };
>
> +#ifdef CONFIG_PCNET32_NAPI
> +void oom_timer(unsigned long data)
> +{
> + struct net_device *dev = (struct net_device *)data;
> + struct pcnet32_private *lp = dev->priv;
> + lp->rl_active = 0;
> + netif_rx_schedule(dev);
> +}
> +
> +static
> +int pcnet32_poll(struct net_device *dev, int *budget)
> +{
> + struct pcnet32_private *lp = dev->priv;
> + ulong ioaddr = dev->base_addr;
> +
> + int entry = lp->cur_rx & lp->rx_mod_mask;
> + int rx_work_limit = dev->quota;
> + int received = 0;
> +
> + if (!netif_running(dev))
> + goto done;
> +
> + do {
> + // Clear RX interrupts
> + lp->a.write_csr (ioaddr, 0, 0x1400);
Please indent with tabs (according to coding style) and avoid using //
comments.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] pcnet32 driver NAPI support
2006-06-08 8:03 ` Pavel Machek
@ 2006-06-08 15:46 ` Lennart Sorensen
0 siblings, 0 replies; 5+ messages in thread
From: Lennart Sorensen @ 2006-06-08 15:46 UTC (permalink / raw)
To: Pavel Machek; +Cc: linux-kernel, linux-net
On Thu, Jun 08, 2006 at 10:03:03AM +0200, Pavel Machek wrote:
> Hi!
>
> > I have made a diff against 2.6.16.20 and 2.6.17-rc6.
> >
> > Comments would be very welcome.
> >
> > Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
> >
> > Len Sorensen
>
> > diff -ruN linux-2.6.16.20/drivers/net/Kconfig linux-2.6.16.20.pcnet32napi/drivers/net/Kconfig
> > --- linux-2.6.16.20/drivers/net/Kconfig 2006-06-05 13:18:23.000000000 -0400
> > +++ linux-2.6.16.20.pcnet32napi/drivers/net/Kconfig 2006-06-07 11:19:54.000000000 -0400
> > @@ -1272,6 +1272,23 @@
> > <file:Documentation/networking/net-modules.txt>. The module
> > will be called pcnet32.
> >
> > +config PCNET32_NAPI
> > + bool "Use NAPI RX polling "
> > + depends on PCNET32
> > + help
> > + NAPI is a new driver API designed to reduce CPU and interrupt load
> > + when the driver is receiving lots of packets from the card. It is
> > + still somewhat experimental and thus not yet enabled by default.
> > +
> > + If your estimated Rx load is 10kpps or more, or if the card will be
> > + deployed on potentially unfriendly networks (e.g. in a firewall),
> > + then say Y here.
> > +
> > + See <file:Documentation/networking/NAPI_HOWTO.txt> for more
> > + information.
> > +
> > + If in doubt, say N.
> > +
> > config AMD8111_ETH
> > tristate "AMD 8111 (new PCI lance) support"
> > depends on NET_PCI && PCI
> > diff -ruN linux-2.6.16.20/drivers/net/pcnet32.c linux-2.6.16.20.pcnet32napi/drivers/net/pcnet32.c
> > --- linux-2.6.16.20/drivers/net/pcnet32.c 2006-06-05 13:18:23.000000000 -0400
> > +++ linux-2.6.16.20.pcnet32napi/drivers/net/pcnet32.c 2006-06-07 12:00:36.000000000 -0400
> > @@ -21,9 +21,15 @@
> > *
> > *************************************************************************/
> >
> > +#include <linux/config.h>
> > +
> > +#ifdef CONFIG_PCNET32_NAPI
> > +#define DRV_NAME "pcnet32napi"
> > +#else
> > #define DRV_NAME "pcnet32"
> > -#define DRV_VERSION "1.31c"
> > -#define DRV_RELDATE "01.Nov.2005"
> > +#endif
> > +#define DRV_VERSION "1.31d"
> > +#define DRV_RELDATE "06.Jun.2006"
> > #define PFX DRV_NAME ": "
> >
> > static const char *version =
> > @@ -265,6 +271,7 @@
> > * v1.31c 01 Nov 2005 Don Fry Allied Telesyn 2700/2701 FX are 100Mbit only.
> > * Force 100Mbit FD if Auto (ASEL) is selected.
> > * See Bugzilla 2669 and 4551.
> > + * v1.31d 06 Jun 2006 Len Sorensen added NAPI support.
> > */
> >
> >
> > @@ -383,6 +390,7 @@
> > struct mii_if_info mii_if;
> > struct timer_list watchdog_timer;
> > struct timer_list blink_timer;
> > + struct timer_list oom_timer;
> > u32 msg_enable; /* debug message level */
> > };
> >
> > @@ -392,7 +400,13 @@
> > static int pcnet32_open(struct net_device *);
> > static int pcnet32_init_ring(struct net_device *);
> > static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
> > +#ifdef CONFIG_PCNET32_NAPI
> > +void disable_rx_and_norxbuff_ints(struct net_device *dev);
> > +void enable_rx_and_norxbuff_ints(struct net_device *dev);
> > +static int pcnet32_poll(struct net_device *, int *budget);
> > +#else
> > static int pcnet32_rx(struct net_device *);
> > +#endif
> > static void pcnet32_tx_timeout (struct net_device *dev);
> > static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
> > static int pcnet32_close(struct net_device *);
> > @@ -422,6 +436,174 @@
> > PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
> > };
> >
> > +#ifdef CONFIG_PCNET32_NAPI
> > +void oom_timer(unsigned long data)
> > +{
> > + struct net_device *dev = (struct net_device *)data;
> > + struct pcnet32_private *lp = dev->priv;
> > + lp->rl_active = 0;
> > + netif_rx_schedule(dev);
> > +}
> > +
> > +static
> > +int pcnet32_poll(struct net_device *dev, int *budget)
> > +{
> > + struct pcnet32_private *lp = dev->priv;
> > + ulong ioaddr = dev->base_addr;
> > +
> > + int entry = lp->cur_rx & lp->rx_mod_mask;
> > + int rx_work_limit = dev->quota;
> > + int received = 0;
> > +
> > + if (!netif_running(dev))
> > + goto done;
> > +
> > + do {
> > + // Clear RX interrupts
> > + lp->a.write_csr (ioaddr, 0, 0x1400);
>
> Please indent with tabs (according to coding style) and avoid using //
> comments.
The existing driver has some places that indent by 4 spaces (on top of a
bunch of tabs) which I tried to copy exactly. The part you found there
on the other hand I do have to fix. The driver in 2.6.16 had a lot less
tabs and a lot more spaces, and 2.6.8 (which I started from originally)
had very bad and inconsistent indentation. I am happy to see
2.6.17-rc6's version is a lot more consistent, although personally I
think some of the changes are amazingly ugly, splitting argument lists
to a function call over 10 lines with only about 8 characters per line.
Len Sorensen
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-06-08 15:46 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-07 16:52 [PATCH] pcnet32 driver NAPI support Lennart Sorensen
2006-06-07 18:20 ` Don Fry
2006-06-07 19:34 ` Lennart Sorensen
2006-06-08 8:03 ` Pavel Machek
2006-06-08 15:46 ` Lennart Sorensen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox