LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 1/2] Xlinx ML403 AC97 Controller Reference device driver
From: Takashi Iwai @ 2007-08-09 22:30 UTC (permalink / raw)
  To: Joachim Förster
  Cc: alsa-devel, Stephen Neuendorffer, Lorenz Kolb,
	linuxppc-embedded@ozlabs.org
In-Reply-To: <1186689700.28843.76.camel@localhost>

At Thu, 09 Aug 2007 22:01:40 +0200,
Joachim Förster wrote:
> 
> Hi Grant,
> 
> On Thu, 2007-08-09 at 11:49 -0600, Grant Likely wrote:
> > > diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
> > > index eacee2d..827f2f5 100644
> > > --- a/sound/ppc/Makefile
> > > +++ b/sound/ppc/Makefile
> > 
> > Couldn't this end up on MicroBlaze too?  If so, sound/ppc is the wrong place.
> 
> Well, I don't know. The only arch depended calls I use (am aware of) are
> in/out_be32(), so this _might_ work for mb, too. (I won't be able to
> test that in the next few months ...)
> 
> On Thu, 2007-08-09 at 11:17 -0700, Stephen Neuendorffer wrote: 
> >  I second grant here... this should eventually work on microblaze, too,
> > so putting it drivers/ and using XILINX_DRIVERS instead of XILINX_VIRTEX
> > (based on the patch Wolfgang recently posted) would probably be preferable.
> > 
> > > +
> > > +config SND_ML403_AC97CR
> > > +       tristate "Xilinx ML403 AC97 Controller Reference"
> > > +       depends on SND && XILINX_VIRTEX
> > 
> > Steve
> 
> So, like Stephen Neuendorffer said, I should move it to sound/drivers,
> right? Takashi?

Well, yes, drivers appears like a more reasonable place.

> On Thu, 2007-08-09 at 11:49 -0600, Grant Likely wrote:
> > > +snd-ml403_ac97cr-objs := ml403_ac97cr.o
> > 
> > This line is only needed if you're compiling multiple .c files into one .ko
> 
> Ah, well, then I have to rename the main .c file. But all the other ALSA
> drivers seem to _not_ include the "snd-" in front of it (ok, except the
> new PS3 driver and maybe other new ones?)

Right.  I prefer the file name should be without prefix, too.
The snd- prefix came from a historical reason, to avoid the name crash
with OSS drivers.


Takashi

^ permalink raw reply

* [PATCH 1/2] pseries: device node status can be "ok" or "okay"
From: Linas Vepstas @ 2007-08-09 23:27 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: ppc-dev


It seems that some versions of firmware will report a device
node status as the string "okay". As we are not expecting this
string, the device node will be ignored by the EEH subsystem.
Which means EEH will not be enabled. 

When EEH is not enabled, PCI errors will be converted into 
Machine Check exceptions, and we'll have a very unhappy system. 

Signed-off-by: Linas Vepstas <linas@austin.ibm.com>

----

Paul,

This is a bug with serious reprecussions ... but appearently 
affects only a few systems, so far.  I've never seen it before. 
Your pick as to whether to jam this into 2.6.23 or wait until 
later.

--linas

 arch/powerpc/platforms/pseries/eeh.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-2.6.22-git2/arch/powerpc/platforms/pseries/eeh.c
===================================================================
--- linux-2.6.22-git2.orig/arch/powerpc/platforms/pseries/eeh.c	2007-08-09 18:00:09.000000000 -0500
+++ linux-2.6.22-git2/arch/powerpc/platforms/pseries/eeh.c	2007-08-09 18:03:14.000000000 -0500
@@ -955,7 +955,7 @@ static void *early_enable_eeh(struct dev
 	pdn->eeh_freeze_count = 0;
 	pdn->eeh_false_positives = 0;
 
-	if (status && strcmp(status, "ok") != 0)
+	if (status && strncmp(status, "ok", 2) != 0)
 		return NULL;	/* ignore devices with bad status */
 
 	/* Ignore bad nodes. */

^ permalink raw reply

* [PATCH 2/2] pseries: remove dead eeh video code
From: Linas Vepstas @ 2007-08-09 23:28 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: ppc-dev
In-Reply-To: <20070809232700.GY25995@austin.ibm.com>


Remove dead code, and a misleading comment about EEH checking
for video devices.  The removed code is a left-over from the
olden days where there was concern over how video devices 
worked in Linux. We are never going to go that way again, 
so kill this.

Signed-off-by: Linas Vepstas <linas@austin.ibm.com>

----
 arch/powerpc/platforms/pseries/eeh.c |   17 -----------------
 1 file changed, 17 deletions(-)

Index: linux-2.6.22-git2/arch/powerpc/platforms/pseries/eeh.c
===================================================================
--- linux-2.6.22-git2.orig/arch/powerpc/platforms/pseries/eeh.c	2007-08-09 18:03:14.000000000 -0500
+++ linux-2.6.22-git2/arch/powerpc/platforms/pseries/eeh.c	2007-08-09 18:06:45.000000000 -0500
@@ -969,23 +969,6 @@ static void *early_enable_eeh(struct dev
 	}
 	pdn->class_code = *class_code;
 
-	/*
-	 * Now decide if we are going to "Disable" EEH checking
-	 * for this device.  We still run with the EEH hardware active,
-	 * but we won't be checking for ff's.  This means a driver
-	 * could return bad data (very bad!), an interrupt handler could
-	 * hang waiting on status bits that won't change, etc.
-	 * But there are a few cases like display devices that make sense.
-	 */
-	enable = 1;	/* i.e. we will do checking */
-#if 0
-	if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY)
-		enable = 0;
-#endif
-
-	if (!enable)
-		pdn->eeh_mode |= EEH_MODE_NOCHECK;
-
 	/* Ok... see if this device supports EEH.  Some do, some don't,
 	 * and the only way to find out is to check each and every one. */
 	regs = of_get_property(dn, "reg", NULL);

^ permalink raw reply

* DTC 1.0.0 Release
From: Jon Loeliger @ 2007-08-10  1:01 UTC (permalink / raw)
  To: linuxppc-dev

Hey guys,

Well, I tagged and released an official DTC v1.0.0 Release
and pushed it out to jdl.com just now.  You can grab the
git repo directly:

    git://www.jdl.com/software/dtc.git

or download a tarball here:

    http://www.jdl.com/software/dtc-1.0.0.tgz

As usual, please let me know of any issues with it.

Thanks,
jdl


PS -- Hey Becky!  So there!  My status report doesn't lie!

^ permalink raw reply

* Re: [PATCH v3 1/2] [POWERPC] MPC832x_RDB: update dts to use spi, register mmc_spi stub
From: David Gibson @ 2007-08-10  1:02 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <af4642f6ed6a4bc167161ac73ad75350@kernel.crashing.org>

On Thu, Aug 09, 2007 at 10:15:44PM +0200, Segher Boessenkool wrote:
> > Hrm... Freescale is using these 'fsl,device-id' properties, I'm
> > guessing they're basically the same thing as the 'cell-index' used in
> > the EMAC binding.
> >
> > We should co-ordinate better on this, if it's to become a
> > convention...
> 
> That means we shouldn't coordinate on this, right?

Heh.  Either one is kind of ugly, I'll grant you.

But, many SoCs do have a notion of device "number", which is relevant
for programming other general control registers in places.  We need to
encode it somehow, and it would be good to have a consistent way of
doing it.

-- 
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 2/6] PowerPC 440EPx: Sequoia DTS
From: David Gibson @ 2007-08-10  1:07 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <019ae19815eb3301065ba732e3e72f44@kernel.crashing.org>

On Thu, Aug 09, 2007 at 09:53:41PM +0200, Segher Boessenkool wrote:
> >>>> I haven't heard or thought of anything better either.  Using 
> >>>> "ranges"
> >>>> is conceptually wrong, even ignoring the technical problems that 
> >>>> come
> >>>> with it.
> >>>
> >>> Why is "ranges" conceptually wrong?
> >>
> >> The flash partitions aren't separate devices sitting on a
> >> "flash bus", they are "sub-devices" of their parent.
> >
> > Well, yes, but nonetheless the partitions show up as part of the
> > overall physical address space.  How do you encode that other than in
> > 'ranges'?
> 
> All that address space shows up in the flash node already.  To
> access the partitions you have to go via that "master" node
> anyway (some commands have to be sent to address 0 on the flash,
> or similar).

Hrm, I suppose.  Although for read-only access that's not relevant.

> It is a very nice feature to not only be able to translate addresses
> "up" the device tree, but also "down".

I don't follow, sorry.

> Also, it mimics reality, just like a good OF citizen should:
> those partitions aren't actually devices at all, so they
> certainly shouldn't be assigned a part of the host address
> space.

Hrm.  I'm not entirely convinced that the distinction between
"actually a device" and "not actually a device" is really as clear cut
as you imply.

> >>> To be honest this looks rather to me like another case where having
> >>> overlapping 'reg' and 'ranges' would actually make sense.
> >>
> >> It never makes sense.  You should give the "master" device
> >> the full "reg" range it covers, and have it define its own
> >> address space; "sub-devices" can carve out their little hunk
> >> from that.  You don't want more than one device owning the
> >> same address range in the same address space.
> >
> > Why not?  After all, the physical address ranges of the flash
> > partitions really do overlap with that of the flash device as a whole.
> 
> They don't overlap, a partition is a proper subset of the flash.

A proper subset is a form of overlapping (indeed cases of being a
proper subset form a proper subset of cases of overlapping, to be
gratuitously meta-set-theoretic).

> Which as usual is shown as "reg" in the child node and #a,#s in
> the parent node.

That in no way encodes that the child addresses are a subset of the
parent address space.  Instead #a and #s establish a new, separate
address space for the children, and without 'ranges', there's no
information about any sort of connection, overlapping, proper-subset
or otherwise, with the parent address space.

-- 
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 2/6] PowerPC 440EPx: Sequoia DTS
From: David Gibson @ 2007-08-10  1:11 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <627e5728e1f0e475f3504529a79ee228@kernel.crashing.org>

On Thu, Aug 09, 2007 at 10:00:47PM +0200, Segher Boessenkool wrote:
> >> For the JEDEC chips, we need a "vendor-id" and "device-id"
> >> property at least (or similar names -- whatever is general
> >> practice for this); both are a single byte, encoded as with
> >> encode-int.
> >
> > Ok... should those really be separate properties, or should that go in
> > compatible, i.e. something like:
> > 	compatible = "amd,XXXXXX", "jedec,a4-b7", "jedec-flash";
> 
> Good question.  I think we want the separate bytes, if nothing
> else then just for the benefit of drivers that have their own
> table of those already.  But the "compatible" thing also has
> its merits of course.  

Ok.  Well, I guess there's no reason we can't have both.  Separate
properties for convenient access, and a compatible encoding for
unified matching.

>  I'll ask some flash gurus about what's
> special about JEDEC flash, and maybe even read a datasheet or
> two.  We're in no hurry right, CFI flash is lots more common
> nowadays ;-)

Ok.

> >>>> One thing though -- what _exactly_ does "read-only" signify?
> >>>
> >>> That's... a good question.
> >>
> >> Yeah.  It seems to me that the way it is currently used is
> >> pure policy enforcement, which doesn't belong in the device
> >> tree.
> >
> > Well.. not really policy enforcement, but a policy hint.
> 
> So it most likely doesn't belong there.  How the OS userland
> wants to mount those partitions, if at all, and if they even
> contain a filesystem -- that's all its own business and belongs
> in /etc/fstab or whatever the newfangled thing is.

Hrm.  You can argue the same about all the partition information, but
where else does it go.  Encoding suggested platform policy into the
device tree isn't fabulous, but it beats hardcoded per-platform flash
maps.

> On most flash chips, you can actually write-protect some
> sectors; "read-only" sounds more like that.  Although
> "write-protected" would be a better name.
> 
> Or maybe "read-only" is useful and I just don't see why.  In
> that case, please figure out what its semantics are :-)

Heh, well, in practice the semantics are that it passes a read-only
flag through to the mtd layer.  I guess we need to ask the physmap_of
author what he thought the read-only bit in the old binding should be
used for.

-- 
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 v2] cell: move SPU affinity init to spu_management_of_ops
From: Geoff Levand @ 2007-08-10  1:25 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, cbe-oss-dev, Arnd Bergmann, Andre Detsch
In-Reply-To: <46B792B3.8020000@am.sony.com>

Geoff Levand wrote:
> Arnd Bergmann wrote:
>> On Saturday 04 August 2007, Geoff Levand wrote:
>>> 
>>> From: Andre Detsch <adetsch@br.ibm.com>
>>> 
>>> This patch moves affinity initialization code from spu_base.c to a
>>> new spu_management_of_ops function (init_affinity), which is empty
>>> in the case of PS3. This fixes a linking problem that was happening
>>> when compiling for PS3.
>>> Also, some small code style changes were made.
>>> 
>>> Signed-off-by: Andre Detsch <adetsch@br.ibm.com>
>>> Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
>> 
>> 
>> Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
> 
> Hi Paul,
> 
> As this one fixes a build breakage, I would like you to queue it
> up for Linus to pull at the next opportunity.

