]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
powerpc: Merge in the ppc64 version of the prom code.
authorPaul Mackerras <paulus@samba.org>
Thu, 6 Oct 2005 02:06:20 +0000 (12:06 +1000)
committerPaul Mackerras <paulus@samba.org>
Thu, 6 Oct 2005 02:06:20 +0000 (12:06 +1000)
This brings in the ppc64 version of prom_init.c, prom.c and btext.c
and makes them work for ppc32.  This also brings in the new calling
convention, where the first entry to the kernel (with r5 != 0) goes
to the prom_init code, which then restarts from the beginning (with
r5 == 0) after it has done its stuff.

For now this also brings in the ppc32 version of setup.c.  It also
merges lmb.h.

Signed-off-by: Paul Mackerras <paulus@samba.org>
15 files changed:
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/btext.c [new file with mode: 0644]
arch/powerpc/kernel/head.S
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/prom.c [new file with mode: 0644]
arch/powerpc/kernel/prom_init.c [new file with mode: 0644]
arch/powerpc/kernel/setup.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/pmac_setup.c
include/asm-powerpc/cputable.h
include/asm-powerpc/iommu.h [new file with mode: 0644]
include/asm-powerpc/lmb.h [new file with mode: 0644]
include/asm-powerpc/pSeries_reconfig.h [new file with mode: 0644]
include/asm-powerpc/prom.h [new file with mode: 0644]
include/asm-powerpc/rtas.h [new file with mode: 0644]
include/asm-powerpc/system.h

index be3f9d123a6d09fc40d57761a256573ba961f863..4842e82dbc2ba66e9eb03474d57f176b3f1d0ccc 100644 (file)
@@ -5,10 +5,11 @@
 ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS   += -mno-minimal-toc
 endif
-
 ifeq ($(CONFIG_PPC32),y)
-extra-$(CONFIG_PPC_STD_MMU)    := head.o
+CFLAGS_prom_init.o      += -fPIC
 endif
+
+extra-$(CONFIG_PPC_STD_MMU)    := head.o
 extra-$(CONFIG_PPC64)          := head_64.o
 extra-$(CONFIG_40x)            := head_4xx.o
 extra-$(CONFIG_44x)            := head_44x.o
@@ -18,13 +19,15 @@ extra-$(CONFIG_6xx)         += idle_6xx.o
 extra-$(CONFIG_PPC_FPU)                += fpu.o
 extra-y                                += vmlinux.lds
 
-obj-y                          := traps.o
-obj-$(CONFIG_PPC32)            += semaphore.o process.o
+obj-y                          := traps.o prom.o semaphore.o
+obj-$(CONFIG_PPC32)            += setup.o process.o
 obj-$(CONFIG_PPC64)            += idle_power4.o
 ifeq ($(CONFIG_PPC32),y)
+obj-$(CONFIG_PPC_OF)           += prom_init.o
 obj-$(CONFIG_MODULES)          += ppc_ksyms.o
 endif
 obj-$(CONFIG_ALTIVEC)          += vecemu.o vector.o
+obj-$(CONFIG_BOOTX_TEXT)       += btext.o
 
 ifeq ($(CONFIG_PPC_ISERIES),y)
 arch/powerpc/kernel/head_64.o: arch/powerpc/platforms/iseries/lparmap.s
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
new file mode 100644 (file)
index 0000000..44f5d98
--- /dev/null
@@ -0,0 +1,852 @@
+/*
+ * Procedures for drawing on the screen early on in the boot process.
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/btext.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/lmb.h>
+#include <asm/processor.h>
+
+#define NO_SCROLL
+
+#ifndef NO_SCROLL
+static void scrollscreen(void);
+#endif
+
+static void draw_byte(unsigned char c, long locX, long locY);
+static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
+
+static int g_loc_X;
+static int g_loc_Y;
+static int g_max_loc_X;
+static int g_max_loc_Y;
+
+static int dispDeviceRowBytes;
+static int dispDeviceDepth;
+static int dispDeviceRect[4];
+static unsigned char *dispDeviceBase, *logicalDisplayBase;
+
+unsigned long disp_BAT[2] __initdata = {0, 0};
+
+#define cmapsz (16*256)
+
+static unsigned char vga_font[cmapsz];
+
+int boot_text_mapped;
+int force_printk_to_btext = 0;
+
+
+/* Calc BAT values for mapping the display and store them
+ * in disp_BAT.  Those values are then used from head.S to map
+ * the display during identify_machine() and MMU_Init()
+ *
+ * The display is mapped to virtual address 0xD0000000, rather
+ * than 1:1, because some some CHRP machines put the frame buffer
+ * in the region starting at 0xC0000000 (KERNELBASE).
+ * This mapping is temporary and will disappear as soon as the
+ * setup done by MMU_Init() is applied.
+ *
+ * For now, we align the BAT and then map 8Mb on 601 and 16Mb
+ * on other PPCs. This may cause trouble if the framebuffer
+ * is really badly aligned, but I didn't encounter this case
+ * yet.
+ */
+void __init
+btext_prepare_BAT(void)
+{
+       unsigned long vaddr = KERNELBASE + 0x10000000;
+       unsigned long addr;
+       unsigned long lowbits;
+
+       addr = (unsigned long)dispDeviceBase;
+       if (!addr) {
+               boot_text_mapped = 0;
+               return;
+       }
+       if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
+               /* 603, 604, G3, G4, ... */
+               lowbits = addr & ~0xFF000000UL;
+               addr &= 0xFF000000UL;
+               disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
+               disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); 
+       } else {
+               /* 601 */
+               lowbits = addr & ~0xFF800000UL;
+               addr &= 0xFF800000UL;
+               disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
+               disp_BAT[1] = addr | BL_8M | 0x40;
+       }
+       logicalDisplayBase = (void *) (vaddr + lowbits);
+}
+
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+void __init
+btext_setup_display(int width, int height, int depth, int pitch,
+                   unsigned long address)
+{
+       g_loc_X = 0;
+       g_loc_Y = 0;
+       g_max_loc_X = width / 8;
+       g_max_loc_Y = height / 16;
+       logicalDisplayBase = (unsigned char *)address;
+       dispDeviceBase = (unsigned char *)address;
+       dispDeviceRowBytes = pitch;
+       dispDeviceDepth = depth;
+       dispDeviceRect[0] = dispDeviceRect[1] = 0;
+       dispDeviceRect[2] = width;
+       dispDeviceRect[3] = height;
+       boot_text_mapped = 1;
+}
+
+/* Here's a small text engine to use during early boot
+ * or for debugging purposes
+ *
+ * todo:
+ *
+ *  - build some kind of vgacon with it to enable early printk
+ *  - move to a separate file
+ *  - add a few video driver hooks to keep in sync with display
+ *    changes.
+ */
+
+void map_boot_text(void)
+{
+       unsigned long base, offset, size;
+       unsigned char *vbase;
+
+       /* By default, we are no longer mapped */
+       boot_text_mapped = 0;
+       if (dispDeviceBase == 0)
+               return;
+       base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL;
+       offset = ((unsigned long) dispDeviceBase) - base;
+       size = dispDeviceRowBytes * dispDeviceRect[3] + offset
+               + dispDeviceRect[0];
+       vbase = __ioremap(base, size, _PAGE_NO_CACHE);
+       if (vbase == 0)
+               return;
+       logicalDisplayBase = vbase + offset;
+       boot_text_mapped = 1;
+}
+
+int btext_initialize(struct device_node *np)
+{
+       unsigned int width, height, depth, pitch;
+       unsigned long address = 0;
+       u32 *prop;
+
+       prop = (u32 *)get_property(np, "width", NULL);
+       if (prop == NULL)
+               return -EINVAL;
+       width = *prop;
+       prop = (u32 *)get_property(np, "height", NULL);
+       if (prop == NULL)
+               return -EINVAL;
+       height = *prop;
+       prop = (u32 *)get_property(np, "depth", NULL);
+       if (prop == NULL)
+               return -EINVAL;
+       depth = *prop;
+       pitch = width * ((depth + 7) / 8);
+       prop = (u32 *)get_property(np, "linebytes", NULL);
+       if (prop)
+               pitch = *prop;
+       if (pitch == 1)
+               pitch = 0x1000;
+       prop = (u32 *)get_property(np, "address", NULL);
+       if (prop)
+               address = *prop;
+
+       /* FIXME: Add support for PCI reg properties */
+
+       if (address == 0)
+               return -EINVAL;
+
+       g_loc_X = 0;
+       g_loc_Y = 0;
+       g_max_loc_X = width / 8;
+       g_max_loc_Y = height / 16;
+       logicalDisplayBase = (unsigned char *)address;
+       dispDeviceBase = (unsigned char *)address;
+       dispDeviceRowBytes = pitch;
+       dispDeviceDepth = depth;
+       dispDeviceRect[0] = dispDeviceRect[1] = 0;
+       dispDeviceRect[2] = width;
+       dispDeviceRect[3] = height;
+
+       map_boot_text();
+
+       return 0;
+}
+
+void __init init_boot_display(void)
+{
+       char *name;
+       struct device_node *np = NULL; 
+       int rc = -ENODEV;
+
+       printk("trying to initialize btext ...\n");
+
+       name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
+       if (name != NULL) {
+               np = of_find_node_by_path(name);
+               if (np != NULL) {
+                       if (strcmp(np->type, "display") != 0) {
+                               printk("boot stdout isn't a display !\n");
+                               of_node_put(np);
+                               np = NULL;
+                       }
+               }
+       }
+       if (np)
+               rc = btext_initialize(np);
+       if (rc == 0)
+               return;
+
+       for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
+               if (get_property(np, "linux,opened", NULL)) {
+                       printk("trying %s ...\n", np->full_name);
+                       rc = btext_initialize(np);
+                       printk("result: %d\n", rc);
+               }
+               if (rc == 0)
+                       return;
+       }
+}
+
+/* Calc the base address of a given point (x,y) */
+static unsigned char * calc_base(int x, int y)
+{
+       unsigned char *base;
+
+       base = logicalDisplayBase;
+       if (base == 0)
+               base = dispDeviceBase;
+       base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
+       base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
+       return base;
+}
+
+/* Adjust the display to a new resolution */
+void btext_update_display(unsigned long phys, int width, int height,
+                         int depth, int pitch)
+{
+       if (dispDeviceBase == 0)
+               return;
+
+       /* check it's the same frame buffer (within 256MB) */
+       if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000)
+               return;
+
+       dispDeviceBase = (__u8 *) phys;
+       dispDeviceRect[0] = 0;
+       dispDeviceRect[1] = 0;
+       dispDeviceRect[2] = width;
+       dispDeviceRect[3] = height;
+       dispDeviceDepth = depth;
+       dispDeviceRowBytes = pitch;
+       if (boot_text_mapped) {
+               iounmap(logicalDisplayBase);
+               boot_text_mapped = 0;
+       }
+       map_boot_text();
+       g_loc_X = 0;
+       g_loc_Y = 0;
+       g_max_loc_X = width / 8;
+       g_max_loc_Y = height / 16;
+}
+EXPORT_SYMBOL(btext_update_display);
+
+void btext_clearscreen(void)
+{
+       unsigned long *base     = (unsigned long *)calc_base(0, 0);
+       unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+                                       (dispDeviceDepth >> 3)) >> 3;
+       int i,j;
+
+       for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
+       {
+               unsigned long *ptr = base;
+               for(j=width; j; --j)
+                       *(ptr++) = 0;
+               base += (dispDeviceRowBytes >> 3);
+       }
+}
+
+#ifndef NO_SCROLL
+static void scrollscreen(void)
+{
+       unsigned long *src      = (unsigned long *)calc_base(0,16);
+       unsigned long *dst      = (unsigned long *)calc_base(0,0);
+       unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
+                                  (dispDeviceDepth >> 3)) >> 3;
+       int i,j;
+
+       for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
+       {
+               unsigned long *src_ptr = src;
+               unsigned long *dst_ptr = dst;
+               for(j=width; j; --j)
+                       *(dst_ptr++) = *(src_ptr++);
+               src += (dispDeviceRowBytes >> 3);
+               dst += (dispDeviceRowBytes >> 3);
+       }
+       for (i=0; i<16; i++)
+       {
+               unsigned long *dst_ptr = dst;
+               for(j=width; j; --j)
+                       *(dst_ptr++) = 0;
+               dst += (dispDeviceRowBytes >> 3);
+       }
+}
+#endif /* ndef NO_SCROLL */
+
+void btext_drawchar(char c)
+{
+       int cline = 0;
+#ifdef NO_SCROLL
+       int x;
+#endif
+       if (!boot_text_mapped)
+               return;
+
+       switch (c) {
+       case '\b':
+               if (g_loc_X > 0)
+                       --g_loc_X;
+               break;
+       case '\t':
+               g_loc_X = (g_loc_X & -8) + 8;
+               break;
+       case '\r':
+               g_loc_X = 0;
+               break;
+       case '\n':
+               g_loc_X = 0;
+               g_loc_Y++;
+               cline = 1;
+               break;
+       default:
+               draw_byte(c, g_loc_X++, g_loc_Y);
+       }
+       if (g_loc_X >= g_max_loc_X) {
+               g_loc_X = 0;
+               g_loc_Y++;
+               cline = 1;
+       }
+#ifndef NO_SCROLL
+       while (g_loc_Y >= g_max_loc_Y) {
+               scrollscreen();
+               g_loc_Y--;
+       }
+#else
+       /* wrap around from bottom to top of screen so we don't
+          waste time scrolling each line.  -- paulus. */
+       if (g_loc_Y >= g_max_loc_Y)
+               g_loc_Y = 0;
+       if (cline) {
+               for (x = 0; x < g_max_loc_X; ++x)
+                       draw_byte(' ', x, g_loc_Y);
+       }
+#endif
+}
+
+void btext_drawstring(const char *c)
+{
+       if (!boot_text_mapped)
+               return;
+       while (*c)
+               btext_drawchar(*c++);
+}
+
+void btext_drawhex(unsigned long v)
+{
+       char *hex_table = "0123456789abcdef";
+
+       if (!boot_text_mapped)
+               return;
+#ifdef CONFIG_PPC64
+       btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 52) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 48) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 44) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 40) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 36) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 32) & 0x0000000FUL]);
+#endif
+       btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
+       btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
+       btext_drawchar(' ');
+}
+
+static void draw_byte(unsigned char c, long locX, long locY)
+{
+       unsigned char *base     = calc_base(locX << 3, locY << 4);
+       unsigned char *font     = &vga_font[((unsigned int)c) * 16];
+       int rb                  = dispDeviceRowBytes;
+
+       switch(dispDeviceDepth) {
+       case 24:
+       case 32:
+               draw_byte_32(font, (unsigned int *)base, rb);
+               break;
+       case 15:
+       case 16:
+               draw_byte_16(font, (unsigned int *)base, rb);
+               break;
+       case 8:
+               draw_byte_8(font, (unsigned int *)base, rb);
+               break;
+       }
+}
+
+static unsigned int expand_bits_8[16] = {
+       0x00000000,
+       0x000000ff,
+       0x0000ff00,
+       0x0000ffff,
+       0x00ff0000,
+       0x00ff00ff,
+       0x00ffff00,
+       0x00ffffff,
+       0xff000000,
+       0xff0000ff,
+       0xff00ff00,
+       0xff00ffff,
+       0xffff0000,
+       0xffff00ff,
+       0xffffff00,
+       0xffffffff
+};
+
+static unsigned int expand_bits_16[4] = {
+       0x00000000,
+       0x0000ffff,
+       0xffff0000,
+       0xffffffff
+};
+
+
+static void draw_byte_32(unsigned char *font, unsigned int *base, int rb)
+{
+       int l, bits;
+       int fg = 0xFFFFFFFFUL;
+       int bg = 0x00000000UL;
+
+       for (l = 0; l < 16; ++l)
+       {
+               bits = *font++;
+               base[0] = (-(bits >> 7) & fg) ^ bg;
+               base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+               base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+               base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+               base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+               base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+               base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+               base[7] = (-(bits & 1) & fg) ^ bg;
+               base = (unsigned int *) ((char *)base + rb);
+       }
+}
+
+static void draw_byte_16(unsigned char *font, unsigned int *base, int rb)
+{
+       int l, bits;
+       int fg = 0xFFFFFFFFUL;
+       int bg = 0x00000000UL;
+       unsigned int *eb = (int *)expand_bits_16;
+
+       for (l = 0; l < 16; ++l)
+       {
+               bits = *font++;
+               base[0] = (eb[bits >> 6] & fg) ^ bg;
+               base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
+               base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
+               base[3] = (eb[bits & 3] & fg) ^ bg;
+               base = (unsigned int *) ((char *)base + rb);
+       }
+}
+
+static void draw_byte_8(unsigned char *font, unsigned int *base, int rb)
+{
+       int l, bits;
+       int fg = 0x0F0F0F0FUL;
+       int bg = 0x00000000UL;
+       unsigned int *eb = (int *)expand_bits_8;
+
+       for (l = 0; l < 16; ++l)
+       {
+               bits = *font++;
+               base[0] = (eb[bits >> 4] & fg) ^ bg;
+               base[1] = (eb[bits & 0xf] & fg) ^ bg;
+               base = (unsigned int *) ((char *)base + rb);
+       }
+}
+
+static unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00,
+};
index 2c3a1d34e3c79bf555931daf6d71e8bfb5bfdd87..d49bff1a7d51cde337eef16d50fac9077b7c3c61 100644 (file)
@@ -134,11 +134,13 @@ __start:
  * because OF may have I/O devices mapped into that area
  * (particularly on CHRP).
  */
-       mr      r31,r3                  /* save parameters */
+       cmpwi   0,r5,0
+       beq     1f
+       bl      prom_init
+       trap
+
+1:     mr      r31,r3                  /* save parameters */
        mr      r30,r4
-       mr      r29,r5
-       mr      r28,r6
-       mr      r27,r7
        li      r24,0                   /* cpu # */
 
 /*
@@ -204,8 +206,7 @@ __after_mmu_off:
  * On CHRP, we are loaded at 0x10000 since OF on CHRP uses
  * the exception vectors at 0 (and therefore this copy
  * overwrites OF's exception vectors with our own).
- * If the MMU is already turned on, we copy stuff to KERNELBASE,
- * otherwise we copy it to 0.
+ * The MMU is off at this point.
  */
        bl      reloc_offset
        mr      r26,r3
@@ -1187,9 +1188,6 @@ start_here:
  */
        mr      r3,r31
        mr      r4,r30
-       mr      r5,r29
-       mr      r6,r28
-       mr      r7,r27
        bl      machine_init
        bl      MMU_init
 
index 33f742cf979bd82aa1dadbaf81f0abbdd85fc26f..91a562e3257b8dab1df218aacd461524de986df1 100644 (file)
@@ -212,36 +212,6 @@ EXPORT_SYMBOL(_machine);
 EXPORT_SYMBOL(sys_ctrler);
 EXPORT_SYMBOL(pmac_newworld);
 #endif
