Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile
new file mode 100644
index 0000000..8f2420d
--- /dev/null
+++ b/arch/sparc64/prom/Makefile
@@ -0,0 +1,10 @@
+# $Id: Makefile,v 1.7 2000/12/14 22:57:25 davem Exp $
+# Makefile for the Sun Boot PROM interface library under
+# Linux.
+#
+
+EXTRA_AFLAGS := -ansi
+EXTRA_CFLAGS := -Werror
+
+lib-y   := bootstr.o devops.o init.o memory.o misc.o \
+	   tree.o console.o printf.o p1275.o map.o cif.o
diff --git a/arch/sparc64/prom/bootstr.c b/arch/sparc64/prom/bootstr.c
new file mode 100644
index 0000000..a727861
--- /dev/null
+++ b/arch/sparc64/prom/bootstr.c
@@ -0,0 +1,40 @@
+/* $Id: bootstr.c,v 1.6 1999/08/31 06:55:01 davem Exp $
+ * bootstr.c:  Boot string/argument acquisition from the PROM.
+ *
+ * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright(C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/oplib.h>
+
+/* WARNING: The boot loader knows that these next three variables come one right
+ *          after another in the .data section.  Do not move this stuff into
+ *          the .bss section or it will break things.
+ */
+
+#define BARG_LEN  256
+struct {
+	int bootstr_len;
+	int bootstr_valid;
+	char bootstr_buf[BARG_LEN];
+} bootstr_info = {
+	.bootstr_len = BARG_LEN,
+#ifdef CONFIG_CMDLINE
+	.bootstr_valid = 1,
+	.bootstr_buf = CONFIG_CMDLINE,
+#endif
+};
+
+char * __init
+prom_getbootargs(void)
+{
+	/* This check saves us from a panic when bootfd patches args. */
+	if (bootstr_info.bootstr_valid)
+		return bootstr_info.bootstr_buf;
+	prom_getstring(prom_chosen_node, "bootargs",
+		       bootstr_info.bootstr_buf, BARG_LEN);
+	bootstr_info.bootstr_valid = 1;
+	return bootstr_info.bootstr_buf;
+}
diff --git a/arch/sparc64/prom/cif.S b/arch/sparc64/prom/cif.S
new file mode 100644
index 0000000..29d0ae7
--- /dev/null
+++ b/arch/sparc64/prom/cif.S
@@ -0,0 +1,225 @@
+/* cif.S: PROM entry/exit assembler trampolines.
+ *
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#include <asm/pstate.h>
+
+	.text
+	.globl	prom_cif_interface
+prom_cif_interface:
+	sethi	%hi(p1275buf), %o0
+	or	%o0, %lo(p1275buf), %o0
+	ldx	[%o0 + 0x010], %o1	! prom_cif_stack
+	save	%o1, -0x190, %sp
+	ldx	[%i0 + 0x008], %l2	! prom_cif_handler
+	rdpr	%pstate, %l4
+	wrpr	%g0, 0x15, %pstate	! save alternate globals
+	stx	%g1, [%sp + 2047 + 0x0b0]
+	stx	%g2, [%sp + 2047 + 0x0b8]
+	stx	%g3, [%sp + 2047 + 0x0c0]
+	stx	%g4, [%sp + 2047 + 0x0c8]
+	stx	%g5, [%sp + 2047 + 0x0d0]
+	stx	%g6, [%sp + 2047 + 0x0d8]
+	stx	%g7, [%sp + 2047 + 0x0e0]
+	wrpr	%g0, 0x814, %pstate	! save interrupt globals
+	stx	%g1, [%sp + 2047 + 0x0e8]
+	stx	%g2, [%sp + 2047 + 0x0f0]
+	stx	%g3, [%sp + 2047 + 0x0f8]
+	stx	%g4, [%sp + 2047 + 0x100]
+	stx	%g5, [%sp + 2047 + 0x108]
+	stx	%g6, [%sp + 2047 + 0x110]
+	stx	%g7, [%sp + 2047 + 0x118]
+	wrpr	%g0, 0x14, %pstate	! save normal globals
+	stx	%g1, [%sp + 2047 + 0x120]
+	stx	%g2, [%sp + 2047 + 0x128]
+	stx	%g3, [%sp + 2047 + 0x130]
+	stx	%g4, [%sp + 2047 + 0x138]
+	stx	%g5, [%sp + 2047 + 0x140]
+	stx	%g6, [%sp + 2047 + 0x148]
+	stx	%g7, [%sp + 2047 + 0x150]
+	wrpr	%g0, 0x414, %pstate	! save mmu globals
+	stx	%g1, [%sp + 2047 + 0x158]
+	stx	%g2, [%sp + 2047 + 0x160]
+	stx	%g3, [%sp + 2047 + 0x168]
+	stx	%g4, [%sp + 2047 + 0x170]
+	stx	%g5, [%sp + 2047 + 0x178]
+	stx	%g6, [%sp + 2047 + 0x180]
+	stx	%g7, [%sp + 2047 + 0x188]
+	mov	%g1, %l0		! also save to locals, so we can handle
+	mov	%g2, %l1		! tlb faults later on, when accessing
+	mov	%g3, %l3		! the stack.
+	mov	%g7, %l5
+	wrpr	%l4, PSTATE_IE, %pstate	! turn off interrupts
+	call	%l2
+	 add	%i0, 0x018, %o0		! prom_args
+	wrpr	%g0, 0x414, %pstate	! restore mmu globals
+	mov	%l0, %g1
+	mov	%l1, %g2
+	mov	%l3, %g3
+	mov	%l5, %g7
+	wrpr	%g0, 0x14, %pstate	! restore normal globals
+	ldx	[%sp + 2047 + 0x120], %g1
+	ldx	[%sp + 2047 + 0x128], %g2
+	ldx	[%sp + 2047 + 0x130], %g3
+	ldx	[%sp + 2047 + 0x138], %g4
+	ldx	[%sp + 2047 + 0x140], %g5
+	ldx	[%sp + 2047 + 0x148], %g6
+	ldx	[%sp + 2047 + 0x150], %g7
+	wrpr	%g0, 0x814, %pstate	! restore interrupt globals
+	ldx	[%sp + 2047 + 0x0e8], %g1
+	ldx	[%sp + 2047 + 0x0f0], %g2
+	ldx	[%sp + 2047 + 0x0f8], %g3
+	ldx	[%sp + 2047 + 0x100], %g4
+	ldx	[%sp + 2047 + 0x108], %g5
+	ldx	[%sp + 2047 + 0x110], %g6
+	ldx	[%sp + 2047 + 0x118], %g7
+	wrpr	%g0, 0x15, %pstate	! restore alternate globals
+	ldx	[%sp + 2047 + 0x0b0], %g1
+	ldx	[%sp + 2047 + 0x0b8], %g2
+	ldx	[%sp + 2047 + 0x0c0], %g3
+	ldx	[%sp + 2047 + 0x0c8], %g4
+	ldx	[%sp + 2047 + 0x0d0], %g5
+	ldx	[%sp + 2047 + 0x0d8], %g6
+	ldx	[%sp + 2047 + 0x0e0], %g7
+	wrpr	%l4, 0, %pstate	! restore original pstate
+	ret
+	 restore
+
+	.globl	prom_cif_callback
+prom_cif_callback:
+	sethi	%hi(p1275buf), %o1
+	or	%o1, %lo(p1275buf), %o1
+	save	%sp, -0x270, %sp
+	rdpr	%pstate, %l4
+	wrpr	%g0, 0x15, %pstate	! save PROM alternate globals
+	stx	%g1, [%sp + 2047 + 0x0b0]
+	stx	%g2, [%sp + 2047 + 0x0b8]
+	stx	%g3, [%sp + 2047 + 0x0c0]
+	stx	%g4, [%sp + 2047 + 0x0c8]
+	stx	%g5, [%sp + 2047 + 0x0d0]
+	stx	%g6, [%sp + 2047 + 0x0d8]
+	stx	%g7, [%sp + 2047 + 0x0e0]
+					! restore Linux alternate globals
+	ldx	[%sp + 2047 + 0x190], %g1
+	ldx	[%sp + 2047 + 0x198], %g2
+	ldx	[%sp + 2047 + 0x1a0], %g3
+	ldx	[%sp + 2047 + 0x1a8], %g4
+	ldx	[%sp + 2047 + 0x1b0], %g5
+	ldx	[%sp + 2047 + 0x1b8], %g6
+	ldx	[%sp + 2047 + 0x1c0], %g7
+	wrpr	%g0, 0x814, %pstate	! save PROM interrupt globals
+	stx	%g1, [%sp + 2047 + 0x0e8]
+	stx	%g2, [%sp + 2047 + 0x0f0]
+	stx	%g3, [%sp + 2047 + 0x0f8]
+	stx	%g4, [%sp + 2047 + 0x100]
+	stx	%g5, [%sp + 2047 + 0x108]
+	stx	%g6, [%sp + 2047 + 0x110]
+	stx	%g7, [%sp + 2047 + 0x118]
+					! restore Linux interrupt globals
+	ldx	[%sp + 2047 + 0x1c8], %g1
+	ldx	[%sp + 2047 + 0x1d0], %g2
+	ldx	[%sp + 2047 + 0x1d8], %g3
+	ldx	[%sp + 2047 + 0x1e0], %g4
+	ldx	[%sp + 2047 + 0x1e8], %g5
+	ldx	[%sp + 2047 + 0x1f0], %g6
+	ldx	[%sp + 2047 + 0x1f8], %g7
+	wrpr	%g0, 0x14, %pstate	! save PROM normal globals
+	stx	%g1, [%sp + 2047 + 0x120]
+	stx	%g2, [%sp + 2047 + 0x128]
+	stx	%g3, [%sp + 2047 + 0x130]
+	stx	%g4, [%sp + 2047 + 0x138]
+	stx	%g5, [%sp + 2047 + 0x140]
+	stx	%g6, [%sp + 2047 + 0x148]
+	stx	%g7, [%sp + 2047 + 0x150]
+					! restore Linux normal globals
+	ldx	[%sp + 2047 + 0x200], %g1
+	ldx	[%sp + 2047 + 0x208], %g2
+	ldx	[%sp + 2047 + 0x210], %g3
+	ldx	[%sp + 2047 + 0x218], %g4
+	ldx	[%sp + 2047 + 0x220], %g5
+	ldx	[%sp + 2047 + 0x228], %g6
+	ldx	[%sp + 2047 + 0x230], %g7
+	wrpr	%g0, 0x414, %pstate	! save PROM mmu globals
+	stx	%g1, [%sp + 2047 + 0x158]
+	stx	%g2, [%sp + 2047 + 0x160]
+	stx	%g3, [%sp + 2047 + 0x168]
+	stx	%g4, [%sp + 2047 + 0x170]
+	stx	%g5, [%sp + 2047 + 0x178]
+	stx	%g6, [%sp + 2047 + 0x180]
+	stx	%g7, [%sp + 2047 + 0x188]
+					! restore Linux mmu globals
+	ldx	[%sp + 2047 + 0x238], %o0
+	ldx	[%sp + 2047 + 0x240], %o1
+	ldx	[%sp + 2047 + 0x248], %l2
+	ldx	[%sp + 2047 + 0x250], %l3
+	ldx	[%sp + 2047 + 0x258], %l5
+	ldx	[%sp + 2047 + 0x260], %l6
+	ldx	[%sp + 2047 + 0x268], %l7
+					! switch to Linux tba
+	sethi	%hi(sparc64_ttable_tl0), %l1
+	rdpr	%tba, %l0		! save PROM tba
+	mov	%o0, %g1
+	mov	%o1, %g2
+	mov	%l2, %g3
+	mov	%l3, %g4
+	mov	%l5, %g5
+	mov	%l6, %g6
+	mov	%l7, %g7
+	wrpr	%l1, %tba		! install Linux tba
+	wrpr	%l4, 0, %pstate		! restore PSTATE
+	call	prom_world
+	 mov	%g0, %o0
+	ldx	[%i1 + 0x000], %l2
+	call	%l2
+	 mov	%i0, %o0
+	mov	%o0, %l1
+	call	prom_world
+	 or	%g0, 1, %o0
+	wrpr	%g0, 0x14, %pstate	! interrupts off
+					! restore PROM mmu globals
+	ldx	[%sp + 2047 + 0x158], %o0
+	ldx	[%sp + 2047 + 0x160], %o1
+	ldx	[%sp + 2047 + 0x168], %l2
+	ldx	[%sp + 2047 + 0x170], %l3
+	ldx	[%sp + 2047 + 0x178], %l5
+	ldx	[%sp + 2047 + 0x180], %l6
+	ldx	[%sp + 2047 + 0x188], %l7
+	wrpr	%g0, 0x414, %pstate	! restore PROM mmu globals
+	mov	%o0, %g1
+	mov	%o1, %g2
+	mov	%l2, %g3
+	mov	%l3, %g4
+	mov	%l5, %g5
+	mov	%l6, %g6
+	mov	%l7, %g7
+	wrpr	%l0, %tba		! restore PROM tba
+	wrpr	%g0, 0x14, %pstate	! restore PROM normal globals
+	ldx	[%sp + 2047 + 0x120], %g1
+	ldx	[%sp + 2047 + 0x128], %g2
+	ldx	[%sp + 2047 + 0x130], %g3
+	ldx	[%sp + 2047 + 0x138], %g4
+	ldx	[%sp + 2047 + 0x140], %g5
+	ldx	[%sp + 2047 + 0x148], %g6
+	ldx	[%sp + 2047 + 0x150], %g7
+	wrpr	%g0, 0x814, %pstate	! restore PROM interrupt globals
+	ldx	[%sp + 2047 + 0x0e8], %g1
+	ldx	[%sp + 2047 + 0x0f0], %g2
+	ldx	[%sp + 2047 + 0x0f8], %g3
+	ldx	[%sp + 2047 + 0x100], %g4
+	ldx	[%sp + 2047 + 0x108], %g5
+	ldx	[%sp + 2047 + 0x110], %g6
+	ldx	[%sp + 2047 + 0x118], %g7
+	wrpr	%g0, 0x15, %pstate	! restore PROM alternate globals
+	ldx	[%sp + 2047 + 0x0b0], %g1
+	ldx	[%sp + 2047 + 0x0b8], %g2
+	ldx	[%sp + 2047 + 0x0c0], %g3
+	ldx	[%sp + 2047 + 0x0c8], %g4
+	ldx	[%sp + 2047 + 0x0d0], %g5
+	ldx	[%sp + 2047 + 0x0d8], %g6
+	ldx	[%sp + 2047 + 0x0e0], %g7
+	wrpr	%l4, 0, %pstate
+	ret
+	 restore %l1, 0, %o0
+
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
new file mode 100644
index 0000000..028a53f
--- /dev/null
+++ b/arch/sparc64/prom/console.c
@@ -0,0 +1,146 @@
+/* $Id: console.c,v 1.9 1997/10/29 07:41:43 ecd Exp $
+ * console.c: Routines that deal with sending and receiving IO
+ *            to/from the current console device using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <linux/string.h>
+
+extern int prom_stdin, prom_stdout;
+
+/* Non blocking get character from console input device, returns -1
+ * if no input was taken.  This can be used for polling.
+ */
+__inline__ int
+prom_nbgetchar(void)
+{
+	char inc;
+
+	if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)|
+			      P1275_INOUT(3,1),
+			      prom_stdin, &inc, P1275_SIZE(1)) == 1)
+		return inc;
+	else
+		return -1;
+}
+
+/* Non blocking put character to console device, returns -1 if
+ * unsuccessful.
+ */
+__inline__ int
+prom_nbputchar(char c)
+{
+	char outc;
+	
+	outc = c;
+	if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
+			       P1275_INOUT(3,1),
+			       prom_stdout, &outc, P1275_SIZE(1)) == 1)
+		return 0;
+	else
+		return -1;
+}
+
+/* Blocking version of get character routine above. */
+char
+prom_getchar(void)
+{
+	int character;
+	while((character = prom_nbgetchar()) == -1) ;
+	return (char) character;
+}
+
+/* Blocking version of put character routine above. */
+void
+prom_putchar(char c)
+{
+	prom_nbputchar(c);
+	return;
+}
+
+void
+prom_puts(char *s, int len)
+{
+	p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
+			   P1275_INOUT(3,1),
+			   prom_stdout, s, P1275_SIZE(len));
+}
+
+/* Query for input device type */
+enum prom_input_device
+prom_query_input_device(void)
+{
+	int st_p;
+	char propb[64];
+
+	st_p = prom_inst2pkg(prom_stdin);
+	if(prom_node_has_property(st_p, "keyboard"))
+		return PROMDEV_IKBD;
+	prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+	if(strncmp(propb, "serial", 6))
+		return PROMDEV_I_UNK;
+	/* FIXME: Is there any better way how to find out? */	
+	memset(propb, 0, sizeof(propb));
+	st_p = prom_finddevice ("/options");
+	prom_getproperty(st_p, "input-device", propb, sizeof(propb));
+
+	/*
+	 * If we get here with propb == 'keyboard', we are on ttya, as
+	 * the PROM defaulted to this due to 'no input device'.
+	 */
+	if (!strncmp(propb, "keyboard", 8))
+		return PROMDEV_ITTYA;
+
+	if (strncmp (propb, "tty", 3) || !propb[3])
+		return PROMDEV_I_UNK;
+	switch (propb[3]) {
+		case 'a': return PROMDEV_ITTYA;
+		case 'b': return PROMDEV_ITTYB;
+		default: return PROMDEV_I_UNK;
+	}
+}
+
+/* Query for output device type */
+
+enum prom_output_device
+prom_query_output_device(void)
+{
+	int st_p;
+	char propb[64];
+	int propl;
+
+	st_p = prom_inst2pkg(prom_stdout);
+	propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+	if (propl >= 0 && propl == sizeof("display") &&
+	    strncmp("display", propb, sizeof("display")) == 0)
+		return PROMDEV_OSCREEN;
+	if(strncmp("serial", propb, 6))
+		return PROMDEV_O_UNK;
+	/* FIXME: Is there any better way how to find out? */	
+	memset(propb, 0, sizeof(propb));
+	st_p = prom_finddevice ("/options");
+	prom_getproperty(st_p, "output-device", propb, sizeof(propb));
+
+	/*
+	 * If we get here with propb == 'screen', we are on ttya, as
+	 * the PROM defaulted to this due to 'no input device'.
+	 */
+	if (!strncmp(propb, "screen", 6))
+		return PROMDEV_OTTYA;
+
+	if (strncmp (propb, "tty", 3) || !propb[3])
+		return PROMDEV_O_UNK;
+	switch (propb[3]) {
+		case 'a': return PROMDEV_OTTYA;
+		case 'b': return PROMDEV_OTTYB;
+		default: return PROMDEV_O_UNK;
+	}
+}
diff --git a/arch/sparc64/prom/devops.c b/arch/sparc64/prom/devops.c
new file mode 100644
index 0000000..2c99b21
--- /dev/null
+++ b/arch/sparc64/prom/devops.c
@@ -0,0 +1,41 @@
+/* $Id: devops.c,v 1.3 1997/10/29 07:43:28 ecd Exp $
+ * devops.c:  Device operations using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Open the device described by the string 'dstr'.  Returns the handle
+ * to that device used for subsequent operations on that device.
+ * Returns 0 on failure.
+ */
+int
+prom_devopen(char *dstr)
+{
+	return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)|
+				  P1275_INOUT(1,1),
+				  dstr);
+}
+
+/* Close the device described by device handle 'dhandle'. */
+int
+prom_devclose(int dhandle)
+{
+	p1275_cmd ("close", P1275_INOUT(1,0), dhandle);
+	return 0;
+}
+
+/* Seek to specified location described by 'seekhi' and 'seeklo'
+ * for device 'dhandle'.
+ */
+void
+prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
+{
+	p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo);
+}
diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c
new file mode 100644
index 0000000..817faae
--- /dev/null
+++ b/arch/sparc64/prom/init.c
@@ -0,0 +1,101 @@
+/* $Id: init.c,v 1.10 1999/09/21 14:35:59 davem Exp $
+ * init.c:  Initialize internal variables used by the PROM
+ *          library functions.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+enum prom_major_version prom_vers;
+unsigned int prom_rev, prom_prev;
+
+/* The root node of the prom device tree. */
+int prom_root_node;
+int prom_stdin, prom_stdout;
+int prom_chosen_node;
+
+/* You must call prom_init() before you attempt to use any of the
+ * routines in the prom library.  It returns 0 on success, 1 on
+ * failure.  It gets passed the pointer to the PROM vector.
+ */
+
+extern void prom_meminit(void);
+extern void prom_cif_init(void *, void *);
+
+void __init prom_init(void *cif_handler, void *cif_stack)
+{
+	char buffer[80], *p;
+	int ints[3];
+	int node;
+	int i = 0;
+	int bufadjust;
+
+	prom_vers = PROM_P1275;
+
+	prom_cif_init(cif_handler, cif_stack);
+
+	prom_root_node = prom_getsibling(0);
+	if((prom_root_node == 0) || (prom_root_node == -1))
+		prom_halt();
+
+	prom_chosen_node = prom_finddevice("/chosen");
+	if (!prom_chosen_node || prom_chosen_node == -1)
+		prom_halt();
+
+	prom_stdin = prom_getint (prom_chosen_node, "stdin");
+	prom_stdout = prom_getint (prom_chosen_node, "stdout");
+
+	node = prom_finddevice("/openprom");
+	if (!node || node == -1)
+		prom_halt();
+
+	prom_getstring (node, "version", buffer, sizeof (buffer));
+
+	prom_printf ("\n");
+
+	if (strncmp (buffer, "OBP ", 4))
+		goto strange_version;
+
+	/*
+	 * Version field is expected to be 'OBP xx.yy.zz date...'
+	 * However, Sun can't stick to this format very well, so
+	 * we need to check for 'OBP  xx.yy.zz date...' and adjust
+	 * accordingly. -spot
+	 */
+
+	if (strncmp (buffer, "OBP  ", 5))
+		bufadjust = 4;
+	else
+		bufadjust = 5;
+
+	p = buffer + bufadjust;
+	while (p && isdigit(*p) && i < 3) {
+		ints[i++] = simple_strtoul(p, NULL, 0);
+		if ((p = strchr(p, '.')) != NULL)
+			p++;
+	}
+	if (i != 3)
+		goto strange_version;
+
+	prom_rev = ints[1];
+	prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];
+
+	printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);
+
+	prom_meminit();
+
+	/* Initialization successful. */
+	return;
+
+strange_version:
+	prom_printf ("Strange OBP version `%s'.\n", buffer);
+	prom_halt ();
+}
diff --git a/arch/sparc64/prom/map.S b/arch/sparc64/prom/map.S
new file mode 100644
index 0000000..21b3f9c
--- /dev/null
+++ b/arch/sparc64/prom/map.S
@@ -0,0 +1,72 @@
+/* $Id: map.S,v 1.2 1999/11/19 05:53:02 davem Exp $
+ * map.S: Tricky coding required to fixup the kernel OBP maps
+ *	  properly.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+	.text
+	.align	8192
+	.globl	prom_boot_page
+prom_boot_page:
+call_method:
+	.asciz	"call-method"
+	.align	8
+map:
+	.asciz	"map"
+	.align	8
+
+	/* When we are invoked, our caller has remapped us to
+	 * page zero, therefore we must use PC relative addressing
+	 * for everything after we begin performing the unmap/map
+	 * calls.
+	 */
+	.globl	prom_remap
+prom_remap:	/* %o0 = physpage, %o1 = virtpage, %o2 = mmu_ihandle */
+	rd	%pc, %g1
+	srl	%o2, 0, %o2			! kill sign extension
+	sethi	%hi(p1275buf), %g2
+	or	%g2, %lo(p1275buf), %g2
+	ldx	[%g2 + 0x10], %g3		! prom_cif_stack
+	save	%g3, -(192 + 128), %sp
+	ldx	[%g2 + 0x08], %l0		! prom_cif_handler
+	mov	%g6, %i3
+	mov	%g4, %i4
+	mov	%g5, %i5
+	flushw
+
+	sethi	%hi(prom_remap - call_method), %g7
+	or	%g7, %lo(prom_remap - call_method), %g7
+	sub	%g1, %g7, %l2			! call-method string
+	sethi	%hi(prom_remap - map), %g7
+	or	%g7, %lo(prom_remap - map), %g7
+	sub	%g1, %g7, %l4			! map string
+
+	/* OK, map the 4MB region we really live at. */
+	stx	%l2, [%sp + 2047 + 128 + 0x00]	! call-method
+	mov	7, %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x08]	! num_args
+	mov	1, %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x10]	! num_rets
+	stx	%l4, [%sp + 2047 + 128 + 0x18]	! map
+	stx	%i2, [%sp + 2047 + 128 + 0x20]	! mmu_ihandle
+	mov	-1, %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x28]	! mode == default
+	sethi	%hi(4 * 1024 * 1024), %l5
+	stx	%l5, [%sp + 2047 + 128 + 0x30]	! size
+	stx	%i1, [%sp + 2047 + 128 + 0x38]	! vaddr
+	stx	%g0, [%sp + 2047 + 128 + 0x40]	! filler
+	stx	%i0, [%sp + 2047 + 128 + 0x48]	! paddr
+	call	%l0
+	 add	%sp, (2047 + 128), %o0		! argument array
+
+	/* Restore hard-coded globals. */
+	mov	%i3, %g6
+	mov	%i4, %g4
+	mov	%i5, %g5
+
+	/* Wheee.... we are done. */
+	ret
+	restore
+
+	.align	8192
diff --git a/arch/sparc64/prom/memory.c b/arch/sparc64/prom/memory.c
new file mode 100644
index 0000000..f4a8143
--- /dev/null
+++ b/arch/sparc64/prom/memory.c
@@ -0,0 +1,152 @@
+/* $Id: memory.c,v 1.5 1999/08/31 06:55:04 davem Exp $
+ * memory.c: Prom routine for acquiring various bits of information
+ *           about RAM on the machine, both virtual and physical.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* This routine, for consistency, returns the ram parameters in the
+ * V0 prom memory descriptor format.  I choose this format because I
+ * think it was the easiest to work with.  I feel the religious
+ * arguments now... ;)  Also, I return the linked lists sorted to
+ * prevent paging_init() upset stomach as I have not yet written
+ * the pepto-bismol kernel module yet.
+ */
+
+struct linux_prom64_registers prom_reg_memlist[64];
+struct linux_prom64_registers prom_reg_tmp[64];
+
+struct linux_mlist_p1275 prom_phys_total[64];
+struct linux_mlist_p1275 prom_prom_taken[64];
+struct linux_mlist_p1275 prom_phys_avail[64];
+
+struct linux_mlist_p1275 *prom_ptot_ptr = prom_phys_total;
+struct linux_mlist_p1275 *prom_ptak_ptr = prom_prom_taken;
+struct linux_mlist_p1275 *prom_pavl_ptr = prom_phys_avail;
+
+struct linux_mem_p1275 prom_memlist;
+
+
+/* Internal Prom library routine to sort a linux_mlist_p1275 memory
+ * list.  Used below in initialization.
+ */
+static void __init
+prom_sortmemlist(struct linux_mlist_p1275 *thislist)
+{
+	int swapi = 0;
+	int i, mitr;
+	unsigned long tmpaddr, tmpsize;
+	unsigned long lowest;
+
+	for(i=0; thislist[i].theres_more; i++) {
+		lowest = thislist[i].start_adr;
+		for(mitr = i+1; thislist[mitr-1].theres_more; mitr++)
+			if(thislist[mitr].start_adr < lowest) {
+				lowest = thislist[mitr].start_adr;
+				swapi = mitr;
+			}
+		if(lowest == thislist[i].start_adr) continue;
+		tmpaddr = thislist[swapi].start_adr;
+		tmpsize = thislist[swapi].num_bytes;
+		for(mitr = swapi; mitr > i; mitr--) {
+			thislist[mitr].start_adr = thislist[mitr-1].start_adr;
+			thislist[mitr].num_bytes = thislist[mitr-1].num_bytes;
+		}
+		thislist[i].start_adr = tmpaddr;
+		thislist[i].num_bytes = tmpsize;
+	}
+}
+
+/* Initialize the memory lists based upon the prom version. */
+void __init prom_meminit(void)
+{
+	int node = 0;
+	unsigned int iter, num_regs;
+
+	node = prom_finddevice("/memory");
+	num_regs = prom_getproperty(node, "available",
+				    (char *) prom_reg_memlist,
+				    sizeof(prom_reg_memlist));
+	num_regs = (num_regs/sizeof(struct linux_prom64_registers));
+	for(iter=0; iter<num_regs; iter++) {
+		prom_phys_avail[iter].start_adr =
+			prom_reg_memlist[iter].phys_addr;
+		prom_phys_avail[iter].num_bytes =
+			prom_reg_memlist[iter].reg_size;
+		prom_phys_avail[iter].theres_more =
+			&prom_phys_avail[iter+1];
+	}
+	prom_phys_avail[iter-1].theres_more = NULL;
+
+	num_regs = prom_getproperty(node, "reg",
+				    (char *) prom_reg_memlist,
+				    sizeof(prom_reg_memlist));
+	num_regs = (num_regs/sizeof(struct linux_prom64_registers));
+	for(iter=0; iter<num_regs; iter++) {
+		prom_phys_total[iter].start_adr =
+			prom_reg_memlist[iter].phys_addr;
+		prom_phys_total[iter].num_bytes =
+			prom_reg_memlist[iter].reg_size;
+		prom_phys_total[iter].theres_more =
+			&prom_phys_total[iter+1];
+	}
+	prom_phys_total[iter-1].theres_more = NULL;
+
+	node = prom_finddevice("/virtual-memory");
+	num_regs = prom_getproperty(node, "available",
+				    (char *) prom_reg_memlist,
+				    sizeof(prom_reg_memlist));
+	num_regs = (num_regs/sizeof(struct linux_prom64_registers));
+
+	/* Convert available virtual areas to taken virtual
+	 * areas.  First sort, then convert.
+	 */
+	for(iter=0; iter<num_regs; iter++) {
+		prom_prom_taken[iter].start_adr =
+			prom_reg_memlist[iter].phys_addr;
+		prom_prom_taken[iter].num_bytes =
+			prom_reg_memlist[iter].reg_size;
+		prom_prom_taken[iter].theres_more =
+			&prom_prom_taken[iter+1];
+	}
+	prom_prom_taken[iter-1].theres_more = NULL;
+
+	prom_sortmemlist(prom_prom_taken);
+
+	/* Finally, convert. */
+	for(iter=0; iter<num_regs; iter++) {
+		prom_prom_taken[iter].start_adr =
+			prom_prom_taken[iter].start_adr +
+			prom_prom_taken[iter].num_bytes;
+		prom_prom_taken[iter].num_bytes =
+			prom_prom_taken[iter+1].start_adr -
+			prom_prom_taken[iter].start_adr;
+	}
+	prom_prom_taken[iter-1].num_bytes =
+		-1UL - prom_prom_taken[iter-1].start_adr;
+
+	/* Sort the other two lists. */
+	prom_sortmemlist(prom_phys_total);
+	prom_sortmemlist(prom_phys_avail);
+
+	/* Link all the lists into the top-level descriptor. */
+	prom_memlist.p1275_totphys=&prom_ptot_ptr;
+	prom_memlist.p1275_prommap=&prom_ptak_ptr;
+	prom_memlist.p1275_available=&prom_pavl_ptr;
+}
+
+/* This returns a pointer to our libraries internal p1275 format
+ * memory descriptor.
+ */
+struct linux_mem_p1275 *
+prom_meminfo(void)
+{
+	return &prom_memlist;
+}
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
new file mode 100644
index 0000000..19c44e9
--- /dev/null
+++ b/arch/sparc64/prom/misc.c
@@ -0,0 +1,339 @@
+/* $Id: misc.c,v 1.20 2001/09/21 03:17:07 kanoj Exp $
+ * misc.c:  Miscellaneous prom functions that don't belong
+ *          anywhere else.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+
+/* Reset and reboot the machine with the command 'bcommand'. */
+void prom_reboot(char *bcommand)
+{
+	p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
+		  P1275_INOUT(1, 0), bcommand);
+}
+
+/* Forth evaluate the expression contained in 'fstring'. */
+void prom_feval(char *fstring)
+{
+	if (!fstring || fstring[0] == 0)
+		return;
+	p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) |
+		  P1275_INOUT(1, 1), fstring);
+}
+
+/* We want to do this more nicely some day. */
+extern void (*prom_palette)(int);
+
+#ifdef CONFIG_SMP
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
+/* Drop into the prom, with the chance to continue with the 'go'
+ * prom command.
+ */
+void prom_cmdline(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	if (!serial_console && prom_palette)
+		prom_palette(1);
+
+#ifdef CONFIG_SMP
+	smp_capture();
+#endif
+
+	p1275_cmd("enter", P1275_INOUT(0, 0));
+
+#ifdef CONFIG_SMP
+	smp_release();
+#endif
+
+	if (!serial_console && prom_palette)
+		prom_palette(0);
+
+	local_irq_restore(flags);
+}
+
+#ifdef CONFIG_SMP
+extern void smp_promstop_others(void);
+#endif
+
+/* Drop into the prom, but completely terminate the program.
+ * No chance of continuing.
+ */
+void prom_halt(void)
+{
+#ifdef CONFIG_SMP
+	smp_promstop_others();
+	udelay(8000);
+#endif
+again:
+	p1275_cmd("exit", P1275_INOUT(0, 0));
+	goto again; /* PROM is out to get me -DaveM */
+}
+
+void prom_halt_power_off(void)
+{
+#ifdef CONFIG_SMP
+	smp_promstop_others();
+	udelay(8000);
+#endif
+	p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
+
+	/* if nothing else helps, we just halt */
+	prom_halt();
+}
+
+/* Set prom sync handler to call function 'funcp'. */
+void prom_setcallback(callback_func_t funcp)
+{
+	if (!funcp)
+		return;
+	p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) |
+		  P1275_INOUT(1, 1), funcp);
+}
+
+/* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
+ * format type.  'num_bytes' is the number of bytes that your idbuf
+ * has space for.  Returns 0xff on error.
+ */
+unsigned char prom_get_idprom(char *idbuf, int num_bytes)
+{
+	int len;
+
+	len = prom_getproplen(prom_root_node, "idprom");
+	if ((len >num_bytes) || (len == -1))
+		return 0xff;
+	if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
+		return idbuf[0];
+
+	return 0xff;
+}
+
+/* Get the major prom version number. */
+int prom_version(void)
+{
+	return PROM_P1275;
+}
+
+/* Get the prom plugin-revision. */
+int prom_getrev(void)
+{
+	return prom_rev;
+}
+
+/* Get the prom firmware print revision. */
+int prom_getprev(void)
+{
+	return prom_prev;
+}
+
+/* Install Linux trap table so PROM uses that instead of its own. */
+void prom_set_trap_table(unsigned long tba)
+{
+	p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
+}
+
+int mmu_ihandle_cache = 0;
+
+int prom_get_mmu_ihandle(void)
+{
+	int node, ret;
+
+	if (mmu_ihandle_cache != 0)
+		return mmu_ihandle_cache;
+
+	node = prom_finddevice("/chosen");
+	ret = prom_getint(node, "mmu");
+	if (ret == -1 || ret == 0)
+		mmu_ihandle_cache = -1;
+	else
+		mmu_ihandle_cache = ret;
+
+	return ret;
+}
+
+static int prom_get_memory_ihandle(void)
+{
+	static int memory_ihandle_cache;
+	int node, ret;
+
+	if (memory_ihandle_cache != 0)
+		return memory_ihandle_cache;
+
+	node = prom_finddevice("/chosen");
+	ret = prom_getint(node, "memory");
+	if (ret == -1 || ret == 0)
+		memory_ihandle_cache = -1;
+	else
+		memory_ihandle_cache = ret;
+
+	return ret;
+}
+
+/* Load explicit I/D TLB entries. */
+long prom_itlb_load(unsigned long index,
+		    unsigned long tte_data,
+		    unsigned long vaddr)
+{
+	return p1275_cmd("call-method",
+			 (P1275_ARG(0, P1275_ARG_IN_STRING) |
+			  P1275_ARG(2, P1275_ARG_IN_64B) |
+			  P1275_ARG(3, P1275_ARG_IN_64B) |
+			  P1275_INOUT(5, 1)),
+			 "SUNW,itlb-load",
+			 prom_get_mmu_ihandle(),
+			 /* And then our actual args are pushed backwards. */
+			 vaddr,
+			 tte_data,
+			 index);
+}
+
+long prom_dtlb_load(unsigned long index,
+		    unsigned long tte_data,
+		    unsigned long vaddr)
+{
+	return p1275_cmd("call-method",
+			 (P1275_ARG(0, P1275_ARG_IN_STRING) |
+			  P1275_ARG(2, P1275_ARG_IN_64B) |
+			  P1275_ARG(3, P1275_ARG_IN_64B) |
+			  P1275_INOUT(5, 1)),
+			 "SUNW,dtlb-load",
+			 prom_get_mmu_ihandle(),
+			 /* And then our actual args are pushed backwards. */
+			 vaddr,
+			 tte_data,
+			 index);
+}
+
+int prom_map(int mode, unsigned long size,
+	     unsigned long vaddr, unsigned long paddr)
+{
+	int ret = p1275_cmd("call-method",
+			    (P1275_ARG(0, P1275_ARG_IN_STRING) |
+			     P1275_ARG(3, P1275_ARG_IN_64B) |
+			     P1275_ARG(4, P1275_ARG_IN_64B) |
+			     P1275_ARG(6, P1275_ARG_IN_64B) |
+			     P1275_INOUT(7, 1)),
+			    "map",
+			    prom_get_mmu_ihandle(),
+			    mode,
+			    size,
+			    vaddr,
+			    0,
+			    paddr);
+
+	if (ret == 0)
+		ret = -1;
+	return ret;
+}
+
+void prom_unmap(unsigned long size, unsigned long vaddr)
+{
+	p1275_cmd("call-method",
+		  (P1275_ARG(0, P1275_ARG_IN_STRING) |
+		   P1275_ARG(2, P1275_ARG_IN_64B) |
+		   P1275_ARG(3, P1275_ARG_IN_64B) |
+		   P1275_INOUT(4, 0)),
+		  "unmap",
+		  prom_get_mmu_ihandle(),
+		  size,
+		  vaddr);
+}
+
+/* Set aside physical memory which is not touched or modified
+ * across soft resets.
+ */
+unsigned long prom_retain(char *name,
+			  unsigned long pa_low, unsigned long pa_high,
+			  long size, long align)
+{
+	/* XXX I don't think we return multiple values correctly.
+	 * XXX OBP supposedly returns pa_low/pa_high here, how does
+	 * XXX it work?
+	 */
+
+	/* If align is zero, the pa_low/pa_high args are passed,
+	 * else they are not.
+	 */
+	if (align == 0)
+		return p1275_cmd("SUNW,retain",
+				 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
+				 name, pa_low, pa_high, size, align);
+	else
+		return p1275_cmd("SUNW,retain",
+				 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
+				 name, size, align);
+}
+
+/* Get "Unumber" string for the SIMM at the given
+ * memory address.  Usually this will be of the form
+ * "Uxxxx" where xxxx is a decimal number which is
+ * etched into the motherboard next to the SIMM slot
+ * in question.
+ */
+int prom_getunumber(int syndrome_code,
+		    unsigned long phys_addr,
+		    char *buf, int buflen)
+{
+	return p1275_cmd("call-method",
+			 (P1275_ARG(0, P1275_ARG_IN_STRING)	|
+			  P1275_ARG(3, P1275_ARG_OUT_BUF)	|
+			  P1275_ARG(6, P1275_ARG_IN_64B)	|
+			  P1275_INOUT(8, 2)),
+			 "SUNW,get-unumber", prom_get_memory_ihandle(),
+			 buflen, buf, P1275_SIZE(buflen),
+			 0, phys_addr, syndrome_code);
+}
+
+/* Power management extensions. */
+void prom_sleepself(void)
+{
+	p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
+}
+
+int prom_sleepsystem(void)
+{
+	return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
+}
+
+int prom_wakeupsystem(void)
+{
+	return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
+}
+
+#ifdef CONFIG_SMP
+void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
+{
+	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
+}
+
+void prom_stopself(void)
+{
+	p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
+}
+
+void prom_idleself(void)
+{
+	p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
+}
+
+void prom_resumecpu(int cpunode)
+{
+	p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
+}
+#endif
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
new file mode 100644
index 0000000..59fe38b
--- /dev/null
+++ b/arch/sparc64/prom/p1275.c
@@ -0,0 +1,161 @@
+/* $Id: p1275.c,v 1.22 2001/10/18 09:40:00 davem Exp $
+ * p1275.c: Sun IEEE 1275 PROM low level interface routines
+ *
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/spitfire.h>
+#include <asm/pstate.h>
+
+struct {
+	long prom_callback;			/* 0x00 */
+	void (*prom_cif_handler)(long *);	/* 0x08 */
+	unsigned long prom_cif_stack;		/* 0x10 */
+	unsigned long prom_args [23];		/* 0x18 */
+	char prom_buffer [3000];
+} p1275buf;
+
+extern void prom_world(int);
+
+extern void prom_cif_interface(void);
+extern void prom_cif_callback(void);
+
+static inline unsigned long spitfire_get_primary_context(void)
+{
+	unsigned long ctx;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (ctx)
+			     : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+	return ctx;
+}
+
+/*
+ * This provides SMP safety on the p1275buf. prom_callback() drops this lock
+ * to allow recursuve acquisition.
+ */
+DEFINE_SPINLOCK(prom_entry_lock);
+
+long p1275_cmd (char *service, long fmt, ...)
+{
+	char *p, *q;
+	unsigned long flags;
+	int nargs, nrets, i;
+	va_list list;
+	long attrs, x;
+	
+	p = p1275buf.prom_buffer;
+	BUG_ON((spitfire_get_primary_context() & CTX_NR_MASK) != 0);
+
+	spin_lock_irqsave(&prom_entry_lock, flags);
+
+	p1275buf.prom_args[0] = (unsigned long)p;		/* service */
+	strcpy (p, service);
+	p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
+	p1275buf.prom_args[1] = nargs = (fmt & 0x0f);		/* nargs */
+	p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); 	/* nrets */
+	attrs = fmt >> 8;
+	va_start(list, fmt);
+	for (i = 0; i < nargs; i++, attrs >>= 3) {
+		switch (attrs & 0x7) {
+		case P1275_ARG_NUMBER:
+			p1275buf.prom_args[i + 3] =
+						(unsigned)va_arg(list, long);
+			break;
+		case P1275_ARG_IN_64B:
+			p1275buf.prom_args[i + 3] =
+				va_arg(list, unsigned long);
+			break;
+		case P1275_ARG_IN_STRING:
+			strcpy (p, va_arg(list, char *));
+			p1275buf.prom_args[i + 3] = (unsigned long)p;
+			p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
+			break;
+		case P1275_ARG_OUT_BUF:
+			(void) va_arg(list, char *);
+			p1275buf.prom_args[i + 3] = (unsigned long)p;
+			x = va_arg(list, long);
+			i++; attrs >>= 3;
+			p = (char *)(((long)(p + (int)x + 7)) & ~7);
+			p1275buf.prom_args[i + 3] = x;
+			break;
+		case P1275_ARG_IN_BUF:
+			q = va_arg(list, char *);
+			p1275buf.prom_args[i + 3] = (unsigned long)p;
+			x = va_arg(list, long);
+			i++; attrs >>= 3;
+			memcpy (p, q, (int)x);
+			p = (char *)(((long)(p + (int)x + 7)) & ~7);
+			p1275buf.prom_args[i + 3] = x;
+			break;
+		case P1275_ARG_OUT_32B:
+			(void) va_arg(list, char *);
+			p1275buf.prom_args[i + 3] = (unsigned long)p;
+			p += 32;
+			break;
+		case P1275_ARG_IN_FUNCTION:
+			p1275buf.prom_args[i + 3] =
+					(unsigned long)prom_cif_callback;
+			p1275buf.prom_callback = va_arg(list, long);
+			break;
+		}
+	}
+	va_end(list);
+
+	prom_world(1);
+	prom_cif_interface();
+	prom_world(0);
+
+	attrs = fmt >> 8;
+	va_start(list, fmt);
+	for (i = 0; i < nargs; i++, attrs >>= 3) {
+		switch (attrs & 0x7) {
+		case P1275_ARG_NUMBER:
+			(void) va_arg(list, long);
+			break;
+		case P1275_ARG_IN_STRING:
+			(void) va_arg(list, char *);
+			break;
+		case P1275_ARG_IN_FUNCTION:
+			(void) va_arg(list, long);
+			break;
+		case P1275_ARG_IN_BUF:
+			(void) va_arg(list, char *);
+			(void) va_arg(list, long);
+			i++; attrs >>= 3;
+			break;
+		case P1275_ARG_OUT_BUF:
+			p = va_arg(list, char *);
+			x = va_arg(list, long);
+			memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x);
+			i++; attrs >>= 3;
+			break;
+		case P1275_ARG_OUT_32B:
+			p = va_arg(list, char *);
+			memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32);
+			break;
+		}
+	}
+	va_end(list);
+	x = p1275buf.prom_args [nargs + 3];
+
+	spin_unlock_irqrestore(&prom_entry_lock, flags);
+
+	return x;
+}
+
+void prom_cif_init(void *cif_handler, void *cif_stack)
+{
+	p1275buf.prom_cif_handler = (void (*)(long *))cif_handler;
+	p1275buf.prom_cif_stack = (unsigned long)cif_stack;
+}
diff --git a/arch/sparc64/prom/printf.c b/arch/sparc64/prom/printf.c
new file mode 100644
index 0000000..a6df82c
--- /dev/null
+++ b/arch/sparc64/prom/printf.c
@@ -0,0 +1,47 @@
+/*
+ * printf.c:  Internal prom library printf facility.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
+ *
+ * We used to warn all over the code: DO NOT USE prom_printf(),
+ * and yet people do. Anton's banking code was outputting banks
+ * with prom_printf for most of the 2.4 lifetime. Since an effective
+ * stick is not available, we deployed a carrot: an early printk
+ * through PROM by means of -p boot option. This ought to fix it.
+ * USE printk; if you need, deploy -p.
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+static char ppbuf[1024];
+
+void
+prom_write(const char *buf, unsigned int n)
+{
+	char ch;
+
+	while (n != 0) {
+		--n;
+		if ((ch = *buf++) == '\n')
+			prom_putchar('\r');
+		prom_putchar(ch);
+	}
+}
+
+void
+prom_printf(char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args);
+	va_end(args);
+
+	prom_write(ppbuf, i);
+}
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
new file mode 100644
index 0000000..ccf7325
--- /dev/null
+++ b/arch/sparc64/prom/tree.c
@@ -0,0 +1,377 @@
+/* $Id: tree.c,v 1.10 1998/01/10 22:39:00 ecd Exp $
+ * tree.c: Basic device tree traversal/scanning for the Linux
+ *         prom library.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Return the child of node 'node' or zero if no this node has no
+ * direct descendent.
+ */
+__inline__ int
+__prom_getchild(int node)
+{
+	return p1275_cmd ("child", P1275_INOUT(1, 1), node);
+}
+
+__inline__ int
+prom_getchild(int node)
+{
+	int cnode;
+
+	if(node == -1) return 0;
+	cnode = __prom_getchild(node);
+	if(cnode == -1) return 0;
+	return (int)cnode;
+}
+
+__inline__ int
+prom_getparent(int node)
+{
+	int cnode;
+
+	if(node == -1) return 0;
+	cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
+	if(cnode == -1) return 0;
+	return (int)cnode;
+}
+
+/* Return the next sibling of node 'node' or zero if no more siblings
+ * at this level of depth in the tree.
+ */
+__inline__ int
+__prom_getsibling(int node)
+{
+	return p1275_cmd ("peer", P1275_INOUT(1, 1), node);
+}
+
+__inline__ int
+prom_getsibling(int node)
+{
+	int sibnode;
+
+	if(node == -1) return 0;
+	sibnode = __prom_getsibling(node);
+	if(sibnode == -1) return 0;
+	return sibnode;
+}
+
+/* Return the length in bytes of property 'prop' at node 'node'.
+ * Return -1 on error.
+ */
+__inline__ int
+prom_getproplen(int node, char *prop)
+{
+	if((!node) || (!prop)) return -1;
+	return p1275_cmd ("getproplen", 
+			  P1275_ARG(1,P1275_ARG_IN_STRING)|
+			  P1275_INOUT(2, 1), 
+			  node, prop);
+}
+
+/* Acquire a property 'prop' at node 'node' and place it in
+ * 'buffer' which has a size of 'bufsize'.  If the acquisition
+ * was successful the length will be returned, else -1 is returned.
+ */
+__inline__ int
+prom_getproperty(int node, char *prop, char *buffer, int bufsize)
+{
+	int plen;
+
+	plen = prom_getproplen(node, prop);
+	if((plen > bufsize) || (plen == 0) || (plen == -1))
+		return -1;
+	else {
+		/* Ok, things seem all right. */
+		return p1275_cmd ("getprop", 
+				  P1275_ARG(1,P1275_ARG_IN_STRING)|
+				  P1275_ARG(2,P1275_ARG_OUT_BUF)|
+				  P1275_INOUT(4, 1), 
+				  node, prop, buffer, P1275_SIZE(plen));
+	}
+}
+
+/* Acquire an integer property and return its value.  Returns -1
+ * on failure.
+ */
+__inline__ int
+prom_getint(int node, char *prop)
+{
+	int intprop;
+
+	if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
+		return intprop;
+
+	return -1;
+}
+
+/* Acquire an integer property, upon error return the passed default
+ * integer.
+ */
+
+int
+prom_getintdefault(int node, char *property, int deflt)
+{
+	int retval;
+
+	retval = prom_getint(node, property);
+	if(retval == -1) return deflt;
+
+	return retval;
+}
+
+/* Acquire a boolean property, 1=TRUE 0=FALSE. */
+int
+prom_getbool(int node, char *prop)
+{
+	int retval;
+
+	retval = prom_getproplen(node, prop);
+	if(retval == -1) return 0;
+	return 1;
+}
+
+/* Acquire a property whose value is a string, returns a null
+ * string on error.  The char pointer is the user supplied string
+ * buffer.
+ */
+void
+prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
+{
+	int len;
+
+	len = prom_getproperty(node, prop, user_buf, ubuf_size);
+	if(len != -1) return;
+	user_buf[0] = 0;
+	return;
+}
+
+
+/* Does the device at node 'node' have name 'name'?
+ * YES = 1   NO = 0
+ */
+int
+prom_nodematch(int node, char *name)
+{
+	char namebuf[128];
+	prom_getproperty(node, "name", namebuf, sizeof(namebuf));
+	if(strcmp(namebuf, name) == 0) return 1;
+	return 0;
+}
+
+/* Search siblings at 'node_start' for a node with name
+ * 'nodename'.  Return node if successful, zero if not.
+ */
+int
+prom_searchsiblings(int node_start, char *nodename)
+{
+
+	int thisnode, error;
+	char promlib_buf[128];
+
+	for(thisnode = node_start; thisnode;
+	    thisnode=prom_getsibling(thisnode)) {
+		error = prom_getproperty(thisnode, "name", promlib_buf,
+					 sizeof(promlib_buf));
+		/* Should this ever happen? */
+		if(error == -1) continue;
+		if(strcmp(nodename, promlib_buf)==0) return thisnode;
+	}
+
+	return 0;
+}
+
+/* Gets name in the {name@x,yyyyy|name (if no reg)} form */
+int 
+prom_getname (int node, char *buffer, int len)
+{
+	int i, sbus = 0;
+	int pci = 0, ebus = 0, ide = 0;
+	struct linux_prom_registers *reg;
+	struct linux_prom64_registers reg64[PROMREG_MAX];
+	
+	for (sbus = prom_getparent (node); sbus; sbus = prom_getparent (sbus)) {
+		i = prom_getproperty (sbus, "name", buffer, len);
+		if (i > 0) {
+			buffer [i] = 0;
+			if (!strcmp (buffer, "sbus"))
+				goto getit;
+		}
+	}
+	if ((pci = prom_getparent (node))) {
+		i = prom_getproperty (pci, "name", buffer, len);
+		if (i > 0) {
+			buffer [i] = 0;
+			if (!strcmp (buffer, "pci"))
+				goto getit;
+		}
+		pci = 0;
+	}
+	if ((ebus = prom_getparent (node))) {
+		i = prom_getproperty (ebus, "name", buffer, len);
+		if (i > 0) {
+			buffer[i] = 0;
+			if (!strcmp (buffer, "ebus"))
+				goto getit;
+		}
+		ebus = 0;
+	}
+	if ((ide = prom_getparent (node))) {
+		i = prom_getproperty (ide, "name", buffer, len);
+		if (i > 0) {
+			buffer [i] = 0;
+			if (!strcmp (buffer, "ide"))
+				goto getit;
+		}
+		ide = 0;
+	}
+getit:
+	i = prom_getproperty (node, "name", buffer, len);
+	if (i <= 0) {
+		buffer [0] = 0;
+		return -1;
+	}
+	buffer [i] = 0;
+	len -= i;
+	i = prom_getproperty (node, "reg", (char *)reg64, sizeof (reg64));
+	if (i <= 0) return 0;
+	if (len < 16) return -1;
+	buffer = strchr (buffer, 0);
+	if (sbus) {
+		reg = (struct linux_prom_registers *)reg64;
+		sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr);
+	} else if (pci) {
+		int dev, fn;
+		reg = (struct linux_prom_registers *)reg64;
+		fn = (reg[0].which_io >> 8) & 0x07;
+		dev = (reg[0].which_io >> 11) & 0x1f;
+		if (fn)
+			sprintf (buffer, "@%x,%x", dev, fn);
+		else
+			sprintf (buffer, "@%x", dev);
+	} else if (ebus) {
+		reg = (struct linux_prom_registers *)reg64;
+		sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr);
+	} else if (ide) {
+		reg = (struct linux_prom_registers *)reg64;
+		sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr);
+	} else if (i == 4) {	/* Happens on 8042's children on Ultra/PCI. */
+		reg = (struct linux_prom_registers *)reg64;
+		sprintf (buffer, "@%x", reg[0].which_io);
+	} else {
+		sprintf (buffer, "@%x,%x",
+			 (unsigned int)(reg64[0].phys_addr >> 36),
+			 (unsigned int)(reg64[0].phys_addr));
+	}
+	return 0;
+}
+
+/* Return the first property type for node 'node'.
+ * buffer should be at least 32B in length
+ */
+__inline__ char *
+prom_firstprop(int node, char *buffer)
+{
+	*buffer = 0;
+	if(node == -1) return buffer;
+	p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)|
+			       P1275_INOUT(3, 0), 
+			       node, (char *) 0x0, buffer);
+	return buffer;
+}
+
+/* Return the property type string after property type 'oprop'
+ * at node 'node' .  Returns NULL string if no more
+ * property types for this node.
+ */
+__inline__ char *
+prom_nextprop(int node, char *oprop, char *buffer)
+{
+	char buf[32];
+
+	if(node == -1) {
+		*buffer = 0;
+		return buffer;
+	}
+	if (oprop == buffer) {
+		strcpy (buf, oprop);
+		oprop = buf;
+	}
+	p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
+				    P1275_ARG(2,P1275_ARG_OUT_32B)|
+				    P1275_INOUT(3, 0), 
+				    node, oprop, buffer); 
+	return buffer;
+}
+
+int
+prom_finddevice(char *name)
+{
+	if(!name) return 0;
+	return p1275_cmd ("finddevice", P1275_ARG(0,P1275_ARG_IN_STRING)|
+				        P1275_INOUT(1, 1), 
+				        name);
+}
+
+int prom_node_has_property(int node, char *prop)
+{
+	char buf [32];
+        
+	*buf = 0;
+	do {
+		prom_nextprop(node, buf, buf);
+		if(!strcmp(buf, prop))
+			return 1;
+	} while (*buf);
+	return 0;
+}
+                                                                                           
+/* Set property 'pname' at node 'node' to value 'value' which has a length
+ * of 'size' bytes.  Return the number of bytes the prom accepted.
+ */
+int
+prom_setprop(int node, char *pname, char *value, int size)
+{
+	if(size == 0) return 0;
+	if((pname == 0) || (value == 0)) return 0;
+	
+	return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
+					  P1275_ARG(2,P1275_ARG_IN_BUF)|
+					  P1275_INOUT(4, 1), 
+					  node, pname, value, P1275_SIZE(size));
+}
+
+__inline__ int
+prom_inst2pkg(int inst)
+{
+	int node;
+	
+	node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst);
+	if (node == -1) return 0;
+	return node;
+}
+
+/* Return 'node' assigned to a particular prom 'path'
+ * FIXME: Should work for v0 as well
+ */
+int
+prom_pathtoinode(char *path)
+{
+	int node, inst;
+
+	inst = prom_devopen (path);
+	if (inst == 0) return 0;
+	node = prom_inst2pkg (inst);
+	prom_devclose (inst);
+	if (node == -1) return 0;
+	return node;
+}