Hi Thomas,

Thomas Chou wrote:
This patch added basic mii regs support so that almost any phy chips can
be used. However, mii irq is not supported.

The patch changed the preallocated tx rx buffer to uncached, so that
cache flushing will not be needed.

FIXME: This mii hack should be ported to use the generic phylib. The
phylib can search mii address during initialization. The mii interrupt
can be handled.

Signed-off-by: Thomas Chou <[EMAIL PROTECTED]>

Applied to uClinux-dist.

Regards
Greg



 linux-2.6.x/drivers/net/open_eth.c |  248 +++++++++++++++++++++--------------
 1 files changed, 149 insertions(+), 99 deletions(-)

diff --git a/linux-2.6.x/drivers/net/open_eth.c 
b/linux-2.6.x/drivers/net/open_eth.c
index 0c155df..0bde24f 100644
--- a/linux-2.6.x/drivers/net/open_eth.c
+++ b/linux-2.6.x/drivers/net/open_eth.c
@@ -53,12 +53,14 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/mii.h>
#include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
 #include <asm/page.h>
+#define OETH_REVISION_DATECODE 20050321 #define ANNOUNCEPHYINT
 //#undef  ANNOUNCEPHYINT
@@ -68,24 +70,18 @@
     #include <asm/cacheflush.h>
     #define _print              printk
     #define MACIRQ_NUM          na_igor_mac_irq
-    #define PHYIRQ_NUM          na_mii_irq_irq
     #define ETH_BASE_ADD        na_igor_mac
     #ifdef na_mii_irq
+      #define PHYIRQ_NUM        na_mii_irq_irq
       #define PHYIRQ_BASE_ADDR  na_mii_irq
-    #else
-      #ifdef na_mii_irq_base
-        #define PHYIRQ_BASE_ADDR  na_mii_irq_base
-      #else
-        ...?...
-      #endif
     #endif
-    #define TDK78Q2120PHY
-      #define NUM_PHY_REGS                            19
-        /* Numbered 0, 1, ...       (NUM_PHY_REGS - 1)                  */
-//    #define PHY_ADDRESS                           0x1F
-      // TDK78Q2120PHY's respond to the "'broadcast" phy address 0
+    /* #define TDK78Q2120PHY */
+    #if defined(TDK78Q2120PHY)
       #define PHY_ADDRESS                           0x00
-#endif  // CONFIG_EXCALIBUR
+    #else /* generic PHY, eg NS,Micrel */
+      #define PHY_ADDRESS                           0x01
+    #endif /* defined(TDK78Q2120PHY) */
+#endif  /* CONFIG_EXCALIBUR */
#include "open_eth.h" @@ -159,7 +155,7 @@ static const int probe_mdio_phys[] = OETH_SYSFS_MDIO_ACCESS;
   #define TOTBYTSALLRXBUFS  (OETH_RXBD_NUM * OETH_RX_BUFF_SIZE)
   #define TOTBYTSALLTXBUFS  (OETH_TXBD_NUM * OETH_TX_BUFF_SIZE)
   #define TOTBYTSALLBUFS    (TOTBYTSALLRXBUFS + TOTBYTSALLTXBUFS)
-  #if(na_sram_size >= TOTBYTSALLBUFS)
+#if defined(na_sram_size) && (na_sram_size >= TOTBYTSALLBUFS)
     #define SRAM_BUFF   1
     #define SRAM_BUFF_BASE  (na_sram_base)
   #else
@@ -187,6 +183,8 @@ struct oeth_private {
     oeth_bd         *tx_bd_base;/* Address of Tx BDs. */
struct net_device_stats stats;
+    struct tasklet_struct      oeth_rx_tasklet;
+    struct tasklet_struct      oeth_tx_tasklet;
 };
#ifdef SANCHKEPKT
@@ -651,7 +649,6 @@ oeth_print_packet(unsigned long add, int len)
 #endif
// Read a phy register
-#if defined(TDK78Q2120PHY)
 int eth_mdread(struct net_device *dev,
                int                fiad_phy_addr,
                int                phyreg)
@@ -681,12 +678,8 @@ int eth_mdread(struct net_device *dev,
return rdata;
   }
