1
2
3
4
5
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 <asm/smp.h>
16#include <linux/user.h>
17#include <linux/screen_info.h>
18#include <linux/delay.h>
19#include <linux/fs.h>
20#include <linux/seq_file.h>
21#include <linux/syscalls.h>
22#include <linux/kdev_t.h>
23#include <linux/major.h>
24#include <linux/string.h>
25#include <linux/init.h>
26#include <linux/inet.h>
27#include <linux/console.h>
28#include <linux/root_dev.h>
29#include <linux/interrupt.h>
30#include <linux/cpu.h>
31#include <linux/initrd.h>
32#include <linux/module.h>
33
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/mmu_context.h>
43#include <asm/timer.h>
44#include <asm/sections.h>
45#include <asm/setup.h>
46#include <asm/mmu.h>
47#include <asm/ns87303.h>
48#include <asm/btext.h>
49#include <asm/elf.h>
50#include <asm/mdesc.h>
51#include <asm/cacheflush.h>
52
53#ifdef CONFIG_IP_PNP
54#include <net/ipconfig.h>
55#endif
56
57#include "entry.h"
58#include "kernel.h"
59
60
61
62
63DEFINE_SPINLOCK(ns87303_lock);
64EXPORT_SYMBOL(ns87303_lock);
65
66struct screen_info screen_info = {
67 0, 0,
68 0,
69 0,
70 0,
71 128,
72 0, 0, 0,
73 54,
74 0,
75 16
76};
77
78static void
79prom_console_write(struct console *con, const char *s, unsigned n)
80{
81 prom_write(s, n);
82}
83
84
85unsigned long cmdline_memory_size = 0;
86
87static struct console prom_early_console = {
88 .name = "earlyprom",
89 .write = prom_console_write,
90 .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
91 .index = -1,
92};
93
94
95
96
97
98static void __init process_switch(char c)
99{
100 switch (c) {
101 case 'd':
102 case 's':
103 break;
104 case 'h':
105 prom_printf("boot_flags_init: Halt!\n");
106 prom_halt();
107 break;
108 case 'p':
109 prom_early_console.flags &= ~CON_BOOT;
110 break;
111 case 'P':
112
113 if (tlb_type != cheetah) {
114 printk("BOOT: Ignoring P-Cache force option.\n");
115 break;
116 }
117 cheetah_pcache_forced_on = 1;
118 add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
119 cheetah_enable_pcache();
120 break;
121
122 default:
123 printk("Unknown boot switch (-%c)\n", c);
124 break;
125 }
126}
127
128static void __init boot_flags_init(char *commands)
129{
130 while (*commands) {
131
132 while (*commands && *commands == ' ')
133 commands++;
134
135
136 if (*commands == '\0')
137 break;
138 if (*commands == '-') {
139 commands++;
140 while (*commands && *commands != ' ')
141 process_switch(*commands++);
142 continue;
143 }
144 if (!strncmp(commands, "mem=", 4)) {
145
146
147
148
149 cmdline_memory_size = simple_strtoul(commands + 4,
150 &commands, 0);
151 if (*commands == 'K' || *commands == 'k') {
152 cmdline_memory_size <<= 10;
153 commands++;
154 } else if (*commands=='M' || *commands=='m') {
155 cmdline_memory_size <<= 20;
156 commands++;
157 }
158 }
159 while (*commands && *commands != ' ')
160 commands++;
161 }
162}
163
164extern unsigned short root_flags;
165extern unsigned short root_dev;
166extern unsigned short ram_flags;
167#define RAMDISK_IMAGE_START_MASK 0x07FF
168#define RAMDISK_PROMPT_FLAG 0x8000
169#define RAMDISK_LOAD_FLAG 0x4000
170
171extern int root_mountflags;
172
173char reboot_command[COMMAND_LINE_SIZE];
174
175static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
176
177void __init per_cpu_patch(void)
178{
179 struct cpuid_patch_entry *p;
180 unsigned long ver;
181 int is_jbus;
182
183 if (tlb_type == spitfire && !this_is_starfire)
184 return;
185
186 is_jbus = 0;
187 if (tlb_type != hypervisor) {
188 __asm__ ("rdpr %%ver, %0" : "=r" (ver));
189 is_jbus = ((ver >> 32UL) == __JALAPENO_ID ||
190 (ver >> 32UL) == __SERRANO_ID);
191 }
192
193 p = &__cpuid_patch;
194 while (p < &__cpuid_patch_end) {
195 unsigned long addr = p->addr;
196 unsigned int *insns;
197
198 switch (tlb_type) {
199 case spitfire:
200 insns = &p->starfire[0];
201 break;
202 case cheetah:
203 case cheetah_plus:
204 if (is_jbus)
205 insns = &p->cheetah_jbus[0];
206 else
207 insns = &p->cheetah_safari[0];
208 break;
209 case hypervisor:
210 insns = &p->sun4v[0];
211 break;
212 default:
213 prom_printf("Unknown cpu type, halting.\n");
214 prom_halt();
215 }
216
217 *(unsigned int *) (addr + 0) = insns[0];
218 wmb();
219 __asm__ __volatile__("flush %0" : : "r" (addr + 0));
220
221 *(unsigned int *) (addr + 4) = insns[1];
222 wmb();
223 __asm__ __volatile__("flush %0" : : "r" (addr + 4));
224
225 *(unsigned int *) (addr + 8) = insns[2];
226 wmb();
227 __asm__ __volatile__("flush %0" : : "r" (addr + 8));
228
229 *(unsigned int *) (addr + 12) = insns[3];
230 wmb();
231 __asm__ __volatile__("flush %0" : : "r" (addr + 12));
232
233 p++;
234 }
235}
236
237void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start,
238 struct sun4v_1insn_patch_entry *end)
239{
240 while (start < end) {
241 unsigned long addr = start->addr;
242
243 *(unsigned int *) (addr + 0) = start->insn;
244 wmb();
245 __asm__ __volatile__("flush %0" : : "r" (addr + 0));
246
247 start++;
248 }
249}
250
251void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
252 struct sun4v_2insn_patch_entry *end)
253{
254 while (start < end) {
255 unsigned long addr = start->addr;
256
257 *(unsigned int *) (addr + 0) = start->insns[0];
258 wmb();
259 __asm__ __volatile__("flush %0" : : "r" (addr + 0));
260
261 *(unsigned int *) (addr + 4) = start->insns[1];
262 wmb();
263 __asm__ __volatile__("flush %0" : : "r" (addr + 4));
264
265 start++;
266 }
267}
268
269void __init sun4v_patch(void)
270{
271 extern void sun4v_hvapi_init(void);
272
273 if (tlb_type != hypervisor)
274 return;
275
276 sun4v_patch_1insn_range(&__sun4v_1insn_patch,
277 &__sun4v_1insn_patch_end);
278
279 sun4v_patch_2insn_range(&__sun4v_2insn_patch,
280 &__sun4v_2insn_patch_end);
281
282 sun4v_hvapi_init();
283}
284
285static void __init popc_patch(void)
286{
287 struct popc_3insn_patch_entry *p3;
288 struct popc_6insn_patch_entry *p6;
289
290 p3 = &__popc_3insn_patch;
291 while (p3 < &__popc_3insn_patch_end) {
292 unsigned long i, addr = p3->addr;
293
294 for (i = 0; i < 3; i++) {
295 *(unsigned int *) (addr + (i * 4)) = p3->insns[i];
296 wmb();
297 __asm__ __volatile__("flush %0"
298 : : "r" (addr + (i * 4)));
299 }
300
301 p3++;
302 }
303
304 p6 = &__popc_6insn_patch;
305 while (p6 < &__popc_6insn_patch_end) {
306 unsigned long i, addr = p6->addr;
307
308 for (i = 0; i < 6; i++) {
309 *(unsigned int *) (addr + (i * 4)) = p6->insns[i];
310 wmb();
311 __asm__ __volatile__("flush %0"
312 : : "r" (addr + (i * 4)));
313 }
314
315 p6++;
316 }
317}
318
319static void __init pause_patch(void)
320{
321 struct pause_patch_entry *p;
322
323 p = &__pause_3insn_patch;
324 while (p < &__pause_3insn_patch_end) {
325 unsigned long i, addr = p->addr;
326
327 for (i = 0; i < 3; i++) {
328 *(unsigned int *) (addr + (i * 4)) = p->insns[i];
329 wmb();
330 __asm__ __volatile__("flush %0"
331 : : "r" (addr + (i * 4)));
332 }
333
334 p++;
335 }
336}
337
338#ifdef CONFIG_SMP
339void __init boot_cpu_id_too_large(int cpu)
340{
341 prom_printf("Serious problem, boot cpu id (%d) >= NR_CPUS (%d)\n",
342 cpu, NR_CPUS);
343 prom_halt();
344}
345#endif
346
347
348unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
349 HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
350 HWCAP_SPARC_V9);
351EXPORT_SYMBOL(sparc64_elf_hwcap);
352
353static const char *hwcaps[] = {
354 "flush", "stbar", "swap", "muldiv", "v9",
355 "ultra3", "blkinit", "n2",
356
357
358
359
360 "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
361 "ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau",
362 "ima", "cspare", "pause", "cbcond",
363};
364
365static const char *crypto_hwcaps[] = {
366 "aes", "des", "kasumi", "camellia", "md5", "sha1", "sha256",
367 "sha512", "mpmul", "montmul", "montsqr", "crc32c",
368};
369
370void cpucap_info(struct seq_file *m)
371{
372 unsigned long caps = sparc64_elf_hwcap;
373 int i, printed = 0;
374
375 seq_puts(m, "cpucaps\t\t: ");
376 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
377 unsigned long bit = 1UL << i;
378 if (caps & bit) {
379 seq_printf(m, "%s%s",
380 printed ? "," : "", hwcaps[i]);
381 printed++;
382 }
383 }
384 if (caps & HWCAP_SPARC_CRYPTO) {
385 unsigned long cfr;
386
387 __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
388 for (i = 0; i < ARRAY_SIZE(crypto_hwcaps); i++) {
389 unsigned long bit = 1UL << i;
390 if (cfr & bit) {
391 seq_printf(m, "%s%s",
392 printed ? "," : "", crypto_hwcaps[i]);
393 printed++;
394 }
395 }
396 }
397 seq_putc(m, '\n');
398}
399
400static void __init report_one_hwcap(int *printed, const char *name)
401{
402 if ((*printed) == 0)
403 printk(KERN_INFO "CPU CAPS: [");
404 printk(KERN_CONT "%s%s",
405 (*printed) ? "," : "", name);
406 if (++(*printed) == 8) {
407 printk(KERN_CONT "]\n");
408 *printed = 0;
409 }
410}
411
412static void __init report_crypto_hwcaps(int *printed)
413{
414 unsigned long cfr;
415 int i;
416
417 __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
418
419 for (i = 0; i < ARRAY_SIZE(crypto_hwcaps); i++) {
420 unsigned long bit = 1UL << i;
421 if (cfr & bit)
422 report_one_hwcap(printed, crypto_hwcaps[i]);
423 }
424}
425
426static void __init report_hwcaps(unsigned long caps)
427{
428 int i, printed = 0;
429
430 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
431 unsigned long bit = 1UL << i;
432 if (caps & bit)
433 report_one_hwcap(&printed, hwcaps[i]);
434 }
435 if (caps & HWCAP_SPARC_CRYPTO)
436 report_crypto_hwcaps(&printed);
437 if (printed != 0)
438 printk(KERN_CONT "]\n");
439}
440
441static unsigned long __init mdesc_cpu_hwcap_list(void)
442{
443 struct mdesc_handle *hp;
444 unsigned long caps = 0;
445 const char *prop;
446 int len;
447 u64 pn;
448
449 hp = mdesc_grab();
450 if (!hp)
451 return 0;
452
453 pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "cpu");
454 if (pn == MDESC_NODE_NULL)
455 goto out;
456
457 prop = mdesc_get_property(hp, pn, "hwcap-list", &len);
458 if (!prop)
459 goto out;
460
461 while (len) {
462 int i, plen;
463
464 for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
465 unsigned long bit = 1UL << i;
466
467 if (!strcmp(prop, hwcaps[i])) {
468 caps |= bit;
469 break;
470 }
471 }
472 for (i = 0; i < ARRAY_SIZE(crypto_hwcaps); i++) {
473 if (!strcmp(prop, crypto_hwcaps[i]))
474 caps |= HWCAP_SPARC_CRYPTO;
475 }
476
477 plen = strlen(prop) + 1;
478 prop += plen;
479 len -= plen;
480 }
481
482out:
483 mdesc_release(hp);
484 return caps;
485}
486
487
488
489
490static void __init init_sparc64_elf_hwcap(void)
491{
492 unsigned long cap = sparc64_elf_hwcap;
493 unsigned long mdesc_caps;
494
495 if (tlb_type == cheetah || tlb_type == cheetah_plus)
496 cap |= HWCAP_SPARC_ULTRA3;
497 else if (tlb_type == hypervisor) {
498 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
499 sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
500 sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
501 sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
502 sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
503 cap |= HWCAP_SPARC_BLKINIT;
504 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
505 sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
506 sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
507 sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
508 cap |= HWCAP_SPARC_N2;
509 }
510
511 cap |= (AV_SPARC_MUL32 | AV_SPARC_DIV32 | AV_SPARC_V8PLUS);
512
513 mdesc_caps = mdesc_cpu_hwcap_list();
514 if (!mdesc_caps) {
515 if (tlb_type == spitfire)
516 cap |= AV_SPARC_VIS;
517 if (tlb_type == cheetah || tlb_type == cheetah_plus)
518 cap |= AV_SPARC_VIS | AV_SPARC_VIS2;
519 if (tlb_type == cheetah_plus) {
520 unsigned long impl, ver;
521
522 __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
523 impl = ((ver >> 32) & 0xffff);
524 if (impl == PANTHER_IMPL)
525 cap |= AV_SPARC_POPC;
526 }
527 if (tlb_type == hypervisor) {
528 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
529 cap |= AV_SPARC_ASI_BLK_INIT;
530 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
531 sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
532 sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
533 sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
534 cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
535 AV_SPARC_ASI_BLK_INIT |
536 AV_SPARC_POPC);
537 if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
538 sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
539 sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
540 cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
541 AV_SPARC_FMAF);
542 }
543 }
544 sparc64_elf_hwcap = cap | mdesc_caps;
545
546 report_hwcaps(sparc64_elf_hwcap);
547
548 if (sparc64_elf_hwcap & AV_SPARC_POPC)
549 popc_patch();
550 if (sparc64_elf_hwcap & AV_SPARC_PAUSE)
551 pause_patch();
552}
553
554void __init setup_arch(char **cmdline_p)
555{
556
557 *cmdline_p = prom_getbootargs();
558 strlcpy(boot_command_line, *cmdline_p, COMMAND_LINE_SIZE);
559 parse_early_param();
560
561 boot_flags_init(*cmdline_p);
562#ifdef CONFIG_EARLYFB
563 if (btext_find_display())
564#endif
565 register_console(&prom_early_console);
566
567 if (tlb_type == hypervisor)
568 printk("ARCH: SUN4V\n");
569 else
570 printk("ARCH: SUN4U\n");
571
572#ifdef CONFIG_DUMMY_CONSOLE
573 conswitchp = &dummy_con;
574#endif
575
576 idprom_init();
577
578 if (!root_flags)
579 root_mountflags &= ~MS_RDONLY;
580 ROOT_DEV = old_decode_dev(root_dev);
581#ifdef CONFIG_BLK_DEV_RAM
582 rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
583 rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
584 rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
585#endif
586
587 task_thread_info(&init_task)->kregs = &fake_swapper_regs;
588
589#ifdef CONFIG_IP_PNP
590 if (!ic_set_manually) {
591 phandle chosen = prom_finddevice("/chosen");
592 u32 cl, sv, gw;
593
594 cl = prom_getintdefault (chosen, "client-ip", 0);
595 sv = prom_getintdefault (chosen, "server-ip", 0);
596 gw = prom_getintdefault (chosen, "gateway-ip", 0);
597 if (cl && sv) {
598 ic_myaddr = cl;
599 ic_servaddr = sv;
600 if (gw)
601 ic_gateway = gw;
602#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
603 ic_proto_enabled = 0;
604#endif
605 }
606 }
607#endif
608
609
610 init_cur_cpu_trap(current_thread_info());
611
612 paging_init();
613 init_sparc64_elf_hwcap();
614}
615
616extern int stop_a_enabled;
617
618void sun_do_break(void)
619{
620 if (!stop_a_enabled)
621 return;
622
623 prom_printf("\n");
624 flush_user_windows();
625
626 prom_cmdline();
627}
628EXPORT_SYMBOL(sun_do_break);
629
630int stop_a_enabled = 1;
631EXPORT_SYMBOL(stop_a_enabled);
632