[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