diff options
Diffstat (limited to 'arch/sparc/kernel/setup_64.c')
-rw-r--r-- | arch/sparc/kernel/setup_64.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c new file mode 100644 index 000000000000..555db7452ebe --- /dev/null +++ b/arch/sparc/kernel/setup_64.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
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/screen_info.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/syscalls.h> | ||
23 | #include <linux/kdev_t.h> | ||
24 | #include <linux/major.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/inet.h> | ||
28 | #include <linux/console.h> | ||
29 | #include <linux/root_dev.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/cpu.h> | ||
32 | #include <linux/initrd.h> | ||
33 | |||
34 | #include <asm/system.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/processor.h> | ||
37 | #include <asm/oplib.h> | ||
38 | #include <asm/page.h> | ||
39 | #include <asm/pgtable.h> | ||
40 | #include <asm/idprom.h> | ||
41 | #include <asm/head.h> | ||
42 | #include <asm/starfire.h> | ||
43 | #include <asm/mmu_context.h> | ||
44 | #include <asm/timer.h> | ||
45 | #include <asm/sections.h> | ||
46 | #include <asm/setup.h> | ||
47 | #include <asm/mmu.h> | ||
48 | #include <asm/ns87303.h> | ||
49 | |||
50 | #ifdef CONFIG_IP_PNP | ||
51 | #include <net/ipconfig.h> | ||
52 | #endif | ||
53 | |||
54 | #include "entry.h" | ||
55 | #include "kernel.h" | ||
56 | |||
57 | /* Used to synchronize accesses to NatSemi SUPER I/O chip configure | ||
58 | * operations in asm/ns87303.h | ||
59 | */ | ||
60 | DEFINE_SPINLOCK(ns87303_lock); | ||
61 | |||
62 | struct screen_info screen_info = { | ||
63 | 0, 0, /* orig-x, orig-y */ | ||
64 | 0, /* unused */ | ||
65 | 0, /* orig-video-page */ | ||
66 | 0, /* orig-video-mode */ | ||
67 | 128, /* orig-video-cols */ | ||
68 | 0, 0, 0, /* unused, ega_bx, unused */ | ||
69 | 54, /* orig-video-lines */ | ||
70 | 0, /* orig-video-isVGA */ | ||
71 | 16 /* orig-video-points */ | ||
72 | }; | ||
73 | |||
74 | static void | ||
75 | prom_console_write(struct console *con, const char *s, unsigned n) | ||
76 | { | ||
77 | prom_write(s, n); | ||
78 | } | ||
79 | |||
80 | /* Exported for mm/init.c:paging_init. */ | ||
81 | unsigned long cmdline_memory_size = 0; | ||
82 | |||
83 | static struct console prom_early_console = { | ||
84 | .name = "earlyprom", | ||
85 | .write = prom_console_write, | ||
86 | .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME, | ||
87 | .index = -1, | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * Process kernel command line switches that are specific to the | ||
92 | * SPARC or that require special low-level processing. | ||
93 | */ | ||
94 | static void __init process_switch(char c) | ||
95 | { | ||
96 | switch (c) { | ||
97 | case 'd': | ||
98 | case 's': | ||
99 | break; | ||
100 | case 'h': | ||
101 | prom_printf("boot_flags_init: Halt!\n"); | ||
102 | prom_halt(); | ||
103 | break; | ||
104 | case 'p': | ||
105 | /* Just ignore, this behavior is now the default. */ | ||
106 | break; | ||
107 | case 'P': | ||
108 | /* Force UltraSPARC-III P-Cache on. */ | ||
109 | if (tlb_type != cheetah) { | ||
110 | printk("BOOT: Ignoring P-Cache force option.\n"); | ||
111 | break; | ||
112 | } | ||
113 | cheetah_pcache_forced_on = 1; | ||
114 | add_taint(TAINT_MACHINE_CHECK); | ||
115 | cheetah_enable_pcache(); | ||
116 | break; | ||
117 | |||
118 | default: | ||
119 | printk("Unknown boot switch (-%c)\n", c); | ||
120 | break; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | static void __init boot_flags_init(char *commands) | ||
125 | { | ||
126 | while (*commands) { | ||
127 | /* Move to the start of the next "argument". */ | ||
128 | while (*commands && *commands == ' ') | ||
129 | commands++; | ||
130 | |||
131 | /* Process any command switches, otherwise skip it. */ | ||
132 | if (*commands == '\0') | ||
133 | break; | ||
134 | if (*commands == '-') { | ||
135 | commands++; | ||
136 | while (*commands && *commands != ' ') | ||
137 | process_switch(*commands++); | ||
138 | continue; | ||
139 | } | ||
140 | if (!strncmp(commands, "mem=", 4)) { | ||
141 | /* | ||
142 | * "mem=XXX[kKmM]" overrides the PROM-reported | ||
143 | * memory size. | ||
144 | */ | ||
145 | cmdline_memory_size = simple_strtoul(commands + 4, | ||
146 | &commands, 0); | ||
147 | if (*commands == 'K' || *commands == 'k') { | ||
148 | cmdline_memory_size <<= 10; | ||
149 | commands++; | ||
150 | } else if (*commands=='M' || *commands=='m') { | ||
151 | cmdline_memory_size <<= 20; | ||
152 | commands++; | ||
153 | } | ||
154 | } | ||
155 | while (*commands && *commands != ' ') | ||
156 | commands++; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | extern unsigned short root_flags; | ||
161 | extern unsigned short root_dev; | ||
162 | extern unsigned short ram_flags; | ||
163 | #define RAMDISK_IMAGE_START_MASK 0x07FF | ||
164 | #define RAMDISK_PROMPT_FLAG 0x8000 | ||
165 | #define RAMDISK_LOAD_FLAG 0x4000 | ||
166 | |||
167 | extern int root_mountflags; | ||
168 | |||
169 | char reboot_command[COMMAND_LINE_SIZE]; | ||
170 | |||
171 | static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; | ||
172 | |||
173 | void __init per_cpu_patch(void) | ||
174 | { | ||
175 | struct cpuid_patch_entry *p; | ||
176 | unsigned long ver; | ||
177 | int is_jbus; | ||
178 | |||
179 | if (tlb_type == spitfire && !this_is_starfire) | ||
180 | return; | ||
181 | |||
182 | is_jbus = 0; | ||
183 | if (tlb_type != hypervisor) { | ||
184 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | ||
185 | is_jbus = ((ver >> 32UL) == __JALAPENO_ID || | ||
186 | (ver >> 32UL) == __SERRANO_ID); | ||
187 | } | ||
188 | |||
189 | p = &__cpuid_patch; | ||
190 | while (p < &__cpuid_patch_end) { | ||
191 | unsigned long addr = p->addr; | ||
192 | unsigned int *insns; | ||
193 | |||
194 | switch (tlb_type) { | ||
195 | case spitfire: | ||
196 | insns = &p->starfire[0]; | ||
197 | break; | ||
198 | case cheetah: | ||
199 | case cheetah_plus: | ||
200 | if (is_jbus) | ||
201 | insns = &p->cheetah_jbus[0]; | ||
202 | else | ||
203 | insns = &p->cheetah_safari[0]; | ||
204 | break; | ||
205 | case hypervisor: | ||
206 | insns = &p->sun4v[0]; | ||
207 | break; | ||
208 | default: | ||
209 | prom_printf("Unknown cpu type, halting.\n"); | ||
210 | prom_halt(); | ||
211 | }; | ||
212 | |||
213 | *(unsigned int *) (addr + 0) = insns[0]; | ||
214 | wmb(); | ||
215 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | ||
216 | |||
217 | *(unsigned int *) (addr + 4) = insns[1]; | ||
218 | wmb(); | ||
219 | __asm__ __volatile__("flush %0" : : "r" (addr + 4)); | ||
220 | |||
221 | *(unsigned int *) (addr + 8) = insns[2]; | ||
222 | wmb(); | ||
223 | __asm__ __volatile__("flush %0" : : "r" (addr + 8)); | ||
224 | |||
225 | *(unsigned int *) (addr + 12) = insns[3]; | ||
226 | wmb(); | ||
227 | __asm__ __volatile__("flush %0" : : "r" (addr + 12)); | ||
228 | |||
229 | p++; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | void __init sun4v_patch(void) | ||
234 | { | ||
235 | extern void sun4v_hvapi_init(void); | ||
236 | struct sun4v_1insn_patch_entry *p1; | ||
237 | struct sun4v_2insn_patch_entry *p2; | ||
238 | |||
239 | if (tlb_type != hypervisor) | ||
240 | return; | ||
241 | |||
242 | p1 = &__sun4v_1insn_patch; | ||
243 | while (p1 < &__sun4v_1insn_patch_end) { | ||
244 | unsigned long addr = p1->addr; | ||
245 | |||
246 | *(unsigned int *) (addr + 0) = p1->insn; | ||
247 | wmb(); | ||
248 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | ||
249 | |||
250 | p1++; | ||
251 | } | ||
252 | |||
253 | p2 = &__sun4v_2insn_patch; | ||
254 | while (p2 < &__sun4v_2insn_patch_end) { | ||
255 | unsigned long addr = p2->addr; | ||
256 | |||
257 | *(unsigned int *) (addr + 0) = p2->insns[0]; | ||
258 | wmb(); | ||
259 | __asm__ __volatile__("flush %0" : : "r" (addr + 0)); | ||
260 | |||
261 | *(unsigned int *) (addr + 4) = p2->insns[1]; | ||
262 | wmb(); | ||
263 | __asm__ __volatile__("flush %0" : : "r" (addr + 4)); | ||
264 | |||
265 | p2++; | ||
266 | } | ||
267 | |||
268 | sun4v_hvapi_init(); | ||
269 | } | ||
270 | |||
271 | #ifdef CONFIG_SMP | ||
272 | void __init boot_cpu_id_too_large(int cpu) | ||
273 | { | ||
274 | prom_printf("Serious problem, boot cpu id (%d) >= NR_CPUS (%d)\n", | ||
275 | cpu, NR_CPUS); | ||
276 | prom_halt(); | ||
277 | } | ||
278 | #endif | ||
279 | |||
280 | void __init setup_arch(char **cmdline_p) | ||
281 | { | ||
282 | /* Initialize PROM console and command line. */ | ||
283 | *cmdline_p = prom_getbootargs(); | ||
284 | strcpy(boot_command_line, *cmdline_p); | ||
285 | parse_early_param(); | ||
286 | |||
287 | boot_flags_init(*cmdline_p); | ||
288 | register_console(&prom_early_console); | ||
289 | |||
290 | if (tlb_type == hypervisor) | ||
291 | printk("ARCH: SUN4V\n"); | ||
292 | else | ||
293 | printk("ARCH: SUN4U\n"); | ||
294 | |||
295 | #ifdef CONFIG_DUMMY_CONSOLE | ||
296 | conswitchp = &dummy_con; | ||
297 | #elif defined(CONFIG_PROM_CONSOLE) | ||
298 | conswitchp = &prom_con; | ||
299 | #endif | ||
300 | |||
301 | idprom_init(); | ||
302 | |||
303 | if (!root_flags) | ||
304 | root_mountflags &= ~MS_RDONLY; | ||
305 | ROOT_DEV = old_decode_dev(root_dev); | ||
306 | #ifdef CONFIG_BLK_DEV_RAM | ||
307 | rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; | ||
308 | rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); | ||
309 | rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); | ||
310 | #endif | ||
311 | |||
312 | task_thread_info(&init_task)->kregs = &fake_swapper_regs; | ||
313 | |||
314 | #ifdef CONFIG_IP_PNP | ||
315 | if (!ic_set_manually) { | ||
316 | int chosen = prom_finddevice ("/chosen"); | ||
317 | u32 cl, sv, gw; | ||
318 | |||
319 | cl = prom_getintdefault (chosen, "client-ip", 0); | ||
320 | sv = prom_getintdefault (chosen, "server-ip", 0); | ||
321 | gw = prom_getintdefault (chosen, "gateway-ip", 0); | ||
322 | if (cl && sv) { | ||
323 | ic_myaddr = cl; | ||
324 | ic_servaddr = sv; | ||
325 | if (gw) | ||
326 | ic_gateway = gw; | ||
327 | #if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP) | ||
328 | ic_proto_enabled = 0; | ||
329 | #endif | ||
330 | } | ||
331 | } | ||
332 | #endif | ||
333 | |||
334 | /* Get boot processor trap_block[] setup. */ | ||
335 | init_cur_cpu_trap(current_thread_info()); | ||
336 | |||
337 | paging_init(); | ||
338 | } | ||
339 | |||
340 | /* BUFFER is PAGE_SIZE bytes long. */ | ||
341 | |||
342 | extern void smp_info(struct seq_file *); | ||
343 | extern void smp_bogo(struct seq_file *); | ||
344 | extern void mmu_info(struct seq_file *); | ||
345 | |||
346 | unsigned int dcache_parity_tl1_occurred; | ||
347 | unsigned int icache_parity_tl1_occurred; | ||
348 | |||
349 | int ncpus_probed; | ||
350 | |||
351 | static int show_cpuinfo(struct seq_file *m, void *__unused) | ||
352 | { | ||
353 | seq_printf(m, | ||
354 | "cpu\t\t: %s\n" | ||
355 | "fpu\t\t: %s\n" | ||
356 | "prom\t\t: %s\n" | ||
357 | "type\t\t: %s\n" | ||
358 | "ncpus probed\t: %d\n" | ||
359 | "ncpus active\t: %d\n" | ||
360 | "D$ parity tl1\t: %u\n" | ||
361 | "I$ parity tl1\t: %u\n" | ||
362 | #ifndef CONFIG_SMP | ||
363 | "Cpu0ClkTck\t: %016lx\n" | ||
364 | #endif | ||
365 | , | ||
366 | sparc_cpu_type, | ||
367 | sparc_fpu_type, | ||
368 | prom_version, | ||
369 | ((tlb_type == hypervisor) ? | ||
370 | "sun4v" : | ||
371 | "sun4u"), | ||
372 | ncpus_probed, | ||
373 | num_online_cpus(), | ||
374 | dcache_parity_tl1_occurred, | ||
375 | icache_parity_tl1_occurred | ||
376 | #ifndef CONFIG_SMP | ||
377 | , cpu_data(0).clock_tick | ||
378 | #endif | ||
379 | ); | ||
380 | #ifdef CONFIG_SMP | ||
381 | smp_bogo(m); | ||
382 | #endif | ||
383 | mmu_info(m); | ||
384 | #ifdef CONFIG_SMP | ||
385 | smp_info(m); | ||
386 | #endif | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
391 | { | ||
392 | /* The pointer we are returning is arbitrary, | ||
393 | * it just has to be non-NULL and not IS_ERR | ||
394 | * in the success case. | ||
395 | */ | ||
396 | return *pos == 0 ? &c_start : NULL; | ||
397 | } | ||
398 | |||
399 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
400 | { | ||
401 | ++*pos; | ||
402 | return c_start(m, pos); | ||
403 | } | ||
404 | |||
405 | static void c_stop(struct seq_file *m, void *v) | ||
406 | { | ||
407 | } | ||
408 | |||
409 | const struct seq_operations cpuinfo_op = { | ||
410 | .start =c_start, | ||
411 | .next = c_next, | ||
412 | .stop = c_stop, | ||
413 | .show = show_cpuinfo, | ||
414 | }; | ||
415 | |||
416 | extern int stop_a_enabled; | ||
417 | |||
418 | void sun_do_break(void) | ||
419 | { | ||
420 | if (!stop_a_enabled) | ||
421 | return; | ||
422 | |||
423 | prom_printf("\n"); | ||
424 | flush_user_windows(); | ||
425 | |||
426 | prom_cmdline(); | ||
427 | } | ||
428 | |||
429 | int stop_a_enabled = 1; | ||