patch-2.3.45 linux/drivers/net/eth16i.c
Next file: linux/drivers/net/ewrk3.c
Previous file: linux/drivers/net/epic100.c
Back to the patch index
Back to the overall index
- Lines: 543
- Date:
Sun Feb 13 18:20:21 2000
- Orig file:
v2.3.44/linux/drivers/net/eth16i.c
- Orig date:
Tue Jan 4 13:57:17 2000
diff -u --recursive --new-file v2.3.44/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
@@ -158,6 +158,8 @@
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -168,26 +170,7 @@
#include <asm/io.h>
#include <asm/dma.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#endif
-#if LINUX_VERSION_CODE < 0x20138
-#define test_and_set_bit(val,addr) set_bit(val,addr)
-#endif
-
-#if LINUX_VERSION_CODE < 0x020100
-typedef struct enet_statistics eth16i_stats_type;
-#else
-typedef struct net_device_stats eth16i_stats_type;
-#endif
/* Few macros */
#define BIT(a) ( (1 << (a)) )
@@ -371,12 +354,14 @@
#define RESET ID_ROM_0
/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] =
- { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
+static unsigned int eth16i_portlist[] = {
+ 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
+};
-static unsigned int eth32i_portlist[] =
- { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
+static unsigned int eth32i_portlist[] = {
+ 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+ 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
+};
/* This is the Interrupt lookup table for Eth16i card */
static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 };
@@ -399,7 +384,7 @@
/* Information for each board */
struct eth16i_local {
- eth16i_stats_type stats;
+ struct net_device_stats stats;
unsigned char tx_started;
unsigned char tx_buf_busy;
unsigned short tx_queue; /* Number of packets in transmit buffer */
@@ -409,6 +394,7 @@
unsigned long tx_buffered_packets;
unsigned long tx_buffered_bytes;
unsigned long col_16;
+ spinlock_t lock;
};
/* Function prototypes */
@@ -429,8 +415,10 @@
static int eth16i_close(struct net_device *dev);
static int eth16i_tx(struct sk_buff *skb, struct net_device *dev);
static void eth16i_rx(struct net_device *dev);
+static void eth16i_timeout(struct net_device *dev);
static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void eth16i_reset(struct net_device *dev);
+static void eth16i_timeout(struct net_device *dev);
static void eth16i_skip_packet(struct net_device *dev);
static void eth16i_multicast(struct net_device *dev);
static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
@@ -444,18 +432,10 @@
static ushort eth16i_parse_mediatype(const char* s);
#endif
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev);
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
static char *cardname = "ICL EtherTeam 16i/32";
-#ifdef HAVE_DEVLIST
-
-/* Support for alternate probe manager */
-/struct netdev_entry eth16i_drv =
- {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list};
-
-#else /* Not HAVE_DEVLIST */
-
int __init eth16i_probe(struct net_device *dev)
{
int i;
@@ -488,10 +468,11 @@
return ENODEV;
}
-#endif /* Not HAVE_DEVLIST */
static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
{
+ struct eth16i_local *lp;
+
static unsigned version_printed = 0;
boot = 1; /* To inform initilization that we are in boot probe */
@@ -535,17 +516,6 @@
printk(KERN_INFO "%s", version);
dev->base_addr = ioaddr;
-
-#if 0
- if(dev->irq) {
- if(eth16i_set_irq(dev)) {
- dev->irq = eth16i_get_irq(ioaddr);
- }
-
- }
- else {
-#endif
-
dev->irq = eth16i_get_irq(ioaddr);
/* Try to obtain interrupt vector */
@@ -556,10 +526,6 @@
return -EAGAIN;
}
-#if 0
- irq2dev_map[dev->irq] = dev;
-#endif
-
printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
dev->name, cardname, ioaddr, dev->irq);
@@ -583,12 +549,16 @@
}
memset(dev->priv, 0, sizeof(struct eth16i_local));
-
dev->open = eth16i_open;
dev->stop = eth16i_close;
dev->hard_start_xmit = eth16i_tx;
dev->get_stats = eth16i_get_stats;
- dev->set_multicast_list = ð16i_multicast;
+ dev->set_multicast_list = eth16i_multicast;
+ dev->tx_timeout = eth16i_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ lp = (struct eth16i_local *)dev->priv;
+ spin_lock_init(&lp->lock);
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
@@ -1004,10 +974,7 @@
/* Turn on interrupts*/
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
@@ -1023,9 +990,8 @@
/* Turn off interrupts*/
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
lp->open_time = 0;
/* Disable transmit and receive */
@@ -1042,153 +1008,115 @@
return 0;
}
-static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+static void eth16i_timeout(struct net_device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
- int status = 0;
+ /*
+ If we get here, some higher level has decided that
+ we are broken. There should really be a "kick me"
+ function call instead.
+ */
- if(dev->tbusy) {
-
- /*
- If we get here, some higher level has decided that
- we are broken. There should really be a "kick me"
- function call instead.
- */
-
- int tickssofar = jiffies - dev->trans_start;
- if(tickssofar < TX_TIMEOUT)
- return 1;
-
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
- printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
- dev->name,
- inw(ioaddr + TX_STATUS_REG),
- (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
+ dev->name,
+ inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
"IRQ conflict" : "network cable problem");
- dev->trans_start = jiffies;
-
- /* Let's dump all registers */
- if(eth16i_debug > 0) {
- printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
- dev->name, inb(ioaddr + 0),
- inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4),
- inb(ioaddr + 5),
- inb(ioaddr + 6), inb(ioaddr + 7));
-
- printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
- dev->name, inb(ioaddr + TRANSMIT_START_REG),
- inb(ioaddr + COL_16_REG));
+ dev->trans_start = jiffies;
+ /* Let's dump all registers */
+ if(eth16i_debug > 0) {
+ printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+ dev->name, inb(ioaddr + 0),
+ inb(ioaddr + 1), inb(ioaddr + 2),
+ inb(ioaddr + 3), inb(ioaddr + 4),
+ inb(ioaddr + 5),
+ inb(ioaddr + 6), inb(ioaddr + 7));
+
+ printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
+ dev->name, inb(ioaddr + TRANSMIT_START_REG),
+ inb(ioaddr + COL_16_REG));
printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
- printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
- printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
-
- }
-
- lp->stats.tx_errors++;
-
- eth16i_reset(dev);
-
- dev->trans_start = jiffies;
-
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+ printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
+ printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
}
+ lp->stats.tx_errors++;
+ eth16i_reset(dev);
+ dev->trans_start = jiffies;
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ netif_wake_queue(dev);
+}
- /*
- If some higher layer thinks we've missed an tx-done interrupt
- we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- itself
- */
-
- if(skb == NULL) {
-#if LINUX_VERSION_CODE < 0x020100
- dev_tint(dev);
-#endif
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name);
- return 0;
- }
+static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int status = 0;
+ ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+ unsigned long flags;
- /* Block a timer based transmitter from overlapping.
- This could better be done with atomic_swap(1, dev->tbusy),
- but set_bit() works as well. */
- set_bit(0, (void *)&lp->tx_buf_busy);
-
+ netif_stop_queue(dev);
+
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+ /* We would be better doing the disable_irq tricks the 3c509 does,
+ that would make this suck a lot less */
+
+ spin_lock_irqsave(&lp->lock, flags);
- if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- status = -1;
- }
+ if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
+ }
else {
- ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
+ outw(length, ioaddr + DATAPORT);
- if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
- }
+ if( ioaddr < 0x1000 )
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
else {
- outw(length, ioaddr + DATAPORT);
-
- if( ioaddr < 0x1000 )
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
- else {
- unsigned char frag = length % 4;
-
- outsl(ioaddr + DATAPORT, buf, length >> 2);
-
- if( frag != 0 ) {
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
- if( frag == 3 )
- outsw(ioaddr + DATAPORT,
- (buf + (length & 0xFFFC) + 2), 1);
- }
+ unsigned char frag = length % 4;
+ outsl(ioaddr + DATAPORT, buf, length >> 2);
+ if( frag != 0 ) {
+ outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+ if( frag == 3 )
+ outsw(ioaddr + DATAPORT,
+ (buf + (length & 0xFFFC) + 2), 1);
}
-
- lp->tx_buffered_packets++;
- lp->tx_buffered_bytes = length;
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
}
-
- lp->tx_buf_busy = 0;
+ lp->tx_buffered_packets++;
+ lp->tx_buffered_bytes = length;
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+ }
+ lp->tx_buf_busy = 0;
- if(lp->tx_started == 0) {
- /* If the transmitter is idle..always trigger a transmit */
- outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- dev->trans_start = jiffies;
- lp->tx_started = 1;
- dev->tbusy = 0;
- }
- else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
- /* There is still more room for one more packet in tx buffer */
- dev->tbusy = 0;
- }
-
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ if(lp->tx_started == 0) {
+ /* If the transmitter is idle..always trigger a transmit */
+ outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
+ lp->tx_started = 1;
+ netif_wake_queue(dev);
+ }
+ else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+ /* There is still more room for one more packet in tx buffer */
+ netif_wake_queue(dev);
+ }
- /* Turn TX interrupts back on */
- /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
- status = 0;
- }
-
-#if LINUX_VERSION_CODE >= 0x020100
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ /* Turn TX interrupts back on */
+ /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
+ status = 0;
dev_kfree_skb(skb);
-#else
- dev_kfree_skb(skb, FREE_WRITE);
-#endif
-
- return status;
+ return 0;
}
static void eth16i_rx(struct net_device *dev)
@@ -1284,51 +1212,23 @@
break;
} /* while */
-
-#if 0
- {
- int i;
-
- for(i = 0; i < 20; i++) {
- if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) ==
- RX_BUFFER_EMPTY)
- break;
- inw(ioaddr + DATAPORT);
- outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
- }
-
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name);
- }
-#endif
-
- return;
}
static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct eth16i_local *lp;
- int ioaddr = 0,
- status;
+ int ioaddr = 0, status;
- if(dev == NULL) {
- printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq);
- return;
- }
+ ioaddr = dev->base_addr;
+ lp = (struct eth16i_local *)dev->priv;
/* Turn off all interrupts from adapter */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- set_bit(0, (void *)&dev->tbusy); /* Set the device busy so that */
/* eth16i_tx wont be called */
+ spin_lock(&lp->lock);
- if(dev->interrupt)
- printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
-
- ioaddr = dev->base_addr;
- lp = (struct eth16i_local *)dev->priv;
status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
@@ -1386,13 +1286,11 @@
lp->tx_queue = 0;
lp->tx_queue_len = 0;
lp->tx_started = 1;
- dev->trans_start = jiffies;
- mark_bh(NET_BH);
}
else {
lp->tx_started = 0;
- mark_bh(NET_BH);
}
+ netif_wake_queue(dev);
}
}
@@ -1401,16 +1299,16 @@
eth16i_rx(dev); /* We have packet in receive buffer */
}
- dev->interrupt = 0;
-
/* Turn interrupts back on */
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
/* There is still more room for one more packet in tx buffer */
- dev->tbusy = 0;
+ netif_wake_queue(dev);
}
+ spin_unlock(&lp->lock);
+
return;
}
@@ -1442,10 +1340,6 @@
lp->tx_buf_busy = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
-
- dev->interrupt = 0;
- dev->start = 1;
- dev->tbusy = 0;
BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
}
@@ -1462,10 +1356,9 @@
}
}
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev)
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-
return &lp->stats;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)