diff options
Diffstat (limited to 'arch/sparc64/kernel/head.S')
-rw-r--r-- | arch/sparc64/kernel/head.S | 254 |
1 files changed, 172 insertions, 82 deletions
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index b49dcd4504b0..3eadac5e171e 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <asm/head.h> | 26 | #include <asm/head.h> |
27 | #include <asm/ttable.h> | 27 | #include <asm/ttable.h> |
28 | #include <asm/mmu.h> | 28 | #include <asm/mmu.h> |
29 | #include <asm/cpudata.h> | ||
29 | 30 | ||
30 | /* This section from from _start to sparc64_boot_end should fit into | 31 | /* This section from from _start to sparc64_boot_end should fit into |
31 | * 0x0000000000404000 to 0x0000000000408000. | 32 | * 0x0000000000404000 to 0x0000000000408000. |
@@ -94,12 +95,17 @@ sparc64_boot: | |||
94 | wrpr %g1, 0x0, %pstate | 95 | wrpr %g1, 0x0, %pstate |
95 | ba,a,pt %xcc, 1f | 96 | ba,a,pt %xcc, 1f |
96 | 97 | ||
97 | .globl prom_finddev_name, prom_chosen_path | 98 | .globl prom_finddev_name, prom_chosen_path, prom_root_node |
98 | .globl prom_getprop_name, prom_mmu_name | 99 | .globl prom_getprop_name, prom_mmu_name, prom_peer_name |
99 | .globl prom_callmethod_name, prom_translate_name | 100 | .globl prom_callmethod_name, prom_translate_name, prom_root_compatible |
100 | .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache | 101 | .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache |
101 | .globl prom_boot_mapped_pc, prom_boot_mapping_mode | 102 | .globl prom_boot_mapped_pc, prom_boot_mapping_mode |
102 | .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low | 103 | .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low |
104 | .globl is_sun4v | ||
105 | prom_peer_name: | ||
106 | .asciz "peer" | ||
107 | prom_compatible_name: | ||
108 | .asciz "compatible" | ||
103 | prom_finddev_name: | 109 | prom_finddev_name: |
104 | .asciz "finddevice" | 110 | .asciz "finddevice" |
105 | prom_chosen_path: | 111 | prom_chosen_path: |
@@ -116,7 +122,13 @@ prom_map_name: | |||
116 | .asciz "map" | 122 | .asciz "map" |
117 | prom_unmap_name: | 123 | prom_unmap_name: |
118 | .asciz "unmap" | 124 | .asciz "unmap" |
125 | prom_sun4v_name: | ||
126 | .asciz "sun4v" | ||
119 | .align 4 | 127 | .align 4 |
128 | prom_root_compatible: | ||
129 | .skip 64 | ||
130 | prom_root_node: | ||
131 | .word 0 | ||
120 | prom_mmu_ihandle_cache: | 132 | prom_mmu_ihandle_cache: |
121 | .word 0 | 133 | .word 0 |
122 | prom_boot_mapped_pc: | 134 | prom_boot_mapped_pc: |
@@ -128,8 +140,54 @@ prom_boot_mapping_phys_high: | |||
128 | .xword 0 | 140 | .xword 0 |
129 | prom_boot_mapping_phys_low: | 141 | prom_boot_mapping_phys_low: |
130 | .xword 0 | 142 | .xword 0 |
143 | is_sun4v: | ||
144 | .word 0 | ||
131 | 1: | 145 | 1: |
132 | rd %pc, %l0 | 146 | rd %pc, %l0 |
147 | |||
148 | mov (1b - prom_peer_name), %l1 | ||
149 | sub %l0, %l1, %l1 | ||
150 | mov 0, %l2 | ||
151 | |||
152 | /* prom_root_node = prom_peer(0) */ | ||
153 | stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "peer" | ||
154 | mov 1, %l3 | ||
155 | stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1 | ||
156 | stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1 | ||
157 | stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, 0 | ||
158 | stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1 | ||
159 | call %l7 | ||
160 | add %sp, (2047 + 128), %o0 ! argument array | ||
161 | |||
162 | ldx [%sp + 2047 + 128 + 0x20], %l4 ! prom root node | ||
163 | mov (1b - prom_root_node), %l1 | ||
164 | sub %l0, %l1, %l1 | ||
165 | stw %l4, [%l1] | ||
166 | |||
167 | mov (1b - prom_getprop_name), %l1 | ||
168 | mov (1b - prom_compatible_name), %l2 | ||
169 | mov (1b - prom_root_compatible), %l5 | ||
170 | sub %l0, %l1, %l1 | ||
171 | sub %l0, %l2, %l2 | ||
172 | sub %l0, %l5, %l5 | ||
173 | |||
174 | /* prom_getproperty(prom_root_node, "compatible", | ||
175 | * &prom_root_compatible, 64) | ||
176 | */ | ||
177 | stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop" | ||
178 | mov 4, %l3 | ||
179 | stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4 | ||
180 | mov 1, %l3 | ||
181 | stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1 | ||
182 | stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, prom_root_node | ||
183 | stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible" | ||
184 | stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_root_compatible | ||
185 | mov 64, %l3 | ||
186 | stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size | ||
187 | stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1 | ||
188 | call %l7 | ||
189 | add %sp, (2047 + 128), %o0 ! argument array | ||
190 | |||
133 | mov (1b - prom_finddev_name), %l1 | 191 | mov (1b - prom_finddev_name), %l1 |
134 | mov (1b - prom_chosen_path), %l2 | 192 | mov (1b - prom_chosen_path), %l2 |
135 | mov (1b - prom_boot_mapped_pc), %l3 | 193 | mov (1b - prom_boot_mapped_pc), %l3 |
@@ -238,6 +296,27 @@ prom_boot_mapping_phys_low: | |||
238 | add %sp, (192 + 128), %sp | 296 | add %sp, (192 + 128), %sp |
239 | 297 | ||
240 | sparc64_boot_after_remap: | 298 | sparc64_boot_after_remap: |
299 | sethi %hi(prom_root_compatible), %g1 | ||
300 | or %g1, %lo(prom_root_compatible), %g1 | ||
301 | sethi %hi(prom_sun4v_name), %g7 | ||
302 | or %g7, %lo(prom_sun4v_name), %g7 | ||
303 | mov 5, %g3 | ||
304 | 1: ldub [%g7], %g2 | ||
305 | ldub [%g1], %g4 | ||
306 | cmp %g2, %g4 | ||
307 | bne,pn %icc, 2f | ||
308 | add %g7, 1, %g7 | ||
309 | subcc %g3, 1, %g3 | ||
310 | bne,pt %xcc, 1b | ||
311 | add %g1, 1, %g1 | ||
312 | |||
313 | sethi %hi(is_sun4v), %g1 | ||
314 | or %g1, %lo(is_sun4v), %g1 | ||
315 | mov 1, %g7 | ||
316 | stw %g7, [%g1] | ||
317 | |||
318 | 2: | ||
319 | BRANCH_IF_SUN4V(g1, jump_to_sun4u_init) | ||
241 | BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot) | 320 | BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot) |
242 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot) | 321 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot) |
243 | ba,pt %xcc, spitfire_boot | 322 | ba,pt %xcc, spitfire_boot |
@@ -301,20 +380,58 @@ jump_to_sun4u_init: | |||
301 | nop | 380 | nop |
302 | 381 | ||
303 | sun4u_init: | 382 | sun4u_init: |
383 | BRANCH_IF_SUN4V(g1, sun4v_init) | ||
384 | |||
304 | /* Set ctx 0 */ | 385 | /* Set ctx 0 */ |
305 | mov PRIMARY_CONTEXT, %g7 | 386 | mov PRIMARY_CONTEXT, %g7 |
306 | stxa %g0, [%g7] ASI_DMMU | 387 | stxa %g0, [%g7] ASI_DMMU |
307 | membar #Sync | 388 | membar #Sync |
308 | 389 | ||
309 | mov SECONDARY_CONTEXT, %g7 | 390 | mov SECONDARY_CONTEXT, %g7 |
310 | stxa %g0, [%g7] ASI_DMMU | 391 | stxa %g0, [%g7] ASI_DMMU |
311 | membar #Sync | 392 | membar #Sync |
312 | 393 | ||
313 | BRANCH_IF_ANY_CHEETAH(g1,g7,cheetah_tlb_fixup) | 394 | ba,pt %xcc, sun4u_continue |
395 | nop | ||
396 | |||
397 | sun4v_init: | ||
398 | /* Set ctx 0 */ | ||
399 | mov PRIMARY_CONTEXT, %g7 | ||
400 | stxa %g0, [%g7] ASI_MMU | ||
401 | membar #Sync | ||
402 | |||
403 | mov SECONDARY_CONTEXT, %g7 | ||
404 | stxa %g0, [%g7] ASI_MMU | ||
405 | membar #Sync | ||
406 | ba,pt %xcc, niagara_tlb_fixup | ||
407 | nop | ||
408 | |||
409 | sun4u_continue: | ||
410 | BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup) | ||
314 | 411 | ||
315 | ba,pt %xcc, spitfire_tlb_fixup | 412 | ba,pt %xcc, spitfire_tlb_fixup |
316 | nop | 413 | nop |
317 | 414 | ||
415 | niagara_tlb_fixup: | ||
416 | mov 3, %g2 /* Set TLB type to hypervisor. */ | ||
417 | sethi %hi(tlb_type), %g1 | ||
418 | stw %g2, [%g1 + %lo(tlb_type)] | ||
419 | |||
420 | /* Patch copy/clear ops. */ | ||
421 | call niagara_patch_copyops | ||
422 | nop | ||
423 | call niagara_patch_bzero | ||
424 | nop | ||
425 | call niagara_patch_pageops | ||
426 | nop | ||
427 | |||
428 | /* Patch TLB/cache ops. */ | ||
429 | call hypervisor_patch_cachetlbops | ||
430 | nop | ||
431 | |||
432 | ba,pt %xcc, tlb_fixup_done | ||
433 | nop | ||
434 | |||
318 | cheetah_tlb_fixup: | 435 | cheetah_tlb_fixup: |
319 | mov 2, %g2 /* Set TLB type to cheetah+. */ | 436 | mov 2, %g2 /* Set TLB type to cheetah+. */ |
320 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f) | 437 | BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f) |
@@ -411,85 +528,55 @@ setup_trap_table: | |||
411 | wrpr %g0, 15, %pil | 528 | wrpr %g0, 15, %pil |
412 | 529 | ||
413 | /* Make the firmware call to jump over to the Linux trap table. */ | 530 | /* Make the firmware call to jump over to the Linux trap table. */ |
414 | call prom_set_trap_table | 531 | sethi %hi(is_sun4v), %o0 |
415 | sethi %hi(sparc64_ttable_tl0), %o0 | 532 | lduw [%o0 + %lo(is_sun4v)], %o0 |
533 | brz,pt %o0, 1f | ||
534 | nop | ||
416 | 535 | ||
417 | /* Start using proper page size encodings in ctx register. */ | 536 | TRAP_LOAD_TRAP_BLOCK(%g2, %g3) |
418 | sethi %hi(sparc64_kern_pri_context), %g3 | 537 | add %g2, TRAP_PER_CPU_FAULT_INFO, %g2 |
419 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 | 538 | stxa %g2, [%g0] ASI_SCRATCHPAD |
420 | mov PRIMARY_CONTEXT, %g1 | ||
421 | stxa %g2, [%g1] ASI_DMMU | ||
422 | membar #Sync | ||
423 | 539 | ||
424 | /* The Linux trap handlers expect various trap global registers | 540 | /* Compute physical address: |
425 | * to be setup with some fixed values. So here we set these | ||
426 | * up very carefully. These globals are: | ||
427 | * | ||
428 | * Alternate Globals (PSTATE_AG): | ||
429 | * | ||
430 | * %g6 --> current_thread_info() | ||
431 | * | ||
432 | * MMU Globals (PSTATE_MG): | ||
433 | * | ||
434 | * %g1 --> TLB_SFSR | ||
435 | * %g2 --> ((_PAGE_VALID | _PAGE_SZ4MB | | ||
436 | * _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) | ||
437 | * ^ 0xfffff80000000000) | ||
438 | * (this %g2 value is used for computing the PAGE_OFFSET kernel | ||
439 | * TLB entries quickly, the virtual address of the fault XOR'd | ||
440 | * with this %g2 value is the PTE to load into the TLB) | ||
441 | * %g3 --> VPTE_BASE_CHEETAH or VPTE_BASE_SPITFIRE | ||
442 | * | 541 | * |
443 | * Interrupt Globals (PSTATE_IG, setup by init_irqwork_curcpu()): | 542 | * paddr = kern_base + (mmfsa_vaddr - KERNBASE) |
444 | * | ||
445 | * %g6 --> __irq_work[smp_processor_id()] | ||
446 | */ | 543 | */ |
544 | sethi %hi(KERNBASE), %g3 | ||
545 | sub %g2, %g3, %g2 | ||
546 | sethi %hi(kern_base), %g3 | ||
547 | ldx [%g3 + %lo(kern_base)], %g3 | ||
548 | add %g2, %g3, %o1 | ||
447 | 549 | ||
448 | rdpr %pstate, %o1 | 550 | call prom_set_trap_table_sun4v |
449 | mov %g6, %o2 | 551 | sethi %hi(sparc64_ttable_tl0), %o0 |
450 | wrpr %o1, PSTATE_AG, %pstate | 552 | |
451 | mov %o2, %g6 | 553 | ba,pt %xcc, 2f |
452 | |||
453 | #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000) | ||
454 | #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) | ||
455 | wrpr %o1, PSTATE_MG, %pstate | ||
456 | mov TSB_REG, %g1 | ||
457 | stxa %g0, [%g1] ASI_DMMU | ||
458 | membar #Sync | ||
459 | stxa %g0, [%g1] ASI_IMMU | ||
460 | membar #Sync | ||
461 | mov TLB_SFSR, %g1 | ||
462 | sethi %uhi(KERN_HIGHBITS), %g2 | ||
463 | or %g2, %ulo(KERN_HIGHBITS), %g2 | ||
464 | sllx %g2, 32, %g2 | ||
465 | or %g2, KERN_LOWBITS, %g2 | ||
466 | |||
467 | BRANCH_IF_ANY_CHEETAH(g3,g7,8f) | ||
468 | ba,pt %xcc, 9f | ||
469 | nop | 554 | nop |
470 | 555 | ||
471 | 8: | 556 | 1: call prom_set_trap_table |
472 | sethi %uhi(VPTE_BASE_CHEETAH), %g3 | 557 | sethi %hi(sparc64_ttable_tl0), %o0 |
473 | or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 | ||
474 | ba,pt %xcc, 2f | ||
475 | sllx %g3, 32, %g3 | ||
476 | 558 | ||
477 | 9: | 559 | /* Start using proper page size encodings in ctx register. */ |
478 | sethi %uhi(VPTE_BASE_SPITFIRE), %g3 | 560 | 2: sethi %hi(sparc64_kern_pri_context), %g3 |
479 | or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 | 561 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 |
480 | sllx %g3, 32, %g3 | ||
481 | 562 | ||
482 | 2: | 563 | mov PRIMARY_CONTEXT, %g1 |
483 | clr %g7 | 564 | |
484 | #undef KERN_HIGHBITS | 565 | 661: stxa %g2, [%g1] ASI_DMMU |
485 | #undef KERN_LOWBITS | 566 | .section .sun4v_1insn_patch, "ax" |
567 | .word 661b | ||
568 | stxa %g2, [%g1] ASI_MMU | ||
569 | .previous | ||
570 | |||
571 | membar #Sync | ||
486 | 572 | ||
487 | /* Kill PROM timer */ | 573 | /* Kill PROM timer */ |
488 | sethi %hi(0x80000000), %o2 | 574 | sethi %hi(0x80000000), %o2 |
489 | sllx %o2, 32, %o2 | 575 | sllx %o2, 32, %o2 |
490 | wr %o2, 0, %tick_cmpr | 576 | wr %o2, 0, %tick_cmpr |
491 | 577 | ||
492 | BRANCH_IF_ANY_CHEETAH(o2,o3,1f) | 578 | BRANCH_IF_SUN4V(o2, 1f) |
579 | BRANCH_IF_ANY_CHEETAH(o2, o3, 1f) | ||
493 | 580 | ||
494 | ba,pt %xcc, 2f | 581 | ba,pt %xcc, 2f |
495 | nop | 582 | nop |
@@ -502,7 +589,6 @@ setup_trap_table: | |||
502 | 589 | ||
503 | 2: | 590 | 2: |
504 | wrpr %g0, %g0, %wstate | 591 | wrpr %g0, %g0, %wstate |
505 | wrpr %o1, 0x0, %pstate | ||
506 | 592 | ||
507 | call init_irqwork_curcpu | 593 | call init_irqwork_curcpu |
508 | nop | 594 | nop |
@@ -517,7 +603,7 @@ setup_trap_table: | |||
517 | restore | 603 | restore |
518 | 604 | ||
519 | .globl setup_tba | 605 | .globl setup_tba |
520 | setup_tba: /* i0 = is_starfire */ | 606 | setup_tba: |
521 | save %sp, -192, %sp | 607 | save %sp, -192, %sp |
522 | 608 | ||
523 | /* The boot processor is the only cpu which invokes this | 609 | /* The boot processor is the only cpu which invokes this |
@@ -536,31 +622,35 @@ setup_tba: /* i0 = is_starfire */ | |||
536 | restore | 622 | restore |
537 | sparc64_boot_end: | 623 | sparc64_boot_end: |
538 | 624 | ||
539 | #include "systbls.S" | ||
540 | #include "ktlb.S" | 625 | #include "ktlb.S" |
626 | #include "tsb.S" | ||
541 | #include "etrap.S" | 627 | #include "etrap.S" |
542 | #include "rtrap.S" | 628 | #include "rtrap.S" |
543 | #include "winfixup.S" | 629 | #include "winfixup.S" |
544 | #include "entry.S" | 630 | #include "entry.S" |
631 | #include "sun4v_tlb_miss.S" | ||
632 | #include "sun4v_ivec.S" | ||
545 | 633 | ||
546 | /* | 634 | /* |
547 | * The following skip makes sure the trap table in ttable.S is aligned | 635 | * The following skip makes sure the trap table in ttable.S is aligned |
548 | * on a 32K boundary as required by the v9 specs for TBA register. | 636 | * on a 32K boundary as required by the v9 specs for TBA register. |
637 | * | ||
638 | * We align to a 32K boundary, then we have the 32K kernel TSB, | ||
639 | * then the 32K aligned trap table. | ||
549 | */ | 640 | */ |
550 | 1: | 641 | 1: |
551 | .skip 0x4000 + _start - 1b | 642 | .skip 0x4000 + _start - 1b |
552 | 643 | ||
553 | #ifdef CONFIG_SBUS | 644 | .globl swapper_tsb |
554 | /* This is just a hack to fool make depend config.h discovering | 645 | swapper_tsb: |
555 | strategy: As the .S files below need config.h, but | 646 | .skip (32 * 1024) |
556 | make depend does not find it for them, we include config.h | ||
557 | in head.S */ | ||
558 | #endif | ||
559 | 647 | ||
560 | ! 0x0000000000408000 | 648 | ! 0x0000000000408000 |
561 | 649 | ||
562 | #include "ttable.S" | 650 | #include "ttable.S" |
563 | 651 | ||
652 | #include "systbls.S" | ||
653 | |||
564 | .data | 654 | .data |
565 | .align 8 | 655 | .align 8 |
566 | .globl prom_tba, tlb_type | 656 | .globl prom_tba, tlb_type |