patch-2.0.12 linux/drivers/net/eepro.c
Next file: linux/drivers/net/plip.c
Previous file: linux/drivers/net/arcnet.c
Back to the patch index
Back to the overall index
- Lines: 412
- Date:
Tue Aug 6 09:40:29 1996
- Orig file:
v2.0.11/linux/drivers/net/eepro.c
- Orig date:
Fri Apr 12 09:49:37 1996
diff -u --recursive --new-file v2.0.11/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
@@ -8,16 +8,13 @@
according to the terms of the GNU Public License,
incorporated herein by reference.
- The author may be reached at bao@saigon.async.com
+ The author may be reached at bao.ha@srs.gov
or 418 Hastings Place, Martinez, GA 30907.
Things remaining to do:
Better record keeping of errors.
Eliminate transmit interrupt to reduce overhead.
Implement "concurrent processing". I won't be doing it!
- Allow changes to the partition of the transmit and receive
- buffers, currently the ratio is 3:1 of receive to transmit
- buffer ratio.
Bugs:
@@ -27,6 +24,13 @@
Versions:
+ 0.09 Fixed a race condition in the transmit algorithm,
+ which causes crashes under heavy load with fast
+ pentium computers. The performance should also
+ improve a bit. The size of RX buffer, and hence
+ TX buffer, can also be changed via lilo or insmod.
+ (BCH, 7/31/96)
+
0.08 Implement 32-bit I/O for the 82595TX and 82595FX
based lan cards. Disable full-duplex mode if TPE
is not used. (BCH, 4/8/96)
@@ -56,7 +60,7 @@
*/
static const char *version =
- "eepro.c: v0.08 4/8/96 Bao C. Ha (bao.ha@srs.gov)\n";
+ "eepro.c: v0.09 7/31/96 Bao C. Ha (bao.ha@srs.gov)\n";
#include <linux/module.h>
@@ -110,7 +114,7 @@
/* use 0 for production, 1 for verification, >2 for debug */
#ifndef NET_DEBUG
-#define NET_DEBUG 2
+#define NET_DEBUG 3
#endif
static unsigned int net_debug = NET_DEBUG;
@@ -180,15 +184,26 @@
network traffics, the ring linked list should improve performance by
allowing up to 8K worth of packets to be queued.
+The sizes of the receive and transmit buffers can now be changed via lilo
+or insmod. Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0"
+where rx-buffer is in KB unit. Modules uses the parameter mem which is
+also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer."
+The receive buffer has to be more than 3K or less than 29K. Otherwise,
+it is reset to the default of 24K, and, hence, 8K for the trasnmit
+buffer (transmit-buffer = 32K - receive-buffer).
+
*/
#define RAM_SIZE 0x8000
#define RCV_HEADER 8
-#define RCV_RAM 0x6000 /* 24KB for RCV buffer */
-#define RCV_LOWER_LIMIT 0x00 /* 0x0000 */
-#define RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8) /* 0x5ffe */
-#define XMT_RAM (RAM_SIZE - RCV_RAM) /* 8KB for XMT buffer */
-#define XMT_LOWER_LIMIT (RCV_RAM >> 8) /* 0x6000 */
-#define XMT_UPPER_LIMIT ((RAM_SIZE - 2) >> 8) /* 0x7ffe */
+#define RCV_RAM 0x6000 /* 24KB default for RCV buffer */
+#define RCV_LOWER_LIMIT 0x00 /* 0x0000 */
+/* #define RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8) */ /* 0x5ffe */
+#define RCV_UPPER_LIMIT (((rcv_ram) - 2) >> 8)
+/* #define XMT_RAM (RAM_SIZE - RCV_RAM) */ /* 8KB for XMT buffer */
+#define XMT_RAM (RAM_SIZE - (rcv_ram)) /* 8KB for XMT buffer */
+/* #define XMT_LOWER_LIMIT (RCV_RAM >> 8) */ /* 0x6000 */
+#define XMT_LOWER_LIMIT ((rcv_ram) >> 8)
+#define XMT_UPPER_LIMIT ((RAM_SIZE - 2) >> 8) /* 0x7ffe */
#define XMT_HEADER 8
#define RCV_DONE 0x0008
@@ -368,6 +383,16 @@
dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
}
+
+ if ((dev->mem_end & 0x3f) < 3 || /* RX buffer must be more than 3K */
+ (dev->mem_end & 0x3f) > 29) /* and less than 29K */
+ dev->mem_end = RCV_RAM; /* or it will be set to 24K */
+ else dev->mem_end = 1024*dev->mem_end; /* Maybe I should shift << 10 */
+
+ /* From now on, dev->mem_end contains the actual size of rx buffer */
+
+ if (net_debug > 3)
+ printk(", %dK RCV buffer", (int)(dev->mem_end)/1024);
outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
id = inb(ioaddr + REG3);
@@ -401,8 +426,8 @@
}
else printk(", %s.\n", ifmap[dev->if_port]);
- if ((dev->mem_start & 0xf) > 0)
- net_debug = dev->mem_start & 7;
+ if ((dev->mem_start & 0xf) > 0) /* I don't know if this is */
+ net_debug = dev->mem_start & 7; /* still useful or not */
if (net_debug > 3) {
i = read_eeprom(ioaddr, 5);
@@ -516,7 +541,7 @@
eepro_open(struct device *dev)
{
unsigned short temp_reg, old8, old9;
- int i, ioaddr = dev->base_addr;
+ int i, ioaddr = dev->base_addr, rcv_ram = dev->mem_end;
struct eepro_local *lp = (struct eepro_local *)dev->priv;
if (net_debug > 3)
@@ -654,6 +679,7 @@
{
struct eepro_local *lp = (struct eepro_local *)dev->priv;
int ioaddr = dev->base_addr;
+ int rcv_ram = dev->mem_end;
if (net_debug > 5)
printk("eepro: entering eepro_send_packet routine.\n");
@@ -662,12 +688,13 @@
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
+ if (tickssofar < 40)
return 1;
if (net_debug > 1)
printk("%s: transmit timed out, %s?\n", dev->name,
"network cable problem");
lp->stats.tx_errors++;
+
/* Try to restart the adaptor. */
outb(SEL_RESET_CMD, ioaddr);
/* We are supposed to wait for 2 us after a SEL_RESET */
@@ -675,7 +702,7 @@
SLOW_DOWN_IO;
/* Do I also need to flush the transmit buffers here? YES? */
- lp->tx_start = lp->tx_end = RCV_RAM;
+ lp->tx_start = lp->tx_end = rcv_ram;
lp->tx_last = 0;
dev->tbusy=0;
@@ -722,7 +749,7 @@
eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct device *dev = (struct device *)(irq2dev_map[irq]);
- int ioaddr, status, boguscount = 0;
+ int ioaddr, status, boguscount = 20;
if (net_debug > 5)
printk("eepro: entering eepro_interrupt routine.\n");
@@ -737,7 +764,7 @@
do {
status = inb(ioaddr + STATUS_REG);
-
+
if (status & RX_INT) {
if (net_debug > 4)
printk("eepro: packet received interrupt.\n");
@@ -748,6 +775,7 @@
/* Get the received packets */
eepro_rx(dev);
}
+
else if (status & TX_INT) {
if (net_debug > 4)
printk("eepro: packet transmit interrupt.\n");
@@ -757,10 +785,9 @@
/* Process the status of transmitted packets */
eepro_transmit_interrupt(dev);
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
- } while ((++boguscount < 10) && (status & 0x06));
+ }
+
+ } while ((boguscount-- > 0) && (status & 0x06));
dev->interrupt = 0;
if (net_debug > 5)
@@ -774,6 +801,7 @@
{
struct eepro_local *lp = (struct eepro_local *)dev->priv;
int ioaddr = dev->base_addr;
+ int rcv_ram = dev->mem_end;
short temp_reg;
dev->tbusy = 1;
@@ -789,7 +817,7 @@
/* Flush the Tx and disable Rx. */
outb(STOP_RCV_CMD, ioaddr);
- lp->tx_start = lp->tx_end = RCV_RAM ;
+ lp->tx_start = lp->tx_end = rcv_ram ;
lp->tx_last = 0;
/* Mask all the interrupts. */
@@ -912,7 +940,9 @@
outw(status | CHAIN_BIT, ioaddr + IO_PORT);
lp->tx_end = i ;
}
- else lp->tx_start = lp->tx_end = i ;
+ else {
+ lp->tx_start = lp->tx_end = i ;
+ }
/* Acknowledge that the MC setup is done */
do { /* We should be doing this in the eepro_interrupt()! */
@@ -993,13 +1023,25 @@
{
struct eepro_local *lp = (struct eepro_local *)dev->priv;
short ioaddr = dev->base_addr;
- unsigned status, tx_available, last, end, boguscount = 10;
+ int rcv_ram = dev->mem_end;
+ unsigned status, tx_available, last, end, boguscount = 100;
if (net_debug > 5)
printk("eepro: entering hardware_send_packet routine.\n");
while (boguscount-- > 0) {
+ /* Disable RX and TX interrupts. Necessary to avoid
+ corruption of the HOST_ADDRESS_REG by interrupt
+ service routines. */
+ outb(ALL_MASK, ioaddr + INT_MASK_REG);
+
+ if (dev->interrupt == 1) {
+ /* Enable RX and TX interrupts */
+ outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+ continue;
+ }
+
/* determine how much of the transmit buffer space is available */
if (lp->tx_end > lp->tx_start)
tx_available = XMT_RAM - (lp->tx_end - lp->tx_start);
@@ -1007,14 +1049,15 @@
tx_available = lp->tx_start - lp->tx_end;
else tx_available = XMT_RAM;
- /* Disable RX and TX interrupts. Necessary to avoid
- corruption of the HOST_ADDRESS_REG by interrupt
- service routines. */
- outb(ALL_MASK, ioaddr + INT_MASK_REG);
-
if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER)
>= tx_available) /* No space available ??? */
+ {
+ eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */
+
+ /* Enable RX and TX interrupts */
+ outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
continue;
+ }
last = lp->tx_end;
end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
@@ -1023,10 +1066,10 @@
if ((RAM_SIZE - last) <= XMT_HEADER) {
/* Arrrr!!!, must keep the xmt header together,
several days were lost to chase this one down. */
- last = RCV_RAM;
+ last = rcv_ram;
end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
}
- else end = RCV_RAM + (end - RAM_SIZE);
+ else end = rcv_ram + (end - RAM_SIZE);
}
outw(last, ioaddr + HOST_ADDRESS_REG);
@@ -1044,9 +1087,17 @@
outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
}
- if (lp->tx_start != lp->tx_end) {
+ /* A dummy read to flush the DRAM write pipeline */
+ status = inw(ioaddr + IO_PORT);
+
+ if (lp->tx_start == lp->tx_end) {
+ outw(last, ioaddr + XMT_BAR);
+ outb(XMT_CMD, ioaddr);
+ lp->tx_start = last; /* I don't like to change tx_start here */
+ }
+ else {
/* update the next address and the chain bit in the
- last packet */
+ last packet */
if (lp->tx_end != last) {
outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
outw(last, ioaddr + IO_PORT);
@@ -1054,33 +1105,26 @@
outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
status = inw(ioaddr + IO_PORT);
outw(status | CHAIN_BIT, ioaddr + IO_PORT);
- }
- /* A dummy read to flush the DRAM write pipeline */
- status = inw(ioaddr + IO_PORT);
-
- /* Enable RX and TX interrupts */
- outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
-
- if (lp->tx_start == lp->tx_end) {
- outw(last, ioaddr + XMT_BAR);
- outb(XMT_CMD, ioaddr);
- lp->tx_start = last; /* I don't like to change tx_start here */
+ /* Continue the transmit command */
+ outb(RESUME_XMT_CMD, ioaddr);
}
- else outb(RESUME_XMT_CMD, ioaddr);
lp->tx_last = last;
lp->tx_end = end;
+ /* Enable RX and TX interrupts */
+ outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+
if (dev->tbusy) {
dev->tbusy = 0;
- mark_bh(NET_BH);
}
if (net_debug > 5)
printk("eepro: exiting hardware_send_packet routine.\n");
return;
}
+
dev->tbusy = 1;
if (net_debug > 5)
printk("eepro: exiting hardware_send_packet routine.\n");
@@ -1090,7 +1134,7 @@
eepro_rx(struct device *dev)
{
struct eepro_local *lp = (struct eepro_local *)dev->priv;
- short ioaddr = dev->base_addr;
+ short ioaddr = dev->base_addr, rcv_ram = dev->mem_end;
short boguscount = 20;
short rcv_car = lp->rx_start;
unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
@@ -1171,7 +1215,7 @@
{
struct eepro_local *lp = (struct eepro_local *)dev->priv;
short ioaddr = dev->base_addr;
- short boguscount = 10;
+ short boguscount = 20;
short xmt_status;
while (lp->tx_start != lp->tx_end) {
@@ -1179,16 +1223,15 @@
outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG);
xmt_status = inw(ioaddr+IO_PORT);
if ((xmt_status & TX_DONE_BIT) == 0) break;
+
xmt_status = inw(ioaddr+IO_PORT);
lp->tx_start = inw(ioaddr+IO_PORT);
-
- if (dev->tbusy) {
- dev->tbusy = 0;
- mark_bh(NET_BH);
- }
+
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
if (xmt_status & 0x2000)
- lp->stats.tx_packets++;
+ lp->stats.tx_packets++;
else {
lp->stats.tx_errors++;
if (xmt_status & 0x0400)
@@ -1196,10 +1239,12 @@
printk("%s: XMT status = %#x\n",
dev->name, xmt_status);
}
- if (xmt_status & 0x000f)
+ if (xmt_status & 0x000f) {
lp->stats.collisions += (xmt_status & 0x000f);
- if ((xmt_status & 0x0040) == 0x0)
+ }
+ if ((xmt_status & 0x0040) == 0x0) {
lp->stats.tx_heartbeat_errors++;
+ }
if (--boguscount == 0)
break;
@@ -1216,6 +1261,7 @@
static int io = 0x200;
static int irq = 0;
+static int mem = (RCV_RAM/1024); /* Size of the rx buffer in KB */
int
init_module(void)
@@ -1224,6 +1270,7 @@
printk("eepro: You should not use auto-probing with insmod!\n");
dev_eepro.base_addr = io;
dev_eepro.irq = irq;
+ dev_eepro.mem_end = mem;
if (register_netdev(&dev_eepro) != 0)
return -EIO;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov