1/*  $Id: setup.c,v 1.1.1.1 2007/08/03 18:52:18 Exp $
2 *  linux/arch/sparc64/kernel/setup.c
3 *
4 *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
5 *  Copyright (C) 1997       Jakub Jelinek (jj@sunsite.mff.cuni.cz)
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/screen_info.h>
20#include <linux/delay.h>
21#include <linux/fs.h>
22#include <linux/seq_file.h>
23#include <linux/syscalls.h>
24#include <linux/kdev_t.h>
25#include <linux/major.h>
26#include <linux/string.h>
27#include <linux/init.h>
28#include <linux/inet.h>
29#include <linux/console.h>
30#include <linux/root_dev.h>
31#include <linux/interrupt.h>
32#include <linux/cpu.h>
33#include <linux/initrd.h>
34
35#include <asm/system.h>
36#include <asm/io.h>
37#include <asm/processor.h>
38#include <asm/oplib.h>
39#include <asm/page.h>
40#include <asm/pgtable.h>
41#include <asm/idprom.h>
42#include <asm/head.h>
43#include <asm/starfire.h>
44#include <asm/mmu_context.h>
45#include <asm/timer.h>
46#include <asm/sections.h>
47#include <asm/setup.h>
48#include <asm/mmu.h>
49#include <asm/ns87303.h>
50
51#ifdef CONFIG_IP_PNP
52#include <net/ipconfig.h>
53#endif
54
55/* Used to synchronize accesses to NatSemi SUPER I/O chip configure
56 * operations in asm/ns87303.h
57 */
58DEFINE_SPINLOCK(ns87303_lock);
59
60struct screen_info screen_info = {
61	0, 0,			/* orig-x, orig-y */
62	0,			/* unused */
63	0,			/* orig-video-page */
64	0,			/* orig-video-mode */
65	128,			/* orig-video-cols */
66	0, 0, 0,		/* unused, ega_bx, unused */
67	54,			/* orig-video-lines */
68	0,                      /* orig-video-isVGA */
69	16                      /* orig-video-points */
70};
71
72void (*prom_palette)(int);
73void (*prom_keyboard)(void);
74
75static void
76prom_console_write(struct console *con, const char *s, unsigned n)
77{
78	prom_write(s, n);
79}
80
81unsigned int boot_flags = 0;
82#define BOOTME_DEBUG  0x1
83
84/* Exported for mm/init.c:paging_init. */
85unsigned long cmdline_memory_size = 0;
86
87static struct console prom_debug_console = {
88	.name =		"debug",
89	.write =	prom_console_write,
90	.flags =	CON_PRINTBUFFER,
91	.index =	-1,
92};
93
94void kernel_enter_debugger(void)
95{
96}
97
98/*
99 * Process kernel command line switches that are specific to the
100 * SPARC or that require special low-level processing.
101 */
102static void __init process_switch(char c)
103{
104	switch (c) {
105	case 'd':
106		boot_flags |= BOOTME_DEBUG;
107		break;
108	case 's':
109		break;
110	case 'h':
111		prom_printf("boot_flags_init: Halt!\n");
112		prom_halt();
113		break;
114	case 'p':
115		/* Use PROM debug console. */
116		register_console(&prom_debug_console);
117		break;
118	case 'P':
119		/* Force UltraSPARC-III P-Cache on. */
120		if (tlb_type != cheetah) {
121			printk("BOOT: Ignoring P-Cache force option.\n");
122			break;
123		}
124		cheetah_pcache_forced_on = 1;
125		add_taint(TAINT_MACHINE_CHECK);
126		cheetah_enable_pcache();
127		break;
128
129	default:
130		printk("Unknown boot switch (-%c)\n", c);
131		break;
132	}
133}
134
135static void __init process_console(char *commands)
136{
137	serial_console = 0;
138	commands += 8;
139	/* Linux-style serial */
140	if (!strncmp(commands, "ttyS", 4))
141		serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
142	else if (!strncmp(commands, "tty", 3)) {
143		char c = *(commands + 3);
144		/* Solaris-style serial */
145		if (c == 'a' || c == 'b') {
146			serial_console = c - 'a' + 1;
147			prom_printf ("Using /dev/tty%c as console.\n", c);
148		}
149		/* else Linux-style fbcon, not serial */
150	}
151#if defined(CONFIG_PROM_CONSOLE)
152	if (!strncmp(commands, "prom", 4)) {
153		char *p;
154
155		for (p = commands - 8; *p && *p != ' '; p++)
156			*p = ' ';
157		conswitchp = &prom_con;
158	}
159#endif
160}
161
162static void __init boot_flags_init(char *commands)
163{
164	while (*commands) {
165		/* Move to the start of the next "argument". */
166		while (*commands && *commands == ' ')
167			commands++;
168
169		/* Process any command switches, otherwise skip it. */
170		if (*commands == '\0')
171			break;
172		if (*commands == '-') {
173			commands++;
174			while (*commands && *commands != ' ')
175				process_switch(*commands++);
176			continue;
177		}
178		if (!strncmp(commands, "console=", 8)) {
179			process_console(commands);
180		} else if (!strncmp(commands, "mem=", 4)) {
181			cmdline_memory_size = simple_strtoul(commands + 4,
182							     &commands, 0);
183			if (*commands == 'K' || *commands == 'k') {
184				cmdline_memory_size <<= 10;
185				commands++;
186			} else if (*commands=='M' || *commands=='m') {
187				cmdline_memory_size <<= 20;
188				commands++;
189			}
190		}
191		while (*commands && *commands != ' ')
192			commands++;
193	}
194}
195
196extern void panic_setup(char *, int *);
197
198extern unsigned short root_flags;
199extern unsigned short root_dev;
200extern unsigned short ram_flags;
201#define RAMDISK_IMAGE_START_MASK	0x07FF
202#define RAMDISK_PROMPT_FLAG		0x8000
203#define RAMDISK_LOAD_FLAG		0x4000
204
205extern int root_mountflags;
206
207char reboot_command[COMMAND_LINE_SIZE];
208
209static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
210
211void __init per_cpu_patch(void)
212{
213	struct cpuid_patch_entry *p;
214	unsigned long ver;
215	int is_jbus;
216
217	if (tlb_type == spitfire && !this_is_starfire)
218		return;
219
220	is_jbus = 0;
221	if (tlb_type != hypervisor) {
222		__asm__ ("rdpr %%ver, %0" : "=r" (ver));
223		is_jbus = ((ver >> 32UL) == __JALAPENO_ID ||
224			   (ver >> 32UL) == __SERRANO_ID);
225	}
226
227	p = &__cpuid_patch;
228	while (p < &__cpuid_patch_end) {
229		unsigned long addr = p->addr;
230		unsigned int *insns;
231
232		switch (tlb_type) {
233		case spitfire:
234			insns = &p->starfire[0];
235			break;
236		case cheetah:
237		case cheetah_plus:
238			if (is_jbus)
239				insns = &p->cheetah_jbus[0];
240			else
241				insns = &p->cheetah_safari[0];
242			break;
243		case hypervisor:
244			insns = &p->sun4v[0];
245			break;
246		default:
247			prom_printf("Unknown cpu type, halting.\n");
248			prom_halt();
249		};
250
251		*(unsigned int *) (addr +  0) = insns[0];
252		wmb();
253		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
254
255		*(unsigned int *) (addr +  4) = insns[1];
256		wmb();
257		__asm__ __volatile__("flush	%0" : : "r" (addr +  4));
258
259		*(unsigned int *) (addr +  8) = insns[2];
260		wmb();
261		__asm__ __volatile__("flush	%0" : : "r" (addr +  8));
262
263		*(unsigned int *) (addr + 12) = insns[3];
264		wmb();
265		__asm__ __volatile__("flush	%0" : : "r" (addr + 12));
266
267		p++;
268	}
269}
270
271void __init sun4v_patch(void)
272{
273	extern void sun4v_hvapi_init(void);
274	struct sun4v_1insn_patch_entry *p1;
275	struct sun4v_2insn_patch_entry *p2;
276
277	if (tlb_type != hypervisor)
278		return;
279
280	p1 = &__sun4v_1insn_patch;
281	while (p1 < &__sun4v_1insn_patch_end) {
282		unsigned long addr = p1->addr;
283
284		*(unsigned int *) (addr +  0) = p1->insn;
285		wmb();
286		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
287
288		p1++;
289	}
290
291	p2 = &__sun4v_2insn_patch;
292	while (p2 < &__sun4v_2insn_patch_end) {
293		unsigned long addr = p2->addr;
294
295		*(unsigned int *) (addr +  0) = p2->insns[0];
296		wmb();
297		__asm__ __volatile__("flush	%0" : : "r" (addr +  0));
298
299		*(unsigned int *) (addr +  4) = p2->insns[1];
300		wmb();
301		__asm__ __volatile__("flush	%0" : : "r" (addr +  4));
302
303		p2++;
304	}
305
306	sun4v_hvapi_init();
307}
308
309#ifdef CONFIG_SMP
310void __init boot_cpu_id_too_large(int cpu)
311{
312	prom_printf("Serious problem, boot cpu id (%d) >= NR_CPUS (%d)\n",
313		    cpu, NR_CPUS);
314	prom_halt();
315}
316#endif
317
318void __init setup_arch(char **cmdline_p)
319{
320	/* Initialize PROM console and command line. */
321	*cmdline_p = prom_getbootargs();
322	strcpy(boot_command_line, *cmdline_p);
323
324	if (tlb_type == hypervisor)
325		printk("ARCH: SUN4V\n");
326	else
327		printk("ARCH: SUN4U\n");
328
329#ifdef CONFIG_DUMMY_CONSOLE
330	conswitchp = &dummy_con;
331#elif defined(CONFIG_PROM_CONSOLE)
332	conswitchp = &prom_con;
333#endif
334
335	boot_flags_init(*cmdline_p);
336
337	idprom_init();
338
339	if (!root_flags)
340		root_mountflags &= ~MS_RDONLY;
341	ROOT_DEV = old_decode_dev(root_dev);
342#ifdef CONFIG_BLK_DEV_RAM
343	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
344	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
345	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
346#endif
347
348	task_thread_info(&init_task)->kregs = &fake_swapper_regs;
349
350#ifdef CONFIG_IP_PNP
351	if (!ic_set_manually) {
352		int chosen = prom_finddevice ("/chosen");
353		u32 cl, sv, gw;
354
355		cl = prom_getintdefault (chosen, "client-ip", 0);
356		sv = prom_getintdefault (chosen, "server-ip", 0);
357		gw = prom_getintdefault (chosen, "gateway-ip", 0);
358		if (cl && sv) {
359			ic_myaddr = cl;
360			ic_servaddr = sv;
361			if (gw)
362				ic_gateway = gw;
363#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
364			ic_proto_enabled = 0;
365#endif
366		}
367	}
368#endif
369
370	/* Get boot processor trap_block[] setup.  */
371	init_cur_cpu_trap(current_thread_info());
372
373	paging_init();
374}
375
376static int __init set_preferred_console(void)
377{
378	int idev, odev;
379
380	/* The user has requested a console so this is already set up. */
381	if (serial_console >= 0)
382		return -EBUSY;
383
384	idev = prom_query_input_device();
385	odev = prom_query_output_device();
386	if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
387		serial_console = 0;
388	} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
389		serial_console = 1;
390	} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
391		serial_console = 2;
392	} else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
393		serial_console = 3;
394	} else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
395		/* sunhv_console_init() doesn't check the serial_console
396		 * value anyways...
397		 */
398		serial_console = 4;
399		return add_preferred_console("ttyHV", 0, NULL);
400	} else {
401		prom_printf("Inconsistent console: "
402			    "input %d, output %d\n",
403			    idev, odev);
404		prom_halt();
405	}
406
407	if (serial_console)
408		return add_preferred_console("ttyS", serial_console - 1, NULL);
409
410	return -ENODEV;
411}
412console_initcall(set_preferred_console);
413
414/* BUFFER is PAGE_SIZE bytes long. */
415
416extern char *sparc_cpu_type;
417extern char *sparc_fpu_type;
418
419extern void smp_info(struct seq_file *);
420extern void smp_bogo(struct seq_file *);
421extern void mmu_info(struct seq_file *);
422
423unsigned int dcache_parity_tl1_occurred;
424unsigned int icache_parity_tl1_occurred;
425
426int ncpus_probed;
427
428static int show_cpuinfo(struct seq_file *m, void *__unused)
429{
430	seq_printf(m,
431		   "cpu\t\t: %s\n"
432		   "fpu\t\t: %s\n"
433		   "prom\t\t: %s\n"
434		   "type\t\t: %s\n"
435		   "ncpus probed\t: %d\n"
436		   "ncpus active\t: %d\n"
437		   "D$ parity tl1\t: %u\n"
438		   "I$ parity tl1\t: %u\n"
439#ifndef CONFIG_SMP
440		   "Cpu0Bogo\t: %lu.%02lu\n"
441		   "Cpu0ClkTck\t: %016lx\n"
442#endif
443		   ,
444		   sparc_cpu_type,
445		   sparc_fpu_type,
446		   prom_version,
447		   ((tlb_type == hypervisor) ?
448		    "sun4v" :
449		    "sun4u"),
450		   ncpus_probed,
451		   num_online_cpus(),
452		   dcache_parity_tl1_occurred,
453		   icache_parity_tl1_occurred
454#ifndef CONFIG_SMP
455		   , cpu_data(0).udelay_val/(500000/HZ),
456		   (cpu_data(0).udelay_val/(5000/HZ)) % 100,
457		   cpu_data(0).clock_tick
458#endif
459		);
460#ifdef CONFIG_SMP
461	smp_bogo(m);
462#endif
463	mmu_info(m);
464#ifdef CONFIG_SMP
465	smp_info(m);
466#endif
467	return 0;
468}
469
470static void *c_start(struct seq_file *m, loff_t *pos)
471{
472	/* The pointer we are returning is arbitrary,
473	 * it just has to be non-NULL and not IS_ERR
474	 * in the success case.
475	 */
476	return *pos == 0 ? &c_start : NULL;
477}
478
479static void *c_next(struct seq_file *m, void *v, loff_t *pos)
480{
481	++*pos;
482	return c_start(m, pos);
483}
484
485static void c_stop(struct seq_file *m, void *v)
486{
487}
488
489struct seq_operations cpuinfo_op = {
490	.start =c_start,
491	.next =	c_next,
492	.stop =	c_stop,
493	.show =	show_cpuinfo,
494};
495
496extern int stop_a_enabled;
497
498void sun_do_break(void)
499{
500	if (!stop_a_enabled)
501		return;
502
503	prom_printf("\n");
504	flush_user_windows();
505
506	prom_cmdline();
507}
508
509int serial_console = -1;
510int stop_a_enabled = 1;
511