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/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile
new file mode 100644
index 0000000..373822e
--- /dev/null
+++ b/arch/mips/dec/prom/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the DECstation prom monitor library routines
+# under Linux.
+#
+
+lib-y			+= init.o memory.o cmdline.o identify.o console.o
+
+lib-$(CONFIG_MIPS32)	+= locore.o
+lib-$(CONFIG_MIPS64)	+= call_o32.o
+
+EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S
new file mode 100644
index 0000000..0dd56db
--- /dev/null
+++ b/arch/mips/dec/prom/call_o32.S
@@ -0,0 +1,91 @@
+/*
+ *	arch/mips/dec/call_o32.S
+ *
+ *	O32 interface for the 64 (or N32) ABI.
+ *
+ *	Copyright (C) 2002  Maciej W. Rozycki
+ *
+ *	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 <asm/asm.h>
+#include <asm/regdef.h>
+
+/* Maximum number of arguments supported.  Must be even!  */
+#define O32_ARGC	32
+/* Number of static registers we save.  */
+#define O32_STATC	11
+/* Frame size for both of the above.  */
+#define O32_FRAMESZ	(4 * O32_ARGC + SZREG * O32_STATC)
+
+		.text
+
+/*
+ * O32 function call dispatcher, for interfacing 32-bit ROM routines.
+ *
+ * The standard 64 (N32) calling sequence is supported, with a0
+ * holding a function pointer, a1-a7 -- its first seven arguments
+ * and the stack -- remaining ones (up to O32_ARGC, including a1-a7).
+ * Static registers, gp and fp are preserved, v0 holds a result.
+ * This code relies on the called o32 function for sp and ra
+ * restoration and thus both this dispatcher and the current stack
+ * have to be placed in a KSEGx (or KUSEG) address space.  Any
+ * pointers passed have to point to addresses within one of these
+ * spaces as well.
+ */
+NESTED(call_o32, O32_FRAMESZ, ra)
+		REG_SUBU	sp,O32_FRAMESZ
+
+		REG_S		ra,O32_FRAMESZ-1*SZREG(sp)
+		REG_S		fp,O32_FRAMESZ-2*SZREG(sp)
+		REG_S		gp,O32_FRAMESZ-3*SZREG(sp)
+		REG_S		s7,O32_FRAMESZ-4*SZREG(sp)
+		REG_S		s6,O32_FRAMESZ-5*SZREG(sp)
+		REG_S		s5,O32_FRAMESZ-6*SZREG(sp)
+		REG_S		s4,O32_FRAMESZ-7*SZREG(sp)
+		REG_S		s3,O32_FRAMESZ-8*SZREG(sp)
+		REG_S		s2,O32_FRAMESZ-9*SZREG(sp)
+		REG_S		s1,O32_FRAMESZ-10*SZREG(sp)
+		REG_S		s0,O32_FRAMESZ-11*SZREG(sp)
+
+		move		jp,a0
+
+		sll		a0,a1,zero
+		sll		a1,a2,zero
+		sll		a2,a3,zero
+		sll		a3,a4,zero
+		sw		a5,0x10(sp)
+		sw		a6,0x14(sp)
+		sw		a7,0x18(sp)
+
+		PTR_LA		t0,O32_FRAMESZ(sp)
+		PTR_LA		t1,0x1c(sp)
+		li		t2,O32_ARGC-7
+1:
+		lw		t3,(t0)
+		REG_ADDU	t0,SZREG
+		sw		t3,(t1)
+		REG_SUBU	t2,1
+		REG_ADDU	t1,4
+		bnez		t2,1b
+
+		jalr		jp
+
+		REG_L		s0,O32_FRAMESZ-11*SZREG(sp)
+		REG_L		s1,O32_FRAMESZ-10*SZREG(sp)
+		REG_L		s2,O32_FRAMESZ-9*SZREG(sp)
+		REG_L		s3,O32_FRAMESZ-8*SZREG(sp)
+		REG_L		s4,O32_FRAMESZ-7*SZREG(sp)
+		REG_L		s5,O32_FRAMESZ-6*SZREG(sp)
+		REG_L		s6,O32_FRAMESZ-5*SZREG(sp)
+		REG_L		s7,O32_FRAMESZ-4*SZREG(sp)
+		REG_L		gp,O32_FRAMESZ-3*SZREG(sp)
+		REG_L		fp,O32_FRAMESZ-2*SZREG(sp)
+		REG_L		ra,O32_FRAMESZ-1*SZREG(sp)
+
+		REG_ADDU	sp,O32_FRAMESZ
+		jr		ra
+END(call_o32)
diff --git a/arch/mips/dec/prom/cmdline.c b/arch/mips/dec/prom/cmdline.c
new file mode 100644
index 0000000..c3490be
--- /dev/null
+++ b/arch/mips/dec/prom/cmdline.c
@@ -0,0 +1,39 @@
+/*
+ * cmdline.c: read the command line passed to us by the PROM.
+ *
+ * Copyright (C) 1998 Harald Koerfgen
+ * Copyright (C) 2002, 2004  Maciej W. Rozycki
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/bootinfo.h>
+#include <asm/dec/prom.h>
+
+#undef PROM_DEBUG
+
+void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic)
+{
+	char *arg;
+	int start_arg, i;
+
+	/*
+	 * collect args and prepare cmd_line
+	 */
+	if (!prom_is_rex(magic))
+		start_arg = 1;
+	else
+		start_arg = 2;
+	for (i = start_arg; i < argc; i++) {
+		arg = (void *)(long)(argv[i]);
+		strcat(arcs_cmdline, arg);
+		if (i < (argc - 1))
+			strcat(arcs_cmdline, " ");
+	}
+
+#ifdef PROM_DEBUG
+	printk("arcs_cmdline: %s\n", &(arcs_cmdline[0]));
+#endif
+}
diff --git a/arch/mips/dec/prom/console.c b/arch/mips/dec/prom/console.c
new file mode 100644
index 0000000..cade16e
--- /dev/null
+++ b/arch/mips/dec/prom/console.c
@@ -0,0 +1,55 @@
+/*
+ *	arch/mips/dec/prom/console.c
+ *
+ *	DECstation PROM-based early console support.
+ *
+ *	Copyright (C) 2004  Maciej W. Rozycki
+ *
+ *	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/console.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/dec/prom.h>
+
+static void __init prom_console_write(struct console *con, const char *s,
+				      unsigned int c)
+{
+	static char sfmt[] __initdata = "%%%us";
+	char fmt[13];
+
+	snprintf(fmt, sizeof(fmt), sfmt, c);
+	prom_printf(fmt, s);
+}
+
+static struct console promcons __initdata = {
+	.name	= "prom",
+	.write	= prom_console_write,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
+};
+
+static int promcons_output __initdata = 0;
+
+void __init register_prom_console(void)
+{
+	if (!promcons_output) {
+		promcons_output = 1;
+		register_console(&promcons);
+	}
+}
+
+void __init unregister_prom_console(void)
+{
+	if (promcons_output) {
+		unregister_console(&promcons);
+		promcons_output = 0;
+	}
+}
+
+void disable_early_printk(void)
+	__attribute__((alias("unregister_prom_console")));
diff --git a/arch/mips/dec/prom/dectypes.h b/arch/mips/dec/prom/dectypes.h
new file mode 100644
index 0000000..707b6f1
--- /dev/null
+++ b/arch/mips/dec/prom/dectypes.h
@@ -0,0 +1,14 @@
+#ifndef DECTYPES
+#define	DECTYPES
+
+#define DS2100_3100	1	/* DS2100/3100	Pmax		*/
+#define DS5000_200	2	/* DS5000/200	3max		*/
+#define DS5000_1XX	3	/* DS5000/1xx	kmin		*/
+#define DS5000_2X0	4	/* DS5000/2x0	3max+		*/
+#define DS5800		5	/* DS5800	Isis		*/
+#define DS5400		6	/* DS5400	MIPSfair	*/
+#define DS5000_XX	7	/* DS5000/xx	maxine		*/
+#define DS5500		11	/* DS5500	MIPSfair-2	*/
+#define DS5100		12	/* DS5100	MIPSmate	*/
+
+#endif
diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c
new file mode 100644
index 0000000..9380588
--- /dev/null
+++ b/arch/mips/dec/prom/identify.c
@@ -0,0 +1,177 @@
+/*
+ * identify.c: machine identification code.
+ *
+ * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine
+ * Copyright (C) 2002, 2003, 2004  Maciej W. Rozycki
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mc146818rtc.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/bootinfo.h>
+#include <asm/dec/ioasic.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/kn02ba.h>
+#include <asm/dec/kn02ca.h>
+#include <asm/dec/kn03.h>
+#include <asm/dec/kn230.h>
+#include <asm/dec/prom.h>
+
+#include "dectypes.h"
+
+extern unsigned long mips_machgroup;
+extern unsigned long mips_machtype;
+
+static const char *dec_system_strings[] = {
+	[MACH_DSUNKNOWN]	"unknown DECstation",
+	[MACH_DS23100]		"DECstation 2100/3100",
+	[MACH_DS5100]		"DECsystem 5100",
+	[MACH_DS5000_200]	"DECstation 5000/200",
+	[MACH_DS5000_1XX]	"DECstation 5000/1xx",
+	[MACH_DS5000_XX]	"Personal DECstation 5000/xx",
+	[MACH_DS5000_2X0]	"DECstation 5000/2x0",
+	[MACH_DS5400]		"DECsystem 5400",
+	[MACH_DS5500]		"DECsystem 5500",
+	[MACH_DS5800]		"DECsystem 5800",
+	[MACH_DS5900]		"DECsystem 5900",
+};
+
+const char *get_system_type(void)
+{
+#define STR_BUF_LEN	64
+	static char system[STR_BUF_LEN];
+	static int called = 0;
+
+	if (called == 0) {
+		called = 1;
+		snprintf(system, STR_BUF_LEN, "Digital %s",
+			 dec_system_strings[mips_machtype]);
+	}
+
+	return system;
+}
+
+
+/*
+ * Setup essential system-specific memory addresses.  We need them
+ * early.  Semantically the functions belong to prom/init.c, but they
+ * are compact enough we want them inlined. --macro
+ */
+volatile u8 *dec_rtc_base;
+
+EXPORT_SYMBOL(dec_rtc_base);
+
+static inline void prom_init_kn01(void)
+{
+	dec_rtc_base = (void *)KN01_RTC_BASE;
+	dec_kn_slot_size = KN01_SLOT_SIZE;
+}
+
+static inline void prom_init_kn230(void)
+{
+	dec_rtc_base = (void *)KN01_RTC_BASE;
+	dec_kn_slot_size = KN01_SLOT_SIZE;
+}
+
+static inline void prom_init_kn02(void)
+{
+	dec_rtc_base = (void *)KN02_RTC_BASE;
+	dec_kn_slot_size = KN02_SLOT_SIZE;
+}
+
+static inline void prom_init_kn02xa(void)
+{
+	ioasic_base = (void *)KN02XA_IOASIC_BASE;
+	dec_rtc_base = (void *)KN02XA_RTC_BASE;
+	dec_kn_slot_size = IOASIC_SLOT_SIZE;
+}
+
+static inline void prom_init_kn03(void)
+{
+	ioasic_base = (void *)KN03_IOASIC_BASE;
+	dec_rtc_base = (void *)KN03_RTC_BASE;
+	dec_kn_slot_size = IOASIC_SLOT_SIZE;
+}
+
+
+void __init prom_identify_arch(u32 magic)
+{
+	unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype;
+	u32 dec_sysid;
+
+	if (!prom_is_rex(magic)) {
+		dec_sysid = simple_strtoul(prom_getenv("systype"),
+					   (char **)0, 0);
+	} else {
+		dec_sysid = rex_getsysid();
+		if (dec_sysid == 0) {
+			printk("Zero sysid returned from PROM! "
+			       "Assuming a PMAX-like machine.\n");
+			dec_sysid = 1;
+		}
+	}
+
+	dec_cpunum = (dec_sysid & 0xff000000) >> 24;
+	dec_systype = (dec_sysid & 0xff0000) >> 16;
+	dec_firmrev = (dec_sysid & 0xff00) >> 8;
+	dec_etc = dec_sysid & 0xff;
+
+	/* We're obviously one of the DEC machines */
+	mips_machgroup = MACH_GROUP_DEC;
+
+	/*
+	 * FIXME: This may not be an exhaustive list of DECStations/Servers!
+	 * Put all model-specific initialisation calls here.
+	 */
+	switch (dec_systype) {
+	case DS2100_3100:
+		mips_machtype = MACH_DS23100;
+		prom_init_kn01();
+		break;
+	case DS5100:		/* DS5100 MIPSMATE */
+		mips_machtype = MACH_DS5100;
+		prom_init_kn230();
+		break;
+	case DS5000_200:	/* DS5000 3max */
+		mips_machtype = MACH_DS5000_200;
+		prom_init_kn02();
+		break;
+	case DS5000_1XX:	/* DS5000/100 3min */
+		mips_machtype = MACH_DS5000_1XX;
+		prom_init_kn02xa();
+		break;
+	case DS5000_2X0:	/* DS5000/240 3max+ or DS5900 bigmax */
+		mips_machtype = MACH_DS5000_2X0;
+		prom_init_kn03();
+		if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP))
+			mips_machtype = MACH_DS5900;
+		break;
+	case DS5000_XX:		/* Personal DS5000/xx maxine */
+		mips_machtype = MACH_DS5000_XX;
+		prom_init_kn02xa();
+		break;
+	case DS5800:		/* DS5800 Isis */
+		mips_machtype = MACH_DS5800;
+		break;
+	case DS5400:		/* DS5400 MIPSfair */
+		mips_machtype = MACH_DS5400;
+		break;
+	case DS5500:		/* DS5500 MIPSfair-2 */
+		mips_machtype = MACH_DS5500;
+		break;
+	default:
+		mips_machtype = MACH_DSUNKNOWN;
+		break;
+	}
+
+	if (mips_machtype == MACH_DSUNKNOWN)
+		printk("This is an %s, id is %x\n",
+		       dec_system_strings[mips_machtype], dec_systype);
+	else
+		printk("This is a %s\n", dec_system_strings[mips_machtype]);
+}
diff --git a/arch/mips/dec/prom/init.c b/arch/mips/dec/prom/init.c
new file mode 100644
index 0000000..60f7425
--- /dev/null
+++ b/arch/mips/dec/prom/init.c
@@ -0,0 +1,134 @@
+/*
+ * init.c: PROM library initialisation code.
+ *
+ * Copyright (C) 1998 Harald Koerfgen
+ * Copyright (C) 2002, 2004  Maciej W. Rozycki
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/processor.h>
+
+#include <asm/dec/prom.h>
+
+
+int (*__rex_bootinit)(void);
+int (*__rex_bootread)(void);
+int (*__rex_getbitmap)(memmap *);
+unsigned long *(*__rex_slot_address)(int);
+void *(*__rex_gettcinfo)(void);
+int (*__rex_getsysid)(void);
+void (*__rex_clear_cache)(void);
+
+int (*__prom_getchar)(void);
+char *(*__prom_getenv)(char *);
+int (*__prom_printf)(char *, ...);
+
+int (*__pmax_open)(char*, int);
+int (*__pmax_lseek)(int, long, int);
+int (*__pmax_read)(int, void *, int);
+int (*__pmax_close)(int);
+
+
+/*
+ * Detect which PROM the DECSTATION has, and set the callback vectors
+ * appropriately.
+ */
+void __init which_prom(s32 magic, s32 *prom_vec)
+{
+	/*
+	 * No sign of the REX PROM's magic number means we assume a non-REX
+	 * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx)
+	 */
+	if (prom_is_rex(magic)) {
+		/*
+		 * Set up prom abstraction structure with REX entry points.
+		 */
+		__rex_bootinit =
+			(void *)(long)*(prom_vec + REX_PROM_BOOTINIT);
+		__rex_bootread =
+			(void *)(long)*(prom_vec + REX_PROM_BOOTREAD);
+		__rex_getbitmap =
+			(void *)(long)*(prom_vec + REX_PROM_GETBITMAP);
+		__prom_getchar =
+			(void *)(long)*(prom_vec + REX_PROM_GETCHAR);
+		__prom_getenv =
+			(void *)(long)*(prom_vec + REX_PROM_GETENV);
+		__rex_getsysid =
+			(void *)(long)*(prom_vec + REX_PROM_GETSYSID);
+		__rex_gettcinfo =
+			(void *)(long)*(prom_vec + REX_PROM_GETTCINFO);
+		__prom_printf =
+			(void *)(long)*(prom_vec + REX_PROM_PRINTF);
+		__rex_slot_address =
+			(void *)(long)*(prom_vec + REX_PROM_SLOTADDR);
+		__rex_clear_cache =
+			(void *)(long)*(prom_vec + REX_PROM_CLEARCACHE);
+	} else {
+		/*
+		 * Set up prom abstraction structure with non-REX entry points.
+		 */
+		__prom_getchar = (void *)PMAX_PROM_GETCHAR;
+		__prom_getenv = (void *)PMAX_PROM_GETENV;
+		__prom_printf = (void *)PMAX_PROM_PRINTF;
+		__pmax_open = (void *)PMAX_PROM_OPEN;
+		__pmax_lseek = (void *)PMAX_PROM_LSEEK;
+		__pmax_read = (void *)PMAX_PROM_READ;
+		__pmax_close = (void *)PMAX_PROM_CLOSE;
+	}
+}
+
+void __init prom_init(void)
+{
+	extern void dec_machine_halt(void);
+	static char cpu_msg[] __initdata =
+		"Sorry, this kernel is compiled for a wrong CPU type!\n";
+	static char r3k_msg[] __initdata =
+		"Please recompile with \"CONFIG_CPU_R3000 = y\".\n";
+	static char r4k_msg[] __initdata =
+		"Please recompile with \"CONFIG_CPU_R4x00 = y\".\n";
+	s32 argc = fw_arg0;
+	s32 argv = fw_arg1;
+	u32 magic = fw_arg2;
+	s32 prom_vec = fw_arg3;
+
+	/*
+	 * Determine which PROM we have
+	 * (and therefore which machine we're on!)
+	 */
+	which_prom(magic, prom_vec);
+
+	if (prom_is_rex(magic))
+		rex_clear_cache();
+
+	/* Register the early console.  */
+	register_prom_console();
+
+	/* Were we compiled with the right CPU option? */
+#if defined(CONFIG_CPU_R3000)
+	if ((current_cpu_data.cputype == CPU_R4000SC) ||
+	    (current_cpu_data.cputype == CPU_R4400SC)) {
+		printk(cpu_msg);
+		printk(r4k_msg);
+		dec_machine_halt();
+	}
+#endif
+
+#if defined(CONFIG_CPU_R4X00)
+	if ((current_cpu_data.cputype == CPU_R3000) ||
+	    (current_cpu_data.cputype == CPU_R3000A)) {
+		printk(cpu_msg);
+		printk(r3k_msg);
+		dec_machine_halt();
+	}
+#endif
+
+	prom_meminit(magic);
+	prom_identify_arch(magic);
+	prom_init_cmdline(argc, argv, magic);
+}
diff --git a/arch/mips/dec/prom/locore.S b/arch/mips/dec/prom/locore.S
new file mode 100644
index 0000000..d9acdce
--- /dev/null
+++ b/arch/mips/dec/prom/locore.S
@@ -0,0 +1,30 @@
+/*
+ * locore.S
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+
+	.text
+
+/*
+ * Simple general exception handling routine. This one is used for the
+ * Memory sizing routine for pmax machines. HK
+ */
+
+NESTED(genexcept_early, 0, sp)
+	.set	noat
+	.set	noreorder
+
+	mfc0	k0, CP0_STATUS
+	la	k1, mem_err
+
+	sw	k0, 0(k1)
+
+	mfc0	k0, CP0_EPC
+	nop
+	addiu	k0, 4		# skip the causing instruction
+	jr	k0
+	 rfe
+END(genexcept_early)
+
diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c
new file mode 100644
index 0000000..e4f6f26
--- /dev/null
+++ b/arch/mips/dec/prom/memory.c
@@ -0,0 +1,130 @@
+/*
+ * memory.c: memory initialisation code.
+ *
+ * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine
+ * Copyright (C) 2000, 2002  Maciej W. Rozycki
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/prom.h>
+#include <asm/page.h>
+#include <asm/sections.h>
+
+
+volatile unsigned long mem_err = 0;	/* So we know an error occurred */
+
+/*
+ * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen
+ * off the end of real memory.  Only suitable for the 2100/3100's (PMAX).
+ */
+
+#define CHUNK_SIZE 0x400000
+
+static inline void pmax_setup_memory_region(void)
+{
+	volatile unsigned char *memory_page, dummy;
+	char old_handler[0x80];
+	extern char genexcept_early;
+
+	/* Install exception handler */
+	memcpy(&old_handler, (void *)(KSEG0 + 0x80), 0x80);
+	memcpy((void *)(KSEG0 + 0x80), &genexcept_early, 0x80);
+
+	/* read unmapped and uncached (KSEG1)
+	 * DECstations have at least 4MB RAM
+	 * Assume less than 480MB of RAM, as this is max for 5000/2xx
+	 * FIXME this should be replaced by the first free page!
+	 */
+	for (memory_page = (unsigned char *) KSEG1 + CHUNK_SIZE;
+	     (mem_err== 0) && (memory_page < ((unsigned char *) KSEG1+0x1E000000));
+  	     memory_page += CHUNK_SIZE) {
+		dummy = *memory_page;
+	}
+	memcpy((void *)(KSEG0 + 0x80), &old_handler, 0x80);
+
+	add_memory_region(0, (unsigned long)memory_page - KSEG1 - CHUNK_SIZE,
+			  BOOT_MEM_RAM);
+}
+
+/*
+ * Use the REX prom calls to get hold of the memory bitmap, and thence
+ * determine memory size.
+ */
+static inline void rex_setup_memory_region(void)
+{
+	int i, bitmap_size;
+	unsigned long mem_start = 0, mem_size = 0;
+	memmap *bm;
+
+	/* some free 64k */
+	bm = (memmap *)KSEG0ADDR(0x28000);
+
+	bitmap_size = rex_getbitmap(bm);
+
+	for (i = 0; i < bitmap_size; i++) {
+		/* FIXME: very simplistically only add full sets of pages */
+		if (bm->bitmap[i] == 0xff)
+			mem_size += (8 * bm->pagesize);
+		else if (!mem_size)
+			mem_start += (8 * bm->pagesize);
+		else {
+			add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
+			mem_start += mem_size + (8 * bm->pagesize);
+			mem_size = 0;
+		}
+	}
+	if (mem_size)
+		add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
+}
+
+void __init prom_meminit(u32 magic)
+{
+	if (!prom_is_rex(magic))
+		pmax_setup_memory_region();
+	else
+		rex_setup_memory_region();
+}
+
+unsigned long __init prom_free_prom_memory(void)
+{
+	unsigned long addr, end;
+
+	/*
+	 * Free everything below the kernel itself but leave
+	 * the first page reserved for the exception handlers.
+	 */
+
+#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE)
+	/*
+	 * Leave 128 KB reserved for Lance memory for
+	 * IOASIC DECstations.
+	 *
+	 * XXX: save this address for use in dec_lance.c?
+	 */
+	if (IOASIC)
+		end = __pa(&_text) - 0x00020000;
+	else
+#endif
+		end = __pa(&_text);
+
+	addr = PAGE_SIZE;
+	while (addr < end) {
+		ClearPageReserved(virt_to_page(__va(addr)));
+		set_page_count(virt_to_page(__va(addr)), 1);
+		free_page((unsigned long)__va(addr));
+		addr += PAGE_SIZE;
+	}
+
+	printk("Freeing unused PROM memory: %ldk freed\n",
+	       (end - PAGE_SIZE) >> 10);
+
+	return end - PAGE_SIZE;
+}