-#else
-  ...?...
-#endif
// Write a phy register
-#if defined(TDK78Q2120PHY)
 void eth_mdwrite(struct net_device *dev,
                  int                fiad_phy_addr,
                  int                phyreg,
@@ -716,9 +709,6 @@ void eth_mdwrite(struct net_device *dev,
return;
   }
-#else
-  ...?...
-#endif
void oeth_phymac_synch (struct net_device *dev, int callerflg)
   {
@@ -727,27 +717,25 @@ void oeth_phymac_synch (struct net_device *dev, int 
callerflg)
     unsigned long        ulmr1sts;
     unsigned long        ulphydiagval;
- ulmr1sts = eth_mdread(dev, PHY_ADDRESS, 1);
+    ulmr1sts = eth_mdread(dev, PHY_ADDRESS, MII_BMSR);
     /* Read twice to get CURRENT status                                 */
-    ulmr1sts = eth_mdread(dev, PHY_ADDRESS, 1);
+    ulmr1sts = eth_mdread(dev, PHY_ADDRESS, MII_BMSR);
ulmoderval = regs->moder; #if defined(TDK78Q2120PHY)
       ulphydiagval = eth_mdread(dev, PHY_ADDRESS, 18);
-    #else
-      ...?...
     #endif
if(callerflg == 0)
       {
         // Caller = NOT Phy interrupt handler
- if((ulmr1sts & 0x00000004) != 0)
+        if((ulmr1sts & BMSR_LSTATUS) != 0)
           {
             // Link is ostensibly OK
- if((eth_mdread(dev, PHY_ADDRESS, 0) & 0x00001000) != 0)
+            if((eth_mdread(dev, PHY_ADDRESS, MII_BMCR) & BMCR_ANENABLE) != 0)
               {
                 // Auto negotiation ostensibly enabled
@@ -798,9 +786,7 @@ void oeth_phymac_synch (struct net_device *dev, int callerflg)
                               return;
                             }
                         }
-                    #else
-                      ...?...
-                    #endif
+                    #endif /* defined(TDK78Q2120PHY) */
                   }
               }
           }
@@ -817,21 +803,21 @@ void oeth_phymac_synch (struct net_device *dev, int 
callerflg)
       printk("\noeth_phymac_synch:%s  MR1: 0x%08lX\n",
              dev->name,
              ulmr1sts);
-      if((ulmr1sts & 0x00000002) != 0)
+      if((ulmr1sts & BMSR_JCD) != 0)
         {
           printk("                               Jabber\n");
         }
-      if((ulmr1sts & 0x00000010) != 0)
+      if((ulmr1sts & BMSR_RFAULT) != 0)
         {
           printk("                               Remote Fault\n");
         }
-      if((ulmr1sts & 0x00000020) != 0)
+      if((ulmr1sts & BMSR_ANEGCOMPLETE) != 0)
         {
           printk("                               Autoneg'd\n");
         }
     #endif
- if((ulmr1sts & 0x00000004) != 0)
+    if((ulmr1sts & BMSR_LSTATUS) != 0)
       {
         /* Phy MR1 (status register) indicates link is (now) OK.        */
@@ -918,9 +904,62 @@ void oeth_phymac_synch (struct net_device *dev, int callerflg)
             printk("             %s\n",
                    (ulphydiagval & 0x0400) ? "100BASE-TX" : "10BASE-T");
           #endif
-        #else
-          ...?...
-        #endif
+
+        #else /* generic PHY, use MR1 */
+
+           if((ulmr1sts & (BMSR_100FULL | BMSR_10FULL)) != 0)
+            {
+              /* Phy MR1 indicates              */
+              /*  link is (now) running full duplex.                    */
+
+              if((ulmoderval & (OETH_MODER_FULLD)) == 0)
+                {
+                  regs->moder = ((unsigned long) (ulmoderval |
+                                                  (OETH_MODER_FULLD)));
+                }
+              // FIXME:...
+              // ...Note manual says not supposed to "change
+              // ... registers after ModeR's TxEn or RxEn
+              // ...  bit(s) have been set"
+              if(regs->ipgt != ((unsigned long) (0x00000015)))
+                {
+                  regs->ipgt = ((unsigned long) (0x00000015));
+                }
+
+              #if defined(ANNOUNCEPHYINT)
+                printk("             FullD\n");
+              #endif
+            }
+            else
+            {
+              /* Phy MR1 indicates              */
+              /*  link is (now) running half duplex.                    */
+
+              if((ulmoderval & (OETH_MODER_FULLD)) != 0)
+                {
+                  regs->moder = ((unsigned long) (ulmoderval &
+                                                  (~(OETH_MODER_FULLD))));
+                }
+              // FIXME:...
+              // ...Note manual says not supposed to "change
+              // ... registers after ModeR's TxEn or RxEn
+              // ...  bit(s) have been set"
+              if(regs->ipgt != ((unsigned long) (0x00000012)))
+                {
+                  regs->ipgt = ((unsigned long) (0x00000012));
+                }
+
+              #if defined(ANNOUNCEPHYINT)
+                printk("             HalfD\n");
+              #endif
+            }
+
+          #if defined(ANNOUNCEPHYINT)
+            printk("             %s\n",
+                   (ulmr1sts & (BMSR_100FULL | BMSR_100HALF)) ? "100BASE-TX" : 
"10BASE-T");
+          #endif
+
+        #endif /* defined(TDK78Q2120PHY) */
       }
     #if defined(ANNOUNCEPHYINT)
       else
@@ -1002,9 +1041,7 @@ static irqreturn_t oeth_PhyInterrupt(int             irq,
oeth_phymac_synch((struct net_device *) dev_id,
                         1);  // Caller = Phy interrupt handler
-    #else
-      ...?...
-    #endif
+    #endif  /* defined(TDK78Q2120PHY) */
return IRQ_HANDLED;
   }
@@ -1015,9 +1052,11 @@ static irqreturn_t oeth_PhyInterrupt(int             irq,
     Entered at interrupt level
 */
 static void
-oeth_tx(struct net_device *dev)
+oeth_tx(unsigned long devn)
 {
+    struct net_device *dev = (void *)devn;
     volatile struct oeth_private *cep;
+    unsigned        long          flags;
     volatile oeth_bd *bdp;
#ifndef TXBUFF_PREALLOC
@@ -1027,7 +1066,7 @@ oeth_tx(struct net_device *dev)
     cep = (struct oeth_private *)dev->priv;
// Cycles over the TX BDs, starting at the first one that would've been sent. -TS
-    for (;; cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK)
+    while (1)
       {
         bdp = cep->tx_bd_base + cep->tx_last;
@@ -1038,6 +1077,8 @@ oeth_tx(struct net_device *dev) /* Check status for errors
          */
+       if (bdp->len_status & 0x1ff) printk("oeth: 
tx%02d,%08x\n",cep->tx_last,bdp->len_status);
+
         if (bdp->len_status & OETH_TX_BD_LATECOL)
             cep->stats.tx_window_errors++;
             //;dgt - ifconfig doesn't report tx_window_errors ?
@@ -1062,6 +1103,7 @@ oeth_tx(struct net_device *dev)
             cep->stats.tx_errors++;
cep->stats.tx_packets++;
+        cep->stats.tx_bytes += bdp->len_status >> 16;
         cep->stats.collisions += (bdp->len_status >> 4) & 0x000f;
#ifndef TXBUFF_PREALLOC
@@ -1072,17 +1114,33 @@ oeth_tx(struct net_device *dev)
         dev_kfree_skb(skb);
 #endif
+ local_irq_save(flags);
+
         if (cep->tx_full)
             cep->tx_full = 0;
+       cep->tx_last = (cep->tx_last + 1) & OETH_TXBD_NUM_MASK;
+
+       local_irq_restore(flags);
+
       }
+
+        if(((cep->tx_next + 1) & OETH_TXBD_NUM_MASK) != cep->tx_last)
+          {
+            netif_wake_queue(dev);
+          }
+//        else
+//        {
+//          Tx done interrupt but no tx BD's released ?
+//        }
 }
/*
     Entered at interrupt level
 */
 static void
-oeth_rx(struct net_device *dev)
+oeth_rx(unsigned long devn)
 {
+    struct net_device *dev = (void *)devn;
     volatile struct oeth_private *cep;
     volatile        oeth_bd      *bdp;
     struct          sk_buff      *skb;
@@ -1114,8 +1172,8 @@ oeth_rx(struct net_device *dev)
             {
                 bdp->addr = (unsigned long) skb->tail;
- dcache_push (((unsigned long) (bdp->addr)),
-                             MAX_FRAME_SIZE);
+/*                 dcache_push (((unsigned long) (bdp->addr)), */
+/*                              MAX_FRAME_SIZE); */
bdp->len_status |= OETH_RX_BD_EMPTY;
             }
@@ -1135,6 +1193,8 @@ oeth_rx(struct net_device *dev)
/* Check status for errors.
          */
+       if (bdp->len_status & 0x1ff) printk("oeth: 
rx%02d,%08x\n",cep->rx_cur,bdp->len_status);
+
         if (bdp->len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
             cep->stats.rx_length_errors++;
             //;dgt - ifconfig doesn't report rx_length_errors ?
@@ -1201,8 +1261,8 @@ oeth_rx(struct net_device *dev)
           {
             bdp->len_status &= ~OETH_RX_BD_STATS;
- dcache_push (((unsigned long) (bdp->addr)),
-                         OETH_RX_BUFF_SIZE);
+/*             dcache_push (((unsigned long) (bdp->addr)), */
+/*                          OETH_RX_BUFF_SIZE); */
bdp->len_status |= OETH_RX_BD_EMPTY; @@ -1338,10 +1398,11 @@ oeth_rx(struct net_device *dev)
                 }                                               //;dgt
cep->stats.rx_packets++; // This is the only thing that increments the packet stat if RXBUFF_PREALLOC is defined.
+           cep->stats.rx_bytes += pkt_len;
           }
- dcache_push (((unsigned long) (bdp->addr)),
-                     pkt_len);
+/*         dcache_push (((unsigned long) (bdp->addr)), */
+/*                      pkt_len); */
bdp->len_status &= ~OETH_RX_BD_STATS;
         bdp->len_status |= OETH_RX_BD_EMPTY;
@@ -1363,6 +1424,7 @@ oeth_rx(struct net_device *dev)
                 small_skb->protocol = eth_type_trans(small_skb,dev);
                 netif_rx(small_skb);
                 cep->stats.rx_packets++;
+               cep->stats.rx_bytes += pkt_len;
               }
             else
               {
@@ -1370,8 +1432,8 @@ oeth_rx(struct net_device *dev)
                 cep->stats.rx_dropped++;
               }
- dcache_push (((unsigned long) (bdp->addr)),
-                         pkt_len);
+/*             dcache_push (((unsigned long) (bdp->addr)), */
+/*                          pkt_len); */
bdp->len_status &= ~OETH_RX_BD_STATS;
             bdp->len_status |=  OETH_RX_BD_EMPTY;
@@ -1383,6 +1445,7 @@ oeth_rx(struct net_device *dev)
             skb->protocol = eth_type_trans(skb,dev);
             netif_rx(skb);
             cep->stats.rx_packets++;
+           cep->stats.rx_bytes += pkt_len;
   #if OETH_DEBUG
             _print("RX long\n");
             oeth_print_packet(bdp->addr, bdp->len_status >> 16);
@@ -1397,8 +1460,8 @@ oeth_rx(struct net_device *dev)
bdp->addr = (unsigned long)skb->tail; - dcache_push (((unsigned long) (bdp->addr)),
-                             MAX_FRAME_SIZE);
+/*                 dcache_push (((unsigned long) (bdp->addr)), */
+/*                              MAX_FRAME_SIZE); */
bdp->len_status |= OETH_RX_BD_EMPTY;
               }
@@ -1433,23 +1496,13 @@ static irqreturn_t oeth_interrupt(int             irq,
/* Handle receive event in its own function.
      */
-    if (int_events & (OETH_INT_RXF | OETH_INT_RXE))
-        oeth_rx(dev_id);
+    if (int_events & (OETH_INT_RXF | OETH_INT_RXE | OETH_INT_BUSY))
+ tasklet_schedule(&cep->oeth_rx_tasklet); /* Handle transmit event in its own function.
      */
-    if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
-        oeth_tx(dev_id);
-
-        if(((cep->tx_next + 1) & OETH_TXBD_NUM_MASK) != cep->tx_last)
-          {
-            netif_wake_queue(dev);
-          }
-//        else
-//        {
-//          Tx done interrupt but no tx BD's released ?
-//        }
-    }
+    if (int_events & (OETH_INT_TXB | OETH_INT_TXE))
+ tasklet_schedule(&cep->oeth_tx_tasklet); /* Check for receive busy, i.e. packets coming but no place to
      * put them.
@@ -1457,11 +1510,6 @@ static irqreturn_t oeth_interrupt(int             irq,
     if (int_events & OETH_INT_BUSY)
       {
         cep->stats.rx_dropped++;                                //;dgt
-
-        if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE)))
-          {
-            oeth_rx(dev_id);
-          }
       }
return IRQ_HANDLED;
@@ -1536,9 +1584,7 @@ oeth_open(struct net_device *dev)
                 ((unsigned long) (0x0001));
           // Enable phy interrupt pass thru to PHYIRQ_NUM
       #endif
-    #else
-      ...?...
-    #endif
+    #endif  /* defined(TDK78Q2120PHY) */
oeth_phymac_synch(dev,
                       0);  // Caller = NOT Phy interrupt handler
@@ -1557,6 +1603,8 @@ oeth_open(struct net_device *dev)
 #endif
netif_start_queue(dev);
+    tasklet_init(&cep->oeth_rx_tasklet, oeth_rx, (unsigned long)dev);
+    tasklet_init(&cep->oeth_tx_tasklet, oeth_tx, (unsigned long)dev);
return 0;
 }
@@ -1573,8 +1621,7 @@ oeth_close(struct net_device *dev)
/* Free phy interrupt handler
      */
-    #if defined(TDK78Q2120PHY)
-      #if defined(PHYIRQ_NUM)
+    #if defined(PHYIRQ_NUM)
         (*(volatile unsigned long *)
              (((unsigned long *)
                   ((((char *)
@@ -1584,15 +1631,15 @@ oeth_close(struct net_device *dev)
           // Disable phy interrupt pass thru to PHYIRQ_NUM
free_irq(PHYIRQ_NUM, (void *)dev);
-      #endif
-    #else
-      ...?...
     #endif
/* Free interrupt hadler
      */
     free_irq(MACIRQ_NUM, (void *)dev);
+ tasklet_kill(&cep->oeth_tx_tasklet);
+    tasklet_kill(&cep->oeth_rx_tasklet);
+
     /* Disable receiver and transmitesr
      */
     regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
@@ -1783,23 +1830,12 @@ oeth_start_xmit(struct sk_buff *skb, struct net_device 
*dev)
       {
         cep->tx_full = 1;
       }
-      else
-      {
-        if(((cep->tx_next + 1) & OETH_TXBD_NUM_MASK) != cep->tx_last)
-          {
-            netif_wake_queue(dev);
-          }
-//        else
-//        {
-//          Don't let the tx ring completely fill
-//        }
-      }
/* Send it on its way. Tell controller its ready, interrupt when done,
      * and to put the CRC on the end.
      */
-    dcache_push (((unsigned long) (bdp->addr)),
-                 lenSkbDataByts);
+/*     dcache_push (((unsigned long) (bdp->addr)), */
+/*                  lenSkbDataByts); */
bdp->len_status |= ( 0
                         | OETH_TX_BD_READY
@@ -1811,6 +1847,18 @@ oeth_start_xmit(struct sk_buff *skb, struct net_device 
*dev)
local_irq_restore(flags); + if (cep->tx_next != cep->tx_last)
+      {
+        if(((cep->tx_next + 1) & OETH_TXBD_NUM_MASK) != cep->tx_last)
+          {
+            netif_wake_queue(dev);
+          }
+//        else
+//        {
+//          Don't let the tx ring completely fill
+//        }
+      }
+
     return 0;
 }
@@ -2195,7 +2243,7 @@ static int __init oeth_probe(struct net_device *dev)
       //   MR18 (Diagnostics):  0x0000
/* TDK78Q2120 LEDs (seven?) NOT configurable? */
-    #else
+    #elif defined(LXT971PHY)
       ...Intel LXT971A phy...?...
/* Set PHY to show Tx status, Rx status and Link status */
@@ -2211,7 +2259,7 @@ static int __init oeth_probe(struct net_device *dev)
     for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) {
#ifndef SRAM_BUFF
-        mem_addr = __get_free_page(GFP_KERNEL);
+        mem_addr = __get_free_page(GFP_KERNEL) | 0x80000000;
   #endif    // SRAM_BUFF
for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) {
@@ -2247,15 +2295,15 @@ static int __init oeth_probe(struct net_device *dev)
     for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) {
#ifndef SRAM_BUFF
-        mem_addr = __get_free_page(GFP_KERNEL);
+        mem_addr = __get_free_page(GFP_KERNEL) | 0x80000000;
   #endif    // SRAM_BUFF
for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++)
           {
             rx_bd[k].addr = __pa(mem_addr);
- dcache_push (((unsigned long) (rx_bd[k].addr)),
-                         OETH_RX_BUFF_SIZE);
+/*             dcache_push (((unsigned long) (rx_bd[k].addr)), */
+/*                          OETH_RX_BUFF_SIZE); */
rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
               // FIXME...Should we really let the rx ring
@@ -2267,6 +2315,8 @@ static int __init oeth_probe(struct net_device *dev)
     }
     rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+ cache_push_all();
+
 #else
     /* Initialize RXBDs.
      */

--
------------------------------------------------------------------------
Greg Ungerer  --  Chief Software Dude       EMAIL:     [EMAIL PROTECTED]
Secure Computing Corporation                PHONE:       +61 7 3435 2888
825 Stanley St,                             FAX:         +61 7 3891 3630
Woolloongabba, QLD, 4102, Australia         WEB: http://www.SnapGear.com
_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to