-#ifdef CONFIG_PPC_OF
-EXPORT_SYMBOL(find_devices);
-EXPORT_SYMBOL(find_type_devices);
-EXPORT_SYMBOL(find_compatible_devices);
-EXPORT_SYMBOL(find_path_device);
-EXPORT_SYMBOL(device_is_compatible);
-EXPORT_SYMBOL(machine_is_compatible);
-EXPORT_SYMBOL(find_all_nodes);
-EXPORT_SYMBOL(get_property);
-EXPORT_SYMBOL(request_OF_resource);
-EXPORT_SYMBOL(release_OF_resource);
-EXPORT_SYMBOL(pci_busdev_to_OF_node);
-EXPORT_SYMBOL(pci_device_to_OF_node);
-EXPORT_SYMBOL(pci_device_from_OF_node);
-EXPORT_SYMBOL(of_find_node_by_name);
-EXPORT_SYMBOL(of_find_node_by_type);
-EXPORT_SYMBOL(of_find_compatible_node);
-EXPORT_SYMBOL(of_find_node_by_path);
-EXPORT_SYMBOL(of_find_all_nodes);
-EXPORT_SYMBOL(of_get_parent);
-EXPORT_SYMBOL(of_get_next_child);
-EXPORT_SYMBOL(of_node_get);
-EXPORT_SYMBOL(of_node_put);
-#endif /* CONFIG_PPC_OF */
-#if defined(CONFIG_BOOTX_TEXT)
-EXPORT_SYMBOL(btext_update_display);
-#endif
-#if defined(CONFIG_SCSI) && defined(CONFIG_PPC_PMAC)
-EXPORT_SYMBOL(note_scsi_host);
-#endif
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(kd_mksound);
 #endif
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
new file mode 100644 (file)
index 0000000..dc3d24e
--- /dev/null
@@ -0,0 +1,2141 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ * 
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.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.
+ */
+
+#undef DEBUG
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/initrd.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/lmb.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/pci.h>
+#include <asm/iommu.h>
+#include <asm/btext.h>
+#include <asm/sections.h>
+#include <asm/machdep.h>
+#include <asm/pSeries_reconfig.h>
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(KERN_ERR fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+struct pci_reg_property {
+       struct pci_address addr;
+       u32 size_hi;
+       u32 size_lo;
+};
+
+struct isa_reg_property {
+       u32 space;
+       u32 address;
+       u32 size;
+};
+
+
+typedef int interpret_func(struct device_node *, unsigned long *,
+                          int, int, int);
+
+extern struct rtas_t rtas;
+extern struct lmb lmb;
+extern unsigned long klimit;
+
+static unsigned long memory_limit;
+
+static int __initdata dt_root_addr_cells;
+static int __initdata dt_root_size_cells;
+
+#ifdef CONFIG_PPC64
+static int __initdata iommu_is_off;
+int __initdata iommu_force_on;
+extern unsigned long tce_alloc_start, tce_alloc_end;
+#endif
+
+typedef u32 cell_t;
+
+#if 0
+static struct boot_param_header *initial_boot_params __initdata;
+#else
+struct boot_param_header *initial_boot_params;
+#endif
+
+static struct device_node *allnodes = NULL;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+static DEFINE_RWLOCK(devtree_lock);
+
+/* export that to outside world */
+struct device_node *of_chosen;
+
+struct device_node *dflt_interrupt_controller;
+int num_interrupt_controllers;
+
+u32 rtas_data;
+u32 rtas_entry;
+
+/*
+ * Wrapper for allocating memory for various data that needs to be
+ * attached to device nodes as they are processed at boot or when
+ * added to the device tree later (e.g. DLPAR).  At boot there is
+ * already a region reserved so we just increment *mem_start by size;
+ * otherwise we call kmalloc.
+ */
+static void * prom_alloc(unsigned long size, unsigned long *mem_start)
+{
+       unsigned long tmp;
+
+       if (!mem_start)
+               return kmalloc(size, GFP_KERNEL);
+
+       tmp = *mem_start;
+       *mem_start += size;
+       return (void *)tmp;
+}
+
+/*
+ * Find the device_node with a given phandle.
+ */
+static struct device_node * find_phandle(phandle ph)
+{
+       struct device_node *np;
+
+       for (np = allnodes; np != 0; np = np->allnext)
+               if (np->linux_phandle == ph)
+                       return np;
+       return NULL;
+}
+
+/*
+ * Find the interrupt parent of a node.
+ */
+static struct device_node * __devinit intr_parent(struct device_node *p)
+{
+       phandle *parp;
+
+       parp = (phandle *) get_property(p, "interrupt-parent", NULL);
+       if (parp == NULL)
+               return p->parent;
+       p = find_phandle(*parp);
+       if (p != NULL)
+               return p;
+       /*
+        * On a powermac booted with BootX, we don't get to know the
+        * phandles for any nodes, so find_phandle will return NULL.
+        * Fortunately these machines only have one interrupt controller
+        * so there isn't in fact any ambiguity.  -- paulus
+        */
+       if (num_interrupt_controllers == 1)
+               p = dflt_interrupt_controller;
+       return p;
+}
+
+/*
+ * Find out the size of each entry of the interrupts property
+ * for a node.
+ */
+int __devinit prom_n_intr_cells(struct device_node *np)
+{
+       struct device_node *p;
+       unsigned int *icp;
+
+       for (p = np; (p = intr_parent(p)) != NULL; ) {
+               icp = (unsigned int *)
+                       get_property(p, "#interrupt-cells", NULL);
+               if (icp != NULL)
+                       return *icp;
+               if (get_property(p, "interrupt-controller", NULL) != NULL
+                   || get_property(p, "interrupt-map", NULL) != NULL) {
+                       printk("oops, node %s doesn't have #interrupt-cells\n",
+                              p->full_name);
+                       return 1;
+               }
+       }
+#ifdef DEBUG_IRQ
+       printk("prom_n_intr_cells failed for %s\n", np->full_name);
+#endif
+       return 1;
+}
+
+/*
+ * Map an interrupt from a device up to the platform interrupt
+ * descriptor.
+ */
+static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler,
+                                  struct device_node *np, unsigned int *ints,
+                                  int nintrc)
+{
+       struct device_node *p, *ipar;
+       unsigned int *imap, *imask, *ip;
+       int i, imaplen, match;
+       int newintrc = 0, newaddrc = 0;
+       unsigned int *reg;
+       int naddrc;
+
+       reg = (unsigned int *) get_property(np, "reg", NULL);
+       naddrc = prom_n_addr_cells(np);
+       p = intr_parent(np);
+       while (p != NULL) {
+               if (get_property(p, "interrupt-controller", NULL) != NULL)
+                       /* this node is an interrupt controller, stop here */
+                       break;
+               imap = (unsigned int *)
+                       get_property(p, "interrupt-map", &imaplen);
+               if (imap == NULL) {
+                       p = intr_parent(p);
+                       continue;
+               }
+               imask = (unsigned int *)
+                       get_property(p, "interrupt-map-mask", NULL);
+               if (imask == NULL) {
+                       printk("oops, %s has interrupt-map but no mask\n",
+                              p->full_name);
+                       return 0;
+               }
+               imaplen /= sizeof(unsigned int);
+               match = 0;
+               ipar = NULL;
+               while (imaplen > 0 && !match) {
+                       /* check the child-interrupt field */
+                       match = 1;
+                       for (i = 0; i < naddrc && match; ++i)
+                               match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
+                       for (; i < naddrc + nintrc && match; ++i)
+                               match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
+                       imap += naddrc + nintrc;
+                       imaplen -= naddrc + nintrc;
+                       /* grab the interrupt parent */
+                       ipar = find_phandle((phandle) *imap++);
+                       --imaplen;
+                       if (ipar == NULL && num_interrupt_controllers == 1)
+                               /* cope with BootX not giving us phandles */
+                               ipar = dflt_interrupt_controller;
+                       if (ipar == NULL) {
+                               printk("oops, no int parent %x in map of %s\n",
+                                      imap[-1], p->full_name);
+                               return 0;
+                       }
+                       /* find the parent's # addr and intr cells */
+                       ip = (unsigned int *)
+                               get_property(ipar, "#interrupt-cells", NULL);
+                       if (ip == NULL) {
+                               printk("oops, no #interrupt-cells on %s\n",
+                                      ipar->full_name);
+                               return 0;
+                       }
+                       newintrc = *ip;
+                       ip = (unsigned int *)
+                               get_property(ipar, "#address-cells", NULL);
+                       newaddrc = (ip == NULL)? 0: *ip;
+                       imap += newaddrc + newintrc;
+                       imaplen -= newaddrc + newintrc;
+               }
+               if (imaplen < 0) {
+                       printk("oops, error decoding int-map on %s, len=%d\n",
+                              p->full_name, imaplen);
+                       return 0;
+               }
+               if (!match) {
+#ifdef DEBUG_IRQ
+                       printk("oops, no match in %s int-map for %s\n",
+                              p->full_name, np->full_name);
+#endif
+                       return 0;
+               }
+               p = ipar;
+               naddrc = newaddrc;
+               nintrc = newintrc;
+               ints = imap - nintrc;
+               reg = ints - naddrc;
+       }
+       if (p == NULL) {
+#ifdef DEBUG_IRQ
+               printk("hmmm, int tree for %s doesn't have ctrler\n",
+                      np->full_name);
+#endif
+               return 0;
+       }
+       *irq = ints;
+       *ictrler = p;
+       return nintrc;
+}
+
+static int __devinit finish_node_interrupts(struct device_node *np,
+                                           unsigned long *mem_start,
+                                           int measure_only)
+{
+       unsigned int *ints;
+       int intlen, intrcells, intrcount;
+       int i, j, n;
+       unsigned int *irq, virq;
+       struct device_node *ic;
+
+       ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+       if (ints == NULL)
+               return 0;
+       intrcells = prom_n_intr_cells(np);
+       intlen /= intrcells * sizeof(unsigned int);
+
+       np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
+       if (!np->intrs)
+               return -ENOMEM;
+
+       if (measure_only)
+               return 0;
+
+       intrcount = 0;
+       for (i = 0; i < intlen; ++i, ints += intrcells) {
+               n = map_interrupt(&irq, &ic, np, ints, intrcells);
+               if (n <= 0)
+                       continue;
+
+               /* don't map IRQ numbers under a cascaded 8259 controller */
+               if (ic && device_is_compatible(ic, "chrp,iic")) {
+                       np->intrs[intrcount].line = irq[0];
+               } else {
+#ifdef CONFIG_PPC64
+                       virq = virt_irq_create_mapping(irq[0]);
+                       if (virq == NO_IRQ) {
+                               printk(KERN_CRIT "Could not allocate interrupt"
+                                      " number for %s\n", np->full_name);
+                               continue;
+                       }
+                       virq = irq_offset_up(virq);
+#else
+                       virq = irq[0];
+#endif
+                       np->intrs[intrcount].line = virq;
+               }
+
+#ifdef CONFIG_PPC64
+               /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
+               if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) {
+                       char *name = get_property(ic->parent, "name", NULL);
+                       if (name && !strcmp(name, "u3"))
+                               np->intrs[intrcount].line += 128;
+                       else if (!(name && !strcmp(name, "mac-io")))
+                               /* ignore other cascaded controllers, such as
+                                  the k2-sata-root */
+                               break;
+               }
+#endif
+               np->intrs[intrcount].sense = 1;
+               if (n > 1)
+                       np->intrs[intrcount].sense = irq[1];
+               if (n > 2) {
+                       printk("hmmm, got %d intr cells for %s:", n,
+                              np->full_name);
+                       for (j = 0; j < n; ++j)
+                               printk(" %d", irq[j]);
+                       printk("\n");
+               }
+               ++intrcount;
+       }
+       np->n_intrs = intrcount;
+
+       return 0;
+}
+
+static int __devinit interpret_pci_props(struct device_node *np,
+                                        unsigned long *mem_start,
+                                        int naddrc, int nsizec,
+                                        int measure_only)
+{
+       struct address_range *adr;
+       struct pci_reg_property *pci_addrs;
+       int i, l, n_addrs;
+
+       pci_addrs = (struct pci_reg_property *)
+               get_property(np, "assigned-addresses", &l);
+       if (!pci_addrs)
+               return 0;
+
+       n_addrs = l / sizeof(*pci_addrs);
+
+       adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
+       if (!adr)
+               return -ENOMEM;
+
+       if (measure_only)
+               return 0;
+
+       np->addrs = adr;
+       np->n_addrs = n_addrs;
+
+       for (i = 0; i < n_addrs; i++) {
+               adr[i].space = pci_addrs[i].addr.a_hi;
+               adr[i].address = pci_addrs[i].addr.a_lo |
+                       ((u64)pci_addrs[i].addr.a_mid << 32);
+               adr[i].size = pci_addrs[i].size_lo;
+       }
+
+       return 0;
+}
+
+static int __init interpret_dbdma_props(struct device_node *np,
+                                       unsigned long *mem_start,
+                                       int naddrc, int nsizec,
+                                       int measure_only)
+{
+       struct reg_property32 *rp;
+       struct address_range *adr;
+       unsigned long base_address;
+       int i, l;
+       struct device_node *db;
+
+       base_address = 0;
+       if (!measure_only) {
+               for (db = np->parent; db != NULL; db = db->parent) {
+                       if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
+                               base_address = db->addrs[0].address;
+                               break;
+                       }
+               }
+       }
+
+       rp = (struct reg_property32 *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= sizeof(struct reg_property32)) {
+               i = 0;
+               adr = (struct address_range *) (*mem_start);
+               while ((l -= sizeof(struct reg_property32)) >= 0) {
+                       if (!measure_only) {
+                               adr[i].space = 2;
+                               adr[i].address = rp[i].address + base_address;
+                               adr[i].size = rp[i].size;
+                       }
+                       ++i;
+               }
+               np->addrs = adr;
+               np->n_addrs = i;
+               (*mem_start) += i * sizeof(struct address_range);
+       }
+
+       return 0;
+}
+
+static int __init interpret_macio_props(struct device_node *np,
+                                       unsigned long *mem_start,
+                                       int naddrc, int nsizec,
+                                       int measure_only)
+{
+       struct reg_property32 *rp;
+       struct address_range *adr;
+       unsigned long base_address;
+       int i, l;
+       struct device_node *db;
+
+       base_address = 0;
+       if (!measure_only) {
+               for (db = np->parent; db != NULL; db = db->parent) {
+                       if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
+                               base_address = db->addrs[0].address;
+                               break;
+                       }
+               }
+       }
+
+       rp = (struct reg_property32 *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= sizeof(struct reg_property32)) {
+               i = 0;
+               adr = (struct address_range *) (*mem_start);
+               while ((l -= sizeof(struct reg_property32)) >= 0) {
+                       if (!measure_only) {
+                               adr[i].space = 2;
+                               adr[i].address = rp[i].address + base_address;
+                               adr[i].size = rp[i].size;
+                       }
+                       ++i;
+               }
+               np->addrs = adr;
+               np->n_addrs = i;
+               (*mem_start) += i * sizeof(struct address_range);
+       }
+
+       return 0;
+}
+
+static int __init interpret_isa_props(struct device_node *np,
+                                     unsigned long *mem_start,
+                                     int naddrc, int nsizec,
+                                     int measure_only)
+{
+       struct isa_reg_property *rp;
+       struct address_range *adr;
+       int i, l;
+
+       rp = (struct isa_reg_property *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
+               i = 0;
+               adr = (struct address_range *) (*mem_start);
+               while ((l -= sizeof(struct isa_reg_property)) >= 0) {
+                       if (!measure_only) {
+                               adr[i].space = rp[i].space;
+                               adr[i].address = rp[i].address;
+                               adr[i].size = rp[i].size;
+                       }
+                       ++i;
+               }
+               np->addrs = adr;
+               np->n_addrs = i;
+               (*mem_start) += i * sizeof(struct address_range);
+       }
+
+       return 0;
+}
+
+static int __init interpret_root_props(struct device_node *np,
+                                      unsigned long *mem_start,
+                                      int naddrc, int nsizec,
+                                      int measure_only)
+{
+       struct address_range *adr;
+       int i, l;
+       unsigned int *rp;
+       int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
+
+       rp = (unsigned int *) get_property(np, "reg", &l);
+       if (rp != 0 && l >= rpsize) {
+               i = 0;
+               adr = (struct address_range *) (*mem_start);
+               while ((l -= rpsize) >= 0) {
+                       if (!measure_only) {
+                               adr[i].space = 0;
+                               adr[i].address = rp[naddrc - 1];
+                               adr[i].size = rp[naddrc + nsizec - 1];
+                       }
+                       ++i;
+                       rp += naddrc + nsizec;
+               }
+               np->addrs = adr;
+               np->n_addrs = i;
+               (*mem_start) += i * sizeof(struct address_range);
+       }
+
+       return 0;
+}
+
+static int __devinit finish_node(struct device_node *np,
+                                unsigned long *mem_start,
+                                interpret_func *ifunc,
+                                int naddrc, int nsizec,
+                                int measure_only)
+{
+       struct device_node *child;
+       int *ip, rc = 0;
+
+       /* get the device addresses and interrupts */
+       if (ifunc != NULL)
+               rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
+       if (rc)
+               goto out;
+
+       rc = finish_node_interrupts(np, mem_start, measure_only);
+       if (rc)
+               goto out;
+
+       /* Look for #address-cells and #size-cells properties. */
+       ip = (int *) get_property(np, "#address-cells", NULL);
+       if (ip != NULL)
+               naddrc = *ip;
+       ip = (int *) get_property(np, "#size-cells", NULL);
+       if (ip != NULL)
+               nsizec = *ip;
+
+       if (!strcmp(np->name, "device-tree") || np->parent == NULL)
+               ifunc = interpret_root_props;
+       else if (np->type == 0)
+               ifunc = NULL;
+       else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
+               ifunc = interpret_pci_props;
+       else if (!strcmp(np->type, "dbdma"))
+               ifunc = interpret_dbdma_props;
+       else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
+               ifunc = interpret_macio_props;
+       else if (!strcmp(np->type, "isa"))
+               ifunc = interpret_isa_props;
+       else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
+               ifunc = interpret_root_props;
+       else if (!((ifunc == interpret_dbdma_props
+                   || ifunc == interpret_macio_props)
+                  && (!strcmp(np->type, "escc")
+                      || !strcmp(np->type, "media-bay"))))
+               ifunc = NULL;
+
+       for (child = np->child; child != NULL; child = child->sibling) {
+               rc = finish_node(child, mem_start, ifunc,
+                                naddrc, nsizec, measure_only);
+               if (rc)
+                       goto out;
+       }
+out:
+       return rc;
+}
+
+static void __init scan_interrupt_controllers(void)
+{
+       struct device_node *np;
+       int n = 0;
+       char *name, *ic;
+       int iclen;
+
+       for (np = allnodes; np != NULL; np = np->allnext) {
+               ic = get_property(np, "interrupt-controller", &iclen);
+               name = get_property(np, "name", NULL);
+               /* checking iclen makes sure we don't get a false
+                  match on /chosen.interrupt_controller */
+               if ((name != NULL
+                    && strcmp(name, "interrupt-controller") == 0)
+                   || (ic != NULL && iclen == 0
+                       && strcmp(name, "AppleKiwi"))) {
+                       if (n == 0)
+                               dflt_interrupt_controller = np;
+                       ++n;
+               }
+       }
+       num_interrupt_controllers = n;
+}
+
+/**
+ * finish_device_tree is called once things are running normally
+ * (i.e. with text and data mapped to the address they were linked at).
+ * It traverses the device tree and fills in some of the additional,
+ * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt
+ * mapping is also initialized at this point.
+ */
+void __init finish_device_tree(void)
+{
+       unsigned long start, end, size = 0;
+
+       DBG(" -> finish_device_tree\n");
+
+#ifdef CONFIG_PPC64
+       /* Initialize virtual IRQ map */
+       virt_irq_init();
+#endif
+       scan_interrupt_controllers();
+
+       /*
+        * Finish device-tree (pre-parsing some properties etc...)
+        * We do this in 2 passes. One with "measure_only" set, which
+        * will only measure the amount of memory needed, then we can
+        * allocate that memory, and call finish_node again. However,
+        * we must be careful as most routines will fail nowadays when
+        * prom_alloc() returns 0, so we must make sure our first pass
+        * doesn't start at 0. We pre-initialize size to 16 for that
+        * reason and then remove those additional 16 bytes
+        */
+       size = 16;
+       finish_node(allnodes, &size, NULL, 0, 0, 1);
+       size -= 16;
+       end = start = (unsigned long) __va(lmb_alloc(size, 128));
+       finish_node(allnodes, &end, NULL, 0, 0, 0);
+       BUG_ON(end != start + size);
+
+       DBG(" <- finish_device_tree\n");
+}
+
+static inline char *find_flat_dt_string(u32 offset)
+{
+       return ((char *)initial_boot_params) +
+               initial_boot_params->off_dt_strings + offset;
+}
+
+/**
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory informations at boot before we can
+ * unflatten the tree
+ */
+static int __init scan_flat_dt(int (*it)(unsigned long node,
+                                        const char *uname, int depth,
+                                        void *data),
+                              void *data)
+{
+       unsigned long p = ((unsigned long)initial_boot_params) +
+               initial_boot_params->off_dt_struct;
+       int rc = 0;
+       int depth = -1;
+
+       do {
+               u32 tag = *((u32 *)p);
+               char *pathp;
+               
+               p += 4;
+               if (tag == OF_DT_END_NODE) {
+                       depth --;
+                       continue;
+               }
+               if (tag == OF_DT_NOP)
+                       continue;
+               if (tag == OF_DT_END)
+                       break;
+               if (tag == OF_DT_PROP) {
+                       u32 sz = *((u32 *)p);
+                       p += 8;
+                       if (initial_boot_params->version < 0x10)
+                               p = _ALIGN(p, sz >= 8 ? 8 : 4);
+                       p += sz;
+                       p = _ALIGN(p, 4);
+                       continue;
+               }
+               if (tag != OF_DT_BEGIN_NODE) {
+                       printk(KERN_WARNING "Invalid tag %x scanning flattened"
+                              " device tree !\n", tag);
+                       return -EINVAL;
+               }
+               depth++;
+               pathp = (char *)p;
+               p = _ALIGN(p + strlen(pathp) + 1, 4);
+               if ((*pathp) == '/') {
+                       char *lp, *np;
+                       for (lp = NULL, np = pathp; *np; np++)
+                               if ((*np) == '/')
+                                       lp = np+1;
+                       if (lp != NULL)
+                               pathp = lp;
+               }
+               rc = it(p, pathp, depth, data);
+               if (rc != 0)
+                       break;          
+       } while(1);
+
+       return rc;
+}
+
+/**
+ * This  function can be used within scan_flattened_dt callback to get
+ * access to properties
+ */
+static void* __init get_flat_dt_prop(unsigned long node, const char *name,
+                                    unsigned long *size)
+{
+       unsigned long p = node;
+
+       do {
+               u32 tag = *((u32 *)p);
+               u32 sz, noff;
+               const char *nstr;
+
+               p += 4;
+               if (tag == OF_DT_NOP)
+                       continue;
+               if (tag != OF_DT_PROP)
+                       return NULL;
+
+               sz = *((u32 *)p);
+               noff = *((u32 *)(p + 4));
+               p += 8;
+               if (initial_boot_params->version < 0x10)
+                       p = _ALIGN(p, sz >= 8 ? 8 : 4);
+
+               nstr = find_flat_dt_string(noff);
+               if (nstr == NULL) {
+                       printk(KERN_WARNING "Can't find property index"
+                              " name !\n");
+                       return NULL;
+               }
+               if (strcmp(name, nstr) == 0) {
+                       if (size)
+                               *size = sz;
+                       return (void *)p;
+               }
+               p += sz;
+               p = _ALIGN(p, 4);
+       } while(1);
+}
+
+static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+                                      unsigned long align)
+{
+       void *res;
+
+       *mem = _ALIGN(*mem, align);
+       res = (void *)*mem;
+       *mem += size;
+
+       return res;
+}
+
+static unsigned long __init unflatten_dt_node(unsigned long mem,
+                                             unsigned long *p,
+                                             struct device_node *dad,
+                                             struct device_node ***allnextpp,
+                                             unsigned long fpsize)
+{
+       struct device_node *np;
+       struct property *pp, **prev_pp = NULL;
+       char *pathp;
+       u32 tag;
+       unsigned int l, allocl;
+       int has_name = 0;
+       int new_format = 0;
+
+       tag = *((u32 *)(*p));
+       if (tag != OF_DT_BEGIN_NODE) {
+               printk("Weird tag at start of node: %x\n", tag);
+               return mem;
+       }
+       *p += 4;
+       pathp = (char *)*p;
+       l = allocl = strlen(pathp) + 1;
+       *p = _ALIGN(*p + l, 4);
+
+       /* version 0x10 has a more compact unit name here instead of the full
+        * path. we accumulate the full path size using "fpsize", we'll rebuild
+        * it later. We detect this because the first character of the name is
+        * not '/'.
+        */
+       if ((*pathp) != '/') {
+               new_format = 1;
+               if (fpsize == 0) {
+                       /* root node: special case. fpsize accounts for path
+                        * plus terminating zero. root node only has '/', so
+                        * fpsize should be 2, but we want to avoid the first
+                        * level nodes to have two '/' so we use fpsize 1 here
+                        */
+                       fpsize = 1;
+                       allocl = 2;
+               } else {
+                       /* account for '/' and path size minus terminal 0
+                        * already in 'l'
+                        */
+                       fpsize += l;
+                       allocl = fpsize;
+               }
+       }
+
+
+       np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
+                               __alignof__(struct device_node));
+       if (allnextpp) {
+               memset(np, 0, sizeof(*np));
+               np->full_name = ((char*)np) + sizeof(struct device_node);
+               if (new_format) {
+                       char *p = np->full_name;
+                       /* rebuild full path for new format */
+                       if (dad && dad->parent) {
+                               strcpy(p, dad->full_name);
+#ifdef DEBUG
+                               if ((strlen(p) + l + 1) != allocl) {
+                                       DBG("%s: p: %d, l: %d, a: %d\n",
+                                           pathp, strlen(p), l, allocl);
+                               }
+#endif
+                               p += strlen(p);
+                       }
+                       *(p++) = '/';
+                       memcpy(p, pathp, l);
+               } else
+                       memcpy(np->full_name, pathp, l);
+               prev_pp = &np->properties;
+               **allnextpp = np;
+               *allnextpp = &np->allnext;
+               if (dad != NULL) {
+                       np->parent = dad;
+                       /* we temporarily use the next field as `last_child'*/
+                       if (dad->next == 0)
+                               dad->child = np;
+                       else
+                               dad->next->sibling = np;
+                       dad->next = np;
+               }
+               kref_init(&np->kref);
+       }
+       while(1) {
+               u32 sz, noff;
+               char *pname;
+
+               tag = *((u32 *)(*p));
+               if (tag == OF_DT_NOP) {
+                       *p += 4;
+                       continue;
+               }
+               if (tag != OF_DT_PROP)
+                       break;
+               *p += 4;
+               sz = *((u32 *)(*p));
+               noff = *((u32 *)((*p) + 4));
+               *p += 8;
+               if (initial_boot_params->version < 0x10)
+                       *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
+
+               pname = find_flat_dt_string(noff);
+               if (pname == NULL) {
+                       printk("Can't find property name in list !\n");
+                       break;
+               }
+               if (strcmp(pname, "name") == 0)
+                       has_name = 1;
+               l = strlen(pname) + 1;
+               pp = unflatten_dt_alloc(&mem, sizeof(struct property),
+                                       __alignof__(struct property));
+               if (allnextpp) {
+                       if (strcmp(pname, "linux,phandle") == 0) {
+                               np->node = *((u32 *)*p);
+                               if (np->linux_phandle == 0)
+                                       np->linux_phandle = np->node;
+                       }
+                       if (strcmp(pname, "ibm,phandle") == 0)
+                               np->linux_phandle = *((u32 *)*p);
+                       pp->name = pname;
+                       pp->length = sz;
+                       pp->value = (void *)*p;
+                       *prev_pp = pp;
+                       prev_pp = &pp->next;
+               }
+               *p = _ALIGN((*p) + sz, 4);
+       }
+       /* with version 0x10 we may not have the name property, recreate
+        * it here from the unit name if absent
+        */
+       if (!has_name) {
+               char *p = pathp, *ps = pathp, *pa = NULL;
+               int sz;
+
+               while (*p) {
+                       if ((*p) == '@')
+                               pa = p;
+                       if ((*p) == '/')
+                               ps = p + 1;
+                       p++;
+               }
+               if (pa < ps)
+                       pa = p;
+               sz = (pa - ps) + 1;
+               pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
+                                       __alignof__(struct property));
+               if (allnextpp) {
+                       pp->name = "name";
+                       pp->length = sz;
+                       pp->value = (unsigned char *)(pp + 1);
+                       *prev_pp = pp;
+                       prev_pp = &pp->next;
+                       memcpy(pp->value, ps, sz - 1);
+                       ((char *)pp->value)[sz - 1] = 0;
+                       DBG("fixed up name for %s -> %s\n", pathp, pp->value);
+               }
+       }
+       if (allnextpp) {
+               *prev_pp = NULL;
+               np->name = get_property(np, "name", NULL);
+               np->type = get_property(np, "device_type", NULL);
+
+               if (!np->name)
+                       np->name = "<NULL>";
+               if (!np->type)
+                       np->type = "<NULL>";
+       }
+       while (tag == OF_DT_BEGIN_NODE) {
+               mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
+               tag = *((u32 *)(*p));
+       }
+       if (tag != OF_DT_END_NODE) {
+               printk("Weird tag at end of node: %x\n", tag);
+               return mem;
+       }
+       *p += 4;
+       return mem;
+}
+
+
+/**
+ * unflattens the device-tree passed by the firmware, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used (this used to be done by finish_device_tree)
+ */
+void __init unflatten_device_tree(void)
+{
+       unsigned long start, mem, size;
+       struct device_node **allnextp = &allnodes;
+       char *p = NULL;
+       int l = 0;
+
+       DBG(" -> unflatten_device_tree()\n");
+
+       /* First pass, scan for size */
+       start = ((unsigned long)initial_boot_params) +
+               initial_boot_params->off_dt_struct;
+       size = unflatten_dt_node(0, &start, NULL, NULL, 0);
+       size = (size | 3) + 1;
+
+       DBG("  size is %lx, allocating...\n", size);
+
+       /* Allocate memory for the expanded device tree */
+       mem = lmb_alloc(size + 4, __alignof__(struct device_node));
+       if (!mem) {
+               DBG("Couldn't allocate memory with lmb_alloc()!\n");
+               panic("Couldn't allocate memory with lmb_alloc()!\n");
+       }
+       mem = (unsigned long) __va(mem);
+
+       ((u32 *)mem)[size / 4] = 0xdeadbeef;
+
+       DBG("  unflattening %lx...\n", mem);
+
+       /* Second pass, do actual unflattening */
+       start = ((unsigned long)initial_boot_params) +
+               initial_boot_params->off_dt_struct;
+       unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
+       if (*((u32 *)start) != OF_DT_END)
+               printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
+       if (((u32 *)mem)[size / 4] != 0xdeadbeef)
+               printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
+                      ((u32 *)mem)[size / 4] );
+       *allnextp = NULL;
+
+       /* Get pointer to OF "/chosen" node for use everywhere */
+       of_chosen = of_find_node_by_path("/chosen");
+
+       /* Retreive command line */
+       if (of_chosen != NULL) {
+               p = (char *)get_property(of_chosen, "bootargs", &l);
+               if (p != NULL && l > 0)
+                       strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE));
+       }
+#ifdef CONFIG_CMDLINE
+       if (l == 0 || (l == 1 && (*p) == 0))
+               strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+#endif /* CONFIG_CMDLINE */
+
+       DBG("Command line is: %s\n", cmd_line);
+
+       DBG(" <- unflatten_device_tree()\n");
+}
+
+
+static int __init early_init_dt_scan_cpus(unsigned long node,
+                                         const char *uname, int depth, void *data)
+{
+       char *type = get_flat_dt_prop(node, "device_type", NULL);
+       u32 *prop;
+       unsigned long size = 0;
+
+       /* We are scanning "cpu" nodes only */
+       if (type == NULL || strcmp(type, "cpu") != 0)
+               return 0;
+
+#ifdef CONFIG_PPC_PSERIES
+       /* On LPAR, look for the first ibm,pft-size property for the  hash table size
+        */
+       if (systemcfg->platform == PLATFORM_PSERIES_LPAR && ppc64_pft_size == 0) {
+               u32 *pft_size;
+               pft_size = get_flat_dt_prop(node, "ibm,pft-size", NULL);
+               if (pft_size != NULL) {
+                       /* pft_size[0] is the NUMA CEC cookie */
+                       ppc64_pft_size = pft_size[1];
+               }
+       }
+#endif
+
+#ifdef CONFIG_PPC64
+       if (initial_boot_params && initial_boot_params->version >= 2) {
+               /* version 2 of the kexec param format adds the phys cpuid
+                * of booted proc.
+                */
+               boot_cpuid_phys = initial_boot_params->boot_cpuid_phys;
+               boot_cpuid = 0;
+       } else {
+               /* Check if it's the boot-cpu, set it's hw index in paca now */
+               if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) {
+                       u32 *prop = get_flat_dt_prop(node, "reg", NULL);
+                       set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop);
+                       boot_cpuid_phys = get_hard_smp_processor_id(0);
+               }
+       }
+#endif
+
+#ifdef CONFIG_ALTIVEC
+       /* Check if we have a VMX and eventually update CPU features */
+       prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", &size);
+       if (prop && (*prop) > 0) {
+               cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
+               cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
+       }
+
+       /* Same goes for Apple's "altivec" property */
+       prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL);
+       if (prop) {
+               cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
+               cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
+       }
+#endif /* CONFIG_ALTIVEC */
+
+#ifdef CONFIG_PPC_PSERIES
+       /*
+        * Check for an SMT capable CPU and set the CPU feature. We do
+        * this by looking at the size of the ibm,ppc-interrupt-server#s
+        * property
+        */
+       prop = (u32 *)get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s",
+                                      &size);
+       cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
+       if (prop && ((size / sizeof(u32)) > 1))
+               cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
+#endif
+
+       return 0;
+}
+
+static int __init early_init_dt_scan_chosen(unsigned long node,
+                                           const char *uname, int depth, void *data)
+{
+       u32 *prop;
+       unsigned long *lprop;
+
+       DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+       if (depth != 1 || strcmp(uname, "chosen") != 0)
+               return 0;
+
+       /* get platform type */
+       prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL);
+       if (prop == NULL)
+               return 0;
+#ifdef CONFIG_PPC64
+       systemcfg->platform = *prop;
+#else
+       _machine = *prop;
+#endif
+
+#ifdef CONFIG_PPC64
+       /* check if iommu is forced on or off */
+       if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
+               iommu_is_off = 1;
+       if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL)
+               iommu_force_on = 1;
+#endif
+
+       lprop = get_flat_dt_prop(node, "linux,memory-limit", NULL);
+       if (lprop)
+               memory_limit = *lprop;
+
+#ifdef CONFIG_PPC64
+       lprop = get_flat_dt_prop(node, "linux,tce-alloc-start", NULL);
+       if (lprop)
+               tce_alloc_start = *lprop;
+       lprop = get_flat_dt_prop(node, "linux,tce-alloc-end", NULL);
+       if (lprop)
+               tce_alloc_end = *lprop;
+#endif
+
+#ifdef CONFIG_PPC_RTAS
+       /* To help early debugging via the front panel, we retreive a minimal
+        * set of RTAS infos now if available
+        */
+       {
+               u64 *basep, *entryp;
+
+               basep = get_flat_dt_prop(node, "linux,rtas-base", NULL);
+               entryp = get_flat_dt_prop(node, "linux,rtas-entry", NULL);
+               prop = get_flat_dt_prop(node, "linux,rtas-size", NULL);
+               if (basep && entryp && prop) {
+                       rtas.base = *basep;
+                       rtas.entry = *entryp;
+                       rtas.size = *prop;
+               }
+       }
+#endif /* CONFIG_PPC_RTAS */
+
+       /* break now */
+       return 1;
+}
+
+static int __init early_init_dt_scan_root(unsigned long node,
+                                         const char *uname, int depth, void *data)
+{
+       u32 *prop;
+
+       if (depth != 0)
+               return 0;
+
+       prop = get_flat_dt_prop(node, "#size-cells", NULL);
+       dt_root_size_cells = (prop == NULL) ? 1 : *prop;
+       DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
+
+       prop = get_flat_dt_prop(node, "#address-cells", NULL);
+       dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
+       DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
+       
+       /* break now */
+       return 1;
+}
+
+static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
+{
+       cell_t *p = *cellp;
+       unsigned long r;
+
+       /* Ignore more than 2 cells */
+       while (s > sizeof(unsigned long) / 4) {
+               p++;
+               s--;
+       }
+       r = *p++;
+#ifdef CONFIG_PPC64
+       if (s > 1) {
+               r <<= 32;
+               r |= *(p++);
+               s--;
+       }
+#endif
+
+       *cellp = p;
+       return r;
+}
+
+
+static int __init early_init_dt_scan_memory(unsigned long node,
+                                           const char *uname, int depth, void *data)
+{
+       char *type = get_flat_dt_prop(node, "device_type", NULL);
+       cell_t *reg, *endp;
+       unsigned long l;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL || strcmp(type, "memory") != 0)
+               return 0;
+
+       reg = (cell_t *)get_flat_dt_prop(node, "reg", &l);
+       if (reg == NULL)
+               return 0;
+
+       endp = reg + (l / sizeof(cell_t));
+
+       DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",
+           uname, l, reg[0], reg[1], reg[2], reg[3]);
+
+       while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
+               unsigned long base, size;
+
+               base = dt_mem_next_cell(dt_root_addr_cells, &reg);
+               size = dt_mem_next_cell(dt_root_size_cells, &reg);
+
+               if (size == 0)
+                       continue;
+               DBG(" - %lx ,  %lx\n", base, size);
+#ifdef CONFIG_PPC64
+               if (iommu_is_off) {
+                       if (base >= 0x80000000ul)
+                               continue;
+                       if ((base + size) > 0x80000000ul)
+                               size = 0x80000000ul - base;
+               }
+#endif
+               lmb_add(base, size);
+       }
+       return 0;
+}
+
+static void __init early_reserve_mem(void)
+{
+       unsigned long base, size;
+       unsigned long *reserve_map;
+
+       reserve_map = (unsigned long *)(((unsigned long)initial_boot_params) +
+                                       initial_boot_params->off_mem_rsvmap);
+       while (1) {
+               base = *(reserve_map++);
+               size = *(reserve_map++);
+               if (size == 0)
+                       break;
+               DBG("reserving: %lx -> %lx\n", base, size);
+               lmb_reserve(base, size);
+       }
+
+#if 0
+       DBG("memory reserved, lmbs :\n");
+       lmb_dump_all();
+#endif
+}
+
+void __init early_init_devtree(void *params)
+{
+       DBG(" -> early_init_devtree()\n");
+
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /* Retrieve various informations from the /chosen node of the
+        * device-tree, including the platform type, initrd location and
+        * size, TCE reserve, and more ...
+        */
+       scan_flat_dt(early_init_dt_scan_chosen, NULL);
+
+       /* Scan memory nodes and rebuild LMBs */
+       lmb_init();
+       scan_flat_dt(early_init_dt_scan_root, NULL);
+       scan_flat_dt(early_init_dt_scan_memory, NULL);
+       lmb_enforce_memory_limit(memory_limit);
+       lmb_analyze();
+#ifdef CONFIG_PPC64
+       systemcfg->physicalMemorySize = lmb_phys_mem_size();
+#endif
+       lmb_reserve(0, __pa(klimit));
+
+       DBG("Phys. mem: %lx\n", lmb_phys_mem_size());
+
+       /* Reserve LMB regions used by kernel, initrd, dt, etc... */
+       early_reserve_mem();
+
+       DBG("Scanning CPUs ...\n");
+
+       /* Retreive hash table size from flattened tree plus other
+        * CPU related informations (altivec support, boot CPU ID, ...)
+        */
+       scan_flat_dt(early_init_dt_scan_cpus, NULL);
+
+#ifdef CONFIG_PPC_PSERIES
+       /* If hash size wasn't obtained above, we calculate it now based on
+        * the total RAM size
+        */
+       if (ppc64_pft_size == 0) {
+               unsigned long rnd_mem_size, pteg_count;
+
+               /* round mem_size up to next power of 2 */
+               rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize);
+               if (rnd_mem_size < systemcfg->physicalMemorySize)
+                       rnd_mem_size <<= 1;
+
+               /* # pages / 2 */
+               pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11);
+
+               ppc64_pft_size = __ilog2(pteg_count << 7);
+       }
+
+       DBG("Hash pftSize: %x\n", (int)ppc64_pft_size);
+#endif
+       DBG(" <- early_init_devtree()\n");
+}
+
+#undef printk
+
+int
+prom_n_addr_cells(struct device_node* np)
+{
+       int* ip;
+       do {
+               if (np->parent)
+                       np = np->parent;
+               ip = (int *) get_property(np, "#address-cells", NULL);
+               if (ip != NULL)
+                       return *ip;
+       } while (np->parent);
+       /* No #address-cells property for the root node, default to 1 */
+       return 1;
+}
+
+int
+prom_n_size_cells(struct device_node* np)
+{
+       int* ip;
+       do {
+               if (np->parent)
+                       np = np->parent;
+               ip = (int *) get_property(np, "#size-cells", NULL);
+               if (ip != NULL)
+                       return *ip;
+       } while (np->parent);
+       /* No #size-cells property for the root node, default to 1 */
+       return 1;
+}
+
+/**
+ * Work out the sense (active-low level / active-high edge)
+ * of each interrupt from the device tree.
+ */
+void __init prom_get_irq_senses(unsigned char *senses, int off, int max)
+{
+       struct device_node *np;
+       int i, j;
+
+       /* default to level-triggered */
+       memset(senses, 1, max - off);
+
+       for (np = allnodes; np != 0; np = np->allnext) {
+               for (j = 0; j < np->n_intrs; j++) {
+                       i = np->intrs[j].line;
+                       if (i >= off && i < max)
+                               senses[i-off] = np->intrs[j].sense ?
+                                       IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE :
+                                       IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE;
+               }
+       }
+}
+
+/**
+ * Construct and return a list of the device_nodes with a given name.
+ */
+struct device_node *find_devices(const char *name)
+{
+       struct device_node *head, **prevp, *np;
+
+       prevp = &head;
+       for (np = allnodes; np != 0; np = np->allnext) {
+               if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+                       *prevp = np;
+                       prevp = &np->next;
+               }
+       }
+       *prevp = NULL;
+       return head;
+}
+EXPORT_SYMBOL(find_devices);
+
+/**
+ * Construct and return a list of the device_nodes with a given type.
+ */
+struct device_node *find_type_devices(const char *type)
+{
+       struct device_node *head, **prevp, *np;
+
+       prevp = &head;
+       for (np = allnodes; np != 0; np = np->allnext) {
+               if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+                       *prevp = np;
+                       prevp = &np->next;
+               }
+       }
+       *prevp = NULL;
+       return head;
+}
+EXPORT_SYMBOL(find_type_devices);
+
+/**
+ * Returns all nodes linked together
+ */
+struct device_node *find_all_nodes(void)
+{
+       struct device_node *head, **prevp, *np;
+
+       prevp = &head;
+       for (np = allnodes; np != 0; np = np->allnext) {
+               *prevp = np;
+               prevp = &np->next;
+       }
+       *prevp = NULL;
+       return head;
+}
+EXPORT_SYMBOL(find_all_nodes);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int device_is_compatible(struct device_node *device, const char *compat)
+{
+       const char* cp;
+       int cplen, l;
+
+       cp = (char *) get_property(device, "compatible", &cplen);
+       if (cp == NULL)
+               return 0;
+       while (cplen > 0) {
+               if (strncasecmp(cp, compat, strlen(compat)) == 0)
+                       return 1;
+               l = strlen(cp) + 1;
+               cp += l;
+               cplen -= l;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(device_is_compatible);
+
+
+/**
+ * Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+int machine_is_compatible(const char *compat)
+{
+       struct device_node *root;
+       int rc = 0;
+
+       root = of_find_node_by_path("/");
+       if (root) {
+               rc = device_is_compatible(root, compat);
+               of_node_put(root);
+       }
+       return rc;
+}
+EXPORT_SYMBOL(machine_is_compatible);
+
+/**
+ * Construct and return a list of the device_nodes with a given type
+ * and compatible property.
+ */
+struct device_node *find_compatible_devices(const char *type,
+                                           const char *compat)
+{
+       struct device_node *head, **prevp, *np;
+
+       prevp = &head;
+       for (np = allnodes; np != 0; np = np->allnext) {
+               if (type != NULL
+                   && !(np->type != 0 && strcasecmp(np->type, type) == 0))
+                       continue;
+               if (device_is_compatible(np, compat)) {
+                       *prevp = np;
+                       prevp = &np->next;
+               }
+       }
+       *prevp = NULL;
+       return head;
+}
+EXPORT_SYMBOL(find_compatible_devices);
+
+/**
+ * Find the device_node with a given full_name.
+ */
+struct device_node *find_path_device(const char *path)
+{
+       struct device_node *np;
+
+       for (np = allnodes; np != 0; np = np->allnext)
+               if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+                       return np;
+       return NULL;
+}
+EXPORT_SYMBOL(find_path_device);
+
+/*******
+ *
+ * New implementation of the OF "find" APIs, return a refcounted
+ * object, call of_node_put() when done.  The device tree and list
+ * are protected by a rw_lock.
+ *
+ * Note that property management will need some locking as well,
+ * this isn't dealt with yet.
+ *
+ *******/
+
+/**
+ *     of_find_node_by_name - Find a node by its "name" property
+ *     @from:  The node to start searching from or NULL, the node
+ *             you pass will not be searched, only the next one
+ *             will; typically, you pass what the previous call
+ *             returned. of_node_put() will be called on it
+ *     @name:  The name string to match against
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np != 0; np = np->allnext)
+               if (np->name != 0 && strcasecmp(np->name, name) == 0
+                   && of_node_get(np))
+                       break;
+       if (from)
+               of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ *     of_find_node_by_type - Find a node by its "device_type" property
+ *     @from:  The node to start searching from or NULL, the node
+ *             you pass will not be searched, only the next one
+ *             will; typically, you pass what the previous call
+ *             returned. of_node_put() will be called on it
+ *     @name:  The type string to match against
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np != 0; np = np->allnext)
+               if (np->type != 0 && strcasecmp(np->type, type) == 0
+                   && of_node_get(np))
+                       break;
+       if (from)
+               of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ *     of_find_compatible_node - Find a node based on type and one of the
+ *                                tokens in its "compatible" property
+ *     @from:          The node to start searching from or NULL, the node
+ *                     you pass will not be searched, only the next one
+ *                     will; typically, you pass what the previous call
+ *                     returned. of_node_put() will be called on it
+ *     @type:          The type string to match "device_type" or NULL to ignore
+ *     @compatible:    The string to match to one of the tokens in the device
+ *                     "compatible" list.
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compatible)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np != 0; np = np->allnext) {
+               if (type != NULL
+                   && !(np->type != 0 && strcasecmp(np->type, type) == 0))
+                       continue;
+               if (device_is_compatible(np, compatible) && of_node_get(np))
+                       break;
+       }
+       if (from)
+               of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
+
+/**
+ *     of_find_node_by_path - Find a node matching a full OF path
+ *     @path:  The full path to match
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+       struct device_node *np = allnodes;
+
+       read_lock(&devtree_lock);
+       for (; np != 0; np = np->allnext) {
+               if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
+                   && of_node_get(np))
+                       break;
+       }
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ *     of_find_node_by_phandle - Find a node given a phandle
+ *     @handle:        phandle of the node to find
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       for (np = allnodes; np != 0; np = np->allnext)
+               if (np->linux_phandle == handle)
+                       break;
+       if (np)
+               of_node_get(np);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+/**
+ *     of_find_all_nodes - Get next node in global list
+ *     @prev:  Previous node or NULL to start iteration
+ *             of_node_put() will be called on it
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_all_nodes(struct device_node *prev)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = prev ? prev->allnext : allnodes;
+       for (; np != 0; np = np->allnext)
+               if (of_node_get(np))
+                       break;
+       if (prev)
+               of_node_put(prev);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_all_nodes);
+
+/**
+ *     of_get_parent - Get a node's parent if any
+ *     @node:  Node to get parent
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+       struct device_node *np;
+
+       if (!node)
+               return NULL;
+
+       read_lock(&devtree_lock);
+       np = of_node_get(node->parent);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ *     of_get_next_child - Iterate a node childs
+ *     @node:  parent node
+ *     @prev:  previous child of the parent node, or NULL to get first
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+       struct device_node *prev)
+{
+       struct device_node *next;
+
+       read_lock(&devtree_lock);
+       next = prev ? prev->sibling : node->child;
+       for (; next != 0; next = next->sibling)
+               if (of_node_get(next))
+                       break;
+       if (prev)
+               of_node_put(prev);
+       read_unlock(&devtree_lock);
+       return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ *     of_node_get - Increment refcount of a node
+ *     @node:  Node to inc refcount, NULL is supported to
+ *             simplify writing of callers
+ *
+ *     Returns node.
+ */
+struct device_node *of_node_get(struct device_node *node)
+{
+       if (node)
+               kref_get(&node->kref);
+       return node;
+}
+EXPORT_SYMBOL(of_node_get);
+
+static inline struct device_node * kref_to_device_node(struct kref *kref)
+{
+       return container_of(kref, struct device_node, kref);
+}
+
+/**
+ *     of_node_release - release a dynamically allocated node
+ *     @kref:  kref element of the node to be released
+ *
+ *     In of_node_put() this function is passed to kref_put()
+ *     as the destructor.
+ */
+static void of_node_release(struct kref *kref)
+{
+       struct device_node *node = kref_to_device_node(kref);
+       struct property *prop = node->properties;
+
+       if (!OF_IS_DYNAMIC(node))
+               return;
+       while (prop) {
+               struct property *next = prop->next;
+               kfree(prop->name);
+               kfree(prop->value);
+               kfree(prop);
+               prop = next;
+       }
+       kfree(node->intrs);
+       kfree(node->addrs);
+       kfree(node->full_name);
+       kfree(node->data);
+       kfree(node);
+}
+
+/**
+ *     of_node_put - Decrement refcount of a node
+ *     @node:  Node to dec refcount, NULL is supported to
+ *             simplify writing of callers
+ *
+ */
+void of_node_put(struct device_node *node)
+{
+       if (node)
+               kref_put(&node->kref, of_node_release);
+}
+EXPORT_SYMBOL(of_node_put);
+
+/*
+ * Plug a device node into the tree and global list.
+ */
+void of_attach_node(struct device_node *np)
+{
+       write_lock(&devtree_lock);
+       np->sibling = np->parent->child;
+       np->allnext = allnodes;
+       np->parent->child = np;
+       allnodes = np;
+       write_unlock(&devtree_lock);
+}
+
+/*
+ * "Unplug" a node from the device tree.  The caller must hold
+ * a reference to the node.  The memory associated with the node
+ * is not freed until its refcount goes to zero.
+ */
+void of_detach_node(const struct device_node *np)
+{
+       struct device_node *parent;
+
+       write_lock(&devtree_lock);
+
+       parent = np->parent;
+
+       if (allnodes == np)
+               allnodes = np->allnext;
+       else {
+               struct device_node *prev;
+               for (prev = allnodes;
+                    prev->allnext != np;
+                    prev = prev->allnext)
+                       ;
+               prev->allnext = np->allnext;
+       }
+
+       if (parent->child == np)
+               parent->child = np->sibling;
+       else {
+               struct device_node *prevsib;
+               for (prevsib = np->parent->child;
+                    prevsib->sibling != np;
+                    prevsib = prevsib->sibling)
+                       ;
+               prevsib->sibling = np->sibling;
+       }
+
+       write_unlock(&devtree_lock);
+}
+
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Fix up the uninitialized fields in a new device node:
+ * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields
+ *
+ * A lot of boot-time code is duplicated here, because functions such
+ * as finish_node_interrupts, interpret_pci_props, etc. cannot use the
+ * slab allocator.
+ *
+ * This should probably be split up into smaller chunks.
+ */
+
+static int of_finish_dynamic_node(struct device_node *node,
+                                 unsigned long *unused1, int unused2,
+                                 int unused3, int unused4)
+{
+       struct device_node *parent = of_get_parent(node);
+       int err = 0;
+       phandle *ibm_phandle;
+
+       node->name = get_property(node, "name", NULL);
+       node->type = get_property(node, "device_type", NULL);
+
+       if (!parent) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       /* We don't support that function on PowerMac, at least
+        * not yet
+        */
+       if (systemcfg->platform == PLATFORM_POWERMAC)
+               return -ENODEV;
+
+       /* fix up new node's linux_phandle field */
+       if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
+               node->linux_phandle = *ibm_phandle;
+
+out:
+       of_node_put(parent);
+       return err;
+}
+
+static int prom_reconfig_notifier(struct notifier_block *nb,
+                                 unsigned long action, void *node)
+{
+       int err;
+
+       switch (action) {
+       case PSERIES_RECONFIG_ADD:
+               err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0);
+               if (err < 0) {
+                       printk(KERN_ERR "finish_node returned %d\n", err);
+                       err = NOTIFY_BAD;
+               }
+               break;
+       default:
+               err = NOTIFY_DONE;
+               break;
+       }
+       return err;
+}
+
+static struct notifier_block prom_reconfig_nb = {
+       .notifier_call = prom_reconfig_notifier,
+       .priority = 10, /* This one needs to run first */
+};
+
+static int __init prom_reconfig_setup(void)
+{
+       return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
+}
+__initcall(prom_reconfig_setup);
+#endif
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *get_property(struct device_node *np, const char *name,
+                           int *lenp)
+{
+       struct property *pp;
+
+       for (pp = np->properties; pp != 0; pp = pp->next)
+               if (strcmp(pp->name, name) == 0) {
+                       if (lenp != 0)
+                               *lenp = pp->length;
+                       return pp->value;
+               }
+       return NULL;
+}
+EXPORT_SYMBOL(get_property);
+
+/*
+ * Add a property to a node
+ */
+void prom_add_property(struct device_node* np, struct property* prop)
+{
+       struct property **next = &np->properties;
+
+       prop->next = NULL;      
+       while (*next)
+               next = &(*next)->next;
+       *next = prop;
+}
+
+/* I quickly hacked that one, check against spec ! */
+static inline unsigned long
+bus_space_to_resource_flags(unsigned int bus_space)
+{
+       u8 space = (bus_space >> 24) & 0xf;
+       if (space == 0)
+               space = 0x02;
+       if (space == 0x02)
+               return IORESOURCE_MEM;
+       else if (space == 0x01)
+               return IORESOURCE_IO;
+       else {
+               printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
+                       bus_space);
+               return 0;
+       }
+}
+
+static struct resource *find_parent_pci_resource(struct pci_dev* pdev,
+                                                struct address_range *range)
+{
+       unsigned long mask;
+       int i;
+
+       /* Check this one */
+       mask = bus_space_to_resource_flags(range->space);
+       for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
+               if ((pdev->resource[i].flags & mask) == mask &&
+                       pdev->resource[i].start <= range->address &&
+                       pdev->resource[i].end > range->address) {
+                               if ((range->address + range->size - 1) > pdev->resource[i].end) {
+                                       /* Add better message */
+                                       printk(KERN_WARNING "PCI/OF resource overlap !\n");
+                                       return NULL;
+                               }
+                               break;
+                       }
+       }
+       if (i == DEVICE_COUNT_RESOURCE)
+               return NULL;
+       return &pdev->resource[i];
+}
+
+/*
+ * Request an OF device resource. Currently handles child of PCI devices,
+ * or other nodes attached to the root node. Ultimately, put some
+ * link to resources in the OF node.
+ */
+struct resource *request_OF_resource(struct device_node* node, int index,
+                                    const char* name_postfix)
+{
+       struct pci_dev* pcidev;
+       u8 pci_bus, pci_devfn;
+       unsigned long iomask;
+       struct device_node* nd;
+       struct resource* parent;
+       struct resource *res = NULL;
+       int nlen, plen;
+
+       if (index >= node->n_addrs)
+               goto fail;
+
+       /* Sanity check on bus space */
+       iomask = bus_space_to_resource_flags(node->addrs[index].space);
+       if (iomask & IORESOURCE_MEM)
+               parent = &iomem_resource;
+       else if (iomask & IORESOURCE_IO)
+               parent = &ioport_resource;
+       else
+               goto fail;
+
+       /* Find a PCI parent if any */
+       nd = node;
+       pcidev = NULL;
+       while (nd) {
+               if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
+                       pcidev = pci_find_slot(pci_bus, pci_devfn);
+               if (pcidev) break;
+               nd = nd->parent;
+       }
+       if (pcidev)
+               parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
+       if (!parent) {
+               printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
+                       node->name);
+               goto fail;
+       }
+
+       res = __request_region(parent, node->addrs[index].address,
+                              node->addrs[index].size, NULL);
+       if (!res)
+               goto fail;
+       nlen = strlen(node->name);
+       plen = name_postfix ? strlen(name_postfix) : 0;
+       res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
+       if (res->name) {
+               strcpy((char *)res->name, node->name);
+               if (plen)
+                       strcpy((char *)res->name+nlen, name_postfix);
+       }
+       return res;
+fail:
+       return NULL;
+}
+EXPORT_SYMBOL(request_OF_resource);
+
+int release_OF_resource(struct device_node *node, int index)
+{
+       struct pci_dev* pcidev;
+       u8 pci_bus, pci_devfn;
+       unsigned long iomask, start, end;
+       struct device_node* nd;
+       struct resource* parent;
+       struct resource *res = NULL;
+
+       if (index >= node->n_addrs)
+               return -EINVAL;
+
+       /* Sanity check on bus space */
+       iomask = bus_space_to_resource_flags(node->addrs[index].space);
+       if (iomask & IORESOURCE_MEM)
+               parent = &iomem_resource;
+       else if (iomask & IORESOURCE_IO)
+               parent = &ioport_resource;
+       else
+               return -EINVAL;
+
+       /* Find a PCI parent if any */
+       nd = node;
+       pcidev = NULL;
+       while(nd) {
+               if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
+                       pcidev = pci_find_slot(pci_bus, pci_devfn);
+               if (pcidev) break;
+               nd = nd->parent;
+       }
+       if (pcidev)
+               parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
+       if (!parent) {
+               printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
+                       node->name);
+               return -ENODEV;
+       }
+
+       /* Find us in the parent and its childs */
+       res = parent->child;
+       start = node->addrs[index].address;
+       end = start + node->addrs[index].size - 1;
+       while (res) {
+               if (res->start == start && res->end == end &&
+                   (res->flags & IORESOURCE_BUSY))
+                       break;
+               if (res->start <= start && res->end >= end)
+                       res = res->child;
+               else
+                       res = res->sibling;
+       }
+       if (!res)
+               return -ENODEV;
+
+       if (res->name) {
+               kfree(res->name);
+               res->name = NULL;
+       }
+       release_resource(res);
+       kfree(res);
+
+       return 0;
+}
+EXPORT_SYMBOL(release_OF_resource);
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
new file mode 100644 (file)
index 0000000..e01cda1
--- /dev/null
@@ -0,0 +1,2126 @@
+/*
+ * Procedures for interfacing to Open Firmware.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ * 
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.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.
+ */
+
+#undef DEBUG_PROM
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/initrd.h>
+#include <linux/bitops.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/pci.h>
+#include <asm/iommu.h>
+#include <asm/bootinfo.h>
+#include <asm/btext.h>
+#include <asm/sections.h>
+#include <asm/machdep.h>
+
+#ifdef CONFIG_LOGO_LINUX_CLUT224
+#include <linux/linux_logo.h>
+extern const struct linux_logo logo_linux_clut224;
+#endif
+
+/*
+ * Properties whose value is longer than this get excluded from our
+ * copy of the device tree. This value does need to be big enough to
+ * ensure that we don't lose things like the interrupt-map property
+ * on a PCI-PCI bridge.
+ */
+#define MAX_PROPERTY_LENGTH    (1UL * 1024 * 1024)
+
+/*
+ * Eventually bump that one up
+ */
+#define DEVTREE_CHUNK_SIZE     0x100000
+
+/*
+ * This is the size of the local memory reserve map that gets copied
+ * into the boot params passed to the kernel. That size is totally
+ * flexible as the kernel just reads the list until it encounters an
+ * entry with size 0, so it can be changed without breaking binary
+ * compatibility
+ */
+#define MEM_RESERVE_MAP_SIZE   8
+
+/*
+ * prom_init() is called very early on, before the kernel text
+ * and data have been mapped to KERNELBASE.  At this point the code
+ * is running at whatever address it has been loaded at.
+ * On ppc32 we compile with -mrelocatable, which means that references
+ * to extern and static variables get relocated automatically.
+ * On ppc64 we have to relocate the references explicitly with
+ * RELOC.  (Note that strings count as static variables.)
+ *
+ * Because OF may have mapped I/O devices into the area starting at
+ * KERNELBASE, particularly on CHRP machines, we can't safely call
+ * OF once the kernel has been mapped to KERNELBASE.  Therefore all
+ * OF calls must be done within prom_init().
+ *
+ * ADDR is used in calls to call_prom.  The 4th and following
+ * arguments to call_prom should be 32-bit values.
+ * On ppc64, 64 bit values are truncated to 32 bits (and
+ * fortunately don't get interpreted as two arguments).
+ */
+#ifdef CONFIG_PPC64
+#define RELOC(x)        (*PTRRELOC(&(x)))
+#define ADDR(x)                (u32) add_reloc_offset((unsigned long)(x))
+#else
+#define RELOC(x)       (x)
+#define ADDR(x)                (u32) (x)
+#endif
+
+#define PROM_BUG() do {                                                \
+        prom_printf("kernel BUG at %s line 0x%x!\n",           \
+                   RELOC(__FILE__), __LINE__);                 \
+        __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR);      \
+} while (0)
+
+#ifdef DEBUG_PROM
+#define prom_debug(x...)       prom_printf(x)
+#else
+#define prom_debug(x...)
+#endif
+
+#ifdef CONFIG_PPC32
+#define PLATFORM_POWERMAC      _MACH_Pmac
+#define PLATFORM_CHRP          _MACH_chrp
+#endif
+
+
+typedef u32 prom_arg_t;
+
+struct prom_args {
+        u32 service;
+        u32 nargs;
+        u32 nret;
+        prom_arg_t args[10];
+};
+
+struct prom_t {
+       ihandle root;
+       ihandle chosen;
+       int cpu;
+       ihandle stdout;
+};
+
+struct mem_map_entry {
+       unsigned long   base;
+       unsigned long   size;
+};
+
+typedef u32 cell_t;
+
+extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
+
+#ifdef CONFIG_PPC64
+extern void enter_prom(struct prom_args *args, unsigned long entry);
+#else
+static inline void enter_prom(struct prom_args *args, unsigned long entry)
+{
+       ((void (*)(struct prom_args *))entry)(args);
+}
+#endif
+
+extern void copy_and_flush(unsigned long dest, unsigned long src,
+                          unsigned long size, unsigned long offset);
+
+/* prom structure */
+static struct prom_t __initdata prom;
+
+static unsigned long prom_entry __initdata;
+
+#define PROM_SCRATCH_SIZE 256
+
+static char __initdata of_stdout_device[256];
+static char __initdata prom_scratch[PROM_SCRATCH_SIZE];
+
+static unsigned long __initdata dt_header_start;
+static unsigned long __initdata dt_struct_start, dt_struct_end;
+static unsigned long __initdata dt_string_start, dt_string_end;
+
+static unsigned long __initdata prom_initrd_start, prom_initrd_end;
+
+#ifdef CONFIG_PPC64
+static int __initdata iommu_force_on;
+static int __initdata ppc64_iommu_off;
+static unsigned long __initdata prom_tce_alloc_start;
+static unsigned long __initdata prom_tce_alloc_end;
+#endif
+
+static int __initdata of_platform;
+
+static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
+
+static unsigned long __initdata prom_memory_limit;
+
+static unsigned long __initdata alloc_top;
+static unsigned long __initdata alloc_top_high;
+static unsigned long __initdata alloc_bottom;
+static unsigned long __initdata rmo_top;
+static unsigned long __initdata ram_top;
+
+static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
+static int __initdata mem_reserve_cnt;
+
+static cell_t __initdata regbuf[1024];
+
+
+#define MAX_CPU_THREADS 2
+
+/* TO GO */
+#ifdef CONFIG_HMT
+struct {
+       unsigned int pir;
+       unsigned int threadid;
+} hmt_thread_data[NR_CPUS];
+#endif /* CONFIG_HMT */
+
+/*
+ * Error results ... some OF calls will return "-1" on error, some
+ * will return 0, some will return either. To simplify, here are
+ * macros to use with any ihandle or phandle return value to check if
+ * it is valid
+ */
+
+#define PROM_ERROR             (-1u)
+#define PHANDLE_VALID(p)       ((p) != 0 && (p) != PROM_ERROR)
+#define IHANDLE_VALID(i)       ((i) != 0 && (i) != PROM_ERROR)
+
+
+/* This is the one and *ONLY* place where we actually call open
+ * firmware.
+ */
+
+static int __init call_prom(const char *service, int nargs, int nret, ...)
+{
+       int i;
+       struct prom_args args;
+       va_list list;
+
+       args.service = ADDR(service);
+       args.nargs = nargs;
+       args.nret = nret;
+
+       va_start(list, nret);
+       for (i = 0; i < nargs; i++)
+               args.args[i] = va_arg(list, prom_arg_t);
+       va_end(list);
+
+       for (i = 0; i < nret; i++)
+               args.args[nargs+i] = 0;
+
+       enter_prom(&args, RELOC(prom_entry));
+
+       return (nret > 0) ? args.args[nargs] : 0;
+}
+
+static int __init call_prom_ret(const char *service, int nargs, int nret,
+                               prom_arg_t *rets, ...)
+{
+       int i;
+       struct prom_args args;
+       va_list list;
+
+       args.service = ADDR(service);
+       args.nargs = nargs;
+       args.nret = nret;
+
+       va_start(list, rets);
+       for (i = 0; i < nargs; i++)
+               args.args[i] = va_arg(list, prom_arg_t);
+       va_end(list);
+
+       for (i = 0; i < nret; i++)
+               rets[nargs+i] = 0;
+
+       enter_prom(&args, RELOC(prom_entry));
+
+       if (rets != NULL)
+               for (i = 1; i < nret; ++i)
+                       rets[i] = args.args[nargs+i];
+
+       return (nret > 0) ? args.args[nargs] : 0;
+}
+
+
+static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
+                               unsigned long align)
+{
+       return (unsigned int)call_prom("claim", 3, 1,
+                                      (prom_arg_t)virt, (prom_arg_t)size,
+                                      (prom_arg_t)align);
+}
+
+static void __init prom_print(const char *msg)
+{
+       const char *p, *q;
+       struct prom_t *_prom = &RELOC(prom);
+
+       if (_prom->stdout == 0)
+               return;
+
+       for (p = msg; *p != 0; p = q) {
+               for (q = p; *q != 0 && *q != '\n'; ++q)
+                       ;
+               if (q > p)
+                       call_prom("write", 3, 1, _prom->stdout, p, q - p);
+               if (*q == 0)
+                       break;
+               ++q;
+               call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2);
+       }
+}
+
+
+static void __init prom_print_hex(unsigned long val)
+{
+       int i, nibbles = sizeof(val)*2;
+       char buf[sizeof(val)*2+1];
+       struct prom_t *_prom = &RELOC(prom);
+
+       for (i = nibbles-1;  i >= 0;  i--) {
+               buf[i] = (val & 0xf) + '0';
+               if (buf[i] > '9')
+                       buf[i] += ('a'-'0'-10);
+               val >>= 4;
+       }
+       buf[nibbles] = '\0';
+       call_prom("write", 3, 1, _prom->stdout, buf, nibbles);
+}
+
+
+static void __init prom_printf(const char *format, ...)
+{
+       const char *p, *q, *s;
+       va_list args;
+       unsigned long v;
+       struct prom_t *_prom = &RELOC(prom);
+
+       va_start(args, format);
+#ifdef CONFIG_PPC64
+       format = PTRRELOC(format);
+#endif
+       for (p = format; *p != 0; p = q) {
+               for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
+                       ;
+               if (q > p)
+                       call_prom("write", 3, 1, _prom->stdout, p, q - p);
+               if (*q == 0)
+                       break;
+               if (*q == '\n') {
+                       ++q;
+                       call_prom("write", 3, 1, _prom->stdout,
+                                 ADDR("\r\n"), 2);
+                       continue;
+               }
+               ++q;
+               if (*q == 0)
+                       break;
+               switch (*q) {
+               case 's':
+                       ++q;
+                       s = va_arg(args, const char *);
+                       prom_print(s);
+                       break;
+               case 'x':
+                       ++q;
+                       v = va_arg(args, unsigned long);
+                       prom_print_hex(v);
+                       break;
+               }
+       }
+}
+
+
+static void __init __attribute__((noreturn)) prom_panic(const char *reason)
+{
+#ifdef CONFIG_PPC64
+       reason = PTRRELOC(reason);
+#endif
+       prom_print(reason);
+       /* ToDo: should put up an SRC here on p/iSeries */
+       call_prom("exit", 0, 0);
+
+       for (;;)                        /* should never get here */
+               ;
+}
+
+
+static int __init prom_next_node(phandle *nodep)
+{
+       phandle node;
+
+       if ((node = *nodep) != 0
+           && (*nodep = call_prom("child", 1, 1, node)) != 0)
+               return 1;
+       if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+               return 1;
+       for (;;) {
+               if ((node = call_prom("parent", 1, 1, node)) == 0)
+                       return 0;
+               if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+                       return 1;
+       }
+}
+
+static int __init prom_getprop(phandle node, const char *pname,
+                              void *value, size_t valuelen)
+{
+       return call_prom("getprop", 4, 1, node, ADDR(pname),
+                        (u32)(unsigned long) value, (u32) valuelen);
+}
+
+static int __init prom_getproplen(phandle node, const char *pname)
+{
+       return call_prom("getproplen", 2, 1, node, ADDR(pname));
+}
+
+static int __init prom_setprop(phandle node, const char *pname,
+                              void *value, size_t valuelen)
+{
+       return call_prom("setprop", 4, 1, node, ADDR(pname),
+                        (u32)(unsigned long) value, (u32) valuelen);
+}
+
+/* We can't use the standard versions because of RELOC headaches. */
+#define isxdigit(c)    (('0' <= (c) && (c) <= '9') \
+                        || ('a' <= (c) && (c) <= 'f') \
+                        || ('A' <= (c) && (c) <= 'F'))
+
+#define isdigit(c)     ('0' <= (c) && (c) <= '9')
+#define islower(c)     ('a' <= (c) && (c) <= 'z')
+#define toupper(c)     (islower(c) ? ((c) - 'a' + 'A') : (c))
+
+unsigned long prom_strtoul(const char *cp, const char **endp)
+{
+       unsigned long result = 0, base = 10, value;
+
+       if (*cp == '0') {
+               base = 8;
+               cp++;
+               if (toupper(*cp) == 'X') {
+                       cp++;
+                       base = 16;
+               }
+       }
+
+       while (isxdigit(*cp) &&
+              (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {
+               result = result * base + value;
+               cp++;
+       }
+
+       if (endp)
+               *endp = cp;
+
+       return result;
+}
+
+unsigned long prom_memparse(const char *ptr, const char **retptr)
+{
+       unsigned long ret = prom_strtoul(ptr, retptr);
+       int shift = 0;
+
+       /*
+        * We can't use a switch here because GCC *may* generate a
+        * jump table which won't work, because we're not running at
+        * the address we're linked at.
+        */
+       if ('G' == **retptr || 'g' == **retptr)
+               shift = 30;
+
+       if ('M' == **retptr || 'm' == **retptr)
+               shift = 20;
+
+       if ('K' == **retptr || 'k' == **retptr)
+               shift = 10;
+
+       if (shift) {
+               ret <<= shift;
+               (*retptr)++;
+       }
+
+       return ret;
+}
+
+/*
+ * Early parsing of the command line passed to the kernel, used for
+ * "mem=x" and the options that affect the iommu
+ */
+static void __init early_cmdline_parse(void)
+{
+       struct prom_t *_prom = &RELOC(prom);
+       char *opt, *p;
+       int l = 0;
+
+       RELOC(prom_cmd_line[0]) = 0;
+       p = RELOC(prom_cmd_line);
+       if ((long)_prom->chosen > 0)
+               l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
+#ifdef CONFIG_CMDLINE
+       if (l == 0) /* dbl check */
+               strlcpy(RELOC(prom_cmd_line),
+                       RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));
+#endif /* CONFIG_CMDLINE */
+       prom_printf("command line: %s\n", RELOC(prom_cmd_line));
+
+#ifdef CONFIG_PPC64
+       opt = strstr(RELOC(prom_cmd_line), RELOC("iommu="));
+       if (opt) {
+               prom_printf("iommu opt is: %s\n", opt);
+               opt += 6;
+               while (*opt && *opt == ' ')
+                       opt++;
+               if (!strncmp(opt, RELOC("off"), 3))
+                       RELOC(ppc64_iommu_off) = 1;
+               else if (!strncmp(opt, RELOC("force"), 5))
+                       RELOC(iommu_force_on) = 1;
+       }
+#endif
+
+       opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
+       if (opt) {
+               opt += 4;
+               RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
+#ifdef CONFIG_PPC64
+               /* Align to 16 MB == size of ppc64 large page */
+               RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
+#endif
+       }
+}
+
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * To tell the firmware what our capabilities are, we have to pass
+ * it a fake 32-bit ELF header containing a couple of PT_NOTE sections
+ * that contain structures that contain the actual values.
+ */
+static struct fake_elf {
+       Elf32_Ehdr      elfhdr;
+       Elf32_Phdr      phdr[2];
+       struct chrpnote {
+               u32     namesz;
+               u32     descsz;
+               u32     type;
+               char    name[8];        /* "PowerPC" */
+               struct chrpdesc {
+                       u32     real_mode;
+                       u32     real_base;
+                       u32     real_size;
+                       u32     virt_base;
+                       u32     virt_size;
+                       u32     load_base;
+               } chrpdesc;
+       } chrpnote;
+       struct rpanote {
+               u32     namesz;
+               u32     descsz;
+               u32     type;
+               char    name[24];       /* "IBM,RPA-Client-Config" */
+               struct rpadesc {
+                       u32     lpar_affinity;
+                       u32     min_rmo_size;
+                       u32     min_rmo_percent;
+                       u32     max_pft_size;
+                       u32     splpar;
+                       u32     min_load;
+                       u32     new_mem_def;
+                       u32     ignore_me;
+               } rpadesc;
+       } rpanote;
+} fake_elf = {
+       .elfhdr = {
+               .e_ident = { 0x7f, 'E', 'L', 'F',
+                            ELFCLASS32, ELFDATA2MSB, EV_CURRENT },
+               .e_type = ET_EXEC,      /* yeah right */
+               .e_machine = EM_PPC,
+               .e_version = EV_CURRENT,
+               .e_phoff = offsetof(struct fake_elf, phdr),
+               .e_phentsize = sizeof(Elf32_Phdr),
+               .e_phnum = 2
+       },
+       .phdr = {
+               [0] = {
+                       .p_type = PT_NOTE,
+                       .p_offset = offsetof(struct fake_elf, chrpnote),
+                       .p_filesz = sizeof(struct chrpnote)
+               }, [1] = {
+                       .p_type = PT_NOTE,
+                       .p_offset = offsetof(struct fake_elf, rpanote),
+                       .p_filesz = sizeof(struct rpanote)
+               }
+       },
+       .chrpnote = {
+               .namesz = sizeof("PowerPC"),
+               .descsz = sizeof(struct chrpdesc),
+               .type = 0x1275,
+               .name = "PowerPC",
+               .chrpdesc = {
+                       .real_mode = ~0U,       /* ~0 means "don't care" */
+                       .real_base = ~0U,
+                       .real_size = ~0U,
+                       .virt_base = ~0U,
+                       .virt_size = ~0U,
+                       .load_base = ~0U
+               },
+       },
+       .rpanote = {
+               .namesz = sizeof("IBM,RPA-Client-Config"),
+               .descsz = sizeof(struct rpadesc),
+               .type = 0x12759999,
+               .name = "IBM,RPA-Client-Config",
+               .rpadesc = {
+                       .lpar_affinity = 0,
+                       .min_rmo_size = 64,     /* in megabytes */
+                       .min_rmo_percent = 0,
+                       .max_pft_size = 48,     /* 2^48 bytes max PFT size */
+                       .splpar = 1,
+                       .min_load = ~0U,
+                       .new_mem_def = 0
+               }
+       }
+};
+
+static void __init prom_send_capabilities(void)
+{
+       ihandle elfloader;
+
+       elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader"));
+       if (elfloader == 0) {
+               prom_printf("couldn't open /packages/elf-loader\n");
+               return;
+       }
+       call_prom("call-method", 3, 1, ADDR("process-elf-header"),
+                       elfloader, ADDR(&fake_elf));
+       call_prom("close", 1, 0, elfloader);
+}
+#endif
+
+/*
+ * Memory allocation strategy... our layout is normally:
+ *
+ *  at 14Mb or more we have vmlinux, then a gap and initrd.  In some
+ *  rare cases, initrd might end up being before the kernel though.
+ *  We assume this won't override the final kernel at 0, we have no
+ *  provision to handle that in this version, but it should hopefully
+ *  never happen.
+ *
+ *  alloc_top is set to the top of RMO, eventually shrink down if the
+ *  TCEs overlap
+ *
+ *  alloc_bottom is set to the top of kernel/initrd
+ *
+ *  from there, allocations are done this way : rtas is allocated
+ *  topmost, and the device-tree is allocated from the bottom. We try
+ *  to grow the device-tree allocation as we progress. If we can't,
+ *  then we fail, we don't currently have a facility to restart
+ *  elsewhere, but that shouldn't be necessary.
+ *
+ *  Note that calls to reserve_mem have to be done explicitly, memory
+ *  allocated with either alloc_up or alloc_down isn't automatically
+ *  reserved.
+ */
+
+
+/*
+ * Allocates memory in the RMO upward from the kernel/initrd
+ *
+ * When align is 0, this is a special case, it means to allocate in place
+ * at the current location of alloc_bottom or fail (that is basically
+ * extending the previous allocation). Used for the device-tree flattening
+ */
+static unsigned long __init alloc_up(unsigned long size, unsigned long align)
+{
+       unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align);
+       unsigned long addr = 0;
+
+       prom_debug("alloc_up(%x, %x)\n", size, align);
+       if (RELOC(ram_top) == 0)
+               prom_panic("alloc_up() called with mem not initialized\n");
+
+       if (align)
+               base = _ALIGN_UP(RELOC(alloc_bottom), align);
+       else
+               base = RELOC(alloc_bottom);
+
+       for(; (base + size) <= RELOC(alloc_top); 
+           base = _ALIGN_UP(base + 0x100000, align)) {
+               prom_debug("    trying: 0x%x\n\r", base);
+               addr = (unsigned long)prom_claim(base, size, 0);
+               if (addr != PROM_ERROR)
+                       break;
+               addr = 0;
+               if (align == 0)
+                       break;
+       }
+       if (addr == 0)
+               return 0;
+       RELOC(alloc_bottom) = addr;
+
+       prom_debug(" -> %x\n", addr);
+       prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));
+       prom_debug("  alloc_top    : %x\n", RELOC(alloc_top));
+       prom_debug("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
+       prom_debug("  rmo_top      : %x\n", RELOC(rmo_top));
+       prom_debug("  ram_top      : %x\n", RELOC(ram_top));
+
+       return addr;
+}
+
+/*
+ * Allocates memory downward, either from top of RMO, or if highmem
+ * is set, from the top of RAM.  Note that this one doesn't handle
+ * failures.  It does claim memory if highmem is not set.
+ */
+static unsigned long __init alloc_down(unsigned long size, unsigned long align,
+                                      int highmem)
+{
+       unsigned long base, addr = 0;
+
+       prom_debug("alloc_down(%x, %x, %s)\n", size, align,
+                  highmem ? RELOC("(high)") : RELOC("(low)"));
+       if (RELOC(ram_top) == 0)
+               prom_panic("alloc_down() called with mem not initialized\n");
+
+       if (highmem) {
+               /* Carve out storage for the TCE table. */
+               addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align);
+               if (addr <= RELOC(alloc_bottom))
+                       return 0;
+               /* Will we bump into the RMO ? If yes, check out that we
+                * didn't overlap existing allocations there, if we did,
+                * we are dead, we must be the first in town !
+                */
+               if (addr < RELOC(rmo_top)) {
+                       /* Good, we are first */
+                       if (RELOC(alloc_top) == RELOC(rmo_top))
+                               RELOC(alloc_top) = RELOC(rmo_top) = addr;
+                       else
+                               return 0;
+               }
+               RELOC(alloc_top_high) = addr;
+               goto bail;
+       }
+
+       base = _ALIGN_DOWN(RELOC(alloc_top) - size, align);
+       for (; base > RELOC(alloc_bottom);
+            base = _ALIGN_DOWN(base - 0x100000, align))  {
+               prom_debug("    trying: 0x%x\n\r", base);
+               addr = (unsigned long)prom_claim(base, size, 0);
+               if (addr != PROM_ERROR)
+                       break;
+               addr = 0;
+       }
+       if (addr == 0)
+               return 0;
+       RELOC(alloc_top) = addr;
+
+ bail:
+       prom_debug(" -> %x\n", addr);
+       prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));
+       prom_debug("  alloc_top    : %x\n", RELOC(alloc_top));
+       prom_debug("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
+       prom_debug("  rmo_top      : %x\n", RELOC(rmo_top));
+       prom_debug("  ram_top      : %x\n", RELOC(ram_top));
+
+       return addr;
+}
+
+/*
+ * Parse a "reg" cell
+ */
+static unsigned long __init prom_next_cell(int s, cell_t **cellp)
+{
+       cell_t *p = *cellp;
+       unsigned long r = 0;
+
+       /* Ignore more than 2 cells */
+       while (s > sizeof(unsigned long) / 4) {
+               p++;
+               s--;
+       }
+       r = *p++;
+#ifdef CONFIG_PPC64
+       if (s) {
+               r <<= 32;
+               r |= *(p++);
+       }
+#endif
+       *cellp = p;
+       return r;
+}
+
+/*
+ * Very dumb function for adding to the memory reserve list, but
+ * we don't need anything smarter at this point
+ *
+ * XXX Eventually check for collisions.  They should NEVER happen.
+ * If problems seem to show up, it would be a good start to track
+ * them down.
+ */
+static void reserve_mem(unsigned long base, unsigned long size)
+{
+       unsigned long top = base + size;
+       unsigned long cnt = RELOC(mem_reserve_cnt);
+
+       if (size == 0)
+               return;
+
+       /* We need to always keep one empty entry so that we
+        * have our terminator with "size" set to 0 since we are
+        * dumb and just copy this entire array to the boot params
+        */
+       base = _ALIGN_DOWN(base, PAGE_SIZE);
+       top = _ALIGN_UP(top, PAGE_SIZE);
+       size = top - base;
+
+       if (cnt >= (MEM_RESERVE_MAP_SIZE - 1))
+               prom_panic("Memory reserve map exhausted !\n");
+       RELOC(mem_reserve_map)[cnt].base = base;
+       RELOC(mem_reserve_map)[cnt].size = size;
+       RELOC(mem_reserve_cnt) = cnt + 1;
+}
+
+/*
+ * Initialize memory allocation mecanism, parse "memory" nodes and
+ * obtain that way the top of memory and RMO to setup out local allocator
+ */
+static void __init prom_init_mem(void)
+{
+       phandle node;
+       char *path, type[64];
+       unsigned int plen;
+       cell_t *p, *endp;
+       struct prom_t *_prom = &RELOC(prom);
+       u32 rac, rsc;
+
+       /*
+        * We iterate the memory nodes to find
+        * 1) top of RMO (first node)
+        * 2) top of memory
+        */
+       rac = 2;
+       prom_getprop(_prom->root, "#address-cells", &rac, sizeof(rac));
+       rsc = 1;
+       prom_getprop(_prom->root, "#size-cells", &rsc, sizeof(rsc));
+       prom_debug("root_addr_cells: %x\n", (unsigned long) rac);
+       prom_debug("root_size_cells: %x\n", (unsigned long) rsc);
+
+       prom_debug("scanning memory:\n");
+       path = RELOC(prom_scratch);
+
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               prom_getprop(node, "device_type", type, sizeof(type));
+
+               if (strcmp(type, RELOC("memory")))
+                       continue;
+       
+               plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
+               if (plen > sizeof(regbuf)) {
+                       prom_printf("memory node too large for buffer !\n");
+                       plen = sizeof(regbuf);
+               }
+               p = RELOC(regbuf);
+               endp = p + (plen / sizeof(cell_t));
+
+#ifdef DEBUG_PROM
+               memset(path, 0, PROM_SCRATCH_SIZE);
+               call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
+               prom_debug("  node %s :\n", path);
+#endif /* DEBUG_PROM */
+
+               while ((endp - p) >= (rac + rsc)) {
+                       unsigned long base, size;
+
+                       base = prom_next_cell(rac, &p);
+                       size = prom_next_cell(rsc, &p);
+
+                       if (size == 0)
+                               continue;
+                       prom_debug("    %x %x\n", base, size);
+                       if (base == 0)
+                               RELOC(rmo_top) = size;
+                       if ((base + size) > RELOC(ram_top))
+                               RELOC(ram_top) = base + size;
+               }
+       }
+
+       RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000);
+
+       /* Check if we have an initrd after the kernel, if we do move our bottom
+        * point to after it
+        */
+       if (RELOC(prom_initrd_start)) {
+               if (RELOC(prom_initrd_end) > RELOC(alloc_bottom))
+                       RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
+       }
+
+       /*
+        * If prom_memory_limit is set we reduce the upper limits *except* for
+        * alloc_top_high. This must be the real top of RAM so we can put
+        * TCE's up there.
+        */
+
+       RELOC(alloc_top_high) = RELOC(ram_top);
+
+       if (RELOC(prom_memory_limit)) {
+               if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
+                       prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
+                               RELOC(prom_memory_limit));
+                       RELOC(prom_memory_limit) = 0;
+               } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
+                       prom_printf("Ignoring mem=%x >= ram_top.\n",
+                               RELOC(prom_memory_limit));
+                       RELOC(prom_memory_limit) = 0;
+               } else {
+                       RELOC(ram_top) = RELOC(prom_memory_limit);
+                       RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
+               }
+       }
+
+       /*
+        * Setup our top alloc point, that is top of RMO or top of
+        * segment 0 when running non-LPAR.
+        * Some RS64 machines have buggy firmware where claims up at
+        * 1GB fail.  Cap at 768MB as a workaround.
+        * Since 768MB is plenty of room, and we need to cap to something
+        * reasonable on 32-bit, cap at 768MB on all machines.
+        */
+       if (!RELOC(rmo_top))
+               RELOC(rmo_top) = RELOC(ram_top);
+       RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top));
+       RELOC(alloc_top) = RELOC(rmo_top);
+
+       prom_printf("memory layout at init:\n");
+       prom_printf("  memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
+       prom_printf("  alloc_bottom : %x\n", RELOC(alloc_bottom));
+       prom_printf("  alloc_top    : %x\n", RELOC(alloc_top));
+       prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
+       prom_printf("  rmo_top      : %x\n", RELOC(rmo_top));
+       prom_printf("  ram_top      : %x\n", RELOC(ram_top));
+}
+
+
+/*
+ * Allocate room for and instantiate RTAS
+ */
+static void __init prom_instantiate_rtas(void)
+{
+       phandle rtas_node;
+       ihandle rtas_inst;
+       u32 base, entry = 0;
+       u32 size = 0;
+
+       prom_debug("prom_instantiate_rtas: start...\n");
+
+       rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
+       prom_debug("rtas_node: %x\n", rtas_node);
+       if (!PHANDLE_VALID(rtas_node))
+               return;
+
+       prom_getprop(rtas_node, "rtas-size", &size, sizeof(size));
+       if (size == 0)
+               return;
+
+       base = alloc_down(size, PAGE_SIZE, 0);
+       if (base == 0) {
+               prom_printf("RTAS allocation failed !\n");
+               return;
+       }
+
+       rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
+       if (!IHANDLE_VALID(rtas_inst)) {
+               prom_printf("opening rtas package failed");
+               return;
+       }
+
+       prom_printf("instantiating rtas at 0x%x ...", base);
+
+       if (call_prom_ret("call-method", 3, 2, &entry,
+                         ADDR("instantiate-rtas"),
+                         rtas_inst, base) == PROM_ERROR
+           || entry == 0) {
+               prom_printf(" failed\n");
+               return;
+       }
+       prom_printf(" done\n");
+
+       reserve_mem(base, size);
+
+       prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base));
+       prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry));
+
+       prom_debug("rtas base     = 0x%x\n", base);
+       prom_debug("rtas entry    = 0x%x\n", entry);
+       prom_debug("rtas size     = 0x%x\n", (long)size);
+
+       prom_debug("prom_instantiate_rtas: end...\n");
+}
+
+#ifdef CONFIG_PPC64
+/*
+ * Allocate room for and initialize TCE tables
+ */
+static void __init prom_initialize_tce_table(void)
+{
+       phandle node;
+       ihandle phb_node;
+       char compatible[64], type[64], model[64];
+       char *path = RELOC(prom_scratch);
+       u64 base, align;
+       u32 minalign, minsize;
+       u64 tce_entry, *tce_entryp;
+       u64 local_alloc_top, local_alloc_bottom;
+       u64 i;
+
+       if (RELOC(ppc64_iommu_off))
+               return;
+
+       prom_debug("starting prom_initialize_tce_table\n");
+
+       /* Cache current top of allocs so we reserve a single block */
+       local_alloc_top = RELOC(alloc_top_high);
+       local_alloc_bottom = local_alloc_top;
+
+       /* Search all nodes looking for PHBs. */
+       for (node = 0; prom_next_node(&node); ) {
+               compatible[0] = 0;
+               type[0] = 0;
+               model[0] = 0;
+               prom_getprop(node, "compatible",
+                            compatible, sizeof(compatible));
+               prom_getprop(node, "device_type", type, sizeof(type));
+               prom_getprop(node, "model", model, sizeof(model));
+
+               if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL))
+                       continue;
+
+               /* Keep the old logic in tack to avoid regression. */
+               if (compatible[0] != 0) {
+                       if ((strstr(compatible, RELOC("python")) == NULL) &&
+                           (strstr(compatible, RELOC("Speedwagon")) == NULL) &&
+                           (strstr(compatible, RELOC("Winnipeg")) == NULL))
+                               continue;
+               } else if (model[0] != 0) {
+                       if ((strstr(model, RELOC("ython")) == NULL) &&
+                           (strstr(model, RELOC("peedwagon")) == NULL) &&
+                           (strstr(model, RELOC("innipeg")) == NULL))
+                               continue;
+               }
+
+               if (prom_getprop(node, "tce-table-minalign", &minalign,
+                                sizeof(minalign)) == PROM_ERROR)
+                       minalign = 0;
+               if (prom_getprop(node, "tce-table-minsize", &minsize,
+                                sizeof(minsize)) == PROM_ERROR)
+                       minsize = 4UL << 20;
+
+               /*
+                * Even though we read what OF wants, we just set the table
+                * size to 4 MB.  This is enough to map 2GB of PCI DMA space.
+                * By doing this, we avoid the pitfalls of trying to DMA to
+                * MMIO space and the DMA alias hole.
+                *
+                * On POWER4, firmware sets the TCE region by assuming
+                * each TCE table is 8MB. Using this memory for anything
+                * else will impact performance, so we always allocate 8MB.
+                * Anton
+                */
+               if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
+                       minsize = 8UL << 20;
+               else
+                       minsize = 4UL << 20;
+
+               /* Align to the greater of the align or size */
+               align = max(minalign, minsize);
+               base = alloc_down(minsize, align, 1);
+               if (base == 0)
+                       prom_panic("ERROR, cannot find space for TCE table.\n");
+               if (base < local_alloc_bottom)
+                       local_alloc_bottom = base;
+
+               /* Save away the TCE table attributes for later use. */
+               prom_setprop(node, "linux,tce-base", &base, sizeof(base));
+               prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize));
+
+               /* It seems OF doesn't null-terminate the path :-( */
+               memset(path, 0, sizeof(path));
+               /* Call OF to setup the TCE hardware */
+               if (call_prom("package-to-path", 3, 1, node,
+                             path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) {
+                       prom_printf("package-to-path failed\n");
+               }
+
+               prom_debug("TCE table: %s\n", path);
+               prom_debug("\tnode = 0x%x\n", node);
+               prom_debug("\tbase = 0x%x\n", base);
+               prom_debug("\tsize = 0x%x\n", minsize);
+
+               /* Initialize the table to have a one-to-one mapping
+                * over the allocated size.
+                */
+               tce_entryp = (unsigned long *)base;
+               for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
+                       tce_entry = (i << PAGE_SHIFT);
+                       tce_entry |= 0x3;
+                       *tce_entryp = tce_entry;
+               }
+
+               prom_printf("opening PHB %s", path);
+               phb_node = call_prom("open", 1, 1, path);
+               if (phb_node == 0)
+                       prom_printf("... failed\n");
+               else
+                       prom_printf("... done\n");
+
+               call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"),
+                         phb_node, -1, minsize,
+                         (u32) base, (u32) (base >> 32));
+               call_prom("close", 1, 0, phb_node);
+       }
+
+       reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
+
+       if (RELOC(prom_memory_limit)) {
+               /*
+                * We align the start to a 16MB boundary so we can map
+                * the TCE area using large pages if possible.
+                * The end should be the top of RAM so no need to align it.
+                */
+               RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom,
+                                                         0x1000000);
+               RELOC(prom_tce_alloc_end) = local_alloc_top;
+       }
+
+       /* Flag the first invalid entry */
+       prom_debug("ending prom_initialize_tce_table\n");
+}
+#endif
+
+/*
+ * With CHRP SMP we need to use the OF to start the other processors.
+ * We can't wait until smp_boot_cpus (the OF is trashed by then)
+ * so we have to put the processors into a holding pattern controlled
+ * by the kernel (not OF) before we destroy the OF.
+ *
+ * This uses a chunk of low memory, puts some holding pattern
+ * code there and sends the other processors off to there until
+ * smp_boot_cpus tells them to do something.  The holding pattern
+ * checks that address until its cpu # is there, when it is that
+ * cpu jumps to __secondary_start().  smp_boot_cpus() takes care
+ * of setting those values.
+ *
+ * We also use physical address 0x4 here to tell when a cpu
+ * is in its holding pattern code.
+ *
+ * -- Cort
+ */
+static void __init prom_hold_cpus(void)
+{
+#ifdef CONFIG_PPC64
+       unsigned long i;
+       unsigned int reg;
+       phandle node;
+       char type[64];
+       int cpuid = 0;
+       unsigned int interrupt_server[MAX_CPU_THREADS];
+       unsigned int cpu_threads, hw_cpu_num;
+       int propsize;
+       extern void __secondary_hold(void);
+       extern unsigned long __secondary_hold_spinloop;
+       extern unsigned long __secondary_hold_acknowledge;
+       unsigned long *spinloop
+               = (void *) __pa(&__secondary_hold_spinloop);
+       unsigned long *acknowledge
+               = (void *) __pa(&__secondary_hold_acknowledge);
+#ifdef CONFIG_PPC64
+       unsigned long secondary_hold
+               = __pa(*PTRRELOC((unsigned long *)__secondary_hold));
+#else
+       unsigned long secondary_hold = __pa(&__secondary_hold);
+#endif
+       struct prom_t *_prom = &RELOC(prom);
+
+       prom_debug("prom_hold_cpus: start...\n");
+       prom_debug("    1) spinloop       = 0x%x\n", (unsigned long)spinloop);
+       prom_debug("    1) *spinloop      = 0x%x\n", *spinloop);
+       prom_debug("    1) acknowledge    = 0x%x\n",
+                  (unsigned long)acknowledge);
+       prom_debug("    1) *acknowledge   = 0x%x\n", *acknowledge);
+       prom_debug("    1) secondary_hold = 0x%x\n", secondary_hold);
+
+       /* Set the common spinloop variable, so all of the secondary cpus
+        * will block when they are awakened from their OF spinloop.
+        * This must occur for both SMP and non SMP kernels, since OF will
+        * be trashed when we move the kernel.
+        */
+       *spinloop = 0;
+
+#ifdef CONFIG_HMT
+       for (i = 0; i < NR_CPUS; i++) {
+               RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
+       }
+#endif
+       /* look for cpus */
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               prom_getprop(node, "device_type", type, sizeof(type));
+               if (strcmp(type, RELOC("cpu")) != 0)
+                       continue;
+
+               /* Skip non-configured cpus. */
+               if (prom_getprop(node, "status", type, sizeof(type)) > 0)
+                       if (strcmp(type, RELOC("okay")) != 0)
+                               continue;
+
+               reg = -1;
+               prom_getprop(node, "reg", &reg, sizeof(reg));
+
+               prom_debug("\ncpuid        = 0x%x\n", cpuid);
+               prom_debug("cpu hw idx   = 0x%x\n", reg);
+
+               /* Init the acknowledge var which will be reset by
+                * the secondary cpu when it awakens from its OF
+                * spinloop.
+                */
+               *acknowledge = (unsigned long)-1;
+
+               propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s",
+                                       &interrupt_server,
+                                       sizeof(interrupt_server));
+               if (propsize < 0) {
+                       /* no property.  old hardware has no SMT */
+                       cpu_threads = 1;
+                       interrupt_server[0] = reg; /* fake it with phys id */
+               } else {
+                       /* We have a threaded processor */
+                       cpu_threads = propsize / sizeof(u32);
+                       if (cpu_threads > MAX_CPU_THREADS) {
+                               prom_printf("SMT: too many threads!\n"
+                                           "SMT: found %x, max is %x\n",
+                                           cpu_threads, MAX_CPU_THREADS);
+                               cpu_threads = 1; /* ToDo: panic? */
+                       }
+               }
+
+               hw_cpu_num = interrupt_server[0];
+               if (hw_cpu_num != _prom->cpu) {
+                       /* Primary Thread of non-boot cpu */
+                       prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg);
+                       call_prom("start-cpu", 3, 0, node,
+                                 secondary_hold, reg);
+
+                       for ( i = 0 ; (i < 100000000) && 
+                             (*acknowledge == ((unsigned long)-1)); i++ )
+                               mb();
+
+                       if (*acknowledge == reg) {
+                               prom_printf("done\n");
+                               /* We have to get every CPU out of OF,
+                                * even if we never start it. */
+                               if (cpuid >= NR_CPUS)
+                                       goto next;
+                       } else {
+                               prom_printf("failed: %x\n", *acknowledge);
+                       }
+               }
+#ifdef CONFIG_SMP
+               else
+                       prom_printf("%x : boot cpu     %x\n", cpuid, reg);
+#endif
+next:
+#ifdef CONFIG_SMP
+               /* Init paca for secondary threads.   They start later. */
+               for (i=1; i < cpu_threads; i++) {
+                       cpuid++;
+                       if (cpuid >= NR_CPUS)
+                               continue;
+               }
+#endif /* CONFIG_SMP */
+               cpuid++;
+       }
+#ifdef CONFIG_HMT
+       /* Only enable HMT on processors that provide support. */
+       if (__is_processor(PV_PULSAR) || 
+           __is_processor(PV_ICESTAR) ||
+           __is_processor(PV_SSTAR)) {
+               prom_printf("    starting secondary threads\n");
+
+               for (i = 0; i < NR_CPUS; i += 2) {
+                       if (!cpu_online(i))
+                               continue;
+
+                       if (i == 0) {
+                               unsigned long pir = mfspr(SPRN_PIR);
+                               if (__is_processor(PV_PULSAR)) {
+                                       RELOC(hmt_thread_data)[i].pir = 
+                                               pir & 0x1f;
+                               } else {
+                                       RELOC(hmt_thread_data)[i].pir = 
+                                               pir & 0x3ff;
+                               }
+                       }
+               }
+       } else {
+               prom_printf("Processor is not HMT capable\n");
+       }
+#endif
+
+       if (cpuid > NR_CPUS)
+               prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS)
+                           ") exceeded: ignoring extras\n");
+
+       prom_debug("prom_hold_cpus: end...\n");
+#endif
+}
+
+
+static void __init prom_init_client_services(unsigned long pp)
+{
+       struct prom_t *_prom = &RELOC(prom);
+
+       /* Get a handle to the prom entry point before anything else */
+       RELOC(prom_entry) = pp;
+
+       /* get a handle for the stdout device */
+       _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
+       if (!PHANDLE_VALID(_prom->chosen))
+               prom_panic("cannot find chosen"); /* msg won't be printed :( */
+
+       /* get device tree root */
+       _prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
+       if (!PHANDLE_VALID(_prom->root))
+               prom_panic("cannot find device tree root"); /* msg won't be printed :( */
+}
+
+static void __init prom_init_stdout(void)
+{
+       struct prom_t *_prom = &RELOC(prom);
+       char *path = RELOC(of_stdout_device);
+       char type[16];
+       u32 val;
+
+       if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0)
+               prom_panic("cannot find stdout");
+
+       _prom->stdout = val;
+
+       /* Get the full OF pathname of the stdout device */
+       memset(path, 0, 256);
+       call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255);
+       val = call_prom("instance-to-package", 1, 1, _prom->stdout);
+       prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val));
+       prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device));
+       prom_setprop(_prom->chosen, "linux,stdout-path",
+                    RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1);
+
+       /* If it's a display, note it */
+       memset(type, 0, sizeof(type));
+       prom_getprop(val, "device_type", type, sizeof(type));
+       if (strcmp(type, RELOC("display")) == 0)
+               prom_setprop(val, "linux,boot-display", NULL, 0);
+}
+
+static void __init prom_close_stdin(void)
+{
+       struct prom_t *_prom = &RELOC(prom);
+       ihandle val;
+
+       if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0)
+               call_prom("close", 1, 0, val);
+}
+
+static int __init prom_find_machine_type(void)
+{
+       struct prom_t *_prom = &RELOC(prom);
+       char compat[256];
+       int len, i = 0;
+       phandle rtas;
+
+       len = prom_getprop(_prom->root, "compatible",
+                          compat, sizeof(compat)-1);
+       if (len > 0) {
+               compat[len] = 0;
+               while (i < len) {
+                       char *p = &compat[i];
+                       int sl = strlen(p);
+                       if (sl == 0)
+                               break;
+                       if (strstr(p, RELOC("Power Macintosh")) ||
+                           strstr(p, RELOC("MacRISC4")))
+                               return PLATFORM_POWERMAC;
+#ifdef CONFIG_PPC64
+                       if (strstr(p, RELOC("Momentum,Maple")))
+                               return PLATFORM_MAPLE;
+#endif
+                       i += sl + 1;
+               }
+       }
+#ifdef CONFIG_PPC64
+       /* Default to pSeries. We need to know if we are running LPAR */
+       rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
+       if (PHANDLE_VALID(rtas)) {
+               int x = prom_getproplen(rtas, "ibm,hypertas-functions");
+               if (x != PROM_ERROR) {
+                       prom_printf("Hypertas detected, assuming LPAR !\n");
+                       return PLATFORM_PSERIES_LPAR;
+               }
+       }
+       return PLATFORM_PSERIES;
+#else
+       return PLATFORM_CHRP;
+#endif
+}
+
+static int __init setup_disp(phandle dp)
+{
+#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
+       int width = 640, height = 480, depth = 8, pitch;
+       unsigned address;
+       u32 addrs[8][5];
+       int i, naddrs;
+       char name[32];
+       char *getprop = "getprop";
+
+       prom_printf("Initializing screen: ");
+
+       memset(name, 0, sizeof(name));
+       call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
+       name[sizeof(name)-1] = 0;
+       prom_print(name);
+       prom_print("\n");
+       call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
+       call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
+       call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
+       pitch = width * ((depth + 7) / 8);
+       call_prom(getprop, 4, 1, dp, "linebytes",
+                 &pitch, sizeof(pitch));
+       if (pitch == 1)
+               pitch = 0x1000;         /* for strange IBM display */
+       address = 0;
+       call_prom(getprop, 4, 1, dp, "address", &address, sizeof(address));
+       if (address == 0) {
+               /* look for an assigned address with a size of >= 1MB */
+               naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses",
+                                  addrs, sizeof(addrs));
+               naddrs /= 20;
+               for (i = 0; i < naddrs; ++i) {
+                       if (addrs[i][4] >= (1 << 20)) {
+                               address = addrs[i][2];
+                               /* use the BE aperture if possible */
+                               if (addrs[i][4] >= (16 << 20))
+                                       address += (8 << 20);
+                               break;
+                       }
+               }
+               if (address == 0) {
+                       prom_print("Failed to get address\n");
+                       return 0;
+               }
+       }
+       /* kludge for valkyrie */
+       if (strcmp(name, "valkyrie") == 0)
+               address += 0x1000;
+
+       prom_printf("\n\n\n\naddress = %x\n", address);
+       btext_setup_display(width, height, depth, pitch, address);
+#endif /* CONFIG_BOOTX_TEXT && CONFIG_PPC32 */
+       return 1;
+}
+
+static int __init prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+       return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r);
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later.  However, OF will probably fall over if we do that
+ * we've taken over the MMU.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static void __init prom_check_displays(void)
+{
+       char type[16], *path;
+       phandle node;
+       ihandle ih;
+       int i;
+       int got_display = 0;
+
+       static unsigned char default_colors[] = {
+               0x00, 0x00, 0x00,
+               0x00, 0x00, 0xaa,
+               0x00, 0xaa, 0x00,
+               0x00, 0xaa, 0xaa,
+               0xaa, 0x00, 0x00,
+               0xaa, 0x00, 0xaa,
+               0xaa, 0xaa, 0x00,
+               0xaa, 0xaa, 0xaa,
+               0x55, 0x55, 0x55,
+               0x55, 0x55, 0xff,
+               0x55, 0xff, 0x55,
+               0x55, 0xff, 0xff,
+               0xff, 0x55, 0x55,
+               0xff, 0x55, 0xff,
+               0xff, 0xff, 0x55,
+               0xff, 0xff, 0xff
+       };
+       const unsigned char *clut;
+
+       prom_printf("Looking for displays\n");
+       for (node = 0; prom_next_node(&node); ) {
+               memset(type, 0, sizeof(type));
+               prom_getprop(node, "device_type", type, sizeof(type));
+               if (strcmp(type, RELOC("display")) != 0)
+                       continue;
+
+               /* It seems OF doesn't null-terminate the path :-( */
+               path = RELOC(prom_scratch);
+               memset(path, 0, PROM_SCRATCH_SIZE);
+
+               /*
+                * leave some room at the end of the path for appending extra
+                * arguments
+                */
+               if (call_prom("package-to-path", 3, 1, node, path,
+                             PROM_SCRATCH_SIZE-10) == PROM_ERROR)
+                       continue;
+               prom_printf("found display   : %s, opening ... ", path);
+               
+               ih = call_prom("open", 1, 1, path);
+               if (ih == 0) {
+                       prom_printf("failed\n");
+                       continue;
+               }
+
+               /* Success */
+               prom_printf("done\n");
+               prom_setprop(node, "linux,opened", NULL, 0);
+
+               /* Setup a usable color table when the appropriate
+                * method is available. Should update this to set-colors */
+               clut = RELOC(default_colors);
+               for (i = 0; i < 32; i++, clut += 3)
+                       if (prom_set_color(ih, i, clut[0], clut[1],
+                                          clut[2]) != 0)
+                               break;
+
+#ifdef CONFIG_LOGO_LINUX_CLUT224
+               clut = PTRRELOC(RELOC(logo_linux_clut224.clut));
+               for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3)
+                       if (prom_set_color(ih, i + 32, clut[0], clut[1],
+                                          clut[2]) != 0)
+                               break;
+#endif /* CONFIG_LOGO_LINUX_CLUT224 */
+               if (!got_display)
+                       got_display = setup_disp(node);
+       }
+}
+
+
+/* Return (relocated) pointer to this much memory: moves initrd if reqd. */
+static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
+                             unsigned long needed, unsigned long align)
+{
+       void *ret;
+
+       *mem_start = _ALIGN(*mem_start, align);
+       while ((*mem_start + needed) > *mem_end) {
+               unsigned long room, chunk;
+
+               prom_debug("Chunk exhausted, claiming more at %x...\n",
+                          RELOC(alloc_bottom));
+               room = RELOC(alloc_top) - RELOC(alloc_bottom);
+               if (room > DEVTREE_CHUNK_SIZE)
+                       room = DEVTREE_CHUNK_SIZE;
+               if (room < PAGE_SIZE)
+                       prom_panic("No memory for flatten_device_tree (no room)");
+               chunk = alloc_up(room, 0);
+               if (chunk == 0)
+                       prom_panic("No memory for flatten_device_tree (claim failed)");
+               *mem_end = RELOC(alloc_top);
+       }
+
+       ret = (void *)*mem_start;
+       *mem_start += needed;
+
+       return ret;
+}
+
+#define dt_push_token(token, mem_start, mem_end) \
+       do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0)
+
+static unsigned long __init dt_find_string(char *str)
+{
+       char *s, *os;
+
+       s = os = (char *)RELOC(dt_string_start);
+       s += 4;
+       while (s <  (char *)RELOC(dt_string_end)) {
+               if (strcmp(s, str) == 0)
+                       return s - os;
+               s += strlen(s) + 1;
+       }
+       return 0;
+}
+
+/*
+ * The Open Firmware 1275 specification states properties must be 31 bytes or
+ * less, however not all firmwares obey this. Make it 64 bytes to be safe.
+ */
+#define MAX_PROPERTY_NAME 64
+
+static void __init scan_dt_build_strings(phandle node,
+                                        unsigned long *mem_start,
+                                        unsigned long *mem_end)
+{
+       char *prev_name, *namep, *sstart;
+       unsigned long soff;
+       phandle child;
+
+       sstart =  (char *)RELOC(dt_string_start);
+
+       /* get and store all property names */
+       prev_name = RELOC("");
+       for (;;) {
+               /* 64 is max len of name including nul. */
+               namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
+               if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {
+                       /* No more nodes: unwind alloc */
+                       *mem_start = (unsigned long)namep;
+                       break;
+               }
+
+               /* skip "name" */
+               if (strcmp(namep, RELOC("name")) == 0) {
+                       *mem_start = (unsigned long)namep;
+                       prev_name = RELOC("name");
+                       continue;
+               }
+               /* get/create string entry */
+               soff = dt_find_string(namep);
+               if (soff != 0) {
+                       *mem_start = (unsigned long)namep;
+                       namep = sstart + soff;
+               } else {
+                       /* Trim off some if we can */
+                       *mem_start = (unsigned long)namep + strlen(namep) + 1;
+                       RELOC(dt_string_end) = *mem_start;
+               }
+               prev_name = namep;
+       }
+
+       /* do all our children */
+       child = call_prom("child", 1, 1, node);
+       while (child != 0) {
+               scan_dt_build_strings(child, mem_start, mem_end);
+               child = call_prom("peer", 1, 1, child);
+       }
+}
+
+static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
+                                       unsigned long *mem_end)
+{
+       phandle child;
+       char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
+       unsigned long soff;
+       unsigned char *valp;
+       static char pname[MAX_PROPERTY_NAME];
+       int l;
+
+       dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
+
+       /* get the node's full name */
+       namep = (char *)*mem_start;
+       l = call_prom("package-to-path", 3, 1, node,
+                     namep, *mem_end - *mem_start);
+       if (l >= 0) {
+               /* Didn't fit?  Get more room. */
+               if ((l+1) > (*mem_end - *mem_start)) {
+                       namep = make_room(mem_start, mem_end, l+1, 1);
+                       call_prom("package-to-path", 3, 1, node, namep, l);
+               }
+               namep[l] = '\0';
+
+               /* Fixup an Apple bug where they have bogus \0 chars in the
+                * middle of the path in some properties
+                */
+               for (p = namep, ep = namep + l; p < ep; p++)
+                       if (*p == '\0') {
+                               memmove(p, p+1, ep - p);
+                               ep--; l--; p--;
+                       }
+
+               /* now try to extract the unit name in that mess */
+               for (p = namep, lp = NULL; *p; p++)
+                       if (*p == '/')
+                               lp = p + 1;
+               if (lp != NULL)
+                       memmove(namep, lp, strlen(lp) + 1);
+               *mem_start = _ALIGN(((unsigned long) namep) +
+                                   strlen(namep) + 1, 4);
+       }
+
+       /* get it again for debugging */
+       path = RELOC(prom_scratch);
+       memset(path, 0, PROM_SCRATCH_SIZE);
+       call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
+
+       /* get and store all properties */
+       prev_name = RELOC("");
+       sstart = (char *)RELOC(dt_string_start);
+       for (;;) {
+               if (call_prom("nextprop", 3, 1, node, prev_name,
+                             RELOC(pname)) != 1)
+                       break;
+
+               /* skip "name" */
+               if (strcmp(RELOC(pname), RELOC("name")) == 0) {
+                       prev_name = RELOC("name");
+                       continue;
+               }
+
+               /* find string offset */
+               soff = dt_find_string(RELOC(pname));
+               if (soff == 0) {
+                       prom_printf("WARNING: Can't find string index for"
+                                   " <%s>, node %s\n", RELOC(pname), path);
+                       break;
+               }
+               prev_name = sstart + soff;
+
+               /* get length */
+               l = call_prom("getproplen", 2, 1, node, RELOC(pname));
+
+               /* sanity checks */
+               if (l == PROM_ERROR)
+                       continue;
+               if (l > MAX_PROPERTY_LENGTH) {
+                       prom_printf("WARNING: ignoring large property ");
+                       /* It seems OF doesn't null-terminate the path :-( */
+                       prom_printf("[%s] ", path);
+                       prom_printf("%s length 0x%x\n", RELOC(pname), l);
+                       continue;
+               }
+
+               /* push property head */
+               dt_push_token(OF_DT_PROP, mem_start, mem_end);
+               dt_push_token(l, mem_start, mem_end);
+               dt_push_token(soff, mem_start, mem_end);
+
+               /* push property content */
+               valp = make_room(mem_start, mem_end, l, 4);
+               call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
+               *mem_start = _ALIGN(*mem_start, 4);
+       }
+
+       /* Add a "linux,phandle" property. */
+       soff = dt_find_string(RELOC("linux,phandle"));
+       if (soff == 0)
+               prom_printf("WARNING: Can't find string index for"
+                           " <linux-phandle> node %s\n", path);
+       else {
+               dt_push_token(OF_DT_PROP, mem_start, mem_end);
+               dt_push_token(4, mem_start, mem_end);
+               dt_push_token(soff, mem_start, mem_end);
+               valp = make_room(mem_start, mem_end, 4, 4);
+               *(u32 *)valp = node;
+       }
+
+       /* do all our children */
+       child = call_prom("child", 1, 1, node);
+       while (child != 0) {
+               scan_dt_build_struct(child, mem_start, mem_end);
+               child = call_prom("peer", 1, 1, child);
+       }
+
+       dt_push_token(OF_DT_END_NODE, mem_start, mem_end);
+}
+
+static void __init flatten_device_tree(void)
+{
+       phandle root;
+       unsigned long mem_start, mem_end, room;
+       struct boot_param_header *hdr;
+       struct prom_t *_prom = &RELOC(prom);
+       char *namep;
+       u64 *rsvmap;
+
+       /*
+        * Check how much room we have between alloc top & bottom (+/- a
+        * few pages), crop to 4Mb, as this is our "chuck" size
+        */
+       room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000;
+       if (room > DEVTREE_CHUNK_SIZE)
+               room = DEVTREE_CHUNK_SIZE;
+       prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom));
+
+       /* Now try to claim that */
+       mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
+       if (mem_start == 0)
+               prom_panic("Can't allocate initial device-tree chunk\n");
+       mem_end = RELOC(alloc_top);
+
+       /* Get root of tree */
+       root = call_prom("peer", 1, 1, (phandle)0);
+       if (root == (phandle)0)
+               prom_panic ("couldn't get device tree root\n");
+
+       /* Build header and make room for mem rsv map */ 
+       mem_start = _ALIGN(mem_start, 4);
+       hdr = make_room(&mem_start, &mem_end,
+                       sizeof(struct boot_param_header), 4);
+       RELOC(dt_header_start) = (unsigned long)hdr;
+       rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
+
+       /* Start of strings */
+       mem_start = PAGE_ALIGN(mem_start);
+       RELOC(dt_string_start) = mem_start;
+       mem_start += 4; /* hole */
+
+       /* Add "linux,phandle" in there, we'll need it */
+       namep = make_room(&mem_start, &mem_end, 16, 1);
+       strcpy(namep, RELOC("linux,phandle"));
+       mem_start = (unsigned long)namep + strlen(namep) + 1;
+
+       /* Build string array */
+       prom_printf("Building dt strings...\n"); 
+       scan_dt_build_strings(root, &mem_start, &mem_end);
+       RELOC(dt_string_end) = mem_start;
+
+       /* Build structure */
+       mem_start = PAGE_ALIGN(mem_start);
+       RELOC(dt_struct_start) = mem_start;
+       prom_printf("Building dt structure...\n"); 
+       scan_dt_build_struct(root, &mem_start, &mem_end);
+       dt_push_token(OF_DT_END, &mem_start, &mem_end);
+       RELOC(dt_struct_end) = PAGE_ALIGN(mem_start);
+
+       /* Finish header */
+       hdr->boot_cpuid_phys = _prom->cpu;
+       hdr->magic = OF_DT_HEADER;
+       hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
+       hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
+       hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
+       hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
+       hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
+       hdr->version = OF_DT_VERSION;
+       /* Version 16 is not backward compatible */
+       hdr->last_comp_version = 0x10;
+
+       /* Reserve the whole thing and copy the reserve map in, we
+        * also bump mem_reserve_cnt to cause further reservations to
+        * fail since it's too late.
+        */
+       reserve_mem(RELOC(dt_header_start), hdr->totalsize);
+       memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));
+
+#ifdef DEBUG_PROM
+       {
+               int i;
+               prom_printf("reserved memory map:\n");
+               for (i = 0; i < RELOC(mem_reserve_cnt); i++)
+                       prom_printf("  %x - %x\n",
+                                   RELOC(mem_reserve_map)[i].base,
+                                   RELOC(mem_reserve_map)[i].size);
+       }
+#endif
+       RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE;
+
+       prom_printf("Device tree strings 0x%x -> 0x%x\n",
+                   RELOC(dt_string_start), RELOC(dt_string_end)); 
+       prom_printf("Device tree struct  0x%x -> 0x%x\n",
+                   RELOC(dt_struct_start), RELOC(dt_struct_end));
+
+}
+
+
+static void __init fixup_device_tree(void)
+{
+#if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)
+       phandle u3, i2c, mpic;
+       u32 u3_rev;
+       u32 interrupts[2];
+       u32 parent;
+
+       /* Some G5s have a missing interrupt definition, fix it up here */
+       u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000"));
+       if (!PHANDLE_VALID(u3))
+               return;
+       i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000"));
+       if (!PHANDLE_VALID(i2c))
+               return;
+       mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000"));
+       if (!PHANDLE_VALID(mpic))
+               return;
+
+       /* check if proper rev of u3 */
+       if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
+           == PROM_ERROR)
+               return;
+       if (u3_rev != 0x35 && u3_rev != 0x37)
+               return;
+       /* does it need fixup ? */
+       if (prom_getproplen(i2c, "interrupts") > 0)
+               return;
+
+       prom_printf("fixing up bogus interrupts for u3 i2c...\n");
+
+       /* interrupt on this revision of u3 is number 0 and level */
+       interrupts[0] = 0;
+       interrupts[1] = 1;
+       prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts));
+       parent = (u32)mpic;
+       prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent));
+#endif
+}
+
+
+static void __init prom_find_boot_cpu(void)
+{
+               struct prom_t *_prom = &RELOC(prom);
+       u32 getprop_rval;
+       ihandle prom_cpu;
+       phandle cpu_pkg;
+
+       if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
+               prom_panic("cannot find boot cpu");
+
+       cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
+
+       prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval));
+       _prom->cpu = getprop_rval;
+
+       prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu);
+}
+
+static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+               struct prom_t *_prom = &RELOC(prom);
+
+       if (r3 && r4 && r4 != 0xdeadbeef) {
+               unsigned long val;
+
+               RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
+               RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
+
+               val = RELOC(prom_initrd_start);
+               prom_setprop(_prom->chosen, "linux,initrd-start", &val,
+                            sizeof(val));
+               val = RELOC(prom_initrd_end);
+               prom_setprop(_prom->chosen, "linux,initrd-end", &val,
+                            sizeof(val));
+
+               reserve_mem(RELOC(prom_initrd_start),
+                           RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
+
+               prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start));
+               prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end));
+       }
+#endif /* CONFIG_BLK_DEV_INITRD */
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+
+unsigned long __init prom_init(unsigned long r3, unsigned long r4,
+                              unsigned long pp,
+                              unsigned long r6, unsigned long r7)
+{      
+               struct prom_t *_prom;
+       extern char _stext[];
+       unsigned long hdr;
+       u32 getprop_rval;
+
+#ifdef CONFIG_PPC32
+       unsigned long offset = reloc_offset();
+       reloc_got2(offset);
+#endif
+
+       _prom = &RELOC(prom);
+
+       /*
+        * First zero the BSS
+        */
+       memset(&RELOC(__bss_start), 0, __bss_stop - __bss_start);
+
+       /*
+        * Init interface to Open Firmware, get some node references,
+        * like /chosen
+        */
+       prom_init_client_services(pp);
+
+       /*
+        * Init prom stdout device
+        */
+       prom_init_stdout();
+
+       /*
+        * Check for an initrd
+        */
+       prom_check_initrd(r3, r4);
+
+       /*
+        * Get default machine type. At this point, we do not differentiate
+        * between pSeries SMP and pSeries LPAR
+        */
+       RELOC(of_platform) = prom_find_machine_type();
+       getprop_rval = RELOC(of_platform);
+       prom_setprop(_prom->chosen, "linux,platform",
+                    &getprop_rval, sizeof(getprop_rval));
+
+#ifdef CONFIG_PPC_PSERIES
+       /*
+        * On pSeries, inform the firmware about our capabilities
+        */
+       if (RELOC(of_platform) & PLATFORM_PSERIES)
+               prom_send_capabilities();
+#endif
+
+#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_BPA)
+       /*
+        * On pSeries and BPA, copy the CPU hold code
+        */
+               if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA))
+                       copy_and_flush(0, KERNELBASE - offset, 0x100, 0);
+#endif
+
+       /*
+        * Do early parsing of command line
+        */
+       early_cmdline_parse();
+
+       /*
+        * Initialize memory management within prom_init
+        */
+       prom_init_mem();
+
+       /*
+        * Determine which cpu is actually running right _now_
+        */
+       prom_find_boot_cpu();
+
+       /* 
+        * Initialize display devices
+        */
+       prom_check_displays();
+
+#ifdef CONFIG_PPC64
+       /*
+        * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else
+        * that uses the allocator, we need to make sure we get the top of memory
+        * available for us here...
+        */
+       if (RELOC(of_platform) == PLATFORM_PSERIES)
+               prom_initialize_tce_table();
+#endif
+
+       /*
+        * On non-powermacs, try to instantiate RTAS and puts all CPUs
+        * in spin-loops. PowerMacs don't have a working RTAS and use
+        * a different way to spin CPUs
+        */
+       if (RELOC(of_platform) != PLATFORM_POWERMAC) {
+               prom_instantiate_rtas();
+               prom_hold_cpus();
+       }
+
+       /*
+        * Fill in some infos for use by the kernel later on
+        */
+       if (RELOC(prom_memory_limit))
+               prom_setprop(_prom->chosen, "linux,memory-limit",
+                            &RELOC(prom_memory_limit),
+                            sizeof(prom_memory_limit));
+#ifdef CONFIG_PPC64
+       if (RELOC(ppc64_iommu_off))
+               prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0);
+
+       if (RELOC(iommu_force_on))
+               prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0);
+
+       if (RELOC(prom_tce_alloc_start)) {
+               prom_setprop(_prom->chosen, "linux,tce-alloc-start",
+                            &RELOC(prom_tce_alloc_start),
+                            sizeof(prom_tce_alloc_start));
+               prom_setprop(_prom->chosen, "linux,tce-alloc-end",
+                            &RELOC(prom_tce_alloc_end),
+                            sizeof(prom_tce_alloc_end));
+       }
+#endif
+
+       /*
+        * Fixup any known bugs in the device-tree
+        */
+       fixup_device_tree();
+
+       /*
+        * Now finally create the flattened device-tree
+        */
+       prom_printf("copying OF device tree ...\n");
+       flatten_device_tree();
+
+       /* in case stdin is USB and still active on IBM machines... */
+       prom_close_stdin();
+
+       /*
+        * Call OF "quiesce" method to shut down pending DMA's from
+        * devices etc...
+        */
+       prom_printf("Calling quiesce ...\n");
+       call_prom("quiesce", 0, 0);
+
+       /*
+        * And finally, call the kernel passing it the flattened device
+        * tree and NULL as r5, thus triggering the new entry point which
+        * is common to us and kexec
+        */
+       hdr = RELOC(dt_header_start);
+       prom_printf("returning from prom_init\n");
+       prom_debug("->dt_header_start=0x%x\n", hdr);
+
+#ifdef CONFIG_PPC32
+       reloc_got2(-offset);
+#endif
+
+       __start(hdr, 0, 0);
+
+       return 0;
+}
diff --git a/arch/powerpc/kernel/setup.c b/arch/powerpc/kernel/setup.c
new file mode 100644 (file)
index 0000000..27d7f82
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ * Common prep/pmac/chrp boot and setup code.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/initrd.h>
+#include <linux/ide.h>
+#include <linux/tty.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/cpu.h>
+#include <linux/console.h>
+
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+#include <asm/amigappc.h>
+#include <asm/smp.h>
+#include <asm/elf.h>
+#include <asm/cputable.h>
+#include <asm/bootx.h>
+#include <asm/btext.h>
+#include <asm/machdep.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/nvram.h>
+#include <asm/xmon.h>
+#include <asm/ocp.h>
+
+#define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \
+                     defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \
+                     defined(CONFIG_PPC_MPC52xx))
+
+#if USES_PPC_SYS
+#include <asm/ppc_sys.h>
+#endif
+
+#if defined CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
+
+extern void platform_init(void);
+extern void bootx_init(unsigned long r4, unsigned long phys);
+
+extern void ppc6xx_idle(void);
+extern void power4_idle(void);
+
+boot_infos_t *boot_infos;
+struct ide_machdep_calls ppc_ide_md;
+
+/* Used with the BI_MEMSIZE bootinfo parameter to store the memory
+   size value reported by the boot loader. */
+unsigned long boot_mem_size;
+
+unsigned long ISA_DMA_THRESHOLD;
+unsigned int DMA_MODE_READ;
+unsigned int DMA_MODE_WRITE;
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+int _machine = 0;
+
+extern void prep_init(void);
+extern void pmac_init(void);
+extern void chrp_init(void);
+
+dev_t boot_dev;
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned long SYSRQ_KEY = 0x54;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
+
+struct machdep_calls ppc_md;
+
+/*
+ * These are used in binfmt_elf.c to put aux entries on the stack
+ * for each elf executable being started.
+ */
+int dcache_bsize;
+int icache_bsize;
+int ucache_bsize;
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB_VGA16) || \
+    defined(CONFIG_FB_VGA16_MODULE) || defined(CONFIG_FB_VESA)
+struct screen_info screen_info = {
+       0, 25,                  /* orig-x, orig-y */
+       0,                      /* unused */
+       0,                      /* orig-video-page */
+       0,                      /* orig-video-mode */
+       80,                     /* orig-video-cols */
+       0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+       25,                     /* orig-video-lines */
+       1,                      /* orig-video-isVGA */
+       16                      /* orig-video-points */
+};
+#endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */
+
+void machine_restart(char *cmd)
+{
+#ifdef CONFIG_NVRAM
+       nvram_sync();
+#endif
+       ppc_md.restart(cmd);
+}
+
+void machine_power_off(void)
+{
+#ifdef CONFIG_NVRAM
+       nvram_sync();
+#endif
+       ppc_md.power_off();
+}
+
+void machine_halt(void)
+{
+#ifdef CONFIG_NVRAM
+       nvram_sync();
+#endif
+       ppc_md.halt();
+}
+
+void (*pm_power_off)(void) = machine_power_off;
+
+#ifdef CONFIG_TAU
+extern u32 cpu_temp(unsigned long cpu);
+extern u32 cpu_temp_both(unsigned long cpu);
+#endif /* CONFIG_TAU */
+
+int show_cpuinfo(struct seq_file *m, void *v)
+{
+       int i = (int) v - 1;
+       int err = 0;
+       unsigned int pvr;
+       unsigned short maj, min;
+       unsigned long lpj;
+
+       if (i >= NR_CPUS) {
+               /* Show summary information */
+#ifdef CONFIG_SMP
+               unsigned long bogosum = 0;
+               for (i = 0; i < NR_CPUS; ++i)
+                       if (cpu_online(i))
+                               bogosum += cpu_data[i].loops_per_jiffy;
+               seq_printf(m, "total bogomips\t: %lu.%02lu\n",
+                          bogosum/(500000/HZ), bogosum/(5000/HZ) % 100);
+#endif /* CONFIG_SMP */
+
+               if (ppc_md.show_cpuinfo != NULL)
+                       err = ppc_md.show_cpuinfo(m);
+               return err;
+       }
+
+#ifdef CONFIG_SMP
+       if (!cpu_online(i))
+               return 0;
+       pvr = cpu_data[i].pvr;
+       lpj = cpu_data[i].loops_per_jiffy;
+#else
+       pvr = mfspr(SPRN_PVR);
+       lpj = loops_per_jiffy;
+#endif
+
+       seq_printf(m, "processor\t: %d\n", i);
+       seq_printf(m, "cpu\t\t: ");
+
+       if (cur_cpu_spec->pvr_mask)
+               seq_printf(m, "%s", cur_cpu_spec->cpu_name);
+       else
+               seq_printf(m, "unknown (%08x)", pvr);
+#ifdef CONFIG_ALTIVEC
+       if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
+               seq_printf(m, ", altivec supported");
+#endif
+       seq_printf(m, "\n");
+
+#ifdef CONFIG_TAU
+       if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) {
+#ifdef CONFIG_TAU_AVERAGE
+               /* more straightforward, but potentially misleading */
+               seq_printf(m,  "temperature \t: %u C (uncalibrated)\n",
+                          cpu_temp(i));
+#else
+               /* show the actual temp sensor range */
+               u32 temp;
+               temp = cpu_temp_both(i);
+               seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n",
+                          temp & 0xff, temp >> 16);
+#endif
+       }
+#endif /* CONFIG_TAU */
+
+       if (ppc_md.show_percpuinfo != NULL) {
+               err = ppc_md.show_percpuinfo(m, i);
+               if (err)
+                       return err;
+       }
+
+       /* If we are a Freescale core do a simple check so
+        * we dont have to keep adding cases in the future */
+       if ((PVR_VER(pvr) & 0x8000) == 0x8000) {
+               maj = PVR_MAJ(pvr);
+               min = PVR_MIN(pvr);
+       } else {
+               switch (PVR_VER(pvr)) {
+                       case 0x0020:    /* 403 family */
+                               maj = PVR_MAJ(pvr) + 1;
+                               min = PVR_MIN(pvr);
+                               break;
+                       case 0x1008:    /* 740P/750P ?? */
+                               maj = ((pvr >> 8) & 0xFF) - 1;
+                               min = pvr & 0xFF;
+                               break;
+                       default:
+                               maj = (pvr >> 8) & 0xFF;
+                               min = pvr & 0xFF;
+                               break;
+               }
+       }
+
+       seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n",
+                  maj, min, PVR_VER(pvr), PVR_REV(pvr));
+
+       seq_printf(m, "bogomips\t: %lu.%02lu\n",
+                  lpj / (500000/HZ), (lpj / (5000/HZ)) % 100);
+
+#if USES_PPC_SYS
+       if (cur_ppc_sys_spec->ppc_sys_name)
+               seq_printf(m, "chipset\t\t: %s\n",
+                       cur_ppc_sys_spec->ppc_sys_name);
+#endif
+
+#ifdef CONFIG_SMP
+       seq_printf(m, "\n");
+#endif
+
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       int i = *pos;
+
+       return i <= NR_CPUS? (void *) (i + 1): NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+       .start =c_start,
+       .next = c_next,
+       .stop = c_stop,
+       .show = show_cpuinfo,
+};
+
+/*
+ * We're called here very early in the boot.  We determine the machine
+ * type and call the appropriate low-level setup functions.
+ *  -- Cort <cort@fsmlabs.com>
+ *
+ * Note that the kernel may be running at an address which is different
+ * from the address that it was linked at, so we must use RELOC/PTRRELOC
+ * to access static data (including strings).  -- paulus
+ */
+unsigned long __init early_init(unsigned long dt_ptr)
+{
+       unsigned long offset = reloc_offset();
+
+       reloc_got2(offset);
+
+       /*
+        * Identify the CPU type and fix up code sections
+        * that depend on which cpu we have.
+        */
+       identify_cpu(offset, 0);
+       do_cpu_ftr_fixups(offset);
+
+#ifdef CONFIG_BOOTX_TEXT
+       btext_prepare_BAT();
+#endif
+
+       reloc_got2(-offset);
+
+       return KERNELBASE + offset;
+}
+
+#ifdef CONFIG_PPC_OF
+/*
+ * Assume here that all clock rates are the same in a
+ * smp system.  -- Cort
+ */
+int
+of_show_percpuinfo(struct seq_file *m, int i)
+{
+       struct device_node *cpu_node;
+       u32 *fp;
+       int s;
+       
+       cpu_node = find_type_devices("cpu");
+       if (!cpu_node)
+               return 0;
+       for (s = 0; s < i && cpu_node->next; s++)
+               cpu_node = cpu_node->next;
+       fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL);
+       if (fp)
+               seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
+       return 0;
+}
+
+void __init
+intuit_machine_type(void)
+{
+       char *model;
+       struct device_node *root;
+       
+       /* ask the OF info if we're a chrp or pmac */
+       root = find_path_device("/");
+       if (root != 0) {
+               /* assume pmac unless proven to be chrp -- Cort */
+               _machine = _MACH_Pmac;
+               model = get_property(root, "device_type", NULL);
+               if (model && !strncmp("chrp", model, 4))
+                       _machine = _MACH_chrp;
+               else {
+                       model = get_property(root, "model", NULL);
+                       if (model && !strncmp(model, "IBM", 3))
+                               _machine = _MACH_chrp;
+               }
+       }
+}
+#endif
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+/*
+ * The PPC_MULTIPLATFORM version of platform_init...
+ */
+void __init platform_init(void)
+{
+       /* if we didn't get any bootinfo telling us what we are... */
+       if (_machine == 0) {
+               /* prep boot loader tells us if we're prep or not */
+               if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
+                       _machine = _MACH_prep;
+       }
+
+#ifdef CONFIG_PPC_PREP
+       /* not much more to do here, if prep */
+       if (_machine == _MACH_prep) {
+               prep_init();
+               return;
+       }
+#endif
+
+#ifdef CONFIG_ADB
+       if (strstr(cmd_line, "adb_sync")) {
+               extern int __adb_probe_sync;
+               __adb_probe_sync = 1;
+       }
+#endif /* CONFIG_ADB */
+
+       switch (_machine) {
+#ifdef CONFIG_PPC_PMAC
+       case _MACH_Pmac:
+               pmac_init();
+               break;
+#endif
+#ifdef CONFIG_PPC_CHRP
+       case _MACH_chrp:
+               chrp_init();
+               break;
+#endif
+       }
+}
+
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+extern char *of_stdout_device;
+
+static int __init set_preferred_console(void)
+{
+       struct device_node *prom_stdout;
+       char *name;
+       int offset = 0;
+
+       if (of_stdout_device == NULL)
+               return -ENODEV;
+
+       /* The user has requested a console so this is already set up. */
+       if (strstr(saved_command_line, "console="))
+               return -EBUSY;
+
+       prom_stdout = find_path_device(of_stdout_device);
+       if (!prom_stdout)
+               return -ENODEV;
+
+       name = (char *)get_property(prom_stdout, "name", NULL);
+       if (!name)
+               return -ENODEV;
+
+       if (strcmp(name, "serial") == 0) {
+               int i;
+               u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
+               if (i > 8) {
+                       switch (reg[1]) {
+                               case 0x3f8:
+                                       offset = 0;
+                                       break;
+                               case 0x2f8:
+                                       offset = 1;
+                                       break;
+                               case 0x898:
+                                       offset = 2;
+                                       break;
+                               case 0x890:
+                                       offset = 3;
+                                       break;
+                               default:
+                                       /* We dont recognise the serial port */
+                                       return -ENODEV;
+                       }
+               }
+       } else if (strcmp(name, "ch-a") == 0)
+               offset = 0;
+       else if (strcmp(name, "ch-b") == 0)
+               offset = 1;
+       else
+               return -ENODEV;
+       return add_preferred_console("ttyS", offset, NULL);
+}
+console_initcall(set_preferred_console);
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+struct bi_record *find_bootinfo(void)
+{
+       struct bi_record *rec;
+
+       rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20));
+       if ( rec->tag != BI_FIRST ) {
+               /*
+                * This 0x10000 offset is a terrible hack but it will go away when
+                * we have the bootloader handle all the relocation and
+                * prom calls -- Cort
+                */
+               rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20));
+               if ( rec->tag != BI_FIRST )
+                       return NULL;
+       }
+       return rec;
+}
+
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init()).
+ * This is called very early on the boot process, after a minimal
+ * MMU environment has been set up but before MMU_init is called.
+ */
+void __init machine_init(unsigned long dt_ptr, unsigned long phys)
+{
+       early_init_devtree(__va(dt_ptr));
+
+#ifdef CONFIG_CMDLINE
+       strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
+#endif /* CONFIG_CMDLINE */
+
+#ifdef CONFIG_6xx
+       ppc_md.power_save = ppc6xx_idle;
+#endif
+#ifdef CONFIG_POWER4
+       ppc_md.power_save = power4_idle;
+#endif
+
+       platform_init();
+
+       if (ppc_md.progress)
+               ppc_md.progress("id mach(): done", 0x200);
+}
+
+#ifdef CONFIG_BOOKE_WDT
+/* Checks wdt=x and wdt_period=xx command-line option */
+int __init early_parse_wdt(char *p)
+{
+       if (p && strncmp(p, "0", 1) != 0)
+              booke_wdt_enabled = 1;
+
+       return 0;
+}
+early_param("wdt", early_parse_wdt);
+
+int __init early_parse_wdt_period (char *p)
+{
+       if (p)
+               booke_wdt_period = simple_strtoul(p, NULL, 0);
+
+       return 0;
+}
+early_param("wdt_period", early_parse_wdt_period);
+#endif /* CONFIG_BOOKE_WDT */
+
+/* Checks "l2cr=xxxx" command-line option */
+int __init ppc_setup_l2cr(char *str)
+{
+       if (cpu_has_feature(CPU_FTR_L2CR)) {
+               unsigned long val = simple_strtoul(str, NULL, 0);
+               printk(KERN_INFO "l2cr set to %lx\n", val);
+               _set_L2CR(0);           /* force invalidate by disable cache */
+               _set_L2CR(val);         /* and enable it */
+       }
+       return 1;
+}
+__setup("l2cr=", ppc_setup_l2cr);
+
+#ifdef CONFIG_GENERIC_NVRAM
+
+/* Generic nvram hooks used by drivers/char/gen_nvram.c */
+unsigned char nvram_read_byte(int addr)
+{
+       if (ppc_md.nvram_read_val)
+               return ppc_md.nvram_read_val(addr);
+       return 0xff;
+}
+EXPORT_SYMBOL(nvram_read_byte);
+
+void nvram_write_byte(unsigned char val, int addr)
+{
+       if (ppc_md.nvram_write_val)
+               ppc_md.nvram_write_val(addr, val);
+}
+EXPORT_SYMBOL(nvram_write_byte);
+
+void nvram_sync(void)
+{
+       if (ppc_md.nvram_sync)
+               ppc_md.nvram_sync();
+}
+EXPORT_SYMBOL(nvram_sync);
+
+#endif /* CONFIG_NVRAM */
+
+static struct cpu cpu_devices[NR_CPUS];
+
+int __init ppc_init(void)
+{
+       int i;
+
+       /* clear the progress line */
+       if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
+
+       /* register CPU devices */
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_possible(i))
+                       register_cpu(&cpu_devices[i], i, NULL);
+
+       /* call platform init */
+       if (ppc_md.init != NULL) {
+               ppc_md.init();
+       }
+       return 0;
+}
+
+arch_initcall(ppc_init);
+
+/* Warning, IO base is not yet inited */
+void __init setup_arch(char **cmdline_p)
+{
+       extern char *klimit;
+       extern void do_init_bootmem(void);
+
+       /* so udelay does something sensible, assume <= 1000 bogomips */
+       loops_per_jiffy = 500000000 / HZ;
+
+#ifdef CONFIG_BOOTX_TEXT
+       map_boot_text();
+#endif
+
+       unflatten_device_tree();
+       finish_device_tree();
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+       /* This could be called "early setup arch", it must be done
+        * now because xmon need it
+        */
+       if (_machine == _MACH_Pmac)
+               pmac_feature_init();    /* New cool way */
+#endif
+
+#ifdef CONFIG_XMON
+       xmon_map_scc();
+       if (strstr(cmd_line, "xmon"))
+               xmon(NULL);
+#endif /* CONFIG_XMON */
+       if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
+
+#if defined(CONFIG_KGDB)
+       if (ppc_md.kgdb_map_scc)
+               ppc_md.kgdb_map_scc();
+       set_debug_traps();
+       if (strstr(cmd_line, "gdb")) {
+               if (ppc_md.progress)
+                       ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
+               printk("kgdb breakpoint activated\n");
+               breakpoint();
+       }
+#endif
+
+       /*
+        * Set cache line size based on type of cpu as a default.
+        * Systems with OF can look in the properties on the cpu node(s)
+        * for a possibly more accurate value.
+        */
+       if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) {
+               dcache_bsize = cur_cpu_spec->dcache_bsize;
+               icache_bsize = cur_cpu_spec->icache_bsize;
+               ucache_bsize = 0;
+       } else
+               ucache_bsize = dcache_bsize = icache_bsize
+                       = cur_cpu_spec->dcache_bsize;
+
+       /* reboot on panic */
+       panic_timeout = 180;
+
+       init_mm.start_code = PAGE_OFFSET;
+       init_mm.end_code = (unsigned long) _etext;
+       init_mm.end_data = (unsigned long) _edata;
+       init_mm.brk = (unsigned long) klimit;
+
+       /* Save unparsed command line copy for /proc/cmdline */
+       strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE);
+       *cmdline_p = cmd_line;
+
+       parse_early_param();
+
+       /* set up the bootmem stuff with available memory */
+       do_init_bootmem();
+       if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
+
+#ifdef CONFIG_PPC_OCP
+       /* Initialize OCP device list */
+       ocp_early_init();
+       if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab);
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+       conswitchp = &dummy_con;
+#endif
+
+       ppc_md.setup_arch();
+       if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
+
+       paging_init();
+
+       /* this is for modules since _machine can be a define -- Cort */
+       ppc_md.ppc_machine = _machine;
+}
index 3667e0b2b8e3db9d8efd59019002d1574698544d..1b12bf9956cb25dc128f4c2bba0b96f1961e2cc1 100644 (file)
@@ -101,6 +101,8 @@ int ppc_override_l2cr = 0;
 int ppc_override_l2cr_value;
 int has_l2cache = 0;
 
+int pmac_newworld = 1;
+
 static int current_root_goodness = -1;
 
 extern int pmac_newworld;
@@ -355,8 +357,8 @@ static void __init ohare_init(void)
        }
 }
 
-extern char *bootpath;
-extern char *bootdevice;
+char *bootpath;
+char *bootdevice;
 void *boot_host;
 int boot_target;
 int boot_part;
@@ -391,6 +393,7 @@ note_scsi_host(struct device_node *node, void *host)
                }
        }
 }
+EXPORT_SYMBOL(note_scsi_host);
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
@@ -565,9 +568,7 @@ pmac_halt(void)
        pmac_power_off();
 }
 
-void __init
-pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
-         unsigned long r6, unsigned long r7)
+void __init pmac_init(void)
 {
        /* isa_io_base gets set in pmac_find_bridges */
        isa_mem_base = PMAC_ISA_MEM_BASE;
index 1e50efab091d8770bcc2a0e5828e2ac3e2179b15..a4a50d08d3840b2cb6f43206fa59188d62f40891 100644 (file)
@@ -57,6 +57,9 @@ struct cpu_spec {
 
 extern struct cpu_spec         *cur_cpu_spec;
 
+extern void identify_cpu(unsigned long offset, unsigned long cpu);
+extern void do_cpu_ftr_fixups(unsigned long offset);
+
 #endif /* __ASSEMBLY__ */
 
 /* CPU kernel features */
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
new file mode 100644 (file)
index 0000000..d096faf
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
+ * Rewrite, cleanup:
+ * Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation
+ * 
+ * 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.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef _ASM_IOMMU_H
+#define _ASM_IOMMU_H
+
+#include <asm/types.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+/*
+ * IOMAP_MAX_ORDER defines the largest contiguous block
+ * of dma space we can get.  IOMAP_MAX_ORDER = 13
+ * allows up to 2**12 pages (4096 * 4096) = 16 MB
+ */
+#define IOMAP_MAX_ORDER 13
+
+struct iommu_table {
+       unsigned long  it_busno;     /* Bus number this table belongs to */
+       unsigned long  it_size;      /* Size of iommu table in entries */
+       unsigned long  it_offset;    /* Offset into global table */
+       unsigned long  it_base;      /* mapped address of tce table */
+       unsigned long  it_index;     /* which iommu table this is */
+       unsigned long  it_type;      /* type: PCI or Virtual Bus */
+       unsigned long  it_blocksize; /* Entries in each block (cacheline) */
+       unsigned long  it_hint;      /* Hint for next alloc */
+       unsigned long  it_largehint; /* Hint for large allocs */
+       unsigned long  it_halfpoint; /* Breaking point for small/large allocs */
+       spinlock_t     it_lock;      /* Protects it_map */
+       unsigned long *it_map;       /* A simple allocation bitmap for now */
+};
+
+struct scatterlist;
+struct device_node;
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+
+/* Walks all buses and creates iommu tables */
+extern void iommu_setup_pSeries(void);
+extern void iommu_setup_u3(void);
+
+/* Frees table for an individual device node */
+extern void iommu_free_table(struct device_node *dn);
+
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+#ifdef CONFIG_PPC_PSERIES
+
+/* Creates table for an individual device node */
+extern void iommu_devnode_init_pSeries(struct device_node *dn);
+
+#endif /* CONFIG_PPC_PSERIES */
+
+#ifdef CONFIG_PPC_ISERIES
+
+/* Creates table for an individual device node */
+extern void iommu_devnode_init_iSeries(struct device_node *dn);
+
+#endif /* CONFIG_PPC_ISERIES */
+
+/* Initializes an iommu_table based in values set in the passed-in
+ * structure
+ */
+extern struct iommu_table *iommu_init_table(struct iommu_table * tbl);
+
+extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
+               struct scatterlist *sglist, int nelems,
+               enum dma_data_direction direction);
+extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+               int nelems, enum dma_data_direction direction);
+
+extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
+               dma_addr_t *dma_handle, unsigned int __nocast flag);
+extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
+               void *vaddr, dma_addr_t dma_handle);
+extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
+               size_t size, enum dma_data_direction direction);
+extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
+               size_t size, enum dma_data_direction direction);
+
+extern void iommu_init_early_pSeries(void);
+extern void iommu_init_early_iSeries(void);
+extern void iommu_init_early_u3(void);
+
+#ifdef CONFIG_PCI
+extern void pci_iommu_init(void);
+extern void pci_direct_iommu_init(void);
+#else
+static inline void pci_iommu_init(void) { }
+#endif
+
+extern void alloc_u3_dart_table(void);
+
+#endif /* _ASM_IOMMU_H */
diff --git a/include/asm-powerpc/lmb.h b/include/asm-powerpc/lmb.h
new file mode 100644 (file)
index 0000000..ea0afe3
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef _PPC64_LMB_H
+#define _PPC64_LMB_H
+
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 2001 Peter Bergner, IBM Corp.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <asm/prom.h>
+
+#define MAX_LMB_REGIONS 128
+
+#define LMB_ALLOC_ANYWHERE     0
+
+struct lmb_property {
+       unsigned long base;
+       unsigned long size;
+};
+
+struct lmb_region {
+       unsigned long cnt;
+       unsigned long size;
+       struct lmb_property region[MAX_LMB_REGIONS+1];
+};
+
+struct lmb {
+       unsigned long debug;
+       unsigned long rmo_size;
+       struct lmb_region memory;
+       struct lmb_region reserved;
+};
+
+extern struct lmb lmb;
+
+extern void __init lmb_init(void);
+extern void __init lmb_analyze(void);
+extern long __init lmb_add(unsigned long, unsigned long);
+extern long __init lmb_reserve(unsigned long, unsigned long);
+extern unsigned long __init lmb_alloc(unsigned long, unsigned long);
+extern unsigned long __init lmb_alloc_base(unsigned long, unsigned long,
+                                          unsigned long);
+extern unsigned long __init lmb_phys_mem_size(void);
+extern unsigned long __init lmb_end_of_DRAM(void);
+extern unsigned long __init lmb_abs_to_phys(unsigned long);
+extern void __init lmb_enforce_memory_limit(unsigned long);
+
+extern void lmb_dump_all(void);
+
+extern unsigned long io_hole_start;
+
+static inline unsigned long
+lmb_size_bytes(struct lmb_region *type, unsigned long region_nr)
+{
+       return type->region[region_nr].size;
+}
+static inline unsigned long
+lmb_size_pages(struct lmb_region *type, unsigned long region_nr)
+{
+       return lmb_size_bytes(type, region_nr) >> PAGE_SHIFT;
+}
+static inline unsigned long
+lmb_start_pfn(struct lmb_region *type, unsigned long region_nr)
+{
+       return type->region[region_nr].base >> PAGE_SHIFT;
+}
+static inline unsigned long
+lmb_end_pfn(struct lmb_region *type, unsigned long region_nr)
+{
+       return lmb_start_pfn(type, region_nr) +
+              lmb_size_pages(type, region_nr);
+}
+
+#endif /* _PPC64_LMB_H */
diff --git a/include/asm-powerpc/pSeries_reconfig.h b/include/asm-powerpc/pSeries_reconfig.h
new file mode 100644 (file)
index 0000000..c0db1ea
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _PPC64_PSERIES_RECONFIG_H
+#define _PPC64_PSERIES_RECONFIG_H
+
+#include <linux/notifier.h>
+
+/*
+ * Use this API if your code needs to know about OF device nodes being
+ * added or removed on pSeries systems.
+ */
+
+#define PSERIES_RECONFIG_ADD    0x0001
+#define PSERIES_RECONFIG_REMOVE 0x0002
+
+#ifdef CONFIG_PPC_PSERIES
+extern int pSeries_reconfig_notifier_register(struct notifier_block *);
+extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
+#else /* !CONFIG_PPC_PSERIES */
+static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
+{
+       return 0;
+}
+static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
+#endif /* CONFIG_PPC_PSERIES */
+
+#endif /* _PPC64_PSERIES_RECONFIG_H */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
new file mode 100644 (file)
index 0000000..194b56e
--- /dev/null
@@ -0,0 +1,215 @@
+#ifndef _POWERPC_PROM_H
+#define _POWERPC_PROM_H
+#ifdef __KERNEL__
+
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/atomic.h>
+
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER           0xd00dfeed      /* marker */
+#define OF_DT_BEGIN_NODE       0x1             /* Start of node, full name */
+#define OF_DT_END_NODE         0x2             /* End node */
+#define OF_DT_PROP             0x3             /* Property: name off, size,
+                                                * content */
+#define OF_DT_NOP              0x4             /* nop */
+#define OF_DT_END              0x9
+
+#define OF_DT_VERSION          0x10
+
+/*
+ * This is what gets passed to the kernel by prom_init or kexec
+ *
+ * The dt struct contains the device tree structure, full pathes and
+ * property contents. The dt strings contain a separate block with just
+ * the strings for the property names, and is fully page aligned and
+ * self contained in a page, so that it can be kept around by the kernel,
+ * each property name appears only once in this page (cheap compression)
+ *
+ * the mem_rsvmap contains a map of reserved ranges of physical memory,
+ * passing it here instead of in the device-tree itself greatly simplifies
+ * the job of everybody. It's just a list of u64 pairs (base/size) that
+ * ends when size is 0
+ */
+struct boot_param_header
+{
+       u32     magic;                  /* magic word OF_DT_HEADER */
+       u32     totalsize;              /* total size of DT block */
+       u32     off_dt_struct;          /* offset to structure */
+       u32     off_dt_strings;         /* offset to strings */
+       u32     off_mem_rsvmap;         /* offset to memory reserve map */
+       u32     version;                /* format version */
+       u32     last_comp_version;      /* last compatible version */
+       /* version 2 fields below */
+       u32     boot_cpuid_phys;        /* Physical CPU id we're booting on */
+       /* version 3 fields below */
+       u32     dt_strings_size;        /* size of the DT strings block */
+};
+
+
+
+typedef u32 phandle;
+typedef u32 ihandle;
+
+struct address_range {
+       unsigned long space;
+       unsigned long address;
+       unsigned long size;
+};
+
+struct interrupt_info {
+       int     line;
+       int     sense;          /* +ve/-ve logic, edge or level, etc. */
+};
+
+struct pci_address {
+       u32 a_hi;
+       u32 a_mid;
+       u32 a_lo;
+};
+
+struct isa_address {
+       u32 a_hi;
+       u32 a_lo;
+};
+
+struct isa_range {
+       struct isa_address isa_addr;
+       struct pci_address pci_addr;
+       unsigned int size;
+};
+
+struct reg_property {
+       unsigned long address;
+       unsigned long size;
+};
+
+struct reg_property32 {
+       unsigned int address;
+       unsigned int size;
+};
+
+struct reg_property64 {
+       unsigned long address;
+       unsigned long size;
+};
+
+struct property {
+       char    *name;
+       int     length;
+       unsigned char *value;
+       struct property *next;
+};
+
+struct device_node {
+       char    *name;
+       char    *type;
+       phandle node;
+       phandle linux_phandle;
+       int     n_addrs;
+       struct  address_range *addrs;
+       int     n_intrs;
+       struct  interrupt_info *intrs;
+       char    *full_name;
+
+       struct  property *properties;
+       struct  device_node *parent;
+       struct  device_node *child;
+       struct  device_node *sibling;
+       struct  device_node *next;      /* next device of same type */
+       struct  device_node *allnext;   /* next in list of all nodes */
+       struct  proc_dir_entry *pde;    /* this node's proc directory */
+       struct  kref kref;
+       unsigned long _flags;
+       void    *data;
+};
+
+extern struct device_node *of_chosen;
+
+/* flag descriptions */
+#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
+
+#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
+#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
+
+#define HAVE_ARCH_DEVTREE_FIXUPS
+
+static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
+{
+       dn->pde = de;
+}
+
+
+/* OBSOLETE: Old style node lookup */
+extern struct device_node *find_devices(const char *name);
+extern struct device_node *find_type_devices(const char *type);
+extern struct device_node *find_path_device(const char *path);
+extern struct device_node *find_compatible_devices(const char *type,
+                                                  const char *compat);
+extern struct device_node *find_all_nodes(void);
+
+/* New style node lookup */
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name);
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type);
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compat);
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_find_all_nodes(struct device_node *prev);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+                                            struct device_node *prev);
+extern struct device_node *of_node_get(struct device_node *node);
+extern void of_node_put(struct device_node *node);
+
+/* For updating the device tree at runtime */
+extern void of_attach_node(struct device_node *);
+extern void of_detach_node(const struct device_node *);
+
+/* Other Prototypes */
+extern void finish_device_tree(void);
+extern void unflatten_device_tree(void);
+extern void early_init_devtree(void *);
+extern int device_is_compatible(struct device_node *device, const char *);
+extern int machine_is_compatible(const char *compat);
+extern unsigned char *get_property(struct device_node *node, const char *name,
+                                  int *lenp);
+extern void print_properties(struct device_node *node);
+extern int prom_n_addr_cells(struct device_node* np);
+extern int prom_n_size_cells(struct device_node* np);
+extern int prom_n_intr_cells(struct device_node* np);
+extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
+extern void prom_add_property(struct device_node* np, struct property* prop);
+
+/*
+ * PCI <-> OF matching functions
+ * (XXX should these be here?)
+ */
+struct pci_bus;
+struct pci_dev;
+extern int pci_device_from_OF_node(struct device_node *node,
+                                  u8* bus, u8* devfn);
+extern struct device_node* pci_busdev_to_OF_node(struct pci_bus *, int);
+extern struct device_node* pci_device_to_OF_node(struct pci_dev *);
+extern void pci_create_OF_bus_map(void);
+extern struct resource *request_OF_resource(struct device_node* node,
+                               int index, const char* name_postfix);
+extern int release_OF_resource(struct device_node* node, int index);
+
+#endif /* __KERNEL__ */
+#endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h
new file mode 100644 (file)
index 0000000..5c904d3
--- /dev/null
@@ -0,0 +1,249 @@
+#ifndef _POWERPC_RTAS_H
+#define _POWERPC_RTAS_H
+
+#include <linux/spinlock.h>
+#include <asm/page.h>
+
+/*
+ * Definitions for talking to the RTAS on CHRP machines.
+ *
+ * Copyright (C) 2001 Peter Bergner
+ * Copyright (C) 2001 PPC 64 Team, IBM Corp
+ *
+ * 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.
+ */
+
+#define RTAS_UNKNOWN_SERVICE (-1)
+#define RTAS_INSTANTIATE_MAX (1UL<<30) /* Don't instantiate rtas at/above this value */
+
+/* Buffer size for ppc_rtas system call. */
+#define RTAS_RMOBUF_MAX (64 * 1024)
+
+/* RTAS return status codes */
+#define RTAS_BUSY              -2    /* RTAS Busy */
+#define RTAS_EXTENDED_DELAY_MIN        9900
+#define RTAS_EXTENDED_DELAY_MAX        9905
+
+/*
+ * In general to call RTAS use rtas_token("string") to lookup
+ * an RTAS token for the given string (e.g. "event-scan").
+ * To actually perform the call use
+ *    ret = rtas_call(token, n_in, n_out, ...)
+ * Where n_in is the number of input parameters and
+ *       n_out is the number of output parameters
+ *
+ * If the "string" is invalid on this system, RTAS_UNKNOWN_SERVICE
+ * will be returned as a token.  rtas_call() does look for this
+ * token and error out gracefully so rtas_call(rtas_token("str"), ...)
+ * may be safely used for one-shot calls to RTAS.
+ *
+ */
+
+typedef u32 rtas_arg_t;
+
+struct rtas_args {
+       u32 token;
+       u32 nargs;
+       u32 nret; 
+       rtas_arg_t args[16];
+       rtas_arg_t *rets;     /* Pointer to return values in args[]. */
+};  
+
+extern struct rtas_args rtas_stop_self_args;
+
+struct rtas_t {
+       unsigned long entry;            /* physical address pointer */
+       unsigned long base;             /* physical address pointer */
+       unsigned long size;
+       spinlock_t lock;
+       struct rtas_args args;
+       struct device_node *dev;        /* virtual address pointer */
+};
+
+/* RTAS event classes */
+#define RTAS_INTERNAL_ERROR            0x80000000 /* set bit 0 */
+#define RTAS_EPOW_WARNING              0x40000000 /* set bit 1 */
+#define RTAS_POWERMGM_EVENTS           0x20000000 /* set bit 2 */
+#define RTAS_HOTPLUG_EVENTS            0x10000000 /* set bit 3 */
+#define RTAS_EVENT_SCAN_ALL_EVENTS     0xf0000000
+
+/* RTAS event severity */
+#define RTAS_SEVERITY_FATAL            0x5
+#define RTAS_SEVERITY_ERROR            0x4
+#define RTAS_SEVERITY_ERROR_SYNC       0x3
+#define RTAS_SEVERITY_WARNING          0x2
+#define RTAS_SEVERITY_EVENT            0x1
+#define RTAS_SEVERITY_NO_ERROR         0x0
+
+/* RTAS event disposition */
+#define RTAS_DISP_FULLY_RECOVERED      0x0
+#define RTAS_DISP_LIMITED_RECOVERY     0x1
+#define RTAS_DISP_NOT_RECOVERED                0x2
+
+/* RTAS event initiator */
+#define RTAS_INITIATOR_UNKNOWN         0x0
+#define RTAS_INITIATOR_CPU             0x1
+#define RTAS_INITIATOR_PCI             0x2
+#define RTAS_INITIATOR_ISA             0x3
+#define RTAS_INITIATOR_MEMORY          0x4
+#define RTAS_INITIATOR_POWERMGM                0x5
+
+/* RTAS event target */
+#define RTAS_TARGET_UNKNOWN            0x0
+#define RTAS_TARGET_CPU                        0x1
+#define RTAS_TARGET_PCI                        0x2
+#define RTAS_TARGET_ISA                        0x3
+#define RTAS_TARGET_MEMORY             0x4
+#define RTAS_TARGET_POWERMGM           0x5
+
+/* RTAS event type */
+#define RTAS_TYPE_RETRY                        0x01
+#define RTAS_TYPE_TCE_ERR              0x02
+#define RTAS_TYPE_INTERN_DEV_FAIL      0x03
+#define RTAS_TYPE_TIMEOUT              0x04
+#define RTAS_TYPE_DATA_PARITY          0x05
+#define RTAS_TYPE_ADDR_PARITY          0x06
+#define RTAS_TYPE_CACHE_PARITY         0x07
+#define RTAS_TYPE_ADDR_INVALID         0x08
+#define RTAS_TYPE_ECC_UNCORR           0x09
+#define RTAS_TYPE_ECC_CORR             0x0a
+#define RTAS_TYPE_EPOW                 0x40
+#define RTAS_TYPE_PLATFORM             0xE0
+#define RTAS_TYPE_IO                   0xE1
+#define RTAS_TYPE_INFO                 0xE2
+#define RTAS_TYPE_DEALLOC              0xE3
+#define RTAS_TYPE_DUMP                 0xE4
+/* I don't add PowerMGM events right now, this is a different topic */ 
+#define RTAS_TYPE_PMGM_POWER_SW_ON     0x60
+#define RTAS_TYPE_PMGM_POWER_SW_OFF    0x61
+#define RTAS_TYPE_PMGM_LID_OPEN                0x62
+#define RTAS_TYPE_PMGM_LID_CLOSE       0x63
+#define RTAS_TYPE_PMGM_SLEEP_BTN       0x64
+#define RTAS_TYPE_PMGM_WAKE_BTN                0x65
+#define RTAS_TYPE_PMGM_BATTERY_WARN    0x66
+#define RTAS_TYPE_PMGM_BATTERY_CRIT    0x67
+#define RTAS_TYPE_PMGM_SWITCH_TO_BAT   0x68
+#define RTAS_TYPE_PMGM_SWITCH_TO_AC    0x69
+#define RTAS_TYPE_PMGM_KBD_OR_MOUSE    0x6a
+#define RTAS_TYPE_PMGM_ENCLOS_OPEN     0x6b
+#define RTAS_TYPE_PMGM_ENCLOS_CLOSED   0x6c
+#define RTAS_TYPE_PMGM_RING_INDICATE   0x6d
+#define RTAS_TYPE_PMGM_LAN_ATTENTION   0x6e
+#define RTAS_TYPE_PMGM_TIME_ALARM      0x6f
+#define RTAS_TYPE_PMGM_CONFIG_CHANGE   0x70
+#define RTAS_TYPE_PMGM_SERVICE_PROC    0x71
+
+struct rtas_error_log {
+       unsigned long version:8;                /* Architectural version */
+       unsigned long severity:3;               /* Severity level of error */
+       unsigned long disposition:2;            /* Degree of recovery */
+       unsigned long extended:1;               /* extended log present? */
+       unsigned long /* reserved */ :2;        /* Reserved for future use */
+       unsigned long initiator:4;              /* Initiator of event */
+       unsigned long target:4;                 /* Target of failed operation */
+       unsigned long type:8;                   /* General event or error*/
+       unsigned long extended_log_length:32;   /* length in bytes */
+       unsigned char buffer[1];
+};
+
+struct flash_block {
+       char *data;
+       unsigned long length;
+};
+
+/* This struct is very similar but not identical to
+ * that needed by the rtas flash update.
+ * All we need to do for rtas is rewrite num_blocks
+ * into a version/length and translate the pointers
+ * to absolute.
+ */
+#define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block))
+struct flash_block_list {
+       unsigned long num_blocks;
+       struct flash_block_list *next;
+       struct flash_block blocks[FLASH_BLOCKS_PER_NODE];
+};
+struct flash_block_list_header { /* just the header of flash_block_list */
+       unsigned long num_blocks;
+       struct flash_block_list *next;
+};
+extern struct flash_block_list_header rtas_firmware_flash_list;
+
+extern struct rtas_t rtas;
+
+extern void enter_rtas(unsigned long);
+extern int rtas_token(const char *service);
+extern int rtas_call(int token, int, int, int *, ...);
+extern void call_rtas_display_status(unsigned char);
+extern void rtas_restart(char *cmd);
+extern void rtas_power_off(void);
+extern void rtas_halt(void);
+extern void rtas_os_term(char *str);
+extern int rtas_get_sensor(int sensor, int index, int *state);
+extern int rtas_get_power_level(int powerdomain, int *level);
+extern int rtas_set_power_level(int powerdomain, int level, int *setlevel);
+extern int rtas_set_indicator(int indicator, int index, int new_value);
+extern void rtas_progress(char *s, unsigned short hex);
+extern void rtas_initialize(void);
+
+struct rtc_time;
+extern void rtas_get_boot_time(struct rtc_time *rtc_time);
+extern void rtas_get_rtc_time(struct rtc_time *rtc_time);
+extern int rtas_set_rtc_time(struct rtc_time *rtc_time);
+
+/* Given an RTAS status code of 9900..9905 compute the hinted delay */
+unsigned int rtas_extended_busy_delay_time(int status);
+static inline int rtas_is_extended_busy(int status)
+{
+       return status >= 9900 && status <= 9909;
+}
+
+extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
+
+/* Error types logged.  */
+#define ERR_FLAG_ALREADY_LOGGED        0x0
+#define ERR_FLAG_BOOT          0x1     /* log was pulled from NVRAM on boot */
+#define ERR_TYPE_RTAS_LOG      0x2     /* from rtas event-scan */
+#define ERR_TYPE_KERNEL_PANIC  0x4     /* from panic() */
+
+/* All the types and not flags */
+#define ERR_TYPE_MASK  (ERR_TYPE_RTAS_LOG | ERR_TYPE_KERNEL_PANIC)
+
+#define RTAS_DEBUG KERN_DEBUG "RTAS: "
+#define RTAS_ERROR_LOG_MAX 2048
+
+/*
+ * Return the firmware-specified size of the error log buffer
+ *  for all rtas calls that require an error buffer argument.
+ *  This includes 'check-exception' and 'rtas-last-error'.
+ */
+extern int rtas_get_error_log_max(void);
+
+/* Event Scan Parameters */
+#define EVENT_SCAN_ALL_EVENTS  0xf0000000
+#define SURVEILLANCE_TOKEN     9000
+#define LOG_NUMBER             64              /* must be a power of two */
+#define LOG_NUMBER_MASK                (LOG_NUMBER-1)
+
+/* Some RTAS ops require a data buffer and that buffer must be < 4G.
+ * Rather than having a memory allocator, just use this buffer
+ * (get the lock first), make the RTAS call.  Copy the data instead
+ * of holding the buffer for long.
+ */
+
+#define RTAS_DATA_BUF_SIZE 4096
+extern spinlock_t rtas_data_buf_lock;
+extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
+
+extern void rtas_stop_self(void);
+
+/* RMO buffer reserved for user-space RTAS use */
+extern unsigned long rtas_rmo_buf;
+
+#define GLOBAL_INTERRUPT_QUEUE 9005
+
+#endif /* _POWERPC_RTAS_H */
index 027479dcbf439747eb5b8275c56d65ba5ee69768..66866f7301a932461710acc99b3f04413af8539c 100644 (file)
@@ -346,7 +346,12 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
 
 #define arch_align_stack(x) (x)
 
+/* Used in very early kernel initialization. */
 extern unsigned long reloc_offset(void);
+extern unsigned long add_reloc_offset(unsigned long);
+extern void reloc_got2(unsigned long);
+
+#define PTRRELOC(x)    ((typeof(x)) add_reloc_offset((unsigned long)(x)))
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SYSTEM_H */