[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <200612041801.kB4I11F4018165@oogie-boogie.ics.uci.edu>
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, ðtool_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