Skip to contentSkip to conversation

net driver: mpc52xx fec

RFC PATCH In review Domen Puncer 13 participants 47 messages Aug 10, 2007 – Oct 8, 2007

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 net driver: mpc52xx fec

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(-)
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +1002 -0
diff -pruN dummy/fec.c ./drivers/net/fec_mpc52xx/fec.c
@@ -0,0 +1,1002 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <[email protected]> and
+ * now maintained by Sylvain Munaut <[email protected]>
+ *
+ * Copyright (C) 2007  Sylvain Munaut <[email protected]>
+ * 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");
+
drivers/net/fec_mpc52xx/fec.h renamed from fec.h +299 -0

299 lines not on this page · raw message

drivers/net/fec_mpc52xx/fec_phy.c renamed from fec_phy.c +229 -0

229 lines not on this page · raw message

drivers/net/fec_mpc52xx/fec_phy.h renamed from fec_phy.h +49 -0

49 lines not on this page · raw message

drivers/net/fec_mpc52xx/Kconfig renamed from Kconfig +24 -0
diff -pruN dummy/Kconfig ./drivers/net/fec_mpc52xx/Kconfig
@@ -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
drivers/net/fec_mpc52xx/Makefile renamed from Makefile +7 -0
diff -pruN dummy/Makefile ./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
arch/powerpc/boot/dts/lite5200b.dts +17 -1
Index: 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 {
arch/powerpc/sysdev/bestcomm/fec.h +14 -0
Index: 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 *
#1 lore raw

Em Fri, Aug 10, 2007 at 11:51:53AM +0200, Domen Puncer escreveu:

Quoted 78 lines

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

drivers/net/fec_mpc52xx/fec.c renamed from fec.c +48 -0
@@ -0,0 +1,1002 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <[email protected]> and
+ * now maintained by Sylvain Munaut <[email protected]>
+ *
+ * Copyright (C) 2007  Sylvain Munaut <[email protected]>
+ * 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 *);

drivers/net/fec_mpc52xx/fec.c line 57

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +9 -0
+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

Quoted 13 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +13 -0
+
+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)

drivers/net/fec_mpc52xx/fec.c line 80

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10 -0
+		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

drivers/net/fec_mpc52xx/fec.c line 89

Quoted 9 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +9 -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

drivers/net/fec_mpc52xx/fec.c line 94

Quoted 5 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5 -0
+}
+
+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

drivers/net/fec_mpc52xx/fec.c line 99

Quoted 5 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5 -0
+
+	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

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10 -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);
+	}

drivers/net/fec_mpc52xx/fec.c line 119

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10 -0
+}
+
+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

Quoted 44 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +44 -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;

drivers/net/fec_mpc52xx/fec.c line 173

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10 -0
+		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

Quoted 797 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +797 -0
+}
+
+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
+};
+

drivers/net/fec_mpc52xx/fec.c line 980

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +10 -0
+
+/* ======================================================================== */
+/* 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

Quoted 711 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +22 -0
+		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

drivers/net/fec_mpc52xx/fec.h renamed from fec.h +299 -0
@@ -0,0 +1,299 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <[email protected]>
+ *
+ * 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

drivers/net/fec_mpc52xx/fec_phy.c renamed from fec_phy.c +229 -0
@@ -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

drivers/net/fec_mpc52xx/fec_phy.h renamed from fec_phy.h +49 -0
@@ -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 <[email protected]>
+ *
+ * 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

drivers/net/fec_mpc52xx/Kconfig renamed from Kconfig +24 -0
@@ -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

drivers/net/fec_mpc52xx/Makefile renamed from Makefile +7 -0
@@ -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
===================================================================

arch/powerpc/boot/dts/lite5200b.dts +17 -1
@@ -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
===================================================================

arch/powerpc/sysdev/bestcomm/fec.h +14 -1
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#2 lore raw
Quoted 4 lines · Arnaldo Carvalho de Melo

Em Fri, Aug 10, 2007 at 11:51:53AM +0200, Domen Puncer escreveu:

Quoted 1 line

+static u8 null_mac[6];

const

OK.

...

Quoted 9 lines

drivers/net/fec_mpc52xx/fec.c line 80

Quoted 7 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +7 -0
+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]));

Quoted 12 lines

drivers/net/fec_mpc52xx/fec.c line 89

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +9 -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.

Quoted 8 lines

drivers/net/fec_mpc52xx/fec.c line 94

Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5 -0
+}
+
+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.

Quoted 8 lines

drivers/net/fec_mpc52xx/fec.c line 99

Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5 -0
+
+	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.

Quoted 15 lines
Quoted 15 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +14 -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)
+{
Quoted 8 lines

drivers/net/fec_mpc52xx/fec.c line 119

Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +6 -0
+	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.

Quoted 3 lines
Quoted 3 lines
(quoted diff) +2 -0
+			return -EAGAIN;
+

...

Quoted 6 lines

drivers/net/fec_mpc52xx/fec.c line 173

Quoted 4 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +4 -0
+
+	if (new_state && netif_msg_link(priv)) {
+		phy_print_status(phydev);
+	}

No need for {}, this if has only one statement

OK.

...

Quoted 8 lines

drivers/net/fec_mpc52xx/fec.c line 980

Quoted 5 lines
drivers/net/fec_mpc52xx/fec.c renamed from fec.c +5 -0
+static int __init
+mpc52xx_fec_init(void)
+{
+	int ret;
+	if ((ret = fec_mdio_init())) {

Why not:

Quoted 4 lines
	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

#3 lore raw
In reply to Domen Puncer

Hi!

Quoted 8 lines · Domen Puncer

Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================

arch/powerpc/boot/dts/lite5200b.dts +4 -0
+		mdio@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";

arch/powerpc/boot/dts/lite5200b.dts line 388

Quoted 10 lines
arch/powerpc/boot/dts/lite5200b.dts +9 -0
+			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

#4 lore raw

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.

Signature · 2 lines
Matt Sealey <[email protected]>
Genesi, Manager, Developer Relations
Quoted 35 lines · Domen Puncer

Hi!

Quoted 8 lines · Domen Puncer

Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================

arch/powerpc/boot/dts/lite5200b.dts +4 -0
+		mdio@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";

arch/powerpc/boot/dts/lite5200b.dts line 388

Quoted 10 lines
arch/powerpc/boot/dts/lite5200b.dts +9 -0
+			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

#5 lore raw
Quoted 5 lines · Matt Sealey

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>

Quoted 3 lines

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

Quoted 37 lines
Quoted 27 lines · Domen Puncer
Quoted 8 lines

Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================

arch/powerpc/boot/dts/lite5200b.dts +4 -0
+		mdio@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";

arch/powerpc/boot/dts/lite5200b.dts line 388

Quoted 10 lines
arch/powerpc/boot/dts/lite5200b.dts +9 -0
+			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.

Quoted 6 lines

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
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

#6 lore raw
Quoted 9 lines · Domen Puncer
Quoted 5 lines · Matt Sealey

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.

...

Quoted 3 lines

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

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

#7 lore raw

Are you sure this is correct for the Efika?

The MPC5200B manual makes a decent distinction between MII operation and straight MDIO?

Signature · 2 lines
Matt Sealey <[email protected]>
Genesi, Manager, Developer Relations
Quoted 20 lines · Domen Puncer
Quoted 8 lines · Domen Puncer
Quoted 5 lines · Matt Sealey

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.

...

Quoted 3 lines

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

#8 lore raw
Quoted 1 line · Matt Sealey

Are you sure this is correct for the Efika?

It works (tm).

Quoted 3 lines

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

Quoted 26 lines
Signature · 3 lines
-- 
Matt Sealey <[email protected]>
Genesi, Manager, Developer Relations
Quoted 20 lines · Domen Puncer
Quoted 8 lines · Domen Puncer
Quoted 5 lines · Matt Sealey

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.

...

Quoted 3 lines

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

#9 lore raw

RFC PATCH 1/1 net driver: mpc52xx fec

In reply to Domen Puncer

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).

---
 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(-)
drivers/net/Kconfig +1 -0
Index: 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
drivers/net/Makefile +1 -0
Index: 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/
 
arch/powerpc/boot/dts/lite5200b.dts +17 -1
Index: 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 {
arch/powerpc/sysdev/bestcomm/fec.h +14 -1
Index: 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 *
drivers/net/fec_mpc52xx/Kconfig new file +25 -0
Index: 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
drivers/net/fec_mpc52xx/Makefile new file +7 -0
Index: 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
drivers/net/fec_mpc52xx/fec.c new file +1127 -0

1,127 lines not on this page · raw message

drivers/net/fec_mpc52xx/fec.h new file +329 -0

329 lines not on this page · raw message

drivers/net/fec_mpc52xx/fec_phy.c new file +238 -0

238 lines not on this page · raw message

#10 lore raw
Quoted 7 lines · Domen Puncer

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.

Quoted 16 lines
drivers/net/fec_mpc52xx/Kconfig new file +13 -0
@@ -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
+

drivers/net/fec_mpc52xx/Kconfig line 23

Quoted 10 lines
drivers/net/fec_mpc52xx/Kconfig new file +10 -0
+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.

Quoted 7 lines
drivers/net/fec_mpc52xx/Kconfig new file +2 -0
+
+endmenu

Index: linux.git/drivers/net/fec_mpc52xx/Makefile
===================================================================

drivers/net/fec_mpc52xx/Makefile line 7

Quoted 7 lines
drivers/net/fec_mpc52xx/Makefile new file +7 -0
@@ -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.

Quoted 51 lines

Index: linux.git/drivers/net/fec_mpc52xx/fec.c
===================================================================

drivers/net/fec_mpc52xx/fec.c new file +46 -0
@@ -0,0 +1,1127 @@
+/*
+ * drivers/drivers/net/fec_mpc52xx/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <[email protected]> and
+ * now maintained by Sylvain Munaut <[email protected]>
+ *
+ * Copyright (C) 2007  Domen Puncer, Telargo, Inc.
+ * Copyright (C) 2007  Sylvain Munaut <[email protected]>
+ * 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"

drivers/net/fec_mpc52xx/fec.c line 56

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c new file +10 -0
+
+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?

drivers/net/fec_mpc52xx/fec.c line 58

Quoted 2 lines
drivers/net/fec_mpc52xx/fec.c new file +2 -0
+
+static u8 mpc52xx_fec_mac_addr[6];

Why isn't this part of struct fec_priv?

drivers/net/fec_mpc52xx/fec.c line 59

Quoted 1 line
drivers/net/fec_mpc52xx/fec.c new file +1 -0
+static const u8 null_mac[6];

null_mac?!? Just for comparing a mac addr against 0?

<snip>

drivers/net/fec_mpc52xx/fec.c line 60

Quoted 1 line
drivers/net/fec_mpc52xx/fec.c new file +1 -0
+#ifdef CONFIG_FEC_MPC52xx_MDIO

Once again; don't make this a conditional compile; detect at runtime.

<snip>

Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c new file +6 -0
+static void __init fec_str2mac(char *str, unsigned char *mac)
+{
+       int i;
+       u64 val64;
+
+       val64 = simple_strtoull(str, NULL, 16);

drivers/net/fec_mpc52xx/fec.c line 651

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c new file +10 -0
+
+       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.

Quoted 3 lines
drivers/net/fec_mpc52xx/fec.c new file +3 -0
+
+__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
+
Signature · 4 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
[email protected]
(403) 399-0195
#11 lore raw
Quoted 9 lines · Grant Likely
Quoted 7 lines · Domen Puncer

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

Quoted 6 lines

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

Signature · 2 lines
Jon Smirl
[email protected]
#12 lore raw
Quoted 12 lines · Jon Smirl
Quoted 11 lines · Grant Likely
Quoted 7 lines · Domen Puncer

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...

Quoted 7 lines
Quoted 4 lines

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.

Signature · 4 lines
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
[email protected]
(403) 399-0195
#13 lore raw
In reply to Grant Likely
Quoted 10 lines · Grant Likely
Quoted 7 lines · Domen Puncer

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.

Quoted 5 lines

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.

Quoted 29 lines
Quoted 10 lines
drivers/net/fec_mpc52xx/Kconfig new file +10 -0
+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
+

drivers/net/fec_mpc52xx/Kconfig line 23

Quoted 10 lines
drivers/net/fec_mpc52xx/Kconfig new file +10 -0
+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.

Quoted 3 lines

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.

Quoted 11 lines

drivers/net/fec_mpc52xx/fec.c line 56

Quoted 9 lines
drivers/net/fec_mpc52xx/fec.c new file +9 -0
+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.

Quoted 5 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+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=?

Quoted 4 lines
Quoted 2 lines

+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.

Quoted 28 lines

<snip>

Quoted 1 line

+#ifdef CONFIG_FEC_MPC52xx_MDIO

Once again; don't make this a conditional compile; detect at runtime.

<snip>

Quoted 6 lines
drivers/net/fec_mpc52xx/fec.c new file +6 -0
+static void __init fec_str2mac(char *str, unsigned char *mac)
+{
+       int i;
+       u64 val64;
+
+       val64 = simple_strtoull(str, NULL, 16);

drivers/net/fec_mpc52xx/fec.c line 651

Quoted 10 lines
drivers/net/fec_mpc52xx/fec.c new file +10 -0
+
+       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.

Quoted 4 lines

drivers/net/fec_mpc52xx/fec.c line 654

Quoted 3 lines
drivers/net/fec_mpc52xx/fec.c new file +3 -0
+
+__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

Quoted 11 lines
Signature · 9 lines
-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
[email protected]
(403) 399-0195
_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
#14 lore raw
Quoted 4 lines · Domen Puncer

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

#15 lore raw

PATCH 1/1 phy: export phy_mii_ioctl

Export phy_mii_ioctl, so network drivers can use it when built as modules too.

---

Quoted 11 lines · Sven Luther
Quoted 4 lines · Domen Puncer

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!

Quoted 8 lines

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(+)
drivers/net/phy/phy.c +1 -0
Index: 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
#16 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

Quoted 2 lines · Domen Puncer

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/

drivers/net/fec_mpc52xx/fec.c +4 -2
index 922e9a8..c4442e0 100644
@@ -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
 }
Quoted 47 lines

---

Quoted 11 lines · Sven Luther
Quoted 4 lines · Domen Puncer

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!

Quoted 8 lines

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
===================================================================

drivers/net/phy/phy.c +1 -0
@@ -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
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

Signature · 2 lines
Jon Smirl
[email protected]
#17 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

(I edited Cc: -jeff, +sven, hope you don't mind)

Quoted 12 lines · Jon Smirl
Quoted 2 lines · Domen Puncer

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

Quoted 6 lines

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

#18 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

Quoted 2 lines · Domen Puncer

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);

Signature · 2 lines
Jon Smirl
[email protected]
#19 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

Quoted 4 lines · Jon Smirl
Quoted 2 lines · Domen Puncer

More testing and getting it to work properly on Phytec pcm030 would be great.

Quoted 8 lines

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(-)
drivers/net/fec_mpc52xx/fec.c +2 -16
Index: 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
#20 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

Quoted 3 lines · Domen Puncer

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'

Signature · 2 lines
Jon Smirl
[email protected]
#21 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

Quoted 1 line · Jon Smirl

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

Signature · 2 lines
Jon Smirl
[email protected]
#22 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

In reply to Domen Puncer
Quoted 2 lines · Domen Puncer

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.

Signature · 2 lines
Jon Smirl
[email protected]
#23 lore raw

RE: [PATCH] phy: export phy_mii_ioctl

Hello Jon,
I´m also working with a Phytec pcm030, but I can´t 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´m 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 = 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 =  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.

Quoted 11 lines

Date: Tue, 18 Sep 2007 15:29:09 -0400> From: [email protected]
To: [email protected]> Subject: Re: [PATCH] phy: export phy_mii_ioctl
CC: [email protected]; [email protected]

Quoted 4 lines · Domen Puncer

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 .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

Quoted 8 lines
Quoted 1 line

What is happening is the printk for "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.

Quoted 1 line

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.

Quoted 1 line
Quoted 1 line

--> Jon Smirl> [email protected]

_______________________________________________
Linuxppc-embedded mailing list> [email protected]> https://ozlabs.org/mailman/listinfo/linuxppc-embedded

_________________________________________________________________
Busca desde cualquier página Web con una protección excepcional. Consigue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com

#24 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

Pedro,

Quoted 6 lines · Pedro Luis D. L.

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

Quoted 8 lines

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
Quoted 7 lines

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

#25 lore raw

RE: [PATCH] phy: export phy_mii_ioctl

Quoted 7 lines · Juergen

Pedro,

Quoted 3 lines · Pedro Luis D. L.

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

Quoted 3 lines
Quoted 3 lines

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

Quoted 14 lines
Quoted 14 lines

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

Quoted 3 lines
Quoted 1 line

(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

Quoted 1 line

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 :-(

Quoted 9 lines

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=

#26 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

Pedro,

Quoted 1 line · Pedro Luis D. L.

I=B4m using an specific pcm030.dts oftree that works for the 2.6.20 kerne=

l.

Quoted 1 line

I=B4m not quite familiar with the oftree stuff, but I thought it should w=

ork

Quoted 1 line

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

#27 lore raw

RE: [PATCH] phy: export phy_mii_ioctl

Quoted 5 lines

Pedro,
=20

Quoted 1 line · Pedro Luis D. L.

I=B4m using an specific pcm030.dts oftree that works for the 2.6.20 kern=

el.

Quoted 1 line
Quoted 1 line

I=B4m not quite familiar with the oftree stuff, but I thought it should =

work

Quoted 3 lines
Quoted 1 line

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.

Quoted 7 lines

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=

#28 lore raw

Re: [PATCH] phy: export phy_mii_ioctl

In reply to Pedro Luis D. L.
Quoted 5 lines · Pedro Luis D. L.

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.

Quoted 2 lines

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.

Quoted 7 lines

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
Quoted 7 lines

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
[email protected]

#29 lore raw

RE: [PATCH] phy: export phy_mii_ioctl

Quoted 6 lines · Jon Smirl
Quoted 5 lines · Pedro Luis D. L.

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.

Quoted 2 lines
Quoted 2 lines

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.

Quoted 13 lines
Quoted 13 lines

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

Quoted 2 lines
Quoted 1 line

(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=

#30 lore raw

RE: [PATCH] phy: export phy_mii_ioctl

In reply to Jon Smirl

Hello Jon,
I´m also working with a Phytec pcm030, but I can´t 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´m 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 = 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 =  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.

Quoted 11 lines

Date: Tue, 18 Sep 2007 15:29:09 -0400> From: [email protected]
To: [email protected]> Subject: Re: [PATCH] phy: export phy_mii_ioctl
CC: [email protected]; [email protected]

Quoted 4 lines · Domen Puncer

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 .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

Quoted 8 lines
Quoted 1 line

What is happening is the printk for "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.

Quoted 1 line

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.

Quoted 1 line
Quoted 1 line

--> Jon Smirl> [email protected]

_______________________________________________
Linuxppc-embedded mailing list> [email protected]> https://ozlabs.org/mailman/listinfo/linuxppc-embedded

_________________________________________________________________
Busca desde cualquier página Web con una protección excepcional. Consigue la Barra de herramientas de Windows Live hoy mismo y GRATUITAMENTE.
http://www.toolbar.live.com

#32 lore raw
In reply to Domen Puncer

Hi Domen,

On Sun, Sep 02, 2007 at 09:41:43AM +0200, Domen Puncer wrote:
+ */

