Subject: Re: Re: Hi, this is my patch for broadcom sb1250-mac.c

From: "Zhang Haitao" <[email-masked]>
Date: Fri, 30 May 2003 2:43:35 +0800

Hi all
i've corrected some bugs in my last driver,
now the driver work properly both under copper mode and fiber mode. 
so this time i resend it in a more clear style :-)
and hope this time you all will glad to review it.
(you can turn off/on the NAPI options to do some contrast test 
for both original mode and NAPI mode, even the parameters for original mode 
have been modified for better performance)

and dear Greg Lindahl:
you just pointed out the function skb_over_panic(), but there are many reasons will lead that fault!
	  so i've tried to modified sbmac_mii_poll() and removed manually called 
netif_carrier_on() there, i think call netif_carrier_on() from here is the main reason lead my kernel
crashed. 
	as you know we use sbmac_mii_poll to set the link parameters but call netif_carrier_on() and netif_carrier_off() in sbmac_mii_timer(), so if i manualy call netif_carrier_on() to set LINK_STAT_START,
it will lead link status wrong! eg. sometimes that DMA channel have been stopped by other reasons, but driver can not find out that and skb can not be released in time, so an skb_over_panic() happen here.
so is that right?
waiting for your reply soon!

-------------------------
--- ./sb1250-broadcom.c	2003-05-30 00:48:36.000000000 +0800
+++ ./sb1250-mac.debug.c	2003-05-30 00:48:36.000000000 +0800
@@ -44,8 +44,8 @@
 static int full_duplex[MAX_UNITS] = {-1, -1, -1};
 #endif
 
-static int int_pktcnt = 0;
-static int int_timeout = 0;
+static int int_pktcnt = 32;
+static int int_timeout = 1024;
 
 /* Operational parameters that usually are not changed. */
 
@@ -91,7 +91,8 @@
 static char version1[] __devinitdata =
 "sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg ([email-masked])\n";
 #endif
-
+#define CONFIG_SB1250_NAPI 
+#define NAPI_LOP_MAX 10

 MODULE_AUTHOR("Mitch Lichtenberg ([email-masked])");
@@ -154,8 +155,8 @@
 
 #define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x))
 
-#define SBMAC_MAX_TXDESCR	32
-#define SBMAC_MAX_RXDESCR	32
+#define SBMAC_MAX_TXDESCR	128
+#define SBMAC_MAX_RXDESCR	128
 
 #define ETHER_ALIGN	2
 #define ETHER_ADDR_LEN	6
@@ -190,8 +191,8 @@
 	int		 sbdma_txdir;       /* direction (1=transmit) */
 	int		 sbdma_maxdescr;	/* total # of descriptors in ring */
 #ifdef CONFIG_SBMAC_COALESCE
-        int              sbdma_int_pktcnt;  /* # descriptors rx/tx before interrupt*/
-        int              sbdma_int_timeout; /* # usec rx/tx interrupt */
+        int              sbdma_int_pktcnt;  /* # descriptors rx before interrupt*/
+        int              sbdma_int_timeout; /* # usec rx interrupt */
 #endif
 
 	sbmac_port_t     sbdma_config0;	/* DMA config register 0 */
@@ -262,11 +263,13 @@
 	
 	u_char           sbm_hwaddr[ETHER_ADDR_LEN];
 	
-	sbmacdma_t       sbm_txdma;		/* for now, only use channel 0 */
+	sbmacdma_t       sbm_txdma;		/* for now, use channel 0 */
 	sbmacdma_t       sbm_rxdma;
 	int              rx_hw_checksum;
 	int 		 sbe_idx;
 	
+	int              sbm_fibermode;
+	int 		 sbm_phy_oldsignaldetect;
 };

@@ -288,7 +291,6 @@
 static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
 static void sbdma_emptyring(sbmacdma_t *d);
 static void sbdma_fillring(sbmacdma_t *d);
-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
 static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
 static int sbmac_initctx(struct sbmac_softc *s);
 static void sbmac_channel_start(struct sbmac_softc *s);
@@ -299,6 +301,13 @@
 static uint64_t sbmac_addr2reg(unsigned char *ptr);
 static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs);
 static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
+#ifdef CONFIG_SB1250_NAPI
+static int sbmac_poll(struct net_device *dev_instance, int *budget);
+static inline void sbmac_irq_disable(struct sbmac_softc *s);
+static inline void sbmac_irq_enable(struct sbmac_softc *s);
+#else
+static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+#endif
 static void sbmac_setmulti(struct sbmac_softc *sc);
 static int sbmac_init(struct net_device *dev);
 static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
