ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc64 / kernel / setup.c
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/initrd.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 <linux/tty.h>
27 #include <linux/root_dev.h>
28 #include <linux/notifier.h>
29 #include <linux/cpu.h>
30 #include <asm/io.h>
31 #include <asm/prom.h>
32 #include <asm/processor.h>
33 #include <asm/pgtable.h>
34 #include <asm/bootinfo.h>
35 #include <asm/smp.h>
36 #include <asm/elf.h>
37 #include <asm/machdep.h>
38 #include <asm/iSeries/LparData.h>
39 #include <asm/naca.h>
40 #include <asm/paca.h>
41 #include <asm/ppcdebug.h>
42 #include <asm/time.h>
43 #include <asm/cputable.h>
44 #include <asm/sections.h>
45 #include <asm/btext.h>
46 #include <asm/nvram.h>
47 #include <asm/system.h>
48
49 extern unsigned long klimit;
50 /* extern void *stab; */
51 extern HTAB htab_data;
52 extern unsigned long loops_per_jiffy;
53
54 int have_of = 1;
55
56 extern void  chrp_init(unsigned long r3,
57                        unsigned long r4,
58                        unsigned long r5,
59                        unsigned long r6,
60                        unsigned long r7);
61
62 extern void  pmac_init(unsigned long r3,
63                        unsigned long r4,
64                        unsigned long r5,
65                        unsigned long r6,
66                        unsigned long r7);
67
68 extern void iSeries_init( void );
69 extern void iSeries_init_early( void );
70 extern void pSeries_init_early( void );
71 extern void pSeriesLP_init_early(void);
72 extern void pmac_init_early(void);
73 extern void mm_init_ppc64( void ); 
74 extern void pseries_secondary_smp_init(unsigned long); 
75 extern int  idle_setup(void);
76 extern void vpa_init(int cpu);
77
78 unsigned long decr_overclock = 1;
79 unsigned long decr_overclock_proc0 = 1;
80 unsigned long decr_overclock_set = 0;
81 unsigned long decr_overclock_proc0_set = 0;
82
83 int powersave_nap;
84
85 char saved_command_line[COMMAND_LINE_SIZE];
86 unsigned char aux_device_present;
87
88 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
89                     unsigned long r6, unsigned long r7);
90 int parse_bootinfo(void);
91
92 #ifdef CONFIG_MAGIC_SYSRQ
93 unsigned long SYSRQ_KEY;
94 #endif /* CONFIG_MAGIC_SYSRQ */
95
96 struct machdep_calls ppc_md;
97
98 static int ppc64_panic_event(struct notifier_block *, unsigned long, void *);
99
100 static struct notifier_block ppc64_panic_block = {
101         notifier_call: ppc64_panic_event,
102         priority: INT_MIN /* may not return; must be done last */
103 };
104
105 /*
106  * Perhaps we can put the pmac screen_info[] here
107  * on pmac as well so we don't need the ifdef's.
108  * Until we get multiple-console support in here
109  * that is.  -- Cort
110  * Maybe tie it to serial consoles, since this is really what
111  * these processors use on existing boards.  -- Dan
112  */ 
113 struct screen_info screen_info = {
114         0, 25,                  /* orig-x, orig-y */
115         0,                      /* unused */
116         0,                      /* orig-video-page */
117         0,                      /* orig-video-mode */
118         80,                     /* orig-video-cols */
119         0,0,0,                  /* ega_ax, ega_bx, ega_cx */
120         25,                     /* orig-video-lines */
121         1,                      /* orig-video-isVGA */
122         16                      /* orig-video-points */
123 };
124
125 /*
126  * These are used in binfmt_elf.c to put aux entries on the stack
127  * for each elf executable being started.
128  */
129 int dcache_bsize;
130 int icache_bsize;
131 int ucache_bsize;
132
133 /*
134  * Initialize the PPCDBG state.  Called before relocation has been enabled.
135  */
136 void ppcdbg_initialize(void) {
137         unsigned long offset = reloc_offset();
138         struct naca_struct *_naca = RELOC(naca);
139
140         _naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
141 }
142
143 static struct console udbg_console = {
144         .name   = "udbg",
145         .write  = udbg_console_write,
146         .flags  = CON_PRINTBUFFER,
147         .index  = -1,
148 };
149
150 static int early_console_initialized;
151
152 void __init disable_early_printk(void)
153 {
154         if (!early_console_initialized)
155                 return;
156         unregister_console(&udbg_console);
157         early_console_initialized = 0;
158 }
159
160 /*
161  * Do some initial setup of the system.  The parameters are those which 
162  * were passed in from the bootloader.
163  */
164 void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
165                   unsigned long r6, unsigned long r7)
166 {
167 #if defined(CONFIG_SMP) && defined(CONFIG_PPC_PSERIES)
168         unsigned int ret, i;
169 #endif
170
171 #ifdef CONFIG_XMON_DEFAULT
172         xmon_init();
173 #endif
174
175 #ifdef CONFIG_PPC_ISERIES
176         /* pSeries systems are identified in prom.c via OF. */
177         if ( itLpNaca.xLparInstalled == 1 )
178                 systemcfg->platform = PLATFORM_ISERIES_LPAR;
179 #endif
180         
181         switch (systemcfg->platform) {
182 #ifdef CONFIG_PPC_ISERIES
183         case PLATFORM_ISERIES_LPAR:
184                 iSeries_init_early();
185                 break;
186 #endif
187
188 #ifdef CONFIG_PPC_PSERIES
189         case PLATFORM_PSERIES:
190                 pSeries_init_early();
191                 parse_bootinfo();
192                 break;
193
194         case PLATFORM_PSERIES_LPAR:
195                 pSeriesLP_init_early();
196                 parse_bootinfo();
197                 break;
198 #endif /* CONFIG_PPC_PSERIES */
199 #ifdef CONFIG_PPC_PMAC
200         case PLATFORM_POWERMAC:
201                 pmac_init_early();
202                 parse_bootinfo();
203 #endif /* CONFIG_PPC_PMAC */
204         }
205
206         /* If we were passed an initrd, set the ROOT_DEV properly if the values
207          * look sensible. If not, clear initrd reference.
208          */
209 #ifdef CONFIG_BLK_DEV_INITRD
210         if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
211             initrd_end > initrd_start)
212                 ROOT_DEV = Root_RAM0;
213         else
214                 initrd_start = initrd_end = 0;
215 #endif /* CONFIG_BLK_DEV_INITRD */
216
217 #ifdef CONFIG_BOOTX_TEXT
218         map_boot_text();
219         if (systemcfg->platform == PLATFORM_POWERMAC) {
220                 early_console_initialized = 1;
221                 register_console(&udbg_console);
222         }
223 #endif /* CONFIG_BOOTX_TEXT */
224
225 #ifdef CONFIG_PPC_PSERIES
226         if (systemcfg->platform & PLATFORM_PSERIES) {
227                 early_console_initialized = 1;
228                 register_console(&udbg_console);
229                 __irq_offset_value = NUM_ISA_INTERRUPTS;
230                 finish_device_tree();
231                 chrp_init(r3, r4, r5, r6, r7);
232
233 #ifdef CONFIG_SMP
234                 /* Start secondary threads on SMT systems */
235                 for (i = 0; i < NR_CPUS; i++) {
236                         if(cpu_available(i)  && !cpu_possible(i)) {
237                                 printk("%16.16x : starting thread\n", i);
238                                 rtas_call(rtas_token("start-cpu"), 3, 1, 
239                                           (void *)&ret,
240                                           get_hard_smp_processor_id(i), 
241                                           *((unsigned long *)pseries_secondary_smp_init),
242                                           i);
243                                 cpu_set(i, cpu_possible_map);
244                                 systemcfg->processorCount++;
245                         }
246                 }
247 #endif /* CONFIG_SMP */
248         }
249 #endif /* CONFIG_PPC_PSERIES */
250
251 #ifdef CONFIG_PPC_PMAC
252         if (systemcfg->platform == PLATFORM_POWERMAC) {
253                 finish_device_tree();
254                 pmac_init(r3, r4, r5, r6, r7);
255         }
256 #endif /* CONFIG_PPC_PMAC */
257
258         /* Finish initializing the hash table (do the dynamic
259          * patching for the fast-path hashtable.S code)
260          */
261         htab_finish_init();
262
263         printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
264
265         printk("-----------------------------------------------------\n");
266         printk("naca                          = 0x%p\n", naca);
267         printk("naca->pftSize                 = 0x%lx\n", naca->pftSize);
268         printk("naca->debug_switch            = 0x%lx\n", naca->debug_switch);
269         printk("naca->interrupt_controller    = 0x%ld\n", naca->interrupt_controller);
270         printk("systemcfg                     = 0x%p\n", systemcfg);
271         printk("systemcfg->processorCount     = 0x%lx\n", systemcfg->processorCount);
272         printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
273         printk("systemcfg->dCacheL1LineSize   = 0x%x\n", systemcfg->dCacheL1LineSize);
274         printk("systemcfg->iCacheL1LineSize   = 0x%x\n", systemcfg->iCacheL1LineSize);
275         printk("htab_data.htab                = 0x%p\n", htab_data.htab);
276         printk("htab_data.num_ptegs           = 0x%lx\n", htab_data.htab_num_ptegs);
277         printk("-----------------------------------------------------\n");
278
279         mm_init_ppc64();
280
281 #if defined(CONFIG_SMP) && defined(CONFIG_PPC_PSERIES)
282         if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
283                 vpa_init(boot_cpuid);
284         }
285 #endif
286
287         /* Select the correct idle loop for the platform. */
288         idle_setup();
289
290         switch (systemcfg->platform) {
291 #ifdef CONFIG_PPC_ISERIES
292         case PLATFORM_ISERIES_LPAR:
293                 iSeries_init();
294                 break;
295 #endif
296         default:
297                 /* The following relies on the device tree being */
298                 /* fully configured.                             */
299                 parse_cmd_line(r3, r4, r5, r6, r7);
300         }
301 }
302
303 void machine_restart(char *cmd)
304 {
305         if (ppc_md.nvram_sync)
306                 ppc_md.nvram_sync();
307         ppc_md.restart(cmd);
308 }
309
310 EXPORT_SYMBOL(machine_restart);
311   
312 void machine_power_off(void)
313 {
314         if (ppc_md.nvram_sync)
315                 ppc_md.nvram_sync();
316         ppc_md.power_off();
317 }
318
319 EXPORT_SYMBOL(machine_power_off);
320   
321 void machine_halt(void)
322 {
323         if (ppc_md.nvram_sync)
324                 ppc_md.nvram_sync();
325         ppc_md.halt();
326 }
327
328 EXPORT_SYMBOL(machine_halt);
329
330 unsigned long ppc_proc_freq;
331 unsigned long ppc_tb_freq;
332
333 static int ppc64_panic_event(struct notifier_block *this,
334                              unsigned long event, void *ptr)
335 {
336         ppc_md.panic((char *)ptr);  /* May not return */
337         return NOTIFY_DONE;
338 }
339
340
341 #ifdef CONFIG_SMP
342 DEFINE_PER_CPU(unsigned int, pvr);
343 #endif
344
345 static int show_cpuinfo(struct seq_file *m, void *v)
346 {
347         unsigned long cpu_id = (unsigned long)v - 1;
348         unsigned int pvr;
349         unsigned short maj;
350         unsigned short min;
351
352         if (cpu_id == NR_CPUS) {
353                 seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
354
355                 if (ppc_md.get_cpuinfo != NULL)
356                         ppc_md.get_cpuinfo(m);
357
358                 return 0;
359         }
360
361         /* We only show online cpus: disable preempt (overzealous, I
362          * knew) to prevent cpu going down. */
363         preempt_disable();
364         if (!cpu_online(cpu_id)) {
365                 preempt_enable();
366                 return 0;
367         }
368
369 #ifdef CONFIG_SMP
370         pvr = per_cpu(pvr, cpu_id);
371 #else
372         pvr = _get_PVR();
373 #endif
374         maj = (pvr >> 8) & 0xFF;
375         min = pvr & 0xFF;
376
377         seq_printf(m, "processor\t: %lu\n", cpu_id);
378         seq_printf(m, "cpu\t\t: ");
379
380         if (cur_cpu_spec->pvr_mask)
381                 seq_printf(m, "%s", cur_cpu_spec->cpu_name);
382         else
383                 seq_printf(m, "unknown (%08x)", pvr);
384
385 #ifdef CONFIG_ALTIVEC
386         if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
387                 seq_printf(m, ", altivec supported");
388 #endif /* CONFIG_ALTIVEC */
389
390         seq_printf(m, "\n");
391
392         /*
393          * Assume here that all clock rates are the same in a
394          * smp system.  -- Cort
395          */
396         seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000,
397                    ppc_proc_freq % 1000000);
398
399         seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min);
400
401         preempt_enable();
402         return 0;
403 }
404
405 static void *c_start(struct seq_file *m, loff_t *pos)
406 {
407         return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL;
408 }
409 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
410 {
411         ++*pos;
412         return c_start(m, pos);
413 }
414 static void c_stop(struct seq_file *m, void *v)
415 {
416 }
417 struct seq_operations cpuinfo_op = {
418         .start =c_start,
419         .next = c_next,
420         .stop = c_stop,
421         .show = show_cpuinfo,
422 };
423
424 /*
425  * Fetch the cmd_line from open firmware. 
426  */
427 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
428                   unsigned long r6, unsigned long r7)
429 {
430         cmd_line[0] = 0;
431
432 #ifdef CONFIG_CMDLINE
433         strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
434 #endif /* CONFIG_CMDLINE */
435
436 #ifdef CONFIG_PPC_PSERIES
437         {
438         struct device_node *chosen;
439
440         chosen = of_find_node_by_name(NULL, "chosen");
441         if (chosen != NULL) {
442                 char *p;
443                 p = get_property(chosen, "bootargs", NULL);
444                 if (p != NULL && p[0] != 0)
445                         strlcpy(cmd_line, p, sizeof(cmd_line));
446                 of_node_put(chosen);
447         }
448         }
449 #endif
450
451         /* Look for mem= option on command line */
452         if (strstr(cmd_line, "mem=")) {
453                 char *p, *q;
454                 unsigned long maxmem = 0;
455                 extern unsigned long __max_memory;
456
457                 for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
458                         q = p + 4;
459                         if (p > cmd_line && p[-1] != ' ')
460                                 continue;
461                         maxmem = simple_strtoul(q, &q, 0);
462                         if (*q == 'k' || *q == 'K') {
463                                 maxmem <<= 10;
464                                 ++q;
465                         } else if (*q == 'm' || *q == 'M') {
466                                 maxmem <<= 20;
467                                 ++q;
468                         }
469                 }
470                 __max_memory = maxmem;
471         }
472 }
473
474 #ifdef CONFIG_PPC_PSERIES
475 static int __init set_preferred_console(void)
476 {
477         struct device_node *prom_stdout;
478         char *name;
479
480         /* The user has requested a console so this is already set up. */
481         if (strstr(saved_command_line, "console="))
482                 return -EBUSY;
483
484         prom_stdout = find_path_device(of_stdout_device);
485         if (!prom_stdout)
486                 return -ENODEV;
487
488         name = (char *)get_property(prom_stdout, "name", NULL);
489         if (!name)
490                 return -ENODEV;
491
492         if (strcmp(name, "serial") == 0) {
493                 int i;
494                 u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
495                 if (i > 8) {
496                         int offset;
497                         switch (reg[1]) {
498                                 case 0x3f8:
499                                         offset = 0;
500                                         break;
501                                 case 0x2f8:
502                                         offset = 1;
503                                         break;
504                                 case 0x898:
505                                         offset = 2;
506                                         break;
507                                 case 0x890:
508                                         offset = 3;
509                                         break;
510                                 default:
511                                         /* We dont recognise the serial port */
512                                         return -ENODEV;
513                         }
514
515                         return add_preferred_console("ttyS", offset, NULL);
516                 }
517         } else if (strcmp(name, "vty") == 0) {
518                 /* pSeries LPAR virtual console */
519                 return add_preferred_console("hvc", 0, NULL);
520         }
521
522         return -ENODEV;
523 }
524 console_initcall(set_preferred_console);
525
526 int parse_bootinfo(void)
527 {
528         struct bi_record *rec;
529
530         rec = prom.bi_recs;
531
532         if ( rec == NULL || rec->tag != BI_FIRST )
533                 return -1;
534
535         for ( ; rec->tag != BI_LAST ; rec = bi_rec_next(rec) ) {
536                 switch (rec->tag) {
537                 case BI_CMD_LINE:
538                         strlcpy(cmd_line, (void *)rec->data, sizeof(cmd_line));
539                         break;
540                 }
541         }
542
543         return 0;
544 }
545 #endif
546
547 int __init ppc_init(void)
548 {
549         /* clear the progress line */
550         ppc_md.progress(" ", 0xffff);
551
552         if (ppc_md.init != NULL) {
553                 ppc_md.init();
554         }
555         return 0;
556 }
557
558 arch_initcall(ppc_init);
559
560 void __init ppc64_calibrate_delay(void)
561 {
562         loops_per_jiffy = tb_ticks_per_jiffy;
563
564         printk("Calibrating delay loop... %lu.%02lu BogoMips\n",
565                                loops_per_jiffy/(500000/HZ),
566                                loops_per_jiffy/(5000/HZ) % 100);
567 }       
568
569 extern void (*calibrate_delay)(void);
570
571 /*
572  * Called into from start_kernel, after lock_kernel has been called.
573  * Initializes bootmem, which is unsed to manage page allocation until
574  * mem_init is called.
575  */
576 void __init setup_arch(char **cmdline_p)
577 {
578         extern int panic_timeout;
579         extern void do_init_bootmem(void);
580
581         calibrate_delay = ppc64_calibrate_delay;
582
583         ppc64_boot_msg(0x12, "Setup Arch");
584
585 #ifdef CONFIG_XMON
586         if (strstr(cmd_line, "xmon")) {
587                 /* ensure xmon is enabled */
588                 xmon_init();
589                 debugger(0);
590         }
591 #endif /* CONFIG_XMON */
592
593         /*
594          * Set cache line size based on type of cpu as a default.
595          * Systems with OF can look in the properties on the cpu node(s)
596          * for a possibly more accurate value.
597          */
598         dcache_bsize = systemcfg->dCacheL1LineSize; 
599         icache_bsize = systemcfg->iCacheL1LineSize; 
600
601         /* reboot on panic */
602         panic_timeout = 180;
603
604         if (ppc_md.panic)
605                 notifier_chain_register(&panic_notifier_list, &ppc64_panic_block);
606
607         init_mm.start_code = PAGE_OFFSET;
608         init_mm.end_code = (unsigned long) _etext;
609         init_mm.end_data = (unsigned long) _edata;
610         init_mm.brk = klimit;
611         
612         /* Save unparsed command line copy for /proc/cmdline */
613         strlcpy(saved_command_line, cmd_line, sizeof(saved_command_line));
614         *cmdline_p = cmd_line;
615
616         /* set up the bootmem stuff with available memory */
617         do_init_bootmem();
618
619         ppc_md.setup_arch();
620
621         paging_init();
622         ppc64_boot_msg(0x15, "Setup Done");
623 }
624
625 /* ToDo: do something useful if ppc_md is not yet setup. */
626 #define PPC64_LINUX_FUNCTION 0x0f000000
627 #define PPC64_IPL_MESSAGE 0xc0000000
628 #define PPC64_TERM_MESSAGE 0xb0000000
629 #define PPC64_ATTN_MESSAGE 0xa0000000
630 #define PPC64_DUMP_MESSAGE 0xd0000000
631
632 static void ppc64_do_msg(unsigned int src, const char *msg)
633 {
634         if (ppc_md.progress) {
635                 char buf[32];
636
637                 sprintf(buf, "%08x        \n", src);
638                 ppc_md.progress(buf, 0);
639                 sprintf(buf, "%-16s", msg);
640                 ppc_md.progress(buf, 0);
641         }
642 }
643
644 /* Print a boot progress message. */
645 void ppc64_boot_msg(unsigned int src, const char *msg)
646 {
647         ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg);
648         printk("[boot]%04x %s\n", src, msg);
649 }
650
651 /* Print a termination message (print only -- does not stop the kernel) */
652 void ppc64_terminate_msg(unsigned int src, const char *msg)
653 {
654         ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg);
655         printk("[terminate]%04x %s\n", src, msg);
656 }
657
658 /* Print something that needs attention (device error, etc) */
659 void ppc64_attention_msg(unsigned int src, const char *msg)
660 {
661         ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg);
662         printk("[attention]%04x %s\n", src, msg);
663 }
664
665 /* Print a dump progress message. */
666 void ppc64_dump_msg(unsigned int src, const char *msg)
667 {
668         ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg);
669         printk("[dump]%04x %s\n", src, msg);
670 }
671
672 int set_spread_lpevents( char * str )
673 {
674         /* The parameter is the number of processors to share in processing lp events */
675         unsigned long i;
676         unsigned long val = simple_strtoul( str, NULL, 0 );
677         if ( ( val > 0 ) && ( val <= NR_CPUS ) ) {
678                 for ( i=1; i<val; ++i )
679                         paca[i].lpQueuePtr = paca[0].lpQueuePtr;
680                 printk("lpevent processing spread over %ld processors\n", val);
681         }
682         else
683                 printk("invalid spreaqd_lpevents %ld\n", val);
684         return 1;
685 }       
686
687 /* This should only be called on processor 0 during calibrate decr */
688 void setup_default_decr(void)
689 {
690         struct paca_struct *lpaca = get_paca();
691
692         if ( decr_overclock_set && !decr_overclock_proc0_set )
693                 decr_overclock_proc0 = decr_overclock;
694
695         lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;        
696         lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
697 }
698
699 int set_decr_overclock_proc0( char * str )
700 {
701         unsigned long val = simple_strtoul( str, NULL, 0 );
702         if ( ( val >= 1 ) && ( val <= 48 ) ) {
703                 decr_overclock_proc0_set = 1;
704                 decr_overclock_proc0 = val;
705                 printk("proc 0 decrementer overclock factor of %ld\n", val);
706         }
707         else
708                 printk("invalid proc 0 decrementer overclock factor of %ld\n", val);
709         return 1;
710 }
711
712 int set_decr_overclock( char * str )
713 {
714         unsigned long val = simple_strtoul( str, NULL, 0 );
715         if ( ( val >= 1 ) && ( val <= 48 ) ) {
716                 decr_overclock_set = 1;
717                 decr_overclock = val;
718                 printk("decrementer overclock factor of %ld\n", val);
719         }
720         else
721                 printk("invalid decrementer overclock factor of %ld\n", val);
722         return 1;
723
724 }
725
726 __setup("spread_lpevents=", set_spread_lpevents );
727 __setup("decr_overclock_proc0=", set_decr_overclock_proc0 );
728 __setup("decr_overclock=", set_decr_overclock );