Here is a patch from v0.28-all to a new version of the 3c59x driver.
It includes features such as Early Tx and Rx start, and more robustness as
far as errors in the DMADone interrupt is concerned. It also corrects some
timing problems.
Here it is:
--- tmp/network-drivers/3c59x.c Fri Nov 22 17:05:39 1996
+++ linux/drivers/net/3c59x-new.c Mon Dec 9 17:39:42 1996
@@ -19,6 +19,7 @@
/* "Knobs" that turn on special features. */
/* Enable the automatic media selection code. */
#define AUTOMEDIA 1
+#define REALLY_SLOW_IO 1
/* Allow the use of bus master transfers instead of programmed-I/O for the
Tx process. Bus master transfers are always disabled by default, but
@@ -94,11 +95,11 @@
/* "Knobs" for adjusting internal parameters. */
/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define VORTEX_DEBUG 2
+#define VORTEX_DEBUG 4
/* Number of times to check to see if the Tx FIFO has space, used in some
limited cases. */
-#define WAIT_TX_AVAIL 200
+#define WAIT_TX_AVAIL 10
/* Operational parameter that usually are not changed. */
#define TX_TIMEOUT 40 /* Time in jiffies before concluding Tx hung */
@@ -239,7 +240,7 @@
Wn0EepromData = 12, /* Window 0: EEPROM results register. */
};
enum Win0_EEPROM_bits {
- EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
+ EEPROM_Read = 0x80, EEPROM_Write = 0x40, EEPROM_Erase = 0xC0,
EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
};
@@ -248,7 +249,7 @@
PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
EtherLink3ID=7, IFXcvrIO=8, IRQLine=9,
NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
- DriverTune=13, Checksum=15};
+ SWInfo=13, SWInfo2=15};
enum Window3 { /* Window 3: MAC/config bits. */
Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
@@ -287,7 +288,7 @@
int last_rx_packets; /* For media autoselection. */
unsigned int available_media:8, /* From Wn3_Options */
media_override:3, /* Passed-in media type. */
- default_media:3, /* Read from the EEPROM. */
+ default_media:3, /* Read from the EEPROM */
full_duplex:1, bus_master:1, autoselect:1;
};
@@ -312,6 +313,8 @@
{ "Default", 0, 0xFF, 0 /* Use default */, 0},
};
+static int txstart=16,rxstart=8; /* Thresholds */
+
static int vortex_scan(struct device *dev);
static int vortex_found_device(struct device *dev, int ioaddr, int irq,
int product_index, int options);
@@ -350,27 +353,6 @@
/* Variables to work-around the Compaq PCI BIOS32 problem. */
static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0;
-#ifdef MODULE
-static int debug = -1;
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct device *root_vortex_dev = NULL;
-
-int
-init_module(void)
-{
- int cards_found;
-
- if (debug >= 0)
- vortex_debug = debug;
- if (vortex_debug)
- printk(version);
-
- root_vortex_dev = NULL;
- cards_found = vortex_scan(0);
- return cards_found ? 0 : -ENODEV;
-}
-
-#else
int tc59x_probe(struct device *dev)
{
int cards_found = 0;
@@ -382,7 +364,6 @@
return cards_found ? 0 : -ENODEV;
}
-#endif /* not MODULE */
static int vortex_scan(struct device *dev)
{
@@ -395,22 +376,21 @@
for (; product_ids[board_index]; board_index++, pci_index = 0) {
for (; pci_index < 16; pci_index++) {
unsigned char pci_bus, pci_device_fn, pci_irq_line;
- unsigned char pci_latency;
+ unsigned char pci_latency,pci_mingnt,pci_maxlat;
unsigned int pci_ioaddr;
unsigned short pci_command;
if (pcibios_find_device(TCOM_VENDOR_ID,
- product_ids[board_index], pci_index,
- &pci_bus, &pci_device_fn))
+ product_ids[board_index], pci_index,
+ &pci_bus, &pci_device_fn))
break;
pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
+ PCI_INTERRUPT_LINE, &pci_irq_line);
pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
/* Remove I/O space marker in bit 0. */
pci_ioaddr &= ~3;
-#ifdef VORTEX_BUS_MASTER
/* Get and check the bus-master and latency values.
Some PCI BIOSes fail to set the master-enable bit, and
the latency timer must be set to the maximum value to avoid
@@ -425,18 +405,27 @@
PCI_COMMAND, pci_command);
}
pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
+ PCI_MIN_GNT, &pci_mingnt);
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_MAX_LAT, &pci_maxlat);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_MIN_GNT, pci_mingnt*2);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_MAX_LAT, pci_maxlat*2);
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ printk("MinGnt=%d MaxLat=%d Latency=%d\n",pci_mingnt,pci_maxlat,pci_latency);
+
if (pci_latency != 255) {
printk(" 3Com EtherLink III: Overriding PCI latency"
" timer (CFLT) setting of %d, new value is 255.\n",
pci_latency);
pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 255);
+ PCI_LATENCY_TIMER, 255);
+
}
-#endif /* VORTEX_BUS_MASTER */
vortex_found_device(dev, pci_ioaddr, pci_irq_line, board_index,
- dev && dev->mem_start ? dev->mem_start
- : options[cards_found]);
+ dev && dev->mem_start ? dev->mem_start : options[cards_found]);
dev = 0;
cards_found++;
}
@@ -479,36 +468,6 @@
{
struct vortex_private *vp;
-#ifdef MODULE
- /* Allocate and fill new device structure. */
- int dev_size = sizeof(struct device) +
- sizeof(struct vortex_private);
-
- dev = (struct device *) kmalloc(dev_size, GFP_KERNEL);
- memset(dev, 0, dev_size);
- dev->priv = ((void *)dev) + sizeof(struct device);
- vp = (struct vortex_private *)dev->priv;
- dev->name = vp->devname; /* An empty string. */
- dev->base_addr = ioaddr;
- dev->irq = irq;
- dev->init = vortex_probe1;
- vp->product_name = product_names[product_index];
- vp->options = options;
- if (options >= 0) {
- vp->media_override = ((options & 7) == 2) ? 0 : options & 7;
- vp->full_duplex = (options & 8) ? 1 : 0;
- vp->bus_master = (options & 16) ? 1 : 0;
- } else {
- vp->media_override = 7;
- vp->full_duplex = 0;
- vp->bus_master = 0;
- }
- ether_setup(dev);
- vp->next_module = root_vortex_dev;
- root_vortex_dev = dev;
- if (register_netdev(dev) != 0)
- return -EIO;
-#else /* not a MODULE */
if (dev) {
dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL);
memset(dev->priv, 0, sizeof (struct vortex_private));
@@ -519,18 +478,12 @@
vp = (struct vortex_private *)dev->priv;
vp->product_name = product_names[product_index];
vp->options = options;
- if (options >= 0) {
- vp->media_override = ((options & 7) == 2) ? 0 : options & 7;
- vp->full_duplex = (options & 8) ? 1 : 0;
- vp->bus_master = (options & 16) ? 1 : 0;
- } else {
- vp->media_override = 7;
- vp->full_duplex = 0;
- vp->bus_master = 0;
- }
+
+ vp->media_override = 7;
+ vp->full_duplex = 1;
+ vp->bus_master = 1;
vortex_probe1(dev);
-#endif /* MODULE */
return 0;
}
@@ -538,7 +491,7 @@
{
int ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- int i;
+ int i,timer,swinfo;
printk("%s: 3Com %s at %#3x,", dev->name,
vp->product_name, ioaddr);
@@ -547,7 +500,6 @@
EL3WINDOW(0);
for (i = 0; i < 3; i++) {
short *phys_addr = (short *)dev->dev_addr;
- int timer;
outw(EEPROM_Read + PhysAddr01 + i, ioaddr + Wn0EepromCmd);
/* Pause for at least 162 us. for the read to take place. */
for (timer = 162*4 + 400; timer >= 0; timer--) {
@@ -557,6 +509,7 @@
}
phys_addr[i] = htons(inw(ioaddr + Wn0EepromData));
}
+
for (i = 0; i < 6; i++)
printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
printk(", IRQ %d\n", dev->irq);
@@ -584,6 +537,9 @@
vp->autoselect = config.u.autoselect;
}
+ outw(SetIntrEnb+0x3fe,ioaddr+EL3_CMD); /* Enable all interrupts */
+ outw(SetStatusEnb+0x3fe,ioaddr+EL3_CMD); /* Enable all status */
+
/* We do a request_region() only to register /proc/ioports info. */
request_region(ioaddr, VORTEX_TOTAL_SIZE, vp->product_name);
@@ -728,16 +684,21 @@
outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
/* Allow status bits to be seen. */
outw(SetStatusEnb | 0x1ff, ioaddr + EL3_CMD);
+
/* Ack all pending events, and set active indicator mask. */
outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
ioaddr + EL3_CMD);
outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
| DMADone, ioaddr + EL3_CMD);
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-
+ /* Set TxStartThreshold */
+ outw(SetTxStart + (txstart>>2), ioaddr + EL3_CMD);
+ /* Set RxEarlyThreshold */
+ outw(SetRxThreshold + (rxstart>>2), ioaddr + EL3_CMD);
+ /* Set TxAvailable Threshold */
+/*
+ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+*/
return 0;
}
@@ -839,12 +800,13 @@
int tickssofar = jiffies - dev->trans_start;
int i;
- if (tickssofar < 2) /* We probably aren't empty. */
- return 1;
+ if (tickssofar < TX_TIMEOUT-2 ) return 1;
/* Wait a while to see if there really is room. */
for (i = WAIT_TX_AVAIL; i >= 0; i--)
- if (inw(ioaddr + TxFree) > skb->len)
- break;
+ if (inw(ioaddr + TxFree) > skb->len) {
+ printk("FIFO was not full\n");
+ break;
+ }
if ( i < 0) {
if (tickssofar < TX_TIMEOUT)
return 1;
@@ -874,13 +836,13 @@
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
-#ifdef VORTEX_BUS_MASTER
- if (vp->bus_master) {
+ if (skb->len>1000) {
+ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO;
/* Set the bus-master controller to transfer the packet. */
- outl((int)(skb->data), ioaddr + Wn7_MasterAddr);
- outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
+ outl_p((int)(skb->data), ioaddr + Wn7_MasterAddr);
+ outw_p((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
vp->tx_skb = skb;
- outw(StartDMADown, ioaddr + EL3_CMD);
+ outw_p(StartDMADown, ioaddr + EL3_CMD);
/* dev->tbusy will be cleared at the DMADone interrupt. */
} else {
/* ... and the packet rounded to a doubleword. */
@@ -892,16 +854,6 @@
/* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
}
-#else
- /* ... and the packet rounded to a doubleword. */
- outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
- dev_kfree_skb (skb, FREE_WRITE);
- if (inw(ioaddr + TxFree) > 1536) {
- dev->tbusy = 0;
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-#endif /* bus master */
dev->trans_start = jiffies;
@@ -918,9 +870,13 @@
if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
- int j;
+ if (tx_status&0x10) {
+ txstart+=32;
+ outw(SetTxStart + (txstart>>2), ioaddr + EL3_CMD);
+ printk("Reseted TxStartThreshold to %d\n",txstart);
+ }
outw(TxReset, ioaddr + EL3_CMD);
- for (j = 20; j >= 0 ; j--)
+ for (;;)
if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
}
@@ -979,31 +935,59 @@
if (vortex_debug > 5)
printk("%s: In interrupt loop, status %4.4x.\n",
dev->name, status);
- if (status & RxComplete)
+ if (status & RxEarly) {
vortex_rx(dev);
+ outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+ }
+ else if (status & RxComplete) vortex_rx(dev);
if (status & TxAvailable) {
- if (vortex_debug > 5)
- printk(" TX room bit was handled.\n");
+ printk("TX room bit was handled.\n");
/* There's room in the FIFO for a full-sized packet. */
outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
dev->tbusy = 0;
+ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
mark_bh(NET_BH);
}
-#ifdef VORTEX_BUS_MASTER
if (status & DMADone) {
- outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
- dev->tbusy = 0;
- dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
- mark_bh(NET_BH);
+ int ms,msr=0;
+ ms=inw(ioaddr+Wn7_MasterStatus);
+ if (ms&0x0001) {
+ printk("masterAbort!\n");
+ msr|=0x0001;
+ }
+ if (ms&0x0002) {
+ printk("targetAbort!\n");
+ msr|=0x0002;
+ outw(TotalReset+0x40,ioaddr+EL3_CMD);
+ }
+ if (ms&0x0004) {
+ msr|=0x0004;
+ }
+ if (ms&0x0008) {
+ msr|=0x0008;
+ }
+ if (ms&0x1000) {
+ msr|=0x1000;
+ dev->tbusy = 0;
+ dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */
+ mark_bh(NET_BH);
+ }
+ if (ms&0x4000) {
+ printk("Whoops: masterUpload!!!!!!\n");
+ msr|=0x4000;
+ /*
+ mark_bh(NET_BH);
+ */
+ }
+ SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO;
+ outw_p(msr,ioaddr+Wn7_MasterStatus); /* Ack the event. */
+/*
+ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+*/
}
-#endif
- if (status & (AdapterFailure | RxEarly | StatsFull)) {
+ if (status & (AdapterFailure | StatsFull)) {
/* Handle all uncommon interrupts at once. */
- if (status & RxEarly) { /* Rx early is unused. */
- vortex_rx(dev);
- outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
- }
if (status & StatsFull) { /* Empty statistics. */
static int DoneDidThat = 0;
if (vortex_debug > 4)
@@ -1048,7 +1032,6 @@
}
/* Acknowledge the IRQ. */
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-
} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
if (vortex_debug > 4)
@@ -1164,9 +1147,6 @@
#endif
update_stats(ioaddr, dev);
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
return 0;
}
@@ -1268,25 +1248,6 @@
outw(new_mode, ioaddr + EL3_CMD);
}
#endif
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
- struct device *next_dev;
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_vortex_dev) {
- next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module;
- unregister_netdev(root_vortex_dev);
- outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
- release_region(root_vortex_dev->base_addr, VORTEX_TOTAL_SIZE);
- kfree(root_vortex_dev);
- root_vortex_dev = next_dev;
- }
-}
-#endif /* MODULE */
-
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o ../../modules/3c59x.o"
Phillip Dillinger phillip.dillinger@sealabs.com