@@ -448,6 +457,15 @@
 #define PHYSUP_LINKUP	 0x04
 #define PHYSUP_FDX       0x02
 
+/* Added for Fiber mode detection 
+just read Signal Detect alternation */
+
+#define MII_AUXCTL      0x18   /* Auxiliary Control Register */
+
+#define MII_SGMIISR     0x0C    /* SGMII/100-X Status Register */
+
+#define SGMIISR_FIBERSDS	0x2000
+
 #define	MII_BMCR	0x00 	/* Basic mode control register (rw) */
 #define	MII_BMSR	0x01	/* Basic mode status register (ro) */
 #define MII_K1STSR	0x0A	/* 1K Status Register (ro) */
@@ -459,6 +477,17 @@
 #define ENABLE 		1
 #define DISABLE		0
 
+#ifdef CONFIG_SB1250_NAPI
+static inline void sbmac_irq_disable(struct sbmac_softc *s){
+         SBMAC_WRITECSR(s->sbm_imr, 
+		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0));
+}
+static inline void sbmac_irq_enable(struct sbmac_softc *s){
+	SBMAC_WRITECSR(s->sbm_imr,
+		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0));
+}
+#endif
 /**********************************************************************
  *  SBMAC_MII_SYNC(s)
  *  
@@ -759,7 +788,7 @@
 	
 #ifdef CONFIG_SBMAC_COALESCE
         /*
-         * Setup Rx/Tx DMA coalescing defaults
+         * Setup RxTx DMA coalescing defaults
          */
 
 		if ( int_pktcnt ) {
@@ -944,7 +973,7 @@
 		sb_new = sb;
 		/* 
 		 * nothing special to reinit buffer, it's already aligned
-		 * and sb->data already points to a good place.
+		 * and sb->tail already points to a good place.
 		 */
 	}
 	
@@ -956,11 +985,11 @@
         /*
          * Do not interrupt per DMA transfer.
          */
-        dsc->dscr_a = KVTOPHYS(sb_new->data) |
+        dsc->dscr_a = KVTOPHYS(sb_new->tail) |
                 V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
                 0;
 #else
-	dsc->dscr_a = KVTOPHYS(sb_new->data) |
+	dsc->dscr_a = KVTOPHYS(sb_new->tail) |
 		V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
 		M_DMA_DSCRA_INTERRUPT;
 #endif
@@ -1045,16 +1074,17 @@
 	
 	phys = KVTOPHYS(sb->data);
 	ncb = NUMCACHEBLKS(length+(phys & (CACHELINESIZE-1)));
-	
+#ifdef CONFIG_SBMAC_COALESCE
+	/* do not interript per DMA transfer*/
 	dsc->dscr_a = phys | 
 		V_DMA_DSCRA_A_SIZE(ncb) |
-#ifdef CONFIG_SBMAC_COALESCE
-                0 |
+		M_DMA_ETHTX_SOP;
 #else
+	dsc->dscr_a = phys | 
+		V_DMA_DSCRA_A_SIZE(ncb) |
 		M_DMA_DSCRA_INTERRUPT |
-#endif
 		M_DMA_ETHTX_SOP;
-	
+#endif	
 	/* transmitting: set outbound options and length */
 
 	dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) |
@@ -1133,7 +1163,7 @@
 	}
 }
 
-
+#ifndef CONFIG_SB1250_NAPI
 /**********************************************************************
  *  SBDMA_RX_PROCESS(sc,d)
  *  
@@ -1181,6 +1211,14 @@
 		 */
 		
 		if (curidx == hwidx) break;
+		/*{
+			int i;
+			for (i=0;;i++) {
+			if ((dsc->dscr_a & M_DMA_ETHRX_SOP) != 0) 
+				break;
+			if (i >= NAPI_LOP_MAX) goto ret;
+			}
+		}*/
 		
 		/*
 		 * Otherwise, get the packet's sk_buff ptr back
@@ -1236,7 +1274,6 @@
 				 sb->ip_summed = CHECKSUM_UNNECESSARY;
 			       }
 			    } /*rx_hw_checksum */
-
 			    netif_rx(sb);
 			    }
 		}
@@ -1258,7 +1295,7 @@
 		
 	}
 }
-
+#endif

 /**********************************************************************
@@ -1352,6 +1389,7 @@
 		 */
 		
 		dev_kfree_skb_irq(sb);
