lkml.org 
[lkml]   [1996]   [Mar]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject3c59x "Vortex" driver: new patch (sorry...) (fwd)
I tested my revised version of the "Vortex" driver for 3c590/595
network adapter, by plugging in both a 3c595 and a NE2000 clone, and I
detected a mistake in my revision.

I'm sorry. Please find attached the re-revised patch, to be applied
to the original "Vortex" driver.

If you run into troubles getting the attachment, get the stuff at
anonymous ftp://ftp/disi.unige.it/pub/ciaccio, where you can find
both the patch and the revised driver (and two pictures of mine).

Greetings from Italy

Giuseppe.

|----------------------------------------------------------------------|
| Giuseppe Ciaccio e-mail : ciaccio@disi.unige.it |
| phone, address: finger ciaccio@disi.unige.it |
|----------------------------------------------------------------------|
--- 3c59xold.c Thu Mar 14 15:01:15 1996
+++ 3c59xnew.c Tue Mar 19 18:57:59 1996
@@ -2,6 +2,8 @@
/*
Written 1995 by Donald Becker.

+ Revised 3/19/1996 by Giuseppe Ciaccio ciaccio@disi.unige.it
+
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.

@@ -14,7 +16,7 @@
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
*/

-static char *version = "3c59x.c:v0.13 2/13/96 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "3c59x.c:v0.13 2/13/96 becker@cesdis.gsfc.nasa.gov\nrevised: 3/19/96 ciaccio@disi.unige.it\n";

/* "Knobs" that turn on special features. */
/* Allow the use of bus master transfers instead of programmed-I/O for the
@@ -25,6 +27,18 @@
/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
#define VORTEX_DEBUG 1

+
+/* Sometimes it is safe to wait a moment... */
+#define WAIT_LAPSE 20
+#define LONG_WAIT_LAPSE 200
+#define WAIT_TX_AVAIL 200
+#define MAX_TICKS_SO_FAR 40
+
+
+/* Max packet size is 1536, but can change in the future... */
+#define MAX_PACKET_SIZE 1536
+
+
#include <linux/module.h>

#include <linux/kernel.h>
@@ -66,7 +80,11 @@
int vortex_debug = 1;
#endif

-static int product_ids[] = {0x5900, 0x5950, 0x5951, 0x5952, 0, 0};
+/* These are for PCI only */
+static int product_ids[] = {0x5900, 0x5950, 0x5951, 0x5952, 0};
+#define HOW_MANY_PCI_PRODUCTS 4
+
+/* These are for both PCI and EISA */
static const char *product_names[] = {
"3c590 Vortex 10Mbps",
"3c595 Vortex 100baseTX",
@@ -74,7 +92,9 @@
"3c595 Vortex 100base-MII",
"EISA Vortex 3c597",
};
-#define DEMON_INDEX 5 /* Caution! Must be consistent with above! */
+
+/* Caution! Must be consistent with above! */
+#define DEMON_INDEX HOW_MANY_PCI_PRODUCTS+1

/*
Theory of Operation
@@ -123,6 +143,16 @@
The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes!
This driver only supports ethernet packets because of the skbuff allocation
limit of 4K.
+
+In order to signal room availability in the Tx buffer, the network adapter
+is programmed to send an interrupt, which causes the flag dev->tbusy
+to be zeroed when catched (function vortex_interrupt). However, it seems
+that 3c590 boards sometimes forget to send that interrupt. As a result,
+the ongoing communication is blocked.
+The problem is solved by busy-waiting room availability each time a new
+transmission is to start and dev->tbusy is not zero
+(function vortex_start_xmit).
+
*/

#define TCOM_VENDOR_ID 0x10B7 /* 3Com's manufacturer's ID. */
@@ -301,56 +331,60 @@
int cards_found = 0;

if (pcibios_present()) {
- static int pci_index = 0;
+ static int pci_index;
for (; pci_index < 8; pci_index++) {
unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency;
unsigned int pci_ioaddr;
unsigned short pci_command;
int index;
+ int found = 0;

- for (index = 0; product_ids[index]; index++) {
- if ( ! pcibios_find_device(TCOM_VENDOR_ID, product_ids[index],
+ for (index = 0; index < 5; index++) {
+ if ( pcibios_find_device(TCOM_VENDOR_ID, product_ids[index],
pci_index, &pci_bus,
&pci_device_fn))
- break;
- }
- if ( ! product_ids[index])
- break;
-
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
+ continue;

+ /* A known PCI card was found */
+ found = 1;
+
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ 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
- data corruption that occurs when the timer expires during
- a transfer. Yes, it's a bug. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk(" PCI Master Bit has not been set! Setting...\n");
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command);
- }
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency != 255) {
- printk(" 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);
- }
+ /* 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
+ data corruption that occurs when the timer expires during
+ a transfer. Yes, it's a bug. */
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+ if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+ printk(" PCI Master Bit has not been set! Setting...\n");
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, pci_command);
+ }
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency != 255) {
+ printk(" 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);
+ }
#endif /* VORTEX_BUS_MASTER */
- vortex_found_device(dev, pci_ioaddr, pci_irq_line, index,
- dev && dev->mem_start ? dev->mem_start
- : options[cards_found]);
- dev = 0;
- cards_found++;
+ vortex_found_device(dev, pci_ioaddr, pci_irq_line, index,
+ dev && dev->mem_start ? dev->mem_start
+ : options[cards_found]);
+ dev = 0;
+ cards_found++;
+ }
+ /* If no known card was found, stop scanning. */
+ if (!found) break;
}
}

