LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: snd-aoa status update / automatic driver loading
From: Paul Collins @ 2006-05-19 13:20 UTC (permalink / raw)
  To: Johannes Berg; +Cc: list, Eddy Petrişor, debian-powerpc
In-Reply-To: <1147947784.15507.46.camel@johannes>

Johannes Berg <johannes@sipsolutions.net> writes:

> On Thu, 2006-05-18 at 10:25 +0300, Eddy Petri=C5=9For wrote:
>
>> Any chance for 5,2 ? What is needed for it? Codec only?
>
> I don't know. If you try loading the modules, the kernel will tell you
> something about an unhandled layout id. Alternatively, you can find the
> layout-id file in your /proc/device-tree/ and tell me the number in it.
> The rest I can figure out.

I have a PowerBook5,4 here and I'd be happy to test support for it.
The hardware is identified by snd-powermac as "PowerMac Snapper" and
the layout ID appears to be "3".

[briny(device-tree)] od -c pci@f2000000/mac-io@17/i2s@10000/i2s-a@10000/sou=
nd/layout-id
0000000  \0  \0  \0   3
0000004

--=20
Dag vijandelijk luchtschip de huismeester is dood

^ permalink raw reply

* Re: snd-aoa status update / automatic driver loading
From: Johannes Berg @ 2006-05-19 12:50 UTC (permalink / raw)
  To: Wolfgang Pfeiffer; +Cc: linuxppc-dev list, debian-powerpc
In-Reply-To: <20060518181748.GA2836@localhost>

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

On Thu, 2006-05-18 at 20:17 +0200, Wolfgang Pfeiffer wrote:

> BTW: Is there a way to let 'alsaconf' detect the soundcard on this
> PB5,8 ?
> So far that's impossible, as it seems. But this could also be
> related to mistakes I made in my modules files, or wherever.

No idea, but I don't see why you'd want alsaconf to figure it out if the
kernel can by itself...

johannes

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

^ permalink raw reply

* Re: PowerMac7,3 sound (was: PowerBook5,4 -- no sound?)
From: Johannes Berg @ 2006-05-19 12:47 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: linuxppc-dev
In-Reply-To: <jek68jqz1l.fsf@sykes.suse.de>

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

On Thu, 2006-05-18 at 14:48 +0200, Andreas Schwab wrote:

> Yes, that's while I had that loaded.  Of course, I unloaded it before I
> tried snd-aoa.

Ok, but is that the correct stuff, i.e. does it work?

johannes

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

^ permalink raw reply

* Re: snd-aoa status update / automatic driver loading
From: Johannes Berg @ 2006-05-19 10:22 UTC (permalink / raw)
  To: Tony Vroon; +Cc: linuxppc-dev list, Benjamin Berg, debian-powerpc
In-Reply-To: <446B721D.8020203@gentoo.org>

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

On Wed, 2006-05-17 at 19:57 +0100, Tony Vroon wrote:

> When writing documentation, you might want to add that the ALSA-plugin
> in XMMS & Audacious requires a period time of 100ms instead of the
> default of 50ms, as otherwise the sou*click*nd is n*click*ot ver*click*y
> good.
> (A look at the current code of that plugin, to see how the volume
> control code can be fixed would be highly appreciated)

How's that related to snd-aoa? You can currently buffer up to 131072
bytes which at 96KHz and 32 bits is ~171ms. At the regular 44100Hz/16bit
it is ~743ms. But you can easily increase that in i2sbus-pcm.c line
126ff:
        /* these are somewhat arbitrary */
        hw->buffer_bytes_max = 131072;
        hw->period_bytes_min = 256;
        hw->period_bytes_max = 16384;
The thing is just that this memory area is essentially mlock()ed so if I
did indeed allow 16k per period and 32 periods the stream would mlock
512K. What would others say is appropriate?

Ah then again I can see how this might be related to snd-aoa -- we only
update the pcm position on each period so maybe we should increase the
minimum number of periods. Can you try that? Go into i2sbus-pcm.c line
130 and change
        hw->periods_min = 3;
to maybe 6. Or just try binary search for  smallest value that makes it
work (if it ever does, but I think it should, if this is indeed the
issue). Indeed, at 50ms buffer you have just 8820 bytes which can even
be divided by 3 so that probably means that xmms used 3 periods. Maybe
that's a bit tight. Do you see the same issue with snd-powermac? (it
uses the same period setup)

> Not seen this, although I must say it does not resume from sleep as
> gracefully as I have seen you describe it.

What happens? I just fixed tas resume from sleep (by completely
re-initialising the codec) and something similar should be done for the
onyx probably (or do I do that already?) for suspend to disk, but other
than that... Oh I just realised that it'll lose some sound due to
restarting the dma command ring at the beginning. Hmm. I suppose I can
change that easily, will have to do some testing.

Benjamin (Berg), can we do that even with the lost interrupt issue?

Maybe both of these issues can be fixed by using the frame count
register instead to count how many samples were played? Below is a small
patch to print out a lot of frame count numbers, Benjamin, I'd
appreciate if you could look how this interacted with the lost
interrupts.

Note that for this to work we'd of course have to sample the frame count
register right before starting the DMA engine, it increases even while
we're not playing because we don't stop the clocks. We probably should
do that too for powersaving. Humm. Lots to do :) Oh and this probably
means that yes, it works fine even when we do lose interrupts. 

Alternatively we could use the register just to detect if we lost
interrupts, i.e. calculate how many frames we have per period and then
see if the frame count increased approximately by that much (I've seen
+- a few frames probably due to timing, with higher samplerates we'll
probably see a bit more error) and if it increased by much more we could
estimate how many interrupts we lost. What do you think?

johannes

--- snd-aoa.orig/soundbus/i2sbus/i2sbus-pcm.c	2006-05-19 12:10:16.919474526 +0200
+++ snd-aoa/soundbus/i2sbus/i2sbus-pcm.c	2006-05-19 12:11:22.119474526 +0200
@@ -488,12 +488,17 @@ static snd_pcm_uframes_t i2sbus_pcm_poin
 static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
 {
 	struct pcm_info *pi;
+	u32 fc;
 
 	get_pcm_info(i2sdev, in, &pi, NULL);
 	if (!pi->substream) {
 		printk(KERN_INFO "i2sbus: got %s irq while not active!\n", in?"rx":"tx");
 		return;
 	}
+	fc = in_le32(&i2sdev->intfregs->frame_count);
+	printk(KERN_DEBUG "i2sbus: frame count is %d\n", fc);
+	printk(KERN_DEBUG "i2sbus: delta fc = %d\n", fc - i2sdev->fc);
+	i2sdev->fc = fc;
 	pi->current_period = (pi->current_period+1) % (pi->periods);
 	snd_pcm_period_elapsed(pi->substream);
 }
--- snd-aoa.orig/soundbus/i2sbus/i2sbus.h	2006-05-19 12:10:16.919474526 +0200
+++ snd-aoa/soundbus/i2sbus/i2sbus.h	2006-05-19 12:11:22.119474526 +0200
@@ -50,6 +50,7 @@ struct i2sbus_dev {
 	struct macio_dev *macio;
 	struct i2sbus_control *control;
 	volatile struct i2s_interface_regs __iomem *intfregs;
+	u32 fc;
 
 	int resource_allocated; /* bitmask of resources */
 	struct resource resources[3];


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

^ permalink raw reply

* i2sbus transfer foo
From: Johannes Berg @ 2006-05-19 11:36 UTC (permalink / raw)
  To: linuxppc-dev list

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

Sorry for the vague subject :) I don't really know what to say...

Let me introduce some things first. First of all, the i2sbus controllers
Apple has in their mac-io chip are capable of doing (among others we
don't care about) 16-bit transfers in 32x and 64x i2s modes, and 24-bit
transfers in 64x i2s mode. For the latter, the chip requires that the
inputs are actually 32-bit aligned, which means that it's a bit weird
that it doesn't actually transfer all the 32 bits. But that's another
issue, maybe there's a way to make it transfer 32 bits that I don't
know. Or maybe it even does and we just don't have a codec capable of
using or creating data in those remaining 8 bits.

Anyway, let's dive right in, here's a sample capture where I was
capturing an 880Hz sine wave generated with gstreamer on another machine
via a direct cable:

00007910  f8 36 48 00 f7 a1 cc 00  f7 a1 cc 00 f7 2e ea 00  |.6H.............|
00007920  f7 2e ea 00 f6 df 58 00  f6 df 58 00 f6 b4 ee 00  |......X...X.....|
00007930  f6 b4 ee 00 f6 af 78 00  f6 af 78 00 f6 cf 59 00  |......x...x...Y.|

The hexdump above is directly from the DMA memory area, not gone through
alsa, I made a debugfs file that gives me access to the buffer area
straight away.

Let me start arecord again:
$ arecord -r 44100 -f S32_LE -c2 > /tmp/test.wav

Dumping the dma area again yields:
00008680  e4 00 ff bd e4 00 fe 93  22 00 fe 93 22 00 fd 6f  |........"..."..o|
00008690  2b 00 fd 6f 2b 00 fc 55  62 00 fc 55 62 00 fb 49  |+..o+..Ub..Ub..I|
000086a0  76 00 fb 49 76 00 fa 52  49 00 fa 52 49 00 f9 71  |v..Iv..RI..RI..q|
000086b0  1f 00 f9 71 1f 00 f8 aa  2c 00 f8 aa 2c 00 f7 ff  |...q....,...,...|
and a 3rd time:
0000ff60  00 07 3a 12 00 06 6f 77  00 06 6f 77 00 05 89 d9  |..:...ow..ow....|
0000ff70  00 05 89 d9 00 04 8e 73  00 04 8e 73 00 03 80 4a  |.......s...s...J|
0000ff80  00 03 80 4a 00 02 64 b0  00 02 64 b0 00 01 3e c0  |...J..d...d...>.|
0000ff90  00 01 3e c0 00 00 16 65  00 00 16 65 00 fe ea b6  |..>....e...e....|
4th time it's like 3rd, 5th like first, but 6th time:
0000bc60  e8 39 00 00 13 60 00 00  13 60 00 01 3d 96 00 01  |.9...`...`..=...|
0000bc70  3d 96 00 02 63 55 00 02  63 55 00 03 7f f5 00 03  |=...cU..cU......|
0000bc80  7f f5 00 04 8b 73 00 04  8b 73 00 05 87 84 00 05  |.....s...s......|
0000bc90  87 84 00 06 6d cc 00 06  6d cc 00 07 37 ae 00 07  |....m...m...7...|

See the problem?

When I actually manage to have it aligned like in #3 above,
SNDRV_PCM_FORMAT_S24_BE would be correct. And in that case, I once even
got a nice wav file that audacity can downsample to 16 bit and play
properly. But in all other cases I get mangled sound for obvious
reasons.

The correct data layout seems to be the first though, because when I
transfer that *to* the chip for playback (by making i2sbus announce
32bit big-endian format to alsa) I get proper sound with the correct
volume, hence I just changed i2sbus to always announce 16 and 32-bit BE
formats which also no longer mangles sound with gstreamer (except for
clicking every once a while on some streams[1]).

Oh, and note that those 4 cases aren't all possible cases. If you think
about it you'll notice that there are 8 cases because we have two
channels. I think I even mixed them in the dumps above, not sure.

Some looking at snd-powermac code later I now changed the i2sbus code to
do a dbdma-programmed engine stop in hope that would synchronize (as a
comment in snd-powermac implies) but that doesn't seem to be correct
either. I now more often get the first case though not all the time.

I'm out of ideas. I don't have a clue how to get this thing synchronized
properly. If anyone has a solution let me know, otherwise I'll probably
just disable 24-bit recording for good, then at least the chances of
getting sound that makes sense (even if left and right might be
switched) are 1/2 as opposed to 1/4 assuming even distribution... Also,
the question is why this does not happen on playback, or at least so
much less frequently that I haven't seen it yet...

johannes

[1] only happens with gstreamer on some streams, and then only if I use
alsasink without giving it the latency-time option, even if I give it
the default it doesn't click. very strange.

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

^ permalink raw reply

* Re: [Cbe-oss-dev] Cell and new CPU feature bits
From: Arnd Bergmann @ 2006-05-19 10:11 UTC (permalink / raw)
  To: cbe-oss-dev; +Cc: linuxppc-dev list
In-Reply-To: <1148011621.13249.7.camel@localhost.localdomain>

On Friday 19 May 2006 06:07, Benjamin Herrenschmidt wrote:
>  - Extended implementation of dcbt. (Another bit ? Or sould we just have
> a "CELL" bit ? In which case should it cover the altivec additions too
> or are those likely to exist in future non-Cell processors ?)

Isn't that already covered by PPC_FEATURE_CELL? Git log shows

| commit a7ddc5e85351931b67a48afa22788d77763837d8
| Author: Paul Mackerras <paulus@samba.org>
| Date:   Thu Nov 10 14:29:18 2005 +1100
|
|    powerpc: Add user CPU features for POWER4, POWER5, POWER5+ and Cell.
|
|    This is at the request of the glibc folks, who want to use these bits
|    to select libraries optimized for the microarchitecture and new
|    instructions in these processors.
|
|    Signed-off-by: Paul Mackerras <paulus@samba.org>

	Arnd <><

^ permalink raw reply

* Re: Cell and new CPU feature bits
From: Gabriel Paubert @ 2006-05-19  8:16 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Paul Mackerras, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <1148011621.13249.7.camel@localhost.localdomain>

On Fri, May 19, 2006 at 02:07:01PM +1000, Benjamin Herrenschmidt wrote:
> The Cell has a couple of "features" that should be exposed to userland
> in a way or another. That raises some questions however about how those
> should be done. Among others that come to mind:
> 
>  - The timebase errata (should we use a separate aux vector for "bugs"
> than for "features" ?

Is this bug really going to be exposed in the wild or is it
an early silicon bug that will only bite early-testers?

>  - Additional Altivec instructions (load/store right/left). A new
> feature bit for these ?

Yes. So IBM was not happy with Altivec instructions to generate
vsel control words and got their inspiration from MIPS?

>  - Lack of data stream instructions. Until now, it was assumed that
> those were tied to the presence
>    of an Altivec (and they are documented in the Altivec manual). Maybe
> we should split that to a
>    new bit. I don't know if existing applications use them though, if
> they do, there will be a 
>    problem to get them updated as the new bit isn't present on older
> kernels...

Is it really important? These instructions become nop on Cell, so their
impact on performance should be minimal while they may be useful in
code designed to run on any processor having Altivec.

>  - Extended implementation of dcbt. (Another bit ? Or sould we just have
> a "CELL" bit ? In which
>    case should it cover the altivec additions too or are those likely to
> exist in future non-Cell 
>    processors ?)

I believe that a Cell bit would be useful. After all you need a bit
that tell you that you have the SPUs and related infrastructure?

>  - Not strictly Cell specific but we currently don't expose the support
> for optional instructions
>    fres and frsqte (which are supported by Cell)

Should be exposed IMHO. But these instructions have been present
in a lot of PPC processors AFAIR, they are in my original 603 and
604 manuals from 1994 (fsel is also marked as optional and is not
implemented on the 601, but I'm not sure it's really supported
anymore). I don't know about Power processors. 

> Part of the problem is that we only have 32 userland feature bits and
> for some reason decided to put the microarchitecture in there, thus we
> are running out fast...

It will have to be extended and perhaps become a variable length
structure, better sooner than later.

	Regards,
	Gabriel

^ permalink raw reply

* Re: MPC8xx: resolution of gettimeofday() ?
From: Steven Scholz @ 2006-05-19  8:08 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <20060518164812.GA21075@gate.ebshome.net>

Eugene,

>> what is the resolution of gettimeofday() for an MPC8xx?
>>
>> IIUC then the "decrementer" is used to generate the timer interrupts every 10ms.
>>
>> This decrementer runs at cpuclk/16. Thus with 80MHz CPU clock has a
>> resolution of 16/80MHz = 200ns and overflows every 50000 ticks.
>>
>> But is this decrementer used to update xtime?
>> Will gettimeofday() have a resolution of 200ns?
>>
>> How about linux 2.4 where xtime is a "struct timeval" rather then "struct
>> timespec"?
>>
> 
> Usually on PPC we use timebase to interpolate time between Decrementer 
> interrupts. In this case gettimeofday resolution is determined by 
> timebase resolution which is quite high (megahertz range).

Sorry. I don't understand. What do you mean with "timebase"? Is there a
second timer/counter?

-- 
Steven

^ permalink raw reply

* Re: [Cbe-oss-dev] Cell and new CPU feature bits
From: Segher Boessenkool @ 2006-05-19  7:49 UTC (permalink / raw)
  To: Andrew Pinski
  Cc: Olof Johansson, linuxppc-dev list, cbe-oss-dev, Arnd Bergmann
In-Reply-To: <11D4E003-85A4-48A0-9654-BEAE5600B89C@physics.uc.edu>

>> I'm assuming you mean the instructions described under "AltiVec  
>> Memory
>> Bandwidth Management" in secion 5.2 of the Altivec PEM -- dst, dstt,
>> dstst, dss and dssall?
>
> They are nops on the Cell though.

And that is a compliant implementation.  I don't see a need
or real use for a feature bit here, esp. if we do get one for
the extended dcbt insns (which often are used as a replacement
for the data streaming insns).

> They are also microcoded on the 970.

No, they are cracked, instead.  Much lower hit.  They are completion
serialized though, so the only insn in an issue group, etc.


Segher

^ permalink raw reply

* [PATCH 14/14] powerpc: cleanup of iSeries flat device tree
From: Stephen Rothwell @ 2006-05-19  7:06 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

Consolidate the vio device node creation.  Make some parameters const.
Make a few more things __initdata. Get the device_type strings out of
the device tree blob.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/dt.c |  199 ++++++++++++++++++-----------------
 1 files changed, 101 insertions(+), 98 deletions(-)

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

89435c92f9a6d37d8d47bf40acde012726780f7f
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
index 2a51ec1..d3444aa 100644
--- a/arch/powerpc/platforms/iseries/dt.c
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -47,16 +47,34 @@ #else
 #define DBG(fmt...)
 #endif
 
+/*
+ * These are created by the linker script at the start and end
+ * of the section containing all the strings from this file.
+ */
 extern char __dt_strings_start[];
 extern char __dt_strings_end[];
 
 struct iseries_flat_dt {
 	struct boot_param_header header;
 	u64 reserve_map[2];
-	void *data;
 };
 
-static struct iseries_flat_dt *iseries_dt;
+static void * __initdata dt_data;
+
+/*
+ * Putting these strings here keeps them out of the section
+ * that we rename to .dt_strings using objcopy and capture
+ * for the strings blob of the flattened device tree.
+ */
+static char __initdata device_type_cpu[] = "cpu";
+static char __initdata device_type_memory[] = "memory";
+static char __initdata device_type_serial[] = "serial";
+static char __initdata device_type_network[] = "network";
+static char __initdata device_type_block[] = "block";
+static char __initdata device_type_byte[] = "byte";
+static char __initdata device_type_pci[] = "pci";
+static char __initdata device_type_vdevice[] = "vdevice";
+static char __initdata device_type_vscsi[] = "vscsi";
 
 static struct iseries_flat_dt * __init dt_init(void)
 {
@@ -70,7 +88,7 @@ static struct iseries_flat_dt * __init d
 	dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);
 	dt->header.off_dt_struct = dt->header.off_dt_strings
 		+ ALIGN(str_len, 8);
-	dt->data = (void *)((unsigned long)dt + dt->header.off_dt_struct);
+	dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct);
 	dt->header.dt_strings_size = str_len;
 
 	/* There is no notion of hardware cpu id on iSeries */
@@ -91,26 +109,26 @@ static struct iseries_flat_dt * __init d
 
 static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
 {
-	*((u32 *)dt->data) = value;
-	dt->data += sizeof(u32);
+	*((u32 *)dt_data) = value;
+	dt_data += sizeof(u32);
 }
 
 #ifdef notyet
 static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
 {
-	*((u64 *)dt->data) = value;
-	dt->data += sizeof(u64);
+	*((u64 *)dt_data) = value;
+	dt_data += sizeof(u64);
 }
 #endif
 
-static void __init dt_push_bytes(struct iseries_flat_dt *dt, char *data,
+static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data,
 		int len)
 {
-	memcpy(dt->data, data, len);
-	dt->data += ALIGN(len, 4);
+	memcpy(dt_data, data, len);
+	dt_data += ALIGN(len, 4);
 }
 
-static void __init dt_start_node(struct iseries_flat_dt *dt, char *name)
+static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name)
 {
 	dt_push_u32(dt, OF_DT_BEGIN_NODE);
 	dt_push_bytes(dt, name, strlen(name) + 1);
@@ -118,8 +136,8 @@ static void __init dt_start_node(struct 
 
 #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
 
-static void __init dt_prop(struct iseries_flat_dt *dt, char *name,
-		void *data, int len)
+static void __init dt_prop(struct iseries_flat_dt *dt, const char *name,
+		const void *data, int len)
 {
 	unsigned long offset;
 
@@ -137,36 +155,40 @@ static void __init dt_prop(struct iserie
 	dt_push_bytes(dt, data, len);
 }
 
-static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name,
-		char *data)
+static void __init dt_prop_str(struct iseries_flat_dt *dt, const char *name,
+		const char *data)
 {
 	dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
 }
 
-static void __init dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
+static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
+		u32 data)
 {
 	dt_prop(dt, name, &data, sizeof(u32));
 }
 
-static void __init dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
+#ifdef notyet
+static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name,
+		u64 data)
 {
 	dt_prop(dt, name, &data, sizeof(u64));
 }
