diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-10-10 19:12:13 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-10-10 19:12:13 -0400 |
commit | 5d8e1b181c4ad63e6ca90d51287b31afd400d2eb (patch) | |
tree | 555d79c07b00def9f5eab72431ae95ebd5af4f86 /arch/sparc64/kernel/head.S | |
parent | f96c3bbe91117402f13119ce9e609db9087ed58f (diff) |
[SPARC64]: Fix Ultra5, Ultra60, et al. boot failures.
On the boot processor, we need to do the move onto the Linux trap
table a little bit differently else we'll take unhandlable faults in
the firmware address space.
Previously we would do the following:
1) Disable PSTATE_IE in %pstate.
2) Set %tba by hand to sparc64_ttable_tl0
3) Initialize alternate, mmu, and interrupt global
trap registers.
4) Call prom_set_traptable()
That doesn't work very well actually with the way we boot the kernel
VM these days. It worked by luck on many systems because the firmware
accesses for the prom_set_traptable() call happened to be loaded into
the TLB already, something we cannot assume.
So the new scheme is this:
1) Clear PSTATE_IE in %pstate and set %pil to 15
2) Call prom_set_traptable()
3) Initialize alternate, mmu, and interrupt global
trap registers.
and this works quite well. This sequence has been moved into a
callable function in assembler named setup-trap_table(). The idea is
that eventually trampoline.S can use this code as well. That isn't
possible currently due to some complications, but eventually we should
be able to do it.
Thanks to Meelis Roos for the Ultra5 boot failure report.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/head.S')
-rw-r--r-- | arch/sparc64/kernel/head.S | 127 |
1 files changed, 91 insertions, 36 deletions
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 24340496cdd3..f1dcdf8f7433 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S | |||
@@ -382,32 +382,79 @@ tlb_fixup_done: | |||
382 | nop | 382 | nop |
383 | /* Not reached... */ | 383 | /* Not reached... */ |
384 | 384 | ||
385 | /* IMPORTANT NOTE: Whenever making changes here, check | 385 | /* This is meant to allow the sharing of this code between |
386 | * trampoline.S as well. -jj */ | 386 | * boot processor invocation (via setup_tba() below) and |
387 | .globl setup_tba | 387 | * secondary processor startup (via trampoline.S). The |
388 | setup_tba: /* i0 = is_starfire */ | 388 | * former does use this code, the latter does not yet due |
389 | save %sp, -160, %sp | 389 | * to some complexities. That should be fixed up at some |
390 | * point. | ||
391 | */ | ||
392 | .globl setup_trap_table | ||
393 | setup_trap_table: | ||
394 | save %sp, -192, %sp | ||
395 | |||
396 | /* Force interrupts to be disabled. Transferring over to | ||
397 | * the Linux trap table is a very delicate operation. | ||
398 | * Until we are actually on the Linux trap table, we cannot | ||
399 | * get the PAGE_OFFSET linear mappings translated. We need | ||
400 | * that mapping to be setup in order to initialize the firmware | ||
401 | * page tables. | ||
402 | * | ||
403 | * So there is this window of time, from the return from | ||
404 | * prom_set_trap_table() until inherit_prom_mappings_post() | ||
405 | * (in arch/sparc64/mm/init.c) completes, during which no | ||
406 | * firmware address space accesses can be made. | ||
407 | */ | ||
408 | rdpr %pstate, %o1 | ||
409 | andn %o1, PSTATE_IE, %o1 | ||
410 | wrpr %o1, 0x0, %pstate | ||
411 | wrpr %g0, 15, %pil | ||
390 | 412 | ||
391 | rdpr %tba, %g7 | 413 | /* Ok, now make the final valid firmware call to jump over |
392 | sethi %hi(prom_tba), %o1 | 414 | * to the Linux trap table. |
393 | or %o1, %lo(prom_tba), %o1 | 415 | */ |
394 | stx %g7, [%o1] | 416 | call prom_set_trap_table |
417 | sethi %hi(sparc64_ttable_tl0), %o0 | ||
418 | |||
419 | /* Start using proper page size encodings in ctx register. */ | ||
420 | sethi %hi(sparc64_kern_pri_context), %g3 | ||
421 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 | ||
422 | mov PRIMARY_CONTEXT, %g1 | ||
423 | stxa %g2, [%g1] ASI_DMMU | ||
424 | membar #Sync | ||
425 | |||
426 | /* The Linux trap handlers expect various trap global registers | ||
427 | * to be setup with some fixed values. So here we set these | ||
428 | * up very carefully. These globals are: | ||
429 | * | ||
430 | * Alternate Globals (PSTATE_AG): | ||
431 | * | ||
432 | * %g6 --> current_thread_info() | ||
433 | * | ||
434 | * MMU Globals (PSTATE_MG): | ||
435 | * | ||
436 | * %g1 --> TLB_SFSR | ||
437 | * %g2 --> ((_PAGE_VALID | _PAGE_SZ4MB | | ||
438 | * _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) | ||
439 | * ^ 0xfffff80000000000) | ||
440 | * (this %g2 value is used for computing the PAGE_OFFSET kernel | ||
441 | * TLB entries quickly, the virtual address of the fault XOR'd | ||
442 | * with this %g2 value is the PTE to load into the TLB) | ||
443 | * %g3 --> VPTE_BASE_CHEETAH or VPTE_BASE_SPITFIRE | ||
444 | * | ||
445 | * Interrupt Globals (PSTATE_IG, setup by init_irqwork_curcpu()): | ||
446 | * | ||
447 | * %g6 --> __irq_work[smp_processor_id()] | ||
448 | */ | ||
395 | 449 | ||
396 | /* Setup "Linux" globals 8-) */ | ||
397 | rdpr %pstate, %o1 | 450 | rdpr %pstate, %o1 |
398 | mov %g6, %o2 | 451 | mov %g6, %o2 |
399 | wrpr %o1, (PSTATE_AG|PSTATE_IE), %pstate | 452 | wrpr %o1, PSTATE_AG, %pstate |
400 | sethi %hi(sparc64_ttable_tl0), %g1 | ||
401 | wrpr %g1, %tba | ||
402 | mov %o2, %g6 | 453 | mov %o2, %g6 |
403 | 454 | ||
404 | /* Set up MMU globals */ | ||
405 | wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate | ||
406 | |||
407 | /* Set fixed globals used by dTLB miss handler. */ | ||
408 | #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000) | 455 | #define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000) |
409 | #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) | 456 | #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) |
410 | 457 | wrpr %o1, PSTATE_MG, %pstate | |
411 | mov TSB_REG, %g1 | 458 | mov TSB_REG, %g1 |
412 | stxa %g0, [%g1] ASI_DMMU | 459 | stxa %g0, [%g1] ASI_DMMU |
413 | membar #Sync | 460 | membar #Sync |
@@ -419,17 +466,17 @@ setup_tba: /* i0 = is_starfire */ | |||
419 | sllx %g2, 32, %g2 | 466 | sllx %g2, 32, %g2 |
420 | or %g2, KERN_LOWBITS, %g2 | 467 | or %g2, KERN_LOWBITS, %g2 |
421 | 468 | ||
422 | BRANCH_IF_ANY_CHEETAH(g3,g7,cheetah_vpte_base) | 469 | BRANCH_IF_ANY_CHEETAH(g3,g7,8f) |
423 | ba,pt %xcc, spitfire_vpte_base | 470 | ba,pt %xcc, 9f |
424 | nop | 471 | nop |
425 | 472 | ||
426 | cheetah_vpte_base: | 473 | 8: |
427 | sethi %uhi(VPTE_BASE_CHEETAH), %g3 | 474 | sethi %uhi(VPTE_BASE_CHEETAH), %g3 |
428 | or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 | 475 | or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 |
429 | ba,pt %xcc, 2f | 476 | ba,pt %xcc, 2f |
430 | sllx %g3, 32, %g3 | 477 | sllx %g3, 32, %g3 |
431 | 478 | ||
432 | spitfire_vpte_base: | 479 | 9: |
433 | sethi %uhi(VPTE_BASE_SPITFIRE), %g3 | 480 | sethi %uhi(VPTE_BASE_SPITFIRE), %g3 |
434 | or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 | 481 | or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 |
435 | sllx %g3, 32, %g3 | 482 | sllx %g3, 32, %g3 |
@@ -455,29 +502,37 @@ spitfire_vpte_base: | |||
455 | sllx %o2, 32, %o2 | 502 | sllx %o2, 32, %o2 |
456 | wr %o2, %asr25 | 503 | wr %o2, %asr25 |
457 | 504 | ||
458 | /* Ok, we're done setting up all the state our trap mechanims needs, | ||
459 | * now get back into normal globals and let the PROM know what is up. | ||
460 | */ | ||
461 | 2: | 505 | 2: |
462 | wrpr %g0, %g0, %wstate | 506 | wrpr %g0, %g0, %wstate |
463 | wrpr %o1, PSTATE_IE, %pstate | 507 | wrpr %o1, 0x0, %pstate |
464 | 508 | ||
465 | call init_irqwork_curcpu | 509 | call init_irqwork_curcpu |
466 | nop | 510 | nop |
467 | 511 | ||
468 | call prom_set_trap_table | 512 | /* Now we can turn interrupts back on. */ |
469 | sethi %hi(sparc64_ttable_tl0), %o0 | ||
470 | |||
471 | /* Start using proper page size encodings in ctx register. */ | ||
472 | sethi %hi(sparc64_kern_pri_context), %g3 | ||
473 | ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2 | ||
474 | mov PRIMARY_CONTEXT, %g1 | ||
475 | stxa %g2, [%g1] ASI_DMMU | ||
476 | membar #Sync | ||
477 | |||
478 | rdpr %pstate, %o1 | 513 | rdpr %pstate, %o1 |
479 | or %o1, PSTATE_IE, %o1 | 514 | or %o1, PSTATE_IE, %o1 |
480 | wrpr %o1, 0, %pstate | 515 | wrpr %o1, 0, %pstate |
516 | wrpr %g0, 0x0, %pil | ||
517 | |||
518 | ret | ||
519 | restore | ||
520 | |||
521 | .globl setup_tba | ||
522 | setup_tba: /* i0 = is_starfire */ | ||
523 | save %sp, -192, %sp | ||
524 | |||
525 | /* The boot processor is the only cpu which invokes this | ||
526 | * routine, the other cpus set things up via trampoline.S. | ||
527 | * So save the OBP trap table address here. | ||
528 | */ | ||
529 | rdpr %tba, %g7 | ||
530 | sethi %hi(prom_tba), %o1 | ||
531 | or %o1, %lo(prom_tba), %o1 | ||
532 | stx %g7, [%o1] | ||
533 | |||
534 | call setup_trap_table | ||
535 | nop | ||
481 | 536 | ||
482 | ret | 537 | ret |
483 | restore | 538 | restore |