* [RFC PATCH v0.1] net driver: mpc52xx fec
@ 2007-08-10 9:51 Domen Puncer
2007-08-10 13:02 ` Arnaldo Carvalho de Melo
` (3 more replies)
0 siblings, 4 replies; 47+ messages in thread
From: Domen Puncer @ 2007-08-10 9:51 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: netdev
Hi!
Not for merge (yet)! But please do review.
fec_mpc52xx driver (not in-tree, but floating around) isn't in very
good shape, so I tried to change that.
Diff against original is quite big (fec_phy.c is completely rewritten)
and confuzing, so I'm including whole drivers/net/fec_mpc52xx/ .
I still have 'make CONFIG_FEC_MPC52xx_MDIO=n compile and work' on my
TODO, maybe even ethtool support.
Domen
arch/powerpc/boot/dts/lite5200b.dts | 18
arch/powerpc/sysdev/bestcomm/fec.h | 14
drivers/net/fec_mpc52xx/Kconfig | 24
drivers/net/fec_mpc52xx/Makefile | 7
drivers/net/fec_mpc52xx/fec.c | 1002 ++++++++++++++++++++++++++++++++++++
drivers/net/fec_mpc52xx/fec.h | 299 ++++++++++
drivers/net/fec_mpc52xx/fec_phy.c | 229 ++++++++
drivers/net/fec_mpc52xx/fec_phy.h | 49 +
8 files changed, 1641 insertions(+), 1 deletion(-)
diff -pruN dummy/fec.c ./drivers/net/fec_mpc52xx/fec.c
--- dummy/fec.c 1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec.c 2007-08-10 10:59:00.000000000 +0200
@@ -0,0 +1,1002 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
+ * now maintained by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyrigth (C) 2003-2004 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/hardirq.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/mpc52xx.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/fec.h>
+
+#include "fec_phy.h"
+#include "fec.h"
+
+#define DRIVER_NAME "mpc52xx-fec"
+
+static irqreturn_t fec_interrupt(int, void *);
+static irqreturn_t fec_rx_interrupt(int, void *);
+static irqreturn_t fec_tx_interrupt(int, void *);
+static struct net_device_stats *fec_get_stats(struct net_device *);
+static void fec_set_multicast_list(struct net_device *dev);
+static void fec_hw_init(struct net_device *dev);
+static void fec_stop(struct net_device *dev);
+static void fec_start(struct net_device *dev);
+
+static u8 mpc52xx_fec_mac_addr[6];
+static u8 null_mac[6];
+
+static void fec_tx_timeout(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ dev_warn(&dev->dev, "transmit timed out\n");
+
+ fec_stop(dev);
+ fec_start(dev);
+
+ priv->stats.tx_errors++;
+
+ if (!priv->tx_full)
+ netif_wake_queue(dev);
+}
+
+static void fec_set_paddr(struct net_device *dev, u8 *mac)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->paddr1, *(u32*)(&mac[0]));
+ out_be32(&fec->paddr2, (*(u16*)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
+}
+
+static void fec_get_paddr(struct net_device *dev, u8 *mac)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ *(u32*)(&mac[0]) = in_be32(&fec->paddr1);
+ *(u16*)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
+}
+
+static int fec_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct sockaddr *sock = (struct sockaddr *)addr;
+
+ memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
+
+ fec_set_paddr(dev, sock->sa_data);
+ return 0;
+}
+
+static void fec_free_rx_buffers(struct bcom_task *s)
+{
+ struct sk_buff *skb;
+
+ while (!bcom_queue_empty(s)) {
+ skb = bcom_retrieve_buffer(s, NULL, NULL);
+ kfree_skb(skb);
+ }
+}
+
+static int fec_alloc_rx_buffers(struct bcom_task *rxtsk)
+{
+ while (!bcom_queue_full(rxtsk)) {
+ struct sk_buff *skb;
+ struct bcom_fec_bd *bd;
+
+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+ if (skb == 0)
+ return -EAGAIN;
+
+ /* zero out the initial receive buffers to aid debugging */
+ memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
+
+ bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = virt_to_phys(skb->data);
+
+ bcom_submit_next_buffer(rxtsk, skb);
+ }
+
+ return 0;
+}
+
+/* based on generic_adjust_link - fs_enet-main.c */
+static void fec_adjust_link(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ if (phydev->link != PHY_DOWN) {
+ if (phydev->duplex != priv->duplex) {
+ new_state = 1;
+ priv->duplex = phydev->duplex;
+ }
+
+ if (phydev->speed != priv->speed) {
+ new_state = 1;
+ priv->speed = phydev->speed;
+ }
+
+ if (priv->link == PHY_DOWN) {
+ new_state = 1;
+ priv->link = phydev->link;
+ netif_schedule(dev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+
+ } else if (priv->link) {
+ new_state = 1;
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ }
+
+ if (new_state && netif_msg_link(priv)) {
+ phy_print_status(phydev);
+ }
+}
+
+static int fec_init_phy(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[BUS_ID_SIZE];
+
+ struct device_node *dn, *phy_dn;
+ unsigned int phy_addr;
+ const phandle *ph;
+ const unsigned int *prop;
+ struct resource res;
+ int ret;
+
+ dn = priv->ofdev->node;
+ ph = of_get_property(dn, "phy-handle", NULL);
+ if (!ph) {
+ dev_err(&dev->dev, "can't find \"phy-handle\" in device tree\n");
+ return -ENODEV;
+ }
+ phy_dn = of_find_node_by_phandle(*ph);
+
+ prop = of_get_property(phy_dn, "reg", NULL);
+ ret = of_address_to_resource(phy_dn->parent, 0, &res);
+ if (ret) {
+ dev_err(&dev->dev, "of_address_to_resource failed\n");
+ return ret;
+ }
+
+ phy_addr = *prop;
+ of_node_put(phy_dn);
+
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, res.start, phy_addr);
+
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+
+ phydev = phy_connect(dev, phy_id, &fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: phy_connect failed\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ phydev->advertising &= ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half;
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+static int fec_open(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ int err = -EBUSY;
+
+ if (request_irq(dev->irq, &fec_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ DRIVER_NAME "_ctrl", dev)) {
+ dev_err(&dev->dev, "ctrl interrupt request failed\n");
+ goto out;
+ }
+ if (request_irq(priv->r_irq, &fec_rx_interrupt, IRQF_DISABLED,
+ DRIVER_NAME "_rx", dev)) {
+ dev_err(&dev->dev, "rx interrupt request failed\n");
+ goto free_ctrl_irq;
+ }
+ if (request_irq(priv->t_irq, &fec_tx_interrupt, IRQF_DISABLED,
+ DRIVER_NAME "_tx", dev)) {
+ dev_err(&dev->dev, "tx interrupt request failed\n");
+ goto free_2irqs;
+ }
+
+ bcom_fec_rx_reset(priv->rx_dmatsk);
+ bcom_fec_tx_reset(priv->tx_dmatsk);
+
+ err = fec_alloc_rx_buffers(priv->rx_dmatsk);
+ if (err) {
+ dev_err(&dev->dev, "fec_alloc_rx_buffers failed\n");
+ goto free_irqs;
+ }
+
+ err = fec_init_phy(dev);
+ if (err) {
+ dev_err(&dev->dev, "fec_init_phy failed\n");
+ goto free_skbs;
+ }
+ bcom_enable(priv->rx_dmatsk);
+ bcom_enable(priv->tx_dmatsk);
+
+ /* reset phy - this also wakes it from PDOWN */
+ phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(priv->phydev);
+
+ fec_start(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+
+ free_skbs:
+ fec_free_rx_buffers(priv->rx_dmatsk);
+
+ free_irqs:
+ free_irq(priv->t_irq, dev);
+ free_2irqs:
+ free_irq(priv->r_irq, dev);
+ free_ctrl_irq:
+ free_irq(dev->irq, dev);
+ out:
+
+ return err;
+}
+
+static int fec_close(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+
+ fec_stop(dev);
+
+ fec_free_rx_buffers(priv->rx_dmatsk);
+
+ phy_disconnect(priv->phydev);
+
+ free_irq(dev->irq, dev);
+ free_irq(priv->r_irq, dev);
+ free_irq(priv->t_irq, dev);
+
+ /* power down phy */
+ phy_stop(priv->phydev);
+ phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
+
+ return 0;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct bcom_fec_bd *bd;
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ if (net_ratelimit())
+ dev_err(&dev->dev, "transmit queue overrun\n");
+ return 1;
+ }
+
+ spin_lock_irq(&priv->lock);
+ dev->trans_start = jiffies;
+
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->tx_dmatsk);
+
+ bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_INT;
+ bd->skb_pa = virt_to_phys(skb->data);
+
+ bcom_submit_next_buffer(priv->tx_dmatsk, skb);
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ priv->tx_full = 1;
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irq(&priv->lock);
+
+ return 0;
+}
+
+/* This handles BestComm transmit task interrupts
+ */
+static irqreturn_t fec_tx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct fec_priv *priv = netdev_priv(dev);
+
+ spin_lock(&priv->lock);
+
+ while (bcom_buffer_done(priv->tx_dmatsk)) {
+ struct sk_buff *skb;
+ skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, NULL);
+
+ priv->tx_full = 0;
+ dev_kfree_skb_irq(skb);
+ }
+
+ if (netif_queue_stopped(dev) && !priv->tx_full)
+ netif_wake_queue(dev);
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct fec_priv *priv = netdev_priv(dev);
+
+ while (bcom_buffer_done(priv->rx_dmatsk)) {
+ struct sk_buff *skb;
+ struct sk_buff *rskb;
+ struct bcom_fec_bd *bd;
+ u32 status;
+
+ rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, NULL);
+
+ /* Test for errors in received frame */
+ if (status & BCOM_FEC_RX_BD_ERRORS) {
+ /* Drop packet and reuse the buffer */
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = virt_to_phys(rskb->data);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
+
+ priv->stats.rx_dropped++;
+
+ continue;
+ }
+
+ /* skbs are allocated on open, so now we allocate a new one,
+ * and remove the old (with the packet) */
+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+ if (skb) {
+ /* Process the received skb */
+ int length = status & BCOM_FEC_RX_BD_LEN_MASK;
+
+ skb_put(rskb, length - 4); /* length without CRC32 */
+
+ rskb->dev = dev;
+ rskb->protocol = eth_type_trans(rskb, dev);
+
+ netif_rx(rskb);
+ dev->last_rx = jiffies;
+ } else {
+ /* Can't get a new one : reuse the same & drop pkt */
+ dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
+ priv->stats.rx_dropped++;
+
+ skb = rskb;
+ }
+
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = virt_to_phys(skb->data);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, skb);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 ievent;
+
+ ievent = in_be32(&fec->ievent);
+
+ ievent &= ~FEC_IEVENT_MII; /* mii is handled separately */
+ if (!ievent)
+ return IRQ_NONE;
+
+ out_be32(&fec->ievent, ievent); /* clear pending events */
+
+ if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+ if (ievent & ~FEC_IEVENT_TFINT)
+ dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
+ return IRQ_HANDLED;
+ }
+
+ if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
+ if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+
+ fec_stop(dev);
+ fec_hw_init(dev);
+ fec_start(dev);
+
+ netif_wake_queue(dev);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &priv->stats;
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+/* printk(KERN_ALERT "%s: %i, rmon_r_octets: %i, rmon_r_packets: %i, "
+ "ieee_r_octets_ok: %i, ieee_r_frame_ok: %i, "
+ "%i\n",
+ __func__, __LINE__,
+ in_be32(&fec->rmon_r_octets), in_be32(&fec->rmon_r_packets),
+ in_be32(&fec->ieee_r_octets_ok), in_be32(&fec->ieee_r_frame_ok),
+ 0);
+*/
+ stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+ stats->rx_packets = in_be32(&fec->rmon_r_packets);
+ stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
+ in_be32(&fec->rmon_r_undersize) +
+ in_be32(&fec->rmon_r_oversize) +
+ in_be32(&fec->rmon_r_frag) +
+ in_be32(&fec->rmon_r_jab);
+
+ stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+ stats->tx_packets = in_be32(&fec->rmon_t_packets);
+ stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
+ in_be32(&fec->rmon_t_undersize) +
+ in_be32(&fec->rmon_t_oversize) +
+ in_be32(&fec->rmon_t_frag) +
+ in_be32(&fec->rmon_t_jab);
+
+ stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
+ stats->collisions = in_be32(&fec->rmon_t_col);
+
+ /* detailed rx_errors: */
+ stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
+ + in_be32(&fec->rmon_r_oversize)
+ + in_be32(&fec->rmon_r_frag)
+ + in_be32(&fec->rmon_r_jab);
+ stats->rx_over_errors = in_be32(&fec->r_macerr);
+ stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
+ stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
+ stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
+ stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
+
+ /* detailed tx_errors: */
+ stats->tx_aborted_errors = 0;
+ stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
+ stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
+ stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
+ stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
+
+ return stats;
+}
+
+/*
+ * Read MIB counters in order to reset them,
+ * then zero all the stats fields in memory
+ */
+static void fec_reset_stats(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->mib_control, FEC_MIB_DISABLE);
+ memset_io(&fec->rmon_t_drop, 0,
+ (u32)&fec->reserved10 - (u32)&fec->rmon_t_drop);
+ out_be32(&fec->mib_control, 0);
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void fec_set_multicast_list(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rx_control;
+
+ rx_control = in_be32(&fec->r_cntrl);
+
+ if (dev->flags & IFF_PROMISC) {
+ rx_control |= FEC_RCNTRL_PROM;
+ out_be32(&fec->r_cntrl, rx_control);
+ } else {
+ rx_control &= ~FEC_RCNTRL_PROM;
+ out_be32(&fec->r_cntrl, rx_control);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ out_be32(&fec->gaddr1, 0xffffffff);
+ out_be32(&fec->gaddr2, 0xffffffff);
+ } else {
+ u32 crc;
+ int i;
+ struct dev_mc_list *dmi;
+ u32 gaddr1 = 0x00000000;
+ u32 gaddr2 = 0x00000000;
+
+ dmi = dev->mc_list;
+ for (i=0; i<dev->mc_count; i++) {
+ crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
+ if (crc >= 32)
+ gaddr1 |= 1 << (crc-32);
+ else
+ gaddr2 |= 1 << crc;
+ dmi = dmi->next;
+ }
+ out_be32(&fec->gaddr1, gaddr1);
+ out_be32(&fec->gaddr2, gaddr2);
+ }
+ }
+}
+
+static void __init fec_str2mac(char *str, unsigned char *mac)
+{
+ int i;
+ u64 val64;
+
+ val64 = simple_strtoull(str, NULL, 16);
+
+ for (i = 0; i < 6; i++)
+ mac[5-i] = val64 >> (i*8);
+}
+
+static int __init mpc52xx_fec_mac_setup(char *mac_address)
+{
+ fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
+ return 0;
+}
+
+/* XXX do we need this? */
+__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
+
+/**
+ * fec_hw_init
+ * @dev: network device
+ *
+ * Setup various hardware setting, only needed once on start
+ */
+static void fec_hw_init(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ int i;
+
+ /* Whack a reset. We should wait for this. */
+ out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
+ for (i = 0; i < FEC_RESET_DELAY; ++i) {
+ if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
+ break;
+ udelay(1);
+ }
+ if (i == FEC_RESET_DELAY)
+ dev_err(&dev->dev, "FEC Reset timeout!\n");
+
+ /* set pause to 0x20 frames */
+ out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20);
+
+ /* high service request will be deasserted when there's < 7 bytes in fifo
+ * low service request will be deasserted when there's < 4*7 bytes in fifo
+ */
+ out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+ out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+
+ /* alarm when <= x bytes in FIFO */
+ out_be32(&fec->rfifo_alarm, 0x0000030c);
+ out_be32(&fec->tfifo_alarm, 0x00000100);
+
+ /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */
+ out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B);
+
+ /* enable crc generation */
+ out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC);
+ out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */
+ out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */
+
+ /* set phy speed and enable MII interrupt
+ * this can't be done in phy driver, since it needs to be called
+ * before fec stuff (even on resume) */
+ set_phy_speed(fec, priv->phy_speed);
+ out_be32(&fec->imask, in_be32(&fec->imask) | FEC_IMASK_MII);
+}
+
+/**
+ * fec_start
+ * @dev: network device
+ *
+ * This function is called to start or restart the FEC during a link
+ * change. This happens on fifo errors or when switching between half
+ * and full duplex.
+ */
+static void fec_start(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rcntrl;
+ u32 tcntrl;
+ u32 tmp;
+
+ /* clear sticky error bits */
+ tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
+ out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
+ out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
+
+ /* FIFOs will reset on fec_enable */
+ out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
+
+ /* Set station address. */
+ fec_set_paddr(dev, dev->dev_addr);
+
+ fec_set_multicast_list(dev);
+
+ /* set max frame len, enable flow control, select mii mode */
+ rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
+ rcntrl |= FEC_RCNTRL_FCE;
+ rcntrl |= MII_RCNTL_MODE;
+ if (priv->duplex == DUPLEX_FULL)
+ tcntrl = FEC_TCNTRL_FDEN; /* FD enable */
+ else {
+ rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
+ tcntrl = 0;
+ }
+ out_be32(&fec->r_cntrl, rcntrl);
+ out_be32(&fec->x_cntrl, tcntrl);
+
+ /* Clear any outstanding interrupt. */
+ out_be32(&fec->ievent, 0xffffffff);
+
+ /* Enable interrupts we wish to service. */
+ out_be32(&fec->imask, FEC_IMASK_ENABLE);
+
+ /* And last, enable the transmit and receive processing. */
+ out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->r_des_active, 0x01000000);
+
+ priv->tx_full = 0;
+}
+
+/**
+ * fec_stop
+ * @dev: network device
+ *
+ * stop all activity on fec and empty dma buffers
+ */
+static void fec_stop(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ unsigned long timeout;
+
+ out_be32(&fec->imask, FEC_IMASK_MII); /* disable all but MII interrupt */
+
+ /* Disable the rx and tx tasks. */
+ bcom_disable(priv->rx_dmatsk);
+
+ /* Wait for queues to drain, but only if we're in process context */
+ if (!in_interrupt()) {
+ timeout = jiffies + 2*HZ;
+ while (time_before(jiffies, timeout) &&
+ (!bcom_queue_empty(priv->tx_dmatsk) ||
+ !bcom_queue_empty(priv->rx_dmatsk))) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+ }
+ if (time_after_eq(jiffies, timeout))
+ dev_err(&dev->dev, "queues didn't drain\n");
+ }
+
+ bcom_disable(priv->tx_dmatsk);
+
+ /* Stop FEC */
+ out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
+
+ return;
+}
+
+static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
+
+ return phy_mii_ioctl(priv->phydev, mii, cmd);
+}
+
+/* ======================================================================== */
+/* OF Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
+{
+ int rv;
+ struct net_device *ndev;
+ struct fec_priv *priv = NULL;
+ struct resource mem;
+
+ phys_addr_t rx_fifo;
+ phys_addr_t tx_fifo;
+
+ /* Get the ether ndev & it's private zone */
+ ndev = alloc_etherdev(sizeof(struct fec_priv));
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+
+ priv->ofdev = op;
+
+ /* Reserve FEC control zone */
+ rv = of_address_to_resource(op->node, 0, &mem);
+ if (rv) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Error while parsing device node resource\n" );
+ return rv;
+ }
+ if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) {
+ printk(KERN_ERR DRIVER_NAME
+ " - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",
+ (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
+ return -EBUSY;
+
+ /* Init ether ndev with what we have */
+ ndev->open = fec_open;
+ ndev->stop = fec_close;
+ ndev->hard_start_xmit = fec_hard_start_xmit;
+ ndev->do_ioctl = fec_ioctl;
+ ndev->get_stats = fec_get_stats;
+ ndev->set_mac_address = fec_set_mac_address;
+ ndev->set_multicast_list = fec_set_multicast_list;
+ ndev->tx_timeout = fec_tx_timeout;
+ ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
+ ndev->flags &= ~IFF_RUNNING;
+ ndev->base_addr = mem.start;
+
+ priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
+
+ spin_lock_init(&priv->lock);
+
+ /* ioremap the zones */
+ priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec));
+
+ if (!priv->fec) {
+ rv = -ENOMEM;
+ goto probe_error;
+ }
+
+ /* Bestcomm init */
+ rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data);
+ tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data);
+
+ priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE);
+ priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
+
+ if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
+ printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
+ rv = -ENOMEM;
+ goto probe_error;
+ }
+
+ /* Get the IRQ we need one by one */
+ /* Control */
+ ndev->irq = irq_of_parse_and_map(op->node, 0);
+
+ /* RX */
+ priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
+
+ /* TX */
+ priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
+
+ /* MAC address init */
+ if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
+ memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
+ else
+ fec_get_paddr(ndev, ndev->dev_addr);
+
+ /* Phy speed */
+ priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
+
+ priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
+ priv->duplex = DUPLEX_HALF;
+
+ /* Hardware init */
+ fec_hw_init(ndev);
+
+ fec_reset_stats(ndev);
+
+ /* Register the new network device */
+ rv = register_netdev(ndev);
+ if (rv < 0)
+ goto probe_error;
+
+ /* We're done ! */
+ dev_set_drvdata(&op->dev, ndev);
+
+ return 0;
+
+
+ /* Error handling - free everything that might be allocated */
+probe_error:
+
+ irq_dispose_mapping(ndev->irq);
+
+ if (priv->rx_dmatsk)
+ bcom_fec_rx_release(priv->rx_dmatsk);
+ if (priv->tx_dmatsk)
+ bcom_fec_tx_release(priv->tx_dmatsk);
+
+ if (priv->fec)
+ iounmap(priv->fec);
+
+ release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
+
+ free_netdev(ndev);
+
+ return rv;
+}
+
+static int
+mpc52xx_fec_remove(struct of_device *op)
+{
+ struct net_device *ndev;
+ struct fec_priv *priv;
+
+ ndev = dev_get_drvdata(&op->dev);
+ if (!ndev)
+ return 0;
+ priv = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ irq_dispose_mapping(ndev->irq);
+
+ bcom_fec_rx_release(priv->rx_dmatsk);
+ bcom_fec_tx_release(priv->tx_dmatsk);
+
+ iounmap(priv->fec);
+
+ release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
+
+ free_netdev(ndev);
+
+ dev_set_drvdata(&op->dev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ if (netif_running(dev))
+ fec_close(dev);
+
+ return 0;
+}
+
+static int mpc52xx_fec_of_resume(struct of_device *op)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ fec_hw_init(dev);
+ fec_reset_stats(dev);
+
+ if (netif_running(dev))
+ fec_open(dev);
+
+ return 0;
+}
+#endif
+
+static struct of_device_id mpc52xx_fec_match[] = {
+ {
+ .type = "network",
+ .compatible = "mpc5200-fec",
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
+
+static struct of_platform_driver mpc52xx_fec_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .match_table = mpc52xx_fec_match,
+ .probe = mpc52xx_fec_probe,
+ .remove = mpc52xx_fec_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_fec_of_suspend,
+ .resume = mpc52xx_fec_of_resume,
+#endif
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_fec_init(void)
+{
+ int ret;
+ if ((ret = fec_mdio_init())) {
+ printk(KERN_ERR "%s: %i fec_mdio_init failed\n", __func__, __LINE__);
+ return ret;
+ }
+
+ return of_register_platform_driver(&mpc52xx_fec_driver);
+}
+
+static void __exit
+mpc52xx_fec_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_fec_driver);
+ fec_mdio_exit();
+}
+
+
+module_init(mpc52xx_fec_init);
+module_exit(mpc52xx_fec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
+
diff -pruN dummy/fec.h ./drivers/net/fec_mpc52xx/fec.h
--- dummy/fec.h 1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec.h 2007-08-10 11:24:37.000000000 +0200
@@ -0,0 +1,299 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
+#define __DRIVERS_NET_MPC52XX_FEC_H__
+
+#include <linux/mii.h> // XXX, still needed?
+#include <linux/phy.h>
+
+/* Tunable constant */
+/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
+#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
+#define FEC_RX_NUM_BD 64
+#define FEC_TX_NUM_BD 64
+
+#define FEC_RESET_DELAY 50 /* uS */
+
+#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
+
+struct fec_priv {
+ int duplex;
+ int tx_full;
+ int r_irq;
+ int t_irq;
+ struct mpc52xx_fec __iomem *fec;
+ struct bcom_task *rx_dmatsk;
+ struct bcom_task *tx_dmatsk;
+ spinlock_t lock;
+ struct net_device_stats stats;
+ int msg_enable;
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+ uint phy_speed;
+
+ struct phy_device *phydev;
+ enum phy_state link;
+ int speed;
+
+ struct of_device *ofdev;
+#endif /* CONFIG_FEC_MPC52xx_MDIO */
+};
+
+
+/* ======================================================================== */
+/* Hardware register sets & bits */
+/* ======================================================================== */
+
+struct mpc52xx_fec {
+ u32 fec_id; /* FEC + 0x000 */
+ u32 ievent; /* FEC + 0x004 */
+ u32 imask; /* FEC + 0x008 */
+
+ u32 reserved0[1]; /* FEC + 0x00C */
+ u32 r_des_active; /* FEC + 0x010 */
+ u32 x_des_active; /* FEC + 0x014 */
+ u32 r_des_active_cl; /* FEC + 0x018 */
+ u32 x_des_active_cl; /* FEC + 0x01C */
+ u32 ivent_set; /* FEC + 0x020 */
+ u32 ecntrl; /* FEC + 0x024 */
+
+ u32 reserved1[6]; /* FEC + 0x028-03C */
+ u32 mii_data; /* FEC + 0x040 */
+ u32 mii_speed; /* FEC + 0x044 */
+ u32 mii_status; /* FEC + 0x048 */
+
+ u32 reserved2[5]; /* FEC + 0x04C-05C */
+ u32 mib_data; /* FEC + 0x060 */
+ u32 mib_control; /* FEC + 0x064 */
+
+ u32 reserved3[6]; /* FEC + 0x068-7C */
+ u32 r_activate; /* FEC + 0x080 */
+ u32 r_cntrl; /* FEC + 0x084 */
+ u32 r_hash; /* FEC + 0x088 */
+ u32 r_data; /* FEC + 0x08C */
+ u32 ar_done; /* FEC + 0x090 */
+ u32 r_test; /* FEC + 0x094 */
+ u32 r_mib; /* FEC + 0x098 */
+ u32 r_da_low; /* FEC + 0x09C */
+ u32 r_da_high; /* FEC + 0x0A0 */
+
+ u32 reserved4[7]; /* FEC + 0x0A4-0BC */
+ u32 x_activate; /* FEC + 0x0C0 */
+ u32 x_cntrl; /* FEC + 0x0C4 */
+ u32 backoff; /* FEC + 0x0C8 */
+ u32 x_data; /* FEC + 0x0CC */
+ u32 x_status; /* FEC + 0x0D0 */
+ u32 x_mib; /* FEC + 0x0D4 */
+ u32 x_test; /* FEC + 0x0D8 */
+ u32 fdxfc_da1; /* FEC + 0x0DC */
+ u32 fdxfc_da2; /* FEC + 0x0E0 */
+ u32 paddr1; /* FEC + 0x0E4 */
+ u32 paddr2; /* FEC + 0x0E8 */
+ u32 op_pause; /* FEC + 0x0EC */
+
+ u32 reserved5[4]; /* FEC + 0x0F0-0FC */
+ u32 instr_reg; /* FEC + 0x100 */
+ u32 context_reg; /* FEC + 0x104 */
+ u32 test_cntrl; /* FEC + 0x108 */
+ u32 acc_reg; /* FEC + 0x10C */
+ u32 ones; /* FEC + 0x110 */
+ u32 zeros; /* FEC + 0x114 */
+ u32 iaddr1; /* FEC + 0x118 */
+ u32 iaddr2; /* FEC + 0x11C */
+ u32 gaddr1; /* FEC + 0x120 */
+ u32 gaddr2; /* FEC + 0x124 */
+ u32 random; /* FEC + 0x128 */
+ u32 rand1; /* FEC + 0x12C */
+ u32 tmp; /* FEC + 0x130 */
+
+ u32 reserved6[3]; /* FEC + 0x134-13C */
+ u32 fifo_id; /* FEC + 0x140 */
+ u32 x_wmrk; /* FEC + 0x144 */
+ u32 fcntrl; /* FEC + 0x148 */
+ u32 r_bound; /* FEC + 0x14C */
+ u32 r_fstart; /* FEC + 0x150 */
+ u32 r_count; /* FEC + 0x154 */
+ u32 r_lag; /* FEC + 0x158 */
+ u32 r_read; /* FEC + 0x15C */
+ u32 r_write; /* FEC + 0x160 */
+ u32 x_count; /* FEC + 0x164 */
+ u32 x_lag; /* FEC + 0x168 */
+ u32 x_retry; /* FEC + 0x16C */
+ u32 x_write; /* FEC + 0x170 */
+ u32 x_read; /* FEC + 0x174 */
+
+ u32 reserved7[2]; /* FEC + 0x178-17C */
+ u32 fm_cntrl; /* FEC + 0x180 */
+ u32 rfifo_data; /* FEC + 0x184 */
+ u32 rfifo_status; /* FEC + 0x188 */
+ u32 rfifo_cntrl; /* FEC + 0x18C */
+ u32 rfifo_lrf_ptr; /* FEC + 0x190 */
+ u32 rfifo_lwf_ptr; /* FEC + 0x194 */
+ u32 rfifo_alarm; /* FEC + 0x198 */
+ u32 rfifo_rdptr; /* FEC + 0x19C */
+ u32 rfifo_wrptr; /* FEC + 0x1A0 */
+ u32 tfifo_data; /* FEC + 0x1A4 */
+ u32 tfifo_status; /* FEC + 0x1A8 */
+ u32 tfifo_cntrl; /* FEC + 0x1AC */
+ u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */
+ u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */
+ u32 tfifo_alarm; /* FEC + 0x1B8 */
+ u32 tfifo_rdptr; /* FEC + 0x1BC */
+ u32 tfifo_wrptr; /* FEC + 0x1C0 */
+
+ u32 reset_cntrl; /* FEC + 0x1C4 */
+ u32 xmit_fsm; /* FEC + 0x1C8 */
+
+ u32 reserved8[3]; /* FEC + 0x1CC-1D4 */
+ u32 rdes_data0; /* FEC + 0x1D8 */
+ u32 rdes_data1; /* FEC + 0x1DC */
+ u32 r_length; /* FEC + 0x1E0 */
+ u32 x_length; /* FEC + 0x1E4 */
+ u32 x_addr; /* FEC + 0x1E8 */
+ u32 cdes_data; /* FEC + 0x1EC */
+ u32 status; /* FEC + 0x1F0 */
+ u32 dma_control; /* FEC + 0x1F4 */
+ u32 des_cmnd; /* FEC + 0x1F8 */
+ u32 data; /* FEC + 0x1FC */
+
+ u32 rmon_t_drop; /* FEC + 0x200 */
+ u32 rmon_t_packets; /* FEC + 0x204 */
+ u32 rmon_t_bc_pkt; /* FEC + 0x208 */
+ u32 rmon_t_mc_pkt; /* FEC + 0x20C */
+ u32 rmon_t_crc_align; /* FEC + 0x210 */
+ u32 rmon_t_undersize; /* FEC + 0x214 */
+ u32 rmon_t_oversize; /* FEC + 0x218 */
+ u32 rmon_t_frag; /* FEC + 0x21C */
+ u32 rmon_t_jab; /* FEC + 0x220 */
+ u32 rmon_t_col; /* FEC + 0x224 */
+ u32 rmon_t_p64; /* FEC + 0x228 */
+ u32 rmon_t_p65to127; /* FEC + 0x22C */
+ u32 rmon_t_p128to255; /* FEC + 0x230 */
+ u32 rmon_t_p256to511; /* FEC + 0x234 */
+ u32 rmon_t_p512to1023; /* FEC + 0x238 */
+ u32 rmon_t_p1024to2047; /* FEC + 0x23C */
+ u32 rmon_t_p_gte2048; /* FEC + 0x240 */
+ u32 rmon_t_octets; /* FEC + 0x244 */
+ u32 ieee_t_drop; /* FEC + 0x248 */
+ u32 ieee_t_frame_ok; /* FEC + 0x24C */
+ u32 ieee_t_1col; /* FEC + 0x250 */
+ u32 ieee_t_mcol; /* FEC + 0x254 */
+ u32 ieee_t_def; /* FEC + 0x258 */
+ u32 ieee_t_lcol; /* FEC + 0x25C */
+ u32 ieee_t_excol; /* FEC + 0x260 */
+ u32 ieee_t_macerr; /* FEC + 0x264 */
+ u32 ieee_t_cserr; /* FEC + 0x268 */
+ u32 ieee_t_sqe; /* FEC + 0x26C */
+ u32 t_fdxfc; /* FEC + 0x270 */
+ u32 ieee_t_octets_ok; /* FEC + 0x274 */
+
+ u32 reserved9[2]; /* FEC + 0x278-27C */
+ u32 rmon_r_drop; /* FEC + 0x280 */
+ u32 rmon_r_packets; /* FEC + 0x284 */
+ u32 rmon_r_bc_pkt; /* FEC + 0x288 */
+ u32 rmon_r_mc_pkt; /* FEC + 0x28C */
+ u32 rmon_r_crc_align; /* FEC + 0x290 */
+ u32 rmon_r_undersize; /* FEC + 0x294 */
+ u32 rmon_r_oversize; /* FEC + 0x298 */
+ u32 rmon_r_frag; /* FEC + 0x29C */
+ u32 rmon_r_jab; /* FEC + 0x2A0 */
+
+ u32 rmon_r_resvd_0; /* FEC + 0x2A4 */
+
+ u32 rmon_r_p64; /* FEC + 0x2A8 */
+ u32 rmon_r_p65to127; /* FEC + 0x2AC */
+ u32 rmon_r_p128to255; /* FEC + 0x2B0 */
+ u32 rmon_r_p256to511; /* FEC + 0x2B4 */
+ u32 rmon_r_p512to1023; /* FEC + 0x2B8 */
+ u32 rmon_r_p1024to2047; /* FEC + 0x2BC */
+ u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */
+ u32 rmon_r_octets; /* FEC + 0x2C4 */
+ u32 ieee_r_drop; /* FEC + 0x2C8 */
+ u32 ieee_r_frame_ok; /* FEC + 0x2CC */
+ u32 ieee_r_crc; /* FEC + 0x2D0 */
+ u32 ieee_r_align; /* FEC + 0x2D4 */
+ u32 r_macerr; /* FEC + 0x2D8 */
+ u32 r_fdxfc; /* FEC + 0x2DC */
+ u32 ieee_r_octets_ok; /* FEC + 0x2E0 */
+
+ u32 reserved10[7]; /* FEC + 0x2E4-2FC */
+
+ u32 reserved11[64]; /* FEC + 0x300-3FF */
+};
+
+#define FEC_MIB_DISABLE 0x80000000
+
+#define FEC_IEVENT_HBERR 0x80000000
+#define FEC_IEVENT_BABR 0x40000000
+#define FEC_IEVENT_BABT 0x20000000
+#define FEC_IEVENT_GRA 0x10000000
+#define FEC_IEVENT_TFINT 0x08000000
+#define FEC_IEVENT_MII 0x00800000
+#define FEC_IEVENT_LATE_COL 0x00200000
+#define FEC_IEVENT_COL_RETRY_LIM 0x00100000
+#define FEC_IEVENT_XFIFO_UN 0x00080000
+#define FEC_IEVENT_XFIFO_ERROR 0x00040000
+#define FEC_IEVENT_RFIFO_ERROR 0x00020000
+
+#define FEC_IMASK_HBERR 0x80000000
+#define FEC_IMASK_BABR 0x40000000
+#define FEC_IMASK_BABT 0x20000000
+#define FEC_IMASK_GRA 0x10000000
+#define FEC_IMASK_MII 0x00800000
+#define FEC_IMASK_LATE_COL 0x00200000
+#define FEC_IMASK_COL_RETRY_LIM 0x00100000
+#define FEC_IMASK_XFIFO_UN 0x00080000
+#define FEC_IMASK_XFIFO_ERROR 0x00040000
+#define FEC_IMASK_RFIFO_ERROR 0x00020000
+
+#define FEC_RCNTRL_MAX_FL_SHIFT 16
+#define FEC_RCNTRL_LOOP 0x01
+#define FEC_RCNTRL_DRT 0x02
+#define FEC_RCNTRL_MII_MODE 0x04
+#define FEC_RCNTRL_PROM 0x08
+#define FEC_RCNTRL_BC_REJ 0x10
+#define FEC_RCNTRL_FCE 0x20
+
+#define FEC_TCNTRL_GTS 0x00000001
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_TFC_PAUSE 0x00000008
+#define FEC_TCNTRL_RFC_PAUSE 0x00000010
+
+#define FEC_ECNTRL_RESET 0x00000001
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+
+#define FEC_PADDR2_TYPE 0x8808
+
+#define FEC_OP_PAUSE_OPCODE 0x00010000
+
+#define FEC_FIFO_WMRK_256B 0x3
+
+#define FEC_FIFO_STATUS_ERR 0x00400000
+#define FEC_FIFO_STATUS_UF 0x00200000
+#define FEC_FIFO_STATUS_OF 0x00100000
+
+#define FEC_FIFO_CNTRL_FRAME 0x08000000
+#define FEC_FIFO_CNTRL_LTG_7 0x07000000
+
+#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000
+#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000
+
+#define FEC_XMIT_FSM_APPEND_CRC 0x02000000
+#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000
+
+
+int __init fec_mdio_init(void);
+void __exit fec_mdio_exit(void);
+
+#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */
diff -pruN dummy/fec_phy.c ./drivers/net/fec_mpc52xx/fec_phy.c
--- dummy/fec_phy.c 1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec_phy.c 2007-08-10 10:59:53.000000000 +0200
@@ -0,0 +1,229 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include <asm/of_platform.h>
+#include "fec_phy.h"
+#include "fec.h"
+
+struct fec_mdio_priv {
+ int completed;
+ wait_queue_head_t wq;
+ struct mpc52xx_fec __iomem *regs;
+ int irq;
+};
+
+static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct fec_mdio_priv *priv = bus->priv;
+ int tries = 100;
+
+ u32 request = FEC_MII_READ_FRAME;
+ request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, request);
+
+ /* wait for it to finish, this takes about 23 us on lite5200b */
+ while (priv->completed == 0 && tries--)
+ udelay(5);
+
+ priv->completed = 0;
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
+}
+
+static int fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
+{
+ struct fec_mdio_priv *priv = bus->priv;
+ u32 value = data;
+ int tries = 100;
+
+ value |= FEC_MII_WRITE_FRAME;
+ value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, value);
+
+ /* wait for request to finish */
+ while (priv->completed == 0 && tries--)
+ udelay(5);
+
+ priv->completed = 0;
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static irqreturn_t fec_mdio_interrupt(int irq, void *dev_id)
+{
+ struct fec_mdio_priv *priv = dev_id;
+ struct mpc52xx_fec __iomem *fec;
+ int ievent;
+
+ fec = priv->regs;
+ ievent = in_be32(&fec->ievent);
+
+ ievent &= FEC_IEVENT_MII;
+ if (!ievent)
+ return IRQ_NONE;
+
+ out_be32(&fec->ievent, ievent);
+
+ priv->completed = 1;
+ wake_up(&priv->wq);
+
+ return IRQ_HANDLED;
+}
+
+static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
+{
+ struct device *dev = &of->dev;
+ struct device_node *np = of->node;
+ struct device_node *child = NULL;
+ struct mii_bus *bus;
+ struct fec_mdio_priv *priv;
+ struct resource res = {};
+ int err;
+ int i;
+
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (bus == NULL)
+ return -ENOMEM;
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ bus->name = "mpc52xx MII bus";
+ bus->read = fec_mdio_read;
+ bus->write = fec_mdio_write;
+
+ /* setup irqs */
+ bus->irq = kcalloc(sizeof(bus->irq[0]), PHY_MAX_ADDR, GFP_KERNEL);
+ if (bus->irq == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
+
+ while ((child = of_get_next_child(np, child)) != NULL) {
+ int irq = irq_of_parse_and_map(child, 0);
+ if (irq != NO_IRQ) {
+ const u32 *id = of_get_property(child, "reg", NULL);
+ bus->irq[*id] = irq;
+ }
+ }
+
+ /* setup registers */
+ err = of_address_to_resource(np, 0, &res);
+ if (err)
+ goto out_free;
+ priv->regs = ioremap(res.start, res.end - res.start + 1);
+ if (priv->regs == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ priv->irq = irq_of_parse_and_map(np, 0);
+ err = request_irq(priv->irq, &fec_mdio_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ "fec_mdio", priv);
+ if (err) {
+ printk(KERN_ERR "%s: interrupt request failed with %i\n", __func__, err);
+ goto out_unmap;
+ }
+
+ bus->id = res.start;
+ bus->priv = priv;
+
+ bus->dev = dev;
+ dev_set_drvdata(dev, bus);
+
+ init_waitqueue_head(&priv->wq);
+
+ /* set MII speed */
+ out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
+
+ /* enable MII interrupt */
+ out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
+
+ err = mdiobus_register(bus);
+ if (err)
+ goto out_free_irq;
+
+ return 0;
+
+ out_free_irq:
+ free_irq(priv->irq, dev);
+ irq_dispose_mapping(priv->irq);
+ out_unmap:
+ iounmap(priv->regs);
+ out_free:
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ if (bus->irq[i])
+ irq_dispose_mapping(bus->irq[i]);
+ kfree(bus->irq);
+ kfree(priv);
+ kfree(bus);
+
+ return err;
+}
+
+static int fec_mdio_remove(struct of_device *of)
+{
+ struct device *dev = &of->dev;
+ struct mii_bus *bus = dev_get_drvdata(dev);
+ struct fec_mdio_priv *priv = bus->priv;
+ int i;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(dev, NULL);
+
+ free_irq(priv->irq, dev);
+ irq_dispose_mapping(priv->irq);
+ iounmap(priv->regs);
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ if (bus->irq[i])
+ irq_dispose_mapping(bus->irq[i]);
+ kfree(priv);
+ kfree(bus->irq);
+ kfree(bus);
+
+ return 0;
+}
+
+
+static struct of_device_id fec_mdio_match[] = {
+ {
+ .type = "mdio",
+ .compatible = "mpc5200b-fec-phy",
+ },
+ {},
+};
+
+static struct of_platform_driver fec_mdio_driver = {
+ .name = "mpc5200b-fec-phy",
+ .probe = fec_mdio_probe,
+ .remove = fec_mdio_remove,
+ .match_table = fec_mdio_match,
+};
+
+
+int __init fec_mdio_init(void)
+{
+ return of_register_platform_driver(&fec_mdio_driver);
+}
+
+void __exit fec_mdio_exit(void)
+{
+ of_unregister_platform_driver(&fec_mdio_driver);
+}
diff -pruN dummy/fec_phy.h ./drivers/net/fec_mpc52xx/fec_phy.h
--- dummy/fec_phy.h 1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec_phy.h 2007-08-10 11:22:54.000000000 +0200
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/52xx_io/fec_phy.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ * Based heavily on the MII support for the MPC8xx by Dan Malek
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#define FEC_IMASK_ALL (FEC_IMASK_HBERR | FEC_IMASK_BABR | \
+ FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_MII | \
+ FEC_IMASK_LATE_COL | FEC_IMASK_COL_RETRY_LIM | \
+ FEC_IMASK_XFIFO_UN | FEC_IMASK_XFIFO_ERROR | \
+ FEC_IMASK_RFIFO_ERROR)
+
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+#define MII_RCNTL_MODE FEC_RCNTRL_MII_MODE
+#define FEC_IMASK_ENABLE FEC_IMASK_ALL
+#define set_phy_speed(fec, s) out_be32(&fec->mii_speed, s)
+#else
+#define MII_RCNTL_MODE 0
+#define FEC_IMASK_ENABLE (FEC_IMASK_ALL & ~FEC_IMASK_MII)
+#define set_phy_speed(fec, s) do { } while (0)
+#define fec_mii_start(dev) do { } while (0)
+#define fec_mii(dev) printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n")
+#define fec_mii_init(dev) do { } while (0)
+#define fec_mii_suspend(dev) do { } while (0)
+#define fec_mii_resume(dev) do { } while (0)
+#endif /* CONFIG_FEC_MPC52xx_MDIO */
+
+/* MII-related definitions */
+#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */
+
+#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
+#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
+
+#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
+#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
diff -pruN dummy/Kconfig ./drivers/net/fec_mpc52xx/Kconfig
--- dummy/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/Kconfig 2007-08-08 10:50:04.000000000 +0200
@@ -0,0 +1,24 @@
+menu "MPC5200 Networking Options"
+ depends PPC_MPC52xx && NET_ETHERNET
+
+config FEC_MPC52xx
+ tristate "FEC Ethernet"
+ depends on NET_ETHERNET
+ select PPC_BESTCOMM
+ select PPC_BESTCOMM_FEC
+ select CRC32
+ ---help---
+ This option enables support for the MPC5200's on-chip
+ Fast Ethernet Controller
+
+config USE_MDIO
+ bool "Use external Ethernet MII PHY"
+ select MII
+ depends FEC_MPC52xx
+ ---help---
+ The MPC5200's FEC can connect to the Ethernet either with
+ an external MII PHY chip or 10 Mbps 7-wire interface
+ (Motorola? industry standard).
+ If your board uses an external PHY, say y, else n.
+
+endmenu
diff -pruN dummy/Makefile ./drivers/net/fec_mpc52xx/Makefile
--- dummy/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/Makefile 2007-08-08 10:50:04.000000000 +0200
@@ -0,0 +1,7 @@
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
+
+fec_mpc52xx-objs := fec.o
+
+ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
+fec_mpc52xx-objs += fec_phy.o
+endif
Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================
--- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts
+++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
@@ -365,10 +365,26 @@
ethernet@3000 {
device_type = "network";
compatible = "mpc5200b-fec\0mpc5200-fec";
- reg = <3000 800>;
+ reg = <3000 400>;
mac-address = [ 02 03 04 05 06 07 ]; // Bad!
interrupts = <2 5 0>;
interrupt-parent = <&mpc5200_pic>;
+ phy-handle = <&phy0>;
+ };
+
+ mdio@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "mdio";
+ compatible = "mpc5200b-fec-phy";
+ reg = <3000 400>; // fec range, since we need to setup fec interrupts
+ interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
+ interrupt-parent = <&mpc5200_pic>;
+
+ phy0:ethernet-phy@0 {
+ device_type = "ethernet-phy";
+ reg = <0>;
+ };
};
ata@3a00 {
Index: work-powerpc.git/arch/powerpc/sysdev/bestcomm/fec.h
===================================================================
--- work-powerpc.git.orig/arch/powerpc/sysdev/bestcomm/fec.h
+++ work-powerpc.git/arch/powerpc/sysdev/bestcomm/fec.h
@@ -22,6 +22,20 @@ struct bcom_fec_bd {
#define BCOM_FEC_TX_BD_TFD 0x08000000ul /* transmit frame done */
#define BCOM_FEC_TX_BD_INT 0x04000000ul /* interrupt */
+#define BCOM_FEC_TX_BD_TC 0x04000000ul /* transmit CRC XXX same as ^? */
+#define BCOM_FEC_TX_BD_ABC 0x02000000ul /* append bad CRC */
+
+#define BCOM_FEC_RX_BD_L 0x08000000ul /* buffer is last in frame */
+#define BCOM_FEC_RX_BD_BC 0x00800000ul /* DA is broadcast */
+#define BCOM_FEC_RX_BD_MC 0x00400000ul /* DA is multicast and not broadcast */
+#define BCOM_FEC_RX_BD_LG 0x00200000ul /* Rx frame length violation */
+#define BCOM_FEC_RX_BD_NO 0x00100000ul /* Rx non-octet aligned frame */
+#define BCOM_FEC_RX_BD_CR 0x00040000ul /* Rx CRC error */
+#define BCOM_FEC_RX_BD_OV 0x00020000ul /* overrun */
+#define BCOM_FEC_RX_BD_TR 0x00010000ul /* Rx frame truncated */
+#define BCOM_FEC_RX_BD_LEN_MASK 0x000007fful /* mask for length of received frame */
+#define BCOM_FEC_RX_BD_ERRORS (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \
+ BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR)
extern struct bcom_task *
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-10 9:51 [RFC PATCH v0.1] net driver: mpc52xx fec Domen Puncer
@ 2007-08-10 13:02 ` Arnaldo Carvalho de Melo
2007-08-13 7:21 ` Domen Puncer
2007-08-18 10:06 ` Domen Puncer
` (2 subsequent siblings)
3 siblings, 1 reply; 47+ messages in thread
From: Arnaldo Carvalho de Melo @ 2007-08-10 13:02 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
Em Fri, Aug 10, 2007 at 11:51:53AM +0200, Domen Puncer escreveu:
> Hi!
>
> Not for merge (yet)! But please do review.
>
> fec_mpc52xx driver (not in-tree, but floating around) isn't in very
> good shape, so I tried to change that.
> Diff against original is quite big (fec_phy.c is completely rewritten)
> and confuzing, so I'm including whole drivers/net/fec_mpc52xx/ .
>
> I still have 'make CONFIG_FEC_MPC52xx_MDIO=n compile and work' on my
> TODO, maybe even ethtool support.
>
>
> Domen
>
>
> arch/powerpc/boot/dts/lite5200b.dts | 18
> arch/powerpc/sysdev/bestcomm/fec.h | 14
> drivers/net/fec_mpc52xx/Kconfig | 24
> drivers/net/fec_mpc52xx/Makefile | 7
> drivers/net/fec_mpc52xx/fec.c | 1002 ++++++++++++++++++++++++++++++++++++
> drivers/net/fec_mpc52xx/fec.h | 299 ++++++++++
> drivers/net/fec_mpc52xx/fec_phy.c | 229 ++++++++
> drivers/net/fec_mpc52xx/fec_phy.h | 49 +
> 8 files changed, 1641 insertions(+), 1 deletion(-)
>
> diff -pruN dummy/fec.c ./drivers/net/fec_mpc52xx/fec.c
> --- dummy/fec.c 1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/net/fec_mpc52xx/fec.c 2007-08-10 10:59:00.000000000 +0200
> @@ -0,0 +1,1002 @@
> +/*
> + * drivers/net/fec_mpc52xx/fec.c
> + *
> + * Driver for the MPC5200 Fast Ethernet Controller
> + *
> + * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
> + * now maintained by Sylvain Munaut <tnt@246tNt.com>
> + *
> + * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
> + * Copyrigth (C) 2003-2004 MontaVista, Software, Inc.
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + *
> + */
> +
> +#include <linux/module.h>
> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/spinlock.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/crc32.h>
> +#include <linux/hardirq.h>
> +
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/skbuff.h>
> +
> +#include <asm/of_device.h>
> +#include <asm/of_platform.h>
> +#include <asm/io.h>
> +#include <asm/delay.h>
> +#include <asm/mpc52xx.h>
> +
> +#include <sysdev/bestcomm/bestcomm.h>
> +#include <sysdev/bestcomm/fec.h>
> +
> +#include "fec_phy.h"
> +#include "fec.h"
> +
> +#define DRIVER_NAME "mpc52xx-fec"
> +
> +static irqreturn_t fec_interrupt(int, void *);
> +static irqreturn_t fec_rx_interrupt(int, void *);
> +static irqreturn_t fec_tx_interrupt(int, void *);
> +static struct net_device_stats *fec_get_stats(struct net_device *);
> +static void fec_set_multicast_list(struct net_device *dev);
> +static void fec_hw_init(struct net_device *dev);
> +static void fec_stop(struct net_device *dev);
> +static void fec_start(struct net_device *dev);
> +
> +static u8 mpc52xx_fec_mac_addr[6];
> +static u8 null_mac[6];
const
> +
> +static void fec_tx_timeout(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> +
> + dev_warn(&dev->dev, "transmit timed out\n");
> +
> + fec_stop(dev);
> + fec_start(dev);
> +
> + priv->stats.tx_errors++;
> +
> + if (!priv->tx_full)
> + netif_wake_queue(dev);
> +}
> +
> +static void fec_set_paddr(struct net_device *dev, u8 *mac)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + out_be32(&fec->paddr1, *(u32*)(&mac[0]));
> + out_be32(&fec->paddr2, (*(u16*)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
spaces after the types on casts to pointers
> +}
> +
> +static void fec_get_paddr(struct net_device *dev, u8 *mac)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + *(u32*)(&mac[0]) = in_be32(&fec->paddr1);
> + *(u16*)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
ditto
> +}
> +
> +static int fec_set_mac_address(struct net_device *dev, void *addr)
> +{
> + struct sockaddr *sock = (struct sockaddr *)addr;
no need for a cast, addr is a void pointer
> +
> + memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
> +
> + fec_set_paddr(dev, sock->sa_data);
> + return 0;
Why always return 0? make it void
> +}
> +
> +static void fec_free_rx_buffers(struct bcom_task *s)
> +{
> + struct sk_buff *skb;
> +
> + while (!bcom_queue_empty(s)) {
> + skb = bcom_retrieve_buffer(s, NULL, NULL);
> + kfree_skb(skb);
> + }
> +}
> +
> +static int fec_alloc_rx_buffers(struct bcom_task *rxtsk)
> +{
> + while (!bcom_queue_full(rxtsk)) {
> + struct sk_buff *skb;
> + struct bcom_fec_bd *bd;
> +
> + skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
> + if (skb == 0)
Test against NULL
> + return -EAGAIN;
> +
> + /* zero out the initial receive buffers to aid debugging */
> + memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
> +
> + bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
> +
> + bd->status = FEC_RX_BUFFER_SIZE;
> + bd->skb_pa = virt_to_phys(skb->data);
> +
> + bcom_submit_next_buffer(rxtsk, skb);
> + }
> +
> + return 0;
> +}
> +
> +/* based on generic_adjust_link - fs_enet-main.c */
> +static void fec_adjust_link(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct phy_device *phydev = priv->phydev;
> + int new_state = 0;
> +
> + if (phydev->link != PHY_DOWN) {
> + if (phydev->duplex != priv->duplex) {
> + new_state = 1;
> + priv->duplex = phydev->duplex;
> + }
> +
> + if (phydev->speed != priv->speed) {
> + new_state = 1;
> + priv->speed = phydev->speed;
> + }
> +
> + if (priv->link == PHY_DOWN) {
> + new_state = 1;
> + priv->link = phydev->link;
> + netif_schedule(dev);
> + netif_carrier_on(dev);
> + netif_start_queue(dev);
> + }
> +
> + } else if (priv->link) {
> + new_state = 1;
> + priv->link = PHY_DOWN;
> + priv->speed = 0;
> + priv->duplex = -1;
> + netif_stop_queue(dev);
> + netif_carrier_off(dev);
> + }
> +
> + if (new_state && netif_msg_link(priv)) {
> + phy_print_status(phydev);
> + }
No need for {}, this if has only one statement
> +}
> +
> +static int fec_init_phy(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct phy_device *phydev;
> + char phy_id[BUS_ID_SIZE];
> +
> + struct device_node *dn, *phy_dn;
> + unsigned int phy_addr;
> + const phandle *ph;
> + const unsigned int *prop;
> + struct resource res;
> + int ret;
> +
> + dn = priv->ofdev->node;
> + ph = of_get_property(dn, "phy-handle", NULL);
> + if (!ph) {
> + dev_err(&dev->dev, "can't find \"phy-handle\" in device tree\n");
> + return -ENODEV;
> + }
> + phy_dn = of_find_node_by_phandle(*ph);
> +
> + prop = of_get_property(phy_dn, "reg", NULL);
> + ret = of_address_to_resource(phy_dn->parent, 0, &res);
> + if (ret) {
> + dev_err(&dev->dev, "of_address_to_resource failed\n");
> + return ret;
> + }
> +
> + phy_addr = *prop;
> + of_node_put(phy_dn);
> +
> + snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, res.start, phy_addr);
> +
> + priv->link = PHY_DOWN;
> + priv->speed = 0;
> + priv->duplex = -1;
> +
> + phydev = phy_connect(dev, phy_id, &fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
> + if (IS_ERR(phydev)) {
> + printk(KERN_ERR "%s: phy_connect failed\n", dev->name);
> + return PTR_ERR(phydev);
> + }
> +
> + phydev->advertising &= ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half;
> +
> + priv->phydev = phydev;
> +
> + return 0;
> +}
> +
> +static int fec_open(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + int err = -EBUSY;
> +
> + if (request_irq(dev->irq, &fec_interrupt, IRQF_DISABLED | IRQF_SHARED,
> + DRIVER_NAME "_ctrl", dev)) {
> + dev_err(&dev->dev, "ctrl interrupt request failed\n");
> + goto out;
> + }
> + if (request_irq(priv->r_irq, &fec_rx_interrupt, IRQF_DISABLED,
> + DRIVER_NAME "_rx", dev)) {
> + dev_err(&dev->dev, "rx interrupt request failed\n");
> + goto free_ctrl_irq;
> + }
> + if (request_irq(priv->t_irq, &fec_tx_interrupt, IRQF_DISABLED,
> + DRIVER_NAME "_tx", dev)) {
> + dev_err(&dev->dev, "tx interrupt request failed\n");
> + goto free_2irqs;
> + }
> +
> + bcom_fec_rx_reset(priv->rx_dmatsk);
> + bcom_fec_tx_reset(priv->tx_dmatsk);
> +
> + err = fec_alloc_rx_buffers(priv->rx_dmatsk);
> + if (err) {
> + dev_err(&dev->dev, "fec_alloc_rx_buffers failed\n");
> + goto free_irqs;
> + }
> +
> + err = fec_init_phy(dev);
> + if (err) {
> + dev_err(&dev->dev, "fec_init_phy failed\n");
> + goto free_skbs;
> + }
> + bcom_enable(priv->rx_dmatsk);
> + bcom_enable(priv->tx_dmatsk);
> +
> + /* reset phy - this also wakes it from PDOWN */
> + phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
> + phy_start(priv->phydev);
> +
> + fec_start(dev);
> +
> + netif_start_queue(dev);
> +
> + return 0;
> +
> + free_skbs:
> + fec_free_rx_buffers(priv->rx_dmatsk);
> +
> + free_irqs:
> + free_irq(priv->t_irq, dev);
> + free_2irqs:
> + free_irq(priv->r_irq, dev);
> + free_ctrl_irq:
> + free_irq(dev->irq, dev);
> + out:
> +
> + return err;
> +}
> +
> +static int fec_close(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> +
> + netif_stop_queue(dev);
> +
> + fec_stop(dev);
> +
> + fec_free_rx_buffers(priv->rx_dmatsk);
> +
> + phy_disconnect(priv->phydev);
> +
> + free_irq(dev->irq, dev);
> + free_irq(priv->r_irq, dev);
> + free_irq(priv->t_irq, dev);
> +
> + /* power down phy */
> + phy_stop(priv->phydev);
> + phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
> +
> + return 0;
> +}
> +
> +/* This will only be invoked if your driver is _not_ in XOFF state.
> + * What this means is that you need not check it, and that this
> + * invariant will hold if you make sure that the netif_*_queue()
> + * calls are done at the proper times.
> + */
> +static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct bcom_fec_bd *bd;
> +
> + if (bcom_queue_full(priv->tx_dmatsk)) {
> + if (net_ratelimit())
> + dev_err(&dev->dev, "transmit queue overrun\n");
> + return 1;
> + }
> +
> + spin_lock_irq(&priv->lock);
> + dev->trans_start = jiffies;
> +
> + bd = (struct bcom_fec_bd *)
> + bcom_prepare_next_buffer(priv->tx_dmatsk);
> +
> + bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_INT;
> + bd->skb_pa = virt_to_phys(skb->data);
> +
> + bcom_submit_next_buffer(priv->tx_dmatsk, skb);
> +
> + if (bcom_queue_full(priv->tx_dmatsk)) {
> + priv->tx_full = 1;
> + netif_stop_queue(dev);
> + }
> +
> + spin_unlock_irq(&priv->lock);
> +
> + return 0;
> +}
> +
> +/* This handles BestComm transmit task interrupts
> + */
> +static irqreturn_t fec_tx_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct fec_priv *priv = netdev_priv(dev);
> +
> + spin_lock(&priv->lock);
> +
> + while (bcom_buffer_done(priv->tx_dmatsk)) {
> + struct sk_buff *skb;
> + skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, NULL);
> +
> + priv->tx_full = 0;
> + dev_kfree_skb_irq(skb);
> + }
> +
> + if (netif_queue_stopped(dev) && !priv->tx_full)
> + netif_wake_queue(dev);
> +
> + spin_unlock(&priv->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t fec_rx_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct fec_priv *priv = netdev_priv(dev);
> +
> + while (bcom_buffer_done(priv->rx_dmatsk)) {
> + struct sk_buff *skb;
> + struct sk_buff *rskb;
> + struct bcom_fec_bd *bd;
> + u32 status;
> +
> + rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, NULL);
> +
> + /* Test for errors in received frame */
> + if (status & BCOM_FEC_RX_BD_ERRORS) {
> + /* Drop packet and reuse the buffer */
> + bd = (struct bcom_fec_bd *)
> + bcom_prepare_next_buffer(priv->rx_dmatsk);
> +
> + bd->status = FEC_RX_BUFFER_SIZE;
> + bd->skb_pa = virt_to_phys(rskb->data);
> +
> + bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
> +
> + priv->stats.rx_dropped++;
> +
> + continue;
> + }
> +
> + /* skbs are allocated on open, so now we allocate a new one,
> + * and remove the old (with the packet) */
> + skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
> + if (skb) {
> + /* Process the received skb */
> + int length = status & BCOM_FEC_RX_BD_LEN_MASK;
> +
> + skb_put(rskb, length - 4); /* length without CRC32 */
> +
> + rskb->dev = dev;
> + rskb->protocol = eth_type_trans(rskb, dev);
> +
> + netif_rx(rskb);
> + dev->last_rx = jiffies;
> + } else {
> + /* Can't get a new one : reuse the same & drop pkt */
> + dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
> + priv->stats.rx_dropped++;
> +
> + skb = rskb;
> + }
> +
> + bd = (struct bcom_fec_bd *)
> + bcom_prepare_next_buffer(priv->rx_dmatsk);
> +
> + bd->status = FEC_RX_BUFFER_SIZE;
> + bd->skb_pa = virt_to_phys(skb->data);
> +
> + bcom_submit_next_buffer(priv->rx_dmatsk, skb);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t fec_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 ievent;
> +
> + ievent = in_be32(&fec->ievent);
> +
> + ievent &= ~FEC_IEVENT_MII; /* mii is handled separately */
> + if (!ievent)
> + return IRQ_NONE;
> +
> + out_be32(&fec->ievent, ievent); /* clear pending events */
> +
> + if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
> + if (ievent & ~FEC_IEVENT_TFINT)
> + dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
> + return IRQ_HANDLED;
> + }
> +
> + if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
> + dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
> + if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
> + dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
> +
> + fec_stop(dev);
> + fec_hw_init(dev);
> + fec_start(dev);
> +
> + netif_wake_queue(dev);
> + return IRQ_HANDLED;
> +}
> +
> +/*
> + * Get the current statistics.
> + * This may be called with the card open or closed.
> + */
> +static struct net_device_stats *fec_get_stats(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &priv->stats;
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> +/* printk(KERN_ALERT "%s: %i, rmon_r_octets: %i, rmon_r_packets: %i, "
> + "ieee_r_octets_ok: %i, ieee_r_frame_ok: %i, "
> + "%i\n",
> + __func__, __LINE__,
> + in_be32(&fec->rmon_r_octets), in_be32(&fec->rmon_r_packets),
> + in_be32(&fec->ieee_r_octets_ok), in_be32(&fec->ieee_r_frame_ok),
> + 0);
> +*/
> + stats->rx_bytes = in_be32(&fec->rmon_r_octets);
> + stats->rx_packets = in_be32(&fec->rmon_r_packets);
> + stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
> + in_be32(&fec->rmon_r_undersize) +
> + in_be32(&fec->rmon_r_oversize) +
> + in_be32(&fec->rmon_r_frag) +
> + in_be32(&fec->rmon_r_jab);
> +
> + stats->tx_bytes = in_be32(&fec->rmon_t_octets);
> + stats->tx_packets = in_be32(&fec->rmon_t_packets);
> + stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
> + in_be32(&fec->rmon_t_undersize) +
> + in_be32(&fec->rmon_t_oversize) +
> + in_be32(&fec->rmon_t_frag) +
> + in_be32(&fec->rmon_t_jab);
> +
> + stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
> + stats->collisions = in_be32(&fec->rmon_t_col);
> +
> + /* detailed rx_errors: */
> + stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
> + + in_be32(&fec->rmon_r_oversize)
> + + in_be32(&fec->rmon_r_frag)
> + + in_be32(&fec->rmon_r_jab);
> + stats->rx_over_errors = in_be32(&fec->r_macerr);
> + stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
> + stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
> + stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
> + stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
> +
> + /* detailed tx_errors: */
> + stats->tx_aborted_errors = 0;
> + stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
> + stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
> + stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
> + stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
> +
> + return stats;
> +}
> +
> +/*
> + * Read MIB counters in order to reset them,
> + * then zero all the stats fields in memory
> + */
> +static void fec_reset_stats(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + out_be32(&fec->mib_control, FEC_MIB_DISABLE);
> + memset_io(&fec->rmon_t_drop, 0,
> + (u32)&fec->reserved10 - (u32)&fec->rmon_t_drop);
> + out_be32(&fec->mib_control, 0);
> +
> + memset(&priv->stats, 0, sizeof(priv->stats));
> +}
> +
> +/*
> + * Set or clear the multicast filter for this adaptor.
> + */
> +static void fec_set_multicast_list(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 rx_control;
> +
> + rx_control = in_be32(&fec->r_cntrl);
> +
> + if (dev->flags & IFF_PROMISC) {
> + rx_control |= FEC_RCNTRL_PROM;
> + out_be32(&fec->r_cntrl, rx_control);
> + } else {
> + rx_control &= ~FEC_RCNTRL_PROM;
> + out_be32(&fec->r_cntrl, rx_control);
> +
> + if (dev->flags & IFF_ALLMULTI) {
> + out_be32(&fec->gaddr1, 0xffffffff);
> + out_be32(&fec->gaddr2, 0xffffffff);
> + } else {
> + u32 crc;
> + int i;
> + struct dev_mc_list *dmi;
> + u32 gaddr1 = 0x00000000;
> + u32 gaddr2 = 0x00000000;
> +
> + dmi = dev->mc_list;
> + for (i=0; i<dev->mc_count; i++) {
> + crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
> + if (crc >= 32)
> + gaddr1 |= 1 << (crc-32);
> + else
> + gaddr2 |= 1 << crc;
> + dmi = dmi->next;
> + }
> + out_be32(&fec->gaddr1, gaddr1);
> + out_be32(&fec->gaddr2, gaddr2);
> + }
> + }
> +}
> +
> +static void __init fec_str2mac(char *str, unsigned char *mac)
> +{
> + int i;
> + u64 val64;
> +
> + val64 = simple_strtoull(str, NULL, 16);
> +
> + for (i = 0; i < 6; i++)
> + mac[5-i] = val64 >> (i*8);
> +}
> +
> +static int __init mpc52xx_fec_mac_setup(char *mac_address)
> +{
> + fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
> + return 0;
> +}
> +
> +/* XXX do we need this? */
> +__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
> +
> +/**
> + * fec_hw_init
> + * @dev: network device
> + *
> + * Setup various hardware setting, only needed once on start
> + */
> +static void fec_hw_init(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + int i;
> +
> + /* Whack a reset. We should wait for this. */
> + out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
> + for (i = 0; i < FEC_RESET_DELAY; ++i) {
> + if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
> + break;
> + udelay(1);
> + }
> + if (i == FEC_RESET_DELAY)
> + dev_err(&dev->dev, "FEC Reset timeout!\n");
> +
> + /* set pause to 0x20 frames */
> + out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20);
> +
> + /* high service request will be deasserted when there's < 7 bytes in fifo
> + * low service request will be deasserted when there's < 4*7 bytes in fifo
> + */
> + out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
> + out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
> +
> + /* alarm when <= x bytes in FIFO */
> + out_be32(&fec->rfifo_alarm, 0x0000030c);
> + out_be32(&fec->tfifo_alarm, 0x00000100);
> +
> + /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */
> + out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B);
> +
> + /* enable crc generation */
> + out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC);
> + out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */
> + out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */
> +
> + /* set phy speed and enable MII interrupt
> + * this can't be done in phy driver, since it needs to be called
> + * before fec stuff (even on resume) */
> + set_phy_speed(fec, priv->phy_speed);
> + out_be32(&fec->imask, in_be32(&fec->imask) | FEC_IMASK_MII);
> +}
> +
> +/**
> + * fec_start
> + * @dev: network device
> + *
> + * This function is called to start or restart the FEC during a link
> + * change. This happens on fifo errors or when switching between half
> + * and full duplex.
> + */
> +static void fec_start(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 rcntrl;
> + u32 tcntrl;
> + u32 tmp;
> +
> + /* clear sticky error bits */
> + tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
> + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
> + out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
> +
> + /* FIFOs will reset on fec_enable */
> + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
> +
> + /* Set station address. */
> + fec_set_paddr(dev, dev->dev_addr);
> +
> + fec_set_multicast_list(dev);
> +
> + /* set max frame len, enable flow control, select mii mode */
> + rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
> + rcntrl |= FEC_RCNTRL_FCE;
> + rcntrl |= MII_RCNTL_MODE;
> + if (priv->duplex == DUPLEX_FULL)
> + tcntrl = FEC_TCNTRL_FDEN; /* FD enable */
> + else {
> + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
> + tcntrl = 0;
> + }
> + out_be32(&fec->r_cntrl, rcntrl);
> + out_be32(&fec->x_cntrl, tcntrl);
> +
> + /* Clear any outstanding interrupt. */
> + out_be32(&fec->ievent, 0xffffffff);
> +
> + /* Enable interrupts we wish to service. */
> + out_be32(&fec->imask, FEC_IMASK_ENABLE);
> +
> + /* And last, enable the transmit and receive processing. */
> + out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
> + out_be32(&fec->r_des_active, 0x01000000);
> +
> + priv->tx_full = 0;
> +}
> +
> +/**
> + * fec_stop
> + * @dev: network device
> + *
> + * stop all activity on fec and empty dma buffers
> + */
> +static void fec_stop(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + unsigned long timeout;
> +
> + out_be32(&fec->imask, FEC_IMASK_MII); /* disable all but MII interrupt */
> +
> + /* Disable the rx and tx tasks. */
> + bcom_disable(priv->rx_dmatsk);
> +
> + /* Wait for queues to drain, but only if we're in process context */
> + if (!in_interrupt()) {
> + timeout = jiffies + 2*HZ;
> + while (time_before(jiffies, timeout) &&
> + (!bcom_queue_empty(priv->tx_dmatsk) ||
> + !bcom_queue_empty(priv->rx_dmatsk))) {
> + set_current_state(TASK_INTERRUPTIBLE);
> + schedule_timeout(HZ/10);
> + }
> + if (time_after_eq(jiffies, timeout))
> + dev_err(&dev->dev, "queues didn't drain\n");
> + }
> +
> + bcom_disable(priv->tx_dmatsk);
> +
> + /* Stop FEC */
> + out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
> +
> + return;
> +}
> +
> +static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
> +
> + return phy_mii_ioctl(priv->phydev, mii, cmd);
> +}
> +
> +/* ======================================================================== */
> +/* OF Driver */
> +/* ======================================================================== */
> +
> +static int __devinit
> +mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
> +{
> + int rv;
> + struct net_device *ndev;
> + struct fec_priv *priv = NULL;
> + struct resource mem;
> +
> + phys_addr_t rx_fifo;
> + phys_addr_t tx_fifo;
> +
> + /* Get the ether ndev & it's private zone */
> + ndev = alloc_etherdev(sizeof(struct fec_priv));
> + if (!ndev)
> + return -ENOMEM;
> +
> + priv = netdev_priv(ndev);
> +
> + priv->ofdev = op;
> +
> + /* Reserve FEC control zone */
> + rv = of_address_to_resource(op->node, 0, &mem);
> + if (rv) {
> + printk(KERN_ERR DRIVER_NAME ": "
> + "Error while parsing device node resource\n" );
> + return rv;
> + }
> + if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) {
> + printk(KERN_ERR DRIVER_NAME
> + " - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",
> + (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
> + return -EINVAL;
> + }
> +
> + if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
> + return -EBUSY;
> +
> + /* Init ether ndev with what we have */
> + ndev->open = fec_open;
> + ndev->stop = fec_close;
> + ndev->hard_start_xmit = fec_hard_start_xmit;
> + ndev->do_ioctl = fec_ioctl;
> + ndev->get_stats = fec_get_stats;
> + ndev->set_mac_address = fec_set_mac_address;
> + ndev->set_multicast_list = fec_set_multicast_list;
> + ndev->tx_timeout = fec_tx_timeout;
> + ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
> + ndev->flags &= ~IFF_RUNNING;
> + ndev->base_addr = mem.start;
> +
> + priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
> +
> + spin_lock_init(&priv->lock);
> +
> + /* ioremap the zones */
> + priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec));
> +
> + if (!priv->fec) {
> + rv = -ENOMEM;
> + goto probe_error;
> + }
> +
> + /* Bestcomm init */
> + rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data);
> + tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data);
> +
> + priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE);
> + priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
> +
> + if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
> + printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
> + rv = -ENOMEM;
> + goto probe_error;
> + }
> +
> + /* Get the IRQ we need one by one */
> + /* Control */
> + ndev->irq = irq_of_parse_and_map(op->node, 0);
> +
> + /* RX */
> + priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
> +
> + /* TX */
> + priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
> +
> + /* MAC address init */
> + if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
> + memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
> + else
> + fec_get_paddr(ndev, ndev->dev_addr);
> +
> + /* Phy speed */
> + priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
> +
> + priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
> + priv->duplex = DUPLEX_HALF;
> +
> + /* Hardware init */
> + fec_hw_init(ndev);
> +
> + fec_reset_stats(ndev);
> +
> + /* Register the new network device */
> + rv = register_netdev(ndev);
> + if (rv < 0)
> + goto probe_error;
> +
> + /* We're done ! */
> + dev_set_drvdata(&op->dev, ndev);
> +
> + return 0;
> +
> +
> + /* Error handling - free everything that might be allocated */
> +probe_error:
> +
> + irq_dispose_mapping(ndev->irq);
> +
> + if (priv->rx_dmatsk)
> + bcom_fec_rx_release(priv->rx_dmatsk);
> + if (priv->tx_dmatsk)
> + bcom_fec_tx_release(priv->tx_dmatsk);
> +
> + if (priv->fec)
> + iounmap(priv->fec);
> +
> + release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
> +
> + free_netdev(ndev);
> +
> + return rv;
> +}
> +
> +static int
> +mpc52xx_fec_remove(struct of_device *op)
> +{
> + struct net_device *ndev;
> + struct fec_priv *priv;
> +
> + ndev = dev_get_drvdata(&op->dev);
> + if (!ndev)
> + return 0;
> + priv = netdev_priv(ndev);
> +
> + unregister_netdev(ndev);
> +
> + irq_dispose_mapping(ndev->irq);
> +
> + bcom_fec_rx_release(priv->rx_dmatsk);
> + bcom_fec_tx_release(priv->tx_dmatsk);
> +
> + iounmap(priv->fec);
> +
> + release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
> +
> + free_netdev(ndev);
> +
> + dev_set_drvdata(&op->dev, NULL);
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state)
> +{
> + struct net_device *dev = dev_get_drvdata(&op->dev);
> +
> + if (netif_running(dev))
> + fec_close(dev);
> +
> + return 0;
> +}
> +
> +static int mpc52xx_fec_of_resume(struct of_device *op)
> +{
> + struct net_device *dev = dev_get_drvdata(&op->dev);
> +
> + fec_hw_init(dev);
> + fec_reset_stats(dev);
> +
> + if (netif_running(dev))
> + fec_open(dev);
> +
> + return 0;
> +}
> +#endif
> +
> +static struct of_device_id mpc52xx_fec_match[] = {
> + {
> + .type = "network",
> + .compatible = "mpc5200-fec",
> + },
> + { }
> +};
> +
> +MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
> +
> +static struct of_platform_driver mpc52xx_fec_driver = {
> + .owner = THIS_MODULE,
> + .name = DRIVER_NAME,
> + .match_table = mpc52xx_fec_match,
> + .probe = mpc52xx_fec_probe,
> + .remove = mpc52xx_fec_remove,
> +#ifdef CONFIG_PM
> + .suspend = mpc52xx_fec_of_suspend,
> + .resume = mpc52xx_fec_of_resume,
> +#endif
> +};
> +
> +
> +/* ======================================================================== */
> +/* Module */
> +/* ======================================================================== */
> +
> +static int __init
> +mpc52xx_fec_init(void)
> +{
> + int ret;
> + if ((ret = fec_mdio_init())) {
Why not:
int ret = fec_mdio_init();
if (ret) {
Less parenthesis, looks more clear
> + printk(KERN_ERR "%s: %i fec_mdio_init failed\n", __func__, __LINE__);
> + return ret;
> + }
> +
> + return of_register_platform_driver(&mpc52xx_fec_driver);
> +}
> +
> +static void __exit
> +mpc52xx_fec_exit(void)
> +{
> + of_unregister_platform_driver(&mpc52xx_fec_driver);
> + fec_mdio_exit();
> +}
> +
> +
> +module_init(mpc52xx_fec_init);
> +module_exit(mpc52xx_fec_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Dale Farnsworth");
> +MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
> +
> diff -pruN dummy/fec.h ./drivers/net/fec_mpc52xx/fec.h
> --- dummy/fec.h 1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/net/fec_mpc52xx/fec.h 2007-08-10 11:24:37.000000000 +0200
> @@ -0,0 +1,299 @@
> +/*
> + * drivers/net/fec_mpc52xx/fec.h
> + *
> + * Driver for the MPC5200 Fast Ethernet Controller
> + *
> + * Author: Dale Farnsworth <dfarnsworth@mvista.com>
> + *
> + * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
> + * the terms of the GNU General Public License version 2. This program
> + * is licensed "as is" without any warranty of any kind, whether express
> + * or implied.
> + */
> +
> +#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
> +#define __DRIVERS_NET_MPC52XX_FEC_H__
> +
> +#include <linux/mii.h> // XXX, still needed?
> +#include <linux/phy.h>
> +
> +/* Tunable constant */
> +/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
> +#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
> +#define FEC_RX_NUM_BD 64
> +#define FEC_TX_NUM_BD 64
> +
> +#define FEC_RESET_DELAY 50 /* uS */
> +
> +#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
> +
> +struct fec_priv {
> + int duplex;
> + int tx_full;
> + int r_irq;
> + int t_irq;
> + struct mpc52xx_fec __iomem *fec;
> + struct bcom_task *rx_dmatsk;
> + struct bcom_task *tx_dmatsk;
> + spinlock_t lock;
> + struct net_device_stats stats;
> + int msg_enable;
> +#ifdef CONFIG_FEC_MPC52xx_MDIO
> + uint phy_speed;
> +
> + struct phy_device *phydev;
> + enum phy_state link;
> + int speed;
> +
> + struct of_device *ofdev;
> +#endif /* CONFIG_FEC_MPC52xx_MDIO */
> +};
> +
> +
> +/* ======================================================================== */
> +/* Hardware register sets & bits */
> +/* ======================================================================== */
> +
> +struct mpc52xx_fec {
> + u32 fec_id; /* FEC + 0x000 */
> + u32 ievent; /* FEC + 0x004 */
> + u32 imask; /* FEC + 0x008 */
> +
> + u32 reserved0[1]; /* FEC + 0x00C */
> + u32 r_des_active; /* FEC + 0x010 */
> + u32 x_des_active; /* FEC + 0x014 */
> + u32 r_des_active_cl; /* FEC + 0x018 */
> + u32 x_des_active_cl; /* FEC + 0x01C */
> + u32 ivent_set; /* FEC + 0x020 */
> + u32 ecntrl; /* FEC + 0x024 */
> +
> + u32 reserved1[6]; /* FEC + 0x028-03C */
> + u32 mii_data; /* FEC + 0x040 */
> + u32 mii_speed; /* FEC + 0x044 */
> + u32 mii_status; /* FEC + 0x048 */
> +
> + u32 reserved2[5]; /* FEC + 0x04C-05C */
> + u32 mib_data; /* FEC + 0x060 */
> + u32 mib_control; /* FEC + 0x064 */
> +
> + u32 reserved3[6]; /* FEC + 0x068-7C */
> + u32 r_activate; /* FEC + 0x080 */
> + u32 r_cntrl; /* FEC + 0x084 */
> + u32 r_hash; /* FEC + 0x088 */
> + u32 r_data; /* FEC + 0x08C */
> + u32 ar_done; /* FEC + 0x090 */
> + u32 r_test; /* FEC + 0x094 */
> + u32 r_mib; /* FEC + 0x098 */
> + u32 r_da_low; /* FEC + 0x09C */
> + u32 r_da_high; /* FEC + 0x0A0 */
> +
> + u32 reserved4[7]; /* FEC + 0x0A4-0BC */
> + u32 x_activate; /* FEC + 0x0C0 */
> + u32 x_cntrl; /* FEC + 0x0C4 */
> + u32 backoff; /* FEC + 0x0C8 */
> + u32 x_data; /* FEC + 0x0CC */
> + u32 x_status; /* FEC + 0x0D0 */
> + u32 x_mib; /* FEC + 0x0D4 */
> + u32 x_test; /* FEC + 0x0D8 */
> + u32 fdxfc_da1; /* FEC + 0x0DC */
> + u32 fdxfc_da2; /* FEC + 0x0E0 */
> + u32 paddr1; /* FEC + 0x0E4 */
> + u32 paddr2; /* FEC + 0x0E8 */
> + u32 op_pause; /* FEC + 0x0EC */
> +
> + u32 reserved5[4]; /* FEC + 0x0F0-0FC */
> + u32 instr_reg; /* FEC + 0x100 */
> + u32 context_reg; /* FEC + 0x104 */
> + u32 test_cntrl; /* FEC + 0x108 */
> + u32 acc_reg; /* FEC + 0x10C */
> + u32 ones; /* FEC + 0x110 */
> + u32 zeros; /* FEC + 0x114 */
> + u32 iaddr1; /* FEC + 0x118 */
> + u32 iaddr2; /* FEC + 0x11C */
> + u32 gaddr1; /* FEC + 0x120 */
> + u32 gaddr2; /* FEC + 0x124 */
> + u32 random; /* FEC + 0x128 */
> + u32 rand1; /* FEC + 0x12C */
> + u32 tmp; /* FEC + 0x130 */
> +
> + u32 reserved6[3]; /* FEC + 0x134-13C */
> + u32 fifo_id; /* FEC + 0x140 */
> + u32 x_wmrk; /* FEC + 0x144 */
> + u32 fcntrl; /* FEC + 0x148 */
> + u32 r_bound; /* FEC + 0x14C */
> + u32 r_fstart; /* FEC + 0x150 */
> + u32 r_count; /* FEC + 0x154 */
> + u32 r_lag; /* FEC + 0x158 */
> + u32 r_read; /* FEC + 0x15C */
> + u32 r_write; /* FEC + 0x160 */
> + u32 x_count; /* FEC + 0x164 */
> + u32 x_lag; /* FEC + 0x168 */
> + u32 x_retry; /* FEC + 0x16C */
> + u32 x_write; /* FEC + 0x170 */
> + u32 x_read; /* FEC + 0x174 */
> +
> + u32 reserved7[2]; /* FEC + 0x178-17C */
> + u32 fm_cntrl; /* FEC + 0x180 */
> + u32 rfifo_data; /* FEC + 0x184 */
> + u32 rfifo_status; /* FEC + 0x188 */
> + u32 rfifo_cntrl; /* FEC + 0x18C */
> + u32 rfifo_lrf_ptr; /* FEC + 0x190 */
> + u32 rfifo_lwf_ptr; /* FEC + 0x194 */
> + u32 rfifo_alarm; /* FEC + 0x198 */
> + u32 rfifo_rdptr; /* FEC + 0x19C */
> + u32 rfifo_wrptr; /* FEC + 0x1A0 */
> + u32 tfifo_data; /* FEC + 0x1A4 */
> + u32 tfifo_status; /* FEC + 0x1A8 */
> + u32 tfifo_cntrl; /* FEC + 0x1AC */
> + u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */
> + u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */
> + u32 tfifo_alarm; /* FEC + 0x1B8 */
> + u32 tfifo_rdptr; /* FEC + 0x1BC */
> + u32 tfifo_wrptr; /* FEC + 0x1C0 */
> +
> + u32 reset_cntrl; /* FEC + 0x1C4 */
> + u32 xmit_fsm; /* FEC + 0x1C8 */
> +
> + u32 reserved8[3]; /* FEC + 0x1CC-1D4 */
> + u32 rdes_data0; /* FEC + 0x1D8 */
> + u32 rdes_data1; /* FEC + 0x1DC */
> + u32 r_length; /* FEC + 0x1E0 */
> + u32 x_length; /* FEC + 0x1E4 */
> + u32 x_addr; /* FEC + 0x1E8 */
> + u32 cdes_data; /* FEC + 0x1EC */
> + u32 status; /* FEC + 0x1F0 */
> + u32 dma_control; /* FEC + 0x1F4 */
> + u32 des_cmnd; /* FEC + 0x1F8 */
> + u32 data; /* FEC + 0x1FC */
> +
> + u32 rmon_t_drop; /* FEC + 0x200 */
> + u32 rmon_t_packets; /* FEC + 0x204 */
> + u32 rmon_t_bc_pkt; /* FEC + 0x208 */
> + u32 rmon_t_mc_pkt; /* FEC + 0x20C */
> + u32 rmon_t_crc_align; /* FEC + 0x210 */
> + u32 rmon_t_undersize; /* FEC + 0x214 */
> + u32 rmon_t_oversize; /* FEC + 0x218 */
> + u32 rmon_t_frag; /* FEC + 0x21C */
> + u32 rmon_t_jab; /* FEC + 0x220 */
> + u32 rmon_t_col; /* FEC + 0x224 */
> + u32 rmon_t_p64; /* FEC + 0x228 */
> + u32 rmon_t_p65to127; /* FEC + 0x22C */
> + u32 rmon_t_p128to255; /* FEC + 0x230 */
> + u32 rmon_t_p256to511; /* FEC + 0x234 */
> + u32 rmon_t_p512to1023; /* FEC + 0x238 */
> + u32 rmon_t_p1024to2047; /* FEC + 0x23C */
> + u32 rmon_t_p_gte2048; /* FEC + 0x240 */
> + u32 rmon_t_octets; /* FEC + 0x244 */
> + u32 ieee_t_drop; /* FEC + 0x248 */
> + u32 ieee_t_frame_ok; /* FEC + 0x24C */
> + u32 ieee_t_1col; /* FEC + 0x250 */
> + u32 ieee_t_mcol; /* FEC + 0x254 */
> + u32 ieee_t_def; /* FEC + 0x258 */
> + u32 ieee_t_lcol; /* FEC + 0x25C */
> + u32 ieee_t_excol; /* FEC + 0x260 */
> + u32 ieee_t_macerr; /* FEC + 0x264 */
> + u32 ieee_t_cserr; /* FEC + 0x268 */
> + u32 ieee_t_sqe; /* FEC + 0x26C */
> + u32 t_fdxfc; /* FEC + 0x270 */
> + u32 ieee_t_octets_ok; /* FEC + 0x274 */
> +
> + u32 reserved9[2]; /* FEC + 0x278-27C */
> + u32 rmon_r_drop; /* FEC + 0x280 */
> + u32 rmon_r_packets; /* FEC + 0x284 */
> + u32 rmon_r_bc_pkt; /* FEC + 0x288 */
> + u32 rmon_r_mc_pkt; /* FEC + 0x28C */
> + u32 rmon_r_crc_align; /* FEC + 0x290 */
> + u32 rmon_r_undersize; /* FEC + 0x294 */
> + u32 rmon_r_oversize; /* FEC + 0x298 */
> + u32 rmon_r_frag; /* FEC + 0x29C */
> + u32 rmon_r_jab; /* FEC + 0x2A0 */
> +
> + u32 rmon_r_resvd_0; /* FEC + 0x2A4 */
> +
> + u32 rmon_r_p64; /* FEC + 0x2A8 */
> + u32 rmon_r_p65to127; /* FEC + 0x2AC */
> + u32 rmon_r_p128to255; /* FEC + 0x2B0 */
> + u32 rmon_r_p256to511; /* FEC + 0x2B4 */
> + u32 rmon_r_p512to1023; /* FEC + 0x2B8 */
> + u32 rmon_r_p1024to2047; /* FEC + 0x2BC */
> + u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */
> + u32 rmon_r_octets; /* FEC + 0x2C4 */
> + u32 ieee_r_drop; /* FEC + 0x2C8 */
> + u32 ieee_r_frame_ok; /* FEC + 0x2CC */
> + u32 ieee_r_crc; /* FEC + 0x2D0 */
> + u32 ieee_r_align; /* FEC + 0x2D4 */
> + u32 r_macerr; /* FEC + 0x2D8 */
> + u32 r_fdxfc; /* FEC + 0x2DC */
> + u32 ieee_r_octets_ok; /* FEC + 0x2E0 */
> +
> + u32 reserved10[7]; /* FEC + 0x2E4-2FC */
> +
> + u32 reserved11[64]; /* FEC + 0x300-3FF */
> +};
> +
> +#define FEC_MIB_DISABLE 0x80000000
> +
> +#define FEC_IEVENT_HBERR 0x80000000
> +#define FEC_IEVENT_BABR 0x40000000
> +#define FEC_IEVENT_BABT 0x20000000
> +#define FEC_IEVENT_GRA 0x10000000
> +#define FEC_IEVENT_TFINT 0x08000000
> +#define FEC_IEVENT_MII 0x00800000
> +#define FEC_IEVENT_LATE_COL 0x00200000
> +#define FEC_IEVENT_COL_RETRY_LIM 0x00100000
> +#define FEC_IEVENT_XFIFO_UN 0x00080000
> +#define FEC_IEVENT_XFIFO_ERROR 0x00040000
> +#define FEC_IEVENT_RFIFO_ERROR 0x00020000
> +
> +#define FEC_IMASK_HBERR 0x80000000
> +#define FEC_IMASK_BABR 0x40000000
> +#define FEC_IMASK_BABT 0x20000000
> +#define FEC_IMASK_GRA 0x10000000
> +#define FEC_IMASK_MII 0x00800000
> +#define FEC_IMASK_LATE_COL 0x00200000
> +#define FEC_IMASK_COL_RETRY_LIM 0x00100000
> +#define FEC_IMASK_XFIFO_UN 0x00080000
> +#define FEC_IMASK_XFIFO_ERROR 0x00040000
> +#define FEC_IMASK_RFIFO_ERROR 0x00020000
> +
> +#define FEC_RCNTRL_MAX_FL_SHIFT 16
> +#define FEC_RCNTRL_LOOP 0x01
> +#define FEC_RCNTRL_DRT 0x02
> +#define FEC_RCNTRL_MII_MODE 0x04
> +#define FEC_RCNTRL_PROM 0x08
> +#define FEC_RCNTRL_BC_REJ 0x10
> +#define FEC_RCNTRL_FCE 0x20
> +
> +#define FEC_TCNTRL_GTS 0x00000001
> +#define FEC_TCNTRL_HBC 0x00000002
> +#define FEC_TCNTRL_FDEN 0x00000004
> +#define FEC_TCNTRL_TFC_PAUSE 0x00000008
> +#define FEC_TCNTRL_RFC_PAUSE 0x00000010
> +
> +#define FEC_ECNTRL_RESET 0x00000001
> +#define FEC_ECNTRL_ETHER_EN 0x00000002
> +
> +#define FEC_PADDR2_TYPE 0x8808
> +
> +#define FEC_OP_PAUSE_OPCODE 0x00010000
> +
> +#define FEC_FIFO_WMRK_256B 0x3
> +
> +#define FEC_FIFO_STATUS_ERR 0x00400000
> +#define FEC_FIFO_STATUS_UF 0x00200000
> +#define FEC_FIFO_STATUS_OF 0x00100000
> +
> +#define FEC_FIFO_CNTRL_FRAME 0x08000000
> +#define FEC_FIFO_CNTRL_LTG_7 0x07000000
> +
> +#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000
> +#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000
> +
> +#define FEC_XMIT_FSM_APPEND_CRC 0x02000000
> +#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000
> +
> +
> +int __init fec_mdio_init(void);
> +void __exit fec_mdio_exit(void);
> +
> +#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */
> diff -pruN dummy/fec_phy.c ./drivers/net/fec_mpc52xx/fec_phy.c
> --- dummy/fec_phy.c 1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/net/fec_mpc52xx/fec_phy.c 2007-08-10 10:59:53.000000000 +0200
> @@ -0,0 +1,229 @@
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/phy.h>
> +#include <asm/io.h>
> +#include <asm/mpc52xx.h>
> +#include <asm/of_platform.h>
> +#include "fec_phy.h"
> +#include "fec.h"
> +
> +struct fec_mdio_priv {
> + int completed;
> + wait_queue_head_t wq;
> + struct mpc52xx_fec __iomem *regs;
> + int irq;
> +};
> +
> +static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> +{
> + struct fec_mdio_priv *priv = bus->priv;
> + int tries = 100;
> +
> + u32 request = FEC_MII_READ_FRAME;
> + request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> + request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> + out_be32(&priv->regs->mii_data, request);
> +
> + /* wait for it to finish, this takes about 23 us on lite5200b */
> + while (priv->completed == 0 && tries--)
> + udelay(5);
> +
> + priv->completed = 0;
> +
> + if (tries == 0)
> + return -ETIMEDOUT;
> +
> + return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
> +}
> +
> +static int fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
> +{
> + struct fec_mdio_priv *priv = bus->priv;
> + u32 value = data;
> + int tries = 100;
> +
> + value |= FEC_MII_WRITE_FRAME;
> + value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> + value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> + out_be32(&priv->regs->mii_data, value);
> +
> + /* wait for request to finish */
> + while (priv->completed == 0 && tries--)
> + udelay(5);
> +
> + priv->completed = 0;
> +
> + if (tries == 0)
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static irqreturn_t fec_mdio_interrupt(int irq, void *dev_id)
> +{
> + struct fec_mdio_priv *priv = dev_id;
> + struct mpc52xx_fec __iomem *fec;
> + int ievent;
> +
> + fec = priv->regs;
> + ievent = in_be32(&fec->ievent);
> +
> + ievent &= FEC_IEVENT_MII;
> + if (!ievent)
> + return IRQ_NONE;
> +
> + out_be32(&fec->ievent, ievent);
> +
> + priv->completed = 1;
> + wake_up(&priv->wq);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
> +{
> + struct device *dev = &of->dev;
> + struct device_node *np = of->node;
> + struct device_node *child = NULL;
> + struct mii_bus *bus;
> + struct fec_mdio_priv *priv;
> + struct resource res = {};
> + int err;
> + int i;
> +
> + bus = kzalloc(sizeof(*bus), GFP_KERNEL);
> + if (bus == NULL)
> + return -ENOMEM;
> + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> + if (priv == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> +
> + bus->name = "mpc52xx MII bus";
> + bus->read = fec_mdio_read;
> + bus->write = fec_mdio_write;
> +
> + /* setup irqs */
> + bus->irq = kcalloc(sizeof(bus->irq[0]), PHY_MAX_ADDR, GFP_KERNEL);
> + if (bus->irq == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + bus->irq[i] = PHY_POLL;
> +
> + while ((child = of_get_next_child(np, child)) != NULL) {
> + int irq = irq_of_parse_and_map(child, 0);
> + if (irq != NO_IRQ) {
> + const u32 *id = of_get_property(child, "reg", NULL);
> + bus->irq[*id] = irq;
> + }
> + }
> +
> + /* setup registers */
> + err = of_address_to_resource(np, 0, &res);
> + if (err)
> + goto out_free;
> + priv->regs = ioremap(res.start, res.end - res.start + 1);
> + if (priv->regs == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> +
> + priv->irq = irq_of_parse_and_map(np, 0);
> + err = request_irq(priv->irq, &fec_mdio_interrupt, IRQF_DISABLED | IRQF_SHARED,
> + "fec_mdio", priv);
> + if (err) {
> + printk(KERN_ERR "%s: interrupt request failed with %i\n", __func__, err);
> + goto out_unmap;
> + }
> +
> + bus->id = res.start;
> + bus->priv = priv;
> +
> + bus->dev = dev;
> + dev_set_drvdata(dev, bus);
> +
> + init_waitqueue_head(&priv->wq);
> +
> + /* set MII speed */
> + out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
> +
> + /* enable MII interrupt */
> + out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
> +
> + err = mdiobus_register(bus);
> + if (err)
> + goto out_free_irq;
> +
> + return 0;
> +
> + out_free_irq:
> + free_irq(priv->irq, dev);
> + irq_dispose_mapping(priv->irq);
> + out_unmap:
> + iounmap(priv->regs);
> + out_free:
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + if (bus->irq[i])
> + irq_dispose_mapping(bus->irq[i]);
> + kfree(bus->irq);
> + kfree(priv);
> + kfree(bus);
> +
> + return err;
> +}
> +
> +static int fec_mdio_remove(struct of_device *of)
> +{
> + struct device *dev = &of->dev;
> + struct mii_bus *bus = dev_get_drvdata(dev);
> + struct fec_mdio_priv *priv = bus->priv;
> + int i;
> +
> + mdiobus_unregister(bus);
> + dev_set_drvdata(dev, NULL);
> +
> + free_irq(priv->irq, dev);
> + irq_dispose_mapping(priv->irq);
> + iounmap(priv->regs);
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + if (bus->irq[i])
> + irq_dispose_mapping(bus->irq[i]);
> + kfree(priv);
> + kfree(bus->irq);
> + kfree(bus);
> +
> + return 0;
> +}
> +
> +
> +static struct of_device_id fec_mdio_match[] = {
> + {
> + .type = "mdio",
> + .compatible = "mpc5200b-fec-phy",
> + },
> + {},
> +};
> +
> +static struct of_platform_driver fec_mdio_driver = {
> + .name = "mpc5200b-fec-phy",
> + .probe = fec_mdio_probe,
> + .remove = fec_mdio_remove,
> + .match_table = fec_mdio_match,
> +};
> +
> +
> +int __init fec_mdio_init(void)
> +{
> + return of_register_platform_driver(&fec_mdio_driver);
> +}
> +
> +void __exit fec_mdio_exit(void)
> +{
> + of_unregister_platform_driver(&fec_mdio_driver);
> +}
> diff -pruN dummy/fec_phy.h ./drivers/net/fec_mpc52xx/fec_phy.h
> --- dummy/fec_phy.h 1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/net/fec_mpc52xx/fec_phy.h 2007-08-10 11:22:54.000000000 +0200
> @@ -0,0 +1,49 @@
> +/*
> + * arch/ppc/52xx_io/fec_phy.h
> + *
> + * Driver for the MPC5200 Fast Ethernet Controller
> + * Based heavily on the MII support for the MPC8xx by Dan Malek
> + *
> + * Author: Dale Farnsworth <dfarnsworth@mvista.com>
> + *
> + * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
> + * the terms of the GNU General Public License version 2. This program
> + * is licensed "as is" without any warranty of any kind, whether express
> + * or implied.
> + */
> +
> +#define FEC_IMASK_ALL (FEC_IMASK_HBERR | FEC_IMASK_BABR | \
> + FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_MII | \
> + FEC_IMASK_LATE_COL | FEC_IMASK_COL_RETRY_LIM | \
> + FEC_IMASK_XFIFO_UN | FEC_IMASK_XFIFO_ERROR | \
> + FEC_IMASK_RFIFO_ERROR)
> +
> +#ifdef CONFIG_FEC_MPC52xx_MDIO
> +#define MII_RCNTL_MODE FEC_RCNTRL_MII_MODE
> +#define FEC_IMASK_ENABLE FEC_IMASK_ALL
> +#define set_phy_speed(fec, s) out_be32(&fec->mii_speed, s)
> +#else
> +#define MII_RCNTL_MODE 0
> +#define FEC_IMASK_ENABLE (FEC_IMASK_ALL & ~FEC_IMASK_MII)
> +#define set_phy_speed(fec, s) do { } while (0)
> +#define fec_mii_start(dev) do { } while (0)
> +#define fec_mii(dev) printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n")
> +#define fec_mii_init(dev) do { } while (0)
> +#define fec_mii_suspend(dev) do { } while (0)
> +#define fec_mii_resume(dev) do { } while (0)
> +#endif /* CONFIG_FEC_MPC52xx_MDIO */
> +
> +/* MII-related definitions */
> +#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
> +#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
> +#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
> +#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
> +#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
> +#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
> +#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */
> +
> +#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
> +#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
> +
> +#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
> +#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
> diff -pruN dummy/Kconfig ./drivers/net/fec_mpc52xx/Kconfig
> --- dummy/Kconfig 1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/net/fec_mpc52xx/Kconfig 2007-08-08 10:50:04.000000000 +0200
> @@ -0,0 +1,24 @@
> +menu "MPC5200 Networking Options"
> + depends PPC_MPC52xx && NET_ETHERNET
> +
> +config FEC_MPC52xx
> + tristate "FEC Ethernet"
> + depends on NET_ETHERNET
> + select PPC_BESTCOMM
> + select PPC_BESTCOMM_FEC
> + select CRC32
> + ---help---
> + This option enables support for the MPC5200's on-chip
> + Fast Ethernet Controller
> +
> +config USE_MDIO
> + bool "Use external Ethernet MII PHY"
> + select MII
> + depends FEC_MPC52xx
> + ---help---
> + The MPC5200's FEC can connect to the Ethernet either with
> + an external MII PHY chip or 10 Mbps 7-wire interface
> + (Motorola? industry standard).
> + If your board uses an external PHY, say y, else n.
> +
> +endmenu
> diff -pruN dummy/Makefile ./drivers/net/fec_mpc52xx/Makefile
> --- dummy/Makefile 1970-01-01 01:00:00.000000000 +0100
> +++ ./drivers/net/fec_mpc52xx/Makefile 2007-08-08 10:50:04.000000000 +0200
> @@ -0,0 +1,7 @@
> +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
> +
> +fec_mpc52xx-objs := fec.o
> +
> +ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
> +fec_mpc52xx-objs += fec_phy.o
> +endif
> Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
> ===================================================================
> --- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts
> +++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
> @@ -365,10 +365,26 @@
> ethernet@3000 {
> device_type = "network";
> compatible = "mpc5200b-fec\0mpc5200-fec";
> - reg = <3000 800>;
> + reg = <3000 400>;
> mac-address = [ 02 03 04 05 06 07 ]; // Bad!
> interrupts = <2 5 0>;
> interrupt-parent = <&mpc5200_pic>;
> + phy-handle = <&phy0>;
> + };
> +
> + mdio@3000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + device_type = "mdio";
> + compatible = "mpc5200b-fec-phy";
> + reg = <3000 400>; // fec range, since we need to setup fec interrupts
> + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
> + interrupt-parent = <&mpc5200_pic>;
> +
> + phy0:ethernet-phy@0 {
> + device_type = "ethernet-phy";
> + reg = <0>;
> + };
> };
>
> ata@3a00 {
> Index: work-powerpc.git/arch/powerpc/sysdev/bestcomm/fec.h
> ===================================================================
> --- work-powerpc.git.orig/arch/powerpc/sysdev/bestcomm/fec.h
> +++ work-powerpc.git/arch/powerpc/sysdev/bestcomm/fec.h
> @@ -22,6 +22,20 @@ struct bcom_fec_bd {
>
> #define BCOM_FEC_TX_BD_TFD 0x08000000ul /* transmit frame done */
> #define BCOM_FEC_TX_BD_INT 0x04000000ul /* interrupt */
> +#define BCOM_FEC_TX_BD_TC 0x04000000ul /* transmit CRC XXX same as ^? */
> +#define BCOM_FEC_TX_BD_ABC 0x02000000ul /* append bad CRC */
> +
> +#define BCOM_FEC_RX_BD_L 0x08000000ul /* buffer is last in frame */
> +#define BCOM_FEC_RX_BD_BC 0x00800000ul /* DA is broadcast */
> +#define BCOM_FEC_RX_BD_MC 0x00400000ul /* DA is multicast and not broadcast */
> +#define BCOM_FEC_RX_BD_LG 0x00200000ul /* Rx frame length violation */
> +#define BCOM_FEC_RX_BD_NO 0x00100000ul /* Rx non-octet aligned frame */
> +#define BCOM_FEC_RX_BD_CR 0x00040000ul /* Rx CRC error */
> +#define BCOM_FEC_RX_BD_OV 0x00020000ul /* overrun */
> +#define BCOM_FEC_RX_BD_TR 0x00010000ul /* Rx frame truncated */
> +#define BCOM_FEC_RX_BD_LEN_MASK 0x000007fful /* mask for length of received frame */
> +#define BCOM_FEC_RX_BD_ERRORS (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \
> + BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR)
>
>
> extern struct bcom_task *
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-10 13:02 ` Arnaldo Carvalho de Melo
@ 2007-08-13 7:21 ` Domen Puncer
0 siblings, 0 replies; 47+ messages in thread
From: Domen Puncer @ 2007-08-13 7:21 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, linuxppc-embedded, netdev
On 10/08/07 10:02 -0300, Arnaldo Carvalho de Melo wrote:
> Em Fri, Aug 10, 2007 at 11:51:53AM +0200, Domen Puncer escreveu:
> > +static u8 null_mac[6];
>
> const
OK.
...
> > +static void fec_set_paddr(struct net_device *dev, u8 *mac)
> > +{
> > + struct fec_priv *priv = netdev_priv(dev);
> > + struct mpc52xx_fec __iomem *fec = priv->fec;
> > +
> > + out_be32(&fec->paddr1, *(u32*)(&mac[0]));
> > + out_be32(&fec->paddr2, (*(u16*)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
>
> spaces after the types on casts to pointers
I assume you mean: out_be32(&fec->paddr1, *(u32 *)(&mac[0]));
>
> > +}
> > +
> > +static void fec_get_paddr(struct net_device *dev, u8 *mac)
> > +{
> > + struct fec_priv *priv = netdev_priv(dev);
> > + struct mpc52xx_fec __iomem *fec = priv->fec;
> > +
> > + *(u32*)(&mac[0]) = in_be32(&fec->paddr1);
> > + *(u16*)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
>
> ditto
OK.
>
> > +}
> > +
> > +static int fec_set_mac_address(struct net_device *dev, void *addr)
> > +{
> > + struct sockaddr *sock = (struct sockaddr *)addr;
>
> no need for a cast, addr is a void pointer
Right, missed this one.
>
> > +
> > + memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
> > +
> > + fec_set_paddr(dev, sock->sa_data);
> > + return 0;
>
> Why always return 0? make it void
Because struct net_device->set_mac_address's prototype is like that.
>
> > +}
> > +
> > +static void fec_free_rx_buffers(struct bcom_task *s)
> > +{
> > + struct sk_buff *skb;
> > +
> > + while (!bcom_queue_empty(s)) {
> > + skb = bcom_retrieve_buffer(s, NULL, NULL);
> > + kfree_skb(skb);
> > + }
> > +}
> > +
> > +static int fec_alloc_rx_buffers(struct bcom_task *rxtsk)
> > +{
> > + while (!bcom_queue_full(rxtsk)) {
> > + struct sk_buff *skb;
> > + struct bcom_fec_bd *bd;
> > +
> > + skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
> > + if (skb == 0)
>
> Test against NULL
Right. I also fixed other stuff sparse reports.
>
> > + return -EAGAIN;
> > +
...
> > +
> > + if (new_state && netif_msg_link(priv)) {
> > + phy_print_status(phydev);
> > + }
>
> No need for {}, this if has only one statement
OK.
...
> > +static int __init
> > +mpc52xx_fec_init(void)
> > +{
> > + int ret;
> > + if ((ret = fec_mdio_init())) {
>
> Why not:
>
> int ret = fec_mdio_init();
> if (ret) {
>
> Less parenthesis, looks more clear
I prefer it like that too.
Thanks Arnaldo!
Any other comments on code functionality, design?
Domen
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-10 9:51 [RFC PATCH v0.1] net driver: mpc52xx fec Domen Puncer
2007-08-10 13:02 ` Arnaldo Carvalho de Melo
@ 2007-08-18 10:06 ` Domen Puncer
2007-08-19 15:39 ` Matt Sealey
2007-09-02 7:41 ` [RFC PATCH v0.2] " Domen Puncer
2007-09-27 17:07 ` [RFC PATCH v0.1] " Juergen Beisert
3 siblings, 1 reply; 47+ messages in thread
From: Domen Puncer @ 2007-08-18 10:06 UTC (permalink / raw)
To: Matt Sealey; +Cc: linuxppc-embedded
Hi!
On 10/08/07 11:51 +0200, Domen Puncer wrote:
> Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
> ===================================================================
> --- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts
> +++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
> + mdio@3000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + device_type = "mdio";
> + compatible = "mpc5200b-fec-phy";
> + reg = <3000 400>; // fec range, since we need to setup fec interrupts
> + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
> + interrupt-parent = <&mpc5200_pic>;
> +
> + phy0:ethernet-phy@0 {
> + device_type = "ethernet-phy";
> + reg = <0>;
> + };
> };
I am struggling with this part on Efika.
I would like to add this to the device tree from
fixup_device_tree_efika() (arch/powerpc/kernel/prom_init.c).
AFAICS client-services doesn't offer anything like new-device,
so I guess "interpret" or "call-method" will have to be used.
I have read some docs, but I'm still wandering in the dark.
Can I please get an example?
Pretty please with a cherry on top?
Domen
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-18 10:06 ` Domen Puncer
@ 2007-08-19 15:39 ` Matt Sealey
2007-08-20 8:31 ` Domen Puncer
0 siblings, 1 reply; 47+ messages in thread
From: Matt Sealey @ 2007-08-19 15:39 UTC (permalink / raw)
To: Domen Puncer; +Cc: linuxppc-embedded
Domen,
Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter
Linux with more fixups. The Efika PHY isn't going to change to something
else and it's a bog standard no-frills MII PHY anyway.
I think it is a distinction that the OF docs forgot to make, that the
client interface is *all those Forth words* and not just the 6 or 7
distinct, special callable functions like claim (they exist because of
the simple fact that claiming memory shouldn't involve claiming memory
and such other paradoxes) and call-method. Call-method is a perfectly
valid way of doing things.
But, I'd really recommend you please think of a different way.. if you
want to spec out a device tree entry for it I'll update my script which
I am probably going to stick as an 'official' Genesi support file in
the next week.
If you insist on using prom_init and fixups, yaboot has the best
examples of call-method and interpret, both readable and fairly
easily available.
--
Matt Sealey <matt@genesi-usa.com>
Genesi, Manager, Developer Relations
Domen Puncer wrote:
> Hi!
>
> On 10/08/07 11:51 +0200, Domen Puncer wrote:
>> Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
>> ===================================================================
>> --- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts
>> +++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
>> + mdio@3000 {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + device_type = "mdio";
>> + compatible = "mpc5200b-fec-phy";
>> + reg = <3000 400>; // fec range, since we need to setup fec interrupts
>> + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
>> + interrupt-parent = <&mpc5200_pic>;
>> +
>> + phy0:ethernet-phy@0 {
>> + device_type = "ethernet-phy";
>> + reg = <0>;
>> + };
>> };
>
> I am struggling with this part on Efika.
> I would like to add this to the device tree from
> fixup_device_tree_efika() (arch/powerpc/kernel/prom_init.c).
>
> AFAICS client-services doesn't offer anything like new-device,
> so I guess "interpret" or "call-method" will have to be used.
>
> I have read some docs, but I'm still wandering in the dark.
> Can I please get an example?
> Pretty please with a cherry on top?
>
>
> Domen
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-19 15:39 ` Matt Sealey
@ 2007-08-20 8:31 ` Domen Puncer
2007-08-20 13:13 ` Domen Puncer
0 siblings, 1 reply; 47+ messages in thread
From: Domen Puncer @ 2007-08-20 8:31 UTC (permalink / raw)
To: Matt Sealey; +Cc: Domen Puncer, linuxppc-embedded
On 19/08/07 16:39 +0100, Matt Sealey wrote:
> Domen,
>
> Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter
> Linux with more fixups. The Efika PHY isn't going to change to something
> else and it's a bog standard no-frills MII PHY anyway.
Fine with me, but I'm worried people won't update nvramrc.
Currently I have this:
--- start ---
s" /builtin" find-device
new-device
1 encode-int s" #address-cells" property
0 encode-int s" #size-cells" property
s" mdio" 2dup device-name device-type
s" mpc5200b-fec-phy" s" compatible" property
0xf0003000 0x400 reg
0x2 encode-int
0x5 encode-int
0x3 encode-int
encode+ encode+
s" interupts" property
new-device
s" ethernet-phy@0" device-name
s" ethernet-phy" device-type
0 encode-int s" reg" property
my-self \ save our phandle to stack
ihandle>phandle
finish-device
finish-device
s" /builtin/ethernet" find-device
encode-int \ phy's phandle
s" phy-handle" property
device-end
--- end ---
But I have a problem with it, possibly due to my not-knowledge of Forth.
Compatible keep getting set to:
compatible "/builtin/etherne"
<spin>
> If you insist on using prom_init and fixups, yaboot has the best
> examples of call-method and interpret, both readable and fairly
> easily available.
Thanks.
Domen
> > On 10/08/07 11:51 +0200, Domen Puncer wrote:
> >> Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
> >> ===================================================================
> >> --- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts
> >> +++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
> >> + mdio@3000 {
> >> + #address-cells = <1>;
> >> + #size-cells = <0>;
> >> + device_type = "mdio";
> >> + compatible = "mpc5200b-fec-phy";
> >> + reg = <3000 400>; // fec range, since we need to setup fec interrupts
> >> + interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
> >> + interrupt-parent = <&mpc5200_pic>;
> >> +
> >> + phy0:ethernet-phy@0 {
> >> + device_type = "ethernet-phy";
> >> + reg = <0>;
> >> + };
> >> };
> >
> > I am struggling with this part on Efika.
> > I would like to add this to the device tree from
> > fixup_device_tree_efika() (arch/powerpc/kernel/prom_init.c).
> >
> > AFAICS client-services doesn't offer anything like new-device,
> > so I guess "interpret" or "call-method" will have to be used.
> >
> > I have read some docs, but I'm still wandering in the dark.
> > Can I please get an example?
> > Pretty please with a cherry on top?
> >
> >
> > Domen
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-20 8:31 ` Domen Puncer
@ 2007-08-20 13:13 ` Domen Puncer
2007-08-20 19:02 ` Matt Sealey
0 siblings, 1 reply; 47+ messages in thread
From: Domen Puncer @ 2007-08-20 13:13 UTC (permalink / raw)
To: Domen Puncer; +Cc: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 647 bytes --]
On 20/08/07 10:31 +0200, Domen Puncer wrote:
> On 19/08/07 16:39 +0100, Matt Sealey wrote:
> > Domen,
> >
> > Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter
> > Linux with more fixups. The Efika PHY isn't going to change to something
> > else and it's a bog standard no-frills MII PHY anyway.
>
> Fine with me, but I'm worried people won't update nvramrc.
>
...
> But I have a problem with it, possibly due to my not-knowledge of Forth.
> Compatible keep getting set to:
> compatible "/builtin/etherne"
I missed the encode-string.
Matt, can you please add attached Forth script to Efika updates.
Domen
[-- Attachment #2: smart_firmware_phy --]
[-- Type: text/plain, Size: 613 bytes --]
s" /builtin" find-device
new-device
1 encode-int s" #address-cells" property
0 encode-int s" #size-cells" property
s" mdio" 2dup device-name device-type
s" mpc5200b-fec-phy" encode-string s" compatible" property
0xf0003000 0x400 reg
0x2 encode-int
0x5 encode-int
0x3 encode-int
encode+ encode+
s" interrupts" property
new-device
s" ethernet-phy" 2dup device-name device-type
0x10 encode-int s" reg" property
my-self \ save our phandle to stack
ihandle>phandle
finish-device
finish-device
s" /builtin/ethernet" find-device
encode-int \ phy's phandle
s" phy-handle" property
device-end
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-20 13:13 ` Domen Puncer
@ 2007-08-20 19:02 ` Matt Sealey
2007-08-21 5:49 ` Domen Puncer
0 siblings, 1 reply; 47+ messages in thread
From: Matt Sealey @ 2007-08-20 19:02 UTC (permalink / raw)
To: Domen Puncer; +Cc: Domen Puncer, linuxppc-embedded
Are you sure this is correct for the Efika?
The MPC5200B manual makes a decent distinction between MII operation and
straight MDIO?
--
Matt Sealey <matt@genesi-usa.com>
Genesi, Manager, Developer Relations
Domen Puncer wrote:
> On 20/08/07 10:31 +0200, Domen Puncer wrote:
>> On 19/08/07 16:39 +0100, Matt Sealey wrote:
>>> Domen,
>>>
>>> Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter
>>> Linux with more fixups. The Efika PHY isn't going to change to something
>>> else and it's a bog standard no-frills MII PHY anyway.
>> Fine with me, but I'm worried people won't update nvramrc.
>>
> ...
>> But I have a problem with it, possibly due to my not-knowledge of Forth.
>> Compatible keep getting set to:
>> compatible "/builtin/etherne"
>
> I missed the encode-string.
>
> Matt, can you please add attached Forth script to Efika updates.
>
>
> Domen
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-20 19:02 ` Matt Sealey
@ 2007-08-21 5:49 ` Domen Puncer
0 siblings, 0 replies; 47+ messages in thread
From: Domen Puncer @ 2007-08-21 5:49 UTC (permalink / raw)
To: Matt Sealey; +Cc: Domen Puncer, linuxppc-embedded
On 20/08/07 20:02 +0100, Matt Sealey wrote:
> Are you sure this is correct for the Efika?
It works (tm).
>
> The MPC5200B manual makes a decent distinction between MII operation and
> straight MDIO?
Uh? From what I read MDIO are the lines of MII.
Domen
>
> --
> Matt Sealey <matt@genesi-usa.com>
> Genesi, Manager, Developer Relations
>
> Domen Puncer wrote:
> >On 20/08/07 10:31 +0200, Domen Puncer wrote:
> >>On 19/08/07 16:39 +0100, Matt Sealey wrote:
> >>>Domen,
> >>>
> >>>Do it in a Forth script, or in nvramrc (after probe-all). Don't clutter
> >>>Linux with more fixups. The Efika PHY isn't going to change to something
> >>>else and it's a bog standard no-frills MII PHY anyway.
> >>Fine with me, but I'm worried people won't update nvramrc.
> >>
> >...
> >>But I have a problem with it, possibly due to my not-knowledge of Forth.
> >>Compatible keep getting set to:
> >> compatible "/builtin/etherne"
> >
> >I missed the encode-string.
> >
> >Matt, can you please add attached Forth script to Efika updates.
> >
> >
> > Domen
^ permalink raw reply [flat|nested] 47+ messages in thread
* [RFC PATCH v0.2] net driver: mpc52xx fec
2007-08-10 9:51 [RFC PATCH v0.1] net driver: mpc52xx fec Domen Puncer
2007-08-10 13:02 ` Arnaldo Carvalho de Melo
2007-08-18 10:06 ` Domen Puncer
@ 2007-09-02 7:41 ` Domen Puncer
2007-09-03 15:57 ` Grant Likely
2007-10-02 12:49 ` [RFC PATCH v0.2] net driver: mpc52xx fec Sascha Hauer
2007-09-27 17:07 ` [RFC PATCH v0.1] " Juergen Beisert
3 siblings, 2 replies; 47+ messages in thread
From: Domen Puncer @ 2007-09-02 7:41 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: netdev
Hi!
new in this version:
- fixed stuff that was commented on.
- added 7-wire support (compile at least, if someone has the hardware,
please test!)
- ethtool support
(this obsoletes Sylvain's patch that's floating around:
0008-drivers-net-Add-support-for-Freescale-MPC5200-SoC-i.patch)
If there are no objections, I would like this to be merged after
bestcomm (mpc52xx dma engine) patches hit mainline, and that will
hopefully be at the beginning of the 2.6.24 merge window.
--
Driver for ethernet on mpc5200/mpc5200b SoCs (FEC).
Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
---
arch/powerpc/boot/dts/lite5200b.dts | 18
arch/powerpc/sysdev/bestcomm/fec.h | 15
drivers/net/Kconfig | 1
drivers/net/Makefile | 1
drivers/net/fec_mpc52xx/Kconfig | 25
drivers/net/fec_mpc52xx/Makefile | 7
drivers/net/fec_mpc52xx/fec.c | 1127 ++++++++++++++++++++++++++++++++++++
drivers/net/fec_mpc52xx/fec.h | 329 ++++++++++
drivers/net/fec_mpc52xx/fec_phy.c | 238 +++++++
9 files changed, 1759 insertions(+), 2 deletions(-)
Index: linux.git/drivers/net/Kconfig
===================================================================
--- linux.git.orig/drivers/net/Kconfig
+++ linux.git/drivers/net/Kconfig
@@ -1956,6 +1956,7 @@ config NE_H8300
controller on the Renesas H8/300 processor.
source "drivers/net/fec_8xx/Kconfig"
+source "drivers/net/fec_mpc52xx/Kconfig"
source "drivers/net/fs_enet/Kconfig"
endif # NET_ETHERNET
Index: linux.git/drivers/net/Makefile
===================================================================
--- linux.git.orig/drivers/net/Makefile
+++ linux.git/drivers/net/Makefile
@@ -204,6 +204,7 @@ obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/
obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
obj-$(CONFIG_MLX4_CORE) += mlx4/
Index: linux.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================
--- linux.git.orig/arch/powerpc/boot/dts/lite5200b.dts
+++ linux.git/arch/powerpc/boot/dts/lite5200b.dts
@@ -306,10 +306,26 @@
ethernet@3000 {
device_type = "network";
compatible = "mpc5200b-fec\0mpc5200-fec";
- reg = <3000 800>;
+ reg = <3000 400>;
mac-address = [ 02 03 04 05 06 07 ]; // Bad!
interrupts = <2 5 0>;
interrupt-parent = <&mpc5200_pic>;
+ phy-handle = <&phy0>;
+ };
+
+ mdio@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "mdio";
+ compatible = "mpc5200b-fec-phy";
+ reg = <3000 400>; // fec range, since we need to setup fec interrupts
+ interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
+ interrupt-parent = <&mpc5200_pic>;
+
+ phy0:ethernet-phy@0 {
+ device_type = "ethernet-phy";
+ reg = <0>;
+ };
};
ata@3a00 {
Index: linux.git/arch/powerpc/sysdev/bestcomm/fec.h
===================================================================
--- linux.git.orig/arch/powerpc/sysdev/bestcomm/fec.h
+++ linux.git/arch/powerpc/sysdev/bestcomm/fec.h
@@ -21,7 +21,20 @@ struct bcom_fec_bd {
};
#define BCOM_FEC_TX_BD_TFD 0x08000000ul /* transmit frame done */
-#define BCOM_FEC_TX_BD_INT 0x04000000ul /* interrupt */
+#define BCOM_FEC_TX_BD_TC 0x04000000ul /* transmit CRC */
+#define BCOM_FEC_TX_BD_ABC 0x02000000ul /* append bad CRC */
+
+#define BCOM_FEC_RX_BD_L 0x08000000ul /* buffer is last in frame */
+#define BCOM_FEC_RX_BD_BC 0x00800000ul /* DA is broadcast */
+#define BCOM_FEC_RX_BD_MC 0x00400000ul /* DA is multicast and not broadcast */
+#define BCOM_FEC_RX_BD_LG 0x00200000ul /* Rx frame length violation */
+#define BCOM_FEC_RX_BD_NO 0x00100000ul /* Rx non-octet aligned frame */
+#define BCOM_FEC_RX_BD_CR 0x00040000ul /* Rx CRC error */
+#define BCOM_FEC_RX_BD_OV 0x00020000ul /* overrun */
+#define BCOM_FEC_RX_BD_TR 0x00010000ul /* Rx frame truncated */
+#define BCOM_FEC_RX_BD_LEN_MASK 0x000007fful /* mask for length of received frame */
+#define BCOM_FEC_RX_BD_ERRORS (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \
+ BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR)
extern struct bcom_task *
Index: linux.git/drivers/net/fec_mpc52xx/Kconfig
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx/Kconfig
@@ -0,0 +1,25 @@
+menu "MPC5200 Networking Options"
+ depends PPC_MPC52xx && NET_ETHERNET
+
+config FEC_MPC52xx
+ tristate "FEC Ethernet"
+ depends on NET_ETHERNET
+ select PPC_BESTCOMM
+ select PPC_BESTCOMM_FEC
+ select CRC32
+ ---help---
+ This option enables support for the MPC5200's on-chip
+ Fast Ethernet Controller
+
+config FEC_MPC52xx_MDIO
+ bool "Use external Ethernet MII PHY"
+ depends on FEC_MPC52xx
+ select PHYLIB
+ default y
+ ---help---
+ The MPC5200's FEC can connect to the Ethernet either with
+ an external MII PHY chip or 10 Mbps 7-wire interface
+ (Motorola? industry standard).
+ If your board uses an external PHY, say y, else n.
+
+endmenu
Index: linux.git/drivers/net/fec_mpc52xx/Makefile
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
+
+fec_mpc52xx-objs := fec.o
+
+ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
+fec_mpc52xx-objs += fec_phy.o
+endif
Index: linux.git/drivers/net/fec_mpc52xx/fec.c
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx/fec.c
@@ -0,0 +1,1127 @@
+/*
+ * drivers/drivers/net/fec_mpc52xx/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
+ * now maintained by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/hardirq.h>
+#include <linux/delay.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/mpc52xx.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/fec.h>
+
+#include "fec.h"
+
+#define DRIVER_NAME "mpc52xx-fec"
+
+static irqreturn_t fec_interrupt(int, void *);
+static irqreturn_t fec_rx_interrupt(int, void *);
+static irqreturn_t fec_tx_interrupt(int, void *);
+static struct net_device_stats *fec_get_stats(struct net_device *);
+static void fec_set_multicast_list(struct net_device *dev);
+static void fec_hw_init(struct net_device *dev);
+static void fec_stop(struct net_device *dev);
+static void fec_start(struct net_device *dev);
+static void fec_reset(struct net_device *dev);
+
+static u8 mpc52xx_fec_mac_addr[6];
+static const u8 null_mac[6];
+
+static void fec_tx_timeout(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ dev_warn(&dev->dev, "transmit timed out\n");
+
+ fec_reset(dev);
+
+ priv->stats.tx_errors++;
+
+ if (!priv->tx_full)
+ netif_wake_queue(dev);
+}
+
+static void fec_set_paddr(struct net_device *dev, u8 *mac)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->paddr1, *(u32 *)(&mac[0]));
+ out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
+}
+
+static void fec_get_paddr(struct net_device *dev, u8 *mac)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ *(u32 *)(&mac[0]) = in_be32(&fec->paddr1);
+ *(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
+}
+
+static int fec_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct sockaddr *sock = addr;
+
+ memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
+
+ fec_set_paddr(dev, sock->sa_data);
+ return 0;
+}
+
+static void fec_free_rx_buffers(struct bcom_task *s)
+{
+ struct sk_buff *skb;
+
+ while (!bcom_queue_empty(s)) {
+ skb = bcom_retrieve_buffer(s, NULL, NULL);
+ kfree_skb(skb);
+ }
+}
+
+static int fec_alloc_rx_buffers(struct bcom_task *rxtsk)
+{
+ while (!bcom_queue_full(rxtsk)) {
+ struct sk_buff *skb;
+ struct bcom_fec_bd *bd;
+
+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+ if (skb == NULL)
+ return -EAGAIN;
+
+ /* zero out the initial receive buffers to aid debugging */
+ memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
+
+ bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = virt_to_phys(skb->data);
+
+ bcom_submit_next_buffer(rxtsk, skb);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+/* based on generic_adjust_link from fs_enet-main.c */
+static void fec_adjust_link(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ if (phydev->link != PHY_DOWN) {
+ if (phydev->duplex != priv->duplex) {
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rcntrl;
+ u32 tcntrl;
+
+ new_state = 1;
+ priv->duplex = phydev->duplex;
+
+ rcntrl = in_be32(&fec->r_cntrl);
+ tcntrl = in_be32(&fec->x_cntrl);
+
+ rcntrl &= ~FEC_RCNTRL_DRT;
+ tcntrl &= ~FEC_TCNTRL_FDEN;
+ if (phydev->duplex == DUPLEX_FULL)
+ tcntrl |= FEC_TCNTRL_FDEN; /* FD enable */
+ else
+ rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
+
+ out_be32(&fec->r_cntrl, rcntrl);
+ out_be32(&fec->x_cntrl, tcntrl);
+ }
+
+ if (phydev->speed != priv->speed) {
+ new_state = 1;
+ priv->speed = phydev->speed;
+ }
+
+ if (priv->link == PHY_DOWN) {
+ new_state = 1;
+ priv->link = phydev->link;
+ netif_schedule(dev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+
+ } else if (priv->link) {
+ new_state = 1;
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ }
+
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+}
+
+static int fec_init_phy(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[BUS_ID_SIZE];
+
+ struct device_node *dn, *phy_dn;
+ unsigned int phy_addr;
+ const phandle *ph;
+ const unsigned int *prop;
+ struct resource res;
+ int ret;
+
+ dn = priv->ofdev->node;
+ ph = of_get_property(dn, "phy-handle", NULL);
+ if (!ph) {
+ dev_err(&dev->dev, "can't find \"phy-handle\" in device tree\n");
+ return -ENODEV;
+ }
+ phy_dn = of_find_node_by_phandle(*ph);
+
+ prop = of_get_property(phy_dn, "reg", NULL);
+ ret = of_address_to_resource(phy_dn->parent, 0, &res);
+ if (ret) {
+ dev_err(&dev->dev, "of_address_to_resource failed\n");
+ return ret;
+ }
+
+ phy_addr = *prop;
+ of_node_put(phy_dn);
+
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, res.start, phy_addr);
+
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+
+ phydev = phy_connect(dev, phy_id, &fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ dev_err(&dev->dev, "phy_connect failed\n");
+ return PTR_ERR(phydev);
+ }
+ dev_info(&dev->dev, "attached phy %i to driver %s\n",
+ phydev->addr, phydev->drv->name);
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+static int fec_phy_start(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ int err;
+
+ err = fec_init_phy(dev);
+ if (err) {
+ dev_err(&dev->dev, "fec_init_phy failed\n");
+ return err;
+ }
+
+ /* reset phy - this also wakes it from PDOWN */
+ phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(priv->phydev);
+
+ return 0;
+}
+
+static void fec_phy_stop(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ phy_disconnect(priv->phydev);
+ /* power down phy */
+ phy_stop(priv->phydev);
+ phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
+}
+
+static int fec_phy_mii_ioctl(struct fec_priv *priv,
+ struct mii_ioctl_data *mii_data, int cmd)
+{
+ return phy_mii_ioctl(priv->phydev, mii_data, cmd);
+}
+
+static void fec_phy_hw_init(struct fec_priv *priv)
+{
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->mii_speed, priv->phy_speed);
+ out_be32(&fec->imask, in_be32(&fec->imask) | FEC_IMASK_MII);
+}
+#else
+static inline int fec_phy_start(struct net_device *dev) { return 0; }
+static inline void fec_phy_stop(struct net_device *dev) { }
+static inline int fec_phy_mii_ioctl(struct fec_priv *priv,
+ struct mii_ioctl_data *mii_data, int cmd) { return -ENOTSUPP; }
+static inline void fec_phy_hw_init(struct fec_priv *priv) { }
+#endif
+
+static int fec_open(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ int err = -EBUSY;
+
+ if (request_irq(dev->irq, &fec_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ DRIVER_NAME "_ctrl", dev)) {
+ dev_err(&dev->dev, "ctrl interrupt request failed\n");
+ goto out;
+ }
+ if (request_irq(priv->r_irq, &fec_rx_interrupt, IRQF_DISABLED,
+ DRIVER_NAME "_rx", dev)) {
+ dev_err(&dev->dev, "rx interrupt request failed\n");
+ goto free_ctrl_irq;
+ }
+ if (request_irq(priv->t_irq, &fec_tx_interrupt, IRQF_DISABLED,
+ DRIVER_NAME "_tx", dev)) {
+ dev_err(&dev->dev, "tx interrupt request failed\n");
+ goto free_2irqs;
+ }
+
+ bcom_fec_rx_reset(priv->rx_dmatsk);
+ bcom_fec_tx_reset(priv->tx_dmatsk);
+
+ err = fec_alloc_rx_buffers(priv->rx_dmatsk);
+ if (err) {
+ dev_err(&dev->dev, "fec_alloc_rx_buffers failed\n");
+ goto free_irqs;
+ }
+
+ err = fec_phy_start(dev);
+ if (err)
+ goto free_skbs;
+
+ bcom_enable(priv->rx_dmatsk);
+ bcom_enable(priv->tx_dmatsk);
+
+ fec_start(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+
+ free_skbs:
+ fec_free_rx_buffers(priv->rx_dmatsk);
+
+ free_irqs:
+ free_irq(priv->t_irq, dev);
+ free_2irqs:
+ free_irq(priv->r_irq, dev);
+ free_ctrl_irq:
+ free_irq(dev->irq, dev);
+ out:
+
+ return err;
+}
+
+static int fec_close(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+
+ fec_stop(dev);
+
+ fec_free_rx_buffers(priv->rx_dmatsk);
+
+ free_irq(dev->irq, dev);
+ free_irq(priv->r_irq, dev);
+ free_irq(priv->t_irq, dev);
+
+ fec_phy_stop(dev);
+
+ return 0;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct bcom_fec_bd *bd;
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ if (net_ratelimit())
+ dev_err(&dev->dev, "transmit queue overrun\n");
+ return 1;
+ }
+
+ spin_lock_irq(&priv->lock);
+ dev->trans_start = jiffies;
+
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->tx_dmatsk);
+
+ bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC;
+ bd->skb_pa = virt_to_phys(skb->data);
+
+ bcom_submit_next_buffer(priv->tx_dmatsk, skb);
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ priv->tx_full = 1;
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irq(&priv->lock);
+
+ return 0;
+}
+
+/* This handles BestComm transmit task interrupts
+ */
+static irqreturn_t fec_tx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct fec_priv *priv = netdev_priv(dev);
+
+ spin_lock(&priv->lock);
+
+ while (bcom_buffer_done(priv->tx_dmatsk)) {
+ struct sk_buff *skb;
+ skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, NULL);
+
+ priv->tx_full = 0;
+ dev_kfree_skb_irq(skb);
+ }
+
+ if (netif_queue_stopped(dev) && !priv->tx_full)
+ netif_wake_queue(dev);
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct fec_priv *priv = netdev_priv(dev);
+
+ while (bcom_buffer_done(priv->rx_dmatsk)) {
+ struct sk_buff *skb;
+ struct sk_buff *rskb;
+ struct bcom_fec_bd *bd;
+ u32 status;
+
+ rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, NULL);
+
+ /* Test for errors in received frame */
+ if (status & BCOM_FEC_RX_BD_ERRORS) {
+ /* Drop packet and reuse the buffer */
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = virt_to_phys(rskb->data);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
+
+ priv->stats.rx_dropped++;
+
+ continue;
+ }
+
+ /* skbs are allocated on open, so now we allocate a new one,
+ * and remove the old (with the packet) */
+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+ if (skb) {
+ /* Process the received skb */
+ int length = status & BCOM_FEC_RX_BD_LEN_MASK;
+
+ skb_put(rskb, length - 4); /* length without CRC32 */
+
+ rskb->dev = dev;
+ rskb->protocol = eth_type_trans(rskb, dev);
+
+ netif_rx(rskb);
+ dev->last_rx = jiffies;
+ } else {
+ /* Can't get a new one : reuse the same & drop pkt */
+ dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
+ priv->stats.rx_dropped++;
+
+ skb = rskb;
+ }
+
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = virt_to_phys(skb->data);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, skb);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 ievent;
+
+ ievent = in_be32(&fec->ievent);
+
+ ievent &= ~FEC_IEVENT_MII; /* mii is handled separately */
+ if (!ievent)
+ return IRQ_NONE;
+
+ out_be32(&fec->ievent, ievent); /* clear pending events */
+
+ if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+ if (ievent & ~FEC_IEVENT_TFINT)
+ dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
+ return IRQ_HANDLED;
+ }
+
+ if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
+ if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+
+ fec_reset(dev);
+
+ netif_wake_queue(dev);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &priv->stats;
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+ stats->rx_packets = in_be32(&fec->rmon_r_packets);
+ stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
+ in_be32(&fec->rmon_r_undersize) +
+ in_be32(&fec->rmon_r_oversize) +
+ in_be32(&fec->rmon_r_frag) +
+ in_be32(&fec->rmon_r_jab);
+
+ stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+ stats->tx_packets = in_be32(&fec->rmon_t_packets);
+ stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
+ in_be32(&fec->rmon_t_undersize) +
+ in_be32(&fec->rmon_t_oversize) +
+ in_be32(&fec->rmon_t_frag) +
+ in_be32(&fec->rmon_t_jab);
+
+ stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
+ stats->collisions = in_be32(&fec->rmon_t_col);
+
+ /* detailed rx_errors: */
+ stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
+ + in_be32(&fec->rmon_r_oversize)
+ + in_be32(&fec->rmon_r_frag)
+ + in_be32(&fec->rmon_r_jab);
+ stats->rx_over_errors = in_be32(&fec->r_macerr);
+ stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
+ stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
+ stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
+ stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
+
+ /* detailed tx_errors: */
+ stats->tx_aborted_errors = 0;
+ stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
+ stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
+ stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
+ stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
+
+ return stats;
+}
+
+/*
+ * Read MIB counters in order to reset them,
+ * then zero all the stats fields in memory
+ */
+static void fec_reset_stats(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->mib_control, FEC_MIB_DISABLE);
+ memset_io(&fec->rmon_t_drop, 0, (__force u32)&fec->reserved10 -
+ (__force u32)&fec->rmon_t_drop);
+ out_be32(&fec->mib_control, 0);
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void fec_set_multicast_list(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rx_control;
+
+ rx_control = in_be32(&fec->r_cntrl);
+
+ if (dev->flags & IFF_PROMISC) {
+ rx_control |= FEC_RCNTRL_PROM;
+ out_be32(&fec->r_cntrl, rx_control);
+ } else {
+ rx_control &= ~FEC_RCNTRL_PROM;
+ out_be32(&fec->r_cntrl, rx_control);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ out_be32(&fec->gaddr1, 0xffffffff);
+ out_be32(&fec->gaddr2, 0xffffffff);
+ } else {
+ u32 crc;
+ int i;
+ struct dev_mc_list *dmi;
+ u32 gaddr1 = 0x00000000;
+ u32 gaddr2 = 0x00000000;
+
+ dmi = dev->mc_list;
+ for (i=0; i<dev->mc_count; i++) {
+ crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
+ if (crc >= 32)
+ gaddr1 |= 1 << (crc-32);
+ else
+ gaddr2 |= 1 << crc;
+ dmi = dmi->next;
+ }
+ out_be32(&fec->gaddr1, gaddr1);
+ out_be32(&fec->gaddr2, gaddr2);
+ }
+ }
+}
+
+static void __init fec_str2mac(char *str, unsigned char *mac)
+{
+ int i;
+ u64 val64;
+
+ val64 = simple_strtoull(str, NULL, 16);
+
+ for (i = 0; i < 6; i++)
+ mac[5-i] = val64 >> (i*8);
+}
+
+static int __init mpc52xx_fec_mac_setup(char *mac_address)
+{
+ fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
+ return 0;
+}
+
+__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
+
+/**
+ * fec_hw_init
+ * @dev: network device
+ *
+ * Setup various hardware setting, only needed once on start
+ */
+static void fec_hw_init(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ int i;
+
+ /* Whack a reset. We should wait for this. */
+ out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
+ for (i = 0; i < FEC_RESET_DELAY; ++i) {
+ if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
+ break;
+ udelay(1);
+ }
+ if (i == FEC_RESET_DELAY)
+ dev_err(&dev->dev, "FEC Reset timeout!\n");
+
+ /* set pause to 0x20 frames */
+ out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20);
+
+ /* high service request will be deasserted when there's < 7 bytes in fifo
+ * low service request will be deasserted when there's < 4*7 bytes in fifo
+ */
+ out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+ out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+
+ /* alarm when <= x bytes in FIFO */
+ out_be32(&fec->rfifo_alarm, 0x0000030c);
+ out_be32(&fec->tfifo_alarm, 0x00000100);
+
+ /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */
+ out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B);
+
+ /* enable crc generation */
+ out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC);
+ out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */
+ out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */
+
+ /* set phy speed and enable MII interrupt
+ * this can't be done in phy driver, since it needs to be called
+ * before fec stuff (even on resume) */
+ fec_phy_hw_init(priv);
+}
+
+/**
+ * fec_start
+ * @dev: network device
+ *
+ * This function is called to start or restart the FEC during a link
+ * change. This happens on fifo errors or when switching between half
+ * and full duplex.
+ */
+static void fec_start(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rcntrl;
+ u32 tcntrl;
+ u32 tmp;
+
+ /* clear sticky error bits */
+ tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
+ out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
+ out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
+
+ /* FIFOs will reset on fec_enable */
+ out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
+
+ /* Set station address. */
+ fec_set_paddr(dev, dev->dev_addr);
+
+ fec_set_multicast_list(dev);
+
+ /* set max frame len, enable flow control, select mii mode */
+ rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
+ rcntrl |= FEC_RCNTRL_FCE;
+ rcntrl |= MII_RCNTL_MODE;
+ if (priv->duplex == DUPLEX_FULL)
+ tcntrl = FEC_TCNTRL_FDEN; /* FD enable */
+ else {
+ rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
+ tcntrl = 0;
+ }
+ out_be32(&fec->r_cntrl, rcntrl);
+ out_be32(&fec->x_cntrl, tcntrl);
+
+ /* Clear any outstanding interrupt. */
+ out_be32(&fec->ievent, 0xffffffff);
+
+ /* Enable interrupts we wish to service. */
+ out_be32(&fec->imask, FEC_IMASK_ENABLE);
+
+ /* And last, enable the transmit and receive processing. */
+ out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->r_des_active, 0x01000000);
+
+ priv->tx_full = 0;
+}
+
+/**
+ * fec_stop
+ * @dev: network device
+ *
+ * stop all activity on fec and empty dma buffers
+ */
+static void fec_stop(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ unsigned long timeout;
+
+ /* disable all but MII interrupt */
+ out_be32(&fec->imask, in_be32(&fec->imask) & FEC_IMASK_MII);
+
+ /* Disable the rx task. */
+ bcom_disable(priv->rx_dmatsk);
+
+ /* Wait for tx queue to drain, but only if we're in process context */
+ if (!in_interrupt()) {
+ timeout = jiffies + msecs_to_jiffies(2000);
+ while (time_before(jiffies, timeout) &&
+ !bcom_queue_empty(priv->tx_dmatsk))
+ msleep(100);
+
+ if (time_after_eq(jiffies, timeout))
+ dev_err(&dev->dev, "queues didn't drain\n");
+#if 1
+ if (time_after_eq(jiffies, timeout)) {
+ dev_err(&dev->dev, " tx: index: %i, outdex: %i\n",
+ priv->tx_dmatsk->index,
+ priv->tx_dmatsk->outdex);
+ dev_err(&dev->dev, " rx: index: %i, outdex: %i\n",
+ priv->rx_dmatsk->index,
+ priv->rx_dmatsk->outdex);
+ }
+#endif
+ }
+
+ bcom_disable(priv->tx_dmatsk);
+
+ /* Stop FEC */
+ out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
+
+ return;
+}
+
+/* reset fec and bestcomm tasks */
+static void fec_reset(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ fec_stop(dev);
+
+ out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status));
+ out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO);
+
+ fec_free_rx_buffers(priv->rx_dmatsk);
+
+ fec_hw_init(dev);
+
+ phy_stop(priv->phydev);
+ phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(priv->phydev);
+
+ bcom_fec_rx_reset(priv->rx_dmatsk);
+ bcom_fec_tx_reset(priv->tx_dmatsk);
+
+ fec_alloc_rx_buffers(priv->rx_dmatsk);
+
+ fec_start(dev);
+}
+
+
+/* ethtool interface */
+static void fec_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRIVER_NAME);
+}
+
+static int fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static u32 fec_get_msglevel(struct net_device *dev)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void fec_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+ priv->msg_enable = level;
+}
+
+static const struct ethtool_ops fec_ethtool_ops = {
+ .get_drvinfo = fec_get_drvinfo,
+ .get_settings = fec_get_settings,
+ .set_settings = fec_set_settings,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = fec_get_msglevel,
+ .set_msglevel = fec_set_msglevel,
+};
+
+
+static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct fec_priv *priv = netdev_priv(dev);
+
+ return fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
+}
+
+/* ======================================================================== */
+/* OF Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
+{
+ int rv;
+ struct net_device *ndev;
+ struct fec_priv *priv = NULL;
+ struct resource mem;
+
+ phys_addr_t rx_fifo;
+ phys_addr_t tx_fifo;
+
+ /* Get the ether ndev & it's private zone */
+ ndev = alloc_etherdev(sizeof(struct fec_priv));
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+
+ priv->ofdev = op;
+
+ /* Reserve FEC control zone */
+ rv = of_address_to_resource(op->node, 0, &mem);
+ if (rv) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Error while parsing device node resource\n" );
+ return rv;
+ }
+ if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) {
+ printk(KERN_ERR DRIVER_NAME
+ " - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",
+ (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
+ return -EBUSY;
+
+ /* Init ether ndev with what we have */
+ ndev->open = fec_open;
+ ndev->stop = fec_close;
+ ndev->hard_start_xmit = fec_hard_start_xmit;
+ ndev->do_ioctl = fec_ioctl;
+ ndev->ethtool_ops = &fec_ethtool_ops;
+ ndev->get_stats = fec_get_stats;
+ ndev->set_mac_address = fec_set_mac_address;
+ ndev->set_multicast_list = fec_set_multicast_list;
+ ndev->tx_timeout = fec_tx_timeout;
+ ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
+ ndev->flags &= ~IFF_RUNNING;
+ ndev->base_addr = mem.start;
+
+ priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
+
+ spin_lock_init(&priv->lock);
+
+ /* ioremap the zones */
+ priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec));
+
+ if (!priv->fec) {
+ rv = -ENOMEM;
+ goto probe_error;
+ }
+
+ /* Bestcomm init */
+ rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data);
+ tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data);
+
+ priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE);
+ priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
+
+ if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
+ printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
+ rv = -ENOMEM;
+ goto probe_error;
+ }
+
+ /* Get the IRQ we need one by one */
+ /* Control */
+ ndev->irq = irq_of_parse_and_map(op->node, 0);
+
+ /* RX */
+ priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
+
+ /* TX */
+ priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
+
+ /* MAC address init */
+ if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
+ memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
+ else
+ fec_get_paddr(ndev, ndev->dev_addr);
+
+ /* Phy speed */
+ priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
+
+ priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
+ priv->duplex = DUPLEX_FULL;
+
+ /* Hardware init */
+ fec_hw_init(ndev);
+
+ fec_reset_stats(ndev);
+
+ /* Register the new network device */
+ rv = register_netdev(ndev);
+ if (rv < 0)
+ goto probe_error;
+
+ /* We're done ! */
+ dev_set_drvdata(&op->dev, ndev);
+
+ return 0;
+
+
+ /* Error handling - free everything that might be allocated */
+probe_error:
+
+ irq_dispose_mapping(ndev->irq);
+
+ if (priv->rx_dmatsk)
+ bcom_fec_rx_release(priv->rx_dmatsk);
+ if (priv->tx_dmatsk)
+ bcom_fec_tx_release(priv->tx_dmatsk);
+
+ if (priv->fec)
+ iounmap(priv->fec);
+
+ release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
+
+ free_netdev(ndev);
+
+ return rv;
+}
+
+static int
+mpc52xx_fec_remove(struct of_device *op)
+{
+ struct net_device *ndev;
+ struct fec_priv *priv;
+
+ ndev = dev_get_drvdata(&op->dev);
+ if (!ndev)
+ return 0;
+ priv = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ irq_dispose_mapping(ndev->irq);
+
+ bcom_fec_rx_release(priv->rx_dmatsk);
+ bcom_fec_tx_release(priv->tx_dmatsk);
+
+ iounmap(priv->fec);
+
+ release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
+
+ free_netdev(ndev);
+
+ dev_set_drvdata(&op->dev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ if (netif_running(dev))
+ fec_close(dev);
+
+ return 0;
+}
+
+static int mpc52xx_fec_of_resume(struct of_device *op)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ fec_hw_init(dev);
+ fec_reset_stats(dev);
+
+ if (netif_running(dev))
+ fec_open(dev);
+
+ return 0;
+}
+#endif
+
+static struct of_device_id mpc52xx_fec_match[] = {
+ {
+ .type = "network",
+ .compatible = "mpc5200-fec",
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
+
+static struct of_platform_driver mpc52xx_fec_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .match_table = mpc52xx_fec_match,
+ .probe = mpc52xx_fec_probe,
+ .remove = mpc52xx_fec_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_fec_of_suspend,
+ .resume = mpc52xx_fec_of_resume,
+#endif
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_fec_init(void)
+{
+ int ret;
+ ret = fec_mdio_init();
+ if (ret) {
+ printk(KERN_ERR DRIVER_NAME ": fec_mdio_init failed\n");
+ return ret;
+ }
+
+ return of_register_platform_driver(&mpc52xx_fec_driver);
+}
+
+static void __exit
+mpc52xx_fec_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_fec_driver);
+ fec_mdio_exit();
+}
+
+
+module_init(mpc52xx_fec_init);
+module_exit(mpc52xx_fec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
+
Index: linux.git/drivers/net/fec_mpc52xx/fec.h
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx/fec.h
@@ -0,0 +1,329 @@
+/*
+ * drivers/drivers/net/fec_mpc52xx/fec.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
+#define __DRIVERS_NET_MPC52XX_FEC_H__
+
+#include <linux/phy.h>
+
+/* Tunable constant */
+/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
+#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
+#define FEC_RX_NUM_BD 64
+#define FEC_TX_NUM_BD 64
+
+#define FEC_RESET_DELAY 50 /* uS */
+
+#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
+
+struct fec_priv {
+ int duplex;
+ int tx_full;
+ int r_irq;
+ int t_irq;
+ struct mpc52xx_fec __iomem *fec;
+ struct bcom_task *rx_dmatsk;
+ struct bcom_task *tx_dmatsk;
+ spinlock_t lock;
+ struct net_device_stats stats;
+ int msg_enable;
+ struct of_device *ofdev;
+ uint phy_speed;
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+ struct phy_device *phydev;
+ enum phy_state link;
+ int speed;
+#endif /* CONFIG_FEC_MPC52xx_MDIO */
+};
+
+
+/* ======================================================================== */
+/* Hardware register sets & bits */
+/* ======================================================================== */
+
+struct mpc52xx_fec {
+ u32 fec_id; /* FEC + 0x000 */
+ u32 ievent; /* FEC + 0x004 */
+ u32 imask; /* FEC + 0x008 */
+
+ u32 reserved0[1]; /* FEC + 0x00C */
+ u32 r_des_active; /* FEC + 0x010 */
+ u32 x_des_active; /* FEC + 0x014 */
+ u32 r_des_active_cl; /* FEC + 0x018 */
+ u32 x_des_active_cl; /* FEC + 0x01C */
+ u32 ivent_set; /* FEC + 0x020 */
+ u32 ecntrl; /* FEC + 0x024 */
+
+ u32 reserved1[6]; /* FEC + 0x028-03C */
+ u32 mii_data; /* FEC + 0x040 */
+ u32 mii_speed; /* FEC + 0x044 */
+ u32 mii_status; /* FEC + 0x048 */
+
+ u32 reserved2[5]; /* FEC + 0x04C-05C */
+ u32 mib_data; /* FEC + 0x060 */
+ u32 mib_control; /* FEC + 0x064 */
+
+ u32 reserved3[6]; /* FEC + 0x068-7C */
+ u32 r_activate; /* FEC + 0x080 */
+ u32 r_cntrl; /* FEC + 0x084 */
+ u32 r_hash; /* FEC + 0x088 */
+ u32 r_data; /* FEC + 0x08C */
+ u32 ar_done; /* FEC + 0x090 */
+ u32 r_test; /* FEC + 0x094 */
+ u32 r_mib; /* FEC + 0x098 */
+ u32 r_da_low; /* FEC + 0x09C */
+ u32 r_da_high; /* FEC + 0x0A0 */
+
+ u32 reserved4[7]; /* FEC + 0x0A4-0BC */
+ u32 x_activate; /* FEC + 0x0C0 */
+ u32 x_cntrl; /* FEC + 0x0C4 */
+ u32 backoff; /* FEC + 0x0C8 */
+ u32 x_data; /* FEC + 0x0CC */
+ u32 x_status; /* FEC + 0x0D0 */
+ u32 x_mib; /* FEC + 0x0D4 */
+ u32 x_test; /* FEC + 0x0D8 */
+ u32 fdxfc_da1; /* FEC + 0x0DC */
+ u32 fdxfc_da2; /* FEC + 0x0E0 */
+ u32 paddr1; /* FEC + 0x0E4 */
+ u32 paddr2; /* FEC + 0x0E8 */
+ u32 op_pause; /* FEC + 0x0EC */
+
+ u32 reserved5[4]; /* FEC + 0x0F0-0FC */
+ u32 instr_reg; /* FEC + 0x100 */
+ u32 context_reg; /* FEC + 0x104 */
+ u32 test_cntrl; /* FEC + 0x108 */
+ u32 acc_reg; /* FEC + 0x10C */
+ u32 ones; /* FEC + 0x110 */
+ u32 zeros; /* FEC + 0x114 */
+ u32 iaddr1; /* FEC + 0x118 */
+ u32 iaddr2; /* FEC + 0x11C */
+ u32 gaddr1; /* FEC + 0x120 */
+ u32 gaddr2; /* FEC + 0x124 */
+ u32 random; /* FEC + 0x128 */
+ u32 rand1; /* FEC + 0x12C */
+ u32 tmp; /* FEC + 0x130 */
+
+ u32 reserved6[3]; /* FEC + 0x134-13C */
+ u32 fifo_id; /* FEC + 0x140 */
+ u32 x_wmrk; /* FEC + 0x144 */
+ u32 fcntrl; /* FEC + 0x148 */
+ u32 r_bound; /* FEC + 0x14C */
+ u32 r_fstart; /* FEC + 0x150 */
+ u32 r_count; /* FEC + 0x154 */
+ u32 r_lag; /* FEC + 0x158 */
+ u32 r_read; /* FEC + 0x15C */
+ u32 r_write; /* FEC + 0x160 */
+ u32 x_count; /* FEC + 0x164 */
+ u32 x_lag; /* FEC + 0x168 */
+ u32 x_retry; /* FEC + 0x16C */
+ u32 x_write; /* FEC + 0x170 */
+ u32 x_read; /* FEC + 0x174 */
+
+ u32 reserved7[2]; /* FEC + 0x178-17C */
+ u32 fm_cntrl; /* FEC + 0x180 */
+ u32 rfifo_data; /* FEC + 0x184 */
+ u32 rfifo_status; /* FEC + 0x188 */
+ u32 rfifo_cntrl; /* FEC + 0x18C */
+ u32 rfifo_lrf_ptr; /* FEC + 0x190 */
+ u32 rfifo_lwf_ptr; /* FEC + 0x194 */
+ u32 rfifo_alarm; /* FEC + 0x198 */
+ u32 rfifo_rdptr; /* FEC + 0x19C */
+ u32 rfifo_wrptr; /* FEC + 0x1A0 */
+ u32 tfifo_data; /* FEC + 0x1A4 */
+ u32 tfifo_status; /* FEC + 0x1A8 */
+ u32 tfifo_cntrl; /* FEC + 0x1AC */
+ u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */
+ u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */
+ u32 tfifo_alarm; /* FEC + 0x1B8 */
+ u32 tfifo_rdptr; /* FEC + 0x1BC */
+ u32 tfifo_wrptr; /* FEC + 0x1C0 */
+
+ u32 reset_cntrl; /* FEC + 0x1C4 */
+ u32 xmit_fsm; /* FEC + 0x1C8 */
+
+ u32 reserved8[3]; /* FEC + 0x1CC-1D4 */
+ u32 rdes_data0; /* FEC + 0x1D8 */
+ u32 rdes_data1; /* FEC + 0x1DC */
+ u32 r_length; /* FEC + 0x1E0 */
+ u32 x_length; /* FEC + 0x1E4 */
+ u32 x_addr; /* FEC + 0x1E8 */
+ u32 cdes_data; /* FEC + 0x1EC */
+ u32 status; /* FEC + 0x1F0 */
+ u32 dma_control; /* FEC + 0x1F4 */
+ u32 des_cmnd; /* FEC + 0x1F8 */
+ u32 data; /* FEC + 0x1FC */
+
+ u32 rmon_t_drop; /* FEC + 0x200 */
+ u32 rmon_t_packets; /* FEC + 0x204 */
+ u32 rmon_t_bc_pkt; /* FEC + 0x208 */
+ u32 rmon_t_mc_pkt; /* FEC + 0x20C */
+ u32 rmon_t_crc_align; /* FEC + 0x210 */
+ u32 rmon_t_undersize; /* FEC + 0x214 */
+ u32 rmon_t_oversize; /* FEC + 0x218 */
+ u32 rmon_t_frag; /* FEC + 0x21C */
+ u32 rmon_t_jab; /* FEC + 0x220 */
+ u32 rmon_t_col; /* FEC + 0x224 */
+ u32 rmon_t_p64; /* FEC + 0x228 */
+ u32 rmon_t_p65to127; /* FEC + 0x22C */
+ u32 rmon_t_p128to255; /* FEC + 0x230 */
+ u32 rmon_t_p256to511; /* FEC + 0x234 */
+ u32 rmon_t_p512to1023; /* FEC + 0x238 */
+ u32 rmon_t_p1024to2047; /* FEC + 0x23C */
+ u32 rmon_t_p_gte2048; /* FEC + 0x240 */
+ u32 rmon_t_octets; /* FEC + 0x244 */
+ u32 ieee_t_drop; /* FEC + 0x248 */
+ u32 ieee_t_frame_ok; /* FEC + 0x24C */
+ u32 ieee_t_1col; /* FEC + 0x250 */
+ u32 ieee_t_mcol; /* FEC + 0x254 */
+ u32 ieee_t_def; /* FEC + 0x258 */
+ u32 ieee_t_lcol; /* FEC + 0x25C */
+ u32 ieee_t_excol; /* FEC + 0x260 */
+ u32 ieee_t_macerr; /* FEC + 0x264 */
+ u32 ieee_t_cserr; /* FEC + 0x268 */
+ u32 ieee_t_sqe; /* FEC + 0x26C */
+ u32 t_fdxfc; /* FEC + 0x270 */
+ u32 ieee_t_octets_ok; /* FEC + 0x274 */
+
+ u32 reserved9[2]; /* FEC + 0x278-27C */
+ u32 rmon_r_drop; /* FEC + 0x280 */
+ u32 rmon_r_packets; /* FEC + 0x284 */
+ u32 rmon_r_bc_pkt; /* FEC + 0x288 */
+ u32 rmon_r_mc_pkt; /* FEC + 0x28C */
+ u32 rmon_r_crc_align; /* FEC + 0x290 */
+ u32 rmon_r_undersize; /* FEC + 0x294 */
+ u32 rmon_r_oversize; /* FEC + 0x298 */
+ u32 rmon_r_frag; /* FEC + 0x29C */
+ u32 rmon_r_jab; /* FEC + 0x2A0 */
+
+ u32 rmon_r_resvd_0; /* FEC + 0x2A4 */
+
+ u32 rmon_r_p64; /* FEC + 0x2A8 */
+ u32 rmon_r_p65to127; /* FEC + 0x2AC */
+ u32 rmon_r_p128to255; /* FEC + 0x2B0 */
+ u32 rmon_r_p256to511; /* FEC + 0x2B4 */
+ u32 rmon_r_p512to1023; /* FEC + 0x2B8 */
+ u32 rmon_r_p1024to2047; /* FEC + 0x2BC */
+ u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */
+ u32 rmon_r_octets; /* FEC + 0x2C4 */
+ u32 ieee_r_drop; /* FEC + 0x2C8 */
+ u32 ieee_r_frame_ok; /* FEC + 0x2CC */
+ u32 ieee_r_crc; /* FEC + 0x2D0 */
+ u32 ieee_r_align; /* FEC + 0x2D4 */
+ u32 r_macerr; /* FEC + 0x2D8 */
+ u32 r_fdxfc; /* FEC + 0x2DC */
+ u32 ieee_r_octets_ok; /* FEC + 0x2E0 */
+
+ u32 reserved10[7]; /* FEC + 0x2E4-2FC */
+
+ u32 reserved11[64]; /* FEC + 0x300-3FF */
+};
+
+#define FEC_MIB_DISABLE 0x80000000
+
+#define FEC_IEVENT_HBERR 0x80000000
+#define FEC_IEVENT_BABR 0x40000000
+#define FEC_IEVENT_BABT 0x20000000
+#define FEC_IEVENT_GRA 0x10000000
+#define FEC_IEVENT_TFINT 0x08000000
+#define FEC_IEVENT_MII 0x00800000
+#define FEC_IEVENT_LATE_COL 0x00200000
+#define FEC_IEVENT_COL_RETRY_LIM 0x00100000
+#define FEC_IEVENT_XFIFO_UN 0x00080000
+#define FEC_IEVENT_XFIFO_ERROR 0x00040000
+#define FEC_IEVENT_RFIFO_ERROR 0x00020000
+
+#define FEC_IMASK_HBERR 0x80000000
+#define FEC_IMASK_BABR 0x40000000
+#define FEC_IMASK_BABT 0x20000000
+#define FEC_IMASK_GRA 0x10000000
+#define FEC_IMASK_MII 0x00800000
+#define FEC_IMASK_LATE_COL 0x00200000
+#define FEC_IMASK_COL_RETRY_LIM 0x00100000
+#define FEC_IMASK_XFIFO_UN 0x00080000
+#define FEC_IMASK_XFIFO_ERROR 0x00040000
+#define FEC_IMASK_RFIFO_ERROR 0x00020000
+
+/* all but MII, which is enabled separately */
+#define FEC_IMASK_ENABLE (FEC_IMASK_HBERR | FEC_IMASK_BABR | \
+ FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_LATE_COL | \
+ FEC_IMASK_COL_RETRY_LIM | FEC_IMASK_XFIFO_UN | \
+ FEC_IMASK_XFIFO_ERROR | FEC_IMASK_RFIFO_ERROR)
+
+#define FEC_RCNTRL_MAX_FL_SHIFT 16
+#define FEC_RCNTRL_LOOP 0x01
+#define FEC_RCNTRL_DRT 0x02
+#define FEC_RCNTRL_MII_MODE 0x04
+#define FEC_RCNTRL_PROM 0x08
+#define FEC_RCNTRL_BC_REJ 0x10
+#define FEC_RCNTRL_FCE 0x20
+
+#define FEC_TCNTRL_GTS 0x00000001
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_TFC_PAUSE 0x00000008
+#define FEC_TCNTRL_RFC_PAUSE 0x00000010
+
+#define FEC_ECNTRL_RESET 0x00000001
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+
+#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */
+
+#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
+#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
+
+#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
+#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
+
+#define FEC_PADDR2_TYPE 0x8808
+
+#define FEC_OP_PAUSE_OPCODE 0x00010000
+
+#define FEC_FIFO_WMRK_256B 0x3
+
+#define FEC_FIFO_STATUS_ERR 0x00400000
+#define FEC_FIFO_STATUS_UF 0x00200000
+#define FEC_FIFO_STATUS_OF 0x00100000
+
+#define FEC_FIFO_CNTRL_FRAME 0x08000000
+#define FEC_FIFO_CNTRL_LTG_7 0x07000000
+
+#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000
+#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000
+
+#define FEC_XMIT_FSM_APPEND_CRC 0x02000000
+#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000
+
+
+#ifdef CONFIG_FEC_MPC52xx_MDIO /* 18-wire MII mode */
+
+#define MII_RCNTL_MODE FEC_RCNTRL_MII_MODE
+
+int __init fec_mdio_init(void);
+void __exit fec_mdio_exit(void);
+
+#else /* 7-wire 10 Mbps mode */
+
+#define MII_RCNTL_MODE 0
+
+static inline int __init fec_mdio_init(void) { return 0; }
+static inline void __exit fec_mdio_exit(void) { }
+
+#endif /* CONFIG_FEC_MPC52xx_MDIO */
+
+#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */
Index: linux.git/drivers/net/fec_mpc52xx/fec_phy.c
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx/fec_phy.c
@@ -0,0 +1,238 @@
+/*
+ * Driver for the MPC5200 Fast Ethernet Controller - PHY/MII part
+ *
+ * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include <asm/of_platform.h>
+#include "fec.h"
+
+struct fec_mdio_priv {
+ int completed;
+ wait_queue_head_t wq;
+ struct mpc52xx_fec __iomem *regs;
+ int irq;
+};
+
+static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct fec_mdio_priv *priv = bus->priv;
+ int tries = 100;
+
+ u32 request = FEC_MII_READ_FRAME;
+ request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, request);
+
+ /* wait for it to finish, this takes about 23 us on lite5200b */
+ while (priv->completed == 0 && tries--)
+ udelay(5);
+
+ priv->completed = 0;
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
+}
+
+static int fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
+{
+ struct fec_mdio_priv *priv = bus->priv;
+ u32 value = data;
+ int tries = 100;
+
+ value |= FEC_MII_WRITE_FRAME;
+ value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, value);
+
+ /* wait for request to finish */
+ while (priv->completed == 0 && tries--)
+ udelay(5);
+
+ priv->completed = 0;
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static irqreturn_t fec_mdio_interrupt(int irq, void *dev_id)
+{
+ struct fec_mdio_priv *priv = dev_id;
+ struct mpc52xx_fec __iomem *fec;
+ int ievent;
+
+ fec = priv->regs;
+ ievent = in_be32(&fec->ievent);
+
+ ievent &= FEC_IEVENT_MII;
+ if (!ievent)
+ return IRQ_NONE;
+
+ out_be32(&fec->ievent, ievent);
+
+ priv->completed = 1;
+ wake_up(&priv->wq);
+
+ return IRQ_HANDLED;
+}
+
+static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
+{
+ struct device *dev = &of->dev;
+ struct device_node *np = of->node;
+ struct device_node *child = NULL;
+ struct mii_bus *bus;
+ struct fec_mdio_priv *priv;
+ struct resource res = {};
+ int err;
+ int i;
+
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (bus == NULL)
+ return -ENOMEM;
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ bus->name = "mpc52xx MII bus";
+ bus->read = fec_mdio_read;
+ bus->write = fec_mdio_write;
+
+ /* setup irqs */
+ bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (bus->irq == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
+
+ while ((child = of_get_next_child(np, child)) != NULL) {
+ int irq = irq_of_parse_and_map(child, 0);
+ if (irq != NO_IRQ) {
+ const u32 *id = of_get_property(child, "reg", NULL);
+ bus->irq[*id] = irq;
+ }
+ }
+
+ /* setup registers */
+ err = of_address_to_resource(np, 0, &res);
+ if (err)
+ goto out_free;
+ priv->regs = ioremap(res.start, res.end - res.start + 1);
+ if (priv->regs == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ priv->irq = irq_of_parse_and_map(np, 0);
+ err = request_irq(priv->irq, &fec_mdio_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ "fec_mdio", priv);
+ if (err) {
+ printk(KERN_ERR "%s: interrupt request failed with %i\n", __func__, err);
+ goto out_unmap;
+ }
+
+ bus->id = res.start;
+ bus->priv = priv;
+
+ bus->dev = dev;
+ dev_set_drvdata(dev, bus);
+
+ init_waitqueue_head(&priv->wq);
+
+ /* set MII speed */
+ out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
+
+ /* enable MII interrupt */
+ out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
+
+ err = mdiobus_register(bus);
+ if (err)
+ goto out_free_irq;
+
+ return 0;
+
+ out_free_irq:
+ free_irq(priv->irq, dev);
+ irq_dispose_mapping(priv->irq);
+ out_unmap:
+ iounmap(priv->regs);
+ out_free:
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ if (bus->irq[i] != PHY_POLL)
+ irq_dispose_mapping(bus->irq[i]);
+ kfree(bus->irq);
+ kfree(priv);
+ kfree(bus);
+
+ return err;
+}
+
+static int fec_mdio_remove(struct of_device *of)
+{
+ struct device *dev = &of->dev;
+ struct mii_bus *bus = dev_get_drvdata(dev);
+ struct fec_mdio_priv *priv = bus->priv;
+ int i;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(dev, NULL);
+
+ free_irq(priv->irq, dev);
+ irq_dispose_mapping(priv->irq);
+ iounmap(priv->regs);
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ if (bus->irq[i])
+ irq_dispose_mapping(bus->irq[i]);
+ kfree(priv);
+ kfree(bus->irq);
+ kfree(bus);
+
+ return 0;
+}
+
+
+static struct of_device_id fec_mdio_match[] = {
+ {
+ .type = "mdio",
+ .compatible = "mpc5200b-fec-phy",
+ },
+ {},
+};
+
+static struct of_platform_driver fec_mdio_driver = {
+ .name = "mpc5200b-fec-phy",
+ .probe = fec_mdio_probe,
+ .remove = fec_mdio_remove,
+ .match_table = fec_mdio_match,
+};
+
+
+int __init fec_mdio_init(void)
+{
+ return of_register_platform_driver(&fec_mdio_driver);
+}
+
+void __exit fec_mdio_exit(void)
+{
+ of_unregister_platform_driver(&fec_mdio_driver);
+}
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-09-02 7:41 ` [RFC PATCH v0.2] " Domen Puncer
@ 2007-09-03 15:57 ` Grant Likely
2007-09-03 16:09 ` Jon Smirl
2007-09-15 12:14 ` Domen Puncer
2007-10-02 12:49 ` [RFC PATCH v0.2] net driver: mpc52xx fec Sascha Hauer
1 sibling, 2 replies; 47+ messages in thread
From: Grant Likely @ 2007-09-03 15:57 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
On 9/2/07, Domen Puncer <domen@coderock.org> wrote:
> Hi!
>
> new in this version:
> - fixed stuff that was commented on.
> - added 7-wire support (compile at least, if someone has the hardware,
> please test!)
> - ethtool support
Thanks for this work Domen, comments below...
This is a large patch, and it should be broken up into logical
changes. ie. split into dts changes, bestcomm changes, fec driver and
mdio driver. Easier to review that way. The bestcomm and dts changes
don't need to go to the netdev list.
> --- /dev/null
> +++ linux.git/drivers/net/fec_mpc52xx/Kconfig
> @@ -0,0 +1,25 @@
> +menu "MPC5200 Networking Options"
> + depends PPC_MPC52xx && NET_ETHERNET
> +
> +config FEC_MPC52xx
> + tristate "FEC Ethernet"
> + depends on NET_ETHERNET
> + select PPC_BESTCOMM
> + select PPC_BESTCOMM_FEC
> + select CRC32
> + ---help---
> + This option enables support for the MPC5200's on-chip
> + Fast Ethernet Controller
> +
> +config FEC_MPC52xx_MDIO
> + bool "Use external Ethernet MII PHY"
> + depends on FEC_MPC52xx
> + select PHYLIB
> + default y
> + ---help---
> + The MPC5200's FEC can connect to the Ethernet either with
> + an external MII PHY chip or 10 Mbps 7-wire interface
> + (Motorola? industry standard).
> + If your board uses an external PHY, say y, else n.
This option should change. Either build the MDIO driver into the FEC
driver unconditionally and drop this option, or make the MDIO driver
independent from the FEC driver (it does use the MDIO bus
infrastructure after all). Either way the FEC driver should detect
the phy type at runtime (possibly based on the presence/absence of a
phy-handle property) instead of being hard compiled. 5200 support is
now multiplatform after all.
If you drop the MDIO config option, then I'd also consider eliminating
driver/net/fec_mpc52xx/Kconfig entirely and rolling the single
MPC52xx_FEC option into drivers/net/Kconfig.
> +
> +endmenu
> Index: linux.git/drivers/net/fec_mpc52xx/Makefile
> ===================================================================
> --- /dev/null
> +++ linux.git/drivers/net/fec_mpc52xx/Makefile
> @@ -0,0 +1,7 @@
> +obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
> +
> +fec_mpc52xx-objs := fec.o
> +
> +ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
> +fec_mpc52xx-objs += fec_phy.o
> +endif
Hmm, is the phy driver separate or not? You've got the logic in place
to probe MDIO separately from the FEC driver, yet they are linked as a
single driver.
> Index: linux.git/drivers/net/fec_mpc52xx/fec.c
> ===================================================================
> --- /dev/null
> +++ linux.git/drivers/net/fec_mpc52xx/fec.c
> @@ -0,0 +1,1127 @@
> +/*
> + * drivers/drivers/net/fec_mpc52xx/fec.c
> + *
> + * Driver for the MPC5200 Fast Ethernet Controller
> + *
> + * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
> + * now maintained by Sylvain Munaut <tnt@246tNt.com>
> + *
> + * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
> + * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
> + * Copyright (C) 2003-2004 MontaVista, Software, Inc.
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + *
> + */
> +
> +#include <linux/module.h>
> +
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/spinlock.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/crc32.h>
> +#include <linux/hardirq.h>
> +#include <linux/delay.h>
> +
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/skbuff.h>
> +
> +#include <asm/of_device.h>
> +#include <asm/of_platform.h>
> +#include <asm/io.h>
> +#include <asm/delay.h>
> +#include <asm/mpc52xx.h>
> +
> +#include <sysdev/bestcomm/bestcomm.h>
> +#include <sysdev/bestcomm/fec.h>
> +
> +#include "fec.h"
> +
> +#define DRIVER_NAME "mpc52xx-fec"
> +
> +static irqreturn_t fec_interrupt(int, void *);
> +static irqreturn_t fec_rx_interrupt(int, void *);
> +static irqreturn_t fec_tx_interrupt(int, void *);
> +static struct net_device_stats *fec_get_stats(struct net_device *);
> +static void fec_set_multicast_list(struct net_device *dev);
> +static void fec_hw_init(struct net_device *dev);
> +static void fec_stop(struct net_device *dev);
> +static void fec_start(struct net_device *dev);
> +static void fec_reset(struct net_device *dev);
Nit: Are all these forward decls needed?
> +
> +static u8 mpc52xx_fec_mac_addr[6];
Why isn't this part of struct fec_priv?
> +static const u8 null_mac[6];
null_mac?!? Just for comparing a mac addr against 0?
<snip>
> +#ifdef CONFIG_FEC_MPC52xx_MDIO
Once again; don't make this a conditional compile; detect at runtime.
<snip>
> +static void __init fec_str2mac(char *str, unsigned char *mac)
> +{
> + int i;
> + u64 val64;
> +
> + val64 = simple_strtoull(str, NULL, 16);
> +
> + for (i = 0; i < 6; i++)
> + mac[5-i] = val64 >> (i*8);
> +}
> +
> +static int __init mpc52xx_fec_mac_setup(char *mac_address)
> +{
> + fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
> + return 0;
> +}
fec_str2mac is called in *1* place. I'd roll it into mpc52xx_fec_mac_setup.
> +
> +__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
> +
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-09-03 15:57 ` Grant Likely
@ 2007-09-03 16:09 ` Jon Smirl
2007-09-03 16:41 ` Grant Likely
2007-09-15 12:14 ` Domen Puncer
1 sibling, 1 reply; 47+ messages in thread
From: Jon Smirl @ 2007-09-03 16:09 UTC (permalink / raw)
To: Grant Likely; +Cc: netdev, Domen Puncer, linuxppc-embedded
On 9/3/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> On 9/2/07, Domen Puncer <domen@coderock.org> wrote:
> > Hi!
> >
> > new in this version:
> > - fixed stuff that was commented on.
> > - added 7-wire support (compile at least, if someone has the hardware,
> > please test!)
> > - ethtool support
>
> Thanks for this work Domen, comments below...
>
> This is a large patch, and it should be broken up into logical
> changes. ie. split into dts changes, bestcomm changes, fec driver and
> mdio driver. Easier to review that way. The bestcomm and dts changes
> don't need to go to the netdev list.
A similar patch that is already broken up is available for Efika.
http://dev.gentoo.org/~nixnut/efika/efika-patches-2.6.22.tar.bz2
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-09-03 16:09 ` Jon Smirl
@ 2007-09-03 16:41 ` Grant Likely
0 siblings, 0 replies; 47+ messages in thread
From: Grant Likely @ 2007-09-03 16:41 UTC (permalink / raw)
To: Jon Smirl; +Cc: netdev, Domen Puncer, linuxppc-embedded
On 9/3/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> On 9/3/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> > On 9/2/07, Domen Puncer <domen@coderock.org> wrote:
> > > Hi!
> > >
> > > new in this version:
> > > - fixed stuff that was commented on.
> > > - added 7-wire support (compile at least, if someone has the hardware,
> > > please test!)
> > > - ethtool support
> >
> > Thanks for this work Domen, comments below...
> >
> > This is a large patch, and it should be broken up into logical
> > changes. ie. split into dts changes, bestcomm changes, fec driver and
> > mdio driver. Easier to review that way. The bestcomm and dts changes
> > don't need to go to the netdev list.
>
> A similar patch that is already broken up is available for Efika.
> http://dev.gentoo.org/~nixnut/efika/efika-patches-2.6.22.tar.bz2
No. That series is Sylvain's full patchset including the old FEC
driver. Domen's patch is a reworked FEC driver, and it only replaces
patch 0008 from that series. However, this patch should be split up
further because it makes changes to both the device tree and the
bestcomm code.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-09-03 15:57 ` Grant Likely
2007-09-03 16:09 ` Jon Smirl
@ 2007-09-15 12:14 ` Domen Puncer
2007-09-17 9:53 ` Sven Luther
1 sibling, 1 reply; 47+ messages in thread
From: Domen Puncer @ 2007-09-15 12:14 UTC (permalink / raw)
To: Grant Likely; +Cc: netdev, linuxppc-embedded
On 03/09/07 09:57 -0600, Grant Likely wrote:
> On 9/2/07, Domen Puncer <domen@coderock.org> wrote:
> > Hi!
> >
> > new in this version:
> > - fixed stuff that was commented on.
> > - added 7-wire support (compile at least, if someone has the hardware,
> > please test!)
> > - ethtool support
>
> Thanks for this work Domen, comments below...
Thanks for reviewing and sorry for not replying sooner, I lost the
mail.
>
> This is a large patch, and it should be broken up into logical
> changes. ie. split into dts changes, bestcomm changes, fec driver and
> mdio driver. Easier to review that way. The bestcomm and dts changes
> don't need to go to the netdev list.
OK.
> > +config FEC_MPC52xx
> > + tristate "FEC Ethernet"
> > + depends on NET_ETHERNET
> > + select PPC_BESTCOMM
> > + select PPC_BESTCOMM_FEC
> > + select CRC32
> > + ---help---
> > + This option enables support for the MPC5200's on-chip
> > + Fast Ethernet Controller
> > +
> > +config FEC_MPC52xx_MDIO
> > + bool "Use external Ethernet MII PHY"
> > + depends on FEC_MPC52xx
> > + select PHYLIB
> > + default y
> > + ---help---
> > + The MPC5200's FEC can connect to the Ethernet either with
> > + an external MII PHY chip or 10 Mbps 7-wire interface
> > + (Motorola? industry standard).
> > + If your board uses an external PHY, say y, else n.
>
> This option should change. Either build the MDIO driver into the FEC
> driver unconditionally and drop this option, or make the MDIO driver
> independent from the FEC driver (it does use the MDIO bus
> infrastructure after all). Either way the FEC driver should detect
> the phy type at runtime (possibly based on the presence/absence of a
> phy-handle property) instead of being hard compiled. 5200 support is
> now multiplatform after all.
>
> If you drop the MDIO config option, then I'd also consider eliminating
> driver/net/fec_mpc52xx/Kconfig entirely and rolling the single
> MPC52xx_FEC option into drivers/net/Kconfig.
Right. I separated it.
> > +static irqreturn_t fec_interrupt(int, void *);
> > +static irqreturn_t fec_rx_interrupt(int, void *);
> > +static irqreturn_t fec_tx_interrupt(int, void *);
> > +static struct net_device_stats *fec_get_stats(struct net_device *);
> > +static void fec_set_multicast_list(struct net_device *dev);
> > +static void fec_hw_init(struct net_device *dev);
> > +static void fec_stop(struct net_device *dev);
> > +static void fec_start(struct net_device *dev);
> > +static void fec_reset(struct net_device *dev);
>
> Nit: Are all these forward decls needed?
Some aren't - cleaned.
>
> > +
> > +static u8 mpc52xx_fec_mac_addr[6];
>
> Why isn't this part of struct fec_priv?
Because at __setup time, there's no fec_priv instance.
OTOH, does anyone even use mpc52xx-mac=?
>
> > +static const u8 null_mac[6];
>
> null_mac?!? Just for comparing a mac addr against 0?
right, is_zero_ether_addr is the right thing.
>
> <snip>
>
> > +#ifdef CONFIG_FEC_MPC52xx_MDIO
>
> Once again; don't make this a conditional compile; detect at runtime.
>
> <snip>
>
> > +static void __init fec_str2mac(char *str, unsigned char *mac)
> > +{
> > + int i;
> > + u64 val64;
> > +
> > + val64 = simple_strtoull(str, NULL, 16);
> > +
> > + for (i = 0; i < 6; i++)
> > + mac[5-i] = val64 >> (i*8);
> > +}
> > +
> > +static int __init mpc52xx_fec_mac_setup(char *mac_address)
> > +{
> > + fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
> > + return 0;
> > +}
>
> fec_str2mac is called in *1* place. I'd roll it into mpc52xx_fec_mac_setup.
>
> > +
> > +__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
> > +
>
OK.
Updated and split version at:
http://coderock.org/tmp/fec-v3rc1/
I'll repost to lists once I run-test them.
Domen
>
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
> grant.likely@secretlab.ca
> (403) 399-0195
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-09-15 12:14 ` Domen Puncer
@ 2007-09-17 9:53 ` Sven Luther
2007-09-17 20:21 ` [PATCH] phy: export phy_mii_ioctl Domen Puncer
0 siblings, 1 reply; 47+ messages in thread
From: Sven Luther @ 2007-09-17 9:53 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
On Sat, Sep 15, 2007 at 02:14:44PM +0200, Domen Puncer wrote:
> Updated and split version at:
> http://coderock.org/tmp/fec-v3rc1/
>
> I'll repost to lists once I run-test them.
When applying those patches, the build did die with :
ERROR: "phy_mii_ioctl" [drivers/net/fec_mpc52xx/fec_mpc52xx.ko] undefined!
Apparently, phy_mii_ioctl is not an exported symbol.
Domen, did you maybe forget a little snipplet when you cut the patches
in different pieces ? Or did i mess up applying them ?
Friendly,
Sven Luther
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH] phy: export phy_mii_ioctl
2007-09-17 9:53 ` Sven Luther
@ 2007-09-17 20:21 ` Domen Puncer
2007-09-17 22:08 ` Jon Smirl
2007-09-20 6:36 ` Jeff Garzik
0 siblings, 2 replies; 47+ messages in thread
From: Domen Puncer @ 2007-09-17 20:21 UTC (permalink / raw)
To: Jeff Garzik; +Cc: netdev, linuxppc-embedded
Export phy_mii_ioctl, so network drivers can use it when built
as modules too.
Signed-off-by: Domen Puncer <domen@coderock.org>
---
On 17/09/07 11:53 +0200, Sven Luther wrote:
> On Sat, Sep 15, 2007 at 02:14:44PM +0200, Domen Puncer wrote:
> > Updated and split version at:
> > http://coderock.org/tmp/fec-v3rc1/
> >
> > I'll repost to lists once I run-test them.
>
> When applying those patches, the build did die with :
>
>
> ERROR: "phy_mii_ioctl" [drivers/net/fec_mpc52xx/fec_mpc52xx.ko] undefined!
>
> Apparently, phy_mii_ioctl is not an exported symbol.
>
> Domen, did you maybe forget a little snipplet when you cut the patches
> in different pieces ? Or did i mess up applying them ?
>
> Friendly,
>
> Sven Luther
drivers/net/phy/phy.c | 1 +
1 files changed, 1 insertion(+)
Index: linux.git/drivers/net/phy/phy.c
===================================================================
--- linux.git.orig/drivers/net/phy/phy.c
+++ linux.git/drivers/net/phy/phy.c
@@ -409,6 +409,7 @@ int phy_mii_ioctl(struct phy_device *phy
return 0;
}
+EXPORT_SYMBOL(phy_mii_ioctl);
/**
* phy_start_aneg - start auto-negotiation for this PHY device
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-17 20:21 ` [PATCH] phy: export phy_mii_ioctl Domen Puncer
@ 2007-09-17 22:08 ` Jon Smirl
2007-09-18 15:16 ` Domen Puncer
2007-09-20 6:36 ` Jeff Garzik
1 sibling, 1 reply; 47+ messages in thread
From: Jon Smirl @ 2007-09-17 22:08 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, Jeff Garzik, linuxppc-embedded
On 9/17/07, Domen Puncer <domen@coderock.org> wrote:
> Export phy_mii_ioctl, so network drivers can use it when built
> as modules too.
Domen, do you want to collect all of these changes for MPC5200 FEC in
to a single patch series? The code is getting scattered around, I'll
check it over to make sure it is all working. I have these patches
applied individually and they all work.
It builds on this series:
[PATCH 0/7] MPC52xx Bestcomm submission for 2.6.24
If you can put this together is a clean series, I should be able to
layer support for the Phytec pcm030 on top of it.
It would be these three combined...
http://coderock.org/tmp/fec-v3rc1/
diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
index 922e9a8..c4442e0 100644
--- a/drivers/net/fec_mpc52xx/fec.c
+++ b/drivers/net/fec_mpc52xx/fec.c
@@ -1087,11 +1087,13 @@ static struct of_platform_driver mpc52xx_fec_driver = {
/* ======================================================================== */
/* Module */
/* ======================================================================== */
+extern int fec_mdio_init(void);
+void fec_mdio_exit(void);
static int __init
mpc52xx_fec_init(void)
{
-#ifdef FEC_MPC52xx_MDIO
+#ifdef CONFIG_FEC_MPC52xx_MDIO
int ret;
ret = fec_mdio_init();
if (ret) {
@@ -1106,7 +1108,7 @@ static void __exit
mpc52xx_fec_exit(void)
{
of_unregister_platform_driver(&mpc52xx_fec_driver);
-#ifdef FEC_MPC52xx_MDIO
+#ifdef CONFIG_FEC_MPC52xx_MDIO
fec_mdio_exit();
#endif
}
>
> Signed-off-by: Domen Puncer <domen@coderock.org>
>
> ---
> On 17/09/07 11:53 +0200, Sven Luther wrote:
> > On Sat, Sep 15, 2007 at 02:14:44PM +0200, Domen Puncer wrote:
> > > Updated and split version at:
> > > http://coderock.org/tmp/fec-v3rc1/
> > >
> > > I'll repost to lists once I run-test them.
> >
> > When applying those patches, the build did die with :
> >
> >
> > ERROR: "phy_mii_ioctl" [drivers/net/fec_mpc52xx/fec_mpc52xx.ko] undefined!
> >
> > Apparently, phy_mii_ioctl is not an exported symbol.
> >
> > Domen, did you maybe forget a little snipplet when you cut the patches
> > in different pieces ? Or did i mess up applying them ?
> >
> > Friendly,
> >
> > Sven Luther
>
>
> drivers/net/phy/phy.c | 1 +
> 1 files changed, 1 insertion(+)
>
> Index: linux.git/drivers/net/phy/phy.c
> ===================================================================
> --- linux.git.orig/drivers/net/phy/phy.c
> +++ linux.git/drivers/net/phy/phy.c
> @@ -409,6 +409,7 @@ int phy_mii_ioctl(struct phy_device *phy
>
> return 0;
> }
> +EXPORT_SYMBOL(phy_mii_ioctl);
>
> /**
> * phy_start_aneg - start auto-negotiation for this PHY device
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply related [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-17 22:08 ` Jon Smirl
@ 2007-09-18 15:16 ` Domen Puncer
2007-09-18 19:17 ` Jon Smirl
2007-09-18 19:29 ` Jon Smirl
0 siblings, 2 replies; 47+ messages in thread
From: Domen Puncer @ 2007-09-18 15:16 UTC (permalink / raw)
To: Jon Smirl; +Cc: netdev, linuxppc-embedded
(I edited Cc: -jeff, +sven, hope you don't mind)
On 17/09/07 18:08 -0400, Jon Smirl wrote:
> On 9/17/07, Domen Puncer <domen@coderock.org> wrote:
> > Export phy_mii_ioctl, so network drivers can use it when built
> > as modules too.
>
> Domen, do you want to collect all of these changes for MPC5200 FEC in
> to a single patch series? The code is getting scattered around, I'll
> check it over to make sure it is all working. I have these patches
> applied individually and they all work.
>
> It builds on this series:
> [PATCH 0/7] MPC52xx Bestcomm submission for 2.6.24
>
> If you can put this together is a clean series, I should be able to
> layer support for the Phytec pcm030 on top of it.
>
> It would be these three combined...
>
> http://coderock.org/tmp/fec-v3rc1/
http://coderock.org/tmp/fec-v3rc2/
export_phy_mii_ioctl
fec_driver-bestcomm
fec_driver-dts
fec_driver-fec
fec_driver-phy
Built (on top of 7 bestcomm patches) and ran it built-in and as module
on Efika.
Order of applying only matters for phy part, which has to be after
the fec driver.
More testing and getting it to work properly on Phytec pcm030 would
be great.
Domen
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-18 15:16 ` Domen Puncer
@ 2007-09-18 19:17 ` Jon Smirl
2007-09-19 11:56 ` Domen Puncer
2007-09-18 19:29 ` Jon Smirl
1 sibling, 1 reply; 47+ messages in thread
From: Jon Smirl @ 2007-09-18 19:17 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
On 9/18/07, Domen Puncer <domen@coderock.org> wrote:
> More testing and getting it to work properly on Phytec pcm030 would
> be great.
I compiled it as a module:
CC [M] drivers/net/fec_mpc52xx/fec.o
drivers/net/fec_mpc52xx/fec.c:613: warning: 'mpc52xx_fec_mac_setup'
defined but not used
This code needs to be enclosed in "#ifndef MODULE". But why aren't you
using module_param() to make a string parameter and then copy it into
mpc52xx_fec_mac_addr[] if the parameter is not null?
If it is a module param you need to use
fec_mpc52xx_phy.mpc52xx-mac="xxxx" instead of just mpc52xx-mac. The
way it is not you can't use mpc52xx-mac when built as a module.
static int __init mpc52xx_fec_mac_setup(char *mac_address)
{
int i;
u64 val64;
val64 = simple_strtoull(mac_address, NULL, 16);
for (i = 0; i < 6; i++)
mpc52xx_fec_mac_addr[5-i] = val64 >> (i*8);
return 0;
}
__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-18 15:16 ` Domen Puncer
2007-09-18 19:17 ` Jon Smirl
@ 2007-09-18 19:29 ` Jon Smirl
2007-09-19 8:54 ` Pedro Luis D. L.
2007-09-19 8:54 ` Pedro Luis D. L.
1 sibling, 2 replies; 47+ messages in thread
From: Jon Smirl @ 2007-09-18 19:29 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
On 9/18/07, Domen Puncer <domen@coderock.org> wrote:
> More testing and getting it to work properly on Phytec pcm030 would
> be great.
Do we want to do anything about this?
[ 1.569657] net eth0: attached phy 0 to driver Generic PHY
[ 2.576013] Sending DHCP requests .<6>PHY: f0003000:00 - Link is Up
- 100/Full
[ 4.612000] ., OK
[ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, my
address is 192.168.1.5
What is happening is the printk for "<6>PHY: f0003000:00 - Link is Up
- 100/Full" is done in an interrupt and it comes in the middle of the
kernel doing DHCP and printing ... without a CR.
Two possible solutions, get rid of the link-up message or wait in in
the initial driver load until the link is up. Or we could leave it the
way it is, but some people may report this as a bug.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* RE: [PATCH] phy: export phy_mii_ioctl
2007-09-18 19:29 ` Jon Smirl
@ 2007-09-19 8:54 ` Pedro Luis D. L.
2007-09-19 10:37 ` Juergen Beisert
2007-09-19 13:56 ` Jon Smirl
2007-09-19 8:54 ` Pedro Luis D. L.
1 sibling, 2 replies; 47+ messages in thread
From: Pedro Luis D. L. @ 2007-09-19 8:54 UTC (permalink / raw)
To: Jon Smirl, Domen Puncer; +Cc: netdev, linuxppc-embedded
Hello Jon,
I=B4m also working with a Phytec pcm030, but I can=B4t get it booted...
Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over these w=
ith this new ones that Domen released.
The base kernel I=B4m using is 2.6.22.6 from kernel.org.
Although I used the patch that creates pcm030.c in arch/platforms/52xx/ and=
compiled using this file, it gets halted at booting time.
Bytes transferred =3D 5091 (13e3 hex)
## Booting image at 00500000 ...
Image Name: Linux-2.6.22.6
Created: 2007-09-19 8:53:02 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1196911 Bytes =3D 1.1 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at 0x400000
(No more output and boot is halted)
Are you using any other patch for the platform or any other kernel, because=
I tried to apply these patches to a 2.6.20 kernel and are not successful.
Bests,
Pedro.
> Date: Tue, 18 Sep 2007 15:29:09 -0400> From: jonsmirl@gmail.com=20
> To: domen@coderock.org> Subject: Re: [PATCH] phy: export phy_mii_ioctl=20
> CC: netdev@vger.kernel.org; linuxppc-embedded@ozlabs.org=20
>> On 9/18/07, Domen Puncer wrote:=20
>> More testing and getting it to work properly on Phytec pcm030 would=20
>> be great.>> Do we want to do anything about this?=20
>> [ 1.569657] net eth0: attached phy 0 to driver Generic PHY=20
> [ 2.576013] Sending DHCP requests .PHY: f0003000:00 - Link is Up=20
> - 100/Full> [ 4.612000] ., OK=20
> [ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, my=20
> address is 192.168.1.5
>> What is happening is the printk for "PHY: f0003000:00 - Link is Up=20
> - 100/Full" is done in an interrupt and it comes in the middle of the> ke=
rnel doing DHCP and printing ... without a CR.=20
>> Two possible solutions, get rid of the link-up message or wait in in=20
> the initial driver load until the link is up. Or we could leave it the=20
> way it is, but some people may report this as a bug.
>>> --> Jon Smirl> jonsmirl@gmail.com=20
> _______________________________________________=20
> Linuxppc-embedded mailing list> Linuxppc-embedded@ozlabs.org> https://ozl=
abs.org/mailman/listinfo/linuxppc-embedded
_________________________________________________________________
Busca desde cualquier p=E1gina Web con una protecci=F3n excepcional. Consig=
ue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com=
^ permalink raw reply [flat|nested] 47+ messages in thread
* RE: [PATCH] phy: export phy_mii_ioctl
2007-09-18 19:29 ` Jon Smirl
2007-09-19 8:54 ` Pedro Luis D. L.
@ 2007-09-19 8:54 ` Pedro Luis D. L.
1 sibling, 0 replies; 47+ messages in thread
From: Pedro Luis D. L. @ 2007-09-19 8:54 UTC (permalink / raw)
To: Jon Smirl, Domen Puncer; +Cc: netdev, linuxppc-embedded
Hello Jon,
I=B4m also working with a Phytec pcm030, but I can=B4t get it booted...
Which kernel are you using?
I tried to apply the 7 bestcomm patches from Sylvain and patch over these w=
ith this new ones that Domen released.
The base kernel I=B4m using is 2.6.22.6 from kernel.org.
Although I used the patch that creates pcm030.c in arch/platforms/52xx/ and=
compiled using this file, it gets halted at booting time.
Bytes transferred =3D 5091 (13e3 hex)
## Booting image at 00500000 ...
Image Name: Linux-2.6.22.6
Created: 2007-09-19 8:53:02 UTC
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1196911 Bytes =3D 1.1 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Booting using flat device tree at 0x400000
(No more output and boot is halted)
Are you using any other patch for the platform or any other kernel, because=
I tried to apply these patches to a 2.6.20 kernel and are not successful.
Bests,
Pedro.
> Date: Tue, 18 Sep 2007 15:29:09 -0400> From: jonsmirl@gmail.com=20
> To: domen@coderock.org> Subject: Re: [PATCH] phy: export phy_mii_ioctl=20
> CC: netdev@vger.kernel.org; linuxppc-embedded@ozlabs.org=20
>> On 9/18/07, Domen Puncer wrote:=20
>> More testing and getting it to work properly on Phytec pcm030 would=20
>> be great.>> Do we want to do anything about this?=20
>> [ 1.569657] net eth0: attached phy 0 to driver Generic PHY=20
> [ 2.576013] Sending DHCP requests .PHY: f0003000:00 - Link is Up=20
> - 100/Full> [ 4.612000] ., OK=20
> [ 6.764005] IP-Config: Got DHCP answer from 192.168.1.200, my=20
> address is 192.168.1.5
>> What is happening is the printk for "PHY: f0003000:00 - Link is Up=20
> - 100/Full" is done in an interrupt and it comes in the middle of the> ke=
rnel doing DHCP and printing ... without a CR.=20
>> Two possible solutions, get rid of the link-up message or wait in in=20
> the initial driver load until the link is up. Or we could leave it the=20
> way it is, but some people may report this as a bug.
>>> --> Jon Smirl> jonsmirl@gmail.com=20
> _______________________________________________=20
> Linuxppc-embedded mailing list> Linuxppc-embedded@ozlabs.org> https://ozl=
abs.org/mailman/listinfo/linuxppc-embedded
_________________________________________________________________
Busca desde cualquier p=E1gina Web con una protecci=F3n excepcional. Consig=
ue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com=
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-19 8:54 ` Pedro Luis D. L.
@ 2007-09-19 10:37 ` Juergen Beisert
2007-09-19 11:38 ` Pedro Luis D. L.
2007-09-19 13:56 ` Jon Smirl
1 sibling, 1 reply; 47+ messages in thread
From: Juergen Beisert @ 2007-09-19 10:37 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: netdev, Domen Puncer
Pedro,
On Wednesday 19 September 2007 10:54, Pedro Luis D. L. wrote:
> I=B4m also working with a Phytec pcm030, but I can=B4t get it booted...
> Which kernel are you using?
> I tried to apply the 7 bestcomm patches from Sylvain and patch over these
> with this new ones that Domen released. The base kernel I=B4m using is
> 2.6.22.6 from kernel.org.
> Although I used the patch that creates pcm030.c in arch/platforms/52xx/ a=
nd
> compiled using this file, it gets halted at booting time.
>
> Bytes transferred =3D 5091 (13e3 hex)
> ## Booting image at 00500000 ...
> Image Name: Linux-2.6.22.6
> Created: 2007-09-19 8:53:02 UTC
> Image Type: PowerPC Linux Kernel Image (gzip compressed)
> Data Size: 1196911 Bytes =3D 1.1 MB
> Load Address: 00000000
> Entry Point: 00000000
> Verifying Checksum ... OK
> Uncompressing Kernel Image ... OK
> Booting using flat device tree at 0x400000
>
> (No more output and boot is halted)
Check your oftree! Most of the time this behaviour means its a wrong oftree=
in=20
use.
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply [flat|nested] 47+ messages in thread
* RE: [PATCH] phy: export phy_mii_ioctl
2007-09-19 10:37 ` Juergen Beisert
@ 2007-09-19 11:38 ` Pedro Luis D. L.
2007-09-19 14:51 ` Juergen Beisert
0 siblings, 1 reply; 47+ messages in thread
From: Pedro Luis D. L. @ 2007-09-19 11:38 UTC (permalink / raw)
To: linuxppc-embedded
Juergen wrote:
>
>Pedro,
>
>On Wednesday 19 September 2007 10:54, Pedro Luis D. L. wrote:
>> I=B4m also working with a Phytec pcm030, but I can=B4t get it booted...
>> Which kernel are you using?
>> I tried to apply the 7 bestcomm patches from Sylvain and patch over thes=
e
>> with this new ones that Domen released. The base kernel I=B4m using is
>> 2.6.22.6 from kernel.org.
>> Although I used the patch that creates pcm030.c in arch/platforms/52xx/ =
and
>> compiled using this file, it gets halted at booting time.
>>
>> Bytes transferred =3D 5091 (13e3 hex)
>> ## Booting image at 00500000 ...
>> Image Name: Linux-2.6.22.6
>> Created: 2007-09-19 8:53:02 UTC
>> Image Type: PowerPC Linux Kernel Image (gzip compressed)
>> Data Size: 1196911 Bytes =3D 1.1 MB
>> Load Address: 00000000
>> Entry Point: 00000000
>> Verifying Checksum ... OK
>> Uncompressing Kernel Image ... OK
>> Booting using flat device tree at 0x400000
>>
>> (No more output and boot is halted)
>=20
>Check your oftree! Most of the time this behaviour means its a wrong oftre=
e in=20
>use.
I=B4m using an specific pcm030.dts oftree that works for the 2.6.20 kernel.=
I=B4m not quite familiar with the oftree stuff, but I thought it should wo=
rk also for the 2.6.22.6.
Is there any other dts file? Where can I find it?
Pedro.
PD: Sorry. I sent the previous message to Jon, Domen and someone else too b=
esides the list. I had some problems with the browser... Even sent twice th=
e message :-(
>Juergen
>=20
>--=20
>Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
>Pengutronix - Linux Solutions for Science and Industry
> Handelsregister: Amtsgericht Hildesheim, HRA 2686
> Vertretung Sued/Muenchen, Germany
> Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
>
_________________________________________________________________
Llama a tus amigos de PC a PC: =A1Es GRATIS!
http://get.live.com/messenger/overview=
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-18 19:17 ` Jon Smirl
@ 2007-09-19 11:56 ` Domen Puncer
2007-09-19 18:44 ` Jon Smirl
0 siblings, 1 reply; 47+ messages in thread
From: Domen Puncer @ 2007-09-19 11:56 UTC (permalink / raw)
To: Jon Smirl; +Cc: netdev, linuxppc-embedded
On 18/09/07 15:17 -0400, Jon Smirl wrote:
> On 9/18/07, Domen Puncer <domen@coderock.org> wrote:
> > More testing and getting it to work properly on Phytec pcm030 would
> > be great.
>
> I compiled it as a module:
> CC [M] drivers/net/fec_mpc52xx/fec.o
> drivers/net/fec_mpc52xx/fec.c:613: warning: 'mpc52xx_fec_mac_setup'
> defined but not used
>
> This code needs to be enclosed in "#ifndef MODULE". But why aren't you
> using module_param() to make a string parameter and then copy it into
> mpc52xx_fec_mac_addr[] if the parameter is not null?
Right,
Patch at the end.
When compiled as module use "modprobe fec_mpc52xx mac=foo",
when built-in add to boot line: "fec_mpc52xx.mac=foo"
As for link-up-printk in the middle of DHCP requests...
is it really that big of a problem?
This sort of things happen when printk doesn't have the whole
line... getting rid of link-up message would just hide it (it can show
ie. when an usb device is bound to scsi layer).
Domen
---
drivers/net/fec_mpc52xx/fec.c | 18 ++----------------
1 files changed, 2 insertions(+), 16 deletions(-)
Index: linux.git/drivers/net/fec_mpc52xx/fec.c
===================================================================
--- linux.git.orig/drivers/net/fec_mpc52xx/fec.c
+++ linux.git/drivers/net/fec_mpc52xx/fec.c
@@ -53,6 +53,8 @@ static void fec_start(struct net_device
static void fec_reset(struct net_device *dev);
static u8 mpc52xx_fec_mac_addr[6];
+module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0);
+MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe");
static void fec_tx_timeout(struct net_device *dev)
{
@@ -609,22 +611,6 @@ static void fec_set_multicast_list(struc
}
}
-static int __init mpc52xx_fec_mac_setup(char *mac_address)
-{
- int i;
- u64 val64;
-
- val64 = simple_strtoull(mac_address, NULL, 16);
-
- for (i = 0; i < 6; i++)
- mpc52xx_fec_mac_addr[5-i] = val64 >> (i*8);
-
- return 0;
-}
-
-__setup("mpc52xx-mac=",mpc52xx_fec_mac_setup);
-
-
/**
* fec_hw_init
* @dev: network device
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-19 8:54 ` Pedro Luis D. L.
2007-09-19 10:37 ` Juergen Beisert
@ 2007-09-19 13:56 ` Jon Smirl
2007-09-19 14:31 ` Pedro Luis D. L.
1 sibling, 1 reply; 47+ messages in thread
From: Jon Smirl @ 2007-09-19 13:56 UTC (permalink / raw)
To: Pedro Luis D. L.; +Cc: netdev, Domen Puncer, linuxppc-embedded
On 9/19/07, Pedro Luis D. L. <carcadiz@hotmail.com> wrote:
>
> Hello Jon,
> I=B4m also working with a Phytec pcm030, but I can=B4t get it booted...
> Which kernel are you using?
> I tried to apply the 7 bestcomm patches from Sylvain and patch over these=
with this new ones that Domen released.
> The base kernel I=B4m using is 2.6.22.6 from kernel.org.
> Although I used the patch that creates pcm030.c in arch/platforms/52xx/ a=
nd compiled using this file, it gets halted at booting time.
>
> Bytes transferred =3D 5091 (13e3 hex)
> ## Booting image at 00500000 ...
> Image Name: Linux-2.6.22.6
> Created: 2007-09-19 8:53:02 UTC
> Image Type: PowerPC Linux Kernel Image (gzip compressed)
> Data Size: 1196911 Bytes =3D 1.1 MB
> Load Address: 00000000
> Entry Point: 00000000
> Verifying Checksum ... OK
> Uncompressing Kernel Image ... OK
> Booting using flat device tree at 0x400000
>
> (No more output and boot is halted)
The root name of your device tree needs to match the name in pcm030.c
pcm030_probe(void). If they don't match this happens.
--=20
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* RE: [PATCH] phy: export phy_mii_ioctl
2007-09-19 13:56 ` Jon Smirl
@ 2007-09-19 14:31 ` Pedro Luis D. L.
0 siblings, 0 replies; 47+ messages in thread
From: Pedro Luis D. L. @ 2007-09-19 14:31 UTC (permalink / raw)
To: linuxppc-embedded
On 9/19/07, Jon Smirl wrote:
>On 9/19/07, Pedro Luis D. L. wrote:
>>
>> Hello Jon,
>> I=B4m also working with a Phytec pcm030, but I can=B4t get it booted...
>> Which kernel are you using?
>> I tried to apply the 7 bestcomm patches from Sylvain and patch over thes=
e with this new ones that Domen released.
>> The base kernel I=B4m using is 2.6.22.6 from kernel.org.
>> Although I used the patch that creates pcm030.c in arch/platforms/52xx/ =
and compiled using this file, it gets halted at booting time.
>>
>> Bytes transferred =3D 5091 (13e3 hex)
>> ## Booting image at 00500000 ...
>> Image Name: Linux-2.6.22.6
>> Created: 2007-09-19 8:53:02 UTC
>> Image Type: PowerPC Linux Kernel Image (gzip compressed)
>> Data Size: 1196911 Bytes =3D 1.1 MB
>> Load Address: 00000000
>> Entry Point: 00000000
>> Verifying Checksum ... OK
>> Uncompressing Kernel Image ... OK
>> Booting using flat device tree at 0x400000
>>
>> (No more output and boot is halted)
>=20
=20
I checked that and both are the same:
In pcm030.c:
static int __init pcm030_probe(void)
{
unsigned long node =3D of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(node, "pcm030"))
return 0;
return 1;
}
define_machine(pcm030) {
.name =3D "pcm030",
.probe =3D pcm030_probe,
.setup_arch =3D pcm030_setup_arch,
.restart =3D mpc52xx_restart,
.init =3D pcm030_init,
.init_IRQ =3D mpc52xx_init_irq,
.get_irq =3D mpc52xx_get_irq,
.show_cpuinfo =3D pcm030_show_cpuinfo,
.calibrate_decr =3D generic_calibrate_decr,
};
in pcm030.dts:
model =3D "pcm030";
compatible =3D "pcm030\0mpc5200b\0mpc52xx";
#address-cells =3D ;
#size-cells =3D ;
And it still doesn=B4t boot...
I know it sounds hard, but... Can I skip the "if (!of_flat_dt_is_compatible=
(node, "pcm030"))" line?
This pcm030.c and pcm030.dts files work and boot with 2.6.20 kernel...
Pedro Dominguez
=20
_________________________________________________________________
Consigue el nuevo Windows Live Messenger
http://get.live.com/messenger/overview=
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-19 11:38 ` Pedro Luis D. L.
@ 2007-09-19 14:51 ` Juergen Beisert
2007-09-19 15:11 ` Pedro Luis D. L.
0 siblings, 1 reply; 47+ messages in thread
From: Juergen Beisert @ 2007-09-19 14:51 UTC (permalink / raw)
To: linuxppc-embedded
Pedro,
On Wednesday 19 September 2007 13:38, Pedro Luis D. L. wrote:
> I=B4m using an specific pcm030.dts oftree that works for the 2.6.20 kerne=
l.
> I=B4m not quite familiar with the oftree stuff, but I thought it should w=
ork
> also for the 2.6.22.6. Is there any other dts file? Where can I find it?
dts patch sent offline.
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply [flat|nested] 47+ messages in thread
* RE: [PATCH] phy: export phy_mii_ioctl
2007-09-19 14:51 ` Juergen Beisert
@ 2007-09-19 15:11 ` Pedro Luis D. L.
0 siblings, 0 replies; 47+ messages in thread
From: Pedro Luis D. L. @ 2007-09-19 15:11 UTC (permalink / raw)
To: linuxppc-embedded
>Pedro,
>=20
>On Wednesday 19 September 2007 13:38, Pedro Luis D. L. wrote:
>> I=B4m using an specific pcm030.dts oftree that works for the 2.6.20 kern=
el.
>> I=B4m not quite familiar with the oftree stuff, but I thought it should =
work
>> also for the 2.6.22.6. Is there any other dts file? Where can I find it?
>=20
>dts patch sent offline.
Thanks for the patch, Juergen. Received and applied, but still doesn't boot=
.
I=B4m starting to suspect there should be something else...
Pedro.
>Juergen
>--=20
>Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
> Pengutronix - Linux Solutions for Science and Industry
> Handelsregister: Amtsgericht Hildesheim, HRA 2686
> Vertretung Sued/Muenchen, Germany
> Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
_________________________________________________________________
Consigue el nuevo Windows Live Messenger
http://get.live.com/messenger/overview=
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-19 11:56 ` Domen Puncer
@ 2007-09-19 18:44 ` Jon Smirl
2007-09-19 21:18 ` Jon Smirl
0 siblings, 1 reply; 47+ messages in thread
From: Jon Smirl @ 2007-09-19 18:44 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
On 9/19/07, Domen Puncer <domen@coderock.org> wrote:
> Patch at the end.
> When compiled as module use "modprobe fec_mpc52xx mac=foo",
> when built-in add to boot line: "fec_mpc52xx.mac=foo"
This patch series is working for me now.
This needs a cleanup too, but it is unrelated....
CC drivers/serial/mpc52xx_uart.o
drivers/serial/mpc52xx_uart.c: In function 'mpc52xx_console_setup':
drivers/serial/mpc52xx_uart.c:760: warning: format '%lx' expects type
'long unsigned int', but argument 2 has type 'resource_size_t'
drivers/serial/mpc52xx_uart.c: In function 'mpc52xx_uart_of_probe':
drivers/serial/mpc52xx_uart.c:978: warning: format '%lx' expects type
'long unsigned int', but argument 3 has type 'resource_size_t'
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-19 18:44 ` Jon Smirl
@ 2007-09-19 21:18 ` Jon Smirl
0 siblings, 0 replies; 47+ messages in thread
From: Jon Smirl @ 2007-09-19 21:18 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
On 9/19/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> This needs a cleanup too, but it is unrelated....
Another set of related warnings that need clean up....
CC drivers/spi/mpc52xx_psc_spi.o
drivers/spi/mpc52xx_psc_spi.c: In function 'mpc52xx_psc_spi_activate_cs':
drivers/spi/mpc52xx_psc_spi.c:110: warning: passing argument 1 of
'in_be16' from incompatible pointer type
drivers/spi/mpc52xx_psc_spi.c:116: warning: passing argument 1 of
'out_be16' from incompatible pointer type
drivers/spi/mpc52xx_psc_spi.c: In function 'mpc52xx_psc_spi_port_config':
drivers/spi/mpc52xx_psc_spi.c:417: warning: passing argument 1 of
'out_be16' from incompatible pointer type
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [PATCH] phy: export phy_mii_ioctl
2007-09-17 20:21 ` [PATCH] phy: export phy_mii_ioctl Domen Puncer
2007-09-17 22:08 ` Jon Smirl
@ 2007-09-20 6:36 ` Jeff Garzik
1 sibling, 0 replies; 47+ messages in thread
From: Jeff Garzik @ 2007-09-20 6:36 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
Domen Puncer wrote:
> Export phy_mii_ioctl, so network drivers can use it when built
> as modules too.
>
> Signed-off-by: Domen Puncer <domen@coderock.org>
applied
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-08-10 9:51 [RFC PATCH v0.1] net driver: mpc52xx fec Domen Puncer
` (2 preceding siblings ...)
2007-09-02 7:41 ` [RFC PATCH v0.2] " Domen Puncer
@ 2007-09-27 17:07 ` Juergen Beisert
2007-09-27 18:12 ` Jon Smirl
2007-09-28 15:07 ` Juergen Beisert
3 siblings, 2 replies; 47+ messages in thread
From: Juergen Beisert @ 2007-09-27 17:07 UTC (permalink / raw)
To: linuxppc-embedded
On Friday 10 August 2007 11:51, Domen Puncer wrote:
> Not for merge (yet)! But please do review.
>
> fec_mpc52xx driver (not in-tree, but floating around) isn't in very
> good shape, so I tried to change that.
> Diff against original is quite big (fec_phy.c is completely rewritten)
> and confuzing, so I'm including whole drivers/net/fec_mpc52xx/ .
>
> I still have 'make CONFIG_FEC_MPC52xx_MDIO=3Dn compile and work' on my
> TODO, maybe even ethtool support.
Currently I'm trying with your fec driver and Sylvain Munaut's bestcomm dri=
ver=20
*and* rt-preemt 2.6.23-rc8-rt1 and now I'm getting this error while stress=
=20
test the network:
BUG: scheduling while atomic: softirq-timer/0/0x00000002/5, CPU#0
Call Trace:
[c0309e00] [c0007ddc] show_stack+0x3c/0x194 (unreliable)
[c0309e30] [c0017934] __schedule_bug+0x38/0x48
[c0309e40] [c01c8f24] __schedule+0x3e8/0x428
[c0309e70] [c01c96d4] schedule+0x54/0xf0
[c0309e80] [c01c9e8c] schedule_timeout+0x68/0xe4
[c0309ec0] [c00282dc] msleep+0x1c/0x34
[c0309ed0] [c0125fb8] fec_stop+0xbc/0x1a8
[c0309ef0] [c0126530] fec_reset+0x20/0xb0
[c0309f10] [c0127840] fec_tx_timeout+0x3c/0xa4
[c0309f30] [c016b5dc] dev_watchdog+0x13c/0x14c
[c0309f50] [c0027c90] run_timer_softirq+0x2e4/0x444
[c0309f90] [c00239a4] ksoftirqd+0x134/0x214
[c0309fd0] [c0034d94] kthread+0x48/0x84
[c0309ff0] [c000f828] kernel_thread+0x44/0x60
Do you have an idea what happens?
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-27 17:07 ` [RFC PATCH v0.1] " Juergen Beisert
@ 2007-09-27 18:12 ` Jon Smirl
2007-09-27 18:43 ` Scott Wood
2007-09-28 15:07 ` Juergen Beisert
1 sibling, 1 reply; 47+ messages in thread
From: Jon Smirl @ 2007-09-27 18:12 UTC (permalink / raw)
To: Juergen Beisert; +Cc: linuxppc-embedded
On 9/27/07, Juergen Beisert <jbe@pengutronix.de> wrote:
> On Friday 10 August 2007 11:51, Domen Puncer wrote:
> > Not for merge (yet)! But please do review.
> >
> > fec_mpc52xx driver (not in-tree, but floating around) isn't in very
> > good shape, so I tried to change that.
> > Diff against original is quite big (fec_phy.c is completely rewritten)
> > and confuzing, so I'm including whole drivers/net/fec_mpc52xx/ .
> >
> > I still have 'make CONFIG_FEC_MPC52xx_MDIO=n compile and work' on my
> > TODO, maybe even ethtool support.
>
> Currently I'm trying with your fec driver and Sylvain Munaut's bestcomm driver
> *and* rt-preemt 2.6.23-rc8-rt1 and now I'm getting this error while stress
> test the network:
>
> BUG: scheduling while atomic: softirq-timer/0/0x00000002/5, CPU#0
> Call Trace:
> [c0309e00] [c0007ddc] show_stack+0x3c/0x194 (unreliable)
> [c0309e30] [c0017934] __schedule_bug+0x38/0x48
> [c0309e40] [c01c8f24] __schedule+0x3e8/0x428
> [c0309e70] [c01c96d4] schedule+0x54/0xf0
> [c0309e80] [c01c9e8c] schedule_timeout+0x68/0xe4
> [c0309ec0] [c00282dc] msleep+0x1c/0x34
> [c0309ed0] [c0125fb8] fec_stop+0xbc/0x1a8
> [c0309ef0] [c0126530] fec_reset+0x20/0xb0
> [c0309f10] [c0127840] fec_tx_timeout+0x3c/0xa4
> [c0309f30] [c016b5dc] dev_watchdog+0x13c/0x14c
> [c0309f50] [c0027c90] run_timer_softirq+0x2e4/0x444
> [c0309f90] [c00239a4] ksoftirqd+0x134/0x214
> [c0309fd0] [c0034d94] kthread+0x48/0x84
> [c0309ff0] [c000f828] kernel_thread+0x44/0x60
>
> Do you have an idea what happens?
The call to msleep() is inside a block protected with
:#define in_interrupt() (irq_count())
if (!in_interrupt)
The stack trace looks like it is in a timer interrupt so shouldn't
irq_count be non-zero?
Could there be some lack of coordination on irq_count and the timer
tick with the preempt patch applied? Or does irq_count() not count
soft irqs?
(!in_interrupt) may be the wrong way to protect this code.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-27 18:12 ` Jon Smirl
@ 2007-09-27 18:43 ` Scott Wood
2007-09-28 9:12 ` Juergen Beisert
0 siblings, 1 reply; 47+ messages in thread
From: Scott Wood @ 2007-09-27 18:43 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-embedded
Jon Smirl wrote:
> The call to msleep() is inside a block protected with
> :#define in_interrupt() (irq_count())
> if (!in_interrupt)
>
> The stack trace looks like it is in a timer interrupt so shouldn't
> irq_count be non-zero?
> Could there be some lack of coordination on irq_count and the timer
> tick with the preempt patch applied? Or does irq_count() not count
> soft irqs?
>
> (!in_interrupt) may be the wrong way to protect this code.
I think in_atomic() is what you want.
-Scott
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-27 18:43 ` Scott Wood
@ 2007-09-28 9:12 ` Juergen Beisert
2007-09-28 15:40 ` Scott Wood
` (2 more replies)
0 siblings, 3 replies; 47+ messages in thread
From: Juergen Beisert @ 2007-09-28 9:12 UTC (permalink / raw)
To: linuxppc-embedded
On Thursday 27 September 2007 20:43, Scott Wood wrote:
> Jon Smirl wrote:
> > The call to msleep() is inside a block protected with
> >
> > :#define in_interrupt() (irq_count())
> >
> > if (!in_interrupt)
> >
> > The stack trace looks like it is in a timer interrupt so shouldn't
> > irq_count be non-zero?
> > Could there be some lack of coordination on irq_count and the timer
> > tick with the preempt patch applied? Or does irq_count() not count
> > soft irqs?
> >
> > (!in_interrupt) may be the wrong way to protect this code.
>
> I think in_atomic() is what you want.
I tried with in_atomic(). The BUG report is gone, but the problem still=20
exists.=20
While network stress testing:=20
[...]
NETDEV WATCHDOG: eth0: transmit timed out
net eth0: transmit timed out
net eth0: queues didn't drain
net eth0: tx: index: 35, outdex: 36
net eth0: rx: index: 24, outdex: 25
PHY: f0003000:00 - Link is Down
PHY: f0003000:00 - Link is Up - 100/Full
The link is up again, but any connection is dead (no answers to ping etc.).=
=20
But the serial console is still working. I'm not sure if the RT-Preempt pat=
ch=20
*causes* this behavior or only *discover* it. Any idea?
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=C2=A0Pengutronix - Linux Solutions for Science and Industry
=C2=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=C2=A0 =C2=A0 =C2=A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-27 17:07 ` [RFC PATCH v0.1] " Juergen Beisert
2007-09-27 18:12 ` Jon Smirl
@ 2007-09-28 15:07 ` Juergen Beisert
2007-09-28 15:38 ` Jon Smirl
1 sibling, 1 reply; 47+ messages in thread
From: Juergen Beisert @ 2007-09-28 15:07 UTC (permalink / raw)
To: linuxppc-embedded
On Thursday 27 September 2007 19:07, Juergen Beisert wrote:
> On Friday 10 August 2007 11:51, Domen Puncer wrote:
> > Not for merge (yet)! But please do review.
> >
> > fec_mpc52xx driver (not in-tree, but floating around) isn't in very
> > good shape, so I tried to change that.
> > Diff against original is quite big (fec_phy.c is completely rewritten)
> > and confuzing, so I'm including whole drivers/net/fec_mpc52xx/ .
> >
> > I still have 'make CONFIG_FEC_MPC52xx_MDIO=3Dn compile and work' on my
> > TODO, maybe even ethtool support.
I add a few more debug outputs and now with this driver I can run a
$ nmap <ip>
from my host against the target and target's network stops always at the sa=
me=20
point.
The last output from the driver is (with DEBUG macro defined):
net eth0: ievent: 08020000
and no further interrupt occurs anymore (I checked all three interrupt entr=
y=20
functions)
nmap on host's side outputs:
Starting Nmap 4.20 ( http://insecure.org ) at 2007-09-28 16:56 CEST
Interesting ports on 192.168.23.226:
Not shown: 852 filtered ports, 843 closed ports
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnet
Nmap finished: 1 IP address (1 host up) scanned in 14.120 seconds
But I can't run it a second time, as the network on target's side doesn't=20
respond. Any idea?
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-28 15:07 ` Juergen Beisert
@ 2007-09-28 15:38 ` Jon Smirl
2007-10-01 8:35 ` Juergen Beisert
0 siblings, 1 reply; 47+ messages in thread
From: Jon Smirl @ 2007-09-28 15:38 UTC (permalink / raw)
To: Juergen Beisert; +Cc: linuxppc-embedded
On 9/28/07, Juergen Beisert <jbe@pengutronix.de> wrote:
> But I can't run it a second time, as the network on target's side doesn't
> respond. Any idea?
Do the stress tests complete on a non-rt kernel?
That will narrow down the type of bug being looked for.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-28 9:12 ` Juergen Beisert
@ 2007-09-28 15:40 ` Scott Wood
2007-10-08 8:48 ` Sascha Hauer
2007-10-08 9:01 ` Sascha Hauer
2 siblings, 0 replies; 47+ messages in thread
From: Scott Wood @ 2007-09-28 15:40 UTC (permalink / raw)
To: Juergen Beisert; +Cc: linuxppc-embedded
Juergen Beisert wrote:
> I tried with in_atomic(). The BUG report is gone, but the problem still
> exists.
>
> While network stress testing:
>
> [...]
> NETDEV WATCHDOG: eth0: transmit timed out
> net eth0: transmit timed out
> net eth0: queues didn't drain
> net eth0: tx: index: 35, outdex: 36
> net eth0: rx: index: 24, outdex: 25
> PHY: f0003000:00 - Link is Down
> PHY: f0003000:00 - Link is Up - 100/Full
>
> The link is up again, but any connection is dead (no answers to ping etc.).
> But the serial console is still working. I'm not sure if the RT-Preempt patch
> *causes* this behavior or only *discover* it. Any idea?
I'd try looking at the driver's locking to make sure that it's correct.
-Scott
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-28 15:38 ` Jon Smirl
@ 2007-10-01 8:35 ` Juergen Beisert
2007-10-01 16:24 ` Juergen Beisert
0 siblings, 1 reply; 47+ messages in thread
From: Juergen Beisert @ 2007-10-01 8:35 UTC (permalink / raw)
To: linuxppc-embedded
On Friday 28 September 2007 17:38, Jon Smirl wrote:
> On 9/28/07, Juergen Beisert <jbe@pengutronix.de> wrote:
> > But I can't run it a second time, as the network on target's side doesn=
't
> > respond. Any idea?
>
> Do the stress tests complete on a non-rt kernel?
I tried it again:
1) Target runs 2.6.23-rc8 without rt-preempt:
@host$ nmap 192.168.23.226
Starting Nmap 4.20 ( http://insecure.org ) at 2007-10-01 10:20 CEST
Interesting ports on 192.168.23.226:
Not shown: 1695 closed ports
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnet
Nmap finished: 1 IP address (1 host up) scanned in 0.581 seconds
Target continues to work. Does not make a difference if the root filesystem=
is=20
jffs2 or nfs.
2) Same target runs 2.6.23-rc8-rt1
@host$ nmap 192.168.23.226
Starting Nmap 4.20 ( http://insecure.org ) at 2007-10-01 10:15 CEST
Interesting ports on 192.168.23.226:
Not shown: 871 filtered ports, 824 closed ports
PORT STATE SERVICE
22/tcp open ssh
23/tcp open telnet
Nmap finished: 1 IP address (1 host up) scanned in 14.116 seconds
Network on target dies. But can be reactivated by an "ifconfig eth0 down;=20
ifconfig eth0 up". I included some printk statements into the fec.c source =
to=20
see what interrupts are happen.
"r" means fec_rx_interrupt was entered, "t" means fec_tx_interrupt was ente=
red=20
and "p" means fec_interrupt was entered. This is the output of the=20
nmap "attack" above:
rtrtrrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttrr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
ttr
at this point: fec_hard_start_xmit, stop queue
rrt
at this point: fec_tx_interrupt, wake queue
at this point: fec_hard_start_xmit, stop queue
t
at this point: fec_tx_interrupt, wake queue
tp
<7>net eth0: ievent: 08020000
=2E..at this point the network is dead.
BTW: Without rt-preempt none of the wake/stop queue events and no=20
fec_interrupt occurs. I only see a long list of "r"s and "t"s...
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-10-01 8:35 ` Juergen Beisert
@ 2007-10-01 16:24 ` Juergen Beisert
0 siblings, 0 replies; 47+ messages in thread
From: Juergen Beisert @ 2007-10-01 16:24 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: Daniel Walker
On Monday 01 October 2007 10:35, Juergen Beisert wrote:
> 2) Same target runs 2.6.23-rc8-rt1
>
> @host$ nmap 192.168.23.226
>
> Starting Nmap 4.20 ( http://insecure.org ) at 2007-10-01 10:15 CEST
> Interesting ports on 192.168.23.226:
> Not shown: 871 filtered ports, 824 closed ports
> PORT STATE SERVICE
> 22/tcp open ssh
> 23/tcp open telnet
>
> Nmap finished: 1 IP address (1 host up) scanned in 14.116 seconds
>
> Network on target dies. But can be reactivated by an "ifconfig eth0 down;
> ifconfig eth0 up". I included some printk statements into the fec.c source
> to see what interrupts are happen.
>
> "r" means fec_rx_interrupt was entered, "t" means fec_tx_interrupt was
> entered and "p" means fec_interrupt was entered. This is the output of the
> nmap "attack" above:
>
> rtrtrrr
> at this point: fec_hard_start_xmit, stop queue
> rrt
> at this point: fec_tx_interrupt, wake queue
> ttrr
> at this point: fec_hard_start_xmit, stop queue
> rrt
> at this point: fec_tx_interrupt, wake queue
> ttrr
> at this point: fec_hard_start_xmit, stop queue
> rrt
> at this point: fec_tx_interrupt, wake queue
> ttrr
> at this point: fec_hard_start_xmit, stop queue
> rrt
> at this point: fec_tx_interrupt, wake queue
> ttrr
> at this point: fec_hard_start_xmit, stop queue
> rrt
> at this point: fec_tx_interrupt, wake queue
> ttrr
> at this point: fec_hard_start_xmit, stop queue
> rrt
> at this point: fec_tx_interrupt, wake queue
> ttr
> at this point: fec_hard_start_xmit, stop queue
> rrt
> at this point: fec_tx_interrupt, wake queue
> at this point: fec_hard_start_xmit, stop queue
> t
> at this point: fec_tx_interrupt, wake queue
> tp
> <7>net eth0: ievent: 08020000
>
> ...at this point the network is dead.
>
> BTW: Without rt-preempt none of the wake/stop queue events and no
> fec_interrupt occurs. I only see a long list of "r"s and "t"s...
We tried again with rt-preempt and increased the priority of FEC's three=20
interrupts: And now it survives the nmap "attack". But we don't know now if=
=20
we only changed the behavior or fixed the bug?
BTW: Is it possible that fec_interrupt(() doesn' handle FEC_IEVENT_RFIFO_ER=
ROR =20
and FEC_IEVENT_XFIFO_ERROR)) incorrectly? The lines makes more sense with t=
he=20
following patch (but we are not sure about authors real intention).
@@ -506,7 +484,7 @@ static irqreturn_t fec_interrupt(int irq
out_be32(&fec->ievent, ievent); /* clear pending events */
=2D if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+ if (!(ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR))) {
if (ievent & ~FEC_IEVENT_TFINT)
dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
return IRQ_HANDLED;
Juergen
=2D-=20
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
=A0Pengutronix - Linux Solutions for Science and Industry
=A0 Handelsregister: Amtsgericht Hildesheim, HRA 2686
=A0 =A0 =A0 Vertretung Sued/Muenchen, Germany
Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-09-02 7:41 ` [RFC PATCH v0.2] " Domen Puncer
2007-09-03 15:57 ` Grant Likely
@ 2007-10-02 12:49 ` Sascha Hauer
2007-10-02 14:32 ` Domen Puncer
1 sibling, 1 reply; 47+ messages in thread
From: Sascha Hauer @ 2007-10-02 12:49 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
Hi Domen,
On Sun, Sep 02, 2007 at 09:41:43AM +0200, Domen Puncer wrote:
+ */
> +static void fec_start(struct net_device *dev)
> +{
> + struct fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 rcntrl;
> + u32 tcntrl;
> + u32 tmp;
> +
> + /* clear sticky error bits */
> + tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
> + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
> + out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
> +
> + /* FIFOs will reset on fec_enable */
> + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
> +
> + /* Set station address. */
> + fec_set_paddr(dev, dev->dev_addr);
> +
> + fec_set_multicast_list(dev);
> +
> + /* set max frame len, enable flow control, select mii mode */
> + rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
> + rcntrl |= FEC_RCNTRL_FCE;
> + rcntrl |= MII_RCNTL_MODE;
> + if (priv->duplex == DUPLEX_FULL)
> + tcntrl = FEC_TCNTRL_FDEN; /* FD enable */
> + else {
> + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
> + tcntrl = 0;
> + }
> + out_be32(&fec->r_cntrl, rcntrl);
> + out_be32(&fec->x_cntrl, tcntrl);
> +
> + /* Clear any outstanding interrupt. */
> + out_be32(&fec->ievent, 0xffffffff);
> +
> + /* Enable interrupts we wish to service. */
> + out_be32(&fec->imask, FEC_IMASK_ENABLE);
This disables phy interrupts.
> +static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> +{
> + struct fec_mdio_priv *priv = bus->priv;
> + int tries = 100;
> +
> + u32 request = FEC_MII_READ_FRAME;
> + request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> + request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> + out_be32(&priv->regs->mii_data, request);
> +
> + /* wait for it to finish, this takes about 23 us on lite5200b */
> + while (priv->completed == 0 && tries--)
> + udelay(5);
> +
> + priv->completed = 0;
> +
> + if (tries == 0)
> + return -ETIMEDOUT;
This does not work as expected. When a timeout occurs tries is -1 not 0,
so the test above will never trigger.
Using --tries instead of tries-- reveals another bug. We get a timeout
everytime now, because MII interrupts are accidently disabled in
fec_start().
We cannot use a waitqueue or similar for waiting for the mii transfer
because we are atomic here.
A simple fix is provided below. It removes the need for the interrupt
handler in the phy handling routines. Anyway, it might be better to fix
the phy layer not to use atomic contexts, so this patch might not be the
way to go.
Regards,
Sascha
+
> +static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
> +{
> + struct device *dev = &of->dev;
>
> [...]
>
> + init_waitqueue_head(&priv->wq);
This waitqueue is never used. wake_up() is called in the interrupt
handler, but noone ever sleeps on the queue.
---
drivers/net/fec_mpc52xx/fec.c | 7 +---
drivers/net/fec_mpc52xx/fec_phy.c | 59 +++++++-------------------------------
2 files changed, 15 insertions(+), 51 deletions(-)
Index: linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/net/fec_mpc52xx/fec.c
+++ linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec.c
@@ -265,7 +265,6 @@ static void fec_phy_hw_init(struct fec_p
return;
out_be32(&fec->mii_speed, priv->phy_speed);
- out_be32(&fec->imask, in_be32(&fec->imask) | FEC_IMASK_MII);
}
static int fec_open(struct net_device *dev)
@@ -654,7 +653,7 @@ static void fec_hw_init(struct net_devic
out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */
out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */
- /* set phy speed and enable MII interrupt
+ /* set phy speed.
* this can't be done in phy driver, since it needs to be called
* before fec stuff (even on resume) */
fec_phy_hw_init(priv);
@@ -730,8 +729,8 @@ static void fec_stop(struct net_device *
struct mpc52xx_fec __iomem *fec = priv->fec;
unsigned long timeout;
- /* disable all but MII interrupt */
- out_be32(&fec->imask, in_be32(&fec->imask) & FEC_IMASK_MII);
+ /* disable all interrupts */
+ out_be32(&fec->imask, 0);
/* Disable the rx task. */
bcom_disable(priv->rx_dmatsk);
Index: linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec_phy.c
===================================================================
--- linux-2.6.23-rc8.orig/drivers/net/fec_mpc52xx/fec_phy.c
+++ linux-2.6.23-rc8/drivers/net/fec_mpc52xx/fec_phy.c
@@ -18,29 +18,28 @@
#include "fec.h"
struct fec_mdio_priv {
- int completed;
- wait_queue_head_t wq;
struct mpc52xx_fec __iomem *regs;
- int irq;
};
static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
{
struct fec_mdio_priv *priv = bus->priv;
+ struct mpc52xx_fec __iomem *fec;
int tries = 100;
-
u32 request = FEC_MII_READ_FRAME;
+
+ fec = priv->regs;
+ out_be32(&fec->ievent, FEC_IEVENT_MII);
+
request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
out_be32(&priv->regs->mii_data, request);
/* wait for it to finish, this takes about 23 us on lite5200b */
- while (priv->completed == 0 && tries--)
+ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
udelay(5);
- priv->completed = 0;
-
if (tries == 0)
return -ETIMEDOUT;
@@ -50,9 +49,13 @@ static int fec_mdio_read(struct mii_bus
static int fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
{
struct fec_mdio_priv *priv = bus->priv;
+ struct mpc52xx_fec __iomem *fec;
u32 value = data;
int tries = 100;
+ fec = priv->regs;
+ out_be32(&fec->ievent, FEC_IEVENT_MII);
+
value |= FEC_MII_WRITE_FRAME;
value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
@@ -60,38 +63,15 @@ static int fec_mdio_write(struct mii_bus
out_be32(&priv->regs->mii_data, value);
/* wait for request to finish */
- while (priv->completed == 0 && tries--)
+ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
udelay(5);
- priv->completed = 0;
-
if (tries == 0)
return -ETIMEDOUT;
return 0;
}
-static irqreturn_t fec_mdio_interrupt(int irq, void *dev_id)
-{
- struct fec_mdio_priv *priv = dev_id;
- struct mpc52xx_fec __iomem *fec;
- int ievent;
-
- fec = priv->regs;
- ievent = in_be32(&fec->ievent);
-
- ievent &= FEC_IEVENT_MII;
- if (!ievent)
- return IRQ_NONE;
-
- out_be32(&fec->ievent, ievent);
-
- priv->completed = 1;
- wake_up(&priv->wq);
-
- return IRQ_HANDLED;
-}
-
static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
{
struct device *dev = &of->dev;
@@ -143,22 +123,12 @@ static int fec_mdio_probe(struct of_devi
goto out_free;
}
- priv->irq = irq_of_parse_and_map(np, 0);
- err = request_irq(priv->irq, &fec_mdio_interrupt, IRQF_DISABLED | IRQF_SHARED,
- "fec_mdio", priv);
- if (err) {
- printk(KERN_ERR "%s: interrupt request failed with %i\n", __func__, err);
- goto out_unmap;
- }
-
bus->id = res.start;
bus->priv = priv;
bus->dev = dev;
dev_set_drvdata(dev, bus);
- init_waitqueue_head(&priv->wq);
-
/* set MII speed */
out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
@@ -167,13 +137,10 @@ static int fec_mdio_probe(struct of_devi
err = mdiobus_register(bus);
if (err)
- goto out_free_irq;
+ goto out_unmap;
return 0;
- out_free_irq:
- free_irq(priv->irq, dev);
- irq_dispose_mapping(priv->irq);
out_unmap:
iounmap(priv->regs);
out_free:
@@ -197,8 +164,6 @@ static int fec_mdio_remove(struct of_dev
mdiobus_unregister(bus);
dev_set_drvdata(dev, NULL);
- free_irq(priv->irq, dev);
- irq_dispose_mapping(priv->irq);
iounmap(priv->regs);
for (i=0; i<PHY_MAX_ADDR; i++)
if (bus->irq[i])
--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-10-02 12:49 ` [RFC PATCH v0.2] net driver: mpc52xx fec Sascha Hauer
@ 2007-10-02 14:32 ` Domen Puncer
2007-10-02 15:46 ` Robert Schwebel
0 siblings, 1 reply; 47+ messages in thread
From: Domen Puncer @ 2007-10-02 14:32 UTC (permalink / raw)
To: Sascha Hauer; +Cc: netdev, linuxppc-embedded
On 02/10/07 14:49 +0200, Sascha Hauer wrote:
>
> Hi Domen,
Hi Sascha!
>
> On Sun, Sep 02, 2007 at 09:41:43AM +0200, Domen Puncer wrote:
> + */
> > +static void fec_start(struct net_device *dev)
> > +{
> > + struct fec_priv *priv = netdev_priv(dev);
> > + struct mpc52xx_fec __iomem *fec = priv->fec;
> > + u32 rcntrl;
> > + u32 tcntrl;
> > + u32 tmp;
> > +
> > + /* clear sticky error bits */
> > + tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
> > + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
> > + out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
> > +
> > + /* FIFOs will reset on fec_enable */
> > + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
> > +
> > + /* Set station address. */
> > + fec_set_paddr(dev, dev->dev_addr);
> > +
> > + fec_set_multicast_list(dev);
> > +
> > + /* set max frame len, enable flow control, select mii mode */
> > + rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
> > + rcntrl |= FEC_RCNTRL_FCE;
> > + rcntrl |= MII_RCNTL_MODE;
> > + if (priv->duplex == DUPLEX_FULL)
> > + tcntrl = FEC_TCNTRL_FDEN; /* FD enable */
> > + else {
> > + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
> > + tcntrl = 0;
> > + }
> > + out_be32(&fec->r_cntrl, rcntrl);
> > + out_be32(&fec->x_cntrl, tcntrl);
> > +
> > + /* Clear any outstanding interrupt. */
> > + out_be32(&fec->ievent, 0xffffffff);
> > +
> > + /* Enable interrupts we wish to service. */
> > + out_be32(&fec->imask, FEC_IMASK_ENABLE);
>
>
> This disables phy interrupts.
Right, oops.
>
>
> > +static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> > +{
> > + struct fec_mdio_priv *priv = bus->priv;
> > + int tries = 100;
> > +
> > + u32 request = FEC_MII_READ_FRAME;
> > + request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> > + request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> > +
> > + out_be32(&priv->regs->mii_data, request);
> > +
> > + /* wait for it to finish, this takes about 23 us on lite5200b */
> > + while (priv->completed == 0 && tries--)
> > + udelay(5);
> > +
> > + priv->completed = 0;
> > +
> > + if (tries == 0)
> > + return -ETIMEDOUT;
>
> This does not work as expected. When a timeout occurs tries is -1 not 0,
> so the test above will never trigger.
> Using --tries instead of tries-- reveals another bug. We get a timeout
> everytime now, because MII interrupts are accidently disabled in
> fec_start().
Oh, double bug made it work! ;-)
>
> We cannot use a waitqueue or similar for waiting for the mii transfer
> because we are atomic here.
> A simple fix is provided below. It removes the need for the interrupt
> handler in the phy handling routines. Anyway, it might be better to fix
> the phy layer not to use atomic contexts, so this patch might not be the
> way to go.
Doh, looks like this was the problem with wq's, but I forgot to remove
them, when I "fixed" the code.
>
>
> Regards,
> Sascha
>
> +
> > +static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
> > +{
> > + struct device *dev = &of->dev;
> >
> > [...]
> >
> > + init_waitqueue_head(&priv->wq);
>
> This waitqueue is never used. wake_up() is called in the interrupt
> handler, but noone ever sleeps on the queue.
>
>
> ---
> drivers/net/fec_mpc52xx/fec.c | 7 +---
> drivers/net/fec_mpc52xx/fec_phy.c | 59 +++++++-------------------------------
> 2 files changed, 15 insertions(+), 51 deletions(-)
The patch looks ok to me.
Domen
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.2] net driver: mpc52xx fec
2007-10-02 14:32 ` Domen Puncer
@ 2007-10-02 15:46 ` Robert Schwebel
0 siblings, 0 replies; 47+ messages in thread
From: Robert Schwebel @ 2007-10-02 15:46 UTC (permalink / raw)
To: Domen Puncer; +Cc: netdev, linuxppc-embedded
On Tue, Oct 02, 2007 at 04:32:02PM +0200, Domen Puncer wrote:
> The patch looks ok to me.
Short update: even with the patch, the driver doesn't work on an
rt-preempt enabled kernel, or at least not reliable. It survives normal
traffic and ping -f, but dies when running nmap against the box, with a
set RFIFO_ERROR flag.
More research needs to be done.
Robert
--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-28 9:12 ` Juergen Beisert
2007-09-28 15:40 ` Scott Wood
@ 2007-10-08 8:48 ` Sascha Hauer
2007-10-08 9:01 ` Sascha Hauer
2 siblings, 0 replies; 47+ messages in thread
From: Sascha Hauer @ 2007-10-08 8:48 UTC (permalink / raw)
To: Juergen Beisert; +Cc: linuxppc-embedded
Hi,
On Fri, Sep 28, 2007 at 11:12:17AM +0200, Juergen Beisert wrote:
> I tried with in_atomic(). The BUG report is gone, but the problem still
> exists.
>
> While network stress testing:
>
> [...]
> NETDEV WATCHDOG: eth0: transmit timed out
> net eth0: transmit timed out
> net eth0: queues didn't drain
> net eth0: tx: index: 35, outdex: 36
> net eth0: rx: index: 24, outdex: 25
> PHY: f0003000:00 - Link is Down
> PHY: f0003000:00 - Link is Up - 100/Full
>
> The link is up again, but any connection is dead (no answers to ping etc.).
> But the serial console is still working. I'm not sure if the RT-Preempt patch
> *causes* this behavior or only *discover* it. Any idea?
We finally solved this problem. It has nothing to do with locking
though. The problem is that the bcom engine was not reenabled after
resetting the fec. The following patch solves this.
Reenable the bestcom engine after resetting the mpc52xx fec
controller.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/net/fec_mpc52xx/fec.c | 3 +++
1 file changed, 3 insertions(+)
Index: linux-2.6/drivers/net/fec_mpc52xx/fec.c
===================================================================
--- linux-2.6.orig/drivers/net/fec_mpc52xx/fec.c
+++ linux-2.6/drivers/net/fec_mpc52xx/fec.c
@@ -788,6 +788,9 @@ static void fec_reset(struct net_device
fec_alloc_rx_buffers(priv->rx_dmatsk);
+ bcom_enable(priv->rx_dmatsk);
+ bcom_enable(priv->tx_dmatsk);
+
fec_start(dev);
}
>
> Juergen
> --
> Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
> Pengutronix - Linux Solutions for Science and Industry
> Handelsregister: Amtsgericht Hildesheim, HRA 2686
> Vertretung Sued/Muenchen, Germany
> Phone: +49-8766-939 228 | Fax: +49-5121-206917-9
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-09-28 9:12 ` Juergen Beisert
2007-09-28 15:40 ` Scott Wood
2007-10-08 8:48 ` Sascha Hauer
@ 2007-10-08 9:01 ` Sascha Hauer
2007-10-08 16:46 ` Jon Smirl
2 siblings, 1 reply; 47+ messages in thread
From: Sascha Hauer @ 2007-10-08 9:01 UTC (permalink / raw)
To: Juergen Beisert; +Cc: linuxppc-embedded
On Fri, Sep 28, 2007 at 11:12:17AM +0200, Juergen Beisert wrote:
>
> While network stress testing:
>
> [...]
> NETDEV WATCHDOG: eth0: transmit timed out
> net eth0: transmit timed out
> net eth0: queues didn't drain
> net eth0: tx: index: 35, outdex: 36
> net eth0: rx: index: 24, outdex: 25
> PHY: f0003000:00 - Link is Down
> PHY: f0003000:00 - Link is Up - 100/Full
>
> The link is up again, but any connection is dead (no answers to ping etc.).
> But the serial console is still working. I'm not sure if the RT-Preempt patch
> *causes* this behavior or only *discover* it. Any idea?
While the previous patch I sent fixed the reset path for the fec
controller this patch makes sure the chip does not have to be resetted.
Problem was that we ran out of receive buffers when we nmapped our
board (nmap sends lots of small packages in a short period of time).
By increasing the number of rx buffers this problem does not appear
anymore.
This patch produces a significant memory overhead to the driver of about
340k, so we might want to have this configurable as a module parameter.
Let me know what the preferred way is, I can update the patch
accordingly.
Sascha
Increase the number of RX packets in the fec_mpc52xx driver. This is
necessary to no run out of rx packets when lots of small packets arrive
in short time (for example when nmapping the board)
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/net/fec_mpc52xx/fec.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-2.6/drivers/net/fec_mpc52xx/fec.h
===================================================================
--- linux-2.6.orig/drivers/net/fec_mpc52xx/fec.h
+++ linux-2.6/drivers/net/fec_mpc52xx/fec.h
@@ -19,7 +19,7 @@
/* Tunable constant */
/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
-#define FEC_RX_NUM_BD 64
+#define FEC_RX_NUM_BD 256
#define FEC_TX_NUM_BD 64
#define FEC_RESET_DELAY 50 /* uS */
--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de
^ permalink raw reply [flat|nested] 47+ messages in thread
* Re: [RFC PATCH v0.1] net driver: mpc52xx fec
2007-10-08 9:01 ` Sascha Hauer
@ 2007-10-08 16:46 ` Jon Smirl
0 siblings, 0 replies; 47+ messages in thread
From: Jon Smirl @ 2007-10-08 16:46 UTC (permalink / raw)
To: Sascha Hauer; +Cc: linuxppc-embedded
On 10/8/07, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> While the previous patch I sent fixed the reset path for the fec
> controller this patch makes sure the chip does not have to be resetted.
> Problem was that we ran out of receive buffers when we nmapped our
> board (nmap sends lots of small packages in a short period of time).
> By increasing the number of rx buffers this problem does not appear
> anymore.
> This patch produces a significant memory overhead to the driver of about
> 340k, so we might want to have this configurable as a module parameter.
> Let me know what the preferred way is, I can update the patch
> accordingly.
Is nmap sending UPD packets, why does the chip need to receive
everything without dropping packets? It we do get into receive
overrun, is everything recovering correctly?
As another test you could slow everything down by forcing the net to 10Mb.
It may be interesting to explore why the small packets aren't being
processed fast enough, there could be other bugs lurking.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 47+ messages in thread
end of thread, other threads:[~2007-10-08 16:46 UTC | newest]
Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-10 9:51 [RFC PATCH v0.1] net driver: mpc52xx fec Domen Puncer
2007-08-10 13:02 ` Arnaldo Carvalho de Melo
2007-08-13 7:21 ` Domen Puncer
2007-08-18 10:06 ` Domen Puncer
2007-08-19 15:39 ` Matt Sealey
2007-08-20 8:31 ` Domen Puncer
2007-08-20 13:13 ` Domen Puncer
2007-08-20 19:02 ` Matt Sealey
2007-08-21 5:49 ` Domen Puncer
2007-09-02 7:41 ` [RFC PATCH v0.2] " Domen Puncer
2007-09-03 15:57 ` Grant Likely
2007-09-03 16:09 ` Jon Smirl
2007-09-03 16:41 ` Grant Likely
2007-09-15 12:14 ` Domen Puncer
2007-09-17 9:53 ` Sven Luther
2007-09-17 20:21 ` [PATCH] phy: export phy_mii_ioctl Domen Puncer
2007-09-17 22:08 ` Jon Smirl
2007-09-18 15:16 ` Domen Puncer
2007-09-18 19:17 ` Jon Smirl
2007-09-19 11:56 ` Domen Puncer
2007-09-19 18:44 ` Jon Smirl
2007-09-19 21:18 ` Jon Smirl
2007-09-18 19:29 ` Jon Smirl
2007-09-19 8:54 ` Pedro Luis D. L.
2007-09-19 10:37 ` Juergen Beisert
2007-09-19 11:38 ` Pedro Luis D. L.
2007-09-19 14:51 ` Juergen Beisert
2007-09-19 15:11 ` Pedro Luis D. L.
2007-09-19 13:56 ` Jon Smirl
2007-09-19 14:31 ` Pedro Luis D. L.
2007-09-19 8:54 ` Pedro Luis D. L.
2007-09-20 6:36 ` Jeff Garzik
2007-10-02 12:49 ` [RFC PATCH v0.2] net driver: mpc52xx fec Sascha Hauer
2007-10-02 14:32 ` Domen Puncer
2007-10-02 15:46 ` Robert Schwebel
2007-09-27 17:07 ` [RFC PATCH v0.1] " Juergen Beisert
2007-09-27 18:12 ` Jon Smirl
2007-09-27 18:43 ` Scott Wood
2007-09-28 9:12 ` Juergen Beisert
2007-09-28 15:40 ` Scott Wood
2007-10-08 8:48 ` Sascha Hauer
2007-10-08 9:01 ` Sascha Hauer
2007-10-08 16:46 ` Jon Smirl
2007-09-28 15:07 ` Juergen Beisert
2007-09-28 15:38 ` Jon Smirl
2007-10-01 8:35 ` Juergen Beisert
2007-10-01 16:24 ` Juergen Beisert
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).