#define EX_PPR         88      /* SMT thread status register (priority) */
 
 #ifdef CONFIG_RELOCATABLE
-#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                     \
+#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                   \
        ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
        mfspr   r11,SPRN_##h##SRR0;     /* save SRR0 */                 \
        LOAD_HANDLER(r12,label);                                        \
        blr;
 #else
 /* If not relocatable, we can jump directly -- and save messing with LR */
-#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                     \
+#define __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                   \
        mfspr   r11,SPRN_##h##SRR0;     /* save SRR0 */                 \
        mfspr   r12,SPRN_##h##SRR1;     /* and SRR1 */                  \
        li      r10,MSR_RI;                                             \
        mtmsrd  r10,1;                  /* Set RI (EE=0) */             \
        b       label;
 #endif
+#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                     \
+       __EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                    \
 
 /*
  * As EXCEPTION_PROLOG_PSERIES(), except we've already got relocation on
  * case EXCEPTION_RELON_PROLOG_PSERIES_1 will be using lr.
  */
 #define EXCEPTION_RELON_PROLOG_PSERIES(area, label, h, extra, vec)     \
+       EXCEPTION_PROLOG_0(area);                                       \
        EXCEPTION_PROLOG_1(area, extra, vec);                           \
        EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)
 
 END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,0,942)  /*non P7*/              
 
 /*
- * Save PPR in paca whenever some register is available to use.
- * Then increase the priority.
+ * Get an SPR into a register if the CPU has the given feature
  */
-#define HMT_MEDIUM_PPR_SAVE(area, ra)                                  \
+#define OPT_GET_SPR(ra, spr, ftr)                                      \
 BEGIN_FTR_SECTION_NESTED(943)                                          \
-       mfspr   ra,SPRN_PPR;                                            \
-       std     ra,area+EX_PPR(r13);                                    \
-       HMT_MEDIUM;                                                     \
-END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,943) 
+       mfspr   ra,spr;                                                 \
+END_FTR_SECTION_NESTED(ftr,ftr,943)
 
-#define __EXCEPTION_PROLOG_1(area, extra, vec)                         \
+/*
+ * Save a register to the PACA if the CPU has the given feature
+ */
+#define OPT_SAVE_REG_TO_PACA(offset, ra, ftr)                          \
+BEGIN_FTR_SECTION_NESTED(943)                                          \
+       std     ra,offset(r13);                                         \
+END_FTR_SECTION_NESTED(ftr,ftr,943)
+
+#define EXCEPTION_PROLOG_0(area)                                       \
        GET_PACA(r13);                                                  \
        std     r9,area+EX_R9(r13);     /* save r9 */                   \
-       HMT_MEDIUM_PPR_SAVE(area, r9);                                  \
+       OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);                     \
+       HMT_MEDIUM;                                                     \
        std     r10,area+EX_R10(r13);   /* save r10 - r12 */            \
-       BEGIN_FTR_SECTION_NESTED(66);                                   \
-       mfspr   r10,SPRN_CFAR;                                          \
-       std     r10,area+EX_CFAR(r13);                                  \
-       END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66);         \
+       OPT_GET_SPR(r10, SPRN_CFAR, CPU_FTR_CFAR)
+
+#define __EXCEPTION_PROLOG_1(area, extra, vec)                         \
+       OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR);         \
+       OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR);          \
        SAVE_LR(r10, area);                                             \
        mfcr    r9;                                                     \
        extra(vec);                                                     \
        __EXCEPTION_PROLOG_PSERIES_1(label, h)
 
 #define EXCEPTION_PROLOG_PSERIES(area, label, h, extra, vec)           \
+       EXCEPTION_PROLOG_0(area);                                       \
        EXCEPTION_PROLOG_1(area, extra, vec);                           \
        EXCEPTION_PROLOG_PSERIES_1(label, h);
 
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,    \
                                 EXC_STD, KVMTEST_PR, vec)
 
+/* Version of above for when we have to branch out-of-line */
+#define STD_EXCEPTION_PSERIES_OOL(vec, label)                  \
+       .globl label##_pSeries;                                 \
+label##_pSeries:                                               \
+       EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec);        \
+       EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD)
+
 #define STD_EXCEPTION_HV(loc, vec, label)              \
        . = loc;                                        \
        .globl label##_hv;                              \
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,    \
                                 EXC_HV, KVMTEST, vec)
 
