patch-2.4.19 linux-2.4.19/arch/ppc64/kernel/setup.c

Next file: linux-2.4.19/arch/ppc64/kernel/signal.c
Previous file: linux-2.4.19/arch/ppc64/kernel/semaphore.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/arch/ppc64/kernel/setup.c linux-2.4.19/arch/ppc64/kernel/setup.c
@@ -0,0 +1,718 @@
+/*
+ * 
+ * Common boot and setup code.
+ *
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ *
+ *      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/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/ioport.h>
+#include <asm/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+#include <asm/smp.h>
+#include <asm/elf.h>
+#include <asm/machdep.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
+#include <asm/ppcdebug.h>
+#include <asm/time.h>
+
+extern unsigned long klimit;
+/* extern void *stab; */
+extern HTAB htab_data;
+extern unsigned long loops_per_jiffy;
+
+extern unsigned long embedded_sysmap_start;
+extern unsigned long embedded_sysmap_end;
+
+int have_of = 1;
+
+extern void  chrp_init(unsigned long r3,
+		       unsigned long r4,
+		       unsigned long r5,
+		       unsigned long r6,
+		       unsigned long r7);
+
+extern void chrp_init_map_io_space( void );
+extern void iSeries_init( void );
+extern void iSeries_init_early( void );
+extern void pSeries_init_early( void );
+extern void pSeriesLP_init_early(void);
+extern void mm_init_ppc64( void ); 
+
+unsigned long decr_overclock = 1;
+unsigned long decr_overclock_proc0 = 1;
+unsigned long decr_overclock_set = 0;
+unsigned long decr_overclock_proc0_set = 0;
+
+#ifdef CONFIG_XMON
+extern void xmon_map_scc(void);
+#endif
+
+char saved_command_line[256];
+unsigned char aux_device_present;
+
+void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
+		    unsigned long r6, unsigned long r7);
+int parse_bootinfo(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned long SYSRQ_KEY;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
+struct machdep_calls ppc_md;
+
+/*
+ * Perhaps we can put the pmac screen_info[] here
+ * on pmac as well so we don't need the ifdef's.
+ * Until we get multiple-console support in here
+ * that is.  -- Cort
+ * Maybe tie it to serial consoles, since this is really what
+ * these processors use on existing boards.  -- Dan
+ */ 
+struct screen_info screen_info = {
+	0, 25,			/* orig-x, orig-y */
+	0,			/* unused */
+	0,			/* orig-video-page */
+	0,			/* orig-video-mode */
+	80,			/* orig-video-cols */
+	0,0,0,			/* ega_ax, ega_bx, ega_cx */
+	25,			/* orig-video-lines */
+	1,			/* orig-video-isVGA */
+	16			/* orig-video-points */
+};
+
+/*
+ * These are used in binfmt_elf.c to put aux entries on the stack
+ * for each elf executable being started.
+ */
+int dcache_bsize;
+int icache_bsize;
+int ucache_bsize;
+
+/*
+ * Initialize the PPCDBG state.  Called before relocation has been enabled.
+ */
+void ppcdbg_initialize(void) {
+	unsigned long offset = reloc_offset();
+	struct naca_struct *_naca = RELOC(naca);
+
+	_naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
+}
+
+/*
+ * Do some initial setup of the system.  The paramters are those which 
+ * were passed in from the bootloader.
+ */
+void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
+		  unsigned long r6, unsigned long r7)
+{
+	/* This should be fixed properly in kernel/resource.c */
+	iomem_resource.end = MEM_SPACE_LIMIT;
+
+	/* pSeries systems are identified in prom.c via OF. */
+	if ( itLpNaca.xLparInstalled == 1 )
+		naca->platform = PLATFORM_ISERIES_LPAR;
+	
+	switch (naca->platform) {
+	case PLATFORM_ISERIES_LPAR:
+		iSeries_init_early();
+		break;
+
+#ifdef CONFIG_PPC_PSERIES
+	case PLATFORM_PSERIES:
+		pSeries_init_early();
+#ifdef CONFIG_BLK_DEV_INITRD
+		initrd_start = initrd_end = 0;
+#endif
+		parse_bootinfo();
+		break;
+
+	case PLATFORM_PSERIES_LPAR:
+		pSeriesLP_init_early();
+#ifdef CONFIG_BLK_DEV_INITRD
+		initrd_start = initrd_end = 0;
+#endif
+		parse_bootinfo();
+		break;
+#endif
+	}
+
+	udbg_puts("\n-----------------------------------------------------\n");
+	udbg_puts("Naca Info...\n\n");
+	udbg_puts("naca                       = 0x");
+	udbg_puthex((unsigned long)naca);
+	udbg_putc('\n');
+
+	udbg_puts("naca->processorCount       = 0x");
+	udbg_puthex(naca->processorCount);
+	udbg_putc('\n');
+
+	udbg_puts("naca->physicalMemorySize   = 0x");
+	udbg_puthex(naca->physicalMemorySize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->dCacheL1LineSize     = 0x");
+	udbg_puthex(naca->dCacheL1LineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->dCacheL1LogLineSize  = 0x");
+	udbg_puthex(naca->dCacheL1LogLineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->dCacheL1LinesPerPage = 0x");
+	udbg_puthex(naca->dCacheL1LinesPerPage);
+	udbg_putc('\n');
+
+	udbg_puts("naca->iCacheL1LineSize     = 0x");
+	udbg_puthex(naca->iCacheL1LineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->iCacheL1LogLineSize  = 0x");
+	udbg_puthex(naca->iCacheL1LogLineSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->iCacheL1LinesPerPage = 0x");
+	udbg_puthex(naca->iCacheL1LinesPerPage);
+	udbg_putc('\n');
+
+	udbg_puts("naca->pftSize              = 0x");
+	udbg_puthex(naca->pftSize);
+	udbg_putc('\n');
+
+	udbg_puts("naca->serialPortAddr       = 0x");
+	udbg_puthex(naca->serialPortAddr);
+	udbg_putc('\n');
+
+	udbg_puts("naca->interrupt_controller = 0x");
+	udbg_puthex(naca->interrupt_controller);
+	udbg_putc('\n');
+
+	udbg_printf("\nHTAB Info ...\n\n"); 
+	udbg_puts("htab_data.htab             = 0x");
+	udbg_puthex((unsigned long)htab_data.htab);
+	udbg_putc('\n');
+	udbg_puts("htab_data.num_ptegs        = 0x");
+	udbg_puthex(htab_data.htab_num_ptegs);
+	udbg_putc('\n');
+
+	udbg_puts("\n-----------------------------------------------------\n");
+
+
+	if (naca->platform & PLATFORM_PSERIES) {
+		finish_device_tree();
+		chrp_init(r3, r4, r5, r6, r7);
+	}
+
+	mm_init_ppc64();
+
+	switch (naca->platform) {
+	case PLATFORM_ISERIES_LPAR:
+		iSeries_init();
+		break;
+	default:
+		/* The following relies on the device tree being */
+		/* fully configured.                             */
+		parse_cmd_line(r3, r4, r5, r6, r7);
+	}
+}
+
+void machine_restart(char *cmd)
+{
+	ppc_md.restart(cmd);
+}
+  
+void machine_power_off(void)
+{
+	ppc_md.power_off();
+}
+  
+void machine_halt(void)
+{
+	ppc_md.halt();
+}
+
+unsigned long ppc_proc_freq;
+unsigned long ppc_tb_freq;
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	unsigned long cpu_id = (unsigned long)v - 1;
+	unsigned int pvr;
+	unsigned short maj;
+	unsigned short min;
+
+#ifdef CONFIG_SMP
+	if (cpu_id == NR_CPUS) {
+
+		if (ppc_md.get_cpuinfo != NULL)
+			ppc_md.get_cpuinfo(m);
+
+		return 0;
+	}
+
+	if (!(cpu_online_map & (1<<cpu_id)))
+		return 0;
+#endif
+
+	pvr = paca[cpu_id].pvr;
+	maj = (pvr >> 8) & 0xFF;
+	min = pvr & 0xFF;
+
+	seq_printf(m, "processor\t: %lu\n", cpu_id);
+	seq_printf(m, "cpu\t\t: ");
+
+	pvr = paca[cpu_id].pvr;
+
+	switch (PVR_VER(pvr)) {
+	case PV_PULSAR:
+		seq_printf(m, "RS64-III (pulsar)\n");
+		break;
+	case PV_POWER4:
+		seq_printf(m, "POWER4 (gp)\n");
+		break;
+	case PV_ICESTAR:
+		seq_printf(m, "RS64-III (icestar)\n");
+		break;
+	case PV_SSTAR:
+		seq_printf(m, "RS64-IV (sstar)\n");
+		break;
+	case PV_630:
+		seq_printf(m, "POWER3 (630)\n");
+		break;
+	case PV_630p:
+		seq_printf(m, "POWER3 (630+)\n");
+		break;
+	default:
+		seq_printf(m, "Unknown (%08x)\n", pvr);
+		break;
+	}
+
+	/*
+	 * Assume here that all clock rates are the same in a
+	 * smp system.  -- Cort
+	 */
+	if (naca->platform != PLATFORM_ISERIES_LPAR) {
+		struct device_node *cpu_node;
+		int *fp;
+
+		cpu_node = find_type_devices("cpu");
+		if (cpu_node) {
+			fp = (int *) get_property(cpu_node, "clock-frequency",
+						  NULL);
+			if (fp)
+				seq_printf(m, "clock\t\t: %dMHz\n",
+					   *fp / 1000000);
+		}
+	}
+
+	if (ppc_md.setup_residual != NULL)
+		ppc_md.setup_residual(m, cpu_id);
+
+	seq_printf(m, "revision\t: %hd.%hd\n", maj, min);
+	
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
+
+/*
+ * Fetch the cmd_line from open firmware. */
+void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
+		  unsigned long r6, unsigned long r7)
+{
+	struct device_node *chosen;
+	char *p;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if ((initrd_start == 0) && r3 && r4 && r4 != 0xdeadbeef) {
+		initrd_start = (r3 >= KERNELBASE) ? r3 : (unsigned long)__va(r3);
+		initrd_end = initrd_start + r4;
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+		initrd_below_start_ok = 1;
+	}
+#endif
+
+	cmd_line[0] = 0;
+	chosen = find_devices("chosen");
+	if (chosen != NULL) {
+		p = get_property(chosen, "bootargs", NULL);
+		if (p != NULL)
+			strncpy(cmd_line, p, sizeof(cmd_line));
+	}
+	cmd_line[sizeof(cmd_line) - 1] = 0;
+
+	/* Look for mem= option on command line */
+	if (strstr(cmd_line, "mem=")) {
+		char *p, *q;
+		unsigned long maxmem = 0;
+		extern unsigned long __max_memory;
+
+		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
+			q = p + 4;
+			if (p > cmd_line && p[-1] != ' ')
+				continue;
+			maxmem = simple_strtoul(q, &q, 0);
+			if (*q == 'k' || *q == 'K') {
+				maxmem <<= 10;
+				++q;
+			} else if (*q == 'm' || *q == 'M') {
+				maxmem <<= 20;
+				++q;
+			}
+		}
+		__max_memory = maxmem;
+	}
+	ppc_md.progress("id mach: done", 0x200);
+}
+
+
+char *bi_tag2str(unsigned long tag)
+{
+	switch (tag) {
+	case BI_FIRST:
+		return "BI_FIRST";
+	case BI_LAST:
+		return "BI_LAST";
+	case BI_CMD_LINE:
+		return "BI_CMD_LINE";
+	case BI_BOOTLOADER_ID:
+		return "BI_BOOTLOADER_ID";
+	case BI_INITRD:
+		return "BI_INITRD";
+	case BI_SYSMAP:
+		return "BI_SYSMAP";
+	case BI_MACHTYPE:
+		return "BI_MACHTYPE";
+	default:
+		return "BI_UNKNOWN";
+	}
+}
+
+int parse_bootinfo(void)
+{
+	struct bi_record *rec;
+	extern char *sysmap;
+	extern unsigned long sysmap_size;
+
+	rec = prom.bi_recs;
+
+	if ( rec == NULL || rec->tag != BI_FIRST )
+		return -1;
+
+	for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) {
+		switch (rec->tag) {
+		case BI_CMD_LINE:
+			memcpy(cmd_line, (void *)rec->data, rec->size);
+			break;
+		case BI_SYSMAP:
+			sysmap = (char *)((rec->data[0] >= (KERNELBASE))
+					? rec->data[0] : (unsigned long)__va(rec->data[0]));
+			sysmap_size = rec->data[1];
+			break;
+#ifdef CONFIG_BLK_DEV_INITRD
+		case BI_INITRD:
+			initrd_start = (unsigned long)__va(rec->data[0]);
+			initrd_end = initrd_start + rec->data[1];
+			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+			initrd_below_start_ok = 1;
+			break;
+#endif /* CONFIG_BLK_DEV_INITRD */
+		}
+	}
+
+	return 0;
+}
+
+void __init ppc_init(void)
+{
+	/* clear the progress line */
+	ppc_md.progress(" ", 0xffff);
+
+	if (ppc_md.init != NULL) {
+		ppc_md.init();
+	}
+}
+
+void __init ppc64_calibrate_delay(void)
+{
+	loops_per_jiffy = tb_ticks_per_jiffy;
+
+	printk("Calibrating delay loop... %lu.%02lu BogoMips\n",
+			       loops_per_jiffy/(500000/HZ),
+			       loops_per_jiffy/(5000/HZ) % 100);
+
+}	
+
+extern void (*calibrate_delay)(void);
+
+/*
+ * Called into from start_kernel, after lock_kernel has been called.
+ * Initializes bootmem, which is unsed to manage page allocation until
+ * mem_init is called.
+ */
+void __init setup_arch(char **cmdline_p)
+{
+	extern int panic_timeout;
+	extern char _etext[], _edata[];
+	extern void do_init_bootmem(void);
+
+	calibrate_delay = ppc64_calibrate_delay;
+
+#ifdef CONFIG_XMON
+	xmon_map_scc();
+	if (strstr(cmd_line, "xmon"))
+		xmon(0);
+#endif /* CONFIG_XMON */
+#ifdef CONFIG_KDB
+	xmon_map_scc();	/* in kdb/start.c --need to rename TAI */
+#endif
+	ppc_md.progress("setup_arch:enter", 0x3eab);
+
+#if defined(CONFIG_KGDB)
+	kgdb_map_scc();
+	set_debug_traps();
+	breakpoint();
+#endif
+	/*
+	 * Set cache line size based on type of cpu as a default.
+	 * Systems with OF can look in the properties on the cpu node(s)
+	 * for a possibly more accurate value.
+	 */
+	dcache_bsize = naca->dCacheL1LineSize; 
+	icache_bsize = naca->iCacheL1LineSize; 
+
+	/* reboot on panic */
+	panic_timeout = 180;
+
+	init_mm.start_code = PAGE_OFFSET;
+	init_mm.end_code = (unsigned long) _etext;
+	init_mm.end_data = (unsigned long) _edata;
+	init_mm.brk = (unsigned long) klimit;
+	
+	/* Save unparsed command line copy for /proc/cmdline */
+	strcpy(saved_command_line, cmd_line);
+	*cmdline_p = cmd_line;
+
+	/* set up the bootmem stuff with available memory */
+	do_init_bootmem();
+	ppc_md.progress("setup_arch:bootmem", 0x3eab);
+
+	ppc_md.setup_arch();
+
+	paging_init();
+	ppc_md.progress("setup_arch: exit", 0x3eab);
+}
+
+#ifdef CONFIG_IDE
+
+/* Convert the shorts/longs in hd_driveid from little to big endian;
+ * chars are endian independant, of course, but strings need to be flipped.
+ * (Despite what it says in drivers/block/ide.h, they come up as little
+ * endian...)
+ *
+ * Changes to linux/hdreg.h may require changes here. */
+void ppc64_ide_fix_driveid(struct hd_driveid *id)
+{
+        int i;
+	unsigned short *stringcast;
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (unsigned short *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (unsigned short *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (unsigned short *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; i++)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+        for (i = 0; i < 4; i++)
+                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; i++)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->word89         = __le16_to_cpu(id->word89);
+	id->word90         = __le16_to_cpu(id->word90);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->word92         = __le16_to_cpu(id->word92);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	for (i = 0; i < 5; i++)
+		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 21; i++)
+		id->words104_125[i]  = __le16_to_cpu(id->words104_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	id->cfa_power=__le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 15; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 29; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word=__le16_to_cpu(id->integrity_word);
+}
+#endif
+
+
+void exception_trace(unsigned long trap)
+{
+	unsigned long x, srr0, srr1, reg20, reg1, reg21;
+
+	asm("mflr %0" : "=r" (x) :);
+	asm("mfspr %0,0x1a" : "=r" (srr0) :);
+	asm("mfspr %0,0x1b" : "=r" (srr1) :);
+	asm("mr %0,1" : "=r" (reg1) :);
+	asm("mr %0,20" : "=r" (reg20) :);
+	asm("mr %0,21" : "=r" (reg21) :);
+
+	udbg_puts("\n");
+	udbg_puts("Took an exception : "); udbg_puthex(x); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(reg1); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(reg20); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(reg21); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(srr0); udbg_puts("\n");
+	udbg_puts("   "); udbg_puthex(srr1); udbg_puts("\n");
+}
+
+int set_spread_lpevents( char * str )
+{
+	/* The parameter is the number of processors to share in processing lp events */
+	unsigned long i;
+	unsigned long val = simple_strtoul( str, NULL, 0 );
+	if ( ( val > 0 ) && ( val <= MAX_PACAS ) ) {
+		for ( i=1; i<val; ++i )
+			paca[i].lpQueuePtr = paca[0].lpQueuePtr;
+		printk("lpevent processing spread over %ld processors\n", val);
+	}
+	else
+		printk("invalid spreaqd_lpevents %ld\n", val);
+	return 1;
+}	
+
+/* This should only be called on processor 0 during calibrate decr */
+void setup_default_decr(void)
+{
+	struct paca_struct *lpaca = get_paca();
+
+	if ( decr_overclock_set && !decr_overclock_proc0_set )
+		decr_overclock_proc0 = decr_overclock;
+
+	lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;	
+	lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
+}
+
+int set_decr_overclock_proc0( char * str )
+{
+	unsigned long val = simple_strtoul( str, NULL, 0 );
+	if ( ( val >= 1 ) && ( val <= 48 ) ) {
+		decr_overclock_proc0_set = 1;
+		decr_overclock_proc0 = val;
+		printk("proc 0 decrementer overclock factor of %ld\n", val);
+	}
+	else
+		printk("invalid proc 0 decrementer overclock factor of %ld\n", val);
+	return 1;
+}
+
+int set_decr_overclock( char * str )
+{
+	unsigned long val = simple_strtoul( str, NULL, 0 );
+	if ( ( val >= 1 ) && ( val <= 48 ) ) {
+		decr_overclock_set = 1;
+		decr_overclock = val;
+		printk("decrementer overclock factor of %ld\n", val);
+	}
+	else
+		printk("invalid decrementer overclock factor of %ld\n", val);
+	return 1;
+
+}
+
+__setup("spread_lpevents=", set_spread_lpevents );
+__setup("decr_overclock_proc0=", set_decr_overclock_proc0 );
+__setup("decr_overclock=", set_decr_overclock );

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)