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

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 = &eth16i_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)