* Re: ioctl32 unknown cmds with 2.6.24-rc1
From: Geert Uytterhoeven @ 2007-10-25 14:51 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, Johannes Berg
In-Reply-To: <200710251620.50218.arnd@arndb.de>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1797 bytes --]
On Thu, 25 Oct 2007, Arnd Bergmann wrote:
> On Thursday 25 October 2007, Geert Uytterhoeven wrote:
> > If you want to look into this, the question is just why these messages are
> > printed now, while they weren't printed before. I don't think any other
> > behavior got changed.
>
> I'm not so sure about that. The reason that the messages are printed now
> is that there is no fallback handler for these ioctl numbers any more,
> but they are instead expected to be handled by the compat_blkdev_ioctl()
> function, which is only called for block devices.
>
> My first idea was that the ioctl numbers are used on files that are
> not block devices, in this case the warning message would be (somewhat)
> appropriate.
>
> Whenever we get one of these messages on a real block device, that is
> supposed to mean that an ioctl that was actually valid could not be
> executed, and compat_blkdev_ioctl() returned -ENOIOCTLCMD.
In many cases these ioctls can indeed not be handled.
E.g. when using `hdparm -tT /dev/ps3da', hdparm issues an ioctl to flush the
cache. But this ioctl is not supported, not before and not after 2.6.23.
Before 2.6.23, it didn't print the message, in 2.6.23, it does.
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619
^ permalink raw reply
* Re: libfdt: Remove un-const-safe fdt_set_header macro
From: Jon Loeliger @ 2007-10-25 14:49 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20071025042938.GD24856@localhost.localdomain>
So, like, the other day David Gibson mumbled:
> The fdt_set_header() macro casts an arbitrary pointer into (struct
> fdt_header *) to set fdt header fields. While we need to change the
> type, so that we can use this macro on the usual (void *) used to
> represent a device tree blob, the current macro also casts away any
> const on the input pointer, which loses an important check.
>
> This patch replaces the fdt_set_header() macro with a set of inline
> functions, one for each header field which do a similar thing, but
> which won't silently remove const from a given pointer. This approach
> is also more in keeping with the individual accessor macros we use for
> reading fdt header fields.
>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Applied.
jdl
^ permalink raw reply
* Re: [PATCH 01/11] [POWERPC] Add 'machine: ...' line to common show_cpuinfo()
From: Marian Balakowicz @ 2007-10-25 14:47 UTC (permalink / raw)
To: Milton Miller; +Cc: linuxppc-dev, Stephen Rothwell
In-Reply-To: <200710250433.l9P4XE8N038953@sullivan.realtime.net>
Milton Miller wrote:
> On Wed Oct 24 17:11:29 EST 2007, Stephen Rothwell wrote:
>> On Wed, 24 Oct 2007 01:13:09 +0200 Marian Balakowicz wrote:
>>> + root = of_find_node_by_path("/");
>>> + if (root)
>>> + model = of_get_property(root, "model", NULL);
>>> + of_node_put(root);
>> The paranoid part of me says:
>>
>> if (model)
>>
>>> + seq_printf(m, "machine\t\t: %s\n", model);
>
> My thoughts too (don't fail if no model property in /), and that
> means that
>
>>> + const char *model = "";
>
> can change to
> + const char *model = NULL;
>
>
>
> However, a quick grep shows there are several platforms that print
> out machine\t\t: something in show_cpuinfo. Some are fixed strings
> (eg linkstation, holly, iSeries), some print model with a fallback
> (powermac), some augment the model (chrp, pseries, cell), some print
> something else (52xx/efika). There are others. All of those need
> to be dealt with or another tag chosen.
That's true, there is pretty wide range of different approaches. I
would opt for using a different tag and letting the platforms use
their custom machine string if they desire so. How about "model\t\t:
..."? It's not conflicting and self-explanatory too.
Cheers,
m.
^ permalink raw reply
* Re: PCI on Lite5200/Icecube, known issues?
From: Grant Likely @ 2007-10-25 14:45 UTC (permalink / raw)
To: Wolfgang Grandegger; +Cc: linuxppc-embedded
In-Reply-To: <4720A628.8010108@grandegger.com>
On 10/25/07, Wolfgang Grandegger <wg@grandegger.com> wrote:
> Hello,
>
> The access to PCI memory space does not to work (I allways read 0xff) on
> my Icecube-Eval-Board. Are there any known issues/bugs with using the
> PCI on the Lite5200/Icecube board with 2.6.23? Has it been tested? I
> realized, that CONFIG_PCI is not set in the default configuration.
arch/ppc or arch/powerpc?
I'm not a PCI expert, but I just fired up my Lite5200 with a couple of
eth adapters plugged in and the devices are usable. This is a
2.6.24-rc1 arch/powerpc kernel.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: libfdt: Documentation (patch the second)
From: Jon Loeliger @ 2007-10-25 14:38 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20071025012731.GA24856@localhost.localdomain>
So, like, the other day David Gibson mumbled:
> Add documentation for another handful of libfdt functions to libfdt.h
>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Applied.
jdl
^ permalink raw reply
* USB Host Controlle for MPC855/MPC8xx in linux 2.4?
From: hamed khateb @ 2007-10-25 14:38 UTC (permalink / raw)
To: linuxppc-embedded
Hi
anyone has driver for USB Host Controlle for MPC855/MPC8xx in linux 2.4?
I read in the Archives mail which was sended by Henrik , Henrink use the driver of Brad Parker's for MPC875 (or MPC8xx) , so any one know how I can contact Henrik or Brad Parker's?
this is the link of the email of Henrik : http://ozlabs.org/pipermail/linuxppc-embedded/2007-October/028566.html
Best Regards
Hamid
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
^ permalink raw reply
* RFS for PPC
From: vishnuvaradan vishnuvaradan @ 2007-10-25 14:36 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 211 bytes --]
Hi
I can able to find RFS for ppc in denx website
But that RFS does not support X windows
Any Pre-compiled RFS for ppc is available ?
or
Help me to create RFS including X window support for ppc
Regards
Vishnu
[-- Attachment #2: Type: text/html, Size: 248 bytes --]
^ permalink raw reply
* Re: USB Host Controller MPC875 Linux 2.6
From: hamed khateb @ 2007-10-25 14:19 UTC (permalink / raw)
To: linuxppc-embedded
Hi
Can I accept the email address of Henrik , I would like to ask him about driver for USB Host Controlle for MPC8xx in linux 2.4
Best regards
Hamid
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
^ permalink raw reply
* Re: ioctl32 unknown cmds with 2.6.24-rc1
From: Arnd Bergmann @ 2007-10-25 14:20 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Geert Uytterhoeven, Johannes Berg
In-Reply-To: <Pine.LNX.4.62.0710251542500.3812@pademelon.sonytel.be>
On Thursday 25 October 2007, Geert Uytterhoeven wrote:
> If you want to look into this, the question is just why these messages are
> printed now, while they weren't printed before. I don't think any other
> behavior got changed.
I'm not so sure about that. The reason that the messages are printed now
is that there is no fallback handler for these ioctl numbers any more,
but they are instead expected to be handled by the compat_blkdev_ioctl()
function, which is only called for block devices.
My first idea was that the ioctl numbers are used on files that are
not block devices, in this case the warning message would be (somewhat)
appropriate.
Whenever we get one of these messages on a real block device, that is
supposed to mean that an ioctl that was actually valid could not be
executed, and compat_blkdev_ioctl() returned -ENOIOCTLCMD.
Arnd <><
^ permalink raw reply
* Re: [linux-usb-devel] [PATCH 1/2] USB: Rework OHCI PPC OF for new bindings
From: Grant Likely @ 2007-10-25 14:21 UTC (permalink / raw)
To: Valentine Barshak; +Cc: David Brownell, linux-usb-devel, linuxppc-dev
In-Reply-To: <47208273.8050601@ru.mvista.com>
On 10/25/07, Valentine Barshak <vbarshak@ru.mvista.com> wrote:
> Grant Likely wrote:
> > On 10/24/07, David Brownell <david-b@pacbell.net> wrote:
> >> On Wednesday 24 October 2007, Matt Sealey wrote:
> >>> Can we just make sure real quickly that the changing of compatibles
> >>> doesn't break existing, not-easily-flashable firmwares?
> >> Yeah, I'm not keen on such breakage either...
> >
> > Add my voice to the chorus. It's okay to change the binding, but make
> > sure the old binding is still supported.
> >
> > Cheers,
> > g.
> >
>
> Actually, I thought that changing the DTS stuff for mpc52xx boards would
> suffice. Sorry, I was unaware of Efika firmware here. I'll keep old
> bindings as well.
Even if that were the case; I'm nervous about breaking compatibility
with old device trees.
We probably need a formal guideline here. ie. When is it okay to drop
compatibility with old dts files?
> Does the device tree have "ohci-bigendian" or "ohci-be" compatible
> property on Efika?
If it doesn't, it can be added during prom_init.c We're already doing
a bunch of efika fixups there anyway.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* PCI on Lite5200/Icecube, known issues?
From: Wolfgang Grandegger @ 2007-10-25 14:20 UTC (permalink / raw)
To: linuxppc-embedded
Hello,
The access to PCI memory space does not to work (I allways read 0xff) on
my Icecube-Eval-Board. Are there any known issues/bugs with using the
PCI on the Lite5200/Icecube board with 2.6.23? Has it been tested? I
realized, that CONFIG_PCI is not set in the default configuration.
Thanks,
Wolfgang.
^ permalink raw reply
* Re: [PATCH 01/11] [POWERPC] Add 'machine: ...' line to common show_cpuinfo()
From: Marian Balakowicz @ 2007-10-25 14:17 UTC (permalink / raw)
To: David Gibson, linuxppc-dev
In-Reply-To: <20071023232303.GA10595@localhost.localdomain>
David Gibson wrote:
> On Wed, Oct 24, 2007 at 01:13:09AM +0200, Marian Balakowicz wrote:
>> Print out '/model' property as a machine name in generic
>> show_cpuinfo() routine.
>
> There's no such thing as /model; subnodes and properties have a
> different namespace, so the root node, /, has a property named
> 'model'.
>
> Yes, it's clear what you mean in this context, but it's a bad habit to
> get into.
Right, I'll try to make it more clear, thanks for pointing this out.
Cheers,
m.
^ permalink raw reply
* Re: [PATCH v4] FEC - fast ethernet controller for mpc52xx
From: Domen Puncer @ 2007-10-25 14:10 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linuxppc-dev, netdev
In-Reply-To: <47206209.8080109@pobox.com>
On 25/10/07 05:29 -0400, Jeff Garzik wrote:
> Domen Puncer wrote:
> >+static int mpc52xx_fec_alloc_rx_buffers(struct bcom_task *rxtsk)
> >+{
> >+ while (!bcom_queue_full(rxtsk)) {
> >+ struct sk_buff *skb;
> >+ struct bcom_fec_bd *bd;
> >+
> >+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
> >+ if (skb == NULL)
> >+ return -EAGAIN;
> >+
> >+ /* zero out the initial receive buffers to aid debugging */
> >+ memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
> >+
> >+ bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
> >+
> >+ bd->status = FEC_RX_BUFFER_SIZE;
> >+ bd->skb_pa = virt_to_phys(skb->data);
> >+
> >+ bcom_submit_next_buffer(rxtsk, skb);
>
> use your platform's dma mapping functions, rather than virt_to_phys()
>
> it might be the exact same implementation, inside the platform
> internals, but drivers should not be using this directly.
I've replaced this with dma_map_single(), unmatched with
dma_unmap_single(), since bestcomm doesn't have a way to do that
and it's blank on ppc32 anyway.
Is this OK? PPC guys?
>
> >+{
> >+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> >+ int err = -EBUSY;
> >+
> >+ if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_DISABLED |
> >IRQF_SHARED,
>
> why IRQF_DISABLED? that should not be needed.
Removed all three occurances.
> >+ bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC;
> >+ bd->skb_pa = virt_to_phys(skb->data);
>
> use dma_xxx
dma_map_single
>
> >+ bcom_submit_next_buffer(priv->tx_dmatsk, skb);
> >+
> >+ if (bcom_queue_full(priv->tx_dmatsk)) {
> >+ priv->tx_full = 1;
>
> no need for your own tx_full variable
I'm not sure what I should do here.
It does it internally, so just removing tx_full is OK?
> >+ dev_kfree_skb_irq(skb);
> >+ }
> >+
> >+ if (netif_queue_stopped(dev) && !priv->tx_full)
>
> no need to test netif_queue_stopped(), netif_wake_queue() does that anyway
>
> no need for tx_full
OK.
> >+static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
> >+{
> >+ struct net_device *dev = dev_id;
> >+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> >+ struct mpc52xx_fec __iomem *fec = priv->fec;
> >+ u32 ievent;
> >+
> >+ ievent = in_be32(&fec->ievent);
>
> generally wise to check for 0xffffffff, which often indicates hardware
> fault / device not there / scrogged
It's on the CPU, so it has to be there :-)
dev_warn and fec_reset would catch that anyway.
>
>
> >+ 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");
> >+
> >+ mpc52xx_fec_reset(dev);
> >+
> >+ netif_wake_queue(dev);
> >+ return IRQ_HANDLED;
> >+}
> >+
> >+
> >+ memset(&priv->stats, 0, sizeof(priv->stats));
>
> don't use your own copy of net_device_stats, it's in net_device now
Nice. OK.
>
>
> >+/*
> >+ * Set or clear the multicast filter for this adaptor.
> >+ */
> >+static void mpc52xx_fec_set_multicast_list(struct net_device *dev)
> >+{
> >+ struct mpc52xx_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);
>
> fall back to ALLMULTI behavior if dev->mc_count is too large (for your
> chip's version of "too large")
Uh, as far as I understand, this gaddr is some mask of which packages to
receive? IOW. if dmi_addrs are just right, it'll become IFF_ALLMULTI
anyway.
>
> >+/* ethtool interface */
> >+static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
> >+ struct ethtool_drvinfo *info)
> >+{
> >+ strcpy(info->driver, DRIVER_NAME);
>
> version? anything else?
Version is Linux version. What else?
I think the only reason I implemented this was because some tool
didn't want to play without it.
>
>
> >+ ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
> >+ ndev->flags &= ~IFF_RUNNING;
>
> delete this, no reason to ever touch IFF_RUNNING yourself
OK.
>
> >+ if (!is_zero_ether_addr(mpc52xx_fec_mac_addr))
> >+ memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
> >+ else
> >+ mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
> >+
> >+ priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
>
> netif_msg_init
OK. Also added "debug" module parameter now.
>
>
> >+mpc52xx_fec_remove(struct of_device *op)
> >+{
> >+ struct net_device *ndev;
> >+ struct mpc52xx_fec_priv *priv;
> >+
> >+ ndev = dev_get_drvdata(&op->dev);
> >+ if (!ndev)
> >+ return 0;
>
> testing for impossible condition
Removed now.
Version incorporating fixes:
--- cut here ;-) ---
Driver for ethernet on mpc5200/mpc5200b SoCs (FEC).
Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
---
drivers/net/Kconfig | 24
drivers/net/Makefile | 4
drivers/net/fec_mpc52xx.c | 1109 ++++++++++++++++++++++++++++++++++++++++++
drivers/net/fec_mpc52xx.h | 313 +++++++++++
drivers/net/fec_mpc52xx_phy.c | 198 +++++++
5 files changed, 1648 insertions(+)
Index: linux.git/drivers/net/Kconfig
===================================================================
--- linux.git.orig/drivers/net/Kconfig
+++ linux.git/drivers/net/Kconfig
@@ -1880,6 +1880,30 @@ config FEC2
Say Y here if you want to use the second built-in 10/100 Fast
ethernet controller on some Motorola ColdFire processors.
+config FEC_MPC52xx
+ tristate "MPC52xx FEC driver"
+ depends on PPC_MPC52xx
+ select PPC_BESTCOMM
+ select PPC_BESTCOMM_FEC
+ select CRC32
+ select PHYLIB
+ ---help---
+ This option enables support for the MPC5200's on-chip
+ Fast Ethernet Controller
+ If compiled as module, it will be called 'fec_mpc52xx.ko'.
+
+config FEC_MPC52xx_MDIO
+ bool "MPC52xx FEC MDIO bus driver"
+ depends on FEC_MPC52xx
+ 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 connected to FEC, enable this.
+ If not sure, enable.
+ If compiled as module, it will be called 'fec_mpc52xx_phy.ko'.
+
config NE_H8300
tristate "NE2000 compatible support for H8/300"
depends on H8300
Index: linux.git/drivers/net/Makefile
===================================================================
--- linux.git.orig/drivers/net/Makefile
+++ linux.git/drivers/net/Makefile
@@ -96,6 +96,10 @@ obj-$(CONFIG_SHAPER) += shaper.o
obj-$(CONFIG_HP100) += hp100.o
obj-$(CONFIG_SMC9194) += smc9194.o
obj-$(CONFIG_FEC) += fec.o
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
+ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
+ obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
+endif
obj-$(CONFIG_68360_ENET) += 68360enet.o
obj-$(CONFIG_WD80x3) += wd.o 8390.o
obj-$(CONFIG_EL2) += 3c503.o 8390.o
Index: linux.git/drivers/net/fec_mpc52xx.c
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx.c
@@ -0,0 +1,1109 @@
+/*
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
+ * now maintained by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/hardirq.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.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_mpc52xx.h"
+
+#define DRIVER_NAME "mpc52xx-fec"
+
+static irqreturn_t mpc52xx_fec_interrupt(int, void *);
+static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
+static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
+static void mpc52xx_fec_stop(struct net_device *dev);
+static void mpc52xx_fec_start(struct net_device *dev);
+static void mpc52xx_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");
+
+#define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFDOWN )
+static int debug = -1; /* the above default */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "debugging messages level");
+
+static void mpc52xx_fec_tx_timeout(struct net_device *dev)
+{
+ dev_warn(&dev->dev, "transmit timed out\n");
+
+ mpc52xx_fec_reset(dev);
+
+ dev->stats.tx_errors++;
+
+ netif_wake_queue(dev);
+}
+
+static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
+{
+ struct mpc52xx_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 mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac)
+{
+ struct mpc52xx_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 mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct sockaddr *sock = addr;
+
+ memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
+
+ mpc52xx_fec_set_paddr(dev, sock->sa_data);
+ return 0;
+}
+
+static void mpc52xx_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 mpc52xx_fec_alloc_rx_buffers(struct net_device *dev, struct bcom_task *rxtsk)
+{
+ while (!bcom_queue_full(rxtsk)) {
+ struct sk_buff *skb;
+ struct bcom_fec_bd *bd;
+
+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+ if (skb == NULL)
+ return -EAGAIN;
+
+ /* zero out the initial receive buffers to aid debugging */
+ memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
+
+ bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = dma_map_single(&dev->dev, skb->data,
+ FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ bcom_submit_next_buffer(rxtsk, skb);
+ }
+
+ return 0;
+}
+
+/* based on generic_adjust_link from fs_enet-main.c */
+static void mpc52xx_fec_adjust_link(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ if (phydev->link != PHY_DOWN) {
+ if (phydev->duplex != priv->duplex) {
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rcntrl;
+ u32 tcntrl;
+
+ new_state = 1;
+ priv->duplex = phydev->duplex;
+
+ rcntrl = in_be32(&fec->r_cntrl);
+ tcntrl = in_be32(&fec->x_cntrl);
+
+ rcntrl &= ~FEC_RCNTRL_DRT;
+ tcntrl &= ~FEC_TCNTRL_FDEN;
+ if (phydev->duplex == DUPLEX_FULL)
+ tcntrl |= FEC_TCNTRL_FDEN; /* FD enable */
+ else
+ rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
+
+ out_be32(&fec->r_cntrl, rcntrl);
+ out_be32(&fec->x_cntrl, tcntrl);
+ }
+
+ if (phydev->speed != priv->speed) {
+ new_state = 1;
+ priv->speed = phydev->speed;
+ }
+
+ if (priv->link == PHY_DOWN) {
+ new_state = 1;
+ priv->link = phydev->link;
+ netif_schedule(dev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+
+ } else if (priv->link) {
+ new_state = 1;
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ }
+
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+}
+
+static int mpc52xx_fec_init_phy(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[BUS_ID_SIZE];
+
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT,
+ (unsigned int)dev->base_addr, priv->phy_addr);
+
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+
+ phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ dev_err(&dev->dev, "phy_connect failed\n");
+ return PTR_ERR(phydev);
+ }
+ dev_info(&dev->dev, "attached phy %i to driver %s\n",
+ phydev->addr, phydev->drv->name);
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+static int mpc52xx_fec_phy_start(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ int err;
+
+ if (!priv->has_phy)
+ return 0;
+
+ err = mpc52xx_fec_init_phy(dev);
+ if (err) {
+ dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n");
+ return err;
+ }
+
+ /* reset phy - this also wakes it from PDOWN */
+ phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(priv->phydev);
+
+ return 0;
+}
+
+static void mpc52xx_fec_phy_stop(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->has_phy)
+ return;
+
+ phy_disconnect(priv->phydev);
+ /* power down phy */
+ phy_stop(priv->phydev);
+ phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
+}
+
+static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
+ struct mii_ioctl_data *mii_data, int cmd)
+{
+ if (!priv->has_phy)
+ return -ENOTSUPP;
+
+ return phy_mii_ioctl(priv->phydev, mii_data, cmd);
+}
+
+static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
+{
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ if (!priv->has_phy)
+ return;
+
+ out_be32(&fec->mii_speed, priv->phy_speed);
+}
+
+static int mpc52xx_fec_open(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ int err = -EBUSY;
+
+ if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED,
+ DRIVER_NAME "_ctrl", dev)) {
+ dev_err(&dev->dev, "ctrl interrupt request failed\n");
+ goto out;
+ }
+ if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0,
+ DRIVER_NAME "_rx", dev)) {
+ dev_err(&dev->dev, "rx interrupt request failed\n");
+ goto free_ctrl_irq;
+ }
+ if (request_irq(priv->t_irq, &mpc52xx_fec_tx_interrupt, 0,
+ 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 = mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk);
+ if (err) {
+ dev_err(&dev->dev, "mpc52xx_fec_alloc_rx_buffers failed\n");
+ goto free_irqs;
+ }
+
+ err = mpc52xx_fec_phy_start(dev);
+ if (err)
+ goto free_skbs;
+
+ bcom_enable(priv->rx_dmatsk);
+ bcom_enable(priv->tx_dmatsk);
+
+ mpc52xx_fec_start(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+
+ free_skbs:
+ mpc52xx_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 mpc52xx_fec_close(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+
+ mpc52xx_fec_stop(dev);
+
+ mpc52xx_fec_free_rx_buffers(priv->rx_dmatsk);
+
+ free_irq(dev->irq, dev);
+ free_irq(priv->r_irq, dev);
+ free_irq(priv->t_irq, dev);
+
+ mpc52xx_fec_phy_stop(dev);
+
+ return 0;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct bcom_fec_bd *bd;
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ if (net_ratelimit())
+ dev_err(&dev->dev, "transmit queue overrun\n");
+ return 1;
+ }
+
+ spin_lock_irq(&priv->lock);
+ dev->trans_start = jiffies;
+
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->tx_dmatsk);
+
+ bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC;
+ bd->skb_pa = dma_map_single(&dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+
+ bcom_submit_next_buffer(priv->tx_dmatsk, skb);
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irq(&priv->lock);
+
+ return 0;
+}
+
+/* This handles BestComm transmit task interrupts
+ */
+static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mpc52xx_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);
+ /* Here (and in rx routines) would be a good place for
+ * dma_unmap_single(), but bcom doesn't return bcom_bd of the
+ * finished transfer, and _unmap is empty on this platfrom.
+ */
+
+ dev_kfree_skb_irq(skb);
+ }
+
+ netif_wake_queue(dev);
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mpc52xx_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 = dma_map_single(&dev->dev, rskb->data,
+ FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
+
+ dev->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");
+ dev->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 = dma_map_single(&dev->dev, rskb->data,
+ FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, skb);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mpc52xx_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");
+
+ mpc52xx_fec_reset(dev);
+
+ netif_wake_queue(dev);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *mpc52xx_fec_get_stats(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+ stats->rx_packets = in_be32(&fec->rmon_r_packets);
+ stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
+ in_be32(&fec->rmon_r_undersize) +
+ in_be32(&fec->rmon_r_oversize) +
+ in_be32(&fec->rmon_r_frag) +
+ in_be32(&fec->rmon_r_jab);
+
+ stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+ stats->tx_packets = in_be32(&fec->rmon_t_packets);
+ stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
+ in_be32(&fec->rmon_t_undersize) +
+ in_be32(&fec->rmon_t_oversize) +
+ in_be32(&fec->rmon_t_frag) +
+ in_be32(&fec->rmon_t_jab);
+
+ stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
+ stats->collisions = in_be32(&fec->rmon_t_col);
+
+ /* detailed rx_errors: */
+ stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
+ + in_be32(&fec->rmon_r_oversize)
+ + in_be32(&fec->rmon_r_frag)
+ + in_be32(&fec->rmon_r_jab);
+ stats->rx_over_errors = in_be32(&fec->r_macerr);
+ stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
+ stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
+ stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
+ stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
+
+ /* detailed tx_errors: */
+ stats->tx_aborted_errors = 0;
+ stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
+ stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
+ stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
+ stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
+
+ return stats;
+}
+
+/*
+ * Read MIB counters in order to reset them,
+ * then zero all the stats fields in memory
+ */
+static void mpc52xx_fec_reset_stats(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->mib_control, FEC_MIB_DISABLE);
+ memset_io(&fec->rmon_t_drop, 0, (__force u32)&fec->reserved10 -
+ (__force u32)&fec->rmon_t_drop);
+ out_be32(&fec->mib_control, 0);
+
+ memset(&dev->stats, 0, sizeof(dev->stats));
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void mpc52xx_fec_set_multicast_list(struct net_device *dev)
+{
+ struct mpc52xx_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);
+ }
+ }
+}
+
+/**
+ * mpc52xx_fec_hw_init
+ * @dev: network device
+ *
+ * Setup various hardware setting, only needed once on start
+ */
+static void mpc52xx_fec_hw_init(struct net_device *dev)
+{
+ struct mpc52xx_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.
+ * this can't be done in phy driver, since it needs to be called
+ * before fec stuff (even on resume) */
+ mpc52xx_fec_phy_hw_init(priv);
+}
+
+/**
+ * mpc52xx_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 mpc52xx_fec_start(struct net_device *dev)
+{
+ struct mpc52xx_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 mpc52xx_fec_enable */
+ out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
+
+ /* Set station address. */
+ mpc52xx_fec_set_paddr(dev, dev->dev_addr);
+
+ mpc52xx_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;
+
+ if (priv->has_phy)
+ rcntrl |= FEC_RCNTRL_MII_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);
+}
+
+/**
+ * mpc52xx_fec_stop
+ * @dev: network device
+ *
+ * stop all activity on fec and empty dma buffers
+ */
+static void mpc52xx_fec_stop(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ unsigned long timeout;
+
+ /* disable all interrupts */
+ out_be32(&fec->imask, 0);
+
+ /* Disable the rx task. */
+ bcom_disable(priv->rx_dmatsk);
+
+ /* Wait for tx queue to drain, but only if we're in process context */
+ if (!in_interrupt()) {
+ timeout = jiffies + msecs_to_jiffies(2000);
+ while (time_before(jiffies, timeout) &&
+ !bcom_queue_empty(priv->tx_dmatsk))
+ msleep(100);
+
+ if (time_after_eq(jiffies, timeout))
+ dev_err(&dev->dev, "queues didn't drain\n");
+#if 1
+ if (time_after_eq(jiffies, timeout)) {
+ dev_err(&dev->dev, " tx: index: %i, outdex: %i\n",
+ priv->tx_dmatsk->index,
+ priv->tx_dmatsk->outdex);
+ dev_err(&dev->dev, " rx: index: %i, outdex: %i\n",
+ priv->rx_dmatsk->index,
+ priv->rx_dmatsk->outdex);
+ }
+#endif
+ }
+
+ bcom_disable(priv->tx_dmatsk);
+
+ /* Stop FEC */
+ out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
+
+ return;
+}
+
+/* reset fec and bestcomm tasks */
+static void mpc52xx_fec_reset(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ mpc52xx_fec_stop(dev);
+
+ out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status));
+ out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO);
+
+ mpc52xx_fec_free_rx_buffers(priv->rx_dmatsk);
+
+ mpc52xx_fec_hw_init(dev);
+
+ phy_stop(priv->phydev);
+ phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(priv->phydev);
+
+ bcom_fec_rx_reset(priv->rx_dmatsk);
+ bcom_fec_tx_reset(priv->tx_dmatsk);
+
+ mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk);
+
+ bcom_enable(priv->rx_dmatsk);
+ bcom_enable(priv->tx_dmatsk);
+
+ mpc52xx_fec_start(dev);
+}
+
+
+/* ethtool interface */
+static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRIVER_NAME);
+}
+
+static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static u32 mpc52xx_fec_get_msglevel(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ priv->msg_enable = level;
+}
+
+static const struct ethtool_ops mpc52xx_fec_ethtool_ops = {
+ .get_drvinfo = mpc52xx_fec_get_drvinfo,
+ .get_settings = mpc52xx_fec_get_settings,
+ .set_settings = mpc52xx_fec_set_settings,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = mpc52xx_fec_get_msglevel,
+ .set_msglevel = mpc52xx_fec_set_msglevel,
+};
+
+
+static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+ return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
+}
+
+/* ======================================================================== */
+/* OF Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
+{
+ int rv;
+ struct net_device *ndev;
+ struct mpc52xx_fec_priv *priv = NULL;
+ struct resource mem;
+ const phandle *ph;
+
+ phys_addr_t rx_fifo;
+ phys_addr_t tx_fifo;
+
+ /* Get the ether ndev & it's private zone */
+ ndev = alloc_etherdev(sizeof(struct mpc52xx_fec_priv));
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+
+ /* 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 = mpc52xx_fec_open;
+ ndev->stop = mpc52xx_fec_close;
+ ndev->hard_start_xmit = mpc52xx_fec_hard_start_xmit;
+ ndev->do_ioctl = mpc52xx_fec_ioctl;
+ ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops;
+ ndev->get_stats = mpc52xx_fec_get_stats;
+ ndev->set_mac_address = mpc52xx_fec_set_mac_address;
+ ndev->set_multicast_list = mpc52xx_fec_set_multicast_list;
+ ndev->tx_timeout = mpc52xx_fec_tx_timeout;
+ ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
+ 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 (!is_zero_ether_addr(mpc52xx_fec_mac_addr))
+ memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
+ else
+ mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
+
+ priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
+ priv->duplex = DUPLEX_FULL;
+
+ /* is the phy present in device tree? */
+ ph = of_get_property(op->node, "phy-handle", NULL);
+ if (ph) {
+ const unsigned int *prop;
+ struct device_node *phy_dn;
+ priv->has_phy = 1;
+
+ phy_dn = of_find_node_by_phandle(*ph);
+ prop = of_get_property(phy_dn, "reg", NULL);
+ priv->phy_addr = *prop;
+
+ of_node_put(phy_dn);
+
+ /* Phy speed */
+ priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
+ } else {
+ dev_info(&ndev->dev, "can't find \"phy-handle\" in device"
+ " tree, using 7-wire mode\n");
+ }
+
+ /* Hardware init */
+ mpc52xx_fec_hw_init(ndev);
+
+ mpc52xx_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 mpc52xx_fec_priv *priv;
+
+ ndev = dev_get_drvdata(&op->dev);
+ 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))
+ mpc52xx_fec_close(dev);
+
+ return 0;
+}
+
+static int mpc52xx_fec_of_resume(struct of_device *op)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ mpc52xx_fec_hw_init(dev);
+ mpc52xx_fec_reset_stats(dev);
+
+ if (netif_running(dev))
+ mpc52xx_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)
+{
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+ int ret;
+ ret = of_register_platform_driver(&mpc52xx_fec_mdio_driver);
+ if (ret) {
+ printk(KERN_ERR DRIVER_NAME ": failed to register mdio driver\n");
+ return ret;
+ }
+#endif
+ return of_register_platform_driver(&mpc52xx_fec_driver);
+}
+
+static void __exit
+mpc52xx_fec_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_fec_driver);
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+ of_unregister_platform_driver(&mpc52xx_fec_mdio_driver);
+#endif
+}
+
+
+module_init(mpc52xx_fec_init);
+module_exit(mpc52xx_fec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
Index: linux.git/drivers/net/fec_mpc52xx.h
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx.h
@@ -0,0 +1,313 @@
+/*
+ * drivers/drivers/net/fec_mpc52xx/fec.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
+#define __DRIVERS_NET_MPC52XX_FEC_H__
+
+#include <linux/phy.h>
+
+/* Tunable constant */
+/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
+#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
+#define FEC_RX_NUM_BD 256
+#define FEC_TX_NUM_BD 64
+
+#define FEC_RESET_DELAY 50 /* uS */
+
+#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
+
+struct mpc52xx_fec_priv {
+ int duplex;
+ int r_irq;
+ int t_irq;
+ struct mpc52xx_fec __iomem *fec;
+ struct bcom_task *rx_dmatsk;
+ struct bcom_task *tx_dmatsk;
+ spinlock_t lock;
+ int msg_enable;
+
+ int has_phy;
+ unsigned int phy_speed;
+ unsigned int phy_addr;
+ struct phy_device *phydev;
+ enum phy_state link;
+ int speed;
+};
+
+
+/* ======================================================================== */
+/* Hardware register sets & bits */
+/* ======================================================================== */
+
+struct mpc52xx_fec {
+ u32 fec_id; /* FEC + 0x000 */
+ u32 ievent; /* FEC + 0x004 */
+ u32 imask; /* FEC + 0x008 */
+
+ u32 reserved0[1]; /* FEC + 0x00C */
+ u32 r_des_active; /* FEC + 0x010 */
+ u32 x_des_active; /* FEC + 0x014 */
+ u32 r_des_active_cl; /* FEC + 0x018 */
+ u32 x_des_active_cl; /* FEC + 0x01C */
+ u32 ivent_set; /* FEC + 0x020 */
+ u32 ecntrl; /* FEC + 0x024 */
+
+ u32 reserved1[6]; /* FEC + 0x028-03C */
+ u32 mii_data; /* FEC + 0x040 */
+ u32 mii_speed; /* FEC + 0x044 */
+ u32 mii_status; /* FEC + 0x048 */
+
+ u32 reserved2[5]; /* FEC + 0x04C-05C */
+ u32 mib_data; /* FEC + 0x060 */
+ u32 mib_control; /* FEC + 0x064 */
+
+ u32 reserved3[6]; /* FEC + 0x068-7C */
+ u32 r_activate; /* FEC + 0x080 */
+ u32 r_cntrl; /* FEC + 0x084 */
+ u32 r_hash; /* FEC + 0x088 */
+ u32 r_data; /* FEC + 0x08C */
+ u32 ar_done; /* FEC + 0x090 */
+ u32 r_test; /* FEC + 0x094 */
+ u32 r_mib; /* FEC + 0x098 */
+ u32 r_da_low; /* FEC + 0x09C */
+ u32 r_da_high; /* FEC + 0x0A0 */
+
+ u32 reserved4[7]; /* FEC + 0x0A4-0BC */
+ u32 x_activate; /* FEC + 0x0C0 */
+ u32 x_cntrl; /* FEC + 0x0C4 */
+ u32 backoff; /* FEC + 0x0C8 */
+ u32 x_data; /* FEC + 0x0CC */
+ u32 x_status; /* FEC + 0x0D0 */
+ u32 x_mib; /* FEC + 0x0D4 */
+ u32 x_test; /* FEC + 0x0D8 */
+ u32 fdxfc_da1; /* FEC + 0x0DC */
+ u32 fdxfc_da2; /* FEC + 0x0E0 */
+ u32 paddr1; /* FEC + 0x0E4 */
+ u32 paddr2; /* FEC + 0x0E8 */
+ u32 op_pause; /* FEC + 0x0EC */
+
+ u32 reserved5[4]; /* FEC + 0x0F0-0FC */
+ u32 instr_reg; /* FEC + 0x100 */
+ u32 context_reg; /* FEC + 0x104 */
+ u32 test_cntrl; /* FEC + 0x108 */
+ u32 acc_reg; /* FEC + 0x10C */
+ u32 ones; /* FEC + 0x110 */
+ u32 zeros; /* FEC + 0x114 */
+ u32 iaddr1; /* FEC + 0x118 */
+ u32 iaddr2; /* FEC + 0x11C */
+ u32 gaddr1; /* FEC + 0x120 */
+ u32 gaddr2; /* FEC + 0x124 */
+ u32 random; /* FEC + 0x128 */
+ u32 rand1; /* FEC + 0x12C */
+ u32 tmp; /* FEC + 0x130 */
+
+ u32 reserved6[3]; /* FEC + 0x134-13C */
+ u32 fifo_id; /* FEC + 0x140 */
+ u32 x_wmrk; /* FEC + 0x144 */
+ u32 fcntrl; /* FEC + 0x148 */
+ u32 r_bound; /* FEC + 0x14C */
+ u32 r_fstart; /* FEC + 0x150 */
+ u32 r_count; /* FEC + 0x154 */
+ u32 r_lag; /* FEC + 0x158 */
+ u32 r_read; /* FEC + 0x15C */
+ u32 r_write; /* FEC + 0x160 */
+ u32 x_count; /* FEC + 0x164 */
+ u32 x_lag; /* FEC + 0x168 */
+ u32 x_retry; /* FEC + 0x16C */
+ u32 x_write; /* FEC + 0x170 */
+ u32 x_read; /* FEC + 0x174 */
+
+ u32 reserved7[2]; /* FEC + 0x178-17C */
+ u32 fm_cntrl; /* FEC + 0x180 */
+ u32 rfifo_data; /* FEC + 0x184 */
+ u32 rfifo_status; /* FEC + 0x188 */
+ u32 rfifo_cntrl; /* FEC + 0x18C */
+ u32 rfifo_lrf_ptr; /* FEC + 0x190 */
+ u32 rfifo_lwf_ptr; /* FEC + 0x194 */
+ u32 rfifo_alarm; /* FEC + 0x198 */
+ u32 rfifo_rdptr; /* FEC + 0x19C */
+ u32 rfifo_wrptr; /* FEC + 0x1A0 */
+ u32 tfifo_data; /* FEC + 0x1A4 */
+ u32 tfifo_status; /* FEC + 0x1A8 */
+ u32 tfifo_cntrl; /* FEC + 0x1AC */
+ u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */
+ u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */
+ u32 tfifo_alarm; /* FEC + 0x1B8 */
+ u32 tfifo_rdptr; /* FEC + 0x1BC */
+ u32 tfifo_wrptr; /* FEC + 0x1C0 */
+
+ u32 reset_cntrl; /* FEC + 0x1C4 */
+ u32 xmit_fsm; /* FEC + 0x1C8 */
+
+ u32 reserved8[3]; /* FEC + 0x1CC-1D4 */
+ u32 rdes_data0; /* FEC + 0x1D8 */
+ u32 rdes_data1; /* FEC + 0x1DC */
+ u32 r_length; /* FEC + 0x1E0 */
+ u32 x_length; /* FEC + 0x1E4 */
+ u32 x_addr; /* FEC + 0x1E8 */
+ u32 cdes_data; /* FEC + 0x1EC */
+ u32 status; /* FEC + 0x1F0 */
+ u32 dma_control; /* FEC + 0x1F4 */
+ u32 des_cmnd; /* FEC + 0x1F8 */
+ u32 data; /* FEC + 0x1FC */
+
+ u32 rmon_t_drop; /* FEC + 0x200 */
+ u32 rmon_t_packets; /* FEC + 0x204 */
+ u32 rmon_t_bc_pkt; /* FEC + 0x208 */
+ u32 rmon_t_mc_pkt; /* FEC + 0x20C */
+ u32 rmon_t_crc_align; /* FEC + 0x210 */
+ u32 rmon_t_undersize; /* FEC + 0x214 */
+ u32 rmon_t_oversize; /* FEC + 0x218 */
+ u32 rmon_t_frag; /* FEC + 0x21C */
+ u32 rmon_t_jab; /* FEC + 0x220 */
+ u32 rmon_t_col; /* FEC + 0x224 */
+ u32 rmon_t_p64; /* FEC + 0x228 */
+ u32 rmon_t_p65to127; /* FEC + 0x22C */
+ u32 rmon_t_p128to255; /* FEC + 0x230 */
+ u32 rmon_t_p256to511; /* FEC + 0x234 */
+ u32 rmon_t_p512to1023; /* FEC + 0x238 */
+ u32 rmon_t_p1024to2047; /* FEC + 0x23C */
+ u32 rmon_t_p_gte2048; /* FEC + 0x240 */
+ u32 rmon_t_octets; /* FEC + 0x244 */
+ u32 ieee_t_drop; /* FEC + 0x248 */
+ u32 ieee_t_frame_ok; /* FEC + 0x24C */
+ u32 ieee_t_1col; /* FEC + 0x250 */
+ u32 ieee_t_mcol; /* FEC + 0x254 */
+ u32 ieee_t_def; /* FEC + 0x258 */
+ u32 ieee_t_lcol; /* FEC + 0x25C */
+ u32 ieee_t_excol; /* FEC + 0x260 */
+ u32 ieee_t_macerr; /* FEC + 0x264 */
+ u32 ieee_t_cserr; /* FEC + 0x268 */
+ u32 ieee_t_sqe; /* FEC + 0x26C */
+ u32 t_fdxfc; /* FEC + 0x270 */
+ u32 ieee_t_octets_ok; /* FEC + 0x274 */
+
+ u32 reserved9[2]; /* FEC + 0x278-27C */
+ u32 rmon_r_drop; /* FEC + 0x280 */
+ u32 rmon_r_packets; /* FEC + 0x284 */
+ u32 rmon_r_bc_pkt; /* FEC + 0x288 */
+ u32 rmon_r_mc_pkt; /* FEC + 0x28C */
+ u32 rmon_r_crc_align; /* FEC + 0x290 */
+ u32 rmon_r_undersize; /* FEC + 0x294 */
+ u32 rmon_r_oversize; /* FEC + 0x298 */
+ u32 rmon_r_frag; /* FEC + 0x29C */
+ u32 rmon_r_jab; /* FEC + 0x2A0 */
+
+ u32 rmon_r_resvd_0; /* FEC + 0x2A4 */
+
+ u32 rmon_r_p64; /* FEC + 0x2A8 */
+ u32 rmon_r_p65to127; /* FEC + 0x2AC */
+ u32 rmon_r_p128to255; /* FEC + 0x2B0 */
+ u32 rmon_r_p256to511; /* FEC + 0x2B4 */
+ u32 rmon_r_p512to1023; /* FEC + 0x2B8 */
+ u32 rmon_r_p1024to2047; /* FEC + 0x2BC */
+ u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */
+ u32 rmon_r_octets; /* FEC + 0x2C4 */
+ u32 ieee_r_drop; /* FEC + 0x2C8 */
+ u32 ieee_r_frame_ok; /* FEC + 0x2CC */
+ u32 ieee_r_crc; /* FEC + 0x2D0 */
+ u32 ieee_r_align; /* FEC + 0x2D4 */
+ u32 r_macerr; /* FEC + 0x2D8 */
+ u32 r_fdxfc; /* FEC + 0x2DC */
+ u32 ieee_r_octets_ok; /* FEC + 0x2E0 */
+
+ u32 reserved10[7]; /* FEC + 0x2E4-2FC */
+
+ u32 reserved11[64]; /* FEC + 0x300-3FF */
+};
+
+#define FEC_MIB_DISABLE 0x80000000
+
+#define FEC_IEVENT_HBERR 0x80000000
+#define FEC_IEVENT_BABR 0x40000000
+#define FEC_IEVENT_BABT 0x20000000
+#define FEC_IEVENT_GRA 0x10000000
+#define FEC_IEVENT_TFINT 0x08000000
+#define FEC_IEVENT_MII 0x00800000
+#define FEC_IEVENT_LATE_COL 0x00200000
+#define FEC_IEVENT_COL_RETRY_LIM 0x00100000
+#define FEC_IEVENT_XFIFO_UN 0x00080000
+#define FEC_IEVENT_XFIFO_ERROR 0x00040000
+#define FEC_IEVENT_RFIFO_ERROR 0x00020000
+
+#define FEC_IMASK_HBERR 0x80000000
+#define FEC_IMASK_BABR 0x40000000
+#define FEC_IMASK_BABT 0x20000000
+#define FEC_IMASK_GRA 0x10000000
+#define FEC_IMASK_MII 0x00800000
+#define FEC_IMASK_LATE_COL 0x00200000
+#define FEC_IMASK_COL_RETRY_LIM 0x00100000
+#define FEC_IMASK_XFIFO_UN 0x00080000
+#define FEC_IMASK_XFIFO_ERROR 0x00040000
+#define FEC_IMASK_RFIFO_ERROR 0x00020000
+
+/* all but MII, which is enabled separately */
+#define FEC_IMASK_ENABLE (FEC_IMASK_HBERR | FEC_IMASK_BABR | \
+ FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_LATE_COL | \
+ FEC_IMASK_COL_RETRY_LIM | FEC_IMASK_XFIFO_UN | \
+ FEC_IMASK_XFIFO_ERROR | FEC_IMASK_RFIFO_ERROR)
+
+#define FEC_RCNTRL_MAX_FL_SHIFT 16
+#define FEC_RCNTRL_LOOP 0x01
+#define FEC_RCNTRL_DRT 0x02
+#define FEC_RCNTRL_MII_MODE 0x04
+#define FEC_RCNTRL_PROM 0x08
+#define FEC_RCNTRL_BC_REJ 0x10
+#define FEC_RCNTRL_FCE 0x20
+
+#define FEC_TCNTRL_GTS 0x00000001
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_TFC_PAUSE 0x00000008
+#define FEC_TCNTRL_RFC_PAUSE 0x00000010
+
+#define FEC_ECNTRL_RESET 0x00000001
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+
+#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */
+
+#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
+#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
+
+#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
+#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
+
+#define FEC_PADDR2_TYPE 0x8808
+
+#define FEC_OP_PAUSE_OPCODE 0x00010000
+
+#define FEC_FIFO_WMRK_256B 0x3
+
+#define FEC_FIFO_STATUS_ERR 0x00400000
+#define FEC_FIFO_STATUS_UF 0x00200000
+#define FEC_FIFO_STATUS_OF 0x00100000
+
+#define FEC_FIFO_CNTRL_FRAME 0x08000000
+#define FEC_FIFO_CNTRL_LTG_7 0x07000000
+
+#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000
+#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000
+
+#define FEC_XMIT_FSM_APPEND_CRC 0x02000000
+#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000
+
+
+extern struct of_platform_driver mpc52xx_fec_mdio_driver;
+
+#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */
Index: linux.git/drivers/net/fec_mpc52xx_phy.c
===================================================================
--- /dev/null
+++ linux.git/drivers/net/fec_mpc52xx_phy.c
@@ -0,0 +1,198 @@
+/*
+ * Driver for the MPC5200 Fast Ethernet Controller - MDIO bus driver
+ *
+ * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include "fec_mpc52xx.h"
+
+struct mpc52xx_fec_mdio_priv {
+ struct mpc52xx_fec __iomem *regs;
+};
+
+static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct mpc52xx_fec_mdio_priv *priv = bus->priv;
+ struct mpc52xx_fec __iomem *fec;
+ int tries = 100;
+ u32 request = FEC_MII_READ_FRAME;
+
+ fec = priv->regs;
+ out_be32(&fec->ievent, FEC_IEVENT_MII);
+
+ request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, request);
+
+ /* wait for it to finish, this takes about 23 us on lite5200b */
+ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
+ udelay(5);
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
+}
+
+static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
+{
+ struct mpc52xx_fec_mdio_priv *priv = bus->priv;
+ struct mpc52xx_fec __iomem *fec;
+ u32 value = data;
+ int tries = 100;
+
+ fec = priv->regs;
+ out_be32(&fec->ievent, FEC_IEVENT_MII);
+
+ value |= FEC_MII_WRITE_FRAME;
+ value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, value);
+
+ /* wait for request to finish */
+ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
+ udelay(5);
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int mpc52xx_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 mpc52xx_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 = mpc52xx_fec_mdio_read;
+ bus->write = mpc52xx_fec_mdio_write;
+
+ /* setup irqs */
+ bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (bus->irq == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
+
+ while ((child = of_get_next_child(np, child)) != NULL) {
+ int irq = irq_of_parse_and_map(child, 0);
+ if (irq != NO_IRQ) {
+ const u32 *id = of_get_property(child, "reg", NULL);
+ bus->irq[*id] = irq;
+ }
+ }
+
+ /* setup registers */
+ err = of_address_to_resource(np, 0, &res);
+ if (err)
+ goto out_free;
+ priv->regs = ioremap(res.start, res.end - res.start + 1);
+ if (priv->regs == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ bus->id = res.start;
+ bus->priv = priv;
+
+ bus->dev = dev;
+ dev_set_drvdata(dev, bus);
+
+ /* 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_unmap;
+
+ return 0;
+
+ out_unmap:
+ iounmap(priv->regs);
+ out_free:
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ if (bus->irq[i] != PHY_POLL)
+ irq_dispose_mapping(bus->irq[i]);
+ kfree(bus->irq);
+ kfree(priv);
+ kfree(bus);
+
+ return err;
+}
+
+static int mpc52xx_fec_mdio_remove(struct of_device *of)
+{
+ struct device *dev = &of->dev;
+ struct mii_bus *bus = dev_get_drvdata(dev);
+ struct mpc52xx_fec_mdio_priv *priv = bus->priv;
+ int i;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(dev, NULL);
+
+ 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 mpc52xx_fec_mdio_match[] = {
+ {
+ .type = "mdio",
+ .compatible = "mpc5200b-fec-phy",
+ },
+ {},
+};
+
+struct of_platform_driver mpc52xx_fec_mdio_driver = {
+ .name = "mpc5200b-fec-phy",
+ .probe = mpc52xx_fec_mdio_probe,
+ .remove = mpc52xx_fec_mdio_remove,
+ .match_table = mpc52xx_fec_mdio_match,
+};
+
+/* let fec driver call it, since this has to be registered before it */
+EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
+
+
+MODULE_LICENSE("Dual BSD/GPL");
--
Domen Puncer | Research & Development
.............................................................................................
Telargo d.o.o. | Zagrebška cesta 20 | 2000 Maribor | Slovenia
.............................................................................................
www.telargo.com
^ permalink raw reply
* Re: [PATCH 05/11] [POWERPC] TQM5200 DTS
From: Grant Likely @ 2007-10-25 13:53 UTC (permalink / raw)
To: Martin Krause; +Cc: linuxppc-dev
In-Reply-To: <13403420.post@talk.nabble.com>
On 10/25/07, Martin Krause <Martin.Krause@tqs.de> wrote:
>
>
> < + flash@00000000 {
> < + compatible = "cfi-flash";
> < + reg = <00000000 02000000>;
> < + bank-width = <4>;
> < + device-width = <2>;
> < + #size-cells = <1>;
> < + #address-cells = <1>;
> < + partition@0 {
> < + label = "firmware";
> < + reg = <0 a0000>;
> < + };
> < + partition@a0000 {
> < + label = "dtb";
> < + reg = <a0000 20000>;
> < + };
> < + partition@c0000 {
> < + label = "kernel";
> < + reg = <c0000 240000>;
> < + };
> < + partition@300000 {
> < + label = "initrd";
> < + reg = <300000 200000>;
> < + };
> < + partition@500000 {
> < + label = "small-fs";
> < + reg = <500000 400000>;
> < + };
> < + partition@900000 {
> < + label = "misc";
> < + reg = <900000 800000>;
> < + };
> < + partition@1100000 {
> < + label = "big-fs";
> < + reg = <1100000 f00000>;
> < + };
> < + };
> < + };
>
> This MTD layout only works on boards with 32 MiB (or 64 MiB) flash
> memory. On TQM5200 boards with smaller Flashes (16 MiB, 8 MiB and 4 MiB)
> the MTD partition borders do not match with the physikal memory borders.
If there is a variant board with a different configuration, then the
device tree needs to be changed for that variant board; either by
having multiple .dts files in arch/powerpc/boot/dts or by having the
bootloader populate the correct information. A dtb as passed to the
kernel must exactly represent the hardware.
That also means that there is going to be a different flash map for
each possible flash size configuration.
> On a board with 16 MiB FLASH for example the "big-fs" _and_ the "misc"
> partition could not be used. "big-fs", because the memory is too small
> (which is OK) and "misc", because it overlaps 1 MiB over the physikal
> flash border. So only the first 9 MiB of the flash could be used in Linux.
> The remaining 7 MiB couldn't be accessed.
Perhaps it would be better to drop the flash layout from the in-kernel
dts files entirely since flash layout can be a fluid thing.
g.
>
> I would propose a Flash layout, where the (filesystem) partitions end
> on powers of two, to match the physical flash boarders:
>
> partition@0 {
> label = "firmware";
> reg = <0 a0000>;
> };
> partition@a0000 {
> label = "dtb";
> reg = <a0000 20000>;
> };
> partition@c0000 {
> label = "kernel";
> reg = <c0000 180000>;
> };
> partition@240000 {
> label = "initrd";
> reg = <240000 1c0000>;
> };
> partition@400000 {
> label = "small-fs";
> reg = <400000 400000>;
> };
> partition@800000 {
> label = "misc";
> reg = <800000 800000>;
> };
> partition@1000000 {
> label = "big-fs";
> reg = <1000000 1000000>;
> };
> };
> };
>
> Best Regards,
> Martin Krause
> --
> View this message in context: http://www.nabble.com/-PATCH-00-11---POWERPC--Add-TQM5200-CM5200-Motion-PRO-board-support-tf4680980.html#a13403420
> Sent from the linuxppc-dev mailing list archive at Nabble.com.
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: kernel 2.6.15: cpm_uart driver broken?
From: raul.moreno @ 2007-10-25 13:54 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
I've found this thread, but I haven't seen the end of the discussion. I=
am
using this kernel version, and I am also having problems with the cpm_u=
art.
Only the console (SMC1) is working, the other devices working as uart f=
ail.
I've realised that the problem is in the DMA. The system crash when the=
Rx
and Tx buffers are allocated in external memory (in case of allocating =
in
the DPRAM of my mpc866, it works properly) and I don't know why. It is
supposed other devices (as fec) use the same functions
("dma_alloc_coherent") and they work.
Moreover I don't find any documentation about the parameters
"CONFIG_CONSISTENT_START" and "CONFIG_CONSISTENT_SIZE". Does these
parameters affect to the driver behaviour?
Could anyone help me?
Kind regards,
Ra=FAl Moreno
***********Internet Email Confidentiality Footer*************
This email and any files transmitted with it are confidential and inten=
ded
solely for the use of the organization or individual to whom they are
addressed. It is expressly forbidden to retransmit or copy email and/o=
r
this attached files without our permission . If you are not the
addressee indicated in this message (or responsible for delivery of the=
message to such person), you may not copy or deliver this message
to anyone. In such case, you should destroy this message and kindly
notify the sender by reply email. Please advise immediately if you or
your employer does not consent to Internet email for messages of this
kind. Opinions, conclusions and other information in this message that=
do not relate to the official business of my firm shall be understood a=
s
neither given nor endorsed by it.=
^ permalink raw reply
* Re: ioctl32 unknown cmds with 2.6.24-rc1
From: Geert Uytterhoeven @ 2007-10-25 13:45 UTC (permalink / raw)
To: Johannes Berg; +Cc: linuxppc-dev, Arnd Bergmann
In-Reply-To: <1193319517.14136.2.camel@johannes.berg>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 2128 bytes --]
On Thu, 25 Oct 2007, Johannes Berg wrote:
> On Wed, 2007-10-24 at 16:27 +0200, Arnd Bergmann wrote:
> > On Wednesday 24 October 2007, Johannes Berg wrote:
> > > Show Details
> > > I've been getting these warnings (many more of them but this is a list
> > > of unique ones) on my quad G5 with 32-bit userspace:
> > >
> > > ioctl32(cdrom_id:1078): Unknown cmd fd(3) cmd(00005331){t:'S';sz:0} arg(00000000) on /dev/.tmp-3-0
> > > ioctl32(ata_id:1095): Unknown cmd fd(3) cmd(0000030d){t:03;sz:0} arg(ff863970) on /dev/.tmp-3-0
> > > ioctl32(smartd:3563): Unknown cmd fd(3) cmd(0000031f){t:03;sz:0} arg(ffeb5480) on /dev/sda
> > > ioctl32(hald-probe-stor:3761): Unknown cmd fd(4) cmd(00005320){t:'S';sz:0} arg(00000004) on /dev/hda
> > > ioctl32(gnome-terminal:4187): Unknown cmd fd(19) cmd(0000530b){t:'S';sz:0} arg(0fd8e400) on /dev/pts/0
> > >
> > > Does anybody know whether this is expected?
> >
> > It's probably my fault, since I changed the compat ioctl handling for
> > block devices. Geert already reported the same, but I haven't had
> > a chance to reproduce it on my system to look into what went wrong.
> > Probably a trivial bug I introduced in block/compat_ioctl.c
>
> I have to admit that ioctl numbers scare me :) Any idea what I should be
> looking for?
Fortunately there's nothing to really worry about, as it's purely cosmetic :-)
If you want to look into this, the question is just why these messages are
printed now, while they weren't printed before. I don't think any other
behavior got changed.
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619
^ permalink raw reply
* Re: ioctl32 unknown cmds with 2.6.24-rc1
From: Johannes Berg @ 2007-10-25 13:38 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, Geert Uytterhoeven
In-Reply-To: <200710241627.18284.arnd@arndb.de>
[-- Attachment #1: Type: text/plain, Size: 1225 bytes --]
On Wed, 2007-10-24 at 16:27 +0200, Arnd Bergmann wrote:
> On Wednesday 24 October 2007, Johannes Berg wrote:
> > Show Details
> > I've been getting these warnings (many more of them but this is a list
> > of unique ones) on my quad G5 with 32-bit userspace:
> >
> > ioctl32(cdrom_id:1078): Unknown cmd fd(3) cmd(00005331){t:'S';sz:0} arg(00000000) on /dev/.tmp-3-0
> > ioctl32(ata_id:1095): Unknown cmd fd(3) cmd(0000030d){t:03;sz:0} arg(ff863970) on /dev/.tmp-3-0
> > ioctl32(smartd:3563): Unknown cmd fd(3) cmd(0000031f){t:03;sz:0} arg(ffeb5480) on /dev/sda
> > ioctl32(hald-probe-stor:3761): Unknown cmd fd(4) cmd(00005320){t:'S';sz:0} arg(00000004) on /dev/hda
> > ioctl32(gnome-terminal:4187): Unknown cmd fd(19) cmd(0000530b){t:'S';sz:0} arg(0fd8e400) on /dev/pts/0
> >
> > Does anybody know whether this is expected?
>
> It's probably my fault, since I changed the compat ioctl handling for
> block devices. Geert already reported the same, but I haven't had
> a chance to reproduce it on my system to look into what went wrong.
> Probably a trivial bug I introduced in block/compat_ioctl.c
I have to admit that ioctl numbers scare me :) Any idea what I should be
looking for?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply
* Re: [PATCH] fix appletouch geyser 1 breakage
From: Johannes Berg @ 2007-10-25 13:23 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linuxppc-dev list, Anton Ekblad, Benjamin Berg
In-Reply-To: <d120d5000710240729v2e3faea8u615cfa7f1e489d11@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 425 bytes --]
On Wed, 2007-10-24 at 10:29 -0400, Dmitry Torokhov wrote:
> Do yo know who has powerbooks with older geyser models (0x214, 215,
> 216)?
Not sure, Benjamin? We're talking about the touchpad, just lsusb should
be enough.
> It would be nice to know if they send the data continiously and
> whether the geyser 3 reset hack works on them.
That'd be good, but for fountains it definitely doesn't work.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply
* Re: New time code miscalculates cpu usage
From: Sergei Shtylyov @ 2007-10-25 12:46 UTC (permalink / raw)
To: benh; +Cc: Olof Johansson, linuxppc-dev, paulus
In-Reply-To: <1193262969.6653.32.camel@pasglop>
Hello.
Benjamin Herrenschmidt wrote:
>>>Not sure when this started happening, but I wanted to report it. I'll
>>>start bisecting in a day or two if noone else has gotten around to
>>>looking at it:
>>>$ echo "int main(void) { while(1); }" > test.c ; gcc test.c
>>>$ time ./a.out & sleep 2 ; killall a.out
>>>real 0m2.008s
>>>user 0m4.014s
>>>sys 0m0.002s
>>>Seen on POWER5 and PA6T, haven't tried anything else yet.
>> I'm not surprised -- the kernel accounts twice for each tick.
> Your input would be much more valuable if you actually pointed out where
> that happens and why since you seem to know it.
I've already pointed out the reason, yet it won't hurt to repeat indeed.
timer_interrupt() calls both account_process_time() and the hrtimers event
handler which leads to:
- if determenistic accounting is off, account_process_time() is the same as
update_process_times() which gets also calleed by hrtimers via the event
handler, so we get each tick accounted for twice;
- if determenistic accounting is on, then timer_interrupt() calls
account_process_time() and update_process_times() is still called by
hrtimers, so each tick's gets accounted for userspace twice...
> Ben.
WBR, Sergei
^ permalink raw reply
* Re: [PATCH 0/2] mpc52xx: stop drivers from accessing clock config directly
From: Domen Puncer @ 2007-10-25 12:29 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40710241314w2dbe0863ja15746614cff0dd@mail.gmail.com>
On 24/10/07 14:14 -0600, Grant Likely wrote:
> On 10/24/07, Domen Puncer <domen.puncer@telargo.com> wrote:
> > On 24/10/07 12:24 -0600, Grant Likely wrote:
> > > Domen,
> > >
> > > Here's a real solution to the problem. I've somewhat tested this on
> > > the lite5200b. Can you give it a spin on efika and see if SPI still
> > > works for you?
> >
> > My test case was lite5200b too, I don't think I ever tried SPI on
> > efika.
> > (Are even the right pins on irda connector, or is a necessary line
> > missing?)
>
> Hmm, I guess that's right. Can you at least make sure it still boots
> on Efika? Some of the clock detection stuff has changed so I want to
> make sure it still boots.
OK, with the following patch it compiles and boots.
I don't have any psc configured as spi in device tree though.
---
arch/powerpc/platforms/52xx/efika.c | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
Index: linux.git/arch/powerpc/platforms/52xx/efika.c
===================================================================
--- linux.git.orig/arch/powerpc/platforms/52xx/efika.c
+++ linux.git/arch/powerpc/platforms/52xx/efika.c
@@ -180,7 +180,7 @@ static void __init efika_setup_arch(void
{
rtas_initialize();
- mpc52xx_setup_clocks();
+ mpc5200_setup_clocks();
efika_pcisetup();
^ permalink raw reply
* Re: [linux-usb-devel] [PATCH 1/2] USB: Rework OHCI PPC OF for new bindings
From: Valentine Barshak @ 2007-10-25 11:48 UTC (permalink / raw)
To: Grant Likely; +Cc: David Brownell, linux-usb-devel, linuxppc-dev
In-Reply-To: <fa686aa40710241941w16fe3e75hb8ede9f9c8464e94@mail.gmail.com>
Grant Likely wrote:
> On 10/24/07, David Brownell <david-b@pacbell.net> wrote:
>> On Wednesday 24 October 2007, Matt Sealey wrote:
>>> Can we just make sure real quickly that the changing of compatibles
>>> doesn't break existing, not-easily-flashable firmwares?
>> Yeah, I'm not keen on such breakage either...
>
> Add my voice to the chorus. It's okay to change the binding, but make
> sure the old binding is still supported.
>
> Cheers,
> g.
>
Actually, I thought that changing the DTS stuff for mpc52xx boards would
suffice. Sorry, I was unaware of Efika firmware here. I'll keep old
bindings as well.
Does the device tree have "ohci-bigendian" or "ohci-be" compatible
property on Efika?
Thanks,
Valentine.
^ permalink raw reply
* Re: [PATCH] wrapper: Revert ps3 binary flag usage, and remove .bin suffix.
From: Geert Uytterhoeven @ 2007-10-25 11:08 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, paulus
In-Reply-To: <20071024165628.GA13863@loki.buserror.net>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 3412 bytes --]
On Wed, 24 Oct 2007, Scott Wood wrote:
> The ps3 target produces two images, and the binary one is not the
> "primary" image that corresponds to the -o flag; thus, it no longer
> uses the generic binary flag.
>
> On platforms which do use the binary flag, it no longer produces a
> .bin suffix, so that the output file matches what was passed to the -o flag.
>
> This should fix the zImage ln problems for the ps3 target.
>
> Signed-off-by: Scott Wood <scottwood@freescale.com>
Acked-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
> ---
> arch/powerpc/boot/wrapper | 13 +++++++------
> 1 files changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
> index 39b27e5..ece6f49 100755
> --- a/arch/powerpc/boot/wrapper
> +++ b/arch/powerpc/boot/wrapper
> @@ -149,7 +149,6 @@ cuboot*)
> ps3)
> platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
> lds=$object/zImage.ps3.lds
> - binary=y
> gzip=
> ext=bin
> objflags="-O binary --set-section-flags=.bss=contents,alloc,load,data"
> @@ -233,7 +232,7 @@ entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3`
>
> if [ -n "$binary" ]; then
> mv "$ofile" "$ofile".elf
> - ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin
> + ${CROSS}objcopy -O binary "$ofile".elf "$ofile"
> fi
>
> # post-processing needed for some platforms
> @@ -246,9 +245,9 @@ coff)
> $object/hack-coff "$ofile"
> ;;
> cuboot*)
> - gzip -f -9 "$ofile".bin
> + gzip -f -9 "$ofile"
> mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \
> - $uboot_version -d "$ofile".bin.gz "$ofile"
> + $uboot_version -d "$ofile".gz "$ofile"
> ;;
> treeboot*)
> mv "$ofile" "$ofile.elf"
> @@ -269,11 +268,11 @@ ps3)
> # then copied to offset 0x100. At runtime the bootwrapper program
> # copies the 0x100 bytes at __system_reset_kernel to addr 0x100.
>
> - system_reset_overlay=0x`${CROSS}nm "$ofile".elf \
> + system_reset_overlay=0x`${CROSS}nm "$ofile" \
> | grep ' __system_reset_overlay$' \
> | cut -d' ' -f1`
> system_reset_overlay=`printf "%d" $system_reset_overlay`
> - system_reset_kernel=0x`${CROSS}nm "$ofile".elf \
> + system_reset_kernel=0x`${CROSS}nm "$ofile" \
> | grep ' __system_reset_kernel$' \
> | cut -d' ' -f1`
> system_reset_kernel=`printf "%d" $system_reset_kernel`
> @@ -282,6 +281,8 @@ ps3)
>
> rm -f "$object/otheros.bld"
>
> + ${CROSS}objcopy -O binary "$ofile" "$ofile.bin"
> +
> msg=$(dd if="$ofile.bin" of="$ofile.bin" conv=notrunc \
> skip=$overlay_dest seek=$system_reset_kernel \
> count=$overlay_size bs=1 2>&1)
> --
> 1.5.3.4
>
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619
^ permalink raw reply
* Re: [PATCH 05/11] [POWERPC] TQM5200 DTS
From: Martin Krause @ 2007-10-25 9:57 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20071023231333.29359.35252.stgit@hekate.izotz.org>
< + flash@00000000 {
< + compatible = "cfi-flash";
< + reg = <00000000 02000000>;
< + bank-width = <4>;
< + device-width = <2>;
< + #size-cells = <1>;
< + #address-cells = <1>;
< + partition@0 {
< + label = "firmware";
< + reg = <0 a0000>;
< + };
< + partition@a0000 {
< + label = "dtb";
< + reg = <a0000 20000>;
< + };
< + partition@c0000 {
< + label = "kernel";
< + reg = <c0000 240000>;
< + };
< + partition@300000 {
< + label = "initrd";
< + reg = <300000 200000>;
< + };
< + partition@500000 {
< + label = "small-fs";
< + reg = <500000 400000>;
< + };
< + partition@900000 {
< + label = "misc";
< + reg = <900000 800000>;
< + };
< + partition@1100000 {
< + label = "big-fs";
< + reg = <1100000 f00000>;
< + };
< + };
< + };
This MTD layout only works on boards with 32 MiB (or 64 MiB) flash
memory. On TQM5200 boards with smaller Flashes (16 MiB, 8 MiB and 4 MiB)
the MTD partition borders do not match with the physikal memory borders.
On a board with 16 MiB FLASH for example the "big-fs" _and_ the "misc"
partition could not be used. "big-fs", because the memory is too small
(which is OK) and "misc", because it overlaps 1 MiB over the physikal
flash border. So only the first 9 MiB of the flash could be used in Linux.
The remaining 7 MiB couldn't be accessed.
I would propose a Flash layout, where the (filesystem) partitions end
on powers of two, to match the physical flash boarders:
partition@0 {
label = "firmware";
reg = <0 a0000>;
};
partition@a0000 {
label = "dtb";
reg = <a0000 20000>;
};
partition@c0000 {
label = "kernel";
reg = <c0000 180000>;
};
partition@240000 {
label = "initrd";
reg = <240000 1c0000>;
};
partition@400000 {
label = "small-fs";
reg = <400000 400000>;
};
partition@800000 {
label = "misc";
reg = <800000 800000>;
};
partition@1000000 {
label = "big-fs";
reg = <1000000 1000000>;
};
};
};
Best Regards,
Martin Krause
--
View this message in context: http://www.nabble.com/-PATCH-00-11---POWERPC--Add-TQM5200-CM5200-Motion-PRO-board-support-tf4680980.html#a13403420
Sent from the linuxppc-dev mailing list archive at Nabble.com.
^ permalink raw reply
* Re: [PATCH v4] FEC - fast ethernet controller for mpc52xx
From: Jeff Garzik @ 2007-10-25 9:29 UTC (permalink / raw)
To: Domen Puncer; +Cc: linuxppc-dev, netdev
In-Reply-To: <20071019112700.GD27403@nd47.coderock.org>
Domen Puncer wrote:
> +static int mpc52xx_fec_alloc_rx_buffers(struct bcom_task *rxtsk)
> +{
> + while (!bcom_queue_full(rxtsk)) {
> + struct sk_buff *skb;
> + struct bcom_fec_bd *bd;
> +
> + skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
> + if (skb == NULL)
> + return -EAGAIN;
> +
> + /* zero out the initial receive buffers to aid debugging */
> + memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
> +
> + bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
> +
> + bd->status = FEC_RX_BUFFER_SIZE;
> + bd->skb_pa = virt_to_phys(skb->data);
> +
> + bcom_submit_next_buffer(rxtsk, skb);
use your platform's dma mapping functions, rather than virt_to_phys()
it might be the exact same implementation, inside the platform
internals, but drivers should not be using this directly.
> +/* based on generic_adjust_link from fs_enet-main.c */
> +static void mpc52xx_fec_adjust_link(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct phy_device *phydev = priv->phydev;
> + int new_state = 0;
> +
> + if (phydev->link != PHY_DOWN) {
> + if (phydev->duplex != priv->duplex) {
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 rcntrl;
> + u32 tcntrl;
> +
> + new_state = 1;
> + priv->duplex = phydev->duplex;
> +
> + rcntrl = in_be32(&fec->r_cntrl);
> + tcntrl = in_be32(&fec->x_cntrl);
> +
> + rcntrl &= ~FEC_RCNTRL_DRT;
> + tcntrl &= ~FEC_TCNTRL_FDEN;
> + if (phydev->duplex == DUPLEX_FULL)
> + tcntrl |= FEC_TCNTRL_FDEN; /* FD enable */
> + else
> + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
> +
> + out_be32(&fec->r_cntrl, rcntrl);
> + out_be32(&fec->x_cntrl, tcntrl);
> + }
> +
> + if (phydev->speed != priv->speed) {
> + new_state = 1;
> + priv->speed = phydev->speed;
> + }
> +
> + if (priv->link == PHY_DOWN) {
> + new_state = 1;
> + priv->link = phydev->link;
> + netif_schedule(dev);
> + netif_carrier_on(dev);
> + netif_start_queue(dev);
> + }
> +
> + } else if (priv->link) {
> + new_state = 1;
> + priv->link = PHY_DOWN;
> + priv->speed = 0;
> + priv->duplex = -1;
> + netif_stop_queue(dev);
> + netif_carrier_off(dev);
> + }
> +
> + if (new_state && netif_msg_link(priv))
> + phy_print_status(phydev);
> +}
> +
> +static int mpc52xx_fec_init_phy(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct phy_device *phydev;
> + char phy_id[BUS_ID_SIZE];
> +
> + snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT,
> + (unsigned int)dev->base_addr, priv->phy_addr);
> +
> + priv->link = PHY_DOWN;
> + priv->speed = 0;
> + priv->duplex = -1;
> +
> + phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
> + if (IS_ERR(phydev)) {
> + dev_err(&dev->dev, "phy_connect failed\n");
> + return PTR_ERR(phydev);
> + }
> + dev_info(&dev->dev, "attached phy %i to driver %s\n",
> + phydev->addr, phydev->drv->name);
> +
> + priv->phydev = phydev;
> +
> + return 0;
> +}
> +
> +static int mpc52xx_fec_phy_start(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + int err;
> +
> + if (!priv->has_phy)
> + return 0;
> +
> + err = mpc52xx_fec_init_phy(dev);
> + if (err) {
> + dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n");
> + return err;
> + }
> +
> + /* reset phy - this also wakes it from PDOWN */
> + phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
> + phy_start(priv->phydev);
> +
> + return 0;
> +}
> +
> +static void mpc52xx_fec_phy_stop(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + if (!priv->has_phy)
> + return;
> +
> + phy_disconnect(priv->phydev);
> + /* power down phy */
> + phy_stop(priv->phydev);
> + phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
> +}
> +
> +static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
> + struct mii_ioctl_data *mii_data, int cmd)
> +{
> + if (!priv->has_phy)
> + return -ENOTSUPP;
> +
> + return phy_mii_ioctl(priv->phydev, mii_data, cmd);
> +}
> +
> +static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
> +{
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + if (!priv->has_phy)
> + return;
> +
> + out_be32(&fec->mii_speed, priv->phy_speed);
> +}
> +
> +static int mpc52xx_fec_open(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + int err = -EBUSY;
> +
> + if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_DISABLED | IRQF_SHARED,
why IRQF_DISABLED? that should not be needed.
> + DRIVER_NAME "_ctrl", dev)) {
> + dev_err(&dev->dev, "ctrl interrupt request failed\n");
> + goto out;
> + }
> + if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, IRQF_DISABLED,
ditto
> + DRIVER_NAME "_rx", dev)) {
> + dev_err(&dev->dev, "rx interrupt request failed\n");
> + goto free_ctrl_irq;
> + }
> + if (request_irq(priv->t_irq, &mpc52xx_fec_tx_interrupt, IRQF_DISABLED,
ditto
> + 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 = mpc52xx_fec_alloc_rx_buffers(priv->rx_dmatsk);
> + if (err) {
> + dev_err(&dev->dev, "mpc52xx_fec_alloc_rx_buffers failed\n");
> + goto free_irqs;
> + }
> +
> + err = mpc52xx_fec_phy_start(dev);
> + if (err)
> + goto free_skbs;
> +
> + bcom_enable(priv->rx_dmatsk);
> + bcom_enable(priv->tx_dmatsk);
> +
> + mpc52xx_fec_start(dev);
> +
> + netif_start_queue(dev);
> +
> + return 0;
> +
> + free_skbs:
> + mpc52xx_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 mpc52xx_fec_close(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + netif_stop_queue(dev);
> +
> + mpc52xx_fec_stop(dev);
> +
> + mpc52xx_fec_free_rx_buffers(priv->rx_dmatsk);
> +
> + free_irq(dev->irq, dev);
> + free_irq(priv->r_irq, dev);
> + free_irq(priv->t_irq, dev);
> +
> + mpc52xx_fec_phy_stop(dev);
> +
> + return 0;
> +}
> +
> +/* This will only be invoked if your driver is _not_ in XOFF state.
> + * What this means is that you need not check it, and that this
> + * invariant will hold if you make sure that the netif_*_queue()
> + * calls are done at the proper times.
> + */
> +static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct bcom_fec_bd *bd;
> +
> + if (bcom_queue_full(priv->tx_dmatsk)) {
> + if (net_ratelimit())
> + dev_err(&dev->dev, "transmit queue overrun\n");
> + return 1;
> + }
> +
> + spin_lock_irq(&priv->lock);
> + dev->trans_start = jiffies;
> +
> + bd = (struct bcom_fec_bd *)
> + bcom_prepare_next_buffer(priv->tx_dmatsk);
> +
> + bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC;
> + bd->skb_pa = virt_to_phys(skb->data);
use dma_xxx
> + bcom_submit_next_buffer(priv->tx_dmatsk, skb);
> +
> + if (bcom_queue_full(priv->tx_dmatsk)) {
> + priv->tx_full = 1;
no need for your own tx_full variable
> + netif_stop_queue(dev);
> + }
> +
> + spin_unlock_irq(&priv->lock);
> +
> + return 0;
> +}
> +
> +/* This handles BestComm transmit task interrupts
> + */
> +static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct mpc52xx_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)
no need to test netif_queue_stopped(), netif_wake_queue() does that anyway
no need for tx_full
> + netif_wake_queue(dev);
> +
> + spin_unlock(&priv->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct mpc52xx_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 mpc52xx_fec_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 ievent;
> +
> + ievent = in_be32(&fec->ievent);
generally wise to check for 0xffffffff, which often indicates hardware
fault / device not there / scrogged
> + 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");
> +
> + mpc52xx_fec_reset(dev);
> +
> + netif_wake_queue(dev);
> + return IRQ_HANDLED;
> +}
> +
> +/*
> + * Get the current statistics.
> + * This may be called with the card open or closed.
> + */
> +static struct net_device_stats *mpc52xx_fec_get_stats(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &priv->stats;
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + stats->rx_bytes = in_be32(&fec->rmon_r_octets);
> + stats->rx_packets = in_be32(&fec->rmon_r_packets);
> + stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
> + in_be32(&fec->rmon_r_undersize) +
> + in_be32(&fec->rmon_r_oversize) +
> + in_be32(&fec->rmon_r_frag) +
> + in_be32(&fec->rmon_r_jab);
> +
> + stats->tx_bytes = in_be32(&fec->rmon_t_octets);
> + stats->tx_packets = in_be32(&fec->rmon_t_packets);
> + stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
> + in_be32(&fec->rmon_t_undersize) +
> + in_be32(&fec->rmon_t_oversize) +
> + in_be32(&fec->rmon_t_frag) +
> + in_be32(&fec->rmon_t_jab);
> +
> + stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
> + stats->collisions = in_be32(&fec->rmon_t_col);
> +
> + /* detailed rx_errors: */
> + stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
> + + in_be32(&fec->rmon_r_oversize)
> + + in_be32(&fec->rmon_r_frag)
> + + in_be32(&fec->rmon_r_jab);
> + stats->rx_over_errors = in_be32(&fec->r_macerr);
> + stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
> + stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
> + stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
> + stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
> +
> + /* detailed tx_errors: */
> + stats->tx_aborted_errors = 0;
> + stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
> + stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
> + stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
> + stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
> +
> + return stats;
> +}
> +
> +/*
> + * Read MIB counters in order to reset them,
> + * then zero all the stats fields in memory
> + */
> +static void mpc52xx_fec_reset_stats(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + out_be32(&fec->mib_control, FEC_MIB_DISABLE);
> + memset_io(&fec->rmon_t_drop, 0, (__force u32)&fec->reserved10 -
> + (__force u32)&fec->rmon_t_drop);
> + out_be32(&fec->mib_control, 0);
> +
> + memset(&priv->stats, 0, sizeof(priv->stats));
don't use your own copy of net_device_stats, it's in net_device now
> +/*
> + * Set or clear the multicast filter for this adaptor.
> + */
> +static void mpc52xx_fec_set_multicast_list(struct net_device *dev)
> +{
> + struct mpc52xx_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);
fall back to ALLMULTI behavior if dev->mc_count is too large (for your
chip's version of "too large")
> +/**
> + * mpc52xx_fec_hw_init
> + * @dev: network device
> + *
> + * Setup various hardware setting, only needed once on start
> + */
> +static void mpc52xx_fec_hw_init(struct net_device *dev)
> +{
> + struct mpc52xx_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.
> + * this can't be done in phy driver, since it needs to be called
> + * before fec stuff (even on resume) */
> + mpc52xx_fec_phy_hw_init(priv);
> +}
> +
> +/**
> + * mpc52xx_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 mpc52xx_fec_start(struct net_device *dev)
> +{
> + struct mpc52xx_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 mpc52xx_fec_enable */
> + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
> +
> + /* Set station address. */
> + mpc52xx_fec_set_paddr(dev, dev->dev_addr);
> +
> + mpc52xx_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;
> +
> + if (priv->has_phy)
> + rcntrl |= FEC_RCNTRL_MII_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;
> +}
> +
> +/**
> + * mpc52xx_fec_stop
> + * @dev: network device
> + *
> + * stop all activity on fec and empty dma buffers
> + */
> +static void mpc52xx_fec_stop(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + unsigned long timeout;
> +
> + /* disable all interrupts */
> + out_be32(&fec->imask, 0);
> +
> + /* Disable the rx task. */
> + bcom_disable(priv->rx_dmatsk);
> +
> + /* Wait for tx queue to drain, but only if we're in process context */
> + if (!in_interrupt()) {
> + timeout = jiffies + msecs_to_jiffies(2000);
> + while (time_before(jiffies, timeout) &&
> + !bcom_queue_empty(priv->tx_dmatsk))
> + msleep(100);
> +
> + if (time_after_eq(jiffies, timeout))
> + dev_err(&dev->dev, "queues didn't drain\n");
> +#if 1
> + if (time_after_eq(jiffies, timeout)) {
> + dev_err(&dev->dev, " tx: index: %i, outdex: %i\n",
> + priv->tx_dmatsk->index,
> + priv->tx_dmatsk->outdex);
> + dev_err(&dev->dev, " rx: index: %i, outdex: %i\n",
> + priv->rx_dmatsk->index,
> + priv->rx_dmatsk->outdex);
> + }
> +#endif
> + }
> +
> + bcom_disable(priv->tx_dmatsk);
> +
> + /* Stop FEC */
> + out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
> +
> + return;
> +}
> +
> +/* reset fec and bestcomm tasks */
> +static void mpc52xx_fec_reset(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + mpc52xx_fec_stop(dev);
> +
> + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status));
> + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO);
> +
> + mpc52xx_fec_free_rx_buffers(priv->rx_dmatsk);
> +
> + mpc52xx_fec_hw_init(dev);
> +
> + phy_stop(priv->phydev);
> + phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
> + phy_start(priv->phydev);
> +
> + bcom_fec_rx_reset(priv->rx_dmatsk);
> + bcom_fec_tx_reset(priv->tx_dmatsk);
> +
> + mpc52xx_fec_alloc_rx_buffers(priv->rx_dmatsk);
> +
> + bcom_enable(priv->rx_dmatsk);
> + bcom_enable(priv->tx_dmatsk);
> +
> + mpc52xx_fec_start(dev);
> +}
> +
> +
> +/* ethtool interface */
> +static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
> + struct ethtool_drvinfo *info)
> +{
> + strcpy(info->driver, DRIVER_NAME);
version? anything else?
> +static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + return phy_ethtool_gset(priv->phydev, cmd);
> +}
> +
> +static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + return phy_ethtool_sset(priv->phydev, cmd);
> +}
> +
> +static u32 mpc52xx_fec_get_msglevel(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + return priv->msg_enable;
> +}
> +
> +static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + priv->msg_enable = level;
> +}
> +
> +static const struct ethtool_ops mpc52xx_fec_ethtool_ops = {
> + .get_drvinfo = mpc52xx_fec_get_drvinfo,
> + .get_settings = mpc52xx_fec_get_settings,
> + .set_settings = mpc52xx_fec_set_settings,
> + .get_link = ethtool_op_get_link,
> + .get_msglevel = mpc52xx_fec_get_msglevel,
> + .set_msglevel = mpc52xx_fec_set_msglevel,
> +};
> +
> +
> +static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
> +}
> +
> +/* ======================================================================== */
> +/* OF Driver */
> +/* ======================================================================== */
> +
> +static int __devinit
> +mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
> +{
> + int rv;
> + struct net_device *ndev;
> + struct mpc52xx_fec_priv *priv = NULL;
> + struct resource mem;
> + const phandle *ph;
> +
> + phys_addr_t rx_fifo;
> + phys_addr_t tx_fifo;
> +
> + /* Get the ether ndev & it's private zone */
> + ndev = alloc_etherdev(sizeof(struct mpc52xx_fec_priv));
> + if (!ndev)
> + return -ENOMEM;
> +
> + priv = netdev_priv(ndev);
> +
> + /* 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 = mpc52xx_fec_open;
> + ndev->stop = mpc52xx_fec_close;
> + ndev->hard_start_xmit = mpc52xx_fec_hard_start_xmit;
> + ndev->do_ioctl = mpc52xx_fec_ioctl;
> + ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops;
> + ndev->get_stats = mpc52xx_fec_get_stats;
> + ndev->set_mac_address = mpc52xx_fec_set_mac_address;
> + ndev->set_multicast_list = mpc52xx_fec_set_multicast_list;
> + ndev->tx_timeout = mpc52xx_fec_tx_timeout;
> + ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
> + ndev->flags &= ~IFF_RUNNING;
delete this, no reason to ever touch IFF_RUNNING yourself
> + 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 (!is_zero_ether_addr(mpc52xx_fec_mac_addr))
> + memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
> + else
> + mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
> +
> + priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
netif_msg_init
> + priv->duplex = DUPLEX_FULL;
> +
> + /* is the phy present in device tree? */
> + ph = of_get_property(op->node, "phy-handle", NULL);
> + if (ph) {
> + const unsigned int *prop;
> + struct device_node *phy_dn;
> + priv->has_phy = 1;
> +
> + phy_dn = of_find_node_by_phandle(*ph);
> + prop = of_get_property(phy_dn, "reg", NULL);
> + priv->phy_addr = *prop;
> +
> + of_node_put(phy_dn);
> +
> + /* Phy speed */
> + priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
> + } else {
> + dev_info(&ndev->dev, "can't find \"phy-handle\" in device"
> + " tree, using 7-wire mode\n");
> + }
> +
> + /* Hardware init */
> + mpc52xx_fec_hw_init(ndev);
> +
> + mpc52xx_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 mpc52xx_fec_priv *priv;
> +
> + ndev = dev_get_drvdata(&op->dev);
> + if (!ndev)
> + return 0;
testing for impossible condition
> + 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))
> + mpc52xx_fec_close(dev);
> +
> + return 0;
> +}
> +
> +static int mpc52xx_fec_of_resume(struct of_device *op)
> +{
> + struct net_device *dev = dev_get_drvdata(&op->dev);
> +
> + mpc52xx_fec_hw_init(dev);
> + mpc52xx_fec_reset_stats(dev);
> +
> + if (netif_running(dev))
> + mpc52xx_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)
> +{
> +#ifdef CONFIG_FEC_MPC52xx_MDIO
> + int ret;
> + ret = of_register_platform_driver(&mpc52xx_fec_mdio_driver);
> + if (ret) {
> + printk(KERN_ERR DRIVER_NAME ": failed to register mdio driver\n");
> + return ret;
> + }
> +#endif
> + return of_register_platform_driver(&mpc52xx_fec_driver);
> +}
> +
> +static void __exit
> +mpc52xx_fec_exit(void)
> +{
> + of_unregister_platform_driver(&mpc52xx_fec_driver);
> +#ifdef CONFIG_FEC_MPC52xx_MDIO
> + of_unregister_platform_driver(&mpc52xx_fec_mdio_driver);
> +#endif
> +}
> +
> +
> +module_init(mpc52xx_fec_init);
> +module_exit(mpc52xx_fec_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Dale Farnsworth");
> +MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
> Index: linux.git/drivers/net/fec_mpc52xx.h
> ===================================================================
> --- /dev/null
> +++ linux.git/drivers/net/fec_mpc52xx.h
> @@ -0,0 +1,315 @@
> +/*
> + * drivers/drivers/net/fec_mpc52xx/fec.h
> + *
> + * Driver for the MPC5200 Fast Ethernet Controller
> + *
> + * Author: Dale Farnsworth <dfarnsworth@mvista.com>
> + *
> + * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
> + * the terms of the GNU General Public License version 2. This program
> + * is licensed "as is" without any warranty of any kind, whether express
> + * or implied.
> + */
> +
> +#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
> +#define __DRIVERS_NET_MPC52XX_FEC_H__
> +
> +#include <linux/phy.h>
> +
> +/* Tunable constant */
> +/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
> +#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
> +#define FEC_RX_NUM_BD 256
> +#define FEC_TX_NUM_BD 64
> +
> +#define FEC_RESET_DELAY 50 /* uS */
> +
> +#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
> +
> +struct mpc52xx_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;
> +
> + int has_phy;
> + unsigned int phy_speed;
> + unsigned int phy_addr;
> + struct phy_device *phydev;
> + enum phy_state link;
> + int speed;
> +};
> +
> +
> +/* ======================================================================== */
> +/* Hardware register sets & bits */
> +/* ======================================================================== */
> +
> +struct mpc52xx_fec {
> + u32 fec_id; /* FEC + 0x000 */
> + u32 ievent; /* FEC + 0x004 */
> + u32 imask; /* FEC + 0x008 */
> +
> + u32 reserved0[1]; /* FEC + 0x00C */
> + u32 r_des_active; /* FEC + 0x010 */
> + u32 x_des_active; /* FEC + 0x014 */
> + u32 r_des_active_cl; /* FEC + 0x018 */
> + u32 x_des_active_cl; /* FEC + 0x01C */
> + u32 ivent_set; /* FEC + 0x020 */
> + u32 ecntrl; /* FEC + 0x024 */
> +
> + u32 reserved1[6]; /* FEC + 0x028-03C */
> + u32 mii_data; /* FEC + 0x040 */
> + u32 mii_speed; /* FEC + 0x044 */
> + u32 mii_status; /* FEC + 0x048 */
> +
> + u32 reserved2[5]; /* FEC + 0x04C-05C */
> + u32 mib_data; /* FEC + 0x060 */
> + u32 mib_control; /* FEC + 0x064 */
> +
> + u32 reserved3[6]; /* FEC + 0x068-7C */
> + u32 r_activate; /* FEC + 0x080 */
> + u32 r_cntrl; /* FEC + 0x084 */
> + u32 r_hash; /* FEC + 0x088 */
> + u32 r_data; /* FEC + 0x08C */
> + u32 ar_done; /* FEC + 0x090 */
> + u32 r_test; /* FEC + 0x094 */
> + u32 r_mib; /* FEC + 0x098 */
> + u32 r_da_low; /* FEC + 0x09C */
> + u32 r_da_high; /* FEC + 0x0A0 */
> +
> + u32 reserved4[7]; /* FEC + 0x0A4-0BC */
> + u32 x_activate; /* FEC + 0x0C0 */
> + u32 x_cntrl; /* FEC + 0x0C4 */
> + u32 backoff; /* FEC + 0x0C8 */
> + u32 x_data; /* FEC + 0x0CC */
> + u32 x_status; /* FEC + 0x0D0 */
> + u32 x_mib; /* FEC + 0x0D4 */
> + u32 x_test; /* FEC + 0x0D8 */
> + u32 fdxfc_da1; /* FEC + 0x0DC */
> + u32 fdxfc_da2; /* FEC + 0x0E0 */
> + u32 paddr1; /* FEC + 0x0E4 */
> + u32 paddr2; /* FEC + 0x0E8 */
> + u32 op_pause; /* FEC + 0x0EC */
> +
> + u32 reserved5[4]; /* FEC + 0x0F0-0FC */
> + u32 instr_reg; /* FEC + 0x100 */
> + u32 context_reg; /* FEC + 0x104 */
> + u32 test_cntrl; /* FEC + 0x108 */
> + u32 acc_reg; /* FEC + 0x10C */
> + u32 ones; /* FEC + 0x110 */
> + u32 zeros; /* FEC + 0x114 */
> + u32 iaddr1; /* FEC + 0x118 */
> + u32 iaddr2; /* FEC + 0x11C */
> + u32 gaddr1; /* FEC + 0x120 */
> + u32 gaddr2; /* FEC + 0x124 */
> + u32 random; /* FEC + 0x128 */
> + u32 rand1; /* FEC + 0x12C */
> + u32 tmp; /* FEC + 0x130 */
> +
> + u32 reserved6[3]; /* FEC + 0x134-13C */
> + u32 fifo_id; /* FEC + 0x140 */
> + u32 x_wmrk; /* FEC + 0x144 */
> + u32 fcntrl; /* FEC + 0x148 */
> + u32 r_bound; /* FEC + 0x14C */
> + u32 r_fstart; /* FEC + 0x150 */
> + u32 r_count; /* FEC + 0x154 */
> + u32 r_lag; /* FEC + 0x158 */
> + u32 r_read; /* FEC + 0x15C */
> + u32 r_write; /* FEC + 0x160 */
> + u32 x_count; /* FEC + 0x164 */
> + u32 x_lag; /* FEC + 0x168 */
> + u32 x_retry; /* FEC + 0x16C */
> + u32 x_write; /* FEC + 0x170 */
> + u32 x_read; /* FEC + 0x174 */
> +
> + u32 reserved7[2]; /* FEC + 0x178-17C */
> + u32 fm_cntrl; /* FEC + 0x180 */
> + u32 rfifo_data; /* FEC + 0x184 */
> + u32 rfifo_status; /* FEC + 0x188 */
> + u32 rfifo_cntrl; /* FEC + 0x18C */
> + u32 rfifo_lrf_ptr; /* FEC + 0x190 */
> + u32 rfifo_lwf_ptr; /* FEC + 0x194 */
> + u32 rfifo_alarm; /* FEC + 0x198 */
> + u32 rfifo_rdptr; /* FEC + 0x19C */
> + u32 rfifo_wrptr; /* FEC + 0x1A0 */
> + u32 tfifo_data; /* FEC + 0x1A4 */
> + u32 tfifo_status; /* FEC + 0x1A8 */
> + u32 tfifo_cntrl; /* FEC + 0x1AC */
> + u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */
> + u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */
> + u32 tfifo_alarm; /* FEC + 0x1B8 */
> + u32 tfifo_rdptr; /* FEC + 0x1BC */
> + u32 tfifo_wrptr; /* FEC + 0x1C0 */
> +
> + u32 reset_cntrl; /* FEC + 0x1C4 */
> + u32 xmit_fsm; /* FEC + 0x1C8 */
> +
> + u32 reserved8[3]; /* FEC + 0x1CC-1D4 */
> + u32 rdes_data0; /* FEC + 0x1D8 */
> + u32 rdes_data1; /* FEC + 0x1DC */
> + u32 r_length; /* FEC + 0x1E0 */
> + u32 x_length; /* FEC + 0x1E4 */
> + u32 x_addr; /* FEC + 0x1E8 */
> + u32 cdes_data; /* FEC + 0x1EC */
> + u32 status; /* FEC + 0x1F0 */
> + u32 dma_control; /* FEC + 0x1F4 */
> + u32 des_cmnd; /* FEC + 0x1F8 */
> + u32 data; /* FEC + 0x1FC */
> +
> + u32 rmon_t_drop; /* FEC + 0x200 */
> + u32 rmon_t_packets; /* FEC + 0x204 */
> + u32 rmon_t_bc_pkt; /* FEC + 0x208 */
> + u32 rmon_t_mc_pkt; /* FEC + 0x20C */
> + u32 rmon_t_crc_align; /* FEC + 0x210 */
> + u32 rmon_t_undersize; /* FEC + 0x214 */
> + u32 rmon_t_oversize; /* FEC + 0x218 */
> + u32 rmon_t_frag; /* FEC + 0x21C */
> + u32 rmon_t_jab; /* FEC + 0x220 */
> + u32 rmon_t_col; /* FEC + 0x224 */
> + u32 rmon_t_p64; /* FEC + 0x228 */
> + u32 rmon_t_p65to127; /* FEC + 0x22C */
> + u32 rmon_t_p128to255; /* FEC + 0x230 */
> + u32 rmon_t_p256to511; /* FEC + 0x234 */
> + u32 rmon_t_p512to1023; /* FEC + 0x238 */
> + u32 rmon_t_p1024to2047; /* FEC + 0x23C */
> + u32 rmon_t_p_gte2048; /* FEC + 0x240 */
> + u32 rmon_t_octets; /* FEC + 0x244 */
> + u32 ieee_t_drop; /* FEC + 0x248 */
> + u32 ieee_t_frame_ok; /* FEC + 0x24C */
> + u32 ieee_t_1col; /* FEC + 0x250 */
> + u32 ieee_t_mcol; /* FEC + 0x254 */
> + u32 ieee_t_def; /* FEC + 0x258 */
> + u32 ieee_t_lcol; /* FEC + 0x25C */
> + u32 ieee_t_excol; /* FEC + 0x260 */
> + u32 ieee_t_macerr; /* FEC + 0x264 */
> + u32 ieee_t_cserr; /* FEC + 0x268 */
> + u32 ieee_t_sqe; /* FEC + 0x26C */
> + u32 t_fdxfc; /* FEC + 0x270 */
> + u32 ieee_t_octets_ok; /* FEC + 0x274 */
> +
> + u32 reserved9[2]; /* FEC + 0x278-27C */
> + u32 rmon_r_drop; /* FEC + 0x280 */
> + u32 rmon_r_packets; /* FEC + 0x284 */
> + u32 rmon_r_bc_pkt; /* FEC + 0x288 */
> + u32 rmon_r_mc_pkt; /* FEC + 0x28C */
> + u32 rmon_r_crc_align; /* FEC + 0x290 */
> + u32 rmon_r_undersize; /* FEC + 0x294 */
> + u32 rmon_r_oversize; /* FEC + 0x298 */
> + u32 rmon_r_frag; /* FEC + 0x29C */
> + u32 rmon_r_jab; /* FEC + 0x2A0 */
> +
> + u32 rmon_r_resvd_0; /* FEC + 0x2A4 */
> +
> + u32 rmon_r_p64; /* FEC + 0x2A8 */
> + u32 rmon_r_p65to127; /* FEC + 0x2AC */
> + u32 rmon_r_p128to255; /* FEC + 0x2B0 */
> + u32 rmon_r_p256to511; /* FEC + 0x2B4 */
> + u32 rmon_r_p512to1023; /* FEC + 0x2B8 */
> + u32 rmon_r_p1024to2047; /* FEC + 0x2BC */
> + u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */
> + u32 rmon_r_octets; /* FEC + 0x2C4 */
> + u32 ieee_r_drop; /* FEC + 0x2C8 */
> + u32 ieee_r_frame_ok; /* FEC + 0x2CC */
> + u32 ieee_r_crc; /* FEC + 0x2D0 */
> + u32 ieee_r_align; /* FEC + 0x2D4 */
> + u32 r_macerr; /* FEC + 0x2D8 */
> + u32 r_fdxfc; /* FEC + 0x2DC */
> + u32 ieee_r_octets_ok; /* FEC + 0x2E0 */
> +
> + u32 reserved10[7]; /* FEC + 0x2E4-2FC */
> +
> + u32 reserved11[64]; /* FEC + 0x300-3FF */
> +};
> +
> +#define FEC_MIB_DISABLE 0x80000000
> +
> +#define FEC_IEVENT_HBERR 0x80000000
> +#define FEC_IEVENT_BABR 0x40000000
> +#define FEC_IEVENT_BABT 0x20000000
> +#define FEC_IEVENT_GRA 0x10000000
> +#define FEC_IEVENT_TFINT 0x08000000
> +#define FEC_IEVENT_MII 0x00800000
> +#define FEC_IEVENT_LATE_COL 0x00200000
> +#define FEC_IEVENT_COL_RETRY_LIM 0x00100000
> +#define FEC_IEVENT_XFIFO_UN 0x00080000
> +#define FEC_IEVENT_XFIFO_ERROR 0x00040000
> +#define FEC_IEVENT_RFIFO_ERROR 0x00020000
> +
> +#define FEC_IMASK_HBERR 0x80000000
> +#define FEC_IMASK_BABR 0x40000000
> +#define FEC_IMASK_BABT 0x20000000
> +#define FEC_IMASK_GRA 0x10000000
> +#define FEC_IMASK_MII 0x00800000
> +#define FEC_IMASK_LATE_COL 0x00200000
> +#define FEC_IMASK_COL_RETRY_LIM 0x00100000
> +#define FEC_IMASK_XFIFO_UN 0x00080000
> +#define FEC_IMASK_XFIFO_ERROR 0x00040000
> +#define FEC_IMASK_RFIFO_ERROR 0x00020000
> +
> +/* all but MII, which is enabled separately */
> +#define FEC_IMASK_ENABLE (FEC_IMASK_HBERR | FEC_IMASK_BABR | \
> + FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_LATE_COL | \
> + FEC_IMASK_COL_RETRY_LIM | FEC_IMASK_XFIFO_UN | \
> + FEC_IMASK_XFIFO_ERROR | FEC_IMASK_RFIFO_ERROR)
> +
> +#define FEC_RCNTRL_MAX_FL_SHIFT 16
> +#define FEC_RCNTRL_LOOP 0x01
> +#define FEC_RCNTRL_DRT 0x02
> +#define FEC_RCNTRL_MII_MODE 0x04
> +#define FEC_RCNTRL_PROM 0x08
> +#define FEC_RCNTRL_BC_REJ 0x10
> +#define FEC_RCNTRL_FCE 0x20
> +
> +#define FEC_TCNTRL_GTS 0x00000001
> +#define FEC_TCNTRL_HBC 0x00000002
> +#define FEC_TCNTRL_FDEN 0x00000004
> +#define FEC_TCNTRL_TFC_PAUSE 0x00000008
> +#define FEC_TCNTRL_RFC_PAUSE 0x00000010
> +
> +#define FEC_ECNTRL_RESET 0x00000001
> +#define FEC_ECNTRL_ETHER_EN 0x00000002
> +
> +#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
> +#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
> +#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
> +#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
> +#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
> +#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
> +#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */
> +
> +#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
> +#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
> +
> +#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
> +#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
> +
> +#define FEC_PADDR2_TYPE 0x8808
> +
> +#define FEC_OP_PAUSE_OPCODE 0x00010000
> +
> +#define FEC_FIFO_WMRK_256B 0x3
> +
> +#define FEC_FIFO_STATUS_ERR 0x00400000
> +#define FEC_FIFO_STATUS_UF 0x00200000
> +#define FEC_FIFO_STATUS_OF 0x00100000
> +
> +#define FEC_FIFO_CNTRL_FRAME 0x08000000
> +#define FEC_FIFO_CNTRL_LTG_7 0x07000000
> +
> +#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000
> +#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000
> +
> +#define FEC_XMIT_FSM_APPEND_CRC 0x02000000
> +#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000
> +
> +
> +extern struct of_platform_driver mpc52xx_fec_mdio_driver;
> +
> +#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */
> Index: linux.git/drivers/net/fec_mpc52xx_phy.c
> ===================================================================
> --- /dev/null
> +++ linux.git/drivers/net/fec_mpc52xx_phy.c
> @@ -0,0 +1,198 @@
> +/*
> + * Driver for the MPC5200 Fast Ethernet Controller - MDIO bus driver
> + *
> + * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/phy.h>
> +#include <linux/of_platform.h>
> +#include <asm/io.h>
> +#include <asm/mpc52xx.h>
> +#include "fec_mpc52xx.h"
> +
> +struct mpc52xx_fec_mdio_priv {
> + struct mpc52xx_fec __iomem *regs;
> +};
> +
> +static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> +{
> + struct mpc52xx_fec_mdio_priv *priv = bus->priv;
> + struct mpc52xx_fec __iomem *fec;
> + int tries = 100;
> + u32 request = FEC_MII_READ_FRAME;
> +
> + fec = priv->regs;
> + out_be32(&fec->ievent, FEC_IEVENT_MII);
> +
> + request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> + request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> + out_be32(&priv->regs->mii_data, request);
> +
> + /* wait for it to finish, this takes about 23 us on lite5200b */
> + while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
> + udelay(5);
> +
> + if (tries == 0)
> + return -ETIMEDOUT;
> +
> + return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
> +}
> +
> +static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
> +{
> + struct mpc52xx_fec_mdio_priv *priv = bus->priv;
> + struct mpc52xx_fec __iomem *fec;
> + u32 value = data;
> + int tries = 100;
> +
> + fec = priv->regs;
> + out_be32(&fec->ievent, FEC_IEVENT_MII);
> +
> + value |= FEC_MII_WRITE_FRAME;
> + value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> + value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> + out_be32(&priv->regs->mii_data, value);
> +
> + /* wait for request to finish */
> + while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
> + udelay(5);
> +
> + if (tries == 0)
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int mpc52xx_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 mpc52xx_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 = mpc52xx_fec_mdio_read;
> + bus->write = mpc52xx_fec_mdio_write;
> +
> + /* setup irqs */
> + bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
> + if (bus->irq == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + bus->irq[i] = PHY_POLL;
> +
> + while ((child = of_get_next_child(np, child)) != NULL) {
> + int irq = irq_of_parse_and_map(child, 0);
> + if (irq != NO_IRQ) {
> + const u32 *id = of_get_property(child, "reg", NULL);
> + bus->irq[*id] = irq;
> + }
> + }
> +
> + /* setup registers */
> + err = of_address_to_resource(np, 0, &res);
> + if (err)
> + goto out_free;
> + priv->regs = ioremap(res.start, res.end - res.start + 1);
> + if (priv->regs == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> +
> + bus->id = res.start;
> + bus->priv = priv;
> +
> + bus->dev = dev;
> + dev_set_drvdata(dev, bus);
> +
> + /* 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_unmap;
> +
> + return 0;
> +
> + out_unmap:
> + iounmap(priv->regs);
> + out_free:
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + if (bus->irq[i] != PHY_POLL)
> + irq_dispose_mapping(bus->irq[i]);
> + kfree(bus->irq);
> + kfree(priv);
> + kfree(bus);
> +
> + return err;
> +}
> +
> +static int mpc52xx_fec_mdio_remove(struct of_device *of)
> +{
> + struct device *dev = &of->dev;
> + struct mii_bus *bus = dev_get_drvdata(dev);
> + struct mpc52xx_fec_mdio_priv *priv = bus->priv;
> + int i;
> +
> + mdiobus_unregister(bus);
> + dev_set_drvdata(dev, NULL);
> +
> + 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 mpc52xx_fec_mdio_match[] = {
> + {
> + .type = "mdio",
> + .compatible = "mpc5200b-fec-phy",
> + },
> + {},
> +};
> +
> +struct of_platform_driver mpc52xx_fec_mdio_driver = {
> + .name = "mpc5200b-fec-phy",
> + .probe = mpc52xx_fec_mdio_probe,
> + .remove = mpc52xx_fec_mdio_remove,
> + .match_table = mpc52xx_fec_mdio_match,
> +};
> +
> +/* let fec driver call it, since this has to be registered before it */
> +EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
> +
> +
> +MODULE_LICENSE("Dual BSD/GPL");
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: linux-2.6.git: cannot build PS3 image
From: Geert Uytterhoeven @ 2007-10-25 9:27 UTC (permalink / raw)
To: Scott Wood; +Cc: Linux/PPC Development
In-Reply-To: <Pine.LNX.4.62.0710241820010.17958@pademelon.sonytel.be>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1935 bytes --]
On Wed, 24 Oct 2007, Geert Uytterhoeven wrote:
> On Wed, 17 Oct 2007, Scott Wood wrote:
> > Geert Uytterhoeven wrote:
> > >> diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
> > >> index 39b27e5..795f988 100755
> > >> --- a/arch/powerpc/boot/wrapper
> > >> +++ b/arch/powerpc/boot/wrapper
> > >> @@ -232,7 +232,7 @@ base=0x`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1`
> > >> entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3`
> > >>
> > >> if [ -n "$binary" ]; then
> > >> - mv "$ofile" "$ofile".elf
> > >> + cp "$ofile" "$ofile".elf
> > >> ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin
> > >> fi
> > >
> > > No comments?
> >
> > That'd work in this case, though it'd probably be better to make the
> > $ofile be the end result that will boot on the ps3, and leave a suffix
> > on the intermediate files.
>
> The $ofile is the end result to boot using kboot (2nd stage kernel).
> otheros.bld is the end result to write to FLASH ROM (1st stage kernel).
Bummer, ignore the first sentence. For a 2nd stage kernel, we do not boot
$ofile (= arch/powerpc/boot/zImage.ps3), but the plain vmlinux or
vmlinux.strip.
Hence zImage.ps3 is an intermediate file only and we don't need zImage at all.
Nevertheless, your other patch fixed the problem, thanks! ;-)
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox