LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] synchronize_irq needs a barrier
From: Nick Piggin @ 2007-10-19  4:49 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-kernel, linuxppc-dev, tglx, akpm, torvalds, mingo
In-Reply-To: <E1IiiX6-0002V0-00@gondolin.me.apana.org.au>

On Friday 19 October 2007 13:28, Herbert Xu wrote:
> Nick Piggin <nickpiggin@yahoo.com.au> wrote:
> >> First of all let's agree on some basic assumptions:
> >>
> >> * A pair of spin lock/unlock subsumes the effect of a full mb.
> >
> > Not unless you mean a pair of spin lock/unlock as in
> > 2 spin lock/unlock pairs (4 operations).
> >
> > *X = 10;
> > spin_lock(&lock);
> > /* *Y speculatively loaded here */
> > /* store to *X leaves CPU store queue here */
> > spin_unlock(&lock);
> > y = *Y;
>
> Good point.
>
> Although in this case we're still safe because in the worst
> cases:
>
> CPU0				CPU1
> irq_sync = 1
> synchronize_irq
> 	spin lock
> 	load IRQ_INPROGRESS
> irq_sync sync is visible
> 	spin unlock
> 				spin lock
> 					load irq_sync
> 	while (IRQ_INPROGRESS)
> 		wait
> 	return
> 				set IRQ_INPROGRESS
> 				spin unlock
> 				tg3_msi
> 					ack IRQ
> 					if (irq_sync)
> 						return
> 				spin lock
> 				clear IRQ_INPROGRESS
> 				spin unlock
>
> ------------------------------------------------------------
>
> CPU0				CPU1
> 				spin lock
> 					load irq_sync
> irq_sync = 1
> synchronize_irq
> 				set IRQ_INPROGRESS
> 				spin unlock
> 	spin lock
> 	load IRQ_INPROGRESS
> irq_sync sync is visible
> 	spin unlock
> 	while (IRQ_INPROGRESS)
> 		wait
> 				tg3_msi
> 					ack IRQ
> 					if (irq_sync)
> 						return
> 					do work
> 				spin lock
> 				clear IRQ_INPROGRESS
> 				spin unlock
> 	return
>
> So because we're using the same lock on both sides, it does
> do the right thing even without the memory barrier.


Yeah, if you've got the lock on both sides there, then I
agree it will be correct.

^ permalink raw reply

* Re: [PATCH] synchronize_irq needs a barrier
From: Benjamin Herrenschmidt @ 2007-10-19  4:58 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Linux Kernel Mailing List, linuxppc-dev, Thomas Gleixner, akpm,
	Linus Torvalds, Ingo Molnar
In-Reply-To: <20071019044806.GA10080@gondor.apana.org.au>


On Fri, 2007-10-19 at 12:48 +0800, Herbert Xu wrote:

> [IRQ]: Fix synchronize_irq races with IRQ handler
> 
> As it is some callers of synchronize_irq rely on memory barriers
> to provide synchronisation against the IRQ handlers.  For example,
> the tg3 driver does
> 
> 	tp->irq_sync = 1;
> 	smp_mb();
> 	synchronize_irq();
> 
> and then in the IRQ handler:
> 
> 	if (!tp->irq_sync)
> 		netif_rx_schedule(dev, &tp->napi);
> 
> Unfortunately memory barriers only work well when they come in
> pairs.  Because we don't actually have memory barriers on the
> IRQ path, the memory barrier before the synchronize_irq() doesn't
> actually protect us.
> 
> In particular, synchronize_irq() may return followed by the
> result of netif_rx_schedule being made visible.
> 
> This patch (mostly written by Linus) fixes this by using spin
> locks instead of memory barries on the synchronize_irq() path.
> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Good for me.

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Cheers,
Ben.

^ permalink raw reply

* [PATCH] NULL terminate the pci_device_ids in pasemi_edac
From: Stephen Rothwell @ 2007-10-19  5:07 UTC (permalink / raw)
  To: Olof Johansson; +Cc: ppc-dev, Andrew Morton

Fixes:
drivers/edac/pasemi_edac: struct pci_device_id is 32 bytes.  The last of 1 is:
0x00 0x00 0x19 0x59 0x00 0x00 0xa0 0x0a 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
FATAL: drivers/edac/pasemi_edac: struct pci_device_id is not terminated with a NULL entry!

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
 drivers/edac/pasemi_edac.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index e66cdd4..9007d06 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
@@ -270,6 +270,7 @@ static void __devexit pasemi_edac_remove(struct pci_dev *pdev)
 
 static const struct pci_device_id pasemi_edac_pci_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa00a) },
+	{ }
 };
 
 MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl);
-- 
1.5.3.4

^ permalink raw reply related

* Tiny login: user add command
From: pjmaiya @ 2007-10-19  5:23 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 800 bytes --]

Hi,
 I am using montavista linux. Using TCT tool i have added package for user creation. I am having following problem
  a.. If I use tiny login package, I will be getting useradd binary but number of parameter are few like
 Usage: adduser [OPTIONS]... <USER> 
Options:

  -h <directory>    specify home directory
  -s <shell>        specify shell
  -g <gecos>        specify GECOS stringa.. If I don't use tiny login package, I will be selecting useradd package from admin menu. But I am unable to execute this command since it gives follwing error
      /usr/sbin/groupadd missing..

  a.. Actually I want useradd command similar to linux where more argument are taken, especially I wanted 'user' to be part of more than one group.
can anyone help me out..

thanx in advance,
pjmaiya

[-- Attachment #2: Type: text/html, Size: 1818 bytes --]

^ permalink raw reply

* Re: Merge dtc
From: Milton Miller @ 2007-10-19  5:34 UTC (permalink / raw)
  To: David Gibson; +Cc: ppcdev, Paul Mackerras, Sam Ravnborg
In-Reply-To: <20071019013048.GC30283@localhost.localdomain>


On Oct 18, 2007, at 8:30 PM, David Gibson wrote:

> On Thu, Oct 18, 2007 at 12:49:54PM -0500, Milton Miller wrote:
>> On Tue Oct 16 15:02:17 EST 2007, David Gibson wrote:
>>> Too big for the list, full patch at
>>> http://ozlabs.org/~dgibson/home/merge-dtc.patch+
>>
>> So split it up.   The obvious one is "here is the unique content, then
>> copy these files from dtc git" would have been better.
>
> *facepalm*
>
> The point of the small patches thing is not to glom together logically
> separate patches.  It's *not* to split patches up simply for the sake
> of making them smaller.

The point of posting on the list is to encourage review before merging. 
  Hiding them behind a download means a lot fewer people are looking at 
the code.

> You've suggested the closest thing to a logical split here, but even
> then - the dtc files are dead without the Makefile changes, and the
> Makefile changes won't build without the dtc files (so the patches
> would have to go in reversed order to what you suggest).
>
> Not to mention that the Makefile patch will be tiny and the raw import
> will still be way too big for the list.

I'm talking about split for review, not necessarily merge.

We split by function for review so that different people pay closer 
attention to their areas of intrest and speciality.  This helps prevent 
people being distracted by the bulk.

The files that are verbatim from the other project have been reviewed 
in that project (at least in theory), and therefore are not likely to 
draw comments.   Especially since they are (1) shadows from another 
project and (2) host files, there is more flexibility and less review 
required, eg relaxed coding standards, correctness already tested, and 
in this case multiple platform testing.

Sam's suggestion to split the generated files was because they require 
no review other than for damage.

In contrast, the files such as the make rules are original and unique 
to this import, and therefore draw comments during review.  If you 
weren't asking for a review, why did you post to the mailing list?

Oh, and the files being in the tree but dead is fine from a bisect 
standpoint.  The patch can be reverted if the makefile doesn't go in 
(not that a maintainer would commit them separately).

>> I finally went and looked at the url.  The Kbuild integration is 
>> wrong.
>
> Wrong?  Not how you'd prefer them perhaps...

Wrong in that its unlike every other program that Kbuild makes.

>>   It should build dtc in dtc-src and run the binary from there, and 
>> the
>> rules should be in a Kconfig as a normal host-target in that 
>> directory.
>
> Why?  This approach has the advantage that the subdirectory contains
> *only* verbatim imported files, which could well make updates simpler.

The file name Kbuild is unlikely to conflict with a file from that 
other repository.  It doesn't contain all the files in that repository 
(or even all in a subdirectory) so there is some filtering going on 
anyways.

>    (I don't have a problem with that Kbuild including Makefie.dtc).
>>
>> things like the dependancy on scripts_basic in the top level
>> Makefile.
>
> I'm not even sure what you mean by this.

I was trying to give a hint where you could find "compile programs in 
that directory so I can run them here" for you to draw upon.

^ permalink raw reply

* [NET]: Fix possible dev_deactivate race condition
From: Herbert Xu @ 2007-10-19  5:36 UTC (permalink / raw)
  To: David S. Miller
  Cc: Linux Kernel Mailing List, linuxppc-dev, Thomas Gleixner, netdev,
	akpm, Linus Torvalds, Ingo Molnar
In-Reply-To: <20071019042025.GA9617@gondor.apana.org.au>

On Fri, Oct 19, 2007 at 12:20:25PM +0800, Herbert Xu wrote:
>
> In fact this bug exists elsewhere too.  For example, the network
> stack does this in net/sched/sch_generic.c:
> 
>         /* Wait for outstanding qdisc_run calls. */
> 	while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
> 		yield();
> 
> This has the same problem as the current synchronize_irq code.

OK here is the fix for that case.

[NET]: Fix possible dev_deactivate race condition

The function dev_deactivate is supposed to only return when
all outstanding transmissions have completed.  Unfortunately
it is possible for store operations in the driver's transmit
function to only become visible after dev_deactivate returns.

This patch fixes this by taking the queue lock after we see
the end of the queue run.  This ensures that all effects of
any previous transmit calls are visible.

If however we detect that there is another queue run occuring,
then we'll warn about it because this should never happen as
we have pointed dev->qdisc to noop_qdisc within the same queue
lock earlier in the functino.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index e01d576..b3b7420 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -556,6 +556,7 @@ void dev_deactivate(struct net_device *dev)
 {
 	struct Qdisc *qdisc;
 	struct sk_buff *skb;
+	int running;
 
 	spin_lock_bh(&dev->queue_lock);
 	qdisc = dev->qdisc;
@@ -571,12 +572,31 @@ void dev_deactivate(struct net_device *dev)
 
 	dev_watchdog_down(dev);
 
-	/* Wait for outstanding dev_queue_xmit calls. */
+	/* Wait for outstanding qdisc-less dev_queue_xmit calls. */
 	synchronize_rcu();
 
 	/* Wait for outstanding qdisc_run calls. */
-	while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
-		yield();
+	do {
+		while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
+			yield();
+
+		/*
+		 * Double-check inside queue lock to ensure that all effects
+		 * of the queue run are visible when we return.
+		 */
+		spin_lock_bh(&dev->queue_lock);
+		running = test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
+		spin_unlock_bh(&dev->queue_lock);
+
+		/*
+		 * The running flag should never be set at this point because
+		 * we've already set dev->qdisc to noop_qdisc *inside* the same
+		 * pair of spin locks.  That is, if any qdisc_run starts after
+		 * our initial test it should see the noop_qdisc and then
+		 * clear the RUNNING bit before dropping the queue lock.  So
+		 * if it is set here then we've found a bug.
+		 */
+	} while (WARN_ON_ONCE(running));
 }
 
 void dev_init_scheduler(struct net_device *dev)

^ permalink raw reply related

* Re: [NET]: Fix possible dev_deactivate race condition
From: David Miller @ 2007-10-19  5:38 UTC (permalink / raw)
  To: herbert; +Cc: linux-kernel, linuxppc-dev, tglx, netdev, akpm, torvalds, mingo
In-Reply-To: <20071019053624.GA10560@gondor.apana.org.au>

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Fri, 19 Oct 2007 13:36:24 +0800

> [NET]: Fix possible dev_deactivate race condition
> 
> The function dev_deactivate is supposed to only return when
> all outstanding transmissions have completed.  Unfortunately
> it is possible for store operations in the driver's transmit
> function to only become visible after dev_deactivate returns.
> 
> This patch fixes this by taking the queue lock after we see
> the end of the queue run.  This ensures that all effects of
> any previous transmit calls are visible.
> 
> If however we detect that there is another queue run occuring,
> then we'll warn about it because this should never happen as
> we have pointed dev->qdisc to noop_qdisc within the same queue
> lock earlier in the functino.
> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Applied, thanks Herbert!

^ permalink raw reply

* Re: Merge dtc
From: Milton Miller @ 2007-10-19  5:56 UTC (permalink / raw)
  To: David Gibson; +Cc: ppcdev, Sam Ravnborg, Paul Mackerras
In-Reply-To: <20071019014510.GD30283@localhost.localdomain>

On Oct 18, 2007, at 8:45 PM, David Gibson wrote:
> On Thu, Oct 18, 2007 at 09:59:26PM +0200, Sam Ravnborg wrote:
>> On Thu, Oct 18, 2007 at 12:49:54PM -0500, Milton Miller wrote:
>>> On Tue Oct 16 15:02:17 EST 2007, David Gibson wrote:
>>>
>>>> This very large patch incorporates a copy of dtc into the kernel
>>>> source, in arch/powerpc/boot/dtc-src.  This means that dtc is no
>>>> longer an external dependency to build kernels with configurations
>>>> which need a dtb file.
>
>> As Milton already pointed out you should build dtc in the
>> dtc directory (why the -src prefix??).
>
> The -src suffix is only there because I'm not building in the
> directory - we can't have both a dtc binary and a dtc directory in
> arch/powerpc/boot.

So run the dtc binary stored in the sub directory.  Thats what we do 
elsewhere.

> Ok, so how do I build in the subdirectory?  I was going to do that,
> but couldn't for the life of me figure out how.

Documentation/kbuild/makefiles.txt  6.4 boot images:

         "$(Q)$(MAKE) $(build)=<dir>" is the recommended way to invoke
         make in a subdirectory.

Section 4 Host Program Support is also relavent, and mentions $(always).


>> And the dtc specific Makefile looks like something from
>> the late 80'. Please drop all these ALLUPPERCASE variables
>> and accept a little bit of redundancy.
>
> Hrm... I'm pretty dubious about this.  Practically every Makefile in
> the universe, *except* Kbuild uses uppercase for most variables.
> Makefile.dtc is imported verbatim from the standalone dtc package, and
> is supposed to have the minimal information about what needs to be
> built to import into Makefiles that actually know how to build things.
>
>> Then mere humans may be able to read the Makefile.
>
> Says a maintainer of Kbuild, about my tiny and not-very-complex
> Makefile fragment... um, ok...

overley complex calls to override source, conditional rules based on 
shipped files?  Its not a trivial fragment.

milton

^ permalink raw reply

* Re: [PATCH] synchronize_irq needs a barrier
From: Herbert Xu @ 2007-10-19  5:53 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Linux Kernel Mailing List, linuxppc-dev, Thomas Gleixner, akpm,
	Linus Torvalds, Ingo Molnar
In-Reply-To: <1192768014.7367.96.camel@pasglop>

On Fri, Oct 19, 2007 at 02:26:54PM +1000, Benjamin Herrenschmidt wrote:
>
> I think a simple smp_mb(); here after foo = 1; is enough, which means
> basically just having an smp_mp(); inside napi_synchronize(), before
> the test_bit(). Or do I miss something ?

Yes I think you're right.  In this case we do have barriers
everywhere else so this should work.

Although if you want napi_synchronize to have the property that
when it returns all NAPI processing effects are visible then
you'd need another smp_mb() after the loop.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PATCH 1/2] qemu platform, v2
From: Rob Landley @ 2007-10-19  6:28 UTC (permalink / raw)
  To: Grant Likely
  Cc: Milton Miller, linuxppc-dev, Paul Mackerras, Christoph Hellwig
In-Reply-To: <fa686aa40710181029o6852b1b0pf6259f27cabfd085@mail.gmail.com>

On Thursday 18 October 2007 12:29:08 pm Grant Likely wrote:
> On 10/18/07, Milton Miller <miltonm@bga.com> wrote:
> > If we say only some boards or ports are special and need to build then
> > I would vote for shipping asm files.  If we think we need to build any
> > random embedded platform without installing dtc then we should merge
> > dtc.
>
> I don't think we do.  It's looking like there are going to be out of
> tree users of dtc also (The are some patches floating around for
> u-boot to use the device tree for it's own initialization).  I don't
> think it's unreasonable to install dtc for embedded development.

There are out of tree users of yacc and lex, but the kernel has *.c_shipped 
files so as not to require that external tool of people who simply want to 
build the sucker without modifying it.  "make oldconfig" was modified not to 
require curses.

How about *.S_shipped files?

> I like the idea of shipping asm files to support the qemu target; at
> least until qemu gets better firmware.

I've now gotten qemu to boot a kernel I built, using Milton's 1/2 patch and a 
a self-contained build of a 4k ppc_boot.rom (which includes the dtc source 
because I don't expect anybody else to have it installed, either).  
Description and links to source, binaries, and build scripts in this message:

http://lists.gnu.org/archive/html/qemu-devel/2007-10/msg00415.html

There's a problem with qemu-cvs (detailed in the message), but qemu-system-ppc 
0.9.0 boots fine, up to a shell prompt.

> Cheers,
> g.

Rob
-- 
"One of my most productive days was throwing away 1000 lines of code."
  - Ken Thompson.

^ permalink raw reply

* Re: [PATCH] NULL terminate the pci_device_ids in pasemi_edac
From: Olof Johansson @ 2007-10-19  6:47 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: ppc-dev, Andrew Morton
In-Reply-To: <20071019150722.8d48eb1d.sfr@canb.auug.org.au>

On Fri, Oct 19, 2007 at 03:07:22PM +1000, Stephen Rothwell wrote:
> Fixes:
> drivers/edac/pasemi_edac: struct pci_device_id is 32 bytes.  The last of 1 is:
> 0x00 0x00 0x19 0x59 0x00 0x00 0xa0 0x0a 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
> 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> FATAL: drivers/edac/pasemi_edac: struct pci_device_id is not terminated with a NULL entry!
> 
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>

Acked-by: Olof Johansson <olof@lixom.net>

Thanks for fixing this, Stephen. ID lists without termination can really
cause weird problems at the most random times since it depends on how
the kernel is built whether they do any (immediate) harm or not.


-Olof

^ permalink raw reply

* Re: Merge dtc
From: David Gibson @ 2007-10-19  6:55 UTC (permalink / raw)
  To: Milton Miller; +Cc: ppcdev, Sam Ravnborg, Paul Mackerras
In-Reply-To: <1b5c57d93e45d94d007b543ea5e2de02@bga.com>

On Fri, Oct 19, 2007 at 12:56:41AM -0500, Milton Miller wrote:
> On Oct 18, 2007, at 8:45 PM, David Gibson wrote:
> > On Thu, Oct 18, 2007 at 09:59:26PM +0200, Sam Ravnborg wrote:
> >> On Thu, Oct 18, 2007 at 12:49:54PM -0500, Milton Miller wrote:
> >>> On Tue Oct 16 15:02:17 EST 2007, David Gibson wrote:
> >>>
> >>>> This very large patch incorporates a copy of dtc into the kernel
> >>>> source, in arch/powerpc/boot/dtc-src.  This means that dtc is no
> >>>> longer an external dependency to build kernels with configurations
> >>>> which need a dtb file.
> >
> >> As Milton already pointed out you should build dtc in the
> >> dtc directory (why the -src prefix??).
> >
> > The -src suffix is only there because I'm not building in the
> > directory - we can't have both a dtc binary and a dtc directory in
> > arch/powerpc/boot.
> 
> So run the dtc binary stored in the sub directory.  Thats what we do 
> elsewhere.

Yes, yes, which boils down to your other point of building in the
subdirectory.  It's not a separate issue.

> > Ok, so how do I build in the subdirectory?  I was going to do that,
> > but couldn't for the life of me figure out how.
> 
> Documentation/kbuild/makefiles.txt  6.4 boot images:
> 
>          "$(Q)$(MAKE) $(build)=<dir>" is the recommended way to invoke
>          make in a subdirectory.

But where does it go?  To have somewhere to put that rule, we'd still
need a target in arch/powerpc/boot itself.

> Section 4 Host Program Support is also relavent, and mentions $(always).

I know I tried using $(always), but I couldn't figure out how to make
it do something useful.

> >> And the dtc specific Makefile looks like something from
> >> the late 80'. Please drop all these ALLUPPERCASE variables
> >> and accept a little bit of redundancy.
> >
> > Hrm... I'm pretty dubious about this.  Practically every Makefile in
> > the universe, *except* Kbuild uses uppercase for most variables.
> > Makefile.dtc is imported verbatim from the standalone dtc package, and
> > is supposed to have the minimal information about what needs to be
> > built to import into Makefiles that actually know how to build things.
> >
> >> Then mere humans may be able to read the Makefile.
> >
> > Says a maintainer of Kbuild, about my tiny and not-very-complex
> > Makefile fragment... um, ok...
> 
> overley complex calls to override source, 

I'm not sure what you're referring to...  even if you mean in
Makefile.dtc or in the diff to arch/powerpc/boot/Makefile.

>conditional rules based on 
> shipped files?  

Or here, for sure.  The shipped/lex/yacc rules are just based on those
from Kconfig and genksyms.

> Its not a trivial fragment.

Compared to the behemoth that is Kbuild...

I'm happy to improve the Makefile integration, but you seem to be
rather vague on how, and the Kbuild documentation makes my brain hurt.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: Merge dtc
From: Sam Ravnborg @ 2007-10-19  7:07 UTC (permalink / raw)
  To: Milton Miller, ppcdev, Paul Mackerras
In-Reply-To: <20071019065530.GA27017@localhost.localdomain>

> Compared to the behemoth that is Kbuild...
> 
> I'm happy to improve the Makefile integration, but you seem to be
> rather vague on how, and the Kbuild documentation makes my brain hurt.

I can make an ALL UPPERCASE VERSION if that makes it easier for you to read ;-)
Give me a day or two then I shall give it a try and see what I can do about it.
I will use the previsous posted URL as basis if you do not tell me otherwise.

	Sam

^ permalink raw reply

* Re: Merge dtc
From: David Gibson @ 2007-10-19  7:10 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: ppcdev, Paul Mackerras, Milton Miller
In-Reply-To: <20071019070718.GA28099@uranus.ravnborg.org>

On Fri, Oct 19, 2007 at 09:07:18AM +0200, Sam Ravnborg wrote:
> > Compared to the behemoth that is Kbuild...
> > 
> > I'm happy to improve the Makefile integration, but you seem to be
> > rather vague on how, and the Kbuild documentation makes my brain hurt.
> 
> I can make an ALL UPPERCASE VERSION if that makes it easier for you
> to read ;-)

Hardy har har.  Since this is supposed to build both within the kernel
and standalone there will necessarily be a few style conflicts at the
boundary.  Kbuild is not in the majority here; in fact it's close to
unique.

> Give me a day or two then I shall give it a try and see what I can
> do about it.  I will use the previsous posted URL as basis if you do
> not tell me otherwise.

Thank you.  The previous URL should be fine, I've made no changes
since then.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* RE: [PATCH v5 9/9] add MPC837x MDS board default device tree
From: Li Yang-r58472 @ 2007-10-19  7:31 UTC (permalink / raw)
  To: David Gibson, Phillips Kim-R1AAHA; +Cc: linuxppc-dev, paulus
In-Reply-To: <20071019005613.GA18240@localhost.localdomain>

> -----Original Message-----
> From: David Gibson [mailto:david@gibson.dropbear.id.au]=20
> Sent: Friday, October 19, 2007 8:56 AM
> To: Li Yang-r58472
> Cc: galak@kernel.crashing.org; paulus@samba.org;=20
> linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH v5 9/9] add MPC837x MDS board default device tree
>=20
> On Thu, Oct 18, 2007 at 06:16:20PM +0800, Li Yang wrote:
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts=20
> > b/arch/powerpc/boot/dts/mpc8377_mds.dts
> > new file mode 100644
> > index 0000000..8530de6
> > --- /dev/null
> > +++ b/arch/powerpc/boot/dts/mpc8377_mds.dts
> > @@ -0,0 +1,282 @@
> [snip]
> > +		crypto@30000 {
> > +			model =3D "SEC3";
> > +			compatible =3D "talitos";
>=20
> That compatible doesn't look specific enough.  It should at=20
> least have a vendor portion.  In general it's best to have=20
> all the information you need to pick a driver and options in=20
> compatible, rather than splitting that info into model.

I think we could do this in a separate patch.  Change the spec and then
update all the in-tree device tree with SEC node.

- Leo

^ permalink raw reply

* Re: [NET]: Fix possible dev_deactivate race condition
From: Peter Zijlstra @ 2007-10-19  7:35 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Linux Kernel Mailing List, David S. Miller, linuxppc-dev,
	Thomas Gleixner, netdev, akpm, Linus Torvalds, Ingo Molnar
In-Reply-To: <20071019053624.GA10560@gondor.apana.org.au>

On Fri, 2007-10-19 at 13:36 +0800, Herbert Xu wrote:
> On Fri, Oct 19, 2007 at 12:20:25PM +0800, Herbert Xu wrote:
> >
> > In fact this bug exists elsewhere too.  For example, the network
> > stack does this in net/sched/sch_generic.c:
> > 
> >         /* Wait for outstanding qdisc_run calls. */
> >       while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
> >               yield();
> > 
> > This has the same problem as the current synchronize_irq code.
> 

> diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
> index e01d576..b3b7420 100644
> --- a/net/sched/sch_generic.c
> +++ b/net/sched/sch_generic.c
> @@ -556,6 +556,7 @@ void dev_deactivate(struct net_device *dev)
>  {
>         struct Qdisc *qdisc;
>         struct sk_buff *skb;
> +       int running;
>  
>         spin_lock_bh(&dev->queue_lock);
>         qdisc = dev->qdisc;
> @@ -571,12 +572,31 @@ void dev_deactivate(struct net_device *dev)
>  
>         dev_watchdog_down(dev);
>  
> -       /* Wait for outstanding dev_queue_xmit calls. */
> +       /* Wait for outstanding qdisc-less dev_queue_xmit calls. */
>         synchronize_rcu();
>  
>         /* Wait for outstanding qdisc_run calls. */
> -       while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
> -               yield();
> +       do {
> +               while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
> +                       yield();
> +

Ouch!, is there really no sane locking alternative? Hashed waitqueues
like for the page lock come to mind.

> +               /*
> +                * Double-check inside queue lock to ensure that all effects
> +                * of the queue run are visible when we return.
> +                */
> +               spin_lock_bh(&dev->queue_lock);
> +               running = test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
> +               spin_unlock_bh(&dev->queue_lock);
> +
> +               /*
> +                * The running flag should never be set at this point because
> +                * we've already set dev->qdisc to noop_qdisc *inside* the same
> +                * pair of spin locks.  That is, if any qdisc_run starts after
> +                * our initial test it should see the noop_qdisc and then
> +                * clear the RUNNING bit before dropping the queue lock.  So
> +                * if it is set here then we've found a bug.
> +                */
> +       } while (WARN_ON_ONCE(running));
>  }
>  
>  void dev_init_scheduler(struct net_device *dev) 

^ permalink raw reply

* Re: tiny login: useradd command
From: Clemens Koller @ 2007-10-19  8:39 UTC (permalink / raw)
  To: pjmaiya; +Cc: linuxppc-embedded
In-Reply-To: <005e01c81171$11421820$4601a8c0@signet>

pjmaiya schrieb:
 > Hi,
 >  I am using montavista linux.

Then, please ask their support, when they charge a 5 number USD amount as
part of their license/support model. (That's what I've been told this week.)

 > Using TCT tool i have added package for
 > user creation. I am having following problem
 >
 >     * If I use tiny login package, I will be getting useradd binary but
 >       number of parameter are few like
 >
 >  Usage: adduser [OPTIONS]... <USER>
 >
 > Options:
 >
 >   -h <directory>    specify home directory
 >   -s <shell>        specify shell
 >   -g <gecos>        specify GECOS string
 >
 >     * If I don't use tiny login package, I will be selecting useradd
 >       package from admin menu. But I am unable to execute this command
 >       since it gives follwing error
 >
 >       /usr/sbin/groupadd missing..
 >
 >
 >     * Actually I want useradd command similar to linux where more
 >       argument are taken, especially I wanted 'user' to be part of more
 >       than one group.
 >
 > can anyone help me out..

I would just take useradd/groupadd from the Shadow password file utilities.

Regards,

Clemens Koller
__________________________________
R&D Imaging Devices
Anagramm GmbH
Rupert-Mayer-Straße 45/1
Linhof Werksgelände
D-81379 München
Tel.089-741518-50
Fax 089-741518-19
http://www.anagramm-technology.com

^ permalink raw reply

* SystemACE driver problem
From: aauer1 @ 2007-10-19  9:03 UTC (permalink / raw)
  To: linuxppc-embedded


Hello

I'm trying to boot a Linux Kernel 2.6.23-rc2 from Grant Likely (thanks for
the great work) on a Xilinx ML403 board. I want to use the second partition
of the Compact Flash Card as root filesystem. But the boot process hangs at
the initialization of the SystemACE module. A strange effect is that the
DONE LED (configuration of the FPGA is done) turns off. So, this means that
the FPGA loses his configuration.
Has anybody recognized a similar problem with the SystemACE module??