+#endif
 
-static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, char *name,
-		u64 *data, int n)
+static void __init dt_prop_u64_list(struct iseries_flat_dt *dt,
+		const char *name, u64 *data, int n)
 {
 	dt_prop(dt, name, data, sizeof(u64) * n);
 }
 
-static void __init dt_prop_u32_list(struct iseries_flat_dt *dt, char *name,
-		u32 *data, int n)
+static void __init dt_prop_u32_list(struct iseries_flat_dt *dt,
+		const char *name, u32 *data, int n)
 {
 	dt_prop(dt, name, data, sizeof(u32) * n);
 }
 
 #ifdef notyet
-static void __init dt_prop_empty(struct iseries_flat_dt *dt, char *name)
+static void __init dt_prop_empty(struct iseries_flat_dt *dt, const char *name)
 {
 	dt_prop(dt, name, NULL, 0);
 }
@@ -199,7 +221,7 @@ static void __init dt_cpus(struct iserie
 		snprintf(p, 32 - (p - buf), "@%d", i);
 		dt_start_node(dt, buf);
 
-		dt_prop_str(dt, "device_type", "cpu");
+		dt_prop_str(dt, "device_type", device_type_cpu);
 
 		index = lppaca[i].dyn_hv_phys_proc_index;
 		d = &xIoHriProcessorVpd[index];
@@ -244,32 +266,41 @@ static void __init dt_model(struct iseri
 	dt_prop_str(dt, "compatible", "IBM,iSeries");
 }
 
+static void __init dt_do_vdevice(struct iseries_flat_dt *dt,
+		const char *name, u32 reg, int unit,
+		const char *type, const char *compat, int end)
+{
+	char buf[32];
+
+	snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0));
+	dt_start_node(dt, buf);
+	dt_prop_str(dt, "device_type", type);
+	if (compat)
+		dt_prop_str(dt, "compatible", compat);
+	dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0));
+	if (unit >= 0)
+		dt_prop_u32(dt, "linux,unit_address", unit);
+	if (end)
+		dt_end_node(dt);
+}
+
 static void __init dt_vdevices(struct iseries_flat_dt *dt)
 {
 	u32 reg = 0;
 	HvLpIndexMap vlan_map;
 	int i;
-	char buf[32];
 
 	dt_start_node(dt, "vdevice");
-	dt_prop_str(dt, "device_type", "vdevice");
+	dt_prop_str(dt, "device_type", device_type_vdevice);
 	dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");
 	dt_prop_u32(dt, "#address-cells", 1);
 	dt_prop_u32(dt, "#size-cells", 0);
 
-	snprintf(buf, sizeof(buf), "vty@%08x", reg);
-	dt_start_node(dt, buf);
-	dt_prop_str(dt, "device_type", "serial");
-	dt_prop_u32(dt, "reg", reg);
-	dt_end_node(dt);
+	dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, NULL, 1);
 	reg++;
 
-	snprintf(buf, sizeof(buf), "v-scsi@%08x", reg);
-	dt_start_node(dt, buf);
-	dt_prop_str(dt, "device_type", "vscsi");
-	dt_prop_str(dt, "compatible", "IBM,v-scsi");
-	dt_prop_u32(dt, "reg", reg);
-	dt_end_node(dt);
+	dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,
+			"IBM,v-scsi", 1);
 	reg++;
 
 	vlan_map = HvLpConfig_getVirtualLanIndexMap();
@@ -278,13 +309,8 @@ static void __init dt_vdevices(struct is
 
 		if ((vlan_map & (0x8000 >> i)) == 0)
 			continue;
-		snprintf(buf, 32, "l-lan@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "network");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-l-lan");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-
+		dt_do_vdevice(dt, "l-lan", reg, i, device_type_network,
+				"IBM,iSeries-l-lan", 0);
 		mac_addr[0] = 0x02;
 		mac_addr[1] = 0x01;
 		mac_addr[2] = 0xff;
@@ -300,47 +326,31 @@ static void __init dt_vdevices(struct is
 	}
 	reg += HVMAXARCHITECTEDVIRTUALLANS;
 
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) {
-		snprintf(buf, 32, "viodasd@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "block");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-viodasd");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-		dt_end_node(dt);
-	}
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
+		dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
+				"IBM,iSeries-viodasd", 1);
 	reg += HVMAXARCHITECTEDVIRTUALDISKS;
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) {
-		snprintf(buf, 32, "viocd@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "block");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-viocd");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-		dt_end_node(dt);
-	}
+
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
+		dt_do_vdevice(dt, "viocd", reg, i, device_type_block,
+				"IBM,iSeries-viocd", 1);
 	reg += HVMAXARCHITECTEDVIRTUALCDROMS;
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) {
-		snprintf(buf, 32, "viotape@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "byte");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-viotape");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-		dt_end_node(dt);
-	}
+
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
+		dt_do_vdevice(dt, "viotape", reg, i, device_type_byte,
+				"IBM,iSeries-viotape", 1);
 
 	dt_end_node(dt);
 }
 
 struct pci_class_name {
 	u16 code;
-	char *name;
-	char *type;
+	const char *name;
+	const char *type;
 };
 
 static struct pci_class_name __initdata pci_class_name[] = {
-	{ PCI_CLASS_NETWORK_ETHERNET, "ethernet", "network" },
+	{ PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network },
 };
 
 static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
