1 /* $Id: setup.c,v 1.71.2.1 2002/02/27 21:31:38 davem 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/tty.h>
20 #include <linux/delay.h>
21 #include <linux/config.h>
22 #include <linux/fs.h>
23 #include <linux/seq_file.h>
24 #include <linux/kdev_t.h>
25 #include <linux/major.h>
26 #include <linux/string.h>
27 #include <linux/blk.h>
28 #include <linux/init.h>
29 #include <linux/inet.h>
30 #include <linux/console.h>
31
32 #include <asm/segment.h>
33 #include <asm/system.h>
34 #include <asm/io.h>
35 #include <asm/processor.h>
36 #include <asm/oplib.h>
37 #include <asm/page.h>
38 #include <asm/pgtable.h>
39 #include <asm/idprom.h>
40 #include <asm/head.h>
41 #include <asm/starfire.h>
42 #include <asm/hardirq.h>
43 #include <asm/sections.h>
44
45 #ifdef CONFIG_IP_PNP
46 #include <net/ipconfig.h>
47 #endif
48
49 struct screen_info screen_info = {
50 0, 0, /* orig-x, orig-y */
51 0, /* unused */
52 0, /* orig-video-page */
53 0, /* orig-video-mode */
54 128, /* orig-video-cols */
55 0, 0, 0, /* unused, ega_bx, unused */
56 54, /* orig-video-lines */
57 0, /* orig-video-isVGA */
58 16 /* orig-video-points */
59 };
60
61 /* Typing sync at the prom prompt calls the function pointed to by
62 * the sync callback which I set to the following function.
63 * This should sync all filesystems and return, for now it just
64 * prints out pretty messages and returns.
65 */
66
67 #if CONFIG_SUN_CONSOLE
68 void (*prom_palette)(int);
69 #endif
70 void (*prom_keyboard)(void);
71 asmlinkage void sys_sync(void); /* it's really int */
72
73 static void
prom_console_write(struct console * con,const char * s,unsigned n)74 prom_console_write(struct console *con, const char *s, unsigned n)
75 {
76 prom_printf("%s", s);
77 }
78
79 static struct console prom_console = {
80 name: "prom",
81 write: prom_console_write,
82 flags: CON_CONSDEV | CON_ENABLED,
83 index: -1,
84 };
85
86 #define PROM_TRUE -1
87 #define PROM_FALSE 0
88
89 /* Pretty sick eh? */
prom_callback(long * args)90 int prom_callback(long *args)
91 {
92 struct console *cons, *saved_console = NULL;
93 unsigned long flags;
94 char *cmd;
95 extern spinlock_t prom_entry_lock;
96
97 if (!args)
98 return -1;
99 if (!(cmd = (char *)args[0]))
100 return -1;
101
102 /*
103 * The callback can be invoked on the cpu that first dropped
104 * into prom_cmdline after taking the serial interrupt, or on
105 * a slave processor that was smp_captured() if the
106 * administrator has done a switch-cpu inside obp. In either
107 * case, the cpu is marked as in-interrupt. Drop IRQ locks.
108 */
109 irq_exit(smp_processor_id(), 0);
110 save_and_cli(flags);
111 spin_unlock(&prom_entry_lock);
112 cons = console_drivers;
113 while (cons) {
114 unregister_console(cons);
115 cons->flags &= ~(CON_PRINTBUFFER);
116 cons->next = saved_console;
117 saved_console = cons;
118 cons = console_drivers;
119 }
120 register_console(&prom_console);
121 if (!strcmp(cmd, "sync")) {
122 prom_printf("PROM `%s' command...\n", cmd);
123 show_free_areas();
124 if(current->pid != 0) {
125 sti();
126 sys_sync();
127 cli();
128 }
129 args[2] = 0;
130 args[args[1] + 3] = -1;
131 prom_printf("Returning to PROM\n");
132 } else if (!strcmp(cmd, "va>tte-data")) {
133 unsigned long ctx, va;
134 unsigned long tte = 0;
135 long res = PROM_FALSE;
136
137 ctx = args[3];
138 va = args[4];
139 if (ctx) {
140 /*
141 * Find process owning ctx, lookup mapping.
142 */
143 struct task_struct *p;
144 struct mm_struct *mm = NULL;
145 pgd_t *pgdp;
146 pmd_t *pmdp;
147 pte_t *ptep;
148
149 for_each_task(p) {
150 mm = p->mm;
151 if (CTX_HWBITS(mm->context) == ctx)
152 break;
153 }
154 if (!mm ||
155 CTX_HWBITS(mm->context) != ctx)
156 goto done;
157
158 pgdp = pgd_offset(mm, va);
159 if (pgd_none(*pgdp))
160 goto done;
161 pmdp = pmd_offset(pgdp, va);
162 if (pmd_none(*pmdp))
163 goto done;
164 ptep = pte_offset(pmdp, va);
165 if (!pte_present(*ptep))
166 goto done;
167 tte = pte_val(*ptep);
168 res = PROM_TRUE;
169 goto done;
170 }
171
172 if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
173 /* Spitfire Errata #32 workaround */
174 __asm__ __volatile__("stxa %0, [%1] %2\n\t"
175 "flush %%g6"
176 : /* No outputs */
177 : "r" (0),
178 "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
179
180 /*
181 * Locked down tlb entry.
182 */
183
184 if (tlb_type == spitfire)
185 tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
186 else if (tlb_type == cheetah || tlb_type == cheetah_plus)
187 tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
188
189 res = PROM_TRUE;
190 goto done;
191 }
192
193 if (va < PGDIR_SIZE) {
194 /*
195 * vmalloc or prom_inherited mapping.
196 */
197 pgd_t *pgdp;
198 pmd_t *pmdp;
199 pte_t *ptep;
200 int error;
201
202 if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) {
203 tte = prom_virt_to_phys(va, &error);
204 if (!error)
205 res = PROM_TRUE;
206 goto done;
207 }
208 pgdp = pgd_offset_k(va);
209 if (pgd_none(*pgdp))
210 goto done;
211 pmdp = pmd_offset(pgdp, va);
212 if (pmd_none(*pmdp))
213 goto done;
214 ptep = pte_offset(pmdp, va);
215 if (!pte_present(*ptep))
216 goto done;
217 tte = pte_val(*ptep);
218 res = PROM_TRUE;
219 goto done;
220 }
221
222 if (va < PAGE_OFFSET) {
223 /*
224 * No mappings here.
225 */
226 goto done;
227 }
228
229 if (va & (1UL << 40)) {
230 /*
231 * I/O page.
232 */
233
234 tte = (__pa(va) & _PAGE_PADDR) |
235 _PAGE_VALID | _PAGE_SZ4MB |
236 _PAGE_E | _PAGE_P | _PAGE_W;
237 res = PROM_TRUE;
238 goto done;
239 }
240
241 /*
242 * Normal page.
243 */
244 tte = (__pa(va) & _PAGE_PADDR) |
245 _PAGE_VALID | _PAGE_SZ4MB |
246 _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W;
247 res = PROM_TRUE;
248
249 done:
250 if (res == PROM_TRUE) {
251 args[2] = 3;
252 args[args[1] + 3] = 0;
253 args[args[1] + 4] = res;
254 args[args[1] + 5] = tte;
255 } else {
256 args[2] = 2;
257 args[args[1] + 3] = 0;
258 args[args[1] + 4] = res;
259 }
260 } else if (!strcmp(cmd, ".soft1")) {
261 unsigned long tte;
262
263 tte = args[3];
264 prom_printf("%lx:\"%s%s%s%s%s\" ",
265 (tte & _PAGE_SOFT) >> 7,
266 tte & _PAGE_MODIFIED ? "M" : "-",
267 tte & _PAGE_ACCESSED ? "A" : "-",
268 tte & _PAGE_READ ? "W" : "-",
269 tte & _PAGE_WRITE ? "R" : "-",
270 tte & _PAGE_PRESENT ? "P" : "-");
271
272 args[2] = 2;
273 args[args[1] + 3] = 0;
274 args[args[1] + 4] = PROM_TRUE;
275 } else if (!strcmp(cmd, ".soft2")) {
276 unsigned long tte;
277
278 tte = args[3];
279 prom_printf("%lx ", (tte & 0x07FC000000000000) >> 50);
280
281 args[2] = 2;
282 args[args[1] + 3] = 0;
283 args[args[1] + 4] = PROM_TRUE;
284 } else {
285 prom_printf("unknown PROM `%s' command...\n", cmd);
286 }
287 unregister_console(&prom_console);
288 while (saved_console) {
289 cons = saved_console;
290 saved_console = cons->next;
291 register_console(cons);
292 }
293 spin_lock(&prom_entry_lock);
294 restore_flags(flags);
295 /*
296 * Restore in-interrupt status for a resume from obp.
297 */
298 irq_enter(smp_processor_id(), 0);
299 return 0;
300 }
301
302 extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
303
304 unsigned int boot_flags = 0;
305 #define BOOTME_DEBUG 0x1
306 #define BOOTME_SINGLE 0x2
307 #define BOOTME_KGDB 0x4
308
309 #ifdef CONFIG_SUN_CONSOLE
310 static int console_fb __initdata = 0;
311 #endif
312
313 /* Exported for mm/init.c:paging_init. */
314 unsigned long cmdline_memory_size = 0;
315
316 static struct console prom_debug_console = {
317 name: "debug",
318 write: prom_console_write,
319 flags: CON_PRINTBUFFER,
320 index: -1,
321 };
322
323 /* XXX Implement this at some point... */
kernel_enter_debugger(void)324 void kernel_enter_debugger(void)
325 {
326 }
327
obp_system_intr(void)328 int obp_system_intr(void)
329 {
330 if (boot_flags & BOOTME_DEBUG) {
331 printk("OBP: system interrupted\n");
332 prom_halt();
333 return 1;
334 }
335 return 0;
336 }
337
338 /*
339 * Process kernel command line switches that are specific to the
340 * SPARC or that require special low-level processing.
341 */
process_switch(char c)342 static void __init process_switch(char c)
343 {
344 switch (c) {
345 case 'd':
346 boot_flags |= BOOTME_DEBUG;
347 break;
348 case 's':
349 boot_flags |= BOOTME_SINGLE;
350 break;
351 case 'h':
352 prom_printf("boot_flags_init: Halt!\n");
353 prom_halt();
354 break;
355 case 'p':
356 /* Use PROM debug console. */
357 register_console(&prom_debug_console);
358 break;
359 default:
360 printk("Unknown boot switch (-%c)\n", c);
361 break;
362 }
363 }
364
boot_flags_init(char * commands)365 static void __init boot_flags_init(char *commands)
366 {
367 while (*commands) {
368 /* Move to the start of the next "argument". */
369 while (*commands && *commands == ' ')
370 commands++;
371
372 /* Process any command switches, otherwise skip it. */
373 if (*commands == '\0')
374 break;
375 else if (*commands == '-') {
376 commands++;
377 while (*commands && *commands != ' ')
378 process_switch(*commands++);
379 } else if (strlen(commands) >= 9
380 && !strncmp(commands, "kgdb=tty", 8)) {
381 boot_flags |= BOOTME_KGDB;
382 switch (commands[8]) {
383 #ifdef CONFIG_SUN_SERIAL
384 case 'a':
385 rs_kgdb_hook(0);
386 prom_printf("KGDB: Using serial line /dev/ttya.\n");
387 break;
388 case 'b':
389 rs_kgdb_hook(1);
390 prom_printf("KGDB: Using serial line /dev/ttyb.\n");
391 break;
392 #endif
393 default:
394 printk("KGDB: Unknown tty line.\n");
395 boot_flags &= ~BOOTME_KGDB;
396 break;
397 }
398 commands += 9;
399 } else {
400 #if CONFIG_SUN_CONSOLE
401 if (!strncmp(commands, "console=", 8)) {
402 commands += 8;
403 if (!strncmp (commands, "ttya", 4)) {
404 console_fb = 2;
405 prom_printf ("Using /dev/ttya as console.\n");
406 } else if (!strncmp (commands, "ttyb", 4)) {
407 console_fb = 3;
408 prom_printf ("Using /dev/ttyb as console.\n");
409 #if defined(CONFIG_PROM_CONSOLE)
410 } else if (!strncmp (commands, "prom", 4)) {
411 char *p;
412
413 for (p = commands - 8; *p && *p != ' '; p++)
414 *p = ' ';
415 conswitchp = &prom_con;
416 console_fb = 1;
417 #endif
418 } else {
419 console_fb = 1;
420 }
421 } else
422 #endif
423 if (!strncmp(commands, "mem=", 4)) {
424 /*
425 * "mem=XXX[kKmM]" overrides the PROM-reported
426 * memory size.
427 */
428 cmdline_memory_size = simple_strtoul(commands + 4,
429 &commands, 0);
430 if (*commands == 'K' || *commands == 'k') {
431 cmdline_memory_size <<= 10;
432 commands++;
433 } else if (*commands=='M' || *commands=='m') {
434 cmdline_memory_size <<= 20;
435 commands++;
436 }
437 }
438 while (*commands && *commands != ' ')
439 commands++;
440 }
441 }
442 }
443
444 extern int prom_probe_memory(void);
445 extern unsigned long start, end;
446 extern void panic_setup(char *, int *);
447
448 extern unsigned short root_flags;
449 extern unsigned short root_dev;
450 extern unsigned short ram_flags;
451 #define RAMDISK_IMAGE_START_MASK 0x07FF
452 #define RAMDISK_PROMPT_FLAG 0x8000
453 #define RAMDISK_LOAD_FLAG 0x4000
454
455 extern int root_mountflags;
456
457 char saved_command_line[256];
458 char reboot_command[256];
459
460 extern unsigned long phys_base, kern_base, kern_size;
461
462 static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
463
register_prom_callbacks(void)464 void register_prom_callbacks(void)
465 {
466 prom_setcallback(prom_callback);
467 prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
468 "' linux-va>tte-data to va>tte-data");
469 prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
470 "' linux-.soft1 to .soft1");
471 prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
472 "' linux-.soft2 to .soft2");
473 }
474
475 extern void paging_init(void);
476
setup_arch(char ** cmdline_p)477 void __init setup_arch(char **cmdline_p)
478 {
479 extern int serial_console; /* in console.c, of course */
480 unsigned long highest_paddr;
481 int i;
482
483 /* Initialize PROM console and command line. */
484 *cmdline_p = prom_getbootargs();
485 strcpy(saved_command_line, *cmdline_p);
486
487 printk("ARCH: SUN4U\n");
488
489 #ifdef CONFIG_DUMMY_CONSOLE
490 conswitchp = &dummy_con;
491 #elif defined(CONFIG_PROM_CONSOLE)
492 conswitchp = &prom_con;
493 #endif
494
495 #ifdef CONFIG_SMP
496 i = (unsigned long)&irq_stat[1] - (unsigned long)&irq_stat[0];
497 if ((i == SMP_CACHE_BYTES) || (i == (2 * SMP_CACHE_BYTES))) {
498 extern unsigned int irqsz_patchme[1];
499 irqsz_patchme[0] |= ((i == SMP_CACHE_BYTES) ? SMP_CACHE_BYTES_SHIFT : \
500 SMP_CACHE_BYTES_SHIFT + 1);
501 flushi((long)&irqsz_patchme[0]);
502 } else {
503 prom_printf("Unexpected size of irq_stat[] elements\n");
504 prom_halt();
505 }
506 #endif
507 /* Work out if we are starfire early on */
508 check_if_starfire();
509
510 boot_flags_init(*cmdline_p);
511
512 idprom_init();
513 (void) prom_probe_memory();
514
515 /* In paging_init() we tip off this value to see if we need
516 * to change init_mm.pgd to point to the real alias mapping.
517 */
518 phys_base = 0xffffffffffffffffUL;
519 highest_paddr = 0UL;
520 for (i = 0; sp_banks[i].num_bytes != 0; i++) {
521 unsigned long top;
522
523 if (sp_banks[i].base_addr < phys_base)
524 phys_base = sp_banks[i].base_addr;
525 top = sp_banks[i].base_addr +
526 sp_banks[i].num_bytes;
527 if (highest_paddr < top)
528 highest_paddr = top;
529 }
530
531 switch (tlb_type) {
532 default:
533 case spitfire:
534 kern_base = spitfire_get_itlb_data(sparc64_highest_locked_tlbent());
535 kern_base &= _PAGE_PADDR_SF;
536 break;
537
538 case cheetah:
539 case cheetah_plus:
540 kern_base = cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
541 kern_base &= _PAGE_PADDR;
542 break;
543 };
544
545 kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
546
547 if (!root_flags)
548 root_mountflags &= ~MS_RDONLY;
549 ROOT_DEV = to_kdev_t(root_dev);
550 #ifdef CONFIG_BLK_DEV_INITRD
551 rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
552 rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
553 rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
554 #endif
555
556 init_task.thread.kregs = &fake_swapper_regs;
557
558 #ifdef CONFIG_IP_PNP
559 if (!ic_set_manually) {
560 int chosen = prom_finddevice ("/chosen");
561 u32 cl, sv, gw;
562
563 cl = prom_getintdefault (chosen, "client-ip", 0);
564 sv = prom_getintdefault (chosen, "server-ip", 0);
565 gw = prom_getintdefault (chosen, "gateway-ip", 0);
566 if (cl && sv) {
567 ic_myaddr = cl;
568 ic_servaddr = sv;
569 if (gw)
570 ic_gateway = gw;
571 #if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
572 ic_proto_enabled = 0;
573 #endif
574 }
575 }
576 #endif
577
578 #ifdef CONFIG_SUN_SERIAL
579 switch (console_fb) {
580 case 0: /* Let's get our io devices from prom */
581 {
582 int idev = prom_query_input_device();
583 int odev = prom_query_output_device();
584 if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
585 serial_console = 0;
586 } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
587 serial_console = 1;
588 } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
589 serial_console = 2;
590 } else {
591 prom_printf("Inconsistent console: "
592 "input %d, output %d\n",
593 idev, odev);
594 prom_halt();
595 }
596 }
597 break;
598 case 1: /* Force one of the framebuffers as console */
599 serial_console = 0;
600 break;
601 case 2: /* Force ttya as console */
602 serial_console = 1;
603 break;
604 case 3: /* Force ttyb as console */
605 serial_console = 2;
606 break;
607 }
608 #else
609 serial_console = 0;
610 #endif
611 if (serial_console)
612 conswitchp = NULL;
613
614 paging_init();
615 }
616
sys_ioperm(unsigned long from,unsigned long num,int on)617 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
618 {
619 return -EIO;
620 }
621
622 /* BUFFER is PAGE_SIZE bytes long. */
623
624 extern char *sparc_cpu_type;
625 extern char *sparc_fpu_type;
626
627 extern void smp_info(struct seq_file *);
628 extern void smp_bogo(struct seq_file *);
629 extern void mmu_info(struct seq_file *);
630
631 #ifndef CONFIG_SMP
632 unsigned long up_clock_tick;
633 #endif
634
show_cpuinfo(struct seq_file * m,void * __unused)635 static int show_cpuinfo(struct seq_file *m, void *__unused)
636 {
637 seq_printf(m,
638 "cpu\t\t: %s\n"
639 "fpu\t\t: %s\n"
640 "promlib\t\t: Version 3 Revision %d\n"
641 "prom\t\t: %d.%d.%d\n"
642 "type\t\t: sun4u\n"
643 "ncpus probed\t: %d\n"
644 "ncpus active\t: %d\n"
645 #ifndef CONFIG_SMP
646 "Cpu0Bogo\t: %lu.%02lu\n"
647 "Cpu0ClkTck\t: %016lx\n"
648 #endif
649 ,
650 sparc_cpu_type,
651 sparc_fpu_type,
652 prom_rev,
653 prom_prev >> 16,
654 (prom_prev >> 8) & 0xff,
655 prom_prev & 0xff,
656 linux_num_cpus,
657 smp_num_cpus
658 #ifndef CONFIG_SMP
659 , loops_per_jiffy/(500000/HZ),
660 (loops_per_jiffy/(5000/HZ)) % 100,
661 up_clock_tick
662 #endif
663 );
664 #ifdef CONFIG_SMP
665 smp_bogo(m);
666 #endif
667 mmu_info(m);
668 #ifdef CONFIG_SMP
669 smp_info(m);
670 #endif
671 return 0;
672 }
673
c_start(struct seq_file * m,loff_t * pos)674 static void *c_start(struct seq_file *m, loff_t *pos)
675 {
676 /* The pointer we are returning is arbitrary,
677 * it just has to be non-NULL and not IS_ERR
678 * in the success case.
679 */
680 return *pos == 0 ? &c_start : NULL;
681 }
682
c_next(struct seq_file * m,void * v,loff_t * pos)683 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
684 {
685 ++*pos;
686 return c_start(m, pos);
687 }
688
c_stop(struct seq_file * m,void * v)689 static void c_stop(struct seq_file *m, void *v)
690 {
691 }
692
693 struct seq_operations cpuinfo_op = {
694 start: c_start,
695 next: c_next,
696 stop: c_stop,
697 show: show_cpuinfo,
698 };
699