File: /usr/src/linux/arch/sparc/kernel/setup.c

1     /*  $Id: setup.c,v 1.125 2001/09/20 00:35:30 davem Exp $
2      *  linux/arch/sparc/kernel/setup.c
3      *
4      *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
5      *  Copyright (C) 2000  Anton Blanchard (anton@samba.org)
6      */
7     
8     #include <linux/errno.h>
9     #include <linux/sched.h>
10     #include <linux/kernel.h>
11     #include <linux/mm.h>
12     #include <linux/stddef.h>
13     #include <linux/unistd.h>
14     #include <linux/ptrace.h>
15     #include <linux/slab.h>
16     #include <asm/smp.h>
17     #include <linux/user.h>
18     #include <linux/a.out.h>
19     #include <linux/tty.h>
20     #include <linux/delay.h>
21     #include <linux/config.h>
22     #include <linux/fs.h>
23     #include <linux/kdev_t.h>
24     #include <linux/major.h>
25     #include <linux/string.h>
26     #include <linux/blk.h>
27     #include <linux/init.h>
28     #include <linux/interrupt.h>
29     #include <linux/console.h>
30     #include <linux/spinlock.h>
31     
32     #include <asm/segment.h>
33     #include <asm/system.h>
34     #include <asm/io.h>
35     #include <asm/kgdb.h>
36     #include <asm/processor.h>
37     #include <asm/oplib.h>
38     #include <asm/page.h>
39     #include <asm/pgtable.h>
40     #include <asm/traps.h>
41     #include <asm/vaddrs.h>
42     #include <asm/kdebug.h>
43     #include <asm/mbus.h>
44     #include <asm/idprom.h>
45     #include <asm/softirq.h>
46     #include <asm/hardirq.h>
47     #include <asm/machines.h>
48     
49     #undef PROM_DEBUG_CONSOLE
50     
51     struct screen_info screen_info = {
52     	0, 0,			/* orig-x, orig-y */
53     	0,			/* unused */
54     	0,			/* orig-video-page */
55     	0,			/* orig-video-mode */
56     	128,			/* orig-video-cols */
57     	0,0,0,			/* ega_ax, ega_bx, ega_cx */
58     	54,			/* orig-video-lines */
59     	0,                      /* orig-video-isVGA */
60     	16                      /* orig-video-points */
61     };
62     
63     /* Typing sync at the prom prompt calls the function pointed to by
64      * romvec->pv_synchook which I set to the following function.
65      * This should sync all filesystems and return, for now it just
66      * prints out pretty messages and returns.
67      */
68     
69     extern unsigned long trapbase;
70     extern int serial_console;
71     extern void breakpoint(void);
72     #if CONFIG_SUN_CONSOLE
73     void (*prom_palette)(int);
74     #endif
75     asmlinkage void sys_sync(void);	/* it's really int */
76     
77     /* Pretty sick eh? */
78     void prom_sync_me(void)
79     {
80     	unsigned long prom_tbr, flags;
81     
82     	/* XXX Badly broken. FIX! - Anton */
83     	save_and_cli(flags);
84     	__asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
85     	__asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
86     			     "nop\n\t"
87     			     "nop\n\t"
88     			     "nop\n\t" : : "r" (&trapbase));
89     
90     #ifdef CONFIG_SUN_CONSOLE
91     	if (prom_palette)
92     		prom_palette(1);
93     #endif
94     	prom_printf("PROM SYNC COMMAND...\n");
95     	show_free_areas();
96     	if(current->pid != 0) {
97     		sti();
98     		sys_sync();
99     		cli();
100     	}
101     	prom_printf("Returning to prom\n");
102     
103     	__asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
104     			     "nop\n\t"
105     			     "nop\n\t"
106     			     "nop\n\t" : : "r" (prom_tbr));
107     	restore_flags(flags);
108     
109     	return;
110     }
111     
112     extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
113     
114     unsigned int boot_flags __initdata = 0;
115     #define BOOTME_DEBUG  0x1
116     #define BOOTME_SINGLE 0x2
117     #define BOOTME_KGDBA  0x4
118     #define BOOTME_KGDBB  0x8
119     #define BOOTME_KGDB   0xc
120     
121     #ifdef CONFIG_SUN_CONSOLE
122     static int console_fb __initdata = 0;
123     #endif
124     
125     /* Exported for mm/init.c:paging_init. */
126     unsigned long cmdline_memory_size __initdata = 0;
127     
128     void kernel_enter_debugger(void)
129     {
130     	if (boot_flags & BOOTME_KGDB) {
131     		printk("KGDB: Entered\n");
132     		breakpoint();
133     	}
134     }
135     
136     int obp_system_intr(void)
137     {
138     	if (boot_flags & BOOTME_KGDB) {
139     		printk("KGDB: system interrupted\n");
140     		breakpoint();
141     		return 1;
142     	}
143     	if (boot_flags & BOOTME_DEBUG) {
144     		printk("OBP: system interrupted\n");
145     		prom_halt();
146     		return 1;
147     	}
148     	return 0;
149     }
150     
151     /* 
152      * Process kernel command line switches that are specific to the
153      * SPARC or that require special low-level processing.
154      */
155     static void __init process_switch(char c)
156     {
157     	switch (c) {
158     	case 'd':
159     		boot_flags |= BOOTME_DEBUG;
160     		break;
161     	case 's':
162     		boot_flags |= BOOTME_SINGLE;
163     		break;
164     	case 'h':
165     		prom_printf("boot_flags_init: Halt!\n");
166     		prom_halt();
167     		break;
168     	default:
169     		printk("Unknown boot switch (-%c)\n", c);
170     		break;
171     	}
172     }
173     
174     static void __init boot_flags_init(char *commands)
175     {
176     	while (*commands) {
177     		/* Move to the start of the next "argument". */
178     		while (*commands && *commands == ' ')
179     			commands++;
180     
181     		/* Process any command switches, otherwise skip it. */
182     		if (*commands == '\0')
183     			break;
184     		else if (*commands == '-') {
185     			commands++;
186     			while (*commands && *commands != ' ')
187     				process_switch(*commands++);
188     		} else if (strlen(commands) >= 9
189     			   && !strncmp(commands, "kgdb=tty", 8)) {
190     			switch (commands[8]) {
191     #ifdef CONFIG_SUN_SERIAL
192     			case 'a':
193     				boot_flags |= BOOTME_KGDBA;
194     				prom_printf("KGDB: Using serial line /dev/ttya.\n");
195     				break;
196     			case 'b':
197     				boot_flags |= BOOTME_KGDBB;
198     				prom_printf("KGDB: Using serial line /dev/ttyb.\n");
199     				break;
200     #endif
201     			default:
202     				printk("KGDB: Unknown tty line.\n");
203     				break;
204     			}
205     			commands += 9;
206     		} else {
207     #if CONFIG_SUN_CONSOLE
208     			if (!strncmp(commands, "console=", 8)) {
209     				commands += 8;
210     				if (!strncmp (commands, "ttya", 4)) {
211     					console_fb = 2;
212     					prom_printf ("Using /dev/ttya as console.\n");
213     				} else if (!strncmp (commands, "ttyb", 4)) {
214     					console_fb = 3;
215     					prom_printf ("Using /dev/ttyb as console.\n");
216     #if defined(CONFIG_PROM_CONSOLE)
217     				} else if (!strncmp (commands, "prom", 4)) {
218     					char *p;
219     					
220     					for (p = commands - 8; *p && *p != ' '; p++)
221     						*p = ' ';
222     					conswitchp = &prom_con;
223     					console_fb = 1;
224     #endif
225     				} else {
226     					console_fb = 1;
227     				}
228     			} else
229     #endif
230     			if (!strncmp(commands, "mem=", 4)) {
231     				/*
232     				 * "mem=XXX[kKmM] overrides the PROM-reported
233     				 * memory size.
234     				 */
235     				cmdline_memory_size = simple_strtoul(commands + 4,
236     							     &commands, 0);
237     				if (*commands == 'K' || *commands == 'k') {
238     					cmdline_memory_size <<= 10;
239     					commands++;
240     				} else if (*commands=='M' || *commands=='m') {
241     					cmdline_memory_size <<= 20;
242     					commands++;
243     				}
244     			}
245     			while (*commands && *commands != ' ')
246     				commands++;
247     		}
248     	}
249     }
250     
251     /* This routine will in the future do all the nasty prom stuff
252      * to probe for the mmu type and its parameters, etc. This will
253      * also be where SMP things happen plus the Sparc specific memory
254      * physical memory probe as on the alpha.
255      */
256     
257     extern int prom_probe_memory(void);
258     extern void sun4c_probe_vac(void);
259     extern char cputypval;
260     extern unsigned long start, end;
261     extern void panic_setup(char *, int *);
262     extern void srmmu_end_memory(unsigned long, unsigned long *);
263     extern void sun_serial_setup(void);
264     
265     extern unsigned short root_flags;
266     extern unsigned short root_dev;
267     extern unsigned short ram_flags;
268     #define RAMDISK_IMAGE_START_MASK	0x07FF
269     #define RAMDISK_PROMPT_FLAG		0x8000
270     #define RAMDISK_LOAD_FLAG		0x4000
271     
272     extern int root_mountflags;
273     
274     char saved_command_line[256];
275     char reboot_command[256];
276     enum sparc_cpu sparc_cpu_model;
277     
278     struct tt_entry *sparc_ttable;
279     
280     struct pt_regs fake_swapper_regs;
281     
282     #ifdef PROM_DEBUG_CONSOLE
283     static void
284     prom_console_write(struct console *con, const char *s, unsigned n)
285     {
286     	prom_printf("%s", s);
287     }
288     
289     static struct console prom_console = {
290     	name:		"debug",
291     	write:		prom_console_write,
292     	flags:		CON_PRINTBUFFER,
293     	index:		-1,
294     };
295     #endif
296     
297     extern void paging_init(void);
298     
299     void __init setup_arch(char **cmdline_p)
300     {
301     	int i;
302     	unsigned long highest_paddr;
303     
304     	sparc_ttable = (struct tt_entry *) &start;
305     
306     	/* Initialize PROM console and command line. */
307     	*cmdline_p = prom_getbootargs();
308     	strcpy(saved_command_line, *cmdline_p);
309     
310     	/* Set sparc_cpu_model */
311     	sparc_cpu_model = sun_unknown;
312     	if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
313     	if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
314     	if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
315     	if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; }  /* CP-1200 with PROM 2.30 -E */
316     	if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
317     	if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
318     	if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
319     
320     #ifdef CONFIG_SUN4
321     	if (sparc_cpu_model != sun4) {
322     		prom_printf("This kernel is for Sun4 architecture only.\n");
323     		prom_halt();
324     	}
325     #endif
326     	printk("ARCH: ");
327     	switch(sparc_cpu_model) {
328     	case sun4:
329     		printk("SUN4\n");
330     		break;
331     	case sun4c:
332     		printk("SUN4C\n");
333     		break;
334     	case sun4m:
335     		printk("SUN4M\n");
336     		break;
337     	case sun4d:
338     		printk("SUN4D\n");
339     		break;
340     	case sun4e:
341     		printk("SUN4E\n");
342     		break;
343     	case sun4u:
344     		printk("SUN4U\n");
345     		break;
346     	default:
347     		printk("UNKNOWN!\n");
348     		break;
349     	};
350     #ifdef PROM_DEBUG_CONSOLE
351     	register_console(&prom_console);
352     #endif
353     
354     #ifdef CONFIG_DUMMY_CONSOLE
355     	conswitchp = &dummy_con;
356     #elif defined(CONFIG_PROM_CONSOLE)
357     	conswitchp = &prom_con;
358     #endif
359     	boot_flags_init(*cmdline_p);
360     
361     	idprom_init();
362     	if (ARCH_SUN4C_SUN4)
363     		sun4c_probe_vac();
364     	load_mmu();
365     	(void) prom_probe_memory();
366     
367     	phys_base = 0xffffffffUL;
368     	highest_paddr = 0UL;
369     	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
370     		unsigned long top;
371     
372     		if (sp_banks[i].base_addr < phys_base)
373     			phys_base = sp_banks[i].base_addr;
374     		top = sp_banks[i].base_addr +
375     			sp_banks[i].num_bytes;
376     		if (highest_paddr < top)
377     			highest_paddr = top;
378     	}
379     
380     	if (!root_flags)
381     		root_mountflags &= ~MS_RDONLY;
382     	ROOT_DEV = to_kdev_t(root_dev);
383     #ifdef CONFIG_BLK_DEV_RAM
384     	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
385     	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
386     	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);	
387     #endif
388     
389     	prom_setsync(prom_sync_me);
390     
391     	{
392     #if !CONFIG_SUN_SERIAL
393     		serial_console = 0;
394     #else
395     		switch (console_fb) {
396     		case 0: /* Let get our io devices from prom */
397     			{
398     				int idev = prom_query_input_device();
399     				int odev = prom_query_output_device();
400     				if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
401     					serial_console = 0;
402     				} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
403     					serial_console = 1;
404     				} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
405     					serial_console = 2;
406     				} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
407     					prom_printf("MrCoffee ttya\n");
408     					serial_console = 1;
409     				} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
410     					serial_console = 0;
411     					prom_printf("MrCoffee keyboard\n");
412     				} else {
413     					prom_printf("Inconsistent or unknown console\n");
414     					prom_printf("You cannot mix serial and non serial input/output devices\n");
415     					prom_halt();
416     				}
417     			}
418     			break;
419     		case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
420     		case 2: serial_console = 1; break; /* Force ttya as console */
421     		case 3: serial_console = 2; break; /* Force ttyb as console */
422     		}
423     #endif
424     	}
425     
426     	if ((boot_flags & BOOTME_KGDBA)) {
427     		rs_kgdb_hook(0);
428     	}
429     	if ((boot_flags & BOOTME_KGDBB)) {
430     		rs_kgdb_hook(1);
431     	}
432     
433     	if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
434     	   ((*(short *)linux_dbvec) != -1)) {
435     		printk("Booted under KADB. Syncing trap table.\n");
436     		(*(linux_dbvec->teach_debugger))();
437     	}
438     	if((boot_flags & BOOTME_KGDB)) {
439     		set_debug_traps();
440     		prom_printf ("Breakpoint!\n");
441     		breakpoint();
442     	}
443     
444     	init_mm.context = (unsigned long) NO_CONTEXT;
445     	init_task.thread.kregs = &fake_swapper_regs;
446     
447     	if (serial_console)
448     		conswitchp = NULL;
449     
450     	paging_init();
451     }
452     
453     asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
454     {
455     	return -EIO;
456     }
457     
458     /* BUFFER is PAGE_SIZE bytes long. */
459     
460     extern char *sparc_cpu_type[];
461     extern char *sparc_fpu_type[];
462     
463     int get_cpuinfo(char *buffer)
464     {
465     	int cpuid=hard_smp_processor_id();
466     	int len;
467     
468     	len = sprintf(buffer, "cpu\t\t: %s\n"
469                 "fpu\t\t: %s\n"
470                 "promlib\t\t: Version %d Revision %d\n"
471                 "prom\t\t: %d.%d\n"
472                 "type\t\t: %s\n"
473     	    "ncpus probed\t: %d\n"
474     	    "ncpus active\t: %d\n"
475     #ifndef CONFIG_SMP
476                 "BogoMips\t: %lu.%02lu\n"
477     #endif
478     	    ,
479     	    sparc_cpu_type[cpuid] ? : "undetermined",
480     	    sparc_fpu_type[cpuid] ? : "undetermined",
481                 romvec->pv_romvers, prom_rev, romvec->pv_printrev >> 16, (short)romvec->pv_printrev,
482                 &cputypval,
483     	    linux_num_cpus, smp_num_cpus
484     #ifndef CONFIG_SMP
485     	    , loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ)) % 100
486     #endif
487     	    );
488     #ifdef CONFIG_SMP
489     	len += smp_bogo_info(buffer + len);
490     #endif
491     	len += mmu_info(buffer + len);
492     #ifdef CONFIG_SMP
493     	len += smp_info(buffer + len);
494     #endif
495     	return len;
496     }
497