Stephen Hemminger <[EMAIL PROTECTED]> writes:

  > > 
  > >   > Indentation. See Documentation style.
  > >   > What about IRQF_SHARED?
  > > 
  > > Not sure, maybe I should make this another driver parameter. On my
  > > platform is not shared...
  > 
  > The trouble with devices, is that some poor sop clones the hardware to
  > another board and your assumption is no longer valid.

Tt's a parameter now.

  > >
  > >   > > +static int oeth_start_xmit(struct sk_buff *skb, struct net_device 
*dev)
  > >   > > +{
  > >   > > +   struct oeth_private *cep = netdev_priv(dev);
  > >   > > +   volatile struct oeth_bd *bdp;
  > >   > > +   unsigned long flags;
  > >   > > +   u32 len_status;
  > >   > > +
  > >   > > +   spin_lock_irqsave(&cep->lock, flags);
  > >   > > +
  > >   > > +   if (cep->tx_full) {
  > >   > > +           /* All transmit buffers are full.  Bail out. */
  > >   > > +           printk("%s: tx queue full!.\n", dev->name);
  > >   > > +           print_queue(cep->tx_bd_base, cep->tx_next, 
OETH_TXBD_NUM);
  > >   > > +           spin_unlock_irqrestore(&cep->lock, flags);
  > >   > > +           return 1;
  > >   > return NETDEV_TX_BUSY.
  > >   >
  > >   > you forgot to call stop_queue
  > > 
  > > Fixed.
  > > 
  > > What should I return in the case below: 
  > > 
  > > if (skb->len > OETH_TX_BUFF_SIZE) {
  > >         printk("%s: tx frame too long!.\n", dev->name);
  > >         spin_unlock_irqrestore(&cep->lock, flags);
  > >         return 1;
  > > }
  > 
  > Drop the skb with dev_kfree_skb_irq() and return NETDEV_TX_OK.
  > You should net_ratelimit() the message also if you don't want the
  > machine to hang if you ever get a buggy application.
 
Done.

  > >   > > +
  > >   > > +   /* Copy data to TX buffer. */
  > >   > > +   memcpy_hton ((unsigned char *)bdp->addr, skb->data,  skb->len);
  > >   > 
  > >   > Use skb_copy_and_csum_dev and you get checksum offload for free.
  > > 
  > > Wouldn't that just add (a bit of) overhead? It performs the memcpy, but 
it also
  > > checks if the HW is capable of doing the checksum (which it is)... 
  > > Incidentally the memcpy_hton is just memcpy now.
  > 
  > The cost of copy and checksum is the same as copy on all most hardware.

Unfortunately on my platform is not.

  > And does your hardware do IPV6 etc?

No. 

  > >   > > +                   cep->stats.rx_dropped++;
  > >   > > +           }
  > >   > > +           else {
  > >   > > +                   skb->dev = dev;
  > >   > > +                   OEDRX((printk("RX in ETH buf\n")));
  > >   > > +                   OEDRX((oeth_print_packet((u32*)bdp->addr, 
pkt_len)));
  > >   > > +
  > >   > > +                   memcpy_ntoh(skb_put(skb, pkt_len), (unsigned 
char *)bdp->addr, pkt_len);
  > >   > 
  > >   > 
  > >   > Copying packet in IRQ routine causes long latencies.
  > > 
  > > Any suggestions on how else to do this?
  > 
  > You can use NAPI (see 8139too.c) it has similar "issues"

I implemented NAPI. New version attached. 

Is there anything else that I should do?

  > >   > > +#if CONFIG_MII
  > >   > > +static int check_if_running(struct net_device *dev)
  > >   > > +{
  > >   > > +   if (!netif_running(dev))
  > >   > > +           return -EINVAL;
  > >   > > +   return 0;
  > >   > > +}
  > >   > 
  > >   > Bogus wrapper.
  > > 
  > > OK. BTW this is present in 3 more files: hamachi.c, starfire.c and
  > > sundance.c 
  > 
  > Send the Bunk after it.

Sorry, I don't know what that means...

 Kconfig    |    5 
 open_eth.c |  753 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 open_eth.h |  132 ++++++++++
 3 files changed, 890 insertions(+)

--- /dev/null   2006-09-20 11:38:04.545479250 -0700
+++ drivers/net/open_eth.c      2006-12-05 11:50:57.977895000 -0800
@@ -0,0 +1,753 @@
+/*
+ * Ethernet driver for Open Ethernet Controller (www.opencores.org).
+ *      Copyright (c) 2002 Simon Srot ([EMAIL PROTECTED])
+ *      Copyright (c) 2006 Tensilica Inc.
+ * 
+ * Based on:
+ *
+ * Ethernet driver for Motorola MPC8xx.
+ *      Copyright (c) 1997 Dan Malek ([EMAIL PROTECTED])
+ *
+ * mcen302.c: A Linux network driver for Mototrola 68EN302 MCU
+ *
+ *      Copyright (C) 1999 Aplio S.A. Written by Vadim Lebedev
+ *
+ * 
+ *  The Open Ethernet Controller is just a MAC, it needs to be
+ *  combined with a PHY and buffer memory in order to create an
+ *  ethernet device. Thus some of the hardware parameters are device
+ *  specific. They need to be defined in asm/hardware.h. Example:
+ * 
+ * The IRQ for the device:
+ * #define OETH_IRQ                1
+ *
+ * The flag to be passed to request_irq:
+ * #define OETH_REQUEST_IRQ_FLAG   0
+ * 
+ * The address where the MAC registers are mapped:
+ * #define OETH_BASE_ADDR          0xFD030000
+ *
+ * The address where the MAC RX/TX buffers are mapped:
+ * #define OETH_SRAM_BUFF_BASE     0xFD800000
+ * 
+ * Sizes for a RX or TX buffer:
+ * #define OETH_RX_BUFF_SIZE       2048
+ * #define OETH_TX_BUFF_SIZE       2048
+ * The number of RX and TX buffers:
+ * #define OETH_RXBD_NUM           16
+ * #define OETH_TXBD_NUM           16
+ * The PHY ID (needed if MII is enabled):
+ * #define OETH_PHY_ID             0
+ * 
+ * Code to perform the device specific initialization (REGS is a
+ *  struct oeth_regs*):
+ * #define OETH_PLATFORM_SPECIFIC_INIT(REGS)
+ * it should at least initialize the device MAC address in
+ *  REGS->mac_addr1 and REGS->mac_addr2.
+ * 
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+
+#include <asm/hardware.h>
+
+#include "open_eth.h"
+
+#define DRV_NAME "OpencoresEthernet"
+
+/* The Opencores Ethernet driver needs some parameters from the
+ * hardware implementation. They should be defined in the
+ asm/hardware.h file. */
+
+/* Debug helpers. */
+/* #define OETH_DEBUG_TRANSMIT  */
+#ifdef OETH_DEBUG_TRANSMIT
+#define OEDTX(x) x
+#else
+#define OEDTX(x)
+#endif
+
+/* #define OETH_DEBUG_RECEIVE */
+#ifdef OETH_DEBUG_RECEIVE
+#define OEDRX(x) x
+#else
+#define OEDRX(x)
+#endif
+
+#define OETH_REGS_SIZE  0x1000 /* MAC registers + RX and TX descriptors */
+#define OETH_BD_BASE    (OETH_BASE_ADDR + 0x400)
+#define OETH_TOTAL_BD   128
+
+/* The transmitter timeout FIXME: dann this needs to be handled */
+#define OETH_TX_TIMEOUT               (2*HZ)
+
+/* The buffer descriptors track the ring buffers. */
+struct oeth_private {
+       struct oeth_regs *regs; /* Address of controller registers. */
+       struct oeth_bd *rx_bd_base;     /* Address of Rx BDs. */
+       struct oeth_bd *tx_bd_base;     /* Address of Tx BDs. */
+       u8 tx_next;             /* Next buffer to be sent */
+       u8 tx_last;             /* Next buffer to be checked if packet sent */
+       u8 tx_full;             /* Buffer ring full indicator */
+       u8 rx_cur;              /* Next buffer to be checked if packet received 
*/
+       spinlock_t lock;
+       spinlock_t rx_lock;
+       struct net_device_stats stats;
+#if CONFIG_MII
+       struct mii_if_info mii_if;      /* MII lib hooks/info */
+#endif
+};
+
+static void oeth_tx(struct net_device *dev);
+static irqreturn_t oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+#if defined(OETH_DEBUG_RECEIVE) || defined(OETH_DEBUG_TRANSMIT)
+static void oeth_print_packet(u32 * add, int len)
+{
+       int i;
+
+       printk("ipacket: add = %p len = %d\n", add, len);
+       for (i = 0; i < len; i++) {
+               if (!(i % 16))
+                       printk("\n");
+               else if (!(i % 8))
+                       printk(" ");
+               printk(" %.2x", *(((unsigned char *)add) + i));
+       }
+       printk("\n");
+}
+#endif
+
+static int oeth_open(struct net_device *dev)
+{
+       int ret;
+       struct oeth_private *cep = netdev_priv(dev);
+       struct oeth_regs *regs = cep->regs;
+
+       /* Install our interrupt handler. */
+       ret = request_irq(OETH_IRQ, oeth_interrupt, OETH_REQUEST_IRQ_FLAG,
+                         dev->name, (void *)dev);
+       if (ret) {
+               printk("request_irq failed for the Opencore ethernet device\n");
+               return ret;
+       }
+       /* Enable the receiver and transmiter. */
+       regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
+
+       /* Start the queue, we are ready to process packets now. */
+       netif_start_queue(dev);
+       return 0;
+}
+
+static int oeth_close(struct net_device *dev)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       struct oeth_regs *regs = cep->regs;
+       volatile struct oeth_bd *bdp;
+       int i;
+
+       spin_lock_irq(&cep->lock);
+       /* Disable the receiver and transmiter. */
+       regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
+
+       bdp = cep->rx_bd_base;
+       for (i = 0; i < OETH_RXBD_NUM; i++) {
+               bdp->len_status &= ~(OETH_TX_BD_STATS | OETH_TX_BD_READY);
+               bdp++;
+       }
+
+       bdp = cep->tx_bd_base;
+       for (i = 0; i < OETH_TXBD_NUM; i++) {
+               bdp->len_status &= ~(OETH_RX_BD_STATS | OETH_RX_BD_EMPTY);
+               bdp++;
+       }
+
+       spin_unlock_irq(&cep->lock);
+
+       return 0;
+}
+
+static int oeth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       volatile struct oeth_bd *bdp;
+       unsigned long flags;
+       u32 len_status;
+
+       spin_lock_irqsave(&cep->lock, flags);
+
+       if (cep->tx_full) {
+               /* All transmit buffers are full.  Bail out. */
+               printk("%s: tx queue full!.\n", dev->name);
+               netif_stop_queue(dev);
+               spin_unlock_irqrestore(&cep->lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+
+       /* Fill in a Tx ring entry. */
+       bdp = cep->tx_bd_base + cep->tx_next;
+
+       len_status = bdp->len_status;
+
+       /* Clear all of the status flags. */
+       len_status &= ~OETH_TX_BD_STATS;
+
+       /* If the frame is short, tell MAC to pad it. */
+       if (skb->len <= ETH_ZLEN)
+               len_status |= OETH_TX_BD_PAD;
+       else
+               len_status &= ~OETH_TX_BD_PAD;
+
+       OEDTX((printk("TX skb\n")));
+       OEDTX((oeth_print_packet((u32 *) skb->data, skb->len)));
+       OEDTX((printk("end TX skb print\n")));
+
+       if (skb->len > OETH_TX_BUFF_SIZE) {
+               if (net_ratelimit())
+                       printk("%s: tx frame too long!.\n", dev->name);
+               dev_kfree_skb_irq(skb);
+               spin_unlock_irqrestore(&cep->lock, flags);
+               return NETDEV_TX_OK;
+       }
+
+       /* Copy data to TX buffer. */
+       memcpy((unsigned char *)bdp->addr, skb->data, skb->len);
+
+       len_status = (len_status & 0x0000ffff) | (skb->len << 16);
+
+       if ((bdp->addr + (len_status >> 16))
+           >= (OETH_SRAM_BUFF_BASE + OETH_TXBD_NUM * OETH_TX_BUFF_SIZE
+               + OETH_RXBD_NUM * OETH_RX_BUFF_SIZE))
+               panic("MEMORY OVERWRITE at address: %x !!!\n",
+                     (bdp->addr + (len_status >> 16)));
+
+       OEDTX((printk("TX controller buff\n")));
+       OEDTX((oeth_print_packet((u32 *) bdp->addr, bdp->len_status >> 16)));
+       OEDTX(printk("end TX controller buff print\n"));
+
+       dev_kfree_skb_irq(skb);
+
+       cep->tx_next =
+           (cep->tx_next + 1 == OETH_TXBD_NUM) ? 0 : (cep->tx_next + 1);
+
+       if (cep->tx_next == cep->tx_last) {
+               cep->tx_full = 1;
+               /* Do not transmit anymore if the TX queue is full. */
+               netif_stop_queue(dev);
+       }
+
+       /* Send it on its way.  Tell controller its ready, interrupt when done,
+        * and to put the CRC on the end. */
+       len_status |= (OETH_TX_BD_READY | OETH_TX_BD_IRQ | OETH_TX_BD_CRC);
+       bdp->len_status = len_status;
+
+       spin_unlock_irqrestore(&cep->lock, flags);
+
+       dev->trans_start = jiffies;
+       return 0;
+}
+
+/* The interrupt handler. */
+static irqreturn_t oeth_interrupt(int irq, void *dev_id, struct pt_regs 
*ptregs)
+{
+       struct net_device *dev = dev_id;
+       struct oeth_private *cep = netdev_priv(dev);
+       volatile struct oeth_regs *regs = cep->regs;
+       u32 int_events;
+
+       spin_lock(&cep->lock);
+
+       /* Get the interrupt events that caused us to be here. */
+       int_events = regs->int_src;
+       /* Acknowledge interrupt. */
+       regs->int_src = int_events;
+
+       /* If RX or BUSY enable RX polling. */
+       if (int_events & (OETH_INT_RXF | OETH_INT_RXE | OETH_INT_BUSY))
+               if (netif_rx_schedule_prep(dev)) {
+                       regs->int_mask &= ~(OETH_INT_MASK_RXF
+                                           | OETH_INT_MASK_RXE);
+                       __netif_rx_schedule(dev);
+               }
+
+       /* Handle transmit event in its own function. */
+       if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
+               oeth_tx(dev);
+       }
+
+       spin_unlock(&cep->lock);
+
+       return IRQ_HANDLED;
+}
+
+static void oeth_tx(struct net_device *dev)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       volatile struct oeth_bd *bdp;
+
+       for (;;
+            cep->tx_last =
+            (cep->tx_last + 1 == OETH_TXBD_NUM) ? 0 : (cep->tx_last + 1)) {
+               u32 len_status;
+
+               bdp = cep->tx_bd_base + cep->tx_last;
+               len_status = bdp->len_status;
+
+               /* If the OETH_TX_BD_READY is set the transmission has
+                * not been done yet! */
+               if ((len_status & OETH_TX_BD_READY)
+                   || ((cep->tx_last == cep->tx_next) && !cep->tx_full))
+                       break;
+
+               /* Check status for errors. */
+               if (len_status & OETH_TX_BD_LATECOL)
+                       cep->stats.tx_window_errors++;
+               if (len_status & OETH_TX_BD_RETLIM)
+                       cep->stats.tx_aborted_errors++;
+               if (len_status & OETH_TX_BD_UNDERRUN)
+                       cep->stats.tx_fifo_errors++;
+               if (len_status & OETH_TX_BD_CARRIER) {
+                       cep->stats.tx_carrier_errors++;
+               }
+               if (len_status &
+                   (OETH_TX_BD_LATECOL | OETH_TX_BD_RETLIM |
+                    OETH_TX_BD_UNDERRUN))
+                       cep->stats.tx_errors++;
+
+               cep->stats.tx_packets++;
+               cep->stats.tx_bytes += len_status >> 16;
+               cep->stats.collisions += (len_status & OETH_TX_BD_RETRY) >> 4;
+
+               if (cep->tx_full) {
+                       cep->tx_full = 0;
+                       /* We have freed an entry in the TX queue, we can
+                        * start transmitting again. */
+                       if (netif_queue_stopped(dev))
+                               netif_wake_queue(dev);
+               }
+       }
+}
+
+static unsigned int oeth_rx(struct net_device *dev, int budget)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       volatile struct oeth_bd *bdp;
+       struct sk_buff *skb;
+       int received;
+       int pkt_len;
+       int bad = 0;
+       int current_buff = cep->rx_cur;
+       static int last_current_buff = 0;
+
+       for (received = 0; received < budget;
+            cep->rx_cur =
+            (cep->rx_cur + 1 == OETH_RXBD_NUM) ? 0 : (cep->rx_cur + 1)) {
+               u32 len_status;
+               bdp = cep->rx_bd_base + cep->rx_cur;
+
+               /* First, grab all of the stats for the incoming
+                * packet.  These get messed up if we get called due
+                * to a busy condition. */
+               len_status = bdp->len_status;
+
+               if (len_status & OETH_RX_BD_EMPTY)
+                       break;
+
+               received++;
+
+               /* Check status for errors. */
+               if (len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+                       cep->stats.rx_length_errors++;
+                       bad = 1;
+               }
+               if (len_status & OETH_RX_BD_DRIBBLE) {
+                       cep->stats.rx_frame_errors++;
+                       bad = 1;
+               }
+               if (len_status & OETH_RX_BD_CRCERR) {
+                       cep->stats.rx_crc_errors++;
+                       bad = 1;
+               }
+               if (len_status & OETH_RX_BD_OVERRUN) {
+                       cep->stats.rx_crc_errors++;
+                       bad = 1;
+               }
+               if (len_status & OETH_RX_BD_TOOLONG) {
+                       cep->stats.rx_crc_errors++;
+                       bad = 1;
+               }
+               if (len_status & OETH_RX_BD_MISS) {
+
+               }
+               if (len_status & OETH_RX_BD_LATECOL) {
+                       cep->stats.rx_frame_errors++;
+                       bad = 1;
+               }
+
+               if (bad) {
+                       bdp->len_status = (len_status & ~OETH_RX_BD_STATS)
+                           | OETH_RX_BD_EMPTY;
+                       continue;
+               }
+
+               /* Process the incoming frame. */
+               pkt_len = len_status >> 16;
+
+               skb = netdev_alloc_skb(pkt_len);
+
+               if (likely(skb)) {
+                       skb->dev = dev;
+                       OEDRX((printk("RX in ETH buf\n")));
+                       OEDRX((oeth_print_packet((u32 *) bdp->addr, pkt_len)));
+
+                       memcpy(skb_put(skb, pkt_len),
+                              (unsigned char *)bdp->addr, pkt_len);
+                       OEDRX((printk("RX in memory\n")));
+                       OEDRX((oeth_print_packet((u32 *) skb->data, pkt_len)));
+                       skb->protocol = eth_type_trans(skb, dev);
+                       dev->last_rx = jiffies;
+                       cep->stats.rx_packets++;
+                       cep->stats.rx_bytes += pkt_len;
+                       netif_receive_skb(skb);
+               }
+
+               bdp->len_status = (len_status & ~OETH_RX_BD_STATS)
+                   | OETH_RX_BD_EMPTY;
+       }
+}
+
+static int oeth_poll(struct net_device *dev, int *budget)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       int orig_budget = min(*budget, dev->quota);
+       int done = 1;
+       unsigned int work_done;
+       static int no_work_done = 0;
+
+       spin_lock(&cep->rx_lock);
+
+       work_done = oeth_rx(dev, orig_budget);
+       if (likely(work_done > 0)) {
+               *budget -= work_done;
+               dev->quota -= work_done;
+               done = (work_done < orig_budget);
+       }
+       
+       if (done) {
+               /* Stop polling and reenable interrupts. */
+               __netif_rx_complete(dev);
+               cep->regs->int_mask |= (OETH_INT_MASK_RXF | OETH_INT_MASK_RXE);
+       }
+       spin_unlock(&cep->rx_lock);
+
+       return !done;
+}
+
+static struct net_device_stats *oeth_get_stats(struct net_device *dev)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       return &cep->stats;
+}
+
+static int oeth_set_mac_address(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+       struct oeth_private *cep = netdev_priv(dev);
+       volatile struct oeth_regs *regs = cep->regs;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       regs->mac_addr1 = addr->sa_data[0] << 8 | addr->sa_data[1];
+       regs->mac_addr0 = addr->sa_data[2] << 24
+           | addr->sa_data[3] << 16 | addr->sa_data[4] << 8 | addr->sa_data[5];
+       return 0;
+}
+
+static int __init oeth_init(struct net_device *dev, unsigned int base_addr,
+                           unsigned int irq);
+
+/*
+ * Probe for an Opencores ethernet controller.
+ */
+static struct net_device *__devinit oeth_probe(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct oeth_private));
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       if (!check_mem_region(OETH_BASE_ADDR, OETH_REGS_SIZE)) {
+               SET_MODULE_OWNER(dev);
+               if (oeth_init(dev, OETH_BASE_ADDR, OETH_IRQ) == 0) {
+                       if (register_netdev(dev))
+                               printk(KERN_WARNING
+                                      "Openethernet: No card found\n");
+                       else
+                               return dev;
+               }
+
+       }
+       return NULL;
+}
+
+#if CONFIG_MII
+static void oeth_get_drvinfo(struct net_device *dev,
+                            struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, "0.0");
+       strcpy(info->bus_info, "none");
+}
+
+static int oeth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       spin_lock_irq(&cep->lock);
+       mii_ethtool_gset(&cep->mii_if, ecmd);
+       spin_unlock_irq(&cep->lock);
+       return 0;
+}
+
+static int oeth_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       int res;
+       spin_lock_irq(&cep->lock);
+       res = mii_ethtool_sset(&cep->mii_if, ecmd);
+       spin_unlock_irq(&cep->lock);
+       return res;
+}
+
+static int oeth_nway_reset(struct net_device *dev)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       return mii_nway_restart(&cep->mii_if);
+}
+
+static u32 oeth_get_link(struct net_device *dev)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       return mii_link_ok(&cep->mii_if);
+}
+
+static struct ethtool_ops ethtool_ops = {
+       .get_drvinfo = oeth_get_drvinfo,
+       .get_link = oeth_get_link,
+       .get_settings = oeth_get_settings,
+       .set_settings = oeth_set_settings,
+       .nway_reset = oeth_nway_reset,
+};
+#endif
+
+/* MII Data accesses. */
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       struct oeth_regs *regs = cep->regs;
+       int read_value, i;
+       volatile int v;
+
+       regs->miiaddress = (phy_id & OETH_MIIADDRESS_FIAD)
+           | ((location << 8) & OETH_MIIADDRESS_RGAD);
+       regs->miicommand = OETH_MIICOMMAND_RSTAT;
+
+       /* Check if the MII is done. */
+       for (i = 10000; i >= 0; i--) {
+               v = regs->miistatus;
+               if (!(v & OETH_MIISTATUS_BUSY)) {
+                       read_value = regs->miirx_data;
+                       /* Don't leave miicommand in read status, it
+                        * seems to not be reset to 0 after completion. */
+                       regs->miicommand = 0;
+                       return read_value;
+               }
+       }
+       printk(KERN_ERR "mdio_read timeout %s\n", dev->name);
+       return -1;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location,
+                      int value)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       struct oeth_regs *regs = cep->regs;
+       int i;
+       volatile int v;
+       regs->miiaddress = (phy_id & OETH_MIIADDRESS_FIAD)
+           | ((location << 8) & OETH_MIIADDRESS_RGAD);
+       regs->miitx_data = value;
+       regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
+       /* Check if the MII is done. */
+       for (i = 10000; i >= 0; i--) {
+               v = regs->miistatus;
+               if (!(v & OETH_MIISTATUS_BUSY))
+                       return;
+       }
+       printk(KERN_ERR "mdio_write timeout %s\n", dev->name);
+}
+
+/* Initialize the Open Ethernet MAC. */
+static int oeth_init(struct net_device *dev, unsigned int base_addr,
+                    unsigned int irq)
+{
+       struct oeth_private *cep = netdev_priv(dev);
+       volatile struct oeth_regs *regs;
+       volatile struct oeth_bd *tx_bd, *rx_bd;
+       int i;
+       unsigned long mem_addr = OETH_SRAM_BUFF_BASE;
+
+       /* Initialize the locks. */
+       spin_lock_init(&cep->lock);
+       spin_lock_init(&cep->rx_lock);
+
+       /* Memory regions for the controller registers and buffer space. */
+       request_region(base_addr, OETH_REGS_SIZE, DRV_NAME);
+       dev->base_addr = base_addr;
+       request_region(OETH_SRAM_BUFF_BASE,
+                      OETH_TXBD_NUM * OETH_TX_BUFF_SIZE
+                      + OETH_RXBD_NUM * OETH_RX_BUFF_SIZE, DRV_NAME);
+       /* Get pointer ethernet controller configuration registers. */
+       regs = cep->regs = (struct oeth_regs *)(base_addr);
+
+       /* Reset the controller. */
+       regs->moder = OETH_MODER_RST;   /* Reset ON */
+       regs->moder &= ~OETH_MODER_RST; /* Reset OFF */
+
+       /* Setting TXBD base to OETH_TXBD_NUM. */
+       regs->tx_bd_num = OETH_TXBD_NUM;
+
+       /* Initialize TXBD pointer. */
+       cep->tx_bd_base = (struct oeth_bd *)OETH_BD_BASE;
+       tx_bd = cep->tx_bd_base;
+
+       /* Initialize RXBD pointer. */
+       cep->rx_bd_base = cep->tx_bd_base + OETH_TXBD_NUM;
+       rx_bd = cep->rx_bd_base;
+
+       /* Initialize receive/transmit pointers. */
+       cep->rx_cur = 0;
+       cep->tx_next = 0;
+       cep->tx_last = 0;
+       cep->tx_full = 0;
+
+       /* Set min (64) and max (1536) packet length. */
+       regs->packet_len = (64 << 16) | 1536;
+
+       /* Set IPGT, IPGR1, IPGR2 and COLLCONF registers to the
+        * recommended values. */
+       regs->ipgt = 0x00000015;
+       regs->ipgr1 = 0x0000000c;
+       regs->ipgr2 = 0x00000012;
+       regs->collconf = 0x000f003f;
+
+       /* Set control module mode. Do not deal with PAUSE frames for now. */
+       regs->ctrlmoder = 0;
+
+#if CONFIG_MII
+       /* Initialize MII. */
+       cep->mii_if.dev = dev;
+       cep->mii_if.mdio_read = mdio_read;
+       cep->mii_if.mdio_write = mdio_write;
+       cep->mii_if.phy_id = OETH_PHY_ID;
+       cep->mii_if.phy_id_mask = OETH_MIIADDRESS_FIAD;
+       cep->mii_if.reg_num_mask = 0x1f;
+       SET_ETHTOOL_OPS(dev, &ethtool_ops);
+#endif
+
+       /* Platform specific initialization. This function should set
+          at least set regs->mac_addr1 and regs->mac_addr2. */
+       OETH_PLATFORM_SPECIFIC_INIT(regs);
+
+       /* Initialize TXBDs. */
+       for (i = 0; i < OETH_TXBD_NUM; i++) {
+               tx_bd[i].len_status =
+                   OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_TX_BD_IRQ;
+               tx_bd[i].addr = mem_addr;
+               mem_addr += OETH_TX_BUFF_SIZE;
+       }
+       tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
+
+       /* Initialize RXBDs. */
+       for (i = 0; i < OETH_RXBD_NUM; i++) {
+               rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
+               rx_bd[i].addr = mem_addr;
+               mem_addr += OETH_RX_BUFF_SIZE;
+       }
+       rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP;
+
+       /* Set default ethernet MAC address. */
+       dev->dev_addr[0] = (regs->mac_addr1 >> 8) & 0xff;
+       dev->dev_addr[1] = regs->mac_addr1 & 0xff;
+       dev->dev_addr[2] = (regs->mac_addr0 >> 24) & 0xff;
+       dev->dev_addr[3] = (regs->mac_addr0 >> 16) & 0xff;
+       dev->dev_addr[4] = (regs->mac_addr0 >> 8) & 0xff;
+       dev->dev_addr[5] = regs->mac_addr0 & 0xff;
+
+       /* Clear all pending interrupts. */
+       regs->int_src = 0xffffffff;
+
+       /* Promisc, IFG, CRCEn  */
+       regs->moder |= OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN;
+
+       /* Enable interrupt sources. */
+       regs->int_mask = OETH_INT_MASK_TXB | OETH_INT_MASK_TXE
+           | OETH_INT_MASK_RXF | OETH_INT_MASK_RXE
+           | OETH_INT_MASK_TXC | OETH_INT_MASK_RXC | OETH_INT_MASK_BUSY;
+
+       /* The Open Ethernet specific entries in the device structure. */
+       dev->open            = oeth_open;
+       dev->hard_start_xmit = oeth_start_xmit;
+       dev->stop            = oeth_close;
+       dev->get_stats       = oeth_get_stats;
+       dev->set_mac_address = oeth_set_mac_address;
+       dev->poll            = oeth_poll;
+       dev->weight          = OETH_RXBD_NUM * 2;
+       dev->irq             = irq;
+       /* FIXME: Something needs to be done with dev->tx_timeout and
+          dev->watchdog timeout here. */
+
+       printk(KERN_INFO "Open Ethernet Core Version 1.0\n");
+
+       return 0;
+}
+
+static struct net_device *oeth_dev;
+
+static int __init oeth_init_module(void)
+{
+       oeth_dev = oeth_probe(0);
+       if (!oeth_dev)
+               return PTR_ERR(oeth_dev);
+       return 0;
+}
+
+static void __exit oeth_cleanup_module(void)
+{
+       unregister_netdev(oeth_dev);
+       release_region(oeth_dev->base_addr, OETH_REGS_SIZE);
+       release_region(OETH_SRAM_BUFF_BASE,
+                      OETH_TXBD_NUM * OETH_TX_BUFF_SIZE
+                      + OETH_RXBD_NUM * OETH_RX_BUFF_SIZE);
+       free_netdev(oeth_dev);
+}
+
+module_init(oeth_init_module);
+module_exit(oeth_cleanup_module);
+
+MODULE_DESCRIPTION("Opencores ethernet driver.");
+MODULE_LICENSE("GPL");
--- /dev/null   2006-09-20 11:38:04.545479250 -0700
+++ drivers/net/open_eth.h      2006-12-04 15:00:55.000000000 -0800
@@ -0,0 +1,132 @@
+/* Ethernet configuration registers */
+struct oeth_regs {
+       u32 moder;              /* Mode Register */
+       u32 int_src;            /* Interrupt Source Register */
+       u32 int_mask;           /* Interrupt Mask Register */
+       u32 ipgt;               /* Back to Bak Inter Packet Gap Register */
+       u32 ipgr1;              /* Non Back to Back Inter Packet Gap Register 1 
*/
+       u32 ipgr2;              /* Non Back to Back Inter Packet Gap Register 2 
*/
+       u32 packet_len;         /* Packet Length Register (min. and max.) */
+       u32 collconf;           /* Collision and Retry Configuration Register */
+       u32 tx_bd_num;          /* Transmit Buffer Descriptor Number Register */
+       u32 ctrlmoder;          /* Control Module Mode Register */
+       u32 miimoder;           /* MII Mode Register */
+       u32 miicommand;         /* MII Command Register */
+       u32 miiaddress;         /* MII Address Register */
+       u32 miitx_data;         /* MII Transmit Data Register */
+       u32 miirx_data;         /* MII Receive Data Register */
+       u32 miistatus;          /* MII Status Register */
+       u32 mac_addr0;          /* MAC Individual Address Register 0 */
+       u32 mac_addr1;          /* MAC Individual Address Register 1 */
+       u32 hash_addr0;         /* Hash Register 0 */
+       u32 hash_addr1;         /* Hash Register 1 */
+};
+
+/* Ethernet buffer descriptor */
+struct oeth_bd {
+       u32 len_status;
+       u32 addr;               /* Buffer address */
+};
+
+/* Tx BD */
+#define OETH_TX_BD_READY        0x8000 /* Tx BD Ready */
+#define OETH_TX_BD_IRQ          0x4000 /* Tx BD IRQ Enable */
+#define OETH_TX_BD_WRAP         0x2000 /* Tx BD Wrap (last BD) */
+#define OETH_TX_BD_PAD          0x1000 /* Tx BD Pad Enable */
+#define OETH_TX_BD_CRC          0x0800 /* Tx BD CRC Enable */
+
+#define OETH_TX_BD_UNDERRUN     0x0100 /* Tx BD Underrun Status */
+#define OETH_TX_BD_RETRY        0x00F0 /* Tx BD Retry Status */
+#define OETH_TX_BD_RETLIM       0x0008 /* Tx BD Retransmission Limit Status */
+#define OETH_TX_BD_LATECOL      0x0004 /* Tx BD Late Collision Status */
+#define OETH_TX_BD_DEFER        0x0002 /* Tx BD Defer Status */
+#define OETH_TX_BD_CARRIER      0x0001 /* Tx BD Carrier Sense Lost Status */
+#define OETH_TX_BD_STATS        (OETH_TX_BD_UNDERRUN            | \
+                                OETH_TX_BD_RETRY                | \
+                                OETH_TX_BD_RETLIM               | \
+                                OETH_TX_BD_LATECOL              | \
+                                OETH_TX_BD_DEFER                | \
+                                OETH_TX_BD_CARRIER)
+
+/* Rx BD */
+#define OETH_RX_BD_EMPTY        0x8000 /* Rx BD Empty */
+#define OETH_RX_BD_IRQ          0x4000 /* Rx BD IRQ Enable */
+#define OETH_RX_BD_WRAP         0x2000 /* Rx BD Wrap (last BD) */
+
+#define OETH_RX_BD_MISS         0x0080 /* Rx BD Miss Status */
+#define OETH_RX_BD_OVERRUN      0x0040 /* Rx BD Overrun Status */
+#define OETH_RX_BD_INVSIMB      0x0020 /* Rx BD Invalid Symbol Status */
+#define OETH_RX_BD_DRIBBLE      0x0010 /* Rx BD Dribble Nibble Status */
+#define OETH_RX_BD_TOOLONG      0x0008 /* Rx BD Too Long Status */
+#define OETH_RX_BD_SHORT        0x0004 /* Rx BD Too Short Frame Status */
+#define OETH_RX_BD_CRCERR       0x0002 /* Rx BD CRC Error Status */
+#define OETH_RX_BD_LATECOL      0x0001 /* Rx BD Late Collision Status */
+#define OETH_RX_BD_STATS        (OETH_RX_BD_MISS                | \
+                                OETH_RX_BD_OVERRUN              | \
+                                OETH_RX_BD_INVSIMB              | \
+                                OETH_RX_BD_DRIBBLE              | \
+                                OETH_RX_BD_TOOLONG              | \
+                                OETH_RX_BD_SHORT                | \
+                                OETH_RX_BD_CRCERR               | \
+                                OETH_RX_BD_LATECOL)
+
+/* MODER Register */
+#define OETH_MODER_RXEN         0x00000001     /* Receive Enable  */
+#define OETH_MODER_TXEN         0x00000002     /* Transmit Enable */
+#define OETH_MODER_NOPRE        0x00000004     /* No Preamble  */
+#define OETH_MODER_BRO          0x00000008     /* Reject Broadcast */
+#define OETH_MODER_IAM          0x00000010     /* Use Individual Hash */
+#define OETH_MODER_PRO          0x00000020     /* Promiscuous (receive all) */
+#define OETH_MODER_IFG          0x00000040     /* Min. IFG not required */
+#define OETH_MODER_LOOPBCK      0x00000080     /* Loop Back */
+#define OETH_MODER_NOBCKOF      0x00000100     /* No Backoff */
+#define OETH_MODER_EXDFREN      0x00000200     /* Excess Defer */
+#define OETH_MODER_FULLD        0x00000400     /* Full Duplex */
+#define OETH_MODER_RST          0x00000800     /* Reset MAC */
+#define OETH_MODER_DLYCRCEN     0x00001000     /* Delayed CRC Enable */
+#define OETH_MODER_CRCEN        0x00002000     /* CRC Enable */
+#define OETH_MODER_HUGEN        0x00004000     /* Huge Enable */
+#define OETH_MODER_PAD          0x00008000     /* Pad Enable */
+#define OETH_MODER_RECSMALL     0x00010000     /* Receive Small */
+
+/* Interrupt Source Register */
+#define OETH_INT_TXB            0x00000001     /* Transmit Buffer IRQ */
+#define OETH_INT_TXE            0x00000002     /* Transmit Error IRQ */
+#define OETH_INT_RXF            0x00000004     /* Receive Frame IRQ */
+#define OETH_INT_RXE            0x00000008     /* Receive Error IRQ */
+#define OETH_INT_BUSY           0x00000010     /* Busy IRQ */
+#define OETH_INT_TXC            0x00000020     /* Transmit Control Frame IRQ */
+#define OETH_INT_RXC            0x00000040     /* Received Control Frame IRQ */
+
+/* Interrupt Mask Register */
+#define OETH_INT_MASK_TXB       0x00000001     /* Transmit Buffer IRQ Mask */
+#define OETH_INT_MASK_TXE       0x00000002     /* Transmit Error IRQ Mask */
+#define OETH_INT_MASK_RXF       0x00000004     /* Receive Frame IRQ Mask */
+#define OETH_INT_MASK_RXE       0x00000008     /* Receive Error IRQ Mask */
+#define OETH_INT_MASK_BUSY      0x00000010     /* Busy IRQ Mask */
+#define OETH_INT_MASK_TXC       0x00000020     /* Transmit Control Frame IRQ 
Mask */
+#define OETH_INT_MASK_RXC       0x00000040     /* Received Control Frame IRQ 
Mask */
+
+/* Control Module Mode Register */
+#define OETH_CTRLMODER_PASSALL  0x00000001     /* Pass Control Frames */
+#define OETH_CTRLMODER_RXFLOW   0x00000002     /* Receive Control Flow Enable 
*/
+#define OETH_CTRLMODER_TXFLOW   0x00000004     /* Transmit Control Flow Enable 
*/
+
+/* MII Mode Register */
+#define OETH_MIIMODER_CLKDIV    0x000000FF     /* Clock Divider */
+#define OETH_MIIMODER_NOPRE     0x00000100     /* No Preamble */
+#define OETH_MIIMODER_RST       0x00000200     /* MIIM Reset */
+
+/* MII Command Register */
+#define OETH_MIICOMMAND_SCANSTAT  0x00000001   /* Scan Status */
+#define OETH_MIICOMMAND_RSTAT     0x00000002   /* Read Status */
+#define OETH_MIICOMMAND_WCTRLDATA 0x00000004   /* Write Control Data */
+
+/* MII Address Register */
+#define OETH_MIIADDRESS_FIAD    0x0000001F     /* PHY Address */
+#define OETH_MIIADDRESS_RGAD    0x00001F00     /* RGAD Address */
+
+/* MII Status Register */
+#define OETH_MIISTATUS_LINKFAIL 0x00000001     /* Link Fail */
+#define OETH_MIISTATUS_BUSY     0x00000002     /* MII Busy */
+#define OETH_MIISTATUS_NVALID   0x00000004     /* Data in MII Status Register 
is invalid */
--- drivers/net/Kconfig~        2006-09-05 12:30:28.000000000 -0700
+++ drivers/net/Kconfig 2006-12-01 11:29:25.000000000 -0800
@@ -550,6 +550,11 @@
         help
           If you have an XT2000 board, you probably want to enable this driver.
 
+config OPENCORES_ETHERNET
+       tristate "Opencores.org Ethernet MAC driver"
+       depends on NET_ETHERNET
+       help
+         
 config SUNBMAC
        tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)"
        depends on NET_ETHERNET && SBUS && EXPERIMENTAL
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to