@@ -530,13 +564,13 @@
}

outw(TxReset, ioaddr + EL3_CMD);
- for (i = 20; i >= 0 ; i--)
+ for (i = WAIT_LAPSE; i >= 0 ; i--)
if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
break;

outw(RxReset, ioaddr + EL3_CMD);
/* Wait a few ticks for the RxReset command to complete. */
- for (i = 20; i >= 0 ; i--)
+ for (i = WAIT_LAPSE; i >= 0 ; i--)
if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
break;

@@ -638,26 +672,28 @@
struct vortex_private *vp = (struct vortex_private *)dev->priv;
int ioaddr = dev->base_addr;

- /* Transmitter timeout, serious problems. */
if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 40)
- return 1;
- printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
- dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS));
- vp->stats.tx_errors++;
- /* Issue TX_RESET and TX_START commands. */
- outw(TxReset, ioaddr + EL3_CMD);
- {
- int i;
- for (i = 20; i >= 0 ; i--)
- if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
- break;
- }
- outw(TxEnable, ioaddr + EL3_CMD);
- dev->trans_start = jiffies;
- dev->tbusy = 0;
- return 0;
+ /* Missing interrupt of TxAvailable ? */
+ /* Let's have a little busy-waiting for */
+ /* room available in Tx buffer */
+ int i = WAIT_TX_AVAIL;
+ while ((inw(ioaddr + TxFree) <= MAX_PACKET_SIZE) && --i);
+ if (!i) {
+ if ((jiffies - dev->trans_start) < MAX_TICKS_SO_FAR)
+ return 1;
+ printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+ dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS));
+ vp->stats.tx_errors++;
+ /* Issue TX_RESET and TX_START commands. */
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (i = 20; i >= 0 ; i--)
+ if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress) break;
+ outw(TxEnable, ioaddr + EL3_CMD);
+ dev->trans_start = jiffies;
+ dev->tbusy = 0;
+ return 0;
+ }
+ dev->tbusy = 0;
}

if (skb == NULL || skb->len <= 0) {
@@ -688,21 +724,19 @@
/* ... 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
+ if (inw(ioaddr + TxFree) > MAX_PACKET_SIZE) dev->tbusy = 0;
+ else
/* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+ outw(SetTxThreshold + MAX_PACKET_SIZE, 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
+ if (inw(ioaddr + TxFree) > MAX_PACKET_SIZE) dev->tbusy = 0;
+ else
/* Interrupt us when the FIFO has room for max-sized packet. */
- outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+ outw(SetTxThreshold + MAX_PACKET_SIZE, ioaddr + EL3_CMD);
#endif /* bus master */

dev->trans_start = jiffies;
@@ -722,7 +756,7 @@
if (tx_status & 0x30) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
- for (j = 20; j >= 0 ; j--)
+ for (j = WAIT_LAPSE; j >= 0 ; j--)
if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
break;
}
@@ -802,11 +836,11 @@
#endif
if (status & (AdapterFailure | RxEarly | StatsFull)) {
/* Handle all uncommon interrupts at once. */
- if (status & RxEarly) { /* Rx early is unused. */
+ if (status & RxEarly) { /* Rx early is unused. */
vortex_rx(dev);
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
}
- if (status & StatsFull) { /* Empty statistics. */
+ if (status & StatsFull) { /* Empty statistics. */
static int DoneDidThat = 0;
if (vortex_debug > 4)
printk("%s: Updating stats.\n", dev->name);
@@ -842,6 +876,9 @@
}
}

+ if (!(status & (RxComplete | TxAvailable | DMADone | AdapterFailure | RxEarly | StatsFull)))
+ printk("%s: vortex_interrupt(): irq %d with unknown status.\n", dev->name, irq);
+
if (++i > 10) {
printk("%s: Infinite loop in interrupt, status %4.4x. "
"Disabling functions (%4.4x).\n",
@@ -904,7 +941,7 @@
netif_rx(skb);
outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
/* Wait a limited time to go to next packet. */
- for (i = 200; i >= 0; i--)
+ for (i = LONG_WAIT_LAPSE; i >= 0; i--)
if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
break;
vp->stats.rx_packets++;
@@ -916,7 +953,7 @@
vp->stats.rx_dropped++;
outw(RxDiscard, ioaddr + EL3_CMD);
/* Wait a limited time to skip this packet. */
- for (i = 200; i >= 0; i--)
+ for (i = LONG_WAIT_LAPSE; i >= 0; i--)
if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress)
break;
}
\
 
 \ /
  Last update: 2005-03-22 13:36    [W:0.027 / U:0.520 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site