patch-1.3.96 linux/drivers/net/de4x5.c

Next file: linux/drivers/net/de4x5.h
Previous file: linux/drivers/net/atarilance.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.95/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
@@ -121,6 +121,11 @@
     patched this  driver to detect it  because the SROM format used complies
     to a previous DEC-STD format.
 
+    I have removed the buffer copies needed for receive on Intels.  I cannot
+    remove them for   Alphas since  the  Tulip hardware   only does longword
+    aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
+    longword aligned data copies (which makes them really slow). No comment.
+
     TO DO:
     ------
 
@@ -182,11 +187,19 @@
 			  Duh, put the SA_SHIRQ flag into request_interrupt().
 			  Fix SMC ethernet address in enet_det[].
 			  Print chip name instead of "UNKNOWN" during boot.
+      0.42    26-Apr-96   Fix MII write TA bit error.
+                          Fix bug in dc21040 and dc21041 autosense code.
+			  Remove buffer copies on receive for Intels.
+			  Change sk_buff handling during media disconnects to
+			  eliminate DUP packets.
+			  Add dynamic TX thresholding.
+			  Change all chips to use perfect multicast filtering.
+			  Fix alloc_device() bug <jari@markkus2.fimr.fi>
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.41 96/3/21 davies@wanton.lkg.dec.com\n";
+static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n";
 
 #include <linux/module.h>
 
@@ -298,6 +311,7 @@
 ** Ethernet Info
 */
 #define PKT_BUF_SZ	1536            /* Buffer size for each Tx/Rx buffer */
+#define IEEE802_3_SZ    1518            /* Packet + CRC */
 #define MAX_PKT_SZ   	1514            /* Maximum ethernet packet length */
 #define MAX_DAT_SZ   	1500            /* Maximum ethernet data length */
 #define MIN_DAT_SZ   	1               /* Minimum ethernet data length */
@@ -418,6 +432,7 @@
     char info[100];
     short chksum;
 };
+#define SUB_VENDOR_ID 0x500a
 
 /*
 ** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
@@ -451,7 +466,8 @@
     char adapter_name[80];                  /* Adapter name                 */
     struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring           */
     struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring           */
-    struct sk_buff *skb[NUM_TX_DESC];       /* TX skb for freeing when sent */
+    struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
+    struct sk_buff *rx_skb[NUM_RX_DESC];    /* RX skb's                     */
     int rx_new, rx_old;                     /* RX descriptor ring pointers  */
     int tx_new, tx_old;                     /* TX descriptor ring pointers  */
     char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
@@ -531,6 +547,8 @@
 			lp->tx_old+lp->txRingSize-lp->tx_new-1:\
 			lp->tx_old               -lp->tx_new-1)
 
+#define TX_PKT_PENDING (lp->tx_old != lp->tx_new)
+
 /*
 ** Public Functions
 */
@@ -551,6 +569,7 @@
 static int     de4x5_rx(struct device *dev);
 static int     de4x5_tx(struct device *dev);
 static int     de4x5_ast(struct device *dev);
+static int     de4x5_txur(struct device *dev);
 
 static int     autoconf_media(struct device *dev);
 static void    create_packet(struct device *dev, char *frame, int len);
@@ -563,13 +582,16 @@
 static int     de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *));
 static int     dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int));
 static int     test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
-/*static int     test_sym_link(struct device *dev, u32 msec);*/
+static int     test_sym_link(struct device *dev, int msec);
 static int     test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec);
 static int     is_spd_100(struct device *dev);
 static int     is_100_up(struct device *dev);
 static int     is_10_up(struct device *dev);
 static int     is_anc_capable(struct device *dev);
 static int     ping_media(struct device *dev, int msec);
+static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len);
+static void    de4x5_free_rx_buffs(struct device *dev);
+static void    de4x5_free_tx_buffs(struct device *dev);
 static void    de4x5_save_skbs(struct device *dev);
 static void    de4x5_restore_skbs(struct device *dev);
 static void    de4x5_cache_state(struct device *dev, int flag);
@@ -621,6 +643,7 @@
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
 static void    de4x5_dbg_srom(struct de4x5_srom *p);
+static void    de4x5_dbg_rx(struct sk_buff *skb, int len);
 static int     de4x5_strncmp(char *a, char *b, int n);
 
 #ifdef MODULE
@@ -655,7 +678,8 @@
 ** more info. Until I fix (un)register_netdevice() we won't be able to use it
 ** though.
 */
-int de4x5_probe(struct device *dev)
+int
+de4x5_probe(struct device *dev)
 {
     int tmp = num_de4x5s, status = -ENODEV;
     u_long iobase = dev->base_addr;
@@ -793,62 +817,66 @@
 	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
 	
 	/*
-	** Allocate contiguous receive buffers, long word aligned. 
+	** Set up the RX descriptor ring (Intels)
+	** Allocate contiguous receive buffers, long word aligned (Alphas) 
 	*/
+#ifndef __alpha__
+	for (i=0; i<NUM_RX_DESC; i++) {
+	    lp->rx_ring[i].status = 0;
+	    lp->rx_ring[i].des1 = RX_BUFF_SZ;
+	    lp->rx_ring[i].buf = 0;
+	    lp->rx_ring[i].next = 0;
+	    lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
+	}
+
+#else
 	if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
-				   GFP_KERNEL)) != NULL) {
-	    lp->cache.buf = tmp;
-	    tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
-	    for (i=0; i<NUM_RX_DESC; i++) {
-		lp->rx_ring[i].status = 0;
-		lp->rx_ring[i].des1 = RX_BUFF_SZ;
-		lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
-		lp->rx_ring[i].next = (u32)NULL;
-	    }
-	    barrier();
+				   GFP_KERNEL)) == NULL) {
+	    kfree(lp->cache.priv);
+	    return -ENOMEM;
+	}
+
+	lp->cache.buf = tmp;
+	tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN);
+	for (i=0; i<NUM_RX_DESC; i++) {
+	    lp->rx_ring[i].status = 0;
+	    lp->rx_ring[i].des1 = RX_BUFF_SZ;
+	    lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
+	    lp->rx_ring[i].next = 0;
+	    lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
+	}
+#endif
+
+	barrier();
 	    