+/* Version of above for when we have to branch out-of-line */
+#define STD_EXCEPTION_HV_OOL(vec, label)               \
+       .globl label##_hv;                              \
+label##_hv:                                            \
+       EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec);   \
+       EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV)
+
 #define STD_RELON_EXCEPTION_PSERIES(loc, vec, label)   \
        . = loc;                                        \
        .globl label##_relon_pSeries;                   \
        EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
                                       EXC_STD, KVMTEST_PR, vec)
 
+#define STD_RELON_EXCEPTION_PSERIES_OOL(vec, label)            \
+       .globl label##_relon_pSeries;                           \
+label##_relon_pSeries:                                         \
+       EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec);        \
+       EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_STD)
+
 #define STD_RELON_EXCEPTION_HV(loc, vec, label)                \
        . = loc;                                        \
        .globl label##_relon_hv;                        \
        EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
                                       EXC_HV, KVMTEST, vec)
 
+#define STD_RELON_EXCEPTION_HV_OOL(vec, label)                 \
+       .globl label##_relon_hv;                                \
+label##_relon_hv:                                              \
+       EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec);           \
+       EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_HV)
+
 /* This associate vector numbers with bits in paca->irq_happened */
 #define SOFTEN_VALUE_0x500     PACA_IRQ_EE
 #define SOFTEN_VALUE_0x502     PACA_IRQ_EE
 #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)             \
        HMT_MEDIUM_PPR_DISCARD;                                         \
        SET_SCRATCH0(r13);    /* save r13 */                            \
-       __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec);           \
+       EXCEPTION_PROLOG_0(PACA_EXGEN);                                 \
+       __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec);                   \
        EXCEPTION_PROLOG_PSERIES_1(label##_common, h);
+
 #define _MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)              \
        __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)
 
        _MASKABLE_EXCEPTION_PSERIES(vec, label,                         \
                                    EXC_HV, SOFTEN_TEST_HV)
 
+#define MASKABLE_EXCEPTION_HV_OOL(vec, label)                          \
+       .globl label##_hv;                                              \
+label##_hv:                                                            \
+       EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_HV, vec);            \
+       EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
+
 #define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra)       \
        HMT_MEDIUM_PPR_DISCARD;                                         \
        SET_SCRATCH0(r13);    /* save r13 */                            \
+       EXCEPTION_PROLOG_0(PACA_EXGEN);                                 \
        __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec);           \
        EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, h);
 #define _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra)        \
        _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label,                   \
                                          EXC_HV, SOFTEN_NOTEST_HV)
 
+#define MASKABLE_RELON_EXCEPTION_HV_OOL(vec, label)                    \
+       .globl label##_relon_hv;                                        \
+label##_relon_hv:                                                      \
+       EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_NOTEST_HV, vec);          \
+       EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_HV);
+
 /*
  * Our exception common code can be passed various "additions"
  * to specify the behaviour of interrupts, whether to kick the
 
         * some code path might still want to branch into the original
         * vector
         */
-       b       machine_check_pSeries
+       HMT_MEDIUM_PPR_DISCARD
+       SET_SCRATCH0(r13)               /* save r13 */
+       EXCEPTION_PROLOG_0(PACA_EXMC)
+       b       machine_check_pSeries_0
 
        . = 0x300
        .globl data_access_pSeries
 data_access_slb_pSeries:
        HMT_MEDIUM_PPR_DISCARD
        SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXSLB)
        EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_DAR
 instruction_access_slb_pSeries:
        HMT_MEDIUM_PPR_DISCARD
        SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXSLB)
        EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
         */
        . = 0xe00
 hv_exception_trampoline:
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       h_data_storage_hv
+
        . = 0xe20
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       h_instr_storage_hv
+
        . = 0xe40
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       emulation_assist_hv
-       . = 0xe50
-       b       hmi_exception_hv
+
        . = 0xe60
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       hmi_exception_hv
+
        . = 0xe80
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       h_doorbell_hv
 
        /* We need to deal with the Altivec unavailable exception
         */
 performance_monitor_pSeries_1:
        . = 0xf00
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       performance_monitor_pSeries
 
 altivec_unavailable_pSeries_1:
        . = 0xf20
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       altivec_unavailable_pSeries
 
 vsx_unavailable_pSeries_1:
        . = 0xf40
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       vsx_unavailable_pSeries
 
 #ifdef CONFIG_CBE_RAS
 denorm_exception_hv:
        HMT_MEDIUM_PPR_DISCARD
        mtspr   SPRN_SPRG_HSCRATCH0,r13
