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