-	    request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
-				    DE4X5_EISA_TOTAL_SIZE), 
-			   lp->adapter_name);
+	request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
+				DE4X5_EISA_TOTAL_SIZE), 
+		       lp->adapter_name);
 	    
-	    lp->rxRingSize = NUM_RX_DESC;
-	    lp->txRingSize = NUM_TX_DESC;
+	lp->rxRingSize = NUM_RX_DESC;
+	lp->txRingSize = NUM_TX_DESC;
 	    
-	    /* Write the end of list marker to the descriptor lists */
-	    lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER;
-	    lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
+	/* Write the end of list marker to the descriptor lists */
+	lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER;
+	lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
 	    
-	    /* Tell the adapter where the TX/RX rings are located. */
-	    outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
-	    outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+	/* Tell the adapter where the TX/RX rings are located. */
+	outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+	outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
 	    
-	    /* Initialise the IRQ mask and Enable/Disable */
-	    lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
-	    lp->irq_en   = IMR_NIM | IMR_AIM;
+	/* Initialise the IRQ mask and Enable/Disable */
+	lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
+	lp->irq_en   = IMR_NIM | IMR_AIM;
 
-	    /* Create a loopback packet frame for later media probing */
-	    create_packet(dev, lp->frame, sizeof(lp->frame));
+	/* Create a loopback packet frame for later media probing */
+	create_packet(dev, lp->frame, sizeof(lp->frame));
 
-	    /* Initialise the adapter state */
-	    lp->state = CLOSED;
+	/* Initialise the adapter state */
+	lp->state = CLOSED;
+
+	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
+	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
 
-	    printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
-		   ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
-	} else {
-	    printk("%s: Kernel could not allocate RX buffer memory.\n", dev->name);
-	}
-	if (status) {
-	    release_region(iobase, (lp->bus == PCI ? 
-				    DE4X5_PCI_TOTAL_SIZE :
-				    DE4X5_EISA_TOTAL_SIZE));
-	    if (lp->rx_ring[0].buf) {
-		kfree(bus_to_virt(lp->rx_ring[0].buf));
-	    }
-	    kfree(dev->priv);
-	    dev->priv = NULL;
-	    
-	    return -ENXIO;
-	}
     }
     
     if (de4x5_debug > 0) {
@@ -883,9 +911,17 @@
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int status = 0;
+    int i, status = 0;
     s32 omr;
     
+    /* Allocate the RX buffers */
+    for (i=0; i<lp->rxRingSize; i++) {
+	if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
+	    de4x5_free_rx_buffs(dev);
+	    return -EAGAIN;
+	}
+    }
+
     /*
     ** Wake up the adapter
     */
@@ -893,14 +929,13 @@
 	outl(0, PCI_CFDA);
 	de4x5_ms_delay(10);
     }
-    
-    lp->state = OPEN;
-    
+
     /* 
     ** Re-initialize the DE4X5... 
     */
     status = de4x5_init(dev);
     
+    lp->state = OPEN;
     de4x5_dbg_open(dev);
     
     if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
@@ -937,7 +972,7 @@
 /*
 ** Initialize the DE4X5 operating conditions. NB: a chip problem with the
 ** DC21140 requires using perfect filtering mode for that chip. Since I can't
-** see why I'd want > 14 multicast addresses, I may change all chips to use
+** see why I'd want > 14 multicast addresses, I have changed all chips to use
 ** the perfect filtering mode. Keep the DMA burst length at 8: there seems
 ** to be data corruption problems if it is larger (UDP errors seen from a
 ** ttcp source).
@@ -956,7 +991,8 @@
     return 0;
 }
 
-static int de4x5_sw_reset(struct device *dev)
+static int
+de4x5_sw_reset(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -978,14 +1014,11 @@
     bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
     outl(bmr, DE4X5_BMR);
     
-    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn of promiscuous mode */
-    if (lp->chipset != DC21140) {
-	omr |= TR_96;
-	lp->setup_f = HASH_PERF;
-    } else {
-	omr |= OMR_SDP | OMR_SB | (!lp->phy[lp->active].id ? OMR_SF : 0);
-	lp->setup_f = PERFECT;
+    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
+    if (lp->chipset == DC21140) {
+	omr |= (OMR_SDP | OMR_SB);
     }
+    lp->setup_f = PERFECT;
     outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
     outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
     
@@ -1005,11 +1038,7 @@
     /* Build the setup frame depending on filtering mode */
     SetMulticastFilter(dev);
     
-    if (lp->chipset != DC21140) {
-	load_packet(dev, lp->setup_frame, HASH_F|TD_SET|SETUP_FRAME_LEN, NULL);
-    } else {
-	load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
-    }
+    load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL);
     outl(omr|OMR_ST, DE4X5_OMR);
     
     /* Poll for setup frame completion (adapter interrupts are disabled now) */
@@ -1041,15 +1070,14 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     int status = 0;
-    
+
     if (skb == NULL) {
 	dev_tint(dev);
 	return 0;
     }
 
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
-	de4x5_put_cache(dev, skb);               /* Queue the buffer locally */
-	return 0;                                
+	return -1;                                
     }
     
     /*
@@ -1063,14 +1091,14 @@
     sti();
     
     /* Transmit descriptor ring full or stale skb */
-    if (dev->tbusy || lp->skb[lp->tx_new]) {
+    if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
 	if (dev->interrupt) {
 	    de4x5_putb_cache(dev, skb);          /* Requeue the buffer */
 	} else {
 	    de4x5_put_cache(dev, skb);
 	}
 	if (de4x5_debug > 1) {
-	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->skb[lp->tx_new] ? "YES" : "NO"));
+	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%ld\n  lostMedia:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO"));
 	}
     } else if (skb->len > 0) {
 	/* If we already have stuff queued locally, use that first */
@@ -1079,7 +1107,7 @@
 	    skb = de4x5_get_cache(dev);
 	}
 
-	while (skb && !dev->tbusy && !lp->skb[lp->tx_new]) {
+	while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) {
 	    set_bit(0, (void*)&dev->tbusy);
 	    cli();
 	    if (TX_BUFFS_AVAIL) {           /* Fill in a Tx ring entry */
@@ -1097,7 +1125,7 @@
 	    }
 	    sti();
 	}
