Performance patch for NE Ethernet

Richard B. Johnson (root@analogic.com)
Wed, 12 Feb 1997 18:56:07 -0500 (EST)


The following improves the performance of NE* clones.

-------------------------------------------------
--- ne.c.orig Wed Feb 12 18:08:29 1997
+++ ne.c Wed Feb 12 18:36:11 1997
@@ -25,7 +25,8 @@
Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c
Paul Gortmaker : Allow users with bad cards to avoid full probe.
Paul Gortmaker : PCI probe changes, more PCI cards supported.
-
+ R Johnson : Modified only ne_get_8390_hdr(),
+ : ne_block_input(), and ne_block_output().
*/

/* Routines for the NatSemi-based designs (NE[12]000). */
@@ -101,6 +102,7 @@
/* ---- No user-serviceable parts below ---- */

#define NE_BASE (dev->base_addr)
+#define BUF (skb->data)
#define NE_CMD 0x00
#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
@@ -504,213 +506,106 @@
ei_status.dmaing = 0;

/* This check _should_not_ be necessary, omit eventually. */
- while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+ while ((inb_p((NE_BASE+EN0_ISR)) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2*HZ/100) {
printk("%s: ne_reset_8390() did not complete.\n", dev->name);
break;
}
- outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */
+ outb_p(ENISR_RESET, (NE_BASE + EN0_ISR)); /* Ack intr. */
}

-/* Grab the 8390 specific header. Similar to the block_input routine, but
+/*
+ Grab the 8390 specific header. Similar to the block_input routine, but
we don't need to be concerned with ring wrap as the header will be at
- the start of a page, so we optimize accordingly. */
+ the start of a page, so we optimize accordingly.i
+ Modified: rjohson@analogic.com, to improve speed.
+ */

static void
ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
-
- int nic_base = dev->base_addr;
-
- /* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing) {
+ /* This *shouldn't* happen. If it does, we'll fix it. */
+ if (ei_status.dmaing)
+ {
printk("%s: DMAing conflict in ne_get_8390_hdr "
"[DMAstat:%d][irqlock:%d][intr:%d].\n",
dev->name, ei_status.dmaing, ei_status.irqlock,
dev->interrupt);
+ ne_reset_8390(dev);
return;
}
-
ei_status.dmaing |= 0x01;
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
- outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
- outb_p(0, nic_base + EN0_RCNTHI);
- outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */
- outb_p(ring_page, nic_base + EN0_RSARHI);
- outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, (NE_BASE + NE_CMD));
+ outb_p(sizeof(struct e8390_pkt_hdr), (NE_BASE + EN0_RCNTLO));
+ outw(0, (NE_BASE + EN0_RSARLO)); /* On page boundary */
+ outb_p(ring_page, (NE_BASE + EN0_RSARHI));
+ outb_p(E8390_RREAD+E8390_START, (NE_BASE + NE_CMD));

if (ei_status.word16)
- insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+ insw((NE_BASE + NE_DATAPORT), hdr, sizeof(struct e8390_pkt_hdr)>>1);
else
- insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
+ insb((NE_BASE + NE_DATAPORT), hdr, sizeof(struct e8390_pkt_hdr));

- outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ outb_p(ENISR_RDC, (NE_BASE + EN0_ISR)); /* Ack intr. */
ei_status.dmaing &= ~0x01;
+ return;
}

-/* Block input and output, similar to the Crynwr packet driver. If you
+/*
+ Block input and output, similar to the Crynwr packet driver. If you
are porting to a new ethercard, look at the packet driver source for hints.
The NEx000 doesn't share the on-board packet memory -- you have to put
- the packet out through the "remote DMA" dataport using outb. */
-
+ the packet out through the "remote DMA" dataport using outb.
+ Modified: rjohnson@analogic.com, to improve performance. Strategy is
+ to fix any errors in ne_get_8390_hdr. Otherwise whip right through.
+ */
static void
ne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
{
-#ifdef NE_SANITY_CHECK
- int xfer_count = count;
-#endif
- int nic_base = dev->base_addr;
- char *buf = skb->data;

- /* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing) {
- printk("%s: DMAing conflict in ne_block_input "
- "[DMAstat:%d][irqlock:%d][intr:%d].\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
- return;
- }
+ if(ei_status.dmaing)
+ return;
ei_status.dmaing |= 0x01;
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
- outb_p(count & 0xff, nic_base + EN0_RCNTLO);
- outb_p(count >> 8, nic_base + EN0_RCNTHI);
- outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
- outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
- outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
- if (ei_status.word16) {
- insw(NE_BASE + NE_DATAPORT,buf,count>>1);
- if (count & 0x01) {
- buf[count-1] = inb(NE_BASE + NE_DATAPORT);
-#ifdef NE_SANITY_CHECK
- xfer_count++;
-#endif
- }
- } else {
- insb(NE_BASE + NE_DATAPORT, buf, count);
- }
-
-#ifdef NE_SANITY_CHECK
- /* This was for the ALPHA version only, but enough people have
- been encountering problems so it is still here. If you see
- this message you either 1) have a slightly incompatible clone
- or 2) have noise/speed problems with your bus. */
- if (ei_debug > 1) { /* DMA termination address check... */
- int addr, tries = 20;
- do {
- /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
- -- it's broken for Rx on some cards! */
- int high = inb_p(nic_base + EN0_RSARHI);
- int low = inb_p(nic_base + EN0_RSARLO);
- addr = (high << 8) + low;
- if (((ring_offset + xfer_count) & 0xff) == low)
- break;
- } while (--tries > 0);
- if (tries <= 0)
- printk("%s: RX transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, ring_offset + xfer_count, addr);
- }
-#endif
- outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ++count;
+ count &= ~1;
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, (NE_BASE + NE_CMD));
+ outw(count, (NE_BASE + EN0_RCNTLO));
+ outw(ring_offset, (NE_BASE + EN0_RSARLO));
+
+ outb_p(E8390_RREAD+E8390_START, (NE_BASE + NE_CMD));
+ if(ei_status.word16)
+ insw((NE_BASE + NE_DATAPORT), BUF, count>>1);
+ else
+ insb((NE_BASE + NE_DATAPORT), BUF, count);
+ outb_p(ENISR_RDC, (NE_BASE + EN0_ISR)); /* Ack intr. */
ei_status.dmaing &= ~0x01;
+ return;
}
-
+/*
+ Modified: rjohnson@analogic.com, to improve performance. Strategy is
+ to fix any errors in ne_get_8390_hdr. Otherwise whip right through.
+ */
static void
ne_block_output(struct device *dev, int count,
const unsigned char *buf, const int start_page)
{
- int nic_base = NE_BASE;
- unsigned long dma_start;
-#ifdef NE_SANITY_CHECK
- int retries = 0;
-#endif

- /* Round the count up for word writes. Do we need to do this?
- What effect will an odd byte count have on the 8390?
- I should check someday. */
- if (ei_status.word16 && (count & 0x01))
- count++;
-
- /* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing) {
- printk("%s: DMAing conflict in ne_block_output."
- "[DMAstat:%d][irqlock:%d][intr:%d]\n",
- dev->name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
- return;
- }
+ if(ei_status.dmaing)
+ return;
ei_status.dmaing |= 0x01;
- /* We should already be in page 0, but to be safe... */
- outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+ ++count;
+ count &= ~1;
+ outb_p(ENISR_RDC, (NE_BASE + EN0_ISR));
+ outw(count, (NE_BASE + EN0_RCNTLO));
+ outb_p(0x00, (NE_BASE + EN0_RSARLO));
+ outb_p(start_page, (NE_BASE + EN0_RSARHI));

-#ifdef NE_SANITY_CHECK
- retry:
-#endif
-
-#ifdef NE8390_RW_BUGFIX
- /* Handle the read-before-write bug the same way as the
- Crynwr packet driver -- the NatSemi method doesn't work.
- Actually this doesn't always work either, but if you have
- problems with your NEx000 this is better than nothing! */
- outb_p(0x42, nic_base + EN0_RCNTLO);
- outb_p(0x00, nic_base + EN0_RCNTHI);
- outb_p(0x42, nic_base + EN0_RSARLO);
- outb_p(0x00, nic_base + EN0_RSARHI);
- outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
- /* Make certain that the dummy read has occurred. */
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
- SLOW_DOWN_IO;
-#endif
-
- outb_p(ENISR_RDC, nic_base + EN0_ISR);
-
- /* Now the normal output. */
- outb_p(count & 0xff, nic_base + EN0_RCNTLO);
- outb_p(count >> 8, nic_base + EN0_RCNTHI);
- outb_p(0x00, nic_base + EN0_RSARLO);
- outb_p(start_page, nic_base + EN0_RSARHI);
-
- outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
- if (ei_status.word16) {
- outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
- } else {
- outsb(NE_BASE + NE_DATAPORT, buf, count);
- }
-
- dma_start = jiffies;
-
-#ifdef NE_SANITY_CHECK
- /* This was for the ALPHA version only, but enough people have
- been encountering problems so it is still here. */
- if (ei_debug > 1) { /* DMA termination address check... */
- int addr, tries = 20;
- do {
- int high = inb_p(nic_base + EN0_RSARHI);
- int low = inb_p(nic_base + EN0_RSARLO);
- addr = (high << 8) + low;
- if ((start_page << 8) + count == addr)
- break;
- } while (--tries > 0);
- if (tries <= 0) {
- printk("%s: Tx packet transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, (start_page << 8) + count, addr);
- if (retries++ == 0)
- goto retry;
- }
- }
-#endif
-
- while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
- if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
- printk("%s: timeout waiting for Tx RDC.\n", dev->name);
- ne_reset_8390(dev);
- NS8390_init(dev,1);
- break;
- }
-
- outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ outb_p(E8390_RWRITE+E8390_START, (NE_BASE + NE_CMD));
+ if (ei_status.word16)
+ outsw((NE_BASE + NE_DATAPORT), buf, count>>1);
+ else
+ outsb((NE_BASE + NE_DATAPORT), buf, count);
+ outb_p(ENISR_RDC, (NE_BASE + EN0_ISR)); /* Ack intr. */
ei_status.dmaing &= ~0x01;
return;
}
--------------------------------------------

Cheers,
Dick Johnson
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Richard B. Johnson
Project Engineer
Analogic Corporation
Voice : (508) 977-3000 ext. 3754
Fax : (508) 532-6097
Modem : (508) 977-6870
Ftp : ftp@boneserver.analogic.com
Email : rjohnson@analogic.com, johnson@analogic.com
Penguin : Linux version 2.1.26 on an i586 machine (66.15 BogoMips).
Warning : It's hard to remain at the trailing edge of technology.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-