patch-2.2.15 linux/drivers/net/3c527.c

Next file: linux/drivers/net/82596.c
Previous file: linux/drivers/net/3c509.c
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/drivers/net/3c527.c linux/drivers/net/3c527.c
@@ -3,6 +3,7 @@
  *
  *	(c) Copyright 1998 Red Hat Software Inc
  *	Written by Alan Cox.
+ *	Further debugging by Carl Drougge.
  *
  *	Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
  *	(for the MCA stuff) written by Wim Dumon.
@@ -16,7 +17,7 @@
  */
 
 static const char *version =
-	"3c527.c:v0.06 1999/09/16 Alan Cox (alan@redhat.com)\n";
+	"3c527.c:v0.08 2000/02/22 Alan Cox (alan@redhat.com)\n";
 
 /*
  *	Things you need
@@ -100,6 +101,7 @@
 	u32 base;
 	u16 rx_halted;
 	u16 tx_halted;
+	u16 rx_pending;		/* ring due a service */
 	u16 exec_pending;
 	u16 mc_reload_wait;	/* a multicast load request is pending */
 	atomic_t tx_count;		/* buffers left */
@@ -418,6 +420,9 @@
 	printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
 		dev->name, lp->rx_len, lp->tx_len, lp->base);
 	
+	if(lp->tx_len >TX_RING_MAX)
+		lp->tx_len = TX_RING_MAX;
+		
 	dev->open		= mc32_open;
 	dev->stop		= mc32_close;
 	dev->hard_start_xmit	= mc32_send_packet;
@@ -426,6 +431,7 @@
 	
 	lp->rx_halted		= 1;
 	lp->tx_halted		= 1;
+	lp->rx_pending		= 0;
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
@@ -579,6 +585,7 @@
 	mc32_ring_poll(dev);	
 	
 	lp->rx_halted=0;
+	lp->rx_pending=0;
 }
 
 static void mc32_tx_abort(struct device *dev)
@@ -783,6 +790,7 @@
 static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	int ioaddr = dev->base_addr;
 
 	if (dev->tbusy) {
 		/*
@@ -833,6 +841,14 @@
 		lp->tx_skb_end++;
 		lp->tx_skb_end&=(TX_RING_MAX-1);
 		
+		/* TX suspend - shouldnt be needed but apparently is.
+		   This is a research item ... */
+		   
+		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
+		lp->tx_box->mbox=0;
+		outb(3, ioaddr+HOST_CMD);
+		
+		/* Transmit now stopped */
 		/* P is the last sending/sent buffer as a pointer */
 		p=(struct skb_header *)bus_to_virt(lp->base+tx_head);
 		
@@ -841,7 +857,7 @@
 		
 		np->control	|= (1<<6);	/* EOL */
 		wmb();
-		
+				
 		np->length	= skb->len;
 
 		if(np->length < 60)
@@ -857,7 +873,9 @@
 		
 		dev->tbusy	= 0;			/* Keep feeding me */		
 		
+		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 		lp->tx_box->mbox=0;
+		outb(5, ioaddr+HOST_CMD);		/* Restart TX */
 		restore_flags(flags);
 	}
 	return 0;
@@ -926,17 +944,15 @@
 	}
 	while(x++<48);
 	
-	/* 
-	 *	This is curious. It seems the receive stop and receive continue
-	 *	commands race against each other, even though we poll for 
-	 *	command ready to be issued. The delay is hackish but is a workaround
-	 *	while I investigate in depth
-	 */
+	/*
+	 *	Restart ring processing
+	 */	
 	
 	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 	lp->rx_box->mbox=0;
 	lp->rx_box->data[0] = top;
 	outb(1<<3, ioaddr+HOST_CMD);	
+	lp->rx_halted = 0;
 }
 
 
@@ -949,7 +965,6 @@
 	struct device *dev = dev_id;
 	struct mc32_local *lp;
 	int ioaddr, status, boguscount = 0;
-	int rx_event = 0;
 	
 	if (dev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
@@ -1011,7 +1026,15 @@
 			case 0:
 				break;
 			case 2:	/* RX */
-				rx_event=1;
+				lp->rx_pending=1;
+				if(!lp->rx_halted)
+				{
+					/*
+					 *	Halt ring receive
+					 */
+					while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
+					outb(3<<3, ioaddr+HOST_CMD);
+				}
 				break;
 			case 3:
 			case 4:
@@ -1024,9 +1047,10 @@
 				break;
 			case 6:
 				/* Out of RX buffers stat */
-				/* Must restart */
 				lp->net_stats.rx_dropped++;
-				rx_event = 1; 	/* To restart */
+				lp->rx_pending=1;
+				/* Must restart */
+				lp->rx_halted=1;
 				break;
 			default:
 				printk("%s: strange rx ack %d\n", 
@@ -1060,11 +1084,17 @@
 	}
 	
 	/*
-	 *	Process and restart the receive ring.
+	 *	Process and restart the receive ring. This has some state
+	 *	as we must halt the ring to process it and halting the ring
+	 *	might not occur in the same IRQ handling loop as we issue
+	 *	the halt.
 	 */
 	 
-	if(rx_event)
+	if(lp->rx_pending && lp->rx_halted)
+	{
 		mc32_rx_ring(dev);
+		lp->rx_pending = 0;
+	}
 	dev->interrupt = 0;
 	return;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)