diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-05-19 23:43:47 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-05-19 23:43:47 -0400 |
commit | 3d07f0e83d4323d2cd45cc583f7cf1957aca3cac (patch) | |
tree | 279203d24b3a366ed6da93a3f9664409eb1a8488 /arch/powerpc/kernel | |
parent | 593adf317cf165f7c66facf2285db9d4befbd1c0 (diff) | |
parent | bbfff72ee3e76bd4712b87386af00bfe97114bc9 (diff) |
Merge remote branch 'kumar/next' into next
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/cpu_setup_fsl_booke.S | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64e.S | 112 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 8 |
3 files changed, 120 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index 913611105c1f..8053db02b85e 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S | |||
@@ -88,6 +88,9 @@ _GLOBAL(__setup_cpu_e5500) | |||
88 | bl __e500_dcache_setup | 88 | bl __e500_dcache_setup |
89 | #ifdef CONFIG_PPC_BOOK3E_64 | 89 | #ifdef CONFIG_PPC_BOOK3E_64 |
90 | bl .__setup_base_ivors | 90 | bl .__setup_base_ivors |
91 | bl .setup_perfmon_ivor | ||
92 | bl .setup_doorbell_ivors | ||
93 | bl .setup_ehv_ivors | ||
91 | #else | 94 | #else |
92 | bl __setup_e500mc_ivors | 95 | bl __setup_e500mc_ivors |
93 | #endif | 96 | #endif |
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 4d0abb4930a1..d24d4400cc79 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S | |||
@@ -253,9 +253,6 @@ exception_marker: | |||
253 | .balign 0x1000 | 253 | .balign 0x1000 |
254 | .globl interrupt_base_book3e | 254 | .globl interrupt_base_book3e |
255 | interrupt_base_book3e: /* fake trap */ | 255 | interrupt_base_book3e: /* fake trap */ |
256 | /* Note: If real debug exceptions are supported by the HW, the vector | ||
257 | * below will have to be patched up to point to an appropriate handler | ||
258 | */ | ||
259 | EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ | 256 | EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ |
260 | EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ | 257 | EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ |
261 | EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ | 258 | EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ |
@@ -272,8 +269,13 @@ interrupt_base_book3e: /* fake trap */ | |||
272 | EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ | 269 | EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ |
273 | EXCEPTION_STUB(0x1c0, data_tlb_miss) | 270 | EXCEPTION_STUB(0x1c0, data_tlb_miss) |
274 | EXCEPTION_STUB(0x1e0, instruction_tlb_miss) | 271 | EXCEPTION_STUB(0x1e0, instruction_tlb_miss) |
272 | EXCEPTION_STUB(0x260, perfmon) | ||
275 | EXCEPTION_STUB(0x280, doorbell) | 273 | EXCEPTION_STUB(0x280, doorbell) |
276 | EXCEPTION_STUB(0x2a0, doorbell_crit) | 274 | EXCEPTION_STUB(0x2a0, doorbell_crit) |
275 | EXCEPTION_STUB(0x2c0, guest_doorbell) | ||
276 | EXCEPTION_STUB(0x2e0, guest_doorbell_crit) | ||
277 | EXCEPTION_STUB(0x300, hypercall) | ||
278 | EXCEPTION_STUB(0x320, ehpriv) | ||
277 | 279 | ||
278 | .globl interrupt_end_book3e | 280 | .globl interrupt_end_book3e |
279 | interrupt_end_book3e: | 281 | interrupt_end_book3e: |
@@ -455,6 +457,70 @@ interrupt_end_book3e: | |||
455 | kernel_dbg_exc: | 457 | kernel_dbg_exc: |
456 | b . /* NYI */ | 458 | b . /* NYI */ |
457 | 459 | ||
460 | /* Debug exception as a debug interrupt*/ | ||
461 | START_EXCEPTION(debug_debug); | ||
462 | DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) | ||
463 | |||
464 | /* | ||
465 | * If there is a single step or branch-taken exception in an | ||
466 | * exception entry sequence, it was probably meant to apply to | ||
467 | * the code where the exception occurred (since exception entry | ||
468 | * doesn't turn off DE automatically). We simulate the effect | ||
469 | * of turning off DE on entry to an exception handler by turning | ||
470 | * off DE in the DSRR1 value and clearing the debug status. | ||
471 | */ | ||
472 | |||
473 | mfspr r14,SPRN_DBSR /* check single-step/branch taken */ | ||
474 | andis. r15,r14,DBSR_IC@h | ||
475 | beq+ 1f | ||
476 | |||
477 | LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) | ||
478 | LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e) | ||
479 | cmpld cr0,r10,r14 | ||
480 | cmpld cr1,r10,r15 | ||
481 | blt+ cr0,1f | ||
482 | bge+ cr1,1f | ||
483 | |||
484 | /* here it looks like we got an inappropriate debug exception. */ | ||
485 | lis r14,DBSR_IC@h /* clear the IC event */ | ||
486 | rlwinm r11,r11,0,~MSR_DE /* clear DE in the DSRR1 value */ | ||
487 | mtspr SPRN_DBSR,r14 | ||
488 | mtspr SPRN_DSRR1,r11 | ||
489 | lwz r10,PACA_EXDBG+EX_CR(r13) /* restore registers */ | ||
490 | ld r1,PACA_EXDBG+EX_R1(r13) | ||
491 | ld r14,PACA_EXDBG+EX_R14(r13) | ||
492 | ld r15,PACA_EXDBG+EX_R15(r13) | ||
493 | mtcr r10 | ||
494 | ld r10,PACA_EXDBG+EX_R10(r13) /* restore registers */ | ||
495 | ld r11,PACA_EXDBG+EX_R11(r13) | ||
496 | mfspr r13,SPRN_SPRG_DBG_SCRATCH | ||
497 | rfdi | ||
498 | |||
499 | /* Normal debug exception */ | ||
500 | /* XXX We only handle coming from userspace for now since we can't | ||
501 | * quite save properly an interrupted kernel state yet | ||
502 | */ | ||
503 | 1: andi. r14,r11,MSR_PR; /* check for userspace again */ | ||
504 | beq kernel_dbg_exc; /* if from kernel mode */ | ||
505 | |||
506 | /* Now we mash up things to make it look like we are coming on a | ||
507 | * normal exception | ||
508 | */ | ||
509 | mfspr r15,SPRN_SPRG_DBG_SCRATCH | ||
510 | mtspr SPRN_SPRG_GEN_SCRATCH,r15 | ||
511 | mfspr r14,SPRN_DBSR | ||
512 | EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) | ||
513 | std r14,_DSISR(r1) | ||
514 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
515 | mr r4,r14 | ||
516 | ld r14,PACA_EXDBG+EX_R14(r13) | ||
517 | ld r15,PACA_EXDBG+EX_R15(r13) | ||
518 | bl .save_nvgprs | ||
519 | bl .DebugException | ||
520 | b .ret_from_except | ||
521 | |||
522 | MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) | ||
523 | |||
458 | /* Doorbell interrupt */ | 524 | /* Doorbell interrupt */ |
459 | MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) | 525 | MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) |
460 | 526 | ||
@@ -469,6 +535,11 @@ kernel_dbg_exc: | |||
469 | // b ret_from_crit_except | 535 | // b ret_from_crit_except |
470 | b . | 536 | b . |
471 | 537 | ||
538 | MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) | ||
539 | MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE) | ||
540 | MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE) | ||
541 | MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE) | ||
542 | |||
472 | 543 | ||
473 | /* | 544 | /* |
474 | * An interrupt came in while soft-disabled; clear EE in SRR1, | 545 | * An interrupt came in while soft-disabled; clear EE in SRR1, |
@@ -588,7 +659,12 @@ fast_exception_return: | |||
588 | BAD_STACK_TRAMPOLINE(0x000) | 659 | BAD_STACK_TRAMPOLINE(0x000) |
589 | BAD_STACK_TRAMPOLINE(0x100) | 660 | BAD_STACK_TRAMPOLINE(0x100) |
590 | BAD_STACK_TRAMPOLINE(0x200) | 661 | BAD_STACK_TRAMPOLINE(0x200) |
662 | BAD_STACK_TRAMPOLINE(0x260) | ||
663 | BAD_STACK_TRAMPOLINE(0x2c0) | ||
664 | BAD_STACK_TRAMPOLINE(0x2e0) | ||
591 | BAD_STACK_TRAMPOLINE(0x300) | 665 | BAD_STACK_TRAMPOLINE(0x300) |
666 | BAD_STACK_TRAMPOLINE(0x310) | ||
667 | BAD_STACK_TRAMPOLINE(0x320) | ||
592 | BAD_STACK_TRAMPOLINE(0x400) | 668 | BAD_STACK_TRAMPOLINE(0x400) |
593 | BAD_STACK_TRAMPOLINE(0x500) | 669 | BAD_STACK_TRAMPOLINE(0x500) |
594 | BAD_STACK_TRAMPOLINE(0x600) | 670 | BAD_STACK_TRAMPOLINE(0x600) |
@@ -1124,3 +1200,33 @@ _GLOBAL(__setup_base_ivors) | |||
1124 | sync | 1200 | sync |
1125 | 1201 | ||
1126 | blr | 1202 | blr |
1203 | |||
1204 | _GLOBAL(setup_perfmon_ivor) | ||
1205 | SET_IVOR(35, 0x260) /* Performance Monitor */ | ||
1206 | blr | ||
1207 | |||
1208 | _GLOBAL(setup_doorbell_ivors) | ||
1209 | SET_IVOR(36, 0x280) /* Processor Doorbell */ | ||
1210 | SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */ | ||
1211 | |||
1212 | /* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */ | ||
1213 | mfspr r10,SPRN_MMUCFG | ||
1214 | rlwinm. r10,r10,0,MMUCFG_LPIDSIZE | ||
1215 | beqlr | ||
1216 | |||
1217 | SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ | ||
1218 | SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ | ||
1219 | blr | ||
1220 | |||
1221 | _GLOBAL(setup_ehv_ivors) | ||
1222 | /* | ||
1223 | * We may be running as a guest and lack E.HV even on a chip | ||
1224 | * that normally has it. | ||
1225 | */ | ||
1226 | mfspr r10,SPRN_MMUCFG | ||
1227 | rlwinm. r10,r10,0,MMUCFG_LPIDSIZE | ||
1228 | beqlr | ||
1229 | |||
1230 | SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */ | ||
1231 | SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */ | ||
1232 | blr | ||
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index c2ec0a12e14f..a88bf2713d41 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <asm/udbg.h> | 62 | #include <asm/udbg.h> |
63 | #include <asm/kexec.h> | 63 | #include <asm/kexec.h> |
64 | #include <asm/mmu_context.h> | 64 | #include <asm/mmu_context.h> |
65 | #include <asm/code-patching.h> | ||
65 | 66 | ||
66 | #include "setup.h" | 67 | #include "setup.h" |
67 | 68 | ||
@@ -477,6 +478,9 @@ static void __init irqstack_early_init(void) | |||
477 | #ifdef CONFIG_PPC_BOOK3E | 478 | #ifdef CONFIG_PPC_BOOK3E |
478 | static void __init exc_lvl_early_init(void) | 479 | static void __init exc_lvl_early_init(void) |
479 | { | 480 | { |
481 | extern unsigned int interrupt_base_book3e; | ||
482 | extern unsigned int exc_debug_debug_book3e; | ||
483 | |||
480 | unsigned int i; | 484 | unsigned int i; |
481 | 485 | ||
482 | for_each_possible_cpu(i) { | 486 | for_each_possible_cpu(i) { |
@@ -487,6 +491,10 @@ static void __init exc_lvl_early_init(void) | |||
487 | mcheckirq_ctx[i] = (struct thread_info *) | 491 | mcheckirq_ctx[i] = (struct thread_info *) |
488 | __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); | 492 | __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); |
489 | } | 493 | } |
494 | |||
495 | if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC)) | ||
496 | patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1, | ||
497 | (unsigned long)&exc_debug_debug_book3e, 0); | ||
490 | } | 498 | } |
491 | #else | 499 | #else |
492 | #define exc_lvl_early_init() | 500 | #define exc_lvl_early_init() |