@@ -384,9 +394,7 @@ static void __init scan_bridge_slot(stru
 					agent_id, 0);
 			if (err) {
 				if (err != 0x302)
-					printk(KERN_DEBUG
-						"connectBusUnit(%x, %x, %x) "
-						"== %x\n",
+					DBG("connectBusUnit(%x, %x, %x) %x\n",
 						bus, sub_bus, agent_id, err);
 				continue;
 			}
@@ -394,24 +402,21 @@ static void __init scan_bridge_slot(stru
 			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
 					PCI_VENDOR_ID, &vendor_id);
 			if (err) {
-				printk(KERN_DEBUG
-					"ReadVendor(%x, %x, %x) == %x\n",
+				DBG("ReadVendor(%x, %x, %x) %x\n",
 					bus, sub_bus, agent_id, err);
 				continue;
 			}
 			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
 					PCI_DEVICE_ID, &device_id);
 			if (err) {
-				printk(KERN_DEBUG
-					"ReadDevice(%x, %x, %x) == %x\n",
+				DBG("ReadDevice(%x, %x, %x) %x\n",
 					bus, sub_bus, agent_id, err);
 				continue;
 			}
 			err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
 					PCI_CLASS_REVISION , &class_id);
 			if (err) {
-				printk(KERN_DEBUG
-					"ReadClass(%x, %x, %x) == %x\n",
+				DBG("ReadClass(%x, %x, %x) %x\n",
 					bus, sub_bus, agent_id, err);
 				continue;
 			}
@@ -470,19 +475,18 @@ static void __init scan_bridge(struct is
 		ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
 		if (ret != 0) {
 			if (ret != 0xb)
-				printk(KERN_DEBUG "connectBusUnit(%x, %x, %x) "
-						"== %x\n",
+				DBG("connectBusUnit(%x, %x, %x) %x\n",
 						bus, sub_bus, agent_id, ret);
 			continue;
 		}
-		printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
+		DBG("found device at bus %d idsel %d func %d (AgentId %x)\n",
 				bus, id_sel, function, agent_id);
 		ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
 				iseries_hv_addr(&bridge_info),
 				sizeof(struct HvCallPci_BridgeInfo));
 		if (ret != 0)
 			continue;
-		printk("bridge info: type %x subbus %x "
+		DBG("bridge info: type %x subbus %x "
 			"maxAgents %x maxsubbus %x logslot %x\n",
 			bridge_info.busUnitInfo.deviceType,
 			bridge_info.subBusNumber,
@@ -493,7 +497,7 @@ static void __init scan_bridge(struct is
 				HvCallPci_BridgeDevice)
 			scan_bridge_slot(dt, bus, &bridge_info);
 		else
-			printk("PCI: Invalid Bridge Configuration(0x%02X)",
+			DBG("PCI: Invalid Bridge Configuration(0x%02X)",
 				bridge_info.busUnitInfo.deviceType);
 	}
 }
@@ -515,13 +519,12 @@ static void __init scan_phb(struct iseri
 				sizeof(struct HvCallPci_DeviceInfo));
 		if (err) {
 			if (err != 0x302)
-				printk(KERN_DEBUG "getDeviceInfo(%x, %x, %x) "
-						"== %x\n",
+				DBG("getDeviceInfo(%x, %x, %x) %x\n",
 						bus, sub_bus, id_sel, err);
 			continue;
 		}
 		if (dev_info.deviceType != HvCallPci_NodeDevice) {
-			printk(KERN_DEBUG "PCI: Invalid System Configuration"
+			DBG("PCI: Invalid System Configuration"
 					"(0x%02X) for bus 0x%02x id 0x%02x.\n",
 					dev_info.deviceType, bus, id_sel);
 			continue;
@@ -547,14 +550,14 @@ static void __init dt_pci_devices(struct
 			 * something has gone wrong.
 			 */
 			if (err != 0x0301)
-				printk(KERN_ERR "Unexpected Return on Probe"
-						"(0x%02X): 0x%04X", bus, err);
+				DBG("Unexpected Return on Probe(0x%02X) "
+						"0x%04X\n", bus, err);
 			continue;
 		}
-		printk("bus %d appears to exist\n", bus);
+		DBG("bus %d appears to exist\n", bus);
 		snprintf(buf, 32, "pci@%d", phb_num);
 		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "pci");
+		dt_prop_str(dt, "device_type", device_type_pci);
 		dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
 		dt_prop_u32(dt, "#address-cells", 3);
 		dt_prop_u32(dt, "#size-cells", 2);
@@ -569,12 +572,13 @@ static void __init dt_pci_devices(struct
 static void dt_finish(struct iseries_flat_dt *dt)
 {
 	dt_push_u32(dt, OF_DT_END);
-	dt->header.totalsize = (unsigned long)dt->data - (unsigned long)dt;
-	klimit = ALIGN((unsigned long)dt->data, 8);
+	dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt;
+	klimit = ALIGN((unsigned long)dt_data, 8);
 }
 
 void * __init build_flat_dt(unsigned long phys_mem_size)
 {
+	struct iseries_flat_dt *iseries_dt;
 	u64 tmp[2];
 
 	iseries_dt = dt_init();
@@ -587,8 +591,7 @@ void * __init build_flat_dt(unsigned lon
 
 	/* /memory */
 	dt_start_node(iseries_dt, "memory@0");
-	dt_prop_str(iseries_dt, "name", "memory");
-	dt_prop_str(iseries_dt, "device_type", "memory");
+	dt_prop_str(iseries_dt, "device_type", device_type_memory);
 	tmp[0] = 0;
 	tmp[1] = phys_mem_size;
 	dt_prop_u64_list(iseries_dt, "reg", tmp, 2);
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 12/14] powerpc: make iSeries flattened device tree dynamic
From: Stephen Rothwell @ 2006-05-19  7:04 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

First we capture all the strings from dt.c statically by noting that gcc
puts them in a special section of their own.  Idea from Michael Ellerman.

Then we move the flattened device tree to klimit.

Still to come, making the values blob grow as needed.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/kernel/vmlinux.lds.S       |    5 ++
 arch/powerpc/platforms/iseries/Makefile |    5 +-
 arch/powerpc/platforms/iseries/dt.c     |   96 ++++++++++++++++++-------------
 3 files changed, 66 insertions(+), 40 deletions(-)

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

0f75701d8ac409a5e5c9e1de1d414129a435b267
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index fe79c25..8b25953 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -93,6 +93,11 @@ #endif /* CONFIG_PPC32 */
 		__ptov_table_begin = .;
 		*(.ptov_fixup);
 		__ptov_table_end = .;
+#ifdef CONFIG_PPC_ISERIES
+		__dt_strings_start = .;
+		*(.dt_strings);
+		__dt_strings_end = .;
+#endif
 	}
 
 	. = ALIGN(16);
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index 3230621..dee4eb4 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -1,8 +1,11 @@
 EXTRA_CFLAGS	+= -mno-minimal-toc
 
-obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
+obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \
 	hvcall.o proc.o htab.o iommu.o misc.o irq.o
 obj-$(CONFIG_PCI) += pci.o vpdinfo.o
 obj-$(CONFIG_SMP) += smp.o
 obj-$(CONFIG_VIOPATH) += viopath.o
 obj-$(CONFIG_MODULES) += ksyms.o
+
+$(obj)/dt_mod.o:	$(obj)/dt.o
+	@$(OBJCOPY) --rename-section .rodata.str1.8=.dt_strings $(obj)/dt.o $(obj)/dt_mod.o
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
index 93d4233..0371329 100644
--- a/arch/powerpc/platforms/iseries/dt.c
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -30,6 +30,7 @@ #include <asm/lppaca.h>
 #include <asm/page.h>
 #include <asm/cputable.h>
 #include <asm/abs_addr.h>
+#include <asm/system.h>
 #include <asm/iseries/hv_types.h>
 #include <asm/iseries/hv_lp_config.h>
 #include <asm/iseries/hv_call_xm.h>
@@ -47,6 +48,9 @@ #else
 #define DBG(fmt...)
 #endif
 
+extern char __dt_strings_start[];
+extern char __dt_strings_end[];
+
 struct blob {
 	unsigned char data[PAGE_SIZE * 2];
 	unsigned long next;
@@ -55,26 +59,34 @@ struct blob {
 struct iseries_flat_dt {
 	struct boot_param_header header;
 	u64 reserve_map[2];
-	struct blob dt;
-	struct blob strings;
+	struct blob *dt;
 };
 
-static struct iseries_flat_dt iseries_dt;
+static struct iseries_flat_dt *iseries_dt;
 
-static void __init dt_init(struct iseries_flat_dt *dt)
+static struct iseries_flat_dt * __init dt_init(void)
 {
+	struct iseries_flat_dt *dt;
+	unsigned long str_len;
+
+	str_len = __dt_strings_end - __dt_strings_start;
+	dt = (struct iseries_flat_dt *)ALIGN(klimit, 8);
 	dt->header.off_mem_rsvmap =
 		offsetof(struct iseries_flat_dt, reserve_map);
-	dt->header.off_dt_struct = offsetof(struct iseries_flat_dt, dt);
-	dt->header.off_dt_strings = offsetof(struct iseries_flat_dt, strings);
-	dt->header.totalsize = sizeof(struct iseries_flat_dt);
-	dt->header.dt_strings_size = sizeof(struct blob);
+	dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);
+	dt->header.off_dt_struct = dt->header.off_dt_strings
+		+ ALIGN(str_len, 8);
+	dt->dt = (struct blob *)((unsigned long)dt + dt->header.off_dt_struct);
+	klimit = ALIGN((unsigned long)(dt->dt) + sizeof(struct blob), 8);
+	dt->header.totalsize = klimit - (unsigned long)dt;
+	dt->header.dt_strings_size = str_len;
 
 	/* There is no notion of hardware cpu id on iSeries */
 	dt->header.boot_cpuid_phys = smp_processor_id();
 
-	dt->dt.next = (unsigned long)&dt->dt.data;
-	dt->strings.next = (unsigned long)&dt->strings.data;
+	dt->dt->next = (unsigned long)&dt->dt->data;
+	memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start,
+			str_len);
 
 	dt->header.magic = OF_DT_HEADER;
 	dt->header.version = 0x10;
@@ -82,6 +94,8 @@ static void __init dt_init(struct iserie
 
 	dt->reserve_map[0] = 0;
 	dt->reserve_map[1] = 0;
+
+	return dt;
 }
 
 static void __init dt_check_blob(struct blob *b)
@@ -94,19 +108,19 @@ static void __init dt_check_blob(struct 
 
 static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
 {
-	*((u32*)dt->dt.next) = value;
-	dt->dt.next += sizeof(u32);
+	*((u32*)dt->dt->next) = value;
+	dt->dt->next += sizeof(u32);
 
-	dt_check_blob(&dt->dt);
+	dt_check_blob(dt->dt);
 }
 
 #ifdef notyet
 static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
 {
-	*((u64*)dt->dt.next) = value;
-	dt->dt.next += sizeof(u64);
+	*((u64*)dt->dt->next) = value;
+	dt->dt->next += sizeof(u64);
 
-	dt_check_blob(&dt->dt);
+	dt_check_blob(dt->dt);
 }
 #endif
 
@@ -125,7 +139,7 @@ static unsigned long __init dt_push_byte
 static void __init dt_start_node(struct iseries_flat_dt *dt, char *name)
 {
 	dt_push_u32(dt, OF_DT_BEGIN_NODE);
-	dt_push_bytes(&dt->dt, name, strlen(name) + 1);
+	dt_push_bytes(dt->dt, name, strlen(name) + 1);
 }
 
 #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
@@ -140,14 +154,13 @@ static void __init dt_prop(struct iserie
 	/* Length of the data */
 	dt_push_u32(dt, len);
 
-	/* Put the property name in the string blob. */
-	offset = dt_push_bytes(&dt->strings, name, strlen(name) + 1);
+	offset = name - __dt_strings_start;
 
 	/* The offset of the properties name in the string blob. */
 	dt_push_u32(dt, (u32)offset);
 
 	/* The actual data. */
-	dt_push_bytes(&dt->dt, data, len);
+	dt_push_bytes(dt->dt, data, len);
 }
 
 static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name,
@@ -579,40 +592,45 @@ static void __init dt_pci_devices(struct
 	}
 }
 
+static void dt_finish(struct iseries_flat_dt *dt)
+{
+	dt_push_u32(dt, OF_DT_END);
+}
+
 void * __init build_flat_dt(unsigned long phys_mem_size)
 {
 	u64 tmp[2];
 
-	dt_init(&iseries_dt);
+	iseries_dt = dt_init();
 
-	dt_start_node(&iseries_dt, "");
+	dt_start_node(iseries_dt, "");
 
-	dt_prop_u32(&iseries_dt, "#address-cells", 2);
-	dt_prop_u32(&iseries_dt, "#size-cells", 2);
-	dt_model(&iseries_dt);
+	dt_prop_u32(iseries_dt, "#address-cells", 2);
+	dt_prop_u32(iseries_dt, "#size-cells", 2);
+	dt_model(iseries_dt);
 
 	/* /memory */
-	dt_start_node(&iseries_dt, "memory@0");
-	dt_prop_str(&iseries_dt, "name", "memory");
-	dt_prop_str(&iseries_dt, "device_type", "memory");
+	dt_start_node(iseries_dt, "memory@0");
+	dt_prop_str(iseries_dt, "name", "memory");
+	dt_prop_str(iseries_dt, "device_type", "memory");
 	tmp[0] = 0;
 	tmp[1] = phys_mem_size;
-	dt_prop_u64_list(&iseries_dt, "reg", tmp, 2);
-	dt_end_node(&iseries_dt);
+	dt_prop_u64_list(iseries_dt, "reg", tmp, 2);
+	dt_end_node(iseries_dt);
 
 	/* /chosen */
-	dt_start_node(&iseries_dt, "chosen");
-	dt_prop_str(&iseries_dt, "bootargs", cmd_line);
-	dt_end_node(&iseries_dt);
+	dt_start_node(iseries_dt, "chosen");
+	dt_prop_str(iseries_dt, "bootargs", cmd_line);
+	dt_end_node(iseries_dt);
 
-	dt_cpus(&iseries_dt);
+	dt_cpus(iseries_dt);
 
-	dt_vdevices(&iseries_dt);
-	dt_pci_devices(&iseries_dt);
+	dt_vdevices(iseries_dt);
+	dt_pci_devices(iseries_dt);
 
-	dt_end_node(&iseries_dt);
+	dt_end_node(iseries_dt);
 
-	dt_push_u32(&iseries_dt, OF_DT_END);
+	dt_finish(iseries_dt);
 
-	return &iseries_dt;
+	return iseries_dt;
 }
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 13/14] powerpc: make iSeries flattened device tree dynamic - part 2
From: Stephen Rothwell @ 2006-05-19  7:04 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

This actually simplies things as we just figure out how much space we
used at the end and adjust klimit then.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/dt.c |   62 +++++++++++------------------------
 1 files changed, 19 insertions(+), 43 deletions(-)

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

0496bb52c33374b4f014df39c0e8a1b53325e93b
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
index 0371329..2a51ec1 100644
--- a/arch/powerpc/platforms/iseries/dt.c
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -27,7 +27,6 @@ #include <linux/if_ether.h>	/* ETH_ALEN 
 #include <asm/machdep.h>
 #include <asm/prom.h>
 #include <asm/lppaca.h>
-#include <asm/page.h>
 #include <asm/cputable.h>
 #include <asm/abs_addr.h>
 #include <asm/system.h>
@@ -51,15 +50,10 @@ #endif
 extern char __dt_strings_start[];
 extern char __dt_strings_end[];
 
-struct blob {
-	unsigned char data[PAGE_SIZE * 2];
-	unsigned long next;
-};
-
 struct iseries_flat_dt {
 	struct boot_param_header header;
 	u64 reserve_map[2];
-	struct blob *dt;
+	void *data;
 };
 
 static struct iseries_flat_dt *iseries_dt;
@@ -76,15 +70,12 @@ static struct iseries_flat_dt * __init d
 	dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);
 	dt->header.off_dt_struct = dt->header.off_dt_strings
 		+ ALIGN(str_len, 8);
-	dt->dt = (struct blob *)((unsigned long)dt + dt->header.off_dt_struct);
-	klimit = ALIGN((unsigned long)(dt->dt) + sizeof(struct blob), 8);
-	dt->header.totalsize = klimit - (unsigned long)dt;
+	dt->data = (void *)((unsigned long)dt + dt->header.off_dt_struct);
 	dt->header.dt_strings_size = str_len;
 
 	/* There is no notion of hardware cpu id on iSeries */
 	dt->header.boot_cpuid_phys = smp_processor_id();
 
-	dt->dt->next = (unsigned long)&dt->dt->data;
 	memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start,
 			str_len);
 
@@ -98,54 +89,37 @@ static struct iseries_flat_dt * __init d
 	return dt;
 }
 
-static void __init dt_check_blob(struct blob *b)
-{
-	if (b->next >= (unsigned long)&b->next) {
-		DBG("Ran out of space in flat device tree blob!\n");
-		BUG();
-	}
-}
-
 static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
 {
-	*((u32*)dt->dt->next) = value;
-	dt->dt->next += sizeof(u32);
-
-	dt_check_blob(dt->dt);
+	*((u32 *)dt->data) = value;
+	dt->data += sizeof(u32);
 }
 
 #ifdef notyet
 static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
 {
-	*((u64*)dt->dt->next) = value;
-	dt->dt->next += sizeof(u64);
-
-	dt_check_blob(dt->dt);
+	*((u64 *)dt->data) = value;
+	dt->data += sizeof(u64);
 }
 #endif
 
-static unsigned long __init dt_push_bytes(struct blob *blob, char *data, int len)
+static void __init dt_push_bytes(struct iseries_flat_dt *dt, char *data,
+		int len)
 {
-	unsigned long start = blob->next - (unsigned long)blob->data;
-
-	memcpy((char *)blob->next, data, len);
-	blob->next = _ALIGN(blob->next + len, 4);
-
-	dt_check_blob(blob);
-
-	return start;
+	memcpy(dt->data, data, len);
+	dt->data += ALIGN(len, 4);
 }
 
 static void __init dt_start_node(struct iseries_flat_dt *dt, char *name)
 {
 	dt_push_u32(dt, OF_DT_BEGIN_NODE);
-	dt_push_bytes(dt->dt, name, strlen(name) + 1);
+	dt_push_bytes(dt, name, strlen(name) + 1);
 }
 
 #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
 
 static void __init dt_prop(struct iseries_flat_dt *dt, char *name,
-		char *data, int len)
+		void *data, int len)
 {
 	unsigned long offset;
 
@@ -160,7 +134,7 @@ static void __init dt_prop(struct iserie
 	dt_push_u32(dt, (u32)offset);
 
 	/* The actual data. */
-	dt_push_bytes(dt->dt, data, len);
+	dt_push_bytes(dt, data, len);
 }
 
 static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name,
@@ -171,24 +145,24 @@ static void __init dt_prop_str(struct is
 
 static void __init dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
 {
-	dt_prop(dt, name, (char *)&data, sizeof(u32));
+	dt_prop(dt, name, &data, sizeof(u32));
 }
 
 static void __init dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
 {
-	dt_prop(dt, name, (char *)&data, sizeof(u64));
+	dt_prop(dt, name, &data, sizeof(u64));
 }
 
 static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, char *name,
 		u64 *data, int n)
 {
-	dt_prop(dt, name, (char *)data, sizeof(u64) * n);
+	dt_prop(dt, name, data, sizeof(u64) * n);
 }
 
 static void __init dt_prop_u32_list(struct iseries_flat_dt *dt, char *name,
 		u32 *data, int n)
 {
-	dt_prop(dt, name, (char *)data, sizeof(u32) * n);
+	dt_prop(dt, name, data, sizeof(u32) * n);
 }
 
 #ifdef notyet
@@ -595,6 +569,8 @@ static void __init dt_pci_devices(struct
 static void dt_finish(struct iseries_flat_dt *dt)
 {
 	dt_push_u32(dt, OF_DT_END);
+	dt->header.totalsize = (unsigned long)dt->data - (unsigned long)dt;
+	klimit = ALIGN((unsigned long)dt->data, 8);
 }
 
 void * __init build_flat_dt(unsigned long phys_mem_size)
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 11/14] powerpc: split device tree stuff out of iseries/setup.c
From: Stephen Rothwell @ 2006-05-19  7:00 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>


Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/Makefile |    2 
 arch/powerpc/platforms/iseries/dt.c     |  618 +++++++++++++++++++++++++++++++
 arch/powerpc/platforms/iseries/setup.c  |  578 -----------------------------
 arch/powerpc/platforms/iseries/setup.h  |    2 
 4 files changed, 622 insertions(+), 578 deletions(-)
 create mode 100644 arch/powerpc/platforms/iseries/dt.c

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

5909be4784e723a8a0444a556801cb320a4ddffc
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index 7e67a20..3230621 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -1,6 +1,6 @@
 EXTRA_CFLAGS	+= -mno-minimal-toc
 
-obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o \
+obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
 	hvcall.o proc.o htab.o iommu.o misc.o irq.o
 obj-$(CONFIG_PCI) += pci.o vpdinfo.o
 obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
new file mode 100644
index 0000000..93d4233
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -0,0 +1,618 @@
+/*
+ *    Copyright (c) 2005-2006 Michael Ellerman, IBM Corporation
+ *
+ *    Description:
+ *      This file contains all the routines to build a flattened device
+ *      tree for a legacy iSeries machine.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/threads.h>
+#include <linux/bitops.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/if_ether.h>	/* ETH_ALEN */
+
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/lppaca.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/abs_addr.h>
+#include <asm/iseries/hv_types.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/it_exp_vpd_panel.h>
+#include <asm/udbg.h>
+
+#include "processor_vpd.h"
+#include "call_hpt.h"
+#include "call_pci.h"
+#include "pci.h"
+
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+struct blob {
+	unsigned char data[PAGE_SIZE * 2];
+	unsigned long next;
+};
+
+struct iseries_flat_dt {
+	struct boot_param_header header;
+	u64 reserve_map[2];
+	struct blob dt;
+	struct blob strings;
+};
+
+static struct iseries_flat_dt iseries_dt;
+
+static void __init dt_init(struct iseries_flat_dt *dt)
+{
+	dt->header.off_mem_rsvmap =
+		offsetof(struct iseries_flat_dt, reserve_map);
+	dt->header.off_dt_struct = offsetof(struct iseries_flat_dt, dt);
+	dt->header.off_dt_strings = offsetof(struct iseries_flat_dt, strings);
+	dt->header.totalsize = sizeof(struct iseries_flat_dt);
+	dt->header.dt_strings_size = sizeof(struct blob);
+
+	/* There is no notion of hardware cpu id on iSeries */
+	dt->header.boot_cpuid_phys = smp_processor_id();
+
+	dt->dt.next = (unsigned long)&dt->dt.data;
+	dt->strings.next = (unsigned long)&dt->strings.data;
+
+	dt->header.magic = OF_DT_HEADER;
+	dt->header.version = 0x10;
+	dt->header.last_comp_version = 0x10;
+
+	dt->reserve_map[0] = 0;
+	dt->reserve_map[1] = 0;
+}
+
+static void __init dt_check_blob(struct blob *b)
+{
+	if (b->next >= (unsigned long)&b->next) {
+		DBG("Ran out of space in flat device tree blob!\n");
+		BUG();
+	}
+}
+
+static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
+{
+	*((u32*)dt->dt.next) = value;
+	dt->dt.next += sizeof(u32);
+
+	dt_check_blob(&dt->dt);
+}
+
+#ifdef notyet
+static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
+{
+	*((u64*)dt->dt.next) = value;
+	dt->dt.next += sizeof(u64);
+
+	dt_check_blob(&dt->dt);
+}
+#endif
+
+static unsigned long __init dt_push_bytes(struct blob *blob, char *data, int len)
+{
+	unsigned long start = blob->next - (unsigned long)blob->data;
+
+	memcpy((char *)blob->next, data, len);
+	blob->next = _ALIGN(blob->next + len, 4);
+
+	dt_check_blob(blob);
+
+	return start;
+}
+
+static void __init dt_start_node(struct iseries_flat_dt *dt, char *name)
+{
+	dt_push_u32(dt, OF_DT_BEGIN_NODE);
+	dt_push_bytes(&dt->dt, name, strlen(name) + 1);
+}
+
+#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
+
+static void __init dt_prop(struct iseries_flat_dt *dt, char *name,
+		char *data, int len)
+{
+	unsigned long offset;
+
+	dt_push_u32(dt, OF_DT_PROP);
+
+	/* Length of the data */
+	dt_push_u32(dt, len);
+
+	/* Put the property name in the string blob. */
+	offset = dt_push_bytes(&dt->strings, name, strlen(name) + 1);
+
+	/* The offset of the properties name in the string blob. */
+	dt_push_u32(dt, (u32)offset);
+
+	/* The actual data. */
+	dt_push_bytes(&dt->dt, data, len);
+}
+
+static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name,
+		char *data)
+{
+	dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
+}
+
+static void __init dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
+{
+	dt_prop(dt, name, (char *)&data, sizeof(u32));
+}
+
+static void __init dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
+{
+	dt_prop(dt, name, (char *)&data, sizeof(u64));
+}
+
+static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, char *name,
+		u64 *data, int n)
+{
+	dt_prop(dt, name, (char *)data, sizeof(u64) * n);
+}
+
+static void __init dt_prop_u32_list(struct iseries_flat_dt *dt, char *name,
+		u32 *data, int n)
+{
+	dt_prop(dt, name, (char *)data, sizeof(u32) * n);
+}
+
+#ifdef notyet
+static void __init dt_prop_empty(struct iseries_flat_dt *dt, char *name)
+{
+	dt_prop(dt, name, NULL, 0);
+}
+#endif
+
+static void __init dt_cpus(struct iseries_flat_dt *dt)
+{
+	unsigned char buf[32];
+	unsigned char *p;
+	unsigned int i, index;
+	struct IoHriProcessorVpd *d;
+	u32 pft_size[2];
+
+	/* yuck */
+	snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);
+	p = strchr(buf, ' ');
+	if (!p) p = buf + strlen(buf);
+
+	dt_start_node(dt, "cpus");
+	dt_prop_u32(dt, "#address-cells", 1);
+	dt_prop_u32(dt, "#size-cells", 0);
+
+	pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA  */
+	pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (lppaca[i].dyn_proc_status >= 2)
+			continue;
+
+		snprintf(p, 32 - (p - buf), "@%d", i);
+		dt_start_node(dt, buf);
+
+		dt_prop_str(dt, "device_type", "cpu");
+
+		index = lppaca[i].dyn_hv_phys_proc_index;
+		d = &xIoHriProcessorVpd[index];
+
+		dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
+		dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);
+
+		dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);
+		dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);
+
+		/* magic conversions to Hz copied from old code */
+		dt_prop_u32(dt, "clock-frequency",
+			((1UL << 34) * 1000000) / d->xProcFreq);
+		dt_prop_u32(dt, "timebase-frequency",
+			((1UL << 32) * 1000000) / d->xTimeBaseFreq);
+
+		dt_prop_u32(dt, "reg", i);
+
+		dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);
+
+		dt_end_node(dt);
+	}
+
+	dt_end_node(dt);
+}
+
+static void __init dt_model(struct iseries_flat_dt *dt)
+{
+	char buf[16] = "IBM,";
+
+	/* "IBM," + mfgId[2:3] + systemSerial[1:5] */
+	strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
+	strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
+	buf[11] = '\0';
+	dt_prop_str(dt, "system-id", buf);
+
+	/* "IBM," + machineType[0:4] */
+	strne2a(buf + 4, xItExtVpdPanel.machineType, 4);
+	buf[8] = '\0';
+	dt_prop_str(dt, "model", buf);
+
+	dt_prop_str(dt, "compatible", "IBM,iSeries");
+}
+
+static void __init dt_vdevices(struct iseries_flat_dt *dt)
+{
+	u32 reg = 0;
+	HvLpIndexMap vlan_map;
+	int i;
+	char buf[32];
+
+	dt_start_node(dt, "vdevice");
+	dt_prop_str(dt, "device_type", "vdevice");
+	dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");
+	dt_prop_u32(dt, "#address-cells", 1);
+	dt_prop_u32(dt, "#size-cells", 0);
+
+	snprintf(buf, sizeof(buf), "vty@%08x", reg);
+	dt_start_node(dt, buf);
+	dt_prop_str(dt, "device_type", "serial");
+	dt_prop_u32(dt, "reg", reg);
+	dt_end_node(dt);
+	reg++;
+
+	snprintf(buf, sizeof(buf), "v-scsi@%08x", reg);
+	dt_start_node(dt, buf);
+	dt_prop_str(dt, "device_type", "vscsi");
+	dt_prop_str(dt, "compatible", "IBM,v-scsi");
+	dt_prop_u32(dt, "reg", reg);
+	dt_end_node(dt);
+	reg++;
+
+	vlan_map = HvLpConfig_getVirtualLanIndexMap();
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+		unsigned char mac_addr[ETH_ALEN];
+
+		if ((vlan_map & (0x8000 >> i)) == 0)
+			continue;
+		snprintf(buf, 32, "l-lan@%08x", reg + i);
+		dt_start_node(dt, buf);
+		dt_prop_str(dt, "device_type", "network");
+		dt_prop_str(dt, "compatible", "IBM,iSeries-l-lan");
+		dt_prop_u32(dt, "reg", reg + i);
+		dt_prop_u32(dt, "linux,unit_address", i);
+
+		mac_addr[0] = 0x02;
+		mac_addr[1] = 0x01;
+		mac_addr[2] = 0xff;
+		mac_addr[3] = i;
+		mac_addr[4] = 0xff;
+		mac_addr[5] = HvLpConfig_getLpIndex_outline();
+		dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);
+		dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);
+		dt_prop_u32(dt, "max-frame-size", 9000);
+		dt_prop_u32(dt, "address-bits", 48);
+
+		dt_end_node(dt);
+	}
+	reg += HVMAXARCHITECTEDVIRTUALLANS;
+
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) {
+		snprintf(buf, 32, "viodasd@%08x", reg + i);
+		dt_start_node(dt, buf);
+		dt_prop_str(dt, "device_type", "block");
+		dt_prop_str(dt, "compatible", "IBM,iSeries-viodasd");
+		dt_prop_u32(dt, "reg", reg + i);
+		dt_prop_u32(dt, "linux,unit_address", i);
+		dt_end_node(dt);
+	}
+	reg += HVMAXARCHITECTEDVIRTUALDISKS;
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) {
+		snprintf(buf, 32, "viocd@%08x", reg + i);
+		dt_start_node(dt, buf);
+		dt_prop_str(dt, "device_type", "block");
+		dt_prop_str(dt, "compatible", "IBM,iSeries-viocd");
+		dt_prop_u32(dt, "reg", reg + i);
+		dt_prop_u32(dt, "linux,unit_address", i);
+		dt_end_node(dt);
+	}
+	reg += HVMAXARCHITECTEDVIRTUALCDROMS;
+	for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) {
+		snprintf(buf, 32, "viotape@%08x", reg + i);
+		dt_start_node(dt, buf);
+		dt_prop_str(dt, "device_type", "byte");
+		dt_prop_str(dt, "compatible", "IBM,iSeries-viotape");
+		dt_prop_u32(dt, "reg", reg + i);
+		dt_prop_u32(dt, "linux,unit_address", i);
+		dt_end_node(dt);
+	}
+
+	dt_end_node(dt);
+}
+
+struct pci_class_name {
+	u16 code;
+	char *name;
+	char *type;
+};
+
+static struct pci_class_name __initdata pci_class_name[] = {
+	{ PCI_CLASS_NETWORK_ETHERNET, "ethernet", "network" },
+};
+
+static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
+{
+	struct pci_class_name *cp;
+
+	for (cp = pci_class_name;
+			cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)
+		if (cp->code == class_code)
+			return cp;
+	return NULL;
+}
+
+/*
+ * This assumes that the node slot is always on the primary bus!
+ */
+static void __init scan_bridge_slot(struct iseries_flat_dt *dt,
+		HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)
+{
+	HvSubBusNumber sub_bus = bridge_info->subBusNumber;
+	u16 vendor_id;
+	u16 device_id;
+	u32 class_id;
+	int err;
+	char buf[32];
+	u32 reg[5];
+	int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
+	int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
+	HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
+	u8 devfn;
+	struct pci_class_name *cp;
+
+	/*
+	 * Connect all functions of any device found.
+	 */
+	for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
+		for (function = 0; function < 8; function++) {
+			HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
+					function);
+			err = HvCallXm_connectBusUnit(bus, sub_bus,
+					agent_id, 0);
+			if (err) {
+				if (err != 0x302)
+					printk(KERN_DEBUG
+						"connectBusUnit(%x, %x, %x) "
+						"== %x\n",
+						bus, sub_bus, agent_id, err);
+				continue;
+			}
+
+			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
+					PCI_VENDOR_ID, &vendor_id);
+			if (err) {
+				printk(KERN_DEBUG
+					"ReadVendor(%x, %x, %x) == %x\n",
+					bus, sub_bus, agent_id, err);
+				continue;
+			}
+			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
+					PCI_DEVICE_ID, &device_id);
+			if (err) {
+				printk(KERN_DEBUG
+					"ReadDevice(%x, %x, %x) == %x\n",
+					bus, sub_bus, agent_id, err);
+				continue;
+			}
+			err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
+					PCI_CLASS_REVISION , &class_id);
+			if (err) {
+				printk(KERN_DEBUG
+					"ReadClass(%x, %x, %x) == %x\n",
+					bus, sub_bus, agent_id, err);
+				continue;
+			}
+
+			devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
+					function);
+			cp = dt_find_pci_class_name(class_id >> 16);
+			if (cp && cp->name)
+				strncpy(buf, cp->name, sizeof(buf) - 1);
+			else
+				snprintf(buf, sizeof(buf), "pci%x,%x",
+						vendor_id, device_id);
+			buf[sizeof(buf) - 1] = '\0';
+			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+					"@%x", PCI_SLOT(devfn));
+			buf[sizeof(buf) - 1] = '\0';
+			if (function != 0)
+				snprintf(buf + strlen(buf),
+					sizeof(buf) - strlen(buf),
+					",%x", function);
+			dt_start_node(dt, buf);
+			reg[0] = (bus << 16) | (devfn << 8);
+			reg[1] = 0;
+			reg[2] = 0;
+			reg[3] = 0;
+			reg[4] = 0;
+			dt_prop_u32_list(dt, "reg", reg, 5);
+			if (cp && (cp->type || cp->name))
+				dt_prop_str(dt, "device_type",
+					cp->type ? cp->type : cp->name);
+			dt_prop_u32(dt, "vendor-id", vendor_id);
+			dt_prop_u32(dt, "device-id", device_id);
+			dt_prop_u32(dt, "class-code", class_id >> 8);
+			dt_prop_u32(dt, "revision-id", class_id & 0xff);
+			dt_prop_u32(dt, "linux,subbus", sub_bus);
+			dt_prop_u32(dt, "linux,agent-id", agent_id);
+			dt_prop_u32(dt, "linux,logical-slot-number",
+					bridge_info->logicalSlotNumber);
+			dt_end_node(dt);
+
+		}
+	}
+}
+
+static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
+		HvSubBusNumber sub_bus, int id_sel)
+{
+	struct HvCallPci_BridgeInfo bridge_info;
+	HvAgentId agent_id;
+	int function;
+	int ret;
+
+	/* Note: hvSubBus and irq is always be 0 at this level! */
+	for (function = 0; function < 8; ++function) {
+		agent_id = ISERIES_PCI_AGENTID(id_sel, function);
+		ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
+		if (ret != 0) {
+			if (ret != 0xb)
+				printk(KERN_DEBUG "connectBusUnit(%x, %x, %x) "
+						"== %x\n",
+						bus, sub_bus, agent_id, ret);
+			continue;
+		}
+		printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
+				bus, id_sel, function, agent_id);
+		ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
+				iseries_hv_addr(&bridge_info),
+				sizeof(struct HvCallPci_BridgeInfo));
+		if (ret != 0)
+			continue;
+		printk("bridge info: type %x subbus %x "
+			"maxAgents %x maxsubbus %x logslot %x\n",
+			bridge_info.busUnitInfo.deviceType,
+			bridge_info.subBusNumber,
+			bridge_info.maxAgents,
+			bridge_info.maxSubBusNumber,
+			bridge_info.logicalSlotNumber);
+		if (bridge_info.busUnitInfo.deviceType ==
+				HvCallPci_BridgeDevice)
+			scan_bridge_slot(dt, bus, &bridge_info);
+		else
+			printk("PCI: Invalid Bridge Configuration(0x%02X)",
+				bridge_info.busUnitInfo.deviceType);
+	}
+}
+
+static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
+{
+	struct HvCallPci_DeviceInfo dev_info;
+	const HvSubBusNumber sub_bus = 0;	/* EADs is always 0. */
+	int err;
+	int id_sel;
+	const int max_agents = 8;
+
+	/*
+	 * Probe for EADs Bridges
+	 */
+	for (id_sel = 1; id_sel < max_agents; ++id_sel) {
+		err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,
+				iseries_hv_addr(&dev_info),
+				sizeof(struct HvCallPci_DeviceInfo));
+		if (err) {
+			if (err != 0x302)
+				printk(KERN_DEBUG "getDeviceInfo(%x, %x, %x) "
+						"== %x\n",
+						bus, sub_bus, id_sel, err);
+			continue;
+		}
+		if (dev_info.deviceType != HvCallPci_NodeDevice) {
+			printk(KERN_DEBUG "PCI: Invalid System Configuration"
+					"(0x%02X) for bus 0x%02x id 0x%02x.\n",
+					dev_info.deviceType, bus, id_sel);
+			continue;
+		}
+		scan_bridge(dt, bus, sub_bus, id_sel);
+	}
+}
+
+static void __init dt_pci_devices(struct iseries_flat_dt *dt)
+{
+	HvBusNumber bus;
+	char buf[32];
+	u32 buses[2];
+	int phb_num = 0;
+
+	/* Check all possible buses. */
+	for (bus = 0; bus < 256; bus++) {
+		int err = HvCallXm_testBus(bus);
+
+		if (err) {
+			/*
+			 * Check for Unexpected Return code, a clue that
+			 * something has gone wrong.
+			 */
+			if (err != 0x0301)
+				printk(KERN_ERR "Unexpected Return on Probe"
+						"(0x%02X): 0x%04X", bus, err);
+			continue;
+		}
+		printk("bus %d appears to exist\n", bus);
+		snprintf(buf, 32, "pci@%d", phb_num);
+		dt_start_node(dt, buf);
+		dt_prop_str(dt, "device_type", "pci");
+		dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
+		dt_prop_u32(dt, "#address-cells", 3);
+		dt_prop_u32(dt, "#size-cells", 2);
+		buses[0] = buses[1] = bus;
+		dt_prop_u32_list(dt, "bus-range", buses, 2);
+		scan_phb(dt, bus);
+		dt_end_node(dt);
+		phb_num++;
+	}
+}
+
+void * __init build_flat_dt(unsigned long phys_mem_size)
+{
+	u64 tmp[2];
+
+	dt_init(&iseries_dt);
+
+	dt_start_node(&iseries_dt, "");
+
+	dt_prop_u32(&iseries_dt, "#address-cells", 2);
+	dt_prop_u32(&iseries_dt, "#size-cells", 2);
+	dt_model(&iseries_dt);
+
+	/* /memory */
+	dt_start_node(&iseries_dt, "memory@0");
+	dt_prop_str(&iseries_dt, "name", "memory");
+	dt_prop_str(&iseries_dt, "device_type", "memory");
+	tmp[0] = 0;
+	tmp[1] = phys_mem_size;
+	dt_prop_u64_list(&iseries_dt, "reg", tmp, 2);
+	dt_end_node(&iseries_dt);
+
+	/* /chosen */
+	dt_start_node(&iseries_dt, "chosen");
+	dt_prop_str(&iseries_dt, "bootargs", cmd_line);
+	dt_end_node(&iseries_dt);
+
+	dt_cpus(&iseries_dt);
+
+	dt_vdevices(&iseries_dt);
+	dt_pci_devices(&iseries_dt);
+
+	dt_end_node(&iseries_dt);
+
+	dt_push_u32(&iseries_dt, OF_DT_END);
+
+	return &iseries_dt;
+}
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 5661bd0..617c724 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -28,7 +28,6 @@ #include <linux/kdev_t.h>
 #include <linux/major.h>
 #include <linux/root_dev.h>
 #include <linux/kernel.h>