-	if (skb && (dev->tbusy || lp->skb[lp->tx_new])) {
+	if (skb && (dev->tbusy || lp->tx_skb[lp->tx_new])) {
 	    de4x5_putb_cache(dev, skb);
 	}
     }
@@ -1121,7 +1149,7 @@
 {
     struct device *dev = (struct device *)dev_id;
     struct de4x5_private *lp;
-    s32 imr, omr, sts;
+    s32 imr, omr, sts, limit;
     u_long iobase;
     
     if (dev == NULL) {
@@ -1137,7 +1165,7 @@
     DISABLE_IRQs;                        /* Ensure non re-entrancy */
     dev->interrupt = MASK_INTERRUPTS;
 	
-    for (;;) {
+    for (limit=0; limit<8; limit++) {
 	sts = inl(DE4X5_STS);            /* Read IRQ status */
 	outl(sts, DE4X5_STS);            /* Reset the board interrupts */
 	    
@@ -1154,6 +1182,10 @@
 	    lp->irq_mask &= ~IMR_LFM;
 	}
 	    
+	if (sts & STS_UNF) {             /* Transmit underrun */
+	    de4x5_txur(dev);
+	}
+	    
 	if (sts & STS_SE) {              /* Bus Error */
 	    STOP_DE4X5;
 	    printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
@@ -1204,24 +1236,15 @@
 		struct sk_buff *skb;
 		short pkt_len = (short)(lp->rx_ring[entry].status >> 16) - 4;
 		
-		if ((skb = dev_alloc_skb(pkt_len+2)) == NULL) {
+		if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
 		    printk("%s: Insufficient memory; nuking packet.\n", 
 			                                            dev->name);
 		    lp->stats.rx_dropped++;   /* Really, deferred. */
 		    break;
 		}
+		de4x5_dbg_rx(skb, pkt_len);
 
-		skb->dev = dev;
-		skb_reserve(skb,2);	      /* Align */
-		if (entry < lp->rx_old) {     /* Wrapped buffer */
-		    short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-		    memcpy(skb_put(skb,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), len);
-		    memcpy(skb_put(skb,pkt_len-len), bus_to_virt(lp->rx_ring[0].buf), pkt_len - len);
-		} else {                      /* Linear buffer */
-		    memcpy(skb_put(skb,pkt_len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), pkt_len);
-		}
-		    
-		/* Push up the protocol stack */
+	/* Push up the protocol stack */
 		skb->protocol=eth_type_trans(skb,dev);
 		netif_rx(skb);
 		    
@@ -1284,29 +1307,32 @@
 	status = lp->tx_ring[entry].status;
 	if (status < 0) {                     /* Buffer not sent yet */
 	    break;
-	} else if (status & TD_ES) {          /* An error happened */
-	    lp->stats.tx_errors++; 
-	    if (status & TD_NC)  lp->stats.tx_carrier_errors++;
-	    if (status & TD_LC)  lp->stats.tx_window_errors++;
-	    if (status & TD_UF)  lp->stats.tx_fifo_errors++;
-	    if (status & TD_LC)  lp->stats.collisions++;
-	    if (status & TD_EC)  lp->pktStats.excessive_collisions++;
-	    if (status & TD_DE)  lp->stats.tx_aborted_errors++;
-	    
-	    if ((status != 0x7fffffff) &&     /* Not setup frame */
-		(status & (TD_LO | TD_NC | TD_EC | TD_LF))) {
-		lp->lostMedia++;
-	    } else {
-		outl(POLL_DEMAND, DE4X5_TPD); /* Restart a stalled TX */
+	} else if (status != 0x7fffffff) {    /* Not setup frame */
+	    if (status & TD_ES) {             /* An error happened */
+		lp->stats.tx_errors++; 
+		if (status & TD_NC) lp->stats.tx_carrier_errors++;
+		if (status & TD_LC) lp->stats.tx_window_errors++;
+		if (status & TD_UF) lp->stats.tx_fifo_errors++;
+		if (status & TD_LC) lp->stats.collisions++;
+		if (status & TD_EC) lp->pktStats.excessive_collisions++;
+		if (status & TD_DE) lp->stats.tx_aborted_errors++;
+	    
+		if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
+		    lp->lostMedia++;
+		}
+		if (TX_PKT_PENDING) {
+		    outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
+		}
+	    } else {                      /* Packet sent */
+		lp->stats.tx_packets++;
+		lp->lostMedia = 0;        /* Remove transient problem */
+		lp->linkOK++;
+	    }
+	    /* Free the buffer. */
+	    if (lp->tx_skb[entry] != NULL) {
+		dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE);
+		lp->tx_skb[entry] = NULL;
 	    }
-	} else {                              /* Packet sent */
-	    lp->stats.tx_packets++;
-	    lp->lostMedia = 0;                /* Remove transient problem */
-	}
-	/* Free the buffer if it's not a setup frame. */
-	if (lp->skb[entry] != NULL) {
-	    dev_kfree_skb(lp->skb[entry], FREE_WRITE);
-	    lp->skb[entry] = NULL;
 	}
 	
 	/* Update all the pointers */
@@ -1343,6 +1369,29 @@
 }
 
 static int
+de4x5_txur(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+    int omr;
+
+    omr = inl(DE4X5_OMR);
+    if (!(omr & OMR_SF)) {
+	omr &= ~(OMR_ST|OMR_SR);
+	outl(omr, DE4X5_OMR);
+	while (inl(DE4X5_STS) & STS_TS);
+	if ((omr & OMR_TR) < OMR_TR) {
+	    omr += 0x4000;
+	} else {
+	    omr |= OMR_SF;
+	}
+	outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
+    }
+    
+    return 0;
+}
+
+static int
 de4x5_close(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
@@ -1362,14 +1411,15 @@
     ** We stop the DE4X5 here... mask interrupts and stop TX & RX
     */
     DISABLE_IRQs;
-    
     STOP_DE4X5;
     
-    /*
-    ** Free the associated irq
-    */
+    /* Free the associated irq */
     free_irq(dev->irq, dev);
     lp->state = CLOSED;
+
+    /* Free any socket buffers */
+    de4x5_free_rx_buffs(dev);
+    de4x5_free_tx_buffs(dev);
     
     MOD_DEC_USE_COUNT;
     
@@ -1393,14 +1443,15 @@
     return &lp->stats;
 }
 
-static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
+static void
+load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
     lp->tx_ring[lp->tx_new].buf = virt_to_bus(buf);
     lp->tx_ring[lp->tx_new].des1 &= TD_TER;
     lp->tx_ring[lp->tx_new].des1 |= flags;
-    lp->skb[lp->tx_new] = skb;
+    lp->tx_skb[lp->tx_new] = skb;
     barrier();
     lp->tx_ring[lp->tx_new].status = T_OWN;
     barrier();
@@ -1426,13 +1477,8 @@
 	    outl(omr, DE4X5_OMR);
 	} else { 
 	    SetMulticastFilter(dev);
-	    if (lp->setup_f == HASH_PERF) {
-		load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
-			    SETUP_FRAME_LEN, NULL);
-	    } else {
-		load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-			    SETUP_FRAME_LEN, NULL);
-	    }
+	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+			                                SETUP_FRAME_LEN, NULL);
 	    
 	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	    outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
@@ -1448,7 +1494,8 @@
 ** from a list of ethernet multicast addresses.
 ** Little endian crc one liner from Matt Thomas, DEC.
 */
-static void SetMulticastFilter(struct device *dev)
+static void
+SetMulticastFilter(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct dev_mc_list *dmi=dev->mc_list;
@@ -1508,7 +1555,8 @@
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void eisa_probe(struct device *dev, u_long ioaddr)
+static void
+eisa_probe(struct device *dev, u_long ioaddr)
 {
     int i, maxSlots, status;
     u_short vendor, device;
@@ -1575,7 +1623,8 @@
 #define PCI_DEVICE    (dev_num << 3)
 #define PCI_LAST_DEV  32
 
-static void pci_probe(struct device *dev, u_long ioaddr)
+static void
+pci_probe(struct device *dev, u_long ioaddr)
 {
     u_char irq;
     u_char pb, pbus, dev_num, dnum, dev_fn;
@@ -1583,7 +1632,7 @@
     u_int class = DE4X5_CLASS_CODE;
     u_int iobase;
     struct bus_type *lp = &bus;
-    
+
     if ((!ioaddr || !loading_module) && autoprobed) return;
     
     if (!pcibios_present()) return;          /* No PCI bus in this machine! */
@@ -1607,7 +1656,7 @@
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
 	    if (!(is_DC21040 || is_DC21041 || is_DC21140)) continue;
-	    
+
 	    /* Set the device number information */
 	    lp->device = dev_num;
 	    lp->bus_num = pb;
@@ -1626,14 +1675,13 @@
 	    /* Check if I/O accesses and Bus Mastering are enabled */
 	    pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
 	    if (!(status & PCI_COMMAND_IO)) continue;
-	    
 	    if (!(status & PCI_COMMAND_MASTER)) {
 		status |= PCI_COMMAND_MASTER;
 		pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
 		pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
 	    }
 	    if (!(status & PCI_COMMAND_MASTER)) continue;
-	    
+
 	    DevicePresent(DE4X5_APROM);
 	    if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
 		if ((dev = alloc_device(dev, iobase)) != NULL) {
@@ -1657,7 +1705,8 @@
 ** Allocate the device by pointing to the next available space in the
 ** device structure. Should one not be available, it is created.
 */
-static struct device *alloc_device(struct device *dev, u_long iobase)
+static struct device *
+alloc_device(struct device *dev, u_long iobase)
 {
     int addAutoProbe = 0;
     struct device *tmp = NULL, *ret;
@@ -1700,7 +1749,7 @@
 	    ** and initialize it (name, I/O address, next device (NULL) and
 	    ** initialisation probe routine).
 	    */
-	    dev->name = (char *)(dev + sizeof(struct device));
+	    dev->name = (char *)(dev + 1);
 	    if (num_eth > 9999) {
 		sprintf(dev->name,"eth????");/* New device name */
 	    } else {
@@ -1739,7 +1788,7 @@
 		    ** area and initialize it (name, I/O address, next device
 		    ** (NULL) and initialisation probe routine).
 		    */
-		    tmp->name = (char *)(tmp + sizeof(struct device));
+		    tmp->name = (char *)(tmp + 1);
 		    if (num_eth > 9999) {
 			sprintf(tmp->name,"eth????");
 		    } else {               /* New device name */
@@ -1765,7 +1814,8 @@
 ** [TP] or no recent receive activity) to check whether the user has been 
 ** sneaky and changed the port on us.
 */
-static int autoconf_media(struct device *dev)
+static int
+autoconf_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -1783,7 +1833,7 @@
     } else if (lp->chipset == DC21140) {
 	next_tick = dc21140m_autoconf(dev);
     }
-    if (lp->autosense == AUTO) enable_ast(dev, next_tick);
+    enable_ast(dev, next_tick);
     
     return (lp->media);
 }
@@ -1800,7 +1850,8 @@
 ** I may have to "age out" locally queued packets so that the higher layer
 ** timeouts don't effectively duplicate packets on the network.
 */
-static int dc21040_autoconf(struct device *dev)
+static int
+dc21040_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -1827,32 +1878,32 @@
 	break;
 	
       case TP:
-	dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
+	next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
 		                                         TP_SUSPECT, test_tp);
 	break;
 	
       case TP_SUSPECT:
-	de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
 	break;
 	
       case BNC:
       case AUI:
       case BNC_AUI:
-	dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
+	next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
 		                                  BNC_AUI_SUSPECT, ping_media);
 	break;
 	
       case BNC_AUI_SUSPECT:
-	de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
 	break;
 	
       case EXT_SIA:
-	dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
+	next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
 		                              NC, EXT_SIA_SUSPECT, ping_media);
 	break;
 	
       case EXT_SIA_SUSPECT:
-	de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
 	break;
 	
       case NC:
@@ -1862,7 +1913,10 @@
 	/* JAE: for Alpha, default to BNC/AUI, *not* TP */
 	reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
 #endif  /* i386 */
-	de4x5_dbg_media(dev);
+	if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
 	lp->media = INIT;
 	lp->tx_enable = NO;
 	break;
@@ -1953,7 +2007,8 @@
 ** any more packets to be queued to the hardware. Re-enable everything only
 ** when the media is found.
 */
-static int dc21041_autoconf(struct device *dev)
+static int
+dc21041_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2013,6 +2068,7 @@
 		    lp->media = TP;
 		    next_tick = dc21041_autoconf(dev);
 		} else {
+		    lp->local_state = 1;
 		    de4x5_init_connection(dev);
 		}
 	    }
