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/sgi-ip32/Makefile b/arch/mips/sgi-ip32/Makefile
new file mode 100644
index 0000000..470898f
--- /dev/null
+++ b/arch/mips/sgi-ip32/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the SGI specific kernel interface routines
+# under Linux.
+#
+
+obj-y	+= ip32-berr.o ip32-irq.o ip32-irq-glue.o ip32-setup.o ip32-reset.o \
+	   crime.o ip32-memory.o
+
+EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c
new file mode 100644
index 0000000..eb3a16a
--- /dev/null
+++ b/arch/mips/sgi-ip32/crime.c
@@ -0,0 +1,103 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001, 2003 Keith M Wesolowski
+ * Copyright (C) 2005 Ilya A. Volynets <ilya@total-knowledge.com>
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/mace.h>
+
+struct sgi_crime *crime;
+struct sgi_mace *mace;
+
+void __init crime_init(void)
+{
+	unsigned int id, rev;
+	const int field = 2 * sizeof(unsigned long);
+
+	set_io_port_base((unsigned long) ioremap(MACEPCI_LOW_IO, 0x2000000));
+	crime = ioremap(CRIME_BASE, sizeof(struct sgi_crime));
+	mace = ioremap(MACE_BASE, sizeof(struct sgi_mace));
+
+	id = crime->id;
+	rev = id & CRIME_ID_REV;
+	id = (id & CRIME_ID_IDBITS) >> 4;
+	printk (KERN_INFO "CRIME id %1x rev %d at 0x%0*lx\n",
+		id, rev, field, (unsigned long) CRIME_BASE);
+}
+
+irqreturn_t
+crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long stat, addr;
+	int fatal = 0;
+
+	stat = crime->mem_error_stat & CRIME_MEM_ERROR_STAT_MASK;
+	addr = crime->mem_error_addr & CRIME_MEM_ERROR_ADDR_MASK;
+
+	printk("CRIME memory error at 0x%08lx ST 0x%08lx<", addr, stat);
+
+	if (stat & CRIME_MEM_ERROR_INV)
+		printk("INV,");
+	if (stat & CRIME_MEM_ERROR_ECC) {
+		unsigned long ecc_syn =
+			crime->mem_ecc_syn & CRIME_MEM_ERROR_ECC_SYN_MASK;
+		unsigned long ecc_gen =
+			crime->mem_ecc_chk & CRIME_MEM_ERROR_ECC_CHK_MASK;
+		printk("ECC,SYN=0x%08lx,GEN=0x%08lx,", ecc_syn, ecc_gen);
+	}
+	if (stat & CRIME_MEM_ERROR_MULTIPLE) {
+		fatal = 1;
+		printk("MULTIPLE,");
+	}
+	if (stat & CRIME_MEM_ERROR_HARD_ERR) {
+		fatal = 1;
+		printk("HARD,");
+	}
+	if (stat & CRIME_MEM_ERROR_SOFT_ERR)
+		printk("SOFT,");
+	if (stat & CRIME_MEM_ERROR_CPU_ACCESS)
+		printk("CPU,");
+	if (stat & CRIME_MEM_ERROR_VICE_ACCESS)
+		printk("VICE,");
+	if (stat & CRIME_MEM_ERROR_GBE_ACCESS)
+		printk("GBE,");
+	if (stat & CRIME_MEM_ERROR_RE_ACCESS)
+		printk("RE,REID=0x%02lx,", (stat & CRIME_MEM_ERROR_RE_ID)>>8);
+	if (stat & CRIME_MEM_ERROR_MACE_ACCESS)
+		printk("MACE,MACEID=0x%02lx,", stat & CRIME_MEM_ERROR_MACE_ID);
+
+	crime->mem_error_stat = 0;
+
+	if (fatal) {
+		printk("FATAL>\n");
+		panic("Fatal memory error.");
+	} else
+		printk("NONFATAL>\n");
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t
+crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
+	unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
+
+	addr <<= 2;
+	printk ("CRIME CPU error at 0x%09lx status 0x%08lx\n", addr, stat);
+	crime->cpu_error_stat = 0;
+
+	return IRQ_HANDLED;
+}
diff --git a/arch/mips/sgi-ip32/ip32-berr.c b/arch/mips/sgi-ip32/ip32-berr.c
new file mode 100644
index 0000000..a278e91
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-berr.c
@@ -0,0 +1,36 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 by Silicon Graphics
+ * Copyright (C) 2002  Maciej W. Rozycki
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+#include <asm/ptrace.h>
+#include <asm/tlbdebug.h>
+
+int ip32_be_handler(struct pt_regs *regs, int is_fixup)
+{
+	int data = regs->cp0_cause & 4;
+
+	if (is_fixup)
+		return MIPS_BE_FIXUP;
+
+	printk("Got %cbe at 0x%lx\n", data ? 'd' : 'i', regs->cp0_epc);
+	show_regs(regs);
+	dump_tlb_all();
+	while(1);
+	force_sig(SIGBUS, current);
+}
+
+void __init ip32_be_init(void)
+{
+	board_be_handler = ip32_be_handler;
+}
diff --git a/arch/mips/sgi-ip32/ip32-irq-glue.S b/arch/mips/sgi-ip32/ip32-irq-glue.S
new file mode 100644
index 0000000..200924e
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-irq-glue.S
@@ -0,0 +1,86 @@
+/*
+ * Low level interrupt handler for the SGI O2 aka IP32 aka Moosehead
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Harald Koerfgen
+ * Copyright (C) 2001 Keith M Wesolowski
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/addrspace.h>
+
+		.text
+		.set    noreorder
+		.set    noat
+		.align  5
+		NESTED(ip32_handle_int, PT_SIZE, ra)
+		.set    noat
+		SAVE_ALL
+		CLI			# TEST: interrupts should be off
+		.set    at
+		.set    noreorder
+
+		mfc0	s0,CP0_CAUSE
+
+		andi	t1, s0, IE_IRQ0
+		bnez	t1, handle_irq0
+		 andi	t1, s0, IE_IRQ1
+		bnez	t1, handle_irq1
+		 andi	t1, s0, IE_IRQ2
+		bnez	t1, handle_irq2
+		 andi	t1, s0, IE_IRQ3
+		bnez	t1, handle_irq3
+		 andi	t1, s0, IE_IRQ4
+		bnez	t1, handle_irq4
+		 andi	t1, s0, IE_IRQ5
+		bnez	t1, handle_irq5
+		 nop
+
+		/* Either someone has triggered the "software interrupts"
+		 * or we lost an interrupt somehow.  Ignore it.
+		 */
+		j	ret_from_irq
+		 nop
+
+handle_irq0:
+		jal	ip32_irq0
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq1:
+		jal	ip32_irq1
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq2:
+		jal	ip32_irq2
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq3:
+		jal	ip32_irq3
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq4:
+		jal	ip32_irq4
+		 move	a0, sp
+		j	ret_from_irq
+		 nop
+
+handle_irq5:
+		jal	ip32_irq5
+		move	a0, sp
+		j	ret_from_irq
+		 nop
+
+		END(ip32_handle_int)
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
new file mode 100644
index 0000000..fc3a8e9
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -0,0 +1,590 @@
+/*
+ * Code to handle IP32 IRQs
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Harald Koerfgen
+ * Copyright (C) 2001 Keith M Wesolowski
+ */
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+
+#include <asm/mipsregs.h>
+#include <asm/signal.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/ip32_ints.h>
+
+/* issue a PIO read to make sure no PIO writes are pending */
+static void inline flush_crime_bus(void)
+{
+	volatile unsigned long junk = crime->control;
+}
+
+static void inline flush_mace_bus(void)
+{
+	volatile unsigned long junk = mace->perif.ctrl.misc;
+}
+
+#undef DEBUG_IRQ
+#ifdef DEBUG_IRQ
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* O2 irq map
+ *
+ * IP0 -> software (ignored)
+ * IP1 -> software (ignored)
+ * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ???
+ * IP3 -> (irq1) X unknown
+ * IP4 -> (irq2) X unknown
+ * IP5 -> (irq3) X unknown
+ * IP6 -> (irq4) X unknown
+ * IP7 -> (irq5) 0 CPU count/compare timer (system timer)
+ *
+ * crime: (C)
+ *
+ * CRIME_INT_STAT 31:0:
+ *
+ * 0  -> 1  Video in 1
+ * 1  -> 2  Video in 2
+ * 2  -> 3  Video out
+ * 3  -> 4  Mace ethernet
+ * 4  -> S  SuperIO sub-interrupt
+ * 5  -> M  Miscellaneous sub-interrupt
+ * 6  -> A  Audio sub-interrupt
+ * 7  -> 8  PCI bridge errors
+ * 8  -> 9  PCI SCSI aic7xxx 0
+ * 9  -> 10 PCI SCSI aic7xxx 1
+ * 10 -> 11 PCI slot 0
+ * 11 -> 12 unused (PCI slot 1)
+ * 12 -> 13 unused (PCI slot 2)
+ * 13 -> 14 unused (PCI shared 0)
+ * 14 -> 15 unused (PCI shared 1)
+ * 15 -> 16 unused (PCI shared 2)
+ * 16 -> 17 GBE0 (E)
+ * 17 -> 18 GBE1 (E)
+ * 18 -> 19 GBE2 (E)
+ * 19 -> 20 GBE3 (E)
+ * 20 -> 21 CPU errors
+ * 21 -> 22 Memory errors
+ * 22 -> 23 RE empty edge (E)
+ * 23 -> 24 RE full edge (E)
+ * 24 -> 25 RE idle edge (E)
+ * 25 -> 26 RE empty level
+ * 26 -> 27 RE full level
+ * 27 -> 28 RE idle level
+ * 28 -> 29 unused (software 0) (E)
+ * 29 -> 30 unused (software 1) (E)
+ * 30 -> 31 unused (software 2) - crime 1.5 CPU SysCorError (E)
+ * 31 -> 32 VICE
+ *
+ * S, M, A: Use the MACE ISA interrupt register
+ * MACE_ISA_INT_STAT 31:0
+ *
+ * 0-7 -> 33-40 Audio
+ * 8 -> 41 RTC
+ * 9 -> 42 Keyboard
+ * 10 -> X Keyboard polled
+ * 11 -> 44 Mouse
+ * 12 -> X Mouse polled
+ * 13-15 -> 46-48 Count/compare timers
+ * 16-19 -> 49-52 Parallel (16 E)
+ * 20-25 -> 53-58 Serial 1 (22 E)
+ * 26-31 -> 59-64 Serial 2 (28 E)
+ *
+ * Note that this means IRQs 5-7, 43, and 45 do not exist.  This is a
+ * different IRQ map than IRIX uses, but that's OK as Linux irq handling
+ * is quite different anyway.
+ */
+
+/*
+ * IRQ spinlock - Ralf says not to disable CPU interrupts,
+ * and I think he knows better.
+ */
+static DEFINE_SPINLOCK(ip32_irq_lock);
+
+/* Some initial interrupts to set up */
+extern irqreturn_t crime_memerr_intr (int irq, void *dev_id,
+				      struct pt_regs *regs);
+extern irqreturn_t crime_cpuerr_intr (int irq, void *dev_id,
+				      struct pt_regs *regs);
+
+struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT,
+			CPU_MASK_NONE, "CRIME memory error", NULL, NULL };
+struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT,
+			CPU_MASK_NONE, "CRIME CPU error", NULL, NULL };
+
+extern void ip32_handle_int(void);
+
+/*
+ * For interrupts wired from a single device to the CPU.  Only the clock
+ * uses this it seems, which is IRQ 0 and IP7.
+ */
+
+static void enable_cpu_irq(unsigned int irq)
+{
+	set_c0_status(STATUSF_IP7);
+}
+
+static unsigned int startup_cpu_irq(unsigned int irq)
+{
+	enable_cpu_irq(irq);
+	return 0;
+}
+
+static void disable_cpu_irq(unsigned int irq)
+{
+	clear_c0_status(STATUSF_IP7);
+}
+
+static void end_cpu_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_cpu_irq (irq);
+}
+
+#define shutdown_cpu_irq disable_cpu_irq
+#define mask_and_ack_cpu_irq disable_cpu_irq
+
+static struct hw_interrupt_type ip32_cpu_interrupt = {
+	"IP32 CPU",
+	startup_cpu_irq,
+	shutdown_cpu_irq,
+	enable_cpu_irq,
+	disable_cpu_irq,
+	mask_and_ack_cpu_irq,
+	end_cpu_irq,
+	NULL
+};
+
+/*
+ * This is for pure CRIME interrupts - ie not MACE.  The advantage?
+ * We get to split the register in half and do faster lookups.
+ */
+
+static uint64_t crime_mask;
+
+static void enable_crime_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	crime_mask |= 1 << (irq - 1);
+	crime->imask = crime_mask;
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static unsigned int startup_crime_irq(unsigned int irq)
+{
+	enable_crime_irq(irq);
+	return 0; /* This is probably not right; we could have pending irqs */
+}
+
+static void disable_crime_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	crime_mask &= ~(1 << (irq - 1));
+	crime->imask = crime_mask;
+	flush_crime_bus();
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static void mask_and_ack_crime_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	/* Edge triggered interrupts must be cleared. */
+	if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ)
+	    || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ)
+	    || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) {
+	        uint64_t crime_int;
+		spin_lock_irqsave(&ip32_irq_lock, flags);
+		crime_int = crime->hard_int;
+		crime_int &= ~(1 << (irq - 1));
+		crime->hard_int = crime_int;
+		spin_unlock_irqrestore(&ip32_irq_lock, flags);
+	}
+	disable_crime_irq(irq);
+}
+
+static void end_crime_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_crime_irq(irq);
+}
+
+#define shutdown_crime_irq disable_crime_irq
+
+static struct hw_interrupt_type ip32_crime_interrupt = {
+	"IP32 CRIME",
+	startup_crime_irq,
+	shutdown_crime_irq,
+	enable_crime_irq,
+	disable_crime_irq,
+	mask_and_ack_crime_irq,
+	end_crime_irq,
+	NULL
+};
+
+/*
+ * This is for MACE PCI interrupts.  We can decrease bus traffic by masking
+ * as close to the source as possible.  This also means we can take the
+ * next chunk of the CRIME register in one piece.
+ */
+
+static unsigned long macepci_mask;
+
+static void enable_macepci_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	macepci_mask |= MACEPCI_CONTROL_INT(irq - 9);
+	mace->pci.control = macepci_mask;
+	crime_mask |= 1 << (irq - 1);
+	crime->imask = crime_mask;
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static unsigned int startup_macepci_irq(unsigned int irq)
+{
+  	enable_macepci_irq (irq);
+	return 0;
+}
+
+static void disable_macepci_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	crime_mask &= ~(1 << (irq - 1));
+	crime->imask = crime_mask;
+	flush_crime_bus();
+	macepci_mask &= ~MACEPCI_CONTROL_INT(irq - 9);
+	mace->pci.control = macepci_mask;
+	flush_mace_bus();
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static void end_macepci_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_macepci_irq(irq);
+}
+
+#define shutdown_macepci_irq disable_macepci_irq
+#define mask_and_ack_macepci_irq disable_macepci_irq
+
+static struct hw_interrupt_type ip32_macepci_interrupt = {
+	"IP32 MACE PCI",
+	startup_macepci_irq,
+	shutdown_macepci_irq,
+	enable_macepci_irq,
+	disable_macepci_irq,
+	mask_and_ack_macepci_irq,
+	end_macepci_irq,
+	NULL
+};
+
+/* This is used for MACE ISA interrupts.  That means bits 4-6 in the
+ * CRIME register.
+ */
+
+#define MACEISA_AUDIO_INT	(MACEISA_AUDIO_SW_INT |		\
+				 MACEISA_AUDIO_SC_INT |		\
+				 MACEISA_AUDIO1_DMAT_INT |	\
+				 MACEISA_AUDIO1_OF_INT |	\
+				 MACEISA_AUDIO2_DMAT_INT |	\
+				 MACEISA_AUDIO2_MERR_INT |	\
+				 MACEISA_AUDIO3_DMAT_INT |	\
+				 MACEISA_AUDIO3_MERR_INT)
+#define MACEISA_MISC_INT	(MACEISA_RTC_INT |		\
+				 MACEISA_KEYB_INT |		\
+				 MACEISA_KEYB_POLL_INT |	\
+				 MACEISA_MOUSE_INT |		\
+				 MACEISA_MOUSE_POLL_INT |	\
+				 MACEISA_TIMER0_INT |		\
+				 MACEISA_TIMER1_INT |		\
+				 MACEISA_TIMER2_INT)
+#define MACEISA_SUPERIO_INT	(MACEISA_PARALLEL_INT |		\
+				 MACEISA_PAR_CTXA_INT |		\
+				 MACEISA_PAR_CTXB_INT |		\
+				 MACEISA_PAR_MERR_INT |		\
+				 MACEISA_SERIAL1_INT |		\
+				 MACEISA_SERIAL1_TDMAT_INT |	\
+				 MACEISA_SERIAL1_TDMAPR_INT |	\
+				 MACEISA_SERIAL1_TDMAME_INT |	\
+				 MACEISA_SERIAL1_RDMAT_INT |	\
+				 MACEISA_SERIAL1_RDMAOR_INT |	\
+				 MACEISA_SERIAL2_INT |		\
+				 MACEISA_SERIAL2_TDMAT_INT |	\
+				 MACEISA_SERIAL2_TDMAPR_INT |	\
+				 MACEISA_SERIAL2_TDMAME_INT |	\
+				 MACEISA_SERIAL2_RDMAT_INT |	\
+				 MACEISA_SERIAL2_RDMAOR_INT)
+
+static unsigned long maceisa_mask;
+
+static void enable_maceisa_irq (unsigned int irq)
+{
+	unsigned int crime_int = 0;
+	unsigned long flags;
+
+	DBG ("maceisa enable: %u\n", irq);
+
+	switch (irq) {
+	case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
+		crime_int = MACE_AUDIO_INT;
+		break;
+	case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ:
+		crime_int = MACE_MISC_INT;
+		break;
+	case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ:
+		crime_int = MACE_SUPERIO_INT;
+		break;
+	}
+	DBG ("crime_int %08x enabled\n", crime_int);
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	crime_mask |= crime_int;
+	crime->imask = crime_mask;
+	maceisa_mask |= 1 << (irq - 33);
+	mace->perif.ctrl.imask = maceisa_mask;
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static unsigned int startup_maceisa_irq(unsigned int irq)
+{
+	enable_maceisa_irq(irq);
+	return 0;
+}
+
+static void disable_maceisa_irq(unsigned int irq)
+{
+	unsigned int crime_int = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	maceisa_mask &= ~(1 << (irq - 33));
+        if(!(maceisa_mask & MACEISA_AUDIO_INT))
+		crime_int |= MACE_AUDIO_INT;
+        if(!(maceisa_mask & MACEISA_MISC_INT))
+		crime_int |= MACE_MISC_INT;
+        if(!(maceisa_mask & MACEISA_SUPERIO_INT))
+		crime_int |= MACE_SUPERIO_INT;
+	crime_mask &= ~crime_int;
+	crime->imask = crime_mask;
+	flush_crime_bus();
+	mace->perif.ctrl.imask = maceisa_mask;
+	flush_mace_bus();
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static void mask_and_ack_maceisa_irq(unsigned int irq)
+{
+	unsigned long mace_int, flags;
+
+	switch (irq) {
+	case MACEISA_PARALLEL_IRQ:
+	case MACEISA_SERIAL1_TDMAPR_IRQ:
+	case MACEISA_SERIAL2_TDMAPR_IRQ:
+		/* edge triggered */
+		spin_lock_irqsave(&ip32_irq_lock, flags);
+		mace_int = mace->perif.ctrl.istat;
+		mace_int &= ~(1 << (irq - 33));
+		mace->perif.ctrl.istat = mace_int;
+		spin_unlock_irqrestore(&ip32_irq_lock, flags);
+		break;
+	}
+	disable_maceisa_irq(irq);
+}
+
+static void end_maceisa_irq(unsigned irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		enable_maceisa_irq(irq);
+}
+
+#define shutdown_maceisa_irq disable_maceisa_irq
+
+static struct hw_interrupt_type ip32_maceisa_interrupt = {
+	"IP32 MACE ISA",
+	startup_maceisa_irq,
+	shutdown_maceisa_irq,
+	enable_maceisa_irq,
+	disable_maceisa_irq,
+	mask_and_ack_maceisa_irq,
+	end_maceisa_irq,
+	NULL
+};
+
+/* This is used for regular non-ISA, non-PCI MACE interrupts.  That means
+ * bits 0-3 and 7 in the CRIME register.
+ */
+
+static void enable_mace_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	crime_mask |= 1 << (irq - 1);
+	crime->imask = crime_mask;
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static unsigned int startup_mace_irq(unsigned int irq)
+{
+	enable_mace_irq(irq);
+	return 0;
+}
+
+static void disable_mace_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ip32_irq_lock, flags);
+	crime_mask &= ~(1 << (irq - 1));
+	crime->imask = crime_mask;
+	flush_crime_bus();
+	spin_unlock_irqrestore(&ip32_irq_lock, flags);
+}
+
+static void end_mace_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_mace_irq(irq);
+}
+
+#define shutdown_mace_irq disable_mace_irq
+#define mask_and_ack_mace_irq disable_mace_irq
+
+static struct hw_interrupt_type ip32_mace_interrupt = {
+	"IP32 MACE",
+	startup_mace_irq,
+	shutdown_mace_irq,
+	enable_mace_irq,
+	disable_mace_irq,
+	mask_and_ack_mace_irq,
+	end_mace_irq,
+	NULL
+};
+
+static void ip32_unknown_interrupt(struct pt_regs *regs)
+{
+	printk ("Unknown interrupt occurred!\n");
+	printk ("cp0_status: %08x\n", read_c0_status());
+	printk ("cp0_cause: %08x\n", read_c0_cause());
+	printk ("CRIME intr mask: %016lx\n", crime->imask);
+	printk ("CRIME intr status: %016lx\n", crime->istat);
+	printk ("CRIME hardware intr register: %016lx\n", crime->hard_int);
+	printk ("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask);
+	printk ("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat);
+	printk ("MACE PCI control register: %08x\n", mace->pci.control);
+
+	printk("Register dump:\n");
+	show_regs(regs);
+
+	printk("Please mail this report to linux-mips@linux-mips.org\n");
+	printk("Spinning...");
+	while(1) ;
+}
+
+/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
+/* change this to loop over all edge-triggered irqs, exception masked out ones */
+void ip32_irq0(struct pt_regs *regs)
+{
+	uint64_t crime_int;
+	int irq = 0;
+
+	crime_int = crime->istat & crime_mask;
+	irq = ffs(crime_int);
+	crime_int = 1 << (irq - 1);
+
+	if (crime_int & CRIME_MACEISA_INT_MASK) {
+		unsigned long mace_int = mace->perif.ctrl.istat;
+		irq = ffs(mace_int & maceisa_mask) + 32;
+	}
+	DBG("*irq %u*\n", irq);
+	do_IRQ(irq, regs);
+}
+
+void ip32_irq1(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt(regs);
+}
+
+void ip32_irq2(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt(regs);
+}
+
+void ip32_irq3(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt(regs);
+}
+
+void ip32_irq4(struct pt_regs *regs)
+{
+	ip32_unknown_interrupt(regs);
+}
+
+void ip32_irq5(struct pt_regs *regs)
+{
+	ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
+}
+
+void __init arch_init_irq(void)
+{
+	unsigned int irq;
+
+	/* Install our interrupt handler, then clear and disable all
+	 * CRIME and MACE interrupts. */
+	crime->imask = 0;
+	crime->hard_int = 0;
+	crime->soft_int = 0;
+	mace->perif.ctrl.istat = 0;
+	mace->perif.ctrl.imask = 0;
+	set_except_vector(0, ip32_handle_int);
+
+	for (irq = 0; irq <= IP32_IRQ_MAX; irq++) {
+		hw_irq_controller *controller;
+
+		if (irq == IP32_R4K_TIMER_IRQ)
+			controller = &ip32_cpu_interrupt;
+		else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ)
+			controller = &ip32_mace_interrupt;
+		else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ)
+			controller = &ip32_macepci_interrupt;
+		else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ)
+			controller = &ip32_crime_interrupt;
+		else
+			controller = &ip32_maceisa_interrupt;
+
+		irq_desc[irq].status = IRQ_DISABLED;
+		irq_desc[irq].action = 0;
+		irq_desc[irq].depth = 0;
+		irq_desc[irq].handler = controller;
+	}
+	setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
+	setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
+
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+	change_c0_status(ST0_IM, ALLINTS);
+}
diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c
new file mode 100644
index 0000000..fc76ca9
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-memory.c
@@ -0,0 +1,49 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Keith M Wesolowski
+ * Copyright (C) 2005 Ilya A. Volynets (Total Knowledge)
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/ip32/crime.h>
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+extern void crime_init(void);
+
+void __init prom_meminit (void)
+{
+	u64 base, size;
+	int bank;
+
+	crime_init();
+
+	for (bank=0; bank < CRIME_MAXBANKS; bank++) {
+		u64 bankctl = crime->bank_ctrl[bank];
+		base = (bankctl & CRIME_MEM_BANK_CONTROL_ADDR) << 25;
+		if (bank != 0 && base == 0)
+			continue;
+		size = (bankctl & CRIME_MEM_BANK_CONTROL_SDRAM_SIZE) ? 128 : 32;
+		size <<= 20;
+		if (base + size > (256 << 20))
+			base += CRIME_HI_MEM_BASE;
+
+		printk("CRIME MC: bank %u base 0x%016lx size %luMB\n",
+			bank, base, size);
+		add_memory_region (base, size, BOOT_MEM_RAM);
+	}
+}
+
+
+unsigned long __init prom_free_prom_memory (void)
+{
+	return 0;
+}
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
new file mode 100644
index 0000000..281f090
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -0,0 +1,202 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 Keith M Wesolowski
+ * Copyright (C) 2001 Paul Mundt
+ * Copyright (C) 2003 Guido Guenther <agx@sigxcpu.org>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/ds17287rtc.h>
+#include <linux/interrupt.h>
+
+#include <asm/addrspace.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/wbflush.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/ip32_ints.h>
+
+#define POWERDOWN_TIMEOUT	120
+/*
+ * Blink frequency during reboot grace period and when paniced.
+ */
+#define POWERDOWN_FREQ		(HZ / 4)
+#define PANIC_FREQ		(HZ / 8)
+
+static struct timer_list power_timer, blink_timer, debounce_timer;
+static int has_paniced, shuting_down;
+
+static void ip32_machine_restart(char *command) __attribute__((noreturn));
+static void ip32_machine_halt(void) __attribute__((noreturn));
+static void ip32_machine_power_off(void) __attribute__((noreturn));
+
+static void ip32_machine_restart(char *cmd)
+{
+	crime->control = CRIME_CONTROL_HARD_RESET;
+	while (1);
+}
+
+static inline void ip32_machine_halt(void)
+{
+	ip32_machine_power_off();
+}
+
+static void ip32_machine_power_off(void)
+{
+	volatile unsigned char reg_a, xctrl_a, xctrl_b;
+
+	disable_irq(MACEISA_RTC_IRQ);
+	reg_a = CMOS_READ(RTC_REG_A);
+
+	/* setup for kickstart & wake-up (DS12287 Ref. Man. p. 19) */
+	reg_a &= ~DS_REGA_DV2;
+	reg_a |= DS_REGA_DV1;
+
+	CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A);
+	wbflush();
+	xctrl_b = CMOS_READ(DS_B1_XCTRL4B)
+		   | DS_XCTRL4B_ABE | DS_XCTRL4B_KFE;
+	CMOS_WRITE(xctrl_b, DS_B1_XCTRL4B);
+	xctrl_a = CMOS_READ(DS_B1_XCTRL4A) & ~DS_XCTRL4A_IFS;
+	CMOS_WRITE(xctrl_a, DS_B1_XCTRL4A);
+	wbflush();
+	/* adios amigos... */
+	CMOS_WRITE(xctrl_a | DS_XCTRL4A_PAB, DS_B1_XCTRL4A);
+	CMOS_WRITE(reg_a, RTC_REG_A);
+	wbflush();
+	while (1);
+}
+
+static void power_timeout(unsigned long data)
+{
+	ip32_machine_power_off();
+}
+
+static void blink_timeout(unsigned long data)
+{
+	unsigned long led = mace->perif.ctrl.misc ^ MACEISA_LED_RED;
+	mace->perif.ctrl.misc = led;
+	mod_timer(&blink_timer, jiffies + data);
+}
+
+static void debounce(unsigned long data)
+{
+	volatile unsigned char reg_a, reg_c, xctrl_a;
+
+	reg_c = CMOS_READ(RTC_INTR_FLAGS);
+	CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A);
+	wbflush();
+	xctrl_a = CMOS_READ(DS_B1_XCTRL4A);
+	if ((xctrl_a & DS_XCTRL4A_IFS) || (reg_c & RTC_IRQF )) {
+		/* Interrupt still being sent. */
+		debounce_timer.expires = jiffies + 50;
+		add_timer(&debounce_timer);
+
+		/* clear interrupt source */
+		CMOS_WRITE(xctrl_a & ~DS_XCTRL4A_IFS, DS_B1_XCTRL4A);
+		CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A);
+		return;
+	}
+	CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A);
+
+	if (has_paniced)
+		ip32_machine_restart(NULL);
+
+	enable_irq(MACEISA_RTC_IRQ);
+}
+
+static inline void ip32_power_button(void)
+{
+	if (has_paniced)
+		return;
+
+	if (shuting_down || kill_proc(1, SIGINT, 1)) {
+		/* No init process or button pressed twice.  */
+		ip32_machine_power_off();
+	}
+
+	shuting_down = 1;
+	blink_timer.data = POWERDOWN_FREQ;
+	blink_timeout(POWERDOWN_FREQ);
+
+	init_timer(&power_timer);
+	power_timer.function = power_timeout;
+	power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
+	add_timer(&power_timer);
+}
+
+static irqreturn_t ip32_rtc_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	volatile unsigned char reg_c;
+
+	reg_c = CMOS_READ(RTC_INTR_FLAGS);
+	if (!(reg_c & RTC_IRQF)) {
+		printk(KERN_WARNING 
+			"%s: RTC IRQ without RTC_IRQF\n", __FUNCTION__);
+	}
+	/* Wait until interrupt goes away */
+	disable_irq(MACEISA_RTC_IRQ);
+	init_timer(&debounce_timer);
+	debounce_timer.function = debounce;
+	debounce_timer.expires = jiffies + 50;
+	add_timer(&debounce_timer);
+
+	printk(KERN_DEBUG "Power button pressed\n");
+	ip32_power_button();
+	return IRQ_HANDLED;
+}
+
+static int panic_event(struct notifier_block *this, unsigned long event,
+		       void *ptr)
+{
+	unsigned long led;
+
+	if (has_paniced)
+		return NOTIFY_DONE;
+	has_paniced = 1;
+
+	/* turn off the green LED */
+	led = mace->perif.ctrl.misc | MACEISA_LED_GREEN;
+	mace->perif.ctrl.misc = led;
+
+	blink_timer.data = PANIC_FREQ;
+	blink_timeout(PANIC_FREQ);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	.notifier_call = panic_event,
+};
+
+static __init int ip32_reboot_setup(void)
+{
+	/* turn on the green led only */
+	unsigned long led = mace->perif.ctrl.misc;
+	led |= MACEISA_LED_RED;
+	led &= ~MACEISA_LED_GREEN;
+	mace->perif.ctrl.misc = led;
+
+	_machine_restart = ip32_machine_restart;
+	_machine_halt = ip32_machine_halt;
+	_machine_power_off = ip32_machine_power_off;
+
+	init_timer(&blink_timer);
+	blink_timer.function = blink_timeout;
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL);
+
+	return 0;
+}
+
+subsys_initcall(ip32_reboot_setup);
diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
new file mode 100644
index 0000000..8d270be
--- /dev/null
+++ b/arch/mips/sgi-ip32/ip32-setup.c
@@ -0,0 +1,159 @@
+/*
+ * IP32 basic setup
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Harald Koerfgen
+ * Copyright (C) 2002, 2003, 2005 Ilya A. Volynets
+ */
+#include <linux/config.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/param.h>
+#include <linux/sched.h>
+
+#include <asm/bootinfo.h>
+#include <asm/mc146818-time.h>
+#include <asm/mipsregs.h>
+#include <asm/mmu_context.h>
+#include <asm/sgialib.h>
+#include <asm/time.h>
+#include <asm/traps.h>
+#include <asm/io.h>
+#include <asm/ip32/crime.h>
+#include <asm/ip32/mace.h>
+#include <asm/ip32/ip32_ints.h>
+
+extern void ip32_be_init(void);
+extern void crime_init(void);
+
+#ifdef CONFIG_SGI_O2MACE_ETH
+/*
+ * This is taken care of in here 'cause they say using Arc later on is
+ * problematic
+ */
+extern char o2meth_eaddr[8];
+static inline unsigned char str2hexnum(unsigned char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		unsigned char num;
+
+		if(*str == ':')
+			str++;
+		num = str2hexnum(*str++) << 4;
+		num |= (str2hexnum(*str++));
+		ea[i] = num;
+	}
+}
+#endif
+
+#ifdef CONFIG_SERIAL_8250
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+extern int early_serial_setup(struct uart_port *port);
+
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
+#define BASE_BAUD (1843200 / 16)
+
+#endif /* CONFIG_SERIAL_8250 */
+
+/* An arbitrary time; this can be decreased if reliability looks good */
+#define WAIT_MS 10
+
+void __init ip32_time_init(void)
+{
+	printk(KERN_INFO "Calibrating system timer... ");
+	write_c0_count(0);
+	crime->timer = 0;
+	while (crime->timer < CRIME_MASTER_FREQ * WAIT_MS / 1000) ;
+	mips_hpt_frequency = read_c0_count() * 1000 / WAIT_MS;
+	printk("%d MHz CPU detected\n", mips_hpt_frequency * 2 / 1000000);
+}
+
+void __init ip32_timer_setup(struct irqaction *irq)
+{
+	irq->handler = no_action;
+	setup_irq(IP32_R4K_TIMER_IRQ, irq);
+}
+
+static int __init ip32_setup(void)
+{
+	board_be_init = ip32_be_init;
+
+	rtc_get_time = mc146818_get_cmos_time;
+	rtc_set_mmss = mc146818_set_rtc_mmss;
+
+	board_time_init = ip32_time_init;
+	board_timer_setup = ip32_timer_setup;
+
+#ifdef CONFIG_SERIAL_8250
+ 	{
+		static struct uart_port o2_serial[2];
+
+		memset(o2_serial, 0, sizeof(o2_serial));
+		o2_serial[0].type	= PORT_16550A;
+		o2_serial[0].line	= 0;
+		o2_serial[0].irq	= MACEISA_SERIAL1_IRQ;
+		o2_serial[0].flags	= STD_COM_FLAGS;
+		o2_serial[0].uartclk	= BASE_BAUD * 16;
+		o2_serial[0].iotype	= UPIO_MEM;
+		o2_serial[0].membase	= (char *)&mace->isa.serial1;
+		o2_serial[0].fifosize	= 14;
+                /* How much to shift register offset by. Each UART register
+		 * is replicated over 256 byte space */
+		o2_serial[0].regshift	= 8;
+		o2_serial[1].type	= PORT_16550A;
+		o2_serial[1].line	= 1;
+		o2_serial[1].irq	= MACEISA_SERIAL2_IRQ;
+		o2_serial[1].flags	= STD_COM_FLAGS;
+		o2_serial[1].uartclk	= BASE_BAUD * 16;
+		o2_serial[1].iotype	= UPIO_MEM;
+		o2_serial[1].membase	= (char *)&mace->isa.serial2;
+		o2_serial[1].fifosize	= 14;
+		o2_serial[1].regshift	= 8;
+
+		early_serial_setup(&o2_serial[0]);
+		early_serial_setup(&o2_serial[1]);
+	}
+#endif
+#ifdef CONFIG_SGI_O2MACE_ETH
+	{
+		char *mac = ArcGetEnvironmentVariable("eaddr");
+		str2eaddr(o2meth_eaddr, mac);
+	}
+#endif
+
+#if defined(CONFIG_SERIAL_CORE_CONSOLE)
+	{
+		char* con = ArcGetEnvironmentVariable("console");
+		if (con && *con == 'd') {
+			static char options[8];
+			char *baud = ArcGetEnvironmentVariable("dbaud");
+			if (baud)
+				strcpy(options, baud);
+			add_preferred_console("ttyS", *(con + 1) == '2' ? 1 : 0,
+					      baud ? options : NULL);
+		}
+	}
+#endif
+
+	return 0;
+}
+
+early_initcall(ip32_setup);