-#include <linux/if_ether.h>	/* ETH_ALEN */
 
 #include <asm/processor.h>
 #include <asm/machdep.h>
@@ -46,13 +45,11 @@ #include <asm/paca.h>
 #include <asm/cache.h>
 #include <asm/sections.h>
 #include <asm/abs_addr.h>
-#include <asm/iseries/hv_types.h>
 #include <asm/iseries/hv_lp_config.h>
 #include <asm/iseries/hv_call_event.h>
 #include <asm/iseries/hv_call_xm.h>
 #include <asm/iseries/it_lp_queue.h>
 #include <asm/iseries/mf.h>
-#include <asm/iseries/it_exp_vpd_panel.h>
 #include <asm/iseries/hv_lp_event.h>
 #include <asm/iseries/lpar_map.h>
 #include <asm/udbg.h>
@@ -66,8 +63,6 @@ #include "processor_vpd.h"
 #include "main_store.h"
 #include "call_sm.h"
 #include "call_hpt.h"
-#include "call_pci.h"
-#include "pci.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -711,575 +706,6 @@ define_machine(iseries) {
 	/* XXX Implement enable_pmcs for iSeries */
 };
 
-struct blob {
-	unsigned char data[PAGE_SIZE * 2];
-	unsigned long next;
-};
-
-struct iseries_flat_dt {
-	struct boot_param_header header;
-	u64 reserve_map[2];
-	struct blob dt;
-	struct blob strings;
-};
-
-static struct iseries_flat_dt iseries_dt;
-
-static void __init dt_init(struct iseries_flat_dt *dt)
-{
-	dt->header.off_mem_rsvmap =
-		offsetof(struct iseries_flat_dt, reserve_map);
-	dt->header.off_dt_struct = offsetof(struct iseries_flat_dt, dt);
-	dt->header.off_dt_strings = offsetof(struct iseries_flat_dt, strings);
-	dt->header.totalsize = sizeof(struct iseries_flat_dt);
-	dt->header.dt_strings_size = sizeof(struct blob);
-
-	/* There is no notion of hardware cpu id on iSeries */
-	dt->header.boot_cpuid_phys = smp_processor_id();
-
-	dt->dt.next = (unsigned long)&dt->dt.data;
-	dt->strings.next = (unsigned long)&dt->strings.data;
-
-	dt->header.magic = OF_DT_HEADER;
-	dt->header.version = 0x10;
-	dt->header.last_comp_version = 0x10;
-
-	dt->reserve_map[0] = 0;
-	dt->reserve_map[1] = 0;
-}
-
-static void __init dt_check_blob(struct blob *b)
-{
-	if (b->next >= (unsigned long)&b->next) {
-		DBG("Ran out of space in flat device tree blob!\n");
-		BUG();
-	}
-}
-
-static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
-{
-	*((u32*)dt->dt.next) = value;
-	dt->dt.next += sizeof(u32);
-
-	dt_check_blob(&dt->dt);
-}
-
-#ifdef notyet
-static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
-{
-	*((u64*)dt->dt.next) = value;
-	dt->dt.next += sizeof(u64);
-
-	dt_check_blob(&dt->dt);
-}
-#endif
-
-static unsigned long __init dt_push_bytes(struct blob *blob, char *data, int len)
-{
-	unsigned long start = blob->next - (unsigned long)blob->data;
-
-	memcpy((char *)blob->next, data, len);
-	blob->next = _ALIGN(blob->next + len, 4);
-
-	dt_check_blob(blob);
-
-	return start;
-}
-
-static void __init dt_start_node(struct iseries_flat_dt *dt, char *name)
-{
-	dt_push_u32(dt, OF_DT_BEGIN_NODE);
-	dt_push_bytes(&dt->dt, name, strlen(name) + 1);
-}
-
-#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
-
-static void __init dt_prop(struct iseries_flat_dt *dt, char *name,
-		char *data, int len)
-{
-	unsigned long offset;
-
-	dt_push_u32(dt, OF_DT_PROP);
-
-	/* Length of the data */
-	dt_push_u32(dt, len);
-
-	/* Put the property name in the string blob. */
-	offset = dt_push_bytes(&dt->strings, name, strlen(name) + 1);
-
-	/* The offset of the properties name in the string blob. */
-	dt_push_u32(dt, (u32)offset);
-
-	/* The actual data. */
-	dt_push_bytes(&dt->dt, data, len);
-}
-
-static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name,
-		char *data)
-{
-	dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
-}
-
-static void __init dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
-{
-	dt_prop(dt, name, (char *)&data, sizeof(u32));
-}
-
-static void __init dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
-{
-	dt_prop(dt, name, (char *)&data, sizeof(u64));
-}
-
-static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, char *name,
-		u64 *data, int n)
-{
-	dt_prop(dt, name, (char *)data, sizeof(u64) * n);
-}
-
-static void __init dt_prop_u32_list(struct iseries_flat_dt *dt, char *name,
-		u32 *data, int n)
-{
-	dt_prop(dt, name, (char *)data, sizeof(u32) * n);
-}
-
-#ifdef notyet
-static void __init dt_prop_empty(struct iseries_flat_dt *dt, char *name)
-{
-	dt_prop(dt, name, NULL, 0);
-}
-#endif
-
-static void __init dt_cpus(struct iseries_flat_dt *dt)
-{
-	unsigned char buf[32];
-	unsigned char *p;
-	unsigned int i, index;
-	struct IoHriProcessorVpd *d;
-	u32 pft_size[2];
-
-	/* yuck */
-	snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);
-	p = strchr(buf, ' ');
-	if (!p) p = buf + strlen(buf);
-
-	dt_start_node(dt, "cpus");
-	dt_prop_u32(dt, "#address-cells", 1);
-	dt_prop_u32(dt, "#size-cells", 0);
-
-	pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA  */
-	pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
-
-	for (i = 0; i < NR_CPUS; i++) {
-		if (lppaca[i].dyn_proc_status >= 2)
-			continue;
-
-		snprintf(p, 32 - (p - buf), "@%d", i);
-		dt_start_node(dt, buf);
-
-		dt_prop_str(dt, "device_type", "cpu");
-
-		index = lppaca[i].dyn_hv_phys_proc_index;
-		d = &xIoHriProcessorVpd[index];
-
-		dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
-		dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);
-
-		dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);
-		dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);
-
-		/* magic conversions to Hz copied from old code */
-		dt_prop_u32(dt, "clock-frequency",
-			((1UL << 34) * 1000000) / d->xProcFreq);
-		dt_prop_u32(dt, "timebase-frequency",
-			((1UL << 32) * 1000000) / d->xTimeBaseFreq);
-
-		dt_prop_u32(dt, "reg", i);
-
-		dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);
-
-		dt_end_node(dt);
-	}
-
-	dt_end_node(dt);
-}
-
-static void __init dt_model(struct iseries_flat_dt *dt)
-{
-	char buf[16] = "IBM,";
-
-	/* "IBM," + mfgId[2:3] + systemSerial[1:5] */
-	strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
-	strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
-	buf[11] = '\0';
-	dt_prop_str(dt, "system-id", buf);
-
-	/* "IBM," + machineType[0:4] */
-	strne2a(buf + 4, xItExtVpdPanel.machineType, 4);
-	buf[8] = '\0';
-	dt_prop_str(dt, "model", buf);
-
-	dt_prop_str(dt, "compatible", "IBM,iSeries");
-}
-
-static void __init dt_vdevices(struct iseries_flat_dt *dt)
-{
-	u32 reg = 0;
-	HvLpIndexMap vlan_map;
-	int i;
-	char buf[32];
-
-	dt_start_node(dt, "vdevice");
-	dt_prop_str(dt, "device_type", "vdevice");
-	dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");
-	dt_prop_u32(dt, "#address-cells", 1);
-	dt_prop_u32(dt, "#size-cells", 0);
-
-	snprintf(buf, sizeof(buf), "vty@%08x", reg);
-	dt_start_node(dt, buf);
-	dt_prop_str(dt, "device_type", "serial");
-	dt_prop_u32(dt, "reg", reg);
-	dt_end_node(dt);
-	reg++;
-
-	snprintf(buf, sizeof(buf), "v-scsi@%08x", reg);
-	dt_start_node(dt, buf);
-	dt_prop_str(dt, "device_type", "vscsi");
-	dt_prop_str(dt, "compatible", "IBM,v-scsi");
-	dt_prop_u32(dt, "reg", reg);
-	dt_end_node(dt);
-	reg++;
-
-	vlan_map = HvLpConfig_getVirtualLanIndexMap();
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
-		unsigned char mac_addr[ETH_ALEN];
-
-		if ((vlan_map & (0x8000 >> i)) == 0)
-			continue;
-		snprintf(buf, 32, "l-lan@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "network");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-l-lan");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-
-		mac_addr[0] = 0x02;
-		mac_addr[1] = 0x01;
-		mac_addr[2] = 0xff;
-		mac_addr[3] = i;
-		mac_addr[4] = 0xff;
-		mac_addr[5] = HvLpConfig_getLpIndex_outline();
-		dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);
-		dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);
-		dt_prop_u32(dt, "max-frame-size", 9000);
-		dt_prop_u32(dt, "address-bits", 48);
-
-		dt_end_node(dt);
-	}
-	reg += HVMAXARCHITECTEDVIRTUALLANS;
-
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) {
-		snprintf(buf, 32, "viodasd@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "block");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-viodasd");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-		dt_end_node(dt);
-	}
-	reg += HVMAXARCHITECTEDVIRTUALDISKS;
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) {
-		snprintf(buf, 32, "viocd@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "block");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-viocd");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-		dt_end_node(dt);
-	}
-	reg += HVMAXARCHITECTEDVIRTUALCDROMS;
-	for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) {
-		snprintf(buf, 32, "viotape@%08x", reg + i);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "byte");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-viotape");
-		dt_prop_u32(dt, "reg", reg + i);
-		dt_prop_u32(dt, "linux,unit_address", i);
-		dt_end_node(dt);
-	}
-
-	dt_end_node(dt);
-}
-
-struct pci_class_name {
-	u16 code;
-	char *name;
-	char *type;
-};
-
-static struct pci_class_name __initdata pci_class_name[] = {
-	{ PCI_CLASS_NETWORK_ETHERNET, "ethernet", "network" },
-};
-
-static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
-{
-	struct pci_class_name *cp;
-
-	for (cp = pci_class_name;
-			cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)
-		if (cp->code == class_code)
-			return cp;
-	return NULL;
-}
-
-/*
- * This assumes that the node slot is always on the primary bus!
- */
-static void __init scan_bridge_slot(struct iseries_flat_dt *dt,
-		HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)
-{
-	HvSubBusNumber sub_bus = bridge_info->subBusNumber;
-	u16 vendor_id;
-	u16 device_id;
-	u32 class_id;
-	int err;
-	char buf[32];
-	u32 reg[5];
-	int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
-	int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
-	HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
-	u8 devfn;
-	struct pci_class_name *cp;
-
-	/*
-	 * Connect all functions of any device found.
-	 */
-	for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
-		for (function = 0; function < 8; function++) {
-			HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
-					function);
-			err = HvCallXm_connectBusUnit(bus, sub_bus,
-					agent_id, 0);
-			if (err) {
-				if (err != 0x302)
-					printk(KERN_DEBUG
-						"connectBusUnit(%x, %x, %x) "
-						"== %x\n",
-						bus, sub_bus, agent_id, err);
-				continue;
-			}
-
-			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
-					PCI_VENDOR_ID, &vendor_id);
-			if (err) {
-				printk(KERN_DEBUG
-					"ReadVendor(%x, %x, %x) == %x\n",
-					bus, sub_bus, agent_id, err);
-				continue;
-			}
-			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
-					PCI_DEVICE_ID, &device_id);
-			if (err) {
-				printk(KERN_DEBUG
-					"ReadDevice(%x, %x, %x) == %x\n",
-					bus, sub_bus, agent_id, err);
-				continue;
-			}
-			err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
-					PCI_CLASS_REVISION , &class_id);
-			if (err) {
-				printk(KERN_DEBUG
-					"ReadClass(%x, %x, %x) == %x\n",
-					bus, sub_bus, agent_id, err);
-				continue;
-			}
-
-			devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
-					function);
-			cp = dt_find_pci_class_name(class_id >> 16);
-			if (cp && cp->name)
-				strncpy(buf, cp->name, sizeof(buf) - 1);
-			else
-				snprintf(buf, sizeof(buf), "pci%x,%x",
-						vendor_id, device_id);
-			buf[sizeof(buf) - 1] = '\0';
-			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-					"@%x", PCI_SLOT(devfn));
-			buf[sizeof(buf) - 1] = '\0';
-			if (function != 0)
-				snprintf(buf + strlen(buf),
-					sizeof(buf) - strlen(buf),
-					",%x", function);
-			dt_start_node(dt, buf);
-			reg[0] = (bus << 16) | (devfn << 8);
-			reg[1] = 0;
-			reg[2] = 0;
-			reg[3] = 0;
-			reg[4] = 0;
-			dt_prop_u32_list(dt, "reg", reg, 5);
-			if (cp && (cp->type || cp->name))
-				dt_prop_str(dt, "device_type",
-					cp->type ? cp->type : cp->name);
-			dt_prop_u32(dt, "vendor-id", vendor_id);
-			dt_prop_u32(dt, "device-id", device_id);
-			dt_prop_u32(dt, "class-code", class_id >> 8);
-			dt_prop_u32(dt, "revision-id", class_id & 0xff);
-			dt_prop_u32(dt, "linux,subbus", sub_bus);
-			dt_prop_u32(dt, "linux,agent-id", agent_id);
-			dt_prop_u32(dt, "linux,logical-slot-number",
-					bridge_info->logicalSlotNumber);
-			dt_end_node(dt);
-
-		}
-	}
-}
-
-static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
-		HvSubBusNumber sub_bus, int id_sel)
-{
-	struct HvCallPci_BridgeInfo bridge_info;
-	HvAgentId agent_id;
-	int function;
-	int ret;
-
-	/* Note: hvSubBus and irq is always be 0 at this level! */
-	for (function = 0; function < 8; ++function) {
-		agent_id = ISERIES_PCI_AGENTID(id_sel, function);
-		ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
-		if (ret != 0) {
-			if (ret != 0xb)
-				printk(KERN_DEBUG "connectBusUnit(%x, %x, %x) "
-						"== %x\n",
-						bus, sub_bus, agent_id, ret);
-			continue;
-		}
-		printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
-				bus, id_sel, function, agent_id);
-		ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
-				iseries_hv_addr(&bridge_info),
-				sizeof(struct HvCallPci_BridgeInfo));
-		if (ret != 0)
-			continue;
-		printk("bridge info: type %x subbus %x "
-			"maxAgents %x maxsubbus %x logslot %x\n",
-			bridge_info.busUnitInfo.deviceType,
-			bridge_info.subBusNumber,
-			bridge_info.maxAgents,
-			bridge_info.maxSubBusNumber,
-			bridge_info.logicalSlotNumber);
-		if (bridge_info.busUnitInfo.deviceType ==
-				HvCallPci_BridgeDevice)
-			scan_bridge_slot(dt, bus, &bridge_info);
-		else
-			printk("PCI: Invalid Bridge Configuration(0x%02X)",
-				bridge_info.busUnitInfo.deviceType);
-	}
-}
-
-static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
-{
-	struct HvCallPci_DeviceInfo dev_info;
-	const HvSubBusNumber sub_bus = 0;	/* EADs is always 0. */
-	int err;
-	int id_sel;
-	const int max_agents = 8;
-
-	/*
-	 * Probe for EADs Bridges
-	 */
-	for (id_sel = 1; id_sel < max_agents; ++id_sel) {
-		err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,
-				iseries_hv_addr(&dev_info),
-				sizeof(struct HvCallPci_DeviceInfo));
-		if (err) {
-			if (err != 0x302)
-				printk(KERN_DEBUG "getDeviceInfo(%x, %x, %x) "
-						"== %x\n",
-						bus, sub_bus, id_sel, err);
-			continue;
-		}
-		if (dev_info.deviceType != HvCallPci_NodeDevice) {
-			printk(KERN_DEBUG "PCI: Invalid System Configuration"
-					"(0x%02X) for bus 0x%02x id 0x%02x.\n",
-					dev_info.deviceType, bus, id_sel);
-			continue;
-		}
-		scan_bridge(dt, bus, sub_bus, id_sel);
-	}
-}
-
-static void __init dt_pci_devices(struct iseries_flat_dt *dt)
-{
-	HvBusNumber bus;
-	char buf[32];
-	u32 buses[2];
-	int phb_num = 0;
-
-	/* Check all possible buses. */
-	for (bus = 0; bus < 256; bus++) {
-		int err = HvCallXm_testBus(bus);
-
-		if (err) {
-			/*
-			 * Check for Unexpected Return code, a clue that
-			 * something has gone wrong.
-			 */
-			if (err != 0x0301)
-				printk(KERN_ERR "Unexpected Return on Probe"
-						"(0x%02X): 0x%04X", bus, err);
-			continue;
-		}
-		printk("bus %d appears to exist\n", bus);
-		snprintf(buf, 32, "pci@%d", phb_num);
-		dt_start_node(dt, buf);
-		dt_prop_str(dt, "device_type", "pci");
-		dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
-		dt_prop_u32(dt, "#address-cells", 3);
-		dt_prop_u32(dt, "#size-cells", 2);
-		buses[0] = buses[1] = bus;
-		dt_prop_u32_list(dt, "bus-range", buses, 2);
-		scan_phb(dt, bus);
-		dt_end_node(dt);
-		phb_num++;
-	}
-}
-
-static void __init build_flat_dt(struct iseries_flat_dt *dt,
-		unsigned long phys_mem_size)
-{
-	u64 tmp[2];
-
-	dt_init(dt);
-
-	dt_start_node(dt, "");
-
-	dt_prop_u32(dt, "#address-cells", 2);
-	dt_prop_u32(dt, "#size-cells", 2);
-	dt_model(dt);
-
-	/* /memory */
-	dt_start_node(dt, "memory@0");
-	dt_prop_str(dt, "name", "memory");
-	dt_prop_str(dt, "device_type", "memory");
-	tmp[0] = 0;
-	tmp[1] = phys_mem_size;
-	dt_prop_u64_list(dt, "reg", tmp, 2);
-	dt_end_node(dt);
-
-	/* /chosen */
-	dt_start_node(dt, "chosen");
-	dt_prop_str(dt, "bootargs", cmd_line);
-	dt_end_node(dt);
-
-	dt_cpus(dt);
-
-	dt_vdevices(dt);
-	dt_pci_devices(dt);
-
-	dt_end_node(dt);
-
-	dt_push_u32(dt, OF_DT_END);
-}
-
 void * __init iSeries_early_setup(void)
 {
 	unsigned long phys_mem_size;
@@ -1294,9 +720,7 @@ void * __init iSeries_early_setup(void)
 
 	iSeries_get_cmdline();
 
-	build_flat_dt(&iseries_dt, phys_mem_size);
-
-	return (void *) __pa(&iseries_dt);
+	return (void *) __pa(build_flat_dt(phys_mem_size));
 }
 
 static void hvputc(char c)
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h
index 5213044..0a47ac5 100644
--- a/arch/powerpc/platforms/iseries/setup.h
+++ b/arch/powerpc/platforms/iseries/setup.h
@@ -21,4 +21,6 @@ extern unsigned long iSeries_get_boot_ti
 extern int iSeries_set_rtc_time(struct rtc_time *tm);
 extern void iSeries_get_rtc_time(struct rtc_time *tm);
 