@@ -2023,7 +2079,7 @@
 	break;
 	
       case ANS_SUSPECT:
-	de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
 	break;
 	
       case TP:
@@ -2046,6 +2102,7 @@
 		    }
 		    next_tick = dc21041_autoconf(dev);
 		} else {
+		    lp->local_state = 1;
 		    de4x5_init_connection(dev);
 		}
 	    }
@@ -2056,7 +2113,7 @@
 	break;
 	
       case TP_SUSPECT:
-	de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
 	break;
 	
       case AUI:
@@ -2067,7 +2124,7 @@
 	    }
 	    irqs = 0;
 	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x000e, 1000);
+	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000);
 	    if (sts < 0) {
 		next_tick = sts & ~TIMER_CB;
 	    } else {
@@ -2075,6 +2132,7 @@
 		    lp->media = BNC;
 		    next_tick = dc21041_autoconf(dev);
 		} else {
+		    lp->local_state = 1;
 		    de4x5_init_connection(dev);
 		}
 	    }
@@ -2085,7 +2143,7 @@
 	break;
 	
       case AUI_SUSPECT:
-	de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
 	break;
 	
       case BNC:
@@ -2097,7 +2155,7 @@
 	    }
 	    irqs = 0;
 	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x0006, 1000);
+	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000);
 	    if (sts < 0) {
 		next_tick = sts & ~TIMER_CB;
 	    } else {
@@ -2131,14 +2189,17 @@
 	break;
 	
       case BNC_SUSPECT:
-	de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
+	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
 	break;
 	
       case NC:
 	omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
 	outl(omr | OMR_FD, DE4X5_OMR);
 	reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
-	de4x5_dbg_media(dev);
+	if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
 	lp->media = INIT;
 	lp->tx_enable = NO;
 	break;
@@ -2147,10 +2208,16 @@
     return next_tick;
 }
 
-static int dc21140m_autoconf(struct device *dev)
+/*
+** Some autonegotiation chips are broken in that they do not return the
+** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement
+** register, except at the first power up negotiation.
+*/
+static int
+dc21140m_autoconf(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int ana, anlpa, cap, cr, sr, iobase = dev->base_addr;
+    int ana, anlpa, cap, cr, slnk, sr, iobase = dev->base_addr;
     int next_tick = DE4X5_AUTOSENSE_MS;
     u_long imr, omr;
     
@@ -2163,12 +2230,14 @@
 	    next_tick &= ~TIMER_CB;
 	} else {
 	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
+	    lp->tmp = MII_SR_ASSC;         /* Fake out the MII speed set */
 	    SET_10Mb;
 	    if (lp->autosense == _100Mb) {
 		lp->media = _100Mb;
 	    } else if (lp->autosense == _10Mb) {
 		lp->media = _10Mb;
-	    } else if ((lp->autosense == AUTO) && (sr=is_anc_capable(dev))) {
+	    } else if ((lp->autosense == AUTO) && 
+		                     ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
 		ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
 		ana &= (de4x5_full_duplex ? ~0 : ~MII_ANA_FDAM);
 		mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
@@ -2206,21 +2275,23 @@
 	    break;
 	    
 	  case 1:
-	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 3000)) < 0) {
+	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
 		next_tick = sr & ~TIMER_CB;
 	    } else {
 		lp->media = SPD_DET;
 		lp->local_state = 0;
 		if (sr) {                         /* Success! */
+		    lp->tmp = MII_SR_ASSC;
 		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
 		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		    if ((anlpa & MII_ANLPA_ACK) && !(anlpa & MII_ANLPA_RF) &&
-			(cap = anlpa & MII_ANLPA_TAF & ana)) {
+		    if (!(anlpa & MII_ANLPA_RF) && 
+			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
 			if (cap & MII_ANA_100M) {
 			    de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
 			    lp->media = _100Mb;
 			} else if (cap & MII_ANA_10M) {
 			    de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+
 			    lp->media = _10Mb;
 			}
 		    }
@@ -2232,17 +2303,23 @@
 	break;
 	
       case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
-	if (!lp->phy[lp->active].id) {
-	    outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
+        if (lp->timeout < 0) {
+	    lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS :
+		                                  (~inl(DE4X5_GEP) & GEP_LNP));
+	    SET_100Mb_PDET;
 	}
-	if (is_spd_100(dev) && is_100_up(dev)) {
-	    lp->media = _100Mb;
-	} else if (!is_spd_100(dev) && is_10_up(dev)) {
-	    lp->media = _10Mb;
+        if ((slnk = test_sym_link(dev, 6200)) < 0) {
+	    next_tick = slnk & ~TIMER_CB;
 	} else {
-	    lp->media = NC;
+	    if (is_spd_100(dev) && is_100_up(dev)) {
+		lp->media = _100Mb;
+	    } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) {
+		lp->media = _10Mb;
+	    } else {
+		lp->media = NC;
+	    }
+	    next_tick = dc21140m_autoconf(dev);
 	}
-	next_tick = dc21140m_autoconf(dev);
 	break;
 	
       case _100Mb:                               /* Set 100Mb/s */
@@ -2276,8 +2353,10 @@
 	break;
 	
       case NC:
-	SET_10Mb;
-	de4x5_dbg_media(dev);
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
 	lp->media = INIT;
 	lp->tx_enable = FALSE;
 	break;
@@ -2286,12 +2365,16 @@
     return next_tick;
 }
 
-static void de4x5_init_connection(struct device *dev)
+static void
+de4x5_init_connection(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
 
-    de4x5_dbg_media(dev);
+    if (lp->media != lp->c_media) {
+        de4x5_dbg_media(dev);
+	lp->c_media = lp->media;          /* Stop scrolling media messages */
+    }
     de4x5_restore_skbs(dev);
     cli();
     de4x5_rx(dev);
@@ -2304,7 +2387,8 @@
     return;
 }
 
-static int de4x5_reset_phy(struct device *dev)
+static int
+de4x5_reset_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2360,7 +2444,8 @@
     return sts;
 }
 
-static int test_tp(struct device *dev, s32 msec)
+static int
+test_tp(struct device *dev, s32 msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2381,11 +2466,37 @@
     return sisr;
 }
 
+static int
+test_sym_link(struct device *dev, int msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int iobase = dev->base_addr;
+    int gep = 0;
+    
+    if (lp->timeout < 0) {
+	lp->timeout = msec/100;
+    }
+    
+    if (lp->phy[lp->active].id) {
+	gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0);
+    } else {
+	gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP));
+    }
+    if (!(gep & GEP_SLNK) && --lp->timeout) {
+	gep = 100 | TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return gep;
+}
+
 /*
 **
 **
 */
-static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
+static int
+test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int test, iobase = dev->base_addr;
@@ -2395,7 +2506,7 @@
     }
     
     if (pol) pol = ~0;
-    reg = mii_rd(reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
+    reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
     test = (reg ^ pol) & mask;
     
     if (test && --lp->timeout) {
@@ -2407,7 +2518,8 @@
     return reg;
 }
 
-static int is_spd_100(struct device *dev)
+static int
+is_spd_100(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2424,7 +2536,8 @@
     return spd;
 }
 
-static int is_100_up(struct device *dev)
+static int
+is_100_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2438,7 +2551,8 @@
     }
 }
 
-static int is_10_up(struct device *dev)
+static int
+is_10_up(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2452,13 +2566,14 @@
     }
 }
 
-static int is_anc_capable(struct device *dev)
+static int
+is_anc_capable(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
     
     if (lp->phy[lp->active].id) {
-	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_ANC);
+	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
     } else {
 	return 0;
     }
@@ -2468,7 +2583,8 @@
 ** Send a packet onto the media and watch for send errors that indicate the
 ** media is bad or unconnected.
 */
-static int ping_media(struct device *dev, int msec)
+static int
+ping_media(struct device *dev, int msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2501,34 +2617,112 @@
 }
 
 /*
+** This function does 2 things: on Intels it kmalloc's another buffer to
+** replace the one about to be passed up. On Alpha's it kmallocs a buffer
+** into which the packet is copied.
+*/
+static struct sk_buff *
+de4x5_alloc_rx_buff(struct device *dev, int index, int len)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct sk_buff *p;
+
+#ifndef __alpha__
+    struct sk_buff *ret;
+    u_long i=0, tmp;
+
+    p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    tmp = virt_to_bus(p->data);
+    i = ((tmp + ALIGN) & ~ALIGN) - tmp;
+    skb_reserve(p, i);
+    lp->rx_ring[index].buf = tmp + i;
+
+    ret = lp->rx_skb[index];
+    lp->rx_skb[index] = p;
+    skb_put(ret, len);
+
+    return ret;
+
+#else
+    if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */
+
+    p = dev_alloc_skb(len + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    skb_reserve(p, 2);	                               /* Align */
+    if (index < lp->rx_old) {                          /* Wrapped buffer */
+	short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
+	memcpy(skb_put(p,tlen), bus_to_virt(lp->rx_ring[lp->rx_old].buf),tlen);
+	memcpy(skb_put(p,len-tlen), bus_to_virt(lp->rx_ring[0].buf), len-tlen);
+    } else {                                           /* Linear buffer */
+	memcpy(skb_put(p,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf),len);
+    }
+		    
+    return p;
+#endif
+}
+
+static void
+de4x5_free_rx_buffs(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->rxRingSize; i++) {
+	if (lp->rx_skb[i]) {
+	    dev_kfree_skb(lp->rx_skb[i], FREE_WRITE);
+	}
+	lp->rx_ring[i].status = 0;
+	lp->rx_skb[i] = (struct sk_buff *)1;    /* Dummy entry */
+    }
+
+    return;
+}
+
+static void
+de4x5_free_tx_buffs(struct device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->txRingSize; i++) {
+	if (lp->tx_skb[i]) {
+	    dev_kfree_skb(lp->tx_skb[i], FREE_WRITE);
+	    lp->tx_skb[i] = NULL;
+	}
+	lp->tx_ring[i].status = 0;
+    }
+
+    /* Unload the locally queued packets */
+    while (lp->cache.skb) {
+	dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE);
+    }
+
+    return;
+}
+
+/*
 ** When a user pulls a connection, the DECchip can end up in a
 ** 'running - waiting for end of transmission' state. This means that we
 ** have to perform a chip soft reset to ensure that we can synchronize
 ** the hardware and software and make any media probes using a loopback
 ** packet meaningful.
 */
-static void de4x5_save_skbs(struct device *dev)
+static void
+de4x5_save_skbs(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    int i;
     s32 omr;
 
     if (!lp->cache.save_cnt) {
 	STOP_DE4X5;
 	de4x5_tx(dev);                          /* Flush any sent skb's */
-	for (i=lp->tx_new; i!=lp->tx_old; i--) {
-	    if (lp->skb[i]) {
-		de4x5_putb_cache(dev, lp->skb[i]);
-		lp->skb[i] = NULL;
-	    }
-	    if (i==0) i=lp->txRingSize;
-	}
-        if (lp->skb[i]) {
-	    de4x5_putb_cache(dev, lp->skb[i]);
-	    lp->skb[i] = NULL;
-	}
-
+	de4x5_free_tx_buffs(dev);
 	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
 	de4x5_sw_reset(dev);
 	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
@@ -2540,12 +2734,11 @@
     return;
 }
 
-static void de4x5_restore_skbs(struct device *dev)
+static void
+de4x5_restore_skbs(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
-    struct sk_buff *skb;
-    int i;
     s32 omr;
 
     if (lp->cache.save_cnt) {
@@ -2553,16 +2746,7 @@
 	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
 	de4x5_sw_reset(dev);
 	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
-	dev->tbusy = 1;
-
-	for (i=0; TX_BUFFS_AVAIL && lp->cache.skb; i++) {
-	    skb = de4x5_get_cache(dev);
-	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
-	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-	}
-	if (TX_BUFFS_AVAIL) {
-	    dev->tbusy = 0;
-	}
+	dev->tbusy = 0;
 	lp->cache.save_cnt--;
 	START_DE4X5;
     }
@@ -2570,7 +2754,8 @@
     return;
 }
 
-static void de4x5_cache_state(struct device *dev, int flag)
+static void
+de4x5_cache_state(struct device *dev, int flag)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2609,7 +2794,8 @@
     return;
 }
 
-static void de4x5_put_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_put_cache(struct device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p;
@@ -2625,7 +2811,8 @@
     return;
 }
 
-static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
+static void
+de4x5_putb_cache(struct device *dev, struct sk_buff *skb)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p = lp->cache.skb;
@@ -2636,7 +2823,8 @@
     return;
 }
 
-static struct sk_buff *de4x5_get_cache(struct device *dev)
+static struct sk_buff *
+de4x5_get_cache(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p = lp->cache.skb;
@@ -2653,7 +2841,8 @@
 ** Check the Auto Negotiation State. Return OK when a link pass interrupt
 ** is received and the auto-negotiation status is NWAY OK.
 */
-static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
+static int
+test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2680,7 +2869,8 @@
     return sts;
 }
 
-static void de4x5_setup_intr(struct device *dev)
+static void
+de4x5_setup_intr(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2700,7 +2890,8 @@
 /*
 **
 */
-static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
+static void
+reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     u_long iobase = dev->base_addr;
@@ -2716,7 +2907,8 @@
 /*
 ** Create a loopback ethernet packet with an invalid CRC
 */
-static void create_packet(struct device *dev, char *frame, int len)
+static void
+create_packet(struct device *dev, char *frame, int len)
 {
     int i;
     char *buf = frame;
@@ -2737,7 +2929,8 @@
 /*
 ** Known delay in microseconds
 */
-static void de4x5_us_delay(u32 usec)
+static void
+de4x5_us_delay(u32 usec)
 {
     udelay(usec);
     
@@ -2747,7 +2940,8 @@
 /*
 ** Known delay in milliseconds, in millisecond steps.
 */
-static void de4x5_ms_delay(u32 msec)
+static void
+de4x5_ms_delay(u32 msec)
 {
     u_int i;
     
@@ -2762,7 +2956,8 @@
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-static int EISA_signature(char *name, s32 eisa_id)
+static int
+EISA_signature(char *name, s32 eisa_id)
 {
     c_char *signatures[] = DE4X5_SIGNATURE;
     char ManCode[DE4X5_STRLEN];
@@ -2796,7 +2991,8 @@
 /*
 ** Look for a particular board name in the PCI configuration space
 */
-static int PCI_signature(char *name, struct bus_type *lp)
+static int
+PCI_signature(char *name, struct bus_type *lp)
 {
     c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
     int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
@@ -2833,7 +3029,8 @@
 ** Set up the Ethernet PROM counter to the start of the Ethernet address on
 ** the DC21040, else  read the SROM for the other chips.
 */
-static void DevicePresent(u_long aprom_addr)
+static void
+DevicePresent(u_long aprom_addr)
 {
     int i;
     struct bus_type *lp = &bus;
@@ -2851,7 +3048,8 @@
     return;
 }
 
-static int get_hw_addr(struct device *dev)
+static int
+get_hw_addr(struct device *dev)
 {
     u_long iobase = dev->base_addr;
     int broken, i, k, tmp, status = 0;
@@ -2902,7 +3100,7 @@
 	chksum |= (u_short) (inb(EISA_APROM) << 8);
 	if ((k != chksum) && (dec_only)) status = -1;
     }
-    
+
     return status;
 }
 
@@ -2910,7 +3108,8 @@
 ** Test for enet addresses in the first 32 bytes. The built-in strncmp
 ** didn't seem to work here...?
 */
-static int de4x5_bad_srom(struct bus_type *lp)
+static int
+de4x5_bad_srom(struct bus_type *lp)
 {
     int i, status = 0;
 
@@ -2925,7 +3124,8 @@
     return status;
 }
 
-static int de4x5_strncmp(char *a, char *b, int n)
+static int
+de4x5_strncmp(char *a, char *b, int n)
 {
     int ret=0;
 
@@ -2939,7 +3139,8 @@
 /*
 ** SROM Read
 */
-static short srom_rd(u_long addr, u_char offset)
+static short
+srom_rd(u_long addr, u_char offset)
 {
     sendto_srom(SROM_RD | SROM_SR, addr);
     
@@ -2950,7 +3151,8 @@
     return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
 }
 
-static void srom_latch(u_int command, u_long addr)
+static void
+srom_latch(u_int command, u_long addr)
 {
     sendto_srom(command, addr);
     sendto_srom(command | DT_CLK, addr);
@@ -2959,7 +3161,8 @@
     return;
 }
 
-static void srom_command(u_int command, u_long addr)
+static void
+srom_command(u_int command, u_long addr)
 {
     srom_latch(command, addr);
     srom_latch(command, addr);
@@ -2968,7 +3171,8 @@
     return;
 }
 
-static void srom_address(u_int command, u_long addr, u_char offset)
+static void
+srom_address(u_int command, u_long addr, u_char offset)
 {
     int i;
     char a;
@@ -2987,7 +3191,8 @@
     return;
 }
 
-static short srom_data(u_int command, u_long addr)
+static short
+srom_data(u_int command, u_long addr)
 {
     int i;
     short word = 0;
@@ -3007,7 +3212,8 @@
 }
 
 /*
-static void srom_busy(u_int command, u_long addr)
+static void
+srom_busy(u_int command, u_long addr)
 {
    sendto_srom((command & 0x0000ff00) | DT_CS, addr);
    
@@ -3021,7 +3227,8 @@
 }
 */
 
-static void sendto_srom(u_int command, u_long addr)
+static void
+sendto_srom(u_int command, u_long addr)
 {
     outl(command, addr);
     udelay(1);
@@ -3029,7 +3236,8 @@
     return;
 }
 
-static int getfrom_srom(u_long addr)
+static int
+getfrom_srom(u_long addr)
 {
     s32 tmp;
     
@@ -3043,7 +3251,8 @@
 ** MII Read/Write
 */
 
-static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
+static int
+mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
 {
     mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
     mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
@@ -3055,7 +3264,8 @@
     return mii_rdata(ioaddr);              /* Read data                      */
 }
 
-static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
+static void
+mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
 {
     mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
     mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
@@ -3069,7 +3279,8 @@
     return;
 }
 
-static int mii_rdata(u_long ioaddr)
+static int
+mii_rdata(u_long ioaddr)
 {
     int i;
     s32 tmp = 0;
@@ -3082,7 +3293,8 @@
     return tmp;
 }
 
-static void mii_wdata(int data, int len, u_long ioaddr)
+static void
+mii_wdata(int data, int len, u_long ioaddr)
 {
     int i;
     
@@ -3094,7 +3306,8 @@
     return;
 }
 
-static void mii_address(u_char addr, u_long ioaddr)
+static void
+mii_address(u_char addr, u_long ioaddr)
 {
     int i;
     
@@ -3107,11 +3320,12 @@
     return;
 }
 
-static void mii_ta(u_long rw, u_long ioaddr)
+static void
+mii_ta(u_long rw, u_long ioaddr)
 {
     if (rw == MII_STWR) {
 	sendto_mii(MII_MWR | MII_WR, 1, ioaddr);  
-	getfrom_mii(MII_MRD | MII_RD, ioaddr);
+	sendto_mii(MII_MWR | MII_WR, 0, ioaddr);  
     } else {
 	getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
     }
@@ -3119,7 +3333,8 @@
     return;
 }
 
-static int mii_swap(int data, int len)
+static int
+mii_swap(int data, int len)
 {
     int i, tmp = 0;
     
@@ -3132,7 +3347,8 @@
     return tmp;
 }
 
-static void sendto_mii(u32 command, int data, u_long ioaddr)
+static void
+sendto_mii(u32 command, int data, u_long ioaddr)
 {
     u32 j;
     
@@ -3145,7 +3361,8 @@
     return;
 }
 
-static int getfrom_mii(u32 command, u_long ioaddr)
+static int
+getfrom_mii(u32 command, u_long ioaddr)
 {
     outl(command, ioaddr);
     udelay(1);
@@ -3159,7 +3376,8 @@
 ** Here's 3 ways to calculate the OUI from the ID registers. One's a brain
 ** dead approach, 2 aren't (clue: mine isn't!).
 */
-static int mii_get_oui(u_char phyaddr, u_long ioaddr)
+static int
+mii_get_oui(u_char phyaddr, u_long ioaddr)
 {
 /*
     union {
@@ -3202,7 +3420,8 @@
     return r2;                                  /* (I did it) My way */
 }
 
-static int mii_get_phy(struct device *dev)
+static int
+mii_get_phy(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3246,7 +3465,8 @@
     return lp->mii_cnt;
 }
 
-static char *build_setup_frame(struct device *dev, int mode)
+static char *
+build_setup_frame(struct device *dev, int mode)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
@@ -3277,14 +3497,16 @@
     return pa;                     /* Points to the next entry */
 }
 
-static void enable_ast(struct device *dev, u32 time_out)
+static void
+enable_ast(struct device *dev, u32 time_out)
 {
     timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
     
     return;
 }
 
-static void disable_ast(struct device *dev)
+static void
+disable_ast(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
@@ -3293,7 +3515,8 @@
     return;
 }
 
-static long de4x5_switch_to_mii(struct device *dev)
+static long
+de4x5_switch_to_mii(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3319,7 +3542,8 @@
     return omr;
 }
 
-static long de4x5_switch_to_srl(struct device *dev)
+static long
+de4x5_switch_to_srl(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3327,7 +3551,6 @@
     
     /* Deassert the OMR_PS bit in CSR6 */
     omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
-    outl(omr | OMR_TTM, DE4X5_OMR);
     outl(omr, DE4X5_OMR);
     
     /* Soft Reset */
@@ -3345,7 +3568,8 @@
     return omr;
 }
 
-static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
+static void
+timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int dt;
@@ -3366,7 +3590,8 @@
     return;
 }
 
-static void de4x5_dbg_open(struct device *dev)
+static void
+de4x5_dbg_open(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int i;
@@ -3416,7 +3641,8 @@
     return;
 }
 
-static void de4x5_dbg_mii(struct device *dev, int k)
+static void
+de4x5_dbg_mii(struct device *dev, int k)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     int iobase = dev->base_addr;
@@ -3442,7 +3668,8 @@
     return;
 }
 
-static void de4x5_dbg_media(struct device *dev)
+static void
+de4x5_dbg_media(struct device *dev)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     
@@ -3473,7 +3700,8 @@
     return;
 }
 
-static void de4x5_dbg_srom(struct de4x5_srom *p)
+static void
+de4x5_dbg_srom(struct de4x5_srom *p)
 {
     int i;
 
@@ -3496,11 +3724,48 @@
     return;
 }
 
+static void
+de4x5_dbg_rx(struct sk_buff *skb, int len)
+{
+    int i, j;
+
+    if (de4x5_debug > 2) {
+	printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
+	       (u_char)skb->data[0],
+	       (u_char)skb->data[1],
+	       (u_char)skb->data[2],
+	       (u_char)skb->data[3],
+	       (u_char)skb->data[4],
+	       (u_char)skb->data[5],
+	       (u_char)skb->data[6],
+	       (u_char)skb->data[7],
+	       (u_char)skb->data[8],
+	       (u_char)skb->data[9],
+	       (u_char)skb->data[10],
+	       (u_char)skb->data[11],
+	       (u_char)skb->data[12],
+	       (u_char)skb->data[13],
+	       len);
+	if (de4x5_debug > 3) {
+	    for (j=0; len>0;j+=16, len-=16) {
+		printk("    %03x: ",j);
+		for (i=0; i<16 && i<len; i++) {
+		    printk("%02x ",(u_char)skb->data[i+j]);
+		}
+		printk("\n");
+	    }
+	}
+    }
+
+    return;
+}
+
 /*
 ** Perform IOCTL call functions here. Some are privileged operations and the
 ** effective uid is checked in those cases.
 */
-static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int
+de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
@@ -3540,13 +3805,8 @@
 	build_setup_frame(dev, PHYS_ADDR_ONLY);
 	/* Set up the descriptor and give ownership to the card */
 	while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
-	if (lp->setup_f == HASH_PERF) {
-	    load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | 
-			SETUP_FRAME_LEN, NULL);
-	} else {
-	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-			SETUP_FRAME_LEN, NULL);
-	}
+	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+		                                        SETUP_FRAME_LEN, NULL);
 	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
 	outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
 	dev->tbusy = 0;                              /* Unlock the TX ring */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this