Hi Philippe,

I think this needs to be done as a platform driver. It is really the
standard way to deal with platform specifics cleanly. I know this
hardware really only exists on one device, but that is no reason
not to do it. Follow the example of the other Freescale FEC driver.
It won't really change the code too much, it just makes the
platform hardware specifics more cleanly separated from the driver
proper.

A few inline comments below too.


On 24/09/12 18:05, Philippe De Muyter wrote:
This is a fully functionnal  ethernet driver for the MCF547x and MCF548x
                  ^^^^^^^^^^^
                  functional

processors, tested on the M5484EVB board and on a custom board inpired
by the M5484EVB board.  It implements a FEC+DMA driver and a mdio driver.

Original work was made by freescale for 2.6.25, but never submitted for
mainline, but cache support, mdio driver, phylib support, general
cleanup and 2.6.30-3.6 ports are mine.

Signed-off-by: Philippe De Muyter <p...@macqel.be>
---
  arch/m68k/include/asm/m54xxsim.h           |    2 +
  arch/m68k/kernel/setup_no.c                |    5 +
  drivers/net/ethernet/freescale/Kconfig     |   26 +-
  drivers/net/ethernet/freescale/Makefile    |    1 +
  drivers/net/ethernet/freescale/fec_m54xx.c | 1506 ++++++++++++++++++++++++++++
  drivers/net/ethernet/freescale/fec_m54xx.h |  144 +++
  6 files changed, 1683 insertions(+), 1 deletions(-)
  create mode 100644 drivers/net/ethernet/freescale/fec_m54xx.c
  create mode 100644 drivers/net/ethernet/freescale/fec_m54xx.h

diff --git a/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h
index f5531d5..b4c81bf 100644
--- a/arch/m68k/include/asm/m54xxsim.h
+++ b/arch/m68k/include/asm/m54xxsim.h
@@ -46,6 +46,8 @@
  #define MCF_IRQ_UART2         (MCFINT_VECBASE + 33)
  #define MCF_IRQ_UART3         (MCFINT_VECBASE + 32)
  #define MCF_IRQ_DMA           (MCFINT_VECBASE + 48)   /* DMA */
+#define MCF_IRQ_FEC0           (MCFINT_VECBASE + 39)   /* FEC0 */
+#define MCF_IRQ_FEC1           (MCFINT_VECBASE + 38)   /* FEC1 */

  /*
   *    Generic GPIO support

If you want to separate out these types of changes into separate
patches I will happily push them via the m68knommu tree right now.


diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 71fb299..10131b4 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -261,6 +261,11 @@ void __init setup_arch(char **cmdline_p)
        paging_init();
  }

+const char *machdep_get_mac_address(int i)
+{
+       return 0;
+}
+
  /*
   *    Get CPU information for use by the procfs.
   */

This really seems like the wrong place to deal with this.
Doing as a platform driver should make this go away anyway.


diff --git a/drivers/net/ethernet/freescale/Kconfig 
b/drivers/net/ethernet/freescale/Kconfig
index 3574e14..64d8fc6 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -7,7 +7,7 @@ config NET_VENDOR_FREESCALE
        default y
        depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
                   M523x || M527x || M5272 || M528x || M520x || M532x || \
-                  ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
+                  M54xx || ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && 
PPC_BESTCOMM)
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y
          and read the Ethernet-HOWTO, available from
@@ -30,6 +30,30 @@ config FEC
          Say Y here if you want to use the built-in 10/100 Fast ethernet
          controller on some Motorola ColdFire and Freescale i.MX processors.

+config FEC_54xx
+       tristate "MCF547x/MCF548x Fast Ethernet Controller support"
+       depends on M54xx
+       default y
+       select CRC32
+       select PHYLIB
+       select M54xx_DMA
+       help
+         The MCF547x and MCF548x have a built-in Fast Ethernet Controller.
+         This is not the same FEC controller as on other ColdFire as here
+         the DMA controller is not reserved to the FEC driver, but made
+         available for general DMA work.
+         Saying Y here will include support for this device in the kernel.
+
+config FEC2
+       bool "Second FEC ethernet controller (on some ColdFire CPUs)"
+       depends on FEC || FEC_54xx
+       default y
+       help
+         Say Y here if you want to use the second built-in 10/100 Fast
+         ethernet controller on some Motorola ColdFire processors. On M54xx,
+         If your second ethernet port is not connected, saying N here will
+         free 2 DMA channels and allow you to use FEC io ports as GPIO's.
+

With a platform driver you won't want this. The similar configuration
we had for the other common Freescale FEC driver got removed. We don't
want to re-introduce it again :-)


  config FEC_MPC52xx
        tristate "FEC MPC52xx driver"
        depends on PPC_MPC52xx && PPC_BESTCOMM
diff --git a/drivers/net/ethernet/freescale/Makefile 
b/drivers/net/ethernet/freescale/Makefile
index 1752488..05a5022 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -3,6 +3,7 @@
  #

  obj-$(CONFIG_FEC) += fec.o
+obj-$(CONFIG_FEC_54xx) += fec_m54xx.o
  obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
  ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
        obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.c 
b/drivers/net/ethernet/freescale/fec_m54xx.c
new file mode 100644
index 0000000..b28c89a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_m54xx.c
@@ -0,0 +1,1506 @@
+/*
+ * Performance and stability improvements: (C) Copyright 2008,
+ *      Daniel Krueger, SYSTEC electronic GmbH
+ *
+ * Code crunched to get it to work on 2.6.24 -- FEC cleanup coming
+ * soon -- Kurt Mahan
+ *
+ * 2.6.30 and above port, cleanup, cache support, netdev_ops, mdio,
+ * phy & ethtool support,
+ * (C) Copyright 2010-2012 Philippe De Muyter <p...@macqel.be> Macq SA
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/bitops.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include <asm/m54xxdma_api.h>
+#include <asm/m54xxsram.h>
+#include <asm/irq.h>
+#include <asm/cacheflush.h>
+/*
+ * txd's and rxd's are in System SRAM which is uncached
+ * real buffers are in sdram which is cached
+ */
+#define flush_and_invalidate_dcache() flush_cache_all()
+
+#include "fec_m54xx.h"
+#include <linux/phy.h>
+
+#ifdef CONFIG_FEC2
+#define FEC_MAX_PORTS  2
+#else
+#define FEC_MAX_PORTS  1
+#endif
+
+#define FEC_MII_TIMEOUT                1000 /* us */
+#define FEC_TX_TIMEOUT         (1 * HZ)
+
+#define FEC_TX_BUF_NUMBER      (8)
+#define FEC_RX_BUF_NUMBER      (64)
+
+#define FEC_TX_INDEX_MASK      (0x7)
+#define FEC_RX_INDEX_MASK      (0x3f)
+
+#define MAC_ADDR_LEN   6
+
+#define VERSION "0.30"
+MODULE_DESCRIPTION("DMA Fast Ethernet Controller driver ver " VERSION);
+
+/* fec private */
+struct fec_priv {
+       struct net_device *netdev;              /* owning net device */
+       void *fecpriv_txbuf[FEC_TX_BUF_NUMBER]; /* tx buffer ptrs */
+       struct MCD_bufDescFec *fecpriv_txdesc;  /* tx descriptor ptrs */
+       /* fecpriv_current_tx changed only by fec_interrupt_fec_tx_handler */
+       unsigned int fecpriv_current_tx;        /* current tx desc index */
+       /* fecpriv_next_tx changed only by fec_start_tx */
+       unsigned int fecpriv_next_tx;           /* next tx desc index */
+       unsigned int fecpriv_current_rx;        /* current rx desc index */
+       struct MCD_bufDescFec *fecpriv_rxdesc;  /* rx descriptor ptrs */
+       struct sk_buff *askb_rx[FEC_RX_BUF_NUMBER]; /* rx SKB ptrs */
+       unsigned int fecpriv_initiator_rx;      /* rx dma initiator */
+       unsigned int fecpriv_initiator_tx;      /* tx dma initiator */
+       int fecpriv_fec_rx_channel;             /* rx dma channel */
+       int fecpriv_fec_tx_channel;             /* tx dma channel */
+       int fecpriv_rx_requestor;               /* rx dma requestor */
+       int fecpriv_tx_requestor;               /* tx dma requestor */
+       unsigned char *fecpriv_mac_addr;        /* private fec mac addr */
+       struct net_device_stats fecpriv_stat;   /* stats ptr */
+       spinlock_t fecpriv_lock;
+       int fecpriv_rxflag;
+       struct tasklet_struct fecpriv_tasklet_reinit;
+       int index;                              /* fec hw number */
+#if 0
+       int in_poll;
+#endif
+
+       int duplex;
+       int speed;
+
+       /* phy link details */
+       int phy_addr;
+       struct phy_device *phydev;
+       enum phy_state link;
+
+       /* MDIO bus details */
+       unsigned int phy_speed;
+       struct completion mdio_done;
+};
+
+/* default fec0 address */
+unsigned char fec0_addr[MAC_ADDR_LEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x50 };
+
+#ifdef CONFIG_FEC2
+/* default fec1 address */
+unsigned char fec1_addr[MAC_ADDR_LEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x51 };
+#endif

I am sure the netdev people will have something to say on having
defaul MAC addresses. I think it is generally frowned upon. It is
much better just configure it with ifconfig from user space.


+extern const char *machdep_get_mac_address(int i);
+
+/* based on generic_adjust_link from fs_enet-main.c */
+static void fec_adjust_link(struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       struct phy_device *phydev = fp->phydev;
+       int new_state = 0;
+
+       if (phydev->link != PHY_DOWN) {
+               if (phydev->duplex != fp->duplex) {
+                       unsigned long base_addr = (unsigned long) 
dev->base_addr;
+                       u32 rcntrl;
+                       u32 tcntrl;
+
+                       new_state = 1;
+                       fp->duplex = phydev->duplex;
+
+                       rcntrl = readl(base_addr + FEC_RCR);
+                       tcntrl = readl(base_addr + FEC_TCR);

I like the use of readl/writel!


+                       rcntrl &= ~FEC_RCR_DRT;
+                       tcntrl &= ~FEC_TCR_FDEN;
+                       if (phydev->duplex == DUPLEX_FULL)
+                               /* Enable the full duplex mode */
+                               tcntrl |= FEC_TCR_FDEN;
+                       else
+                               /* Disable reception of frames while 
transmitting */
+                               rcntrl |= FEC_RCR_DRT;
+
+                       writel(rcntrl, base_addr + FEC_RCR);
+                       writel(tcntrl, base_addr + FEC_TCR);
+               }
+
+               if (phydev->speed != fp->speed) {
+                       new_state = 1;
+                       fp->speed = phydev->speed;
+               }
+
+               if (fp->link == PHY_DOWN) {
+                       new_state = 1;
+                       fp->link = phydev->link;
+               }
+
+       } else if (fp->link) {
+               new_state = 1;
+               fp->link = PHY_DOWN;
+               fp->speed = 0;
+               fp->duplex = -1;
+       }
+
+       if (new_state /* && netif_msg_link(fp)*/)
+               phy_print_status(phydev);
+}
+
+static int fec_init_phy(struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       struct phy_device *phydev;
+       char phy_id[MII_BUS_ID_SIZE + 3];
+
+       snprintf(phy_id, sizeof(phy_id), "%x:%02x", 0xfec, fp->phy_addr);
+
+       fp->link = PHY_DOWN;
+       fp->speed = 0;
+       fp->duplex = -1;
+
+       phydev = phy_connect(dev, phy_id, &fec_adjust_link, 0, 
PHY_INTERFACE_MODE_MII);
+       if (IS_ERR(phydev)) {
+               dev_err(&dev->dev, "phy_connect failed\n");
+               return PTR_ERR(phydev);
+       }
+       dev_info(&dev->dev,
+               "attached phy %i (OUI/model = %06x/%02x) to driver %s\n",
+                       phydev->addr, (phydev->phy_id >> 10) & 0x3fffff,
+                       (phydev->phy_id >> 4) & 0x3f, phydev->drv->name);
+
+       fp->phydev = phydev;
+
+       return 0;
+}
+
+static int fec_phy_start(struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       int err;
+
+       /*
+        * on the freescale dev board, a DUAL phy is used :
+        * PHY 0 for FEC 0 and PHY 1 for FEC 1
+        */
+       fp->phy_addr = fp->index;
+
+       err = fec_init_phy(dev);
+       if (err) {
+               dev_err(&dev->dev, "fec_init_phy failed\n");
+               return err;
+       }
+
+       /* reset phy - this also wakes it from PDOWN */
+       phy_write(fp->phydev, MII_BMCR, BMCR_RESET);
+       phy_start(fp->phydev);
+
+       return 0;
+}
+
+/* ethtool interface -- copy of fec_mpc52xx.c */
+#if 0
+static void fec_get_drvinfo(struct net_device *dev,
+               struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRIVER_NAME);
+}
+#endif

If you done with the debug and older cruft it might be time to remove it.


