* Re: Audio codec device tree entries
From: David Gibson @ 2007-10-24 23:52 UTC (permalink / raw)
To: Grant Likely; +Cc: PowerPC dev list, Timur Tabi
In-Reply-To: <fa686aa40710240828p532e8e4axf1f9b9ad4cd324f8@mail.gmail.com>
On Wed, Oct 24, 2007 at 09:28:42AM -0600, Grant Likely wrote:
> On 10/24/07, Timur Tabi <timur@freescale.com> wrote:
> > Jon Smirl wrote:
[snip]
> > My vote is for this version. In fact, I think it *has* to be this way. If
> > you're using a CS4270 codec (as I am), the I2C interface is *optional*. So I
> > want the I2S node to point to the I2C node if it exists.
>
> It doesn't have to be this way. If the codec does not have a control
> interface, then it can happily be a child of the i2s node. But if it
> *does*; don't break convention by separating it from it's control
> interface.
>
> I strongly recommend following the lead of ethernet phys and mdio
> busses here.
Yes. Devices should appear on the bus from which they're addressable,
that is from the control interface in this case. Sometimes different
things need to be done for bus-bridges which are configured from a
different bus than the one they bridge, but this is not such a
situation.
--
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: Audio codec device tree entries
From: David Gibson @ 2007-10-24 23:55 UTC (permalink / raw)
To: Jon Smirl; +Cc: PowerPC dev list, Timur Tabi
In-Reply-To: <9e4733910710240854y6ac115b6i5e0400eb369fcf7@mail.gmail.com>
On Wed, Oct 24, 2007 at 11:54:23AM -0400, Jon Smirl wrote:
> On 10/24/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> > > Do you want to pick one and add it to the device tree documentation
> > > with an example for i2s and ac97? I'll use which ever one is picked.
> >
> > Sure, I'll draft something up and post it for review.
> >
> > On the device probing front; what about this method:
> >
> > Rather than trying to figure things out from the board model, or the
> > combination of the codec and i2s bus; add another node to represent
> > the sound circuit. All that node would need is a unique compatible
> > property and a phandle to either the i2s bus or the codec (depending
> > on which binding approach is used). It could have additional
> > properties to represent optional features, etc.
>
> That's the pseudo-sound node proposal that other people objected to.
>
> It makes sense to me, there needs to be some way to trigger loading
> the fabric driver.
>
> >
> > For example:
> > sound@0 {
> > compatible = "<mfg>,<board>,sound" // The board might have
> > more than one sound i/f which could be wired differently
> > codec-handle = <&codec0>;
> > };
>
> Do you even need the parameters, how about simply this?
>
> sound-fabric {
> };
>
> That will trigger loading all of the sound-fabric drivers built into
> the kernel. In their probe functions they can look in the device tree
> and extract the machine name and then decide to stay loaded or fail
> the probe.
We shouldn't be basing driver configuration on the machine name unless
we really have to. We should be able to find a sane way to encode the
necessary information in the tree proper.
--
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 3/4] Implement clockevents driver for powerpc
From: Paul Mackerras @ 2007-10-24 23:55 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: linuxppc-dev, Thomas Gleixner, Realtime Kernel
In-Reply-To: <471F358D.7070300@ru.mvista.com>
Sergei Shtylyov writes:
> I've just realized that I've missed the call to account_process_time() in
> the new timer_interrupt(). :-<
Which is bogus. I had removed it in the version of the patch that I
posted in early September, but apparently it crept back in.
> Anyway, this leads to each tick being accounted twice if the deterministic
> accounting is not enabled -- first by timer_interrupt() and then by the
> hrtimers core, doesn't it?
Yep.
Actually, I thought I was told that with CFS, the total process time
was accounted accurately using sched_clock(), then apportioned between
utime and stime (using counts of ticks in user/system state, which are
somewhat inaccurate). At the time I thought that would be OK, but now
I'm not so sure.
Paul.
^ permalink raw reply
* Re: Audio codec device tree entries
From: David Gibson @ 2007-10-25 0:01 UTC (permalink / raw)
To: Jon Smirl; +Cc: PowerPC dev list, Timur Tabi
In-Reply-To: <9e4733910710240819m3d1cefeand264d2ced243904e@mail.gmail.com>
On Wed, Oct 24, 2007 at 11:19:33AM -0400, Jon Smirl wrote:
> On 10/24/07, Grant Likely <grant.likely@secretlab.ca> wrote:
> > On 10/24/07, Timur Tabi <timur@freescale.com> wrote:
> > > > codec0: i2s-codec@0 {
> > > > compatible = "ti,tas5508";
> > > > reg = <0>;
> > > > i2s-handle = <&i2s@2000>;
> > > > };
> > >
> > > I'd do this the other way around -- that is:
> > >
> > > i2s@2200 { // PSC2
> > > compatible = "fsl,mpc5200b-psc-i2s","fsl,mpc5200-psc-i2s";
> > > ...
> > > i2c-handle = <&codec0>; /* Or something like that */
> >
> > i2c-handle is a poor property name here. It should be 'codec-handle'.
> > The codec could theoretically live on just about *any* control bus;
> > not just i2c.
>
> That's one of the reasons I put the second option in the post.
>
> In the second option the i2s driver would instantiate first. Next the
> generic code would get loaded. The generic codec will know the control
> but for the device and it can go look in the i2c node for the address.
> i2c node still lists all of the devices on the i2c bus. But the codecs
> are in the i2c-handle property so they don't trigger a second loading
> of the codec.
>
> A fundamental question is, which bus should trigger the loading of the
> generic codec driver. The answer to this determines how the device
> tree should look.
No! Device tree layout should not be determined by the instantiation
model used by Linux drivers right now.
--
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: Audio codec device tree entries
From: David Gibson @ 2007-10-25 0:04 UTC (permalink / raw)
To: Grant Likely; +Cc: PowerPC dev list, Timur Tabi
In-Reply-To: <fa686aa40710240938l5b8c30b9qe538cc641df5e61b@mail.gmail.com>
On Wed, Oct 24, 2007 at 10:38:11AM -0600, Grant Likely wrote:
> On 10/24/07, Jon Smirl <jonsmirl@gmail.com> wrote:
> > On 10/24/07, Grant Likely <grant.likely@secretlab.ca> wrote:
[snip]
> > > For example:
> > > sound@0 {
> > > compatible = "<mfg>,<board>,sound" // The board might have
> > > more than one sound i/f which could be wired differently
> > > codec-handle = <&codec0>;
> > > };
>
> The difference here is that the node provides real information about
> the board. It has a compatible field which tells you *exactly* what
> sound circuit is present on the board. It can have additional
> information that does make sense to encode into the device tree (ie.
> the codec that is used). It's not addressable (no registers or
> anything), but it does describe the board.
>
> It would be possible and reasonable for a single fabric driver to work
> with many different circuit layouts as long as it has the information
> needed to adapt each instance.
This still seems nasty, since it seems to do little but duplicate the
platform information.
I'm afraid I still don't understand quite what information this
"fabric" driver is conveying. Is it really inherently platform
specific, or is it something that can be encoded directly in a
sensible way. If the latter we could have a general "device tree"
fabric driver that will handle all systems with the layout correctly
encoded in the device tree.
--
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: Audio codec device tree entries
From: Jon Smirl @ 2007-10-25 0:17 UTC (permalink / raw)
To: Grant Likely, Jon Smirl, PowerPC dev list, Timur Tabi
In-Reply-To: <20071025000425.GD23694@localhost.localdomain>
On 10/24/07, David Gibson <david@gibson.dropbear.id.au> wrote:
> I'm afraid I still don't understand quite what information this
> "fabric" driver is conveying. Is it really inherently platform
> specific, or is it something that can be encoded directly in a
> sensible way. If the latter we could have a general "device tree"
> fabric driver that will handle all systems with the layout correctly
> encoded in the device tree.
Codecs are like GPIOs, all of their pins are programmable. So the same
codec can be wired into various boards quite differently and then
software programmed to work the same. The fabric driver contains the
mapping information.
People were making a codec driver for each board, but this resulted in
lots of similar codec drivers for the same chips. I believe a common
Wolfson chip had eight drivers in the kernel. In the new model the
codec drivers are generic and the fabric driver describes the mapping.
A side effect of this is that we need to load the fabric driver which
doesn't have a device associated with it.
This is a complex mapping from a STAC9277 used with an Intel hda chip.
Codec: SigmaTel STAC9227
Address: 2
Vendor Id: 0x83847618
Subsystem Id: 0x102801db
Revision Id: 0x100201
No Modem Function Group found
Default PCM:
rates [0x7e0]: 44100 48000 88200 96000 176400 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Default Amp-In caps: ofs=0x00, nsteps=0x0e, stepsize=0x05, mute=0
Default Amp-Out caps: ofs=0x7f, nsteps=0x7f, stepsize=0x02, mute=1
Node 0x02 [Audio Output] wcaps 0xd0c05: Stereo Amp-Out
Amp-Out caps: N/A
Amp-Out vals: [0x62 0x62]
Power: 0x0
Node 0x03 [Audio Output] wcaps 0xd0c05: Stereo Amp-Out
Amp-Out caps: N/A
Amp-Out vals: [0xe4 0xe4]
Power: 0x0
Node 0x04 [Audio Output] wcaps 0xd0c05: Stereo Amp-Out
Amp-Out caps: N/A
Amp-Out vals: [0x62 0x62]
Power: 0x0
Node 0x05 [Audio Output] wcaps 0xd0c05: Stereo Amp-Out
Amp-Out caps: N/A
Amp-Out vals: [0xe4 0xe4]
Power: 0x0
Node 0x06 [Vendor Defined Widget] wcaps 0xfd0c05: Stereo Amp-Out
Amp-Out caps: N/A
Amp-Out vals: [0xff 0xff]
Power: 0x0
Node 0x07 [Audio Input] wcaps 0x1d0541: Stereo
Power: 0x0
Connection: 1
0x1b
Node 0x08 [Audio Input] wcaps 0x1d0541: Stereo
Power: 0x0
Connection: 1
0x1c
Node 0x09 [Audio Input] wcaps 0x1d0541: Stereo
Power: 0x0
Connection: 1
0x1d
Node 0x0a [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x08173f: IN OUT HP Detect
Pin Default 0x0221101f: [Jack] HP Out at Ext Front
Conn = 1/8, Color = Black
Pin-ctls: 0xc0: OUT HP
Connection: 2
0x02* 0x03
Node 0x0b [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x08173f: IN OUT HP Detect
Pin Default 0x02a11020: [Jack] Mic at Ext Front
Conn = 1/8, Color = Black
Pin-ctls: 0x24: IN
Connection: 2
0x02* 0x03
Node 0x0c [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x081737: IN OUT Detect
Pin Default 0x01a19021: [Jack] Mic at Ext Rear
Conn = 1/8, Color = Pink
Pin-ctls: 0x24: IN
Connection: 1
0x03
Node 0x0d [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x08173f: IN OUT HP Detect
Pin Default 0x01014010: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Green
Pin-ctls: 0x40: OUT
Connection: 1
0x02
Node 0x0e [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x081737: IN OUT Detect
Pin Default 0x01011012: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Black
Pin-ctls: 0x40: OUT
Connection: 1
0x04
Node 0x0f [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x081737: IN OUT Detect
Pin Default 0x01016011: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Orange
Pin-ctls: 0x40: OUT
Connection: 1
0x05
Node 0x10 [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x0837: IN OUT Detect
Pin Default 0x0181302e: [Jack] Line In at Ext Rear
Conn = 1/8, Color = Blue
Pin-ctls: 0x20: IN
Connection: 1
0x04
Node 0x11 [Pin Complex] wcaps 0x400181: Stereo
Pincap 0x0837: IN OUT Detect
Pin Default 0x01012014: [Jack] Line Out at Ext Rear
Conn = 1/8, Color = Grey
Pin-ctls: 0x40: OUT
Connection: 1
0x03
Node 0x12 [Pin Complex] wcaps 0x400001: Stereo
Pincap 0x0820: IN
Pin Default 0x40f000f1: [N/A] Other at Ext N/A
Conn = Unknown, Color = Unknown
Pin-ctls: 0x00:
Node 0x13 [Vendor Defined Widget] wcaps 0xf00001: Stereo
Node 0x14 [Vendor Defined Widget] wcaps 0xf00001: Stereo
Node 0x15 [Audio Selector] wcaps 0x30010d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x04, stepsize=0x27, mute=0
Amp-Out vals: [0x00 0x00]
Connection: 9
0x0e 0x12 0x0f 0x0b 0x0c* 0x0d 0x0a 0x10 0x11
Node 0x16 [Audio Selector] wcaps 0x30010d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x04, stepsize=0x27, mute=0
Amp-Out vals: [0x00 0x00]
Connection: 9
0x0e 0x12 0x0f 0x0b 0x0c* 0x0d 0x0a 0x10 0x11
Node 0x17 [Audio Selector] wcaps 0x30010d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x04, stepsize=0x27, mute=0
Amp-Out vals: [0x00 0x00]
Connection: 9
0x0e 0x12 0x0f 0x0b 0x0c* 0x0d 0x0a 0x10 0x11
Node 0x18 [Audio Selector] wcaps 0x300103: Stereo Amp-In
Amp-In caps: N/A
Amp-In vals: [0x00 0x00]
Connection: 1
0x15
Node 0x19 [Audio Selector] wcaps 0x300103: Stereo Amp-In
Amp-In caps: N/A
Amp-In vals: [0x00 0x00]
Connection: 1
0x16
Node 0x1a [Audio Selector] wcaps 0x300103: Stereo Amp-In
Amp-In caps: N/A
Amp-In vals: [0x00 0x00]
Connection: 1
0x17
Node 0x1b [Audio Selector] wcaps 0x30090d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Connection: 1
0x18
Node 0x1c [Audio Selector] wcaps 0x30090d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Connection: 1
0x19
Node 0x1d [Audio Selector] wcaps 0x30090d: Stereo Amp-Out
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Connection: 1
0x1a
Node 0x1e [Audio Output] wcaps 0x40211: Stereo Digital
PCM:
rates [0x7e0]: 44100 48000 88200 96000 176400 192000
bits [0xe]: 16 20 24
formats [0x5]: PCM AC3
Node 0x1f [Vendor Defined Widget] wcaps 0xf30201: Stereo Digital
Node 0x20 [Audio Input] wcaps 0x140311: Stereo Digital
PCM:
rates [0x160]: 44100 48000 96000
bits [0xe]: 16 20 24
formats [0x5]: PCM AC3
Connection: 1
0x22
Node 0x21 [Pin Complex] wcaps 0x400301: Stereo Digital
Pincap 0x0810: OUT
Pin Default 0x014510a0: [Jack] SPDIF Out at Ext Rear
Conn = Optical, Color = Black
Pin-ctls: 0x40: OUT
Connection: 5
0x1e* 0x1f 0x1b 0x1c 0x1d
Node 0x22 [Pin Complex] wcaps 0x430681: Stereo Digital
Pincap 0x0810024: IN EAPD Detect
Pin Default 0x40f000f0: [N/A] Other at Ext N/A
Conn = Unknown, Color = Unknown
Pin-ctls: 0x00:
Power: 0x0
Node 0x23 [Beep Generator Widget] wcaps 0x70000c: Mono Amp-Out
Amp-Out caps: ofs=0x03, nsteps=0x03, stepsize=0x17, mute=0
Amp-Out vals: [0x00]
Node 0x24 [Volume Knob Widget] wcaps 0x600000: Mono
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: New time code miscalculates cpu usage
From: Paul Mackerras @ 2007-10-25 0:19 UTC (permalink / raw)
To: benh; +Cc: Olof Johansson, linuxppc-dev
In-Reply-To: <1193262969.6653.32.camel@pasglop>
Benjamin Herrenschmidt writes:
> Your input would be much more valuable if you actually pointed out where
> that happens and why since you seem to know it.
He did already, a couple of messages ago.
Paul.
^ permalink raw reply
* Re: Audio codec device tree entries
From: David Gibson @ 2007-10-25 0:38 UTC (permalink / raw)
To: Jon Smirl; +Cc: PowerPC dev list, Timur Tabi
In-Reply-To: <9e4733910710241717i3c436e76l48f6c273d7114b94@mail.gmail.com>
On Wed, Oct 24, 2007 at 08:17:57PM -0400, Jon Smirl wrote:
> On 10/24/07, David Gibson <david@gibson.dropbear.id.au> wrote:
> > I'm afraid I still don't understand quite what information this
> > "fabric" driver is conveying. Is it really inherently platform
> > specific, or is it something that can be encoded directly in a
> > sensible way. If the latter we could have a general "device tree"
> > fabric driver that will handle all systems with the layout correctly
> > encoded in the device tree.
>
> Codecs are like GPIOs, all of their pins are programmable. So the same
> codec can be wired into various boards quite differently and then
> software programmed to work the same. The fabric driver contains the
> mapping information.
>
> People were making a codec driver for each board, but this resulted in
> lots of similar codec drivers for the same chips. I believe a common
> Wolfson chip had eight drivers in the kernel. In the new model the
> codec drivers are generic and the fabric driver describes the mapping.
Ok, but the fabric driver is about the wiring of a specific codec
chip, yes? If a board was foolishly designed to have two identical
codec chips, but each wired differently, it would need two instances
of the same codec driver, plus one instance each of two different
fabric drivers?
If this is so, then the fabric information *must* be per-codec, and
should therefore go with the codec node.
> A side effect of this is that we need to load the fabric driver which
> doesn't have a device associated with it.
Well, it does have a device associated with it, it's just a question
of how to represent it. There's not reason a single device node can't
cause instantiation of multiple driver instances. Depending on the
complexity of typical fabric arrangements, one of the following
options might make sense:
- the device node's compatible has enough information to
specify both fabric and codec driver. The fabric driver is
instantiated from this node, and instantiates the codec driver itself
(since I gather fabric drivers are frequently codec specific in any
case).
- both fabric and codec drivers are instantiated from the same
device node, and co-ordinate with each other.
- The codec is represented as:
codec-fabric@... {
compatible = "...";
<properties describing the fabric>
codec {
compatible = "...";
<properties describing the codec>
}
}
This is different from a "pseudo" node, because the codec-fabric node
represents a real piece of hardware: specifically the cluster of
wires between the sound bus and the codec.
Remember: the device tree describes the hardware, how the chooses to
structure its driver model to meet the demands of that hardware is up
to it. Don't put the cart before the horse.
--
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 1/2] mpc52xx: add cdm (clock module) helper function for PSCs
From: Stephen Rothwell @ 2007-10-25 0:50 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, domen.puncer
In-Reply-To: <20071024182426.21194.57761.stgit@trillian.cg.shawcable.net>
[-- Attachment #1: Type: text/plain, Size: 302 bytes --]
On Wed, 24 Oct 2007 12:24:26 -0600 Grant Likely <grant.likely@secretlab.ca> wrote:
>
> +static spinlock_t mpc52xx_cdm_lock = SPIN_LOCK_UNLOCKED;
static DEFINE_SPINLOCK(mpc52xx_cdm_lock);
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: New time code miscalculates cpu usage
From: Benjamin Herrenschmidt @ 2007-10-25 0:53 UTC (permalink / raw)
To: Paul Mackerras; +Cc: Olof Johansson, linuxppc-dev
In-Reply-To: <18207.57612.61323.888483@cargo.ozlabs.ibm.com>
On Thu, 2007-10-25 at 10:19 +1000, Paul Mackerras wrote:
> Benjamin Herrenschmidt writes:
>
> > Your input would be much more valuable if you actually pointed out where
> > that happens and why since you seem to know it.
>
> He did already, a couple of messages ago.
Allright, I missed that.
Ben.
^ permalink raw reply
* libfdt: Documentation (patch the second)
From: David Gibson @ 2007-10-25 1:27 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
Add documentation for another handful of libfdt functions to libfdt.h
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Index: dtc/libfdt/libfdt.h
===================================================================
--- dtc.orig/libfdt/libfdt.h 2007-10-25 10:52:31.000000000 +1000
+++ dtc/libfdt/libfdt.h 2007-10-25 11:26:26.000000000 +1000
@@ -237,13 +237,91 @@
*/
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name. This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name. name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ * structure block offset of the node with the requested path (>=0), on success
+ * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
int fdt_path_offset(const void *fdt, const char *path);
-const char *fdt_get_name(const void *fdt, int nodeoffset, int *baselen);
+/**
+ * fdt_get_name - retreive the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @len: pointer to an intger variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset. If len is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by len.
+ *
+ * returns:
+ * pointer to the node's name, on success
+ * *len contains the length of that name (>=0)
+ * NULL, on error
+ * *len contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len);
const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
const char *name, int *lenp);
--
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] Use of_get_parent() in pci_dma_dev_setup_pSeriesLP()
From: Michael Ellerman @ 2007-10-25 1:46 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <b1a6d99a117d0a0027e3f7dcef4a48f8df68893d.1193199823.git.michael@ellerman.id.au>
[-- Attachment #1: Type: text/plain, Size: 883 bytes --]
On Wed, 2007-10-24 at 14:24 +1000, Michael Ellerman wrote:
> The loop to check parent nodes for a dma-window property in
> pci_dma_dev_setup_pSeriesLP() does not use the of_* accessors and
> does not properly manage refcounts, fix it to do so.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
> ---
> arch/powerpc/platforms/pseries/iommu.c | 17 ++++++++++++-----
> 1 files changed, 12 insertions(+), 5 deletions(-)
I'm starting to make a habit of this .. but nack.
Stephen points out that there are several other places in this file that
need fixing up, so I'll do them all as one series.
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: [linux-usb-devel] [PATCH 1/2] USB: Rework OHCI PPC OF for new bindings
From: David Brownell @ 2007-10-25 1:50 UTC (permalink / raw)
To: Matt Sealey, Valentine Barshak; +Cc: linuxppc-dev, linux-usb-devel
In-Reply-To: <471FC191.6020704@genesi-usa.com>
On Wednesday 24 October 2007, Matt Sealey wrote:
> Can we just make sure real quickly that the changing of compatibles
> doesn't break existing, not-easily-flashable firmwares?
Yeah, I'm not keen on such breakage either...
^ permalink raw reply
* Re: [linux-usb-devel] [PATCH 1/2] USB: Rework OHCI PPC OF for new bindings
From: Grant Likely @ 2007-10-25 2:41 UTC (permalink / raw)
To: David Brownell; +Cc: linux-usb-devel, linuxppc-dev
In-Reply-To: <200710241850.05467.david-b@pacbell.net>
On 10/24/07, David Brownell <david-b@pacbell.net> wrote:
> On Wednesday 24 October 2007, Matt Sealey wrote:
> > Can we just make sure real quickly that the changing of compatibles
> > doesn't break existing, not-easily-flashable firmwares?
>
> Yeah, I'm not keen on such breakage either...
Add my voice to the chorus. It's okay to change the binding, but make
sure the old binding is still supported.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: Audio codec device tree entries
From: Jon Smirl @ 2007-10-25 3:11 UTC (permalink / raw)
To: Jon Smirl, Grant Likely, PowerPC dev list, Timur Tabi
In-Reply-To: <20071025003849.GB24382@localhost.localdomain>
On 10/24/07, David Gibson <david@gibson.dropbear.id.au> wrote:
> On Wed, Oct 24, 2007 at 08:17:57PM -0400, Jon Smirl wrote:
> > On 10/24/07, David Gibson <david@gibson.dropbear.id.au> wrote:
> > > I'm afraid I still don't understand quite what information this
> > > "fabric" driver is conveying. Is it really inherently platform
> > > specific, or is it something that can be encoded directly in a
> > > sensible way. If the latter we could have a general "device tree"
> > > fabric driver that will handle all systems with the layout correctly
> > > encoded in the device tree.
> >
> > Codecs are like GPIOs, all of their pins are programmable. So the same
> > codec can be wired into various boards quite differently and then
> > software programmed to work the same. The fabric driver contains the
> > mapping information.
> >
> > People were making a codec driver for each board, but this resulted in
> > lots of similar codec drivers for the same chips. I believe a common
> > Wolfson chip had eight drivers in the kernel. In the new model the
> > codec drivers are generic and the fabric driver describes the mapping.
>
> Ok, but the fabric driver is about the wiring of a specific codec
> chip, yes? If a board was foolishly designed to have two identical
> codec chips, but each wired differently, it would need two instances
> of the same codec driver, plus one instance each of two different
> fabric drivers?
AFAIK no one has built that case. My target board has two different
codec chips. I was handling them both in a single fabric driver but
there is no reason the code couldn't be split.
I was thinking that there was a single fabric for the board, but you
are right in observing that it is per codec chip.
The term fabric is coming from the Apple aoa driver. They only have a
single fabric per board. But there is no reason the Apple driver
couldn't also be adjusted.
> If this is so, then the fabric information *must* be per-codec, and
> should therefore go with the codec node.
>
> > A side effect of this is that we need to load the fabric driver which
> > doesn't have a device associated with it.
>
> Well, it does have a device associated with it, it's just a question
> of how to represent it. There's not reason a single device node can't
> cause instantiation of multiple driver instances. Depending on the
> complexity of typical fabric arrangements, one of the following
> options might make sense:
> - the device node's compatible has enough information to
> specify both fabric and codec driver. The fabric driver is
> instantiated from this node, and instantiates the codec driver itself
> (since I gather fabric drivers are frequently codec specific in any
> case).
This could work. The generic codec is a alsa soc_device_driver, not a
of_device_driver. The codec node could instantiate the fabric as a
of_device_driver which could then instantiate the soc_device_driver
for the generic codec.
The generic codecs are supposed to work cross platform so they can't
include code that munges the of device tree.
> - both fabric and codec drivers are instantiated from the same
> device node, and co-ordinate with each other.
> - The codec is represented as:
> codec-fabric@... {
> compatible = "...";
> <properties describing the fabric>
> codec {
> compatible = "...";
> <properties describing the codec>
> }
> }
>
> This is different from a "pseudo" node, because the codec-fabric node
> represents a real piece of hardware: specifically the cluster of
> wires between the sound bus and the codec.
>
> Remember: the device tree describes the hardware, how the chooses to
> structure its driver model to meet the demands of that hardware is up
> to it. Don't put the cart before the horse.
>
> --
> 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
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* libfdt: Remove un-const-safe fdt_set_header macro
From: David Gibson @ 2007-10-25 4:29 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
The fdt_set_header() macro casts an arbitrary pointer into (struct
fdt_header *) to set fdt header fields. While we need to change the
type, so that we can use this macro on the usual (void *) used to
represent a device tree blob, the current macro also casts away any
const on the input pointer, which loses an important check.
This patch replaces the fdt_set_header() macro with a set of inline
functions, one for each header field which do a similar thing, but
which won't silently remove const from a given pointer. This approach
is also more in keeping with the individual accessor macros we use for
reading fdt header fields.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Index: dtc/libfdt/libfdt.h
===================================================================
--- dtc.orig/libfdt/libfdt.h 2007-10-25 14:15:30.000000000 +1000
+++ dtc/libfdt/libfdt.h 2007-10-25 14:25:07.000000000 +1000
@@ -149,8 +149,23 @@
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
-#define fdt_set_header(fdt, field, val) \
- ((struct fdt_header *)(fdt))->field = cpu_to_fdt32(val)
+#define __fdt_set_hdr(name) \
+ static inline void fdt_set_##name(void *fdt, uint32_t val) \
+ { \
+ struct fdt_header *fdth = fdt; \
+ fdth->name = cpu_to_fdt32(val); \
+ }
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
/**
* fdt_check_header - sanity check a device tree or possible device tree
Index: dtc/libfdt/fdt_rw.c
===================================================================
--- dtc.orig/libfdt/fdt_rw.c 2007-10-25 14:15:30.000000000 +1000
+++ dtc/libfdt/fdt_rw.c 2007-10-25 14:24:09.000000000 +1000
@@ -109,8 +109,8 @@
err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
- fdt_set_header(fdt, off_dt_struct, fdt_off_dt_struct(fdt) + delta);
- fdt_set_header(fdt, off_dt_strings, fdt_off_dt_strings(fdt) + delta);
+ fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
@@ -123,8 +123,8 @@
if ((err = _blob_splice(fdt, p, oldlen, newlen)))
return err;
- fdt_set_header(fdt, size_dt_struct, fdt_size_dt_struct(fdt) + delta);
- fdt_set_header(fdt, off_dt_strings, fdt_off_dt_strings(fdt) + delta);
+ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
@@ -136,7 +136,7 @@
if ((err = _blob_splice(fdt, p, 0, newlen)))
return err;
- fdt_set_header(fdt, size_dt_strings, fdt_size_dt_strings(fdt) + newlen);
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}
@@ -349,7 +349,7 @@
fdt = buf;
- fdt_set_header(fdt, totalsize, bufsize);
+ fdt_set_totalsize(fdt, bufsize);
/* FIXME: re-order if necessary */
@@ -369,6 +369,6 @@
return err;
/* FIXME: pack components */
- fdt_set_header(fdt, totalsize, _blob_data_size(fdt));
+ fdt_set_totalsize(fdt, _blob_data_size(fdt));
return 0;
}
Index: dtc/libfdt/fdt_sw.c
===================================================================
--- dtc.orig/libfdt/fdt_sw.c 2007-10-25 14:15:30.000000000 +1000
+++ dtc/libfdt/fdt_sw.c 2007-10-25 14:15:35.000000000 +1000
@@ -73,7 +73,7 @@
if ((offset + len < offset) || (offset + len > spaceleft))
return NULL;
- fdt_set_header(fdt, size_dt_struct, offset + len);
+ fdt_set_size_dt_struct(fdt, offset + len);
return fdt_offset_ptr_w(fdt, offset, len);
}
@@ -86,15 +86,15 @@
memset(buf, 0, bufsize);
- fdt_set_header(fdt, magic, SW_MAGIC);
- fdt_set_header(fdt, version, FDT_LAST_SUPPORTED_VERSION);
- fdt_set_header(fdt, last_comp_version, FDT_FIRST_SUPPORTED_VERSION);
- fdt_set_header(fdt, totalsize, bufsize);
-
- fdt_set_header(fdt, off_mem_rsvmap, ALIGN(sizeof(struct fdt_header),
- sizeof(struct fdt_reserve_entry)));
- fdt_set_header(fdt, off_dt_struct, fdt_off_mem_rsvmap(fdt));
- fdt_set_header(fdt, off_dt_strings, bufsize);
+ fdt_set_magic(fdt, SW_MAGIC);
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+ fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+ fdt_set_totalsize(fdt, bufsize);
+
+ fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry)));
+ fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+ fdt_set_off_dt_strings(fdt, bufsize);
return 0;
}
@@ -118,7 +118,7 @@
re->address = cpu_to_fdt64(addr);
re->size = cpu_to_fdt64(size);
- fdt_set_header(fdt, off_dt_struct, offset + sizeof(*re));
+ fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
return 0;
}
@@ -181,7 +181,7 @@
return 0; /* no more room :( */
memcpy(strtab + offset, s, len);
- fdt_set_header(fdt, size_dt_strings, strtabsize + len);
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
return offset;
}
@@ -231,7 +231,7 @@
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
- fdt_set_header(fdt, off_dt_strings, newstroffset);
+ fdt_set_off_dt_strings(fdt, newstroffset);
/* Walk the structure, correcting string offsets */
offset = 0;
@@ -252,7 +252,7 @@
}
/* Finally, adjust the header */
- fdt_set_header(fdt, totalsize, newstroffset + fdt_size_dt_strings(fdt));
- fdt_set_header(fdt, magic, FDT_MAGIC);
+ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+ fdt_set_magic(fdt, FDT_MAGIC);
return 0;
}
--
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 01/11] [POWERPC] Add 'machine: ...' line to common show_cpuinfo()
From: Milton Miller @ 2007-10-25 4:33 UTC (permalink / raw)
To: Marian Balakowicz; +Cc: linuxppc-dev, Stephen Rothwell
In-Reply-To: <20071024171129.3ad06712.sfr@canb.auug.org.au>
On Wed Oct 24 17:11:29 EST 2007, Stephen Rothwell wrote:
> On Wed, 24 Oct 2007 01:13:09 +0200 Marian Balakowicz wrote:
>>
>> + root = of_find_node_by_path("/");
>> + if (root)
>> + model = of_get_property(root, "model", NULL);
>> + of_node_put(root);
>
> The paranoid part of me says:
>
> if (model)
>
>> + seq_printf(m, "machine\t\t: %s\n", model);
>
My thoughts too (don't fail if no model property in /), and that
means that
>> + const char *model = "";
can change to
+ const char *model = NULL;
However, a quick grep shows there are several platforms that print
out machine\t\t: something in show_cpuinfo. Some are fixed strings
(eg linkstation, holly, iSeries), some print model with a fallback
(powermac), some augment the model (chrp, pseries, cell), some print
something else (52xx/efika). There are others. All of those need
to be dealt with or another tag chosen.
milton
^ permalink raw reply
* libfdt: Test on trees with different block layouts
From: David Gibson @ 2007-10-25 5:05 UTC (permalink / raw)
To: Jon Loeliger; +Cc: linuxppc-dev
At present, all the example dtbs we use in the testsuite are version
17 and have reservation map, then structure block then strings block
(the natural ordering based on alignment constraints). However, all
libfdt's read-only and in-place write functions should also work on
v16 trees, and on trees with other layouts.
This patch adds a testcase / utility function to rearrange the blocks
of a dtb and/or regress a v17 tree to v16, and uses it to run tests on
trees with different layouts and versions.
Signed-off-by: David Gibson <david@tgibson.dropbear.id.au>
Index: dtc/tests/mangle-layout.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ dtc/tests/mangle-layout.c 2007-10-25 14:51:55.000000000 +1000
@@ -0,0 +1,166 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Testcase/tool for rearranging blocks of a dtb
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+struct bufstate {
+ void *buf;
+ int size;
+};
+
+void expand_buf(struct bufstate *buf, int newsize)
+{
+ buf->buf = realloc(buf->buf, newsize);
+ if (!buf->buf)
+ CONFIG("Allocation failure");
+ buf->size = newsize;
+}
+
+void new_header(struct bufstate *buf, int version, const void *fdt)
+{
+ int hdrsize;
+
+ if (version == 16)
+ hdrsize = FDT_V16_SIZE;
+ else if (version == 17)
+ hdrsize = FDT_V17_SIZE;
+ else
+ CONFIG("Bad version %d", version);
+
+ expand_buf(buf, hdrsize);
+ memset(buf->buf, 0, hdrsize);
+
+ fdt_set_magic(buf->buf, FDT_MAGIC);
+ fdt_set_version(buf->buf, version);
+ fdt_set_last_comp_version(buf->buf, 16);
+ fdt_set_boot_cpuid_phys(buf->buf, fdt_boot_cpuid_phys(fdt));
+}
+
+void add_block(struct bufstate *buf, int version, char block, const void *fdt)
+{
+ int align, size;
+ const void *src;
+ int offset;
+
+ switch (block) {
+ case 'm':
+ /* Memory reserve map */
+ align = 8;
+ src = fdt + fdt_off_mem_rsvmap(fdt);
+ size = (fdt_num_mem_rsv(fdt) + 1)
+ * sizeof(struct fdt_reserve_entry);
+ break;
+
+ case 't':
+ /* Structure block */
+ align = 4;
+ src = fdt + fdt_off_dt_struct(fdt);
+ size = fdt_size_dt_struct(fdt);
+ break;
+
+ case 's':
+ /* Strings block */
+ align = 1;
+ src = fdt + fdt_off_dt_strings(fdt);
+ size = fdt_size_dt_strings(fdt);
+ break;
+ default:
+ CONFIG("Bad block '%c'", block);
+ }
+
+ offset = ALIGN(buf->size, align);
+ fprintf(stderr, "Moving block %c from %p, to offset %d, size %d\n",
+ block, src, offset, size);
+
+ expand_buf(buf, offset+size);
+
+ memcpy(buf->buf + offset, src, size);
+
+ switch (block) {
+ case 'm':
+ fdt_set_off_mem_rsvmap(buf->buf, offset);
+ break;
+
+ case 't':
+ fdt_set_off_dt_struct(buf->buf, offset);
+ if (version >= 17)
+ fdt_set_size_dt_struct(buf->buf, size);
+ break;
+
+ case 's':
+ fdt_set_off_dt_strings(buf->buf, offset);
+ fdt_set_size_dt_strings(buf->buf, size);
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ void *fdt;
+ int version;
+ const char *blockorder;
+ struct bufstate buf = {NULL, 0};
+ int err;
+ const char *inname;
+ char outname[PATH_MAX];
+
+ test_init(argc, argv);
+ if (argc != 4)
+ CONFIG("Usage: %s <dtb file> <version> <block order>", argv[0]);
+
+ inname = argv[1];
+ fdt = load_blob(argv[1]);
+ version = atoi(argv[2]);
+ blockorder = argv[3];
+ sprintf(outname, "v%d.%s.%s", version, blockorder, inname);
+
+ if ((version != 16) && (version != 17))
+ CONFIG("Version must be 16 or 17");
+
+ if (fdt_version(fdt) < 17)
+ CONFIG("Input tree must be v17");
+
+ new_header(&buf, version, fdt);
+
+ while (*blockorder) {
+ add_block(&buf, version, *blockorder, fdt);
+ blockorder++;
+ }
+
+ fdt_set_totalsize(buf.buf, buf.size);
+
+ err = fdt_check_header(buf.buf);
+ if (err)
+ FAIL("Output tree fails check: %s", fdt_strerror(err));
+
+ save_blob(outname, buf.buf);
+
+ PASS();
+}
Index: dtc/tests/Makefile.tests
===================================================================
--- dtc.orig/tests/Makefile.tests 2007-10-25 13:57:12.000000000 +1000
+++ dtc/tests/Makefile.tests 2007-10-25 14:49:42.000000000 +1000
@@ -6,7 +6,7 @@
notfound \
setprop_inplace nop_property nop_node \
sw_tree1 \
- move_and_save \
+ move_and_save mangle-layout \
open_pack rw_tree1 setprop del_property del_node \
string_escapes dtbs_equal_ordered
LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
Index: dtc/tests/run_tests.sh
===================================================================
--- dtc.orig/tests/run_tests.sh 2007-10-25 13:57:12.000000000 +1000
+++ dtc/tests/run_tests.sh 2007-10-25 14:58:14.000000000 +1000
@@ -79,6 +79,17 @@
tree1_tests deshunted.$tree
done
+ # v16 and alternate layout tests
+ for tree in test_tree1.dtb; do
+ for version in 17 16; do
+ for layout in mts mst tms tsm smt stm; do
+ run_test mangle-layout $tree $version $layout
+ tree1_tests v$version.$layout.$tree
+ run_test dtbs_equal_ordered $tree v$version.$layout.$tree
+ done
+ done
+ done
+
# Read-write tests
for tree in test_tree1.dtb sw_tree1.test.dtb; do
rm -f opened.$tree repacked.$tree
--
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
* [RFC/PATCH] powerpc: Cleanup SMT thread handling
From: Benjamin Herrenschmidt @ 2007-10-25 5:27 UTC (permalink / raw)
To: linuxppc-dev
This patch cleans up the SMT thread handling, removing hard coded
bits here or there and providing a set of helpers to convert between
linux cpu numbers, thread numbers and cores.
This implementation requires the number of threads per core to be a
power of 2 and identical on all cores in the system, but it's an
implementation detail, not an API requirement and so this limitation
can be lifted in the future if anybody ever needs it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
I had that taking dust in a pile for some time (I hated all those
hard coded ^ 1 etc...), please comment on the approach.
I haven't scrubbed for all bits of code that may still be doing
old style hard coded assumptions.
arch/powerpc/kernel/setup-common.c | 78 +++++++++++++++++++++++++++++------
arch/powerpc/platforms/cell/smp.c | 3 -
arch/powerpc/platforms/pseries/smp.c | 3 -
include/asm-powerpc/cputhreads.h | 71 +++++++++++++++++++++++++++++++
4 files changed, 140 insertions(+), 15 deletions(-)
Index: linux-work/arch/powerpc/kernel/setup-common.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/setup-common.c 2007-10-25 13:48:31.000000000 +1000
+++ linux-work/arch/powerpc/kernel/setup-common.c 2007-10-25 13:53:23.000000000 +1000
@@ -33,6 +33,7 @@
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/debugfs.h>
+#include <linux/percpu.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/processor.h>
@@ -57,6 +58,7 @@
#include <asm/mmu.h>
#include <asm/lmb.h>
#include <asm/xmon.h>
+#include <asm/cputhreads.h>
#include "setup.h"
@@ -327,6 +329,31 @@ void __init check_for_initrd(void)
#ifdef CONFIG_SMP
+int threads_per_core, threads_shift;
+cpumask_t threads_core_mask;
+
+static void __init cpu_init_thread_core_maps(int tpc)
+{
+ int i;
+
+ threads_per_core = tpc;
+ threads_core_mask = CPU_MASK_NONE;
+
+ /* This implementation only supports power of 2 number of threads
+ * for simplicity/performances
+ */
+ threads_shift = ilog2(tpc);
+ BUG_ON(tpc != (1 << threads_shift));
+
+ for (i = 0; i < tpc; i++)
+ cpu_set(i, threads_core_mask);
+
+ printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n",
+ tpc, tpc > 1 ? "s" : "");
+ printk(KERN_DEBUG " (thread shift is %d)\n", threads_shift);
+}
+
+
/**
* setup_cpu_maps - initialize the following cpu maps:
* cpu_possible_map
@@ -350,22 +377,32 @@ void __init smp_setup_cpu_maps(void)
{
struct device_node *dn = NULL;
int cpu = 0;
+ int nthreads = 1;
+
+ DBG("smp_setup_cpu_maps()\n");
while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
const int *intserv;
- int j, len = sizeof(u32), nthreads = 1;
+ int j, len;
+
+ DBG(" * %s...\n", dn->full_name);
intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
&len);
- if (intserv)
+ if (intserv) {
nthreads = len / sizeof(int);
- else {
+ DBG(" ibm,ppc-interrupt-server#s -> %d threads\n",
+ nthreads);
+ } else {
+ DBG(" no ibm,ppc-interrupt-server#s -> 1 thread\n");
intserv = of_get_property(dn, "reg", NULL);
if (!intserv)
intserv = &cpu; /* assume logical == phys */
}
for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
+ DBG(" thread %d -> cpu %d (hard id %d)\n",
+ j, cpu, intserv[j]);
cpu_set(cpu, cpu_present_map);
set_hard_smp_processor_id(cpu, intserv[j]);
cpu_set(cpu, cpu_possible_map);
@@ -373,6 +410,12 @@ void __init smp_setup_cpu_maps(void)
}
}
+ /* If no SMT supported, nthreads is forced to 1 */
+ if (!cpu_has_feature(CPU_FTR_SMT)) {
+ DBG(" SMT disabled ! nthreads forced to 1\n");
+ nthreads = 1;
+ }
+
#ifdef CONFIG_PPC64
/*
* On pSeries LPAR, we need to know how many cpus
@@ -395,7 +438,7 @@ void __init smp_setup_cpu_maps(void)
/* Double maxcpus for processors which have SMT capability */
if (cpu_has_feature(CPU_FTR_SMT))
- maxcpus *= 2;
+ maxcpus *= nthreads;
if (maxcpus > NR_CPUS) {
printk(KERN_WARNING
@@ -412,9 +455,16 @@ void __init smp_setup_cpu_maps(void)
out:
of_node_put(dn);
}
-
vdso_data->processorCount = num_present_cpus();
#endif /* CONFIG_PPC64 */
+
+ /* Initialize CPU <=> thread mapping/
+ *
+ * WARNING: We assume that the number of threads is the same for
+ * every CPU in the system. If that is not the case, then some code
+ * here will have to be reworked
+ */
+ cpu_init_thread_core_maps(nthreads);
}
/*
@@ -424,17 +474,19 @@ void __init smp_setup_cpu_maps(void)
*/
void __init smp_setup_cpu_sibling_map(void)
{
-#if defined(CONFIG_PPC64)
- int cpu;
+#ifdef CONFIG_PPC64
+ int i, cpu, base;
- /*
- * Do the sibling map; assume only two threads per processor.
- */
for_each_possible_cpu(cpu) {
- cpu_set(cpu, per_cpu(cpu_sibling_map, cpu));
- if (cpu_has_feature(CPU_FTR_SMT))
- cpu_set(cpu ^ 0x1, per_cpu(cpu_sibling_map, cpu));
+ DBG("Sibling map for CPU %d:", cpu);
+ base = cpu_first_thread_in_core(cpu);
+ for (i = 0; i < threads_per_core; i++) {
+ cpu_set(base + i, per_cpu(cpu_sibling_map, cpu));
+ DBG(" %d", base + i);
+ }
+ DBG("\n");
}
+
#endif /* CONFIG_PPC64 */
}
#endif /* CONFIG_SMP */
Index: linux-work/include/asm-powerpc/cputhreads.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/include/asm-powerpc/cputhreads.h 2007-10-25 13:49:49.000000000 +1000
@@ -0,0 +1,71 @@
+#ifndef _ASM_POWERPC_CPUTHREADS_H
+#define _ASM_POWERPC_CPUTHREADS_H
+
+#include <linux/cpumask.h>
+
+/*
+ * Mapping of threads to cores
+ */
+
+#ifdef CONFIG_SMP
+extern int threads_per_core;
+extern int threads_shift;
+extern cpumask_t threads_core_mask;
+#else
+#define threads_per_core 1
+#define threads_shift 0
+#define threads_core_mask (CPU_MASK_CPU0)
+#endif
+
+/* cpu_thread_mask_to_cores - Return a cpumask of one per cores
+ * hit by the argument
+ *
+ * @threads: a cpumask of threads
+ *
+ * This function returns a cpumask which will have one "cpu" (or thread)
+ * bit set for each core that has at least one thread set in the argument.
+ *
+ * This can typically be used for things like IPI for tlb invalidations
+ * since those need to be done only once per core/TLB
+ */
+static inline cpumask_t cpu_thread_mask_to_cores(cpumask_t threads)
+{
+ cpumask_t tmp, res;
+ int i;
+
+ res = CPU_MASK_NONE;
+ for (i = 0; i < NR_CPUS; i += threads_per_core) {
+ cpus_shift_right(tmp, threads_core_mask, i);
+ if (cpus_intersects(threads, tmp))
+ cpu_set(i, res);
+ }
+ return res;
+}
+
+static inline int cpu_nr_cores(void)
+{
+ return NR_CPUS >> threads_shift;
+}
+
+static inline cpumask_t cpu_online_cores_map(void)
+{
+ return cpu_thread_mask_to_cores(cpu_online_map);
+}
+
+static inline int cpu_thread_to_core(int cpu)
+{
+ return cpu >> threads_shift;
+}
+
+static inline int cpu_thread_in_core(int cpu)
+{
+ return cpu & (threads_per_core - 1);
+}
+
+static inline int cpu_first_thread_in_core(int cpu)
+{
+ return cpu & ~(threads_per_core - 1);
+}
+
+#endif /* _ASM_POWERPC_CPUTHREADS_H */
+
Index: linux-work/arch/powerpc/platforms/cell/smp.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/cell/smp.c 2007-10-25 13:48:31.000000000 +1000
+++ linux-work/arch/powerpc/platforms/cell/smp.c 2007-10-25 13:50:56.000000000 +1000
@@ -42,6 +42,7 @@
#include <asm/firmware.h>
#include <asm/system.h>
#include <asm/rtas.h>
+#include <asm/cputhreads.h>
#include "interrupt.h"
@@ -181,7 +182,7 @@ static int smp_cell_cpu_bootable(unsigne
*/
if (system_state < SYSTEM_RUNNING &&
cpu_has_feature(CPU_FTR_SMT) &&
- !smt_enabled_at_boot && nr % 2 != 0)
+ !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
return 1;
Index: linux-work/arch/powerpc/platforms/pseries/smp.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/pseries/smp.c 2007-10-25 13:48:31.000000000 +1000
+++ linux-work/arch/powerpc/platforms/pseries/smp.c 2007-10-25 13:50:40.000000000 +1000
@@ -46,6 +46,7 @@
#include <asm/pSeries_reconfig.h>
#include <asm/mpic.h>
#include <asm/vdso_datapage.h>
+#include <asm/cputhreads.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -202,7 +203,7 @@ static int smp_pSeries_cpu_bootable(unsi
*/
if (system_state < SYSTEM_RUNNING &&
cpu_has_feature(CPU_FTR_SMT) &&
- !smt_enabled_at_boot && nr % 2 != 0)
+ !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
return 1;
^ permalink raw reply
* Re: problems to boot 2.6.23 kernel on XILINX ppc with 8Mbytes of RAM
From: Magnus Hjorth @ 2007-10-25 7:00 UTC (permalink / raw)
To: manu; +Cc: Linuxppc-embedded
In-Reply-To: <471FA48B.2020809@free.fr>
[-- Attachment #1: Type: text/plain, Size: 1504 bytes --]
Hello Manu,
Could you try the attached patch to arch/ppc/mm/4xx_mmu.c and see if it
solves your problem?
Best regards,
Magnus
manu wrote:
> Hello,
> I work on a custom board based on a virtex 2 pro FPGA and 8Mbytes of SDRAM.
> Untill now I used a 2.4.31 linux ppc kernel with John Williams patches
> and uclinux distribution and everything worked perfectly.
> I've decided to move to the latest 2.6 version from kernel.org
> (2.6.23.1) with an initramfs containing a busybox.
> My complete zImage including the initramfs has a size of 900Kbytes.
> I made some tests with a ML300 board and I managed to get a shell easily.
> When I migrated to the custom board, I had the "Now booting the kernel"
> message and then nothing.
> When I trace the code running on the ppc with the debugger, execution
> seems to be stuck in some early initialization code.
> I managed to reproduce the problem on the ML300 using "mem=8m" parameter
> on the bootline.
> With "mem=16m" the kernel boots correctly.
> I'm really surprised by the amount of RAM required to boot the kernel.
> Is there a way to make it boot with only 8Mbytes of RAM ?
> Thanks for your help.
>
> Manu
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
--
Magnus Hjorth, M.Sc.
Omnisys Instruments AB
Gruvgatan 8
SE-421 30 Västra Frölunda, SWEDEN
Phone: +46 31 734 34 09
Fax: +46 31 734 34 29
http://www.omnisys.se
[-- Attachment #2: 4xx_mmu.patch --]
[-- Type: text/plain, Size: 589 bytes --]
--- 4xx_mmu_old.c 2007-10-25 08:54:46.000000000 +0200
+++ 4xx_mmu.c 2007-10-25 08:55:57.000000000 +0200
@@ -105,7 +105,7 @@
return s;
}
- while (s <= (total_lowmem - LARGE_PAGE_SIZE_16M)) {
+ while (s + LARGE_PAGE_SIZE_16M <= total_lowmem) {
pmd_t *pmdp;
unsigned long val = p | _PMD_SIZE_16M | _PAGE_HWEXEC | _PAGE_HWWRITE;
@@ -120,7 +120,7 @@
s += LARGE_PAGE_SIZE_16M;
}
- while (s <= (total_lowmem - LARGE_PAGE_SIZE_4M)) {
+ while (s + LARGE_PAGE_SIZE_4M <= total_lowmem) {
pmd_t *pmdp;
unsigned long val = p | _PMD_SIZE_4M | _PAGE_HWEXEC | _PAGE_HWWRITE;
^ permalink raw reply
* Re: [PATCH] ehea: fix port_napi_disable/enable
From: Jeff Garzik @ 2007-10-25 7:31 UTC (permalink / raw)
To: Jan-Bernd Themann
Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
Christoph Raisch, Marcus Eder, Stefan Roscher
In-Reply-To: <200710241153.34992.ossthema@de.ibm.com>
Jan-Bernd Themann wrote:
> napi_disable / napi_enable must be applied on all ehea queues.
>
> Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
applied
^ permalink raw reply
* Re: linux-2.6.git: cannot build PS3 image
From: Geert Uytterhoeven @ 2007-10-25 9:27 UTC (permalink / raw)
To: Scott Wood; +Cc: Linux/PPC Development
In-Reply-To: <Pine.LNX.4.62.0710241820010.17958@pademelon.sonytel.be>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1935 bytes --]
On Wed, 24 Oct 2007, Geert Uytterhoeven wrote:
> On Wed, 17 Oct 2007, Scott Wood wrote:
> > Geert Uytterhoeven wrote:
> > >> diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
> > >> index 39b27e5..795f988 100755
> > >> --- a/arch/powerpc/boot/wrapper
> > >> +++ b/arch/powerpc/boot/wrapper
> > >> @@ -232,7 +232,7 @@ base=0x`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1`
> > >> entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3`
> > >>
> > >> if [ -n "$binary" ]; then
> > >> - mv "$ofile" "$ofile".elf
> > >> + cp "$ofile" "$ofile".elf
> > >> ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin
> > >> fi
> > >
> > > No comments?
> >
> > That'd work in this case, though it'd probably be better to make the
> > $ofile be the end result that will boot on the ps3, and leave a suffix
> > on the intermediate files.
>
> The $ofile is the end result to boot using kboot (2nd stage kernel).
> otheros.bld is the end result to write to FLASH ROM (1st stage kernel).
Bummer, ignore the first sentence. For a 2nd stage kernel, we do not boot
$ofile (= arch/powerpc/boot/zImage.ps3), but the plain vmlinux or
vmlinux.strip.
Hence zImage.ps3 is an intermediate file only and we don't need zImage at all.
Nevertheless, your other patch fixed the problem, thanks! ;-)
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619
^ permalink raw reply
* Re: [PATCH v4] FEC - fast ethernet controller for mpc52xx
From: Jeff Garzik @ 2007-10-25 9:29 UTC (permalink / raw)
To: Domen Puncer; +Cc: linuxppc-dev, netdev
In-Reply-To: <20071019112700.GD27403@nd47.coderock.org>
Domen Puncer wrote:
> +static int mpc52xx_fec_alloc_rx_buffers(struct bcom_task *rxtsk)
> +{
> + while (!bcom_queue_full(rxtsk)) {
> + struct sk_buff *skb;
> + struct bcom_fec_bd *bd;
> +
> + skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
> + if (skb == NULL)
> + return -EAGAIN;
> +
> + /* zero out the initial receive buffers to aid debugging */
> + memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
> +
> + bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
> +
> + bd->status = FEC_RX_BUFFER_SIZE;
> + bd->skb_pa = virt_to_phys(skb->data);
> +
> + bcom_submit_next_buffer(rxtsk, skb);
use your platform's dma mapping functions, rather than virt_to_phys()
it might be the exact same implementation, inside the platform
internals, but drivers should not be using this directly.
> +/* based on generic_adjust_link from fs_enet-main.c */
> +static void mpc52xx_fec_adjust_link(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct phy_device *phydev = priv->phydev;
> + int new_state = 0;
> +
> + if (phydev->link != PHY_DOWN) {
> + if (phydev->duplex != priv->duplex) {
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 rcntrl;
> + u32 tcntrl;
> +
> + new_state = 1;
> + priv->duplex = phydev->duplex;
> +
> + rcntrl = in_be32(&fec->r_cntrl);
> + tcntrl = in_be32(&fec->x_cntrl);
> +
> + rcntrl &= ~FEC_RCNTRL_DRT;
> + tcntrl &= ~FEC_TCNTRL_FDEN;
> + if (phydev->duplex == DUPLEX_FULL)
> + tcntrl |= FEC_TCNTRL_FDEN; /* FD enable */
> + else
> + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
> +
> + out_be32(&fec->r_cntrl, rcntrl);
> + out_be32(&fec->x_cntrl, tcntrl);
> + }
> +
> + if (phydev->speed != priv->speed) {
> + new_state = 1;
> + priv->speed = phydev->speed;
> + }
> +
> + if (priv->link == PHY_DOWN) {
> + new_state = 1;
> + priv->link = phydev->link;
> + netif_schedule(dev);
> + netif_carrier_on(dev);
> + netif_start_queue(dev);
> + }
> +
> + } else if (priv->link) {
> + new_state = 1;
> + priv->link = PHY_DOWN;
> + priv->speed = 0;
> + priv->duplex = -1;
> + netif_stop_queue(dev);
> + netif_carrier_off(dev);
> + }
> +
> + if (new_state && netif_msg_link(priv))
> + phy_print_status(phydev);
> +}
> +
> +static int mpc52xx_fec_init_phy(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct phy_device *phydev;
> + char phy_id[BUS_ID_SIZE];
> +
> + snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT,
> + (unsigned int)dev->base_addr, priv->phy_addr);
> +
> + priv->link = PHY_DOWN;
> + priv->speed = 0;
> + priv->duplex = -1;
> +
> + phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
> + if (IS_ERR(phydev)) {
> + dev_err(&dev->dev, "phy_connect failed\n");
> + return PTR_ERR(phydev);
> + }
> + dev_info(&dev->dev, "attached phy %i to driver %s\n",
> + phydev->addr, phydev->drv->name);
> +
> + priv->phydev = phydev;
> +
> + return 0;
> +}
> +
> +static int mpc52xx_fec_phy_start(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + int err;
> +
> + if (!priv->has_phy)
> + return 0;
> +
> + err = mpc52xx_fec_init_phy(dev);
> + if (err) {
> + dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n");
> + return err;
> + }
> +
> + /* reset phy - this also wakes it from PDOWN */
> + phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
> + phy_start(priv->phydev);
> +
> + return 0;
> +}
> +
> +static void mpc52xx_fec_phy_stop(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + if (!priv->has_phy)
> + return;
> +
> + phy_disconnect(priv->phydev);
> + /* power down phy */
> + phy_stop(priv->phydev);
> + phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
> +}
> +
> +static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
> + struct mii_ioctl_data *mii_data, int cmd)
> +{
> + if (!priv->has_phy)
> + return -ENOTSUPP;
> +
> + return phy_mii_ioctl(priv->phydev, mii_data, cmd);
> +}
> +
> +static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
> +{
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + if (!priv->has_phy)
> + return;
> +
> + out_be32(&fec->mii_speed, priv->phy_speed);
> +}
> +
> +static int mpc52xx_fec_open(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + int err = -EBUSY;
> +
> + if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_DISABLED | IRQF_SHARED,
why IRQF_DISABLED? that should not be needed.
> + DRIVER_NAME "_ctrl", dev)) {
> + dev_err(&dev->dev, "ctrl interrupt request failed\n");
> + goto out;
> + }
> + if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, IRQF_DISABLED,
ditto
> + DRIVER_NAME "_rx", dev)) {
> + dev_err(&dev->dev, "rx interrupt request failed\n");
> + goto free_ctrl_irq;
> + }
> + if (request_irq(priv->t_irq, &mpc52xx_fec_tx_interrupt, IRQF_DISABLED,
ditto
> + DRIVER_NAME "_tx", dev)) {
> + dev_err(&dev->dev, "tx interrupt request failed\n");
> + goto free_2irqs;
> + }
> +
> + bcom_fec_rx_reset(priv->rx_dmatsk);
> + bcom_fec_tx_reset(priv->tx_dmatsk);
> +
> + err = mpc52xx_fec_alloc_rx_buffers(priv->rx_dmatsk);
> + if (err) {
> + dev_err(&dev->dev, "mpc52xx_fec_alloc_rx_buffers failed\n");
> + goto free_irqs;
> + }
> +
> + err = mpc52xx_fec_phy_start(dev);
> + if (err)
> + goto free_skbs;
> +
> + bcom_enable(priv->rx_dmatsk);
> + bcom_enable(priv->tx_dmatsk);
> +
> + mpc52xx_fec_start(dev);
> +
> + netif_start_queue(dev);
> +
> + return 0;
> +
> + free_skbs:
> + mpc52xx_fec_free_rx_buffers(priv->rx_dmatsk);
> +
> + free_irqs:
> + free_irq(priv->t_irq, dev);
> + free_2irqs:
> + free_irq(priv->r_irq, dev);
> + free_ctrl_irq:
> + free_irq(dev->irq, dev);
> + out:
> +
> + return err;
> +}
> +
> +static int mpc52xx_fec_close(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + netif_stop_queue(dev);
> +
> + mpc52xx_fec_stop(dev);
> +
> + mpc52xx_fec_free_rx_buffers(priv->rx_dmatsk);
> +
> + free_irq(dev->irq, dev);
> + free_irq(priv->r_irq, dev);
> + free_irq(priv->t_irq, dev);
> +
> + mpc52xx_fec_phy_stop(dev);
> +
> + return 0;
> +}
> +
> +/* This will only be invoked if your driver is _not_ in XOFF state.
> + * What this means is that you need not check it, and that this
> + * invariant will hold if you make sure that the netif_*_queue()
> + * calls are done at the proper times.
> + */
> +static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct bcom_fec_bd *bd;
> +
> + if (bcom_queue_full(priv->tx_dmatsk)) {
> + if (net_ratelimit())
> + dev_err(&dev->dev, "transmit queue overrun\n");
> + return 1;
> + }
> +
> + spin_lock_irq(&priv->lock);
> + dev->trans_start = jiffies;
> +
> + bd = (struct bcom_fec_bd *)
> + bcom_prepare_next_buffer(priv->tx_dmatsk);
> +
> + bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC;
> + bd->skb_pa = virt_to_phys(skb->data);
use dma_xxx
> + bcom_submit_next_buffer(priv->tx_dmatsk, skb);
> +
> + if (bcom_queue_full(priv->tx_dmatsk)) {
> + priv->tx_full = 1;
no need for your own tx_full variable
> + netif_stop_queue(dev);
> + }
> +
> + spin_unlock_irq(&priv->lock);
> +
> + return 0;
> +}
> +
> +/* This handles BestComm transmit task interrupts
> + */
> +static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + spin_lock(&priv->lock);
> +
> + while (bcom_buffer_done(priv->tx_dmatsk)) {
> + struct sk_buff *skb;
> + skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, NULL);
> +
> + priv->tx_full = 0;
> + dev_kfree_skb_irq(skb);
> + }
> +
> + if (netif_queue_stopped(dev) && !priv->tx_full)
no need to test netif_queue_stopped(), netif_wake_queue() does that anyway
no need for tx_full
> + netif_wake_queue(dev);
> +
> + spin_unlock(&priv->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + while (bcom_buffer_done(priv->rx_dmatsk)) {
> + struct sk_buff *skb;
> + struct sk_buff *rskb;
> + struct bcom_fec_bd *bd;
> + u32 status;
> +
> + rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, NULL);
> +
> + /* Test for errors in received frame */
> + if (status & BCOM_FEC_RX_BD_ERRORS) {
> + /* Drop packet and reuse the buffer */
> + bd = (struct bcom_fec_bd *)
> + bcom_prepare_next_buffer(priv->rx_dmatsk);
> +
> + bd->status = FEC_RX_BUFFER_SIZE;
> + bd->skb_pa = virt_to_phys(rskb->data);
> +
> + bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
> +
> + priv->stats.rx_dropped++;
> +
> + continue;
> + }
> +
> + /* skbs are allocated on open, so now we allocate a new one,
> + * and remove the old (with the packet) */
> + skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
> + if (skb) {
> + /* Process the received skb */
> + int length = status & BCOM_FEC_RX_BD_LEN_MASK;
> +
> + skb_put(rskb, length - 4); /* length without CRC32 */
> +
> + rskb->dev = dev;
> + rskb->protocol = eth_type_trans(rskb, dev);
> +
> + netif_rx(rskb);
> + dev->last_rx = jiffies;
> + } else {
> + /* Can't get a new one : reuse the same & drop pkt */
> + dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
> + priv->stats.rx_dropped++;
> +
> + skb = rskb;
> + }
> +
> + bd = (struct bcom_fec_bd *)
> + bcom_prepare_next_buffer(priv->rx_dmatsk);
> +
> + bd->status = FEC_RX_BUFFER_SIZE;
> + bd->skb_pa = virt_to_phys(skb->data);
> +
> + bcom_submit_next_buffer(priv->rx_dmatsk, skb);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *dev = dev_id;
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 ievent;
> +
> + ievent = in_be32(&fec->ievent);
generally wise to check for 0xffffffff, which often indicates hardware
fault / device not there / scrogged
> + ievent &= ~FEC_IEVENT_MII; /* mii is handled separately */
> + if (!ievent)
> + return IRQ_NONE;
> +
> + out_be32(&fec->ievent, ievent); /* clear pending events */
> +
> + if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
> + if (ievent & ~FEC_IEVENT_TFINT)
> + dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
> + return IRQ_HANDLED;
> + }
> +
> + if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
> + dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
> + if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
> + dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
> +
> + mpc52xx_fec_reset(dev);
> +
> + netif_wake_queue(dev);
> + return IRQ_HANDLED;
> +}
> +
> +/*
> + * Get the current statistics.
> + * This may be called with the card open or closed.
> + */
> +static struct net_device_stats *mpc52xx_fec_get_stats(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct net_device_stats *stats = &priv->stats;
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + stats->rx_bytes = in_be32(&fec->rmon_r_octets);
> + stats->rx_packets = in_be32(&fec->rmon_r_packets);
> + stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
> + in_be32(&fec->rmon_r_undersize) +
> + in_be32(&fec->rmon_r_oversize) +
> + in_be32(&fec->rmon_r_frag) +
> + in_be32(&fec->rmon_r_jab);
> +
> + stats->tx_bytes = in_be32(&fec->rmon_t_octets);
> + stats->tx_packets = in_be32(&fec->rmon_t_packets);
> + stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
> + in_be32(&fec->rmon_t_undersize) +
> + in_be32(&fec->rmon_t_oversize) +
> + in_be32(&fec->rmon_t_frag) +
> + in_be32(&fec->rmon_t_jab);
> +
> + stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
> + stats->collisions = in_be32(&fec->rmon_t_col);
> +
> + /* detailed rx_errors: */
> + stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
> + + in_be32(&fec->rmon_r_oversize)
> + + in_be32(&fec->rmon_r_frag)
> + + in_be32(&fec->rmon_r_jab);
> + stats->rx_over_errors = in_be32(&fec->r_macerr);
> + stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
> + stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
> + stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
> + stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
> +
> + /* detailed tx_errors: */
> + stats->tx_aborted_errors = 0;
> + stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
> + stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
> + stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
> + stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
> +
> + return stats;
> +}
> +
> +/*
> + * Read MIB counters in order to reset them,
> + * then zero all the stats fields in memory
> + */
> +static void mpc52xx_fec_reset_stats(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + out_be32(&fec->mib_control, FEC_MIB_DISABLE);
> + memset_io(&fec->rmon_t_drop, 0, (__force u32)&fec->reserved10 -
> + (__force u32)&fec->rmon_t_drop);
> + out_be32(&fec->mib_control, 0);
> +
> + memset(&priv->stats, 0, sizeof(priv->stats));
don't use your own copy of net_device_stats, it's in net_device now
> +/*
> + * Set or clear the multicast filter for this adaptor.
> + */
> +static void mpc52xx_fec_set_multicast_list(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 rx_control;
> +
> + rx_control = in_be32(&fec->r_cntrl);
> +
> + if (dev->flags & IFF_PROMISC) {
> + rx_control |= FEC_RCNTRL_PROM;
> + out_be32(&fec->r_cntrl, rx_control);
> + } else {
> + rx_control &= ~FEC_RCNTRL_PROM;
> + out_be32(&fec->r_cntrl, rx_control);
> +
> + if (dev->flags & IFF_ALLMULTI) {
> + out_be32(&fec->gaddr1, 0xffffffff);
> + out_be32(&fec->gaddr2, 0xffffffff);
> + } else {
> + u32 crc;
> + int i;
> + struct dev_mc_list *dmi;
> + u32 gaddr1 = 0x00000000;
> + u32 gaddr2 = 0x00000000;
> +
> + dmi = dev->mc_list;
> + for (i=0; i<dev->mc_count; i++) {
> + crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
> + if (crc >= 32)
> + gaddr1 |= 1 << (crc-32);
> + else
> + gaddr2 |= 1 << crc;
> + dmi = dmi->next;
> + }
> + out_be32(&fec->gaddr1, gaddr1);
> + out_be32(&fec->gaddr2, gaddr2);
fall back to ALLMULTI behavior if dev->mc_count is too large (for your
chip's version of "too large")
> +/**
> + * mpc52xx_fec_hw_init
> + * @dev: network device
> + *
> + * Setup various hardware setting, only needed once on start
> + */
> +static void mpc52xx_fec_hw_init(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + int i;
> +
> + /* Whack a reset. We should wait for this. */
> + out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
> + for (i = 0; i < FEC_RESET_DELAY; ++i) {
> + if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
> + break;
> + udelay(1);
> + }
> + if (i == FEC_RESET_DELAY)
> + dev_err(&dev->dev, "FEC Reset timeout!\n");
> +
> + /* set pause to 0x20 frames */
> + out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20);
> +
> + /* high service request will be deasserted when there's < 7 bytes in fifo
> + * low service request will be deasserted when there's < 4*7 bytes in fifo
> + */
> + out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
> + out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
> +
> + /* alarm when <= x bytes in FIFO */
> + out_be32(&fec->rfifo_alarm, 0x0000030c);
> + out_be32(&fec->tfifo_alarm, 0x00000100);
> +
> + /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */
> + out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B);
> +
> + /* enable crc generation */
> + out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC);
> + out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */
> + out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */
> +
> + /* set phy speed.
> + * this can't be done in phy driver, since it needs to be called
> + * before fec stuff (even on resume) */
> + mpc52xx_fec_phy_hw_init(priv);
> +}
> +
> +/**
> + * mpc52xx_fec_start
> + * @dev: network device
> + *
> + * This function is called to start or restart the FEC during a link
> + * change. This happens on fifo errors or when switching between half
> + * and full duplex.
> + */
> +static void mpc52xx_fec_start(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + u32 rcntrl;
> + u32 tcntrl;
> + u32 tmp;
> +
> + /* clear sticky error bits */
> + tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
> + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
> + out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
> +
> + /* FIFOs will reset on mpc52xx_fec_enable */
> + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
> +
> + /* Set station address. */
> + mpc52xx_fec_set_paddr(dev, dev->dev_addr);
> +
> + mpc52xx_fec_set_multicast_list(dev);
> +
> + /* set max frame len, enable flow control, select mii mode */
> + rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
> + rcntrl |= FEC_RCNTRL_FCE;
> +
> + if (priv->has_phy)
> + rcntrl |= FEC_RCNTRL_MII_MODE;
> +
> + if (priv->duplex == DUPLEX_FULL)
> + tcntrl = FEC_TCNTRL_FDEN; /* FD enable */
> + else {
> + rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
> + tcntrl = 0;
> + }
> + out_be32(&fec->r_cntrl, rcntrl);
> + out_be32(&fec->x_cntrl, tcntrl);
> +
> + /* Clear any outstanding interrupt. */
> + out_be32(&fec->ievent, 0xffffffff);
> +
> + /* Enable interrupts we wish to service. */
> + out_be32(&fec->imask, FEC_IMASK_ENABLE);
> +
> + /* And last, enable the transmit and receive processing. */
> + out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
> + out_be32(&fec->r_des_active, 0x01000000);
> +
> + priv->tx_full = 0;
> +}
> +
> +/**
> + * mpc52xx_fec_stop
> + * @dev: network device
> + *
> + * stop all activity on fec and empty dma buffers
> + */
> +static void mpc52xx_fec_stop(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> + unsigned long timeout;
> +
> + /* disable all interrupts */
> + out_be32(&fec->imask, 0);
> +
> + /* Disable the rx task. */
> + bcom_disable(priv->rx_dmatsk);
> +
> + /* Wait for tx queue to drain, but only if we're in process context */
> + if (!in_interrupt()) {
> + timeout = jiffies + msecs_to_jiffies(2000);
> + while (time_before(jiffies, timeout) &&
> + !bcom_queue_empty(priv->tx_dmatsk))
> + msleep(100);
> +
> + if (time_after_eq(jiffies, timeout))
> + dev_err(&dev->dev, "queues didn't drain\n");
> +#if 1
> + if (time_after_eq(jiffies, timeout)) {
> + dev_err(&dev->dev, " tx: index: %i, outdex: %i\n",
> + priv->tx_dmatsk->index,
> + priv->tx_dmatsk->outdex);
> + dev_err(&dev->dev, " rx: index: %i, outdex: %i\n",
> + priv->rx_dmatsk->index,
> + priv->rx_dmatsk->outdex);
> + }
> +#endif
> + }
> +
> + bcom_disable(priv->tx_dmatsk);
> +
> + /* Stop FEC */
> + out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
> +
> + return;
> +}
> +
> +/* reset fec and bestcomm tasks */
> +static void mpc52xx_fec_reset(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + struct mpc52xx_fec __iomem *fec = priv->fec;
> +
> + mpc52xx_fec_stop(dev);
> +
> + out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status));
> + out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO);
> +
> + mpc52xx_fec_free_rx_buffers(priv->rx_dmatsk);
> +
> + mpc52xx_fec_hw_init(dev);
> +
> + phy_stop(priv->phydev);
> + phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
> + phy_start(priv->phydev);
> +
> + bcom_fec_rx_reset(priv->rx_dmatsk);
> + bcom_fec_tx_reset(priv->tx_dmatsk);
> +
> + mpc52xx_fec_alloc_rx_buffers(priv->rx_dmatsk);
> +
> + bcom_enable(priv->rx_dmatsk);
> + bcom_enable(priv->tx_dmatsk);
> +
> + mpc52xx_fec_start(dev);
> +}
> +
> +
> +/* ethtool interface */
> +static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
> + struct ethtool_drvinfo *info)
> +{
> + strcpy(info->driver, DRIVER_NAME);
version? anything else?
> +static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + return phy_ethtool_gset(priv->phydev, cmd);
> +}
> +
> +static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + return phy_ethtool_sset(priv->phydev, cmd);
> +}
> +
> +static u32 mpc52xx_fec_get_msglevel(struct net_device *dev)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + return priv->msg_enable;
> +}
> +
> +static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> + priv->msg_enable = level;
> +}
> +
> +static const struct ethtool_ops mpc52xx_fec_ethtool_ops = {
> + .get_drvinfo = mpc52xx_fec_get_drvinfo,
> + .get_settings = mpc52xx_fec_get_settings,
> + .set_settings = mpc52xx_fec_set_settings,
> + .get_link = ethtool_op_get_link,
> + .get_msglevel = mpc52xx_fec_get_msglevel,
> + .set_msglevel = mpc52xx_fec_set_msglevel,
> +};
> +
> +
> +static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> +{
> + struct mpc52xx_fec_priv *priv = netdev_priv(dev);
> +
> + return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
> +}
> +
> +/* ======================================================================== */
> +/* OF Driver */
> +/* ======================================================================== */
> +
> +static int __devinit
> +mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
> +{
> + int rv;
> + struct net_device *ndev;
> + struct mpc52xx_fec_priv *priv = NULL;
> + struct resource mem;
> + const phandle *ph;
> +
> + phys_addr_t rx_fifo;
> + phys_addr_t tx_fifo;
> +
> + /* Get the ether ndev & it's private zone */
> + ndev = alloc_etherdev(sizeof(struct mpc52xx_fec_priv));
> + if (!ndev)
> + return -ENOMEM;
> +
> + priv = netdev_priv(ndev);
> +
> + /* Reserve FEC control zone */
> + rv = of_address_to_resource(op->node, 0, &mem);
> + if (rv) {
> + printk(KERN_ERR DRIVER_NAME ": "
> + "Error while parsing device node resource\n" );
> + return rv;
> + }
> + if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) {
> + printk(KERN_ERR DRIVER_NAME
> + " - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",
> + (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
> + return -EINVAL;
> + }
> +
> + if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
> + return -EBUSY;
> +
> + /* Init ether ndev with what we have */
> + ndev->open = mpc52xx_fec_open;
> + ndev->stop = mpc52xx_fec_close;
> + ndev->hard_start_xmit = mpc52xx_fec_hard_start_xmit;
> + ndev->do_ioctl = mpc52xx_fec_ioctl;
> + ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops;
> + ndev->get_stats = mpc52xx_fec_get_stats;
> + ndev->set_mac_address = mpc52xx_fec_set_mac_address;
> + ndev->set_multicast_list = mpc52xx_fec_set_multicast_list;
> + ndev->tx_timeout = mpc52xx_fec_tx_timeout;
> + ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
> + ndev->flags &= ~IFF_RUNNING;
delete this, no reason to ever touch IFF_RUNNING yourself
> + ndev->base_addr = mem.start;
> + priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
> +
> + spin_lock_init(&priv->lock);
> +
> + /* ioremap the zones */
> + priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec));
> +
> + if (!priv->fec) {
> + rv = -ENOMEM;
> + goto probe_error;
> + }
> +
> + /* Bestcomm init */
> + rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data);
> + tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data);
> +
> + priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE);
> + priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
> +
> + if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
> + printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
> + rv = -ENOMEM;
> + goto probe_error;
> + }
> +
> + /* Get the IRQ we need one by one */
> + /* Control */
> + ndev->irq = irq_of_parse_and_map(op->node, 0);
> +
> + /* RX */
> + priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
> +
> + /* TX */
> + priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
> +
> + /* MAC address init */
> + if (!is_zero_ether_addr(mpc52xx_fec_mac_addr))
> + memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
> + else
> + mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
> +
> + priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
netif_msg_init
> + priv->duplex = DUPLEX_FULL;
> +
> + /* is the phy present in device tree? */
> + ph = of_get_property(op->node, "phy-handle", NULL);
> + if (ph) {
> + const unsigned int *prop;
> + struct device_node *phy_dn;
> + priv->has_phy = 1;
> +
> + phy_dn = of_find_node_by_phandle(*ph);
> + prop = of_get_property(phy_dn, "reg", NULL);
> + priv->phy_addr = *prop;
> +
> + of_node_put(phy_dn);
> +
> + /* Phy speed */
> + priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
> + } else {
> + dev_info(&ndev->dev, "can't find \"phy-handle\" in device"
> + " tree, using 7-wire mode\n");
> + }
> +
> + /* Hardware init */
> + mpc52xx_fec_hw_init(ndev);
> +
> + mpc52xx_fec_reset_stats(ndev);
> +
> + /* Register the new network device */
> + rv = register_netdev(ndev);
> + if (rv < 0)
> + goto probe_error;
> +
> + /* We're done ! */
> + dev_set_drvdata(&op->dev, ndev);
> +
> + return 0;
> +
> +
> + /* Error handling - free everything that might be allocated */
> +probe_error:
> +
> + irq_dispose_mapping(ndev->irq);
> +
> + if (priv->rx_dmatsk)
> + bcom_fec_rx_release(priv->rx_dmatsk);
> + if (priv->tx_dmatsk)
> + bcom_fec_tx_release(priv->tx_dmatsk);
> +
> + if (priv->fec)
> + iounmap(priv->fec);
> +
> + release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
> +
> + free_netdev(ndev);
> +
> + return rv;
> +}
> +
> +static int
> +mpc52xx_fec_remove(struct of_device *op)
> +{
> + struct net_device *ndev;
> + struct mpc52xx_fec_priv *priv;
> +
> + ndev = dev_get_drvdata(&op->dev);
> + if (!ndev)
> + return 0;
testing for impossible condition
> + priv = netdev_priv(ndev);
> +
> + unregister_netdev(ndev);
> +
> + irq_dispose_mapping(ndev->irq);
> +
> + bcom_fec_rx_release(priv->rx_dmatsk);
> + bcom_fec_tx_release(priv->tx_dmatsk);
> +
> + iounmap(priv->fec);
> +
> + release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
> +
> + free_netdev(ndev);
> +
> + dev_set_drvdata(&op->dev, NULL);
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state)
> +{
> + struct net_device *dev = dev_get_drvdata(&op->dev);
> +
> + if (netif_running(dev))
> + mpc52xx_fec_close(dev);
> +
> + return 0;
> +}
> +
> +static int mpc52xx_fec_of_resume(struct of_device *op)
> +{
> + struct net_device *dev = dev_get_drvdata(&op->dev);
> +
> + mpc52xx_fec_hw_init(dev);
> + mpc52xx_fec_reset_stats(dev);
> +
> + if (netif_running(dev))
> + mpc52xx_fec_open(dev);
> +
> + return 0;
> +}
> +#endif
> +
> +static struct of_device_id mpc52xx_fec_match[] = {
> + {
> + .type = "network",
> + .compatible = "mpc5200-fec",
> + },
> + { }
> +};
> +
> +MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
> +
> +static struct of_platform_driver mpc52xx_fec_driver = {
> + .owner = THIS_MODULE,
> + .name = DRIVER_NAME,
> + .match_table = mpc52xx_fec_match,
> + .probe = mpc52xx_fec_probe,
> + .remove = mpc52xx_fec_remove,
> +#ifdef CONFIG_PM
> + .suspend = mpc52xx_fec_of_suspend,
> + .resume = mpc52xx_fec_of_resume,
> +#endif
> +};
> +
> +
> +/* ======================================================================== */
> +/* Module */
> +/* ======================================================================== */
> +
> +static int __init
> +mpc52xx_fec_init(void)
> +{
> +#ifdef CONFIG_FEC_MPC52xx_MDIO
> + int ret;
> + ret = of_register_platform_driver(&mpc52xx_fec_mdio_driver);
> + if (ret) {
> + printk(KERN_ERR DRIVER_NAME ": failed to register mdio driver\n");
> + return ret;
> + }
> +#endif
> + return of_register_platform_driver(&mpc52xx_fec_driver);
> +}
> +
> +static void __exit
> +mpc52xx_fec_exit(void)
> +{
> + of_unregister_platform_driver(&mpc52xx_fec_driver);
> +#ifdef CONFIG_FEC_MPC52xx_MDIO
> + of_unregister_platform_driver(&mpc52xx_fec_mdio_driver);
> +#endif
> +}
> +
> +
> +module_init(mpc52xx_fec_init);
> +module_exit(mpc52xx_fec_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Dale Farnsworth");
> +MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
> Index: linux.git/drivers/net/fec_mpc52xx.h
> ===================================================================
> --- /dev/null
> +++ linux.git/drivers/net/fec_mpc52xx.h
> @@ -0,0 +1,315 @@
> +/*
> + * drivers/drivers/net/fec_mpc52xx/fec.h
> + *
> + * Driver for the MPC5200 Fast Ethernet Controller
> + *
> + * Author: Dale Farnsworth <dfarnsworth@mvista.com>
> + *
> + * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
> + * the terms of the GNU General Public License version 2. This program
> + * is licensed "as is" without any warranty of any kind, whether express
> + * or implied.
> + */
> +
> +#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
> +#define __DRIVERS_NET_MPC52XX_FEC_H__
> +
> +#include <linux/phy.h>
> +
> +/* Tunable constant */
> +/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
> +#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
> +#define FEC_RX_NUM_BD 256
> +#define FEC_TX_NUM_BD 64
> +
> +#define FEC_RESET_DELAY 50 /* uS */
> +
> +#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
> +
> +struct mpc52xx_fec_priv {
> + int duplex;
> + int tx_full;
> + int r_irq;
> + int t_irq;
> + struct mpc52xx_fec __iomem *fec;
> + struct bcom_task *rx_dmatsk;
> + struct bcom_task *tx_dmatsk;
> + spinlock_t lock;
> + struct net_device_stats stats;
> + int msg_enable;
> +
> + int has_phy;
> + unsigned int phy_speed;
> + unsigned int phy_addr;
> + struct phy_device *phydev;
> + enum phy_state link;
> + int speed;
> +};
> +
> +
> +/* ======================================================================== */
> +/* Hardware register sets & bits */
> +/* ======================================================================== */
> +
> +struct mpc52xx_fec {
> + u32 fec_id; /* FEC + 0x000 */
> + u32 ievent; /* FEC + 0x004 */
> + u32 imask; /* FEC + 0x008 */
> +
> + u32 reserved0[1]; /* FEC + 0x00C */
> + u32 r_des_active; /* FEC + 0x010 */
> + u32 x_des_active; /* FEC + 0x014 */
> + u32 r_des_active_cl; /* FEC + 0x018 */
> + u32 x_des_active_cl; /* FEC + 0x01C */
> + u32 ivent_set; /* FEC + 0x020 */
> + u32 ecntrl; /* FEC + 0x024 */
> +
> + u32 reserved1[6]; /* FEC + 0x028-03C */
> + u32 mii_data; /* FEC + 0x040 */
> + u32 mii_speed; /* FEC + 0x044 */
> + u32 mii_status; /* FEC + 0x048 */
> +
> + u32 reserved2[5]; /* FEC + 0x04C-05C */
> + u32 mib_data; /* FEC + 0x060 */
> + u32 mib_control; /* FEC + 0x064 */
> +
> + u32 reserved3[6]; /* FEC + 0x068-7C */
> + u32 r_activate; /* FEC + 0x080 */
> + u32 r_cntrl; /* FEC + 0x084 */
> + u32 r_hash; /* FEC + 0x088 */
> + u32 r_data; /* FEC + 0x08C */
> + u32 ar_done; /* FEC + 0x090 */
> + u32 r_test; /* FEC + 0x094 */
> + u32 r_mib; /* FEC + 0x098 */
> + u32 r_da_low; /* FEC + 0x09C */
> + u32 r_da_high; /* FEC + 0x0A0 */
> +
> + u32 reserved4[7]; /* FEC + 0x0A4-0BC */
> + u32 x_activate; /* FEC + 0x0C0 */
> + u32 x_cntrl; /* FEC + 0x0C4 */
> + u32 backoff; /* FEC + 0x0C8 */
> + u32 x_data; /* FEC + 0x0CC */
> + u32 x_status; /* FEC + 0x0D0 */
> + u32 x_mib; /* FEC + 0x0D4 */
> + u32 x_test; /* FEC + 0x0D8 */
> + u32 fdxfc_da1; /* FEC + 0x0DC */
> + u32 fdxfc_da2; /* FEC + 0x0E0 */
> + u32 paddr1; /* FEC + 0x0E4 */
> + u32 paddr2; /* FEC + 0x0E8 */
> + u32 op_pause; /* FEC + 0x0EC */
> +
> + u32 reserved5[4]; /* FEC + 0x0F0-0FC */
> + u32 instr_reg; /* FEC + 0x100 */
> + u32 context_reg; /* FEC + 0x104 */
> + u32 test_cntrl; /* FEC + 0x108 */
> + u32 acc_reg; /* FEC + 0x10C */
> + u32 ones; /* FEC + 0x110 */
> + u32 zeros; /* FEC + 0x114 */
> + u32 iaddr1; /* FEC + 0x118 */
> + u32 iaddr2; /* FEC + 0x11C */
> + u32 gaddr1; /* FEC + 0x120 */
> + u32 gaddr2; /* FEC + 0x124 */
> + u32 random; /* FEC + 0x128 */
> + u32 rand1; /* FEC + 0x12C */
> + u32 tmp; /* FEC + 0x130 */
> +
> + u32 reserved6[3]; /* FEC + 0x134-13C */
> + u32 fifo_id; /* FEC + 0x140 */
> + u32 x_wmrk; /* FEC + 0x144 */
> + u32 fcntrl; /* FEC + 0x148 */
> + u32 r_bound; /* FEC + 0x14C */
> + u32 r_fstart; /* FEC + 0x150 */
> + u32 r_count; /* FEC + 0x154 */
> + u32 r_lag; /* FEC + 0x158 */
> + u32 r_read; /* FEC + 0x15C */
> + u32 r_write; /* FEC + 0x160 */
> + u32 x_count; /* FEC + 0x164 */
> + u32 x_lag; /* FEC + 0x168 */
> + u32 x_retry; /* FEC + 0x16C */
> + u32 x_write; /* FEC + 0x170 */
> + u32 x_read; /* FEC + 0x174 */
> +
> + u32 reserved7[2]; /* FEC + 0x178-17C */
> + u32 fm_cntrl; /* FEC + 0x180 */
> + u32 rfifo_data; /* FEC + 0x184 */
> + u32 rfifo_status; /* FEC + 0x188 */
> + u32 rfifo_cntrl; /* FEC + 0x18C */
> + u32 rfifo_lrf_ptr; /* FEC + 0x190 */
> + u32 rfifo_lwf_ptr; /* FEC + 0x194 */
> + u32 rfifo_alarm; /* FEC + 0x198 */
> + u32 rfifo_rdptr; /* FEC + 0x19C */
> + u32 rfifo_wrptr; /* FEC + 0x1A0 */
> + u32 tfifo_data; /* FEC + 0x1A4 */
> + u32 tfifo_status; /* FEC + 0x1A8 */
> + u32 tfifo_cntrl; /* FEC + 0x1AC */
> + u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */
> + u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */
> + u32 tfifo_alarm; /* FEC + 0x1B8 */
> + u32 tfifo_rdptr; /* FEC + 0x1BC */
> + u32 tfifo_wrptr; /* FEC + 0x1C0 */
> +
> + u32 reset_cntrl; /* FEC + 0x1C4 */
> + u32 xmit_fsm; /* FEC + 0x1C8 */
> +
> + u32 reserved8[3]; /* FEC + 0x1CC-1D4 */
> + u32 rdes_data0; /* FEC + 0x1D8 */
> + u32 rdes_data1; /* FEC + 0x1DC */
> + u32 r_length; /* FEC + 0x1E0 */
> + u32 x_length; /* FEC + 0x1E4 */
> + u32 x_addr; /* FEC + 0x1E8 */
> + u32 cdes_data; /* FEC + 0x1EC */
> + u32 status; /* FEC + 0x1F0 */
> + u32 dma_control; /* FEC + 0x1F4 */
> + u32 des_cmnd; /* FEC + 0x1F8 */
> + u32 data; /* FEC + 0x1FC */
> +
> + u32 rmon_t_drop; /* FEC + 0x200 */
> + u32 rmon_t_packets; /* FEC + 0x204 */
> + u32 rmon_t_bc_pkt; /* FEC + 0x208 */
> + u32 rmon_t_mc_pkt; /* FEC + 0x20C */
> + u32 rmon_t_crc_align; /* FEC + 0x210 */
> + u32 rmon_t_undersize; /* FEC + 0x214 */
> + u32 rmon_t_oversize; /* FEC + 0x218 */
> + u32 rmon_t_frag; /* FEC + 0x21C */
> + u32 rmon_t_jab; /* FEC + 0x220 */
> + u32 rmon_t_col; /* FEC + 0x224 */
> + u32 rmon_t_p64; /* FEC + 0x228 */
> + u32 rmon_t_p65to127; /* FEC + 0x22C */
> + u32 rmon_t_p128to255; /* FEC + 0x230 */
> + u32 rmon_t_p256to511; /* FEC + 0x234 */
> + u32 rmon_t_p512to1023; /* FEC + 0x238 */
> + u32 rmon_t_p1024to2047; /* FEC + 0x23C */
> + u32 rmon_t_p_gte2048; /* FEC + 0x240 */
> + u32 rmon_t_octets; /* FEC + 0x244 */
> + u32 ieee_t_drop; /* FEC + 0x248 */
> + u32 ieee_t_frame_ok; /* FEC + 0x24C */
> + u32 ieee_t_1col; /* FEC + 0x250 */
> + u32 ieee_t_mcol; /* FEC + 0x254 */
> + u32 ieee_t_def; /* FEC + 0x258 */
> + u32 ieee_t_lcol; /* FEC + 0x25C */
> + u32 ieee_t_excol; /* FEC + 0x260 */
> + u32 ieee_t_macerr; /* FEC + 0x264 */
> + u32 ieee_t_cserr; /* FEC + 0x268 */
> + u32 ieee_t_sqe; /* FEC + 0x26C */
> + u32 t_fdxfc; /* FEC + 0x270 */
> + u32 ieee_t_octets_ok; /* FEC + 0x274 */
> +
> + u32 reserved9[2]; /* FEC + 0x278-27C */
> + u32 rmon_r_drop; /* FEC + 0x280 */
> + u32 rmon_r_packets; /* FEC + 0x284 */
> + u32 rmon_r_bc_pkt; /* FEC + 0x288 */
> + u32 rmon_r_mc_pkt; /* FEC + 0x28C */
> + u32 rmon_r_crc_align; /* FEC + 0x290 */
> + u32 rmon_r_undersize; /* FEC + 0x294 */
> + u32 rmon_r_oversize; /* FEC + 0x298 */
> + u32 rmon_r_frag; /* FEC + 0x29C */
> + u32 rmon_r_jab; /* FEC + 0x2A0 */
> +
> + u32 rmon_r_resvd_0; /* FEC + 0x2A4 */
> +
> + u32 rmon_r_p64; /* FEC + 0x2A8 */
> + u32 rmon_r_p65to127; /* FEC + 0x2AC */
> + u32 rmon_r_p128to255; /* FEC + 0x2B0 */
> + u32 rmon_r_p256to511; /* FEC + 0x2B4 */
> + u32 rmon_r_p512to1023; /* FEC + 0x2B8 */
> + u32 rmon_r_p1024to2047; /* FEC + 0x2BC */
> + u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */
> + u32 rmon_r_octets; /* FEC + 0x2C4 */
> + u32 ieee_r_drop; /* FEC + 0x2C8 */
> + u32 ieee_r_frame_ok; /* FEC + 0x2CC */
> + u32 ieee_r_crc; /* FEC + 0x2D0 */
> + u32 ieee_r_align; /* FEC + 0x2D4 */
> + u32 r_macerr; /* FEC + 0x2D8 */
> + u32 r_fdxfc; /* FEC + 0x2DC */
> + u32 ieee_r_octets_ok; /* FEC + 0x2E0 */
> +
> + u32 reserved10[7]; /* FEC + 0x2E4-2FC */
> +
> + u32 reserved11[64]; /* FEC + 0x300-3FF */
> +};
> +
> +#define FEC_MIB_DISABLE 0x80000000
> +
> +#define FEC_IEVENT_HBERR 0x80000000
> +#define FEC_IEVENT_BABR 0x40000000
> +#define FEC_IEVENT_BABT 0x20000000
> +#define FEC_IEVENT_GRA 0x10000000
> +#define FEC_IEVENT_TFINT 0x08000000
> +#define FEC_IEVENT_MII 0x00800000
> +#define FEC_IEVENT_LATE_COL 0x00200000
> +#define FEC_IEVENT_COL_RETRY_LIM 0x00100000
> +#define FEC_IEVENT_XFIFO_UN 0x00080000
> +#define FEC_IEVENT_XFIFO_ERROR 0x00040000
> +#define FEC_IEVENT_RFIFO_ERROR 0x00020000
> +
> +#define FEC_IMASK_HBERR 0x80000000
> +#define FEC_IMASK_BABR 0x40000000
> +#define FEC_IMASK_BABT 0x20000000
> +#define FEC_IMASK_GRA 0x10000000
> +#define FEC_IMASK_MII 0x00800000
> +#define FEC_IMASK_LATE_COL 0x00200000
> +#define FEC_IMASK_COL_RETRY_LIM 0x00100000
> +#define FEC_IMASK_XFIFO_UN 0x00080000
> +#define FEC_IMASK_XFIFO_ERROR 0x00040000
> +#define FEC_IMASK_RFIFO_ERROR 0x00020000
> +
> +/* all but MII, which is enabled separately */
> +#define FEC_IMASK_ENABLE (FEC_IMASK_HBERR | FEC_IMASK_BABR | \
> + FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_LATE_COL | \
> + FEC_IMASK_COL_RETRY_LIM | FEC_IMASK_XFIFO_UN | \
> + FEC_IMASK_XFIFO_ERROR | FEC_IMASK_RFIFO_ERROR)
> +
> +#define FEC_RCNTRL_MAX_FL_SHIFT 16
> +#define FEC_RCNTRL_LOOP 0x01
> +#define FEC_RCNTRL_DRT 0x02
> +#define FEC_RCNTRL_MII_MODE 0x04
> +#define FEC_RCNTRL_PROM 0x08
> +#define FEC_RCNTRL_BC_REJ 0x10
> +#define FEC_RCNTRL_FCE 0x20
> +
> +#define FEC_TCNTRL_GTS 0x00000001
> +#define FEC_TCNTRL_HBC 0x00000002
> +#define FEC_TCNTRL_FDEN 0x00000004
> +#define FEC_TCNTRL_TFC_PAUSE 0x00000008
> +#define FEC_TCNTRL_RFC_PAUSE 0x00000010
> +
> +#define FEC_ECNTRL_RESET 0x00000001
> +#define FEC_ECNTRL_ETHER_EN 0x00000002
> +
> +#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
> +#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
> +#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
> +#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
> +#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
> +#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
> +#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */
> +
> +#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
> +#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
> +
> +#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
> +#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
> +
> +#define FEC_PADDR2_TYPE 0x8808
> +
> +#define FEC_OP_PAUSE_OPCODE 0x00010000
> +
> +#define FEC_FIFO_WMRK_256B 0x3
> +
> +#define FEC_FIFO_STATUS_ERR 0x00400000
> +#define FEC_FIFO_STATUS_UF 0x00200000
> +#define FEC_FIFO_STATUS_OF 0x00100000
> +
> +#define FEC_FIFO_CNTRL_FRAME 0x08000000
> +#define FEC_FIFO_CNTRL_LTG_7 0x07000000
> +
> +#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000
> +#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000
> +
> +#define FEC_XMIT_FSM_APPEND_CRC 0x02000000
> +#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000
> +
> +
> +extern struct of_platform_driver mpc52xx_fec_mdio_driver;
> +
> +#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */
> Index: linux.git/drivers/net/fec_mpc52xx_phy.c
> ===================================================================
> --- /dev/null
> +++ linux.git/drivers/net/fec_mpc52xx_phy.c
> @@ -0,0 +1,198 @@
> +/*
> + * Driver for the MPC5200 Fast Ethernet Controller - MDIO bus driver
> + *
> + * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/phy.h>
> +#include <linux/of_platform.h>
> +#include <asm/io.h>
> +#include <asm/mpc52xx.h>
> +#include "fec_mpc52xx.h"
> +
> +struct mpc52xx_fec_mdio_priv {
> + struct mpc52xx_fec __iomem *regs;
> +};
> +
> +static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
> +{
> + struct mpc52xx_fec_mdio_priv *priv = bus->priv;
> + struct mpc52xx_fec __iomem *fec;
> + int tries = 100;
> + u32 request = FEC_MII_READ_FRAME;
> +
> + fec = priv->regs;
> + out_be32(&fec->ievent, FEC_IEVENT_MII);
> +
> + request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> + request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> + out_be32(&priv->regs->mii_data, request);
> +
> + /* wait for it to finish, this takes about 23 us on lite5200b */
> + while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
> + udelay(5);
> +
> + if (tries == 0)
> + return -ETIMEDOUT;
> +
> + return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
> +}
> +
> +static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
> +{
> + struct mpc52xx_fec_mdio_priv *priv = bus->priv;
> + struct mpc52xx_fec __iomem *fec;
> + u32 value = data;
> + int tries = 100;
> +
> + fec = priv->regs;
> + out_be32(&fec->ievent, FEC_IEVENT_MII);
> +
> + value |= FEC_MII_WRITE_FRAME;
> + value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
> + value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
> +
> + out_be32(&priv->regs->mii_data, value);
> +
> + /* wait for request to finish */
> + while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
> + udelay(5);
> +
> + if (tries == 0)
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
> +{
> + struct device *dev = &of->dev;
> + struct device_node *np = of->node;
> + struct device_node *child = NULL;
> + struct mii_bus *bus;
> + struct mpc52xx_fec_mdio_priv *priv;
> + struct resource res = {};
> + int err;
> + int i;
> +
> + bus = kzalloc(sizeof(*bus), GFP_KERNEL);
> + if (bus == NULL)
> + return -ENOMEM;
> + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> + if (priv == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> +
> + bus->name = "mpc52xx MII bus";
> + bus->read = mpc52xx_fec_mdio_read;
> + bus->write = mpc52xx_fec_mdio_write;
> +
> + /* setup irqs */
> + bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
> + if (bus->irq == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + bus->irq[i] = PHY_POLL;
> +
> + while ((child = of_get_next_child(np, child)) != NULL) {
> + int irq = irq_of_parse_and_map(child, 0);
> + if (irq != NO_IRQ) {
> + const u32 *id = of_get_property(child, "reg", NULL);
> + bus->irq[*id] = irq;
> + }
> + }
> +
> + /* setup registers */
> + err = of_address_to_resource(np, 0, &res);
> + if (err)
> + goto out_free;
> + priv->regs = ioremap(res.start, res.end - res.start + 1);
> + if (priv->regs == NULL) {
> + err = -ENOMEM;
> + goto out_free;
> + }
> +
> + bus->id = res.start;
> + bus->priv = priv;
> +
> + bus->dev = dev;
> + dev_set_drvdata(dev, bus);
> +
> + /* set MII speed */
> + out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
> +
> + /* enable MII interrupt */
> + out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
> +
> + err = mdiobus_register(bus);
> + if (err)
> + goto out_unmap;
> +
> + return 0;
> +
> + out_unmap:
> + iounmap(priv->regs);
> + out_free:
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + if (bus->irq[i] != PHY_POLL)
> + irq_dispose_mapping(bus->irq[i]);
> + kfree(bus->irq);
> + kfree(priv);
> + kfree(bus);
> +
> + return err;
> +}
> +
> +static int mpc52xx_fec_mdio_remove(struct of_device *of)
> +{
> + struct device *dev = &of->dev;
> + struct mii_bus *bus = dev_get_drvdata(dev);
> + struct mpc52xx_fec_mdio_priv *priv = bus->priv;
> + int i;
> +
> + mdiobus_unregister(bus);
> + dev_set_drvdata(dev, NULL);
> +
> + iounmap(priv->regs);
> + for (i=0; i<PHY_MAX_ADDR; i++)
> + if (bus->irq[i])
> + irq_dispose_mapping(bus->irq[i]);
> + kfree(priv);
> + kfree(bus->irq);
> + kfree(bus);
> +
> + return 0;
> +}
> +
> +
> +static struct of_device_id mpc52xx_fec_mdio_match[] = {
> + {
> + .type = "mdio",
> + .compatible = "mpc5200b-fec-phy",
> + },
> + {},
> +};
> +
> +struct of_platform_driver mpc52xx_fec_mdio_driver = {
> + .name = "mpc5200b-fec-phy",
> + .probe = mpc52xx_fec_mdio_probe,
> + .remove = mpc52xx_fec_mdio_remove,
> + .match_table = mpc52xx_fec_mdio_match,
> +};
> +
> +/* let fec driver call it, since this has to be registered before it */
> +EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
> +
> +
> +MODULE_LICENSE("Dual BSD/GPL");
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 05/11] [POWERPC] TQM5200 DTS
From: Martin Krause @ 2007-10-25 9:57 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20071023231333.29359.35252.stgit@hekate.izotz.org>
< + flash@00000000 {
< + compatible = "cfi-flash";
< + reg = <00000000 02000000>;
< + bank-width = <4>;
< + device-width = <2>;
< + #size-cells = <1>;
< + #address-cells = <1>;
< + partition@0 {
< + label = "firmware";
< + reg = <0 a0000>;
< + };
< + partition@a0000 {
< + label = "dtb";
< + reg = <a0000 20000>;
< + };
< + partition@c0000 {
< + label = "kernel";
< + reg = <c0000 240000>;
< + };
< + partition@300000 {
< + label = "initrd";
< + reg = <300000 200000>;
< + };
< + partition@500000 {
< + label = "small-fs";
< + reg = <500000 400000>;
< + };
< + partition@900000 {
< + label = "misc";
< + reg = <900000 800000>;
< + };
< + partition@1100000 {
< + label = "big-fs";
< + reg = <1100000 f00000>;
< + };
< + };
< + };
This MTD layout only works on boards with 32 MiB (or 64 MiB) flash
memory. On TQM5200 boards with smaller Flashes (16 MiB, 8 MiB and 4 MiB)
the MTD partition borders do not match with the physikal memory borders.
On a board with 16 MiB FLASH for example the "big-fs" _and_ the "misc"
partition could not be used. "big-fs", because the memory is too small
(which is OK) and "misc", because it overlaps 1 MiB over the physikal
flash border. So only the first 9 MiB of the flash could be used in Linux.
The remaining 7 MiB couldn't be accessed.
I would propose a Flash layout, where the (filesystem) partitions end
on powers of two, to match the physical flash boarders:
partition@0 {
label = "firmware";
reg = <0 a0000>;
};
partition@a0000 {
label = "dtb";
reg = <a0000 20000>;
};
partition@c0000 {
label = "kernel";
reg = <c0000 180000>;
};
partition@240000 {
label = "initrd";
reg = <240000 1c0000>;
};
partition@400000 {
label = "small-fs";
reg = <400000 400000>;
};
partition@800000 {
label = "misc";
reg = <800000 800000>;
};
partition@1000000 {
label = "big-fs";
reg = <1000000 1000000>;
};
};
};
Best Regards,
Martin Krause
--
View this message in context: http://www.nabble.com/-PATCH-00-11---POWERPC--Add-TQM5200-CM5200-Motion-PRO-board-support-tf4680980.html#a13403420
Sent from the linuxppc-dev mailing list archive at Nabble.com.
^ permalink raw reply
* Re: [PATCH] wrapper: Revert ps3 binary flag usage, and remove .bin suffix.
From: Geert Uytterhoeven @ 2007-10-25 11:08 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, paulus
In-Reply-To: <20071024165628.GA13863@loki.buserror.net>
[-- Attachment #1: Type: TEXT/PLAIN, Size: 3412 bytes --]
On Wed, 24 Oct 2007, Scott Wood wrote:
> The ps3 target produces two images, and the binary one is not the
> "primary" image that corresponds to the -o flag; thus, it no longer
> uses the generic binary flag.
>
> On platforms which do use the binary flag, it no longer produces a
> .bin suffix, so that the output file matches what was passed to the -o flag.
>
> This should fix the zImage ln problems for the ps3 target.
>
> Signed-off-by: Scott Wood <scottwood@freescale.com>
Acked-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
> ---
> arch/powerpc/boot/wrapper | 13 +++++++------
> 1 files changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
> index 39b27e5..ece6f49 100755
> --- a/arch/powerpc/boot/wrapper
> +++ b/arch/powerpc/boot/wrapper
> @@ -149,7 +149,6 @@ cuboot*)
> ps3)
> platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
> lds=$object/zImage.ps3.lds
> - binary=y
> gzip=
> ext=bin
> objflags="-O binary --set-section-flags=.bss=contents,alloc,load,data"
> @@ -233,7 +232,7 @@ entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3`
>
> if [ -n "$binary" ]; then
> mv "$ofile" "$ofile".elf
> - ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin
> + ${CROSS}objcopy -O binary "$ofile".elf "$ofile"
> fi
>
> # post-processing needed for some platforms
> @@ -246,9 +245,9 @@ coff)
> $object/hack-coff "$ofile"
> ;;
> cuboot*)
> - gzip -f -9 "$ofile".bin
> + gzip -f -9 "$ofile"
> mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \
> - $uboot_version -d "$ofile".bin.gz "$ofile"
> + $uboot_version -d "$ofile".gz "$ofile"
> ;;
> treeboot*)
> mv "$ofile" "$ofile.elf"
> @@ -269,11 +268,11 @@ ps3)
> # then copied to offset 0x100. At runtime the bootwrapper program
> # copies the 0x100 bytes at __system_reset_kernel to addr 0x100.
>
> - system_reset_overlay=0x`${CROSS}nm "$ofile".elf \
> + system_reset_overlay=0x`${CROSS}nm "$ofile" \
> | grep ' __system_reset_overlay$' \
> | cut -d' ' -f1`
> system_reset_overlay=`printf "%d" $system_reset_overlay`
> - system_reset_kernel=0x`${CROSS}nm "$ofile".elf \
> + system_reset_kernel=0x`${CROSS}nm "$ofile" \
> | grep ' __system_reset_kernel$' \
> | cut -d' ' -f1`
> system_reset_kernel=`printf "%d" $system_reset_kernel`
> @@ -282,6 +281,8 @@ ps3)
>
> rm -f "$object/otheros.bld"
>
> + ${CROSS}objcopy -O binary "$ofile" "$ofile.bin"
> +
> msg=$(dd if="$ofile.bin" of="$ofile.bin" conv=notrunc \
> skip=$overlay_dest seek=$system_reset_kernel \
> count=$overlay_size bs=1 2>&1)
> --
> 1.5.3.4
>
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@sonycom.com
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox