[uClinux-dev] Re: fec patch problems

Michael Broughton mbobowik at telusplanet.net
Wed Jan 10 19:15:41 EST 2007


NZG wrote:
> Thanks Mike, 
> they just sold my last development board, sigh, but we should have a run of 
> new boards in house within the next couple days. Testing will resume at that 
> point.
>   

I look forward to hearing your results.

> As for the fec crash with the old driver,I was using the standard 
> uClinux-dist-20051110 cache code when it happened, which doesn't enable the 
> data cache at all does it?
>   

I have always had to enable the data cache myself.

> With this code and the old driver, the system works fine in most conditions, 
> but networking completely goes down under heavy load. It wouldn't be noticed 
> under a lot of normal testing, but is certainly a problem.
>   

This is the same behavior I noticed. I have not been able to reproduce 
this problem on my systems, with the new driver.

> thank you for the patches,
> NZG
>   

Here are a couple more.

I fixed the PHY id so that it can be altered at config time. Also, I 
fixed a type cast that was causing a compiler warning.

Automatic selection of the PHY id would be nice, but I am still unsure 
about the best way to do this. I guess I'll leave this alone for now.

Mike


-------------- next part --------------
diff -Naur linux-2.6.18.2/drivers/net/Kconfig linux-2.6.18.2.mod/drivers/net/Kconfig
--- linux-2.6.18.2/drivers/net/Kconfig	2006-11-03 18:33:58.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/Kconfig	2007-01-10 15:24:44.000000000 -0700
@@ -1839,6 +1839,8 @@
 	  Say Y here if you want to use the built-in ethernet controller of
 	  the Motorola 68360 processor.
 
+source "drivers/net/mcf_fec/Kconfig"
+
 config FEC
 	bool "FEC ethernet controller (of ColdFire CPUs)"
 	depends on M523x || M527x || M5272 || M528x || M520x
diff -Naur linux-2.6.18.2/drivers/net/Makefile linux-2.6.18.2.mod/drivers/net/Makefile
--- linux-2.6.18.2/drivers/net/Makefile	2006-11-03 18:33:58.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/Makefile	2007-01-10 15:24:44.000000000 -0700
@@ -91,6 +91,7 @@
 obj-$(CONFIG_SHAPER) += shaper.o
 obj-$(CONFIG_HP100) += hp100.o
 obj-$(CONFIG_SMC9194) += smc9194.o
+obj-$(CONFIG_MCF_FEC) += mcf_fec/
 obj-$(CONFIG_FEC) += fec.o
 obj-$(CONFIG_68360_ENET) += 68360enet.o
 obj-$(CONFIG_ARM_ETHERH) += 8390.o
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/fec.c linux-2.6.18.2.mod/drivers/net/mcf_fec/fec.c
--- linux-2.6.18.2/drivers/net/mcf_fec/fec.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/fec.c	2007-01-10 15:16:07.000000000 -0700
@@ -0,0 +1,1186 @@
+/*
+ * Fast Ethernet Controller (FEC) driver.
+ * Copyright (c) 2006 Michael Broughton (mbobowik at telusplanet.net)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include "fec.h"
+
+
+
+
+struct fec_private {
+	volatile struct fec_csr *hw;
+
+	unsigned long bdt_mem;
+	unsigned long rb_mem;
+
+	struct bd *tx_bd_ring;
+	struct sk_buff **tx_sb_ring;
+	unsigned long *tx_al_ring;
+	struct bd *rx_bd_ring;
+	unsigned long rx_bf_ring;
+
+	unsigned long tx_head, tx_tail, rx_tail;
+
+	unsigned long iaur, ialr, gaur, galr, rcr, tcr;
+
+	int link, duplex, speed, promisc;
+
+	int irqs[FEC_INTERRUPT_COUNT];
+
+	spinlock_t lock;
+
+	struct net_device_stats stats;
+
+	struct platform_device *pdev;
+
+	struct phy_device *phy;
+	unsigned int phy_id;
+
+	struct mii_bus mdio;
+	int mdio_irqs[PHY_MAX_ADDR];
+};
+
+
+
+
+static int fec_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+				u16 value);
+static int fec_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+static void fec_adjust_link(struct net_device *dev);
+
+static irqreturn_t fec_no_action(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fec_tx_err(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fec_eberr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fec_finish_xmit(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fec_receive(int irq, void *dev_id, struct pt_regs *regs);
+static int fec_request_interrupts(struct net_device *dev);
+static void fec_free_interrupts(struct net_device *dev);
+
+static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void fec_tx_timeout(struct net_device *dev);
+static struct net_device_stats *fec_get_stats(struct net_device *dev);
+static void fec_set_multicast_list(struct net_device *dev);
+static int fec_open(struct net_device *dev);
+static int fec_stop(struct net_device *dev);
+
+static void fec_reset(struct net_device *dev);
+static void fec_change_mode(struct net_device *dev);
+static void fec_hard_reset(struct net_device *dev);
+
+static int fec_res_init(struct net_device *dev);
+static int fec_init(struct net_device *dev);
+static void fec_cleanup(struct net_device *dev);
+static int fec_mdio_init(struct net_device *dev);
+static void fec_mdio_cleanup(struct net_device *dev);
+static int fec_probe(struct platform_device *pdev);
+static int fec_remove(struct platform_device *pdev);
+
+
+
+
+static const struct {
+	char *name;
+	irqreturn_t (*handler)(int, void *, struct pt_regs *);
+} fec_interrupts[FEC_INTERRUPT_COUNT] = {
+	{ "fec(TXF)",	fec_finish_xmit },
+	{ "fec(TXB)",	fec_no_action },
+	{ "fec(UN)",	fec_tx_err },
+	{ "fec(RL)",	fec_tx_err },
+	{ "fec(RXF)",	fec_receive },
+	{ "fec(RXB)",	fec_no_action },
+	{ "fec(MII)",	fec_no_action },
+	{ "fec(LC)",	fec_tx_err },
+	{ "fec(HBERR)",	fec_tx_err },
+	{ "fec(GRA)",	fec_no_action },
+	{ "fec(EBERR)",	fec_eberr },
+	{ "fec(BABT)",	fec_no_action },
+	{ "fec(BABR)",	fec_no_action },
+};
+
+
+static const unsigned char fec_default_mac[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+
+
+/*
+ * Debug routines
+ * *****************************************************************************
+ */
+
+
+#if defined(CONFIG_FEC_DEBUG)
+
+
+static void fec_dump_rings(struct bd *tx_bd, struct sk_buff **tx_sb,
+				struct bd *rx_bd)
+{
+	int i;
+
+	fec_flush_dcache();
+
+	if (tx_bd)
+		for (i = 0; i < TX_BD_COUNT; i++)
+			printk(KERN_DEBUG "FEC Debug: Tx %d BD 0x%04hx SB %p\n",
+					i,
+					tx_bd[i].sc,
+					tx_sb ? tx_sb[i] : 0);
+
+	if (rx_bd)
+		for (i = 0; i < RX_BD_COUNT; i++)
+			printk(KERN_DEBUG "FEC Debug: Rx %d BD 0x%04hx\n",
+					i,
+					x_bd[i].sc);
+}
+
+
+#else
+
+
+#define fec_dump_rings(a,b,c)
+
+
+#endif /* defined(CONFIG_FEC_DEBUG) */
+
+
+
+
+/*
+ * PHY layer callback routines
+ * *****************************************************************************
+ */
+
+
+static int fec_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+				u16 value)
+{
+	struct fec_private *priv = netdev_priv(bus->priv);
+	unsigned long frame, result;
+
+	frame = FEC_MMFR_WRITE(mii_id, regnum, value);
+
+	spin_lock(&priv->lock);
+
+	priv->hw->MMFR = frame;
+
+	while (!(priv->hw->EIR & FEC_EIR_MII))
+		cpu_relax();
+
+	result = priv->hw->MMFR;
+	priv->hw->EIR = FEC_EIR_MII;
+
+	spin_unlock(&priv->lock);
+
+	return 0;
+}
+
+
+static int fec_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct fec_private *priv = netdev_priv(bus->priv);
+	unsigned long frame, result;
+
+	frame = FEC_MMFR_READ(mii_id, regnum);
+
+	spin_lock(&priv->lock);
+
+	priv->hw->MMFR = frame;
+
+	while (!(priv->hw->EIR & FEC_EIR_MII))
+		cpu_relax();
+
+	result = priv->hw->MMFR;
+	priv->hw->EIR = FEC_EIR_MII;
+
+	spin_unlock(&priv->lock);
+
+	return (int)(result & FEC_MMFR_READ_MASK);
+}
+
+
+static void fec_adjust_link(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	if (priv->phy->link != priv->link ||
+		priv->phy->duplex != priv->duplex ||
+		priv->phy->speed != priv->speed) {
+		netif_tx_disable(dev);
+
+		spin_lock_irqsave(&priv->lock, flags);
+
+		priv->link = priv->phy->link;
+		priv->duplex = priv->phy->duplex;
+		priv->speed = priv->phy->speed;
+
+		fec_change_mode(dev);
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		if (priv->link) {
+			netif_wake_queue(dev);
+			pr_info("%s: Link Up %sMbit %s Duplex (phy%s)\n",
+				dev->name,
+				priv->speed == SPEED_100 ? "100" : "10",
+				priv->duplex == DUPLEX_FULL ? "Full" : "Half",
+				priv->phy->dev.bus_id);
+		} else
+			pr_info("%s: Link Down (phy%s)\n", 
+				dev->name,
+				priv->phy->dev.bus_id);
+	}
+}
+
+
+
+
+/*
+ * Interrupt setup and handlers
+ * *****************************************************************************
+ */
+
+
+static irqreturn_t fec_no_action(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fec_private *priv = netdev_priv(dev);
+
+	if (printk_ratelimit())
+		printk(KERN_CRIT
+			"%s: Unexpected or spurious interrupt (0x%lx, 0x%lx)\n",
+			dev->name, priv->hw->EIR, priv->hw->EIMR);
+
+	return IRQ_NONE;
+}
+
+
+static irqreturn_t fec_tx_err(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fec_private *priv = netdev_priv(dev);
+	unsigned long eir;
+
+	eir = priv->hw->EIR & FEC_EIR_ERR;
+
+	do {
+		priv->hw->EIR = eir;
+		if (eir & FEC_EIR_HBERR)
+			priv->stats.tx_heartbeat_errors++;
+		if (eir & FEC_EIR_LC)
+			priv->stats.tx_window_errors++;
+		if (eir & FEC_EIR_RL)
+			priv->stats.tx_aborted_errors++;
+		if (eir & FEC_EIR_UN)
+			priv->stats.tx_fifo_errors++;
+	} while ((eir = priv->hw->EIR & FEC_EIR_ERR));
+
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t fec_eberr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+
+	printk(KERN_CRIT "%s: Ethernet Bus Error\n", dev->name);
+	BUG();
+
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t fec_finish_xmit(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fec_private *priv = netdev_priv(dev);
+	unsigned long free_bds = 0;
+	struct bd *bd;
+
+	while (1) {
+		bd = &priv->tx_bd_ring[priv->tx_tail];
+
+		fec_flush_dcache_line(bd);
+
+		if (bd->sc & FEC_TX_BD_SC_R)
+			break;
+
+		if (!(bd->sc & FEC_TX_BD_SC_TO1))
+			break;
+
+		if (bd->sc & FEC_TX_BD_SC_L) {
+			if (!priv->tx_sb_ring[priv->tx_tail]) {
+				printk(KERN_CRIT "%s: Tx Ring error!\n",
+					dev->name);
+				fec_dump_rings(priv->tx_bd_ring,
+						priv->tx_sb_ring,
+						NULL);
+				BUG();
+			}
+
+			dev_kfree_skb_any(priv->tx_sb_ring[priv->tx_tail]);
+			priv->tx_sb_ring[priv->tx_tail] = NULL;
+
+			priv->stats.tx_packets++;
+		}
+
+		priv->stats.tx_bytes += bd->length;
+
+		bd->sc = (bd->sc & FEC_TX_BD_SC_W) ? FEC_TX_BD_SC_W : 0;
+
+		priv->tx_tail = TX_BD_IDX_INC(priv->tx_tail);
+
+		free_bds++;
+	}
+
+	priv->hw->EIR = FEC_EIR_TXF;
+
+	if (free_bds > 1 && netif_queue_stopped(dev))
+		netif_wake_queue(dev);
+
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t fec_receive(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct fec_private *priv = netdev_priv(dev);
+	struct bd *bd;
+	struct sk_buff *skb;
+	unsigned long start, end;
+	unsigned short len, err;
+
+	while (1) {
+
+		start = end = priv->rx_tail;
+
+		/* Get an index range for an entire frame, or we are done */
+		while (1) {
+			bd = &priv->rx_bd_ring[end];
+
+			fec_flush_dcache_line(bd);
+
+			if (bd->sc & FEC_RX_BD_SC_E)
+				goto receive_done;
+
+			if (bd->sc & FEC_RX_BD_SC_L)
+				break;
+
+			end = RX_BD_IDX_INC(end);
+
+			if (start == end) {
+				printk(KERN_CRIT "%s: Rx Ring error!\n",
+					dev->name);
+				fec_dump_rings(NULL, NULL, priv->rx_bd_ring);
+				BUG();
+			}
+		}
+
+		priv->rx_tail = RX_BD_IDX_INC(end);
+
+		if (bd->sc & FEC_RX_BD_SC_ERR) {
+			priv->stats.rx_errors++;
+
+			if (bd->sc & FEC_RX_BD_SC_NO)
+				priv->stats.rx_frame_errors++;
+			if (bd->sc & FEC_RX_BD_SC_CR)
+				priv->stats.rx_crc_errors++;
+			if (bd->sc & FEC_RX_BD_SC_OV)
+				priv->stats.rx_fifo_errors++;
+			if (bd->sc & FEC_RX_BD_SC_TR)
+				priv->stats.rx_frame_errors++;
+
+			err = 1;
+		} else {
+			len = bd->length - 4;
+			skb = dev_alloc_skb(len + 2);
+			if (skb) {
+				skb_reserve(skb, 2);
+				err = 0;
+			} else {
+				if (printk_ratelimit())
+					printk(KERN_NOTICE
+						"%s: Low on memory, "
+						"dropping packet\n",
+						dev->name);
+				priv->stats.rx_dropped++;
+				err = 1;
+			}
+		}
+
+		if (err) {
+			while (RX_BD_IDX_LT(start, end)) {
+				bd = &priv->rx_bd_ring[start];
+				if (bd->sc & FEC_RX_BD_SC_W)
+					bd->sc = FEC_RX_BD_SC_E |
+							FEC_RX_BD_SC_W;
+				else
+					bd->sc = FEC_RX_BD_SC_E;
+				start = RX_BD_IDX_INC(start);
+			}
+			bd = &priv->rx_bd_ring[end];
+			if (bd->sc & FEC_RX_BD_SC_W)
+				bd->sc = FEC_RX_BD_SC_E | FEC_RX_BD_SC_W;
+			else
+				bd->sc = FEC_RX_BD_SC_E;
+		} else {
+			fec_flush_dcache();
+
+			while (RX_BD_IDX_LT(start, end)) {
+				bd = &priv->rx_bd_ring[start];
+				memcpy(skb_put(skb, RX_BUF_LEN),
+						(void *)bd->address,
+						RX_BUF_LEN);
+				len -= RX_BUF_LEN;
+				if (bd->sc & FEC_RX_BD_SC_W)
+					bd->sc = FEC_RX_BD_SC_E |
+							FEC_RX_BD_SC_W;
+				else
+					bd->sc = FEC_RX_BD_SC_E;
+				start = RX_BD_IDX_INC(start);
+			}
+			bd = &priv->rx_bd_ring[end];
+			memcpy(skb_put(skb, len), (void *)bd->address, len);
+			if (bd->sc & FEC_RX_BD_SC_W)
+				bd->sc = FEC_RX_BD_SC_E | FEC_RX_BD_SC_W;
+			else
+				bd->sc = FEC_RX_BD_SC_E;
+
+			skb->dev = dev;
+			skb->protocol = eth_type_trans(skb, dev);
+
+			switch (netif_rx(skb)) {
+			case NET_RX_CN_LOW:
+			case NET_RX_CN_MOD:
+			case NET_RX_CN_HIGH:
+				/*
+				 * What can I do here?
+				 * If flow control is enabled,
+				 * send a pause frame?
+				 */
+			case NET_RX_SUCCESS:
+				priv->stats.rx_packets++;
+				priv->stats.rx_bytes += bd->length;
+				if (bd->sc & FEC_RX_BD_SC_MC)
+					priv->stats.multicast++;
+				if (bd->sc & FEC_RX_BD_SC_LG)
+					priv->stats.rx_length_errors++;
+				break;
+			case NET_RX_DROP:
+			case NET_RX_BAD:
+				priv->stats.rx_dropped++;
+				break;
+			}
+		}
+
+		priv->hw->RDAR = FEC_RDAR_ACTIVE;
+	}
+
+receive_done:
+	priv->hw->EIR = FEC_EIR_RXF;
+
+	return IRQ_HANDLED;
+}
+
+
+static int fec_request_interrupts(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	int i, j;
+
+	for (i = 0; i < FEC_INTERRUPT_COUNT; i++) {
+		if (request_irq(priv->irqs[i], fec_interrupts[i].handler, 0,
+				fec_interrupts[i].name, dev)) {
+			printk(KERN_ERR "%s: Could not request irq %d - %s!\n",
+				dev->name, priv->irqs[i],
+				fec_interrupts[i].name);
+			for (j = 0; j < i; j++)
+				free_irq(priv->irqs[j], dev);
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+
+static void fec_free_interrupts(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	int i;
+
+	for (i = 0; i < FEC_INTERRUPT_COUNT; i++)
+		free_irq(priv->irqs[i], dev);
+}
+
+
+
+
+/*
+ * Netdev routines
+ * *****************************************************************************
+ */
+
+
+static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	unsigned long free_bds, data;
+	unsigned short len;
+	struct bd *bd, *al_bd = NULL;
+
+	bd = &priv->tx_bd_ring[priv->tx_head];
+
+	free_bds = TX_BD_IDX_DIST(priv->tx_head, priv->tx_tail);
+	if (!free_bds) {
+		fec_flush_dcache_line(bd);
+		if (!(bd->sc & FEC_TX_BD_SC_TO1))
+			free_bds = TX_BD_COUNT;
+	}
+
+	if (free_bds <= 1)
+	{
+		printk(KERN_CRIT "%s: Tx Ring full when queue awake!\n",
+			dev->name);
+		fec_dump_rings(priv->tx_bd_ring, priv->tx_sb_ring, NULL);
+		BUG();
+	}
+
+	/* Make sure the data buffer is aligned on a four byte boundary. */
+	if (TX_SKB_UNALIGNED(skb->data)) {
+		/*
+		 * The data buffer is out of alignment. We need to copy the
+		 * first one, two, or three bytes to an alignment buffer.
+		 * 
+		 * It seems that the normal case is two bytes out of alignment.
+		 */
+		unsigned long *al = &priv->tx_al_ring[priv->tx_head];
+
+		al_bd = bd;
+		len = 4 - TX_SKB_UNALIGNED(skb->data);
+
+		memcpy(al, skb->data, len);
+
+		al_bd->address = (unsigned long)al;
+		al_bd->length = len;
+
+		if (al_bd->sc & FEC_TX_BD_SC_W)
+			al_bd->sc = FEC_TX_BD_SC_TO1 | FEC_TX_BD_SC_W;
+		else
+			al_bd->sc = FEC_TX_BD_SC_TO1;
+
+		priv->tx_head = TX_BD_IDX_INC(priv->tx_head);
+
+		free_bds--;
+
+		bd = &priv->tx_bd_ring[priv->tx_head];
+
+		/* fec_flush_dcache_line(bd); */
+
+		data = (unsigned long)skb->data + len;
+		len = (unsigned short)skb->len - len;
+	} else {
+		data = (unsigned long)skb->data;
+		len = (unsigned short)skb->len;
+	}
+
+	priv->tx_sb_ring[priv->tx_head] = skb;
+
+	bd->address = data;
+	bd->length = len;
+
+	if (bd->sc & FEC_TX_BD_SC_W)
+		bd->sc = FEC_TX_BD_SC_R | FEC_TX_BD_SC_TO1 | FEC_TX_BD_SC_W |
+				FEC_TX_BD_SC_L | FEC_TX_BD_SC_TC;
+	else
+		bd->sc = FEC_TX_BD_SC_R | FEC_TX_BD_SC_TO1 | FEC_TX_BD_SC_L |
+				FEC_TX_BD_SC_TC;
+
+	priv->tx_head = TX_BD_IDX_INC(priv->tx_head);
+
+	free_bds--;
+
+	if (al_bd)
+		al_bd->sc |= FEC_TX_BD_SC_R;
+
+	dev->trans_start = jiffies;
+
+	priv->hw->TDAR = FEC_TDAR_ACTIVE;
+
+	if (free_bds <= 1)
+		netif_stop_queue(dev);
+
+	return NETDEV_TX_OK;
+}
+
+
+static void fec_tx_timeout(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	fec_finish_xmit(0, dev, NULL);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+
+	return &priv->stats;
+}
+
+
+static void fec_set_multicast_list(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	unsigned long flags, iaur, ialr, gaur, galr;
+	struct dev_mc_list *dmi;
+	unsigned int i, j, bit, data, crc, promisc;
+	unsigned char hash;
+
+	iaur = ialr = 0;
+	gaur = galr = (dev->flags & IFF_ALLMULTI) ? 0xffffffff : 0;
+
+	for (j = 0, dmi = dev->mc_list; j < dev->mc_count; j++, dmi = dmi->next)
+	{
+		if (is_multicast_ether_addr(dmi->dmi_addr) &&
+			dev->flags & IFF_ALLMULTI)
+			continue;
+
+		crc = 0xffffffff;
+
+		/*
+		 * This is going to be slow. Anyone who needs to change the
+		 * multicast list often or has a large mc_count will want to
+		 * consider optimizing this.
+		 */
+		for (i = 0; i < dmi->dmi_addrlen; i++) {
+			data = dmi->dmi_addr[i];
+			for (bit = 0; bit < 8; bit++, data >>= 1)
+				crc = (crc >> 1) ^ (((crc ^ data) & 1) ?
+					CRC32_POLY : 0);
+		}
+
+		hash = CRC2HASH(crc);
+
+		if (dmi->dmi_addr[0] & 1) {
+			if (hash > 31)
+				gaur |= 1 << (hash - 32);
+			else
+				galr |= 1 << hash;
+		} else {
+			if (hash > 31)
+				iaur |= 1 << (hash - 32);
+			else
+				ialr |= 1 << hash;
+		}
+	}
+
+	promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
+
+	/* No need to stop the tx queue, the xmit_lock spin lock is locked */
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->promisc == promisc) {
+		priv->hw->IAUR = priv->iaur = iaur;
+		priv->hw->IALR = priv->ialr = ialr;
+		priv->hw->GAUR = priv->gaur = gaur;
+		priv->hw->GALR = priv->galr = galr;
+	} else {
+		priv->promisc = promisc;
+
+		priv->iaur = iaur;
+		priv->ialr = ialr;
+		priv->gaur = gaur;
+		priv->galr = galr;
+
+		fec_change_mode(dev);
+
+		pr_info("%s: Promiscuous mode %s\n", dev->name,
+				priv->promisc ? "enabled" : "disabled");
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static int fec_open(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	char phy_id[BUS_ID_SIZE];
+	int err;
+
+	err = fec_request_interrupts(dev);
+	if (err)
+		return err;
+
+	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->pdev->id, priv->phy_id);
+
+	priv->phy = phy_connect(dev, phy_id, &fec_adjust_link, 0);
+	if (IS_ERR(priv->phy)) {
+		printk(KERN_ERR "%s: %s: PHY connect failed\n",
+			dev->name, phy_id);
+		err = PTR_ERR(priv->phy);
+		priv->phy = NULL;
+		fec_free_interrupts(dev);
+		return err;
+	}
+
+	priv->phy->supported &= PHY_BASIC_FEATURES;
+	priv->phy->advertising = priv->phy->supported;
+
+	priv->hw->ECR = FEC_ECR_ETHER_EN;
+
+	phy_start(priv->phy);
+
+	return 0;
+}
+
+
+static int fec_stop(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+
+	if (priv->phy) {
+		phy_disconnect(priv->phy);
+		priv->phy = NULL;
+	}
+
+	netif_stop_queue(dev);
+
+	priv->hw->EIMR = FEC_EIMR_MASK_ALL;
+	priv->hw->ECR = FEC_ECR_OFF;
+
+	fec_free_interrupts(dev);
+
+	fec_hard_reset(dev);
+
+	return 0;
+}
+
+
+
+
+/*
+ * Reset routines
+ * *****************************************************************************
+ */
+
+
+static void fec_reset(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	int i;
+
+	priv->hw->ECR = FEC_ECR_RESET;
+
+	memset(priv->tx_bd_ring, 0, TX_BD_TABLE_LEN);
+	priv->tx_bd_ring[TX_BD_COUNT-1].sc |= FEC_TX_BD_SC_W;
+
+	for (i = 0; i < TX_SB_COUNT; i++) {
+		if (priv->tx_sb_ring[i]) {
+			dev_kfree_skb_any(priv->tx_sb_ring[i]);
+			priv->tx_sb_ring[i] = NULL;
+		}
+	}
+
+	memset(priv->tx_al_ring, 0, TX_AL_TABLE_LEN);
+
+	for (i = 0; i < RX_BD_COUNT; i++)
+		priv->rx_bd_ring[i].sc = FEC_RX_BD_SC_E;
+	priv->rx_bd_ring[RX_BD_COUNT-1].sc |= FEC_RX_BD_SC_W;
+
+	priv->tx_head = priv->tx_tail = priv->rx_tail = 0;
+
+	priv->hw->EIMR = FEC_EIMR_TXF | FEC_EIMR_RXF | FEC_EIMR_EBERR |
+				FEC_EIMR_ERR;
+	priv->hw->EIR = FEC_EIR_CLEAR_ALL;
+
+	priv->hw->IAUR = priv->iaur;
+	priv->hw->IALR = priv->ialr;
+
+	priv->hw->GAUR = priv->gaur;
+	priv->hw->GALR = priv->galr;
+
+	priv->hw->PALR = (0
+		| (dev->dev_addr[0] << 24)
+		| (dev->dev_addr[1] << 16)
+		| (dev->dev_addr[2] << 8)
+		| (dev->dev_addr[3] << 0));
+	priv->hw->PAUR = (0
+		| (dev->dev_addr[4] << 24)
+		| (dev->dev_addr[5] << 16));
+
+	priv->hw->RCR = priv->rcr;
+	priv->hw->TCR = priv->tcr;
+
+	priv->hw->MSCR = FEC_MSCR_MII_SPEED;
+
+	priv->hw->EMRBR = FEC_EMRBR_R_BUF_SIZE(RX_BUF_LEN);
+	priv->hw->ERDSR = (unsigned long)priv->rx_bd_ring;
+	priv->hw->ETDSR = (unsigned long)priv->tx_bd_ring;
+}
+
+
+static void fec_change_mode(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+
+	if (priv->duplex) {
+		priv->rcr |= FEC_RCR_FCE;
+		priv->rcr &= ~FEC_RCR_DRT;
+		priv->tcr |= FEC_TCR_FDEN;
+	} else {
+		priv->rcr &= ~FEC_RCR_FCE;
+		priv->rcr |= FEC_RCR_DRT;
+		priv->tcr &= ~FEC_TCR_FDEN;
+	}
+
+	if (priv->promisc)
+		priv->rcr |= FEC_RCR_PROM;
+	else
+		priv->rcr &= ~FEC_RCR_PROM;
+
+	fec_reset(dev);
+
+	if (priv->link) {
+		priv->hw->ECR = FEC_ECR_ETHER_EN;
+		priv->hw->RDAR = FEC_RDAR_ACTIVE;
+	}
+}
+
+
+static void fec_hard_reset(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+
+	priv->iaur = 0;
+	priv->ialr = 0;
+	priv->gaur = 0;
+	priv->galr = 0;
+	priv->rcr = FEC_RCR_MAX_FL(MAX_FL) | FEC_RCR_FCE | FEC_RCR_MII_MODE;
+	priv->tcr = FEC_TCR_FDEN;
+
+	priv->link = 0;
+	priv->duplex = DUPLEX_FULL;
+	priv->speed = SPEED_100;
+	priv->promisc = 0;
+
+	fec_reset(dev);
+}
+
+
+
+
+/*
+ * Init and cleanup routines
+ * *****************************************************************************
+ */
+
+
+static int fec_res_init(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	struct resource *r;
+	int i;
+
+	r = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "CSR");
+	if (!r) {
+		printk(KERN_ERR "FEC: CSR resource not found\n");
+		return -ENODEV;
+	}
+	priv->hw = (volatile struct fec_csr *)r->start;
+
+	r = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "MAC");
+	if (r && is_valid_ether_addr((void *)r->start))
+		memcpy(dev->dev_addr, (void *)r->start, ETH_ALEN);
+	else {
+		pr_info("FEC: MAC resource not found or not valid, "
+			"using default\n");
+		memcpy(dev->dev_addr, fec_default_mac, ETH_ALEN);
+	}
+
+	r = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "PHY_ID");
+	if (!r) {
+		printk(KERN_ERR "FEC: PHY_ID resource not found\n");
+		return -ENODEV;
+	}
+	priv->phy_id = *(unsigned int *)r->start;
+
+	for (i = 0; i < FEC_INTERRUPT_COUNT; i++) {
+		r = platform_get_resource_byname(priv->pdev, IORESOURCE_IRQ,
+							fec_interrupts[i].name);
+		if (!r) {
+			printk(KERN_ERR "FEC: %s resource irq not found\n",
+					fec_interrupts[i].name);
+			return -ENODEV;
+		}
+		priv->irqs[i] = (int)r->start;
+	}
+
+	return 0;
+}
+
+
+static int fec_init(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	struct {
+		struct bd	tx_bd_ring[TX_BD_COUNT];
+		struct sk_buff *tx_sb_ring[TX_SB_COUNT];
+		unsigned long	tx_al_ring[TX_AL_COUNT];
+		struct bd	rx_bd_ring[RX_BD_COUNT];
+	} *bdt;
+	unsigned long i, b;
+	int err;
+
+	err = fec_res_init(dev);
+	if (err)
+		return err;
+
+	if (RX_BD_TABLE_LEN > (BD_TABLE_LEN/2)) {
+		printk(KERN_ERR
+			"FEC: Not enought space for "
+			"the Rx buffer descriptors\n");
+		return -ENOMEM;
+	}
+
+	priv->bdt_mem = __get_free_pages(GFP_KERNEL, BD_TABLE_PAGE_ORDER);
+	if (!priv->bdt_mem) {
+		printk(KERN_ERR "FEC: Allocation of BD table mem failed\n");
+		return -ENOMEM;
+	}
+
+	priv->rb_mem = __get_free_pages(GFP_KERNEL, RX_BUF_PAGE_ORDER);
+	if (!priv->rb_mem) {
+		free_page(priv->bdt_mem);
+		printk(KERN_ERR "FEC: Allocation of Rx buffer mem failed\n");
+		return -ENOMEM;
+	}
+
+	memset((void *)priv->bdt_mem, 0, BD_TABLE_LEN);
+	memset((void *)priv->rb_mem, 0, RX_BF_TABLE_LEN);
+
+	bdt = (void *)priv->bdt_mem;
+
+	priv->tx_bd_ring = bdt->tx_bd_ring;
+	priv->tx_sb_ring = bdt->tx_sb_ring;
+	priv->tx_al_ring = bdt->tx_al_ring;
+	priv->rx_bd_ring = bdt->rx_bd_ring;
+
+	for (i = 0, b = priv->rb_mem; i < RX_BD_COUNT; i++, b += RX_BUF_SIZE)
+		priv->rx_bd_ring[i].address = b;
+
+	priv->lock = SPIN_LOCK_UNLOCKED;
+
+	dev->base_addr = (unsigned long)priv->hw;
+	dev->open = fec_open;
+	dev->stop = fec_stop;
+	dev->hard_start_xmit = fec_hard_start_xmit;
+	dev->tx_timeout = fec_tx_timeout;
+	dev->get_stats = fec_get_stats;
+	dev->set_multicast_list = fec_set_multicast_list;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	fec_hard_reset(dev);
+
+	return 0;
+}
+
+
+static void fec_cleanup(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+
+	free_pages(priv->bdt_mem, BD_TABLE_PAGE_ORDER);
+	free_pages(priv->rb_mem, RX_BUF_PAGE_ORDER);
+}
+
+
+static int fec_mdio_init(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+	int i, err;
+
+	priv->mdio.name = "FEC MII Bus";
+	priv->mdio.read = &fec_mdio_read;
+	priv->mdio.write = &fec_mdio_write;
+	priv->mdio.id = priv->pdev->id;
+	priv->mdio.priv = dev;
+	priv->mdio.dev = &priv->pdev->dev;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		priv->mdio_irqs[i] = PHY_POLL;
+	priv->mdio.irq = priv->mdio_irqs;
+
+	if ((err = mdiobus_register(&priv->mdio))) {
+		printk(KERN_ERR "%s: Cannot register as MDIO bus\n",
+			priv->mdio.name);
+		return err;
+	}
+
+	return 0;
+}
+
+
+static void fec_mdio_cleanup(struct net_device *dev)
+{
+	struct fec_private *priv = netdev_priv(dev);
+
+	mdiobus_unregister(&priv->mdio);
+}
+
+
+static int fec_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct fec_private *priv;
+	int err;
+
+	dev = alloc_etherdev(sizeof(*priv));
+	if (!dev)
+		return -ENOMEM;
+
+	priv = netdev_priv(dev);
+	priv->pdev = pdev;
+	platform_set_drvdata(pdev, dev);
+
+	err = fec_init(dev);
+	if (err)
+		goto fec_probe_init_fail;
+
+	err = fec_mdio_init(dev);
+	if (err)
+		goto fec_probe_mdio_init_fail;
+
+	err = register_netdev(dev);
+	if (err)
+		goto fec_probe_reg_netdev_fail;
+
+	pr_info("FEC: probed (%s)\n", dev->name);
+
+	return 0;
+
+fec_probe_reg_netdev_fail:
+	fec_mdio_cleanup(dev);
+
+fec_probe_mdio_init_fail:
+	fec_cleanup(dev);
+
+fec_probe_init_fail:
+	platform_set_drvdata(pdev, NULL);
+
+	free_netdev(dev);
+
+	return err;
+}
+
+
+static int fec_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+
+	unregister_netdev(dev);
+
+	fec_mdio_cleanup(dev);
+
+	fec_cleanup(dev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_netdev(dev);
+
+	return 0;
+}
+
+
+
+
+/*
+ * Module stuff
+ * *****************************************************************************
+ */
+
+
+static struct platform_driver fec_driver = {
+	.probe = fec_probe,
+	.remove = fec_remove,
+	.driver	= {
+		.name = "FEC",
+	},
+};
+
+
+static int __init fec_module_init(void)
+{
+	int err;
+
+	err = fec_platform_init();
+	if (err)
+		return err;
+
+	err = platform_driver_register(&fec_driver);
+	if (err)
+		fec_platform_cleanup();
+
+	return err;
+}
+
+
+static void __exit fec_module_cleanup(void)
+{
+	platform_driver_unregister(&fec_driver);
+	fec_platform_cleanup();
+}
+
+
+module_init(fec_module_init);
+module_exit(fec_module_cleanup);
+
+
+MODULE_AUTHOR("Michael Broughton <mbobowik at telusplanet.net>");
+MODULE_DESCRIPTION("ColdFire FEC driver");
+MODULE_LICENSE("GPL");
+
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/fec.h linux-2.6.18.2.mod/drivers/net/mcf_fec/fec.h
--- linux-2.6.18.2/drivers/net/mcf_fec/fec.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/fec.h	2007-01-10 15:24:44.000000000 -0700
@@ -0,0 +1,304 @@
+/*
+ * Fast Ethernet Controller (FEC) driver.
+ * Copyright (c) 2006 Michael Broughton (mbobowik at telusplanet.net)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#ifndef FEC_H
+#define	FEC_H
+
+
+#include <asm/cacheflush.h>
+#include <asm/coldfire.h>
+
+
+#define TX_TIMEOUT		(2*HZ)
+
+
+/*
+ * Maximum frame length. Usually 1500 plus 18 or 22.
+ */
+#define MAX_FL			1518
+
+/*
+ * Receive buffer size. Must be a power of two in the range 256-2048.
+ */
+#define RX_BUF_SIZE		2048
+
+/*
+ * Padding at the end of each receive buffer. Fixes an overflow issue on some
+ * ColdFire parts when running in 10baseT mode. Must have a value in {0,16,64}.
+ * When the receive buffer size equals 2048, this must be set to 16 or 64.
+ */
+#define RX_BUF_PADDING		16
+
+/*
+ * Base two logarithm of the number of pages to allocate for the buffer
+ * descriptor table.
+ */
+#define BD_TABLE_PAGE_ORDER	0
+
+/*
+ * Base two logarithm of the number of pages to allocate for receive buffers.
+ */
+#define RX_BUF_PAGE_ORDER	3
+
+#define RX_BUF_LEN		(RX_BUF_SIZE-RX_BUF_PADDING)
+
+#define BD_TABLE_LEN		((1<<BD_TABLE_PAGE_ORDER)*PAGE_SIZE)
+#define RX_BUF_COUNT		((1<<RX_BUF_PAGE_ORDER)*PAGE_SIZE/RX_BUF_SIZE)
+
+#define TX_BD_TABLE_LEN		(BD_TABLE_LEN/4)
+#define TX_SB_TABLE_LEN		(BD_TABLE_LEN/8)
+#define TX_AL_TABLE_LEN		(BD_TABLE_LEN/8)
+#define RX_BD_TABLE_LEN		(RX_BUF_COUNT*sizeof(struct bd))
+#define RX_BF_TABLE_LEN		(RX_BUF_COUNT*RX_BUF_SIZE)
+
+#define TX_BD_COUNT		(TX_BD_TABLE_LEN/sizeof(struct bd))
+#define TX_SB_COUNT		(TX_SB_TABLE_LEN/sizeof(struct sk_buff *))
+#define TX_AL_COUNT		(TX_AL_TABLE_LEN/sizeof(unsigned long))
+#define RX_BD_COUNT		(RX_BUF_COUNT)
+#define RX_BF_COUNT		(RX_BUF_COUNT)
+
+
+#define FEC_INTERRUPT_COUNT	13
+
+
+#define TX_SKB_UNALIGNED(a)	((unsigned short)(((unsigned long)(a)) & 0x3))
+
+
+#define HASH_BITS		6
+#define CRC32_POLY		0xedb88320
+#define CRC2HASH(crc)	(((crc) >> (32 - HASH_BITS)) & (~-(1<<HASH_BITS)))
+
+
+/*
+ * Macro's for dealing with buffer descriptor indices. The number of bd's must
+ * be a power of two for these to work.
+ */
+#define RX_BD_IDX_INC(i)	(((i)+1)&(RX_BD_COUNT-1))
+#define TX_BD_IDX_INC(i)	(((i)+1)&(TX_BD_COUNT-1))
+
+#define TX_BD_IDX_DIST(h,t)	(((t)-(h))&(TX_BD_COUNT-1))
+
+#define RX_BD_IDX_LT(a,b)	(((b)-(a))&(RX_BD_COUNT-1))
+
+
+/*
+ * FEC status/control registers
+ */
+struct fec_csr {
+	unsigned long	reserved0;
+	/* Interrupt Event Register */
+	unsigned long	EIR;
+	/* Interrupt Mask Register */
+	unsigned long	EIMR;
+	unsigned long	reserved1;
+	/* Receive Descriptor Active Register */
+	unsigned long	RDAR;
+	/* Transmit Descriptor Active Register */
+	unsigned long	TDAR;
+	unsigned long	reserved2[3];
+	/* Ethernet Control Register */
+	unsigned long	ECR;
+	unsigned long	reserved3[6];
+	/* MII Data Register */
+	unsigned long	MMFR;
+	/* MII Speed Control Register */
+	unsigned long	MSCR;
+	unsigned long	reserved4[7];
+	/* MIB Control/Status Register */
+	unsigned long	MIBC;
+	unsigned long	reserved5[7];
+	/* Receive Control Register */
+	unsigned long	RCR;
+	unsigned long	reserved6[15];
+	/* Transmit Control Register */
+	unsigned long	TCR;
+	unsigned long	reserved7[7];
+	/* Physical Address Low Register */
+	unsigned long	PALR;
+	/* Physical Address High + Type Field */
+	unsigned long	PAUR;
+	/* Opcode + Pause Duration */
+	unsigned long	OPD;
+	unsigned long	reserved8[10];
+	/* Upper 32 bits of Individual Hash Table */
+	unsigned long	IAUR;
+	/* Lower 32 bits of Individual Hash Table */
+	unsigned long	IALR;
+	/* Upper 32 bits of Group Hash Table */
+	unsigned long	GAUR;
+	/* Lower 32 bits of Group Hash Table */
+	unsigned long	GALR;
+	unsigned long	reserved9[7];
+	/* Transmit FIFO  Watermark */
+	unsigned long	TFWR;
+	unsigned long	reserved10;
+	/* FIFO Receive Bound Register */
+	unsigned long	FRBR;
+	/* FIFO Receive Start Register */
+	unsigned long	FRSR;
+	unsigned long	reserved11[11];
+	/* Pointer to Receive Descriptor Ring */
+	unsigned long	ERDSR;
+	/* Pointer to Transmit Descriptor Ring */
+	unsigned long	ETDSR;
+	/* Maximum Receive Buffer Size */
+	unsigned long	EMRBR;
+};
+
+#define FEC_EIR_HBERR		((unsigned long)0x80000000)
+#define FEC_EIR_BABR		((unsigned long)0x40000000)
+#define FEC_EIR_BABT		((unsigned long)0x20000000)
+#define FEC_EIR_GRA		((unsigned long)0x10000000)
+#define FEC_EIR_TXF		((unsigned long)0x08000000)
+#define FEC_EIR_TXB		((unsigned long)0x04000000)
+#define FEC_EIR_RXF		((unsigned long)0x02000000)
+#define FEC_EIR_RXB		((unsigned long)0x01000000)
+#define FEC_EIR_MII		((unsigned long)0x00800000)
+#define FEC_EIR_EBERR		((unsigned long)0x00400000)
+#define FEC_EIR_LC		((unsigned long)0x00200000)
+#define FEC_EIR_RL		((unsigned long)0x00100000)
+#define FEC_EIR_UN		((unsigned long)0x00080000)
+#define FEC_EIR_CLEAR_ALL	((unsigned long)0xffffffff)
+#define FEC_EIR_ERR		(FEC_EIR_HBERR | FEC_EIR_LC | FEC_EIR_RL | \
+					FEC_EIR_UN)
+
+#define FEC_EIMR_HBERR		((unsigned long)0x80000000)
+#define FEC_EIMR_BABR		((unsigned long)0x40000000)
+#define FEC_EIMR_BABT		((unsigned long)0x20000000)
+#define FEC_EIMR_GRA		((unsigned long)0x10000000)
+#define FEC_EIMR_TXF		((unsigned long)0x08000000)
+#define FEC_EIMR_TXB		((unsigned long)0x04000000)
+#define FEC_EIMR_RXF		((unsigned long)0x02000000)
+#define FEC_EIMR_RXB		((unsigned long)0x01000000)
+#define FEC_EIMR_MII		((unsigned long)0x00800000)
+#define FEC_EIMR_EBERR		((unsigned long)0x00400000)
+#define FEC_EIMR_LC		((unsigned long)0x00200000)
+#define FEC_EIMR_RL		((unsigned long)0x00100000)
+#define FEC_EIMR_UN		((unsigned long)0x00080000)
+#define FEC_EIMR_MASK_ALL	((unsigned long)0x00000000)
+#define FEC_EIMR_ERR		(FEC_EIMR_HBERR | FEC_EIMR_LC | FEC_EIMR_RL | \
+								FEC_EIMR_UN)
+
+#define FEC_RDAR_ACTIVE		((unsigned long)0x01000000)
+
+#define FEC_TDAR_ACTIVE		((unsigned long)0x01000000)
+
+#define FEC_ECR_ETHER_EN	((unsigned long)0x00000002)
+#define FEC_ECR_RESET		((unsigned long)0x00000001)
+#define FEC_ECR_OFF		((unsigned long)0x00000000)
+
+#define FEC_MMFR_READ(id,reg) \
+			((unsigned long)(0x60020000 | (((id) & 0x1f) << 23) | \
+			(((reg) & 0x1f) << 18)))
+#define FEC_MMFR_READ_MASK	((unsigned long)0x0000ffff)
+#define FEC_MMFR_WRITE(id,reg,val) \
+			((unsigned long)(0x50020000 | (((id) & 0x1f) << 23) | \
+			(((reg) & 0x1f) << 18) | ((val) & 0xffff)))
+
+#define FEC_MSCR_MII_SPEED	((unsigned long)((((MCF_CLK/500000)+5)/10)<<1))
+
+#define FEC_RCR_MAX_FL(len)	((unsigned long)(((len) & 0x7ff) << 16))
+#define FEC_RCR_FCE		((unsigned long)0x00000020)
+#define FEC_RCR_BC_REJ		((unsigned long)0x00000010)
+#define FEC_RCR_PROM		((unsigned long)0x00000008)
+#define FEC_RCR_MII_MODE	((unsigned long)0x00000004)
+#define FEC_RCR_DRT		((unsigned long)0x00000002)
+#define FEC_RCR_LOOP		((unsigned long)0x00000001)
+
+#define FEC_TCR_RFC_PAUSE	((unsigned long)0x00000010)
+#define FEC_TCR_TFC_PAUSE	((unsigned long)0x00000008)
+#define FEC_TCR_FDEN		((unsigned long)0x00000004)
+#define FEC_TCR_HBC		((unsigned long)0x00000002)
+#define FEC_TCR_GTS		((unsigned long)0x00000001)
+
+#define FEC_EMRBR_R_BUF_SIZE(size)	((unsigned long)((size) & 0x7f0))
+
+
+/*
+ * Buffer Descriptor and status/control field definitions
+ */
+struct bd {
+	unsigned short	sc;
+	unsigned short	length;
+	unsigned long	address;
+};
+
+/* Empty */
+#define FEC_RX_BD_SC_E		((unsigned short)0x8000)
+/* Receive Software Ownership 1 */
+#define FEC_RX_BD_SC_RO1	((unsigned short)0x4000)
+/* Wrap */
+#define FEC_RX_BD_SC_W		((unsigned short)0x2000)
+/* Receive Software Ownership 2 */
+#define FEC_RX_BD_SC_RO2	((unsigned short)0x1000)
+/* Last in Frame */
+#define FEC_RX_BD_SC_L		((unsigned short)0x0800)
+/* Miss */
+#define FEC_RX_BD_SC_M		((unsigned short)0x0100)
+/* Broadcast */
+#define FEC_RX_BD_SC_BC		((unsigned short)0x0080)
+/* Multicast */
+#define FEC_RX_BD_SC_MC		((unsigned short)0x0040)
+/* Frame Length Violation */
+#define FEC_RX_BD_SC_LG		((unsigned short)0x0020)
+/* Non-Octet Aligned Frame */
+#define FEC_RX_BD_SC_NO		((unsigned short)0x0010)
+/* CRC Error */
+#define FEC_RX_BD_SC_CR		((unsigned short)0x0004)
+/* Overrun */
+#define FEC_RX_BD_SC_OV		((unsigned short)0x0002)
+/* Truncated */
+#define FEC_RX_BD_SC_TR		((unsigned short)0x0001)
+#define FEC_RX_BD_SC_ERR	(FEC_RX_BD_SC_NO | FEC_RX_BD_SC_CR | \
+					FEC_RX_BD_SC_OV | FEC_RX_BD_SC_TR)
+
+/* Ready */
+#define FEC_TX_BD_SC_R		((unsigned short)0x8000)
+/* Transmit Software Ownership 1 */
+#define FEC_TX_BD_SC_TO1	((unsigned short)0x4000)
+/* Wrap */
+#define FEC_TX_BD_SC_W		((unsigned short)0x2000)
+/* Transmit Software Ownership 2 */
+#define FEC_TX_BD_SC_TO2	((unsigned short)0x1000)
+/* Last in Frame */
+#define FEC_TX_BD_SC_L		((unsigned short)0x0800)
+/* Transmit CRC */
+#define FEC_TX_BD_SC_TC		((unsigned short)0x0400)
+/* Transmit Bad CRC */
+#define FEC_TX_BD_SC_ABC	((unsigned short)0x0200)
+
+
+#define fec_flush_dcache()		flush_cache_all()
+#define fec_flush_dcache_line(l)	flush_cache_all()
+
+
+#define FEC_RES(n,s,e,f) 	\
+	{ .name = (n), .start = (s), .end = (e), .flags = (f) }
+
+#define FEC_RES_MEM(n,s,e) FEC_RES((n),(s),(e),IORESOURCE_MEM)
+#define FEC_RES_IRQ(i,n) FEC_RES((n),(i),(i),IORESOURCE_IRQ)
+
+
+int fec_platform_init(void);
+void fec_platform_cleanup(void);
+
+
+#endif /* FEC_H */
+
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/Kconfig linux-2.6.18.2.mod/drivers/net/mcf_fec/Kconfig
--- linux-2.6.18.2/drivers/net/mcf_fec/Kconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/Kconfig	2007-01-10 15:09:10.000000000 -0700
@@ -0,0 +1,50 @@
+config MCF_FEC
+	tristate "New FEC"
+	depends on M520x || M523x || M527x || M528x || M532x
+	select PHYLIB
+	help
+	  Say Y here if you want to use the built-in 10/100 Fast ethernet
+	  controller on some Motorola ColdFire processors.
+
+config MCF_FEC_PHY_ID1
+	hex "PHY ID"
+	depends on MCF_FEC
+	default "0x01"
+	help
+	  Specify the location of the PHY on your system.
+
+config MCF_FEC_MAC1
+	hex "MAC address location"
+	depends on MCF_FEC
+	default "0x00000000"
+	help
+	  If you want to load the MAC address from flash memory, specify 
+	  the address here. Zero uses the default value for the platform.
+
+config MCF_FEC2
+	bool "Second FEC support"
+	depends on MCF_FEC && M527x
+	help
+	  Say Y here if you want to use the second built-in 10/100 Fast
+	  ethernet controller on some Motorola ColdFire processors.
+
+config MCF_FEC_PHY_ID2
+	hex "Second FEC PHY ID"
+	depends on MCF_FEC && MCF_FEC2
+	default "0x01"
+	help
+	  Specify the location of the PHY on your system.
+
+config MCF_FEC_MAC2
+	hex "Second FEC MAC address location"
+	depends on MCF_FEC && MCF_FEC2
+	default "0x00000000"
+	help
+	  If you want to load the MAC address from flash memory, specify 
+	  the address here. Zero uses the default value for the platform.
+
+config MCF_FEC_DEBUG
+	bool "Debug mode"
+	depends on MCF_FEC
+	help
+	  Turn on debugging messages and memory dumps.
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m520x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m520x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m520x.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m520x.c	2007-01-10 15:11:36.000000000 -0700
@@ -0,0 +1,110 @@
+/*
+ * Platform device registration.
+ * Copyright (c) 2006 Michael Broughton (mbobowik at telusplanet.net)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#if defined(CONFIG_M520x)
+
+
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include "fec.h"
+
+
+static unsigned char m520x_fec_mac[] = {
+	0x00, 0x14, 0x15, 0x00, 0x01, 0xb5,
+};
+
+
+static unsigned int m520x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
+
+
+static struct platform_device m520x_fec_pdev = {
+	.name = "FEC",
+	.id	= 0,
+	.num_resources = 17,
+	.resource = (struct resource[]) {
+		FEC_RES_MEM("CSR",
+			(unsigned long)(MCF_MBAR + 0x00030000),
+			(unsigned long)(MCF_MBAR + 0x000301ff)),
+		FEC_RES_MEM("MIB",
+			(unsigned long)(MCF_MBAR + 0x00030200),
+			(unsigned long)(MCF_MBAR + 0x000303ff)),
+#if (CONFIG_MCF_FEC_MAC1 == 0)
+		FEC_RES_MEM("MAC",
+			(unsigned long)m520x_fec_mac,
+			(unsigned long)(m520x_fec_mac + ETH_ALEN - 1)),
+#else
+		FEC_RES_MEM("MAC",
+			(unsigned long)(CONFIG_MCF_FEC_MAC1),
+			(unsigned long)(CONFIG_MCF_FEC_MAC1 + ETH_ALEN - 1)),
+#endif
+		FEC_RES_MEM("PHY_ID",
+			(unsigned long)(&m520x_fec_phy_id),
+			(unsigned long)(&m520x_fec_phy_id)),
+		FEC_RES_IRQ((64 + 36), "fec(TXF)"),
+		FEC_RES_IRQ((64 + 37), "fec(TXB)"),
+		FEC_RES_IRQ((64 + 38), "fec(UN)"),
+		FEC_RES_IRQ((64 + 39), "fec(RL)"),
+		FEC_RES_IRQ((64 + 40), "fec(RXF)"),
+		FEC_RES_IRQ((64 + 41), "fec(RXB)"),
+		FEC_RES_IRQ((64 + 42), "fec(MII)"),
+		FEC_RES_IRQ((64 + 43), "fec(LC)"),
+		FEC_RES_IRQ((64 + 44), "fec(HBERR)"),
+		FEC_RES_IRQ((64 + 45), "fec(GRA)"),
+		FEC_RES_IRQ((64 + 46), "fec(EBERR)"),
+		FEC_RES_IRQ((64 + 47), "fec(BABT)"),
+		FEC_RES_IRQ((64 + 48), "fec(BABR)"),
+	},
+};
+
+
+int fec_platform_init(void)
+{
+	volatile unsigned char  *icrp;
+	volatile unsigned long  *imrp;
+	int i;
+
+	icrp = (volatile unsigned char *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_ICR0);
+	for (i = 36; i < 49; i++)
+		icrp[i] = 0x04;
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_IMRH);
+	*imrp &= ~0x0001FFF0;
+
+	*(volatile unsigned char *)(MCF_IPSBAR+MCF_GPIO_PAR_FEC) |= 0xf0;
+	*(volatile unsigned char *)(MCF_IPSBAR+MCF_GPIO_PAR_FECI2C) |= 0x0f;
+
+	return platform_device_register(&m520x_fec_pdev);
+}
+
+
+void fec_platform_cleanup(void)
+{
+	platform_device_unregister(&m520x_fec_pdev);
+}
+
+
+#endif
+
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m523x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m523x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m523x.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m523x.c	2007-01-10 15:11:40.000000000 -0700
@@ -0,0 +1,111 @@
+/*
+ * Platform device registration.
+ * Copyright (c) 2006 Michael Broughton (mbobowik at telusplanet.net)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#if defined(CONFIG_M523x)
+
+
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include "fec.h"
+
+
+static unsigned char m523x_fec_mac[] = {
+	0x00, 0xcf, 0x52, 0x35, 0xeb, 0x01,
+};
+
+
+static unsigned int m523x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
+
+
+static struct platform_device m523x_fec_pdev = {
+	.name = "FEC",
+	.id	= 0,
+	.num_resources = 17,
+	.resource = (struct resource[]) {
+		FEC_RES_MEM("CSR",
+			(unsigned long)(MCF_MBAR + 0x00001000),
+			(unsigned long)(MCF_MBAR + 0x000011ff)),
+		FEC_RES_MEM("MIB",
+			(unsigned long)(MCF_MBAR + 0x00001200),
+			(unsigned long)(MCF_MBAR + 0x000013ff)),
+#if (CONFIG_MCF_FEC_MAC1 == 0)
+		FEC_RES_MEM("MAC",
+			(unsigned long)m523x_fec_mac,
+			(unsigned long)(m523x_fec_mac + ETH_ALEN - 1)),
+#else
+		FEC_RES_MEM("MAC",
+			(unsigned long)(CONFIG_MCF_FEC_MAC1),
+			(unsigned long)(CONFIG_MCF_FEC_MAC1 + ETH_ALEN - 1)),
+#endif
+		FEC_RES_MEM("PHY_ID",
+			(unsigned long)(&m523x_fec_phy_id),
+			(unsigned long)(&m523x_fec_phy_id)),
+		FEC_RES_IRQ((64 + 23), "fec(TXF)"),
+		FEC_RES_IRQ((64 + 24), "fec(TXB)"),
+		FEC_RES_IRQ((64 + 25), "fec(UN)"),
+		FEC_RES_IRQ((64 + 26), "fec(RL)"),
+		FEC_RES_IRQ((64 + 27), "fec(RXF)"),
+		FEC_RES_IRQ((64 + 28), "fec(RXB)"),
+		FEC_RES_IRQ((64 + 29), "fec(MII)"),
+		FEC_RES_IRQ((64 + 30), "fec(LC)"),
+		FEC_RES_IRQ((64 + 31), "fec(HBERR)"),
+		FEC_RES_IRQ((64 + 32), "fec(GRA)"),
+		FEC_RES_IRQ((64 + 33), "fec(EBERR)"),
+		FEC_RES_IRQ((64 + 34), "fec(BABT)"),
+		FEC_RES_IRQ((64 + 35), "fec(BABR)"),
+	},
+};
+
+
+int fec_platform_init(void)
+{
+	volatile unsigned char *icrp;
+	volatile unsigned long *imrp;
+	int i, ilip;
+
+	icrp = (volatile unsigned char *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_ICR0);
+	for (i = 23, ilip = 0x28; i < 36; i++)
+		icrp[i] = ilip--;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_IMRH);
+	*imrp &= ~0x0000000f;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_IMRL);
+	*imrp &= ~0xff800001;
+
+	return platform_device_register(&m523x_fec_pdev);
+}
+
+
+void fec_platform_cleanup(void)
+{
+	platform_device_unregister(&m523x_fec_pdev);
+}
+
+
+#endif
+
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m527x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m527x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m527x.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m527x.c	2007-01-10 15:11:47.000000000 -0700
@@ -0,0 +1,196 @@
+/*
+ * Platform device registration.
+ * Copyright (c) 2006 Michael Broughton (mbobowik at telusplanet.net)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#if defined(CONFIG_M527x)
+
+
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include "fec.h"
+
+
+static unsigned char m527x_fec0_mac[] = {
+	0x00, 0xcf, 0x52, 0x75, 0xeb, 0x01,
+};
+
+
+static unsigned int m527x_fec0_phy_id = CONFIG_MCF_FEC_PHY_ID1;
+
+
+static struct platform_device m527x_fec0_pdev = {
+	.name = "FEC",
+	.id	= 0,
+	.num_resources = 17,
+	.resource = (struct resource[]) {
+		FEC_RES_MEM("CSR",
+			(unsigned long)(MCF_MBAR + 0x00001000),
+			(unsigned long)(MCF_MBAR + 0x000011ff)),
+		FEC_RES_MEM("MIB",
+			(unsigned long)(MCF_MBAR + 0x00001200),
+			(unsigned long)(MCF_MBAR + 0x000013ff)),
+#if (CONFIG_MCF_FEC_MAC1 == 0)
+		FEC_RES_MEM("MAC",
+			(unsigned long)m527x_fec0_mac,
+			(unsigned long)(m527x_fec0_mac + ETH_ALEN - 1)),
+#else
+		FEC_RES_MEM("MAC",
+			(unsigned long)(CONFIG_MCF_FEC_MAC1),
+			(unsigned long)(CONFIG_MCF_FEC_MAC1 + ETH_ALEN - 1)),
+#endif
+		FEC_RES_MEM("PHY_ID",
+			(unsigned long)(&m527x_fec0_phy_id),
+			(unsigned long)(&m527x_fec0_phy_id)),
+		FEC_RES_IRQ((64 + 23), "fec(TXF)"),
+		FEC_RES_IRQ((64 + 24), "fec(TXB)"),
+		FEC_RES_IRQ((64 + 25), "fec(UN)"),
+		FEC_RES_IRQ((64 + 26), "fec(RL)"),
+		FEC_RES_IRQ((64 + 27), "fec(RXF)"),
+		FEC_RES_IRQ((64 + 28), "fec(RXB)"),
+		FEC_RES_IRQ((64 + 29), "fec(MII)"),
+		FEC_RES_IRQ((64 + 30), "fec(LC)"),
+		FEC_RES_IRQ((64 + 31), "fec(HBERR)"),
+		FEC_RES_IRQ((64 + 32), "fec(GRA)"),
+		FEC_RES_IRQ((64 + 33), "fec(EBERR)"),
+		FEC_RES_IRQ((64 + 34), "fec(BABT)"),
+		FEC_RES_IRQ((64 + 35), "fec(BABR)"),
+	},
+};
+
+
+#if defined(CONFIG_MCF_FEC2)
+
+
+static unsigned char m527x_fec1_mac[] = {
+	0x00, 0xcf, 0x52, 0x75, 0xeb, 0x02,
+};
+
+
+static unsigned int m527x_fec1_phy_id = CONFIG_MCF_FEC_PHY_ID2;
+
+
+static struct platform_device m527x_fec1_pdev = {
+	.name = "FEC",
+	.id	= 1,
+	.num_resources = 17,
+	.resource = (struct resource[]) {
+		FEC_RES_MEM("CSR",
+			(unsigned long)(MCF_MBAR + 0x00001800),
+			(unsigned long)(MCF_MBAR + 0x000019ff)),
+		FEC_RES_MEM("MIB",
+			(unsigned long)(MCF_MBAR + 0x00002000),
+			(unsigned long)(MCF_MBAR + 0x000021ff)),
+#if (CONFIG_MCF_FEC_MAC2 == 0)
+		FEC_RES_MEM("MAC",
+			(unsigned long)m527x_fec1_mac,
+			(unsigned long)(m527x_fec1_mac + ETH_ALEN - 1)),
+#else
+		FEC_RES_MEM("MAC",
+			(unsigned long)(CONFIG_MCF_FEC_MAC2),
+			(unsigned long)(CONFIG_MCF_FEC_MAC2 + ETH_ALEN - 1)),
+#endif
+		FEC_RES_MEM("PHY_ID",
+			(unsigned long)(&m527x_fec1_phy_id),
+			(unsigned long)(&m527x_fec1_phy_id)),
+		FEC_RES_IRQ((128 + 23), "fec(TXF)"),
+		FEC_RES_IRQ((128 + 24), "fec(TXB)"),
+		FEC_RES_IRQ((128 + 25), "fec(UN)"),
+		FEC_RES_IRQ((128 + 26), "fec(RL)"),
+		FEC_RES_IRQ((128 + 27), "fec(RXF)"),
+		FEC_RES_IRQ((128 + 28), "fec(RXB)"),
+		FEC_RES_IRQ((128 + 29), "fec(MII)"),
+		FEC_RES_IRQ((128 + 30), "fec(LC)"),
+		FEC_RES_IRQ((128 + 31), "fec(HBERR)"),
+		FEC_RES_IRQ((128 + 32), "fec(GRA)"),
+		FEC_RES_IRQ((128 + 33), "fec(EBERR)"),
+		FEC_RES_IRQ((128 + 34), "fec(BABT)"),
+		FEC_RES_IRQ((128 + 35), "fec(BABR)"),
+	},
+};
+
+
+#endif
+
+
+int fec_platform_init(void)
+{
+	volatile unsigned char *icrp;
+	volatile unsigned long *imrp;
+	int err, i, ilip;
+
+	icrp = (volatile unsigned char *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_ICR0);
+	for (i = 23, ilip = 0x28; i < 36; i++)
+		icrp[i] = ilip--;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_IMRH);
+	*imrp &= ~0x0000000f;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_IMRL);
+	*imrp &= ~0xff800001;
+
+#if defined(CONFIG_MCF_FEC2)
+	icrp = (volatile unsigned char *)(MCF_IPSBAR+MCFICM_INTC1+MCFINTC_ICR0);
+	for (i = 23, ilip = 0x28; i < 36; i++)
+		icrp[i] = ilip--;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC1+MCFINTC_IMRH);
+	*imrp &= ~0x0000000f;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC1+MCFINTC_IMRL);
+	*imrp &= ~0xff800001;
+#endif
+
+	err = platform_device_register(&m527x_fec0_pdev);
+	if (err)
+		goto fec0_platform_init_err;
+
+#if defined(CONFIG_MCF_FEC2)
+	err = platform_device_register(&m527x_fec1_pdev);
+	if (err)
+		goto fec1_platform_init_err;
+#endif
+
+	return 0;
+
+fec1_platform_init_err:
+	platform_device_unregister(&m527x_fec0_pdev);
+
+fec0_platform_init_err:
+	return err;
+}
+
+
+void fec_platform_cleanup(void)
+{
+	platform_device_unregister(&m527x_fec0_pdev);
+#if defined(CONFIG_MCF_FEC2)
+	platform_device_unregister(&m527x_fec1_pdev);
+#endif
+}
+
+
+#endif
+
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m528x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m528x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m528x.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m528x.c	2007-01-10 15:11:50.000000000 -0700
@@ -0,0 +1,118 @@
+/*
+ * Platform device registration.
+ * Copyright (c) 2006 Michael Broughton (mbobowik at telusplanet.net)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#if defined(CONFIG_M528x)
+
+
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include "fec.h"
+
+
+static unsigned char m528x_fec_mac[] = {
+	0x00, 0xcf, 0x52, 0x82, 0xeb, 0x01,
+};
+
+
+static unsigned int m528x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
+
+
+static struct platform_device m528x_fec_pdev = {
+	.name = "FEC",
+	.id	= 0,
+	.num_resources = 17,
+	.resource = (struct resource[]) {
+		FEC_RES_MEM("CSR",
+			(unsigned long)(MCF_MBAR + 0x00001000),
+			(unsigned long)(MCF_MBAR + 0x000011ff)),
+		FEC_RES_MEM("MIB",
+			(unsigned long)(MCF_MBAR + 0x00001200),
+			(unsigned long)(MCF_MBAR + 0x000013ff)),
+#if (CONFIG_MCF_FEC_MAC1 == 0)
+		FEC_RES_MEM("MAC",
+			(unsigned long)m528x_fec_mac,
+			(unsigned long)(m528x_fec_mac + ETH_ALEN - 1)),
+#else
+		FEC_RES_MEM("MAC",
+			(unsigned long)(CONFIG_MCF_FEC_MAC1),
+			(unsigned long)(CONFIG_MCF_FEC_MAC1 + ETH_ALEN - 1)),
+#endif
+		FEC_RES_MEM("PHY_ID",
+			(unsigned long)(&m528x_fec_phy_id),
+			(unsigned long)(&m528x_fec_phy_id)),
+		FEC_RES_IRQ((64 + 23), "fec(TXF)"),
+		FEC_RES_IRQ((64 + 24), "fec(TXB)"),
+		FEC_RES_IRQ((64 + 25), "fec(UN)"),
+		FEC_RES_IRQ((64 + 26), "fec(RL)"),
+		FEC_RES_IRQ((64 + 27), "fec(RXF)"),
+		FEC_RES_IRQ((64 + 28), "fec(RXB)"),
+		FEC_RES_IRQ((64 + 29), "fec(MII)"),
+		FEC_RES_IRQ((64 + 30), "fec(LC)"),
+		FEC_RES_IRQ((64 + 31), "fec(HBERR)"),
+		FEC_RES_IRQ((64 + 32), "fec(GRA)"),
+		FEC_RES_IRQ((64 + 33), "fec(EBERR)"),
+		FEC_RES_IRQ((64 + 34), "fec(BABT)"),
+		FEC_RES_IRQ((64 + 35), "fec(BABR)"),
+	},
+};
+
+
+int fec_platform_init(void)
+{
+	volatile unsigned char *icrp;
+	volatile unsigned long *imrp;
+	volatile unsigned short *gpio_paspar;
+	volatile unsigned char *gpio_pehlpar;
+	int i, ilip;
+
+	icrp = (volatile unsigned char *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_ICR0);
+	for (i = 23, ilip = 0x28; i < 36; i++)
+		icrp[i] = ilip--;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_IMRH);
+	*imrp &= ~0x0000000f;
+
+	imrp = (volatile unsigned long *)(MCF_IPSBAR+MCFICM_INTC0+MCFINTC_IMRL);
+	*imrp &= ~0xff800001;
+
+	gpio_paspar = (volatile unsigned short *) (MCF_IPSBAR + 0x100056);
+	gpio_pehlpar = (volatile unsigned char *) (MCF_IPSBAR + 0x100058);
+	*gpio_paspar |= 0x0f00;
+	*gpio_pehlpar = 0xc0;
+
+	return platform_device_register(&m528x_fec_pdev);
+}
+
+
+void fec_platform_cleanup(void)
+{
+	platform_device_unregister(&m528x_fec_pdev);
+}
+
+
+#endif
+
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m532x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m532x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m532x.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m532x.c	2007-01-10 15:11:53.000000000 -0700
@@ -0,0 +1,135 @@
+/*
+ * Platform device registration.
+ * Copyright (c) 2006 Michael Broughton (mbobowik at telusplanet.net)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#if defined(CONFIG_M532x)
+
+
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+#include "fec.h"
+
+
+static unsigned char m532x_fec_mac[] = {
+	0x00, 0x14, 0x15, 0x00, 0x01, 0xb5,
+};
+
+
+static unsigned int m532x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
+
+
+static struct platform_device m532x_fec_pdev = {
+	.name = "FEC",
+	.id	= 0,
+	.num_resources = 17,
+	.resource = (struct resource[]) {
+		FEC_RES_MEM("CSR",
+			(unsigned long)(MCF_MBAR + 0x00030000),
+			(unsigned long)(MCF_MBAR + 0x000301ff)),
+		FEC_RES_MEM("MIB",
+			(unsigned long)(MCF_MBAR + 0x00030200),
+			(unsigned long)(MCF_MBAR + 0x000303ff)),
+#if (CONFIG_MCF_FEC_MAC1 == 0)
+		FEC_RES_MEM("MAC",
+			(unsigned long)m532x_fec_mac,
+			(unsigned long)(m532x_fec_mac + ETH_ALEN - 1)),
+#else
+		FEC_RES_MEM("MAC",
+			(unsigned long)(CONFIG_MCF_FEC_MAC1),
+			(unsigned long)(CONFIG_MCF_FEC_MAC1 + ETH_ALEN - 1)),
+#endif
+		FEC_RES_MEM("PHY_ID",
+			(unsigned long)(&m532x_fec_phy_id),
+			(unsigned long)(&m532x_fec_phy_id)),
+		FEC_RES_IRQ((64 + 36), "fec(TXF)"),
+		FEC_RES_IRQ((64 + 37), "fec(TXB)"),
+		FEC_RES_IRQ((64 + 38), "fec(UN)"),
+		FEC_RES_IRQ((64 + 39), "fec(RL)"),
+		FEC_RES_IRQ((64 + 40), "fec(RXF)"),
+		FEC_RES_IRQ((64 + 41), "fec(RXB)"),
+		FEC_RES_IRQ((64 + 42), "fec(MII)"),
+		FEC_RES_IRQ((64 + 43), "fec(LC)"),
+		FEC_RES_IRQ((64 + 44), "fec(HBERR)"),
+		FEC_RES_IRQ((64 + 45), "fec(GRA)"),
+		FEC_RES_IRQ((64 + 46), "fec(EBERR)"),
+		FEC_RES_IRQ((64 + 47), "fec(BABT)"),
+		FEC_RES_IRQ((64 + 48), "fec(BABR)"),
+	},
+};
+
+
+int fec_platform_init(void)
+{
+	/* Unmask interrupts */
+	MCF_INTC0_ICR36 = 0x2;
+	MCF_INTC0_ICR37 = 0x2;
+	MCF_INTC0_ICR38 = 0x2;
+	MCF_INTC0_ICR39 = 0x2;
+	MCF_INTC0_ICR40 = 0x2;
+	MCF_INTC0_ICR41 = 0x2;
+	MCF_INTC0_ICR42 = 0x2;
+	MCF_INTC0_ICR43 = 0x2;
+	MCF_INTC0_ICR44 = 0x2;
+	MCF_INTC0_ICR45 = 0x2;
+	MCF_INTC0_ICR46 = 0x2;
+	MCF_INTC0_ICR47 = 0x2;
+	MCF_INTC0_ICR48 = 0x2;
+
+	MCF_INTC0_IMRH &= ~(
+		MCF_INTC_IMRH_INT_MASK36 |
+		MCF_INTC_IMRH_INT_MASK37 |
+		MCF_INTC_IMRH_INT_MASK38 |
+		MCF_INTC_IMRH_INT_MASK39 |
+		MCF_INTC_IMRH_INT_MASK40 |
+		MCF_INTC_IMRH_INT_MASK41 |
+		MCF_INTC_IMRH_INT_MASK42 |
+		MCF_INTC_IMRH_INT_MASK43 |
+		MCF_INTC_IMRH_INT_MASK44 |
+		MCF_INTC_IMRH_INT_MASK45 |
+		MCF_INTC_IMRH_INT_MASK46 |
+		MCF_INTC_IMRH_INT_MASK47 |
+		MCF_INTC_IMRH_INT_MASK48 );
+
+	/* Set up gpio outputs for MII lines */
+	MCF_GPIO_PAR_FECI2C |= (0 |
+		MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+		MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
+	MCF_GPIO_PAR_FEC = (0 |
+		MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
+		MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
+
+	return platform_device_register(&m532x_fec_pdev);
+}
+
+
+void fec_platform_cleanup(void)
+{
+	platform_device_unregister(&m532x_fec_pdev);
+}
+
+
+#endif
+
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/Makefile linux-2.6.18.2.mod/drivers/net/mcf_fec/Makefile
--- linux-2.6.18.2/drivers/net/mcf_fec/Makefile	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/Makefile	2007-01-10 15:24:44.000000000 -0700
@@ -0,0 +1,27 @@
+#
+# Makefile for the FEC driver.
+#
+
+obj-$(CONFIG_MCF_FEC) += mcf_fec.o
+
+mcf_fec-objs := fec.o
+
+
+# Platform specific code.
+
+ifeq ($(CONFIG_M520x),y)
+mcf_fec-objs += m520x.o
+endif
+ifeq ($(CONFIG_M523x),y)
+mcf_fec-objs += m523x.o
+endif
+ifeq ($(CONFIG_M527x),y)
+mcf_fec-objs += m527x.o
+endif
+ifeq ($(CONFIG_M528x),y)
+mcf_fec-objs += m528x.o
+endif
+ifeq ($(CONFIG_M532x),y)
+mcf_fec-objs += m532x.o
+endif
+
-------------- next part --------------
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/fec.c linux-2.6.18.2.mod/drivers/net/mcf_fec/fec.c
--- linux-2.6.18.2/drivers/net/mcf_fec/fec.c	2007-01-10 15:30:20.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/fec.c	2007-01-10 15:16:07.000000000 -0700
@@ -1003,7 +1003,7 @@
 	memset((void *)priv->bdt_mem, 0, BD_TABLE_LEN);
 	memset((void *)priv->rb_mem, 0, RX_BF_TABLE_LEN);
 
-	bdt = (struct fec_bd_table *)priv->bdt_mem;
+	bdt = (void *)priv->bdt_mem;
 
 	priv->tx_bd_ring = bdt->tx_bd_ring;
 	priv->tx_sb_ring = bdt->tx_sb_ring;
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/Kconfig linux-2.6.18.2.mod/drivers/net/mcf_fec/Kconfig
--- linux-2.6.18.2/drivers/net/mcf_fec/Kconfig	2007-01-10 15:30:20.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/Kconfig	2007-01-10 15:09:10.000000000 -0700
@@ -6,31 +6,45 @@
 	  Say Y here if you want to use the built-in 10/100 Fast ethernet
 	  controller on some Motorola ColdFire processors.
 
-config MCF_FEC2
-	bool "Second FEC"
-	depends on MCF_FEC && M527x
-	help
-	  Say Y here if you want to use the second built-in 10/100 Fast
-	  ethernet controller on some Motorola ColdFire processors.
-
-config MCF_FEC_DEBUG
-	bool "Debug mode"
+config MCF_FEC_PHY_ID1
+	hex "PHY ID"
 	depends on MCF_FEC
+	default "0x01"
 	help
-	  Turn on debugging messages and memory dumps.
+	  Specify the location of the PHY on your system.
 
 config MCF_FEC_MAC1
-	hex "FEC MAC address location"
+	hex "MAC address location"
 	depends on MCF_FEC
 	default "0x00000000"
 	help
 	  If you want to load the MAC address from flash memory, specify 
-	  the address here. Zero uses the default value.
+	  the address here. Zero uses the default value for the platform.
+
+config MCF_FEC2
+	bool "Second FEC support"
+	depends on MCF_FEC && M527x
+	help
+	  Say Y here if you want to use the second built-in 10/100 Fast
+	  ethernet controller on some Motorola ColdFire processors.
+
+config MCF_FEC_PHY_ID2
+	hex "Second FEC PHY ID"
+	depends on MCF_FEC && MCF_FEC2
+	default "0x01"
+	help
+	  Specify the location of the PHY on your system.
 
 config MCF_FEC_MAC2
 	hex "Second FEC MAC address location"
-	depends on MCF_FEC2
+	depends on MCF_FEC && MCF_FEC2
 	default "0x00000000"
 	help
 	  If you want to load the MAC address from flash memory, specify 
-	  the address here. Zero uses the default value.
+	  the address here. Zero uses the default value for the platform.
+
+config MCF_FEC_DEBUG
+	bool "Debug mode"
+	depends on MCF_FEC
+	help
+	  Turn on debugging messages and memory dumps.
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m520x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m520x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m520x.c	2007-01-10 15:30:20.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m520x.c	2007-01-10 15:11:36.000000000 -0700
@@ -38,7 +38,7 @@
 };
 
 
-static unsigned int m520x_fec_phy_id = 1;
+static unsigned int m520x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
 
 
 static struct platform_device m520x_fec_pdev = {
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m523x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m523x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m523x.c	2007-01-10 15:30:20.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m523x.c	2007-01-10 15:11:40.000000000 -0700
@@ -38,7 +38,7 @@
 };
 
 
-static unsigned int m523x_fec_phy_id = 1;
+static unsigned int m523x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
 
 
 static struct platform_device m523x_fec_pdev = {
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m527x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m527x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m527x.c	2007-01-10 15:30:20.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m527x.c	2007-01-10 15:11:47.000000000 -0700
@@ -38,7 +38,7 @@
 };
 
 
-static unsigned int m527x_fec0_phy_id = 1;
+static unsigned int m527x_fec0_phy_id = CONFIG_MCF_FEC_PHY_ID1;
 
 
 static struct platform_device m527x_fec0_pdev = {
@@ -89,7 +89,7 @@
 };
 
 
-static unsigned int m527x_fec1_phy_id = 1;
+static unsigned int m527x_fec1_phy_id = CONFIG_MCF_FEC_PHY_ID2;
 
 
 static struct platform_device m527x_fec1_pdev = {
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m528x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m528x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m528x.c	2007-01-10 15:30:20.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m528x.c	2007-01-10 15:11:50.000000000 -0700
@@ -38,7 +38,7 @@
 };
 
 
-static unsigned int m528x_fec_phy_id = 1;
+static unsigned int m528x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
 
 
 static struct platform_device m528x_fec_pdev = {
diff -Naur linux-2.6.18.2/drivers/net/mcf_fec/m532x.c linux-2.6.18.2.mod/drivers/net/mcf_fec/m532x.c
--- linux-2.6.18.2/drivers/net/mcf_fec/m532x.c	2007-01-10 15:30:20.000000000 -0700
+++ linux-2.6.18.2.mod/drivers/net/mcf_fec/m532x.c	2007-01-10 15:11:53.000000000 -0700
@@ -38,7 +38,7 @@
 };
 
 
-static unsigned int m532x_fec_phy_id = 1;
+static unsigned int m532x_fec_phy_id = CONFIG_MCF_FEC_PHY_ID1;
 
 
 static struct platform_device m532x_fec_pdev = {


More information about the uClinux-dev mailing list