+static int fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct fec_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENODEV;
+
+       return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct fec_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENODEV;
+
+       return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+#if 0
+static u32 fec_get_msglevel(struct net_device *dev)
+{
+       struct fec_priv *priv = netdev_priv(dev);
+       return priv->msg_enable;
+}
+
+static void fec_set_msglevel(struct net_device *dev, u32 level)
+{
+       struct fec_priv *priv = netdev_priv(dev);
+       priv->msg_enable = level;
+}
+#endif
+
+static const struct ethtool_ops fec_ethtool_ops = {
+#if 0
+       .get_drvinfo = fec_get_drvinfo,
+#endif
+       .get_settings = fec_get_settings,
+       .set_settings = fec_set_settings,
+       .get_link = ethtool_op_get_link,
+#if 0
+       .get_msglevel = fec_get_msglevel,
+       .set_msglevel = fec_set_msglevel,
+#endif
+};
+
+
+static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct fec_priv *priv = netdev_priv(dev);
+
+       if (!priv->phydev)
+               return -ENOTSUPP;
+
+       return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static int fec_mdio_transfer(struct mii_bus *bus, int phy_addr,
+               int reg, u32 value)
+{
+       struct fec_priv *priv = (struct fec_priv *)bus->priv;
+       unsigned long base_addr = (unsigned long) priv->netdev->base_addr;
+       unsigned long time_left;
+
+       /*
+        * Set MII speed to 2.5 MHz
+        */
+       writel((((MCF_BUSCLK + 4999999) / 5000000) & 0x3F) << 1, base_addr + 
FEC_MSCR);

Eventually this will need to use the clk api.
But for now I am not really too worried.


+       value |= (phy_addr << 23);
+       value |= (reg << 18);
+       value |= FEC_MMFR_ST | FEC_MMFR_TA;
+
+       init_completion(&priv->mdio_done);
+       writel(value, base_addr + FEC_MMFR);
+
+       /* wait for end of transfer, this takes about 23 us on lite5200b */
+       time_left = wait_for_completion_timeout(&priv->mdio_done,
+                       usecs_to_jiffies(FEC_MII_TIMEOUT));
+
+       writel(0, base_addr + FEC_MSCR);
+
+       if (time_left == 0) {
+               pr_err("%s : timeout accessing phy%d/reg%d\n",
+                                               bus->name, phy_addr, reg);
+               return -ETIMEDOUT;
+       }
+
+       return (value & FEC_MMFR_OP_READ) ?
+               (readl(base_addr + FEC_MMFR) & FEC_MMFR_DATA) : 0;
+}
+
+static int fec_mdio_read(struct mii_bus *bus, int phy_addr, int reg)
+{
+       return fec_mdio_transfer(bus, phy_addr, reg, FEC_MMFR_OP_READ);
+}
+
+static int fec_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 data)
+{
+       return fec_mdio_transfer(bus, phy_addr, reg, data | FEC_MMFR_OP_WRITE);
+}
+
+static int __init fec_mdio_init(struct net_device *dev)
+{
+       struct mii_bus *bus;
+       int err;
+       int i;
+       unsigned long addr;
+
+       bus = mdiobus_alloc();
+       if (bus == NULL)
+               return -ENOMEM;
+
+       bus->name = "FEC 0 MII bus";
+       bus->read = fec_mdio_read;
+       bus->write = fec_mdio_write;
+       /*
+        * on the freescale dev board, both PHY's (actually a DUAL phy)
+        * are connected via the MDIO bus of FEC0.
+        * PHY 0 for FEC 0 and PHY 1 for FEC 1
+        */
+       bus->phy_mask = ~((1 << FEC_MAX_PORTS) - 1);
+
+       /* setup irqs */
+       bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
+       if (bus->irq == NULL) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               bus->irq[i] = PHY_POLL;
+
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%x", 0xfec);
+       bus->priv = netdev_priv(dev);
+
+       /* enable MII interrupt */
+       addr = dev->base_addr + FEC_EIMR;
+       writel(readl(addr) | FEC_EIR_MII, addr);
+
+       err = mdiobus_register(bus);
+       if (err)
+               goto out_unmap;
+
+       return 0;
+
+out_unmap:
+out_free:
+       kfree(bus->irq);
+       mdiobus_free(bus);
+
+       return err;
+}
+
+/************************************************************************
+* +NAME: fec_get_stats
+*
+* RETURNS: This function returns the statistical information.
+*************************************************************************/
+struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       struct net_device_stats *statp = &fp->fecpriv_stat;
+       unsigned long base_addr = dev->base_addr;
+
+       /* Receive the statistical information */
+       statp->rx_packets = readl(base_addr + FECSTAT_RMON_R_PACKETS);
+       statp->tx_packets = readl(base_addr + FECSTAT_RMON_T_PACKETS);
+       statp->rx_bytes = readl(base_addr + FECSTAT_RMON_R_OCTETS);
+       statp->tx_bytes = readl(base_addr + FECSTAT_RMON_T_OCTETS);
+
+       statp->multicast = readl(base_addr + FECSTAT_RMON_R_MC_PKT);
+       statp->collisions = readl(base_addr + FECSTAT_RMON_T_COL);
+
+       statp->rx_length_errors = readl(base_addr + FECSTAT_RMON_R_UNDERSIZE) +
+               readl(base_addr + FECSTAT_RMON_R_OVERSIZE) +
+               readl(base_addr + FECSTAT_RMON_R_FRAG) +
+               readl(base_addr + FECSTAT_RMON_R_JAB);
+       statp->rx_crc_errors = readl(base_addr + FECSTAT_IEEE_R_CRC);
+       statp->rx_frame_errors = readl(base_addr + FECSTAT_IEEE_R_ALIGN);
+       statp->rx_over_errors = readl(base_addr + FECSTAT_IEEE_R_MACERR);
+
+       statp->tx_carrier_errors = readl(base_addr + FECSTAT_IEEE_T_CSERR);
+       statp->tx_fifo_errors = readl(base_addr + FECSTAT_IEEE_T_MACERR);
+       statp->tx_window_errors = readl(base_addr + FECSTAT_IEEE_T_LCOL);
+
+       /* I hope that one frame doesn't have more than one error */
+       statp->rx_errors = statp->rx_length_errors +
+               statp->rx_crc_errors +
+               statp->rx_frame_errors +
+               statp->rx_over_errors +
+               statp->rx_dropped;
+       statp->tx_errors = statp->tx_carrier_errors +
+               statp->tx_fifo_errors +
+               statp->tx_window_errors +
+               statp->tx_aborted_errors +
+               statp->tx_heartbeat_errors +
+               statp->tx_dropped;
+
+       return statp;
+}
+
+/************************************************************************
+* NAME: fec_set_multicast_list
+*
+* DESCRIPTION: This function sets the frame filtering parameters
+*************************************************************************/
+void fec_set_multicast_list(struct net_device *dev)
+{
+       unsigned int crc;
+       unsigned long base_addr = (unsigned long) dev->base_addr;
+       struct netdev_hw_addr *ha;
+       u32 gaur, galr;
+
+       if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI) {
+               /* Allow all incoming frames */
+               writel(0xFFFFFFFF, base_addr + FEC_GALR);
+               writel(0xFFFFFFFF, base_addr + FEC_GAUR);
+               return;
+       }
+
+       /* Reset the group address register */
+       galr = 0x00000000;
+       gaur = 0x00000000;
+
+       /* Process all addresses */
+       netdev_for_each_mc_addr(ha, dev) {
+               /* Calculate crc value for the current address */
+               crc = ether_crc_le(MAC_ADDR_LEN, ha->addr) >> 26;
+
+               /* Add this value */
+               crc &= 0x3F;
+               if (crc > 31)
+                       gaur |= 0x1 << (crc - 32);
+               else
+                       galr |= 0x1 << crc;
+       }
+       writel(galr, base_addr + FEC_GALR);
+       writel(gaur, base_addr + FEC_GAUR);
+}
+
+/************************************************************************
+* NAME: fec_set_mac_address
+*
+* DESCRIPTION: This function sets the MAC address
+*************************************************************************/
+int fec_set_mac_address(struct net_device *dev, void *p)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       unsigned long base_addr = (unsigned long) dev->base_addr;
+       struct sockaddr *addr = p;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       /* Copy a new address to the device structure */
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       /* Copy a new address to the private structure */
+       memcpy(fp->fecpriv_mac_addr, addr->sa_data, MAC_ADDR_LEN);
+
+       /* Set the address to the registers */
+       writel((dev->dev_addr[0] << 24) | (dev->dev_addr[1] << 16) |
+             (dev->dev_addr[2] << 8) | dev->dev_addr[3], base_addr + FEC_PALR);
+       writel((dev->dev_addr[4] << 24) | (dev->dev_addr[5] << 16) | 0x8808,
+              base_addr + FEC_PAUR);
+
+       return 0;
+}
+
+/************************************************************************
+* NAME: fec_start_tx
+*
+* DESCRIPTION: This function starts transmission of the frame using DMA
+*
+* RETURNS: This function always returns zero.
+*************************************************************************/
+int fec_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+       int n = fp->fecpriv_next_tx;
+       void *data, *data_aligned;
+       int offset;
+
+       data = kmalloc(skb->len + 15, GFP_DMA | GFP_ATOMIC);
+
+       if (!data) {
+               fp->fecpriv_stat.tx_dropped++;
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       offset = (((unsigned long)virt_to_phys(data) + 15) & 0xFFFFFFF0) -
+               (unsigned long)virt_to_phys(data);
+       data_aligned = (void *)((unsigned long)data + offset);
+       memcpy(data_aligned, skb->data, skb->len);
+
+       /* flush data cache before initializing the descriptor and starting DMA 
*/
+       flush_dcache_range(virt_to_phys(data_aligned), skb->len);

If I compile this with the MMU enabled I get:

  CC      drivers/net/ethernet/freescale/fec_m54xx.o
drivers/net/ethernet/freescale/fec_m54xx.c: In function ‘fec_start_tx’:
drivers/net/ethernet/freescale/fec_m54xx.c:530:2: error: implicit declaration 
of function ‘flush_dcache_range’

Problem is flush_dcache_range() only exists for non-MMU compiles.

This needs to be changed to use the DMA API. With the use of
dma_map_single() and friends you won't need to use any flush_*()
calls at all. (The other FEC driver is a good example of its
use).


+       spin_lock_irq(&fp->fecpriv_lock);
+
+       /* Initialize the descriptor */
+       fp->fecpriv_txbuf[n] = data;
+       txd[n].dataPointer = (unsigned int) virt_to_phys(data_aligned);
+       txd[n].length = skb->len;
+       txd[n].statCtrl |= (MCD_FEC_END_FRAME | MCD_FEC_BUF_READY);
+       n = (n + 1) & FEC_TX_INDEX_MASK;
+       fp->fecpriv_next_tx = n;
+
+       if (fp->fecpriv_txbuf[fp->fecpriv_current_tx] && fp->fecpriv_current_tx 
== n)
+               netif_stop_queue(dev);
+
+       spin_unlock_irq(&fp->fecpriv_lock);
+
+       /* Tell the DMA to continue the transmission */
+       MCD_continDma(fp->fecpriv_fec_tx_channel);
+
+       dev_kfree_skb(skb);
+
+       dev->trans_start = jiffies;
+
+       return 0;
+}
+
+/************************************************************************
+* NAME: fec_tx_timeout
+*
+* DESCRIPTION: If the interrupt processing of received frames was lost
+*              and DMA stopped the reception, this function clears
+*              the transmission descriptors and starts DMA
+*
+*************************************************************************/
+void fec_tx_timeout(struct net_device *dev)
+{
+       int i;
+       struct fec_priv *fp = netdev_priv(dev);
+       struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+       unsigned long base_addr = (unsigned long) dev->base_addr;
+       u32 fecfrst;
+
+       spin_lock_irq(&fp->fecpriv_lock);
+       MCD_killDma(fp->fecpriv_fec_tx_channel);
+       for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+               if (fp->fecpriv_txbuf[i]) {
+                       kfree(fp->fecpriv_txbuf[i]);
+                       fp->fecpriv_txbuf[i] = NULL;
+               }
+               txd[i].statCtrl = MCD_FEC_INTERRUPT;
+       }
+       txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+
+       fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+       /* Reset FIFOs */
+       fecfrst = FEC_SW_RST | FEC_RST_CTL;
+       writel(fecfrst, base_addr + FEC_FECFRST);
+       fecfrst &= ~FEC_SW_RST;
+       writel(fecfrst, base_addr + FEC_FECFRST);
+
+#if 0
+       /* Reset and disable FEC */
+       writel(FEC_ECR_RESET, base_addr + FEC_ECR);
+#endif
+
+       /* Enable FEC */
+       writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+       MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+                    (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+                    FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+                    FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+                    MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+       spin_unlock_irq(&fp->fecpriv_lock);
+
+       netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_interrupt_tx_handler
+*
+* DESCRIPTION: This function is called when the data
+*              transmission from the buffer to the FEC is completed.
+*
+*************************************************************************/
+void fec_interrupt_fec_tx_handler(void *voidp)
+{
+       struct net_device *dev = voidp;
+       struct fec_priv *fp = netdev_priv(dev);
+       void **txb = fp->fecpriv_txbuf;
+       int c = fp->fecpriv_current_tx;
+
+       /* Release the socket buffer */
+       if (txb[c]) {
+               kfree(txb[c]);
+               txb[c] = NULL;
+       }
+       c = (c + 1) & FEC_TX_INDEX_MASK;
+
+       if (MCD_dmaStatus(fp->fecpriv_fec_tx_channel) == MCD_DONE) {
+               for (; c != fp->fecpriv_next_tx; c = (c + 1) & 
FEC_TX_INDEX_MASK) {
+                       if (txb[c]) {
+                               kfree(txb[c]);
+                               txb[c] = NULL;
+                       }
+               }
+       }
+       fp->fecpriv_current_tx = c;
+
+       if (netif_queue_stopped(dev))
+               netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_interrupt_rx_handler
+*
+* DESCRIPTION: This function is called when the data
+*              reception from the FEC to the reception buffer is completed.
+*
+*************************************************************************/
+void fec_interrupt_fec_rx_handler(void *voidp)
+{
+       struct net_device *dev = voidp;
+       struct fec_priv *fp = netdev_priv(dev);
+       struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+       struct sk_buff **rxskb = fp->askb_rx;
+       struct sk_buff *skb;
+       int i;
+       int c = fp->fecpriv_current_rx;
+
+       fp->fecpriv_rxflag = 1;
+       /* Some buffers can be missed */
+       if (!(rxd[c].statCtrl & MCD_FEC_END_FRAME)) {
+               /* Find a valid index */
+               for (i = 0; i < FEC_RX_BUF_NUMBER && !(rxd[c].statCtrl & 
MCD_FEC_END_FRAME); i++, c = (c + 1) & FEC_RX_INDEX_MASK)
+                       ;
+
+               if (i == FEC_RX_BUF_NUMBER) {
+                       /* There are no data to process */
+                       /* Tell the DMA to continue the reception */
+                       MCD_continDma(fp->fecpriv_fec_rx_channel);
+
+                       fp->fecpriv_rxflag = 0;
+
+                       return;
+               }
+       }
+
+       for (; rxd[c].statCtrl & MCD_FEC_END_FRAME; c = (c + 1) & 
FEC_RX_INDEX_MASK) {
+               if ((rxd[c].length <= FEC_MAXBUF_SIZE) &&
+                   (rxd[c].length > 4)) { /* --tym-- */
+                       skb = rxskb[c];
+                       if (!skb)
+                               fp->fecpriv_stat.rx_dropped++;
+                       else {
+                               /*
+                                * invalidate data cache before initializing
+                                * the descriptor and starting DMAs
+                                */
+                               cache_clear(virt_to_phys(skb->data), skb->len);
+
+                               skb_put(skb, rxd[c].length - 4);
+                               skb->protocol = eth_type_trans(skb, dev);
+                               netif_rx(skb);
+                       }
+                       rxd[c].statCtrl &= ~MCD_FEC_END_FRAME;
+                       /* allocate new skbuff */
+                       rxskb[c] = alloc_skb(FEC_MAXBUF_SIZE + 16, /*GFP_ATOMIC 
|*/ GFP_DMA);
+                       if (!rxskb[c]) {
+                               rxd[c].dataPointer = 0;
+                               rxd[c].length = 0;
+                               fp->fecpriv_stat.rx_dropped++;
+                       } else {
+#if 0
+if (!fp->in_poll)
+       pr_debug("rxskb[%d] = %p\n", c, rxskb[c]);
+#endif
+                               skb_reserve(rxskb[c], 16);
+                               rxskb[c]->dev = dev;
+
+                               /*
+                                * invalidate data cache before initializing
+                                * the descriptor and starting DMAs
+                                */
+                               cache_clear(virt_to_phys(rxskb[c]->data), 
FEC_MAXBUF_SIZE);
+
+                               rxd[c].dataPointer = (unsigned int) 
virt_to_phys(rxskb[c]->data);
+                               rxd[c].length = FEC_MAXBUF_SIZE;
+                               rxd[c].statCtrl |= MCD_FEC_BUF_READY;
+                       }
+               }
+       }
+
+       fp->fecpriv_current_rx = c;
+
+       /* Tell the DMA to continue the reception */
+       MCD_continDma(fp->fecpriv_fec_rx_channel);
+
+       fp->fecpriv_rxflag = 0;
+}
+
+/************************************************************************
+* NAME: fec_interrupt_handler
+*
+* DESCRIPTION: This function is called when some special errors occur
+*
+*************************************************************************/
+irqreturn_t fec_interrupt_handler(int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct fec_priv *fp = netdev_priv(dev);
+       unsigned long base_addr = (unsigned long) dev->base_addr;
+       unsigned long events;
+       u32 fecfrst;
+
+       /* Read and clear the events */
+       events = readl(base_addr + FEC_EIR) & readl(base_addr + FEC_EIMR);
+
+       if (events & FEC_EIR_HBERR) {
+               fp->fecpriv_stat.tx_heartbeat_errors++;
+               writel(FEC_EIR_HBERR, base_addr + FEC_EIR);
+       }
+
+       /* receive/transmit FIFO error */
+       if (events & (FEC_EIR_RFERR | FEC_EIR_XFERR)) {
+               /* kill DMA receive channel */
+               MCD_killDma(fp->fecpriv_fec_rx_channel);
+
+               /* kill running transmission by DMA */
+               MCD_killDma(fp->fecpriv_fec_tx_channel);
+
+               /* Reset FIFOs */
+               fecfrst = FEC_SW_RST | FEC_RST_CTL;
+               writel(fecfrst, base_addr + FEC_FECFRST);
+               fecfrst &= ~FEC_SW_RST;
+               writel(fecfrst, base_addr + FEC_FECFRST);
+
+               /* reset receive FIFO status register */
+               writel(FEC_FECRFSR_FAE |
+                      FEC_FECRFSR_RXW |
+                      FEC_FECRFSR_UF,
+                       base_addr + FEC_FECRFSR);
+
+               /* reset transmit FIFO status register */
+               writel(FEC_FECTFSR_FAE |
+                      FEC_FECTFSR_TXW |
+                      FEC_FECTFSR_UF |
+                      FEC_FECTFSR_OF,
+                       base_addr + FEC_FECTFSR);
+
+               /* reset RFERR and XFERR event */
+               writel(FEC_EIR_RFERR | FEC_EIR_XFERR, base_addr + FEC_EIR);
+
+               /* stop queue */
+               netif_stop_queue(dev);
+
+               /* execute reinitialization as tasklet */
+               tasklet_schedule(&fp->fecpriv_tasklet_reinit);
+
+               fp->fecpriv_stat.rx_dropped++;
+       }
+
+       /* transmit FIFO underrun */
+       if (events & FEC_EIR_XFUN) {
+               /* reset XFUN event */
+               writel(FEC_EIR_XFUN, base_addr + FEC_EIR);
+               fp->fecpriv_stat.tx_aborted_errors++;
+       }
+
+       /* late collision */
+       if (events & FEC_EIR_LC) {
+               /* reset LC event */
+               writel(FEC_EIR_LC, base_addr + FEC_EIR);
+               fp->fecpriv_stat.tx_aborted_errors++;
+       }
+
+       /* collision retry limit */
+       if (events & FEC_EIR_RL) {
+               /* reset RL event */
+               writel(FEC_EIR_RL, base_addr + FEC_EIR);
+               fp->fecpriv_stat.tx_aborted_errors++;
+       }
+
+       /* MII transfer completed */
+       if (events & FEC_EIR_MII) {
+               complete(&fp->mdio_done);
+               writel(FEC_EIR_MII, base_addr + FEC_EIR);
+       }
+       return 0;
+}
+
+/************************************************************************
+* NAME: fec_interrupt_reinit
+*
+* DESCRIPTION: This function is called from interrupt handler
+*              when controller must be reinitialized.
+*
+*************************************************************************/
+void fec_interrupt_fec_reinit(unsigned long data)
+{
+       int i;
+       struct net_device *dev = (struct net_device *)data;
+       struct fec_priv *fp = netdev_priv(dev);
+       struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+       struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+       struct sk_buff **rxskb = fp->askb_rx;
+       unsigned long base_addr = (unsigned long) dev->base_addr;
+
+#if 0
+if (!fp->in_poll)
+       pr_debug("fec_interrupt_fec_reinit\n");
+#endif
+       /* Initialize reception descriptors and start DMA for the reception */
+       for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+               if (!rxskb[i]) {
+                       rxskb[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_ATOMIC | 
GFP_DMA);
+                       if (!rxskb[i]) {
+                               rxd[i].dataPointer = 0;
+                               rxd[i].statCtrl = 0;
+                               rxd[i].length = 0;
+                               continue;
+                       }
+#if 0
+if (!fp->in_poll)
+       pr_debug("rxskb[%d] = %p\n", i, rxskb[i]);
+#endif
+                       rxskb[i]->dev = dev;
+                       skb_reserve(rxskb[i], 16);
+               }
+               rxd[i].dataPointer = (unsigned int) 
virt_to_phys(rxskb[i]->data);
+               rxd[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT;
+               rxd[i].length = FEC_MAXBUF_SIZE;
+       }
+
+       rxd[i - 1].statCtrl |= MCD_FEC_WRAP;
+       fp->fecpriv_current_rx = 0;
+
+       /* restart frame transmission */
+       for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+               if (fp->fecpriv_txbuf[i]) {
+                       kfree(fp->fecpriv_txbuf[i]);
+                       fp->fecpriv_txbuf[i] = NULL;
+                       fp->fecpriv_stat.tx_dropped++;
+               }
+               txd[i].statCtrl = MCD_FEC_INTERRUPT;
+       }
+       txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+       fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+       /* flush entire data cache before restarting the DMA */
+       flush_and_invalidate_dcache();
+
+       /* restart DMA from beginning */
+       MCD_startDma(fp->fecpriv_fec_rx_channel, (char *) rxd, 0,
+                    (unsigned char *) (base_addr + FEC_FECRFDR), 0,
+                    FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx,
+                    FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT,
+                    MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+       MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+                    (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+                    FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+                    FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+                    MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+       /* Enable FEC */
+       writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+       netif_wake_queue(dev);
+}
+
+/************************************************************************
+* NAME: fec_open
+*
+* DESCRIPTION: This function performs the initialization of FEC
+*
+* RETURNS: If no error occurs, this function returns zero.
+*************************************************************************/
+int fec_open(struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       struct MCD_bufDescFec *rxd = fp->fecpriv_rxdesc;
+       struct MCD_bufDescFec *txd = fp->fecpriv_txdesc;
+       struct sk_buff **rxskb = fp->askb_rx;
+       unsigned long base_addr = (unsigned long) dev->base_addr;
+       int i;
+       int channel;
+       int error_code = -EBUSY;
+       u32 fecfrst;
+       u32 rcntl;
+
+       /* Receive the DMA channels */
+       channel = dma_set_channel_fec(fp->fecpriv_rx_requestor);
+
+       if (channel == -1) {
+               pr_err("Rx Dma channel cannot be reserved\n");
+               goto ERRORS;
+       }
+
+       fp->fecpriv_fec_rx_channel = channel;
+
+       dma_connect(channel, fec_interrupt_fec_rx_handler, dev);
+
+       channel = dma_set_channel_fec(fp->fecpriv_tx_requestor);
+
+       if (channel == -1) {
+               pr_err("Tx Dma channel cannot be reserved\n");
+               goto ERRORS;
+       }
+
+       fp->fecpriv_fec_tx_channel = channel;
+
+       dma_connect(channel, fec_interrupt_fec_tx_handler, dev);
+
+       /* init tasklet for controller reinitialization */
+       tasklet_init(&fp->fecpriv_tasklet_reinit, fec_interrupt_fec_reinit,
+                    (unsigned long) dev);
+
+       /* Reset FIFOs */
+       fecfrst = FEC_SW_RST | FEC_RST_CTL;
+       writel(fecfrst, base_addr + FEC_FECFRST);
+       fecfrst &= ~FEC_SW_RST;
+       writel(fecfrst, base_addr + FEC_FECFRST);
+
+       /* Reset and disable FEC */
+       writel(FEC_ECR_RESET, base_addr + FEC_ECR);
+
+       udelay(10);
+
+       /* Clear all events */
+       writel(FEC_EIR_CLEAR, base_addr + FEC_EIR);
+
+       /* Reset FIFO status */
+       writel(FEC_FECTFSR_MSK, base_addr + FEC_FECTFSR);
+       writel(FEC_FECRFSR_MSK, base_addr + FEC_FECRFSR);
+
+       /* Set the default address */
+       writel((dev->dev_addr[0] << 24) | (dev->dev_addr[1] << 16) |
+             (dev->dev_addr[2] << 8) | dev->dev_addr[3], base_addr + FEC_PALR);
+       writel((dev->dev_addr[4] << 24) | (dev->dev_addr[5] << 16) | 0x8808,
+              base_addr + FEC_PAUR);
+
+       /* Reset the group address descriptor */
+       writel(0x00000000, base_addr + FEC_GALR);
+       writel(0x00000000, base_addr + FEC_GAUR);
+
+       /* Reset the individual address descriptor */
+       writel(0x00000000, base_addr + FEC_IALR);
+       writel(0x00000000, base_addr + FEC_IAUR);
+
+       /* Set the receive control register */
+       rcntl = FEC_RCR_MAX_FRM_SIZE | FEC_RCR_MII;
+       writel(rcntl, base_addr + FEC_RCR);
+
+       /* Set the receive FIFO control register */
+       writel(FEC_FECRFCR_FRM | FEC_FECRFCR_GR
+                            | (FEC_FECRFCR_MSK     /* disable all but ... */
+                               & ~FEC_FECRFCR_FAE  /* enable frame accept 
error */
+                               & ~FEC_FECRFCR_RXW  /* enable receive wait 
condition */
+#if 0
+                               & ~FEC_FECRFCR_UF   /* enable FIFO underflow */
+#endif
+                            ), base_addr + FEC_FECRFCR);
+
+       /* Set the receive FIFO alarm register */
+       writel(FEC_FECRFAR_ALARM, base_addr + FEC_FECRFAR);
+
+       /* Set the transmit FIFO control register */
+       writel(FEC_FECTFCR_FRM | FEC_FECTFCR_GR
+                            | (FEC_FECTFCR_MSK     /* disable all but ... */
+                               & ~FEC_FECTFCR_FAE  /* enable frame accept 
error */
+#if 0
+                               & ~FEC_FECTFCR_TXW  /* enable transmit wait 
condition */
+                               & ~FEC_FECTFCR_UF   /* enable FIFO underflow */
+#endif
+                               & ~FEC_FECTFCR_OF), /* enable FIFO overflow */
+                               base_addr + FEC_FECTFCR);
+
+       /* Set the transmit FIFO alarm register */
+       writel(FEC_FECTFAR_ALARM, base_addr + FEC_FECTFAR);
+
+       /* Set the Tx FIFO watermark */
+       writel(FEC_FECTFWR_XWMRK, base_addr + FEC_FECTFWR);
+
+       /* Enable the transmitter to append the CRC */
+       writel(FEC_CTCWR_TFCW_CRC, base_addr + FEC_CTCWR);
+
+       /* Enable the ethernet interrupts */ /* FIXME : too late for mdio bus */
+       writel(FEC_EIMR_DISABLE
+            | FEC_EIR_LC
+            | FEC_EIR_RL
+            | FEC_EIR_HBERR
+            | FEC_EIR_XFUN
+            | FEC_EIR_XFERR
+            | FEC_EIR_RFERR
+            | FEC_EIR_MII,
+               base_addr + FEC_EIMR);
+
+       if (fp->phydev->duplex == DUPLEX_FULL)
+               /* Enable the full duplex mode */
+               writel(FEC_TCR_FDEN | FEC_TCR_HBC, base_addr + FEC_TCR);
+       else {
+               /* Disable reception of frames while transmitting */
+               rcntl |= FEC_RCR_DRT;
+               writel(rcntl, base_addr + FEC_RCR);
+       }
+
+       /* Enable MIB */
+       writel(FEC_MIBC_ENABLE, base_addr + FEC_MIBC);
+
+       /* Enable FEC */
+       writel(FEC_ECR_ETHEREN, base_addr + FEC_ECR);
+
+       /* Initialize tx descriptors and start DMA for the transmission */
+       for (i = 0; i < FEC_TX_BUF_NUMBER; i++)
+               txd[i].statCtrl = MCD_FEC_INTERRUPT;
+
+       txd[i - 1].statCtrl |= MCD_FEC_WRAP;
+
+       fp->fecpriv_current_tx = fp->fecpriv_next_tx = 0;
+
+       MCD_startDma(fp->fecpriv_fec_tx_channel, (char *) txd, 0,
+                    (unsigned char *) (base_addr + FEC_FECTFDR), 0,
+                    FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_tx,
+                    FEC_TX_DMA_PRI, MCD_FECTX_DMA | MCD_INTERRUPT,
+                    MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+       /* Initialize rx descriptors and start DMA for the reception */
+       for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+               rxskb[i] = alloc_skb(FEC_MAXBUF_SIZE + 16, GFP_DMA);
+               if (!rxskb[i]) {
+                       rxd[i].dataPointer = 0;
+                       rxd[i].statCtrl = 0;
+                       rxd[i].length = 0;
+               } else {
+#if 0
+if (!fp->in_poll)
+       pr_debug("rxskb[%d] = %p\n", i, rxskb[i]);
+#endif
+                       skb_reserve(rxskb[i], 16);
+                       rxskb[i]->dev = dev;
+                       rxd[i].dataPointer = (unsigned int) 
virt_to_phys(rxskb[i]->data);
+                       rxd[i].statCtrl = MCD_FEC_BUF_READY | MCD_FEC_INTERRUPT;
+                       rxd[i].length = FEC_MAXBUF_SIZE;
+               }
+       }
+
+       rxd[i - 1].statCtrl |= MCD_FEC_WRAP;
+       fp->fecpriv_current_rx = 0;
+
+       /* flush entire data cache before restarting the DMA */
+       flush_and_invalidate_dcache();
+
+       MCD_startDma(fp->fecpriv_fec_rx_channel, (char *) rxd, 0,
+                    (unsigned char *) (base_addr + FEC_FECRFDR), 0,
+                    FEC_MAX_FRM_SIZE, 0, fp->fecpriv_initiator_rx,
+                    FEC_RX_DMA_PRI, MCD_FECRX_DMA | MCD_INTERRUPT,
+                    MCD_NO_CSUM | MCD_NO_BYTE_SWAP);
+
+       netif_start_queue(dev);
+       return 0;
+
+ERRORS:
+
+       /* Remove the channels and return with the error code */
+       if (fp->fecpriv_fec_rx_channel != -1) {
+               dma_disconnect(fp->fecpriv_fec_rx_channel);
+               dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel);
+               fp->fecpriv_fec_rx_channel = -1;
+       }
+
+       if (fp->fecpriv_fec_tx_channel != -1) {
+               dma_disconnect(fp->fecpriv_fec_tx_channel);
+               dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel);
+               fp->fecpriv_fec_tx_channel = -1;
+       }
+
+       return error_code;
+}
+
+/************************************************************************
+* NAME: fec_close
+*
+* DESCRIPTION: This function performs the graceful stop of the
+*                              transmission and disables FEC
+*
+* RETURNS: This function always returns zero.
+*************************************************************************/
+int fec_close(struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+       unsigned long base_addr = (unsigned long) dev->base_addr;
+       unsigned long time;
+       int i;
+       unsigned long addr;
+
+       netif_stop_queue(dev);
+
+       /* Perform the graceful stop */
+       addr = dev->base_addr + FEC_TCR;
+       writel(readl(addr) | FEC_TCR_GTS, addr);
+
+       time = jiffies;
+
+       /* Wait for the graceful stop */
+       while (!(readl(base_addr + FEC_EIR) & FEC_EIR_GRA) && jiffies - time < 
FEC_GR_TIMEOUT * HZ)
+               schedule();
+
+       /* Disable FEC */
+       writel(FEC_ECR_DISABLE, base_addr + FEC_ECR);
+
+       /* Reset the DMA channels */
+       spin_lock_irq(&fp->fecpriv_lock);
+       MCD_killDma(fp->fecpriv_fec_tx_channel);
+       spin_unlock_irq(&fp->fecpriv_lock);
+       dma_remove_channel_by_number(fp->fecpriv_fec_tx_channel);
+       dma_disconnect(fp->fecpriv_fec_tx_channel);
+       fp->fecpriv_fec_tx_channel = -1;
+
+       for (i = 0; i < FEC_TX_BUF_NUMBER; i++) {
+               if (fp->fecpriv_txbuf[i]) {
+                       kfree(fp->fecpriv_txbuf[i]);
+                       fp->fecpriv_txbuf[i] = NULL;
+               }
+       }
+
+       spin_lock_irq(&fp->fecpriv_lock);
+       MCD_killDma(fp->fecpriv_fec_rx_channel);
+       spin_unlock_irq(&fp->fecpriv_lock);
+
+       dma_remove_channel_by_number(fp->fecpriv_fec_rx_channel);
+       dma_disconnect(fp->fecpriv_fec_rx_channel);
+       fp->fecpriv_fec_rx_channel = -1;
+
+       for (i = 0; i < FEC_RX_BUF_NUMBER; i++) {
+               if (fp->askb_rx[i]) {
+                       kfree_skb(fp->askb_rx[i]);
+                       fp->askb_rx[i] = NULL;
+               }
+       }
+
+       return 0;
+}
+
+#ifndef MODULE
+/************************************************************************
+* NAME: fec_str_to_mac
+*
+* DESCRIPTION: This function interprets the character string into MAC addr
+*
+*************************************************************************/
+int fec_str_to_mac(char *str_mac, unsigned char *addr)
+{
+       unsigned long val;
+       char c;
+       unsigned long octet[MAC_ADDR_LEN], *octetptr = octet;
+       int i;
+
+again:
+       val = 0;
+       while ((c = *str_mac) != '\0') {
+               c = hex_to_bin(c);
+               if (c >= 0) {
+                       val = (val * 16) + c;
+                       str_mac++;
+                       continue;
+               }
+               break;
+       }
+       if (*str_mac == ':') {
+               *octetptr++ = val, str_mac++;
+               if (octetptr >= octet + MAC_ADDR_LEN)
+                       return 1;
+               goto again;
+       }
+
+       /* Check for trailing characters */
+       if (*str_mac && !(*str_mac == ' '))
+               return 1;
+
+       *octetptr++ = val;
+
+       if ((octetptr - octet) == MAC_ADDR_LEN) {
+               for (i = 0; i <= MAC_ADDR_LEN; i++)
+                       addr[i] = octet[i];
+       } else
+               return 1;
+
+       return 0;
+}
+
+/************************************************************************
+* NAME: fec_mac_setup0
+*
+* DESCRIPTION: This function sets the MAC address of FEC0 from command line
+*
+*************************************************************************/
+int __init fec_mac_setup0(char *s)
+{
+       if (!s || !*s)
+               return 1;
+
+       if (fec_str_to_mac(s, fec0_addr))
+               pr_err("Invalid MAC address from command line for FEC0");
+       return 1;
+}
+__setup("mac0=", fec_mac_setup0);
+
+#ifdef CONFIG_FEC2
+/************************************************************************
+* NAME: fec_mac_setup1
+*
+* DESCRIPTION: This function sets the MAC address of FEC1 from command line
+*
+*************************************************************************/
+int __init fec_mac_setup1(char *s)
+{
+       if (!s || !*s)
+               return 1;
+
+       if (fec_str_to_mac(s, fec1_addr))
+               pr_err("Invalid MAC address from command line for FEC1");
+       return 1;
+}
+__setup("mac1=", fec_mac_setup1);
+#endif
+#endif
+
+#undef CONFIG_NET_POLL_CONTROLLER
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+static void fec_poll(struct net_device *dev)
+{
+#if 0
+       struct fec_priv *fp = netdev_priv(dev);
+#endif
+       /* disable_irq here is not very nice, but with the lockless
+          interrupt handler we have no other choice. */
+#if 0
+       fp->in_poll = 1;
+#endif
+       disable_irq(112);
+       disable_irq(dev->irq);
+       fec_interrupt_handler(dev->irq, dev);
+       fec_interrupt_fec_rx_handler(dev);
+       fec_interrupt_fec_tx_handler(dev);
+       enable_irq(dev->irq);
+       enable_irq(112);
+#if 0
+       fp->in_poll = 0;
+#endif
+}
+#endif
+
+static const struct net_device_ops fec_netdev_ops = {
+       .ndo_open               = fec_open,
+       .ndo_stop               = fec_close,
+       .ndo_start_xmit         = fec_start_tx,
+       .ndo_set_rx_mode        = fec_set_multicast_list,
+       .ndo_set_mac_address    = fec_set_mac_address,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_tx_timeout         = fec_tx_timeout,
+       .ndo_get_stats          = fec_get_stats,
+       .ndo_do_ioctl           = fec_ioctl,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = fec_poll,
+#endif
+};
+
+/*
+ * Initialize a FEC device
+ */
+int fec_enet_init(struct net_device *dev)
+{
+       static int index;
+       struct fec_priv *fp = netdev_priv(dev);
+       const void *mac_addr;
+       int i;
+       unsigned long addr;
+
+       fp->index = index;
+#if 0
+       fp->in_poll = 0;
+#endif
+       fp->netdev = dev;
+
+       if (index == 0) {
+               /* disable fec0 */
+               writel(FEC_ECR_DISABLE, FEC_BASE_ADDR_FEC0 + FEC_ECR);
+
+               /* setup the interrupt handler */
+               dev->irq = MCF_IRQ_FEC0;
+
+               if (request_irq(dev->irq, fec_interrupt_handler,
+                               IRQF_DISABLED, "ColdFire FEC 0", dev)) {
+                       dev->irq = 0;
+                       pr_err("Cannot allocate FEC0 IRQ\n");
+#if 0
+               } else {
+                       /* interrupt priority and level */
+                       MCF_ICR(ISC_FEC0) = ILP_FEC0;
+#endif
+               }
+
+               /* fec base address */
+               dev->base_addr = FEC_BASE_ADDR_FEC0;
+
+               /* requestor numbers */
+               fp->fecpriv_rx_requestor = DMA_FEC0_RX;
+               fp->fecpriv_tx_requestor = DMA_FEC0_TX;
+
+               /* tx descriptors */
+               fp->fecpriv_txdesc = (void *)FEC_TX_DESC_FEC0;
+
+               /* rx descriptors */
+               fp->fecpriv_rxdesc = (void *)FEC_RX_DESC_FEC0;
+
+               /* mac addr */
+               mac_addr = machdep_get_mac_address(index);
+               if (mac_addr)
+                       memcpy(fec0_addr, mac_addr, MAC_ADDR_LEN);
+               fp->fecpriv_mac_addr = fec0_addr;
+       } else {
+               /* disable fec1 */
+               writel(FEC_ECR_DISABLE, FEC_BASE_ADDR_FEC1 + FEC_ECR);
+#ifdef CONFIG_FEC2
+               /* setup the interrupt handler */
+               dev->irq = MCF_IRQ_FEC1;
+
+               if (request_irq(dev->irq, fec_interrupt_handler,
+                               IRQF_DISABLED, "ColdFire FEC 1", dev)) {
+                       dev->irq = 0;
+                       pr_err("Cannot allocate FEC1 IRQ\n");
+#if 0
+               } else {
+                       /* interrupt priority and level */
+                       MCF_ICR(ISC_FEC1) = ILP_FEC1;
+#endif
+               }
+
+               /* fec base address */
+               dev->base_addr = FEC_BASE_ADDR_FEC1;
+
+               /* requestor numbers */
+               fp->fecpriv_rx_requestor = DMA_FEC1_RX;
+               fp->fecpriv_tx_requestor = DMA_FEC1_TX;
+
+               /* tx descriptors */
+               fp->fecpriv_txdesc = (void *)FEC_TX_DESC_FEC1;
+
+               /* rx descriptors */
+               fp->fecpriv_rxdesc = (void *)FEC_RX_DESC_FEC1;
+
+               /* mac addr */
+               mac_addr = machdep_get_mac_address(index);
+               if (mac_addr)
+                       memcpy(fec1_addr, mac_addr, MAC_ADDR_LEN);
+               fp->fecpriv_mac_addr = fec1_addr;
+#endif
+       }
+
+       /* clear MIB */
+       memset((void *) (dev->base_addr + 0x200), 0, FEC_MIB_LEN);
+
+       /* clear the statistics structure */
+       memset((void *) &(fp->fecpriv_stat), 0,
+              sizeof(struct net_device_stats));
+
+       /* grab the FEC initiators */
+       dma_set_initiator(fp->fecpriv_tx_requestor);
+       fp->fecpriv_initiator_tx = dma_get_initiator(fp->fecpriv_tx_requestor);
+       dma_set_initiator(fp->fecpriv_rx_requestor);
+       fp->fecpriv_initiator_rx = dma_get_initiator(fp->fecpriv_rx_requestor);
+
+       /* reset the DMA channels */
+       fp->fecpriv_fec_rx_channel = -1;
+       fp->fecpriv_fec_tx_channel = -1;
+
+       for (i = 0; i < FEC_RX_BUF_NUMBER; i++)
+               fp->askb_rx[i] = NULL;
+
+       /* initialize the pointers to the socket buffers */
+       for (i = 0; i < FEC_TX_BUF_NUMBER; i++)
+               fp->fecpriv_txbuf[i] = NULL;
+
+       ether_setup(dev);
+
+       dev->watchdog_timeo = FEC_TX_TIMEOUT;
+       dev->netdev_ops = &fec_netdev_ops;
+       dev->ethtool_ops = &fec_ethtool_ops;
+
+
+       memcpy(dev->dev_addr, fp->fecpriv_mac_addr, ETH_ALEN);
+
+       spin_lock_init(&fp->fecpriv_lock);
+
+       /* Initialize FEC/I2C/IRQ Pin Assignment Register */
+       writew((readw(FEC_GPIO_PAR_FECI2CIRQ) & 0xF) | FEC_FECI2CIRQ,
+              FEC_GPIO_PAR_FECI2CIRQ);
+
+       /* set MII mode (as opposed to 7-wires mode) */
+       addr = dev->base_addr + FEC_RCR;
+       writel(readl(addr) | FEC_RCR_MII, addr);
+
+       index++;
+       return 0;
+}
+
+/*
+ * Stop a device
+ */
+void fec_stop(struct net_device *dev)
+{
+       struct fec_priv *fp = netdev_priv(dev);
+
+       dma_remove_initiator(fp->fecpriv_initiator_tx);
+       dma_remove_initiator(fp->fecpriv_initiator_rx);
+
+       if (dev->irq)
+               free_irq(dev->irq, dev);
+}
+
+/*
+ * Module Initialization
+ */
+int __init fec_init(void)
+{
+       struct net_device *dev;
+       int i;
+       int err;
+
+       pr_info("FEC ENET (DMA) Version %s\n", VERSION);
+
+       for (i = 0; i < FEC_MAX_PORTS; i++) {
+               dev = alloc_etherdev(sizeof(struct fec_priv));
+               if (!dev)
+                       return -ENOMEM;
+               netif_carrier_off(dev);
+               err = fec_enet_init(dev);
+               if (err) {
+                       free_netdev(dev);
+                       continue;
+               }
+               if (register_netdev(dev) != 0) {
+                       free_netdev(dev);
+                       return -EIO;
+               }
+
+               /*
+                * On the freescale dev board, E0MDC & E0MDIO are
+                * connected to a dual phy.  E1MDC & E1MDIO are unused.
+                * In other words, only fec 0 can communicate with
+                * the dual phy.
+                */
+               if (i == 0)
+                       fec_mdio_init(dev);
+
+               fec_phy_start(dev);
+
+               pr_info("%s: ethernet %pM\n",
+                      dev->name, dev->dev_addr);
+       }
+       return 0;
+}
+
+/* module_exit(fec_cleanup); */
+module_init(fec_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/freescale/fec_m54xx.h 
b/drivers/net/ethernet/freescale/fec_m54xx.h
new file mode 100644
index 0000000..022ee32
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_m54xx.h
@@ -0,0 +1,144 @@
+
+#define FEC_BASE_ADDR_FEC0     ((unsigned int)MCF_MBAR + 0x9000)
+#define FEC_BASE_ADDR_FEC1     ((unsigned int)MCF_MBAR + 0x9800)
+
+#define FEC_GPIO_PAR_FECI2CIRQ ((unsigned int)MCF_MBAR + 0xA44)
+#define FEC_FECI2CIRQ  (0xFFC0)

These belong in the m54xxsim.h. They are specific to the 5475/5485, that is
that nice platform separate again :-)


+#define FEC_ECR_DISABLE                (0x00000000)
+
+#define FEC_EIR                                0x004
+#define FEC_EIMR                       0x008
+#define FEC_ECR                                0x024
+#define FEC_MMFR                       0x040
+#define FEC_MSCR                       0x044
+#define FEC_MIBC                       0x064
+#define FEC_RCR                                0x084
+#define FEC_TCR                                0x0C4
+#define FEC_PALR                       0x0E4
+#define FEC_PAUR                       0x0E8
+#define FEC_IAUR                       0x118
+#define FEC_IALR                       0x11C
+#define FEC_GAUR                       0x120
+#define FEC_GALR                       0x124
+#define FEC_FECTFWR                    0x144
+#define FEC_FECRFDR                    0x184
+#define FEC_FECRFSR                    0x188
+#define FEC_FECRFCR                    0x18C
+#define FEC_FECRFAR                    0x198
+#define FEC_FECTFDR                    0x1A4
+#define FEC_FECTFSR                    0x1A8
+#define FEC_FECTFCR                    0x1AC
+#define FEC_FECTFAR                    0x1B8
+#define FEC_FECFRST                    0x1C4
+#define FEC_CTCWR                      0x1C8
+#define FECSTAT_RMON_T_PACKETS         0x204
+#define FECSTAT_RMON_T_COL             0x224
+#define FECSTAT_RMON_T_OCTETS          0x244
+#define FECSTAT_IEEE_T_DROP            0x248
+#define FECSTAT_IEEE_T_FRAME_OK                0x24C
+#define FECSTAT_IEEE_T_LCOL            0x25C
+#define FECSTAT_IEEE_T_MACERR          0x264
+#define FECSTAT_IEEE_T_CSERR           0x268
+#define FECSTAT_IEEE_T_OCTETS_OK       0x274
+#define FECSTAT_RMON_R_PACKETS         0x284
+#define FECSTAT_RMON_R_MC_PKT          0x28C
+#define FECSTAT_RMON_R_UNDERSIZE       0x294
+#define FECSTAT_RMON_R_OVERSIZE                0x298
+#define FECSTAT_RMON_R_FRAG            0x29C
+#define FECSTAT_RMON_R_JAB             0x2A0
+#define FECSTAT_RMON_R_OCTETS          0x2C4
+#define FECSTAT_IEEE_R_DROP            0x2C8
+#define FECSTAT_IEEE_R_FRAME_OK                0x2CC
+#define FECSTAT_IEEE_R_CRC             0x2D0
+#define FECSTAT_IEEE_R_ALIGN           0x2D4
+#define FECSTAT_IEEE_R_MACERR          0x2D8
+#define FECSTAT_IEEE_R_OCTETS_OK       0x2E0
+
+#define FEC_MAX_FRM_SIZE       (1518)
+#define FEC_MAXBUF_SIZE                (1520)
+
+/* Register values */
+#define FEC_ECR_RESET          (0x00000001)
+
+#define FEC_EIR_CLEAR          (0xFFFFFFFF)
+#define FEC_EIR_RL             (0x00100000)
+#define FEC_EIR_HBERR          (0x80000000)
+#define FEC_EIR_BABR           (0x40000000)    /* babbling receive error */
+#define FEC_EIR_BABT           (0x20000000)    /* babbling transmit error */
+#define FEC_EIR_GRA            (0x10000000)
+#define FEC_EIR_TXF            (0x08000000)    /* transmit frame interrupt */
+#define FEC_EIR_MII            (0x00800000)    /* MII interrupt */
+#define FEC_EIR_LC             (0x00200000)    /* late collision */
+#define FEC_EIR_XFUN           (0x00080000)    /* transmit FIFO underrun */
+#define FEC_EIR_XFERR          (0x00040000)    /* transmit FIFO error */
+#define FEC_EIR_RFERR          (0x00020000)    /* receive FIFO error */
+
+#define FEC_RCR_MAX_FRM_SIZE   (FEC_MAX_FRM_SIZE << 16)
+#define FEC_RCR_MII            (0x00000004)
+#define FEC_FECRFCR_FAE                (0x00400000)    /* frame accept error */
+#define FEC_FECRFCR_RXW                (0x00200000)    /* receive wait 
condition */
+#define FEC_FECRFCR_UF         (0x00100000)    /* receive FIFO underflow */
+#define FEC_FECRFCR_FRM                (0x08000000)
+#define FEC_FECRFCR_GR         (0x7 << 24)
+
+#define FEC_EIMR_DISABLE       (0x00000000)
+
+#define FEC_FECRFAR_ALARM      (0x300)
+#define FEC_FECTFCR_FRM                (0x08000000)
+#define FEC_FECTFCR_GR         (0x7 << 24)
+#define FEC_FECTFCR_FAE                (0x00400000)    /* frame accept error */
+#define FEC_FECTFCR_TXW                (0x00040000)    /* transmit wait 
condition */
+#define FEC_FECTFCR_UF         (0x00100000)    /* transmit FIFO underflow */
+#define FEC_FECTFCR_OF         (0x00080000)    /* transmit FIFO overflow */
+
+#define FEC_FECTFAR_ALARM      (0x100)
+#define FEC_FECTFWR_XWMRK      (0x00000000)
+
+#define FEC_FECTFSR_MSK                (0xC0B00000)
+#define FEC_FECTFSR_TXW                (0x40000000)   /* transmit wait 
condition */
+#define FEC_FECTFSR_FAE                (0x00800000)   /* frame accept error */
+#define FEC_FECTFSR_UF         (0x00200000)   /* transmit FIFO underflow */
+#define FEC_FECTFSR_OF         (0x00100000)   /* transmit FIFO overflow */
+
+#define FEC_FECRFSR_MSK                (0x80F00000)
+#define FEC_FECRFSR_FAE                (0x00800000)   /* frame accept error */
+#define FEC_FECRFSR_RXW                (0x00400000)   /* receive wait 
condition */
+#define FEC_FECRFSR_UF         (0x00200000)   /* receive FIFO underflow */
+
+#define FEC_CTCWR_TFCW_CRC     (0x03000000)
+#define FEC_TCR_FDEN           (0x00000004)
+#define FEC_TCR_HBC            (0x00000002)
+#define FEC_RCR_DRT            (0x00000002)
+#define FEC_EIMR_MASK          (FEC_EIR_RL | FEC_EIR_HBERR)
+#define FEC_ECR_ETHEREN                (0x00000002)
+#define FEC_FECTFCR_MSK                (0x00FC0000)
+#define FEC_FECRFCR_MSK                (0x00F80000)
+#define FEC_TCR_GTS            (0x00000001)
+#define FEC_MIBC_ENABLE                (0x00000000)
+#define FEC_MIB_LEN            (228)
+#define FEC_PHY_ADDR           (0x01)
+
+#define FEC_RX_DMA_PRI         (6)
+#define FEC_TX_DMA_PRI         (6)
+
+#define FEC_RX_DESC_FEC0       (SYS_SRAM_FEC_START)
+#define FEC_TX_DESC_FEC0       (FEC_RX_DESC_FEC0 + FEC_RX_BUF_NUMBER * 
sizeof(struct MCD_bufDescFec))
+
+#define FEC_RX_DESC_FEC1       (SYS_SRAM_FEC_START + SYS_SRAM_FEC_SIZE/2)
+#define FEC_TX_DESC_FEC1       (FEC_RX_DESC_FEC1 + FEC_RX_BUF_NUMBER * 
sizeof(struct MCD_bufDescFec))
+
+#define FEC_MMFR_ST            (0x40000000)
+#define FEC_MMFR_OP_READ       (0x20000000)
+#define FEC_MMFR_OP_WRITE      (0x10020000)
+#define FEC_MMFR_TA            (0x00020000)
+#define FEC_MMFR_DATA          (0x0000ffff)   /* PHY data mask */
+
+#define FEC_FLAGS_RX           (0x00000001)
+
+#define FEC_CRCPOL             (0xEDB88320)
+
+#define FEC_GR_TIMEOUT         (1)
+
+#define FEC_SW_RST             0x2000000
+#define FEC_RST_CTL            0x1000000


Regards
Greg


--
------------------------------------------------------------------------
Greg Ungerer  --  Principal Engineer        EMAIL:     g...@snapgear.com
SnapGear Group, McAfee                      PHONE:       +61 7 3435 2888
8 Gardner Close                             FAX:         +61 7 3217 5323
Milton, QLD, 4064, Australia                WEB: http://www.SnapGear.com
_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to