+extern void *build_flat_dt(unsigned long phys_mem_size);
+
 #endif /* __ISERIES_SETUP_H__ */
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 10/14] powerpc: give iSeries device tree nodes better names
From: Stephen Rothwell @ 2006-05-19  6:58 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

Use the PCI class code to choose a name for the PCI device nodes and
to guess a device_type.  Failing that, base the name on the vendor and
device ids as specified in the spec.

Mark just about everything __init{data}.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/setup.c |   95 ++++++++++++++++++++++----------
 1 files changed, 66 insertions(+), 29 deletions(-)

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

753e3e7ff975a03dbcc5a761041f0f855215e7c5
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 9586414..5661bd0 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -725,7 +725,7 @@ struct iseries_flat_dt {
 
 static struct iseries_flat_dt iseries_dt;
 
-static void dt_init(struct iseries_flat_dt *dt)
+static void __init dt_init(struct iseries_flat_dt *dt)
 {
 	dt->header.off_mem_rsvmap =
 		offsetof(struct iseries_flat_dt, reserve_map);
@@ -748,7 +748,7 @@ static void dt_init(struct iseries_flat_
 	dt->reserve_map[1] = 0;
 }
 
-static void dt_check_blob(struct blob *b)
+static void __init dt_check_blob(struct blob *b)
 {
 	if (b->next >= (unsigned long)&b->next) {
 		DBG("Ran out of space in flat device tree blob!\n");
@@ -756,7 +756,7 @@ static void dt_check_blob(struct blob *b
 	}
 }
 
-static void dt_push_u32(struct iseries_flat_dt *dt, u32 value)
+static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
 {
 	*((u32*)dt->dt.next) = value;
 	dt->dt.next += sizeof(u32);
@@ -765,7 +765,7 @@ static void dt_push_u32(struct iseries_f
 }
 
 #ifdef notyet
-static void dt_push_u64(struct iseries_flat_dt *dt, u64 value)
+static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
 {
 	*((u64*)dt->dt.next) = value;
 	dt->dt.next += sizeof(u64);
@@ -774,7 +774,7 @@ static void dt_push_u64(struct iseries_f
 }
 #endif
 
-static unsigned long dt_push_bytes(struct blob *blob, char *data, int len)
+static unsigned long __init dt_push_bytes(struct blob *blob, char *data, int len)
 {
 	unsigned long start = blob->next - (unsigned long)blob->data;
 
@@ -786,7 +786,7 @@ static unsigned long dt_push_bytes(struc
 	return start;
 }
 
-static void dt_start_node(struct iseries_flat_dt *dt, char *name)
+static void __init dt_start_node(struct iseries_flat_dt *dt, char *name)
 {
 	dt_push_u32(dt, OF_DT_BEGIN_NODE);
 	dt_push_bytes(&dt->dt, name, strlen(name) + 1);
@@ -794,7 +794,8 @@ static void dt_start_node(struct iseries
 
 #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
 
-static void dt_prop(struct iseries_flat_dt *dt, char *name, char *data, int len)
+static void __init dt_prop(struct iseries_flat_dt *dt, char *name,
+		char *data, int len)
 {
 	unsigned long offset;
 
@@ -813,39 +814,42 @@ static void dt_prop(struct iseries_flat_
 	dt_push_bytes(&dt->dt, data, len);
 }
 
-static void dt_prop_str(struct iseries_flat_dt *dt, char *name, char *data)
+static void __init dt_prop_str(struct iseries_flat_dt *dt, char *name,
+		char *data)
 {
 	dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
 }
 
-static void dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
+static void __init dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
 {
 	dt_prop(dt, name, (char *)&data, sizeof(u32));
 }
 
-static void dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
+static void __init dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
 {
 	dt_prop(dt, name, (char *)&data, sizeof(u64));
 }
 
-static void dt_prop_u64_list(struct iseries_flat_dt *dt, char *name, u64 *data, int n)
+static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, char *name,
+		u64 *data, int n)
 {
 	dt_prop(dt, name, (char *)data, sizeof(u64) * n);
 }
 
-static void dt_prop_u32_list(struct iseries_flat_dt *dt, char *name, u32 *data, int n)
+static void __init dt_prop_u32_list(struct iseries_flat_dt *dt, char *name,
+		u32 *data, int n)
 {
 	dt_prop(dt, name, (char *)data, sizeof(u32) * n);
 }
 
 #ifdef notyet
-static void dt_prop_empty(struct iseries_flat_dt *dt, char *name)
+static void __init dt_prop_empty(struct iseries_flat_dt *dt, char *name)
 {
 	dt_prop(dt, name, NULL, 0);
 }
 #endif
 
-static void dt_cpus(struct iseries_flat_dt *dt)
+static void __init dt_cpus(struct iseries_flat_dt *dt)
 {
 	unsigned char buf[32];
 	unsigned char *p;
@@ -899,7 +903,7 @@ static void dt_cpus(struct iseries_flat_
 	dt_end_node(dt);
 }
 
-static void dt_model(struct iseries_flat_dt *dt)
+static void __init dt_model(struct iseries_flat_dt *dt)
 {
 	char buf[16] = "IBM,";
 
@@ -917,7 +921,7 @@ static void dt_model(struct iseries_flat
 	dt_prop_str(dt, "compatible", "IBM,iSeries");
 }
 
-static void dt_vdevices(struct iseries_flat_dt *dt)
+static void __init dt_vdevices(struct iseries_flat_dt *dt)
 {
 	u32 reg = 0;
 	HvLpIndexMap vlan_map;
@@ -1006,11 +1010,32 @@ static void dt_vdevices(struct iseries_f
 	dt_end_node(dt);
 }
 
+struct pci_class_name {
+	u16 code;
+	char *name;
+	char *type;
+};
+
+static struct pci_class_name __initdata pci_class_name[] = {
+	{ PCI_CLASS_NETWORK_ETHERNET, "ethernet", "network" },
+};
+
+static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
+{
+	struct pci_class_name *cp;
+
+	for (cp = pci_class_name;
+			cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)
+		if (cp->code == class_code)
+			return cp;
+	return NULL;
+}
+
 /*
  * This assumes that the node slot is always on the primary bus!
  */
-static void scan_bridge_slot(struct iseries_flat_dt *dt, HvBusNumber bus,
-		struct HvCallPci_BridgeInfo *bridge_info)
+static void __init scan_bridge_slot(struct iseries_flat_dt *dt,
+		HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)
 {
 	HvSubBusNumber sub_bus = bridge_info->subBusNumber;
 	u16 vendor_id;
@@ -1022,14 +1047,14 @@ static void scan_bridge_slot(struct iser
 	int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
 	int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
 	HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
+	u8 devfn;
+	struct pci_class_name *cp;
 
 	/*
 	 * Connect all functions of any device found.
 	 */
 	for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
 		for (function = 0; function < 8; function++) {
-			u8 devfn;
-
 			HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
 					function);
 			err = HvCallXm_connectBusUnit(bus, sub_bus,
@@ -1070,12 +1095,20 @@ static void scan_bridge_slot(struct iser
 
 			devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
 					function);
-			if (function == 0)
-				snprintf(buf, sizeof(buf), "pci@%x",
-						PCI_SLOT(devfn));
+			cp = dt_find_pci_class_name(class_id >> 16);
+			if (cp && cp->name)
+				strncpy(buf, cp->name, sizeof(buf) - 1);
 			else
-				snprintf(buf, sizeof(buf), "pci@%x,%d",
-						PCI_SLOT(devfn), function);
+				snprintf(buf, sizeof(buf), "pci%x,%x",
+						vendor_id, device_id);
+			buf[sizeof(buf) - 1] = '\0';
+			snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+					"@%x", PCI_SLOT(devfn));
+			buf[sizeof(buf) - 1] = '\0';
+			if (function != 0)
+				snprintf(buf + strlen(buf),
+					sizeof(buf) - strlen(buf),
+					",%x", function);
 			dt_start_node(dt, buf);
 			reg[0] = (bus << 16) | (devfn << 8);
 			reg[1] = 0;
@@ -1083,6 +1116,9 @@ static void scan_bridge_slot(struct iser
 			reg[3] = 0;
 			reg[4] = 0;
 			dt_prop_u32_list(dt, "reg", reg, 5);
+			if (cp && (cp->type || cp->name))
+				dt_prop_str(dt, "device_type",
+					cp->type ? cp->type : cp->name);
 			dt_prop_u32(dt, "vendor-id", vendor_id);
 			dt_prop_u32(dt, "device-id", device_id);
 			dt_prop_u32(dt, "class-code", class_id >> 8);
@@ -1097,7 +1133,7 @@ static void scan_bridge_slot(struct iser
 	}
 }
 
-static void scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
+static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
 		HvSubBusNumber sub_bus, int id_sel)
 {
 	struct HvCallPci_BridgeInfo bridge_info;
@@ -1139,7 +1175,7 @@ static void scan_bridge(struct iseries_f
 	}
 }
 
-static void scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
+static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
 {
 	struct HvCallPci_DeviceInfo dev_info;
 	const HvSubBusNumber sub_bus = 0;	/* EADs is always 0. */
@@ -1171,7 +1207,7 @@ static void scan_phb(struct iseries_flat
 	}
 }
 
-static void dt_pci_devices(struct iseries_flat_dt *dt)
+static void __init dt_pci_devices(struct iseries_flat_dt *dt)
 {
 	HvBusNumber bus;
 	char buf[32];
@@ -1207,7 +1243,8 @@ static void dt_pci_devices(struct iserie
 	}
 }
 
-static void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
+static void __init build_flat_dt(struct iseries_flat_dt *dt,
+		unsigned long phys_mem_size)
 {
 	u64 tmp[2];
 
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 09/14] powerpc: make iSeries flat device tree stuff static
From: Stephen Rothwell @ 2006-05-19  6:55 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>


Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/setup.c |   40 ++++++++++++++++++--------------
 1 files changed, 22 insertions(+), 18 deletions(-)

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

ef5523ad5d01ff256b792ef5a44719c4a56771d9
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 0f49412..9586414 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -723,9 +723,9 @@ struct iseries_flat_dt {
 	struct blob strings;
 };
 
-struct iseries_flat_dt iseries_dt;
+static struct iseries_flat_dt iseries_dt;
 
-void dt_init(struct iseries_flat_dt *dt)
+static void dt_init(struct iseries_flat_dt *dt)
 {
 	dt->header.off_mem_rsvmap =
 		offsetof(struct iseries_flat_dt, reserve_map);
@@ -748,7 +748,7 @@ void dt_init(struct iseries_flat_dt *dt)
 	dt->reserve_map[1] = 0;
 }
 
-void dt_check_blob(struct blob *b)
+static void dt_check_blob(struct blob *b)
 {
 	if (b->next >= (unsigned long)&b->next) {
 		DBG("Ran out of space in flat device tree blob!\n");
@@ -756,7 +756,7 @@ void dt_check_blob(struct blob *b)
 	}
 }
 
-void dt_push_u32(struct iseries_flat_dt *dt, u32 value)
+static void dt_push_u32(struct iseries_flat_dt *dt, u32 value)
 {
 	*((u32*)dt->dt.next) = value;
 	dt->dt.next += sizeof(u32);
@@ -764,15 +764,17 @@ void dt_push_u32(struct iseries_flat_dt 
 	dt_check_blob(&dt->dt);
 }
 
-void dt_push_u64(struct iseries_flat_dt *dt, u64 value)
+#ifdef notyet
+static void dt_push_u64(struct iseries_flat_dt *dt, u64 value)
 {
 	*((u64*)dt->dt.next) = value;
 	dt->dt.next += sizeof(u64);
 
 	dt_check_blob(&dt->dt);
 }
+#endif
 
-unsigned long dt_push_bytes(struct blob *blob, char *data, int len)
+static unsigned long dt_push_bytes(struct blob *blob, char *data, int len)
 {
 	unsigned long start = blob->next - (unsigned long)blob->data;
 
@@ -784,7 +786,7 @@ unsigned long dt_push_bytes(struct blob 
 	return start;
 }
 
-void dt_start_node(struct iseries_flat_dt *dt, char *name)
+static void dt_start_node(struct iseries_flat_dt *dt, char *name)
 {
 	dt_push_u32(dt, OF_DT_BEGIN_NODE);
 	dt_push_bytes(&dt->dt, name, strlen(name) + 1);
@@ -792,7 +794,7 @@ void dt_start_node(struct iseries_flat_d
 
 #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
 
-void dt_prop(struct iseries_flat_dt *dt, char *name, char *data, int len)
+static void dt_prop(struct iseries_flat_dt *dt, char *name, char *data, int len)
 {
 	unsigned long offset;
 
@@ -811,37 +813,39 @@ void dt_prop(struct iseries_flat_dt *dt,
 	dt_push_bytes(&dt->dt, data, len);
 }
 
-void dt_prop_str(struct iseries_flat_dt *dt, char *name, char *data)
+static void dt_prop_str(struct iseries_flat_dt *dt, char *name, char *data)
 {
 	dt_prop(dt, name, data, strlen(data) + 1); /* + 1 for NULL */
 }
 
-void dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
+static void dt_prop_u32(struct iseries_flat_dt *dt, char *name, u32 data)
 {
 	dt_prop(dt, name, (char *)&data, sizeof(u32));
 }
 
-void dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
+static void dt_prop_u64(struct iseries_flat_dt *dt, char *name, u64 data)
 {
 	dt_prop(dt, name, (char *)&data, sizeof(u64));
 }
 
-void dt_prop_u64_list(struct iseries_flat_dt *dt, char *name, u64 *data, int n)
+static void dt_prop_u64_list(struct iseries_flat_dt *dt, char *name, u64 *data, int n)
 {
 	dt_prop(dt, name, (char *)data, sizeof(u64) * n);
 }
 
-void dt_prop_u32_list(struct iseries_flat_dt *dt, char *name, u32 *data, int n)
+static void dt_prop_u32_list(struct iseries_flat_dt *dt, char *name, u32 *data, int n)
 {
 	dt_prop(dt, name, (char *)data, sizeof(u32) * n);
 }
 
-void dt_prop_empty(struct iseries_flat_dt *dt, char *name)
+#ifdef notyet
+static void dt_prop_empty(struct iseries_flat_dt *dt, char *name)
 {
 	dt_prop(dt, name, NULL, 0);
 }
+#endif
 
-void dt_cpus(struct iseries_flat_dt *dt)
+static void dt_cpus(struct iseries_flat_dt *dt)
 {
 	unsigned char buf[32];
 	unsigned char *p;
@@ -895,7 +899,7 @@ void dt_cpus(struct iseries_flat_dt *dt)
 	dt_end_node(dt);
 }
 
-void dt_model(struct iseries_flat_dt *dt)
+static void dt_model(struct iseries_flat_dt *dt)
 {
 	char buf[16] = "IBM,";
 
@@ -913,7 +917,7 @@ void dt_model(struct iseries_flat_dt *dt
 	dt_prop_str(dt, "compatible", "IBM,iSeries");
 }
 
-void dt_vdevices(struct iseries_flat_dt *dt)
+static void dt_vdevices(struct iseries_flat_dt *dt)
 {
 	u32 reg = 0;
 	HvLpIndexMap vlan_map;
@@ -1203,7 +1207,7 @@ static void dt_pci_devices(struct iserie
 	}
 }
 
-void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
+static void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
 {
 	u64 tmp[2];
 
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 08/14] powerpc: clean up iSeries PCI probe
From: Stephen Rothwell @ 2006-05-19  6:54 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>


Only scan the host bridges and then use the existing pci_devs_phb_init()
routine.

Also fix typo in setup of reg property.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/kernel/pci_dn.c           |    6 +++++
 arch/powerpc/platforms/iseries/pci.c   |   42 +++++++++++---------------------
 arch/powerpc/platforms/iseries/setup.c |    2 +-
 3 files changed, 21 insertions(+), 29 deletions(-)

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

979e33e7df3519bb4bbc550ad7e52b5ad2b30221
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 12c4c9e..1c18953 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -31,6 +31,7 @@ #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #include <asm/pSeries_reconfig.h>
 #include <asm/ppc-pci.h>
+#include <asm/firmware.h>
 
 /*
  * Traverse_func that inits the PCI fields of the device node.
@@ -59,6 +60,11 @@ static void * __devinit update_dn_pci_in
 		pdn->busno = (regs[0] >> 16) & 0xff;
 		pdn->devfn = (regs[0] >> 8) & 0xff;
 	}
+	if (firmware_has_feature(FW_FEATURE_ISERIES)) {
+		u32 *busp = (u32 *)get_property(dn, "linux,subbus", NULL);
+		if (busp)
+			pdn->bussubno = *busp;
+	}
 
 	pdn->pci_ext_config_space = (type && *type == 1);
 	return NULL;
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 86a8698..35bcc98 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -166,13 +166,21 @@ static void pci_Log_Error(char *Error_Te
 void iSeries_pcibios_init(void)
 {
 	struct pci_controller *phb;
-	struct device_node *node;
-	struct device_node *dn;
+	struct device_node *root = of_find_node_by_path("/");
+	struct device_node *node = NULL;
 
-	for_each_node_by_type(node, "pci") {
+	if (root == NULL) {
+		printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
+				"of device tree\n");
+		return;
+	}
+	while ((node = of_get_next_child(root, node)) != NULL) {
 		HvBusNumber bus;
 		u32 *busp;
 
+		if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
+			continue;
+
 		busp = (u32 *)get_property(node, "bus-range", NULL);
 		if (busp == NULL)
 			continue;
@@ -186,33 +194,11 @@ void iSeries_pcibios_init(void)
 		phb->first_busno = bus;
 		phb->last_busno = bus;
 		phb->ops = &iSeries_pci_ops;
+	}
 
-		/* Find and connect the devices. */
-		for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) {
-			struct pci_dn *pdn;
-			u32 *reg;
-
-			reg = (u32 *)get_property(dn, "reg", NULL);
-			if (reg == NULL) {
-				printk(KERN_DEBUG "no reg property!\n");
-				continue;
-			}
-			busp = (u32 *)get_property(dn, "linux,subbus", NULL);
-			if (busp == NULL) {
-				printk(KERN_DEBUG "no subbus property!\n");
-				continue;
-			}
+	of_node_put(root);
 
-			pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
-			if (pdn == NULL)
-				return;
-			dn->data = pdn;
-			pdn->node = dn;
-			pdn->busno = bus;
-			pdn->devfn = (reg[0] >> 8) & 0xff;
-			pdn->bussubno = *busp;
-		}
-	}
+	pci_devs_phb_init();
 }
 
 /*
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index d83f5ed..0f49412 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -1073,7 +1073,7 @@ static void scan_bridge_slot(struct iser
 				snprintf(buf, sizeof(buf), "pci@%x,%d",
 						PCI_SLOT(devfn), function);
 			dt_start_node(dt, buf);
-			reg[0] = (bus << 18) | (devfn << 8);
+			reg[0] = (bus << 16) | (devfn << 8);
 			reg[1] = 0;
 			reg[2] = 0;
 			reg[3] = 0;
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 07/14] powerpc: iSeries PCI devices can now have a devpsec attribute
From: Stephen Rothwell @ 2006-05-19  6:53 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>


Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/kernel/pci_64.c |    7 ++-----
 1 files changed, 2 insertions(+), 5 deletions(-)

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

bfe21d083414576fccd84ead574adffea99968c1
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index e1b3b3e..30a4e6a 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -886,8 +886,8 @@ int pci_mmap_page_range(struct pci_dev *
 	return ret;
 }
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t pci_show_devspec(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	struct pci_dev *pdev;
 	struct device_node *np;
@@ -899,13 +899,10 @@ static ssize_t pci_show_devspec(struct d
 	return sprintf(buf, "%s", np->full_name);
 }
 static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
 
 void pcibios_add_platform_entries(struct pci_dev *pdev)
 {
-#ifdef CONFIG_PPC_MULTIPLATFORM
 	device_create_file(&pdev->dev, &dev_attr_devspec);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
 }
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 06/14] powerpc: remove LogicalSlot from pci_dn
From: Stephen Rothwell @ 2006-05-19  6:51 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

As we now store enough information in the device_node.

Also the Flags field was not used either, do remove that.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/iommu.c |    5 ++++-
 arch/powerpc/platforms/iseries/pci.c   |    8 --------
 include/asm-powerpc/pci-bridge.h       |    4 ----
 3 files changed, 4 insertions(+), 13 deletions(-)

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

bf52061e7db75eb167e5f7749d706614de5bcc81
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index 75a5a1e..a992f6a 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -162,10 +162,13 @@ void iommu_devnode_init_iSeries(struct d
 {
 	struct iommu_table *tbl;
 	struct pci_dn *pdn = PCI_DN(dn);
+	u32 *lsn = (u32 *)get_property(dn, "linux,logical-slot-number", NULL);
+
+	BUG_ON(lsn == NULL);
 
 	tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
 
-	iommu_table_getparms_iSeries(pdn->busno, pdn->LogicalSlot, 0, tbl);
+	iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl);
 
 	/* Look for existing tce table */
 	pdn->iommu_table = iommu_table_find(tbl);
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index edaafbb..86a8698 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -191,7 +191,6 @@ void iSeries_pcibios_init(void)
 		for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) {
 			struct pci_dn *pdn;
 			u32 *reg;
-			u32 *lsn;
 
 			reg = (u32 *)get_property(dn, "reg", NULL);
 			if (reg == NULL) {
@@ -203,12 +202,6 @@ void iSeries_pcibios_init(void)
 				printk(KERN_DEBUG "no subbus property!\n");
 				continue;
 			}
-			lsn = (u32 *)get_property(dn,
-					"linux,logical-slot-number", NULL);
-			if (lsn == NULL) {
-				printk(KERN_DEBUG "no logical-slot-number\n");
-				continue;
-			}
 
 			pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
 			if (pdn == NULL)
@@ -218,7 +211,6 @@ void iSeries_pcibios_init(void)
 			pdn->busno = bus;
 			pdn->devfn = (reg[0] >> 8) & 0xff;
 			pdn->bussubno = *busp;
-			pdn->LogicalSlot = *lsn;
 		}
 	}
 }
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 09079e4..84a3075 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -78,10 +78,6 @@ #endif
 	struct	iommu_table *iommu_table;	/* for phb's or bridges */
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 	struct	device_node *node;	/* back-pointer to the device_node */
-#ifdef CONFIG_PPC_ISERIES
-	int	Flags;			/* Possible flags(disable/bist)*/
-	u8	LogicalSlot;		/* Hv Slot Index for Tces */
-#endif
 	u32	config_space[16];	/* saved PCI config space */
 };
 
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 05/14] powerpc: remove Irq from pci_dn
From: Stephen Rothwell @ 2006-05-19  6:50 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

As we now store enough information in the device_node to allocate the
irq number in pcibios_final_fixup.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/pci.c |   53 ++++++++++++++++++----------------
 include/asm-powerpc/pci-bridge.h     |    1 -
 2 files changed, 28 insertions(+), 26 deletions(-)

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

0a0cf362cf41de98069fb817acf23a4d041b45f4
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 5bc08d4..edaafbb 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -190,9 +190,6 @@ void iSeries_pcibios_init(void)
 		/* Find and connect the devices. */
 		for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) {
 			struct pci_dn *pdn;
-			u8 irq;
-			int err;
-			u32 *agent;
 			u32 *reg;
 			u32 *lsn;
 
@@ -206,11 +203,6 @@ void iSeries_pcibios_init(void)
 				printk(KERN_DEBUG "no subbus property!\n");
 				continue;
 			}
-			agent = (u32 *)get_property(dn, "linux,agent-id", NULL);
-			if (agent == NULL) {
-				printk(KERN_DEBUG "no agent-id\n");
-				continue;
-			}
 			lsn = (u32 *)get_property(dn,
 					"linux,logical-slot-number", NULL);
 			if (lsn == NULL) {
@@ -218,21 +210,6 @@ void iSeries_pcibios_init(void)
 				continue;
 			}
 
-			irq = iSeries_allocate_IRQ(bus, 0, *busp);
-			err = HvCallXm_connectBusUnit(bus, *busp, *agent, irq);
-			if (err) {
-				pci_Log_Error("Connect Bus Unit",
-					      bus, *busp, *agent, err);
-				continue;
-			}
-			err = HvCallPci_configStore8(bus, *busp, *agent,
-					PCI_INTERRUPT_LINE, irq);
-			if (err) {
-				pci_Log_Error("PciCfgStore Irq Failed!",
-						bus, *busp, *agent, err);
-				continue;
-			}
-
 			pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
 			if (pdn == NULL)
 				return;
@@ -241,7 +218,6 @@ void iSeries_pcibios_init(void)
 			pdn->busno = bus;
 			pdn->devfn = (reg[0] >> 8) & 0xff;
 			pdn->bussubno = *busp;
-			pdn->Irq = irq;
 			pdn->LogicalSlot = *lsn;
 		}
 	}
@@ -266,6 +242,34 @@ void __init iSeries_pci_final_fixup(void
 		       pdev->bus->number, pdev->devfn, node);
 
 		if (node != NULL) {
+			struct pci_dn *pdn = PCI_DN(node);
+			u32 *agent;
+
+			agent = (u32 *)get_property(node, "linux,agent-id",
+					NULL);
+			if ((pdn != NULL) && (agent != NULL)) {
+				u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
+						pdn->bussubno);
+				int err;
+
+				err = HvCallXm_connectBusUnit(pdn->busno, pdn->bussubno,
+						*agent, irq);
+				if (err)
+					pci_Log_Error("Connect Bus Unit",
+						pdn->busno, pdn->bussubno, *agent, err);
+				else {
+					err = HvCallPci_configStore8(pdn->busno, pdn->bussubno,
+							*agent,
+							PCI_INTERRUPT_LINE,
+							irq);
+					if (err)
+						pci_Log_Error("PciCfgStore Irq Failed!",
+							pdn->busno, pdn->bussubno, *agent, err);
+				}
+				if (!err)
+					pdev->irq = irq;
+			}
+
 			++DeviceCount;
 			pdev->sysdata = (void *)node;
 			PCI_DN(node)->pcidev = pdev;
@@ -275,7 +279,6 @@ void __init iSeries_pci_final_fixup(void
 		} else
 			printk("PCI: Device Tree not found for 0x%016lX\n",
 					(unsigned long)pdev);
-		pdev->irq = PCI_DN(node)->Irq;
 	}
 	iSeries_activate_IRQs();
 	mf_display_src(0xC9000200);
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 59794b4..09079e4 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -79,7 +79,6 @@ #endif
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 	struct	device_node *node;	/* back-pointer to the device_node */
 #ifdef CONFIG_PPC_ISERIES
-	int	Irq;			/* Assigned IRQ */
 	int	Flags;			/* Possible flags(disable/bist)*/
 	u8	LogicalSlot;		/* Hv Slot Index for Tces */
 #endif
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 04/14] powerpc: remove iSeries_Global_Device_List
From: Stephen Rothwell @ 2006-05-19  6:48 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

We can now scan the list of device nodes instead.  This also allows us
to remove the Device_list member of struct pci_dn.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/iommu.c |   15 +++++++++------
 arch/powerpc/platforms/iseries/pci.c   |   14 ++++++--------
 include/asm-powerpc/pci-bridge.h       |    1 -
 3 files changed, 15 insertions(+), 15 deletions(-)

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

80052bf80f481996ffec6dddc8fab45bb36db0a3
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index 3ac2206..75a5a1e 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -32,13 +32,11 @@ #include <asm/iommu.h>
 #include <asm/tce.h>
 #include <asm/machdep.h>
 #include <asm/abs_addr.h>
+#include <asm/prom.h>
 #include <asm/pci-bridge.h>
 #include <asm/iseries/hv_call_xm.h>
 #include <asm/iseries/iommu.h>
 
-extern struct list_head iSeries_Global_Device_List;
-
-
 static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
 		unsigned long uaddr, enum dma_data_direction direction)
 {
@@ -140,10 +138,15 @@ #ifdef CONFIG_PCI
  */
 static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
 {
-	struct pci_dn *pdn;
+	struct device_node *node;
+
+	for (node = NULL; (node = of_find_all_nodes(node)); ) {
+		struct pci_dn *pdn = PCI_DN(node);
+		struct iommu_table *it;
 
-	list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) {
-		struct iommu_table *it = pdn->iommu_table;
+		if (pdn == NULL)
+			continue;
+		it = pdn->iommu_table;
 		if ((it != NULL) &&
 		    (it->it_type == TCE_PCI) &&
 		    (it->it_offset == tbl->it_offset) &&
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 9d571e7..5bc08d4 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -50,8 +50,6 @@ #include "call_pci.h"
  */
 static struct device_node *find_Device_Node(int bus, int devfn);
 
-LIST_HEAD(iSeries_Global_Device_List);
-
 static int Pci_Retry_Max = 3;	/* Only retry 3 times  */
 static int Pci_Error_Flag = 1;	/* Set Retry Error on. */
 
@@ -245,8 +243,6 @@ void iSeries_pcibios_init(void)
 			pdn->bussubno = *busp;
 			pdn->Irq = irq;
 			pdn->LogicalSlot = *lsn;
-			list_add_tail(&pdn->Device_List,
-					&iSeries_Global_Device_List);
 		}
 	}
 }
@@ -338,11 +334,13 @@ EXPORT_SYMBOL(iSeries_memcpy_fromio);
  */
 static struct device_node *find_Device_Node(int bus, int devfn)
 {
-	struct pci_dn *pdn;
+	struct device_node *node;
+
+	for (node = NULL; (node = of_find_all_nodes(node)); ) {
+		struct pci_dn *pdn = PCI_DN(node);
 
-	list_for_each_entry(pdn, &iSeries_Global_Device_List, Device_List) {
-		if ((bus == pdn->busno) && (devfn == pdn->devfn))
-			return pdn->node;
+		if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))
+			return node;
 	}
 	return NULL;
 }
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 38de92d..59794b4 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -79,7 +79,6 @@ #endif
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 	struct	device_node *node;	/* back-pointer to the device_node */
 #ifdef CONFIG_PPC_ISERIES
-	struct	list_head Device_List;
 	int	Irq;			/* Assigned IRQ */
 	int	Flags;			/* Possible flags(disable/bist)*/
 	u8	LogicalSlot;		/* Hv Slot Index for Tces */
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 03/14] powerpc: move iSeries PCI devices to the device tree
From: Stephen Rothwell @ 2006-05-19  6:46 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

Move the probing of PCI devices to setup.c and put them all into the
flattened device tree.  The later probing is now done by traversing the
device tree.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/irq.c   |    7 -
 arch/powerpc/platforms/iseries/irq.h   |    2 
 arch/powerpc/platforms/iseries/pci.c   |  273 +++++++++-----------------------
 arch/powerpc/platforms/iseries/setup.c |  204 ++++++++++++++++++++++++
 4 files changed, 286 insertions(+), 200 deletions(-)

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

97c92bf9859c9d883da1b8459f62dec2ab20804e
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index be3fbfc..62bbbcf 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -42,6 +42,7 @@ #include <asm/iseries/hv_call_xm.h>
 #include <asm/iseries/it_lp_queue.h>
 
 #include "irq.h"
+#include "pci.h"
 #include "call_pci.h"
 
 #if defined(CONFIG_SMP)
@@ -312,12 +313,12 @@ static hw_irq_controller iSeries_IRQ_han
  * Note that sub_bus is always 0 (at the moment at least).
  */
 int __init iSeries_allocate_IRQ(HvBusNumber bus,
-		HvSubBusNumber sub_bus, HvAgentId dev_id)
+		HvSubBusNumber sub_bus, u32 bsubbus)
 {
 	int virtirq;
 	unsigned int realirq;
-	u8 idsel = (dev_id >> 4);
-	u8 function = dev_id & 7;
+	u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
+	u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);
 
 	realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
 		+ function;
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
index b9c801b..188aa80 100644
--- a/arch/powerpc/platforms/iseries/irq.h
+++ b/arch/powerpc/platforms/iseries/irq.h
@@ -2,7 +2,7 @@ #ifndef	_ISERIES_IRQ_H
 #define	_ISERIES_IRQ_H
 
 extern void iSeries_init_IRQ(void);
-extern int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, HvAgentId);
+extern int  iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
 extern void iSeries_activate_IRQs(void);
 extern int iSeries_get_irq(struct pt_regs *);
 
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 91a9474..9d571e7 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -49,14 +49,9 @@ #include "call_pci.h"
  * Forward declares of prototypes.
  */
 static struct device_node *find_Device_Node(int bus, int devfn);
-static void scan_PHB_slots(struct pci_controller *Phb);
-static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel);
-static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info);
 
 LIST_HEAD(iSeries_Global_Device_List);
 
-static int DeviceCount;
-
 static int Pci_Retry_Max = 3;	/* Only retry 3 times  */
 static int Pci_Error_Flag = 1;	/* Set Retry Error on. */
 
@@ -162,32 +157,6 @@ static void pci_Log_Error(char *Error_Te
 }
 
 /*
- * build_device_node(u16 Bus, int SubBus, u8 DevFn)
- */
-static struct device_node *build_device_node(HvBusNumber Bus,
-		HvSubBusNumber SubBus, int AgentId, int Function)
-{
-	struct device_node *node;
-	struct pci_dn *pdn;
-
-	node = kzalloc(sizeof(struct device_node), GFP_KERNEL);
-	if (node == NULL)
-		return NULL;
-	pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
-	if (pdn == NULL) {
-		kfree(node);
-		return NULL;
-	}
-	node->data = pdn;
-	pdn->node = node;
-	list_add_tail(&pdn->Device_List, &iSeries_Global_Device_List);
-	pdn->busno = Bus;
-	pdn->bussubno = SubBus;
-	pdn->devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function);
-	return node;
-}
-
-/*
  * iSeries_pcibios_init
  *
  * Description:
@@ -199,33 +168,86 @@ static struct device_node *build_device_
 void iSeries_pcibios_init(void)
 {
 	struct pci_controller *phb;
-	HvBusNumber bus;
-
-	/* Check all possible buses. */
-	for (bus = 0; bus < 256; bus++) {
-		int ret = HvCallXm_testBus(bus);
-		if (ret == 0) {
-			printk("bus %d appears to exist\n", bus);
-
-			phb = pcibios_alloc_controller(NULL);
-			if (phb == NULL)
-				return -ENOMEM;
+	struct device_node *node;
+	struct device_node *dn;
+
+	for_each_node_by_type(node, "pci") {
+		HvBusNumber bus;
+		u32 *busp;
+
+		busp = (u32 *)get_property(node, "bus-range", NULL);
+		if (busp == NULL)
+			continue;
+		bus = *busp;
+		printk("bus %d appears to exist\n", bus);
+		phb = pcibios_alloc_controller(node);
+		if (phb == NULL)
+			continue;
+
+		phb->pci_mem_offset = phb->local_number = bus;
+		phb->first_busno = bus;
+		phb->last_busno = bus;
+		phb->ops = &iSeries_pci_ops;
+
+		/* Find and connect the devices. */
+		for (dn = NULL; (dn = of_get_next_child(node, dn)) != NULL;) {
+			struct pci_dn *pdn;
+			u8 irq;
+			int err;
+			u32 *agent;
+			u32 *reg;
+			u32 *lsn;
+
+			reg = (u32 *)get_property(dn, "reg", NULL);
+			if (reg == NULL) {
+				printk(KERN_DEBUG "no reg property!\n");
+				continue;
+			}
+			busp = (u32 *)get_property(dn, "linux,subbus", NULL);
+			if (busp == NULL) {
+				printk(KERN_DEBUG "no subbus property!\n");
+				continue;
+			}
+			agent = (u32 *)get_property(dn, "linux,agent-id", NULL);
+			if (agent == NULL) {
+				printk(KERN_DEBUG "no agent-id\n");
+				continue;
+			}
+			lsn = (u32 *)get_property(dn,
+					"linux,logical-slot-number", NULL);
+			if (lsn == NULL) {
+				printk(KERN_DEBUG "no logical-slot-number\n");
+				continue;
+			}
 
-			phb->pci_mem_offset = phb->local_number = bus;
-			phb->first_busno = bus;
-			phb->last_busno = bus;
-			phb->ops = &iSeries_pci_ops;
+			irq = iSeries_allocate_IRQ(bus, 0, *busp);
+			err = HvCallXm_connectBusUnit(bus, *busp, *agent, irq);
+			if (err) {
+				pci_Log_Error("Connect Bus Unit",
+					      bus, *busp, *agent, err);
+				continue;
+			}
+			err = HvCallPci_configStore8(bus, *busp, *agent,
+					PCI_INTERRUPT_LINE, irq);
+			if (err) {
+				pci_Log_Error("PciCfgStore Irq Failed!",
+						bus, *busp, *agent, err);
+				continue;
+			}
 
-			/* Find and connect the devices. */
-			scan_PHB_slots(phb);
+			pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
+			if (pdn == NULL)
+				return;
+			dn->data = pdn;
+			pdn->node = dn;
+			pdn->busno = bus;
+			pdn->devfn = (reg[0] >> 8) & 0xff;
+			pdn->bussubno = *busp;
+			pdn->Irq = irq;
+			pdn->LogicalSlot = *lsn;
+			list_add_tail(&pdn->Device_List,
+					&iSeries_Global_Device_List);
 		}
-		/*
-		 * Check for Unexpected Return code, a clue that something
-		 * has gone wrong.
-		 */
-		else if (ret != 0x0301)
-			printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X",
-			       bus, ret);
 	}
 }
 
