Import 2.3.18pre1
[davej-history.git] / arch / sparc / kernel / setup.c
blob06fa837e28cf1b069665e0644de496cb04be98ed
1 /* $Id: setup.c,v 1.110 1999/08/31 06:54:23 davem Exp $
2 * linux/arch/sparc/kernel/setup.c
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 */
7 #include <linux/errno.h>
8 #include <linux/sched.h>
9 #include <linux/kernel.h>
10 #include <linux/mm.h>
11 #include <linux/stddef.h>
12 #include <linux/unistd.h>
13 #include <linux/ptrace.h>
14 #include <linux/malloc.h>
15 #include <asm/smp.h>
16 #include <linux/user.h>
17 #include <linux/a.out.h>
18 #include <linux/tty.h>
19 #include <linux/delay.h>
20 #include <linux/config.h>
21 #include <linux/fs.h>
22 #include <linux/kdev_t.h>
23 #include <linux/major.h>
24 #include <linux/string.h>
25 #include <linux/blk.h>
26 #include <linux/init.h>
27 #include <linux/interrupt.h>
28 #include <linux/console.h>
29 #include <linux/spinlock.h>
31 #include <asm/segment.h>
32 #include <asm/system.h>
33 #include <asm/io.h>
34 #include <asm/kgdb.h>
35 #include <asm/processor.h>
36 #include <asm/oplib.h>
37 #include <asm/page.h>
38 #include <asm/pgtable.h>
39 #include <asm/traps.h>
40 #include <asm/vaddrs.h>
41 #include <asm/kdebug.h>
42 #include <asm/mbus.h>
43 #include <asm/idprom.h>
44 #include <asm/softirq.h>
45 #include <asm/hardirq.h>
46 #include <asm/machines.h>
48 struct screen_info screen_info = {
49 0, 0, /* orig-x, orig-y */
50 0, /* unused */
51 0, /* orig-video-page */
52 0, /* orig-video-mode */
53 128, /* orig-video-cols */
54 0,0,0, /* ega_ax, ega_bx, ega_cx */
55 54, /* orig-video-lines */
56 0, /* orig-video-isVGA */
57 16 /* orig-video-points */
60 unsigned int phys_bytes_of_ram, end_of_phys_memory;
62 /* Typing sync at the prom prompt calls the function pointed to by
63 * romvec->pv_synchook which I set to the following function.
64 * This should sync all filesystems and return, for now it just
65 * prints out pretty messages and returns.
68 extern unsigned long trapbase;
69 extern int serial_console;
70 extern void breakpoint(void);
71 #if CONFIG_SUN_CONSOLE
72 void (*prom_palette)(int);
73 #endif
74 asmlinkage void sys_sync(void); /* it's really int */
76 /* Pretty sick eh? */
77 void prom_sync_me(void)
79 unsigned long prom_tbr, flags;
81 #ifdef __SMP__
82 global_irq_holder = NO_PROC_ID;
83 *((unsigned char *)&global_irq_lock) = 0;
84 *((unsigned char *)&global_bh_lock) = 0;
85 #endif
86 __save_and_cli(flags);
87 __asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
88 __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
89 "nop\n\t"
90 "nop\n\t"
91 "nop\n\t" : : "r" (&trapbase));
93 #ifdef CONFIG_SUN_CONSOLE
94 if (prom_palette)
95 prom_palette(1);
96 #endif
97 prom_printf("PROM SYNC COMMAND...\n");
98 show_free_areas();
99 if(current->pid != 0) {
100 __sti();
101 sys_sync();
102 __cli();
104 prom_printf("Returning to prom\n");
106 __asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
107 "nop\n\t"
108 "nop\n\t"
109 "nop\n\t" : : "r" (prom_tbr));
110 __restore_flags(flags);
112 return;
115 extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
117 unsigned int boot_flags;
118 #define BOOTME_DEBUG 0x1
119 #define BOOTME_SINGLE 0x2
120 #define BOOTME_KGDBA 0x4
121 #define BOOTME_KGDBB 0x8
122 #define BOOTME_KGDB 0xc
124 #ifdef CONFIG_SUN_CONSOLE
125 static int console_fb = 0;
126 #endif
127 static unsigned long memory_size __initdata = 0;
129 void kernel_enter_debugger(void)
131 if (boot_flags & BOOTME_KGDB) {
132 printk("KGDB: Entered\n");
133 breakpoint();
137 int obp_system_intr(void)
139 if (boot_flags & BOOTME_KGDB) {
140 printk("KGDB: system interrupted\n");
141 breakpoint();
142 return 1;
144 if (boot_flags & BOOTME_DEBUG) {
145 printk("OBP: system interrupted\n");
146 prom_halt();
147 return 1;
149 return 0;
153 * Process kernel command line switches that are specific to the
154 * SPARC or that require special low-level processing.
156 static void __init process_switch(char c)
158 switch (c) {
159 case 'd':
160 boot_flags |= BOOTME_DEBUG;
161 break;
162 case 's':
163 boot_flags |= BOOTME_SINGLE;
164 break;
165 case 'h':
166 prom_printf("boot_flags_init: Halt!\n");
167 halt();
168 break;
169 default:
170 printk("Unknown boot switch (-%c)\n", c);
171 break;
175 static void __init boot_flags_init(char *commands)
177 while (*commands) {
178 /* Move to the start of the next "argument". */
179 while (*commands && *commands == ' ')
180 commands++;
182 /* Process any command switches, otherwise skip it. */
183 if (*commands == '\0')
184 break;
185 else if (*commands == '-') {
186 commands++;
187 while (*commands && *commands != ' ')
188 process_switch(*commands++);
189 } else if (strlen(commands) >= 9
190 && !strncmp(commands, "kgdb=tty", 8)) {
191 switch (commands[8]) {
192 #ifdef CONFIG_SUN_SERIAL
193 case 'a':
194 boot_flags |= BOOTME_KGDBA;
195 prom_printf("KGDB: Using serial line /dev/ttya.\n");
196 break;
197 case 'b':
198 boot_flags |= BOOTME_KGDBB;
199 prom_printf("KGDB: Using serial line /dev/ttyb.\n");
200 break;
201 #endif
202 #ifdef CONFIG_AP1000
203 case 'c':
204 printk("KGDB: AP1000+ debugging\n");
205 break;
206 #endif
207 default:
208 printk("KGDB: Unknown tty line.\n");
209 break;
211 commands += 9;
212 } else {
213 #if CONFIG_SUN_CONSOLE
214 if (!strncmp(commands, "console=", 8)) {
215 commands += 8;
216 if (!strncmp (commands, "ttya", 4)) {
217 console_fb = 2;
218 prom_printf ("Using /dev/ttya as console.\n");
219 } else if (!strncmp (commands, "ttyb", 4)) {
220 console_fb = 3;
221 prom_printf ("Using /dev/ttyb as console.\n");
222 #if defined(CONFIG_PROM_CONSOLE)
223 } else if (!strncmp (commands, "prom", 4)) {
224 char *p;
226 for (p = commands - 8; *p && *p != ' '; p++)
227 *p = ' ';
228 conswitchp = &prom_con;
229 console_fb = 1;
230 #endif
231 } else {
232 console_fb = 1;
234 } else
235 #endif
236 if (!strncmp(commands, "mem=", 4)) {
238 * "mem=XXX[kKmM] overrides the PROM-reported
239 * memory size.
241 memory_size = simple_strtoul(commands + 4,
242 &commands, 0);
243 if (*commands == 'K' || *commands == 'k') {
244 memory_size <<= 10;
245 commands++;
246 } else if (*commands=='M' || *commands=='m') {
247 memory_size <<= 20;
248 commands++;
251 while (*commands && *commands != ' ')
252 commands++;
257 /* This routine will in the future do all the nasty prom stuff
258 * to probe for the mmu type and its parameters, etc. This will
259 * also be where SMP things happen plus the Sparc specific memory
260 * physical memory probe as on the alpha.
263 extern int prom_probe_memory(void);
264 extern void sun4c_probe_vac(void);
265 extern char cputypval;
266 extern unsigned long start, end;
267 extern void panic_setup(char *, int *);
268 extern void srmmu_end_memory(unsigned long, unsigned long *);
269 extern unsigned long sun_serial_setup(unsigned long);
271 extern unsigned short root_flags;
272 extern unsigned short root_dev;
273 extern unsigned short ram_flags;
274 extern unsigned sparc_ramdisk_image;
275 extern unsigned sparc_ramdisk_size;
276 #define RAMDISK_IMAGE_START_MASK 0x07FF
277 #define RAMDISK_PROMPT_FLAG 0x8000
278 #define RAMDISK_LOAD_FLAG 0x4000
280 extern int root_mountflags;
282 char saved_command_line[256];
283 char reboot_command[256];
284 enum sparc_cpu sparc_cpu_model;
286 struct tt_entry *sparc_ttable;
288 struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
290 static void prom_cons_write(struct console *con, const char *str, unsigned count)
292 while (count--)
293 prom_printf("%c", *str++);
296 static struct console prom_console = {
297 "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
300 void __init setup_arch(char **cmdline_p,
301 unsigned long * memory_start_p, unsigned long * memory_end_p)
303 int total, i, packed;
305 sparc_ttable = (struct tt_entry *) &start;
307 /* Initialize PROM console and command line. */
308 *cmdline_p = prom_getbootargs();
309 strcpy(saved_command_line, *cmdline_p);
311 /* Set sparc_cpu_model */
312 sparc_cpu_model = sun_unknown;
313 if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
314 if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
315 if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
316 if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; } /* CP-1200 with PROM 2.30 -E */
317 if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
318 if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
319 if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
321 #ifdef CONFIG_SUN4
322 if (sparc_cpu_model != sun4) {
323 prom_printf("This kernel is for Sun4 architecture only.\n");
324 prom_halt();
326 #endif
327 #if CONFIG_AP1000
328 sparc_cpu_model=ap1000;
329 strcpy(&cputypval, "ap+");
330 #endif
331 printk("ARCH: ");
332 packed = 0;
333 switch(sparc_cpu_model) {
334 case sun4:
335 printk("SUN4\n");
336 packed = 0;
337 break;
338 case sun4c:
339 printk("SUN4C\n");
340 packed = 0;
341 break;
342 case sun4m:
343 printk("SUN4M\n");
344 packed = 1;
345 break;
346 case sun4d:
347 printk("SUN4D\n");
348 packed = 1;
349 break;
350 case sun4e:
351 printk("SUN4E\n");
352 packed = 0;
353 break;
354 case sun4u:
355 printk("SUN4U\n");
356 break;
357 case ap1000:
358 register_console(&prom_console);
359 printk("AP1000\n");
360 packed = 1;
361 break;
362 default:
363 printk("UNKNOWN!\n");
364 break;
367 #ifdef CONFIG_DUMMY_CONSOLE
368 conswitchp = &dummy_con;
369 #elif defined(CONFIG_PROM_CONSOLE)
370 conswitchp = &prom_con;
371 #endif
372 boot_flags_init(*cmdline_p);
374 idprom_init();
375 if (ARCH_SUN4C_SUN4)
376 sun4c_probe_vac();
377 load_mmu();
378 total = prom_probe_memory();
379 *memory_start_p = PAGE_ALIGN(((unsigned long) &end));
381 if(!packed) {
382 for(i=0; sp_banks[i].num_bytes != 0; i++) {
383 end_of_phys_memory = sp_banks[i].base_addr +
384 sp_banks[i].num_bytes;
385 if (memory_size) {
386 if (end_of_phys_memory > memory_size) {
387 sp_banks[i].num_bytes -=
388 (end_of_phys_memory - memory_size);
389 end_of_phys_memory = memory_size;
390 sp_banks[++i].base_addr = 0xdeadbeef;
391 sp_banks[i].num_bytes = 0;
395 *memory_end_p = (end_of_phys_memory + KERNBASE);
396 } else
397 srmmu_end_memory(memory_size, memory_end_p);
399 if (!root_flags)
400 root_mountflags &= ~MS_RDONLY;
401 ROOT_DEV = to_kdev_t(root_dev);
402 #ifdef CONFIG_BLK_DEV_RAM
403 rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
404 rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
405 rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
406 #endif
407 #ifdef CONFIG_BLK_DEV_INITRD
408 if (sparc_ramdisk_image) {
409 initrd_start = sparc_ramdisk_image;
410 if (initrd_start < KERNBASE) initrd_start += KERNBASE;
411 initrd_end = initrd_start + sparc_ramdisk_size;
412 if (initrd_end > *memory_end_p) {
413 printk(KERN_CRIT "initrd extends beyond end of memory "
414 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
415 initrd_end,*memory_end_p);
416 initrd_start = 0;
418 if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
419 initrd_below_start_ok = 1;
420 *memory_start_p = PAGE_ALIGN (initrd_end);
421 } else if (initrd_start && sparc_ramdisk_image < KERNBASE) {
422 switch (sparc_cpu_model) {
423 case sun4m:
424 case sun4d:
425 initrd_start -= KERNBASE;
426 initrd_end -= KERNBASE;
427 break;
428 default:
429 break;
433 #endif
434 prom_setsync(prom_sync_me);
436 #ifdef CONFIG_SUN_SERIAL
437 *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
438 #endif
440 #if !CONFIG_SUN_SERIAL
441 serial_console = 0;
442 #else
443 switch (console_fb) {
444 case 0: /* Let get our io devices from prom */
446 int idev = prom_query_input_device();
447 int odev = prom_query_output_device();
448 if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
449 serial_console = 0;
450 } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
451 serial_console = 1;
452 } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
453 serial_console = 2;
454 } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
455 prom_printf("MrCoffee ttya\n");
456 serial_console = 1;
457 } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
458 serial_console = 0;
459 prom_printf("MrCoffee keyboard\n");
460 } else {
461 prom_printf("Inconsistent or unknown console\n");
462 prom_printf("You cannot mix serial and non serial input/output devices\n");
463 prom_halt();
466 break;
467 case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
468 case 2: serial_console = 1; break; /* Force ttya as console */
469 case 3: serial_console = 2; break; /* Force ttyb as console */
471 #endif
474 if ((boot_flags & BOOTME_KGDBA)) {
475 rs_kgdb_hook(0);
477 if ((boot_flags & BOOTME_KGDBB)) {
478 rs_kgdb_hook(1);
481 if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) &&
482 ((*(short *)linux_dbvec) != -1)) {
483 printk("Booted under KADB. Syncing trap table.\n");
484 (*(linux_dbvec->teach_debugger))();
486 if((boot_flags & BOOTME_KGDB)) {
487 set_debug_traps();
488 prom_printf ("Breakpoint!\n");
489 breakpoint();
493 /* Due to stack alignment restrictions and assumptions... */
494 init_mm.mmap->vm_page_prot = PAGE_SHARED;
495 init_mm.mmap->vm_start = KERNBASE;
496 init_mm.mmap->vm_end = *memory_end_p;
497 init_mm.context = (unsigned long) NO_CONTEXT;
498 init_task.thread.kregs = &fake_swapper_regs;
500 if (serial_console)
501 conswitchp = NULL;
504 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
506 return -EIO;
509 /* BUFFER is PAGE_SIZE bytes long. */
511 extern char *sparc_cpu_type[];
512 extern char *sparc_fpu_type[];
514 int get_cpuinfo(char *buffer)
516 int cpuid=hard_smp_processor_id();
517 int len;
519 len = sprintf(buffer, "cpu\t\t: %s\n"
520 "fpu\t\t: %s\n"
521 "promlib\t\t: Version %d Revision %d\n"
522 "prom\t\t: %d.%d\n"
523 "type\t\t: %s\n"
524 "ncpus probed\t: %d\n"
525 "ncpus active\t: %d\n"
526 #ifndef __SMP__
527 "BogoMips\t: %lu.%02lu\n"
528 #endif
530 sparc_cpu_type[cpuid] ? : "undetermined",
531 sparc_fpu_type[cpuid] ? : "undetermined",
532 romvec->pv_romvers, prom_rev, romvec->pv_printrev >> 16, (short)romvec->pv_printrev,
533 &cputypval,
534 linux_num_cpus, smp_num_cpus
535 #ifndef __SMP__
536 , loops_per_sec/500000, (loops_per_sec/5000) % 100
537 #endif
539 #ifdef __SMP__
540 len += smp_bogo_info(buffer + len);
541 #endif
542 len += mmu_info(buffer + len);
543 #ifdef __SMP__
544 len += smp_info(buffer + len);
545 #endif
546 return len;