patch-2.3.43 linux/drivers/net/tulip.c
Next file: linux/drivers/net/via-rhine.c
Previous file: linux/drivers/net/tokenring/smctr.c
Back to the patch index
Back to the overall index
- Lines: 492
- Date:
Thu Feb 10 12:28:01 2000
- Orig file:
v2.3.42/linux/drivers/net/tulip.c
- Orig date:
Fri Jan 21 18:19:16 2000
diff -u --recursive --new-file v2.3.42/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
@@ -75,6 +75,7 @@
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/init.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
@@ -101,10 +102,6 @@
#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
#endif
-#if (LINUX_VERSION_CODE < 0x20123)
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-
/* This my implementation of shared IRQs, now only used for 1.2.13. */
#ifdef HAVE_SHARED_IRQ
#define USE_SHARED_IRQ
@@ -368,16 +365,9 @@
u32 setup_frame[48]; /* Pseudo-Tx frame to init address table. */
int chip_id;
int revision;
-#if LINUX_VERSION_CODE > 0x20139
struct net_device_stats stats;
-#else
- struct enet_statistics stats;
-#endif
struct timer_list timer; /* Media selection timer. */
- int interrupt; /* In-interrupt flag. */
-#ifdef SMP_CHECK
- int smp_proc_id; /* Which processor in IRQ handler. */
-#endif
+ spinlock_t tx_lock;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
unsigned int tx_full:1; /* The Tx queue is full. */
@@ -435,7 +425,7 @@
This allows the probe routine to use the old driver initialization
interface. */
-int tulip_probe(void)
+static int __init tulip_probe(void)
{
int cards_found = 0;
static int pci_index = 0; /* Static, for multiple probe calls. */
@@ -446,17 +436,13 @@
well with the current structure. So instead we detect just the
Tulip cards in slot order. */
-#if LINUX_VERSION_CODE >= 0x20155
if (! pci_present())
return -ENODEV;
-#else
- if (! pcibios_present())
- return -ENODEV;
-#endif
for (;pci_index < 0xff; pci_index++) {
u16 vendor, device, pci_command, new_command;
unsigned long pci_ioaddr = 0;
int chip_idx = 0;
+ struct pci_dev *pdev;
if (pcibios_find_class
(PCI_CLASS_NETWORK_ETHERNET << 8,
@@ -468,10 +454,10 @@
else
break;
}
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_DEVICE_ID, &device);
+
+ pdev = pci_find_slot (pci_bus, pci_device_fn);
+ vendor = pdev->vendor;
+ device = pdev->device;
for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
if (vendor == tulip_tbl[chip_idx].vendor_id &&
@@ -485,12 +471,7 @@
vendor, device);
continue;
}
-#if LINUX_VERSION_CODE >= 0x20155
pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start;
-#else
- pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
- &pci_ioaddr);
-#endif
/* Remove I/O space marker in bit 0. */
pci_ioaddr &= ~3;
@@ -501,37 +482,32 @@
if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
continue;
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
if (pci_command != new_command) {
printk(KERN_INFO " The PCI BIOS has not enabled this"
" device! Updating PCI command %4.4x->%4.4x.\n",
pci_command, new_command);
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
+ pci_write_config_word(pdev, PCI_COMMAND, new_command);
}
if(tulip_probe1(pci_bus, pci_device_fn, chip_idx, cards_found))
{
/* Get and check the bus-master and latency values. */
unsigned char pci_latency;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 10) {
printk(KERN_INFO " PCI latency timer (CFLT) is "
"unreasonably low at %d. Setting to 64 clocks.\n",
pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 64);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
} else if (tulip_debug > 1)
printk(KERN_INFO " PCI latency timer (CFLT) is %#x, "
" PCI command is %4.4x.\n",
pci_latency, new_command);
/* Bring the 21143 out power-down mode. */
if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- 0x40, 0x40000000);
+ pci_write_config_dword(pdev, 0x40, 0x40000000);
cards_found++;
}
}
@@ -753,6 +729,8 @@
/* The Tulip-specific entries in the device structure. */
dev->open = &tulip_open;
dev->hard_start_xmit = &tulip_start_xmit;
+ dev->tx_timeout = &tulip_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
dev->stop = &tulip_close;
dev->get_stats = &tulip_get_stats;
#ifdef HAVE_PRIVATE_IOCTL
@@ -1216,9 +1194,7 @@
/* When a module we don't have 'x86' to check. */
outl(0x01A00000 | 0x4800, ioaddr + CSR0);
#else
-#if (LINUX_VERSION_CODE > 0x2014c)
#define x86 boot_cpu_data.x86
-#endif
outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
if (x86 <= 4)
printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
@@ -1249,6 +1225,7 @@
MOD_INC_USE_COUNT;
+ spin_lock_init(&tp->tx_lock);
tulip_init_ring(dev);
/* This is set_rx_mode(), but without starting the transmitter. */
@@ -1329,10 +1306,6 @@
outl(tp->csr6, ioaddr + CSR6);
outl(tp->csr6 | 0x2000, ioaddr + CSR6);
- dev->tbusy = 0;
- tp->interrupt = 0;
- dev->start = 1;
-
/* Enable interrupts by setting the interrupt mask. */
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
@@ -1352,6 +1325,8 @@
tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
add_timer(&tp->timer);
+ netif_start_queue(dev);
+
return 0;
}
@@ -1958,9 +1933,13 @@
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
+ printk("%s: transmit timed out\n", dev->name);
+
if (media_cap[dev->if_port] & MediaIsMII) {
/* Do nothing -- the media monitor should handle this. */
+#if 0
if (tulip_debug > 1)
+#endif
printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
dev->name);
dev->trans_start = jiffies;
@@ -2090,19 +2069,13 @@
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int entry;
u32 flag;
-
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- if (jiffies - dev->trans_start < TX_TIMEOUT)
- return 1;
- tulip_tx_timeout(dev);
- return 1;
- }
+ unsigned long cpuflags;
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
+ spin_lock_irqsave(&tp->tx_lock, cpuflags);
+
/* Calculate the next Tx descriptor entry. */
entry = tp->cur_tx % TX_RING_SIZE;
@@ -2111,17 +2084,15 @@
if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
flag = 0x60000000; /* No interrupt */
- dev->tbusy = 0;
} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
flag = 0xe0000000; /* Tx-done intr. */
- dev->tbusy = 0;
} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
flag = 0x60000000; /* No Tx-done intr. */
- dev->tbusy = 0;
} else {
/* Leave room for set_rx_mode() to fill entries. */
flag = 0xe0000000; /* Tx-done intr. */
tp->tx_full = 1;
+ netif_stop_queue(dev);
}
if (entry == TX_RING_SIZE-1)
flag |= 0xe2000000;
@@ -2129,6 +2100,8 @@
tp->tx_ring[entry].length = skb->len | flag;
tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
tp->cur_tx++;
+ spin_unlock_irqrestore(&tp->tx_lock, cpuflags);
+
/* Trigger an immediate transmit demand. */
outl(0, dev->base_addr + CSR1);
@@ -2159,20 +2132,6 @@
ioaddr = dev->base_addr;
tp = (struct tulip_private *)dev->priv;
- if (test_and_set_bit(0, (void*)&tp->interrupt)) {
-#ifdef SMP_CHECK
- printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
- " proc %d already handling.\n", dev->name,
- tp->smp_proc_id, smp_processor_id());
-#else
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-#endif
- return;
- }
- dev->interrupt = 1;
-#ifdef SMP_CHECK
- tp->smp_proc_id = smp_processor_id();
-#endif
do {
csr5 = inl(ioaddr + CSR5);
@@ -2189,6 +2148,8 @@
if (csr5 & (RxIntr | RxNoBuf))
work_budget -= tulip_rx(dev);
+ spin_lock(&tp->tx_lock);
+
if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
unsigned int dirty_tx;
@@ -2224,19 +2185,13 @@
#ifdef ETHER_STATS
if (status & 0x0001) tp->stats.tx_deferred++;
#endif
-#if LINUX_VERSION_CODE > 0x20127
tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
-#endif
tp->stats.collisions += (status >> 3) & 15;
tp->stats.tx_packets++;
}
/* Free the original skb. */
-#if (LINUX_VERSION_CODE > 0x20155)
- dev_kfree_skb(tp->tx_skbuff[entry]);
-#else
- dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
-#endif
+ dev_kfree_skb_irq(tp->tx_skbuff[entry]);
tp->tx_skbuff[entry] = 0;
}
@@ -2248,15 +2203,14 @@
}
#endif
- if (tp->tx_full && dev->tbusy
- && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
+ if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
/* The ring is no longer full, clear tbusy. */
tp->tx_full = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
tp->dirty_tx = dirty_tx;
+
if (csr5 & TxDied) {
if (tulip_debug > 1)
printk(KERN_WARNING "%s: The transmitter stopped!"
@@ -2266,6 +2220,7 @@
outl(tp->csr6 | 0x2002, ioaddr + CSR6);
}
}
+ spin_unlock(&tp->tx_lock);
/* Log errors. */
if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
@@ -2316,8 +2271,6 @@
printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
dev->name, inl(ioaddr + CSR5));
- dev->interrupt = 0;
- clear_bit(0, (void*)&tp->interrupt);
return;
}
@@ -2397,9 +2350,7 @@
netif_rx(skb);
dev->last_rx = jiffies;
tp->stats.rx_packets++;
-#if LINUX_VERSION_CODE > 0x20127
tp->stats.rx_bytes += pkt_len;
-#endif
}
entry = (++tp->cur_rx) % RX_RING_SIZE;
}
@@ -2429,8 +2380,7 @@
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int i;
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
@@ -2463,23 +2413,12 @@
tp->rx_ring[i].length = 0;
tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
if (skb) {
-#if LINUX_VERSION_CODE < 0x20100
- skb->free = 1;
-#endif
-#if (LINUX_VERSION_CODE > 0x20155)
dev_kfree_skb(skb);
-#else
- dev_kfree_skb(skb, FREE_WRITE);
-#endif
}
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (tp->tx_skbuff[i])
-#if (LINUX_VERSION_CODE > 0x20155)
dev_kfree_skb(tp->tx_skbuff[i]);
-#else
- dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
-#endif
tp->tx_skbuff[i] = 0;
}
@@ -2495,7 +2434,7 @@
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
- if (dev->start)
+ if (test_bit(LINK_STATE_START, &dev->state))
tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
return &tp->stats;
@@ -2601,6 +2540,7 @@
long ioaddr = dev->base_addr;
int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ unsigned long cpuflags;
tp->csr6 &= ~0x00D5;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
@@ -2660,13 +2600,12 @@
*setup_frm++ = eaddrs[2];
} while (++i < 15);
/* Now add this frame to the Tx list. */
+ spin_lock_irqsave(&tp->tx_lock, cpuflags);
if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
/* Same setup recently queued, we need not add it. */
} else {
- unsigned long flags;
unsigned int entry, dummy = 0;
- save_flags(flags); cli();
entry = tp->cur_tx++ % TX_RING_SIZE;
if (entry != 0) {
@@ -2688,12 +2627,12 @@
tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
tp->tx_ring[entry].status = 0x80000000;
if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
- dev->tbusy = 1;
+ netif_stop_queue(dev);
tp->tx_full = 1;
}
if (dummy >= 0)
tp->tx_ring[dummy].status = DescOwned;
- restore_flags(flags);
+ spin_unlock_irqrestore(&tp->tx_lock, cpuflags);
/* Trigger an immediate transmit demand. */
outl(0, ioaddr + CSR1);
}
@@ -2711,12 +2650,14 @@
u32 io;
u8 bus, devfn;
struct net_device *dev;
+ struct pci_dev *pdev;
if (loc->bus != LOC_PCI) return NULL;
- bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+ pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
+ if (!pdev) return NULL;
printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
- pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
- pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+ io = pdev->resource[0].start;
+ dev_id = pdev->device;
io &= ~3;
dev = tulip_probe1(bus, devfn, DC21142, -1);
if (dev) {
@@ -2753,9 +2694,6 @@
#endif /* Cardbus support */
-
-#ifdef MODULE
-#if LINUX_VERSION_CODE > 0x20118
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
MODULE_PARM(debug, "i");
@@ -2764,13 +2702,11 @@
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-#endif
/* An additional parameter that may be passed in... */
static int debug = -1;
-int
-init_module(void)
+static int __init tulip_init_module (void)
{
if (debug >= 0)
tulip_debug = debug;
@@ -2783,8 +2719,7 @@
#endif
}
-void
-cleanup_module(void)
+static void __exit tulip_cleanup_module (void)
{
struct net_device *next_dev;
@@ -2802,8 +2737,10 @@
}
}
-#endif /* MODULE */
-
+module_init(tulip_init_module);
+module_exit(tulip_cleanup_module);
+
+
/*
* Local variables:
* SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)