@@ -272,147 +294,6 @@ void pcibios_fixup_resources(struct pci_
 }
 
 /*
- * Loop through each node function to find usable EADs bridges.
- */
-static void scan_PHB_slots(struct pci_controller *Phb)
-{
-	struct HvCallPci_DeviceInfo *DevInfo;
-	HvBusNumber bus = Phb->local_number;	/* System Bus */
-	const HvSubBusNumber SubBus = 0;	/* EADs is always 0. */
-	int HvRc = 0;
-	int IdSel;
-	const int MaxAgents = 8;
-
-	DevInfo = kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
-	if (DevInfo == NULL)
-		return;
-
-	/*
-	 * Probe for EADs Bridges
-	 */
-	for (IdSel = 1; IdSel < MaxAgents; ++IdSel) {
-		HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel,
-				iseries_hv_addr(DevInfo),
-				sizeof(struct HvCallPci_DeviceInfo));
-		if (HvRc == 0) {
-			if (DevInfo->deviceType == HvCallPci_NodeDevice)
-				scan_EADS_bridge(bus, SubBus, IdSel);
-			else
-				printk("PCI: Invalid System Configuration(0x%02X)"
-				       " for bus 0x%02x id 0x%02x.\n",
-				       DevInfo->deviceType, bus, IdSel);
-		}
-		else
-			pci_Log_Error("getDeviceInfo", bus, SubBus, IdSel, HvRc);
-	}
-	kfree(DevInfo);
-}
-
-static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
-		int IdSel)
-{
-	struct HvCallPci_BridgeInfo *BridgeInfo;
-	HvAgentId AgentId;
-	int Function;
-	int HvRc;
-
-	BridgeInfo = (struct HvCallPci_BridgeInfo *)
-		kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL);
-	if (BridgeInfo == NULL)
-		return;
-
-	/* Note: hvSubBus and irq is always be 0 at this level! */
-	for (Function = 0; Function < 8; ++Function) {
-		AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
-		HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0);
-		if (HvRc == 0) {
-			printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
-			       bus, IdSel, Function, AgentId);
-			/*  Connect EADs: 0x18.00.12 = 0x00 */
-			HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
-					iseries_hv_addr(BridgeInfo),
-					sizeof(struct HvCallPci_BridgeInfo));
-			if (HvRc == 0) {
-				printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n",
-					BridgeInfo->busUnitInfo.deviceType,
-					BridgeInfo->subBusNumber,
-					BridgeInfo->maxAgents,
-					BridgeInfo->maxSubBusNumber,
-					BridgeInfo->logicalSlotNumber);
-				if (BridgeInfo->busUnitInfo.deviceType ==
-						HvCallPci_BridgeDevice)  {
-					/* Scan_Bridge_Slot...: 0x18.00.12 */
-					scan_bridge_slot(bus, BridgeInfo);
-				} else
-					printk("PCI: Invalid Bridge Configuration(0x%02X)",
-						BridgeInfo->busUnitInfo.deviceType);
-			}
-		} else if (HvRc != 0x000B)
-			pci_Log_Error("EADs Connect",
-					bus, SubBus, AgentId, HvRc);
-	}
-	kfree(BridgeInfo);
-}
-
-/*
- * This assumes that the node slot is always on the primary bus!
- */
-static int scan_bridge_slot(HvBusNumber Bus,
-		struct HvCallPci_BridgeInfo *BridgeInfo)
-{
-	struct device_node *node;
-	HvSubBusNumber SubBus = BridgeInfo->subBusNumber;
-	u16 VendorId = 0;
-	int HvRc = 0;
-	u8 Irq = 0;
-	int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus);
-	int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus);
-	HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function);
-
-	/* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
-	Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);
-
-	/*
-	 * Connect all functions of any device found.
-	 */
-	for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) {
-		for (Function = 0; Function < 8; ++Function) {
-			HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function);
-			HvRc = HvCallXm_connectBusUnit(Bus, SubBus,
-					AgentId, Irq);
-			if (HvRc != 0) {
-				pci_Log_Error("Connect Bus Unit",
-					      Bus, SubBus, AgentId, HvRc);
-				continue;
-			}
-
-			HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId,
-						      PCI_VENDOR_ID, &VendorId);
-			if (HvRc != 0) {
-				pci_Log_Error("Read Vendor",
-					      Bus, SubBus, AgentId, HvRc);
-				continue;
-			}
-			printk("read vendor ID: %x\n", VendorId);
-
-			/* FoundDevice: 0x18.28.10 = 0x12AE */
-			HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId,
-						      PCI_INTERRUPT_LINE, Irq);
-			if (HvRc != 0)
-				pci_Log_Error("PciCfgStore Irq Failed!",
-					      Bus, SubBus, AgentId, HvRc);
-
-			++DeviceCount;
-			node = build_device_node(Bus, SubBus, EADsIdSel, Function);
-			PCI_DN(node)->Irq = Irq;
-			PCI_DN(node)->LogicalSlot = BridgeInfo->logicalSlotNumber;
-
-		} /* for (Function = 0; Function < 8; ++Function) */
-	} /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */
-	return HvRc;
-}
-
-/*
  * I/0 Memory copy MUST use mmio commands on iSeries
  * To do; For performance, include the hv call directly
  */
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index fd6d0eb..d83f5ed 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -66,6 +66,8 @@ #include "processor_vpd.h"
 #include "main_store.h"
 #include "call_sm.h"
 #include "call_hpt.h"
+#include "call_pci.h"
+#include "pci.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -1000,6 +1002,207 @@ void dt_vdevices(struct iseries_flat_dt 
 	dt_end_node(dt);
 }
 
+/*
+ * This assumes that the node slot is always on the primary bus!
+ */
+static void scan_bridge_slot(struct iseries_flat_dt *dt, HvBusNumber bus,
+		struct HvCallPci_BridgeInfo *bridge_info)
+{
+	HvSubBusNumber sub_bus = bridge_info->subBusNumber;
+	u16 vendor_id;
+	u16 device_id;
+	u32 class_id;
+	int err;
+	char buf[32];
+	u32 reg[5];
+	int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
+	int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
+	HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
+
+	/*
+	 * Connect all functions of any device found.
+	 */
+	for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
+		for (function = 0; function < 8; function++) {
+			u8 devfn;
+
+			HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
+					function);
+			err = HvCallXm_connectBusUnit(bus, sub_bus,
+					agent_id, 0);
+			if (err) {
+				if (err != 0x302)
+					printk(KERN_DEBUG
+						"connectBusUnit(%x, %x, %x) "
+						"== %x\n",
+						bus, sub_bus, agent_id, err);
+				continue;
+			}
+
+			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
+					PCI_VENDOR_ID, &vendor_id);
+			if (err) {
+				printk(KERN_DEBUG
+					"ReadVendor(%x, %x, %x) == %x\n",
+					bus, sub_bus, agent_id, err);
+				continue;
+			}
+			err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
+					PCI_DEVICE_ID, &device_id);
+			if (err) {
+				printk(KERN_DEBUG
+					"ReadDevice(%x, %x, %x) == %x\n",
+					bus, sub_bus, agent_id, err);
+				continue;
+			}
+			err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
+					PCI_CLASS_REVISION , &class_id);
+			if (err) {
+				printk(KERN_DEBUG
+					"ReadClass(%x, %x, %x) == %x\n",
+					bus, sub_bus, agent_id, err);
+				continue;
+			}
+
+			devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
+					function);
+			if (function == 0)
+				snprintf(buf, sizeof(buf), "pci@%x",
+						PCI_SLOT(devfn));
+			else
+				snprintf(buf, sizeof(buf), "pci@%x,%d",
+						PCI_SLOT(devfn), function);
+			dt_start_node(dt, buf);
+			reg[0] = (bus << 18) | (devfn << 8);
+			reg[1] = 0;
+			reg[2] = 0;
+			reg[3] = 0;
+			reg[4] = 0;
+			dt_prop_u32_list(dt, "reg", reg, 5);
+			dt_prop_u32(dt, "vendor-id", vendor_id);
+			dt_prop_u32(dt, "device-id", device_id);
+			dt_prop_u32(dt, "class-code", class_id >> 8);
+			dt_prop_u32(dt, "revision-id", class_id & 0xff);
+			dt_prop_u32(dt, "linux,subbus", sub_bus);
+			dt_prop_u32(dt, "linux,agent-id", agent_id);
+			dt_prop_u32(dt, "linux,logical-slot-number",
+					bridge_info->logicalSlotNumber);
+			dt_end_node(dt);
+
+		}
+	}
+}
+
+static void scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
+		HvSubBusNumber sub_bus, int id_sel)
+{
+	struct HvCallPci_BridgeInfo bridge_info;
+	HvAgentId agent_id;
+	int function;
+	int ret;
+
+	/* Note: hvSubBus and irq is always be 0 at this level! */
+	for (function = 0; function < 8; ++function) {
+		agent_id = ISERIES_PCI_AGENTID(id_sel, function);
+		ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
+		if (ret != 0) {
+			if (ret != 0xb)
+				printk(KERN_DEBUG "connectBusUnit(%x, %x, %x) "
+						"== %x\n",
+						bus, sub_bus, agent_id, ret);
+			continue;
+		}
+		printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
+				bus, id_sel, function, agent_id);
+		ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
+				iseries_hv_addr(&bridge_info),
+				sizeof(struct HvCallPci_BridgeInfo));
+		if (ret != 0)
+			continue;
+		printk("bridge info: type %x subbus %x "
+			"maxAgents %x maxsubbus %x logslot %x\n",
+			bridge_info.busUnitInfo.deviceType,
+			bridge_info.subBusNumber,
+			bridge_info.maxAgents,
+			bridge_info.maxSubBusNumber,
+			bridge_info.logicalSlotNumber);
+		if (bridge_info.busUnitInfo.deviceType ==
+				HvCallPci_BridgeDevice)
+			scan_bridge_slot(dt, bus, &bridge_info);
+		else
+			printk("PCI: Invalid Bridge Configuration(0x%02X)",
+				bridge_info.busUnitInfo.deviceType);
+	}
+}
+
+static void scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
+{
+	struct HvCallPci_DeviceInfo dev_info;
+	const HvSubBusNumber sub_bus = 0;	/* EADs is always 0. */
+	int err;
+	int id_sel;
+	const int max_agents = 8;
+
+	/*
+	 * Probe for EADs Bridges
+	 */
+	for (id_sel = 1; id_sel < max_agents; ++id_sel) {
+		err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,
+				iseries_hv_addr(&dev_info),
+				sizeof(struct HvCallPci_DeviceInfo));
+		if (err) {
+			if (err != 0x302)
+				printk(KERN_DEBUG "getDeviceInfo(%x, %x, %x) "
+						"== %x\n",
+						bus, sub_bus, id_sel, err);
+			continue;
+		}
+		if (dev_info.deviceType != HvCallPci_NodeDevice) {
+			printk(KERN_DEBUG "PCI: Invalid System Configuration"
+					"(0x%02X) for bus 0x%02x id 0x%02x.\n",
+					dev_info.deviceType, bus, id_sel);
+			continue;
+		}
+		scan_bridge(dt, bus, sub_bus, id_sel);
+	}
+}
+
+static void dt_pci_devices(struct iseries_flat_dt *dt)
+{
+	HvBusNumber bus;
+	char buf[32];
+	u32 buses[2];
+	int phb_num = 0;
+
+	/* Check all possible buses. */
+	for (bus = 0; bus < 256; bus++) {
+		int err = HvCallXm_testBus(bus);
+
+		if (err) {
+			/*
+			 * Check for Unexpected Return code, a clue that
+			 * something has gone wrong.
+			 */
+			if (err != 0x0301)
+				printk(KERN_ERR "Unexpected Return on Probe"
+						"(0x%02X): 0x%04X", bus, err);
+			continue;
+		}
+		printk("bus %d appears to exist\n", bus);
+		snprintf(buf, 32, "pci@%d", phb_num);
+		dt_start_node(dt, buf);
+		dt_prop_str(dt, "device_type", "pci");
+		dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
+		dt_prop_u32(dt, "#address-cells", 3);
+		dt_prop_u32(dt, "#size-cells", 2);
+		buses[0] = buses[1] = bus;
+		dt_prop_u32_list(dt, "bus-range", buses, 2);
+		scan_phb(dt, bus);
+		dt_end_node(dt);
+		phb_num++;
+	}
+}
+
 void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
 {
 	u64 tmp[2];
@@ -1029,6 +1232,7 @@ void build_flat_dt(struct iseries_flat_d
 	dt_cpus(dt);
 
 	dt_vdevices(dt);
+	dt_pci_devices(dt);
 
 	dt_end_node(dt);
 
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 02/14] powerpc: reintroduce HvCallPci_configLoad32
From: Stephen Rothwell @ 2006-05-19  6:43 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev
In-Reply-To: <20060519164249.2dc43bc4.sfr@canb.auug.org.au>

This function was removed during iSeries cleanup but will prove useful
in the following patches.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/call_pci.h |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)

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

