aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-02-04 13:10:15 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-02-15 00:54:30 -0500
commit1707dd161349e6c54170c88d94fed012e3d224e3 (patch)
tree307d40e25c468d57089517691f7c94cbd72282ae
parent6100209bf6632d908ebcdab339a83f2e083b94e7 (diff)
powerpc: Save CFAR before branching in interrupt entry paths
Some of the interrupt vectors on 64-bit POWER server processors are only 32 bytes long, which is not enough for the full first-level interrupt handler. For these we currently just have a branch to an out-of-line handler. However, this means that we corrupt the CFAR (come-from address register) on POWER7 and later processors. To fix this, we split the EXCEPTION_PROLOG_1 macro into two pieces: EXCEPTION_PROLOG_0 contains the part up to the point where the CFAR is saved in the PACA, and EXCEPTION_PROLOG_1 contains the rest. We then put EXCEPTION_PROLOG_0 in the short interrupt vectors before we branch to the out-of-line handler, which contains the rest of the first-level interrupt handler. To facilitate this, we define new _OOL (out of line) variants of STD_EXCEPTION_PSERIES, etc. In order to get EXCEPTION_PROLOG_0 to be short enough, i.e., no more than 6 instructions, it was necessary to move the stores that move the PPR and CFAR values into the PACA into __EXCEPTION_PROLOG_1 and to get rid of one of the two HMT_MEDIUM instructions. Previously there was a HMT_MEDIUM_PPR_DISCARD before the prolog, which was nop'd out on processors with the PPR (POWER7 and later), and then another HMT_MEDIUM inside the HMT_MEDIUM_PPR_SAVE macro call inside __EXCEPTION_PROLOG_1, which was nop'd out on processors without PPR. Now the HMT_MEDIUM inside EXCEPTION_PROLOG_0 is there unconditionally and the HMT_MEDIUM_PPR_DISCARD is not strictly necessary, although this leaves it in for the interrupt vectors where there is room for it. Previously we had a handler for hypervisor maintenance interrupts at 0xe50, which doesn't leave enough room for the vector for hypervisor emulation assist interrupts at 0xe40, since we need 8 instructions. The 0xe50 vector was only used on POWER6, as the HMI vector was moved to 0xe60 on POWER7. Since we don't support running in hypervisor mode on POWER6, we just remove the handler at 0xe50. This also changes denorm_exception_hv to use EXCEPTION_PROLOG_0 instead of open-coding it, and removes the HMT_MEDIUM_PPR_DISCARD from the relocation-on vectors (since any CPU that supports relocation-on interrupts also has the PPR). Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/exception-64s.h84
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S95
2 files changed, 133 insertions, 46 deletions
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 370298a0bca3..4dfc51588be5 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -50,7 +50,7 @@
50#define EX_PPR 88 /* SMT thread status register (priority) */ 50#define EX_PPR 88 /* SMT thread status register (priority) */
51 51
52#ifdef CONFIG_RELOCATABLE 52#ifdef CONFIG_RELOCATABLE
53#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \ 53#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
54 ld r12,PACAKBASE(r13); /* get high part of &label */ \ 54 ld r12,PACAKBASE(r13); /* get high part of &label */ \
55 mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ 55 mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
56 LOAD_HANDLER(r12,label); \ 56 LOAD_HANDLER(r12,label); \
@@ -61,13 +61,15 @@
61 blr; 61 blr;
62#else 62#else
63/* If not relocatable, we can jump directly -- and save messing with LR */ 63/* If not relocatable, we can jump directly -- and save messing with LR */
64#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \ 64#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
65 mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ 65 mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
66 mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \ 66 mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \
67 li r10,MSR_RI; \ 67 li r10,MSR_RI; \
68 mtmsrd r10,1; /* Set RI (EE=0) */ \ 68 mtmsrd r10,1; /* Set RI (EE=0) */ \
69 b label; 69 b label;
70#endif 70#endif
71#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
72 __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) \
71 73
72/* 74/*
73 * As EXCEPTION_PROLOG_PSERIES(), except we've already got relocation on 75 * As EXCEPTION_PROLOG_PSERIES(), except we've already got relocation on
@@ -75,6 +77,7 @@
75 * case EXCEPTION_RELON_PROLOG_PSERIES_1 will be using lr. 77 * case EXCEPTION_RELON_PROLOG_PSERIES_1 will be using lr.
76 */ 78 */
77#define EXCEPTION_RELON_PROLOG_PSERIES(area, label, h, extra, vec) \ 79#define EXCEPTION_RELON_PROLOG_PSERIES(area, label, h, extra, vec) \
80 EXCEPTION_PROLOG_0(area); \
78 EXCEPTION_PROLOG_1(area, extra, vec); \ 81 EXCEPTION_PROLOG_1(area, extra, vec); \
79 EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) 82 EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)
80 83
@@ -135,25 +138,32 @@ BEGIN_FTR_SECTION_NESTED(942) \
135END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,0,942) /*non P7*/ 138END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,0,942) /*non P7*/
136 139
137/* 140/*
138 * Save PPR in paca whenever some register is available to use. 141 * Get an SPR into a register if the CPU has the given feature
139 * Then increase the priority.
140 */ 142 */
141#define HMT_MEDIUM_PPR_SAVE(area, ra) \ 143#define OPT_GET_SPR(ra, spr, ftr) \
142BEGIN_FTR_SECTION_NESTED(943) \ 144BEGIN_FTR_SECTION_NESTED(943) \
143 mfspr ra,SPRN_PPR; \ 145 mfspr ra,spr; \
144 std ra,area+EX_PPR(r13); \ 146END_FTR_SECTION_NESTED(ftr,ftr,943)
145 HMT_MEDIUM; \
146END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,943)
147 147
148#define __EXCEPTION_PROLOG_1(area, extra, vec) \ 148/*
149 * Save a register to the PACA if the CPU has the given feature
150 */
151#define OPT_SAVE_REG_TO_PACA(offset, ra, ftr) \
152BEGIN_FTR_SECTION_NESTED(943) \
153 std ra,offset(r13); \
154END_FTR_SECTION_NESTED(ftr,ftr,943)
155
156#define EXCEPTION_PROLOG_0(area) \
149 GET_PACA(r13); \ 157 GET_PACA(r13); \
150 std r9,area+EX_R9(r13); /* save r9 */ \ 158 std r9,area+EX_R9(r13); /* save r9 */ \
151 HMT_MEDIUM_PPR_SAVE(area, r9); \ 159 OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR); \
160 HMT_MEDIUM; \
152 std r10,area+EX_R10(r13); /* save r10 - r12 */ \ 161 std r10,area+EX_R10(r13); /* save r10 - r12 */ \
153 BEGIN_FTR_SECTION_NESTED(66); \ 162 OPT_GET_SPR(r10, SPRN_CFAR, CPU_FTR_CFAR)
154 mfspr r10,SPRN_CFAR; \ 163
155 std r10,area+EX_CFAR(r13); \ 164#define __EXCEPTION_PROLOG_1(area, extra, vec) \
156 END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \ 165 OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR); \
166 OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR); \
157 SAVE_LR(r10, area); \ 167 SAVE_LR(r10, area); \
158 mfcr r9; \ 168 mfcr r9; \
159 extra(vec); \ 169 extra(vec); \
@@ -178,6 +188,7 @@ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,943)
178 __EXCEPTION_PROLOG_PSERIES_1(label, h) 188 __EXCEPTION_PROLOG_PSERIES_1(label, h)
179 189
180#define EXCEPTION_PROLOG_PSERIES(area, label, h, extra, vec) \ 190#define EXCEPTION_PROLOG_PSERIES(area, label, h, extra, vec) \
191 EXCEPTION_PROLOG_0(area); \
181 EXCEPTION_PROLOG_1(area, extra, vec); \ 192 EXCEPTION_PROLOG_1(area, extra, vec); \
182 EXCEPTION_PROLOG_PSERIES_1(label, h); 193 EXCEPTION_PROLOG_PSERIES_1(label, h);
183 194
@@ -312,6 +323,13 @@ label##_pSeries: \
312 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ 323 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
313 EXC_STD, KVMTEST_PR, vec) 324 EXC_STD, KVMTEST_PR, vec)
314 325
326/* Version of above for when we have to branch out-of-line */
327#define STD_EXCEPTION_PSERIES_OOL(vec, label) \
328 .globl label##_pSeries; \
329label##_pSeries: \
330 EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \
331 EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD)
332
315#define STD_EXCEPTION_HV(loc, vec, label) \ 333#define STD_EXCEPTION_HV(loc, vec, label) \
316 . = loc; \ 334 . = loc; \
317 .globl label##_hv; \ 335 .globl label##_hv; \
@@ -321,6 +339,13 @@ label##_hv: \
321 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ 339 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
322 EXC_HV, KVMTEST, vec) 340 EXC_HV, KVMTEST, vec)
323 341
342/* Version of above for when we have to branch out-of-line */
343#define STD_EXCEPTION_HV_OOL(vec, label) \
344 .globl label##_hv; \
345label##_hv: \
346 EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \
347 EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV)
348
324#define STD_RELON_EXCEPTION_PSERIES(loc, vec, label) \ 349#define STD_RELON_EXCEPTION_PSERIES(loc, vec, label) \
325 . = loc; \ 350 . = loc; \
326 .globl label##_relon_pSeries; \ 351 .globl label##_relon_pSeries; \
@@ -331,6 +356,12 @@ label##_relon_pSeries: \
331 EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ 356 EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
332 EXC_STD, KVMTEST_PR, vec) 357 EXC_STD, KVMTEST_PR, vec)
333 358
359#define STD_RELON_EXCEPTION_PSERIES_OOL(vec, label) \
360 .globl label##_relon_pSeries; \
361label##_relon_pSeries: \
362 EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \
363 EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_STD)
364
334#define STD_RELON_EXCEPTION_HV(loc, vec, label) \ 365#define STD_RELON_EXCEPTION_HV(loc, vec, label) \
335 . = loc; \ 366 . = loc; \
336 .globl label##_relon_hv; \ 367 .globl label##_relon_hv; \
@@ -341,6 +372,12 @@ label##_relon_hv: \
341 EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ 372 EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
342 EXC_HV, KVMTEST, vec) 373 EXC_HV, KVMTEST, vec)
343 374
375#define STD_RELON_EXCEPTION_HV_OOL(vec, label) \
376 .globl label##_relon_hv; \
377label##_relon_hv: \
378 EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \