aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sparc/kernel
Linux-2.6.12-rc2v2.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!
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/Makefile27
-rw-r--r--arch/sparc/kernel/apc.c186
-rw-r--r--arch/sparc/kernel/asm-offsets.c45
-rw-r--r--arch/sparc/kernel/auxio.c138
-rw-r--r--arch/sparc/kernel/cpu.c168
-rw-r--r--arch/sparc/kernel/devices.c160
-rw-r--r--arch/sparc/kernel/ebus.c361
-rw-r--r--arch/sparc/kernel/entry.S1956
-rw-r--r--arch/sparc/kernel/errtbls.c276
-rw-r--r--arch/sparc/kernel/etrap.S321
-rw-r--r--arch/sparc/kernel/head.S1326
-rw-r--r--arch/sparc/kernel/idprom.c108
-rw-r--r--arch/sparc/kernel/init_task.c28
-rw-r--r--arch/sparc/kernel/ioport.c731
-rw-r--r--arch/sparc/kernel/irq.c614
-rw-r--r--arch/sparc/kernel/module.c159
-rw-r--r--arch/sparc/kernel/muldiv.c240
-rw-r--r--arch/sparc/kernel/pcic.c1041
-rw-r--r--arch/sparc/kernel/pmc.c99
-rw-r--r--arch/sparc/kernel/process.c746
-rw-r--r--arch/sparc/kernel/ptrace.c632
-rw-r--r--arch/sparc/kernel/rtrap.S319
-rw-r--r--arch/sparc/kernel/sclow.S86
-rw-r--r--arch/sparc/kernel/semaphore.c155
-rw-r--r--arch/sparc/kernel/setup.c476
-rw-r--r--arch/sparc/kernel/signal.c1181
-rw-r--r--arch/sparc/kernel/smp.c295
-rw-r--r--arch/sparc/kernel/sparc-stub.c724
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c334
-rw-r--r--arch/sparc/kernel/sun4c_irq.c250
-rw-r--r--arch/sparc/kernel/sun4d_irq.c594
-rw-r--r--arch/sparc/kernel/sun4d_smp.c486
-rw-r--r--arch/sparc/kernel/sun4m_irq.c399
-rw-r--r--arch/sparc/kernel/sun4m_smp.c451
-rw-r--r--arch/sparc/kernel/sun4setup.c75
-rw-r--r--arch/sparc/kernel/sunos_asm.S67
-rw-r--r--arch/sparc/kernel/sunos_ioctl.c231
-rw-r--r--arch/sparc/kernel/sys_solaris.c37
-rw-r--r--arch/sparc/kernel/sys_sparc.c485
-rw-r--r--arch/sparc/kernel/sys_sunos.c1194
-rw-r--r--arch/sparc/kernel/systbls.S186
-rw-r--r--arch/sparc/kernel/tadpole.c126
-rw-r--r--arch/sparc/kernel/tick14.c85
-rw-r--r--arch/sparc/kernel/time.c641
-rw-r--r--arch/sparc/kernel/trampoline.S162
-rw-r--r--arch/sparc/kernel/traps.c515
-rw-r--r--arch/sparc/kernel/unaligned.c548
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S103
-rw-r--r--arch/sparc/kernel/windows.c127
-rw-r--r--arch/sparc/kernel/wof.S428
-rw-r--r--arch/sparc/kernel/wuf.S360
51 files changed, 20482 insertions, 0 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
new file mode 100644
index 00000000000..3d22ba2af01
--- /dev/null
+++ b/arch/sparc/kernel/Makefile
@@ -0,0 +1,27 @@
+# $Id: Makefile,v 1.62 2000/12/15 00:41:17 davem Exp $
+# Makefile for the linux kernel.
+#
+
+extra-y := head.o init_task.o vmlinux.lds
+
+EXTRA_AFLAGS := -ansi
+
+IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
+obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
+ process.o signal.o ioport.o setup.o idprom.o \
+ sys_sparc.o sunos_asm.o systbls.o \
+ time.o windows.o cpu.o devices.o sclow.o \
+ tadpole.o tick14.o ptrace.o sys_solaris.o \
+ unaligned.o muldiv.o semaphore.o
+
+obj-$(CONFIG_PCI) += pcic.o
+obj-$(CONFIG_SUN4) += sun4setup.o
+obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
+obj-$(CONFIG_SUN_AUXIO) += auxio.o
+obj-$(CONFIG_PCI) += ebus.o
+obj-$(CONFIG_SUN_PM) += apc.o pmc.o
+obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
+
+ifdef CONFIG_SUNOS_EMUL
+obj-y += sys_sunos.o sunos_ioctl.o
+endif
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
new file mode 100644
index 00000000000..406dd94afb4
--- /dev/null
+++ b/arch/sparc/kernel/apc.c
@@ -0,0 +1,186 @@
+/* apc - Driver implementation for power management functions
+ * of Aurora Personality Chip (APC) on SPARCstation-4/5 and
+ * derivatives.
+ *
+ * Copyright (c) 2002 Eric Brower (ebrower@usa.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+#include <asm/auxio.h>
+#include <asm/apc.h>
+
+/* Debugging
+ *
+ * #define APC_DEBUG_LED
+ */
+
+#define APC_MINOR MISC_DYNAMIC_MINOR
+#define APC_OBPNAME "power-management"
+#define APC_DEVNAME "apc"
+
+volatile static u8 __iomem *regs;
+static int apc_regsize;
+static int apc_no_idle __initdata = 0;
+
+#define apc_readb(offs) (sbus_readb(regs+offs))
+#define apc_writeb(val, offs) (sbus_writeb(val, regs+offs))
+
+/* Specify "apc=noidle" on the kernel command line to
+ * disable APC CPU standby support. Certain prototype
+ * systems (SPARCstation-Fox) do not play well with APC
+ * CPU idle, so disable this if your system has APC and
+ * crashes randomly.
+ */
+static int __init apc_setup(char *str)
+{
+ if(!strncmp(str, "noidle", strlen("noidle"))) {
+ apc_no_idle = 1;
+ return 1;
+ }
+ return 0;
+}
+__setup("apc=", apc_setup);
+
+/*
+ * CPU idle callback function
+ * See .../arch/sparc/kernel/process.c
+ */
+void apc_swift_idle(void)
+{
+#ifdef APC_DEBUG_LED
+ set_auxio(0x00, AUXIO_LED);
+#endif
+
+ apc_writeb(apc_readb(APC_IDLE_REG) | APC_IDLE_ON, APC_IDLE_REG);
+
+#ifdef APC_DEBUG_LED
+ set_auxio(AUXIO_LED, 0x00);
+#endif
+}
+
+static inline void apc_free(void)
+{
+ sbus_iounmap(regs, apc_regsize);
+}
+
+static int apc_open(struct inode *inode, struct file *f)
+{
+ return 0;
+}
+
+static int apc_release(struct inode *inode, struct file *f)
+{
+ return 0;
+}
+
+static int apc_ioctl(struct inode *inode, struct file *f,
+ unsigned int cmd, unsigned long __arg)
+{
+ __u8 inarg, __user *arg;
+
+ arg = (__u8 __user *) __arg;
+ switch (cmd) {
+ case APCIOCGFANCTL:
+ if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg))
+ return -EFAULT;
+ break;
+
+ case APCIOCGCPWR:
+ if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg))
+ return -EFAULT;
+ break;
+
+ case APCIOCGBPORT:
+ if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg))
+ return -EFAULT;
+ break;
+
+ case APCIOCSFANCTL:
+ if (get_user(inarg, arg))
+ return -EFAULT;
+ apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
+ break;
+ case APCIOCSCPWR:
+ if (get_user(inarg, arg))
+ return -EFAULT;
+ apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
+ break;
+ case APCIOCSBPORT:
+ if (get_user(inarg, arg))
+ return -EFAULT;
+ apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return 0;
+}
+
+static struct file_operations apc_fops = {
+ .ioctl = apc_ioctl,
+ .open = apc_open,
+ .release = apc_release,
+};
+
+static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
+
+static int __init apc_probe(void)
+{
+ struct sbus_bus *sbus = NULL;
+ struct sbus_dev *sdev = NULL;
+ int iTmp = 0;
+
+ for_each_sbus(sbus) {
+ for_each_sbusdev(sdev, sbus) {
+ if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
+ goto sbus_done;
+ }
+ }
+ }
+
+sbus_done:
+ if (!sdev) {
+ return -ENODEV;
+ }
+
+ apc_regsize = sdev->reg_addrs[0].reg_size;
+ regs = sbus_ioremap(&sdev->resource[0], 0,
+ apc_regsize, APC_OBPNAME);
+ if(!regs) {
+ printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
+ return -ENODEV;
+ }
+
+ iTmp = misc_register(&apc_miscdev);
+ if (iTmp != 0) {
+ printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
+ apc_free();
+ return -ENODEV;
+ }
+
+ /* Assign power management IDLE handler */
+ if(!apc_no_idle)
+ pm_idle = apc_swift_idle;
+
+ printk(KERN_INFO "%s: power management initialized%s\n",
+ APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+ return 0;
+}
+
+/* This driver is not critical to the boot process
+ * and is easiest to ioremap when SBus is already
+ * initialized, so we install ourselves thusly:
+ */
+__initcall(apc_probe);
+
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
new file mode 100644
index 00000000000..1f55231f07d
--- /dev/null
+++ b/arch/sparc/kernel/asm-offsets.c
@@ -0,0 +1,45 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ *
+ * On sparc, thread_info data is static and TI_XXX offsets are computed by hand.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+// #include <linux/mm.h>
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int foo(void)
+{
+ DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
+ BLANK();
+ /* XXX This is the stuff for sclow.S, kill it. */
+ DEFINE(AOFF_task_pid, offsetof(struct task_struct, pid));
+ DEFINE(AOFF_task_uid, offsetof(struct task_struct, uid));
+ DEFINE(AOFF_task_gid, offsetof(struct task_struct, gid));
+ DEFINE(AOFF_task_euid, offsetof(struct task_struct, euid));
+ DEFINE(AOFF_task_egid, offsetof(struct task_struct, egid));
+ /* DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); */
+ DEFINE(ASIZ_task_uid, sizeof(current->uid));
+ DEFINE(ASIZ_task_gid, sizeof(current->gid));
+ DEFINE(ASIZ_task_euid, sizeof(current->euid));
+ DEFINE(ASIZ_task_egid, sizeof(current->egid));
+ BLANK();
+ DEFINE(AOFF_thread_fork_kpsr,
+ offsetof(struct thread_struct, fork_kpsr));
+ BLANK();
+ DEFINE(AOFF_mm_context, offsetof(struct mm_struct, context));
+
+ /* DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); */
+ return 0;
+}
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c
new file mode 100644
index 00000000000..d3b3648362c
--- /dev/null
+++ b/arch/sparc/kernel/auxio.c
@@ -0,0 +1,138 @@
+/* auxio.c: Probing for the Sparc AUXIO register at boot time.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/auxio.h>
+#include <asm/string.h> /* memset(), Linux has no bzero() */
+
+/* Probe and map in the Auxiliary I/O register */
+
+/* auxio_register is not static because it is referenced
+ * in entry.S::floppy_tdone
+ */
+void __iomem *auxio_register = NULL;
+static DEFINE_SPINLOCK(auxio_lock);
+
+void __init auxio_probe(void)
+{
+ int node, auxio_nd;
+ struct linux_prom_registers auxregs[1];
+ struct resource r;
+
+ switch (sparc_cpu_model) {
+ case sun4d:
+ case sun4:
+ return;
+ default:
+ break;
+ }
+ node = prom_getchild(prom_root_node);
+ auxio_nd = prom_searchsiblings(node, "auxiliary-io");
+ if(!auxio_nd) {
+ node = prom_searchsiblings(node, "obio");
+ node = prom_getchild(node);
+ auxio_nd = prom_searchsiblings(node, "auxio");
+ if(!auxio_nd) {
+#ifdef CONFIG_PCI
+ /* There may be auxio on Ebus */
+ return;
+#else
+ if(prom_searchsiblings(node, "leds")) {
+ /* VME chassis sun4m machine, no auxio exists. */
+ return;
+ }
+ prom_printf("Cannot find auxio node, cannot continue...\n");
+ prom_halt();
+#endif
+ }
+ }
+ if(prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)) <= 0)
+ return;
+ prom_apply_obio_ranges(auxregs, 0x1);
+ /* Map the register both read and write */
+ r.flags = auxregs[0].which_io & 0xF;
+ r.start = auxregs[0].phys_addr;
+ r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
+ auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
+ /* Fix the address on sun4m and sun4c. */
+ if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
+ sparc_cpu_model == sun4c)
+ auxio_register += (3 - ((unsigned long)auxio_register & 3));
+
+ set_auxio(AUXIO_LED, 0);
+}
+
+unsigned char get_auxio(void)
+{
+ if(auxio_register)
+ return sbus_readb(auxio_register);
+ return 0;
+}
+
+void set_auxio(unsigned char bits_on, unsigned char bits_off)
+{
+ unsigned char regval;
+ unsigned long flags;
+ spin_lock_irqsave(&auxio_lock, flags);
+ switch(sparc_cpu_model) {
+ case sun4c:
+ regval = sbus_readb(auxio_register);
+ sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN,
+ auxio_register);
+ break;
+ case sun4m:
+ if(!auxio_register)
+ break; /* VME chassic sun4m, no auxio. */
+ regval = sbus_readb(auxio_register);
+ sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M,
+ auxio_register);
+ break;
+ case sun4d:
+ break;
+ default:
+ panic("Can't set AUXIO register on this machine.");
+ };
+ spin_unlock_irqrestore(&auxio_lock, flags);
+}
+
+
+/* sun4m power control register (AUXIO2) */
+
+volatile unsigned char * auxio_power_register = NULL;
+
+void __init auxio_power_probe(void)
+{
+ struct linux_prom_registers regs;
+ int node;
+ struct resource r;
+
+ /* Attempt to find the sun4m power control node. */
+ node = prom_getchild(prom_root_node);
+ node = prom_searchsiblings(node, "obio");
+ node = prom_getchild(node);
+ node = prom_searchsiblings(node, "power");
+ if (node == 0 || node == -1)
+ return;
+
+ /* Map the power control register. */
+ if (prom_getproperty(node, "reg", (char *)&regs, sizeof(regs)) <= 0)
+ return;
+ prom_apply_obio_ranges(&regs, 1);
+ memset(&r, 0, sizeof(r));
+ r.flags = regs.which_io & 0xF;
+ r.start = regs.phys_addr;
+ r.end = regs.phys_addr + regs.reg_size - 1;
+ auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
+ regs.reg_size, "auxpower");
+
+ /* Display a quick message on the console. */
+ if (auxio_power_register)
+ printk(KERN_INFO "Power off control detected.\n");
+}
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
new file mode 100644
index 00000000000..6a4ebc62193
--- /dev/null
+++ b/arch/sparc/kernel/cpu.c
@@ -0,0 +1,168 @@
+/* cpu.c: Dinky routines to look for the kind of Sparc cpu
+ * we are on.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/mbus.h>
+#include <asm/cpudata.h>
+
+DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
+
+struct cpu_iu_info {
+ int psr_impl;
+ int psr_vers;
+ char* cpu_name; /* should be enough I hope... */
+};
+
+struct cpu_fp_info {
+ int psr_impl;
+ int fp_vers;
+ char* fp_name;
+};
+
+/* In order to get the fpu type correct, you need to take the IDPROM's
+ * machine type value into consideration too. I will fix this.
+ */
+struct cpu_fp_info linux_sparc_fpu[] = {
+ { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
+ { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
+ { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
+ /* SparcStation SLC, SparcStation1 */
+ { 0, 3, "Weitek WTL3170/2"},
+ /* SPARCstation-5 */
+ { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
+ { 0, 5, "reserved"},
+ { 0, 6, "reserved"},
+ { 0, 7, "No FPU"},
+ { 1, 0, "ROSS HyperSparc combined IU/FPU"},
+ { 1, 1, "Lsi Logic L64814"},
+ { 1, 2, "Texas Instruments TMS390-C602A"},
+ { 1, 3, "Cypress CY7C602 FPU"},
+ { 1, 4, "reserved"},
+ { 1, 5, "reserved"},
+ { 1, 6, "reserved"},
+ { 1, 7, "No FPU"},
+ { 2, 0, "BIT B5010 or B5110/20 or B5210"},
+ { 2, 1, "reserved"},
+ { 2, 2, "reserved"},
+ { 2, 3, "reserved"},
+ { 2, 4, "reserved"},
+ { 2, 5, "reserved"},
+ { 2, 6, "reserved"},
+ { 2, 7, "No FPU"},
+ /* SuperSparc 50 module */
+ { 4, 0, "SuperSparc on-chip FPU"},
+ /* SparcClassic */
+ { 4, 4, "TI MicroSparc on chip FPU"},
+ { 5, 0, "Matsushita MN10501"},
+ { 5, 1, "reserved"},
+ { 5, 2, "reserved"},
+ { 5, 3, "reserved"},
+ { 5, 4, "reserved"},
+ { 5, 5, "reserved"},
+ { 5, 6, "reserved"},
+ { 5, 7, "No FPU"},
+ { 9, 3, "Fujitsu or Weitek on-chip FPU"},
+};
+
+#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+
+struct cpu_iu_info linux_sparc_chips[] = {
+ /* Sun4/100, 4/200, SLC */
+ { 0, 0, "Fujitsu MB86900/1A or LSI L64831 SparcKIT-40"},
+ /* borned STP1012PGA */
+ { 0, 4, "Fujitsu MB86904"},
+ { 0, 5, "Fujitsu TurboSparc MB86907"},
+ /* SparcStation2, SparcServer 490 & 690 */
+ { 1, 0, "LSI Logic Corporation - L64811"},
+ /* SparcStation2 */
+ { 1, 1, "Cypress/ROSS CY7C601"},
+ /* Embedded controller */
+ { 1, 3, "Cypress/ROSS CY7C611"},
+ /* Ross Technologies HyperSparc */
+ { 1, 0xf, "ROSS HyperSparc RT620"},
+ { 1, 0xe, "ROSS HyperSparc RT625 or RT626"},
+ /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+ /* Someone please write the code to support this beast! ;) */
+ { 2, 0, "Bipolar Integrated Technology - B5010"},
+ { 3, 0, "LSI Logic Corporation - unknown-type"},
+ { 4, 0, "Texas Instruments, Inc. - SuperSparc-(II)"},
+ /* SparcClassic -- borned STP1010TAB-50*/
+ { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
+ { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
+ { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
+ { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
+ { 4, 5, "Texas Instruments, Inc. - unknown"},
+ { 5, 0, "Matsushita - MN10501"},
+ { 6, 0, "Philips Corporation - unknown"},
+ { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
+ /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
+ { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
+ { 9, 0, "Fujitsu or Weitek Power-UP"},
+ { 9, 1, "Fujitsu or Weitek Power-UP"},
+ { 9, 2, "Fujitsu or Weitek Power-UP"},
+ { 9, 3, "Fujitsu or Weitek Power-UP"},
+ { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+};
+
+#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+
+char *sparc_cpu_type;
+char *sparc_fpu_type;
+
+unsigned int fsr_storage;
+
+void __init cpu_probe(void)
+{
+ int psr_impl, psr_vers, fpu_vers;
+ int i, psr;
+
+ psr_impl = ((get_psr()>>28)&0xf);
+ psr_vers = ((get_psr()>>24)&0xf);
+
+ psr = get_psr();
+ put_psr(psr | PSR_EF);
+ fpu_vers = ((get_fsr()>>17)&0x7);
+ put_psr(psr);
+
+ for(i = 0; i<NSPARCCHIPS; i++) {
+ if(linux_sparc_chips[i].psr_impl == psr_impl)
+ if(linux_sparc_chips[i].psr_vers == psr_vers) {
+ sparc_cpu_type = linux_sparc_chips[i].cpu_name;
+ break;
+ }
+ }
+
+ if(i==NSPARCCHIPS)
+ printk("DEBUG: psr.impl = 0x%x psr.vers = 0x%x\n", psr_impl,
+ psr_vers);
+
+ for(i = 0; i<NSPARCFPU; i++) {
+ if(linux_sparc_fpu[i].psr_impl == psr_impl)
+ if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
+ sparc_fpu_type = linux_sparc_fpu[i].fp_name;
+ break;
+ }
+ }
+
+ if(i == NSPARCFPU) {
+ printk("DEBUG: psr.impl = 0x%x fsr.vers = 0x%x\n", psr_impl,
+ fpu_vers);
+ sparc_fpu_type = linux_sparc_fpu[31].fp_name;
+ }
+}
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
new file mode 100644
index 00000000000..fcb0c049c3f
--- /dev/null
+++ b/arch/sparc/kernel/devices.c
@@ -0,0 +1,160 @@
+/* devices.c: Initial scan of the prom device tree for important
+ * Sparc device nodes which we need to find.
+ *
+ * This is based on the sparc64 version, but sun4m doesn't always use
+ * the hardware MIDs, so be careful.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/threads.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <asm/page.h>
+#include <asm/oplib.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/cpudata.h>
+
+extern void cpu_probe(void);
+extern void clock_stop_probe(void); /* tadpole.c */
+extern void sun4c_probe_memerr_reg(void);
+
+static char *cpu_mid_prop(void)
+{
+ if (sparc_cpu_model == sun4d)
+ return "cpu-id";
+ return "mid";
+}
+
+static int check_cpu_node(int nd, int *cur_inst,
+ int (*compare)(int, int, void *), void *compare_arg,
+ int *prom_node, int *mid)
+{
+ char node_str[128];
+
+ prom_getstring(nd, "device_type", node_str, sizeof(node_str));
+ if (strcmp(node_str, "cpu"))
+ return -ENODEV;
+
+ if (!compare(nd, *cur_inst, compare_arg)) {
+ if (prom_node)
+ *prom_node = nd;
+ if (mid) {
+ *mid = prom_getintdefault(nd, cpu_mid_prop(), 0);
+ if (sparc_cpu_model == sun4m)
+ *mid &= 3;
+ }
+ return 0;
+ }
+
+ (*cur_inst)++;
+
+ return -ENODEV;
+}
+
+static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
+ int *prom_node, int *mid)
+{
+ int nd, cur_inst, err;
+
+ nd = prom_root_node;
+ cur_inst = 0;
+
+ err = check_cpu_node(nd, &cur_inst, compare, compare_arg,
+ prom_node, mid);
+ if (!err)
+ return 0;
+
+ nd = prom_getchild(nd);
+ while ((nd = prom_getsibling(nd)) != 0) {
+ err = check_cpu_node(nd, &cur_inst, compare, compare_arg,
+ prom_node, mid);
+ if (!err)
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int cpu_instance_compare(int nd, int instance, void *_arg)
+{
+ int desired_instance = (int) _arg;
+
+ if (instance == desired_instance)
+ return 0;
+ return -ENODEV;
+}
+
+int cpu_find_by_instance(int instance, int *prom_node, int *mid)
+{
+ return __cpu_find_by(cpu_instance_compare, (void *)instance,
+ prom_node, mid);
+}
+
+static int cpu_mid_compare(int nd, int instance, void *_arg)
+{
+ int desired_mid = (int) _arg;
+ int this_mid;
+
+ this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0);
+ if (this_mid == desired_mid
+ || (sparc_cpu_model == sun4m && (this_mid & 3) == desired_mid))
+ return 0;
+ return -ENODEV;
+}
+
+int cpu_find_by_mid(int mid, int *prom_node)
+{
+ return __cpu_find_by(cpu_mid_compare, (void *)mid,
+ prom_node, NULL);
+}
+
+/* sun4m uses truncated mids since we base the cpuid on the ttable/irqset
+ * address (0-3). This gives us the true hardware mid, which might have
+ * some other bits set. On 4d hardware and software mids are the same.
+ */
+int cpu_get_hwmid(int prom_node)
+{
+ return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV);
+}
+
+void __init device_scan(void)
+{
+ prom_printf("Booting Linux...\n");
+
+#ifndef CONFIG_SMP
+ {
+ int err, cpu_node;
+ err = cpu_find_by_instance(0, &cpu_node, NULL);
+ if (err) {
+ /* Probably a sun4e, Sun is trying to trick us ;-) */
+ prom_printf("No cpu nodes, cannot continue\n");
+ prom_halt();
+ }
+ cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
+ "clock-frequency",
+ 0);
+ }
+#endif /* !CONFIG_SMP */
+
+ cpu_probe();
+#ifdef CONFIG_SUN_AUXIO
+ {
+ extern void auxio_probe(void);
+ extern void auxio_power_probe(void);