logo       

Re: Re: Hi, this is my patch for broadcom sb1250-mac.c: msg#00397

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

and Dear YOSHIFUJI Hideaki

i've corrected some bugs in my last broken 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 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)

Thanks

Zhang Haitao

----------------------
--- ./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
(mpl@xxxxxxxxxxxx)\n";
 #endif
-
+#define CONFIG_SB1250_NAPI
+#define NAPI_LOP_MAX 10


 MODULE_AUTHOR("Mitch Lichtenberg (mpl@xxxxxxxxxxxx)");
@@ -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

        }
-

+}
 }

 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


        

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

>In article <3ED58DBA.6000506@xxxxxxxxxxxxxxx> (at Thu, 29 May 2003
12:34:02 +0800), Zhang Haitao <zhanght@xxxxxxxxxxxxxxx> says:
>
>> i'm very glad to let all of you to review this patch
>> or give me some advice from the oops message!
>
>Please don't try to make cosmetic changes
>including indentation, and/or new lines etc.
>
>Thank you.
>
>--
>Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@xxxxxxxxxxxxxx>
>GPG FP: 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA
---------------------------
                        









<Prev in Thread] Current Thread [Next in Thread>