1 /* $Id: setup.c,v 1.72 2002/02/09 19:49:30 davem Exp $
2 * linux/arch/sparc64/kernel/setup.c
4 * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
8 #include <linux/errno.h>
9 #include <linux/sched.h>
10 #include <linux/kernel.h>
12 #include <linux/stddef.h>
13 #include <linux/unistd.h>
14 #include <linux/ptrace.h>
15 #include <linux/slab.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>
23 #include <linux/seq_file.h>
24 #include <linux/syscalls.h>
25 #include <linux/kdev_t.h>
26 #include <linux/major.h>
27 #include <linux/string.h>
28 #include <linux/init.h>
29 #include <linux/inet.h>
30 #include <linux/console.h>
31 #include <linux/root_dev.h>
32 #include <linux/interrupt.h>
33 #include <linux/cpu.h>
34 #include <linux/initrd.h>
36 #include <asm/system.h>
38 #include <asm/processor.h>
39 #include <asm/oplib.h>
41 #include <asm/pgtable.h>
42 #include <asm/idprom.h>
44 #include <asm/starfire.h>
45 #include <asm/mmu_context.h>
46 #include <asm/timer.h>
47 #include <asm/sections.h>
48 #include <asm/setup.h>
52 #include <net/ipconfig.h>
55 struct screen_info screen_info
= {
56 0, 0, /* orig-x, orig-y */
58 0, /* orig-video-page */
59 0, /* orig-video-mode */
60 128, /* orig-video-cols */
61 0, 0, 0, /* unused, ega_bx, unused */
62 54, /* orig-video-lines */
63 0, /* orig-video-isVGA */
64 16 /* orig-video-points */
67 /* Typing sync at the prom prompt calls the function pointed to by
68 * the sync callback which I set to the following function.
69 * This should sync all filesystems and return, for now it just
70 * prints out pretty messages and returns.
73 void (*prom_palette
)(int);
74 void (*prom_keyboard
)(void);
77 prom_console_write(struct console
*con
, const char *s
, unsigned n
)
82 static struct console prom_console
= {
84 .write
= prom_console_write
,
85 .flags
= CON_CONSDEV
| CON_ENABLED
,
93 int prom_callback(long *args
)
95 struct console
*cons
, *saved_console
= NULL
;
98 extern spinlock_t prom_entry_lock
;
102 if (!(cmd
= (char *)args
[0]))
106 * The callback can be invoked on the cpu that first dropped
107 * into prom_cmdline after taking the serial interrupt, or on
108 * a slave processor that was smp_captured() if the
109 * administrator has done a switch-cpu inside obp. In either
110 * case, the cpu is marked as in-interrupt. Drop IRQ locks.
114 /* XXX Revisit the locking here someday. This is a debugging
115 * XXX feature so it isnt all that critical. -DaveM
117 local_irq_save(flags
);
119 spin_unlock(&prom_entry_lock
);
120 cons
= console_drivers
;
122 unregister_console(cons
);
123 cons
->flags
&= ~(CON_PRINTBUFFER
);
124 cons
->next
= saved_console
;
125 saved_console
= cons
;
126 cons
= console_drivers
;
128 register_console(&prom_console
);
129 if (!strcmp(cmd
, "sync")) {
130 prom_printf("PROM `%s' command...\n", cmd
);
132 if (current
->pid
!= 0) {
138 args
[args
[1] + 3] = -1;
139 prom_printf("Returning to PROM\n");
140 } else if (!strcmp(cmd
, "va>tte-data")) {
141 unsigned long ctx
, va
;
142 unsigned long tte
= 0;
143 long res
= PROM_FALSE
;
149 * Find process owning ctx, lookup mapping.
151 struct task_struct
*p
;
152 struct mm_struct
*mm
= NULL
;
158 for_each_process(p
) {
160 if (CTX_NRBITS(mm
->context
) == ctx
)
164 CTX_NRBITS(mm
->context
) != ctx
)
167 pgdp
= pgd_offset(mm
, va
);
170 pudp
= pud_offset(pgdp
, va
);
173 pmdp
= pmd_offset(pudp
, va
);
177 /* Preemption implicitly disabled by virtue of
178 * being called from inside OBP.
180 ptep
= pte_offset_map(pmdp
, va
);
181 if (pte_present(*ptep
)) {
182 tte
= pte_val(*ptep
);
189 if ((va
>= KERNBASE
) && (va
< (KERNBASE
+ (4 * 1024 * 1024)))) {
190 unsigned long kernel_pctx
= 0;
192 if (tlb_type
== cheetah_plus
)
193 kernel_pctx
|= (CTX_CHEETAH_PLUS_NUC
|
194 CTX_CHEETAH_PLUS_CTX0
);
196 /* Spitfire Errata #32 workaround */
197 __asm__
__volatile__("stxa %0, [%1] %2\n\t"
201 "r" (PRIMARY_CONTEXT
),
205 * Locked down tlb entry.
208 if (tlb_type
== spitfire
)
209 tte
= spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT
);
210 else if (tlb_type
== cheetah
|| tlb_type
== cheetah_plus
)
211 tte
= cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT
);
217 if (va
< PGDIR_SIZE
) {
219 * vmalloc or prom_inherited mapping.
227 if ((va
>= LOW_OBP_ADDRESS
) && (va
< HI_OBP_ADDRESS
)) {
228 tte
= prom_virt_to_phys(va
, &error
);
233 pgdp
= pgd_offset_k(va
);
236 pudp
= pud_offset(pgdp
, va
);
239 pmdp
= pmd_offset(pudp
, va
);
243 /* Preemption implicitly disabled by virtue of
244 * being called from inside OBP.
246 ptep
= pte_offset_kernel(pmdp
, va
);
247 if (pte_present(*ptep
)) {
248 tte
= pte_val(*ptep
);
254 if (va
< PAGE_OFFSET
) {
261 if (va
& (1UL << 40)) {
266 tte
= (__pa(va
) & _PAGE_PADDR
) |
267 _PAGE_VALID
| _PAGE_SZ4MB
|
268 _PAGE_E
| _PAGE_P
| _PAGE_W
;
276 tte
= (__pa(va
) & _PAGE_PADDR
) |
277 _PAGE_VALID
| _PAGE_SZ4MB
|
278 _PAGE_CP
| _PAGE_CV
| _PAGE_P
| _PAGE_W
;
282 if (res
== PROM_TRUE
) {
284 args
[args
[1] + 3] = 0;
285 args
[args
[1] + 4] = res
;
286 args
[args
[1] + 5] = tte
;
289 args
[args
[1] + 3] = 0;
290 args
[args
[1] + 4] = res
;
292 } else if (!strcmp(cmd
, ".soft1")) {
296 prom_printf("%lx:\"%s%s%s%s%s\" ",
297 (tte
& _PAGE_SOFT
) >> 7,
298 tte
& _PAGE_MODIFIED
? "M" : "-",
299 tte
& _PAGE_ACCESSED
? "A" : "-",
300 tte
& _PAGE_READ
? "W" : "-",
301 tte
& _PAGE_WRITE
? "R" : "-",
302 tte
& _PAGE_PRESENT
? "P" : "-");
305 args
[args
[1] + 3] = 0;
306 args
[args
[1] + 4] = PROM_TRUE
;
307 } else if (!strcmp(cmd
, ".soft2")) {
311 prom_printf("%lx ", (tte
& 0x07FC000000000000UL
) >> 50);
314 args
[args
[1] + 3] = 0;
315 args
[args
[1] + 4] = PROM_TRUE
;
317 prom_printf("unknown PROM `%s' command...\n", cmd
);
319 unregister_console(&prom_console
);
320 while (saved_console
) {
321 cons
= saved_console
;
322 saved_console
= cons
->next
;
323 register_console(cons
);
325 spin_lock(&prom_entry_lock
);
326 local_irq_restore(flags
);
329 * Restore in-interrupt status for a resume from obp.
335 unsigned int boot_flags
= 0;
336 #define BOOTME_DEBUG 0x1
337 #define BOOTME_SINGLE 0x2
339 /* Exported for mm/init.c:paging_init. */
340 unsigned long cmdline_memory_size
= 0;
342 static struct console prom_debug_console
= {
344 .write
= prom_console_write
,
345 .flags
= CON_PRINTBUFFER
,
349 /* XXX Implement this at some point... */
350 void kernel_enter_debugger(void)
354 int obp_system_intr(void)
356 if (boot_flags
& BOOTME_DEBUG
) {
357 printk("OBP: system interrupted\n");
365 * Process kernel command line switches that are specific to the
366 * SPARC or that require special low-level processing.
368 static void __init
process_switch(char c
)
372 boot_flags
|= BOOTME_DEBUG
;
375 boot_flags
|= BOOTME_SINGLE
;
378 prom_printf("boot_flags_init: Halt!\n");
382 /* Use PROM debug console. */
383 register_console(&prom_debug_console
);
386 /* Force UltraSPARC-III P-Cache on. */
387 if (tlb_type
!= cheetah
) {
388 printk("BOOT: Ignoring P-Cache force option.\n");
391 cheetah_pcache_forced_on
= 1;
392 add_taint(TAINT_MACHINE_CHECK
);
393 cheetah_enable_pcache();
397 printk("Unknown boot switch (-%c)\n", c
);
402 static void __init
process_console(char *commands
)
406 /* Linux-style serial */
407 if (!strncmp(commands
, "ttyS", 4))
408 serial_console
= simple_strtoul(commands
+ 4, NULL
, 10) + 1;
409 else if (!strncmp(commands
, "tty", 3)) {
410 char c
= *(commands
+ 3);
411 /* Solaris-style serial */
412 if (c
== 'a' || c
== 'b') {
413 serial_console
= c
- 'a' + 1;
414 prom_printf ("Using /dev/tty%c as console.\n", c
);
416 /* else Linux-style fbcon, not serial */
418 #if defined(CONFIG_PROM_CONSOLE)
419 if (!strncmp(commands
, "prom", 4)) {
422 for (p
= commands
- 8; *p
&& *p
!= ' '; p
++)
424 conswitchp
= &prom_con
;
429 static void __init
boot_flags_init(char *commands
)
432 /* Move to the start of the next "argument". */
433 while (*commands
&& *commands
== ' ')
436 /* Process any command switches, otherwise skip it. */
437 if (*commands
== '\0')
439 if (*commands
== '-') {
441 while (*commands
&& *commands
!= ' ')
442 process_switch(*commands
++);
445 if (!strncmp(commands
, "console=", 8)) {
446 process_console(commands
);
447 } else if (!strncmp(commands
, "mem=", 4)) {
449 * "mem=XXX[kKmM]" overrides the PROM-reported
452 cmdline_memory_size
= simple_strtoul(commands
+ 4,
454 if (*commands
== 'K' || *commands
== 'k') {
455 cmdline_memory_size
<<= 10;
457 } else if (*commands
=='M' || *commands
=='m') {
458 cmdline_memory_size
<<= 20;
462 while (*commands
&& *commands
!= ' ')
467 extern int prom_probe_memory(void);
468 extern unsigned long start
, end
;
469 extern void panic_setup(char *, int *);
471 extern unsigned short root_flags
;
472 extern unsigned short root_dev
;
473 extern unsigned short ram_flags
;
474 #define RAMDISK_IMAGE_START_MASK 0x07FF
475 #define RAMDISK_PROMPT_FLAG 0x8000
476 #define RAMDISK_LOAD_FLAG 0x4000
478 extern int root_mountflags
;
480 char reboot_command
[COMMAND_LINE_SIZE
];
482 static struct pt_regs fake_swapper_regs
= { { 0, }, 0, 0, 0, 0 };
484 void register_prom_callbacks(void)
486 prom_setcallback(prom_callback
);
487 prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
488 "' linux-va>tte-data to va>tte-data");
489 prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
490 "' linux-.soft1 to .soft1");
491 prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
492 "' linux-.soft2 to .soft2");
495 extern void paging_init(void);
497 void __init
setup_arch(char **cmdline_p
)
499 unsigned long highest_paddr
;
502 /* Initialize PROM console and command line. */
503 *cmdline_p
= prom_getbootargs();
504 strcpy(saved_command_line
, *cmdline_p
);
506 printk("ARCH: SUN4U\n");
508 #ifdef CONFIG_DUMMY_CONSOLE
509 conswitchp
= &dummy_con
;
510 #elif defined(CONFIG_PROM_CONSOLE)
511 conswitchp
= &prom_con
;
514 /* Work out if we are starfire early on */
517 boot_flags_init(*cmdline_p
);
520 (void) prom_probe_memory();
522 /* In paging_init() we tip off this value to see if we need
523 * to change init_mm.pgd to point to the real alias mapping.
525 phys_base
= 0xffffffffffffffffUL
;
527 for (i
= 0; sp_banks
[i
].num_bytes
!= 0; i
++) {
530 if (sp_banks
[i
].base_addr
< phys_base
)
531 phys_base
= sp_banks
[i
].base_addr
;
532 top
= sp_banks
[i
].base_addr
+
533 sp_banks
[i
].num_bytes
;
534 if (highest_paddr
< top
)
537 pfn_base
= phys_base
>> PAGE_SHIFT
;
542 kern_base
= spitfire_get_itlb_data(sparc64_highest_locked_tlbent());
543 kern_base
&= _PAGE_PADDR_SF
;
548 kern_base
= cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
549 kern_base
&= _PAGE_PADDR
;
553 kern_size
= (unsigned long)&_end
- (unsigned long)KERNBASE
;
556 root_mountflags
&= ~MS_RDONLY
;
557 ROOT_DEV
= old_decode_dev(root_dev
);
558 #ifdef CONFIG_BLK_DEV_INITRD
559 rd_image_start
= ram_flags
& RAMDISK_IMAGE_START_MASK
;
560 rd_prompt
= ((ram_flags
& RAMDISK_PROMPT_FLAG
) != 0);
561 rd_doload
= ((ram_flags
& RAMDISK_LOAD_FLAG
) != 0);
564 init_task
.thread_info
->kregs
= &fake_swapper_regs
;
567 if (!ic_set_manually
) {
568 int chosen
= prom_finddevice ("/chosen");
571 cl
= prom_getintdefault (chosen
, "client-ip", 0);
572 sv
= prom_getintdefault (chosen
, "server-ip", 0);
573 gw
= prom_getintdefault (chosen
, "gateway-ip", 0);
579 #if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
580 ic_proto_enabled
= 0;
589 static int __init
set_preferred_console(void)
593 /* The user has requested a console so this is already set up. */
594 if (serial_console
>= 0)
597 idev
= prom_query_input_device();
598 odev
= prom_query_output_device();
599 if (idev
== PROMDEV_IKBD
&& odev
== PROMDEV_OSCREEN
) {
601 } else if (idev
== PROMDEV_ITTYA
&& odev
== PROMDEV_OTTYA
) {
603 } else if (idev
== PROMDEV_ITTYB
&& odev
== PROMDEV_OTTYB
) {
606 prom_printf("Inconsistent console: "
607 "input %d, output %d\n",
613 return add_preferred_console("ttyS", serial_console
- 1, NULL
);
617 console_initcall(set_preferred_console
);
619 /* BUFFER is PAGE_SIZE bytes long. */
621 extern char *sparc_cpu_type
;
622 extern char *sparc_fpu_type
;
624 extern void smp_info(struct seq_file
*);
625 extern void smp_bogo(struct seq_file
*);
626 extern void mmu_info(struct seq_file
*);
628 static int show_cpuinfo(struct seq_file
*m
, void *__unused
)
633 "promlib\t\t: Version 3 Revision %d\n"
634 "prom\t\t: %d.%d.%d\n"
636 "ncpus probed\t: %ld\n"
637 "ncpus active\t: %ld\n"
639 "Cpu0Bogo\t: %lu.%02lu\n"
640 "Cpu0ClkTck\t: %016lx\n"
647 (prom_prev
>> 8) & 0xff,
649 (long)num_possible_cpus(),
650 (long)num_online_cpus()
652 , cpu_data(0).udelay_val
/(500000/HZ
),
653 (cpu_data(0).udelay_val
/(5000/HZ
)) % 100,
654 cpu_data(0).clock_tick
667 static void *c_start(struct seq_file
*m
, loff_t
*pos
)
669 /* The pointer we are returning is arbitrary,
670 * it just has to be non-NULL and not IS_ERR
671 * in the success case.
673 return *pos
== 0 ? &c_start
: NULL
;
676 static void *c_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
679 return c_start(m
, pos
);
682 static void c_stop(struct seq_file
*m
, void *v
)
686 struct seq_operations cpuinfo_op
= {
690 .show
= show_cpuinfo
,
693 extern int stop_a_enabled
;
695 void sun_do_break(void)
701 flush_user_windows();
706 int serial_console
= -1;
707 int stop_a_enabled
= 1;
709 static int __init
topology_init(void)
714 for (i
= 0; i
< NR_CPUS
; i
++) {
715 if (cpu_possible(i
)) {
716 struct cpu
*p
= kmalloc(sizeof(*p
), GFP_KERNEL
);
719 memset(p
, 0, sizeof(*p
));
720 register_cpu(p
, i
, NULL
);
729 subsys_initcall(topology_init
);