lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 04 Dec 2006 10:01:01 -0800
From:	Dan Nicolaescu <dann@....uci.edu>
To:	netdev@...r.kernel.org
Subject: [RFC patch] driver for the Opencores Ethernet Controller


Hi,

Here is a driver for the Opencores Ethernet Controller. I started from
a 2.4 uClinux driver, ported it to 2.6, made it work, cleaned it up
and added the MII interface. 

The Opencores Ethernet Controller is Verilog code that can be used to
implement an Ethernet device in hardware. It needs to be coupled with
a PHY and some buffer memory. Because of that devices that implement
this controller can be very different. The code here tries to support
that by having some parameters that need to be defined at compile
time.

This is my first Ethernet driver, so comments/advice would be
appreciated.

Thanks
        --dan

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


--- /dev/null	2006-09-20 11:38:04.545479250 -0700
+++ drivers/net/open_eth.c	2006-12-04 09:20:17.000000000 -0800
@@ -0,0 +1,1022 @@
+/*
+ * Ethernet driver for Open Ethernet Controller (www.opencores.org).
+ *      Copyright (c) 2002 Simon Srot (simons@...ncores.org)
+ *      Copyright (c) 2006 Tensilica Inc.
+ * 
+ * Based on:
+ *
+ * Ethernet driver for Motorola MPC8xx.
+ *      Copyright (c) 1997 Dan Malek (dmalek@....net)
+ *
+ * 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 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. */
+
+#if 1
+#undef OETH_TXBD_NUM
+#undef OETH_RXBD_NUM
+#define OETH_RXBD_NUM           4
+#define OETH_TXBD_NUM           4
+/* #undef OETH_RX_BUFF_SIZE */
+/* #undef OETH_TX_BUFF_SIZE */
+/* #define OETH_RX_BUFF_SIZE       0x600 */
+/* #define OETH_TX_BUFF_SIZE       0x600 */
+#endif
+
+#define BUFFER_SCREWED 1
+/* #define BUFFER_SCREWED_ADDR (OETH_SRAM_BUFF_BASE + OETH_TXBD_NUM * OETH_TX_BUFF_SIZE + OETH_RXBD_NUM * OETH_RX_BUFF_SIZE + 4) */
+#define BUFFER_SCREWED_ADDR (0xfd803800 + 0x600)
+
+/* 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 */
+
+#if CONFIG_MII	
+	struct mii_if_info mii_if;	/* MII lib hooks/info */
+#endif	
+	spinlock_t       lock;
+	struct net_device_stats stats;
+};
+
+static int oeth_open(struct net_device *dev);
+static int oeth_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void oeth_rx(struct net_device *dev);
+/* FIXME: static  */void oeth_tx(struct net_device *dev);
+static irqreturn_t oeth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int oeth_close(struct net_device *dev);
+static struct net_device_stats *oeth_get_stats(struct net_device *dev);
+static void oeth_set_multicast_list(struct net_device *dev);
+static int oeth_set_mac_address(struct net_device *dev, void *addr);
+
+#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
+
+int dann_int_count = 0;
+int dann_rx_count = 0;
+int dann_tx_count = 0;
+
+static int oeth_open(struct net_device *dev)
+{
+	int ret;
+	struct oeth_private *cep = netdev_priv(dev);
+	struct oeth_regs *regs = cep->regs;
+
+	/*FIXME: just for debugging....*/
+	memset((void*)OETH_SRAM_BUFF_BASE, 0, 0x4000);
+	
+	/* Install our interrupt handler. */
+	ret = request_irq(OETH_IRQ, oeth_interrupt, 0, "eth", (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;
+}
+
+#if 1
+static void* memcpy_hton (void *dest, void *data,  size_t n)
+{
+	int i;
+	u32 *ldest = dest;
+	u32 *ldata = data;
+	if (n % 4) n += 4 - n % 4;
+	for (i = 0; i < n / 4; i++)
+		*ldest++ = /* htonl */ (*ldata++);
+	return dest;
+}
+
+static void* memcpy_ntoh (void *dest, void *data,  size_t n)
+{
+	int i;
+	u32 *ldest = dest;
+	u32 *ldata = data;
+	if (n % 4) n += 4 - n % 4;
+	for (i = 0; i < n / 4; i++)
+		*ldest++ = /* ntohl */ (*ldata++);
+	return dest;
+}
+#else
+#define memcpy_ntoh memcpy
+#define memcpy_hton memcpy
+#endif
+
+static void print_queue(struct oeth_bd *bdp, u16 crt, int max)
+{
+  int i;
+  printk ("Q  Crt element: %d\n", (u32) crt);
+  for (i = 0; i < max; bdp++, i++)
+    {
+      u32 val;
+      val = bdp->len_status;
+      printk("%d:%x (%x) ", val >> 16, val & 0xFFFF, bdp->addr);
+      if (!((i + 1) % 4))
+	printk ("\n");
+    }
+}
+
+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;
+	}
+	
+	/* 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) {
+		printk("%s: tx frame too long!.\n", dev->name);
+		spin_unlock_irqrestore(&cep->lock, flags);
+		return 1;
+	}
+
+	/* Copy data to TX buffer. */
+	memcpy_hton ((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(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);
+		cep->stats.tx_compressed++;
+	}
+
+	/* 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;
+
+	dann_int_count++;
+
+	spin_lock_irq(&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 (int_events & OETH_INT_BUSY)
+		cep->stats.rx_compressed++;
+	
+	/* Handle receive event in its own function. */
+	if (int_events & (OETH_INT_RXF | OETH_INT_RXE))
+		oeth_rx(dev);
+
+	/* Handle transmit event in its own function. */
+	if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
+		oeth_tx(dev);
+	}
+
+	/* Check for receive busy, i.e. packets coming but no place to
+	 * put them. */
+	if (int_events & OETH_INT_BUSY) {
+		if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))){
+/* 			dann_tx_count++; */
+			oeth_rx(dev);
+		}
+
+	}
+
+	spin_unlock_irq(&cep->lock);
+
+	return IRQ_HANDLED;
+}
+static u32 dann_last_val = 0;
+
+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 0		
+		if (len_status & (OETH_TX_BD_LATECOL | OETH_TX_BD_DEFER
+				  | OETH_TX_BD_UNDERRUN | OETH_TX_BD_RETRY))
+		{
+		  if (len_status & (OETH_TX_BD_DEFER | OETH_TX_BD_LATECOL)){
+		    if (len_status & OETH_TX_BD_DEFER)
+		      if (len_status & OETH_TX_BD_LATECOL)
+			printk ("defer late ");
+		      else
+			printk ("defer ");
+		    else
+		      if (len_status & OETH_TX_BD_LATECOL)
+			printk ("late ");
+		  }
+		  if (len_status & OETH_TX_BD_RETRY)
+		    printk ("retrys %d", (len_status & OETH_TX_BD_RETRY) >> 4);
+		  printk ("\n");
+		}
+#endif		
+		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;
+		dann_tx_count++;
+#if BUFFER_SCREWED
+			{
+				u32 *addr = (u32*)BUFFER_SCREWED_ADDR;
+				int i = 0;
+				while ((addr < OETH_SRAM_BUFF_BASE + 0x4000) && (*addr != 0)){
+					*addr = 0;
+					i++;
+					addr++;
+				}
+				if (i)
+					printk ("BUFFER screwed %d words !! TX=%d rx=%d \n", i, dann_tx_count, dann_rx_count);
+			  
+			}
+#endif
+		if (0 & ((*(u32*)0xfd801FFC != 0)
+		    || (*(u32*)0xfd8017FC != 0)
+		    || (*(u32*)0xfd800FFC != 0)
+		    || (*(u32*)0xfd8007FC != 0)))
+		  printk ("SCREWED end! TX=%d rx=%d\n", dann_tx_count, dann_rx_count);
+		  
+		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 void oeth_rx(struct net_device *dev)
+{
+	struct oeth_private *cep = netdev_priv(dev);
+	volatile struct oeth_bd *bdp;
+	struct	sk_buff *skb;
+	int bds_processed;
+	int	pkt_len;
+	int	bad = 0;
+	int current_buff = cep->rx_cur;
+	static int last_current_buff = 0;
+	int count = 0;
+	
+	for (bds_processed = 0; /* bds_processed < OETH_RXBD_NUM */;
+	     cep->rx_cur = (cep->rx_cur+1 == OETH_RXBD_NUM) ? 0 : (cep->rx_cur+1)) {
+		u32 len_status;
+		bds_processed++;
+		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;
+
+		/* Check status for errors. */
+		if (len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
+			cep->stats.rx_length_errors++;
+			printk ("Length Error! l=%8x a=%8x s=%4x\n", len_status >> 16, bdp->addr, len_status && 0xFFFF);
+			bad = 1;
+		}
+		if (len_status & OETH_RX_BD_DRIBBLE) {
+			cep->stats.rx_frame_errors++;
+			printk ("Frame Error! l=%8x a=%8x s=%4x\n", len_status >> 16, bdp->addr, len_status && 0xFFFF);
+			bad = 1;
+		}
+		if (len_status & OETH_RX_BD_CRCERR) {
+			cep->stats.rx_crc_errors++;
+			printk ("CRC Error! l=%8x a=%8x s=%4x\n", len_status >> 16, bdp->addr, len_status && 0xFFFF);
+			bad = 1;
+		}
+		if (len_status & OETH_RX_BD_OVERRUN) {
+			cep->stats.rx_crc_errors++;
+			printk ("RECEIVER OVERRUN! l=%8x a=%8x s=%4x\n", len_status >> 16, bdp->addr, len_status && 0xFFFF);
+			bad = 1;
+		}
+		if (len_status & OETH_RX_BD_TOOLONG) {
+			cep->stats.rx_crc_errors++;
+			printk ("RECEIVER TOOLONG! l=%8x a=%8x s=%4x\n", len_status >> 16, bdp->addr, len_status && 0xFFFF);
+			bad = 1;
+		}
+		if (len_status & OETH_RX_BD_MISS) {
+
+		}
+		if (len_status & OETH_RX_BD_LATECOL) {
+			cep->stats.rx_frame_errors++;
+			printk ("LateCol Error! l=%8x a=%8x s=%4x\n", len_status >> 16, bdp->addr, len_status && 0xFFFF);
+			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 = dev_alloc_skb(pkt_len);
+
+		if (skb == NULL) {
+			printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+			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);
+			OEDRX((printk("RX in memory\n")));
+			OEDRX((oeth_print_packet((u32*)skb->data, pkt_len)));
+			skb->protocol = eth_type_trans(skb,dev);
+			netif_rx(skb);
+			count++;
+			
+			cep->stats.rx_packets++;
+			cep->stats.rx_bytes += pkt_len;
+			if (((u32) bdp->addr + pkt_len)
+			    >= (OETH_SRAM_BUFF_BASE + OETH_TXBD_NUM
+				* OETH_TX_BUFF_SIZE
+				+ OETH_RXBD_NUM * OETH_RX_BUFF_SIZE))
+			  panic ("address exceeds the buffer!\n");
+			dann_rx_count++;
+#if BUFFER_SCREWED
+			{
+				u32 *addr = (u32*)BUFFER_SCREWED_ADDR;
+				u16 *shaddr = (u16*)BUFFER_SCREWED_ADDR;
+				int i = 0;
+				int consecutive = 0;
+				if ((*shaddr + 1) == *(shaddr + 1))
+				  consecutive = 1;
+				else consecutive = 0;
+
+				if (consecutive){
+					while ((*(shaddr - 1) == *shaddr - 1)
+					       && addr > OETH_SRAM_BUFF_BASE){
+						consecutive++;
+						shaddr--;
+					}
+				}
+				
+				while ((addr < OETH_SRAM_BUFF_BASE + 0x4000)
+				       && (*addr != 0)){
+					*addr = 0;
+					i++;
+					addr++;
+				}
+
+				if (i)
+					printk ("BUFFER screwed %d words !! tx=%d RX=%d consecutive=%d crt=%d lastcrt=%d\n", i, dann_tx_count, dann_rx_count, consecutive / 2, current_buff, last_current_buff);
+			  
+			}
+#endif			
+		}
+
+		bdp->len_status = (len_status & ~OETH_RX_BD_STATS)
+			| OETH_RX_BD_EMPTY;
+	}
+	last_current_buff = cep->rx_cur;
+
+
+	if (count == 0)
+		cep->stats.rx_length_errors++;
+	else if (count >= OETH_RXBD_NUM)
+		cep->stats.rx_over_errors++;
+	else
+		cep->stats.rx_crc_errors++;
+	
+}
+
+static int oeth_calc_crc(char *mac_addr)
+{
+	int result = 0;
+	return (result & 0x3f);
+}
+
+static struct net_device_stats *oeth_get_stats(struct net_device *dev)
+{
+	struct oeth_private *cep = netdev_priv(dev);
+	return &cep->stats;
+}
+
+static void oeth_set_multicast_list(struct net_device *dev)
+{
+	struct	dev_mc_list *dmi;
+	struct oeth_private *cep = netdev_priv(dev);
+	volatile struct oeth_regs *regs = cep->regs;
+	int	i;
+
+	if (dev->flags & IFF_PROMISC) {
+
+		/* Log any net taps. */
+		printk("%s: Promiscuous mode enabled.\n", dev->name);
+		regs->moder |= OETH_MODER_PRO;
+	} else {
+
+		regs->moder &= ~OETH_MODER_PRO;
+
+		if (dev->flags & IFF_ALLMULTI) {
+
+			/* Catch all multicast addresses, so set the
+			 * filter to all 1's. */
+			regs->hash_addr0 = 0xffffffff;
+			regs->hash_addr1 = 0xffffffff;
+		}
+		else if (dev->mc_count) {
+
+			/* Clear filter and add the addresses in the list. */
+			regs->hash_addr0 = 0x00000000;
+			regs->hash_addr0 = 0x00000000;
+
+			dmi = dev->mc_list;
+
+			for (i = 0; i < dev->mc_count; i++) {
+
+				int hash_b;
+
+				/* Only support group multicast for now. */
+				if (!(dmi->dmi_addr[0] & 1))
+					continue;
+
+				hash_b = oeth_calc_crc(dmi->dmi_addr);
+				if(hash_b >= 32)
+					regs->hash_addr1 |= 1 << (hash_b - 32);
+				else
+					regs->hash_addr0 |= 1 << hash_b;
+			}
+		}
+	}
+}
+
+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);
+	sprintf(dev->name, "eth%d", unit);
+
+	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 int check_if_running(struct net_device *dev)
+{
+	if (!netif_running(dev))
+		return -EINVAL;
+	return 0;
+}
+
+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"/*  pci_name(cep->pci_dev) */);
+}
+
+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 = {
+	.begin		   = check_if_running,
+	.get_drvinfo	   = oeth_get_drvinfo,
+	.get_settings	   = oeth_get_settings,
+	.set_settings	   = oeth_set_settings,
+	.nway_reset	   = oeth_nway_reset,
+	.get_link	   = oeth_get_link,
+	.get_strings	   = ethtool_op_net_device_stats_get_strings,
+	.get_stats_count   = ethtool_op_net_device_stats_get_stats_count,
+	.get_ethtool_stats = ethtool_op_net_device_get_ethtool_stats,
+};
+
+/* 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;
+}
+#endif
+
+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;
+
+	/* Reset the private structure. */
+	memset(cep, 0, sizeof (struct oeth_private));
+
+	/* Initialize the lock. */
+	spin_lock_init(&cep->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); */
+do {									
+    	/* Set the clock divider to 2 (50MHz / 2) */			
+	regs->miimoder = (OETH_MIIMODER_CLKDIV & 0x2);			
+
+	/* Reset the PHY. */
+	{
+		int i, res;
+		mdio_write(dev, cep->mii_if.phy_id, MII_BMCR, BMCR_RESET);
+		/* Wait until the reset is complete. */
+		for (i = 10000; i >= 0; i--){
+			res = mdio_read(dev, cep->mii_if.phy_id, MII_BMCR);
+			if (!(res & BMCR_RESET))
+				break;
+		}
+		if (res & BMCR_RESET) {
+			printk(KERN_ERR "%s PHY reset timeout BMCR:0x%08x!\n", dev->name, res);
+			return -1;
+		}
+	}
+	
+	/* Tell the PHY to turn on the activity LED. */			
+	mdio_write(dev, 0, MII_TPISTATUS, 0xce);
+	
+	
+	{
+	  /* Test code to setup the networking parameters according to
+	     the DIP switches. */
+	  u32 net_settings = ((*(u32*)DIP_SWITCHES_ADDR) & 0xc0) >> 6;
+	  if (net_settings){
+		  /* Disable autonegotiation in order to disable full duplex. */
+		  u32 cword;
+		  if (net_settings & 1)
+			  /* half duplex requested */
+			  cword = 0x0000;
+		  else
+			  cword = BMCR_FULLDPLX;
+		  
+		  if (net_settings & 2)
+			  /* 10 Mbit requested */
+			  cword |= 0x0000;
+		  else
+			  cword |= BMCR_SPEED100;
+		  
+		  mdio_write(dev, 0, MII_BMCR, cword);
+	  }
+	}
+	
+
+	
+	/* Initialize the MAC address. */
+	regs->mac_addr1 = OETH_MACADDR0 << 8 | OETH_MACADDR1;		
+	regs->mac_addr0 = OETH_MACADDR2 << 24 | OETH_MACADDR3 << 16	
+		| OETH_MACADDR4 << 8 | ((*(u32*)DIP_SWITCHES_ADDR) & 0x3f);	
+									
+ } while (0);
+	
+	/* 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;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	/* 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_multicast_list = oeth_set_multicast_list;
+	dev->set_mac_address	= oeth_set_mac_address;
+	dev->irq		= irq;
+	/* FIXME: Something needs to be done with dev->tx_timeout and
+	   dev->watchdog timeout here. */
+
+	printk("%s: Open Ethernet Core Version 1.0\n", dev->name);
+
+	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-11-28 11:07:43.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 majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