59ad1dcb0d8d81e3a96f869109315652abf271f7
diff --git a/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h
index 59d4e0a..dbdf698 100644
--- a/arch/powerpc/platforms/iseries/call_pci.h
+++ b/arch/powerpc/platforms/iseries/call_pci.h
@@ -145,6 +145,25 @@ static inline u64 HvCallPci_configLoad16
 	return retVal.rc;
 }
 
+static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
+		u8 deviceId, u32 offset, u32 *value)
+{
+	struct HvCallPci_DsaAddr dsa;
+	struct HvCallPci_LoadReturn retVal;
+
+	*((u64*)&dsa) = 0;
+
+	dsa.busNumber = busNumber;
+	dsa.subBusNumber = subBusNumber;
+	dsa.deviceId = deviceId;
+
+	HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);
+
+	*value = retVal.value;
+
+	return retVal.rc;
+}
+
 static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
 		u8 deviceId, u32 offset, u8 value)
 {
-- 
1.3.1.ge923

^ permalink raw reply related

* [PATCH 01/14] powerpc: tidy up iseries/pci.c
From: Stephen Rothwell @ 2006-05-19  6:42 UTC (permalink / raw)
  To: paulus; +Cc: ppc-dev

Remove some unused counters.

No need to allocate iomm_table and iobar_table, which means that
iomm_table_initialize is not longer needed.

Use kzalloc where sensible.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---

 arch/powerpc/platforms/iseries/pci.c |   78 +++++-----------------------------
 1 files changed, 11 insertions(+), 67 deletions(-)

This series of patches are intenede to put the iSeries PCI devices into
the flattened device tree.  Built and run on an iSeries 270 with a single
PCI ethernet.  Built for pSeries_defconfig.

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

039fac4f522c6207625993cd79bb2164dc0b91f1
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 428ffb5..91a9474 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -57,15 +57,6 @@ LIST_HEAD(iSeries_Global_Device_List);
 
 static int DeviceCount;
 
-/* Counters and control flags. */
-static long Pci_Io_Read_Count;
-static long Pci_Io_Write_Count;
-#if 0
-static long Pci_Cfg_Read_Count;
-static long Pci_Cfg_Write_Count;
-#endif
-static long Pci_Error_Count;
-
 static int Pci_Retry_Max = 3;	/* Only retry 3 times  */
 static int Pci_Error_Flag = 1;	/* Set Retry Error on. */
 
@@ -79,41 +70,19 @@ #define IOMM_TABLE_MAX_ENTRIES	1024
 #define IOMM_TABLE_ENTRY_SIZE	0x0000000000400000UL
 #define BASE_IO_MEMORY		0xE000000000000000UL
 
-static unsigned long max_io_memory = 0xE000000000000000UL;
+static unsigned long max_io_memory = BASE_IO_MEMORY;
 static long current_iomm_table_entry;
 
 /*
  * Lookup Tables.
  */
-static struct device_node **iomm_table;
-static u8 *iobar_table;
+static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
+static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES];
 
-/*
- * Static and Global variables
- */
-static char *pci_io_text = "iSeries PCI I/O";
+static const char pci_io_text[] = "iSeries PCI I/O";
 static DEFINE_SPINLOCK(iomm_table_lock);
 
 /*
- * iomm_table_initialize
- *
- * Allocates and initalizes the Address Translation Table and Bar
- * Tables to get them ready for use.  Must be called before any
- * I/O space is handed out to the device BARs.
- */
-static void iomm_table_initialize(void)
-{
-	spin_lock(&iomm_table_lock);
-	iomm_table = kmalloc(sizeof(*iomm_table) * IOMM_TABLE_MAX_ENTRIES,
-			GFP_KERNEL);
-	iobar_table = kmalloc(sizeof(*iobar_table) * IOMM_TABLE_MAX_ENTRIES,
-			GFP_KERNEL);
-	spin_unlock(&iomm_table_lock);
-	if ((iomm_table == NULL) || (iobar_table == NULL))
-		panic("PCI: I/O tables allocation failed.\n");
-}
-
-/*
  * iomm_table_allocate_entry
  *
  * Adds pci_dev entry in address translation table
@@ -140,9 +109,8 @@ static void iomm_table_allocate_entry(st
 	 */
 	spin_lock(&iomm_table_lock);
 	bar_res->name = pci_io_text;
-	bar_res->start =
+	bar_res->start = BASE_IO_MEMORY +
 		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
-	bar_res->start += BASE_IO_MEMORY;
 	bar_res->end = bar_res->start + bar_size - 1;
 	/*
 	 * Allocate the number of table entries needed for BAR.
@@ -154,7 +122,7 @@ static void iomm_table_allocate_entry(st
 		++current_iomm_table_entry;
 	}
 	max_io_memory = BASE_IO_MEMORY +
-		(IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry);
+		IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
 	spin_unlock(&iomm_table_lock);
 }
 
@@ -171,13 +139,10 @@ static void iomm_table_allocate_entry(st
  */
 static void allocate_device_bars(struct pci_dev *dev)
 {
-	struct resource *bar_res;
 	int bar_num;
 
-	for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) {
-		bar_res = &dev->resource[bar_num];
+	for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)
 		iomm_table_allocate_entry(dev, bar_num);
-	}
 }
 
 /*
@@ -205,10 +170,9 @@ static struct device_node *build_device_
 	struct device_node *node;
 	struct pci_dn *pdn;
 
-	node = kmalloc(sizeof(struct device_node), GFP_KERNEL);
+	node = kzalloc(sizeof(struct device_node), GFP_KERNEL);
 	if (node == NULL)
 		return NULL;
-	memset(node, 0, sizeof(struct device_node));
 	pdn = kzalloc(sizeof(*pdn), GFP_KERNEL);
 	if (pdn == NULL) {
 		kfree(node);
@@ -224,7 +188,7 @@ static struct device_node *build_device_
 }
 
 /*
- * unsigned long __init find_and_init_phbs(void)
+ * iSeries_pcibios_init
  *
  * Description:
  *   This function checks for all possible system PCI host bridges that connect
@@ -232,7 +196,7 @@ static struct device_node *build_device_
  *   ownership status.  A pci_controller is built for any bus which is partially
  *   owned or fully owned by this guest partition.
  */
-unsigned long __init find_and_init_phbs(void)
+void iSeries_pcibios_init(void)
 {
 	struct pci_controller *phb;
 	HvBusNumber bus;
@@ -263,18 +227,6 @@ unsigned long __init find_and_init_phbs(
 			printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X",
 			       bus, ret);
 	}
-	return 0;
-}
-
-/*
- * iSeries_pcibios_init
- *
- * Chance to initialize and structures or variable before PCI Bus walk.
- */
-void iSeries_pcibios_init(void)
-{
-	iomm_table_initialize();
-	find_and_init_phbs();
 }
 
 /*
@@ -331,8 +283,7 @@ static void scan_PHB_slots(struct pci_co
 	int IdSel;
 	const int MaxAgents = 8;
 
-	DevInfo = (struct HvCallPci_DeviceInfo*)
-		kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
+	DevInfo = kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL);
 	if (DevInfo == NULL)
 		return;
 
@@ -622,7 +573,6 @@ static int CheckReturnCode(char *TextHdr
 	if (ret != 0)  {
 		struct pci_dn *pdn = PCI_DN(DevNode);
 
-		++Pci_Error_Count;
 		(*retry)++;
 		printk("PCI: %s: Device 0x%04X:%02X  I/O Error(%2d): 0x%04X\n",
 				TextHdr, pdn->busno, pdn->devfn,
@@ -704,7 +654,6 @@ u8 iSeries_Read_Byte(const volatile void
 		return 0xff;
 	}
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0);
 	} while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0);
 
@@ -734,7 +683,6 @@ u16 iSeries_Read_Word(const volatile voi
 		return 0xffff;
 	}
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
 				BarOffset, 0);
 	} while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0);
@@ -765,7 +713,6 @@ u32 iSeries_Read_Long(const volatile voi
 		return 0xffffffff;
 	}
 	do {
-		++Pci_Io_Read_Count;
 		HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
 				BarOffset, 0);
 	} while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0);
@@ -803,7 +750,6 @@ void iSeries_Write_Byte(u8 data, volatil
 		return;
 	}
 	do {
-		++Pci_Io_Write_Count;
 		rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
 	} while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0);
 }
@@ -831,7 +777,6 @@ void iSeries_Write_Word(u16 data, volati
 		return;
 	}
 	do {
-		++Pci_Io_Write_Count;
 		rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0);
 	} while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
 }
@@ -859,7 +804,6 @@ void iSeries_Write_Long(u32 data, volati
 		return;
 	}
 	do {
-		++Pci_Io_Write_Count;
 		rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0);
 	} while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
 }
-- 
1.3.1.ge923

^ permalink raw reply related

* RE: [PATCH/2.6.17-rc4  0/10]  powerpc: add mpc7448hpc2 (Taiga) bo ard  support
From: Zang Roy-r61911 @ 2006-05-19  7:03 UTC (permalink / raw)
  To: Kumar Gala
  Cc: linuxppc-dev list, Yang Xin-Xin-r48390, Paul Mackerras,
	Alexandre.Bounine

> 
> On May 17, 2006, at 5:13 AM, Zang Roy-r61911 wrote:
> 
> > Hi, Paul
> >
> > 	This series of patch adds mpc7448hpc2 (taiga) board support in  
> > arch/powerpc.
> > 	Tsi108 chip of Tundra Semiconductor is also supported.
> >
> > Roy Zang
> 
> Can you post your .dts for us to take a look at.  I know Mark Greer  
> is looking at support for the 105/6/7 family of bridges and the 10x  
> family should have consistent flat device trees.
> 
> - kumar
> 
/*
 * MPC7448HPC2 (Taiga) board Device Tree Source
 *
 * Copyright 2006 Freescale Semiconductor Inc.
 * 2006 Roy Zang <Roy Zang at freescale.com>.
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */


/ {
	model = "mpc7448hpc2";
	compatible = "mpc74xx";
	#address-cells = <1>;
	#size-cells = <1>;
	linux,phandle = <100>;

	cpus {
		#cpus = <1>;
		#address-cells = <1>;
		#size-cells =<0>;
		linux,phandle = <200>;
				
		PowerPC,7448@0 {
			device_type = "cpu";
			reg = <0>;
			d-cache-line-size = <20>;	// 32 bytes
			i-cache-line-size = <20>;	// 32 bytes
			d-cache-size = <8000>;		// L1, 32K bytes
			i-cache-size = <8000>;		// L1, 32K bytes
			timebase-frequency = <0>;	// 33 MHz, from uboot
			clock-frequency = <0>;		// From U-Boot
			bus-frequency = <0>;		// From U-Boot
			32-bit;
			linux,phandle = <201>;
			linux,boot-cpu;
		};
	};

	memory {
		device_type = "memory";
		linux,phandle = <300>;
		reg = <00000000 20000000	// DDR2   512M at 0
		       >;
	};

  	tsi108@c0000000 {
		#address-cells = <1>;
		#size-cells = <1>;
		#interrupt-cells = <2>;
		device_type = "tsi-bridge";
		ranges = <00000000 c0000000 00010000>;
		reg = <c0000000 00010000>;
		bus-frequency = <0>;

		i2c@7000 {
			interrupt-parent = <7400>;
			interrupts = <E 3>;
			reg = <7000 400>;
			device_type = "i2c";
			compatible  = "tsi-i2c";
		};

		mdio@6000 {
			device_type = "mdio";
			compatible = "tsi-ethernet";	

			ethernet-phy@6000 {
				linux,phandle = <6000>;
				interrupt-parent = <7400>;
				interrupts = <2 1>;
				reg = <6000 50>;
				device_type = "ethernet-phy";
			};

			ethernet-phy@6400 {
				linux,phandle = <6400>;
				interrupt-parent = <7400>;
				interrupts = <2 1>;
				reg = <6400 50>;
				device_type = "ethernet-phy";
			};

		};

		ethernet@6200 {
			#size-cells = <0>;
			device_type = "network";
			model = "TSI-ETH";		
			compatible = "tsi-ethernet";	
			reg = <6200 200>;
			address = [ 00 06 D2 00 00 01 ];
			interrupts = <10 3 10 3 10 3>;
			interrupt-parent = <7400>;
			phy-handle = <6000>;
		};

		ethernet@6600 {
			#address-cells = <1>;
			#size-cells = <0>;
			device_type = "network";
			model = "TSI-ETH";		
			compatible = "tsi-ethernet";	
			reg = <6600 200>;
			address = [ 00 06 D2 00 00 02 ];
			interrupts = <11 3 11 3 11 3>;
			interrupt-parent = <7400>;
			phy-handle = <6400>;
		};

		serial@7808 {
			device_type = "serial";
			compatible = "ns16550";
			reg = <7808 200>;
			clock-frequency = <3f6b5a00>;
			interrupts = <c 3>;
			interrupt-parent = <7400>;
		};

		serial@7c08 {
			device_type = "serial";
			compatible = "ns16550";
			reg = <7c08 200>;
			clock-frequency = <3f6b5a00>;
			interrupts = <d 3>;
			interrupt-parent = <7400>;
		};

	  	pic@7400 {
			linux,phandle = <7400>;
			clock-frequency = <0>;
			interrupt-controller;
			#address-cells = <0>;
			#interrupt-cells = <2>;
			reg = <7400 400>;
			built-in;
			compatible = "chrp,open-pic";
			device_type = "open-pic";
                       	big-endian;
		};
		pci@1000 {
			compatible = "tsi10x";
			device_type = "pci";
			linux,phandle = <1000>;
			#interrupt-cells = <1>;
			#size-cells = <2>;
			#address-cells = <3>;
			reg = <1000 1000>;
			bus-range = <0 0>;
			ranges = <02000000 0 e0000000 e0000000 0 1A000000	
				  01000000 0 00000000 fa000000 0 00010000>;
			clock-frequency = <7f28154>;
			interrupt-parent = <7400>;
			interrupts = <8 0>;
			interrupt-map-mask = <f800 0 0 7>;
			interrupt-map = <

				/* IDSEL 0x11 */
				8800 0 0 1 7400 24 0
				8800 0 0 2 7400 25 0
				8800 0 0 3 7400 26 0
				8800 0 0 4 7400 27 0

				/* IDSEL 0x12 */
				9000 0 0 1 7400 25 0
				9000 0 0 2 7400 26 0
				9000 0 0 3 7400 27 0
				9000 0 0 4 7400 24 0

				/* IDSEL 0x13 */
				9800 0 0 1 7400 26 0
				9800 0 0 2 7400 27 0
				9800 0 0 3 7400 24 0
				9800 0 0 4 7400 25 0

				/* IDSEL 0x14 */
				a000 0 0 1 7400 27 0
				a000 0 0 2 7400 24 0
				a000 0 0 3 7400 25 0
				a000 0 0 4 7400 26 0
				>;
		};
	};

};

^ permalink raw reply

* powerpc.git updated
From: Paul Mackerras @ 2006-05-19  6:07 UTC (permalink / raw)
  To: linuxppc-dev

I just pushed a bunch of patches to the powerpc.git tree (master
branch) and pulled in Linus' current linux-2.6.git tree.  The list
below shows which patches are in there but not in Linus' tree yet.
These will all go upstream after 2.6.17 is released.  If you have a
patch that you want to go in that I haven't picked up yet, please
resend it.

Paul.

Andy Fleming:
      Add 85xx CDS to arch/powerpc

Anton Blanchard:
      powerpc: remove io_page_mask

Geoff Levand:
      powerpc: remove do-nothing cpu setup routines

Haren Myneni:
      powerpc: clear IPIs on kdump

Jeremy Kerr:
      powerpc: cell: use kzalloc in alloc_spu_context()
      powerpc: Add of_parse_dma_window()
      powerpc: pseries: Use generic dma-window parsing function

Jimi Xenidis:
      powerpc: Auto reserve of device tree blob

jimix@watson.ibm.com:
      powerpc: udbg_printf() formatting attribute

Kumar Gala:
      powerpc: provide ppc_md.panic() for both ppc32 & ppc64

Linas Vepstas:
      powerpc/pseries: clear PCI failure counter if no new failures
      powerpc/pseries: Increment fail counter in PCI recovery

Michael Ellerman:
      powerpc: Disable and EOI interrupts in machine_crash_shutdown()
      powerpc: Make early debugging options behave with oldconfig
      powerpc: Make early xmon logic immune to location of early parsing
      powerpc: Parse early parameters earlier
      powerpc: Unify mem= handling
      powerpc: Kdump header cleanup
      powerpc: Move crashkernel= handling into the kernel.

Michael Neuling:
      powerpc: whitespace cleanup in reg.h

mostrows@watson.ibm.com:
      powerpc: Create /proc/rtas, /proc/ppc64/rtas if RTAS exists.

Olof Johansson:
      powerpc: Quiet HVSI boot output
      powerpc: Quiet time init output
      powerpc: Quiet page order output
      powerpc: Quiet VETH version printk
      powerpc: Don't print chosen idle loop at every boot
      powerpc: Less verbose mem configuration output
      powerpc: Lack of ISA interrupts on XICS isn't dangerous
      powerpc: Quiet PCI init printouts
      powerpc: Quiet rtasd output at boot
      powerpc: Quiet oprofile output at boot
      powerpc: Remove stale iseries global
      powerpc: kill union tce_entry
      powerpc iommu: minor cleanup

Stephen Rothwell:
      powerpc: add all the iSeries virtual devices to the device tree
      powerpc: use the device tree for the iSeries vio bus probe
      powerpc: use a common vio_match_device routine
      powerpc: merge the rest of the vio code
      powerpc: update iseries_veth device-tree information
      powerpc: update iSeries viodasd device-tree entries
      powerpc: update iSeries vdevice
      powerpc: update iSeries viocd and viotape device-tree
      powerpc: the iSeries vio lan driver changed device type

Will Schmidt:
      nvram_print_partitions cosmetic fixup

^ permalink raw reply


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