aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-10-04 02:47:49 -0400
committerPaul Mackerras <paulus@samba.org>2006-10-16 02:31:36 -0400
commitd04c56f73c30a5e593202ecfcf25ed43d42363a2 (patch)
treebec1208293c904b73f12dd9179ebf8e88dbdb085
parent284a940675a64df253e3dffc60b09bb4bbb149e4 (diff)
[POWERPC] Lazy interrupt disabling for 64-bit machines
This implements a lazy strategy for disabling interrupts. This means that local_irq_disable() et al. just clear the 'interrupts are enabled' flag in the paca. If an interrupt comes along, the interrupt entry code notices that interrupts are supposed to be disabled, and clears the EE bit in SRR1, clears the 'interrupts are hard-enabled' flag in the paca, and returns. This means that interrupts only actually get disabled in the processor when an interrupt comes along. When interrupts are enabled by local_irq_enable() et al., the code sets the interrupts-enabled flag in the paca, and then checks whether interrupts got hard-disabled. If so, it also sets the EE bit in the MSR to hard-enable the interrupts. This has the potential to improve performance, and also makes it easier to make a kernel that can boot on iSeries and on other 64-bit machines, since this lazy-disable strategy is very similar to the soft-disable strategy that iSeries already uses. This version renames paca->proc_enabled to paca->soft_enabled, and changes a couple of soft-disables in the kexec code to hard-disables, which should fix the crash that Michael Ellerman saw. This doesn't yet use a reserved CR field for the soft_enabled and hard_enabled flags. This applies on top of Stephen Rothwell's patches to make it possible to build a combined iSeries/other kernel. Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/asm-offsets.c3
-rw-r--r--arch/powerpc/kernel/crash.c4
-rw-r--r--arch/powerpc/kernel/entry_64.S39
-rw-r--r--arch/powerpc/kernel/head_64.S110
-rw-r--r--arch/powerpc/kernel/idle_power4.S8
-rw-r--r--arch/powerpc/kernel/irq.c24
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c4
-rw-r--r--arch/powerpc/kernel/setup_64.c4
-rw-r--r--arch/powerpc/platforms/iseries/ksyms.c6
-rw-r--r--arch/powerpc/platforms/iseries/misc.S35
-rw-r--r--include/asm-powerpc/hw_irq.h31
-rw-r--r--include/asm-powerpc/paca.h3
12 files changed, 160 insertions, 111 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index d06f378597bb..e96521530d21 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -118,7 +118,8 @@ int main(void)
118 DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); 118 DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr));
119 DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); 119 DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1));
120 DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); 120 DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc));
121 DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled)); 121 DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
122 DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
122 DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); 123 DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
123 DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); 124 DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
124 DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); 125 DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 1af41f7616dc..89b03c8da9d2 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -111,7 +111,7 @@ void crash_ipi_callback(struct pt_regs *regs)
111 if (!cpu_online(cpu)) 111 if (!cpu_online(cpu))
112 return; 112 return;
113 113
114 local_irq_disable(); 114 hard_irq_disable();
115 if (!cpu_isset(cpu, cpus_in_crash)) 115 if (!cpu_isset(cpu, cpus_in_crash))
116 crash_save_this_cpu(regs, cpu); 116 crash_save_this_cpu(regs, cpu);
117 cpu_set(cpu, cpus_in_crash); 117 cpu_set(cpu, cpus_in_crash);
@@ -289,7 +289,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
289 * an SMP system. 289 * an SMP system.
290 * The kernel is broken so disable interrupts. 290 * The kernel is broken so disable interrupts.
291 */ 291 */
292 local_irq_disable(); 292 hard_irq_disable();
293 293
294 for_each_irq(irq) { 294 for_each_irq(irq) {
295 struct irq_desc *desc = irq_desc + irq; 295 struct irq_desc *desc = irq_desc + irq;
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 748e74fcf541..efda48741b29 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -87,6 +87,10 @@ system_call_common:
87 addi r9,r1,STACK_FRAME_OVERHEAD 87 addi r9,r1,STACK_FRAME_OVERHEAD
88 ld r11,exception_marker@toc(r2) 88 ld r11,exception_marker@toc(r2)
89 std r11,-16(r9) /* "regshere" marker */ 89 std r11,-16(r9) /* "regshere" marker */
90 li r10,1
91 stb r10,PACASOFTIRQEN(r13)
92 stb r10,PACAHARDIRQEN(r13)
93 std r10,SOFTE(r1)
90#ifdef CONFIG_PPC_ISERIES 94#ifdef CONFIG_PPC_ISERIES
91BEGIN_FW_FTR_SECTION 95BEGIN_FW_FTR_SECTION
92 /* Hack for handling interrupts when soft-enabling on iSeries */ 96 /* Hack for handling interrupts when soft-enabling on iSeries */
@@ -94,8 +98,6 @@ BEGIN_FW_FTR_SECTION
94 andi. r10,r12,MSR_PR /* from kernel */ 98 andi. r10,r12,MSR_PR /* from kernel */
95 crand 4*cr0+eq,4*cr1+eq,4*cr0+eq 99 crand 4*cr0+eq,4*cr1+eq,4*cr0+eq
96 beq hardware_interrupt_entry 100 beq hardware_interrupt_entry
97 lbz r10,PACAPROCENABLED(r13)
98 std r10,SOFTE(r1)
99END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 101END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
100#endif 102#endif
101 mfmsr r11 103 mfmsr r11
@@ -460,9 +462,9 @@ _GLOBAL(ret_from_except_lite)
460#endif 462#endif
461 463
462restore: 464restore:
465 ld r5,SOFTE(r1)
463#ifdef CONFIG_PPC_ISERIES 466#ifdef CONFIG_PPC_ISERIES
464BEGIN_FW_FTR_SECTION 467BEGIN_FW_FTR_SECTION
465 ld r5,SOFTE(r1)
466 cmpdi 0,r5,0 468 cmpdi 0,r5,0
467 beq 4f 469 beq 4f
468 /* Check for pending interrupts (iSeries) */ 470 /* Check for pending interrupts (iSeries) */
@@ -472,16 +474,16 @@ BEGIN_FW_FTR_SECTION
472 beq+ 4f /* skip do_IRQ if no interrupts */ 474 beq+ 4f /* skip do_IRQ if no interrupts */
473 475
474 li r3,0 476 li r3,0
475 stb r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */ 477 stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */
476 ori r10,r10,MSR_EE 478 ori r10,r10,MSR_EE
477 mtmsrd r10 /* hard-enable again */ 479 mtmsrd r10 /* hard-enable again */
478 addi r3,r1,STACK_FRAME_OVERHEAD 480 addi r3,r1,STACK_FRAME_OVERHEAD
479 bl .do_IRQ 481 bl .do_IRQ
480 b .ret_from_except_lite /* loop back and handle more */ 482 b .ret_from_except_lite /* loop back and handle more */
481 4834:
4824: stb r5,PACAPROCENABLED(r13)
483END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 484END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
484#endif 485#endif
486 stb r5,PACASOFTIRQEN(r13)
485 487
486 ld r3,_MSR(r1) 488 ld r3,_MSR(r1)
487 andi. r0,r3,MSR_RI 489 andi. r0,r3,MSR_RI
@@ -538,25 +540,15 @@ do_work:
538 /* Check that preempt_count() == 0 and interrupts are enabled */ 540 /* Check that preempt_count() == 0 and interrupts are enabled */
539 lwz r8,TI_PREEMPT(r9) 541 lwz r8,TI_PREEMPT(r9)
540 cmpwi cr1,r8,0 542 cmpwi cr1,r8,0
541#ifdef CONFIG_PPC_ISERIES
542BEGIN_FW_FTR_SECTION
543 ld r0,SOFTE(r1) 543 ld r0,SOFTE(r1)
544 cmpdi r0,0 544 cmpdi r0,0
545END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
546#endif
547BEGIN_FW_FTR_SECTION
548 andi. r0,r3,MSR_EE
549END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
550 crandc eq,cr1*4+eq,eq 545 crandc eq,cr1*4+eq,eq
551 bne restore 546 bne restore
552 /* here we are preempting the current task */ 547 /* here we are preempting the current task */
5531: 5481:
554#ifdef CONFIG_PPC_ISERIES
555BEGIN_FW_FTR_SECTION
556 li r0,1 549 li r0,1
557 stb r0,PACAPROCENABLED(r13) 550 stb r0,PACASOFTIRQEN(r13)
558END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 551 stb r0,PACAHARDIRQEN(r13)
559#endif
560 ori r10,r10,MSR_EE 552 ori r10,r10,MSR_EE
561 mtmsrd r10,1 /* reenable interrupts */ 553 mtmsrd r10,1 /* reenable interrupts */
562 bl .preempt_schedule 554 bl .preempt_schedule
@@ -639,8 +631,7 @@ _GLOBAL(enter_rtas)
639 /* There is no way it is acceptable to get here with interrupts enabled, 631 /* There is no way it is acceptable to get here with interrupts enabled,
640 * check it with the asm equivalent of WARN_ON 632 * check it with the asm equivalent of WARN_ON
641 */ 633 */
642 mfmsr r6 634 lbz r0,PACASOFTIRQEN(r13)
643 andi. r0,r6,MSR_EE
6441: tdnei r0,0 6351: tdnei r0,0
645.section __bug_table,"a" 636.section __bug_table,"a"
646 .llong 1b,__LINE__ + 0x1000000, 1f, 2f 637 .llong 1b,__LINE__ + 0x1000000, 1f, 2f
@@ -649,7 +640,13 @@ _GLOBAL(enter_rtas)
6491: .asciz __FILE__ 6401: .asciz __FILE__
6502: .asciz "enter_rtas" 6412: .asciz "enter_rtas"
651.previous 642.previous
652 643
644 /* Hard-disable interrupts */
645 mfmsr r6
646 rldicl r7,r6,48,1
647 rotldi r7,r7,16
648 mtmsrd r7,1
649
653 /* Unfortunately, the stack pointer and the MSR are also clobbered, 650 /* Unfortunately, the stack pointer and the MSR are also clobbered,
654 * so they are saved in the PACA which allows us to restore 651 * so they are saved in the PACA which allows us to restore
655 * our original state after RTAS returns. 652 * our original state after RTAS returns.
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 645c7f10fb28..c93d9f35a121 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -35,9 +35,7 @@
35#include <asm/thread_info.h> 35#include <asm/thread_info.h>
36#include <asm/firmware.h> 36#include <asm/firmware.h>
37 37
38#ifdef CONFIG_PPC_ISERIES
39#define DO_SOFT_DISABLE 38#define DO_SOFT_DISABLE
40#endif
41 39
42/* 40/*
43 * We layout physical memory as follows: 41 * We layout physical memory as follows:
@@ -308,7 +306,9 @@ exception_marker:
308 std r9,_LINK(r1); \ 306 std r9,_LINK(r1); \
309 mfctr r10; /* save CTR in stackframe */ \ 307 mfctr r10; /* save CTR in stackframe */ \
310 std r10,_CTR(r1); \ 308 std r10,_CTR(r1); \
309 lbz r10,PACASOFTIRQEN(r13); \
311 mfspr r11,SPRN_XER; /* save XER in stackframe */ \ 310 mfspr r11,SPRN_XER; /* save XER in stackframe */ \
311 std r10,SOFTE(r1); \
312 std r11,_XER(r1); \ 312 std r11,_XER(r1); \
313 li r9,(n)+1; \ 313 li r9,(n)+1; \
314 std r9,_TRAP(r1); /* set trap number */ \ 314 std r9,_TRAP(r1); /* set trap number */ \
@@ -343,6 +343,34 @@ label##_pSeries: \
343 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) 343 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
344 344
345 345
346#define MASKABLE_EXCEPTION_PSERIES(n, label) \
347 . = n; \
348 .globl label##_pSeries; \
349label##_pSeries: \
350 HMT_MEDIUM; \
351 mtspr SPRN_SPRG1,r13; /* save r13 */ \
352 mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
353 std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \
354 std r10,PACA_EXGEN+EX_R10(r13); \
355 lbz r10,PACASOFTIRQEN(r13); \
356 mfcr r9; \
357 cmpwi r10,0; \
358 beq masked_interrupt; \
359 mfspr r10,SPRN_SPRG1; \
360 std r10,PACA_EXGEN+EX_R13(r13); \
361 std r11,PACA_EXGEN+EX_R11(r13); \
362 std r12,PACA_EXGEN+EX_R12(r13); \
363 clrrdi r12,r13,32; /* get high part of &label */ \
364 mfmsr r10; \
365 mfspr r11,SPRN_SRR0; /* save SRR0 */ \
366 LOAD_HANDLER(r12,label##_common) \
367 ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \
368 mtspr SPRN_SRR0,r12; \
369 mfspr r12,SPRN_SRR1; /* and SRR1 */ \
370 mtspr SPRN_SRR1,r10; \
371 rfid; \
372 b . /* prevent speculative execution */
373
346#define STD_EXCEPTION_ISERIES(n, label, area) \ 374#define STD_EXCEPTION_ISERIES(n, label, area) \
347 .globl label##_iSeries; \ 375 .globl label##_iSeries; \
348label##_iSeries: \ 376label##_iSeries: \
@@ -358,40 +386,32 @@ label##_iSeries: \
358 HMT_MEDIUM; \ 386 HMT_MEDIUM; \
359 mtspr SPRN_SPRG1,r13; /* save r13 */ \ 387 mtspr SPRN_SPRG1,r13; /* save r13 */ \
360 EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ 388 EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \
361 lbz r10,PACAPROCENABLED(r13); \ 389 lbz r10,PACASOFTIRQEN(r13); \
362 cmpwi 0,r10,0; \ 390 cmpwi 0,r10,0; \
363 beq- label##_iSeries_masked; \ 391 beq- label##_iSeries_masked; \
364 EXCEPTION_PROLOG_ISERIES_2; \ 392 EXCEPTION_PROLOG_ISERIES_2; \
365 b label##_common; \ 393 b label##_common; \
366 394
367#ifdef DO_SOFT_DISABLE 395#ifdef CONFIG_PPC_ISERIES
368#define DISABLE_INTS \ 396#define DISABLE_INTS \
369BEGIN_FW_FTR_SECTION; \
370 lbz r10,PACAPROCENABLED(r13); \
371 li r11,0; \ 397 li r11,0; \
372 std r10,SOFTE(r1); \ 398 stb r11,PACASOFTIRQEN(r13); \
399BEGIN_FW_FTR_SECTION; \
400 stb r11,PACAHARDIRQEN(r13); \
401END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \
402BEGIN_FW_FTR_SECTION; \
373 mfmsr r10; \ 403 mfmsr r10; \
374 stb r11,PACAPROCENABLED(r13); \
375 ori r10,r10,MSR_EE; \ 404 ori r10,r10,MSR_EE; \
376 mtmsrd r10,1; \ 405 mtmsrd r10,1; \
377END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 406END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
378 407
379#define ENABLE_INTS \ 408#else
380BEGIN_FW_FTR_SECTION; \ 409#define DISABLE_INTS \
381 lbz r10,PACAPROCENABLED(r13); \ 410 li r11,0; \
382 mfmsr r11; \ 411 stb r11,PACASOFTIRQEN(r13); \
383 std r10,SOFTE(r1); \ 412 stb r11,PACAHARDIRQEN(r13)
384 ori r11,r11,MSR_EE; \
385END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \
386BEGIN_FW_FTR_SECTION; \
387 ld r12,_MSR(r1); \
388 mfmsr r11; \
389 rlwimi r11,r12,0,MSR_EE; \
390END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \
391 mtmsrd r11,1
392 413
393#else /* hard enable/disable interrupts */ 414#endif /* CONFIG_PPC_ISERIES */
394#define DISABLE_INTS
395 415
396#define ENABLE_INTS \ 416#define ENABLE_INTS \
397 ld r12,_MSR(r1); \ 417 ld r12,_MSR(r1); \
@@ -399,8 +419,6 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \
399 rlwimi r11,r12,0,MSR_EE; \ 419 rlwimi r11,r12,0,MSR_EE; \
400 mtmsrd r11,1 420 mtmsrd r11,1
401 421
402#endif
403
404#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ 422#define STD_EXCEPTION_COMMON(trap, label, hdlr) \
405 .align 7; \ 423 .align 7; \
406 .globl label##_common; \ 424 .globl label##_common; \
@@ -541,11 +559,11 @@ instruction_access_slb_pSeries:
541 mfspr r12,SPRN_SRR1 /* and SRR1 */ 559 mfspr r12,SPRN_SRR1 /* and SRR1 */
542 b .slb_miss_realmode /* Rel. branch works in real mode */ 560 b .slb_miss_realmode /* Rel. branch works in real mode */
543 561
544 STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) 562 MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt)
545 STD_EXCEPTION_PSERIES(0x600, alignment) 563 STD_EXCEPTION_PSERIES(0x600, alignment)
546 STD_EXCEPTION_PSERIES(0x700, program_check) 564 STD_EXCEPTION_PSERIES(0x700, program_check)
547 STD_EXCEPTION_PSERIES(0x800, fp_unavailable) 565 STD_EXCEPTION_PSERIES(0x800, fp_unavailable)
548 STD_EXCEPTION_PSERIES(0x900, decrementer) 566 MASKABLE_EXCEPTION_PSERIES(0x900, decrementer)
549 STD_EXCEPTION_PSERIES(0xa00, trap_0a) 567 STD_EXCEPTION_PSERIES(0xa00, trap_0a)
550 STD_EXCEPTION_PSERIES(0xb00, trap_0b) 568 STD_EXCEPTION_PSERIES(0xb00, trap_0b)
551 569
@@ -597,7 +615,24 @@ system_call_pSeries:
597/*** pSeries interrupt support ***/ 615/*** pSeries interrupt support ***/
598 616
599 /* moved from 0xf00 */ 617 /* moved from 0xf00 */
600 STD_EXCEPTION_PSERIES(., performance_monitor) 618 MASKABLE_EXCEPTION_PSERIES(., performance_monitor)
619
620/*
621 * An interrupt came in while soft-disabled; clear EE in SRR1,
622 * clear paca->hard_enabled and return.
623 */
624masked_interrupt:
625 stb r10,PACAHARDIRQEN(r13)
626 mtcrf 0x80,r9
627 ld r9,PACA_EXGEN+EX_R9(r13)
628 mfspr r10,SPRN_SRR1
629 rldicl r10,r10,48,1 /* clear MSR_EE */
630 rotldi r10,r10,16
631 mtspr SPRN_SRR1,r10
632 ld r10,PACA_EXGEN+EX_R10(r13)
633 mfspr r13,SPRN_SPRG1
634 rfid
635 b .
601 636
602 .align 7 637 .align 7
603_GLOBAL(do_stab_bolted_pSeries) 638_GLOBAL(do_stab_bolted_pSeries)
@@ -952,7 +987,8 @@ fast_exception_return:
952 REST_8GPRS(2, r1) 987 REST_8GPRS(2, r1)
953 988
954 mfmsr r10 989 mfmsr r10
955 clrrdi r10,r10,2 /* clear RI (LE is 0 already) */ 990 rldicl r10,r10,48,1 /* clear EE */
991 rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */
956 mtmsrd r10,1 992 mtmsrd r10,1
957 993
958 mtspr SPRN_SRR1,r12 994 mtspr SPRN_SRR1,r12
@@ -1877,11 +1913,16 @@ _GLOBAL(__secondary_start)
1877 /* enable MMU and jump to start_secondary */ 1913 /* enable MMU and jump to start_secondary */
1878 LOAD_REG_ADDR(r3, .start_secondary_prolog) 1914 LOAD_REG_ADDR(r3, .start_secondary_prolog)
1879 LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) 1915 LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
1880#ifdef DO_SOFT_DISABLE 1916#ifdef CONFIG_PPC_ISERIES
1881BEGIN_FW_FTR_SECTION 1917BEGIN_FW_FTR_SECTION
1882 ori r4,r4,MSR_EE 1918 ori r4,r4,MSR_EE
1883END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 1919END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
1884#endif 1920#endif
1921BEGIN_FW_FTR_SECTION
1922 stb r7,PACASOFTIRQEN(r13)
1923 stb r7,PACAHARDIRQEN(r13)
1924END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
1925
1885 mtspr SPRN_SRR0,r3 1926 mtspr SPRN_SRR0,r3
1886 mtspr SPRN_SRR1,r4 1927 mtspr SPRN_SRR1,r4
1887 rfid 1928 rfid
@@ -2019,15 +2060,18 @@ _STATIC(start_here_common)
2019 2060
2020 /* Load up the kernel context */ 2061 /* Load up the kernel context */
20215: 20625:
2022#ifdef DO_SOFT_DISABLE
2023BEGIN_FW_FTR_SECTION
2024 li r5,0 2063 li r5,0
2025 stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ 2064 stb r5,PACASOFTIRQEN(r13) /* Soft Disabled */
2065#ifdef CONFIG_PPC_ISERIES
2066BEGIN_FW_FTR_SECTION
2026 mfmsr r5 2067 mfmsr r5
2027 ori r5,r5,MSR_EE /* Hard Enabled */ 2068 ori r5,r5,MSR_EE /* Hard Enabled */
2028 mtmsrd r5 2069 mtmsrd r5
2029END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 2070END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
2030#endif 2071#endif
2072BEGIN_FW_FTR_SECTION
2073 stb r5,PACAHARDIRQEN(r13)
2074END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
2031 2075
2032 bl .start_kernel 2076 bl .start_kernel
2033 2077
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index 30de81da7b40..ba3195478600 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -30,6 +30,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
30 beqlr 30 beqlr
31 31
32 /* Go to NAP now */ 32 /* Go to NAP now */
33 mfmsr r7
34 rldicl r0,r7,48,1
35 rotldi r0,r0,16
36 mtmsrd r0,1 /* hard-disable interrupts */
37 li r0,1
38 stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */
39 stb r0,PACAHARDIRQEN(r13)
33BEGIN_FTR_SECTION 40BEGIN_FTR_SECTION
34 DSSALL 41 DSSALL
35 sync 42 sync
@@ -38,7 +45,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
38 ld r8,TI_LOCAL_FLAGS(r9) /* set napping bit */ 45 ld r8,TI_LOCAL_FLAGS(r9) /* set napping bit */
39 ori r8,r8,_TLF_NAPPING /* so when we take an exception */ 46 ori r8,r8,_TLF_NAPPING /* so when we take an exception */
40 std r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */ 47 std r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */
41 mfmsr r7
42 ori r7,r7,MSR_EE 48 ori r7,r7,MSR_EE
43 oris r7,r7,MSR_POW@h 49 oris r7,r7,MSR_POW@h
441: sync 501: sync
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 5e37bf14ef2d..67b21a008f6e 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -64,8 +64,9 @@
64#include <asm/ptrace.h> 64#include <asm/ptrace.h>
65#include <asm/machdep.h> 65#include <asm/machdep.h>
66#include <asm/udbg.h> 66#include <asm/udbg.h>
67#ifdef CONFIG_PPC_ISERIES 67#ifdef CONFIG_PPC64
68#include <asm/paca.h> 68#include <asm/paca.h>
69#include <asm/firmware.h>
69#endif 70#endif
70 71
71int __irq_offset_value; 72int __irq_offset_value;
@@ -95,6 +96,27 @@ extern atomic_t ipi_sent;
95EXPORT_SYMBOL(irq_desc); 96EXPORT_SYMBOL(irq_desc);
96 97
97int distribute_irqs = 1; 98int distribute_irqs = 1;
99
100void local_irq_restore(unsigned long en)
101{
102 get_paca()->soft_enabled = en;
103 if (!en)
104 return;
105
106 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
107 if (get_paca()->lppaca_ptr->int_dword.any_int)
108 iseries_handle_interrupts();
109 return;
110 }
111
112 if (get_paca()->hard_enabled)
113 return;
114 /* need to hard-enable interrupts here */
115 get_paca()->hard_enabled = en;
116 if ((int)mfspr(SPRN_DEC) < 0)
117 mtspr(SPRN_DEC, 1);
118 hard_irq_enable();
119}
98#endif /* CONFIG_PPC64 */ 120#endif /* CONFIG_PPC64 */
99 121
100int show_interrupts(struct seq_file *p, void *v) 122int show_interrupts(struct seq_file *p, void *v)
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 807193a3c784..9179f0739ea2 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -49,6 +49,10 @@
49#include <asm/commproc.h> 49#include <asm/commproc.h>
50#endif 50#endif
51 51
52#ifdef CONFIG_PPC64
53EXPORT_SYMBOL(local_irq_restore);
54#endif
55
52#ifdef CONFIG_PPC32 56#ifdef CONFIG_PPC32
53extern void transfer_to_handler(void); 57extern void transfer_to_handler(void);
54extern void do_IRQ(struct pt_regs *regs); 58extern void do_IRQ(struct pt_regs *regs);
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 4b2e32eab9dc..b1b0cda3f748 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -223,8 +223,8 @@ void early_setup_secondary(void)
223{ 223{
224 struct paca_struct *lpaca = get_paca(); 224 struct paca_struct *lpaca = get_paca();
225 225
226 /* Mark enabled in PACA */ 226 /* Mark interrupts enabled in PACA */
227 lpaca->proc_enabled = 0; 227 lpaca->soft_enabled = 0;
228 228
229 /* Initialize hash table for that CPU */ 229 /* Initialize hash table for that CPU */
230 htab_initialize_secondary(); 230 htab_initialize_secondary();
diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c
index a2200842f4e5..2430848b98e7 100644
--- a/arch/powerpc/platforms/iseries/ksyms.c
+++ b/arch/powerpc/platforms/iseries/ksyms.c
@@ -19,9 +19,3 @@ EXPORT_SYMBOL(HvCall4);
19EXPORT_SYMBOL(HvCall5); 19EXPORT_SYMBOL(HvCall5);
20EXPORT_SYMBOL(HvCall6); 20EXPORT_SYMBOL(HvCall6);
21EXPORT_SYMBOL(HvCall7); 21EXPORT_SYMBOL(HvCall7);
22
23#ifdef CONFIG_SMP
24EXPORT_SYMBOL(local_get_flags);
25EXPORT_SYMBOL(local_irq_disable);
26EXPORT_SYMBOL(local_irq_restore);
27#endif
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
index 7641fc7e550a..2c6ff0fdac98 100644
--- a/arch/powerpc/platforms/iseries/misc.S
+++ b/arch/powerpc/platforms/iseries/misc.S
@@ -19,39 +19,8 @@
19 19
20 .text 20 .text
21 21
22/* unsigned long local_save_flags(void) */ 22/* Handle pending interrupts in interrupt context */
23_GLOBAL(local_get_flags) 23_GLOBAL(iseries_handle_interrupts)
24 lbz r3,PACAPROCENABLED(r13)
25 blr
26
27/* unsigned long local_irq_disable(void) */
28_GLOBAL(local_irq_disable)
29 lbz r3,PACAPROCENABLED(r13)
30 li r4,0
31 stb r4,PACAPROCENABLED(r13)
32 blr /* Done */
33
34/* void local_irq_restore(unsigned long flags) */
35_GLOBAL(local_irq_restore)
36 lbz r5,PACAPROCENABLED(r13)
37 /* Check if things are setup the way we want _already_. */
38 cmpw 0,r3,r5
39 beqlr
40 /* are we enabling interrupts? */
41 cmpdi 0,r3,0
42 stb r3,PACAPROCENABLED(r13)
43 beqlr
44 /* Check pending interrupts */
45 /* A decrementer, IPI or PMC interrupt may have occurred
46 * while we were in the hypervisor (which enables) */
47 ld r4,PACALPPACAPTR(r13)
48 ld r4,LPPACAANYINT(r4)
49 cmpdi r4,0
50 beqlr
51
52 /*
53 * Handle pending interrupts in interrupt context
54 */
55 li r0,0x5555 24 li r0,0x5555
56 sc 25 sc
57 blr 26 blr
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h
index d40359204aba..c4a1ab608f6f 100644
--- a/include/asm-powerpc/hw_irq.h
+++ b/include/asm-powerpc/hw_irq.h
@@ -7,16 +7,30 @@
7#ifdef __KERNEL__ 7#ifdef __KERNEL__
8 8
9#include <linux/errno.h> 9#include <linux/errno.h>
10#include <linux/compiler.h>
10#include <asm/ptrace.h> 11#include <asm/ptrace.h>
11#include <asm/processor.h> 12#include <asm/processor.h>
12 13
13extern void timer_interrupt(struct pt_regs *); 14extern void timer_interrupt(struct pt_regs *);
14 15
15#ifdef CONFIG_PPC_ISERIES 16#ifdef CONFIG_PPC64
17#include <asm/paca.h>
18
19static inline unsigned long local_get_flags(void)
20{
21 return get_paca()->soft_enabled;
22}
23
24static inline unsigned long local_irq_disable(void)
25{
26 unsigned long flag = get_paca()->soft_enabled;
27 get_paca()->soft_enabled = 0;
28 barrier();
29 return flag;
30}
16 31
17extern unsigned long local_get_flags(void);
18extern unsigned long local_irq_disable(void);
19extern void local_irq_restore(unsigned long); 32extern void local_irq_restore(unsigned long);
33extern void iseries_handle_interrupts(void);
20 34
21#define local_irq_enable() local_irq_restore(1) 35#define local_irq_enable() local_irq_restore(1)
22#define local_save_flags(flags) ((flags) = local_get_flags()) 36#define local_save_flags(flags) ((flags) = local_get_flags())
@@ -24,17 +38,14 @@ extern void local_irq_restore(unsigned long);
24 38
25#define irqs_disabled() (local_get_flags() == 0) 39#define irqs_disabled() (local_get_flags() == 0)
26 40
41#define hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1)
42#define hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1)
43
27#else 44#else
28 45
29#if defined(CONFIG_BOOKE) 46#if defined(CONFIG_BOOKE)
30#define SET_MSR_EE(x) mtmsr(x) 47#define SET_MSR_EE(x) mtmsr(x)
31#define local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") 48#define local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
32#elif defined(__powerpc64__)
33#define SET_MSR_EE(x) __mtmsrd(x, 1)
34#define local_irq_restore(flags) do { \
35 __asm__ __volatile__("": : :"memory"); \
36 __mtmsrd((flags), 1); \
37} while(0)
38#else 49#else
39#define SET_MSR_EE(x) mtmsr(x) 50#define SET_MSR_EE(x) mtmsr(x)
40#define local_irq_restore(flags) mtmsr(flags) 51#define local_irq_restore(flags) mtmsr(flags)
@@ -81,7 +92,7 @@ static inline void local_irq_save_ptr(unsigned long *flags)
81#define local_irq_save(flags) local_irq_save_ptr(&flags) 92#define local_irq_save(flags) local_irq_save_ptr(&flags)
82#define irqs_disabled() ((mfmsr() & MSR_EE) == 0) 93#define irqs_disabled() ((mfmsr() & MSR_EE) == 0)
83 94
84#endif /* CONFIG_PPC_ISERIES */ 95#endif /* CONFIG_PPC64 */
85 96
86#define mask_irq(irq) \ 97#define mask_irq(irq) \
87 ({ \ 98 ({ \
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 0a4e5c93e8e6..0d3adc09c847 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -93,7 +93,8 @@ struct paca_struct {
93 u64 stab_rr; /* stab/slb round-robin counter */ 93 u64 stab_rr; /* stab/slb round-robin counter */
94 u64 saved_r1; /* r1 save for RTAS calls */ 94 u64 saved_r1; /* r1 save for RTAS calls */
95 u64 saved_msr; /* MSR saved here by enter_rtas */ 95 u64 saved_msr; /* MSR saved here by enter_rtas */
96 u8 proc_enabled; /* irq soft-enable flag */ 96 u8 soft_enabled; /* irq soft-enable flag */
97 u8 hard_enabled; /* set if irqs are enabled in MSR */
97 u8 io_sync; /* writel() needs spin_unlock sync */ 98 u8 io_sync; /* writel() needs spin_unlock sync */
98 99
99 /* Stuff for accurate time accounting */ 100 /* Stuff for accurate time accounting */