Quoted 29 lines
(quoted diff) +29 -0
+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) */

Review

Quoted 10 lines
(quoted diff) +10 -0
+		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.

Quoted 9 lines
(quoted diff) +9 -0
+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;
+

Review

Quoted 10 lines
(quoted diff) +10 -0
+	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

+

Review

Quoted 7 lines
(quoted diff) +4 -0
+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(-)
drivers/net/fec_mpc52xx/fec.c +3 -4
Index: 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);
drivers/net/fec_mpc52xx/fec_phy.c +12 -47

131 lines not on this page · raw message

--
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord http://www.pengutronix.de

#33 lore raw
Quoted 2 lines · Sascha Hauer

Hi Domen,

Hi Sascha!

Quoted 37 lines · Domen Puncer

+ */

Quoted 34 lines
(quoted diff) +34 -0
+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);
+
Quoted 8 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+	/* 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.

Quoted 19 lines
Quoted 19 lines
(quoted diff) +17 -0
+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;
+
Quoted 8 lines

Review

Quoted 2 lines
(quoted diff) +2 -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! ;-)

Quoted 7 lines

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.

Quoted 18 lines

Regards,
Sascha

+

Review

Quoted 7 lines
(quoted diff) +4 -0
+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.

Quoted 4 lines
---
 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

#34 lore raw
Quoted 1 line · Domen Puncer

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

Signature · 2 lines
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de
#35 lore raw
In reply to Domen Puncer
Quoted 9 lines · Domen Puncer

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

#36 lore raw
Quoted 32 lines · Juergen Beisert
Quoted 9 lines · Domen Puncer

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
Quoted 1 line

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.

Signature · 2 lines
Jon Smirl
[email protected]
#37 lore raw
Quoted 11 lines · Jon Smirl

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

#38 lore raw
Quoted 13 lines · Scott Wood
Quoted 12 lines · Jon Smirl

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?

Quoted 3 lines
Quoted 1 line

(!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

#39 lore raw
Quoted 13 lines · Juergen Beisert

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
Quoted 1 line

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

#40 lore raw
In reply to Juergen Beisert

Hi,

Quoted 14 lines · Juergen Beisert

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
Quoted 3 lines

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.

---
 drivers/net/fec_mpc52xx/fec.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/net/fec_mpc52xx/fec.c +3 -0
Index: 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);
 }
 
Quoted 12 lines

Juergen

Signature · 9 lines
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
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
Signature · 2 lines
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de
#41 lore raw
In reply to Juergen Beisert
Quoted 12 lines · Juergen Beisert

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
Quoted 3 lines

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)

---
 drivers/net/fec_mpc52xx/fec.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/fec_mpc52xx/fec.h +1 -1
Index: 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 */
Signature · 2 lines
Pengutronix - Linux Solutions for Science and Industry
Entwicklungszentrum Nord     http://www.pengutronix.de
#42 lore raw
Quoted 10 lines · Sascha Hauer

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.

Signature · 2 lines
Jon Smirl
[email protected]
#43 lore raw
In reply to Juergen Beisert
Quoted 10 lines · Juergen Beisert
Quoted 9 lines · Domen Puncer

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

#44 lore raw
Quoted 2 lines · Juergen Beisert

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.

Signature · 2 lines
Jon Smirl
[email protected]
#45 lore raw
Quoted 2 lines · Jon Smirl
Quoted 1 line · Juergen Beisert

But I can't run it a second time, as the network on target's side doesn=

't

Quoted 3 lines
Quoted 1 line

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

#46 lore raw
Quoted 55 lines · Juergen Beisert

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

Quoted 4 lines

...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