The boot log:
========
[    0.000000] Linux version 2.6.23-rc2 (bbauer@soclin) (gcc version 4.0.0
(DEN7
[    0.000000] Xilinx ML403 Reference System (Virtex-4 FX)
[    0.000000] Zone PFN ranges:
[    0.000000]   DMA             0 ->    16384
[    0.000000]   Normal      16384 ->    16384
[    0.000000] Movable zone start PFN for each node
[    0.000000] early_node_map[1] active PFN ranges
[    0.000000]     0:        0 ->    16384
[    0.000000] Built 1 zonelists in Zone order.  Total pages: 16256
[    0.000000] Kernel command line: console=ttyUL0 root=/dev/xsa2 rw
[    0.000000] Xilinx INTC #0 at 0x41200000 mapped to 0xFDFFF000
[    0.000000] PID hash table entries: 256 (order: 8, 1024 bytes)
[    0.000328] Console: colour dummy device 80x25
[    0.001390] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.002934] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.029759] Memory: 63244k available (1176k kernel code, 388k data, 84k
init)
[    0.120774] Mount-cache hash table entries: 512
[    0.171986] io scheduler noop registered
[    0.172248] io scheduler anticipatory registered (default)
[    0.172300] io scheduler deadline registered
[    0.172508] io scheduler cfq registered
[    0.268807] uartlite.0: ttyUL0 at MMIO 0x40600000 (irq = 2) is a uartlite
[    0.270399] console [ttyUL0] enabled
[    1.762725] RAMDISK driver initialized: 8 RAM disks of 8192K size 1024
blocke
[    1.852062] Registering Xilinx SystemACE driver, major=254
[    1.919734] xsysace xsysace.0: ace_probe(c01638e0)


Thanks,
Andreas
-- 
View this message in context: http://www.nabble.com/SystemACE-driver-problem-tf4651846.html#a13290652
Sent from the linuxppc-embedded mailing list archive at Nabble.com.

^ permalink raw reply

* Re: [NET]: Fix possible dev_deactivate race condition
From: Herbert Xu @ 2007-10-19  9:29 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Linux Kernel Mailing List, David S. Miller, linuxppc-dev,
	Thomas Gleixner, netdev, akpm, Linus Torvalds, Ingo Molnar
In-Reply-To: <1192779319.27435.163.camel@twins>

On Fri, Oct 19, 2007 at 09:35:19AM +0200, Peter Zijlstra wrote:
>
> >         /* Wait for outstanding qdisc_run calls. */
> > -       while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
> > -               yield();
> > +       do {
> > +               while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
> > +                       yield();
> > +
> 
> Ouch!, is there really no sane locking alternative? Hashed waitqueues
> like for the page lock come to mind.

Well if we ever moved the transmission to full process context
then we'll gladly accept your patch :)

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PATCH v2 3/4] Implement clockevents driver for powerpc
From: Gabriel Paubert @ 2007-10-19  9:22 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, Thomas Gleixner, Realtime Kernel
In-Reply-To: <18199.63230.583536.307945@cargo.ozlabs.ibm.com>

On Fri, Oct 19, 2007 at 10:14:54AM +1000, Paul Mackerras wrote:
> Sergei Shtylyov writes:
> 
> > > What problem do you see arising from this?
> > 
> >     Timers firing too early.
> 
> Only if the minimum interrupt latency is less than 1 decrementer
> tick.  That seems pretty unlikely to me unless you have a very slow
> timebase frequency.
> 
> In fact what we should program the decrementer to is:
> 
> 	timeout - (is_booke? 0: 1) - min_interrupt_latency
> 
> I was assuming that min_interrupt_latency (measured in timebase ticks)
> would be at least 1, but apparently some systems can have a timebase
> frequency as low as 1kHz, so we'll have to have an ifdef or something.

If it is the case (the slowest I've seen was in the 8 MHz range), then
it is better not to subtract the one: think of what happens when you
have say, a 10kHz timebase/decrementer frequency and you want to
interrupt after 1 ms. You actually want to interrupt after 11
transitions of the decrementer, not 10 since the result could be
as low as 900us if you happen to read the timebase just before
a transition.

I'd really wish there were a guarantee of a minimum timebase 
frequency, for anything above ~10MHz, we are splitting hairs
about an off-by-one error that never accumulates, but if systems
with very low TB freq exist, you have to be very careful. In any case
timer interrupts should never came earlier than asked for.

	Gabriel

^ permalink raw reply

* Re: [PATCH] NULL terminate the pci_device_ids in pasemi_edac
From: Michael Ellerman @ 2007-10-19 10:34 UTC (permalink / raw)
  To: Olof Johansson; +Cc: Stephen Rothwell, Andrew Morton, ppc-dev
In-Reply-To: <20071019064725.GA1806@lixom.net>

[-- Attachment #1: Type: text/plain, Size: 1199 bytes --]


On Fri, 2007-10-19 at 01:47 -0500, Olof Johansson wrote:
> On Fri, Oct 19, 2007 at 03:07:22PM +1000, Stephen Rothwell wrote:
> > Fixes:
> > drivers/edac/pasemi_edac: struct pci_device_id is 32 bytes.  The last of 1 is:
> > 0x00 0x00 0x19 0x59 0x00 0x00 0xa0 0x0a 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
> > 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> > FATAL: drivers/edac/pasemi_edac: struct pci_device_id is not terminated with a NULL entry!
> > 
> > Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> 
> Acked-by: Olof Johansson <olof@lixom.net>
> 
> Thanks for fixing this, Stephen. ID lists without termination can really
> cause weird problems at the most random times since it depends on how
> the kernel is built whether they do any (immediate) harm or not.

Kind of makes you wonder if some macro foo to automatically append the
NULL entry wouldn't be a good idea.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* RE: [PATCH] qe_lib: export symbols to fix compile error when QE drivers compile as modules
From: Li Yang-r58472 @ 2007-10-19 10:44 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev list, Tabi Timur-B04825
In-Reply-To: <F2C6FCFC-78EF-4660-85F8-10C1AFE860F4@kernel.crashing.org>

> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]=20
> Sent: Wednesday, October 17, 2007 11:30 PM
> To: Li Yang-r58472
> Cc: linuxppc-dev list; Tabi Timur-B04825
> Subject: Re: [PATCH] qe_lib: export symbols to fix compile=20
> error when QE drivers compile as modules
>=20
>=20
> On May 25, 2007, at 7:15 AM, Kumar Gala wrote:
>=20
> >
> > On May 24, 2007, at 9:45 PM, Li Yang-r58472 wrote:
> >
> >>
> >>> -----Original Message-----
> >>> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> >>> Sent: Thursday, May 24, 2007 7:44 PM
> >>> To: Li Yang-r58472
> >>> Cc: Paul; linuxppc-dev@ozlabs.org
> >>> Subject: Re: [PATCH] qe_lib: export symbols to fix compile error=20
> >>> when
> >> QE drivers
> >>> compile as modules
> >>>
> >>>
> >>> On May 24, 2007, at 4:14 AM, Li Yang wrote:
> >>>
> >>>> Export symbols of qe_lib to be used by QE drivers.
> >>>>
> >>>> Signed-off-by: Li Yang <leoli@freescale.com>
> >>>> ---
> >>>> arch/powerpc/sysdev/qe_lib/ucc.c      |    7 +++++++
> >>>> arch/powerpc/sysdev/qe_lib/ucc_fast.c |    8 ++++++++
> >>>> arch/powerpc/sysdev/qe_lib/ucc_slow.c |   12 ++++++++++--
> >>>> 3 files changed, 25 insertions(+), 2 deletions(-)
> >>>
>=20
> What happened with this?

This has been merged as commit 65482ccf9d00bf4f68e17eb9c656d045d26e5d1f.

- Leo

^ permalink raw reply

* Re: [PATCH 04/15] [POWERPC] CM5200 DTS
From: Marian Balakowicz @ 2007-10-19 11:06 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20071018002256.GA24236@localhost.localdomain>

David Gibson wrote:
> On Wed, Oct 17, 2007 at 02:22:04PM +0200, Marian Balakowicz wrote:
>> David Gibson wrote:
>>> [snip]
>>>> +		flash@c000000 {
>>>> +			device_type = "rom";
>>>> +			compatible = "direct-mapped";
>>>> +			reg = <0c000000 02000000>;
>>>> +			probe-type = "CFI";
>>>> +			bank-width = <2>;
>>>> +			partitions = <00000000 00060000
>>>> +				00060000 00020000
>>>> +				00080000 00020000
>>>> +				000a0000 00020000
>>>> +				000c0000 00200000
>>>> +				002c0000 01b40000
>>>> +				01e00000 00200000>;
>>>> +			partition-names = "uboot\0env\0redund_env\0dtb\0kernel\0rootfs\0config";
>>>> +		};
>>> First, this is the old flash binding, please use the new one.
>> Ok.
>>
>>> Second, is the flash really part of the SoC?
>> Not directly, it is attached to LocalPlus Bus Controller, which is
>> part of the SoC. And the soc@ is currently the only recognized of bus
>> for mpc5200, so if we want to move it to some other place new bindings
>> will need to be defined for lpc (LocalPlus Controller) bus. But I am
>> not quite sure where this should be attached. Bus is under LPC which
>> is a part of the SoC, but on the other hand Soc address range covers
>> only device control registers not the address space LPC may handle
>> (that may be varied). Any ideas?
> 
> The bus bridge has to be there.  Is this something similar to the
> "localbus" / "chipselect" bus controllers that a whole bunch of the
> Freescale SoCs have?  

Yes, that's kind of a local bus.

> Because the bridged addresses don't lie in the
> IMMR, althoug the control registers do, the current convention is to
> make the localbus node a sibling of /soc, even though it is really
> part of the SoC (/soc would perhaps be better called /immr, but /soc
> is established now).  This approach is imperfect, but so are most of
> the other compromises we could make.
> 
> Incidentally LPC is a pretty bad abbreviation, since LPC more
> frequently refers to the Low Pin Count connections that frequently
> appear on south bridges or superIO chips.

How about 'LocalPlus Bus' and 'lpb' node then?

m.

^ permalink raw reply

* Re: [PATCH v2 3/4] Implement clockevents driver for powerpc
From: Paul Mackerras @ 2007-10-19 11:22 UTC (permalink / raw)
  To: Gabriel Paubert; +Cc: linuxppc-dev, Thomas Gleixner, Realtime Kernel
In-Reply-To: <20071019092205.GA9668@iram.es>

Gabriel Paubert writes:

> I'd really wish there were a guarantee of a minimum timebase 
> frequency, for anything above ~10MHz, we are splitting hairs
> about an off-by-one error that never accumulates, but if systems
> with very low TB freq exist, you have to be very careful.

Exactly.  In looking through the generic clockevents code, there are a
few places where counts are rounded down.  For example,
clockevents_program_event does this to convert from nanoseconds (in
"delta") to the count value for the clock event device:

	clc = delta * dev->mult;
	clc >>= dev->shift;

Here the right shift can lose up to a whole count.  If the clock
frequency of the device is very slow, say 1kHz, then this could lose
up to 999999 nanoseconds.  Then, on Book E, putting 1 into the
decrementer could result in an interrupt anywhere from straight away to
1 millisecond later (assuming 1kHz timebase frequency, again).

The net result is that delta = 1999999 nanoseconds could result in the
interrupt coming in immediately, i.e. almost 2ms early.

I believe the clockevents framework has not been designed for use with
very slow one-shot clock event devices.  If it is to be used with very
low clock rates, then there are several points where I think the
rounding/truncation issues need to be carefully thought through.

In any case, the code we have at the moment won't work with timebase
clock rates below 15.258kHz, because decrementer_clockevent.mult will
become zero.

Regards,
Paul.

^ permalink raw reply

* [PATCH v4] FEC - fast ethernet controller for mpc52xx
From: Domen Puncer @ 2007-10-19 11:27 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linuxppc-dev, netdev
In-Reply-To: <4717B09B.3060800@pobox.com>

Driver for ethernet on mpc5200/mpc5200b SoCs (FEC).


Signed-off-by: Domen Puncer <domen.puncer@telargo.com>

---
On 18/10/07 15:14 -0400, Jeff Garzik wrote:
> 
> except a resend combining patches 3 and 4 as requested :)