+		//__kfree_skb(sb); //try free fast
 		
 		/* 
 		 * .. and advance to the next buffer.
@@ -1393,6 +1431,7 @@
 static int sbmac_initctx(struct sbmac_softc *s)
 {
 	
+	int auxctl;	
 	/* 
 	 * figure out the addresses of some ports 
 	 */
@@ -1414,6 +1453,8 @@
 	s->sbm_phy_oldk1stsr = 0;
 	s->sbm_phy_oldlinkstat = 0;
 	
+	s->sbm_phy_oldsignaldetect =0;
+	
 	/*
 	 * Initialize the DMA channels.  Right now, only one per MAC is used
 	 * Note: Only do this _once_, as it allocates memory from the kernel!
@@ -1421,7 +1462,6 @@
 	
 	sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR);
 	sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR);
-	
 	/*
 	 * initial state is OFF
 	 */
@@ -1436,6 +1476,17 @@
 	s->sbm_duplex = sbmac_duplex_half;
 	s->sbm_fc = sbmac_fc_disabled;
 	
+	/*
+	 * Fiber/Copper Mode AutoDetection
+	 */
+	
+	sbmac_mii_write(s,1,MII_AUXCTL,0x2007);
+	auxctl = sbmac_mii_read(s,1,MII_AUXCTL);
+	if(auxctl)
+		{
+			s->sbm_fibermode=1;
+		}
+	else s->sbm_fibermode=0;
 	return 0;
 }
 
@@ -1632,6 +1683,8 @@
 	SBMAC_WRITECSR(s->sbm_macenable,
 		       M_MAC_RXDMA_EN0 |
 		       M_MAC_TXDMA_EN0 |
+		       M_MAC_RXDMA_EN1 |
+		       M_MAC_TXDMA_EN1 |
 		       M_MAC_RX_ENABLE |
 		       M_MAC_TX_ENABLE);
 	
@@ -1645,6 +1698,7 @@
 	SBMAC_WRITECSR(s->sbm_imr,
 		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
 		       ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0));
+		       
 #else
 	/*
 	 * Accept any kind of interrupt on TX and RX DMA channel 0
@@ -1967,7 +2021,7 @@
 			V_MAC_IFG_TX_1000 |
 			V_MAC_IFG_THRSH_1000 |
 			V_MAC_SLOT_SIZE_1000;
-		cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
+cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
 		break;
 		
 	case sbmac_speed_auto:		/* XXX not implemented */
@@ -2102,6 +2156,7 @@
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
 	struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv);
+
 	uint64_t isr;
 	
 	for (;;) {
@@ -2124,7 +2179,7 @@
 		}
 		
 		/*
-		 * Receives on channel 0
+		 * Receives on channel 0,1
 		 */
 
 		/*
@@ -2145,40 +2200,43 @@

 		if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
-			sbdma_rx_process(sc,&(sc->sbm_rxdma));
+#ifdef CONFIG_SB1250_NAPI
+		if (netif_rx_schedule_prep(dev)) {
+			sbmac_irq_disable(sc);
+			__netif_rx_schedule(dev);
 		}
+#else
+		sbdma_rx_process(sc,&(sc->sbm_rxdma));
+#endif	
 	}
-	
+}
 }

 /**********************************************************************
- *  SBMAC_START_TX(skb,dev)
- *  
- *  Start output on the specified interface.  Basically, we 
- *  queue as many buffers as we can until the ring fills up, or
- *  we run off the end of the queue, whichever comes first.
- *  
- *  Input parameters: 
- *  	   
- *  	   
- *  Return value:
- *  	   nothing
- ********************************************************************* */
+*  SBMAC_START_TX(skb,dev)
+*  
+*  Start output on the specified interface.  Basically, we 
+*  queue as many buffers as we can until the ring fills up, or
+*  we run off the end of the queue, whichever comes first.
+*  
+*  Input parameters: 
+*  	   
+*  	   
+*  Return value:
+*  	   nothing
+********************************************************************* */
 static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
-	
-	/* lock eth irq */
-	spin_lock_irq (&sc->sbm_lock);
-	
-	/*
+struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+spin_lock_irq (&sc->sbm_lock);
+/*
 	 * Put the buffer on the transmit ring.  If we 
 	 * don't have room, stop the queue.
 	 */
 	
-	if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
-		/* XXX save skb that we could not send */
+if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
+		/* XXX save skb that we could not send, then test 1 channel */
 		netif_stop_queue(dev);
 		spin_unlock_irq(&sc->sbm_lock);
 