Hi Paul,

Can we please get this one merged in ASAP.

-Geoff

^ permalink raw reply

* Re: DTC 1.0.0 Release
From: David Gibson @ 2007-08-10  1:25 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev
In-Reply-To: <E1IJIsf-0003VN-RE@jdl.com>

On Thu, Aug 09, 2007 at 08:01:33PM -0500, Jon Loeliger wrote:
> Hey guys,
> 
> Well, I tagged and released an official DTC v1.0.0 Release
> and pushed it out to jdl.com just now.  You can grab the
> git repo directly:
> 
>     git://www.jdl.com/software/dtc.git
> 
> or download a tarball here:
> 
>     http://www.jdl.com/software/dtc-1.0.0.tgz
> 
> As usual, please let me know of any issues with it.

Well, I'm not thrilled about the versioning, nor some inaccuracies in
the new documentation.  But as you say in the commit message, it's
about bloody time, we can fix the problems later.

-- 
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: DTC 1.0.0 Release Coming?
From: David Gibson @ 2007-08-10  1:30 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, Jon Loeliger
In-Reply-To: <20070806084813.5432ba91@weaponx.rchland.ibm.com>

On Mon, Aug 06, 2007 at 08:48:13AM -0500, Josh Boyer wrote:
> On Fri, 27 Jul 2007 11:33:31 +1000
> David Gibson <david@gibson.dropbear.id.au> wrote:
> 
> > On Thu, Jul 26, 2007 at 10:21:33AM -0500, Jon Loeliger wrote:
> > > So, like, the other day David Gibson mumbled:
> > > 
> > > > > > Only thing I'm not really happy with in the current release is the
> > > > > > versioning stuff.  For starters, it always reports my builds as
> > > > > > -dirty, even when they're not.
> > > > > 
> > > > > I think it won't do that once there is a tag available.
> > > > 
> > > > Your 1.0.0-rc1 tag is there, still showing as dirty.
> 
> git vs quilt issue, as you have already discovered.  I've always seen
> that with kernel builds.

Yeah, ick.

> > > > > I would like to keep the current version mechanism as it
> > > > > is really quite similar to what is in the Kernel now.
> > > > 
> > > > First, I don't think it really is - except in superficial aspect of
> > > > how the version number is partitioned
> > > 
> > > I lifted the code from the Kernel's Makefile directly, and tweaked
> > > it slightly for lack of Kconfig aspects.
> > 
> > Ah, yes, ok, I see.  Frankly I really don't think a lot of that stuff
> > makes much sense outside the context of Kbuild.  The whole complex
> > filechk macro, for example - for which there's only one used parameter
> > in dtc's case.
> 
> Except didn't you say you were going to work with Stephen to get DTC
> into the kernel source itself?  Keeping things similar to Kbuild might
> help in that effort.

Actually, after discussions with Stephen and Paulus, we decided not to
take this route.  In any case having Kbuild like versioning wouldn't
actually help us any in integrating into a full Kbuild system.

> > > I don't want to tie the code and build mechanism to git too much.
> > > Specifically, we need to be able to support stand-alone tarball
> > > based builds.  For example, I've spoken to the Debian package
> > > maintainer on this issue, and he likes this approach as well as
> > > he says it will make packaging it much easier.
> > 
> > Have a look at the patch I posted.  I haven't sufficiently tested it
> > yet, but it should be able to generated version info for a tarball too
> > (provided the .git-manifest file is included, and I'm intending that
> > will be build by a make dist target).  It will give both the
> > git-derived based version, and a file content derived hash so we can
> > robustly tell different builds apart, all with less code than the
> > current system.
> 
> That may be.  But I don't see the current approach being too much of a
> problem either.  Especially given that it's already there and it
> works.  Oh, and you sent out your patch saying it wasn't ready for
> merge and with no sign off.  Small but important issues to fix I'd
> think.

Yeah, it lacks a make dist target, and needs a bit more work to
support that properly.  Never mind, I'll revisit this post the 1.0
release.

> This seems to be the last issue holding up a dtc 1.0 release.  Perhaps
> we could go with what exists and see if there really are problems.  It
> can always be fixed later.
> 
> josh
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
> 

-- 
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: DTC 1.0.0 Release Coming?
From: Josh Boyer @ 2007-08-10  1:37 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev, Jon Loeliger
In-Reply-To: <20070810013001.GF17370@localhost.localdomain>

On Fri, 10 Aug 2007 11:30:01 +1000
David Gibson <dwg@au1.ibm.com> wrote:

> > Except didn't you say you were going to work with Stephen to get DTC
> > into the kernel source itself?  Keeping things similar to Kbuild might
> > help in that effort.
> 
> Actually, after discussions with Stephen and Paulus, we decided not to
> take this route.  In any case having Kbuild like versioning wouldn't
> actually help us any in integrating into a full Kbuild system.

Can you elaborate why you decided not to?  I'm just curious.

> > > Have a look at the patch I posted.  I haven't sufficiently tested it
> > > yet, but it should be able to generated version info for a tarball too
> > > (provided the .git-manifest file is included, and I'm intending that
> > > will be build by a make dist target).  It will give both the
> > > git-derived based version, and a file content derived hash so we can
> > > robustly tell different builds apart, all with less code than the
> > > current system.
> > 
> > That may be.  But I don't see the current approach being too much of a
> > problem either.  Especially given that it's already there and it
> > works.  Oh, and you sent out your patch saying it wasn't ready for
> > merge and with no sign off.  Small but important issues to fix I'd
> > think.
> 
> Yeah, it lacks a make dist target, and needs a bit more work to
> support that properly.  Never mind, I'll revisit this post the 1.0
> release.

Ok.

josh

^ permalink raw reply

* Re: DTC 1.0.0 Release Coming?
From: Geoff Levand @ 2007-08-10  2:13 UTC (permalink / raw)
  To: Josh Boyer, linuxppc-dev, Jon Loeliger
In-Reply-To: <20070810013001.GF17370@localhost.localdomain>

David Gibson wrote:
>> Except didn't you say you were going to work with Stephen to get DTC
>> into the kernel source itself?  Keeping things similar to Kbuild might
>> help in that effort.
> 
> Actually, after discussions with Stephen and Paulus, we decided not to
> take this route.


Could you please let us know what was discussed, and what was proposed to
solve the problem of build failures when dtc is not installed?

-Geoff

^ permalink raw reply

* Re: DTC 1.0.0 Release Coming?
From: David Gibson @ 2007-08-10  2:59 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, Jon Loeliger
In-Reply-To: <20070809203754.2e9192c5@zod.rchland.ibm.com>

On Thu, Aug 09, 2007 at 08:37:54PM -0500, Josh Boyer wrote:
> On Fri, 10 Aug 2007 11:30:01 +1000
> David Gibson <dwg@au1.ibm.com> wrote:
> 
> > > Except didn't you say you were going to work with Stephen to get DTC
> > > into the kernel source itself?  Keeping things similar to Kbuild might
> > > help in that effort.
> > 
> > Actually, after discussions with Stephen and Paulus, we decided not to
> > take this route.  In any case having Kbuild like versioning wouldn't
> > actually help us any in integrating into a full Kbuild system.
> 
> Can you elaborate why you decided not to?  I'm just curious.

We decided that since a formal dtc release was imminent, it would be
simpler to make dtc a new kernel build requirement, rather than
integrate the substantial blob of dtc code into the kernel tree and
then have to deal with the maintenance / synchronization issues
between the in-kernel and upstream versions.

> > > > Have a look at the patch I posted.  I haven't sufficiently tested it
> > > > yet, but it should be able to generated version info for a tarball too
> > > > (provided the .git-manifest file is included, and I'm intending that
> > > > will be build by a make dist target).  It will give both the
> > > > git-derived based version, and a file content derived hash so we can
> > > > robustly tell different builds apart, all with less code than the
> > > > current system.
> > > 
> > > That may be.  But I don't see the current approach being too much of a
> > > problem either.  Especially given that it's already there and it
> > > works.  Oh, and you sent out your patch saying it wasn't ready for
> > > merge and with no sign off.  Small but important issues to fix I'd
> > > think.
> > 
> > Yeah, it lacks a make dist target, and needs a bit more work to
> > support that properly.  Never mind, I'll revisit this post the 1.0
> > release.
> 
> Ok.
> 
> josh
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
> 

-- 
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: DTC 1.0.0 Release
From: Michael Ellerman @ 2007-08-10  3:25 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev, Jon Loeliger
In-Reply-To: <20070810012541.GE17370@localhost.localdomain>

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

On Fri, 2007-08-10 at 11:25 +1000, David Gibson wrote:
> On Thu, Aug 09, 2007 at 08:01:33PM -0500, Jon Loeliger wrote:
> > Hey guys,
> > 
> > Well, I tagged and released an official DTC v1.0.0 Release
> > and pushed it out to jdl.com just now.  You can grab the
> > git repo directly:
> > 
> >     git://www.jdl.com/software/dtc.git
> > 
> > or download a tarball here:
> > 
> >     http://www.jdl.com/software/dtc-1.0.0.tgz
> > 
> > As usual, please let me know of any issues with it.
> 
> Well, I'm not thrilled about the versioning, nor some inaccuracies in
> the new documentation.  But as you say in the commit message, it's
> about bloody time, we can fix the problems later.

Everyone knows not to use x.0.0 releases anyway, so hurry up and push
out 1.0.1 ;)

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] Use 1TB segments
From: Michael Neuling @ 2007-08-10  3:53 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <18095.59959.698141.565343@cargo.ozlabs.ibm.com>

> +static int __init htab_dt_scan_seg_sizes(unsigned long node,
> +					 const char *uname, int depth,
> +					 void *data)
> +{
> +	char *type = of_get_flat_dt_prop(node, "device_type", NULL);
> +	u32 *prop;
> +	unsigned long size = 0;
> +
> +	/* We are scanning "cpu" nodes only */
> +	if (type == NULL || strcmp(type, "cpu") != 0)
> +		return 0;
> +
> +	prop = (u32 *)of_get_flat_dt_prop(node, "ibm,processor-segment-sizes",
> +					  &size);
> +	if (prop != NULL && size >= 8) {
> +		if (prop[0] == 0x1c && prop[1] == 0x28) {
> +			DBG("1T segment support detected\n");
> +			cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT;
> +		}

Shouldn't this iterate through the property prop and _only_ look for a
0x28 entry rather than assuming the first two are going to be 0x1c and
0x28?

Something like:
	prop = (u32 *)of_get_flat_dt_prop(node, "ibm,processor-segment-sizes",
					  &size);
	if (prop != NULL) 
		for (i = 0; i < size/4; i++)
			if (prop[1] == 0x28)
				DBG("1T segment support detected\n");
				cur_cpu_spec->cpu_features |=
					  CPU_FTR_1T_SEGMENT;

Mikey

^ permalink raw reply

* [PATCH v2] Handle alignment faults on new FP load/store instructions
From: Paul Mackerras @ 2007-08-10  4:07 UTC (permalink / raw)
  To: linuxppc-dev

This adds code to handle alignment traps generated by the following
new floating-point load/store instructions, by emulating the
instruction in the kernel (as is done for other instructions that
generate alignment traps):

lfiwax	load floating-point as integer word algebraic indexed
stfiwx	store floating-point as integer word indexed
lfdp	load floating-point double pair
lfdpx	load floating-point double pair indexed
stfdp	store floating-point double pair
stfdpx	store floating-point double pair indexed

All these except stfiwx are new in POWER6.

lfdp/lfdpx/stfdp/stfdpx load and store 16 bytes of memory into an
even/odd FP register pair.  In little-endian mode each 8-byte value is
byte-reversed separately (i.e. not as a 16-byte unit).  lfiwax/stfiwx
load or store the lower 4 bytes of a floating-point register from/to
memory; lfiwax sets the upper 4 bytes of the FP register to the sign
extension of the value loaded.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
Now with added testing!  Sharp-eyed readers will spot the 1-bit
difference between this and the previous version of the patch. :)

diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 5c9ff7f..4c47f9c 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -38,7 +38,7 @@ struct aligninfo {
 /* Bits in the flags field */
 #define LD	0	/* load */
 #define ST	1	/* store */
-#define	SE	2	/* sign-extend value */
+#define SE	2	/* sign-extend value, or FP ld/st as word */
 #define F	4	/* to/from fp regs */
 #define U	8	/* update index register */
 #define M	0x10	/* multiple load/store */
@@ -87,9 +87,9 @@ static struct aligninfo aligninfo[128] = {
 	{ 8, LD+F+U },		/* 00 1 1001: lfdu */
 	{ 4, ST+F+S+U },	/* 00 1 1010: stfsu */
 	{ 8, ST+F+U },		/* 00 1 1011: stfdu */
-	INVALID,		/* 00 1 1100 */
+	{ 16, LD+F },		/* 00 1 1100: lfdp */
 	INVALID,		/* 00 1 1101 */
-	INVALID,		/* 00 1 1110 */
+	{ 16, ST+F },		/* 00 1 1110: stfdp */
 	INVALID,		/* 00 1 1111 */
 	{ 8, LD },		/* 01 0 0000: ldx */
 	INVALID,		/* 01 0 0001 */
@@ -167,10 +167,10 @@ static struct aligninfo aligninfo[128] = {
 	{ 8, LD+F },		/* 11 0 1001: lfdx */
 	{ 4, ST+F+S },		/* 11 0 1010: stfsx */
 	{ 8, ST+F },		/* 11 0 1011: stfdx */
-	INVALID,		/* 11 0 1100 */
-	{ 8, LD+M },		/* 11 0 1101: lmd */
-	INVALID,		/* 11 0 1110 */
-	{ 8, ST+M },		/* 11 0 1111: stmd */
+	{ 16, LD+F },		/* 11 0 1100: lfdpx */
+	{ 4, LD+F+SE },		/* 11 0 1101: lfiwax */
+	{ 16, ST+F },		/* 11 0 1110: stfdpx */
+	{ 4, ST+F },		/* 11 0 1111: stfiwx */
 	{ 4, LD+U },		/* 11 1 0000: lwzux */
 	INVALID,		/* 11 1 0001 */
 	{ 4, ST+U },		/* 11 1 0010: stwux */
@@ -356,6 +356,42 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
 	return 1;
 }
 
+/*
+ * Emulate floating-point pair loads and stores.
+ * Only POWER6 has these instructions, and it does true little-endian,
+ * so we don't need the address swizzling.
+ */
+static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr,
+			   unsigned int reg, unsigned int flags)
+{
+	char *ptr = (char *) &current->thread.fpr[reg];
+	int i, ret;
+
+	if (!(flags & F))
+		return 0;
+	if (reg & 1)
+		return 0;	/* invalid form: FRS/FRT must be even */
+	if (!(flags & SW)) {
+		/* not byte-swapped - easy */
+		if (!(flags & ST))
+			ret = __copy_from_user(ptr, addr, 16);
+		else
+			ret = __copy_to_user(addr, ptr, 16);
+	} else {
+		/* each FPR value is byte-swapped separately */
+		ret = 0;
+		for (i = 0; i < 16; ++i) {
+			if (!(flags & ST))
+				ret |= __get_user(ptr[i^7], addr + i);
+			else
+				ret |= __put_user(ptr[i^7], addr + i);
+		}
+	}
+	if (ret)
+		return -EFAULT;
+	return 1;	/* exception handled and fixed up */
+}
+
 
 /*
  * Called on alignment exception. Attempts to fixup
@@ -471,6 +507,10 @@ int fix_alignment(struct pt_regs *regs)
 		flush_fp_to_thread(current);
 	}
 
+	/* Special case for 16-byte FP loads and stores */
+	if (nb == 16)
+		return emulate_fp_pair(regs, addr, reg, flags);
+
 	/* If we are loading, get the data from user space, else
 	 * get it from register values
 	 */
@@ -531,7 +571,8 @@ int fix_alignment(struct pt_regs *regs)
 	 * or floating point single precision conversion
 	 */
 	switch (flags & ~(U|SW)) {
-	case LD+SE:	/* sign extend */
+	case LD+SE:	/* sign extending integer loads */
+	case LD+F+SE:	/* sign extend for lfiwax */
 		if ( nb == 2 )
 			data.ll = data.x16.low16;
 		else	/* nb must be 4 */

^ permalink raw reply related

* Re: pci in arch/powerpc vs arch/ppc
From: Paul Mackerras @ 2007-08-10  4:32 UTC (permalink / raw)
  To: Alexandros Kostopoulos; +Cc: linuxppc-dev
In-Reply-To: <twig.1186602365.9125@inaccessnetworks.com>

Alexandros Kostopoulos writes:

> In mpc8272ads.dts, the ranges property for pci is:
> 
> ranges = <42000000 0 80000000 80000000 0 20000000
>           02000000 0 a0000000 a0000000 0 20000000
>           01000000 0 00000000 f6000000 0 02000000>;
> 
> The third obviously corresponds to IO space. So, shouldn't the res->start for 
> the host bridge be set to f6000000 ? Because, currently, based on what I've 

No.  The "addresses" in the resource structs for PCI I/O space are
basically PCI I/O port numbers (with a bit of a swizzle for host
bridges other than the primary bridge), whereas the "addresses" in
resource structs for PCI memory space are actually host physical
addresses.

This difference is reflected in the difference between inb() and
readb(); inb() adds pci_io_base on to the port number, which comes
directly from the resource struct.  In contrast, to use readb, you
get the PCI memory space address from the resource struct and pass
that through ioremap to get the cookie (actually the kernel virtual
address) to pass to readb, which doesn't add anything to it before
dereferencing it.

For host bridges other than the primary bridge, we add an offset to
the start/end values in the resource structs in
pcibios_fixup_resources so inb/outb work as expected.

> described in my previous mail, it gets set to 0. It seems to me like a matter 
> of incorrect parsing of the device tree from pci_process_bridge_OF_ranges() 
> for IO space. Or am I missing something else here, and it should actually be 
> 0?

It should actually be zero.  What you have is a disagreement between
the firmware writer (who thinks 0 is a perfectly valid I/O port
address assignment) and the driver writer (who thinks 0 isn't valid).

Paul.

^ permalink raw reply

* Re: [PATCH] Consolidate XILINX_VIRTEX board support
From: Peter Korsgaard @ 2007-08-10  7:17 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <fa686aa40708091157y3c8c0725kbf25ce8a636d5c27@mail.gmail.com>

>>>>> "GL" == Grant Likely <grant.likely@secretlab.ca> writes:

Hi,

WR> -boot-$(CONFIG_XILINX_ML300)        += embed_config.o
WR> -boot-$(CONFIG_XILINX_ML403)        += embed_config.o
WR> +boot-$(CONFIG_XILINX_VIRTEX)       += embed_config.o
>> 
>> Don't do that. Other boards with Xilinx FPGAs don't necessarily need
>> embed_config.c

GL> Then post patches for those boards so we can properly support the
GL> different configuration.

Also if the boards are not generally available? No problem for me, but
I don't quite see the point.

-- 
Bye, Peter Korsgaard

^ permalink raw reply

* [RFC PATCH v0.1] net driver: mpc52xx fec
From: Domen Puncer @ 2007-08-10  9:51 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: netdev

Hi!

Not for merge (yet)! But please do review.

fec_mpc52xx driver (not in-tree, but floating around) isn't in very
good shape, so I tried to change that.
Diff against original is quite big (fec_phy.c is completely rewritten)
and confuzing, so I'm including whole drivers/net/fec_mpc52xx/ .

I still have 'make CONFIG_FEC_MPC52xx_MDIO=n compile and work' on my
TODO, maybe even ethtool support.


	Domen


 arch/powerpc/boot/dts/lite5200b.dts |   18 
 arch/powerpc/sysdev/bestcomm/fec.h  |   14 
 drivers/net/fec_mpc52xx/Kconfig     |   24 
 drivers/net/fec_mpc52xx/Makefile    |    7 
 drivers/net/fec_mpc52xx/fec.c       | 1002 ++++++++++++++++++++++++++++++++++++
 drivers/net/fec_mpc52xx/fec.h       |  299 ++++++++++
 drivers/net/fec_mpc52xx/fec_phy.c   |  229 ++++++++
 drivers/net/fec_mpc52xx/fec_phy.h   |   49 +
 8 files changed, 1641 insertions(+), 1 deletion(-)

diff -pruN dummy/fec.c ./drivers/net/fec_mpc52xx/fec.c
--- dummy/fec.c	1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec.c	2007-08-10 10:59:00.000000000 +0200
@@ -0,0 +1,1002 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.c
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
+ * now maintained by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2007  Sylvain Munaut <tnt@246tNt.com>
+ * Copyrigth (C) 2003-2004  MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/hardirq.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/mpc52xx.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/fec.h>
+
+#include "fec_phy.h"
+#include "fec.h"
+
+#define DRIVER_NAME "mpc52xx-fec"
+
+static irqreturn_t fec_interrupt(int, void *);
+static irqreturn_t fec_rx_interrupt(int, void *);
+static irqreturn_t fec_tx_interrupt(int, void *);
+static struct net_device_stats *fec_get_stats(struct net_device *);
+static void fec_set_multicast_list(struct net_device *dev);
+static void fec_hw_init(struct net_device *dev);
+static void fec_stop(struct net_device *dev);
+static void fec_start(struct net_device *dev);
+
+static u8 mpc52xx_fec_mac_addr[6];
+static u8 null_mac[6];
+
+static void fec_tx_timeout(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+
+	dev_warn(&dev->dev, "transmit timed out\n");
+
+	fec_stop(dev);
+	fec_start(dev);
+
+	priv->stats.tx_errors++;
+
+	if (!priv->tx_full)
+		netif_wake_queue(dev);
+}
+
+static void fec_set_paddr(struct net_device *dev, u8 *mac)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+
+	out_be32(&fec->paddr1, *(u32*)(&mac[0]));
+	out_be32(&fec->paddr2, (*(u16*)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
+}
+
+static void fec_get_paddr(struct net_device *dev, u8 *mac)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+
+	*(u32*)(&mac[0]) = in_be32(&fec->paddr1);
+	*(u16*)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
+}
+
+static int fec_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sock = (struct sockaddr *)addr;
+
+	memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
+
+	fec_set_paddr(dev, sock->sa_data);
+	return 0;
+}
+
+static void fec_free_rx_buffers(struct bcom_task *s)
+{
+	struct sk_buff *skb;
+
+	while (!bcom_queue_empty(s)) {
+		skb = bcom_retrieve_buffer(s, NULL, NULL);
+		kfree_skb(skb);
+	}
+}
+
+static int fec_alloc_rx_buffers(struct bcom_task *rxtsk)
+{
+	while (!bcom_queue_full(rxtsk)) {
+		struct sk_buff *skb;
+		struct bcom_fec_bd *bd;
+
+		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+		if (skb == 0)
+			return -EAGAIN;
+
+		/* zero out the initial receive buffers to aid debugging */
+		memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
+
+		bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
+
+		bd->status = FEC_RX_BUFFER_SIZE;
+		bd->skb_pa = virt_to_phys(skb->data);
+
+		bcom_submit_next_buffer(rxtsk, skb);
+	}
+
+	return 0;
+}
+
+/* based on generic_adjust_link - fs_enet-main.c */
+static void fec_adjust_link(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct phy_device *phydev = priv->phydev;
+	int new_state = 0;
+
+	if (phydev->link != PHY_DOWN) {
+		if (phydev->duplex != priv->duplex) {
+			new_state = 1;
+			priv->duplex = phydev->duplex;
+		}
+
+		if (phydev->speed != priv->speed) {
+			new_state = 1;
+			priv->speed = phydev->speed;
+		}
+
+		if (priv->link == PHY_DOWN) {
+			new_state = 1;
+			priv->link = phydev->link;
+			netif_schedule(dev);
+			netif_carrier_on(dev);
+			netif_start_queue(dev);
+		}
+
+	} else if (priv->link) {
+		new_state = 1;
+		priv->link = PHY_DOWN;
+		priv->speed = 0;
+		priv->duplex = -1;
+		netif_stop_queue(dev);
+		netif_carrier_off(dev);
+	}
+
+	if (new_state && netif_msg_link(priv)) {
+		phy_print_status(phydev);
+	}
+}
+
+static int fec_init_phy(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct phy_device *phydev;
+	char phy_id[BUS_ID_SIZE];
+
+	struct device_node *dn, *phy_dn;
+	unsigned int phy_addr;
+	const phandle *ph;
+	const unsigned int *prop;
+	struct resource res;
+	int ret;
+
+	dn = priv->ofdev->node;
+	ph = of_get_property(dn, "phy-handle", NULL);
+	if (!ph) {
+		dev_err(&dev->dev, "can't find \"phy-handle\" in device tree\n");
+		return -ENODEV;
+	}
+	phy_dn = of_find_node_by_phandle(*ph);
+
+	prop = of_get_property(phy_dn, "reg", NULL);
+	ret = of_address_to_resource(phy_dn->parent, 0, &res);
+	if (ret) {
+		dev_err(&dev->dev, "of_address_to_resource failed\n");
+		return ret;
+	}
+
+	phy_addr = *prop;
+	of_node_put(phy_dn);
+
+	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, res.start, phy_addr);
+
+	priv->link = PHY_DOWN;
+	priv->speed = 0;
+	priv->duplex = -1;
+
+	phydev = phy_connect(dev, phy_id, &fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+	if (IS_ERR(phydev)) {
+		printk(KERN_ERR "%s: phy_connect failed\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+
+	phydev->advertising &= ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half;
+
+	priv->phydev = phydev;
+
+	return 0;
+}
+
+static int fec_open(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	int err = -EBUSY;
+
+	if (request_irq(dev->irq, &fec_interrupt, IRQF_DISABLED | IRQF_SHARED,
+	                DRIVER_NAME "_ctrl", dev)) {
+		dev_err(&dev->dev, "ctrl interrupt request failed\n");
+		goto out;
+	}
+	if (request_irq(priv->r_irq, &fec_rx_interrupt, IRQF_DISABLED,
+	                DRIVER_NAME "_rx", dev)) {
+		dev_err(&dev->dev, "rx interrupt request failed\n");
+		goto free_ctrl_irq;
+	}
+	if (request_irq(priv->t_irq, &fec_tx_interrupt, IRQF_DISABLED,
+	                DRIVER_NAME "_tx", dev)) {
+		dev_err(&dev->dev, "tx interrupt request failed\n");
+		goto free_2irqs;
+	}
+
+	bcom_fec_rx_reset(priv->rx_dmatsk);
+	bcom_fec_tx_reset(priv->tx_dmatsk);
+
+	err = fec_alloc_rx_buffers(priv->rx_dmatsk);
+	if (err) {
+		dev_err(&dev->dev, "fec_alloc_rx_buffers failed\n");
+		goto free_irqs;
+	}
+
+	err = fec_init_phy(dev);
+	if (err) {
+		dev_err(&dev->dev, "fec_init_phy failed\n");
+		goto free_skbs;
+	}
+	bcom_enable(priv->rx_dmatsk);
+	bcom_enable(priv->tx_dmatsk);
+
+	/* reset phy - this also wakes it from PDOWN */
+	phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+	phy_start(priv->phydev);
+
+	fec_start(dev);
+
+	netif_start_queue(dev);
+
+	return 0;
+
+ free_skbs:
+	fec_free_rx_buffers(priv->rx_dmatsk);
+
+ free_irqs:
+	free_irq(priv->t_irq, dev);
+ free_2irqs:
+	free_irq(priv->r_irq, dev);
+ free_ctrl_irq:
+	free_irq(dev->irq, dev);
+ out:
+
+	return err;
+}
+
+static int fec_close(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+
+	fec_stop(dev);
+
+	fec_free_rx_buffers(priv->rx_dmatsk);
+
+	phy_disconnect(priv->phydev);
+
+	free_irq(dev->irq, dev);
+	free_irq(priv->r_irq, dev);
+	free_irq(priv->t_irq, dev);
+
+	/* power down phy */
+	phy_stop(priv->phydev);
+	phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
+
+	return 0;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct bcom_fec_bd *bd;
+
+	if (bcom_queue_full(priv->tx_dmatsk)) {
+		if (net_ratelimit())
+			dev_err(&dev->dev, "transmit queue overrun\n");
+		return 1;
+	}
+
+	spin_lock_irq(&priv->lock);
+	dev->trans_start = jiffies;
+
+	bd = (struct bcom_fec_bd *)
+		bcom_prepare_next_buffer(priv->tx_dmatsk);
+
+	bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_INT;
+	bd->skb_pa = virt_to_phys(skb->data);
+
+	bcom_submit_next_buffer(priv->tx_dmatsk, skb);
+
+	if (bcom_queue_full(priv->tx_dmatsk)) {
+		priv->tx_full = 1;
+		netif_stop_queue(dev);
+	}
+
+	spin_unlock_irq(&priv->lock);
+
+	return 0;
+}
+
+/* This handles BestComm transmit task interrupts
+ */
+static irqreturn_t fec_tx_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct fec_priv *priv = netdev_priv(dev);
+
+	spin_lock(&priv->lock);
+
+	while (bcom_buffer_done(priv->tx_dmatsk)) {
+		struct sk_buff *skb;
+		skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, NULL);
+
+		priv->tx_full = 0;
+		dev_kfree_skb_irq(skb);
+	}
+
+	if (netif_queue_stopped(dev) && !priv->tx_full)
+		netif_wake_queue(dev);
+
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_rx_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct fec_priv *priv = netdev_priv(dev);
+
+	while (bcom_buffer_done(priv->rx_dmatsk)) {
+		struct sk_buff *skb;
+		struct sk_buff *rskb;
+		struct bcom_fec_bd *bd;
+		u32 status;
+
+		rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, NULL);
+
+		/* Test for errors in received frame */
+		if (status & BCOM_FEC_RX_BD_ERRORS) {
+			/* Drop packet and reuse the buffer */
+			bd = (struct bcom_fec_bd *)
+				bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+			bd->status = FEC_RX_BUFFER_SIZE;
+			bd->skb_pa = virt_to_phys(rskb->data);
+
+			bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
+
+			priv->stats.rx_dropped++;
+
+			continue;
+		}
+
+		/* skbs are allocated on open, so now we allocate a new one,
+		 * and remove the old (with the packet) */
+		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+		if (skb) {
+			/* Process the received skb */
+			int length = status & BCOM_FEC_RX_BD_LEN_MASK;
+
+			skb_put(rskb, length - 4);	/* length without CRC32 */
+
+			rskb->dev = dev;
+			rskb->protocol = eth_type_trans(rskb, dev);
+
+			netif_rx(rskb);
+			dev->last_rx = jiffies;
+		} else {
+			/* Can't get a new one : reuse the same & drop pkt */
+			dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
+			priv->stats.rx_dropped++;
+
+			skb = rskb;
+		}
+
+		bd = (struct bcom_fec_bd *)
+			bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+		bd->status = FEC_RX_BUFFER_SIZE;
+		bd->skb_pa = virt_to_phys(skb->data);
+
+		bcom_submit_next_buffer(priv->rx_dmatsk, skb);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t fec_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+	u32 ievent;
+
+	ievent = in_be32(&fec->ievent);
+
+	ievent &= ~FEC_IEVENT_MII;	/* mii is handled separately */
+	if (!ievent)
+		return IRQ_NONE;
+
+	out_be32(&fec->ievent, ievent);		/* clear pending events */
+
+	if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+		if (ievent & ~FEC_IEVENT_TFINT)
+			dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
+		return IRQ_HANDLED;
+	}
+
+	if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
+		dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
+	if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
+		dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+
+	fec_stop(dev);
+	fec_hw_init(dev);
+	fec_start(dev);
+
+	netif_wake_queue(dev);
+	return IRQ_HANDLED;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *fec_get_stats(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &priv->stats;
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+
+/*	printk(KERN_ALERT "%s: %i, rmon_r_octets: %i, rmon_r_packets: %i, "
+			"ieee_r_octets_ok: %i, ieee_r_frame_ok: %i, "
+			"%i\n",
+			__func__, __LINE__,
+			in_be32(&fec->rmon_r_octets), in_be32(&fec->rmon_r_packets),
+			in_be32(&fec->ieee_r_octets_ok), in_be32(&fec->ieee_r_frame_ok),
+			0);
+*/
+	stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+	stats->rx_packets = in_be32(&fec->rmon_r_packets);
+	stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
+		in_be32(&fec->rmon_r_undersize) +
+		in_be32(&fec->rmon_r_oversize) +
+		in_be32(&fec->rmon_r_frag) +
+		in_be32(&fec->rmon_r_jab);
+
+	stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+	stats->tx_packets = in_be32(&fec->rmon_t_packets);
+	stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
+		in_be32(&fec->rmon_t_undersize) +
+		in_be32(&fec->rmon_t_oversize) +
+		in_be32(&fec->rmon_t_frag) +
+		in_be32(&fec->rmon_t_jab);
+
+	stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
+	stats->collisions = in_be32(&fec->rmon_t_col);
+
+	/* detailed rx_errors: */
+	stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
+					+ in_be32(&fec->rmon_r_oversize)
+					+ in_be32(&fec->rmon_r_frag)
+					+ in_be32(&fec->rmon_r_jab);
+	stats->rx_over_errors = in_be32(&fec->r_macerr);
+	stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
+	stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
+	stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
+	stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
+
+	/* detailed tx_errors: */
+	stats->tx_aborted_errors = 0;
+	stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
+	stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
+	stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
+	stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
+
+	return stats;
+}
+
+/*
+ * Read MIB counters in order to reset them,
+ * then zero all the stats fields in memory
+ */
+static void fec_reset_stats(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+
+	out_be32(&fec->mib_control, FEC_MIB_DISABLE);
+	memset_io(&fec->rmon_t_drop, 0,
+			(u32)&fec->reserved10 - (u32)&fec->rmon_t_drop);
+	out_be32(&fec->mib_control, 0);
+
+	memset(&priv->stats, 0, sizeof(priv->stats));
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void fec_set_multicast_list(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+	u32 rx_control;
+
+	rx_control = in_be32(&fec->r_cntrl);
+
+	if (dev->flags & IFF_PROMISC) {
+		rx_control |= FEC_RCNTRL_PROM;
+		out_be32(&fec->r_cntrl, rx_control);
+	} else {
+		rx_control &= ~FEC_RCNTRL_PROM;
+		out_be32(&fec->r_cntrl, rx_control);
+
+		if (dev->flags & IFF_ALLMULTI) {
+			out_be32(&fec->gaddr1, 0xffffffff);
+			out_be32(&fec->gaddr2, 0xffffffff);
+		} else {
+			u32 crc;
+			int i;
+			struct dev_mc_list *dmi;
+			u32 gaddr1 = 0x00000000;
+			u32 gaddr2 = 0x00000000;
+
+			dmi = dev->mc_list;
+			for (i=0; i<dev->mc_count; i++) {
+				crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
+				if (crc >= 32)
+					gaddr1 |= 1 << (crc-32);
+				else
+					gaddr2 |= 1 << crc;
+				dmi = dmi->next;
+			}
+			out_be32(&fec->gaddr1, gaddr1);
+			out_be32(&fec->gaddr2, gaddr2);
+		}
+	}
+}
+
+static void __init fec_str2mac(char *str, unsigned char *mac)
+{
+	int i;
+	u64 val64;
+
+	val64 = simple_strtoull(str, NULL, 16);
+
+	for (i = 0; i < 6; i++)
+		mac[5-i] = val64 >> (i*8);
+}
+
+static int __init mpc52xx_fec_mac_setup(char *mac_address)
+{
+	fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
+	return 0;
+}
+
+/* XXX do we need this? */
+__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
+
+/**
+ * fec_hw_init
+ * @dev: network device
+ *
+ * Setup various hardware setting, only needed once on start
+ */
+static void fec_hw_init(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+	int i;
+
+	/* Whack a reset.  We should wait for this. */
+	out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
+	for (i = 0; i < FEC_RESET_DELAY; ++i) {
+		if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
+			break;
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY)
+		dev_err(&dev->dev, "FEC Reset timeout!\n");
+
+	/* set pause to 0x20 frames */
+	out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20);
+
+	/* high service request will be deasserted when there's < 7 bytes in fifo
+	 * low service request will be deasserted when there's < 4*7 bytes in fifo
+	 */
+	out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+	out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+
+	/* alarm when <= x bytes in FIFO */
+	out_be32(&fec->rfifo_alarm, 0x0000030c);
+	out_be32(&fec->tfifo_alarm, 0x00000100);
+
+	/* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */
+	out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B);
+
+	/* enable crc generation */
+	out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC);
+	out_be32(&fec->iaddr1, 0x00000000);	/* No individual filter */
+	out_be32(&fec->iaddr2, 0x00000000);	/* No individual filter */
+
+	/* set phy speed and enable MII interrupt
+	 * this can't be done in phy driver, since it needs to be called
+	 * before fec stuff (even on resume) */
+	set_phy_speed(fec, priv->phy_speed);
+	out_be32(&fec->imask, in_be32(&fec->imask) | FEC_IMASK_MII);
+}
+
+/**
+ * fec_start
+ * @dev: network device
+ *
+ * This function is called to start or restart the FEC during a link
+ * change.  This happens on fifo errors or when switching between half
+ * and full duplex.
+ */
+static void fec_start(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+	u32 rcntrl;
+	u32 tcntrl;
+	u32 tmp;
+
+	/* clear sticky error bits */
+	tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
+	out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
+	out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
+
+	/* FIFOs will reset on fec_enable */
+	out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
+
+	/* Set station address. */
+	fec_set_paddr(dev, dev->dev_addr);
+
+	fec_set_multicast_list(dev);
+
+	/* set max frame len, enable flow control, select mii mode */
+	rcntrl = FEC_RX_BUFFER_SIZE << 16;	/* max frame length */
+	rcntrl |= FEC_RCNTRL_FCE;
+	rcntrl |= MII_RCNTL_MODE;
+	if (priv->duplex == DUPLEX_FULL)
+		tcntrl = FEC_TCNTRL_FDEN;	/* FD enable */
+	else {
+		rcntrl |= FEC_RCNTRL_DRT;	/* disable Rx on Tx (HD) */
+		tcntrl = 0;
+	}
+	out_be32(&fec->r_cntrl, rcntrl);
+	out_be32(&fec->x_cntrl, tcntrl);
+
+	/* Clear any outstanding interrupt. */
+	out_be32(&fec->ievent, 0xffffffff);
+
+	/* Enable interrupts we wish to service. */
+	out_be32(&fec->imask, FEC_IMASK_ENABLE);
+
+	/* And last, enable the transmit and receive processing. */
+	out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
+	out_be32(&fec->r_des_active, 0x01000000);
+
+	priv->tx_full = 0;
+}
+
+/**
+ * fec_stop
+ * @dev: network device
+ *
+ * stop all activity on fec and empty dma buffers
+ */
+static void fec_stop(struct net_device *dev)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mpc52xx_fec __iomem *fec = priv->fec;
+	unsigned long timeout;
+
+	out_be32(&fec->imask, FEC_IMASK_MII);	/* disable all but MII interrupt */
+
+	/* Disable the rx and tx tasks. */
+	bcom_disable(priv->rx_dmatsk);
+
+	/* Wait for queues to drain, but only if we're in process context */
+	if (!in_interrupt()) {
+		timeout = jiffies + 2*HZ;
+		while (time_before(jiffies, timeout) &&
+				(!bcom_queue_empty(priv->tx_dmatsk) ||
+				!bcom_queue_empty(priv->rx_dmatsk))) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ/10);
+		}
+		if (time_after_eq(jiffies, timeout))
+			dev_err(&dev->dev, "queues didn't drain\n");
+	}
+
+	bcom_disable(priv->tx_dmatsk);
+
+	/* Stop FEC */
+	out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
+
+	return;
+}
+
+static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct fec_priv *priv = netdev_priv(dev);
+	struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data;
+
+	return phy_mii_ioctl(priv->phydev, mii, cmd);
+}
+
+/* ======================================================================== */
+/* OF Driver                                                                */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
+{
+	int rv;
+	struct net_device *ndev;
+	struct fec_priv *priv = NULL;
+	struct resource mem;
+
+	phys_addr_t rx_fifo;
+	phys_addr_t tx_fifo;
+
+	/* Get the ether ndev & it's private zone */
+	ndev = alloc_etherdev(sizeof(struct fec_priv));
+	if (!ndev)
+		return -ENOMEM;
+
+	priv = netdev_priv(ndev);
+
+	priv->ofdev = op;
+
+	/* Reserve FEC control zone */
+	rv = of_address_to_resource(op->node, 0, &mem);
+	if (rv) {
+		printk(KERN_ERR DRIVER_NAME ": "
+				"Error while parsing device node resource\n" );
+		return rv;
+	}
+	if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) {
+		printk(KERN_ERR DRIVER_NAME 
+			" - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",
+			(unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
+		return -EINVAL;
+	}
+
+	if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
+		return -EBUSY;
+
+	/* Init ether ndev with what we have */
+	ndev->open		= fec_open;
+	ndev->stop		= fec_close;
+	ndev->hard_start_xmit	= fec_hard_start_xmit;
+	ndev->do_ioctl		= fec_ioctl;
+	ndev->get_stats		= fec_get_stats;
+	ndev->set_mac_address	= fec_set_mac_address;
+	ndev->set_multicast_list = fec_set_multicast_list;
+	ndev->tx_timeout	= fec_tx_timeout;
+	ndev->watchdog_timeo	= FEC_WATCHDOG_TIMEOUT;
+	ndev->flags &= ~IFF_RUNNING;
+	ndev->base_addr		= mem.start;
+
+	priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
+	
+	spin_lock_init(&priv->lock);
+
+	/* ioremap the zones */
+	priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec));
+	
+	if (!priv->fec) {
+		rv = -ENOMEM;
+		goto probe_error;
+	}
+
+	/* Bestcomm init */
+	rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data);
+	tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data);
+
+	priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE);
+	priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
+
+	if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
+		printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
+		rv = -ENOMEM;
+		goto probe_error;
+	}
+
+	/* Get the IRQ we need one by one */
+		/* Control */
+	ndev->irq = irq_of_parse_and_map(op->node, 0);
+
+		/* RX */
+	priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
+
+		/* TX */
+	priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
+
+	/* MAC address init */
+	if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
+		memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
+	else
+		fec_get_paddr(ndev, ndev->dev_addr);
+
+	/* Phy speed */
+	priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
+
+	priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
+	priv->duplex = DUPLEX_HALF;
+
+	/* Hardware init */
+	fec_hw_init(ndev);
+
+	fec_reset_stats(ndev);
+
+	/* Register the new network device */
+	rv = register_netdev(ndev);
+	if (rv < 0)
+		goto probe_error;
+
+	/* We're done ! */
+	dev_set_drvdata(&op->dev, ndev);
+
+	return 0;
+
+
+	/* Error handling - free everything that might be allocated */
+probe_error:
+
+	irq_dispose_mapping(ndev->irq);
+
+	if (priv->rx_dmatsk)
+		bcom_fec_rx_release(priv->rx_dmatsk);
+	if (priv->tx_dmatsk)
+		bcom_fec_tx_release(priv->tx_dmatsk);
+
+	if (priv->fec)
+		iounmap(priv->fec);
+
+	release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
+
+	free_netdev(ndev);
+
+	return rv;
+}
+
+static int
+mpc52xx_fec_remove(struct of_device *op)
+{
+	struct net_device *ndev;
+	struct fec_priv *priv;
+	
+	ndev = dev_get_drvdata(&op->dev);
+	if (!ndev)
+		return 0;
+	priv = netdev_priv(ndev);
+
+	unregister_netdev(ndev);
+	
+	irq_dispose_mapping(ndev->irq);
+
+	bcom_fec_rx_release(priv->rx_dmatsk);
+	bcom_fec_tx_release(priv->tx_dmatsk);
+
+	iounmap(priv->fec);
+	
+	release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
+
+	free_netdev(ndev);
+	
+	dev_set_drvdata(&op->dev, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state)
+{
+	struct net_device *dev = dev_get_drvdata(&op->dev);
+
+	if (netif_running(dev))
+		fec_close(dev);
+
+	return 0;
+}
+
+static int mpc52xx_fec_of_resume(struct of_device *op)
+{
+	struct net_device *dev = dev_get_drvdata(&op->dev);
+
+	fec_hw_init(dev);
+	fec_reset_stats(dev);
+
+	if (netif_running(dev))
+		fec_open(dev);
+
+	return 0;
+}
+#endif
+
+static struct of_device_id mpc52xx_fec_match[] = {
+	{
+		.type		= "network",
+		.compatible	= "mpc5200-fec",
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
+
+static struct of_platform_driver mpc52xx_fec_driver = {
+	.owner		= THIS_MODULE,
+	.name		= DRIVER_NAME,
+	.match_table	= mpc52xx_fec_match,
+	.probe		= mpc52xx_fec_probe,
+	.remove		= mpc52xx_fec_remove,
+#ifdef CONFIG_PM
+	.suspend	= mpc52xx_fec_of_suspend,
+	.resume		= mpc52xx_fec_of_resume,
+#endif
+};
+
+
+/* ======================================================================== */
+/* Module                                                                   */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_fec_init(void)
+{
+	int ret;
+	if ((ret = fec_mdio_init())) {
+		printk(KERN_ERR "%s: %i fec_mdio_init failed\n", __func__, __LINE__);
+		return ret;
+	}
+
+	return of_register_platform_driver(&mpc52xx_fec_driver);
+}
+
+static void __exit
+mpc52xx_fec_exit(void)
+{
+	of_unregister_platform_driver(&mpc52xx_fec_driver);
+	fec_mdio_exit();
+}
+
+
+module_init(mpc52xx_fec_init);
+module_exit(mpc52xx_fec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
+
diff -pruN dummy/fec.h ./drivers/net/fec_mpc52xx/fec.h
--- dummy/fec.h	1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec.h	2007-08-10 11:24:37.000000000 +0200
@@ -0,0 +1,299 @@
+/*
+ * drivers/net/fec_mpc52xx/fec.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
+#define __DRIVERS_NET_MPC52XX_FEC_H__
+
+#include <linux/mii.h> // XXX, still needed?
+#include <linux/phy.h>
+
+/* Tunable constant */
+/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
+#define FEC_RX_BUFFER_SIZE	1522	/* max receive packet size */
+#define FEC_RX_NUM_BD		64
+#define FEC_TX_NUM_BD		64
+
+#define FEC_RESET_DELAY		50 	/* uS */
+
+#define FEC_WATCHDOG_TIMEOUT	((400*HZ)/1000)
+
+struct fec_priv {
+	int duplex;
+	int tx_full;
+	int r_irq;
+	int t_irq;
+	struct mpc52xx_fec __iomem *fec;
+	struct bcom_task *rx_dmatsk;
+	struct bcom_task *tx_dmatsk;
+	spinlock_t lock;
+	struct net_device_stats stats;
+	int msg_enable;
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+	uint phy_speed;
+
+	struct phy_device *phydev;
+	enum phy_state link;
+	int speed;
+
+	struct of_device *ofdev;
+#endif	/* CONFIG_FEC_MPC52xx_MDIO */
+};
+
+
+/* ======================================================================== */
+/* Hardware register sets & bits                                            */
+/* ======================================================================== */
+
+struct mpc52xx_fec {
+	u32 fec_id;			/* FEC + 0x000 */
+	u32 ievent;			/* FEC + 0x004 */
+	u32 imask;			/* FEC + 0x008 */
+
+	u32 reserved0[1];		/* FEC + 0x00C */
+	u32 r_des_active;		/* FEC + 0x010 */
+	u32 x_des_active;		/* FEC + 0x014 */
+	u32 r_des_active_cl;		/* FEC + 0x018 */
+	u32 x_des_active_cl;		/* FEC + 0x01C */
+	u32 ivent_set;			/* FEC + 0x020 */
+	u32 ecntrl;			/* FEC + 0x024 */
+
+	u32 reserved1[6];		/* FEC + 0x028-03C */
+	u32 mii_data;			/* FEC + 0x040 */
+	u32 mii_speed;			/* FEC + 0x044 */
+	u32 mii_status;			/* FEC + 0x048 */
+
+	u32 reserved2[5];		/* FEC + 0x04C-05C */
+	u32 mib_data;			/* FEC + 0x060 */
+	u32 mib_control;		/* FEC + 0x064 */
+
+	u32 reserved3[6];		/* FEC + 0x068-7C */
+	u32 r_activate;			/* FEC + 0x080 */
+	u32 r_cntrl;			/* FEC + 0x084 */
+	u32 r_hash;			/* FEC + 0x088 */
+	u32 r_data;			/* FEC + 0x08C */
+	u32 ar_done;			/* FEC + 0x090 */
+	u32 r_test;			/* FEC + 0x094 */
+	u32 r_mib;			/* FEC + 0x098 */
+	u32 r_da_low;			/* FEC + 0x09C */
+	u32 r_da_high;			/* FEC + 0x0A0 */
+
+	u32 reserved4[7];		/* FEC + 0x0A4-0BC */
+	u32 x_activate;			/* FEC + 0x0C0 */
+	u32 x_cntrl;			/* FEC + 0x0C4 */
+	u32 backoff;			/* FEC + 0x0C8 */
+	u32 x_data;			/* FEC + 0x0CC */
+	u32 x_status;			/* FEC + 0x0D0 */
+	u32 x_mib;			/* FEC + 0x0D4 */
+	u32 x_test;			/* FEC + 0x0D8 */
+	u32 fdxfc_da1;			/* FEC + 0x0DC */
+	u32 fdxfc_da2;			/* FEC + 0x0E0 */
+	u32 paddr1;			/* FEC + 0x0E4 */
+	u32 paddr2;			/* FEC + 0x0E8 */
+	u32 op_pause;			/* FEC + 0x0EC */
+
+	u32 reserved5[4];		/* FEC + 0x0F0-0FC */
+	u32 instr_reg;			/* FEC + 0x100 */
+	u32 context_reg;		/* FEC + 0x104 */
+	u32 test_cntrl;			/* FEC + 0x108 */
+	u32 acc_reg;			/* FEC + 0x10C */
+	u32 ones;			/* FEC + 0x110 */
+	u32 zeros;			/* FEC + 0x114 */
+	u32 iaddr1;			/* FEC + 0x118 */
+	u32 iaddr2;			/* FEC + 0x11C */
+	u32 gaddr1;			/* FEC + 0x120 */
+	u32 gaddr2;			/* FEC + 0x124 */
+	u32 random;			/* FEC + 0x128 */
+	u32 rand1;			/* FEC + 0x12C */
+	u32 tmp;			/* FEC + 0x130 */
+
+	u32 reserved6[3];		/* FEC + 0x134-13C */
+	u32 fifo_id;			/* FEC + 0x140 */
+	u32 x_wmrk;			/* FEC + 0x144 */
+	u32 fcntrl;			/* FEC + 0x148 */
+	u32 r_bound;			/* FEC + 0x14C */
+	u32 r_fstart;			/* FEC + 0x150 */
+	u32 r_count;			/* FEC + 0x154 */
+	u32 r_lag;			/* FEC + 0x158 */
+	u32 r_read;			/* FEC + 0x15C */
+	u32 r_write;			/* FEC + 0x160 */
+	u32 x_count;			/* FEC + 0x164 */
+	u32 x_lag;			/* FEC + 0x168 */
+	u32 x_retry;			/* FEC + 0x16C */
+	u32 x_write;			/* FEC + 0x170 */
+	u32 x_read;			/* FEC + 0x174 */
+
+	u32 reserved7[2];		/* FEC + 0x178-17C */
+	u32 fm_cntrl;			/* FEC + 0x180 */
+	u32 rfifo_data;			/* FEC + 0x184 */
+	u32 rfifo_status;		/* FEC + 0x188 */
+	u32 rfifo_cntrl;		/* FEC + 0x18C */
+	u32 rfifo_lrf_ptr;		/* FEC + 0x190 */
+	u32 rfifo_lwf_ptr;		/* FEC + 0x194 */
+	u32 rfifo_alarm;		/* FEC + 0x198 */
+	u32 rfifo_rdptr;		/* FEC + 0x19C */
+	u32 rfifo_wrptr;		/* FEC + 0x1A0 */
+	u32 tfifo_data;			/* FEC + 0x1A4 */
+	u32 tfifo_status;		/* FEC + 0x1A8 */
+	u32 tfifo_cntrl;		/* FEC + 0x1AC */
+	u32 tfifo_lrf_ptr;		/* FEC + 0x1B0 */
+	u32 tfifo_lwf_ptr;		/* FEC + 0x1B4 */
+	u32 tfifo_alarm;		/* FEC + 0x1B8 */
+	u32 tfifo_rdptr;		/* FEC + 0x1BC */
+	u32 tfifo_wrptr;		/* FEC + 0x1C0 */
+
+	u32 reset_cntrl;		/* FEC + 0x1C4 */
+	u32 xmit_fsm;			/* FEC + 0x1C8 */
+
+	u32 reserved8[3];		/* FEC + 0x1CC-1D4 */
+	u32 rdes_data0;			/* FEC + 0x1D8 */
+	u32 rdes_data1;			/* FEC + 0x1DC */
+	u32 r_length;			/* FEC + 0x1E0 */
+	u32 x_length;			/* FEC + 0x1E4 */
+	u32 x_addr;			/* FEC + 0x1E8 */
+	u32 cdes_data;			/* FEC + 0x1EC */
+	u32 status;			/* FEC + 0x1F0 */
+	u32 dma_control;		/* FEC + 0x1F4 */
+	u32 des_cmnd;			/* FEC + 0x1F8 */
+	u32 data;			/* FEC + 0x1FC */
+
+	u32 rmon_t_drop;		/* FEC + 0x200 */
+	u32 rmon_t_packets;		/* FEC + 0x204 */
+	u32 rmon_t_bc_pkt;		/* FEC + 0x208 */
+	u32 rmon_t_mc_pkt;		/* FEC + 0x20C */
+	u32 rmon_t_crc_align;		/* FEC + 0x210 */
+	u32 rmon_t_undersize;		/* FEC + 0x214 */
+	u32 rmon_t_oversize;		/* FEC + 0x218 */
+	u32 rmon_t_frag;		/* FEC + 0x21C */
+	u32 rmon_t_jab;			/* FEC + 0x220 */
+	u32 rmon_t_col;			/* FEC + 0x224 */
+	u32 rmon_t_p64;			/* FEC + 0x228 */
+	u32 rmon_t_p65to127;		/* FEC + 0x22C */
+	u32 rmon_t_p128to255;		/* FEC + 0x230 */
+	u32 rmon_t_p256to511;		/* FEC + 0x234 */
+	u32 rmon_t_p512to1023;		/* FEC + 0x238 */
+	u32 rmon_t_p1024to2047;		/* FEC + 0x23C */
+	u32 rmon_t_p_gte2048;		/* FEC + 0x240 */
+	u32 rmon_t_octets;		/* FEC + 0x244 */
+	u32 ieee_t_drop;		/* FEC + 0x248 */
+	u32 ieee_t_frame_ok;		/* FEC + 0x24C */
+	u32 ieee_t_1col;		/* FEC + 0x250 */
+	u32 ieee_t_mcol;		/* FEC + 0x254 */
+	u32 ieee_t_def;			/* FEC + 0x258 */
+	u32 ieee_t_lcol;		/* FEC + 0x25C */
+	u32 ieee_t_excol;		/* FEC + 0x260 */
+	u32 ieee_t_macerr;		/* FEC + 0x264 */
+	u32 ieee_t_cserr;		/* FEC + 0x268 */
+	u32 ieee_t_sqe;			/* FEC + 0x26C */
+	u32 t_fdxfc;			/* FEC + 0x270 */
+	u32 ieee_t_octets_ok;		/* FEC + 0x274 */
+
+	u32 reserved9[2];		/* FEC + 0x278-27C */
+	u32 rmon_r_drop;		/* FEC + 0x280 */
+	u32 rmon_r_packets;		/* FEC + 0x284 */
+	u32 rmon_r_bc_pkt;		/* FEC + 0x288 */
+	u32 rmon_r_mc_pkt;		/* FEC + 0x28C */
+	u32 rmon_r_crc_align;		/* FEC + 0x290 */
+	u32 rmon_r_undersize;		/* FEC + 0x294 */
+	u32 rmon_r_oversize;		/* FEC + 0x298 */
+	u32 rmon_r_frag;		/* FEC + 0x29C */
+	u32 rmon_r_jab;			/* FEC + 0x2A0 */
+
+	u32 rmon_r_resvd_0;		/* FEC + 0x2A4 */
+
+	u32 rmon_r_p64;			/* FEC + 0x2A8 */
+	u32 rmon_r_p65to127;		/* FEC + 0x2AC */
+	u32 rmon_r_p128to255;		/* FEC + 0x2B0 */
+	u32 rmon_r_p256to511;		/* FEC + 0x2B4 */
+	u32 rmon_r_p512to1023;		/* FEC + 0x2B8 */
+	u32 rmon_r_p1024to2047;		/* FEC + 0x2BC */
+	u32 rmon_r_p_gte2048;		/* FEC + 0x2C0 */
+	u32 rmon_r_octets;		/* FEC + 0x2C4 */
+	u32 ieee_r_drop;		/* FEC + 0x2C8 */
+	u32 ieee_r_frame_ok;		/* FEC + 0x2CC */
+	u32 ieee_r_crc;			/* FEC + 0x2D0 */
+	u32 ieee_r_align;		/* FEC + 0x2D4 */
+	u32 r_macerr;			/* FEC + 0x2D8 */
+	u32 r_fdxfc;			/* FEC + 0x2DC */
+	u32 ieee_r_octets_ok;		/* FEC + 0x2E0 */
+
+	u32 reserved10[7];		/* FEC + 0x2E4-2FC */
+
+	u32 reserved11[64];		/* FEC + 0x300-3FF */
+};
+
+#define	FEC_MIB_DISABLE			0x80000000
+
+#define	FEC_IEVENT_HBERR		0x80000000
+#define	FEC_IEVENT_BABR			0x40000000
+#define	FEC_IEVENT_BABT			0x20000000
+#define	FEC_IEVENT_GRA			0x10000000
+#define	FEC_IEVENT_TFINT		0x08000000
+#define	FEC_IEVENT_MII			0x00800000
+#define	FEC_IEVENT_LATE_COL		0x00200000
+#define	FEC_IEVENT_COL_RETRY_LIM	0x00100000
+#define	FEC_IEVENT_XFIFO_UN		0x00080000
+#define	FEC_IEVENT_XFIFO_ERROR		0x00040000
+#define	FEC_IEVENT_RFIFO_ERROR		0x00020000
+
+#define	FEC_IMASK_HBERR			0x80000000
+#define	FEC_IMASK_BABR			0x40000000
+#define	FEC_IMASK_BABT			0x20000000
+#define	FEC_IMASK_GRA			0x10000000
+#define	FEC_IMASK_MII			0x00800000
+#define	FEC_IMASK_LATE_COL		0x00200000
+#define	FEC_IMASK_COL_RETRY_LIM		0x00100000
+#define	FEC_IMASK_XFIFO_UN		0x00080000
+#define	FEC_IMASK_XFIFO_ERROR		0x00040000
+#define	FEC_IMASK_RFIFO_ERROR		0x00020000
+
+#define	FEC_RCNTRL_MAX_FL_SHIFT		16
+#define	FEC_RCNTRL_LOOP			0x01
+#define	FEC_RCNTRL_DRT			0x02
+#define	FEC_RCNTRL_MII_MODE		0x04
+#define	FEC_RCNTRL_PROM			0x08
+#define	FEC_RCNTRL_BC_REJ		0x10
+#define	FEC_RCNTRL_FCE			0x20
+
+#define	FEC_TCNTRL_GTS			0x00000001
+#define	FEC_TCNTRL_HBC			0x00000002
+#define	FEC_TCNTRL_FDEN			0x00000004
+#define	FEC_TCNTRL_TFC_PAUSE		0x00000008
+#define	FEC_TCNTRL_RFC_PAUSE		0x00000010
+
+#define	FEC_ECNTRL_RESET		0x00000001
+#define	FEC_ECNTRL_ETHER_EN		0x00000002
+
+#define FEC_PADDR2_TYPE			0x8808
+
+#define FEC_OP_PAUSE_OPCODE		0x00010000
+
+#define FEC_FIFO_WMRK_256B		0x3
+
+#define FEC_FIFO_STATUS_ERR		0x00400000
+#define FEC_FIFO_STATUS_UF		0x00200000
+#define FEC_FIFO_STATUS_OF		0x00100000
+
+#define FEC_FIFO_CNTRL_FRAME		0x08000000
+#define FEC_FIFO_CNTRL_LTG_7		0x07000000
+
+#define FEC_RESET_CNTRL_RESET_FIFO	0x02000000
+#define FEC_RESET_CNTRL_ENABLE_IS_RESET	0x01000000
+
+#define FEC_XMIT_FSM_APPEND_CRC		0x02000000
+#define FEC_XMIT_FSM_ENABLE_CRC		0x01000000
+
+
+int __init fec_mdio_init(void);
+void __exit fec_mdio_exit(void);
+
+#endif	/* __DRIVERS_NET_MPC52XX_FEC_H__ */
diff -pruN dummy/fec_phy.c ./drivers/net/fec_mpc52xx/fec_phy.c
--- dummy/fec_phy.c	1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec_phy.c	2007-08-10 10:59:53.000000000 +0200
@@ -0,0 +1,229 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include <asm/of_platform.h>
+#include "fec_phy.h"
+#include "fec.h"
+
+struct fec_mdio_priv {
+	int completed;
+	wait_queue_head_t wq;
+	struct mpc52xx_fec __iomem *regs;
+	int irq;
+};
+
+static int fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+	struct fec_mdio_priv *priv = bus->priv;
+	int tries = 100;
+
+	u32 request = FEC_MII_READ_FRAME;
+	request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+	request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+	out_be32(&priv->regs->mii_data, request);
+
+	/* wait for it to finish, this takes about 23 us on lite5200b */
+	while (priv->completed == 0 && tries--)
+		udelay(5);
+
+	priv->completed = 0;
+
+	if (tries == 0)
+		return -ETIMEDOUT;
+
+	return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
+}
+
+static int fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
+{
+	struct fec_mdio_priv *priv = bus->priv;
+	u32 value = data;
+	int tries = 100;
+
+	value |= FEC_MII_WRITE_FRAME;
+	value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+	value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+	out_be32(&priv->regs->mii_data, value);
+
+	/* wait for request to finish */
+	while (priv->completed == 0 && tries--)
+		udelay(5);
+
+	priv->completed = 0;
+
+	if (tries == 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static irqreturn_t fec_mdio_interrupt(int irq, void *dev_id)
+{
+	struct fec_mdio_priv *priv = dev_id;
+	struct mpc52xx_fec __iomem *fec;
+	int ievent;
+
+	fec = priv->regs;
+	ievent = in_be32(&fec->ievent);
+
+	ievent &= FEC_IEVENT_MII;
+	if (!ievent)
+		return IRQ_NONE;
+
+	out_be32(&fec->ievent, ievent);
+
+	priv->completed = 1;
+	wake_up(&priv->wq);
+
+	return IRQ_HANDLED;
+}
+
+static int fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
+{
+	struct device *dev = &of->dev;
+	struct device_node *np = of->node;
+	struct device_node *child = NULL;
+	struct mii_bus *bus;
+	struct fec_mdio_priv *priv;
+	struct resource res = {};
+	int err;
+	int i;
+
+	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+	if (bus == NULL)
+		return -ENOMEM;
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (priv == NULL) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	bus->name = "mpc52xx MII bus";
+	bus->read = fec_mdio_read;
+	bus->write = fec_mdio_write;
+
+	/* setup irqs */
+	bus->irq = kcalloc(sizeof(bus->irq[0]), PHY_MAX_ADDR, GFP_KERNEL);
+	if (bus->irq == NULL) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+	for (i=0; i<PHY_MAX_ADDR; i++)
+		bus->irq[i] = PHY_POLL;
+
+	while ((child = of_get_next_child(np, child)) != NULL) {
+		int irq = irq_of_parse_and_map(child, 0);
+		if (irq != NO_IRQ) {
+			const u32 *id = of_get_property(child, "reg", NULL);
+			bus->irq[*id] = irq;
+		}
+	}
+
+	/* setup registers */
+	err = of_address_to_resource(np, 0, &res);
+	if (err)
+		goto out_free;
+	priv->regs = ioremap(res.start, res.end - res.start + 1);
+	if (priv->regs == NULL) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	priv->irq = irq_of_parse_and_map(np, 0);
+	err = request_irq(priv->irq, &fec_mdio_interrupt, IRQF_DISABLED | IRQF_SHARED,
+	                "fec_mdio", priv);
+	if (err) {
+		printk(KERN_ERR "%s: interrupt request failed with %i\n", __func__, err);
+		goto out_unmap;
+	}
+
+	bus->id = res.start;
+	bus->priv = priv;
+
+	bus->dev = dev;
+	dev_set_drvdata(dev, bus);
+
+	init_waitqueue_head(&priv->wq);
+
+	/* set MII speed */
+	out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
+
+	/* enable MII interrupt */
+	out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
+
+	err = mdiobus_register(bus);
+	if (err)
+		goto out_free_irq;
+
+	return 0;
+
+ out_free_irq:
+	free_irq(priv->irq, dev);
+	irq_dispose_mapping(priv->irq);
+ out_unmap:
+	iounmap(priv->regs);
+ out_free:
+	for (i=0; i<PHY_MAX_ADDR; i++)
+		if (bus->irq[i])
+			irq_dispose_mapping(bus->irq[i]);
+	kfree(bus->irq);
+	kfree(priv);
+	kfree(bus);
+
+	return err;
+}
+
+static int fec_mdio_remove(struct of_device *of)
+{
+	struct device *dev = &of->dev;
+	struct mii_bus *bus = dev_get_drvdata(dev);
+	struct fec_mdio_priv *priv = bus->priv;
+	int i;
+
+	mdiobus_unregister(bus);
+	dev_set_drvdata(dev, NULL);
+
+	free_irq(priv->irq, dev);
+	irq_dispose_mapping(priv->irq);
+	iounmap(priv->regs);
+	for (i=0; i<PHY_MAX_ADDR; i++)
+		if (bus->irq[i])
+			irq_dispose_mapping(bus->irq[i]);
+	kfree(priv);
+	kfree(bus->irq);
+	kfree(bus);
+
+	return 0;
+}
+
+
+static struct of_device_id fec_mdio_match[] = {
+	{
+		.type = "mdio",
+		.compatible = "mpc5200b-fec-phy",
+	},
+	{},
+};
+
+static struct of_platform_driver fec_mdio_driver = {
+	.name = "mpc5200b-fec-phy",
+	.probe = fec_mdio_probe,
+	.remove = fec_mdio_remove,
+	.match_table = fec_mdio_match,
+};
+
+
+int __init fec_mdio_init(void)
+{
+	return of_register_platform_driver(&fec_mdio_driver);
+}
+
+void __exit fec_mdio_exit(void)
+{
+	of_unregister_platform_driver(&fec_mdio_driver);
+}
diff -pruN dummy/fec_phy.h ./drivers/net/fec_mpc52xx/fec_phy.h
--- dummy/fec_phy.h	1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/fec_phy.h	2007-08-10 11:22:54.000000000 +0200
@@ -0,0 +1,49 @@
+/*
+ * arch/ppc/52xx_io/fec_phy.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ * Based heavily on the MII support for the MPC8xx by Dan Malek
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#define FEC_IMASK_ALL		(FEC_IMASK_HBERR | FEC_IMASK_BABR | \
+		FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_MII | \
+		FEC_IMASK_LATE_COL | FEC_IMASK_COL_RETRY_LIM | \
+		FEC_IMASK_XFIFO_UN | FEC_IMASK_XFIFO_ERROR | \
+		FEC_IMASK_RFIFO_ERROR)
+
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+#define MII_RCNTL_MODE		FEC_RCNTRL_MII_MODE
+#define FEC_IMASK_ENABLE	FEC_IMASK_ALL
+#define set_phy_speed(fec, s)	out_be32(&fec->mii_speed, s)
+#else
+#define MII_RCNTL_MODE		0
+#define FEC_IMASK_ENABLE	(FEC_IMASK_ALL & ~FEC_IMASK_MII)
+#define set_phy_speed(fec, s)	do { } while (0)
+#define fec_mii_start(dev)	do { } while (0)
+#define fec_mii(dev)	printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n")
+#define fec_mii_init(dev)	do { } while (0)
+#define fec_mii_suspend(dev)	do { } while (0)
+#define fec_mii_resume(dev)	do { } while (0)
+#endif	/* CONFIG_FEC_MPC52xx_MDIO */
+
+/* MII-related definitions */
+#define FEC_MII_DATA_ST		0x40000000	/* Start frame */
+#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform read */
+#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform write */
+#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address mask */
+#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register mask */
+#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
+#define FEC_MII_DATA_DATAMSK	0x0000ffff	/* PHY data mask */
+
+#define FEC_MII_READ_FRAME	(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
+#define FEC_MII_WRITE_FRAME	(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
+
+#define FEC_MII_DATA_RA_SHIFT	0x12		/* MII reg addr bits */
+#define FEC_MII_DATA_PA_SHIFT	0x17		/* MII PHY addr bits */
diff -pruN dummy/Kconfig ./drivers/net/fec_mpc52xx/Kconfig
--- dummy/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/Kconfig	2007-08-08 10:50:04.000000000 +0200
@@ -0,0 +1,24 @@
+menu "MPC5200 Networking Options"
+	depends PPC_MPC52xx && NET_ETHERNET
+
+config FEC_MPC52xx
+	tristate "FEC Ethernet"
+	depends on NET_ETHERNET
+	select PPC_BESTCOMM
+	select PPC_BESTCOMM_FEC
+	select CRC32
+	---help---
+	  This option enables support for the MPC5200's on-chip
+	  Fast Ethernet Controller
+
+config USE_MDIO
+	bool "Use external Ethernet MII PHY"
+	select MII
+	depends FEC_MPC52xx
+	---help---
+	  The MPC5200's FEC can connect to the Ethernet either with
+	  an external MII PHY chip or 10 Mbps 7-wire interface 
+	  (Motorola? industry standard).
+	  If your board uses an external PHY, say y, else n.
+
+endmenu
diff -pruN dummy/Makefile ./drivers/net/fec_mpc52xx/Makefile
--- dummy/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ ./drivers/net/fec_mpc52xx/Makefile	2007-08-08 10:50:04.000000000 +0200
@@ -0,0 +1,7 @@
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
+
+fec_mpc52xx-objs := fec.o
+
+ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
+fec_mpc52xx-objs += fec_phy.o
+endif
Index: work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
===================================================================
--- work-powerpc.git.orig/arch/powerpc/boot/dts/lite5200b.dts
+++ work-powerpc.git/arch/powerpc/boot/dts/lite5200b.dts
@@ -365,10 +365,26 @@
 		ethernet@3000 {
 			device_type = "network";
 			compatible = "mpc5200b-fec\0mpc5200-fec";
-			reg = <3000 800>;
+			reg = <3000 400>;
 			mac-address = [ 02 03 04 05 06 07 ]; // Bad!
 			interrupts = <2 5 0>;
 			interrupt-parent = <&mpc5200_pic>;
+			phy-handle = <&phy0>;
+		};
+
+		mdio@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			compatible = "mpc5200b-fec-phy";
+			reg = <3000 400>;	// fec range, since we need to setup fec interrupts
+			interrupts = <2 5 0>;	// these are for "mii command finished", not link changes & co.
+			interrupt-parent = <&mpc5200_pic>;
+
+			phy0:ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+			};
 		};
 
 		ata@3a00 {
Index: work-powerpc.git/arch/powerpc/sysdev/bestcomm/fec.h
===================================================================
--- work-powerpc.git.orig/arch/powerpc/sysdev/bestcomm/fec.h
+++ work-powerpc.git/arch/powerpc/sysdev/bestcomm/fec.h
@@ -22,6 +22,20 @@ struct bcom_fec_bd {
 
 #define BCOM_FEC_TX_BD_TFD	0x08000000ul	/* transmit frame done */
 #define BCOM_FEC_TX_BD_INT	0x04000000ul	/* interrupt */
+#define BCOM_FEC_TX_BD_TC	0x04000000ul	/* transmit CRC XXX same as ^? */
+#define BCOM_FEC_TX_BD_ABC	0x02000000ul	/* append bad CRC */
+
+#define BCOM_FEC_RX_BD_L	0x08000000ul	/* buffer is last in frame */
+#define BCOM_FEC_RX_BD_BC	0x00800000ul	/* DA is broadcast */
+#define BCOM_FEC_RX_BD_MC	0x00400000ul	/* DA is multicast and not broadcast */
+#define BCOM_FEC_RX_BD_LG	0x00200000ul	/* Rx frame length violation */
+#define BCOM_FEC_RX_BD_NO	0x00100000ul	/* Rx non-octet aligned frame */
+#define BCOM_FEC_RX_BD_CR	0x00040000ul	/* Rx CRC error */
+#define BCOM_FEC_RX_BD_OV	0x00020000ul	/* overrun */
+#define BCOM_FEC_RX_BD_TR	0x00010000ul	/* Rx frame truncated */
+#define BCOM_FEC_RX_BD_LEN_MASK	0x000007fful	/* mask for length of received frame */
+#define BCOM_FEC_RX_BD_ERRORS	(BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \
+		BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR)
 
 
 extern struct bcom_task *

^ permalink raw reply

* Re: [alsa-devel] [PATCH 1/2] Xlinx ML403 AC97 Controller Reference device driver
From: Joachim Förster @ 2007-08-10 11:50 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Lorenz Kolb, linuxppc-embedded@ozlabs.org
In-Reply-To: <s5hsl6sws0s.wl%tiwai@suse.de>

Hi Takashi,

again some question came up (while correcting all the other issues):

On Thu, 2007-08-09 at 19:13 +0200, Takashi Iwai wrote:
> > +static int __init
> > +snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
> > +			struct snd_ml403_ac97cr **rml403_ac97cr)
> 
> It's no longer __init as long as you use platform_device.
> It should be __devinit instead.

Ok, I changed that (for create(), pcm(), mixer(), etc.). Do I have to
change it for the module_init and module_exit functions, too? I guess,
they are not in the "scope" of platform device, right? So, they will
keep __init / __exit ?

> > --- /dev/null
> > +++ b/sound/ppc/pcm-indirect2.h
> (snip)
> > +#ifdef SND_PCM_INDIRECT2_STAT
> > +static inline void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
> > +					  struct snd_pcm_indirect2 *rec)
> 
> Remove inline from the functions in this file.  They are too lengthy.
> 
> sound/pcm-indirect.h contain inline functions becuase they are
> relatively small, and I didn't want to add them in the core module
> unconditionally.

I looked at my functions again. And I think we could still go with
inline for the *_interrupt() and *_pointer() functions since they have
just a few lines.
With both *_transfer() functions - I don't know. In fact they shouldn't
be much longer than yours in pcm-indirect.h . They seem long, because
there are lot of comments and the #ifdef SND_PCM_INDIRECT2_STAT stuff,
which is/was a debugging feature, which _won't_ be compiled in without
CONFIG_SND_DEBUG.

[I removed inline from the _stat() and _min_periods() function - that's
true, they are too long.]

The other thing I thought about, is: Is it ok to have non-inline
functions in a header file? Don't we need a .c file + .h ? (Are there
any CodingStyle rules about that?)

 Joachim

^ permalink raw reply

* Re: [alsa-devel] [PATCH 1/2] Xlinx ML403 AC97 Controller Reference device driver
From: Takashi Iwai @ 2007-08-10 12:07 UTC (permalink / raw)
  To: Joachim Förster
  Cc: alsa-devel, Lorenz Kolb, linuxppc-embedded@ozlabs.org
In-Reply-To: <1186746640.8965.21.camel@localhost>

At Fri, 10 Aug 2007 13:50:40 +0200,
Joachim Förster wrote:
> 
> Hi Takashi,
> 
> again some question came up (while correcting all the other issues):
> 
> On Thu, 2007-08-09 at 19:13 +0200, Takashi Iwai wrote:
> > > +static int __init
> > > +snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
> > > +			struct snd_ml403_ac97cr **rml403_ac97cr)
> > 
> > It's no longer __init as long as you use platform_device.
> > It should be __devinit instead.
> 
> Ok, I changed that (for create(), pcm(), mixer(), etc.). Do I have to
> change it for the module_init and module_exit functions, too? I guess,
> they are not in the "scope" of platform device, right? So, they will
> keep __init / __exit ?

Yes, they can be __init & __exit.

> > > --- /dev/null
> > > +++ b/sound/ppc/pcm-indirect2.h
> > (snip)
> > > +#ifdef SND_PCM_INDIRECT2_STAT
> > > +static inline void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
> > > +					  struct snd_pcm_indirect2 *rec)
> > 
> > Remove inline from the functions in this file.  They are too lengthy.
> > 
> > sound/pcm-indirect.h contain inline functions becuase they are
> > relatively small, and I didn't want to add them in the core module
> > unconditionally.
> 
> I looked at my functions again. And I think we could still go with
> inline for the *_interrupt() and *_pointer() functions since they have
> just a few lines.
> With both *_transfer() functions - I don't know. In fact they shouldn't
> be much longer than yours in pcm-indirect.h . They seem long, because
> there are lot of comments and the #ifdef SND_PCM_INDIRECT2_STAT stuff,
> which is/was a debugging feature, which _won't_ be compiled in without
> CONFIG_SND_DEBUG.

IMO, the inline isn't usually necessary unless it hits really the
performance.  Let the compiler optimize the codes.  The size reduction
often wins in the end than inlining.

> [I removed inline from the _stat() and _min_periods() function - that's
> true, they are too long.]
> 
> The other thing I thought about, is: Is it ok to have non-inline
> functions in a header file? Don't we need a .c file + .h ? (Are there
> any CodingStyle rules about that?)

