diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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')
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 *)®s, sizeof(regs)) <= 0) + return; + prom_apply_obio_ranges(®s, 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); |