aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2012-03-27 15:40:20 -0400
committerChris Metcalf <cmetcalf@tilera.com>2012-05-25 12:48:20 -0400
commit51007004f44c9588d70ffb77e1f52479bd5b0e37 (patch)
treeddf8dd2f83554ecbe9de0c690cfab3889308397b /arch/tile/kernel
parent76e10d158efb6d4516018846f60c2ab5501900bc (diff)
arch/tile: use interrupt critical sections less
In general we want to avoid ever touching memory while within an interrupt critical section, since the page fault path goes through a different path from the hypervisor when in an interrupt critical section, and we carefully decided with tilegx that we didn't need to support this path in the kernel. (On tilepro we did implement that path as part of supporting atomic instructions in software.) In practice we always need to touch the kernel stack, since that's where we store the interrupt state before releasing the critical section, but this change cleans up a few things. The IRQ_ENABLE macro is split up so that when we want to enable interrupts in a deferred way (e.g. for cpu_idle or for interrupt return) we can read the per-cpu enable mask before entering the critical section. The cache-migration code is changed to use interrupt masking instead of interrupt critical sections. And, the interrupt-entry code is changed so that we defer loading "tp" from per-cpu data until after we have released the interrupt critical section. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r--arch/tile/kernel/entry.S3
-rw-r--r--arch/tile/kernel/intvec_64.S78
2 files changed, 45 insertions, 36 deletions
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index ec91568df880..133c4b56a99e 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
@@ -100,8 +100,9 @@ STD_ENTRY(smp_nap)
100 */ 100 */
101STD_ENTRY(_cpu_idle) 101STD_ENTRY(_cpu_idle)
102 movei r1, 1 102 movei r1, 1
103 IRQ_ENABLE_LOAD(r2, r3)
103 mtspr INTERRUPT_CRITICAL_SECTION, r1 104 mtspr INTERRUPT_CRITICAL_SECTION, r1
104 IRQ_ENABLE(r2, r3) /* unmask, but still with ICS set */ 105 IRQ_ENABLE_APPLY(r2, r3) /* unmask, but still with ICS set */
105 mtspr INTERRUPT_CRITICAL_SECTION, zero 106 mtspr INTERRUPT_CRITICAL_SECTION, zero
106 .global _cpu_idle_nap 107 .global _cpu_idle_nap
107_cpu_idle_nap: 108_cpu_idle_nap:
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 30ae76e50c44..0ae8723ea578 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
@@ -220,7 +220,9 @@ intvec_\vecname:
220 * This routine saves just the first four registers, plus the 220 * This routine saves just the first four registers, plus the
221 * stack context so we can do proper backtracing right away, 221 * stack context so we can do proper backtracing right away,
222 * and defers to handle_interrupt to save the rest. 222 * and defers to handle_interrupt to save the rest.
223 * The backtracer needs pc, ex1, lr, sp, r52, and faultnum. 223 * The backtracer needs pc, ex1, lr, sp, r52, and faultnum,
224 * and needs sp set to its final location at the bottom of
225 * the stack frame.
224 */ 226 */
225 addli r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP) 227 addli r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP)
226 wh64 r0 /* cache line 7 */ 228 wh64 r0 /* cache line 7 */
@@ -450,23 +452,6 @@ intvec_\vecname:
450 push_reg r5, r52 452 push_reg r5, r52
451 st r52, r4 453 st r52, r4
452 454
453 /* Load tp with our per-cpu offset. */
454#ifdef CONFIG_SMP
455 {
456 mfspr r20, SPR_SYSTEM_SAVE_K_0
457 moveli r21, hw2_last(__per_cpu_offset)
458 }
459 {
460 shl16insli r21, r21, hw1(__per_cpu_offset)
461 bfextu r20, r20, 0, LOG2_THREAD_SIZE-1
462 }
463 shl16insli r21, r21, hw0(__per_cpu_offset)
464 shl3add r20, r20, r21
465 ld tp, r20
466#else
467 move tp, zero
468#endif
469
470 /* 455 /*
471 * If we will be returning to the kernel, we will need to 456 * If we will be returning to the kernel, we will need to
472 * reset the interrupt masks to the state they had before. 457 * reset the interrupt masks to the state they had before.
@@ -489,6 +474,44 @@ intvec_\vecname:
489 .endif 474 .endif
490 st r21, r32 475 st r21, r32
491 476
477 /*
478 * we've captured enough state to the stack (including in
479 * particular our EX_CONTEXT state) that we can now release
480 * the interrupt critical section and replace it with our
481 * standard "interrupts disabled" mask value. This allows
482 * synchronous interrupts (and profile interrupts) to punch
483 * through from this point onwards.
484 *
485 * It's important that no code before this point touch memory
486 * other than our own stack (to keep the invariant that this
487 * is all that gets touched under ICS), and that no code after
488 * this point reference any interrupt-specific SPR, in particular
489 * the EX_CONTEXT_K_ values.
490 */
491 .ifc \function,handle_nmi
492 IRQ_DISABLE_ALL(r20)
493 .else
494 IRQ_DISABLE(r20, r21)
495 .endif
496 mtspr INTERRUPT_CRITICAL_SECTION, zero
497
498 /* Load tp with our per-cpu offset. */
499#ifdef CONFIG_SMP
500 {
501 mfspr r20, SPR_SYSTEM_SAVE_K_0
502 moveli r21, hw2_last(__per_cpu_offset)
503 }
504 {
505 shl16insli r21, r21, hw1(__per_cpu_offset)
506 bfextu r20, r20, 0, LOG2_THREAD_SIZE-1
507 }
508 shl16insli r21, r21, hw0(__per_cpu_offset)
509 shl3add r20, r20, r21
510 ld tp, r20
511#else
512 move tp, zero
513#endif
514
492#ifdef __COLLECT_LINKER_FEEDBACK__ 515#ifdef __COLLECT_LINKER_FEEDBACK__
493 /* 516 /*
494 * Notify the feedback routines that we were in the 517 * Notify the feedback routines that we were in the
@@ -513,21 +536,6 @@ intvec_\vecname:
513#endif 536#endif
514 537
515 /* 538 /*
516 * we've captured enough state to the stack (including in
517 * particular our EX_CONTEXT state) that we can now release
518 * the interrupt critical section and replace it with our
519 * standard "interrupts disabled" mask value. This allows
520 * synchronous interrupts (and profile interrupts) to punch
521 * through from this point onwards.
522 */
523 .ifc \function,handle_nmi
524 IRQ_DISABLE_ALL(r20)
525 .else
526 IRQ_DISABLE(r20, r21)
527 .endif
528 mtspr INTERRUPT_CRITICAL_SECTION, zero
529
530 /*
531 * Prepare the first 256 stack bytes to be rapidly accessible 539 * Prepare the first 256 stack bytes to be rapidly accessible
532 * without having to fetch the background data. 540 * without having to fetch the background data.
533 */ 541 */
@@ -736,9 +744,10 @@ STD_ENTRY(interrupt_return)
736 beqzt r30, .Lrestore_regs 744 beqzt r30, .Lrestore_regs
737 j 3f 745 j 3f
7382: TRACE_IRQS_ON 7462: TRACE_IRQS_ON
747 IRQ_ENABLE_LOAD(r20, r21)
739 movei r0, 1 748 movei r0, 1
740 mtspr INTERRUPT_CRITICAL_SECTION, r0 749 mtspr INTERRUPT_CRITICAL_SECTION, r0
741 IRQ_ENABLE(r20, r21) 750 IRQ_ENABLE_APPLY(r20, r21)
742 beqzt r30, .Lrestore_regs 751 beqzt r30, .Lrestore_regs
7433: 7523:
744 753
@@ -755,7 +764,6 @@ STD_ENTRY(interrupt_return)
755 * that will save some cycles if this turns out to be a syscall. 764 * that will save some cycles if this turns out to be a syscall.
756 */ 765 */
757.Lrestore_regs: 766.Lrestore_regs:
758 FEEDBACK_REENTER(interrupt_return) /* called from elsewhere */
759 767
760 /* 768 /*
761 * Rotate so we have one high bit and one low bit to test. 769 * Rotate so we have one high bit and one low bit to test.