Re: [RFC] cirrus ep93xx ethernet driver

2006-06-27 Thread Lennert Buytenhek
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;
+  

[RFC] cirrus ep93xx ethernet driver

2006-06-25 Thread Lennert Buytenhek
The cirrus ep93xx is an ARM SoC that includes an ethernet MAC --
this patch adds a driver for that ethernet MAC.

Signed-off-by: Lennert Buytenhek [EMAIL PROTECTED]

(This is, unfortunately, probably too late for 2.6.18, so I'm sending
it just for feedback.)

Index: linux-2.6.17-git5/drivers/net/arm/Kconfig
===
--- linux-2.6.17-git5.orig/drivers/net/arm/Kconfig
+++ linux-2.6.17-git5/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-git5/drivers/net/arm/Makefile
===
--- linux-2.6.17-git5.orig/drivers/net/arm/Makefile
+++ linux-2.6.17-git5/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-git5/drivers/net/arm/ep93xx_eth.c
===
--- /dev/null
+++ linux-2.6.17-git5/drivers/net/arm/ep93xx_eth.c
@@ -0,0 +1,672 @@
+/*
+ * 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;
+