-       mfspr   r13,SPRN_SPRG_HPACA
-       std     r9,PACA_EXGEN+EX_R9(r13)
-       HMT_MEDIUM_PPR_SAVE(PACA_EXGEN, r9)
-       std     r10,PACA_EXGEN+EX_R10(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        std     r11,PACA_EXGEN+EX_R11(r13)
        std     r12,PACA_EXGEN+EX_R12(r13)
        mfspr   r9,SPRN_SPRG_HSCRATCH0
 machine_check_fwnmi:
        HMT_MEDIUM_PPR_DISCARD
        SET_SCRATCH0(r13)               /* save r13 */
-       EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common,
-                                EXC_STD, KVMTEST, 0x200)
+       EXCEPTION_PROLOG_0(PACA_EXMC)
+machine_check_pSeries_0:
+       EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST, 0x200)
+       EXCEPTION_PROLOG_PSERIES_1(machine_check_common, EXC_STD)
        KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
 
        /* moved from 0x300 */
 
        .align  7
        /* moved from 0xe00 */
-       STD_EXCEPTION_HV(., 0xe02, h_data_storage)
+       STD_EXCEPTION_HV_OOL(0xe02, h_data_storage)
        KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02)
-       STD_EXCEPTION_HV(., 0xe22, h_instr_storage)
+       STD_EXCEPTION_HV_OOL(0xe22, h_instr_storage)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22)
-       STD_EXCEPTION_HV(., 0xe42, emulation_assist)
+       STD_EXCEPTION_HV_OOL(0xe42, emulation_assist)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42)
-       STD_EXCEPTION_HV(., 0xe62, hmi_exception) /* need to flush cache ? */
+       STD_EXCEPTION_HV_OOL(0xe62, hmi_exception) /* need to flush cache ? */
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62)
-       MASKABLE_EXCEPTION_HV(., 0xe82, h_doorbell)
+       MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82)
 
        /* moved from 0xf00 */
-       STD_EXCEPTION_PSERIES(., 0xf00, performance_monitor)
+       STD_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
        KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf00)
-       STD_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable)
+       STD_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
        KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf20)
-       STD_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
+       STD_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
        KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
 
 /*
        . = 0x4380
        .globl data_access_slb_relon_pSeries
 data_access_slb_relon_pSeries:
-       HMT_MEDIUM_PPR_DISCARD
        SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXSLB)
        EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_DAR
        . = 0x4480
        .globl instruction_access_slb_relon_pSeries
 instruction_access_slb_relon_pSeries:
-       HMT_MEDIUM_PPR_DISCARD
        SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXSLB)
        EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
        STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step)
 
        . = 0x4e00
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       h_data_storage_relon_hv
 
        . = 0x4e20
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       h_instr_storage_relon_hv
 
        . = 0x4e40
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       emulation_assist_relon_hv
 
-       . = 0x4e50
-       b       hmi_exception_relon_hv
-
        . = 0x4e60
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       hmi_exception_relon_hv
 
        . = 0x4e80
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       h_doorbell_relon_hv
 
 performance_monitor_relon_pSeries_1:
        . = 0x4f00
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       performance_monitor_relon_pSeries
 
 altivec_unavailable_relon_pSeries_1:
        . = 0x4f20
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       altivec_unavailable_relon_pSeries
 
 vsx_unavailable_relon_pSeries_1:
        . = 0x4f40
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_0(PACA_EXGEN)
        b       vsx_unavailable_relon_pSeries
 
        STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint)
 __end_handlers:
 
        /* Equivalents to the above handlers for relocation-on interrupt vectors */
-       STD_RELON_EXCEPTION_HV(., 0xe00, h_data_storage)
+       STD_RELON_EXCEPTION_HV_OOL(0xe00, h_data_storage)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe00)
-       STD_RELON_EXCEPTION_HV(., 0xe20, h_instr_storage)
+       STD_RELON_EXCEPTION_HV_OOL(0xe20, h_instr_storage)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe20)
-       STD_RELON_EXCEPTION_HV(., 0xe40, emulation_assist)
+       STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe40)
-       STD_RELON_EXCEPTION_HV(., 0xe60, hmi_exception)
+       STD_RELON_EXCEPTION_HV_OOL(0xe60, hmi_exception)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe60)
-       MASKABLE_RELON_EXCEPTION_HV(., 0xe80, h_doorbell)
+       MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell)
        KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe80)
 
-       STD_RELON_EXCEPTION_PSERIES(., 0xf00, performance_monitor)
-       STD_RELON_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable)
-       STD_RELON_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
+       STD_RELON_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
+       STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
+       STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
 
 #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
 /*