1 /*
2  *
3  * Common boot and setup code.
4  *
5  * Copyright (C) 2001 PPC64 Team, IBM Corp
6  *
7  *      This program is free software; you can redistribute it and/or
8  *      modify it under the terms of the GNU General Public License
9  *      as published by the Free Software Foundation; either version
10  *      2 of the License, or (at your option) any later version.
11  */
12 
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/string.h>
16 #include <linux/sched.h>
17 #include <linux/init.h>
18 #include <linux/reboot.h>
19 #include <linux/delay.h>
20 #include <linux/blk.h>
21 #include <linux/ide.h>
22 #include <linux/seq_file.h>
23 #include <linux/ioport.h>
24 #include <linux/console.h>
25 #include <linux/version.h>
26 #include <asm/init.h>
27 #include <asm/io.h>
28 #include <asm/prom.h>
29 #include <asm/processor.h>
30 #include <asm/pgtable.h>
31 #include <asm/bootinfo.h>
32 #include <asm/smp.h>
33 #include <asm/elf.h>
34 #include <asm/machdep.h>
35 #include <asm/iSeries/LparData.h>
36 #include <asm/naca.h>
37 #include <asm/paca.h>
38 #include <asm/ppcdebug.h>
39 #include <asm/time.h>
40 #include <asm/cputable.h>
41 
42 extern unsigned long klimit;
43 /* extern void *stab; */
44 extern HTAB htab_data;
45 extern unsigned long loops_per_jiffy;
46 extern int blk_nohighio;
47 
48 extern unsigned long embedded_sysmap_start;
49 extern unsigned long embedded_sysmap_end;
50 
51 int have_of = 1;
52 
53 extern void  chrp_init(unsigned long r3,
54 		       unsigned long r4,
55 		       unsigned long r5,
56 		       unsigned long r6,
57 		       unsigned long r7);
58 
59 extern void chrp_init_map_io_space( void );
60 extern void iSeries_init( void );
61 extern void iSeries_init_early( void );
62 extern void pSeries_init_early( void );
63 extern void pSeriesLP_init_early(void);
64 extern void mm_init_ppc64( void );
65 extern void pseries_secondary_smp_init(unsigned long);
66 
67 unsigned long decr_overclock = 1;
68 unsigned long decr_overclock_proc0 = 1;
69 unsigned long decr_overclock_set = 0;
70 unsigned long decr_overclock_proc0_set = 0;
71 
72 #ifdef CONFIG_XMON
73 extern void xmon_map_scc(void);
74 #endif
75 
76 char saved_command_line[256];
77 unsigned char aux_device_present;
78 
79 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
80 		    unsigned long r6, unsigned long r7);
81 int parse_bootinfo(void);
82 
83 #ifdef CONFIG_MAGIC_SYSRQ
84 unsigned long SYSRQ_KEY;
85 #endif /* CONFIG_MAGIC_SYSRQ */
86 
87 struct machdep_calls ppc_md;
88 
89 /*
90  * These are used in binfmt_elf.c to put aux entries on the stack
91  * for each elf executable being started.
92  */
93 int dcache_bsize;
94 int icache_bsize;
95 int ucache_bsize;
96 
97 struct console udbg_console = {
98 	name:	"udbg",
99 	write:	udbg_console_write,
100 	flags:	CON_PRINTBUFFER,
101 	index:	-1,
102 };
103 
104 /*
105  * Do some initial setup of the system.  The parameters are those which
106  * were passed in from the bootloader.
107  */
setup_system(unsigned long r3,unsigned long r4,unsigned long r5,unsigned long r6,unsigned long r7)108 void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
109 		  unsigned long r6, unsigned long r7)
110 {
111 	unsigned int ret, i;
112 
113 	/* This should be fixed properly in kernel/resource.c */
114 	iomem_resource.end = MEM_SPACE_LIMIT;
115 
116 	/* pSeries systems are identified in prom.c via OF. */
117 	if ( itLpNaca.xLparInstalled == 1 )
118 		systemcfg->platform = PLATFORM_ISERIES_LPAR;
119 
120 	switch (systemcfg->platform) {
121 	case PLATFORM_ISERIES_LPAR:
122 		iSeries_init_early();
123 		break;
124 
125 #ifdef CONFIG_PPC_PSERIES
126 	case PLATFORM_PSERIES:
127 		pSeries_init_early();
128 #ifdef CONFIG_BLK_DEV_INITRD
129 		initrd_start = initrd_end = 0;
130 #endif
131 		parse_bootinfo();
132 		break;
133 
134 	case PLATFORM_PSERIES_LPAR:
135 		pSeriesLP_init_early();
136 #ifdef CONFIG_BLK_DEV_INITRD
137 		initrd_start = initrd_end = 0;
138 #endif
139 		parse_bootinfo();
140 		break;
141 #endif
142 	}
143 
144 	if (systemcfg->platform & PLATFORM_PSERIES) {
145 		register_console(&udbg_console);
146 		udbg_printf("---- start early boot console ----\n");
147 	}
148 
149 	if (systemcfg->platform & PLATFORM_PSERIES) {
150 		finish_device_tree();
151 		chrp_init(r3, r4, r5, r6, r7);
152 
153 		/* Start secondary threads on SMT systems */
154 		for (i = 0; i < NR_CPUS; i++) {
155 			if(cpu_available(i)  && !cpu_possible(i)) {
156 				printk("%16.16lx : starting thread\n", i);
157 				rtas_call(rtas_token("start-cpu"), 3, 1,
158 					  (void *)&ret,
159 					  i, *((unsigned long *)pseries_secondary_smp_init), i);
160 				paca[i].active = 1;
161 				systemcfg->processorCount++;
162 			}
163 		}
164 	}
165 
166 	printk("-----------------------------------------------------\n");
167 	printk("naca                          = 0x%p\n", naca);
168 	printk("naca->pftSize                 = 0x%lx\n", naca->pftSize);
169 	printk("naca->paca                    = 0x%p\n\n", naca->paca);
170 	printk("systemcfg                     = 0x%p\n", systemcfg);
171 	printk("systemcfg->platform           = 0x%x\n", systemcfg->platform);
172 	printk("systemcfg->processor          = 0x%x\n", systemcfg->processor);
173 	printk("systemcfg->processorCount     = 0x%lx\n", systemcfg->processorCount);
174 	printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
175 	printk("systemcfg->dCacheL1LineSize   = 0x%x\n", systemcfg->dCacheL1LineSize);
176 	printk("systemcfg->iCacheL1LineSize   = 0x%x\n", systemcfg->iCacheL1LineSize);
177 	printk("htab_data.htab                = 0x%p\n", htab_data.htab);
178 	printk("htab_data.num_ptegs           = 0x%lx\n", htab_data.htab_num_ptegs);
179 	printk("-----------------------------------------------------\n");
180 
181 	printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
182 
183 	mm_init_ppc64();
184 
185 	if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
186 		vpa_init(0);
187 	}
188 
189 	idle_setup();
190 
191 	switch (systemcfg->platform) {
192 	    case PLATFORM_ISERIES_LPAR:
193 		iSeries_init();
194 		break;
195 	    default:
196 		/* The following relies on the device tree being */
197 		/* fully configured.                             */
198 		parse_cmd_line(r3, r4, r5, r6, r7);
199 	}
200 	ppc64_boot_msg(0x10, "Setup System");
201 }
202 
203 /* This is called just before console_init().
204  * It will be obsolete when Linux gets real early console support (2.5?)
205  * We need to hack preferred_console to retain the correct behavior
206  */
setup_before_console_init(void)207 void setup_before_console_init(void)
208 {
209 	if (systemcfg->platform & PLATFORM_PSERIES) {
210 		unregister_console(&udbg_console);
211 		udbg_console.next = NULL;
212 		udbg_printf("---- end early boot console ----\n");
213 	}
214 }
215 
machine_restart(char * cmd)216 void machine_restart(char *cmd)
217 {
218 	ppc_md.restart(cmd);
219 }
220 
machine_power_off(void)221 void machine_power_off(void)
222 {
223 	ppc_md.power_off();
224 }
225 
machine_halt(void)226 void machine_halt(void)
227 {
228 	ppc_md.halt();
229 }
230 
231 unsigned long ppc_proc_freq;
232 unsigned long ppc_tb_freq;
233 
show_cpuinfo(struct seq_file * m,void * v)234 static int show_cpuinfo(struct seq_file *m, void *v)
235 {
236 	unsigned long cpu_id = (unsigned long)v - 1;
237 	unsigned int pvr;
238 	unsigned short maj;
239 	unsigned short min;
240 
241 #ifdef CONFIG_SMP
242 	if (cpu_id == NR_CPUS) {
243 
244 		if (ppc_md.get_cpuinfo != NULL)
245 			ppc_md.get_cpuinfo(m);
246 
247 		return 0;
248 	}
249 
250 	if (!(cpu_online_map & (1<<cpu_id)))
251 		return 0;
252 #endif
253 
254 	pvr = paca[cpu_id].pvr;
255 	maj = (pvr >> 8) & 0xFF;
256 	min = pvr & 0xFF;
257 
258 	seq_printf(m, "processor\t: %lu\n", cpu_id);
259 	seq_printf(m, "cpu\t\t: ");
260 
261 	pvr = paca[cpu_id].pvr;
262 
263 	if (cur_cpu_spec->pvr_mask)
264 		seq_printf(m, "%s", cur_cpu_spec->cpu_name);
265 	else
266 		seq_printf(m, "unknown (%08x)", pvr);
267 
268 
269 	seq_printf(m, "\n");
270 
271 	/*
272 	 * Assume here that all clock rates are the same in a
273 	 * smp system.  -- Cort
274 	 */
275 	if (systemcfg->platform != PLATFORM_ISERIES_LPAR) {
276 		struct device_node *cpu_node;
277 		int *fp;
278 
279 		cpu_node = find_type_devices("cpu");
280 		if (cpu_node) {
281 			fp = (int *) get_property(cpu_node, "clock-frequency",
282 						  NULL);
283 			if (fp)
284 				seq_printf(m, "clock\t\t: %dMHz\n",
285 					   *fp / 1000000);
286 		}
287 	}
288 
289 	if (ppc_md.setup_residual != NULL)
290 		ppc_md.setup_residual(m, cpu_id);
291 
292 	seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min);
293 
294 	return 0;
295 }
296 
c_start(struct seq_file * m,loff_t * pos)297 static void *c_start(struct seq_file *m, loff_t *pos)
298 {
299 	return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL;
300 }
c_next(struct seq_file * m,void * v,loff_t * pos)301 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
302 {
303 	++*pos;
304 	return c_start(m, pos);
305 }
c_stop(struct seq_file * m,void * v)306 static void c_stop(struct seq_file *m, void *v)
307 {
308 }
309 struct seq_operations cpuinfo_op = {
310 	.start =c_start,
311 	.next =	c_next,
312 	.stop =	c_stop,
313 	.show =	show_cpuinfo,
314 };
315 
316 /*
317  * Fetch the cmd_line from open firmware.
318  */
parse_cmd_line(unsigned long r3,unsigned long r4,unsigned long r5,unsigned long r6,unsigned long r7)319 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
320 		  unsigned long r6, unsigned long r7)
321 {
322 	char *p;
323 
324 #ifdef CONFIG_BLK_DEV_INITRD
325 	if ((initrd_start == 0) && r3 && r4 && r4 != 0xdeadbeef) {
326 		initrd_start = (r3 >= KERNELBASE) ? r3 : (unsigned long)__va(r3);
327 		initrd_end = initrd_start + r4;
328 		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
329 		initrd_below_start_ok = 1;
330 		lmb_reserve(__pa(initrd_start),r4);
331 	}
332 #endif
333 
334 	/* Hack -- add console=ttySn,9600 if necessary */
335 	if(strstr(cmd_line, "console=") == NULL) {
336 		struct device_node *prom_stdout = find_path_device(of_stdout_device);
337 		u32 *reg;
338 		int i;
339 		char *name, *val = NULL;
340 		printk("of_stdout_device %s\n", of_stdout_device);
341 		if (prom_stdout) {
342 			name = (char *)get_property(prom_stdout, "name", NULL);
343 			if (name) {
344 				if (strcmp(name, "serial") == 0) {
345 					reg = (u32 *)get_property(prom_stdout, "reg", &i);
346 					if (i > 8) {
347 						switch (reg[1]) {
348 						    case 0x3f8: val = "ttyS0,9600"; break;
349 						    case 0x2f8: val = "ttyS1,9600"; break;
350 						    case 0x898: val = "ttyS2,9600"; break;
351 						    case 0x890: val = "ttyS3,9600"; break;
352 						}
353 					}
354 				} else if (strcmp(name, "vty") == 0) {
355 					/* pSeries LPAR virtual console */
356 					val = "hvc0";
357 				}
358 				if (val) {
359 					char tmp_cmd_line[512];
360 					snprintf(tmp_cmd_line, 512,
361 						 "AUTOCONSOLE console=%s %s",
362 						 val, cmd_line);
363 					memcpy(cmd_line, tmp_cmd_line, 512);
364 					printk("console= not found, add console=%s\ncmd_line is now %s\n",
365 					       val, cmd_line);
366 				}
367 			}
368 		}
369 	}
370 
371 	/* Look for mem= option on command line */
372 	if (strstr(cmd_line, "mem=")) {
373 		char *q;
374 		unsigned long maxmem = 0;
375 		extern unsigned long __max_memory;
376 
377 		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
378 			q = p + 4;
379 			if (p > cmd_line && p[-1] != ' ')
380 				continue;
381 			maxmem = simple_strtoul(q, &q, 0);
382 			if (*q == 'k' || *q == 'K') {
383 				maxmem <<= 10;
384 				++q;
385 			} else if (*q == 'm' || *q == 'M') {
386 				maxmem <<= 20;
387 				++q;
388 			}
389 		}
390 		__max_memory = maxmem;
391 	}
392 }
393 
394 #if 0
395 char *bi_tag2str(unsigned long tag)
396 {
397 	switch (tag) {
398 	case BI_FIRST:
399 		return "BI_FIRST";
400 	case BI_LAST:
401 		return "BI_LAST";
402 	case BI_CMD_LINE:
403 		return "BI_CMD_LINE";
404 	case BI_BOOTLOADER_ID:
405 		return "BI_BOOTLOADER_ID";
406 	case BI_INITRD:
407 		return "BI_INITRD";
408 	case BI_SYSMAP:
409 		return "BI_SYSMAP";
410 	case BI_MACHTYPE:
411 		return "BI_MACHTYPE";
412 	default:
413 		return "BI_UNKNOWN";
414 	}
415 }
416 #endif
417 
parse_bootinfo(void)418 int parse_bootinfo(void)
419 {
420 	struct bi_record *rec;
421 	extern char *sysmap;
422 	extern unsigned long sysmap_size;
423 
424 	rec = prom.bi_recs;
425 
426 	if ( rec == NULL || rec->tag != BI_FIRST )
427 		return -1;
428 
429 	for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) {
430 		switch (rec->tag) {
431 		case BI_CMD_LINE:
432 			memcpy(cmd_line, (void *)rec->data, rec->size);
433 			break;
434 		case BI_SYSMAP:
435 			sysmap = (char *)((rec->data[0] >= (KERNELBASE))
436 					? rec->data[0] : (unsigned long)__va(rec->data[0]));
437 			sysmap_size = rec->data[1];
438 			break;
439 #ifdef CONFIG_BLK_DEV_INITRD
440 		case BI_INITRD:
441 			initrd_start = (unsigned long)__va(rec->data[0]);
442 			initrd_end = initrd_start + rec->data[1];
443 			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
444 			initrd_below_start_ok = 1;
445 			break;
446 #endif /* CONFIG_BLK_DEV_INITRD */
447 		}
448 	}
449 
450 	return 0;
451 }
452 
ppc_init(void)453 void __init ppc_init(void)
454 {
455 	/* clear the progress line */
456 	ppc_md.progress(" ", 0xffff);
457 
458 	if (ppc_md.init != NULL) {
459 		ppc_md.init();
460 	}
461 }
462 
ppc64_calibrate_delay(void)463 void __init ppc64_calibrate_delay(void)
464 {
465 	loops_per_jiffy = tb_ticks_per_jiffy;
466 
467 	printk("Calibrating delay loop... %lu.%02lu BogoMips\n",
468 			       loops_per_jiffy/(500000/HZ),
469 			       loops_per_jiffy/(5000/HZ) % 100);
470 }
471 
472 extern void (*calibrate_delay)(void);
473 extern void sort_exception_table(void);
474 
475 /*
476  * Called into from start_kernel, after lock_kernel has been called.
477  * Initializes bootmem, which is unsed to manage page allocation until
478  * mem_init is called.
479  */
setup_arch(char ** cmdline_p)480 void __init setup_arch(char **cmdline_p)
481 {
482 	extern int panic_timeout;
483 	extern char _etext[], _edata[];
484 	extern void do_init_bootmem(void);
485 
486 	blk_nohighio = 1;
487 
488 	calibrate_delay = ppc64_calibrate_delay;
489 
490 	ppc64_boot_msg(0x12, "Setup Arch");
491 #ifdef CONFIG_XMON
492 	xmon_map_scc();
493 	if (strstr(cmd_line, "xmon"))
494 		xmon(0);
495 #endif /* CONFIG_XMON */
496 
497 #if defined(CONFIG_KGDB)
498 	kgdb_map_scc();
499 	set_debug_traps();
500 	breakpoint();
501 #endif
502 	/*
503 	 * Set cache line size based on type of cpu as a default.
504 	 * Systems with OF can look in the properties on the cpu node(s)
505 	 * for a possibly more accurate value.
506 	 */
507 	dcache_bsize = systemcfg->dCacheL1LineSize;
508 	icache_bsize = systemcfg->iCacheL1LineSize;
509 
510 	/* reboot on panic */
511 	panic_timeout = 180;
512 
513 	init_mm.start_code = PAGE_OFFSET;
514 	init_mm.end_code = (unsigned long) _etext;
515 	init_mm.end_data = (unsigned long) _edata;
516 	init_mm.brk = (unsigned long) klimit;
517 
518 	/* Save unparsed command line copy for /proc/cmdline */
519 	strcpy(saved_command_line, cmd_line);
520 	*cmdline_p = cmd_line;
521 
522 	/* set up the bootmem stuff with available memory */
523 	do_init_bootmem();
524 
525 	ppc_md.setup_arch();
526 
527 	paging_init();
528 	sort_exception_table();
529 	ppc64_boot_msg(0x15, "Setup Done");
530 }
531 
532 
533 /* ToDo: do something useful if ppc_md is not yet setup. */
534 #define PPC64_LINUX_FUNCTION 0x0f000000
535 #define PPC64_IPL_MESSAGE 0xc0000000
536 #define PPC64_TERM_MESSAGE 0xb0000000
537 #define PPC64_ATTN_MESSAGE 0xa0000000
538 #define PPC64_DUMP_MESSAGE 0xd0000000
539 
ppc64_do_msg(unsigned int src,const char * msg)540 static void ppc64_do_msg(unsigned int src, const char *msg)
541 {
542 	if (ppc_md.progress) {
543 		char buf[32];
544 
545 		sprintf(buf, "%08x        \n", src);
546 		ppc_md.progress(buf, 0);
547 		sprintf(buf, "%-16s", msg);
548 		ppc_md.progress(buf, 0);
549 	}
550 }
551 
552 /* Print a boot progress message. */
ppc64_boot_msg(unsigned int src,const char * msg)553 void ppc64_boot_msg(unsigned int src, const char *msg)
554 {
555 	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg);
556 	udbg_printf("[boot]%04x %s\n", src, msg);
557 }
558 
559 /* Print a termination message (print only -- does not stop the kernel) */
ppc64_terminate_msg(unsigned int src,const char * msg)560 void ppc64_terminate_msg(unsigned int src, const char *msg)
561 {
562 	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg);
563 	udbg_printf("[terminate]%04x %s\n", src, msg);
564 }
565 
566 /* Print something that needs attention (device error, etc) */
ppc64_attention_msg(unsigned int src,const char * msg)567 void ppc64_attention_msg(unsigned int src, const char *msg)
568 {
569 	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg);
570 	udbg_printf("[attention]%04x %s\n", src, msg);
571 }
572 
573 /* Print a dump progress message. */
ppc64_dump_msg(unsigned int src,const char * msg)574 void ppc64_dump_msg(unsigned int src, const char *msg)
575 {
576 	ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg);
577 	udbg_printf("[dump]%04x %s\n", src, msg);
578 }
579 
580 
exception_trace(unsigned long trap)581 void exception_trace(unsigned long trap)
582 {
583 	unsigned long x, srr0, srr1, reg20, reg1, reg21;
584 
585 	asm("mflr %0" : "=r" (x) :);
586 	asm("mfspr %0,0x1a" : "=r" (srr0) :);
587 	asm("mfspr %0,0x1b" : "=r" (srr1) :);
588 	asm("mr %0,1" : "=r" (reg1) :);
589 	asm("mr %0,20" : "=r" (reg20) :);
590 	asm("mr %0,21" : "=r" (reg21) :);
591 
592 	udbg_puts("\n");
593 	udbg_puts("Took an exception : "); udbg_puthex(x); udbg_puts("\n");
594 	udbg_puts("   "); udbg_puthex(reg1); udbg_puts("\n");
595 	udbg_puts("   "); udbg_puthex(reg20); udbg_puts("\n");
596 	udbg_puts("   "); udbg_puthex(reg21); udbg_puts("\n");
597 	udbg_puts("   "); udbg_puthex(srr0); udbg_puts("\n");
598 	udbg_puts("   "); udbg_puthex(srr1); udbg_puts("\n");
599 }
600 
do_spread_lpevents(unsigned long n)601 void do_spread_lpevents(unsigned long n)
602 {
603 	unsigned long i,m;
604 
605 	if (n < MAX_PACAS)
606 		m = n;
607 	else
608 		m = MAX_PACAS;
609 
610 	for (i=1; i<m; ++i)
611 		paca[i].lpQueuePtr = paca[0].lpQueuePtr;
612 
613 	printk("lpevent processing spread over %ld processors\n", n);
614 }
615 
616 /*
617  * The parameter is the number of processors to share in
618  * processing lp events
619  */
set_spread_lpevents(char * str)620 int set_spread_lpevents(char * str)
621 {
622 	unsigned long val = simple_strtoul( str, NULL, 0 );
623 	if ((val > 0) && (val <= MAX_PACAS)) {
624 		do_spread_lpevents(val);
625 	} else
626 		printk("invalid spreaqd_lpevents %ld\n", val);
627 
628 	return 1;
629 }
630 
631 /* This should only be called on processor 0 during calibrate decr */
setup_default_decr(void)632 void setup_default_decr(void)
633 {
634 	struct paca_struct *lpaca = get_paca();
635 
636 	if ( decr_overclock_set && !decr_overclock_proc0_set )
637 		decr_overclock_proc0 = decr_overclock;
638 
639 	lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;
640 	lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
641 }
642 
set_decr_overclock_proc0(char * str)643 int set_decr_overclock_proc0( char * str )
644 {
645 	unsigned long val = simple_strtoul( str, NULL, 0 );
646 	if ( ( val >= 1 ) && ( val <= 48 ) ) {
647 		decr_overclock_proc0_set = 1;
648 		decr_overclock_proc0 = val;
649 		printk("proc 0 decrementer overclock factor of %ld\n", val);
650 	}
651 	else
652 		printk("invalid proc 0 decrementer overclock factor of %ld\n", val);
653 	return 1;
654 }
655 
set_decr_overclock(char * str)656 int set_decr_overclock( char * str )
657 {
658 	unsigned long val = simple_strtoul( str, NULL, 0 );
659 	if ( ( val >= 1 ) && ( val <= 48 ) ) {
660 		decr_overclock_set = 1;
661 		decr_overclock = val;
662 		printk("decrementer overclock factor of %ld\n", val);
663 	}
664 	else
665 		printk("invalid decrementer overclock factor of %ld\n", val);
666 	return 1;
667 
668 }
669 
670 __setup("spread_lpevents=", set_spread_lpevents );
671 __setup("decr_overclock_proc0=", set_decr_overclock_proc0 );
672 __setup("decr_overclock=", set_decr_overclock );
673