On Mon, Jun 26, 2006 at 04:59:24AM +0200, Lennert Buytenhek wrote: > The cirrus ep93xx is an ARM SoC that includes an ethernet MAC -- > this patch adds a driver for that ethernet MAC.
Attached is a new version that optimises interrupt handling somewhat. Since we clear RX status as the first thing we do in the poll handler, we might as well read the read-to-clear version of the interrupt status register in the interrupt handler and avoid the explicit clear in the poll handler. This shaves close to a second off a 128M sendfile() test. At ~40 seconds for a 128M sendfile (~3.2MB/sec), the network performance of this CPU isn't impressive by any means, but given that the CPU only runs at 200MHz and that the MAC doesn't do checksum offloading and insists on 4-byte buffer alignment, we can't really do a whole lot better. The performance with this driver is still a good deal better than with the vendor driver, though -- for this particular test (128M sendfile), the vendor driver needs 1m21s. Apart from that it still uses numeric chip register addresses, I'm quite happy with the driver as it is, it survives heavy beating and is pretty stable. Index: linux-2.6.17-git10/drivers/net/arm/Kconfig =================================================================== --- linux-2.6.17-git10.orig/drivers/net/arm/Kconfig +++ linux-2.6.17-git10/drivers/net/arm/Kconfig @@ -39,3 +39,10 @@ config ARM_AT91_ETHER help If you wish to compile a kernel for the AT91RM9200 and enable ethernet support, then you should always answer Y to this. + +config EP93XX_ETH + tristate "EP93xx Ethernet support" + depends on NET_ETHERNET && ARM && ARCH_EP93XX + help + This is a driver for the ethernet hardware included in EP93xx CPUs. + Say Y if you are building a kernel for EP93xx based devices. Index: linux-2.6.17-git10/drivers/net/arm/Makefile =================================================================== --- linux-2.6.17-git10.orig/drivers/net/arm/Makefile +++ linux-2.6.17-git10/drivers/net/arm/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_ARM_ETHERH) += etherh.o obj-$(CONFIG_ARM_ETHER3) += ether3.o obj-$(CONFIG_ARM_ETHER1) += ether1.o obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o +obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o Index: linux-2.6.17-git10/drivers/net/arm/ep93xx_eth.c =================================================================== --- /dev/null +++ linux-2.6.17-git10/drivers/net/arm/ep93xx_eth.c @@ -0,0 +1,668 @@ +/* + * EP93xx ethernet network device driver + * Copyright (C) 2006 Lennert Buytenhek <[EMAIL PROTECTED]> + * Dedicated to Marija Kulikova. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/config.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <asm/arch/ep93xx-regs.h> +#include <asm/arch/platform.h> +#include <asm/io.h> +#include "ep93xx_eth.h" + +#define DRV_MODULE_VERSION "0.1" + +#define RX_QUEUE_ENTRIES 64 +#define TX_QUEUE_ENTRIES 8 + +struct ep93xx_descs +{ + struct ep93xx_rdesc rdesc[RX_QUEUE_ENTRIES]; + struct ep93xx_tdesc tdesc[TX_QUEUE_ENTRIES]; + struct ep93xx_rstat rstat[RX_QUEUE_ENTRIES]; + struct ep93xx_tstat tstat[TX_QUEUE_ENTRIES]; +}; + +struct ep93xx_priv +{ + struct resource *res; + void *base_addr; + int irq; + + struct ep93xx_descs *descs; + dma_addr_t descs_dma_addr; + + void *rx_buf[RX_QUEUE_ENTRIES]; + void *tx_buf[TX_QUEUE_ENTRIES]; + + int rx_pointer; + int tx_clean_pointer; + int tx_pointer; + int tx_pending; + + struct net_device_stats stats; +}; + +#define rdb(ep, off) __raw_readb((ep)->base_addr + (off)) +#define rdw(ep, off) __raw_readw((ep)->base_addr + (off)) +#define rdl(ep, off) __raw_readl((ep)->base_addr + (off)) +#define wrb(ep, off, val) __raw_writeb((val), (ep)->base_addr + (off)) +#define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off)) +#define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off)) + +static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + int entry; + + if (unlikely(skb->len) > PAGE_SIZE) { + ep->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; + } + + entry = ep->tx_pointer; + ep->tx_pointer = (ep->tx_pointer + 1) % TX_QUEUE_ENTRIES; + + ep->descs->tdesc[entry].tdesc1 = + TDESC1_EOF | (entry << 16) | (skb->len & 0xfff); + skb_copy_and_csum_dev(skb, ep->tx_buf[entry]); + dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr, + skb->len, DMA_TO_DEVICE); + dev_kfree_skb(skb); + + dev->trans_start = jiffies; + + local_irq_disable(); + ep->tx_pending++; + if (ep->tx_pending == TX_QUEUE_ENTRIES) + netif_stop_queue(dev); + local_irq_enable(); + + wrl(ep, 0x00bc, 1); + + return 0; +} + +static int ep93xx_rx(struct net_device *dev, int *budget) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + int tail_offset; + int rx_done; + int processed; + + tail_offset = rdl(ep, 0x00a8) - ep->descs_dma_addr; + + rx_done = 0; + processed = 0; + while (*budget > 0) { + int entry; + struct ep93xx_rstat *rstat; + u32 rstat0; + u32 rstat1; + int length; + struct sk_buff *skb; + + entry = ep->rx_pointer; + rstat = ep->descs->rstat + entry; + if ((void *)rstat - (void *)ep->descs == tail_offset) { + rx_done = 1; + break; + } + + rstat0 = rstat->rstat0; + rstat1 = rstat->rstat1; + rstat->rstat0 = 0; + rstat->rstat1 = 0; + + if (!(rstat0 & RSTAT0_RFP)) { + printk(KERN_CRIT "ep93xx_rx: buffer not done " + " %.8x %.8x\n", rstat0, rstat1); + BUG(); + } + if (!(rstat0 & RSTAT0_EOF)) { + printk(KERN_CRIT "ep93xx_rx: not end-of-frame " + " %.8x %.8x\n", rstat0, rstat1); + BUG(); + } + if (!(rstat0 & RSTAT0_EOB)) { + printk(KERN_CRIT "ep93xx_rx: not end-of-buffer " + " %.8x %.8x\n", rstat0, rstat1); + BUG(); + } + if (!(rstat1 & RSTAT1_RFP)) { + printk(KERN_CRIT "ep93xx_rx: buffer1 not done " + " %.8x %.8x\n", rstat0, rstat1); + BUG(); + } + if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry) { + printk(KERN_INFO "ep93xx_rx: entry mismatch " + " %.8x %.8x\n", rstat0, rstat1); + BUG(); + } + + if (!(rstat0 & RSTAT0_RWE)) { + printk(KERN_NOTICE "ep93xx_rx: receive error " + " %.8x %.8x\n", rstat0, rstat1); + + ep->stats.rx_errors++; + if (rstat0 & RSTAT0_OE) + ep->stats.rx_fifo_errors++; + if (rstat0 & RSTAT0_FE) + ep->stats.rx_frame_errors++; + if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA)) + ep->stats.rx_length_errors++; + if (rstat0 & RSTAT0_CRCE) + ep->stats.rx_crc_errors++; + goto err; + } + + length = rstat1 & RSTAT1_FRAME_LENGTH; + if (length < 4 || length > PAGE_SIZE) { + printk(KERN_NOTICE "ep93xx_rx: invalid length " + " %.8x %.8x\n", rstat0, rstat1); + goto err; + } + + /* Strip FCS. */ + if (rstat0 & RSTAT0_CRCI) + length -= 4; + + skb = dev_alloc_skb(length + 2); + if (likely(skb != NULL)) { + skb->dev = dev; + skb_reserve(skb, 2); + dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr, + length, DMA_FROM_DEVICE); + eth_copy_and_sum(skb, ep->rx_buf[entry], length, 0); + skb_put(skb, length); + skb->protocol = eth_type_trans(skb, dev); + + dev->last_rx = jiffies; + + netif_receive_skb(skb); + + ep->stats.rx_packets++; + ep->stats.rx_bytes += length; + } else { + ep->stats.rx_dropped++; + } + +err: + ep->rx_pointer = (entry + 1) % RX_QUEUE_ENTRIES; + processed++; + dev->quota--; + (*budget)--; + } + + if (processed) { + wrw(ep, 0x009c, processed); + wrw(ep, 0x00ac, processed); + } + + return !rx_done; +} + +static int ep93xx_have_more_rx(struct ep93xx_priv *ep) +{ + struct ep93xx_rstat *rstat; + int tail_offset; + + rstat = ep->descs->rstat + ep->rx_pointer; + tail_offset = rdl(ep, 0x00a8) - ep->descs_dma_addr; + + return !((void *)rstat - (void *)ep->descs == tail_offset); +} + +static int ep93xx_poll(struct net_device *dev, int *budget) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + + /* @@@ Have to stop polling when device is downed while we + * are polling. */ + +poll_some_more: + if (ep93xx_rx(dev, budget)) + return 1; + + netif_rx_complete(dev); + + local_irq_disable(); + wrl(ep, 0x0024, 0x0000000f); + if (ep93xx_have_more_rx(ep)) { + wrl(ep, 0x0024, 0x00000008); + wrl(ep, 0x0028, 0x00000004); + local_irq_enable(); + + if (netif_rx_reschedule(dev, 0)) + goto poll_some_more; + + return 0; + } + local_irq_enable(); + + return 0; +} + +static void ep93xx_tx_complete(struct net_device *dev) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + int tail_offset; + int wake; + + tail_offset = rdl(ep, 0x00c8) - ep->descs_dma_addr; + + wake = 0; + while (1) { + int entry; + struct ep93xx_tstat *tstat; + u32 tstat0; + + entry = ep->tx_clean_pointer; + tstat = ep->descs->tstat + entry; + if ((void *)tstat - (void *)ep->descs == tail_offset) + break; + + tstat0 = tstat->tstat0; + tstat->tstat0 = 0; + + if (!(tstat0 & TSTAT0_TXFP)) { + printk(KERN_CRIT "ep93xx_tx_complete: buffer not done " + " %.8x\n", tstat0); + BUG(); + } + if (tstat0 & TSTAT0_FA) { + printk(KERN_CRIT "ep93xx_tx_complete: frame aborted " + " %.8x\n", tstat0); + BUG(); + } + if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry) { + printk(KERN_INFO "ep93xx_tx_complete: entry mismatch " + " %.8x\n", tstat0); + BUG(); + } + + if (tstat0 & TSTAT0_TXWE) { + int length = ep->descs->tdesc[entry].tdesc1 & 0xfff; + + ep->stats.tx_packets++; + ep->stats.tx_bytes += length; + } else { + ep->stats.tx_errors++; + } + if (tstat0 & TSTAT0_LCRS) + ep->stats.tx_carrier_errors++; + if (tstat0 & TSTAT0_OW) + ep->stats.tx_window_errors++; + if (tstat0 & TSTAT0_TXU) + ep->stats.tx_fifo_errors++; + ep->stats.collisions += (tstat0 >> 16) & 0x1f; + + ep->tx_clean_pointer = (entry + 1) % TX_QUEUE_ENTRIES; + if (ep->tx_pending == TX_QUEUE_ENTRIES) + wake = 1; + ep->tx_pending--; + } + + if (wake) + netif_wake_queue(dev); +} + +static irqreturn_t ep93xx_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct ep93xx_priv *ep = netdev_priv(dev); + u32 status; + + status = rdl(ep, 0x002c); + if (status == 0) + return IRQ_NONE; + + if (status & 0x00000004) { + if (likely(__netif_rx_schedule_prep(dev))) { + wrl(ep, 0x0024, 0x00000008); + __netif_rx_schedule(dev); + } + } + + if (status & 0x00000008) + ep93xx_tx_complete(dev); + + return IRQ_HANDLED; +} + +static void ep93xx_free_buffers(struct ep93xx_priv *ep) +{ + int i; + + for (i = 0; i < RX_QUEUE_ENTRIES; i++) { + dma_addr_t d; + + d = ep->descs->rdesc[i].buf_addr; + if (d) + dma_unmap_single(NULL, d, PAGE_SIZE, DMA_FROM_DEVICE); + + if (ep->rx_buf[i] != NULL) + free_page((unsigned long)ep->rx_buf[i]); + } + + for (i = 0; i < TX_QUEUE_ENTRIES; i++) { + dma_addr_t d; + + d = ep->descs->tdesc[i].buf_addr; + if (d) + dma_unmap_single(NULL, d, PAGE_SIZE, DMA_TO_DEVICE); + + if (ep->tx_buf[i] != NULL) + free_page((unsigned long)ep->tx_buf[i]); + } + + dma_free_coherent(NULL, sizeof(struct ep93xx_descs), ep->descs, + ep->descs_dma_addr); +} + +static int ep93xx_alloc_buffers(struct ep93xx_priv *ep) +{ + int i; + + ep->descs = dma_alloc_coherent(NULL, sizeof(struct ep93xx_descs), + &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA); + if (ep->descs == NULL) + return 1; + + for (i = 0; i < RX_QUEUE_ENTRIES; i++) { + void *page; + dma_addr_t d; + + page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (page == NULL) + goto err; + + d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(d)) { + free_page((unsigned long)page); + goto err; + } + + ep->rx_buf[i] = page; + ep->descs->rdesc[i].buf_addr = d; + ep->descs->rdesc[i].rdesc1 = (i << 16) | PAGE_SIZE; + } + + for (i = 0; i < TX_QUEUE_ENTRIES; i++) { + void *page; + dma_addr_t d; + + page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (page == NULL) + goto err; + + d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(d)) { + free_page((unsigned long)page); + goto err; + } + + ep->tx_buf[i] = page; + ep->descs->tdesc[i].buf_addr = d; + } + + return 0; + +err: + ep93xx_free_buffers(ep); + return 1; +} + +static void ep93xx_start_hw(struct net_device *dev) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + unsigned long addr; + + wrl(ep, 0x0020, 0x00000001); + while (rdl(ep, 0x0020) & 0x00000001) + ; + + /* Receive descriptor ring. */ + addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rdesc); + wrl(ep, 0x0090, addr); + wrl(ep, 0x0098, addr); + wrw(ep, 0x0094, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rdesc)); + + /* Receive status ring. */ + addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rstat); + wrl(ep, 0x00a0, addr); + wrl(ep, 0x00a8, addr); + wrw(ep, 0x00a4, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rstat)); + + /* Transmit descriptor ring. */ + addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tdesc); + wrl(ep, 0x00b0, addr); + wrl(ep, 0x00b8, addr); + wrw(ep, 0x00b4, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tdesc)); + + /* Transmit status ring. */ + addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tstat); + wrl(ep, 0x00c0, addr); + wrl(ep, 0x00c8, addr); + wrw(ep, 0x00c4, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tstat)); + + wrl(ep, 0x0080, 0x00000101); // bmctl + wrl(ep, 0x0024, 0x0000000f); // inten + wrl(ep, 0x0064, 0x00000000); // gintmask + while (!(rdl(ep, 0x0084) & 0x00000008)) + cpu_relax(); + wrl(ep, 0x009c, RX_QUEUE_ENTRIES); + wrl(ep, 0x00ac, RX_QUEUE_ENTRIES); + + wrb(ep, 0x0050, dev->dev_addr[0]); + wrb(ep, 0x0051, dev->dev_addr[1]); + wrb(ep, 0x0052, dev->dev_addr[2]); + wrb(ep, 0x0053, dev->dev_addr[3]); + wrb(ep, 0x0054, dev->dev_addr[4]); + wrb(ep, 0x0055, dev->dev_addr[5]); + wrl(ep, 0x004c, 0x00000000); + + wrl(ep, 0x0000, 0x00073800); + wrl(ep, 0x0004, 0x00000001); +} + +static void ep93xx_stop_hw(struct net_device *dev) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + + wrl(ep, 0x0020, 0x00000001); + while (rdl(ep, 0x0020) & 0x00000001) + ; +} + +static int ep93xx_open(struct net_device *dev) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + int err; + + if (ep93xx_alloc_buffers(ep)) + return -ENOMEM; + + ep93xx_start_hw(dev); + ep->rx_pointer = 0; + ep->tx_clean_pointer = 0; + ep->tx_pointer = 0; + ep->tx_pending = 0; + + err = request_irq(ep->irq, ep93xx_irq, SA_SHIRQ, "ep93xx_eth", dev); + if (err) { + ep93xx_stop_hw(dev); + ep93xx_free_buffers(ep); + return err; + } + + wrl(ep, 0x0064, 0x00008000); // gintmask + + netif_start_queue(dev); + + return 0; +} + +static int ep93xx_close(struct net_device *dev) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + + netif_stop_queue(dev); + + wrl(ep, 0x0064, 0x00000000); // gintmask + free_irq(ep->irq, dev); + ep93xx_stop_hw(dev); + ep93xx_free_buffers(ep); + + return 0; +} + +static struct net_device_stats *ep93xx_get_stats(struct net_device *dev) +{ + struct ep93xx_priv *ep = netdev_priv(dev); + return &(ep->stats); +} + +struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data) +{ + struct net_device *dev; + struct ep93xx_priv *ep; + + dev = alloc_etherdev(sizeof(struct ep93xx_priv)); + if (dev == NULL) + return NULL; + ep = netdev_priv(dev); + + memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN); + + dev->hard_start_xmit = ep93xx_xmit; + dev->poll = ep93xx_poll; + dev->open = ep93xx_open; + dev->stop = ep93xx_close; + dev->get_stats = ep93xx_get_stats; + + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->weight = 64; + + return dev; +} + + +static int ep93xx_eth_remove(struct platform_device *pdev) +{ + struct net_device *dev; + struct ep93xx_priv *ep; + + dev = platform_get_drvdata(pdev); + if (dev == NULL) + return 0; + platform_set_drvdata(pdev, NULL); + + ep = netdev_priv(dev); + + // @@@ force down + unregister_netdev(dev); + ep93xx_free_buffers(ep); + + if (ep->base_addr != NULL) + iounmap(ep->base_addr); + + if (ep->res != NULL) { + release_resource(ep->res); + kfree(ep->res); + } + + free_netdev(dev); + + return 0; +} + +static int ep93xx_eth_probe(struct platform_device *pdev) +{ + struct ep93xx_eth_data *data; + struct net_device *dev; + struct ep93xx_priv *ep; + int err; + + data = pdev->dev.platform_data; + if (pdev == NULL) + return -ENODEV; + + printk(KERN_INFO "ep93xx-eth " DRV_MODULE_VERSION " loading\n"); + + dev = ep93xx_dev_alloc(data); + if (dev == NULL) { + err = -ENOMEM; + goto err_out; + } + ep = netdev_priv(dev); + + platform_set_drvdata(pdev, dev); + + ep->res = request_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1, + pdev->dev.bus_id); + if (ep->res == NULL) { + dev_err(&pdev->dev, "Could not reserve memory region\n"); + err = -ENOMEM; + goto err_out; + } + + ep->base_addr = ioremap(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start); + if (ep->base_addr == NULL) { + dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); + err = -EIO; + goto err_out; + } + ep->irq = pdev->resource[1].start; + + err = register_netdev(dev); + if (err) { + dev_err(&pdev->dev, "Failed to register netdev\n"); + goto err_out; + } + + return 0; + +err_out: + ep93xx_eth_remove(pdev); + return err; +} + + +static struct platform_driver ep93xx_eth_driver = { + .probe = ep93xx_eth_probe, + .remove = ep93xx_eth_remove, + .driver = { + .name = "ep93xx-eth", + }, +}; + +static int __init ep93xx_eth_init_module(void) +{ + return platform_driver_register(&ep93xx_eth_driver); +} + +static void __exit ep93xx_eth_cleanup_module(void) +{ + platform_driver_unregister(&ep93xx_eth_driver); +} + +module_init(ep93xx_eth_init_module); +module_exit(ep93xx_eth_cleanup_module); +MODULE_LICENSE("GPL"); Index: linux-2.6.17-git10/drivers/net/arm/ep93xx_eth.h =================================================================== --- /dev/null +++ linux-2.6.17-git10/drivers/net/arm/ep93xx_eth.h @@ -0,0 +1,75 @@ +/* + * EP93xx ethernet network device driver + * Copyright (C) 2006 Lennert Buytenhek <[EMAIL PROTECTED]> + * Dedicated to Marija Kulikova. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __EP93XX_ETH_H +#define __EP93XX_ETH_H + +struct ep93xx_rdesc +{ + u32 buf_addr; + u32 rdesc1; +}; + +#define RDESC1_NSOF 0x80000000 +#define RDESC1_BUFFER_INDEX 0x7fff0000 +#define RDESC1_BUFFER_LENGTH 0x0000ffff + +struct ep93xx_rstat +{ + u32 rstat0; + u32 rstat1; +}; + +#define RSTAT0_RFP 0x80000000 +#define RSTAT0_RWE 0x40000000 +#define RSTAT0_EOF 0x20000000 +#define RSTAT0_EOB 0x10000000 +#define RSTAT0_AM 0x00c00000 +#define RSTAT0_RX_ERR 0x00200000 +#define RSTAT0_OE 0x00100000 +#define RSTAT0_FE 0x00080000 +#define RSTAT0_RUNT 0x00040000 +#define RSTAT0_EDATA 0x00020000 +#define RSTAT0_CRCE 0x00010000 +#define RSTAT0_CRCI 0x00008000 +#define RSTAT0_HTI 0x00003f00 +#define RSTAT1_RFP 0x80000000 +#define RSTAT1_BUFFER_INDEX 0x7fff0000 +#define RSTAT1_FRAME_LENGTH 0x0000ffff + +struct ep93xx_tdesc +{ + u32 buf_addr; + u32 tdesc1; +}; + +#define TDESC1_EOF 0x80000000 +#define TDESC1_BUFFER_INDEX 0x7fff0000 +#define TDESC1_BUFFER_ABORT 0x00008000 +#define TDESC1_BUFFER_LENGTH 0x00000fff + +struct ep93xx_tstat +{ + u32 tstat0; +}; + +#define TSTAT0_TXFP 0x80000000 +#define TSTAT0_TXWE 0x40000000 +#define TSTAT0_FA 0x20000000 +#define TSTAT0_LCRS 0x10000000 +#define TSTAT0_OW 0x04000000 +#define TSTAT0_TXU 0x02000000 +#define TSTAT0_ECOLL 0x01000000 +#define TSTAT0_NCOLL 0x001f0000 +#define TSTAT0_BUFFER_INDEX 0x00007fff + + +#endif Index: linux-2.6.17-git10/include/asm-arm/arch-ep93xx/ep93xx-regs.h =================================================================== --- linux-2.6.17-git10.orig/include/asm-arm/arch-ep93xx/ep93xx-regs.h +++ linux-2.6.17-git10/include/asm-arm/arch-ep93xx/ep93xx-regs.h @@ -27,6 +27,7 @@ #define EP93XX_DMA_BASE (EP93XX_AHB_VIRT_BASE + 0x00000000) #define EP93XX_ETHERNET_BASE (EP93XX_AHB_VIRT_BASE + 0x00010000) +#define EP93XX_ETHERNET_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00010000) #define EP93XX_USB_BASE (EP93XX_AHB_VIRT_BASE + 0x00020000) #define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000) Index: linux-2.6.17-git10/include/asm-arm/arch-ep93xx/platform.h =================================================================== --- linux-2.6.17-git10.orig/include/asm-arm/arch-ep93xx/platform.h +++ linux-2.6.17-git10/include/asm-arm/arch-ep93xx/platform.h @@ -11,5 +11,10 @@ void ep93xx_init_devices(void); void ep93xx_clock_init(void); extern struct sys_timer ep93xx_timer; +struct ep93xx_eth_data +{ + unsigned char dev_addr[6]; +}; + #endif - 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