patch-2.3.41 linux/drivers/net/pcnet32.c
Next file: linux/drivers/net/setup.c
Previous file: linux/drivers/net/pcmcia/Config.in
Back to the patch index
Back to the overall index
- Lines: 297
- Date:
Wed Jan 26 13:16:05 2000
- Orig file:
v2.3.40/linux/drivers/net/pcnet32.c
- Orig date:
Fri Jan 21 18:19:16 2000
diff -u --recursive --new-file v2.3.40/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
@@ -13,7 +13,7 @@
* This driver is for PCnet32 and PCnetPCI based ethercards
*/
-static const char *version = "pcnet32.c:v1.23ac 21.9.1999 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
#include <linux/config.h>
#include <linux/module.h>
@@ -41,12 +41,13 @@
static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
static int pcnet32_debug = 1;
+static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
#ifdef MODULE
static struct net_device *pcnet32_dev = NULL;
#endif
-static const int max_interrupt_work = 20;
+static const int max_interrupt_work = 80;
static const int rx_copybreak = 200;
#define PORT_AUI 0x00
@@ -154,7 +155,12 @@
* Michael Richard <mcr@solidum.com>)
* added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
* v1.23 fixed small bug, when manual selecting MII speed/duplex
- * v1.23ac Added SMP spinlocking - Alan Cox <alan@redhat.com>
+ * v1.24 Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO
+ * underflows. Added tx_start_pt module parameter. Increased
+ * TX_RING_SIZE from 16 to 32. Added #ifdef'd code to use DXSUFLO
+ * for FAST[+] chipsets. <kaf@fc.hp.com>
+ * v1.24ac Added SMP spinlocking - Alan Cox <alan@redhat.com>
+ * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
*/
@@ -165,7 +171,7 @@
*/
#ifndef PCNET32_LOG_TX_BUFFERS
#define PCNET32_LOG_TX_BUFFERS 4
-#define PCNET32_LOG_RX_BUFFERS 4
+#define PCNET32_LOG_RX_BUFFERS 5
#endif
#define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS))
@@ -255,12 +261,16 @@
struct pcnet32_access a;
void *origmem;
spinlock_t lock; /* Guard lock */
- int cur_rx, cur_tx; /* The next free ring entry */
- int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
+ unsigned int cur_rx, cur_tx; /* The next free ring entry */
+ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
struct net_device_stats stats;
char tx_full;
int options;
int shared_irq:1, /* shared irq possible */
+ ltint:1,
+#ifdef DO_DXSUFLO
+ dxsuflo:1, /* disable transmit stop on uflo */
+#endif
full_duplex:1, /* full duplex possible */
mii:1; /* mii port available */
#ifdef MODULE
@@ -299,6 +309,10 @@
PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
pcnet32_probe1},
+ { "AMD PCnetPCI series (IBM)",
+ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
+ PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+ pcnet32_probe1},
{ "AMD PCnetHome series",
PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
@@ -448,8 +462,8 @@
int chip_idx;
u16 sdid,svid;
- pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid);
- pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
+ pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdid);
for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) &&
(pdev->device == pcnet32_tbl[chip_idx].device_id) &&
@@ -510,6 +524,10 @@
{
struct pcnet32_private *lp;
int i,media,fdx = 0, mii = 0, fset = 0;
+#ifdef DO_DXSUFLO
+ int dxsuflo = 0;
+#endif
+ int ltint = 0;
int chip_version;
char *chipname;
char *priv;
@@ -552,6 +570,7 @@
case 0x2623:
chipname = "PCnet/FAST 79C971";
fdx = 1; mii = 1; fset = 1;
+ ltint = 1;
break;
case 0x2624:
chipname = "PCnet/FAST+ 79C972";
@@ -600,7 +619,11 @@
if(fset)
{
a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
- a->write_csr(ioaddr, 80, a->read_csr(ioaddr, 80) | 0x0c00);
+ a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);
+#ifdef DO_DXSUFLO
+ dxsuflo = 1;
+#endif
+ ltint = 1;
}
dev = init_etherdev(NULL, 0);
@@ -614,6 +637,29 @@
for (i = 0; i < 6; i++)
printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
+ i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */
+ printk("\n tx_start_pt(0x%04x):",i);
+ switch(i>>10) {
+ case 0: printk(" 20 bytes,"); break;
+ case 1: printk(" 64 bytes,"); break;
+ case 2: printk(" 128 bytes,"); break;
+ case 3: printk("~220 bytes,"); break;
+ }
+ i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */
+ printk(" BCR18(%x):",i&0xffff);
+ if (i & (1<<5)) printk("BurstWrEn ");
+ if (i & (1<<6)) printk("BurstRdEn ");
+ if (i & (1<<7)) printk("DWordIO ");
+ if (i & (1<<11)) printk("NoUFlow ");
+ i = a->read_bcr(ioaddr, 25);
+ printk("\n SRAMSIZE=0x%04x,",i<<8);
+ i = a->read_bcr(ioaddr, 26);
+ printk(" SRAM_BND=0x%04x,",i<<8);
+ i = a->read_bcr(ioaddr, 27);
+ if (i & (1<<14)) printk("LowLatRx,");
+ }
+
dev->base_addr = ioaddr;
request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
@@ -634,6 +680,10 @@
lp->name = chipname;
lp->shared_irq = shared;
lp->full_duplex = fdx;
+#ifdef DO_DXSUFLO
+ lp->dxsuflo = dxsuflo;
+#endif
+ lp->ltint = ltint;
lp->mii = mii;
if (options[card_idx] > sizeof (options_mapping))
lp->options = PORT_ASEL;
@@ -775,7 +825,20 @@
val |= 0x08;
lp->a.write_bcr (ioaddr, 32, val);
}
-
+
+#ifdef DO_DXSUFLO
+ if (lp->dxsuflo) { /* Disable transmit stop on underflow */
+ val = lp->a.read_csr (ioaddr, 3);
+ val |= 0x40;
+ lp->a.write_csr (ioaddr, 3, val);
+ }
+#endif
+ if (lp->ltint) { /* Enable TxDone-intr inhibitor */
+ val = lp->a.read_csr (ioaddr, 5);
+ val |= (1<<14);
+ lp->a.write_csr (ioaddr, 5, val);
+ }
+
lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
lp->init_block.filter[0] = 0x00000000;
lp->init_block.filter[1] = 0x00000000;
@@ -905,6 +968,7 @@
{
struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
unsigned int ioaddr = dev->base_addr;
+ u16 status;
int entry;
unsigned long flags;
@@ -953,11 +1017,28 @@
}
spin_lock_irqsave(&lp->lock, flags);
- /* Fill in a Tx ring entry */
+ /* Default status -- will not enable Successful-TxDone
+ * interrupt when that option is available to us.
+ */
+ status = 0x8300;
+ if ((lp->ltint) &&
+ ((lp->cur_tx - lp->dirty_tx == TX_RING_SIZE/2) ||
+ (lp->cur_tx - lp->dirty_tx >= TX_RING_SIZE-2)))
+ {
+ /* Enable Successful-TxDone interrupt if we have
+ * 1/2 of, or nearly all of, our ring buffer Tx'd
+ * but not yet cleaned up. Thus, most of the time,
+ * we will not enable Successful-TxDone interrupts.
+ */
+ status = 0x9300;
+ }
+
+ /* Fill in a Tx ring entry */
+
/* Mask to ring buffer boundary. */
entry = lp->cur_tx & TX_RING_MOD_MASK;
-
+
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
@@ -967,7 +1048,7 @@
lp->tx_skbuff[entry] = skb;
lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
- lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+ lp->tx_ring[entry].status = le16_to_cpu(status);
lp->cur_tx++;
lp->stats.tx_bytes += skb->len;
@@ -1026,7 +1107,7 @@
pcnet32_rx(dev);
if (csr0 & 0x0200) { /* Tx-done interrupt */
- int dirty_tx = lp->dirty_tx;
+ unsigned int dirty_tx = lp->dirty_tx;
while (dirty_tx < lp->cur_tx) {
int entry = dirty_tx & TX_RING_MOD_MASK;
@@ -1044,14 +1125,27 @@
if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
if (err_status & 0x10000000) lp->stats.tx_window_errors++;
- if (err_status & 0x40000000) {
+#ifndef DO_DXSUFLO
+ if (err_status & 0x40000000) {
+ lp->stats.tx_fifo_errors++;
/* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+ dev->name, csr0);
+ must_restart = 1;
+ }
+#else
+ if (err_status & 0x40000000) {
lp->stats.tx_fifo_errors++;
- /* Remove this verbosity later! */
- printk("%s: Tx FIFO error! Status %4.4x.\n",
- dev->name, csr0);
- must_restart = 1;
- }
+ if (! lp->dxsuflo) { /* If controller doesn't recover ... */
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+ dev->name, csr0);
+ must_restart = 1;
+ }
+ }
+#endif
} else {
if (status & 0x1800)
lp->stats.collisions++;
@@ -1388,18 +1482,22 @@
MODULE_PARM(debug, "i");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(tx_start_pt, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
/* An additional parameter that may be passed in... */
static int debug = -1;
+static int tx_start_pt = -1;
int
init_module(void)
{
if (debug > 0)
pcnet32_debug = debug;
+ if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
+ tx_start = tx_start_pt;
pcnet32_dev = NULL;
return pcnet32_probe();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)