Yeah, *.c sounds more appropriate.


Takashi

^ permalink raw reply

* Unwinding stack frame
From: Bizhan Gholikhamseh (bgholikh) @ 2007-08-10 12:08 UTC (permalink / raw)
  To: linuxppc-embedded

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

Hi,
We are using MPC 8541 processor. Running Linux 2.6.11.
 
I have a question regarding unwinding stack frame in userland.
 
To understand the stack frame format, I am using gdb to walk through
nested function calls frame.
I am not able to understand where the PC (program counter) of callee
functions is saved on the stack/register.
 
Here are my questions:
1- Is there any available software like "pstack" ported to powerpc that
I can use?
I know the stack pointer of  the last frame is save in "R1" register.
2- How about PC, and number of the input parameters to the function.
 
Many thanks in advance,
BZ

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

^ permalink raw reply

* Please pull powerpc.git merge branch
From: Paul Mackerras @ 2007-08-10 12:20 UTC (permalink / raw)
  To: torvalds; +Cc: linuxppc-dev

Linus,

Please do

git pull \
git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git merge

to get another batch of bug-fixes for powerpc.  I have included the
full log messages this time.  The changes for spu_base.c and
spu_manage.c are mostly code movement that was needed so that a
PS3-only config would build, so the real change isn't as large as the
diffstat might seem to indicate.

Thanks,
Paul.

 arch/powerpc/configs/ps3_defconfig        |  200 +++++++++--------------------
 arch/powerpc/kernel/head_64.S             |   16 +-
 arch/powerpc/kernel/pci_64.c              |    1 
 arch/powerpc/mm/slb.c                     |   45 ++-----
 arch/powerpc/mm/slice.c                   |    2 
 arch/powerpc/platforms/83xx/mpc832x_mds.c |    1 
 arch/powerpc/platforms/83xx/mpc832x_rdb.c |    1 
 arch/powerpc/platforms/83xx/mpc836x_mds.c |    1 
 arch/powerpc/platforms/85xx/mpc85xx_mds.c |    1 
 arch/powerpc/platforms/cell/spu_base.c    |  141 --------------------
 arch/powerpc/platforms/cell/spu_manage.c  |  163 ++++++++++++++++++++++++
 arch/powerpc/platforms/ps3/Kconfig        |   10 +
 arch/powerpc/platforms/ps3/device-init.c  |   37 +++--
 arch/powerpc/platforms/ps3/spu.c          |    6 +
 include/asm-powerpc/dma-mapping.h         |    2 
 include/asm-powerpc/spu_priv1.h           |    7 +
 16 files changed, 295 insertions(+), 339 deletions(-)

commit d1f5a77f2c9db5b8a565eabdf8b534b02e32cc44
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Wed Aug 8 15:44:15 2007 +1000

    [POWERPC] Fix size check for hugetlbfs
    
    My "slices" address space management code that was added in the 2.6.22
    implementation of get_unmapped_area() doesn't properly check that the
    size is a multiple of the requested page size.  This allows userland to
    create VMAs that aren't a multiple of the huge page size with hugetlbfs
    (since hugetlbfs entirely relies on get_unmapped_area() to do that
    checking) which leads to a kernel BUG() when such areas are torn down.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8f2ea1fd3f97ab7a809e939b5b9005a16f862439
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Tue Aug 7 08:05:10 2007 +1000

    [POWERPC] Fix initialization and usage of dma_mask
    
    powerpc has a couple of bugs in the usage of dma_masks that tend to
    break when drivers explicitly try to set a 32-bit mask for example.
    
    First, the code that generates the pci devices from the OF device-tree
    doesn't initialize the mask properly, then our implementation of
    set_dma_mask() was trying to validate the -previous- mask value, not the
    one passed in as an argument.
    
    This fixes these problems.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 939e60f6808a9ffd3a4e5f145057379c138c89aa
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Jul 31 16:44:13 2007 +1000

    [POWERPC] Fix more section mismatches in head_64.S
    
    WARNING: vmlinux.o(.text+0x8174): Section mismatch: reference to .init.text:.prom_init (between '.__boot_from_prom' and '.__after_prom_start')
    WARNING: vmlinux.o(.text+0x8498): Section mismatch: reference to .init.text:.early_setup (between '.start_here_multiplatform' and '.start_here_common')
    WARNING: vmlinux.o(.text+0x8514): Section mismatch: reference to .init.text:.setup_system (between '.start_here_common' and 'system_call_common')
    WARNING: vmlinux.o(.text+0x8530): Section mismatch: reference to .init.text:.start_kernel (between '.start_here_common' and 'system_call_common')
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Acked-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3c5ede8cc6c75c3d85e46a5c20f106bcec933347
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Thu Jul 26 17:25:12 2007 -0500

    [POWERPC] Revert "[POWERPC] Add 'mdio' to bus scan id list for platforms with QE UEC"
    
    This reverts commit 3baee955953957be5496cd28e9c544d9db214262.
    
    That commit was a mistake from the start; I added mdio type to the
    bus scan list early on in my ucc_geth migrate to phylib development,
    which is just pure wrong (the ucc_geth_mii driver creates the mii
    bus and the PHY layer handles PHY enumeration without translation).
    
    This follows on from commit 77926826f301fbd8ed96d3cd9ff17a5b59560dfb:
    
     Revert "[POWERPC] Don't complain if size-cells == 0 in prom_parse()"
    
    which was basically trying to hide a symptom of the original mistake
    this revert fixes.
    
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit bd948b0377e7ab93559a80f68d38749bcc2e9a77
Author: geoffrey.levand@am.sony.com <geoffrey.levand@am.sony.com>
Date:   Tue Aug 7 20:31:22 2007 -0700

    [POWERPC] PS3: Update ps3_defconfig
    
    Update ps3_defconfig.
    
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 332a7b3e93c6521219be0a72ebfe2eee795a8345
Author: Geoff Levand <geoffrey.levand@am.sony.com>
Date:   Wed Aug 8 09:39:02 2007 -0700

    [POWERPC] PS3: Remove text saying PS3 support is incomplete
    
    Remove the Kconfig message that indicates the PS3 platform support is
    incomplete.
    
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit edd2a9d185799354db255de62c3ed1f2b1c6b0f4
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed Aug 8 11:01:21 2007 -0700

    [POWERPC] PS3: Fix storage probe logic
    
    Fix the PS3 storage probe logic to properly find device regions on cold
    startup.
    
     o Change the storage probe event mask from notify_device_ready
       to notify_region_update.
     o Improve the storage probe error handling.
     o Change ps3_storage_wait_for_device() to use a temporary variable to hold
       the buffer address.
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f5996449e3244524cab0ba709a4bd87047a8175f
Author: Andre Detsch <adetsch@br.ibm.com>
Date:   Fri Aug 3 18:53:46 2007 -0700

    [POWERPC] cell: Move SPU affinity init to spu_management_of_ops
    
    This patch moves affinity initialization code from spu_base.c to a
    new spu_management_of_ops function (init_affinity), which is empty
    in the case of PS3. This fixes a linking problem that was happening
    when compiling for PS3.
    Also, some small code style changes were made.
    
    Signed-off-by: Andre Detsch <adetsch@br.ibm.com>
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit edd0622bd2e8f755c960827e15aa6908c3c5aa94
Author: Paul Mackerras <paulus@samba.org>
Date:   Fri Aug 10 21:04:07 2007 +1000

    [POWERPC] Fix potential duplicate entry in SLB shadow buffer
    
    We were getting a duplicate entry in the SLB shadow buffer in
    slb_flush_and_rebolt() if the kernel stack was in the same segment
    as PAGE_OFFSET, which on POWER6 causes the hypervisor to terminate
    the partition with an error.  This fixes it.
    
    Also we were not creating an SLB entry (or an SLB shadow buffer
    entry) for the kernel stack on secondary CPUs when starting the
    CPU.  This isn't a major problem, since an appropriate entry will
    be created on demand, but this fixes that also for consistency.
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

^ permalink raw reply

* Re: Device Tree tool [was RE: [PATCH] Consolidate XILINX_VIRTEX board support]
From: Koss, Mike (Mission Systems) @ 2007-08-10 12:22 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-embedded
In-Reply-To: <fa686aa40708091154t55ca4df7q7be2acf5662e6076@mail.gmail.com>


<<SNIPPAGE>>
> > > diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters.h=20
> > > b/arch/ppc/platforms/4xx/xparameters/xparameters.h
> > > index 01aa043..34d9844 100644
> > > --- a/arch/ppc/platforms/4xx/xparameters/xparameters.h
> > > +++ b/arch/ppc/platforms/4xx/xparameters/xparameters.h
> > > @@ -15,8 +15,12 @@
> > >
> > > #if defined(CONFIG_XILINX_ML300)
> > > #include "xparameters_ml300.h"
> > > +#elif defined(CONFIG_XILINX_XUPV2P)  #include=20
> > > +"xparameters_xupv2p.h"
> > > #elif defined(CONFIG_XILINX_ML403)
> > > #include "xparameters_ml403.h"
> > > +#elif defined(CONFIG_XILINX_ML41x)
> > > + #include "xparameters_ml41x.h"
> > > #else
> > > /* Add other board xparameter includes here before the #else */=20
> > > #error No xparameters_*.h file included
> >
> > see comment above.

> This whole xparams stuff is a special case; but it is going away for
arch/powerpc.  xparameters.h is generated by the xilinx EDK tool and it
is painful to work with in the Linux context.  For arch/powerpc, I've
got a tool that generates a device tree from the FPGA hardware design.

What is the tool that you are using and are you willing to share it at
this point? I'm currently working on some code to generate platform
files for our internal drivers and the ll_temac vs using the ugle
xparam's file. I'd like to not duplicate, or actually assist, any effort
in this area.

-- Mike Koss

^ permalink raw reply

* How to increase the kernel stack size
From: suresh suresh @ 2007-08-10 12:43 UTC (permalink / raw)
  To: linuxppc-embedded

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

Hi,

I want to know how to increase the kernel stack size for 2.4.21 kernel.

Thanks,
Suresh

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

^ 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