@@ -2186,12 +2244,142 @@
 	}
 	
 	dev->trans_start = jiffies;
-	
 	spin_unlock_irq (&sc->sbm_lock);
 	
 	return 0;
 }
+#ifdef CONFIG_SB1250_NAPI
+//#define NAPI_POL_MAX 100
+static int sbmac_poll(struct net_device *dev_instance, int *budget) {
+	struct net_device *dev = (struct net_device *) dev_instance;
+    struct sbmac_softc *sc = (struct sbmac_softc *) (dev_instance->priv);
+    sbmacdma_t *d = &(sc->sbm_rxdma);
+    int rx_work_limit = *budget;
+	unsigned long flags;
+	long int receive=0;
+	int curidx;
+	int hwidx;
+	
+	sbdmadscr_t *dsc;
+	struct sk_buff *sb;
+	int len;
+	
+    if(rx_work_limit > dev->quota)
+          rx_work_limit = dev->quota;
+
+    for (;;) {
+		/* 
+		 * figure out where we are (as an index) and where
+		 * the hardware is (also as an index)
+		 *
+		 * This could be done faster if (for example) the 
+		 * descriptor table was page-aligned and contiguous in
+		 * both virtual and physical memory -- you could then
+		 * just compare the low-order bits of the virtual address
+		 * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
+		 */
+		if(--rx_work_limit < 0) goto not_done;
+		curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+		hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+				d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+		
+		/*
+		 * If they're the same, that means we've processed all
+		 * of the descriptors up to (but not including) the one that
+		 * the hardware is working on right now.
+		 */
+		
+		if (curidx == hwidx) break;
+				
+		/*
+		 * Otherwise, get the packet's sk_buff ptr back
+		 */
+		
+		dsc = &(d->sbdma_dscrtable[curidx]);
+		sb = d->sbdma_ctxtable[curidx];
+		d->sbdma_ctxtable[curidx] = NULL;
+		
+		len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4;
 
+		/*
+		 * Check packet status.  If good, process it.
+		 * If not, silently drop it and put it back on the
+		 * receive ring.
+		 */
+		
+		if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+			
+       			/*
+			 * Add a new buffer to replace the old one.  If we fail
+			 * to allocate a buffer, we're going to drop this
+			 * packet and put it right back on the receive ring.
+			 */
+			
+			if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
+			    sc->sbm_stats.rx_dropped++;
+			    sbdma_add_rcvbuffer(d,sb);	/* re-add old buffer */
+			    }
+			else {
+			    /*
+			     * Set length into the packet
+			     */
+			    skb_put(sb,len);
+
+			    /*
+			     * Buffer has been replaced on the receive ring.
+			     * Pass the buffer to the kernel
+			     */
+			    sc->sbm_stats.rx_bytes += len;
+			    sc->sbm_stats.rx_packets++;receive++;
+			    sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
+                            if (sc->rx_hw_checksum == ENABLE) {
+			    /* if the ip checksum is good indicate in skb.
+		                else set CHECKSUM_NONE as device failed to
+					checksum the packet */
+
+			       if (((dsc->dscr_b) |M_DMA_ETHRX_BADTCPCS) ||
+			     	  ((dsc->dscr_a)| M_DMA_ETHRX_BADIP4CS)){
+				  sb->ip_summed = CHECKSUM_NONE;
+			       } else {
+				 printk(KERN_DEBUG "hw checksum fail .\n");
+				 sb->ip_summed = CHECKSUM_UNNECESSARY;
+			       }
+			    } /*rx_hw_checksum */
+                            netif_receive_skb(sb);
+			    }
+		}
+		else {
+			/*
+			 * Packet was mangled somehow.  Just drop it and
+			 * put it back on the receive ring.
+			 */
+			sc->sbm_stats.rx_errors++;
+			sbdma_add_rcvbuffer(d,sb);
+		}
+		
+		
+		/* 
+		 * .. and advance to the next buffer.
+		 */
+		
+		d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+	
+	}
+	if (!receive) receive = 1;
+	dev->quota -= receive;
+	*budget -= receive;
+	
+	spin_lock_irqsave(&sc->sbm_lock,flags);
+	netif_rx_complete(dev);
+        sbmac_irq_enable(sc);
+	spin_unlock_irqrestore(&sc->sbm_lock,flags);
+	return 0;
+not_done:
+	dev->quota -= receive;
+	*budget -= receive;
+	return 1;
+}
+#endif
 /**********************************************************************
  *  SBMAC_SETMULTI(sc)
  *  
@@ -2448,6 +2636,10 @@
 	dev->do_ioctl           = sbmac_mii_ioctl;
 	dev->tx_timeout         = sbmac_tx_timeout;
 	dev->watchdog_timeo     = TX_TIMEOUT;
+#ifdef CONFIG_SB1250_NAPI
+        dev->poll       = sbmac_poll;
+        dev->weight     =dev->quota = 80;
+#endif
 
 	dev->change_mtu         = sb1250_change_mtu;
 
@@ -2525,6 +2717,10 @@
     char buffer[100];
     char *p = buffer;
 
+	int signaldetect;
+    
+	if(s->sbm_fibermode == 0)
+		{
     /* Read the mode status and mode control registers. */
     bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
     bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
@@ -2539,7 +2735,6 @@
     else {
 	k1stsr = 0;
 	}
-
     chg = 0;
 
     if ((bmsr & BMSR_LINKSTAT) == 0) {
@@ -2620,6 +2815,41 @@
 	    printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
 	    }
 
+   }
+   else 
+   	{ //fiber mode
+
+ 	chg=0;
+ 	printk("sbm_phy_oldsignaldetect:%d\n",s->sbm_phy_oldsignaldetect);
+ 	
+	signaldetect = (SGMIISR_FIBERSDS & sbmac_mii_read(s,s->sbm_phys[0],MII_SGMIISR));
+
+    printk("current signaldetect:%d\n",signaldetect);
+    
+   	if (signaldetect == 0)
+   		{
+   		printk("link state is DOWN!\n");
+		s->sbm_phy_oldsignaldetect = 0;
+		return 0;
+		}
+   	else 
+		{
+		if(s->sbm_phy_oldsignaldetect != signaldetect)
+   		{
+   		s->sbm_phy_oldsignaldetect = signaldetect;
+   		chg = 1;
+   		printk("link state has been changed\n");
+   		}
+		}
+   	if (chg==0) return 0;
+   		printk("Link is up\n");
+   		s->sbm_speed = sbmac_speed_1000;
+   		s->sbm_duplex = sbmac_duplex_full;
+   		s->sbm_fc = sbmac_fc_frame;
+   		s->sbm_state = sbmac_state_on;
+	noisy =0; 
+       printk("fiber mode.\t");
+ 	}  
     return 1;
 }
 
@@ -2632,9 +2862,12 @@
 	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
 	int next_tick = HZ;
 	int mii_status;
+	int signaldetect;
 
 	spin_lock_irq (&sc->sbm_lock);
 	
+    if(sc->sbm_fibermode == 0)
+    {	
 	/* make IFF_RUNNING follow the MII status bit "Link established" */
 	mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
 	
@@ -2647,6 +2880,23 @@
 			netif_carrier_off(dev);	
 		}
 	}
+    }
+    else
+    {
+	signaldetect = (SGMIISR_FIBERSDS & sbmac_mii_read(sc,sc->sbm_phys[0],MII_SGMIISR));
+              if(sc->sbm_phy_oldsignaldetect != signaldetect)
+              {
+                sc->sbm_phy_oldsignaldetect = signaldetect;
+		if (signaldetect) {
+                 printk("netif_carrier_on. \n");
+		 netif_carrier_on(dev);
+ 		}
+ 		else {
+		 netif_carrier_off(dev);
+ 		}
+                printk("link state has been changed\n");
+              }
+    }
 	
 	/*
 	 * Poll the PHY to see what speed we should be running at

-------------------------

Yours
Zhang Haitao
[email-masked]
2003-05-30

======= 2003-05-29 00:21:00 =======

>> May 28 14:16:04 netpower kernel: skput:over: 801dce38:2498 put:2498 
>> dev:eth2kern
>> el BUG at skbuff.c:92!
>
>I think this is your clue:
>
>eth2kernel BUG at skbuff.c:92
>
>Go read the code -- it's a overrun for skb_put().
>
>-- greg

= = = = = = = = = = = = = = = = = = = =

---

From: Greg Lindahl <[email-masked]>
Date: Thu, 29 May 2003 12:06:01 -0700

> many reasons will lead that fault!

It is not an obvious bug, but this is an important clue. If you then
look at skb_put (in include/linux/skbuff.h) you will find that you
have written beyond the end of a skbuf, or a stray pointer has damaged
the size of the skbuf. I would next put some debugging code before
every skb_put() call (there are only 2 in sbmac.c) to see if it will
overflow, and printk something if it is.

Any kernel bug that you can make happen repeatedly can be debugged in
this fashion.

-- greg