OK, here it goes. Sorry for the delay.


diffstat:
 drivers/net/Kconfig           |   24 
 drivers/net/Makefile          |    4 
 drivers/net/fec_mpc52xx.c     | 1107 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/fec_mpc52xx.h     |  315 +++++++++++
 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
@@ -1895,6 +1895,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,1107 @@
+/*
+ * 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");
+
+static void mpc52xx_fec_tx_timeout(struct net_device *dev)
+{
+	struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+	dev_warn(&dev->dev, "transmit timed out\n");
+
+	mpc52xx_fec_reset(dev);
+
+	priv->stats.tx_errors++;
+
+	if (!priv->tx_full)
+		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 bcom_task *rxtsk)
+{
+	while (!bcom_queue_full(rxtsk)) {
+		struct sk_buff *skb;
+		struct bcom_fec_bd *bd;
+
+		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+		if (skb == NULL)
+			return -EAGAIN;
+
+		/* zero out the initial receive buffers to aid debugging */
+		memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
+
+		bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
+
+		bd->status = FEC_RX_BUFFER_SIZE;
+		bd->skb_pa = virt_to_phys(skb->data);
+
+		bcom_submit_next_buffer(rxtsk, skb);
+	}
+
+	return 0;
+}
+
+/* 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,
+	                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,
+	                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,
+	                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);
+
+	bcom_submit_next_buffer(priv->tx_dmatsk, skb);
+
+	if (bcom_queue_full(priv->tx_dmatsk)) {
+		priv->tx_full = 1;
+		netif_stop_queue(dev);
+	}
+
+	spin_unlock_irq(&priv->lock);
+
+	return 0;
+}
+
+/* This handles BestComm transmit task interrupts
+ */
+static irqreturn_t 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)
+		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);
+
+	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));
+}
+
+/*
+ * 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);
+
+	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);
+}
+
+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;
+	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;
+	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;
+	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");

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox