From d8bced27be25537bde3714cbdb34ccece81f6a0d Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Tue, 6 Sep 2016 15:32:42 +1000 Subject: powerpc/fadump: Set core e_flags using kernel's ELF ABI version Firmware Assisted Dump is a facility to dump kernel core with assistance from firmware. As part of this process the kernel ELF ABI version is stored in the core file. Currently fadump.h defines this to 0 if it is not already defined. This clashes with a define in elf.h which sets it based on the current task - not based on the kernel's ELF ABI version. Use the compiler-provided #define _CALL_ELF which tells us the ELF ABI version of the kernel to set e_flags, this matches what binutils does. Remove the definition in fadump.h, which becomes unused. Signed-off-by: Daniel Axtens Reviewed-by: Mahesh Salgaonkar Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/fadump.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index b4407d0add27..0031806475f0 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -45,10 +45,6 @@ #define memblock_num_regions(memblock_type) (memblock.memblock_type.cnt) -#ifndef ELF_CORE_EFLAGS -#define ELF_CORE_EFLAGS 0 -#endif - /* Firmware provided dump sections */ #define FADUMP_CPU_STATE_DATA 0x0001 #define FADUMP_HPTE_REGION 0x0002 -- cgit v1.2.3 From 0545d5436aefddff7ca417adc1a431c108403a35 Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Tue, 6 Sep 2016 15:32:43 +1000 Subject: powerpc/sparse: Add more assembler prototypes Another set of things that are only called from assembler and so need prototypes to keep sparse happy. Signed-off-by: Daniel Axtens Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 37 +++++++++++++++++++++++++++++++ arch/powerpc/kernel/irq.c | 1 + arch/powerpc/kernel/process.c | 1 + arch/powerpc/kernel/prom_init.c | 1 + arch/powerpc/kernel/ptrace.c | 1 + arch/powerpc/kernel/signal_32.c | 1 + arch/powerpc/kernel/signal_64.c | 1 + arch/powerpc/kernel/syscalls.c | 1 + arch/powerpc/kernel/time.c | 1 + 9 files changed, 45 insertions(+) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index e71b9097594c..a5b239948bfb 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -15,6 +15,8 @@ #include #include +#include + /* SMP */ extern struct thread_info *current_set[NR_CPUS]; extern struct thread_info *secondary_ti; @@ -72,4 +74,39 @@ void system_reset_exception(struct pt_regs *regs); void machine_check_exception(struct pt_regs *regs); void __kprobes emulation_assist_interrupt(struct pt_regs *regs); +/* signals, syscalls and interrupts */ +#ifdef CONFIG_PPC64 +int sys_swapcontext(struct ucontext __user *old_ctx, + struct ucontext __user *new_ctx, + long ctx_size, long r6, long r7, long r8, struct pt_regs *regs); +#else +long sys_swapcontext(struct ucontext __user *old_ctx, + struct ucontext __user *new_ctx, + int ctx_size, int r6, int r7, int r8, struct pt_regs *regs); +#endif +long sys_switch_endian(void); +notrace unsigned int __check_irq_replay(void); +void notrace restore_interrupts(void); + +/* ptrace */ +long do_syscall_trace_enter(struct pt_regs *regs); +void do_syscall_trace_leave(struct pt_regs *regs); + +/* process */ +void restore_math(struct pt_regs *regs); +void restore_tm_state(struct pt_regs *regs); + +/* prom_init (OpenFirmware) */ +unsigned long __init prom_init(unsigned long r3, unsigned long r4, + unsigned long pp, + unsigned long r6, unsigned long r7, + unsigned long kbase); + +/* setup */ +void __init early_setup(unsigned long dt_ptr); +void early_setup_secondary(void); + +/* time */ +void accumulate_stolen_time(void); + #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 08887cf2b20e..9594ac8e7090 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -67,6 +67,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 9ee2623e0f67..ce8a26a0c947 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index d3eff99e938c..d05a2884ffb9 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -42,6 +42,7 @@ #include #include #include +#include #include diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index bf91658a8a40..2299bf60780d 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -39,6 +39,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index a7daf749b97f..6856276a91cc 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include "ppc32.h" #include diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 70409bb90a95..f08c9196f209 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "signal.h" diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 5fa92706444b..644cce3d8dce 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -40,6 +40,7 @@ #include #include #include +#include static inline unsigned long do_mmap2(unsigned long addr, size_t len, unsigned long prot, unsigned long flags, diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 3efbedefba6a..67859b7d1c97 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -73,6 +73,7 @@ #include #include #include +#include /* powerpc clocksource/clockevent code */ -- cgit v1.2.3 From 27510235dd2bb1ab01d27b01f0b6180eb47aa003 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 26 Jul 2016 15:29:29 +1000 Subject: powerpc/64: Correct comment on LOAD_HANDLER() The comment for LOAD_HANDLER() was wrong. The part about kdump has not been true since 1f6a93e4c35e ("powerpc: Make it possible to move the interrupt handlers away from the kernel"). Describe how it currently works, and combine the two separate comments into one. Signed-off-by: Michael Ellerman Reviewed-by: Nick Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/exception-64s.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index bed66e5743b3..1a9afded909f 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -84,12 +84,12 @@ /* * We're short on space and time in the exception prolog, so we can't - * use the normal SET_REG_IMMEDIATE macro. Normally we just need the - * low halfword of the address, but for Kdump we need the whole low - * word. + * use the normal LOAD_REG_IMMEDIATE macro to load the address of label. + * Instead we get the base of the kernel from paca->kernelbase and or in the low + * part of label. This requires that the label be within 64KB of kernelbase, and + * that kernelbase be 64K aligned. */ #define LOAD_HANDLER(reg, label) \ - /* Handlers must be within 64K of kbase, which must be 64k aligned */ \ ori reg,reg,(label)-_stext; /* virt addr of handler ... */ /* Exception register prefixes */ -- cgit v1.2.3 From d8d42b0511fefc78165ee9b4c2d95f5d6db7350d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 26 Jul 2016 15:29:30 +1000 Subject: powerpc/64: Do load of PACAKBASE in LOAD_HANDLER The LOAD_HANDLER macro requires that you have previously loaded "reg" with PACAKBASE. Although that gives callers flexibility to get PACAKBASE in some interesting way, none of the callers actually do that. So fold the load of PACAKBASE into the macro, making it simpler for callers to use correctly. Signed-off-by: Michael Ellerman Reviewed-by: Nick Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/exception-64s.h | 3 +-- arch/powerpc/kernel/exceptions-64s.S | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 1a9afded909f..c2606715cfff 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -52,7 +52,6 @@ #ifdef CONFIG_RELOCATABLE #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); \ mtctr r12; \ @@ -90,6 +89,7 @@ * that kernelbase be 64K aligned. */ #define LOAD_HANDLER(reg, label) \ + ld reg,PACAKBASE(r13); /* get high part of &label */ \ ori reg,reg,(label)-_stext; /* virt addr of handler ... */ /* Exception register prefixes */ @@ -175,7 +175,6 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) __EXCEPTION_PROLOG_1(area, extra, vec) #define __EXCEPTION_PROLOG_PSERIES_1(label, h) \ - ld r12,PACAKBASE(r13); /* get high part of &label */ \ ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \ mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \ LOAD_HANDLER(r12,label) \ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 0a6a683190af..21ab5dd54e1e 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -41,7 +41,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ #define SYSCALL_PSERIES_2_RFID \ mfspr r12,SPRN_SRR1 ; \ - ld r10,PACAKBASE(r13) ; \ LOAD_HANDLER(r10, system_call_entry) ; \ mtspr SPRN_SRR0,r10 ; \ ld r10,PACAKMSR(r13) ; \ @@ -64,7 +63,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ */ #define SYSCALL_PSERIES_2_DIRECT \ mflr r10 ; \ - ld r12,PACAKBASE(r13) ; \ LOAD_HANDLER(r12, system_call_entry) ; \ mtctr r12 ; \ mfspr r12,SPRN_SRR1 ; \ @@ -185,7 +183,6 @@ data_access_slb_pSeries: * the kernel ends up being put. */ mfctr r11 - ld r10,PACAKBASE(r13) LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr @@ -207,7 +204,6 @@ instruction_access_slb_pSeries: b slb_miss_realmode #else mfctr r11 - ld r10,PACAKBASE(r13) LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr @@ -459,7 +455,6 @@ BEGIN_FTR_SECTION mfmsr r11 /* get MSR value */ ori r11,r11,MSR_ME /* turn on ME bit */ ori r11,r11,MSR_RI /* turn on RI bit */ - ld r12,PACAKBASE(r13) /* get high part of &label */ LOAD_HANDLER(r12, machine_check_handle_early) 1: mtspr SPRN_SRR0,r12 mtspr SPRN_SRR1,r11 @@ -472,7 +467,6 @@ BEGIN_FTR_SECTION */ addi r1,r1,INT_FRAME_SIZE /* go back to previous stack frame */ ld r11,PACAKMSR(r13) - ld r12,PACAKBASE(r13) LOAD_HANDLER(r12, unrecover_mce) li r10,MSR_ME andc r11,r11,r10 /* Turn off MSR_ME */ @@ -493,7 +487,6 @@ machine_check_pSeries_0: * used, so nested machine check corrupts it. machine_check_common * enables MSR_RI. */ - ld r12,PACAKBASE(r13) ld r10,PACAKMSR(r13) xori r10,r10,MSR_RI mfspr r11,SPRN_SRR0 @@ -795,7 +788,6 @@ data_access_slb_relon_pSeries: * the kernel ends up being put. */ mfctr r11 - ld r10,PACAKBASE(r13) LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr @@ -816,7 +808,6 @@ instruction_access_slb_relon_pSeries: b slb_miss_realmode #else mfctr r11 - ld r10,PACAKBASE(r13) LOAD_HANDLER(r10, slb_miss_realmode) mtctr r10 bctr @@ -1357,7 +1348,6 @@ machine_check_handle_early: andi. r11,r12,MSR_RI bne 2f 1: mfspr r11,SPRN_SRR0 - ld r10,PACAKBASE(r13) LOAD_HANDLER(r10,unrecover_mce) mtspr SPRN_SRR0,r10 ld r10,PACAKMSR(r13) @@ -1461,7 +1451,6 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) b . /* prevent speculative execution */ 2: mfspr r11,SPRN_SRR0 - ld r10,PACAKBASE(r13) LOAD_HANDLER(r10,unrecov_slb) mtspr SPRN_SRR0,r10 ld r10,PACAKMSR(r13) @@ -1478,7 +1467,6 @@ unrecov_slb: b 1b 8: mfspr r11,SPRN_SRR0 - ld r10,PACAKBASE(r13) LOAD_HANDLER(r10,bad_addr_slb) mtspr SPRN_SRR0,r10 ld r10,PACAKMSR(r13) -- cgit v1.2.3 From 7dccfbc325bb59f94521d544a8ae12148622b4f2 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 24 Aug 2016 15:03:36 +0530 Subject: powerpc/book3s: Add a cpu table entry for different POWER9 revs Signed-off-by: Aneesh Kumar K.V Acked-by: Michael Neuling Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/cputable.h | 4 +++- arch/powerpc/kernel/cputable.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 82026b419341..f752e6f7cfbe 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -212,6 +212,7 @@ enum { #define CPU_FTR_DABRX LONG_ASM_CONST(0x0800000000000000) #define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x1000000000000000) #define CPU_FTR_SUBCORE LONG_ASM_CONST(0x2000000000000000) +#define CPU_FTR_POWER9_DD1 LONG_ASM_CONST(0x4000000000000000) #ifndef __ASSEMBLY__ @@ -472,6 +473,7 @@ enum { CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \ CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \ CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300) +#define CPU_FTRS_POWER9_DD1 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ @@ -490,7 +492,7 @@ enum { (CPU_FTRS_POWER4 | CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | \ CPU_FTRS_POWER6 | CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | \ CPU_FTRS_POWER8 | CPU_FTRS_POWER8_DD1 | CPU_FTRS_CELL | \ - CPU_FTRS_PA6T | CPU_FTR_VSX | CPU_FTRS_POWER9) + CPU_FTRS_PA6T | CPU_FTR_VSX | CPU_FTRS_POWER9 | CPU_FTRS_POWER9_DD1) #endif #else enum { diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 74248ab18e98..6c4646ac9234 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -506,6 +506,25 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, + { /* Power9 DD1*/ + .pvr_mask = 0xffffff00, + .pvr_value = 0x004e0100, + .cpu_name = "POWER9 (raw)", + .cpu_features = CPU_FTRS_POWER9_DD1, + .cpu_user_features = COMMON_USER_POWER9, + .cpu_user_features2 = COMMON_USER2_POWER9, + .mmu_features = MMU_FTRS_POWER9, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, + .oprofile_cpu_type = "ppc64/power9", + .oprofile_type = PPC_OPROFILE_INVALID, + .cpu_setup = __setup_cpu_power9, + .cpu_restore = __restore_cpu_power9, + .flush_tlb = __flush_tlb_power9, + .platform = "power9", + }, { /* Power9 */ .pvr_mask = 0xffff0000, .pvr_value = 0x004e0000, -- cgit v1.2.3 From 694c4951922d114e789f669deb409b2aef440ae9 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 24 Aug 2016 15:03:37 +0530 Subject: powerpc/mm/radix: Use different RTS encoding for different POWER9 revs POWER9 DD1 uses RTS - 28 for the RTS value but other revisions use RTS - 31. This makes this distinction for the different revisions Signed-off-by: Aneesh Kumar K.V Acked-by: Michael Neuling Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/radix.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h index df294224e280..a2fe8fbfbd3d 100644 --- a/arch/powerpc/include/asm/book3s/64/radix.h +++ b/arch/powerpc/include/asm/book3s/64/radix.h @@ -233,14 +233,19 @@ static inline unsigned long radix__get_tree_size(void) { unsigned long rts_field; /* - * we support 52 bits, hence 52-31 = 21, 0b10101 + * We support 52 bits, hence: + * DD1 52-28 = 24, 0b11000 + * Others 52-31 = 21, 0b10101 * RTS encoding details * bits 0 - 3 of rts -> bits 6 - 8 unsigned long * bits 4 - 5 of rts -> bits 62 - 63 of unsigned long */ - rts_field = (0x5UL << 5); /* 6 - 8 bits */ - rts_field |= (0x2UL << 61); - + if (cpu_has_feature(CPU_FTR_POWER9_DD1)) + rts_field = (0x3UL << 61); + else { + rts_field = (0x5UL << 5); /* 6 - 8 bits */ + rts_field |= (0x2UL << 61); + } return rts_field; } #endif /* __ASSEMBLY__ */ -- cgit v1.2.3 From c6d1a767b9eaa74f0969378ec47791ff8318a65c Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 24 Aug 2016 15:03:38 +0530 Subject: powerpc/mm/radix: Use different pte update sequence for different POWER9 revs POWER9 DD1 requires pte to be marked invalid (V=0) before updating it with the new value. This makes this distinction for the different revisions. Signed-off-by: Aneesh Kumar K.V Acked-by: Michael Neuling Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/32/pgtable.h | 3 +- arch/powerpc/include/asm/book3s/64/pgtable.h | 5 +- arch/powerpc/include/asm/book3s/64/radix.h | 75 ++++++++++++++++++++++------ arch/powerpc/include/asm/nohash/32/pgtable.h | 3 +- arch/powerpc/include/asm/nohash/64/pgtable.h | 3 +- arch/powerpc/mm/pgtable-book3s64.c | 2 +- arch/powerpc/mm/pgtable.c | 2 +- 7 files changed, 71 insertions(+), 22 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h index 38b33dcfcc9d..6b8b2d57fdc8 100644 --- a/arch/powerpc/include/asm/book3s/32/pgtable.h +++ b/arch/powerpc/include/asm/book3s/32/pgtable.h @@ -223,7 +223,8 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, } -static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) +static inline void __ptep_set_access_flags(struct mm_struct *mm, + pte_t *ptep, pte_t entry) { unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 263bf39ced40..8ec8be9495ba 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -565,10 +565,11 @@ static inline bool check_pte_access(unsigned long access, unsigned long ptev) * Generic functions with hash/radix callbacks */ -static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) +static inline void __ptep_set_access_flags(struct mm_struct *mm, + pte_t *ptep, pte_t entry) { if (radix_enabled()) - return radix__ptep_set_access_flags(ptep, entry); + return radix__ptep_set_access_flags(mm, ptep, entry); return hash__ptep_set_access_flags(ptep, entry); } diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h index a2fe8fbfbd3d..2a46dea8e1b1 100644 --- a/arch/powerpc/include/asm/book3s/64/radix.h +++ b/arch/powerpc/include/asm/book3s/64/radix.h @@ -11,6 +11,11 @@ #include #endif +#ifndef __ASSEMBLY__ +#include +#include +#endif + /* An empty PTE can still have a R or C writeback */ #define RADIX_PTE_NONE_MASK (_PAGE_DIRTY | _PAGE_ACCESSED) @@ -105,11 +110,8 @@ #define RADIX_PUD_TABLE_SIZE (sizeof(pud_t) << RADIX_PUD_INDEX_SIZE) #define RADIX_PGD_TABLE_SIZE (sizeof(pgd_t) << RADIX_PGD_INDEX_SIZE) -static inline unsigned long radix__pte_update(struct mm_struct *mm, - unsigned long addr, - pte_t *ptep, unsigned long clr, - unsigned long set, - int huge) +static inline unsigned long __radix_pte_update(pte_t *ptep, unsigned long clr, + unsigned long set) { pte_t pte; unsigned long old_pte, new_pte; @@ -121,9 +123,39 @@ static inline unsigned long radix__pte_update(struct mm_struct *mm, } while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte))); - /* We already do a sync in cmpxchg, is ptesync needed ?*/ + return old_pte; +} + + +static inline unsigned long radix__pte_update(struct mm_struct *mm, + unsigned long addr, + pte_t *ptep, unsigned long clr, + unsigned long set, + int huge) +{ + unsigned long old_pte; + + if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { + + unsigned long new_pte; + + old_pte = __radix_pte_update(ptep, ~0, 0); + asm volatile("ptesync" : : : "memory"); + /* + * new value of pte + */ + new_pte = (old_pte | set) & ~clr; + + /* + * For now let's do heavy pid flush + * radix__flush_tlb_page_psize(mm, addr, mmu_virtual_psize); + */ + radix__flush_tlb_mm(mm); + + __radix_pte_update(ptep, 0, new_pte); + } else + old_pte = __radix_pte_update(ptep, clr, set); asm volatile("ptesync" : : : "memory"); - /* huge pages use the old page table lock */ if (!huge) assert_pte_locked(mm, addr); @@ -134,20 +166,33 @@ static inline unsigned long radix__pte_update(struct mm_struct *mm, * Set the dirty and/or accessed bits atomically in a linux PTE, this * function doesn't need to invalidate tlb. */ -static inline void radix__ptep_set_access_flags(pte_t *ptep, pte_t entry) +static inline void radix__ptep_set_access_flags(struct mm_struct *mm, + pte_t *ptep, pte_t entry) { - pte_t pte; - unsigned long old_pte, new_pte; + unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); - do { - pte = READ_ONCE(*ptep); - old_pte = pte_val(pte); + + if (cpu_has_feature(CPU_FTR_POWER9_DD1)) { + + unsigned long old_pte, new_pte; + + old_pte = __radix_pte_update(ptep, ~0, 0); + asm volatile("ptesync" : : : "memory"); + /* + * new value of pte + */ new_pte = old_pte | set; - } while (!pte_xchg(ptep, __pte(old_pte), __pte(new_pte))); + /* + * For now let's do heavy pid flush + * radix__flush_tlb_page_psize(mm, addr, mmu_virtual_psize); + */ + radix__flush_tlb_mm(mm); - /* We already do a sync in cmpxchg, is ptesync needed ?*/ + __radix_pte_update(ptep, 0, new_pte); + } else + __radix_pte_update(ptep, 0, set); asm volatile("ptesync" : : : "memory"); } diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h index 780847597514..c219ef7be53b 100644 --- a/arch/powerpc/include/asm/nohash/32/pgtable.h +++ b/arch/powerpc/include/asm/nohash/32/pgtable.h @@ -267,7 +267,8 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, } -static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) +static inline void __ptep_set_access_flags(struct mm_struct *mm, + pte_t *ptep, pte_t entry) { unsigned long set = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); diff --git a/arch/powerpc/include/asm/nohash/64/pgtable.h b/arch/powerpc/include/asm/nohash/64/pgtable.h index d4d808cf905e..653a1838469d 100644 --- a/arch/powerpc/include/asm/nohash/64/pgtable.h +++ b/arch/powerpc/include/asm/nohash/64/pgtable.h @@ -300,7 +300,8 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, /* Set the dirty and/or accessed bits atomically in a linux PTE, this * function doesn't need to flush the hash entry */ -static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) +static inline void __ptep_set_access_flags(struct mm_struct *mm, + pte_t *ptep, pte_t entry) { unsigned long bits = pte_val(entry) & (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC); diff --git a/arch/powerpc/mm/pgtable-book3s64.c b/arch/powerpc/mm/pgtable-book3s64.c index 34079302cc17..7328886bca4c 100644 --- a/arch/powerpc/mm/pgtable-book3s64.c +++ b/arch/powerpc/mm/pgtable-book3s64.c @@ -35,7 +35,7 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address, #endif changed = !pmd_same(*(pmdp), entry); if (changed) { - __ptep_set_access_flags(pmdp_ptep(pmdp), pmd_pte(entry)); + __ptep_set_access_flags(vma->vm_mm, pmdp_ptep(pmdp), pmd_pte(entry)); flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); } return changed; diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 0b6fb244d0a1..911fdfb63ec1 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -224,7 +224,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, if (changed) { if (!is_vm_hugetlb_page(vma)) assert_pte_locked(vma->vm_mm, address); - __ptep_set_access_flags(ptep, entry); + __ptep_set_access_flags(vma->vm_mm, ptep, entry); flush_tlb_page(vma, address); } return changed; -- cgit v1.2.3 From ad410674f5606a53ea2f2d45a78448a95e271fa0 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 24 Aug 2016 15:03:39 +0530 Subject: powerpc/mm: Update the HID bit when switching from radix to hash Power9 DD1 requires to update the hid0 register when switching from hash to radix. Signed-off-by: Aneesh Kumar K.V Acked-by: Michael Neuling Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/reg.h | 3 +++ arch/powerpc/mm/hash_utils_64.c | 25 +++++++++++++++++++++++++ arch/powerpc/mm/pgtable-radix.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index f69f40f1519a..9dddabc2fced 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -475,6 +475,9 @@ #define HID0_POWER8_1TO4LPAR __MASK(51) #define HID0_POWER8_DYNLPARDIS __MASK(48) +/* POWER9 HID0 bits */ +#define HID0_POWER9_RADIX __MASK(63 - 8) + #define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ #ifdef CONFIG_6xx #define HID1_EMCP (1<<31) /* 7450 Machine Check Pin Enable */ diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 0821556e16f4..35a6721b3d25 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -711,6 +711,29 @@ int remove_section_mapping(unsigned long start, unsigned long end) } #endif /* CONFIG_MEMORY_HOTPLUG */ +static void update_hid_for_hash(void) +{ + unsigned long hid0; + unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */ + + asm volatile("ptesync": : :"memory"); + /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */ + asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) + : : "r"(rb), "i"(0), "i"(0), "i"(2), "r"(0) : "memory"); + asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory"); + /* + * now switch the HID + */ + hid0 = mfspr(SPRN_HID0); + hid0 &= ~HID0_POWER9_RADIX; + mtspr(SPRN_HID0, hid0); + asm volatile("isync": : :"memory"); + + /* Wait for it to happen */ + while ((mfspr(SPRN_HID0) & HID0_POWER9_RADIX)) + cpu_relax(); +} + static void __init hash_init_partition_table(phys_addr_t hash_table, unsigned long htab_size) { @@ -737,6 +760,8 @@ static void __init hash_init_partition_table(phys_addr_t hash_table, */ partition_tb->patb1 = 0; pr_info("Partition table %p\n", partition_tb); + if (cpu_has_feature(CPU_FTR_POWER9_DD1)) + update_hid_for_hash(); /* * update partition table control register, * 64 K size. diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c index af897d91d09f..8f086352e421 100644 --- a/arch/powerpc/mm/pgtable-radix.c +++ b/arch/powerpc/mm/pgtable-radix.c @@ -294,6 +294,32 @@ found: return; } +static void update_hid_for_radix(void) +{ + unsigned long hid0; + unsigned long rb = 3UL << PPC_BITLSHIFT(53); /* IS = 3 */ + + asm volatile("ptesync": : :"memory"); + /* prs = 0, ric = 2, rs = 0, r = 1 is = 3 */ + asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) + : : "r"(rb), "i"(1), "i"(0), "i"(2), "r"(0) : "memory"); + /* prs = 1, ric = 2, rs = 0, r = 1 is = 3 */ + asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) + : : "r"(rb), "i"(1), "i"(1), "i"(2), "r"(0) : "memory"); + asm volatile("eieio; tlbsync; ptesync; isync; slbia": : :"memory"); + /* + * now switch the HID + */ + hid0 = mfspr(SPRN_HID0); + hid0 |= HID0_POWER9_RADIX; + mtspr(SPRN_HID0, hid0); + asm volatile("isync": : :"memory"); + + /* Wait for it to happen */ + while (!(mfspr(SPRN_HID0) & HID0_POWER9_RADIX)) + cpu_relax(); +} + void __init radix__early_init_mmu(void) { unsigned long lpcr; @@ -345,6 +371,8 @@ void __init radix__early_init_mmu(void) if (!firmware_has_feature(FW_FEATURE_LPAR)) { radix_init_native(); + if (cpu_has_feature(CPU_FTR_POWER9_DD1)) + update_hid_for_radix(); lpcr = mfspr(SPRN_LPCR); mtspr(SPRN_LPCR, lpcr | LPCR_UPRT | LPCR_HR); radix_init_partition_table(); -- cgit v1.2.3 From 03465f899bdac70d34f6ca447a74d8ae9e284ce5 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 16 Sep 2016 20:48:08 +1000 Subject: powerpc: Use kprobe blacklist for exception handlers Currently we mark the C implementations of some exception handlers as __kprobes. This has the effect of putting them in the ".kprobes.text" section, which separates them from the rest of the text. Instead we can use the blacklist macros to add the symbols to a blacklist which kprobes will check. This allows the linker to move exception handler functions close to callers and avoids trampolines in larger kernels. Signed-off-by: Nicholas Piggin [mpe: Reword change log a bit] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/asm-prototypes.h | 6 +++--- arch/powerpc/kernel/hw_breakpoint.c | 9 ++++++--- arch/powerpc/kernel/traps.c | 21 ++++++++++++++------- arch/powerpc/mm/fault.c | 4 ++-- 4 files changed, 25 insertions(+), 15 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index a5b239948bfb..d1492736d852 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -54,8 +54,8 @@ void SMIException(struct pt_regs *regs); void handle_hmi_exception(struct pt_regs *regs); void instruction_breakpoint_exception(struct pt_regs *regs); void RunModeException(struct pt_regs *regs); -void __kprobes single_step_exception(struct pt_regs *regs); -void __kprobes program_check_exception(struct pt_regs *regs); +void single_step_exception(struct pt_regs *regs); +void program_check_exception(struct pt_regs *regs); void alignment_exception(struct pt_regs *regs); void StackOverflow(struct pt_regs *regs); void nonrecoverable_exception(struct pt_regs *regs); @@ -72,7 +72,7 @@ void unrecoverable_exception(struct pt_regs *regs); void kernel_bad_stack(struct pt_regs *regs); void system_reset_exception(struct pt_regs *regs); void machine_check_exception(struct pt_regs *regs); -void __kprobes emulation_assist_interrupt(struct pt_regs *regs); +void emulation_assist_interrupt(struct pt_regs *regs); /* signals, syscalls and interrupts */ #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index aec9a1b1d25b..9781c69eae57 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -206,7 +206,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs) /* * Handle debug exception notifications. */ -int __kprobes hw_breakpoint_handler(struct die_args *args) +int hw_breakpoint_handler(struct die_args *args) { int rc = NOTIFY_STOP; struct perf_event *bp; @@ -290,11 +290,12 @@ out: rcu_read_unlock(); return rc; } +NOKPROBE_SYMBOL(hw_breakpoint_handler); /* * Handle single-step exceptions following a DABR hit. */ -static int __kprobes single_step_dabr_instruction(struct die_args *args) +static int single_step_dabr_instruction(struct die_args *args) { struct pt_regs *regs = args->regs; struct perf_event *bp = NULL; @@ -329,11 +330,12 @@ static int __kprobes single_step_dabr_instruction(struct die_args *args) return NOTIFY_STOP; } +NOKPROBE_SYMBOL(single_step_dabr_instruction); /* * Handle debug exception notifications. */ -int __kprobes hw_breakpoint_exceptions_notify( +int hw_breakpoint_exceptions_notify( struct notifier_block *unused, unsigned long val, void *data) { int ret = NOTIFY_DONE; @@ -349,6 +351,7 @@ int __kprobes hw_breakpoint_exceptions_notify( return ret; } +NOKPROBE_SYMBOL(hw_breakpoint_exceptions_notify); /* * Release the user breakpoints used by ptrace diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 0bab80e64ff9..6b108ed29c20 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -117,7 +117,7 @@ static int die_owner = -1; static unsigned int die_nest_count; static int die_counter; -static unsigned __kprobes long oops_begin(struct pt_regs *regs) +static unsigned long oops_begin(struct pt_regs *regs) { int cpu; unsigned long flags; @@ -144,8 +144,9 @@ static unsigned __kprobes long oops_begin(struct pt_regs *regs) pmac_backlight_unblank(); return flags; } +NOKPROBE_SYMBOL(oops_begin); -static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, +static void oops_end(unsigned long flags, struct pt_regs *regs, int signr) { bust_spinlocks(0); @@ -196,8 +197,9 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, panic("Fatal exception"); do_exit(signr); } +NOKPROBE_SYMBOL(oops_end); -static int __kprobes __die(const char *str, struct pt_regs *regs, long err) +static int __die(const char *str, struct pt_regs *regs, long err) { printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); #ifdef CONFIG_PREEMPT @@ -221,6 +223,7 @@ static int __kprobes __die(const char *str, struct pt_regs *regs, long err) return 0; } +NOKPROBE_SYMBOL(__die); void die(const char *str, struct pt_regs *regs, long err) { @@ -802,7 +805,7 @@ void RunModeException(struct pt_regs *regs) _exception(SIGTRAP, regs, 0, 0); } -void __kprobes single_step_exception(struct pt_regs *regs) +void single_step_exception(struct pt_regs *regs) { enum ctx_state prev_state = exception_enter(); @@ -819,6 +822,7 @@ void __kprobes single_step_exception(struct pt_regs *regs) bail: exception_exit(prev_state); } +NOKPROBE_SYMBOL(single_step_exception); /* * After we have successfully emulated an instruction, we have to @@ -1140,7 +1144,7 @@ static int emulate_math(struct pt_regs *regs) static inline int emulate_math(struct pt_regs *regs) { return -1; } #endif -void __kprobes program_check_exception(struct pt_regs *regs) +void program_check_exception(struct pt_regs *regs) { enum ctx_state prev_state = exception_enter(); unsigned int reason = get_reason(regs); @@ -1260,16 +1264,18 @@ sigill: bail: exception_exit(prev_state); } +NOKPROBE_SYMBOL(program_check_exception); /* * This occurs when running in hypervisor mode on POWER6 or later * and an illegal instruction is encountered. */ -void __kprobes emulation_assist_interrupt(struct pt_regs *regs) +void emulation_assist_interrupt(struct pt_regs *regs) { regs->msr |= REASON_ILLEGAL; program_check_exception(regs); } +NOKPROBE_SYMBOL(emulation_assist_interrupt); void alignment_exception(struct pt_regs *regs) { @@ -1668,7 +1674,7 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status) mtspr(SPRN_DBCR0, current->thread.debug.dbcr0); } -void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) +void DebugException(struct pt_regs *regs, unsigned long debug_status) { current->thread.debug.dbsr = debug_status; @@ -1729,6 +1735,7 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) } else handle_debug(regs, debug_status); } +NOKPROBE_SYMBOL(DebugException); #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ #if !defined(CONFIG_TAU_INT) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index bb1ffc559f38..d0b137d96df1 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -205,7 +205,7 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) * The return value is 0 if the fault was handled, or the signal * number if this is a kernel fault that can't be handled here. */ -int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, +int do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { enum ctx_state prev_state = exception_enter(); @@ -498,8 +498,8 @@ bad_area_nosemaphore: bail: exception_exit(prev_state); return rc; - } +NOKPROBE_SYMBOL(do_page_fault); /* * bad_page_fault is called when we have a bad access from the kernel. -- cgit v1.2.3 From 6f698df10cb24d466b9a790b9daedb9e7bcd5d2a Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 16 Sep 2016 20:48:17 +1000 Subject: powerpc/kernel: Use kprobe blacklist for asm functions Rather than forcing the whole function into the ".kprobes.text" section, just add the symbol's address to the kprobe blacklist. This also lets us drop the three versions of the_KPROBE macro, in exchange for just one version of _ASM_NOKPROBE_SYMBOL - which is a good cleanup. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc_asm.h | 40 +++++++++++++------------------------- arch/powerpc/kernel/misc_32.S | 4 +++- arch/powerpc/kernel/misc_64.S | 5 +++-- 3 files changed, 20 insertions(+), 29 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index d5d5b5e348f2..cd39ac127786 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -217,13 +217,6 @@ name: \ addi r2,r2,(.TOC.-0b)@l; \ .localentry name,.-name -#define _KPROBE(name) \ - .section ".kprobes.text","a"; \ - .align 2 ; \ - .type name,@function; \ - .globl name; \ -name: - #define DOTSYM(a) a #else @@ -247,20 +240,6 @@ GLUE(.,name): #define _GLOBAL_TOC(name) _GLOBAL(name) -#define _KPROBE(name) \ - .section ".kprobes.text","a"; \ - .align 2 ; \ - .globl name; \ - .globl GLUE(.,name); \ - .section ".opd","aw"; \ -name: \ - .quad GLUE(.,name); \ - .quad .TOC.@tocbase; \ - .quad 0; \ - .previous; \ - .type GLUE(.,name),@function; \ -GLUE(.,name): - #define DOTSYM(a) GLUE(.,a) #endif @@ -279,13 +258,22 @@ n: #define _GLOBAL_TOC(name) _GLOBAL(name) -#define _KPROBE(n) \ - .section ".kprobes.text","a"; \ - .globl n; \ -n: - #endif +/* + * __kprobes (the C annotation) puts the symbol into the .kprobes.text + * section, which gets emitted at the end of regular text. + * + * _ASM_NOKPROBE_SYMBOL and NOKPROBE_SYMBOL just adds the symbol to + * a blacklist. The former is for core kprobe functions/data, the + * latter is for those that incdentially must be excluded from probing + * and allows them to be linked at more optimal location within text. + */ +#define _ASM_NOKPROBE_SYMBOL(entry) \ + .pushsection "_kprobe_blacklist","aw"; \ + PPC_LONG (entry) ; \ + .popsection + #define FUNC_START(name) _GLOBAL(name) #define FUNC_END(name) diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index d9c912b6e632..03756ffdcd71 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -328,7 +328,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE) * * flush_icache_range(unsigned long start, unsigned long stop) */ -_KPROBE(flush_icache_range) +_GLOBAL(flush_icache_range) BEGIN_FTR_SECTION PURGE_PREFETCHED_INS blr /* for 601, do nothing */ @@ -358,6 +358,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) sync /* additional sync needed on g4 */ isync blr +_ASM_NOKPROBE_SYMBOL(flush_icache_range) + /* * Flush a particular page from the data cache to RAM. * Note: this is necessary because the instruction cache does *not* diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index cb195157b318..5d7e583f1588 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -66,7 +66,7 @@ PPC64_CACHES: * flush all bytes from start through stop-1 inclusive */ -_KPROBE(flush_icache_range) +_GLOBAL(flush_icache_range) BEGIN_FTR_SECTION PURGE_PREFETCHED_INS blr @@ -109,7 +109,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) bdnz 2b isync blr - .previous .text +_ASM_NOKPROBE_SYMBOL(flush_icache_range) + /* * Like above, but only do the D-cache. * -- cgit v1.2.3 From bea2dccccfd47ef3f8612f1265f653f8e018d793 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 15 Sep 2016 10:40:20 +1000 Subject: powerpc: Don't change the section in _GLOBAL() Currently the _GLOBAL() macro unilaterally sets the assembler section to ".text" at the start of the macro. This is rude as the caller may be using a different section. So let the caller decide which section to emit the code into. On big endian we do need to switch to the ".opd" section to emit the OPD, but do that with pushsection/popsection, thereby leaving the original section intact. I verified that the order of all entries in System.map is unchanged after this patch. The actual addresses shift around slightly so you can't just diff the System.map. Signed-off-by: Michael Ellerman Reviewed-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc_asm.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index cd39ac127786..bb566854ff2a 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -201,14 +201,12 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #ifdef PPC64_ELF_ABI_v2 #define _GLOBAL(name) \ - .section ".text"; \ .align 2 ; \ .type name,@function; \ .globl name; \ name: #define _GLOBAL_TOC(name) \ - .section ".text"; \ .align 2 ; \ .type name,@function; \ .globl name; \ @@ -225,16 +223,15 @@ name: \ #define GLUE(a,b) XGLUE(a,b) #define _GLOBAL(name) \ - .section ".text"; \ .align 2 ; \ .globl name; \ .globl GLUE(.,name); \ - .section ".opd","aw"; \ + .pushsection ".opd","aw"; \ name: \ .quad GLUE(.,name); \ .quad .TOC.@tocbase; \ .quad 0; \ - .previous; \ + .popsection; \ .type GLUE(.,name),@function; \ GLUE(.,name): @@ -251,7 +248,6 @@ GLUE(.,name): n: #define _GLOBAL(n) \ - .text; \ .stabs __stringify(n:F-1),N_FUN,0,0,n;\ .globl n; \ n: -- cgit v1.2.3 From ef24ba7091517d2bbf9ba2cb4256c0dccd51d248 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 6 Sep 2016 21:53:24 +1000 Subject: powerpc: Remove all usages of NO_IRQ NO_IRQ has been == 0 on powerpc for just over ten years (since commit 0ebfff1491ef ("[POWERPC] Add new interrupt mapping core and change platforms to use it")). It's also 0 on most other arches. Although it's fairly harmless, every now and then it causes confusion when a driver is built on powerpc and another arch which doesn't define NO_IRQ. There's at least 6 definitions of NO_IRQ in drivers/, at least some of which are to work around that problem. So we'd like to remove it. This is fairly trivial in the arch code, we just convert: if (irq == NO_IRQ) to if (!irq) if (irq != NO_IRQ) to if (irq) irq = NO_IRQ; to irq = 0; return NO_IRQ; to return 0; And a few other odd cases as well. At least for now we keep the #define NO_IRQ, because there is driver code that uses NO_IRQ and the fixes to remove those will go via other trees. Note we also change some occurrences in PPC sound drivers, drivers/ps3, and drivers/macintosh. Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/machdep.h | 2 +- arch/powerpc/include/asm/mpic_msgr.h | 6 +++--- arch/powerpc/include/asm/parport.h | 2 +- arch/powerpc/kernel/ibmebus.c | 2 +- arch/powerpc/kernel/irq.c | 2 +- arch/powerpc/kernel/legacy_serial.c | 14 +++++++------- arch/powerpc/kernel/pci-common.c | 5 +++-- arch/powerpc/kernel/pci_of_scan.c | 2 +- arch/powerpc/platforms/44x/warp.c | 2 +- arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | 8 ++++---- arch/powerpc/platforms/512x/mpc512x_lpbfifo.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_pic.c | 2 +- arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | 2 +- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 +- arch/powerpc/platforms/83xx/suspend.c | 4 ++-- arch/powerpc/platforms/85xx/common.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 4 ++-- arch/powerpc/platforms/85xx/mpc85xx_ds.c | 4 ++-- arch/powerpc/platforms/85xx/socrates_fpga_pic.c | 6 +++--- arch/powerpc/platforms/86xx/pic.c | 4 ++-- arch/powerpc/platforms/8xx/m8xx_setup.c | 2 +- arch/powerpc/platforms/cell/axon_msi.c | 6 +++--- arch/powerpc/platforms/cell/interrupt.c | 12 ++++++------ arch/powerpc/platforms/cell/iommu.c | 2 +- arch/powerpc/platforms/cell/pmu.c | 4 ++-- arch/powerpc/platforms/cell/spider-pic.c | 18 +++++++++--------- arch/powerpc/platforms/cell/spu_base.c | 16 ++++++++-------- arch/powerpc/platforms/cell/spu_manage.c | 9 ++++++--- arch/powerpc/platforms/chrp/setup.c | 4 ++-- arch/powerpc/platforms/embedded6xx/flipper-pic.c | 2 +- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 4 ++-- arch/powerpc/platforms/embedded6xx/mvme5100.c | 4 ++-- arch/powerpc/platforms/maple/pci.c | 6 +++--- arch/powerpc/platforms/pasemi/misc.c | 2 +- arch/powerpc/platforms/pasemi/msi.c | 4 ++-- arch/powerpc/platforms/pasemi/setup.c | 4 ++-- arch/powerpc/platforms/powermac/low_i2c.c | 6 +++--- arch/powerpc/platforms/powermac/pfunc_base.c | 4 ++-- arch/powerpc/platforms/powermac/pic.c | 6 +++--- arch/powerpc/platforms/powernv/opal-irqchip.c | 4 ++-- arch/powerpc/platforms/powernv/pci-cxl.c | 4 ++-- arch/powerpc/platforms/powernv/pci.c | 4 ++-- arch/powerpc/platforms/ps3/interrupt.c | 10 +++++----- arch/powerpc/platforms/ps3/smp.c | 4 ++-- arch/powerpc/platforms/ps3/spu.c | 4 ++-- arch/powerpc/platforms/pseries/event_sources.c | 2 +- arch/powerpc/platforms/pseries/msi.c | 6 +++--- arch/powerpc/platforms/pseries/setup.c | 4 ++-- arch/powerpc/sysdev/axonram.c | 6 +++--- arch/powerpc/sysdev/cpm1.c | 8 ++++---- arch/powerpc/sysdev/ehv_pic.c | 4 ++-- arch/powerpc/sysdev/fsl_gtm.c | 2 +- arch/powerpc/sysdev/fsl_mpic_err.c | 6 +++--- arch/powerpc/sysdev/fsl_msi.c | 12 ++++++------ arch/powerpc/sysdev/ge/ge_pic.c | 8 ++++---- arch/powerpc/sysdev/i8259.c | 4 ++-- arch/powerpc/sysdev/ipic.c | 4 ++-- arch/powerpc/sysdev/mpc8xx_pic.c | 2 +- arch/powerpc/sysdev/mpic.c | 14 +++++++------- arch/powerpc/sysdev/mpic_msgr.c | 4 ++-- arch/powerpc/sysdev/mpic_u3msi.c | 4 ++-- arch/powerpc/sysdev/mv64x60_pic.c | 2 +- arch/powerpc/sysdev/pmi.c | 2 +- arch/powerpc/sysdev/ppc4xx_hsta_msi.c | 6 +++--- arch/powerpc/sysdev/ppc4xx_msi.c | 6 +++--- arch/powerpc/sysdev/ppc4xx_soc.c | 2 +- arch/powerpc/sysdev/tsi108_pci.c | 2 +- arch/powerpc/sysdev/uic.c | 2 +- arch/powerpc/sysdev/xics/icp-hv.c | 6 +++--- arch/powerpc/sysdev/xics/icp-native.c | 6 +++--- arch/powerpc/sysdev/xics/icp-opal.c | 8 ++++---- arch/powerpc/sysdev/xics/xics-common.c | 2 +- drivers/macintosh/macio_asic.c | 4 ++-- drivers/macintosh/rack-meter.c | 2 +- drivers/macintosh/smu.c | 18 +++++++++--------- drivers/macintosh/via-cuda.c | 2 +- drivers/macintosh/via-pmu.c | 6 +++--- drivers/ps3/ps3-vuart.c | 4 ++-- sound/aoa/core/gpio-feature.c | 4 ++-- sound/ppc/tumbler.c | 8 ++++---- 80 files changed, 204 insertions(+), 200 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 0420b388dd83..e02cbc6a6c70 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -61,7 +61,7 @@ struct machdep_calls { void (*init_IRQ)(void); - /* Return an irq, or NO_IRQ to indicate there are none pending. */ + /* Return an irq, or 0 to indicate there are none pending. */ unsigned int (*get_irq)(void); /* PCI stuff */ diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h index d4f471fb1031..088420d8aa59 100644 --- a/arch/powerpc/include/asm/mpic_msgr.h +++ b/arch/powerpc/include/asm/mpic_msgr.h @@ -122,9 +122,9 @@ static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr, * @msgr: the message register whose IRQ is to be returned * * Returns the IRQ number associated with the given message register. - * NO_IRQ is returned if this message register is not capable of - * receiving interrupts. What message register can and cannot receive - * interrupts is specified in the device tree for the system. + * 0 is returned if this message register is not capable of receiving + * interrupts. What message register can and cannot receive interrupts is + * specified in the device tree for the system. */ static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr) { diff --git a/arch/powerpc/include/asm/parport.h b/arch/powerpc/include/asm/parport.h index a452968b29ea..6595ad1d18cc 100644 --- a/arch/powerpc/include/asm/parport.h +++ b/arch/powerpc/include/asm/parport.h @@ -28,7 +28,7 @@ static int parport_pc_find_nonpci_ports (int autoirq, int autodma) io1 = prop[1]; io2 = prop[2]; virq = irq_of_parse_and_map(np, 0); - if (virq == NO_IRQ) + if (!virq) continue; if (parport_pc_probe_port(io1, io2, virq, autodma, NULL, 0) diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index c1ca9282f4a0..6ca9a2ffaac7 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -227,7 +227,7 @@ int ibmebus_request_irq(u32 ist, irq_handler_t handler, { unsigned int irq = irq_create_mapping(NULL, ist); - if (irq == NO_IRQ) + if (!irq) return -EINVAL; return request_irq(irq, handler, irq_flags, devname, dev_id); diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 471f65ad1b9b..3c05c311e35e 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -519,7 +519,7 @@ void __do_irq(struct pt_regs *regs) may_hard_irq_enable(); /* And finally process it */ - if (unlikely(irq == NO_IRQ)) + if (unlikely(!irq)) __this_cpu_inc(irq_stat.spurious_irqs); else generic_handle_irq(irq); diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 7b750c4ed5c7..bc525ea0dc09 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -193,10 +193,10 @@ static int __init add_legacy_soc_port(struct device_node *np, */ if (tsi && !strcmp(tsi->type, "tsi-bridge")) return add_legacy_port(np, -1, UPIO_TSI, addr, addr, - NO_IRQ, legacy_port_flags, 0); + 0, legacy_port_flags, 0); else return add_legacy_port(np, -1, UPIO_MEM, addr, addr, - NO_IRQ, legacy_port_flags, 0); + 0, legacy_port_flags, 0); } static int __init add_legacy_isa_port(struct device_node *np, @@ -242,7 +242,7 @@ static int __init add_legacy_isa_port(struct device_node *np, /* Add port, irq will be dealt with later */ return add_legacy_port(np, index, UPIO_PORT, be32_to_cpu(reg[1]), - taddr, NO_IRQ, legacy_port_flags, 0); + taddr, 0, legacy_port_flags, 0); } @@ -314,7 +314,7 @@ static int __init add_legacy_pci_port(struct device_node *np, /* Add port, irq will be dealt with later. We passed a translated * IO port value. It will be fixed up later along with the irq */ - return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, + return add_legacy_port(np, index, iotype, base, addr, 0, legacy_port_flags, np != pci_dev); } #endif @@ -462,14 +462,14 @@ static void __init fixup_port_irq(int index, DBG("fixup_port_irq(%d)\n", index); virq = irq_of_parse_and_map(np, 0); - if (virq == NO_IRQ && legacy_serial_infos[index].irq_check_parent) { + if (!virq && legacy_serial_infos[index].irq_check_parent) { np = of_get_parent(np); if (np == NULL) return; virq = irq_of_parse_and_map(np, 0); of_node_put(np); } - if (virq == NO_IRQ) + if (!virq) return; port->irq = virq; @@ -543,7 +543,7 @@ static int __init serial_dev_init(void) struct plat_serial8250_port *port = &legacy_serial_ports[i]; struct device_node *np = legacy_serial_infos[i].np; - if (port->irq == NO_IRQ) + if (!port->irq) fixup_port_irq(i, np, port); if (port->iotype == UPIO_PORT) fixup_port_pio(i, np, port); diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index e58908066b0e..95d3769a2e26 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -360,7 +360,7 @@ static int pci_read_irq_line(struct pci_dev *pci_dev) line, pin); virq = irq_create_mapping(NULL, line); - if (virq != NO_IRQ) + if (virq) irq_set_irq_type(virq, IRQ_TYPE_LEVEL_LOW); } else { pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n", @@ -369,7 +369,8 @@ static int pci_read_irq_line(struct pci_dev *pci_dev) virq = irq_create_of_mapping(&oirq); } - if(virq == NO_IRQ) { + + if (!virq) { pr_debug(" Failed to map !\n"); return -1; } diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 526ac6750e4d..ea3d98115b88 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -178,7 +178,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, dev->hdr_type = PCI_HEADER_TYPE_NORMAL; dev->rom_base_reg = PCI_ROM_ADDRESS; /* Maybe do a default OF mapping here */ - dev->irq = NO_IRQ; + dev->irq = 0; } of_pci_parse_addrs(node, dev); diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index 5ecce543103e..a886c2c22097 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -204,7 +204,7 @@ static void pika_setup_critical_temp(struct device_node *np, i2c_smbus_write_byte_data(client, 3, 0); /* Tlow */ irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { printk(KERN_ERR __FILE__ ": Unable to get ad7414 irq\n"); return; } diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 0035d146df73..fe4d4eac7427 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -97,7 +97,7 @@ cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp, status |= (ignore | mask); if (status == 0xff) - return NO_IRQ; + return 0; cpld_irq = ffz(status) + offset; @@ -110,14 +110,14 @@ static void cpld_pic_cascade(struct irq_desc *desc) irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status, &cpld_regs->pci_mask); - if (irq != NO_IRQ) { + if (irq) { generic_handle_irq(irq); return; } irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status, &cpld_regs->misc_mask); - if (irq != NO_IRQ) { + if (irq) { generic_handle_irq(irq); return; } @@ -177,7 +177,7 @@ mpc5121_ads_cpld_pic_init(void) goto end; cascade_irq = irq_of_parse_and_map(np, 0); - if (cascade_irq == NO_IRQ) + if (!cascade_irq) goto end; /* diff --git a/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c b/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c index d93dd4acf40b..cec3f88f153d 100644 --- a/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c +++ b/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c @@ -473,7 +473,7 @@ static int mpc512x_lpbfifo_probe(struct platform_device *pdev) } lpbfifo.irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (lpbfifo.irq == NO_IRQ) { + if (!lpbfifo.irq) { dev_err(&pdev->dev, "mapping irq failed\n"); ret = -ENODEV; goto err0; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 4fe2074c88cb..fc98912f42cf 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -511,7 +511,7 @@ unsigned int mpc52xx_get_irq(void) irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET); } } else { - return NO_IRQ; + return 0; } return irq_linear_revmap(mpc52xx_irqhost, irq); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 60e89fc9c753..8b065bdf7412 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -131,7 +131,7 @@ int __init pq2ads_pci_init_irq(void) } irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { printk(KERN_ERR "No interrupt in pci pic node.\n"); of_node_put(np); goto out; diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 2ef03e7d248c..0d6a62fc5864 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -89,7 +89,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk, goto err; ret = of_irq_to_resource(np, 0, &res[1]); - if (ret == NO_IRQ) + if (!ret) goto err; pdev = platform_device_alloc("mpc83xx_spi", i); diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index fcbea4b51a78..24717d060008 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -352,7 +352,7 @@ static int pmc_probe(struct platform_device *ofdev) return -ENODEV; pmc_irq = irq_of_parse_and_map(np, 0); - if (pmc_irq != NO_IRQ) { + if (pmc_irq) { ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED, "pmc", ofdev); @@ -400,7 +400,7 @@ out_syscr: out_pmc: iounmap(pmc_regs); out: - if (pmc_irq != NO_IRQ) + if (pmc_irq) free_irq(pmc_irq, ofdev); return ret; diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c index 28720a4ded7b..954e5e8b14ef 100644 --- a/arch/powerpc/platforms/85xx/common.c +++ b/arch/powerpc/platforms/85xx/common.c @@ -76,7 +76,7 @@ void __init mpc85xx_cpm2_pic_init(void) return; } irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { of_node_put(np); printk(KERN_ERR "PIC init: got no IRQ for cpm cascade\n"); return; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 62f171c71c4c..86f20156178e 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -196,7 +196,7 @@ static void mpc85xx_8259_cascade_handler(struct irq_desc *desc) { unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) + if (cascade_irq) /* handle an interrupt from the 8259 */ generic_handle_irq(cascade_irq); @@ -247,7 +247,7 @@ static int mpc85xx_cds_8259_attach(void) } cascade_irq = irq_of_parse_and_map(cascade_node, 0); - if (cascade_irq == NO_IRQ) { + if (!cascade_irq) { printk(KERN_ERR "Failed to map cascade interrupt\n"); return -ENXIO; } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 6bc07d837b1c..ed69c7ee1829 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -51,7 +51,7 @@ static void mpc85xx_8259_cascade(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) { + if (cascade_irq) { generic_handle_irq(cascade_irq); } chip->irq_eoi(&desc->irq_data); @@ -96,7 +96,7 @@ void __init mpc85xx_ds_pic_init(void) } cascade_irq = irq_of_parse_and_map(cascade_node, 0); - if (cascade_irq == NO_IRQ) { + if (!cascade_irq) { printk(KERN_ERR "Failed to map cascade interrupt\n"); return; } diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index b02d6a5bb035..82f8490b5aa7 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -78,7 +78,7 @@ static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq) break; } if (i == 3) - return NO_IRQ; + return 0; raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags); cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i)); @@ -103,7 +103,7 @@ static void socrates_fpga_pic_cascade(struct irq_desc *desc) */ cascade_irq = socrates_fpga_pic_get_irq(irq); - if (cascade_irq != NO_IRQ) + if (cascade_irq) generic_handle_irq(cascade_irq); chip->irq_eoi(&desc->irq_data); } @@ -292,7 +292,7 @@ void socrates_fpga_pic_init(struct device_node *pic) for (i = 0; i < 3; i++) { socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i); - if (socrates_fpga_irqs[i] == NO_IRQ) { + if (!socrates_fpga_irqs[i]) { pr_warning("FPGA PIC: can't get irq%d.\n", i); continue; } diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c index 845defa1fd19..a6c695fa4da0 100644 --- a/arch/powerpc/platforms/86xx/pic.c +++ b/arch/powerpc/platforms/86xx/pic.c @@ -22,7 +22,7 @@ static void mpc86xx_8259_cascade(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) + if (cascade_irq) generic_handle_irq(cascade_irq); chip->irq_eoi(&desc->irq_data); @@ -58,7 +58,7 @@ void __init mpc86xx_init_irq(void) } cascade_irq = irq_of_parse_and_map(cascade_node, 0); - if (cascade_irq == NO_IRQ) { + if (!cascade_irq) { printk(KERN_ERR "Failed to map cascade interrupt\n"); return; } diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index b1ab6e96cb31..f81069f79a94 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -241,6 +241,6 @@ void __init mpc8xx_pics_init(void) } irq = cpm_pic_init(); - if (irq != NO_IRQ) + if (irq) irq_set_chained_handler(irq, cpm_cascade); } diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index aed7714495c1..8b55c5f19d4c 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -271,7 +271,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) for_each_pci_msi_entry(entry, dev) { virq = irq_create_direct_mapping(msic->irq_domain); - if (virq == NO_IRQ) { + if (!virq) { dev_warn(&dev->dev, "axon_msi: virq allocation failed!\n"); return -1; @@ -293,7 +293,7 @@ static void axon_msi_teardown_msi_irqs(struct pci_dev *dev) dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n"); for_each_pci_msi_entry(entry, dev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; irq_set_msi_desc(entry->irq, NULL); @@ -375,7 +375,7 @@ static int axon_msi_probe(struct platform_device *device) } virq = irq_of_parse_and_map(dn, 0); - if (virq == NO_IRQ) { + if (!virq) { printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n", dn->full_name); goto out_free_fifo; diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 4d16b368b6f5..a6bbbaba14a3 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -123,7 +123,7 @@ static void iic_ioexc_cascade(struct irq_desc *desc) unsigned int cirq = irq_linear_revmap(iic_host, base | cascade); - if (cirq != NO_IRQ) + if (cirq) generic_handle_irq(cirq); } /* post-ack level interrupts */ @@ -153,10 +153,10 @@ static unsigned int iic_get_irq(void) *(unsigned long *) &pending = in_be64((u64 __iomem *) &iic->regs->pending_destr); if (!(pending.flags & CBE_IIC_IRQ_VALID)) - return NO_IRQ; + return 0; virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending)); - if (virq == NO_IRQ) - return NO_IRQ; + if (!virq) + return 0; iic->eoi_stack[++iic->eoi_ptr] = pending.prio; BUG_ON(iic->eoi_ptr > 15); return virq; @@ -192,7 +192,7 @@ static void iic_request_ipi(int msg) int virq; virq = irq_create_mapping(iic_host, iic_msg_to_irq(msg)); - if (virq == NO_IRQ) { + if (!virq) { printk(KERN_ERR "iic: failed to map IPI %s\n", smp_ipi_name[msg]); return; @@ -347,7 +347,7 @@ static int __init setup_iic(void) cascade |= 1 << IIC_IRQ_CLASS_SHIFT; cascade |= IIC_UNIT_IIC; cascade = irq_create_mapping(iic_host, cascade); - if (cascade == NO_IRQ) + if (!cascade) continue; /* * irq_data is a generic pointer that gets passed back diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 640772af9bcb..7ff51f96a00e 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -411,7 +411,7 @@ static void cell_iommu_enable_hardware(struct cbe_iommu *iommu) virq = irq_create_mapping(NULL, IIC_IRQ_IOEX_ATI | (iommu->nid << IIC_IRQ_NODE_SHIFT)); - BUG_ON(virq == NO_IRQ); + BUG_ON(!virq); ret = request_irq(virq, ioc_interrupt, 0, iommu->name, iommu); BUG_ON(ret); diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c index 348a27b12512..e3ad0c38f017 100644 --- a/arch/powerpc/platforms/cell/pmu.c +++ b/arch/powerpc/platforms/cell/pmu.c @@ -385,7 +385,7 @@ static int __init cbe_init_pm_irq(void) for_each_online_node(node) { irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI | (node << IIC_IRQ_NODE_SHIFT)); - if (irq == NO_IRQ) { + if (!irq) { printk("ERROR: Unable to allocate irq for node %d\n", node); return -EINVAL; @@ -412,7 +412,7 @@ void cbe_sync_irq(int node) IIC_IRQ_IOEX_PMI | (node << IIC_IRQ_NODE_SHIFT)); - if (irq == NO_IRQ) { + if (!irq) { printk(KERN_WARNING "ERROR, unable to get existing irq %d " \ "for node %d\n", irq, node); return; diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index d06dcac66fcb..ff924af00e78 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -207,11 +207,11 @@ static void spider_irq_cascade(struct irq_desc *desc) cs = in_be32(pic->regs + TIR_CS) >> 24; if (cs == SPIDER_IRQ_INVALID) - virq = NO_IRQ; + virq = 0; else virq = irq_linear_revmap(pic->host, cs); - if (virq != NO_IRQ) + if (virq) generic_handle_irq(virq); chip->irq_eoi(&desc->irq_data); @@ -245,19 +245,19 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) /* Now do the horrible hacks */ tmp = of_get_property(of_node, "#interrupt-cells", NULL); if (tmp == NULL) - return NO_IRQ; + return 0; intsize = *tmp; imap = of_get_property(of_node, "interrupt-map", &imaplen); if (imap == NULL || imaplen < (intsize + 1)) - return NO_IRQ; + return 0; iic = of_find_node_by_phandle(imap[intsize]); if (iic == NULL) - return NO_IRQ; + return 0; imap += intsize + 1; tmp = of_get_property(iic, "#interrupt-cells", NULL); if (tmp == NULL) { of_node_put(iic); - return NO_IRQ; + return 0; } intsize = *tmp; /* Assume unit is last entry of interrupt specifier */ @@ -266,7 +266,7 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) tmp = of_get_property(iic, "ibm,interrupt-server-ranges", NULL); if (tmp == NULL) { of_node_put(iic); - return NO_IRQ; + return 0; } /* ugly as hell but works for now */ pic->node_id = (*tmp) >> 1; @@ -281,7 +281,7 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) (pic->node_id << IIC_IRQ_NODE_SHIFT) | (2 << IIC_IRQ_CLASS_SHIFT) | unit); - if (virq == NO_IRQ) + if (!virq) printk(KERN_ERR "spider_pic: failed to map cascade !"); return virq; } @@ -318,7 +318,7 @@ static void __init spider_init_one(struct device_node *of_node, int chip, /* Hook up the cascade interrupt to the iic and nodeid */ virq = spider_find_cascade_and_node(pic); - if (virq == NO_IRQ) + if (!virq) return; irq_set_handler_data(virq, pic); irq_set_chained_handler(virq, spider_irq_cascade); diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index bb4a8e07c229..e84d8fbc2e21 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -402,7 +402,7 @@ static int spu_request_irqs(struct spu *spu) { int ret = 0; - if (spu->irqs[0] != NO_IRQ) { + if (spu->irqs[0]) { snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number); ret = request_irq(spu->irqs[0], spu_irq_class_0, @@ -410,7 +410,7 @@ static int spu_request_irqs(struct spu *spu) if (ret) goto bail0; } - if (spu->irqs[1] != NO_IRQ) { + if (spu->irqs[1]) { snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number); ret = request_irq(spu->irqs[1], spu_irq_class_1, @@ -418,7 +418,7 @@ static int spu_request_irqs(struct spu *spu) if (ret) goto bail1; } - if (spu->irqs[2] != NO_IRQ) { + if (spu->irqs[2]) { snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number); ret = request_irq(spu->irqs[2], spu_irq_class_2, @@ -429,10 +429,10 @@ static int spu_request_irqs(struct spu *spu) return 0; bail2: - if (spu->irqs[1] != NO_IRQ) + if (spu->irqs[1]) free_irq(spu->irqs[1], spu); bail1: - if (spu->irqs[0] != NO_IRQ) + if (spu->irqs[0]) free_irq(spu->irqs[0], spu); bail0: return ret; @@ -440,11 +440,11 @@ bail0: static void spu_free_irqs(struct spu *spu) { - if (spu->irqs[0] != NO_IRQ) + if (spu->irqs[0]) free_irq(spu->irqs[0], spu); - if (spu->irqs[1] != NO_IRQ) + if (spu->irqs[1]) free_irq(spu->irqs[1], spu); - if (spu->irqs[2] != NO_IRQ) + if (spu->irqs[2]) free_irq(spu->irqs[2], spu); } diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index 21b4bfb97200..672d310dcf14 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c @@ -105,7 +105,10 @@ static int __init spu_map_interrupts_old(struct spu *spu, spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); /* Right now, we only fail if class 2 failed */ - return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; + if (!spu->irqs[2]) + return -EINVAL; + + return 0; } static void __iomem * __init spu_map_prop_old(struct spu *spu, @@ -191,7 +194,7 @@ static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) pr_debug(" irq %d no 0x%x on %s\n", i, oirq.args[0], oirq.np->full_name); spu->irqs[i] = irq_create_of_mapping(&oirq); - if (spu->irqs[i] == NO_IRQ) { + if (!spu->irqs[i]) { pr_debug("spu_new: failed to map it !\n"); goto err; } @@ -202,7 +205,7 @@ err: pr_debug("failed to map irq %x for spu %s\n", *oirq.args, spu->name); for (; i >= 0; i--) { - if (spu->irqs[i] != NO_IRQ) + if (spu->irqs[i]) irq_dispose_mapping(spu->irqs[i]); } return ret; diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index bfb300633dfe..0ce1b45f02a8 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -368,7 +368,7 @@ static void chrp_8259_cascade(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) + if (cascade_irq) generic_handle_irq(cascade_irq); chip->irq_eoi(&desc->irq_data); @@ -514,7 +514,7 @@ static void __init chrp_find_8259(void) } if (chrp_mpic != NULL) { cascade_irq = irq_of_parse_and_map(pic, 0); - if (cascade_irq == NO_IRQ) + if (!cascade_irq) printk(KERN_ERR "i8259: failed to map cascade irq\n"); else irq_set_chained_handler(cascade_irq, diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index b7866e01483d..ade83829d5e8 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -181,7 +181,7 @@ unsigned int flipper_pic_get_irq(void) irq_status = in_be32(io_base + FLIPPER_ICR) & in_be32(io_base + FLIPPER_IMR); if (irq_status == 0) - return NO_IRQ; /* no more IRQs pending */ + return 0; /* no more IRQs pending */ irq = __ffs(irq_status); return irq_linear_revmap(flipper_irq_host, irq); diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 9b7975706bfc..89c54de88b7a 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -114,7 +114,7 @@ static unsigned int __hlwd_pic_get_irq(struct irq_domain *h) irq_status = in_be32(io_base + HW_BROADWAY_ICR) & in_be32(io_base + HW_BROADWAY_IMR); if (irq_status == 0) - return NO_IRQ; /* no more IRQs pending */ + return 0; /* no more IRQs pending */ irq = __ffs(irq_status); return irq_linear_revmap(h, irq); @@ -131,7 +131,7 @@ static void hlwd_pic_irq_cascade(struct irq_desc *desc) raw_spin_unlock(&desc->lock); virq = __hlwd_pic_get_irq(irq_domain); - if (virq != NO_IRQ) + if (virq) generic_handle_irq(virq); else pr_err("spurious interrupt!\n"); diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c index ed7321d6772e..8e3590941960 100644 --- a/arch/powerpc/platforms/embedded6xx/mvme5100.c +++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c @@ -47,7 +47,7 @@ static void mvme5100_8259_cascade(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) + if (cascade_irq) generic_handle_irq(cascade_irq); chip->irq_eoi(&desc->irq_data); @@ -84,7 +84,7 @@ static void __init mvme5100_pic_init(void) } cirq = irq_of_parse_and_map(cp, 0); - if (cirq == NO_IRQ) { + if (!cirq) { pr_warn("mvme5100_pic_init: no cascade interrupt?\n"); return; } diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index a2f89e6326ce..a0589aac4163 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -552,7 +552,7 @@ void maple_pci_irq_fixup(struct pci_dev *dev) pci_bus_to_host(dev->bus) == u4_pcie) { printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n"); dev->irq = irq_create_mapping(NULL, 1); - if (dev->irq != NO_IRQ) + if (dev->irq) irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); } @@ -562,7 +562,7 @@ void maple_pci_irq_fixup(struct pci_dev *dev) if (dev->vendor == PCI_VENDOR_ID_AMD && dev->device == PCI_DEVICE_ID_AMD_8111_IDE && (dev->class & 5) != 5) { - dev->irq = NO_IRQ; + dev->irq = 0; } DBG(" <- maple_pci_irq_fixup\n"); @@ -648,7 +648,7 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) return defirq; } irq = irq_of_parse_and_map(np, channel & 0x1); - if (irq == NO_IRQ) { + if (!irq) { printk("Failed to map onboard IDE interrupt for channel %d\n", channel); return defirq; diff --git a/arch/powerpc/platforms/pasemi/misc.c b/arch/powerpc/platforms/pasemi/misc.c index e0ab299763c1..8571e7bf78b6 100644 --- a/arch/powerpc/platforms/pasemi/misc.c +++ b/arch/powerpc/platforms/pasemi/misc.c @@ -76,7 +76,7 @@ static int __init pasemi_register_i2c_devices(void) } info.irq = irq_of_parse_and_map(node, 0); - if (info.irq == NO_IRQ) + if (!info.irq) info.irq = -1; if (find_i2c_driver(node, &info) < 0) diff --git a/arch/powerpc/platforms/pasemi/msi.c b/arch/powerpc/platforms/pasemi/msi.c index d9af76342d99..d9cd510c8865 100644 --- a/arch/powerpc/platforms/pasemi/msi.c +++ b/arch/powerpc/platforms/pasemi/msi.c @@ -68,7 +68,7 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev); for_each_pci_msi_entry(entry, pdev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; hwirq = virq_to_hw(entry->irq); @@ -109,7 +109,7 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) } virq = irq_create_mapping(msi_mpic->irqhost, hwirq); - if (virq == NO_IRQ) { + if (!virq) { pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n", hwirq); msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 1d0c3a621a38..3182400cf48f 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -59,7 +59,7 @@ struct mce_regs { static struct mce_regs mce_regs[MAX_MCE_REGS]; static int num_mce_regs; -static int nmi_virq = NO_IRQ; +static int nmi_virq = 0; static void __noreturn pas_restart(char *cmd) @@ -264,7 +264,7 @@ static int pas_machine_check_handler(struct pt_regs *regs) srr0 = regs->nip; srr1 = regs->msr; - if (nmi_virq != NO_IRQ && mpic_get_mcirq() == nmi_virq) { + if (nmi_virq && mpic_get_mcirq() == nmi_virq) { printk(KERN_ERR "NMI delivered\n"); debugger(regs); mpic_end_irq(irq_get_irq_data(nmi_virq)); diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index 6d6f277477aa..c8c217b7dd33 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -401,7 +401,7 @@ static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, { struct pmac_i2c_host_kw *host = bus->hostdata; u8 mode_reg = host->speed; - int use_irq = host->irq != NO_IRQ && !bus->polled; + int use_irq = host->irq && !bus->polled; /* Setup mode & subaddress if any */ switch(bus->mode) { @@ -535,7 +535,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) break; } host->irq = irq_of_parse_and_map(np, 0); - if (host->irq == NO_IRQ) + if (!host->irq) printk(KERN_WARNING "low_i2c: Failed to map interrupt for %s\n", np->full_name); @@ -557,7 +557,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) */ if (request_irq(host->irq, kw_i2c_irq, IRQF_NO_SUSPEND, "keywest i2c", host)) - host->irq = NO_IRQ; + host->irq = 0; printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n", *addrp, host->irq, np->full_name); diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c index e49d07f3d542..459138ed4571 100644 --- a/arch/powerpc/platforms/powermac/pfunc_base.c +++ b/arch/powerpc/platforms/powermac/pfunc_base.c @@ -26,7 +26,7 @@ static irqreturn_t macio_gpio_irq(int irq, void *data) static int macio_do_gpio_irq_enable(struct pmf_function *func) { unsigned int irq = irq_of_parse_and_map(func->node, 0); - if (irq == NO_IRQ) + if (!irq) return -EINVAL; return request_irq(irq, macio_gpio_irq, 0, func->node->name, func); } @@ -34,7 +34,7 @@ static int macio_do_gpio_irq_enable(struct pmf_function *func) static int macio_do_gpio_irq_disable(struct pmf_function *func) { unsigned int irq = irq_of_parse_and_map(func->node, 0); - if (irq == NO_IRQ) + if (!irq) return -EINVAL; free_irq(irq, func); return 0; diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 981546345033..f5f9ad7c3398 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -251,7 +251,7 @@ static unsigned int pmac_pic_get_irq(void) } raw_spin_unlock_irqrestore(&pmac_pic_lock, flags); if (unlikely(irq < 0)) - return NO_IRQ; + return 0; return irq_linear_revmap(pmac_pic_host, irq); } @@ -389,7 +389,7 @@ static void __init pmac_pic_probe_oldstyle(void) out_le32(&pmac_irq_hw[i]->enable, 0); /* Hookup cascade irq */ - if (slave && pmac_irq_cascade != NO_IRQ) + if (slave && pmac_irq_cascade) setup_irq(pmac_irq_cascade, &gatwick_cascade_action); printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs); @@ -444,7 +444,7 @@ static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) pswitch = of_find_node_by_name(NULL, "programmer-switch"); if (pswitch) { nmi_irq = irq_of_parse_and_map(pswitch, 0); - if (nmi_irq != NO_IRQ) { + if (nmi_irq) { mpic_irq_set_priority(nmi_irq, 9); setup_irq(nmi_irq, &xmon_action); } diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c index ed8bba68a162..998316bf2dad 100644 --- a/arch/powerpc/platforms/powernv/opal-irqchip.c +++ b/arch/powerpc/platforms/powernv/opal-irqchip.c @@ -222,7 +222,7 @@ int __init opal_event_init(void) /* Get hardware and virtual IRQ */ irq = be32_to_cpup(irqs); virq = irq_create_mapping(NULL, irq); - if (virq == NO_IRQ) { + if (!virq) { pr_warn("Failed to map irq 0x%x\n", irq); continue; } @@ -260,7 +260,7 @@ machine_arch_initcall(powernv, opal_event_init); int opal_event_request(unsigned int opal_event_nr) { if (WARN_ON_ONCE(!opal_event_irqchip.domain)) - return NO_IRQ; + return 0; return irq_create_mapping(opal_event_irqchip.domain, opal_event_nr); } diff --git a/arch/powerpc/platforms/powernv/pci-cxl.c b/arch/powerpc/platforms/powernv/pci-cxl.c index 1349a099c74c..94498a04558b 100644 --- a/arch/powerpc/platforms/powernv/pci-cxl.c +++ b/arch/powerpc/platforms/powernv/pci-cxl.c @@ -344,7 +344,7 @@ int pnv_cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return (hwirq ? hwirq : -ENOMEM); virq = irq_create_mapping(NULL, hwirq); - if (virq == NO_IRQ) { + if (!virq) { pr_warn("%s: Failed to map cxl mode MSI to linux irq\n", pci_name(pdev)); return -ENOMEM; @@ -374,7 +374,7 @@ void pnv_cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev) return; for_each_pci_msi_entry(entry, pdev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; hwirq = virq_to_hw(entry->irq); irq_set_msi_desc(entry->irq, NULL); diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index a21d831c1114..d6a4a61ede3d 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -186,7 +186,7 @@ int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return -ENOSPC; } virq = irq_create_mapping(NULL, phb->msi_base + hwirq); - if (virq == NO_IRQ) { + if (!virq) { pr_warn("%s: Failed to map MSI to linux irq\n", pci_name(pdev)); msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq, 1); @@ -217,7 +217,7 @@ void pnv_teardown_msi_irqs(struct pci_dev *pdev) return; for_each_pci_msi_entry(entry, pdev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; hwirq = virq_to_hw(entry->irq); irq_set_msi_desc(entry->irq, NULL); diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index b831638e6f4a..98f8c3611133 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -192,7 +192,7 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, *virq = irq_create_mapping(NULL, outlet); - if (*virq == NO_IRQ) { + if (!*virq) { FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n", __func__, __LINE__, outlet); result = -ENOMEM; @@ -339,7 +339,7 @@ int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq) if (result) { FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n", __func__, __LINE__, ps3_result(result)); - *virq = NO_IRQ; + *virq = 0; return result; } @@ -418,7 +418,7 @@ int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, " failed: %s\n", __func__, __LINE__, ps3_result(result)); ps3_event_receive_port_destroy(*virq); - *virq = NO_IRQ; + *virq = 0; return result; } @@ -724,12 +724,12 @@ static unsigned int ps3_get_irq(void) asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x)); plug &= 0x3f; - if (unlikely(plug == NO_IRQ)) { + if (unlikely(!plug)) { DBG("%s:%d: no plug found: thread_id %llu\n", __func__, __LINE__, pd->thread_id); dump_bmp(&per_cpu(ps3_private, 0)); dump_bmp(&per_cpu(ps3_private, 1)); - return NO_IRQ; + return 0; } #if defined(DEBUG) diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 3c7707af3384..60154d08debf 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -91,7 +91,7 @@ static void __init ps3_smp_probe(void) result = smp_request_message_ipi(virqs[i], i); if (result) - virqs[i] = NO_IRQ; + virqs[i] = 0; else ps3_register_ipi_irq(cpu, virqs[i]); } @@ -112,7 +112,7 @@ void ps3_smp_cleanup_cpu(int cpu) for (i = 0; i < MSG_COUNT; i++) { /* Can't call free_irq from interrupt context. */ ps3_event_receive_port_destroy(virqs[i]); - virqs[i] = NO_IRQ; + virqs[i] = 0; } DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu); diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 492b2575e0d2..b54850845466 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -284,7 +284,7 @@ fail_alloc_2: fail_alloc_1: ps3_spe_irq_destroy(spu->irqs[0]); fail_alloc_0: - spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ; + spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = 0; return result; } @@ -334,7 +334,7 @@ static int ps3_destroy_spu(struct spu *spu) ps3_spe_irq_destroy(spu->irqs[1]); ps3_spe_irq_destroy(spu->irqs[0]); - spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ; + spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = 0; spu_unmap(spu); diff --git a/arch/powerpc/platforms/pseries/event_sources.c b/arch/powerpc/platforms/pseries/event_sources.c index a6ddca833119..32187dc76730 100644 --- a/arch/powerpc/platforms/pseries/event_sources.c +++ b/arch/powerpc/platforms/pseries/event_sources.c @@ -34,7 +34,7 @@ void request_event_sources_irqs(struct device_node *np, if (count > 15) break; virqs[count] = irq_create_of_mapping(&oirq); - if (virqs[count] == NO_IRQ) { + if (!virqs[count]) { pr_err("event-sources: Unable to allocate " "interrupt number for %s\n", np->full_name); diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 543a6386f3eb..326ef0dd6038 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -119,7 +119,7 @@ static void rtas_teardown_msi_irqs(struct pci_dev *pdev) struct msi_desc *entry; for_each_pci_msi_entry(entry, pdev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; irq_set_msi_desc(entry->irq, NULL); @@ -471,7 +471,7 @@ again: virq = irq_create_mapping(NULL, hwirq); - if (virq == NO_IRQ) { + if (!virq) { pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq); return -ENOSPC; } @@ -490,7 +490,7 @@ again: static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev) { /* No LSI -> leave MSIs (if any) configured */ - if (pdev->irq == NO_IRQ) { + if (!pdev->irq) { dev_dbg(&pdev->dev, "rtas_msi: no LSI, nothing to do.\n"); return; } diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 4ffcaa6f8670..776900043e2a 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -114,7 +114,7 @@ static void pseries_8259_cascade(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq = i8259_irq(); - if (cascade_irq != NO_IRQ) + if (cascade_irq) generic_handle_irq(cascade_irq); chip->irq_eoi(&desc->irq_data); @@ -141,7 +141,7 @@ static void __init pseries_setup_i8259_cascade(void) } cascade = irq_of_parse_and_map(found, 0); - if (cascade == NO_IRQ) { + if (!cascade) { printk(KERN_ERR "pic: failed to map cascade interrupt"); return; } diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 9144204442eb..ada29eaed6e2 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -240,7 +240,7 @@ static int axon_ram_probe(struct platform_device *device) device_add_disk(&device->dev, bank->disk); bank->irq_id = irq_of_parse_and_map(device->dev.of_node, 0); - if (bank->irq_id == NO_IRQ) { + if (!bank->irq_id) { dev_err(&device->dev, "Cannot access ECC interrupt ID\n"); rc = -EFAULT; goto failed; @@ -250,7 +250,7 @@ static int axon_ram_probe(struct platform_device *device) AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device); if (rc != 0) { dev_err(&device->dev, "Cannot register ECC interrupt handler\n"); - bank->irq_id = NO_IRQ; + bank->irq_id = 0; rc = -EFAULT; goto failed; } @@ -268,7 +268,7 @@ static int axon_ram_probe(struct platform_device *device) failed: if (bank != NULL) { - if (bank->irq_id != NO_IRQ) + if (bank->irq_id) free_irq(bank->irq_id, device); if (bank->disk != NULL) { if (bank->disk->major > 0) diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 81d49476c47e..3c0eb9b25535 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -132,7 +132,7 @@ unsigned int cpm_pic_init(void) { struct device_node *np = NULL; struct resource res; - unsigned int sirq = NO_IRQ, hwirq, eirq; + unsigned int sirq = 0, hwirq, eirq; int ret; pr_debug("cpm_pic_init\n"); @@ -154,7 +154,7 @@ unsigned int cpm_pic_init(void) goto end; sirq = irq_of_parse_and_map(np, 0); - if (sirq == NO_IRQ) + if (!sirq) goto end; /* Initialize the CPM interrupt controller. */ @@ -168,7 +168,7 @@ unsigned int cpm_pic_init(void) cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL); if (cpm_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); - sirq = NO_IRQ; + sirq = 0; goto end; } @@ -182,7 +182,7 @@ unsigned int cpm_pic_init(void) } eirq = irq_of_parse_and_map(np, 0); - if (eirq == NO_IRQ) + if (!eirq) goto end; if (setup_irq(eirq, &cpm_error_irqaction)) diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index bffcc7a486a1..48866e6c1efb 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -155,7 +155,7 @@ static struct irq_chip ehv_pic_direct_eoi_irq_chip = { .irq_set_type = ehv_pic_set_irq_type, }; -/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ +/* Return an interrupt vector or 0 if no interrupt is pending. */ unsigned int ehv_pic_get_irq(void) { int irq; @@ -168,7 +168,7 @@ unsigned int ehv_pic_get_irq(void) ev_int_iack(0, &irq); /* legacy mode */ if (irq == 0xFFFF) /* 0xFFFF --> no irq is pending */ - return NO_IRQ; + return 0; /* * this will also setup revmap[] in the slow path for the first diff --git a/arch/powerpc/sysdev/fsl_gtm.c b/arch/powerpc/sysdev/fsl_gtm.c index 06ac3c61b3d0..a6f0b96ce2c9 100644 --- a/arch/powerpc/sysdev/fsl_gtm.c +++ b/arch/powerpc/sysdev/fsl_gtm.c @@ -406,7 +406,7 @@ static int __init fsl_gtm_init(void) unsigned int irq; irq = irq_of_parse_and_map(np, i); - if (irq == NO_IRQ) { + if (!irq) { pr_err("%s: not enough interrupts specified\n", np->full_name); goto err; diff --git a/arch/powerpc/sysdev/fsl_mpic_err.c b/arch/powerpc/sysdev/fsl_mpic_err.c index b83f32562a37..488ec453038a 100644 --- a/arch/powerpc/sysdev/fsl_mpic_err.c +++ b/arch/powerpc/sysdev/fsl_mpic_err.c @@ -115,8 +115,8 @@ static irqreturn_t fsl_error_int_handler(int irq, void *data) errint = __builtin_clz(eisr); cascade_irq = irq_linear_revmap(mpic->irqhost, mpic->err_int_vecs[errint]); - WARN_ON(cascade_irq == NO_IRQ); - if (cascade_irq != NO_IRQ) { + WARN_ON(!cascade_irq); + if (cascade_irq) { generic_handle_irq(cascade_irq); } else { eimr |= 1 << (31 - errint); @@ -134,7 +134,7 @@ void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum) int ret; virq = irq_create_mapping(mpic->irqhost, irqnum); - if (virq == NO_IRQ) { + if (!virq) { pr_err("Error interrupt setup failed\n"); return; } diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 3a2be3676f43..8a244828782e 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -131,7 +131,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) irq_hw_number_t hwirq; for_each_pci_msi_entry(entry, pdev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; hwirq = virq_to_hw(entry->irq); msi_data = irq_get_chip_data(entry->irq); @@ -250,7 +250,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) virq = irq_create_mapping(msi_data->irqhost, hwirq); - if (virq == NO_IRQ) { + if (!virq) { dev_err(&pdev->dev, "fail mapping hwirq %i\n", hwirq); msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1); rc = -ENOSPC; @@ -285,7 +285,7 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data) msir_index = cascade_data->index; if (msir_index >= NR_MSI_REG_MAX) - cascade_irq = NO_IRQ; + cascade_irq = 0; switch (msi_data->feature & FSL_PIC_IP_MASK) { case FSL_PIC_IP_MPIC: @@ -315,7 +315,7 @@ static irqreturn_t fsl_msi_cascade(int irq, void *data) cascade_irq = irq_linear_revmap(msi_data->irqhost, msi_hwirq(msi_data, msir_index, intr_index + have_shift)); - if (cascade_irq != NO_IRQ) { + if (cascade_irq) { generic_handle_irq(cascade_irq); ret = IRQ_HANDLED; } @@ -337,7 +337,7 @@ static int fsl_of_msi_remove(struct platform_device *ofdev) if (msi->cascade_array[i]) { virq = msi->cascade_array[i]->virq; - BUG_ON(virq == NO_IRQ); + BUG_ON(!virq); free_irq(virq, msi->cascade_array[i]); kfree(msi->cascade_array[i]); @@ -362,7 +362,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, int virt_msir, i, ret; virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index); - if (virt_msir == NO_IRQ) { + if (!virt_msir) { dev_err(&dev->dev, "%s: Cannot translate IRQ index %d\n", __func__, irq_index); return 0; diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c index d57b77573068..02553a8ce191 100644 --- a/arch/powerpc/sysdev/ge/ge_pic.c +++ b/arch/powerpc/sysdev/ge/ge_pic.c @@ -102,7 +102,7 @@ static void gef_pic_cascade(struct irq_desc *desc) */ cascade_irq = gef_pic_get_irq(); - if (cascade_irq != NO_IRQ) + if (cascade_irq) generic_handle_irq(cascade_irq); chip->irq_eoi(&desc->irq_data); @@ -206,7 +206,7 @@ void __init gef_pic_init(struct device_node *np) /* Map controller */ gef_pic_cascade_irq = irq_of_parse_and_map(np, 0); - if (gef_pic_cascade_irq == NO_IRQ) { + if (!gef_pic_cascade_irq) { printk(KERN_ERR "SBC610: failed to map cascade interrupt"); return; } @@ -223,12 +223,12 @@ void __init gef_pic_init(struct device_node *np) /* * This is called when we receive an interrupt with apparently comes from this - * chip - check, returning the highest interrupt generated or return NO_IRQ + * chip - check, returning the highest interrupt generated or return 0. */ unsigned int gef_pic_get_irq(void) { u32 cause, mask, active; - unsigned int virq = NO_IRQ; + unsigned int virq = 0; int hwirq; cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS); diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index aa2c186d3115..bafb014e1a7e 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -68,9 +68,9 @@ unsigned int i8259_irq(void) if (!pci_intack) outb(0x0B, 0x20); /* ISR register */ if(~inb(0x20) & 0x80) - irq = NO_IRQ; + irq = 0; } else if (irq == 0xff) - irq = NO_IRQ; + irq = 0; if (lock) raw_spin_unlock(&i8259_lock); diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index f76ee39cb337..f267ee0afc08 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -853,7 +853,7 @@ void ipic_clear_mcp_status(u32 mask) ipic_write(primary_ipic->regs, IPIC_SERMR, mask); } -/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ +/* Return an interrupt vector or 0 if no interrupt is pending. */ unsigned int ipic_get_irq(void) { int irq; @@ -864,7 +864,7 @@ unsigned int ipic_get_irq(void) irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & IPIC_SIVCR_VECTOR_MASK; if (irq == 0) /* 0 --> no irq is pending */ - return NO_IRQ; + return 0; return irq_linear_revmap(primary_ipic->irqhost, irq); } diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index b7cf7abff2eb..3e828b20c21e 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -79,7 +79,7 @@ unsigned int mpc8xx_get_irq(void) irq = in_be32(&siu_reg->sc_sivec) >> 26; if (irq == PIC_VEC_SPURRIOUS) - irq = NO_IRQ; + irq = 0; return irq_linear_revmap(mpc8xx_pic_host, irq); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 7de45b2df366..4d48cecfedd1 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1649,7 +1649,7 @@ void __init mpic_init(struct mpic *mpic) /* Check if this MPIC is chained from a parent interrupt controller */ if (mpic->flags & MPIC_SECONDARY) { int virq = irq_of_parse_and_map(mpic->node, 0); - if (virq != NO_IRQ) { + if (virq) { printk(KERN_INFO "%s: hooking up to IRQ %d\n", mpic->node->full_name, virq); irq_set_handler_data(virq, mpic); @@ -1778,13 +1778,13 @@ static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) if (unlikely(src == mpic->spurious_vec)) { if (mpic->flags & MPIC_SPV_EOI) mpic_eoi(mpic); - return NO_IRQ; + return 0; } if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", mpic->name, (int)src); mpic_eoi(mpic); - return NO_IRQ; + return 0; } return irq_linear_revmap(mpic->irqhost, src); @@ -1817,17 +1817,17 @@ unsigned int mpic_get_coreint_irq(void) if (unlikely(src == mpic->spurious_vec)) { if (mpic->flags & MPIC_SPV_EOI) mpic_eoi(mpic); - return NO_IRQ; + return 0; } if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", mpic->name, (int)src); - return NO_IRQ; + return 0; } return irq_linear_revmap(mpic->irqhost, src); #else - return NO_IRQ; + return 0; #endif } @@ -1852,7 +1852,7 @@ void mpic_request_ipis(void) for (i = 0; i < 4; i++) { unsigned int vipi = irq_create_mapping(mpic->irqhost, mpic->ipi_vecs[0] + i); - if (vipi == NO_IRQ) { + if (!vipi) { printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); continue; } diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c index 3f165d972a0e..db2286be5d9a 100644 --- a/arch/powerpc/sysdev/mpic_msgr.c +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -238,7 +238,7 @@ static int mpic_msgr_probe(struct platform_device *dev) if (receive_mask & (1 << i)) { msgr->irq = irq_of_parse_and_map(np, irq_index); - if (msgr->irq == NO_IRQ) { + if (!msgr->irq) { dev_err(&dev->dev, "Missing interrupt specifier"); kfree(msgr); @@ -246,7 +246,7 @@ static int mpic_msgr_probe(struct platform_device *dev) } irq_index += 1; } else { - msgr->irq = NO_IRQ; + msgr->irq = 0; } mpic_msgrs[reg_number] = msgr; diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 2cbc7e29b85f..cfc1c57d760f 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -110,7 +110,7 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) irq_hw_number_t hwirq; for_each_pci_msi_entry(entry, pdev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; hwirq = virq_to_hw(entry->irq); @@ -155,7 +155,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) msg.address_hi = addr >> 32; virq = irq_create_mapping(msi_mpic->irqhost, hwirq); - if (virq == NO_IRQ) { + if (!virq) { pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq); msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1); return -ENOSPC; diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 0f842dd16bcd..a79953deb489 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -272,7 +272,7 @@ unsigned int mv64x60_get_irq(void) u32 cause; int level1; irq_hw_number_t hwirq; - int virq = NO_IRQ; + int virq = 0; cause = in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_SELECT_CAUSE); if (cause & MV64X60_SELECT_CAUSE_HIGH) { diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c index 8a0b77a3ec0c..9ea6a221d9d5 100644 --- a/arch/powerpc/sysdev/pmi.c +++ b/arch/powerpc/sysdev/pmi.c @@ -158,7 +158,7 @@ static int pmi_of_probe(struct platform_device *dev) data->dev = dev; data->irq = irq_of_parse_and_map(np, 0); - if (data->irq == NO_IRQ) { + if (!data->irq) { printk(KERN_ERR "pmi: invalid interrupt.\n"); rc = -EFAULT; goto error_cleanup_iomap; diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c index 52a93dcae262..9926ad67af76 100644 --- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c @@ -60,7 +60,7 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) } hwirq = ppc4xx_hsta_msi.irq_map[irq]; - if (hwirq == NO_IRQ) { + if (!hwirq) { pr_err("%s: Failed mapping irq %d\n", __func__, irq); return -EINVAL; } @@ -110,7 +110,7 @@ static void hsta_teardown_msi_irqs(struct pci_dev *dev) int irq; for_each_pci_msi_entry(entry, dev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; irq = hsta_find_hwirq_offset(entry->irq); @@ -166,7 +166,7 @@ static int hsta_msi_probe(struct platform_device *pdev) for (irq = 0; irq < irq_count; irq++) { ppc4xx_hsta_msi.irq_map[irq] = irq_of_parse_and_map(dev->of_node, irq); - if (ppc4xx_hsta_msi.irq_map[irq] == NO_IRQ) { + if (!ppc4xx_hsta_msi.irq_map[irq]) { dev_err(dev, "Unable to map IRQ\n"); ret = -EINVAL; goto out2; diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c index 8fb806135043..590dab4f47d6 100644 --- a/arch/powerpc/sysdev/ppc4xx_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_msi.c @@ -102,7 +102,7 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) __func__); } virq = irq_of_parse_and_map(msi_data->msi_dev, int_no); - if (virq == NO_IRQ) { + if (!virq) { dev_err(&dev->dev, "%s: fail mapping irq\n", __func__); msi_bitmap_free_hwirqs(&msi_data->bitmap, int_no, 1); return -ENOSPC; @@ -129,7 +129,7 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev) dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n"); for_each_pci_msi_entry(entry, dev) { - if (entry->irq == NO_IRQ) + if (!entry->irq) continue; hwirq = virq_to_hw(entry->irq); irq_set_msi_desc(entry->irq, NULL); @@ -201,7 +201,7 @@ static int ppc4xx_of_msi_remove(struct platform_device *dev) for (i = 0; i < msi_irqs; i++) { virq = msi->msi_virqs[i]; - if (virq != NO_IRQ) + if (virq) irq_dispose_mapping(virq); } diff --git a/arch/powerpc/sysdev/ppc4xx_soc.c b/arch/powerpc/sysdev/ppc4xx_soc.c index 5c77c9ba33aa..d41134d2f786 100644 --- a/arch/powerpc/sysdev/ppc4xx_soc.c +++ b/arch/powerpc/sysdev/ppc4xx_soc.c @@ -109,7 +109,7 @@ static int __init ppc4xx_l2c_probe(void) /* Get and map irq number from device tree */ irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { printk(KERN_ERR "irq_of_parse_and_map failed\n"); of_node_put(np); return -ENODEV; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 379de955aae3..57c971b7839c 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -433,7 +433,7 @@ void tsi108_irq_cascade(struct irq_desc *desc) struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq = get_pci_source(); - if (cascade_irq != NO_IRQ) + if (cascade_irq) generic_handle_irq(cascade_irq); chip->irq_eoi(&desc->irq_data); diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 6893d8f236df..a00949f3e378 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -319,7 +319,7 @@ void __init uic_init_tree(void) } } -/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ +/* Return an interrupt vector or 0 if no interrupt is pending. */ unsigned int uic_get_irq(void) { u32 msr; diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index c1917cf67c3d..e7fa26c4ff73 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -112,10 +112,10 @@ static unsigned int icp_hv_get_irq(void) unsigned int irq; if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; + return 0; irq = irq_find_mapping(xics_host, vec); - if (likely(irq != NO_IRQ)) { + if (likely(irq)) { xics_push_cppr(vec); return irq; } @@ -126,7 +126,7 @@ static unsigned int icp_hv_get_irq(void) /* We might learn about it later, so EOI it */ icp_hv_set_xirr(xirr); - return NO_IRQ; + return 0; } static void icp_hv_set_cpu_priority(unsigned char cppr) diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index afdf62f2a695..8a6a043e239b 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -124,10 +124,10 @@ static unsigned int icp_native_get_irq(void) unsigned int irq; if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; + return 0; irq = irq_find_mapping(xics_host, vec); - if (likely(irq != NO_IRQ)) { + if (likely(irq)) { xics_push_cppr(vec); return irq; } @@ -138,7 +138,7 @@ static unsigned int icp_native_get_irq(void) /* We might learn about it later, so EOI it */ icp_native_set_xirr(xirr); - return NO_IRQ; + return 0; } #ifdef CONFIG_SMP diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c index 57d72f10a97f..7357cfddb040 100644 --- a/arch/powerpc/sysdev/xics/icp-opal.c +++ b/arch/powerpc/sysdev/xics/icp-opal.c @@ -51,14 +51,14 @@ static unsigned int icp_opal_get_irq(void) rc = opal_int_get_xirr(&xirr, false); if (rc < 0) - return NO_IRQ; + return 0; xirr = be32_to_cpu(xirr); vec = xirr & 0x00ffffff; if (vec == XICS_IRQ_SPURIOUS) - return NO_IRQ; + return 0; irq = irq_find_mapping(xics_host, vec); - if (likely(irq != NO_IRQ)) { + if (likely(irq)) { xics_push_cppr(vec); return irq; } @@ -69,7 +69,7 @@ static unsigned int icp_opal_get_irq(void) /* We might learn about it later, so EOI it */ opal_int_eoi(xirr); - return NO_IRQ; + return 0; } static void icp_opal_set_cpu_priority(unsigned char cppr) diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index 9d530f479588..69d858e51ac7 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -131,7 +131,7 @@ static void xics_request_ipi(void) unsigned int ipi; ipi = irq_create_mapping(xics_host, XICS_IPI); - BUG_ON(ipi == NO_IRQ); + BUG_ON(!ipi); /* * IPIs are marked IRQF_PERCPU. The handler was set in map. diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index b6819f0fc608..3f041b187033 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -236,7 +236,7 @@ static void macio_create_fixup_irq(struct macio_dev *dev, int index, unsigned int irq; irq = irq_create_mapping(NULL, line); - if (irq != NO_IRQ) { + if (!irq) { dev->interrupt[index].start = irq; dev->interrupt[index].flags = IORESOURCE_IRQ; dev->interrupt[index].name = dev_name(&dev->ofdev.dev); @@ -299,7 +299,7 @@ static void macio_setup_interrupts(struct macio_dev *dev) break; res = &dev->interrupt[j]; irq = irq_of_parse_and_map(np, i++); - if (irq == NO_IRQ) + if (!irq) break; res->start = irq; res->flags = IORESOURCE_IRQ; diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 465c52219639..775527135b93 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -427,7 +427,7 @@ static int rackmeter_probe(struct macio_dev* mdev, rm->irq = macio_irq(mdev, 1); #else rm->irq = irq_of_parse_and_map(i2s, 1); - if (rm->irq == NO_IRQ || + if (!rm->irq || of_address_to_resource(i2s, 0, &ri2s) || of_address_to_resource(i2s, 1, &rdma)) { printk(KERN_ERR diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index d6f72c826c1c..08edb2c25b60 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -279,7 +279,7 @@ int smu_queue_cmd(struct smu_cmd *cmd) spin_unlock_irqrestore(&smu->lock, flags); /* Workaround for early calls when irq isn't available */ - if (!smu_irq_inited || smu->db_irq == NO_IRQ) + if (!smu_irq_inited || !smu->db_irq) smu_spinwait_cmd(cmd); return 0; @@ -498,8 +498,8 @@ int __init smu_init (void) INIT_LIST_HEAD(&smu->cmd_list); INIT_LIST_HEAD(&smu->cmd_i2c_list); smu->of_node = np; - smu->db_irq = NO_IRQ; - smu->msg_irq = NO_IRQ; + smu->db_irq = 0; + smu->msg_irq = 0; /* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a * 32 bits value safely @@ -587,13 +587,13 @@ static int smu_late_init(void) if (smu->db_node) { smu->db_irq = irq_of_parse_and_map(smu->db_node, 0); - if (smu->db_irq == NO_IRQ) + if (!smu->db_irq) printk(KERN_ERR "smu: failed to map irq for node %s\n", smu->db_node->full_name); } if (smu->msg_node) { smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0); - if (smu->msg_irq == NO_IRQ) + if (!smu->msg_irq) printk(KERN_ERR "smu: failed to map irq for node %s\n", smu->msg_node->full_name); } @@ -602,23 +602,23 @@ static int smu_late_init(void) * Try to request the interrupts */ - if (smu->db_irq != NO_IRQ) { + if (smu->db_irq) { if (request_irq(smu->db_irq, smu_db_intr, IRQF_SHARED, "SMU doorbell", smu) < 0) { printk(KERN_WARNING "SMU: can't " "request interrupt %d\n", smu->db_irq); - smu->db_irq = NO_IRQ; + smu->db_irq = 0; } } - if (smu->msg_irq != NO_IRQ) { + if (smu->msg_irq) { if (request_irq(smu->msg_irq, smu_msg_intr, IRQF_SHARED, "SMU message", smu) < 0) { printk(KERN_WARNING "SMU: can't " "request interrupt %d\n", smu->msg_irq); - smu->msg_irq = NO_IRQ; + smu->msg_irq = 0; } } diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index bad18130f125..2088e23a8002 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -209,7 +209,7 @@ static int __init via_cuda_start(void) cuda_irq = IRQ_MAC_ADB; #else cuda_irq = irq_of_parse_and_map(vias, 0); - if (cuda_irq == NO_IRQ) { + if (!cuda_irq) { printk(KERN_ERR "via-cuda: can't map interrupts for %s\n", vias->full_name); return -ENODEV; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index f8b6d1403c16..91081dcdc272 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -145,7 +145,7 @@ static int pmu_fully_inited; static int pmu_has_adb; static struct device_node *gpio_node; static unsigned char __iomem *gpio_reg; -static int gpio_irq = NO_IRQ; +static int gpio_irq = 0; static int gpio_irq_enabled = -1; static volatile int pmu_suspended; static spinlock_t pmu_lock; @@ -402,7 +402,7 @@ static int __init via_pmu_start(void) batt_req.complete = 1; irq = irq_of_parse_and_map(vias, 0); - if (irq == NO_IRQ) { + if (!irq) { printk(KERN_ERR "via-pmu: can't map interrupt\n"); return -ENODEV; } @@ -424,7 +424,7 @@ static int __init via_pmu_start(void) if (gpio_node) gpio_irq = irq_of_parse_and_map(gpio_node, 0); - if (gpio_irq != NO_IRQ) { + if (gpio_irq) { if (request_irq(gpio_irq, gpio1_interrupt, IRQF_NO_SUSPEND, "GPIO1 ADB", (void *)0)) diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c index 632701a1d993..b7f300b79ffd 100644 --- a/drivers/ps3/ps3-vuart.c +++ b/drivers/ps3/ps3-vuart.c @@ -958,7 +958,7 @@ static int ps3_vuart_bus_interrupt_get(void) fail_request_irq: ps3_vuart_irq_destroy(vuart_bus_priv.virq); - vuart_bus_priv.virq = NO_IRQ; + vuart_bus_priv.virq = 0; fail_alloc_irq: kfree(vuart_bus_priv.bmp); vuart_bus_priv.bmp = NULL; @@ -982,7 +982,7 @@ static int ps3_vuart_bus_interrupt_put(void) free_irq(vuart_bus_priv.virq, &vuart_bus_priv); ps3_vuart_irq_destroy(vuart_bus_priv.virq); - vuart_bus_priv.virq = NO_IRQ; + vuart_bus_priv.virq = 0; kfree(vuart_bus_priv.bmp); vuart_bus_priv.bmp = NULL; diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c index f34153962d07..71960089e207 100644 --- a/sound/aoa/core/gpio-feature.c +++ b/sound/aoa/core/gpio-feature.c @@ -118,7 +118,7 @@ static void get_irq(struct device_node * np, int *irqptr) if (np) *irqptr = irq_of_parse_and_map(np, 0); else - *irqptr = NO_IRQ; + *irqptr = 0; } /* 0x4 is outenable, 0x1 is out, thus 4 or 5 */ @@ -336,7 +336,7 @@ static int ftr_set_notify(struct gpio_runtime *rt, return -EINVAL; } - if (irq == NO_IRQ) + if (!irq) return -ENODEV; mutex_lock(¬if->mutex); diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index c8fafba218a5..58ee8089bbf9 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1303,19 +1303,19 @@ static int tumbler_init(struct snd_pmac *chip) &mix->line_mute, 1); irq = tumbler_find_device("headphone-detect", NULL, &mix->hp_detect, 0); - if (irq <= NO_IRQ) + if (irq <= 0) irq = tumbler_find_device("headphone-detect", NULL, &mix->hp_detect, 1); - if (irq <= NO_IRQ) + if (irq <= 0) irq = tumbler_find_device("keywest-gpio15", NULL, &mix->hp_detect, 1); mix->headphone_irq = irq; irq = tumbler_find_device("line-output-detect", NULL, &mix->line_detect, 0); - if (irq <= NO_IRQ) + if (irq <= 0) irq = tumbler_find_device("line-output-detect", NULL, &mix->line_detect, 1); - if (IS_G4DA && irq <= NO_IRQ) + if (IS_G4DA && irq <= 0) irq = tumbler_find_device("keywest-gpio16", NULL, &mix->line_detect, 1); mix->lineout_irq = irq; -- cgit v1.2.3 From fe036a0605d60d6c81ffdcd6241e9ae0013fe235 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 19 Aug 2016 14:22:37 +0530 Subject: powerpc/64/kexec: Fix MMU cleanup on radix Just using the hash ops won't work anymore since radix will have NULL in there. Instead create an mmu_cleanup_all() function which will do the right thing based on the MMU mode. For Radix, for now I clear UPRT and the PTCR, effectively switching back to Radix with no partition table setup. Currently set it to NULL on BookE thought it might be a good idea to wipe the TLB there (Scott ?) Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Aneesh Kumar K.V Acked-by: Balbir Singh Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/mmu-book3e.h | 3 +++ arch/powerpc/include/asm/mmu.h | 4 ++++ arch/powerpc/kernel/machine_kexec_64.c | 12 ++---------- arch/powerpc/mm/pgtable-book3s64.c | 9 +++++++++ arch/powerpc/mm/pgtable-radix.c | 12 ++++++++++++ 5 files changed, 30 insertions(+), 10 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h index cd4f04a74802..b62a8d43a06c 100644 --- a/arch/powerpc/include/asm/mmu-book3e.h +++ b/arch/powerpc/include/asm/mmu-book3e.h @@ -313,6 +313,9 @@ extern int book3e_htw_mode; * return 1, indicating that the tlb requires preloading. */ #define HUGETLB_NEED_PRELOAD + +#define mmu_cleanup_all NULL + #endif #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index e2fb408f8398..79c989a05aa1 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -204,6 +204,10 @@ extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup; * make it match the size our of bolted TLB area */ extern u64 ppc64_rma_size; + +/* Cleanup function used by kexec */ +extern void mmu_cleanup_all(void); +extern void radix__mmu_cleanup_all(void); #endif /* CONFIG_PPC64 */ struct mm_struct; diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 4c780a342282..7a7793211ae7 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -55,9 +55,6 @@ int default_machine_kexec_prepare(struct kimage *image) const unsigned long *basep; const unsigned int *sizep; - if (!mmu_hash_ops.hpte_clear_all) - return -ENOENT; - /* * Since we use the kernel fault handlers and paging code to * handle the virtual mode, we must make sure no destination @@ -379,13 +376,8 @@ void default_machine_kexec(struct kimage *image) * a toc is easier in C, so pass in what we can. */ kexec_sequence(&kexec_stack, image->start, image, - page_address(image->control_code_page), -#ifdef CONFIG_PPC_STD_MMU - mmu_hash_ops.hpte_clear_all -#else - NULL -#endif - ); + page_address(image->control_code_page), + mmu_cleanup_all); /* NOTREACHED */ } diff --git a/arch/powerpc/mm/pgtable-book3s64.c b/arch/powerpc/mm/pgtable-book3s64.c index 7328886bca4c..f4f437cbabf1 100644 --- a/arch/powerpc/mm/pgtable-book3s64.c +++ b/arch/powerpc/mm/pgtable-book3s64.c @@ -116,3 +116,12 @@ void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, return; } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +/* For use by kexec */ +void mmu_cleanup_all(void) +{ + if (radix_enabled()) + radix__mmu_cleanup_all(); + else if (mmu_hash_ops.hpte_clear_all) + mmu_hash_ops.hpte_clear_all(); +} diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c index 8f086352e421..ed7bddc456b7 100644 --- a/arch/powerpc/mm/pgtable-radix.c +++ b/arch/powerpc/mm/pgtable-radix.c @@ -396,6 +396,18 @@ void radix__early_init_mmu_secondary(void) } } +void radix__mmu_cleanup_all(void) +{ + unsigned long lpcr; + + if (!firmware_has_feature(FW_FEATURE_LPAR)) { + lpcr = mfspr(SPRN_LPCR); + mtspr(SPRN_LPCR, lpcr & ~LPCR_UPRT); + mtspr(SPRN_PTCR, 0); + radix__flush_tlb_all(); + } +} + void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base, phys_addr_t first_memblock_size) { -- cgit v1.2.3 From be34d300597a7a4fb38c6e3f9929af2f1faa23b8 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 23 Aug 2016 16:27:48 +0530 Subject: powerpc/mm: Add radix flush all with IS=3 Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- .../powerpc/include/asm/book3s/64/tlbflush-radix.h | 1 + arch/powerpc/mm/tlb-radix.c | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h index 65037762b120..a9e19cb2f7c5 100644 --- a/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h +++ b/arch/powerpc/include/asm/book3s/64/tlbflush-radix.h @@ -41,4 +41,5 @@ extern void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmad extern void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa, unsigned long page_size); extern void radix__flush_tlb_lpid(unsigned long lpid); +extern void radix__flush_tlb_all(void); #endif diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c index 48df05ef5231..0e49ec541ab5 100644 --- a/arch/powerpc/mm/tlb-radix.c +++ b/arch/powerpc/mm/tlb-radix.c @@ -400,3 +400,27 @@ void radix__flush_pmd_tlb_range(struct vm_area_struct *vma, radix__flush_tlb_range_psize(vma->vm_mm, start, end, MMU_PAGE_2M); } EXPORT_SYMBOL(radix__flush_pmd_tlb_range); + +void radix__flush_tlb_all(void) +{ + unsigned long rb,prs,r,rs; + unsigned long ric = RIC_FLUSH_ALL; + + rb = 0x3 << PPC_BITLSHIFT(53); /* IS = 3 */ + prs = 0; /* partition scoped */ + r = 1; /* raidx format */ + rs = 1 & ((1UL << 32) - 1); /* any LPID value to flush guest mappings */ + + asm volatile("ptesync": : :"memory"); + /* + * now flush guest entries by passing PRS = 1 and LPID != 0 + */ + asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) + : : "r"(rb), "i"(r), "i"(1), "i"(ric), "r"(rs) : "memory"); + /* + * now flush host entires by passing PRS = 0 and LPID == 0 + */ + asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) + : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(0) : "memory"); + asm volatile("eieio; tlbsync; ptesync": : :"memory"); +} -- cgit v1.2.3 From a24553dd02dc6c7d2912af0b4b9c7f833c90e561 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 13 Sep 2016 13:08:40 +1000 Subject: powerpc/pseries: Remove unnecessary syscall trampoline When we originally added the ability to split the exception vectors from the kernel (commit 1f6a93e4c35e ("powerpc: Make it possible to move the interrupt handlers away from the kernel" 2008-09-15)), the LOAD_HANDLER() macro used an addi instruction to compute the offset of the common handler from the kernel base address. Using addi meant the handler had to be within 32K of the kernel base address, due to the addi instruction taking a signed immediate value. That necessitated creating a trampoline for the system call handler, because system_call_common (in entry64.S) is not linked within 32K of the kernel base address. Later in commit 61e2390ede3c ("powerpc: Make load_hander handle upto 64k offset" 2012-11-15) we changed LOAD_HANDLER to take a 64K offset, by changing it to use ori. Although system_call_common is not in head_64.S or exceptions-64s.S, it is included in head-y, which causes it to be linked early in the kernel text, so in practice it ends up below 64K. Additionally if it can't be placed below 64K the linker will fail to build with a "relocation truncated to fit" error. So remove the trampoline. Newer toolchains are able to work out that the ori in LOAD_HANDLER only takes a 16 bit offset, and so they generate a 16 bit relocation. Older toolchains (binutils 2.22 at least) are not so smart, so we have to add the @l annotation to tell the assembler to generate a 16 bit relocation. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/exception-64s.h | 2 +- arch/powerpc/kernel/exceptions-64s.S | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index c2606715cfff..5032a80e8f6a 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -90,7 +90,7 @@ */ #define LOAD_HANDLER(reg, label) \ ld reg,PACAKBASE(r13); /* get high part of &label */ \ - ori reg,reg,(label)-_stext; /* virt addr of handler ... */ + ori reg,reg,((label)-_stext)@l; /* virt addr of handler ... */ /* Exception register prefixes */ #define EXC_HV H diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index a91308d6abaf..23018162d749 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -41,7 +41,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ #define SYSCALL_PSERIES_2_RFID \ mfspr r12,SPRN_SRR1 ; \ - LOAD_HANDLER(r10, system_call_entry) ; \ + LOAD_HANDLER(r10, system_call_common) ; \ mtspr SPRN_SRR0,r10 ; \ ld r10,PACAKMSR(r13) ; \ mtspr SPRN_SRR1,r10 ; \ @@ -62,7 +62,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ * is volatile across system calls. */ #define SYSCALL_PSERIES_2_DIRECT \ - LOAD_HANDLER(r12, system_call_entry) ; \ + LOAD_HANDLER(r12, system_call_common) ; \ mtctr r12 ; \ mfspr r12,SPRN_SRR1 ; \ li r10,MSR_RI ; \ @@ -902,10 +902,6 @@ hv_facility_unavailable_relon_trampoline: #endif STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist) - .align 7 -system_call_entry: - b system_call_common - ppc64_runlatch_on_trampoline: b __ppc64_runlatch_on -- cgit v1.2.3 From 6b8cb66a6a7cc182b47da6a0a1d4e5da324c0695 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Mon, 19 Sep 2016 12:58:54 +0200 Subject: powerpc: Fix usage of _PAGE_RO in hugepage On some CPUs like the 8xx, _PAGE_RW hence _PAGE_WRITE is defined as 0 and _PAGE_RO has to be set when a page is not writable _PAGE_RO is defined by default in pte-common.h, however BOOK3S/64 doesn't include that file so _PAGE_RO has to be defined explicitly in book3s/64/pgtable.h Fixes: a7b9f671f2d14 ("powerpc32: adds handling of _PAGE_RO") Signed-off-by: Christophe Leroy Reviewed-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/book3s/64/pgtable.h | 2 ++ arch/powerpc/mm/hugetlbpage.c | 7 +++++++ 2 files changed, 9 insertions(+) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index 8ec8be9495ba..9fd77f8794a0 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -6,6 +6,8 @@ */ #define _PAGE_BIT_SWAP_TYPE 0 +#define _PAGE_RO 0 + #define _PAGE_EXEC 0x00001 /* execute permission */ #define _PAGE_WRITE 0x00002 /* write access allowed */ #define _PAGE_READ 0x00004 /* read access allowed */ diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 7372ee13eb1e..a5d3ecdabc44 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -1019,8 +1019,15 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr, pte = READ_ONCE(*ptep); mask = _PAGE_PRESENT | _PAGE_READ; + + /* + * On some CPUs like the 8xx, _PAGE_RW hence _PAGE_WRITE is defined + * as 0 and _PAGE_RO has to be set when a page is not writable + */ if (write) mask |= _PAGE_WRITE; + else + mask |= _PAGE_RO; if ((pte_val(pte) & mask) != mask) return 0; -- cgit v1.2.3 From 148151a66a74bf43c6acc932a3f6cca464837b78 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 5 Aug 2016 13:27:59 +0200 Subject: powerpc/32: Remove CLR_TOP32 CLR_TOP32() is defined as blank. Last useful instance of CLR_TOP32() was removed by commit 40ef8cbc6d360 ("powerpc: Get 64-bit configs to compile with ARCH=powerpc") in 2005. Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc_asm.h | 1 - arch/powerpc/kernel/entry_32.S | 1 - arch/powerpc/kernel/head_32.S | 3 --- arch/powerpc/kernel/head_8xx.S | 1 - 4 files changed, 6 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index bb566854ff2a..c73750b0d9fa 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -511,7 +511,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601) #endif #define MTMSRD(r) mtmsr r #define MTMSR_EERI(reg) mtmsr reg -#define CLR_TOP32(r) #endif #endif /* __KERNEL__ */ diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 9899032230b4..83428a283fa0 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -654,7 +654,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPE) #endif /* CONFIG_SMP */ tophys(r0,r4) - CLR_TOP32(r0) mtspr SPRN_SPRG_THREAD,r0 /* Update current THREAD phys addr */ lwz r1,KSP(r4) /* Load new stack pointer */ diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index dc0488b6f6e1..a3f821eb7e9a 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S @@ -266,7 +266,6 @@ __secondary_hold_acknowledge: #define EXCEPTION_PROLOG_2 \ - CLR_TOP32(r11); \ stw r10,_CCR(r11); /* save registers */ \ stw r12,GPR12(r11); \ stw r9,GPR9(r11); \ @@ -862,7 +861,6 @@ __secondary_start: /* ptr to phys current thread */ tophys(r4,r2) addi r4,r4,THREAD /* phys address of our thread_struct */ - CLR_TOP32(r4) mtspr SPRN_SPRG_THREAD,r4 li r3,0 mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */ @@ -949,7 +947,6 @@ start_here: /* ptr to phys current thread */ tophys(r4,r2) addi r4,r4,THREAD /* init task's THREAD */ - CLR_TOP32(r4) mtspr SPRN_SPRG_THREAD,r4 li r3,0 mtspr SPRN_SPRG_RTAS,r3 /* 0 => not in RTAS */ diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 43ddaae42baf..3a185c51ce8f 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -151,7 +151,6 @@ turn_on_mmu: #define EXCEPTION_PROLOG_2 \ - CLR_TOP32(r11); \ stw r10,_CCR(r11); /* save registers */ \ stw r12,GPR12(r11); \ stw r9,GPR9(r11); \ -- cgit v1.2.3 From 360aebd85a4c946764f6301d68de2a817fad5159 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 28 Sep 2016 14:34:58 +1000 Subject: drivers/pci/hotplug: Support surprise hotplug in powernv driver This supports PCI surprise hotplug. The design is highlighted as below: * The PCI slot's surprise hotplug capability is exposed through device node property "ibm,slot-surprise-pluggable", meaning PCI surprise hotplug will be disabled if skiboot doesn't support it yet. * The interrupt because of presence or link state change is raised on surprise hotplug event. One event is allocated and queued to the PCI slot for workqueue to pick it up and process in serialized fashion. The code flow for surprise hotplug is same to that for managed hotplug except: the affected PEs are put into frozen state to avoid unexpected EEH error reporting in surprise hot remove path. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/pnv-pci.h | 2 + drivers/pci/hotplug/pnv_php.c | 214 +++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h index 0cbd8134ce81..17e89dd613e1 100644 --- a/arch/powerpc/include/asm/pnv-pci.h +++ b/arch/powerpc/include/asm/pnv-pci.h @@ -60,6 +60,8 @@ struct pnv_php_slot { #define PNV_PHP_STATE_POPULATED 2 #define PNV_PHP_STATE_OFFLINE 3 int state; + int irq; + struct workqueue_struct *wq; struct device_node *dn; struct pci_dev *pdev; struct pci_bus *bus; diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 182f218dce4f..5dd0d4f2f907 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -22,6 +22,12 @@ #define DRIVER_AUTHOR "Gavin Shan, IBM Corporation" #define DRIVER_DESC "PowerPC PowerNV PCI Hotplug Driver" +struct pnv_php_event { + bool added; + struct pnv_php_slot *php_slot; + struct work_struct work; +}; + static LIST_HEAD(pnv_php_slot_list); static DEFINE_SPINLOCK(pnv_php_lock); @@ -29,12 +35,40 @@ static void pnv_php_register(struct device_node *dn); static void pnv_php_unregister_one(struct device_node *dn); static void pnv_php_unregister(struct device_node *dn); +static void pnv_php_disable_irq(struct pnv_php_slot *php_slot) +{ + struct pci_dev *pdev = php_slot->pdev; + u16 ctrl; + + if (php_slot->irq > 0) { + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl); + ctrl &= ~(PCI_EXP_SLTCTL_HPIE | + PCI_EXP_SLTCTL_PDCE | + PCI_EXP_SLTCTL_DLLSCE); + pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl); + + free_irq(php_slot->irq, php_slot); + php_slot->irq = 0; + } + + if (php_slot->wq) { + destroy_workqueue(php_slot->wq); + php_slot->wq = NULL; + } + + if (pdev->msix_enabled) + pci_disable_msix(pdev); + else if (pdev->msi_enabled) + pci_disable_msi(pdev); +} + static void pnv_php_free_slot(struct kref *kref) { struct pnv_php_slot *php_slot = container_of(kref, struct pnv_php_slot, kref); WARN_ON(!list_empty(&php_slot->children)); + pnv_php_disable_irq(php_slot); kfree(php_slot->name); kfree(php_slot); } @@ -609,6 +643,181 @@ static int pnv_php_register_slot(struct pnv_php_slot *php_slot) return 0; } +static int pnv_php_enable_msix(struct pnv_php_slot *php_slot) +{ + struct pci_dev *pdev = php_slot->pdev; + struct msix_entry entry; + int nr_entries, ret; + u16 pcie_flag; + + /* Get total number of MSIx entries */ + nr_entries = pci_msix_vec_count(pdev); + if (nr_entries < 0) + return nr_entries; + + /* Check hotplug MSIx entry is in range */ + pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag); + entry.entry = (pcie_flag & PCI_EXP_FLAGS_IRQ) >> 9; + if (entry.entry >= nr_entries) + return -ERANGE; + + /* Enable MSIx */ + ret = pci_enable_msix_exact(pdev, &entry, 1); + if (ret) { + dev_warn(&pdev->dev, "Error %d enabling MSIx\n", ret); + return ret; + } + + return entry.vector; +} + +static void pnv_php_event_handler(struct work_struct *work) +{ + struct pnv_php_event *event = + container_of(work, struct pnv_php_event, work); + struct pnv_php_slot *php_slot = event->php_slot; + + if (event->added) + pnv_php_enable_slot(&php_slot->slot); + else + pnv_php_disable_slot(&php_slot->slot); + + kfree(event); +} + +static irqreturn_t pnv_php_interrupt(int irq, void *data) +{ + struct pnv_php_slot *php_slot = data; + struct pci_dev *pchild, *pdev = php_slot->pdev; + struct eeh_dev *edev; + struct eeh_pe *pe; + struct pnv_php_event *event; + u16 sts, lsts; + u8 presence; + bool added; + unsigned long flags; + int ret; + + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts); + sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts); + if (sts & PCI_EXP_SLTSTA_DLLSC) { + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts); + added = !!(lsts & PCI_EXP_LNKSTA_DLLLA); + } else if (sts & PCI_EXP_SLTSTA_PDC) { + ret = pnv_pci_get_presence_state(php_slot->id, &presence); + if (!ret) + return IRQ_HANDLED; + added = !!(presence == OPAL_PCI_SLOT_PRESENT); + } else { + return IRQ_NONE; + } + + /* Freeze the removed PE to avoid unexpected error reporting */ + if (!added) { + pchild = list_first_entry_or_null(&php_slot->bus->devices, + struct pci_dev, bus_list); + edev = pchild ? pci_dev_to_eeh_dev(pchild) : NULL; + pe = edev ? edev->pe : NULL; + if (pe) { + eeh_serialize_lock(&flags); + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); + eeh_serialize_unlock(flags); + eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE); + } + } + + /* + * The PE is left in frozen state if the event is missed. It's + * fine as the PCI devices (PE) aren't functional any more. + */ + event = kzalloc(sizeof(*event), GFP_ATOMIC); + if (!event) { + dev_warn(&pdev->dev, "PCI slot [%s] missed hotplug event 0x%04x\n", + php_slot->name, sts); + return IRQ_HANDLED; + } + + dev_info(&pdev->dev, "PCI slot [%s] %s (IRQ: %d)\n", + php_slot->name, added ? "added" : "removed", irq); + INIT_WORK(&event->work, pnv_php_event_handler); + event->added = added; + event->php_slot = php_slot; + queue_work(php_slot->wq, &event->work); + + return IRQ_HANDLED; +} + +static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq) +{ + struct pci_dev *pdev = php_slot->pdev; + u16 sts, ctrl; + int ret; + + /* Allocate workqueue */ + php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name); + if (!php_slot->wq) { + dev_warn(&pdev->dev, "Cannot alloc workqueue\n"); + pnv_php_disable_irq(php_slot); + return; + } + + /* Clear pending interrupts */ + pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts); + sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); + pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts); + + /* Request the interrupt */ + ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED, + php_slot->name, php_slot); + if (ret) { + pnv_php_disable_irq(php_slot); + dev_warn(&pdev->dev, "Error %d enabling IRQ %d\n", ret, irq); + return; + } + + /* Enable the interrupts */ + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl); + ctrl |= (PCI_EXP_SLTCTL_HPIE | + PCI_EXP_SLTCTL_PDCE | + PCI_EXP_SLTCTL_DLLSCE); + pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl); + + /* The interrupt is initialized successfully when @irq is valid */ + php_slot->irq = irq; +} + +static void pnv_php_enable_irq(struct pnv_php_slot *php_slot) +{ + struct pci_dev *pdev = php_slot->pdev; + int irq, ret; + + ret = pci_enable_device(pdev); + if (ret) { + dev_warn(&pdev->dev, "Error %d enabling device\n", ret); + return; + } + + pci_set_master(pdev); + + /* Enable MSIx interrupt */ + irq = pnv_php_enable_msix(php_slot); + if (irq > 0) { + pnv_php_init_irq(php_slot, irq); + return; + } + + /* + * Use MSI if MSIx doesn't work. Fail back to legacy INTx + * if MSI doesn't work either + */ + ret = pci_enable_msi(pdev); + if (!ret || pdev->irq) { + irq = pdev->irq; + pnv_php_init_irq(php_slot, irq); + } +} + static int pnv_php_register_one(struct device_node *dn) { struct pnv_php_slot *php_slot; @@ -636,6 +845,11 @@ static int pnv_php_register_one(struct device_node *dn) if (ret) goto unregister_slot; + /* Enable interrupt if the slot supports surprise hotplug */ + prop32 = of_get_property(dn, "ibm,slot-surprise-pluggable", NULL); + if (prop32 && of_read_number(prop32, 1)) + pnv_php_enable_irq(php_slot); + return 0; unregister_slot: -- cgit v1.2.3 From 2e5bbb5461f138cac631fe21b4ad956feabfba22 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Tue, 6 Sep 2016 16:27:31 +1000 Subject: KVM: PPC: Book3S HV: Migrate pinned pages out of CMA When PCI Device pass-through is enabled via VFIO, KVM-PPC will pin pages using get_user_pages_fast(). One of the downsides of the pinning is that the page could be in CMA region. The CMA region is used for other allocations like the hash page table. Ideally we want the pinned pages to be from non CMA region. This patch (currently only for KVM PPC with VFIO) forcefully migrates the pages out (huge pages are omitted for the moment). There are more efficient ways of doing this, but that might be elaborate and might impact a larger audience beyond just the kvm ppc implementation. The magic is in new_iommu_non_cma_page() which allocates the new page from a non CMA region. I've tested the patches lightly at my end. The full solution requires migration of THP pages in the CMA region. That work will be done incrementally on top of this. Signed-off-by: Balbir Singh Acked-by: Alexey Kardashevskiy [mpe: Merged via powerpc tree as that's where the changes are] Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/mmu_context.h | 1 + arch/powerpc/mm/mmu_context_iommu.c | 81 ++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 9d2cd0c36ec2..475d1be39191 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -18,6 +18,7 @@ extern void destroy_context(struct mm_struct *mm); #ifdef CONFIG_SPAPR_TCE_IOMMU struct mm_iommu_table_group_mem_t; +extern int isolate_lru_page(struct page *page); /* from internal.h */ extern bool mm_iommu_preregistered(void); extern long mm_iommu_get(unsigned long ua, unsigned long entries, struct mm_iommu_table_group_mem_t **pmem); diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index da6a2168ae9e..e0f1c33601dd 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include static DEFINE_MUTEX(mem_list_mutex); @@ -72,6 +75,55 @@ bool mm_iommu_preregistered(void) } EXPORT_SYMBOL_GPL(mm_iommu_preregistered); +/* + * Taken from alloc_migrate_target with changes to remove CMA allocations + */ +struct page *new_iommu_non_cma_page(struct page *page, unsigned long private, + int **resultp) +{ + gfp_t gfp_mask = GFP_USER; + struct page *new_page; + + if (PageHuge(page) || PageTransHuge(page) || PageCompound(page)) + return NULL; + + if (PageHighMem(page)) + gfp_mask |= __GFP_HIGHMEM; + + /* + * We don't want the allocation to force an OOM if possibe + */ + new_page = alloc_page(gfp_mask | __GFP_NORETRY | __GFP_NOWARN); + return new_page; +} + +static int mm_iommu_move_page_from_cma(struct page *page) +{ + int ret = 0; + LIST_HEAD(cma_migrate_pages); + + /* Ignore huge pages for now */ + if (PageHuge(page) || PageTransHuge(page) || PageCompound(page)) + return -EBUSY; + + lru_add_drain(); + ret = isolate_lru_page(page); + if (ret) + return ret; + + list_add(&page->lru, &cma_migrate_pages); + put_page(page); /* Drop the gup reference */ + + ret = migrate_pages(&cma_migrate_pages, new_iommu_non_cma_page, + NULL, 0, MIGRATE_SYNC, MR_CMA); + if (ret) { + if (!list_empty(&cma_migrate_pages)) + putback_movable_pages(&cma_migrate_pages); + } + + return 0; +} + long mm_iommu_get(unsigned long ua, unsigned long entries, struct mm_iommu_table_group_mem_t **pmem) { @@ -124,15 +176,36 @@ long mm_iommu_get(unsigned long ua, unsigned long entries, for (i = 0; i < entries; ++i) { if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT), 1/* pages */, 1/* iswrite */, &page)) { + ret = -EFAULT; for (j = 0; j < i; ++j) - put_page(pfn_to_page( - mem->hpas[j] >> PAGE_SHIFT)); + put_page(pfn_to_page(mem->hpas[j] >> + PAGE_SHIFT)); vfree(mem->hpas); kfree(mem); - ret = -EFAULT; goto unlock_exit; } - + /* + * If we get a page from the CMA zone, since we are going to + * be pinning these entries, we might as well move them out + * of the CMA zone if possible. NOTE: faulting in + migration + * can be expensive. Batching can be considered later + */ + if (get_pageblock_migratetype(page) == MIGRATE_CMA) { + if (mm_iommu_move_page_from_cma(page)) + goto populate; + if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT), + 1/* pages */, 1/* iswrite */, + &page)) { + ret = -EFAULT; + for (j = 0; j < i; ++j) + put_page(pfn_to_page(mem->hpas[j] >> + PAGE_SHIFT)); + vfree(mem->hpas); + kfree(mem); + goto unlock_exit; + } + } +populate: mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT; } -- cgit v1.2.3 From da2bc4644c75d992427c45c5ade3bdf18ca1b52d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 30 Sep 2016 19:43:18 +1000 Subject: powerpc/64s: Add new exception vector macros Create arch/powerpc/include/asm/head-64.h with macros that specify an exception vector (name, type, location), which will be used to label and lay out exceptions into the object file. Naming is moved out of exception-64s.h, which is used to specify the implementation of exception handlers. objdump of generated code in exception vectors is unchanged except for names. Alignment directives scattered around are annoying, but done this way so that disassembly can verify identical instruction generation before and after patch. These get cleaned up in future patch. We change the way KVMTEST works, explicitly passing EXC_HV or EXC_STD rather than overloading the trap number. This removes the need to have SOFTEN values for the overloaded trap numbers, eg. 0x502. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/exception-64s.h | 135 +++---- arch/powerpc/include/asm/head-64.h | 163 +++++++++ arch/powerpc/kernel/exceptions-64s.S | 597 +++++++++++++++---------------- 3 files changed, 504 insertions(+), 391 deletions(-) create mode 100644 arch/powerpc/include/asm/head-64.h (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 5032a80e8f6a..72f2b1e3f343 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -34,6 +34,7 @@ * exception handlers (including pSeries LPAR) and iSeries LPAR * implementations as possible. */ +#include #define EX_R9 0 #define EX_R10 8 @@ -191,10 +192,10 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) EXCEPTION_PROLOG_1(area, extra, vec); \ EXCEPTION_PROLOG_PSERIES_1(label, h); -#define __KVMTEST(n) \ - lbz r10,HSTATE_IN_GUEST(r13); \ +#define __KVMTEST(h, n) \ + lbz r10,HSTATE_IN_GUEST(r13); \ cmpwi r10,0; \ - bne do_kvm_##n + bne do_kvm_##h##n #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE /* @@ -207,8 +208,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) #define kvmppc_interrupt kvmppc_interrupt_pr #endif -#define __KVM_HANDLER(area, h, n) \ -do_kvm_##n: \ +#define __KVM_HANDLER_PROLOG(area, n) \ BEGIN_FTR_SECTION_NESTED(947) \ ld r10,area+EX_CFAR(r13); \ std r10,HSTATE_CFAR(r13); \ @@ -221,21 +221,23 @@ do_kvm_##n: \ stw r9,HSTATE_SCRATCH1(r13); \ ld r9,area+EX_R9(r13); \ std r12,HSTATE_SCRATCH0(r13); \ + +#define __KVM_HANDLER(area, h, n) \ + __KVM_HANDLER_PROLOG(area, n) \ li r12,n; \ b kvmppc_interrupt #define __KVM_HANDLER_SKIP(area, h, n) \ -do_kvm_##n: \ cmpwi r10,KVM_GUEST_MODE_SKIP; \ ld r10,area+EX_R10(r13); \ beq 89f; \ - stw r9,HSTATE_SCRATCH1(r13); \ + stw r9,HSTATE_SCRATCH1(r13); \ BEGIN_FTR_SECTION_NESTED(948) \ ld r9,area+EX_PPR(r13); \ std r9,HSTATE_PPR(r13); \ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,948); \ ld r9,area+EX_R9(r13); \ - std r12,HSTATE_SCRATCH0(r13); \ + std r12,HSTATE_SCRATCH0(r13); \ li r12,n; \ b kvmppc_interrupt; \ 89: mtocrf 0x80,r9; \ @@ -243,12 +245,12 @@ do_kvm_##n: \ b kvmppc_skip_##h##interrupt #ifdef CONFIG_KVM_BOOK3S_64_HANDLER -#define KVMTEST(n) __KVMTEST(n) +#define KVMTEST(h, n) __KVMTEST(h, n) #define KVM_HANDLER(area, h, n) __KVM_HANDLER(area, h, n) #define KVM_HANDLER_SKIP(area, h, n) __KVM_HANDLER_SKIP(area, h, n) #else -#define KVMTEST(n) +#define KVMTEST(h, n) #define KVM_HANDLER(area, h, n) #define KVM_HANDLER_SKIP(area, h, n) #endif @@ -332,94 +334,79 @@ do_kvm_##n: \ /* * Exception vectors. */ -#define STD_EXCEPTION_PSERIES(vec, label) \ - . = vec; \ - .globl label##_pSeries; \ -label##_pSeries: \ +#define STD_EXCEPTION_PSERIES(vec, label) \ SET_SCRATCH0(r13); /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ - EXC_STD, KVMTEST, vec) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label, \ + EXC_STD, KVMTEST_PR, vec); \ /* Version of above for when we have to branch out-of-line */ +#define __OOL_EXCEPTION(vec, label, hdlr) \ + SET_SCRATCH0(r13) \ + EXCEPTION_PROLOG_0(PACA_EXGEN) \ + b hdlr; + #define STD_EXCEPTION_PSERIES_OOL(vec, label) \ - .globl label##_pSeries; \ -label##_pSeries: \ - EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \ - EXCEPTION_PROLOG_PSERIES_1(label##_common, EXC_STD) - -#define STD_EXCEPTION_HV(loc, vec, label) \ - . = loc; \ - .globl label##_hv; \ -label##_hv: \ + EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \ + EXCEPTION_PROLOG_PSERIES_1(label, EXC_STD) + +#define STD_EXCEPTION_HV(loc, vec, label) \ SET_SCRATCH0(r13); /* save r13 */ \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ - EXC_HV, KVMTEST, vec) + EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label, \ + EXC_HV, KVMTEST_HV, 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_EXCEPTION_HV_OOL(vec, label) \ + EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, vec); \ + EXCEPTION_PROLOG_PSERIES_1(label, EXC_HV) #define STD_RELON_EXCEPTION_PSERIES(loc, vec, label) \ - . = loc; \ - .globl label##_relon_pSeries; \ -label##_relon_pSeries: \ /* No guest interrupts come through here */ \ SET_SCRATCH0(r13); /* save r13 */ \ - EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ - EXC_STD, NOTEST, vec) + EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label, EXC_STD, NOTEST, vec); #define STD_RELON_EXCEPTION_PSERIES_OOL(vec, label) \ - .globl label##_relon_pSeries; \ -label##_relon_pSeries: \ EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, vec); \ - EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_STD) + EXCEPTION_RELON_PROLOG_PSERIES_1(label, EXC_STD) #define STD_RELON_EXCEPTION_HV(loc, vec, label) \ - . = loc; \ - .globl label##_relon_hv; \ -label##_relon_hv: \ /* No guest interrupts come through here */ \ SET_SCRATCH0(r13); /* save r13 */ \ - EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ - EXC_HV, NOTEST, vec) + EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label, EXC_HV, NOTEST, vec); #define STD_RELON_EXCEPTION_HV_OOL(vec, label) \ - .globl label##_relon_hv; \ -label##_relon_hv: \ EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, vec); \ - EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_HV) + EXCEPTION_RELON_PROLOG_PSERIES_1(label, 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 SOFTEN_VALUE_0x900 PACA_IRQ_DEC -#define SOFTEN_VALUE_0x982 PACA_IRQ_DEC +#define SOFTEN_VALUE_0x980 PACA_IRQ_DEC #define SOFTEN_VALUE_0xa00 PACA_IRQ_DBELL #define SOFTEN_VALUE_0xe80 PACA_IRQ_DBELL -#define SOFTEN_VALUE_0xe82 PACA_IRQ_DBELL #define SOFTEN_VALUE_0xe60 PACA_IRQ_HMI -#define SOFTEN_VALUE_0xe62 PACA_IRQ_HMI #define SOFTEN_VALUE_0xea0 PACA_IRQ_EE -#define SOFTEN_VALUE_0xea2 PACA_IRQ_EE #define __SOFTEN_TEST(h, vec) \ lbz r10,PACASOFTIRQEN(r13); \ cmpwi r10,0; \ li r10,SOFTEN_VALUE_##vec; \ beq masked_##h##interrupt + #define _SOFTEN_TEST(h, vec) __SOFTEN_TEST(h, vec) #define SOFTEN_TEST_PR(vec) \ - KVMTEST(vec); \ + KVMTEST(EXC_STD, vec); \ _SOFTEN_TEST(EXC_STD, vec) #define SOFTEN_TEST_HV(vec) \ - KVMTEST(vec); \ + KVMTEST(EXC_HV, vec); \ _SOFTEN_TEST(EXC_HV, vec) +#define KVMTEST_PR(vec) \ + KVMTEST(EXC_STD, vec) + +#define KVMTEST_HV(vec) \ + KVMTEST(EXC_HV, vec) + #define SOFTEN_NOTEST_PR(vec) _SOFTEN_TEST(EXC_STD, vec) #define SOFTEN_NOTEST_HV(vec) _SOFTEN_TEST(EXC_HV, vec) @@ -427,58 +414,47 @@ label##_relon_hv: \ SET_SCRATCH0(r13); /* save r13 */ \ EXCEPTION_PROLOG_0(PACA_EXGEN); \ __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \ - EXCEPTION_PROLOG_PSERIES_1(label##_common, h); + EXCEPTION_PROLOG_PSERIES_1(label, h); #define _MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) #define MASKABLE_EXCEPTION_PSERIES(loc, vec, label) \ - . = loc; \ - .globl label##_pSeries; \ -label##_pSeries: \ _MASKABLE_EXCEPTION_PSERIES(vec, label, \ EXC_STD, SOFTEN_TEST_PR) +#define MASKABLE_EXCEPTION_PSERIES_OOL(vec, label) \ + EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_PR, vec); \ + EXCEPTION_PROLOG_PSERIES_1(label, EXC_STD) + #define MASKABLE_EXCEPTION_HV(loc, vec, label) \ - . = loc; \ - .globl label##_hv; \ -label##_hv: \ _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); + EXCEPTION_PROLOG_PSERIES_1(label, EXC_HV) #define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \ 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) \ + __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec); \ + EXCEPTION_RELON_PROLOG_PSERIES_1(label, h) + +#define _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) \ __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra) #define MASKABLE_RELON_EXCEPTION_PSERIES(loc, vec, label) \ - . = loc; \ - .globl label##_relon_pSeries; \ -label##_relon_pSeries: \ _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, \ EXC_STD, SOFTEN_NOTEST_PR) #define MASKABLE_RELON_EXCEPTION_HV(loc, vec, label) \ - . = loc; \ - .globl label##_relon_hv; \ -label##_relon_hv: \ _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); + EXCEPTION_PROLOG_PSERIES_1(label, EXC_HV) /* * Our exception common code can be passed various "additions" @@ -504,9 +480,6 @@ BEGIN_FTR_SECTION \ END_FTR_SECTION_IFSET(CPU_FTR_CTRL) #define EXCEPTION_COMMON(trap, label, hdlr, ret, additions) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ /* Volatile regs are potentially clobbered here */ \ additions; \ diff --git a/arch/powerpc/include/asm/head-64.h b/arch/powerpc/include/asm/head-64.h new file mode 100644 index 000000000000..358c25c80c62 --- /dev/null +++ b/arch/powerpc/include/asm/head-64.h @@ -0,0 +1,163 @@ +#ifndef _ASM_POWERPC_HEAD_64_H +#define _ASM_POWERPC_HEAD_64_H + +#include + +#define EXC_REAL_BEGIN(name, start, end) \ + . = start ; \ + .global exc_real_##start##_##name ; \ +exc_real_##start##_##name: + +#define EXC_REAL_END(name, start, end) + +#define EXC_VIRT_BEGIN(name, start, end) \ + . = start ; \ + .global exc_virt_##start##_##name ; \ +exc_virt_##start##_##name: + +#define EXC_VIRT_END(name, start, end) + +#define EXC_COMMON_BEGIN(name) \ + .global name; \ +name: + +#define TRAMP_REAL_BEGIN(name) \ + .global name ; \ +name: + +#ifdef CONFIG_KVM_BOOK3S_64_HANDLER +#define TRAMP_KVM_BEGIN(name) \ + TRAMP_REAL_BEGIN(name) +#else +#define TRAMP_KVM_BEGIN(name) +#endif + +#define EXC_REAL_NONE(start, end) + +#define EXC_VIRT_NONE(start, end) + + +#define EXC_REAL(name, start, end) \ + EXC_REAL_BEGIN(name, start, end); \ + STD_EXCEPTION_PSERIES(start, name##_common); \ + EXC_REAL_END(name, start, end); + +#define EXC_VIRT(name, start, end, realvec) \ + EXC_VIRT_BEGIN(name, start, end); \ + STD_RELON_EXCEPTION_PSERIES(start, realvec, name##_common); \ + EXC_VIRT_END(name, start, end); + +#define EXC_REAL_MASKABLE(name, start, end) \ + EXC_REAL_BEGIN(name, start, end); \ + MASKABLE_EXCEPTION_PSERIES(start, start, name##_common); \ + EXC_REAL_END(name, start, end); + +#define EXC_VIRT_MASKABLE(name, start, end, realvec) \ + EXC_VIRT_BEGIN(name, start, end); \ + MASKABLE_RELON_EXCEPTION_PSERIES(start, realvec, name##_common); \ + EXC_VIRT_END(name, start, end); + +#define EXC_REAL_HV(name, start, end) \ + EXC_REAL_BEGIN(name, start, end); \ + STD_EXCEPTION_HV(start, start, name##_common); \ + EXC_REAL_END(name, start, end); + +#define EXC_VIRT_HV(name, start, end, realvec) \ + EXC_VIRT_BEGIN(name, start, end); \ + STD_RELON_EXCEPTION_HV(start, realvec, name##_common); \ + EXC_VIRT_END(name, start, end); + +#define __EXC_REAL_OOL(name, start, end) \ + EXC_REAL_BEGIN(name, start, end); \ + __OOL_EXCEPTION(start, label, tramp_real_##name); \ + EXC_REAL_END(name, start, end); + +#define __TRAMP_REAL_REAL_OOL(name, vec) \ + TRAMP_REAL_BEGIN(tramp_real_##name); \ + STD_EXCEPTION_PSERIES_OOL(vec, name##_common); \ + +#define __EXC_REAL_OOL_MASKABLE(name, start, end) \ + __EXC_REAL_OOL(name, start, end); + +#define __TRAMP_REAL_REAL_OOL_MASKABLE(name, vec) \ + TRAMP_REAL_BEGIN(tramp_real_##name); \ + MASKABLE_EXCEPTION_PSERIES_OOL(vec, name##_common); \ + +#define __EXC_REAL_OOL_HV_DIRECT(name, start, end, handler) \ + EXC_REAL_BEGIN(name, start, end); \ + __OOL_EXCEPTION(start, label, handler); \ + EXC_REAL_END(name, start, end); + +#define __EXC_REAL_OOL_HV(name, start, end) \ + __EXC_REAL_OOL(name, start, end); + +#define __TRAMP_REAL_REAL_OOL_HV(name, vec) \ + TRAMP_REAL_BEGIN(tramp_real_##name); \ + STD_EXCEPTION_HV_OOL(vec, name##_common); \ + +#define __EXC_REAL_OOL_MASKABLE_HV(name, start, end) \ + __EXC_REAL_OOL(name, start, end); + +#define __TRAMP_REAL_REAL_OOL_MASKABLE_HV(name, vec) \ + TRAMP_REAL_BEGIN(tramp_real_##name); \ + MASKABLE_EXCEPTION_HV_OOL(vec, name##_common); \ + +#define __EXC_VIRT_OOL(name, start, end) \ + EXC_VIRT_BEGIN(name, start, end); \ + __OOL_EXCEPTION(start, label, tramp_virt_##name); \ + EXC_VIRT_END(name, start, end); + +#define __TRAMP_REAL_VIRT_OOL(name, realvec) \ + TRAMP_REAL_BEGIN(tramp_virt_##name); \ + STD_RELON_EXCEPTION_PSERIES_OOL(realvec, name##_common); \ + +#define __EXC_VIRT_OOL_MASKABLE(name, start, end) \ + __EXC_VIRT_OOL(name, start, end); + +#define __TRAMP_REAL_VIRT_OOL_MASKABLE(name, realvec) \ + TRAMP_REAL_BEGIN(tramp_virt_##name); \ + MASKABLE_RELON_EXCEPTION_PSERIES_OOL(realvec, name##_common); \ + +#define __EXC_VIRT_OOL_HV(name, start, end) \ + __EXC_VIRT_OOL(name, start, end); + +#define __TRAMP_REAL_VIRT_OOL_HV(name, realvec) \ + TRAMP_REAL_BEGIN(tramp_virt_##name); \ + STD_RELON_EXCEPTION_HV_OOL(realvec, name##_common); \ + +#define __EXC_VIRT_OOL_MASKABLE_HV(name, start, end) \ + __EXC_VIRT_OOL(name, start, end); + +#define __TRAMP_REAL_VIRT_OOL_MASKABLE_HV(name, realvec) \ + TRAMP_REAL_BEGIN(tramp_virt_##name); \ + MASKABLE_RELON_EXCEPTION_HV_OOL(realvec, name##_common); \ + +#define TRAMP_KVM(area, n) \ + TRAMP_KVM_BEGIN(do_kvm_##n); \ + KVM_HANDLER(area, EXC_STD, n); \ + +#define TRAMP_KVM_SKIP(area, n) \ + TRAMP_KVM_BEGIN(do_kvm_##n); \ + KVM_HANDLER_SKIP(area, EXC_STD, n); \ + +#define TRAMP_KVM_HV(area, n) \ + TRAMP_KVM_BEGIN(do_kvm_H##n); \ + KVM_HANDLER(area, EXC_HV, n + 0x2); \ + +#define TRAMP_KVM_HV_SKIP(area, n) \ + TRAMP_KVM_BEGIN(do_kvm_H##n); \ + KVM_HANDLER_SKIP(area, EXC_HV, n + 0x2); \ + +#define EXC_COMMON(name, realvec, hdlr) \ + EXC_COMMON_BEGIN(name); \ + STD_EXCEPTION_COMMON(realvec, name, hdlr); \ + +#define EXC_COMMON_ASYNC(name, realvec, hdlr) \ + EXC_COMMON_BEGIN(name); \ + STD_EXCEPTION_COMMON_ASYNC(realvec, name, hdlr); \ + +#define EXC_COMMON_HV(name, realvec, hdlr) \ + EXC_COMMON_BEGIN(name); \ + STD_EXCEPTION_COMMON(realvec + 0x2, name, hdlr); \ + +#endif /* _ASM_POWERPC_HEAD_64_H */ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 23018162d749..52d22891f6a4 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -16,6 +16,7 @@ #include #include #include +#include /* * We layout physical memory as follows: @@ -89,8 +90,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ .globl __start_interrupts __start_interrupts: - .globl system_reset_pSeries; -system_reset_pSeries: +EXC_REAL_BEGIN(system_reset, 0x100, 0x200) SET_SCRATCH0(r13) #ifdef CONFIG_PPC_P7_NAP BEGIN_FTR_SECTION @@ -131,9 +131,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) #endif /* CONFIG_PPC_P7_NAP */ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD, NOTEST, 0x100) +EXC_REAL_END(system_reset, 0x100, 0x200) - . = 0x200 -machine_check_pSeries_1: +EXC_REAL_BEGIN(machine_check, 0x200, 0x300) /* This is moved out of line as it can be patched by FW, but * some code path might still want to branch into the original * vector @@ -153,20 +153,14 @@ BEGIN_FTR_SECTION FTR_SECTION_ELSE b machine_check_pSeries_0 ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) +EXC_REAL_END(machine_check, 0x200, 0x300) - . = 0x300 - .globl data_access_pSeries -data_access_pSeries: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD, - KVMTEST, 0x300) +EXC_REAL(data_access, 0x300, 0x380) - . = 0x380 - .globl data_access_slb_pSeries -data_access_slb_pSeries: +EXC_REAL_BEGIN(data_access_slb, 0x380, 0x400) SET_SCRATCH0(r13) EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380) + EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x380) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_DAR mfspr r12,SPRN_SRR1 @@ -184,15 +178,14 @@ data_access_slb_pSeries: mtctr r10 bctr #endif +EXC_REAL_END(data_access_slb, 0x380, 0x400) - STD_EXCEPTION_PSERIES(0x400, instruction_access) +EXC_REAL(instruction_access, 0x400, 0x480) - . = 0x480 - .globl instruction_access_slb_pSeries -instruction_access_slb_pSeries: +EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x500) SET_SCRATCH0(r13) EXCEPTION_PROLOG_0(PACA_EXSLB) - EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x480) + EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480) std r3,PACA_EXSLB+EX_R3(r13) mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */ mfspr r12,SPRN_SRR1 @@ -205,50 +198,52 @@ instruction_access_slb_pSeries: mtctr r10 bctr #endif +EXC_REAL_END(instruction_access_slb, 0x480, 0x500) /* We open code these as we can't have a ". = x" (even with * x = "." within a feature section */ - . = 0x500; - .globl hardware_interrupt_pSeries; +EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x600) .globl hardware_interrupt_hv; -hardware_interrupt_pSeries: hardware_interrupt_hv: BEGIN_FTR_SECTION - _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, + _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_HV, SOFTEN_TEST_HV) +do_kvm_H0x500: KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502) FTR_SECTION_ELSE - _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, + _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_STD, SOFTEN_TEST_PR) +do_kvm_0x500: KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500) ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206) +EXC_REAL_END(hardware_interrupt, 0x500, 0x600) + +EXC_REAL(alignment, 0x600, 0x700) + +TRAMP_KVM(PACA_EXGEN, 0x600) + +EXC_REAL(program_check, 0x700, 0x800) - STD_EXCEPTION_PSERIES(0x600, alignment) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x600) +TRAMP_KVM(PACA_EXGEN, 0x700) - STD_EXCEPTION_PSERIES(0x700, program_check) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x700) +EXC_REAL(fp_unavailable, 0x800, 0x900) - STD_EXCEPTION_PSERIES(0x800, fp_unavailable) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x800) +TRAMP_KVM(PACA_EXGEN, 0x800) - . = 0x900 - .globl decrementer_pSeries -decrementer_pSeries: - _MASKABLE_EXCEPTION_PSERIES(0x900, decrementer, EXC_STD, SOFTEN_TEST_PR) +EXC_REAL_MASKABLE(decrementer, 0x900, 0x980) - STD_EXCEPTION_HV(0x980, 0x982, hdecrementer) +EXC_REAL_HV(hdecrementer, 0x980, 0xa00) - MASKABLE_EXCEPTION_PSERIES(0xa00, 0xa00, doorbell_super) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xa00) +EXC_REAL_MASKABLE(doorbell_super, 0xa00, 0xb00) - STD_EXCEPTION_PSERIES(0xb00, trap_0b) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xb00) +TRAMP_KVM(PACA_EXGEN, 0xa00) - . = 0xc00 - .globl system_call_pSeries -system_call_pSeries: +EXC_REAL(trap_0b, 0xb00, 0xc00) + +TRAMP_KVM(PACA_EXGEN, 0xb00) + +EXC_REAL_BEGIN(system_call, 0xc00, 0xd00) /* * If CONFIG_KVM_BOOK3S_64_HANDLER is set, save the PPR (on systems * that support it) before changing to HMT_MEDIUM. That allows the KVM @@ -265,7 +260,7 @@ system_call_pSeries: std r10,PACA_EXGEN+EX_R10(r13) OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR); mfcr r9 - KVMTEST(0xc00) + KVMTEST_PR(0xc00) GET_SCRATCH0(r13) #else HMT_MEDIUM; @@ -273,96 +268,59 @@ system_call_pSeries: SYSCALL_PSERIES_1 SYSCALL_PSERIES_2_RFID SYSCALL_PSERIES_3 - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00) +EXC_REAL_END(system_call, 0xc00, 0xd00) + +TRAMP_KVM(PACA_EXGEN, 0xc00) + +EXC_REAL(single_step, 0xd00, 0xe00) + +TRAMP_KVM(PACA_EXGEN, 0xd00) - STD_EXCEPTION_PSERIES(0xd00, single_step) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xd00) /* At 0xe??? we have a bunch of hypervisor exceptions, we branch * out of line to handle them */ - . = 0xe00 -hv_data_storage_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b h_data_storage_hv +__EXC_REAL_OOL_HV(h_data_storage, 0xe00, 0xe20) - . = 0xe20 -hv_instr_storage_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b h_instr_storage_hv +__EXC_REAL_OOL_HV(h_instr_storage, 0xe20, 0xe40) - . = 0xe40 -emulation_assist_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b emulation_assist_hv +__EXC_REAL_OOL_HV(emulation_assist, 0xe40, 0xe60) - . = 0xe60 -hv_exception_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b hmi_exception_early +__EXC_REAL_OOL_HV_DIRECT(hmi_exception, 0xe60, 0xe80, hmi_exception_early) - . = 0xe80 -hv_doorbell_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b h_doorbell_hv +__EXC_REAL_OOL_MASKABLE_HV(h_doorbell, 0xe80, 0xea0) - . = 0xea0 -hv_virt_irq_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b h_virt_irq_hv +__EXC_REAL_OOL_MASKABLE_HV(h_virt_irq, 0xea0, 0xec0) - /* We need to deal with the Altivec unavailable exception - * here which is at 0xf20, thus in the middle of the - * prolog code of the PerformanceMonitor one. A little - * trickery is thus necessary - */ - . = 0xf00 -performance_monitor_pseries_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b performance_monitor_pSeries +EXC_REAL_NONE(0xec0, 0xf00) - . = 0xf20 -altivec_unavailable_pseries_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b altivec_unavailable_pSeries +__EXC_REAL_OOL(performance_monitor, 0xf00, 0xf20) - . = 0xf40 -vsx_unavailable_pseries_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b vsx_unavailable_pSeries +__EXC_REAL_OOL(altivec_unavailable, 0xf20, 0xf40) - . = 0xf60 -facility_unavailable_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b facility_unavailable_pSeries +__EXC_REAL_OOL(vsx_unavailable, 0xf40, 0xf60) + +__EXC_REAL_OOL(facility_unavailable, 0xf60, 0xf80) + +__EXC_REAL_OOL_HV(h_facility_unavailable, 0xf80, 0xfa0) + +EXC_REAL_NONE(0xfa0, 0x1200) - . = 0xf80 -hv_facility_unavailable_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b hv_facility_unavailable_hv #ifdef CONFIG_CBE_RAS - STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1202) -#endif /* CONFIG_CBE_RAS */ +EXC_REAL_HV(cbe_system_error, 0x1200, 0x1300) + +TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1200) + +#else /* CONFIG_CBE_RAS */ +EXC_REAL_NONE(0x1200, 0x1300) +#endif - STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1300) +EXC_REAL(instruction_breakpoint, 0x1300, 0x1400) - . = 0x1500 - .global denorm_exception_hv -denorm_exception_hv: +TRAMP_KVM_SKIP(PACA_EXGEN, 0x1300) + +EXC_REAL_BEGIN(denorm_exception_hv, 0x1500, 0x1600) mtspr SPRN_SPRG_HSCRATCH0,r13 EXCEPTION_PROLOG_0(PACA_EXGEN) EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0x1500) @@ -375,31 +333,41 @@ denorm_exception_hv: bne+ denorm_assist #endif - KVMTEST(0x1500) + KVMTEST_PR(0x1500) EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1500) +EXC_REAL_END(denorm_exception_hv, 0x1500, 0x1600) + +TRAMP_KVM_SKIP(PACA_EXGEN, 0x1500) #ifdef CONFIG_CBE_RAS - STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602) -#endif /* CONFIG_CBE_RAS */ +EXC_REAL_HV(cbe_maintenance, 0x1600, 0x1700) - STD_EXCEPTION_PSERIES(0x1700, altivec_assist) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x1700) +TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1600) + +#else /* CONFIG_CBE_RAS */ +EXC_REAL_NONE(0x1600, 0x1700) +#endif + +EXC_REAL(altivec_assist, 0x1700, 0x1800) + +TRAMP_KVM(PACA_EXGEN, 0x1700) #ifdef CONFIG_CBE_RAS - STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1802) -#else +EXC_REAL_HV(cbe_thermal, 0x1800, 0x1900) + +TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1800) + +#else /* CONFIG_CBE_RAS */ +EXC_REAL_NONE(0x1800, 0x1900) . = 0x1800 -#endif /* CONFIG_CBE_RAS */ +#endif /*** Out of line interrupts support ***/ - .align 7 /* moved from 0x200 */ -machine_check_powernv_early: + .align 7; +TRAMP_REAL_BEGIN(machine_check_powernv_early) BEGIN_FTR_SECTION EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) /* @@ -471,13 +439,13 @@ BEGIN_FTR_SECTION b . /* prevent speculative execution */ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) -machine_check_pSeries: +TRAMP_REAL_BEGIN(machine_check_pSeries) .globl machine_check_fwnmi machine_check_fwnmi: SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_0(PACA_EXMC) machine_check_pSeries_0: - EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST, 0x200) + EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200) /* * The following is essentially EXCEPTION_PROLOG_PSERIES_1 with the * difference that MSR_RI is not enabled, because PACA_EXMC is being @@ -494,16 +462,17 @@ machine_check_pSeries_0: rfid b . /* prevent speculative execution */ - KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300) - KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x400) - KVM_HANDLER(PACA_EXSLB, EXC_STD, 0x480) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x900) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982) + +TRAMP_KVM_SKIP(PACA_EXMC, 0x200) +TRAMP_KVM_SKIP(PACA_EXGEN, 0x300) +TRAMP_KVM_SKIP(PACA_EXSLB, 0x380) +TRAMP_KVM(PACA_EXGEN, 0x400) +TRAMP_KVM(PACA_EXSLB, 0x480) +TRAMP_KVM(PACA_EXGEN, 0x900) +TRAMP_KVM_HV(PACA_EXGEN, 0x980) #ifdef CONFIG_PPC_DENORMALISATION -denorm_assist: +TRAMP_REAL_BEGIN(denorm_assist) BEGIN_FTR_SECTION /* * To denormalise we need to move a copy of the register to itself. @@ -568,32 +537,39 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) .align 7 /* moved from 0xe00 */ - STD_EXCEPTION_HV_OOL(0xe02, h_data_storage) - KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0xe02) - STD_EXCEPTION_HV_OOL(0xe22, h_instr_storage) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22) - STD_EXCEPTION_HV_OOL(0xe42, emulation_assist) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42) - MASKABLE_EXCEPTION_HV_OOL(0xe62, hmi_exception) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62) +__TRAMP_REAL_REAL_OOL_HV(h_data_storage, 0xe00) +TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0xe00) + +__TRAMP_REAL_REAL_OOL_HV(h_instr_storage, 0xe20) +TRAMP_KVM_HV(PACA_EXGEN, 0xe20) + +__TRAMP_REAL_REAL_OOL_HV(emulation_assist, 0xe40) +TRAMP_KVM_HV(PACA_EXGEN, 0xe40) - MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82) +__TRAMP_REAL_REAL_OOL_MASKABLE_HV(hmi_exception, 0xe60) +TRAMP_KVM_HV(PACA_EXGEN, 0xe60) - MASKABLE_EXCEPTION_HV_OOL(0xea2, h_virt_irq) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xea2) +__TRAMP_REAL_REAL_OOL_MASKABLE_HV(h_doorbell, 0xe80) +TRAMP_KVM_HV(PACA_EXGEN, 0xe80) + +__TRAMP_REAL_REAL_OOL_MASKABLE_HV(h_virt_irq, 0xea0) +TRAMP_KVM_HV(PACA_EXGEN, 0xea0) /* moved from 0xf00 */ - STD_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf00) - STD_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf20) - STD_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf40) - STD_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable) - KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xf60) - STD_EXCEPTION_HV_OOL(0xf82, hv_facility_unavailable) - KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xf82) +__TRAMP_REAL_REAL_OOL(performance_monitor, 0xf00) +TRAMP_KVM(PACA_EXGEN, 0xf00) + +__TRAMP_REAL_REAL_OOL(altivec_unavailable, 0xf20) +TRAMP_KVM(PACA_EXGEN, 0xf20) + +__TRAMP_REAL_REAL_OOL(vsx_unavailable, 0xf40) +TRAMP_KVM(PACA_EXGEN, 0xf40) + +__TRAMP_REAL_REAL_OOL(facility_unavailable, 0xf60) +TRAMP_KVM(PACA_EXGEN, 0xf60) + +__TRAMP_REAL_REAL_OOL_HV(h_facility_unavailable, 0xf80) +TRAMP_KVM_HV(PACA_EXGEN, 0xf80) /* * An interrupt came in while soft-disabled. We set paca->irq_happened, then: @@ -676,9 +652,8 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) /* * Vectors for the FWNMI option. Share common code. */ - .globl system_reset_fwnmi .align 7 -system_reset_fwnmi: +TRAMP_REAL_BEGIN(system_reset_fwnmi) SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD, NOTEST, 0x100) @@ -686,7 +661,7 @@ system_reset_fwnmi: #endif /* CONFIG_PPC_PSERIES */ #ifdef CONFIG_KVM_BOOK3S_64_HANDLER -kvmppc_skip_interrupt: +TRAMP_REAL_BEGIN(kvmppc_skip_interrupt) /* * Here all GPRs are unchanged from when the interrupt happened * except for r13, which is saved in SPRG_SCRATCH0. @@ -698,7 +673,7 @@ kvmppc_skip_interrupt: rfid b . -kvmppc_skip_Hinterrupt: +TRAMP_REAL_BEGIN(kvmppc_skip_Hinterrupt) /* * Here all GPRs are unchanged from when the interrupt happened * except for r13, which is saved in SPRG_SCRATCH0. @@ -720,34 +695,50 @@ kvmppc_skip_Hinterrupt: /*** Common interrupt handlers ***/ - STD_EXCEPTION_COMMON(0x100, system_reset, system_reset_exception) + .align 7; +EXC_COMMON(system_reset_common, 0x100, system_reset_exception) + .align 7; +EXC_COMMON_ASYNC(hardware_interrupt_common, 0x500, do_IRQ) + .align 7; +EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt) + .align 7; +EXC_COMMON(hdecrementer_common, 0x980, hdec_interrupt) - STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) - STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, timer_interrupt) - STD_EXCEPTION_COMMON(0x980, hdecrementer, hdec_interrupt) + .align 7; #ifdef CONFIG_PPC_DOORBELL - STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, doorbell_exception) +EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, doorbell_exception) #else - STD_EXCEPTION_COMMON_ASYNC(0xa00, doorbell_super, unknown_exception) +EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, unknown_exception) #endif - STD_EXCEPTION_COMMON(0xb00, trap_0b, unknown_exception) - STD_EXCEPTION_COMMON(0xd00, single_step, single_step_exception) - STD_EXCEPTION_COMMON(0xe00, trap_0e, unknown_exception) - STD_EXCEPTION_COMMON(0xe40, emulation_assist, emulation_assist_interrupt) - STD_EXCEPTION_COMMON_ASYNC(0xe60, hmi_exception, handle_hmi_exception) + .align 7; +EXC_COMMON(trap_0b_common, 0xb00, unknown_exception) + .align 7; +EXC_COMMON(single_step_common, 0xd00, single_step_exception) + .align 7; +EXC_COMMON(trap_0e_common, 0xe00, unknown_exception) + .align 7; +EXC_COMMON(emulation_assist_common, 0xe40, emulation_assist_interrupt) + .align 7; +EXC_COMMON_ASYNC(hmi_exception_common, 0xe60, handle_hmi_exception) + .align 7; #ifdef CONFIG_PPC_DOORBELL - STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, doorbell_exception) +EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, doorbell_exception) #else - STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, unknown_exception) +EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, unknown_exception) #endif - STD_EXCEPTION_COMMON_ASYNC(0xea0, h_virt_irq, do_IRQ) - STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, performance_monitor_exception) - STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, instruction_breakpoint_exception) - STD_EXCEPTION_COMMON(0x1502, denorm, unknown_exception) + .align 7; +EXC_COMMON_ASYNC(h_virt_irq_common, 0xea0, do_IRQ) + .align 7; +EXC_COMMON_ASYNC(performance_monitor_common, 0xf00, performance_monitor_exception) + .align 7; +EXC_COMMON(instruction_breakpoint_common, 0x1300, instruction_breakpoint_exception) + .align 7; +EXC_COMMON_HV(denorm_common, 0x1500, unknown_exception) + .align 7; #ifdef CONFIG_ALTIVEC - STD_EXCEPTION_COMMON(0x1700, altivec_assist, altivec_assist_exception) +EXC_COMMON(altivec_assist_common, 0x1700, altivec_assist_exception) #else - STD_EXCEPTION_COMMON(0x1700, altivec_assist, unknown_exception) +EXC_COMMON(altivec_assist_common, 0x1700, unknown_exception) #endif /* @@ -765,10 +756,12 @@ kvmppc_skip_Hinterrupt: * only has extra guff for STAB-based processors -- which never * come here. */ - STD_RELON_EXCEPTION_PSERIES(0x4300, 0x300, data_access) - . = 0x4380 - .globl data_access_slb_relon_pSeries -data_access_slb_relon_pSeries: +EXC_VIRT_NONE(0x4100, 0x4200) +EXC_VIRT_NONE(0x4200, 0x4300) + +EXC_VIRT(data_access, 0x4300, 0x4380, 0x300) + +EXC_VIRT_BEGIN(data_access_slb, 0x4380, 0x4400) SET_SCRATCH0(r13) EXCEPTION_PROLOG_0(PACA_EXSLB) EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380) @@ -789,11 +782,11 @@ data_access_slb_relon_pSeries: mtctr r10 bctr #endif +EXC_VIRT_END(data_access_slb, 0x4380, 0x4400) - STD_RELON_EXCEPTION_PSERIES(0x4400, 0x400, instruction_access) - . = 0x4480 - .globl instruction_access_slb_relon_pSeries -instruction_access_slb_relon_pSeries: +EXC_VIRT(instruction_access, 0x4400, 0x4480, 0x400) + +EXC_VIRT_BEGIN(instruction_access_slb, 0x4480, 0x4500) SET_SCRATCH0(r13) EXCEPTION_PROLOG_0(PACA_EXSLB) EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480) @@ -809,100 +802,86 @@ instruction_access_slb_relon_pSeries: mtctr r10 bctr #endif +EXC_VIRT_END(instruction_access_slb, 0x4480, 0x4500) - . = 0x4500 - .globl hardware_interrupt_relon_pSeries; +EXC_VIRT_BEGIN(hardware_interrupt, 0x4500, 0x4600) .globl hardware_interrupt_relon_hv; -hardware_interrupt_relon_pSeries: hardware_interrupt_relon_hv: BEGIN_FTR_SECTION - _MASKABLE_RELON_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV, SOFTEN_TEST_HV) + _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_HV, SOFTEN_TEST_HV) FTR_SECTION_ELSE - _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD, SOFTEN_TEST_PR) + _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt_common, EXC_STD, SOFTEN_TEST_PR) ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) - STD_RELON_EXCEPTION_PSERIES(0x4600, 0x600, alignment) - STD_RELON_EXCEPTION_PSERIES(0x4700, 0x700, program_check) - STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable) - MASKABLE_RELON_EXCEPTION_PSERIES(0x4900, 0x900, decrementer) - STD_RELON_EXCEPTION_HV(0x4980, 0x982, hdecrementer) - MASKABLE_RELON_EXCEPTION_PSERIES(0x4a00, 0xa00, doorbell_super) - STD_RELON_EXCEPTION_PSERIES(0x4b00, 0xb00, trap_0b) - - . = 0x4c00 - .globl system_call_relon_pSeries -system_call_relon_pSeries: +EXC_VIRT_END(hardware_interrupt, 0x4500, 0x4600) + +EXC_VIRT(alignment, 0x4600, 0x4700, 0x600) +EXC_VIRT(program_check, 0x4700, 0x4800, 0x700) +EXC_VIRT(fp_unavailable, 0x4800, 0x4900, 0x800) +EXC_VIRT_MASKABLE(decrementer, 0x4900, 0x4980, 0x900) +EXC_VIRT_HV(hdecrementer, 0x4980, 0x4a00, 0x980) +EXC_VIRT_MASKABLE(doorbell_super, 0x4a00, 0x4b00, 0xa00) +EXC_VIRT(trap_0b, 0x4b00, 0x4c00, 0xb00) + +EXC_VIRT_BEGIN(system_call, 0x4c00, 0x4d00) HMT_MEDIUM SYSCALL_PSERIES_1 SYSCALL_PSERIES_2_DIRECT SYSCALL_PSERIES_3 +EXC_VIRT_END(system_call, 0x4c00, 0x4d00) - STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step) +EXC_VIRT(single_step, 0x4d00, 0x4e00, 0xd00) - . = 0x4e00 - b . /* Can't happen, see v2.07 Book III-S section 6.5 */ +EXC_VIRT_BEGIN(unused, 0x4e00, 0x4e20) + b . /* Can't happen, see v2.07 Book III-S section 6.5 */ +EXC_VIRT_END(unused, 0x4e00, 0x4e20) - . = 0x4e20 - b . /* Can't happen, see v2.07 Book III-S section 6.5 */ +EXC_VIRT_BEGIN(unused, 0x4e20, 0x4e40) + b . /* Can't happen, see v2.07 Book III-S section 6.5 */ +EXC_VIRT_END(unused, 0x4e20, 0x4e40) - . = 0x4e40 -emulation_assist_relon_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b emulation_assist_relon_hv +__EXC_VIRT_OOL_HV(emulation_assist, 0x4e40, 0x4e60) - . = 0x4e60 - b . /* Can't happen, see v2.07 Book III-S section 6.5 */ +EXC_VIRT_BEGIN(unused, 0x4e60, 0x4e80) + b . /* Can't happen, see v2.07 Book III-S section 6.5 */ +EXC_VIRT_END(unused, 0x4e60, 0x4e80) - . = 0x4e80 -h_doorbell_relon_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b h_doorbell_relon_hv +__EXC_VIRT_OOL_MASKABLE_HV(h_doorbell, 0x4e80, 0x4ea0) - . = 0x4ea0 -h_virt_irq_relon_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b h_virt_irq_relon_hv +__EXC_VIRT_OOL_MASKABLE_HV(h_virt_irq, 0x4ea0, 0x4ec0) - . = 0x4f00 -performance_monitor_relon_pseries_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b performance_monitor_relon_pSeries +EXC_VIRT_NONE(0x4ec0, 0x4f00) - . = 0x4f20 -altivec_unavailable_relon_pseries_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b altivec_unavailable_relon_pSeries +__EXC_VIRT_OOL(performance_monitor, 0x4f00, 0x4f20) - . = 0x4f40 -vsx_unavailable_relon_pseries_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b vsx_unavailable_relon_pSeries +__EXC_VIRT_OOL(altivec_unavailable, 0x4f20, 0x4f40) - . = 0x4f60 -facility_unavailable_relon_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b facility_unavailable_relon_pSeries +__EXC_VIRT_OOL(vsx_unavailable, 0x4f40, 0x4f60) - . = 0x4f80 -hv_facility_unavailable_relon_trampoline: - SET_SCRATCH0(r13) - EXCEPTION_PROLOG_0(PACA_EXGEN) - b hv_facility_unavailable_relon_hv +__EXC_VIRT_OOL(facility_unavailable, 0x4f60, 0x4f80) + +__EXC_VIRT_OOL_HV(h_facility_unavailable, 0x4f80, 0x4fa0) + +EXC_VIRT_NONE(0x4fa0, 0x5200) + +EXC_VIRT_NONE(0x5200, 0x5300) + +EXC_VIRT(instruction_breakpoint, 0x5300, 0x5400, 0x1300) - STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint) #ifdef CONFIG_PPC_DENORMALISATION - . = 0x5500 - b denorm_exception_hv +EXC_VIRT_BEGIN(denorm_exception, 0x5500, 0x5600) + b exc_real_0x1500_denorm_exception_hv +EXC_VIRT_END(denorm_exception, 0x5500, 0x5600) +#else +EXC_VIRT_NONE(0x5500, 0x5600) #endif - STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist) -ppc64_runlatch_on_trampoline: +EXC_VIRT_NONE(0x5600, 0x5700) + +EXC_VIRT(altivec_assist, 0x5700, 0x5800, 0x1700) + +EXC_VIRT_NONE(0x5800, 0x5900) + +TRAMP_REAL_BEGIN(ppc64_runlatch_on_trampoline) b __ppc64_runlatch_on /* @@ -911,8 +890,7 @@ ppc64_runlatch_on_trampoline: * r9 - r13 are saved in paca->exgen. */ .align 7 - .globl data_access_common -data_access_common: +EXC_COMMON_BEGIN(data_access_common) mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) mfspr r10,SPRN_DSISR @@ -932,8 +910,7 @@ MMU_FTR_SECTION_ELSE ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) .align 7 - .globl h_data_storage_common -h_data_storage_common: +EXC_COMMON_BEGIN(h_data_storage_common) mfspr r10,SPRN_HDAR std r10,PACA_EXGEN+EX_DAR(r13) mfspr r10,SPRN_HDSISR @@ -946,8 +923,7 @@ h_data_storage_common: b ret_from_except .align 7 - .globl instruction_access_common -instruction_access_common: +EXC_COMMON_BEGIN(instruction_access_common) EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) RECONCILE_IRQ_STATE(r10, r11) ld r12,_MSR(r1) @@ -962,16 +938,15 @@ MMU_FTR_SECTION_ELSE b handle_page_fault ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) - STD_EXCEPTION_COMMON(0xe20, h_instr_storage, unknown_exception) + .align 7 +EXC_COMMON(h_instr_storage_common, 0xe20, unknown_exception) /* * Machine check is different because we use a different * save area: PACA_EXMC instead of PACA_EXGEN. */ .align 7 - .globl machine_check_common -machine_check_common: - +EXC_COMMON_BEGIN(machine_check_common) mfspr r10,SPRN_DAR std r10,PACA_EXMC+EX_DAR(r13) mfspr r10,SPRN_DSISR @@ -992,8 +967,7 @@ machine_check_common: b ret_from_except .align 7 - .globl alignment_common -alignment_common: +EXC_COMMON_BEGIN(alignment_common) mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) mfspr r10,SPRN_DSISR @@ -1010,8 +984,7 @@ alignment_common: b ret_from_except .align 7 - .globl program_check_common -program_check_common: +EXC_COMMON_BEGIN(program_check_common) EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) bl save_nvgprs RECONCILE_IRQ_STATE(r10, r11) @@ -1020,8 +993,7 @@ program_check_common: b ret_from_except .align 7 - .globl fp_unavailable_common -fp_unavailable_common: +EXC_COMMON_BEGIN(fp_unavailable_common) EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) bne 1f /* if from user, just load it up */ bl save_nvgprs @@ -1049,9 +1021,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM) bl fp_unavailable_tm b ret_from_except #endif + .align 7 - .globl altivec_unavailable_common -altivec_unavailable_common: +EXC_COMMON_BEGIN(altivec_unavailable_common) EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN) #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION @@ -1085,8 +1057,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) b ret_from_except .align 7 - .globl vsx_unavailable_common -vsx_unavailable_common: +EXC_COMMON_BEGIN(vsx_unavailable_common) EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) #ifdef CONFIG_VSX BEGIN_FTR_SECTION @@ -1119,15 +1090,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) b ret_from_except /* Equivalents to the above handlers for relocation-on interrupt vectors */ - STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist) - MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell) - MASKABLE_RELON_EXCEPTION_HV_OOL(0xea0, h_virt_irq) - - STD_RELON_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor) - STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable) - STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable) - STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable) - STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable) +__TRAMP_REAL_VIRT_OOL_HV(emulation_assist, 0xe40) +__TRAMP_REAL_VIRT_OOL_MASKABLE_HV(h_doorbell, 0xe80) +__TRAMP_REAL_VIRT_OOL_MASKABLE_HV(h_virt_irq, 0xea0) +__TRAMP_REAL_VIRT_OOL(performance_monitor, 0xf00) +__TRAMP_REAL_VIRT_OOL(altivec_unavailable, 0xf20) +__TRAMP_REAL_VIRT_OOL(vsx_unavailable, 0xf40) +__TRAMP_REAL_VIRT_OOL(facility_unavailable, 0xf60) +__TRAMP_REAL_VIRT_OOL_HV(h_facility_unavailable, 0xf80) /* * The __end_interrupts marker must be past the out-of-line (OOL) @@ -1155,18 +1125,24 @@ fwnmi_data_area: . = 0x8000 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ - STD_EXCEPTION_COMMON(0xf60, facility_unavailable, facility_unavailable_exception) - STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, facility_unavailable_exception) + .align 7; +EXC_COMMON(facility_unavailable_common, 0xf60, facility_unavailable_exception) + .align 7; +EXC_COMMON(h_facility_unavailable_common, 0xf80, facility_unavailable_exception) #ifdef CONFIG_CBE_RAS - STD_EXCEPTION_COMMON(0x1200, cbe_system_error, cbe_system_error_exception) - STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, cbe_maintenance_exception) - STD_EXCEPTION_COMMON(0x1800, cbe_thermal, cbe_thermal_exception) + .align 7; +EXC_COMMON(cbe_system_error_common, 0x1200, cbe_system_error_exception) + .align 7; +EXC_COMMON(cbe_maintenance_common, 0x1600, cbe_maintenance_exception) + .align 7; +EXC_COMMON(cbe_thermal_common, 0x1800, cbe_thermal_exception) #endif /* CONFIG_CBE_RAS */ - .globl hmi_exception_early -hmi_exception_early: - EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, 0xe62) + + .align 7; +EXC_COMMON_BEGIN(hmi_exception_early) + EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, 0xe60) mr r10,r1 /* Save r1 */ ld r1,PACAEMERGSP(r13) /* Use emergency stack */ subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ @@ -1212,7 +1188,7 @@ hmi_exception_early: hmi_exception_after_realmode: SET_SCRATCH0(r13) EXCEPTION_PROLOG_0(PACA_EXGEN) - b hmi_exception_hv + b tramp_real_hmi_exception #define MACHINE_CHECK_HANDLER_WINDUP \ @@ -1251,8 +1227,7 @@ hmi_exception_after_realmode: * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack. */ .align 7 - .globl machine_check_handle_early -machine_check_handle_early: +EXC_COMMON_BEGIN(machine_check_handle_early) std r0,GPR0(r1) /* Save r0 */ EXCEPTION_PROLOG_COMMON_3(0x200) bl save_nvgprs @@ -1378,7 +1353,7 @@ machine_check_handle_early: MACHINE_CHECK_HANDLER_WINDUP b machine_check_pSeries -unrecover_mce: +EXC_COMMON_BEGIN(unrecover_mce) /* Invoke machine_check_exception to print MCE event and panic. */ addi r3,r1,STACK_FRAME_OVERHEAD bl machine_check_exception @@ -1389,6 +1364,7 @@ unrecover_mce: 1: addi r3,r1,STACK_FRAME_OVERHEAD bl unrecoverable_exception b 1b + /* * r13 points to the PACA, r9 contains the saved CR, * r12 contain the saved SRR1, SRR0 is still ready for return @@ -1398,7 +1374,7 @@ unrecover_mce: * cr6.eq is set for a D-SLB miss, clear for a I-SLB miss * We assume we aren't going to take any exceptions during this procedure. */ -slb_miss_realmode: +EXC_COMMON_BEGIN(slb_miss_realmode) mflr r10 #ifdef CONFIG_RELOCATABLE mtctr r11 @@ -1451,14 +1427,6 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_TYPE_RADIX) rfid b . -unrecov_slb: - EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) - RECONCILE_IRQ_STATE(r10, r11) - bl save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl unrecoverable_exception - b 1b - 8: mfspr r11,SPRN_SRR0 LOAD_HANDLER(r10,bad_addr_slb) mtspr SPRN_SRR0,r10 @@ -1467,7 +1435,16 @@ unrecov_slb: rfid b . -bad_addr_slb: +EXC_COMMON_BEGIN(unrecov_slb) + EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) + RECONCILE_IRQ_STATE(r10, r11) + bl save_nvgprs +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl unrecoverable_exception + b 1b + + +EXC_COMMON_BEGIN(bad_addr_slb) EXCEPTION_PROLOG_COMMON(0x380, PACA_EXSLB) RECONCILE_IRQ_STATE(r10, r11) ld r3, PACA_EXSLB+EX_DAR(r13) @@ -1481,7 +1458,7 @@ bad_addr_slb: b ret_from_except #ifdef CONFIG_PPC_970_NAP -power4_fixup_nap: +TRAMP_REAL_BEGIN(power4_fixup_nap) andc r9,r9,r10 std r9,TI_LOCAL_FLAGS(r11) ld r10,_LINK(r1) /* make idle task do the */ -- cgit v1.2.3 From be642c3457e75983be6f1f4bddcc77c9e2ed4650 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 21 Sep 2016 17:43:28 +1000 Subject: powerpc/64s: Consolidate exception handler alignment Move exception handler alignment directives into the head-64.h macros, beause they will no longer work in-place after the next patch. This slightly changes functions that have alignments applied and therefore code generation, which is why it was not done initially (see earlier patch). Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/head-64.h | 1 + arch/powerpc/kernel/exceptions-64s.S | 36 ------------------------------------ 2 files changed, 1 insertion(+), 36 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/head-64.h b/arch/powerpc/include/asm/head-64.h index 358c25c80c62..613f743e91aa 100644 --- a/arch/powerpc/include/asm/head-64.h +++ b/arch/powerpc/include/asm/head-64.h @@ -18,6 +18,7 @@ exc_virt_##start##_##name: #define EXC_VIRT_END(name, start, end) #define EXC_COMMON_BEGIN(name) \ + .align 7; \ .global name; \ name: diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 52d22891f6a4..d398e8716ef8 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -366,7 +366,6 @@ EXC_REAL_NONE(0x1800, 0x1900) /*** Out of line interrupts support ***/ /* moved from 0x200 */ - .align 7; TRAMP_REAL_BEGIN(machine_check_powernv_early) BEGIN_FTR_SECTION EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200) @@ -535,7 +534,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) b . #endif - .align 7 /* moved from 0xe00 */ __TRAMP_REAL_REAL_OOL_HV(h_data_storage, 0xe00) TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0xe00) @@ -652,7 +650,6 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE) /* * Vectors for the FWNMI option. Share common code. */ - .align 7 TRAMP_REAL_BEGIN(system_reset_fwnmi) SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD, @@ -695,46 +692,30 @@ TRAMP_REAL_BEGIN(kvmppc_skip_Hinterrupt) /*** Common interrupt handlers ***/ - .align 7; EXC_COMMON(system_reset_common, 0x100, system_reset_exception) - .align 7; EXC_COMMON_ASYNC(hardware_interrupt_common, 0x500, do_IRQ) - .align 7; EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt) - .align 7; EXC_COMMON(hdecrementer_common, 0x980, hdec_interrupt) - .align 7; #ifdef CONFIG_PPC_DOORBELL EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, doorbell_exception) #else EXC_COMMON_ASYNC(doorbell_super_common, 0xa00, unknown_exception) #endif - .align 7; EXC_COMMON(trap_0b_common, 0xb00, unknown_exception) - .align 7; EXC_COMMON(single_step_common, 0xd00, single_step_exception) - .align 7; EXC_COMMON(trap_0e_common, 0xe00, unknown_exception) - .align 7; EXC_COMMON(emulation_assist_common, 0xe40, emulation_assist_interrupt) - .align 7; EXC_COMMON_ASYNC(hmi_exception_common, 0xe60, handle_hmi_exception) - .align 7; #ifdef CONFIG_PPC_DOORBELL EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, doorbell_exception) #else EXC_COMMON_ASYNC(h_doorbell_common, 0xe80, unknown_exception) #endif - .align 7; EXC_COMMON_ASYNC(h_virt_irq_common, 0xea0, do_IRQ) - .align 7; EXC_COMMON_ASYNC(performance_monitor_common, 0xf00, performance_monitor_exception) - .align 7; EXC_COMMON(instruction_breakpoint_common, 0x1300, instruction_breakpoint_exception) - .align 7; EXC_COMMON_HV(denorm_common, 0x1500, unknown_exception) - .align 7; #ifdef CONFIG_ALTIVEC EXC_COMMON(altivec_assist_common, 0x1700, altivec_assist_exception) #else @@ -889,7 +870,6 @@ TRAMP_REAL_BEGIN(ppc64_runlatch_on_trampoline) * SRR0 and SRR1 are saved in r11 and r12, * r9 - r13 are saved in paca->exgen. */ - .align 7 EXC_COMMON_BEGIN(data_access_common) mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) @@ -909,7 +889,6 @@ MMU_FTR_SECTION_ELSE b handle_page_fault ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) - .align 7 EXC_COMMON_BEGIN(h_data_storage_common) mfspr r10,SPRN_HDAR std r10,PACA_EXGEN+EX_DAR(r13) @@ -922,7 +901,6 @@ EXC_COMMON_BEGIN(h_data_storage_common) bl unknown_exception b ret_from_except - .align 7 EXC_COMMON_BEGIN(instruction_access_common) EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) RECONCILE_IRQ_STATE(r10, r11) @@ -938,14 +916,12 @@ MMU_FTR_SECTION_ELSE b handle_page_fault ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_TYPE_RADIX) - .align 7 EXC_COMMON(h_instr_storage_common, 0xe20, unknown_exception) /* * Machine check is different because we use a different * save area: PACA_EXMC instead of PACA_EXGEN. */ - .align 7 EXC_COMMON_BEGIN(machine_check_common) mfspr r10,SPRN_DAR std r10,PACA_EXMC+EX_DAR(r13) @@ -966,7 +942,6 @@ EXC_COMMON_BEGIN(machine_check_common) bl machine_check_exception b ret_from_except - .align 7 EXC_COMMON_BEGIN(alignment_common) mfspr r10,SPRN_DAR std r10,PACA_EXGEN+EX_DAR(r13) @@ -983,7 +958,6 @@ EXC_COMMON_BEGIN(alignment_common) bl alignment_exception b ret_from_except - .align 7 EXC_COMMON_BEGIN(program_check_common) EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) bl save_nvgprs @@ -992,7 +966,6 @@ EXC_COMMON_BEGIN(program_check_common) bl program_check_exception b ret_from_except - .align 7 EXC_COMMON_BEGIN(fp_unavailable_common) EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) bne 1f /* if from user, just load it up */ @@ -1022,7 +995,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM) b ret_from_except #endif - .align 7 EXC_COMMON_BEGIN(altivec_unavailable_common) EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN) #ifdef CONFIG_ALTIVEC @@ -1056,7 +1028,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) bl altivec_unavailable_exception b ret_from_except - .align 7 EXC_COMMON_BEGIN(vsx_unavailable_common) EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) #ifdef CONFIG_VSX @@ -1125,22 +1096,16 @@ fwnmi_data_area: . = 0x8000 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ - .align 7; EXC_COMMON(facility_unavailable_common, 0xf60, facility_unavailable_exception) - .align 7; EXC_COMMON(h_facility_unavailable_common, 0xf80, facility_unavailable_exception) #ifdef CONFIG_CBE_RAS - .align 7; EXC_COMMON(cbe_system_error_common, 0x1200, cbe_system_error_exception) - .align 7; EXC_COMMON(cbe_maintenance_common, 0x1600, cbe_maintenance_exception) - .align 7; EXC_COMMON(cbe_thermal_common, 0x1800, cbe_thermal_exception) #endif /* CONFIG_CBE_RAS */ - .align 7; EXC_COMMON_BEGIN(hmi_exception_early) EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, 0xe60) mr r10,r1 /* Save r1 */ @@ -1226,7 +1191,6 @@ hmi_exception_after_realmode: * Handle machine check early in real mode. We come here with * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack. */ - .align 7 EXC_COMMON_BEGIN(machine_check_handle_early) std r0,GPR0(r1) /* Save r0 */ EXCEPTION_PROLOG_COMMON_3(0x200) -- cgit v1.2.3 From 57f266497d81e16141bd2c9009e91dad34ea5f70 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 28 Sep 2016 11:31:48 +1000 Subject: powerpc: Use gas sections for arranging exception vectors Use assembler sections of fixed size and location to arrange the 64-bit Book3S exception vector code (64-bit Book3E also uses it in head_64.S for 0x0..0x100). This allows better flexibility in arranging exception code and hiding unimportant details behind macros. Gas sections can be a bit painful to use this way, mainly because the assembler does not know where they will be finally linked. Taking absolute addresses requires a bit of trickery for example, but it can be hidden behind macros for the most part. Generated code is mostly the same except locations, offsets, alignments. The "+ 0x2" is only required for the trap number / kvm exit number, which gets loaded as a constant into a register. Previously, code also used + 0x2 for label names, but we changed to using "H" to distinguish HV case for that. Remove the last vestiges of that. __after_prom_start is taking absolute address of a label in another fixed section. Newer toolchains seemed to compile this okay, but older ones do not. FIXED_SYMBOL_ABS_ADDR is more foolproof, it just takes an additional line to define. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/exception-64s.h | 2 +- arch/powerpc/include/asm/head-64.h | 261 +++++++++++++++++++++++++++++-- arch/powerpc/kernel/exceptions-64s.S | 111 +++++++++---- arch/powerpc/kernel/head_64.S | 44 ++++-- arch/powerpc/kernel/vmlinux.lds.S | 53 ++++++- 5 files changed, 404 insertions(+), 67 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 72f2b1e3f343..2e4e7d878c8e 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -91,7 +91,7 @@ */ #define LOAD_HANDLER(reg, label) \ ld reg,PACAKBASE(r13); /* get high part of &label */ \ - ori reg,reg,((label)-_stext)@l; /* virt addr of handler ... */ + ori reg,reg,(FIXED_SYMBOL_ABS_ADDR(label))@l; /* Exception register prefixes */ #define EXC_HV H diff --git a/arch/powerpc/include/asm/head-64.h b/arch/powerpc/include/asm/head-64.h index 613f743e91aa..ab90c2fa1ea6 100644 --- a/arch/powerpc/include/asm/head-64.h +++ b/arch/powerpc/include/asm/head-64.h @@ -3,28 +3,218 @@ #include +/* + * We can't do CPP stringification and concatination directly into the section + * name for some reason, so these macros can do it for us. + */ +.macro define_ftsec name + .section ".head.text.\name\()","ax",@progbits +.endm +.macro define_data_ftsec name + .section ".head.data.\name\()","a",@progbits +.endm +.macro use_ftsec name + .section ".head.text.\name\()" +.endm + +/* + * Fixed (location) sections are used by opening fixed sections and emitting + * fixed section entries into them before closing them. Multiple fixed sections + * can be open at any time. + * + * Each fixed section created in a .S file must have corresponding linkage + * directives including location, added to arch/powerpc/kernel/vmlinux.lds.S + * + * For each fixed section, code is generated into it in the order which it + * appears in the source. Fixed section entries can be placed at a fixed + * location within the section using _LOCATION postifx variants. These must + * be ordered according to their relative placements within the section. + * + * OPEN_FIXED_SECTION(section_name, start_address, end_address) + * FIXED_SECTION_ENTRY_BEGIN(section_name, label1) + * + * USE_FIXED_SECTION(section_name) + * label3: + * li r10,128 + * mv r11,r10 + + * FIXED_SECTION_ENTRY_BEGIN_LOCATION(section_name, label2, start_address) + * FIXED_SECTION_ENTRY_END_LOCATION(section_name, label2, end_address) + * CLOSE_FIXED_SECTION(section_name) + * + * ZERO_FIXED_SECTION can be used to emit zeroed data. + * + * Troubleshooting: + * - If the build dies with "Error: attempt to move .org backwards" at + * CLOSE_FIXED_SECTION() or elsewhere, there may be something + * unexpected being added there. Remove the '. = x_len' line, rebuild, and + * check what is pushing the section down. + * - If the build dies in linking, check arch/powerpc/kernel/vmlinux.lds.S + * for instructions. + * - If the kernel crashes or hangs in very early boot, it could be linker + * stubs at the start of the main text. + */ + +#define OPEN_FIXED_SECTION(sname, start, end) \ + sname##_start = (start); \ + sname##_end = (end); \ + sname##_len = (end) - (start); \ + define_ftsec sname; \ + . = 0x0; \ +start_##sname: + +#define OPEN_TEXT_SECTION(start) \ + text_start = (start); \ + .section ".text","ax",@progbits; \ + . = 0x0; \ +start_text: + +#define ZERO_FIXED_SECTION(sname, start, end) \ + sname##_start = (start); \ + sname##_end = (end); \ + sname##_len = (end) - (start); \ + define_data_ftsec sname; \ + . = 0x0; \ + . = sname##_len; + +#define USE_FIXED_SECTION(sname) \ + fs_label = start_##sname; \ + fs_start = sname##_start; \ + use_ftsec sname; + +#define USE_TEXT_SECTION() \ + fs_label = start_text; \ + fs_start = text_start; \ + .text + +#define CLOSE_FIXED_SECTION(sname) \ + USE_FIXED_SECTION(sname); \ + . = sname##_len; \ +end_##sname: + + +#define __FIXED_SECTION_ENTRY_BEGIN(sname, name, __align) \ + USE_FIXED_SECTION(sname); \ + .align __align; \ + .global name; \ +name: + +#define FIXED_SECTION_ENTRY_BEGIN(sname, name) \ + __FIXED_SECTION_ENTRY_BEGIN(sname, name, 0) + +#define FIXED_SECTION_ENTRY_BEGIN_LOCATION(sname, name, start) \ + USE_FIXED_SECTION(sname); \ + name##_start = (start); \ + .if (start) < sname##_start; \ + .error "Fixed section underflow"; \ + .abort; \ + .endif; \ + . = (start) - sname##_start; \ + .global name; \ +name: + +#define FIXED_SECTION_ENTRY_END_LOCATION(sname, name, end) \ + .if (end) > sname##_end; \ + .error "Fixed section overflow"; \ + .abort; \ + .endif; \ + .if (. - name > end - name##_start); \ + .error "Fixed entry overflow"; \ + .abort; \ + .endif; \ + . = ((end) - sname##_start); \ + + +/* + * These macros are used to change symbols in other fixed sections to be + * absolute or related to our current fixed section. + * + * - DEFINE_FIXED_SYMBOL / FIXED_SYMBOL_ABS_ADDR is used to find the + * absolute address of a symbol within a fixed section, from any section. + * + * - ABS_ADDR is used to find the absolute address of any symbol, from within + * a fixed section. + */ +#define DEFINE_FIXED_SYMBOL(label) \ + label##_absolute = (label - fs_label + fs_start) + +#define FIXED_SYMBOL_ABS_ADDR(label) \ + (label##_absolute) + +#define ABS_ADDR(label) (label - fs_label + fs_start) + +/* + * Following are the BOOK3S exception handler helper macros. + * Handlers come in a number of types, and each type has a number of varieties. + * + * EXC_REAL_* - real, unrelocated exception vectors + * EXC_VIRT_* - virt (AIL), unrelocated exception vectors + * TRAMP_REAL_* - real, unrelocated helpers (virt can call these) + * TRAMP_VIRT_* - virt, unreloc helpers (in practice, real can use) + * TRAMP_KVM - KVM handlers that get put into real, unrelocated + * EXC_COMMON_* - virt, relocated common handlers + * + * The EXC handlers are given a name, and branch to name_common, or the + * appropriate KVM or masking function. Vector handler verieties are as + * follows: + * + * EXC_{REAL|VIRT}_BEGIN/END - used to open-code the exception + * + * EXC_{REAL|VIRT} - standard exception + * + * EXC_{REAL|VIRT}_suffix + * where _suffix is: + * - _MASKABLE - maskable exception + * - _OOL - out of line with trampoline to common handler + * - _HV - HV exception + * + * There can be combinations, e.g., EXC_VIRT_OOL_MASKABLE_HV + * + * The one unusual case is __EXC_REAL_OOL_HV_DIRECT, which is + * an OOL vector that branches to a specified handler rather than the usual + * trampoline that goes to common. It, and other underscore macros, should + * be used with care. + * + * KVM handlers come in the following verieties: + * TRAMP_KVM + * TRAMP_KVM_SKIP + * TRAMP_KVM_HV + * TRAMP_KVM_HV_SKIP + * + * COMMON handlers come in the following verieties: + * EXC_COMMON_BEGIN/END - used to open-code the handler + * EXC_COMMON + * EXC_COMMON_ASYNC + * EXC_COMMON_HV + * + * TRAMP_REAL and TRAMP_VIRT can be used with BEGIN/END. KVM + * and OOL handlers are implemented as types of TRAMP and TRAMP_VIRT handlers. + */ + #define EXC_REAL_BEGIN(name, start, end) \ - . = start ; \ - .global exc_real_##start##_##name ; \ -exc_real_##start##_##name: + FIXED_SECTION_ENTRY_BEGIN_LOCATION(real_vectors, exc_real_##start##_##name, start) -#define EXC_REAL_END(name, start, end) +#define EXC_REAL_END(name, start, end) \ + FIXED_SECTION_ENTRY_END_LOCATION(real_vectors, exc_real_##start##_##name, end) #define EXC_VIRT_BEGIN(name, start, end) \ - . = start ; \ - .global exc_virt_##start##_##name ; \ -exc_virt_##start##_##name: + FIXED_SECTION_ENTRY_BEGIN_LOCATION(virt_vectors, exc_virt_##start##_##name, start) -#define EXC_VIRT_END(name, start, end) +#define EXC_VIRT_END(name, start, end) \ + FIXED_SECTION_ENTRY_END_LOCATION(virt_vectors, exc_virt_##start##_##name, end) #define EXC_COMMON_BEGIN(name) \ + USE_TEXT_SECTION(); \ .align 7; \ .global name; \ + DEFINE_FIXED_SYMBOL(name); \ name: #define TRAMP_REAL_BEGIN(name) \ - .global name ; \ -name: + FIXED_SECTION_ENTRY_BEGIN(real_trampolines, name) + +#define TRAMP_VIRT_BEGIN(name) \ + FIXED_SECTION_ENTRY_BEGIN(virt_trampolines, name) #ifdef CONFIG_KVM_BOOK3S_64_HANDLER #define TRAMP_KVM_BEGIN(name) \ @@ -33,9 +223,13 @@ name: #define TRAMP_KVM_BEGIN(name) #endif -#define EXC_REAL_NONE(start, end) +#define EXC_REAL_NONE(start, end) \ + FIXED_SECTION_ENTRY_BEGIN_LOCATION(real_vectors, exc_real_##start##_##unused, start); \ + FIXED_SECTION_ENTRY_END_LOCATION(real_vectors, exc_real_##start##_##unused, end) -#define EXC_VIRT_NONE(start, end) +#define EXC_VIRT_NONE(start, end) \ + FIXED_SECTION_ENTRY_BEGIN_LOCATION(virt_vectors, exc_virt_##start##_##unused, start); \ + FIXED_SECTION_ENTRY_END_LOCATION(virt_vectors, exc_virt_##start##_##unused, end); #define EXC_REAL(name, start, end) \ @@ -77,6 +271,10 @@ name: TRAMP_REAL_BEGIN(tramp_real_##name); \ STD_EXCEPTION_PSERIES_OOL(vec, name##_common); \ +#define EXC_REAL_OOL(name, start, end) \ + __EXC_REAL_OOL(name, start, end); \ + __TRAMP_REAL_REAL_OOL(name, start); + #define __EXC_REAL_OOL_MASKABLE(name, start, end) \ __EXC_REAL_OOL(name, start, end); @@ -84,6 +282,10 @@ name: TRAMP_REAL_BEGIN(tramp_real_##name); \ MASKABLE_EXCEPTION_PSERIES_OOL(vec, name##_common); \ +#define EXC_REAL_OOL_MASKABLE(name, start, end) \ + __EXC_REAL_OOL_MASKABLE(name, start, end); \ + __TRAMP_REAL_REAL_OOL_MASKABLE(name, start); + #define __EXC_REAL_OOL_HV_DIRECT(name, start, end, handler) \ EXC_REAL_BEGIN(name, start, end); \ __OOL_EXCEPTION(start, label, handler); \ @@ -96,6 +298,10 @@ name: TRAMP_REAL_BEGIN(tramp_real_##name); \ STD_EXCEPTION_HV_OOL(vec, name##_common); \ +#define EXC_REAL_OOL_HV(name, start, end) \ + __EXC_REAL_OOL_HV(name, start, end); \ + __TRAMP_REAL_REAL_OOL_HV(name, start); + #define __EXC_REAL_OOL_MASKABLE_HV(name, start, end) \ __EXC_REAL_OOL(name, start, end); @@ -103,36 +309,56 @@ name: TRAMP_REAL_BEGIN(tramp_real_##name); \ MASKABLE_EXCEPTION_HV_OOL(vec, name##_common); \ +#define EXC_REAL_OOL_MASKABLE_HV(name, start, end) \ + __EXC_REAL_OOL_MASKABLE_HV(name, start, end); \ + __TRAMP_REAL_REAL_OOL_MASKABLE_HV(name, start); + #define __EXC_VIRT_OOL(name, start, end) \ EXC_VIRT_BEGIN(name, start, end); \ __OOL_EXCEPTION(start, label, tramp_virt_##name); \ EXC_VIRT_END(name, start, end); #define __TRAMP_REAL_VIRT_OOL(name, realvec) \ - TRAMP_REAL_BEGIN(tramp_virt_##name); \ + TRAMP_VIRT_BEGIN(tramp_virt_##name); \ STD_RELON_EXCEPTION_PSERIES_OOL(realvec, name##_common); \ +#define EXC_VIRT_OOL(name, start, end, realvec) \ + __EXC_VIRT_OOL(name, start, end); \ + __TRAMP_REAL_VIRT_OOL(name, realvec); + #define __EXC_VIRT_OOL_MASKABLE(name, start, end) \ __EXC_VIRT_OOL(name, start, end); #define __TRAMP_REAL_VIRT_OOL_MASKABLE(name, realvec) \ - TRAMP_REAL_BEGIN(tramp_virt_##name); \ + TRAMP_VIRT_BEGIN(tramp_virt_##name); \ MASKABLE_RELON_EXCEPTION_PSERIES_OOL(realvec, name##_common); \ +#define EXC_VIRT_OOL_MASKABLE(name, start, end, realvec) \ + __EXC_VIRT_OOL_MASKABLE(name, start, end); \ + __TRAMP_REAL_VIRT_OOL_MASKABLE(name, realvec); + #define __EXC_VIRT_OOL_HV(name, start, end) \ __EXC_VIRT_OOL(name, start, end); #define __TRAMP_REAL_VIRT_OOL_HV(name, realvec) \ - TRAMP_REAL_BEGIN(tramp_virt_##name); \ + TRAMP_VIRT_BEGIN(tramp_virt_##name); \ STD_RELON_EXCEPTION_HV_OOL(realvec, name##_common); \ +#define EXC_VIRT_OOL_HV(name, start, end, realvec) \ + __EXC_VIRT_OOL_HV(name, start, end); \ + __TRAMP_REAL_VIRT_OOL_HV(name, realvec); + #define __EXC_VIRT_OOL_MASKABLE_HV(name, start, end) \ __EXC_VIRT_OOL(name, start, end); #define __TRAMP_REAL_VIRT_OOL_MASKABLE_HV(name, realvec) \ - TRAMP_REAL_BEGIN(tramp_virt_##name); \ + TRAMP_VIRT_BEGIN(tramp_virt_##name); \ MASKABLE_RELON_EXCEPTION_HV_OOL(realvec, name##_common); \ +#define EXC_VIRT_OOL_MASKABLE_HV(name, start, end, realvec) \ + __EXC_VIRT_OOL_MASKABLE_HV(name, start, end); \ + __TRAMP_REAL_VIRT_OOL_MASKABLE_HV(name, realvec); + #define TRAMP_KVM(area, n) \ TRAMP_KVM_BEGIN(do_kvm_##n); \ KVM_HANDLER(area, EXC_STD, n); \ @@ -141,6 +367,9 @@ name: TRAMP_KVM_BEGIN(do_kvm_##n); \ KVM_HANDLER_SKIP(area, EXC_STD, n); \ +/* + * HV variant exceptions get the 0x2 bit added to their trap number. + */ #define TRAMP_KVM_HV(area, n) \ TRAMP_KVM_BEGIN(do_kvm_H##n); \ KVM_HANDLER(area, EXC_HV, n + 0x2); \ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index d398e8716ef8..6ea330a3c51a 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -19,16 +19,68 @@ #include /* + * There are a few constraints to be concerned with. + * - Real mode exceptions code/data must be located at their physical location. + * - Virtual mode exceptions must be mapped at their 0xc000... location. + * - Fixed location code must not call directly beyond the __end_interrupts + * area when built with CONFIG_RELOCATABLE. LOAD_HANDLER / bctr sequence + * must be used. + * - LOAD_HANDLER targets must be within first 64K of physical 0 / + * virtual 0xc00... + * - Conditional branch targets must be within +/-32K of caller. + * + * "Virtual exceptions" run with relocation on (MSR_IR=1, MSR_DR=1), and + * therefore don't have to run in physically located code or rfid to + * virtual mode kernel code. However on relocatable kernels they do have + * to branch to KERNELBASE offset because the rest of the kernel (outside + * the exception vectors) may be located elsewhere. + * + * Virtual exceptions correspond with physical, except their entry points + * are offset by 0xc000000000000000 and also tend to get an added 0x4000 + * offset applied. Virtual exceptions are enabled with the Alternate + * Interrupt Location (AIL) bit set in the LPCR. However this does not + * guarantee they will be delivered virtually. Some conditions (see the ISA) + * cause exceptions to be delivered in real mode. + * + * It's impossible to receive interrupts below 0x300 via AIL. + * + * KVM: None of the virtual exceptions are from the guest. Anything that + * escalated to HV=1 from HV=0 is delivered via real mode handlers. + * + * * We layout physical memory as follows: * 0x0000 - 0x00ff : Secondary processor spin code - * 0x0100 - 0x17ff : pSeries Interrupt prologs - * 0x1800 - 0x4000 : interrupt support common interrupt prologs - * 0x4000 - 0x5fff : pSeries interrupts with IR=1,DR=1 - * 0x6000 - 0x6fff : more interrupt support including for IR=1,DR=1 + * 0x0100 - 0x18ff : Real mode pSeries interrupt vectors + * 0x1900 - 0x3fff : Real mode trampolines + * 0x4000 - 0x58ff : Relon (IR=1,DR=1) mode pSeries interrupt vectors + * 0x5900 - 0x6fff : Relon mode trampolines * 0x7000 - 0x7fff : FWNMI data area - * 0x8000 - 0x8fff : Initial (CPU0) segment table - * 0x9000 - : Early init and support code + * 0x8000 - .... : Common interrupt handlers, remaining early + * setup code, rest of kernel. + */ +OPEN_FIXED_SECTION(real_vectors, 0x0100, 0x1900) +OPEN_FIXED_SECTION(real_trampolines, 0x1900, 0x4000) +OPEN_FIXED_SECTION(virt_vectors, 0x4000, 0x5900) +OPEN_FIXED_SECTION(virt_trampolines, 0x5900, 0x7000) +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) +/* + * Data area reserved for FWNMI option. + * This address (0x7000) is fixed by the RPA. + * pseries and powernv need to keep the whole page from + * 0x7000 to 0x8000 free for use by the firmware */ +ZERO_FIXED_SECTION(fwnmi_page, 0x7000, 0x8000) +OPEN_TEXT_SECTION(0x8000) +#else +OPEN_TEXT_SECTION(0x7000) +#endif + +USE_FIXED_SECTION(real_vectors) + +#define LOAD_SYSCALL_HANDLER(reg) \ + ld reg,PACAKBASE(r13); \ + ori reg,reg,(ABS_ADDR(system_call_common))@l; + /* Syscall routine is used twice, in reloc-off and reloc-on paths */ #define SYSCALL_PSERIES_1 \ BEGIN_FTR_SECTION \ @@ -42,7 +94,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ #define SYSCALL_PSERIES_2_RFID \ mfspr r12,SPRN_SRR1 ; \ - LOAD_HANDLER(r10, system_call_common) ; \ + LOAD_SYSCALL_HANDLER(r10) ; \ mtspr SPRN_SRR0,r10 ; \ ld r10,PACAKMSR(r13) ; \ mtspr SPRN_SRR1,r10 ; \ @@ -63,7 +115,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ * is volatile across system calls. */ #define SYSCALL_PSERIES_2_DIRECT \ - LOAD_HANDLER(r12, system_call_common) ; \ + LOAD_SYSCALL_HANDLER(r12) ; \ mtctr r12 ; \ mfspr r12,SPRN_SRR1 ; \ li r10,MSR_RI ; \ @@ -86,7 +138,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ * Therefore any relative branches in this section must only * branch to labels in this section. */ - . = 0x100 .globl __start_interrupts __start_interrupts: @@ -200,9 +251,6 @@ EXC_REAL_BEGIN(instruction_access_slb, 0x480, 0x500) #endif EXC_REAL_END(instruction_access_slb, 0x480, 0x500) - /* We open code these as we can't have a ". = x" (even with - * x = "." within a feature section - */ EXC_REAL_BEGIN(hardware_interrupt, 0x500, 0x600) .globl hardware_interrupt_hv; hardware_interrupt_hv: @@ -306,7 +354,6 @@ __EXC_REAL_OOL_HV(h_facility_unavailable, 0xf80, 0xfa0) EXC_REAL_NONE(0xfa0, 0x1200) - #ifdef CONFIG_CBE_RAS EXC_REAL_HV(cbe_system_error, 0x1200, 0x1300) @@ -359,7 +406,6 @@ TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0x1800) #else /* CONFIG_CBE_RAS */ EXC_REAL_NONE(0x1800, 0x1900) - . = 0x1800 #endif @@ -606,7 +652,13 @@ masked_##_H##interrupt: \ GET_SCRATCH0(r13); \ ##_H##rfid; \ b . - + +/* + * Real mode exceptions actually use this too, but alternate + * instruction code patches (which end up in the common .text area) + * cannot reach these if they are put there. + */ +USE_FIXED_SECTION(virt_trampolines) MASKED_INTERRUPT() MASKED_INTERRUPT(H) @@ -620,6 +672,7 @@ masked_##_H##interrupt: \ * in the generated frame has EE set to 1 or the exception * handler will not properly re-enable them. */ +USE_TEXT_SECTION() _GLOBAL(__replay_interrupt) /* We are going to jump to the exception common code which * will retrieve various register values from the PACA which @@ -862,7 +915,7 @@ EXC_VIRT(altivec_assist, 0x5700, 0x5800, 0x1700) EXC_VIRT_NONE(0x5800, 0x5900) -TRAMP_REAL_BEGIN(ppc64_runlatch_on_trampoline) +EXC_COMMON_BEGIN(ppc64_runlatch_on_trampoline) b __ppc64_runlatch_on /* @@ -1070,6 +1123,7 @@ __TRAMP_REAL_VIRT_OOL(vsx_unavailable, 0xf40) __TRAMP_REAL_VIRT_OOL(facility_unavailable, 0xf60) __TRAMP_REAL_VIRT_OOL_HV(h_facility_unavailable, 0xf80) +USE_FIXED_SECTION(virt_trampolines) /* * The __end_interrupts marker must be past the out-of-line (OOL) * handlers, so that they are copied to real address 0x100 when running @@ -1080,21 +1134,7 @@ __TRAMP_REAL_VIRT_OOL_HV(h_facility_unavailable, 0xf80) .align 7 .globl __end_interrupts __end_interrupts: - -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) -/* - * Data area reserved for FWNMI option. - * This address (0x7000) is fixed by the RPA. - */ - .= 0x7000 - .globl fwnmi_data_area -fwnmi_data_area: - - /* pseries and powernv need to keep the whole page from - * 0x7000 to 0x8000 free for use by the firmware - */ - . = 0x8000 -#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ +DEFINE_FIXED_SYMBOL(__end_interrupts) EXC_COMMON(facility_unavailable_common, 0xf60, facility_unavailable_exception) EXC_COMMON(h_facility_unavailable_common, 0xf80, facility_unavailable_exception) @@ -1106,7 +1146,7 @@ EXC_COMMON(cbe_thermal_common, 0x1800, cbe_thermal_exception) #endif /* CONFIG_CBE_RAS */ -EXC_COMMON_BEGIN(hmi_exception_early) +TRAMP_REAL_BEGIN(hmi_exception_early) EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, 0xe60) mr r10,r1 /* Save r1 */ ld r1,PACAEMERGSP(r13) /* Use emergency stack */ @@ -1430,6 +1470,13 @@ TRAMP_REAL_BEGIN(power4_fixup_nap) blr #endif +CLOSE_FIXED_SECTION(real_vectors); +CLOSE_FIXED_SECTION(real_trampolines); +CLOSE_FIXED_SECTION(virt_vectors); +CLOSE_FIXED_SECTION(virt_trampolines); + +USE_TEXT_SECTION() + /* * Hash table stuff */ diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 6e21812ee672..79da0641bae2 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -65,9 +66,14 @@ * 2. The kernel is entered at __start */ - .text - .globl _stext -_stext: +OPEN_FIXED_SECTION(first_256B, 0x0, 0x100) +USE_FIXED_SECTION(first_256B) + /* + * Offsets are relative from the start of fixed section, and + * first_256B starts at 0. Offsets are a bit easier to use here + * than the fixed section entry macros. + */ + . = 0x0 _GLOBAL(__start) /* NOP this out unconditionally */ BEGIN_FTR_SECTION @@ -104,6 +110,7 @@ __secondary_hold_acknowledge: . = 0x5c .globl __run_at_load __run_at_load: +DEFINE_FIXED_SYMBOL(__run_at_load) .long 0x72756e30 /* "run0" -- relocate to 0 by default */ #endif @@ -133,7 +140,7 @@ __secondary_hold: /* Tell the master cpu we're here */ /* Relocation is off & we are located at an address less */ /* than 0x100, so only need to grab low order offset. */ - std r24,__secondary_hold_acknowledge-_stext(0) + std r24,(ABS_ADDR(__secondary_hold_acknowledge))(0) sync li r26,0 @@ -141,7 +148,7 @@ __secondary_hold: tovirt(r26,r26) #endif /* All secondary cpus wait here until told to start. */ -100: ld r12,__secondary_hold_spinloop-_stext(r26) +100: ld r12,(ABS_ADDR(__secondary_hold_spinloop))(r26) cmpdi 0,r12,0 beq 100b @@ -166,12 +173,13 @@ __secondary_hold: #else BUG_OPCODE #endif +CLOSE_FIXED_SECTION(first_256B) /* This value is used to mark exception frames on the stack. */ .section ".toc","aw" exception_marker: .tc ID_72656773_68657265[TC],0x7265677368657265 - .text + .previous /* * On server, we include the exception vectors code here as it @@ -180,8 +188,12 @@ exception_marker: */ #ifdef CONFIG_PPC_BOOK3S #include "exceptions-64s.S" +#else +OPEN_TEXT_SECTION(0x100) #endif +USE_TEXT_SECTION() + #ifdef CONFIG_PPC_BOOK3E /* * The booting_thread_hwid holds the thread id we want to boot in cpu @@ -558,7 +570,7 @@ __after_prom_start: #if defined(CONFIG_PPC_BOOK3E) tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */ #endif - lwz r7,__run_at_load-_stext(r26) + lwz r7,(FIXED_SYMBOL_ABS_ADDR(__run_at_load))(r26) #if defined(CONFIG_PPC_BOOK3E) tophys(r26,r26) #endif @@ -601,7 +613,7 @@ __after_prom_start: #if defined(CONFIG_PPC_BOOK3E) tovirt(r26,r26) /* on booke, we already run at PAGE_OFFSET */ #endif - lwz r7,__run_at_load-_stext(r26) + lwz r7,(FIXED_SYMBOL_ABS_ADDR(__run_at_load))(r26) cmplwi cr0,r7,1 bne 3f @@ -611,19 +623,21 @@ __after_prom_start: sub r5,r5,r11 #else /* just copy interrupts */ - LOAD_REG_IMMEDIATE(r5, __end_interrupts - _stext) + LOAD_REG_IMMEDIATE(r5, FIXED_SYMBOL_ABS_ADDR(__end_interrupts)) #endif b 5f 3: #endif - lis r5,(copy_to_here - _stext)@ha - addi r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */ + /* # bytes of memory to copy */ + lis r5,(ABS_ADDR(copy_to_here))@ha + addi r5,r5,(ABS_ADDR(copy_to_here))@l bl copy_and_flush /* copy the first n bytes */ /* this includes the code being */ /* executed here. */ - addis r8,r3,(4f - _stext)@ha /* Jump to the copy of this code */ - addi r12,r8,(4f - _stext)@l /* that we just made */ + /* Jump to the copy of this code that we just made */ + addis r8,r3,(ABS_ADDR(4f))@ha + addi r12,r8,(ABS_ADDR(4f))@l mtctr r12 bctr @@ -635,8 +649,8 @@ p_end: .llong _end - copy_to_here * Now copy the rest of the kernel up to _end, add * _end - copy_to_here to the copy limit and run again. */ - addis r8,r26,(p_end - _stext)@ha - ld r8,(p_end - _stext)@l(r8) + addis r8,r26,(ABS_ADDR(p_end))@ha + ld r8,(ABS_ADDR(p_end))@l(r8) add r5,r5,r8 5: bl copy_and_flush /* copy the rest */ diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index b59d75e194a5..2d1cfafd1404 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -44,11 +44,58 @@ SECTIONS * Text, read only data and other permanent read-only sections */ - /* Text and gots */ + _text = .; + _stext = .; + + /* + * Head text. + * This needs to be in its own output section to avoid ld placing + * branch trampoline stubs randomly throughout the fixed sections, + * which it will do (even if the branch comes from another section) + * in order to optimize stub generation. + */ + .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) { +#ifdef CONFIG_PPC64 + KEEP(*(.head.text.first_256B)); +#ifdef CONFIG_PPC_BOOK3E +# define END_FIXED 0x100 +#else + KEEP(*(.head.text.real_vectors)); + *(.head.text.real_trampolines); + KEEP(*(.head.text.virt_vectors)); + *(.head.text.virt_trampolines); +# if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) + KEEP(*(.head.data.fwnmi_page)); +# define END_FIXED 0x8000 +# else +# define END_FIXED 0x7000 +# endif +#endif + ASSERT((. == END_FIXED), "vmlinux.lds.S: fixed section overflow error"); +#else /* !CONFIG_PPC64 */ + HEAD_TEXT +#endif + } :kernel + + /* + * If the build dies here, it's likely code in head_64.S is referencing + * labels it can't reach, and the linker inserting stubs without the + * assembler's knowledge. To debug, remove the above assert and + * rebuild. Look for branch stubs in the fixed section region. + * + * Linker stub generation could be allowed in "trampoline" + * sections if absolutely necessary, but this would require + * some rework of the fixed sections. Before resorting to this, + * consider references that have sufficient addressing range, + * (e.g., hand coded trampolines) so the linker does not have + * to add stubs. + * + * Linker stubs at the top of the main text section are currently not + * detected, and will result in a crash at boot due to offsets being + * wrong. + */ .text : AT(ADDR(.text) - LOAD_OFFSET) { ALIGN_FUNCTION(); - HEAD_TEXT - _text = .; /* careful! __ftr_alt_* sections need to be close to .text */ *(.text .fixup __ftr_alt_* .ref.text) SCHED_TEXT -- cgit v1.2.3 From bb85fb5803270c52863b983596c2a038facaf4b3 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Oct 2016 17:40:29 +1100 Subject: powerpc: During context switch, check before setting mm_cpumask During context switch, switch_mm() sets our current CPU in mm_cpumask. We can avoid this atomic sequence in most cases by checking before setting the bit. Testing on a POWER8 using our context switch microbenchmark: tools/testing/selftests/powerpc/benchmarks/context_switch \ --process --no-fp --no-altivec --no-vector Performance improves 2%. Signed-off-by: Anton Blanchard Acked-by: Balbir Singh Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/mmu_context.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 475d1be39191..5c451140660a 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -72,7 +72,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { /* Mark this context has been used on the new CPU */ - cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); + if (!cpumask_test_cpu(smp_processor_id(), mm_cpumask(next))) + cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); /* 32-bit keeps track of the current PGDIR in the thread struct */ #ifdef CONFIG_PPC32 -- cgit v1.2.3 From 61e98ebff3ba3d3b17e999dc483c2680480ed715 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Oct 2016 17:03:03 +1100 Subject: powerpc: Remove static branch prediction in atomic{, 64}_add_unless I see quite a lot of static branch mispredictions on a simple web serving workload. The issue is in __atomic_add_unless(), called from _atomic_dec_and_lock(). There is no obvious common case, so it is better to let the hardware predict the branch. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/atomic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index f08d567e0ca4..2b90335194a7 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -233,7 +233,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) PPC_ATOMIC_ENTRY_BARRIER "1: lwarx %0,0,%1 # __atomic_add_unless\n\ cmpw 0,%0,%3 \n\ - beq- 2f \n\ + beq 2f \n\ add %0,%2,%0 \n" PPC405_ERR77(0,%2) " stwcx. %0,0,%1 \n\ @@ -539,7 +539,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) PPC_ATOMIC_ENTRY_BARRIER "1: ldarx %0,0,%1 # __atomic_add_unless\n\ cmpd 0,%0,%3 \n\ - beq- 2f \n\ + beq 2f \n\ add %0,%2,%0 \n" " stdcx. %0,0,%1 \n\ bne- 1b \n" -- cgit v1.2.3 From 066bcd785aac9c10e5f9b873f9bd2e438653340d Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 2 Aug 2016 14:10:31 +1000 Subject: powerpc/powernv: Specify proper data type for PCI_SLOT_ID_PREFIX This fixes the warning reported from sparse: eeh-powernv.c:875:23: warning: constant 0x8000000000000000 is so big it is unsigned long Fixes: ebe225312739 ("powerpc/powernv: Support PCI slot ID") Suggested-by: Michael Ellerman Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/pnv-pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/pnv-pci.h b/arch/powerpc/include/asm/pnv-pci.h index 17e89dd613e1..74b0b1e311b5 100644 --- a/arch/powerpc/include/asm/pnv-pci.h +++ b/arch/powerpc/include/asm/pnv-pci.h @@ -15,7 +15,7 @@ #include #include -#define PCI_SLOT_ID_PREFIX 0x8000000000000000 +#define PCI_SLOT_ID_PREFIX (1UL << 63) #define PCI_SLOT_ID(phb_id, bdfn) \ (PCI_SLOT_ID_PREFIX | ((uint64_t)(bdfn) << 16) | (phb_id)) -- cgit v1.2.3 From 3cee070a13b141b8eb5727c3bfa9920092f87264 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:10 +1000 Subject: powerpc: Return the new MSR from msr_check_and_set() msr_check_and_set() always performs a mfmsr() to determine if it needs to perform an mtmsr(), as mfmsr() can be a costly operation msr_check_and_set() could return the MSR now on the CPU to avoid callers of msr_check_and_set having to make their own mfmsr() call. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/reg.h | 2 +- arch/powerpc/kernel/process.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 9dddabc2fced..a8f63bcb71af 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1250,7 +1250,7 @@ static inline void mtmsr_isync(unsigned long val) : "memory") #endif -extern void msr_check_and_set(unsigned long bits); +extern unsigned long msr_check_and_set(unsigned long bits); extern bool strict_msr_control; extern void __msr_check_and_clear(unsigned long bits); static inline void msr_check_and_clear(unsigned long bits) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 50295670c617..34ee5f2e3271 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -111,7 +111,7 @@ static int __init enable_strict_msr_control(char *str) } early_param("ppc_strict_facility_enable", enable_strict_msr_control); -void msr_check_and_set(unsigned long bits) +unsigned long msr_check_and_set(unsigned long bits) { unsigned long oldmsr = mfmsr(); unsigned long newmsr; @@ -125,6 +125,8 @@ void msr_check_and_set(unsigned long bits) if (oldmsr != newmsr) mtmsr_isync(newmsr); + + return newmsr; } void __msr_check_and_clear(unsigned long bits) -- cgit v1.2.3 From d11994314b2bfe028bc39be24b44298787925160 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:12 +1000 Subject: powerpc: signals: Stop using current in signal code Much of the signal code takes a pt_regs on which it operates. Over time the signal code has needed to know more about the thread than what pt_regs can supply, this information is obtained as needed by using 'current'. This approach is not strictly incorrect however it does mean that there is now a hard requirement that the pt_regs being passed around does belong to current, this is never checked. A safer approach is for the majority of the signal functions to take a task_struct from which they can obtain pt_regs and any other information they need. The caveat that the task_struct they are passed must be current doesn't go away but can more easily be checked for. Functions called from outside powerpc signal code are passed a pt_regs and they can confirm that the pt_regs is that of current and pass current to other functions, furthurmore, powerpc signal functions can check that the task_struct they are passed is the same as current avoiding possible corruption of current (or the task they are passed) if this assertion ever fails. CC: paulus@samba.org Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/signal.h | 2 - arch/powerpc/kernel/signal.c | 41 ++++---- arch/powerpc/kernel/signal.h | 10 +- arch/powerpc/kernel/signal_32.c | 31 +++--- arch/powerpc/kernel/signal_64.c | 201 +++++++++++++++++++++----------------- 5 files changed, 159 insertions(+), 126 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h index 9322c28aebd2..5ff77722a52d 100644 --- a/arch/powerpc/include/asm/signal.h +++ b/arch/powerpc/include/asm/signal.h @@ -5,6 +5,4 @@ #include #include -extern unsigned long get_tm_stackpointer(struct pt_regs *regs); - #endif /* _ASM_POWERPC_SIGNAL_H */ diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index cb64d6feb45a..bbe77aed198d 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -99,22 +99,24 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, } } -static void do_signal(struct pt_regs *regs) +static void do_signal(struct task_struct *tsk) { sigset_t *oldset = sigmask_to_save(); struct ksignal ksig; int ret; int is32 = is_32bit_task(); + BUG_ON(tsk != current); + get_signal(&ksig); /* Is there any syscall restart business here ? */ - check_syscall_restart(regs, &ksig.ka, ksig.sig > 0); + check_syscall_restart(tsk->thread.regs, &ksig.ka, ksig.sig > 0); if (ksig.sig <= 0) { /* No signal to deliver -- put the saved sigmask back */ restore_saved_sigmask(); - regs->trap = 0; + tsk->thread.regs->trap = 0; return; /* no signals delivered */ } @@ -124,23 +126,22 @@ static void do_signal(struct pt_regs *regs) * user space. The DABR will have been cleared if it * triggered inside the kernel. */ - if (current->thread.hw_brk.address && - current->thread.hw_brk.type) - __set_breakpoint(¤t->thread.hw_brk); + if (tsk->thread.hw_brk.address && tsk->thread.hw_brk.type) + __set_breakpoint(&tsk->thread.hw_brk); #endif /* Re-enable the breakpoints for the signal stack */ - thread_change_pc(current, regs); + thread_change_pc(tsk, tsk->thread.regs); if (is32) { if (ksig.ka.sa.sa_flags & SA_SIGINFO) - ret = handle_rt_signal32(&ksig, oldset, regs); + ret = handle_rt_signal32(&ksig, oldset, tsk); else - ret = handle_signal32(&ksig, oldset, regs); + ret = handle_signal32(&ksig, oldset, tsk); } else { - ret = handle_rt_signal64(&ksig, oldset, regs); + ret = handle_rt_signal64(&ksig, oldset, tsk); } - regs->trap = 0; + tsk->thread.regs->trap = 0; signal_setup_done(ret, &ksig, test_thread_flag(TIF_SINGLESTEP)); } @@ -151,8 +152,10 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) if (thread_info_flags & _TIF_UPROBE) uprobe_notify_resume(regs); - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); + if (thread_info_flags & _TIF_SIGPENDING) { + BUG_ON(regs != current->thread.regs); + do_signal(current); + } if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); @@ -162,7 +165,7 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) user_enter(); } -unsigned long get_tm_stackpointer(struct pt_regs *regs) +unsigned long get_tm_stackpointer(struct task_struct *tsk) { /* When in an active transaction that takes a signal, we need to be * careful with the stack. It's possible that the stack has moved back @@ -187,11 +190,13 @@ unsigned long get_tm_stackpointer(struct pt_regs *regs) */ #ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(regs->msr)) { + BUG_ON(tsk != current); + + if (MSR_TM_ACTIVE(tsk->thread.regs->msr)) { tm_reclaim_current(TM_CAUSE_SIGNAL); - if (MSR_TM_TRANSACTIONAL(regs->msr)) - return current->thread.ckpt_regs.gpr[1]; + if (MSR_TM_TRANSACTIONAL(tsk->thread.regs->msr)) + return tsk->thread.ckpt_regs.gpr[1]; } #endif - return regs->gpr[1]; + return tsk->thread.regs->gpr[1]; } diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h index be305c858e51..254ca074504f 100644 --- a/arch/powerpc/kernel/signal.h +++ b/arch/powerpc/kernel/signal.h @@ -16,10 +16,10 @@ extern void __user *get_sigframe(struct ksignal *ksig, unsigned long sp, size_t frame_size, int is_32); extern int handle_signal32(struct ksignal *ksig, sigset_t *oldset, - struct pt_regs *regs); + struct task_struct *tsk); extern int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, - struct pt_regs *regs); + struct task_struct *tsk); extern unsigned long copy_fpr_to_user(void __user *to, struct task_struct *task); @@ -29,6 +29,8 @@ extern unsigned long copy_fpr_from_user(struct task_struct *task, void __user *from); extern unsigned long copy_transact_fpr_from_user(struct task_struct *task, void __user *from); +extern unsigned long get_tm_stackpointer(struct task_struct *tsk); + #ifdef CONFIG_VSX extern unsigned long copy_vsx_to_user(void __user *to, struct task_struct *task); @@ -43,12 +45,12 @@ extern unsigned long copy_transact_vsx_from_user(struct task_struct *task, #ifdef CONFIG_PPC64 extern int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, - struct pt_regs *regs); + struct task_struct *tsk); #else /* CONFIG_PPC64 */ static inline int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, - struct pt_regs *regs) + struct task_struct *tsk) { return -EFAULT; } diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index d2745375f27e..9637f8eb5204 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -978,7 +978,7 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) * (one which gets siginfo). */ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, - struct pt_regs *regs) + struct task_struct *tsk) { struct rt_sigframe __user *rt_sf; struct mcontext __user *frame; @@ -987,10 +987,13 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, unsigned long newsp = 0; int sigret; unsigned long tramp; + struct pt_regs *regs = tsk->thread.regs; + + BUG_ON(tsk != current); /* Set up Signal Frame */ /* Put a Real Time Context onto stack */ - rt_sf = get_sigframe(ksig, get_tm_stackpointer(regs), sizeof(*rt_sf), 1); + rt_sf = get_sigframe(ksig, get_tm_stackpointer(tsk), sizeof(*rt_sf), 1); addr = rt_sf; if (unlikely(rt_sf == NULL)) goto badframe; @@ -1007,9 +1010,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; addr = frame; - if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { + if (vdso32_rt_sigtramp && tsk->mm->context.vdso_base) { sigret = 0; - tramp = current->mm->context.vdso_base + vdso32_rt_sigtramp; + tramp = tsk->mm->context.vdso_base + vdso32_rt_sigtramp; } else { sigret = __NR_rt_sigreturn; tramp = (unsigned long) frame->tramp; @@ -1036,7 +1039,7 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, } regs->link = tramp; - current->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ + tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ /* create a stack frame for the caller of the handler */ newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16); @@ -1061,7 +1064,7 @@ badframe: printk_ratelimited(KERN_INFO "%s[%d]: bad frame in handle_rt_signal32: " "%p nip %08lx lr %08lx\n", - current->comm, current->pid, + tsk->comm, tsk->pid, addr, regs->nip, regs->link); return 1; @@ -1417,7 +1420,8 @@ int sys_debug_setcontext(struct ucontext __user *ctx, /* * OK, we're invoking a handler */ -int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs) +int handle_signal32(struct ksignal *ksig, sigset_t *oldset, + struct task_struct *tsk) { struct sigcontext __user *sc; struct sigframe __user *frame; @@ -1425,9 +1429,12 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs unsigned long newsp = 0; int sigret; unsigned long tramp; + struct pt_regs *regs = tsk->thread.regs; + + BUG_ON(tsk != current); /* Set up Signal Frame */ - frame = get_sigframe(ksig, get_tm_stackpointer(regs), sizeof(*frame), 1); + frame = get_sigframe(ksig, get_tm_stackpointer(tsk), sizeof(*frame), 1); if (unlikely(frame == NULL)) goto badframe; sc = (struct sigcontext __user *) &frame->sctx; @@ -1446,9 +1453,9 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs || __put_user(ksig->sig, &sc->signal)) goto badframe; - if (vdso32_sigtramp && current->mm->context.vdso_base) { + if (vdso32_sigtramp && tsk->mm->context.vdso_base) { sigret = 0; - tramp = current->mm->context.vdso_base + vdso32_sigtramp; + tramp = tsk->mm->context.vdso_base + vdso32_sigtramp; } else { sigret = __NR_sigreturn; tramp = (unsigned long) frame->mctx.tramp; @@ -1470,7 +1477,7 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, struct pt_regs *regs regs->link = tramp; - current->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ + tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ /* create a stack frame for the caller of the handler */ newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; @@ -1490,7 +1497,7 @@ badframe: printk_ratelimited(KERN_INFO "%s[%d]: bad frame in handle_signal32: " "%p nip %08lx lr %08lx\n", - current->comm, current->pid, + tsk->comm, tsk->pid, frame, regs->nip, regs->link); return 1; diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 6faa8240b7c9..befa10af0c17 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -91,9 +91,9 @@ static elf_vrreg_t __user *sigcontext_vmx_regs(struct sigcontext __user *sc) * Set up the sigcontext for the signal frame. */ -static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, - int signr, sigset_t *set, unsigned long handler, - int ctx_has_vsx_region) +static long setup_sigcontext(struct sigcontext __user *sc, + struct task_struct *tsk, int signr, sigset_t *set, + unsigned long handler, int ctx_has_vsx_region) { /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the * process never used altivec yet (MSR_VEC is zero in pt_regs of @@ -107,17 +107,20 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, elf_vrreg_t __user *v_regs = sigcontext_vmx_regs(sc); unsigned long vrsave; #endif + struct pt_regs *regs = tsk->thread.regs; unsigned long msr = regs->msr; long err = 0; + BUG_ON(tsk != current); + #ifdef CONFIG_ALTIVEC err |= __put_user(v_regs, &sc->v_regs); /* save altivec registers */ - if (current->thread.used_vr) { - flush_altivec_to_thread(current); + if (tsk->thread.used_vr) { + flush_altivec_to_thread(tsk); /* Copy 33 vec registers (vr0..31 and vscr) to the stack */ - err |= __copy_to_user(v_regs, ¤t->thread.vr_state, + err |= __copy_to_user(v_regs, &tsk->thread.vr_state, 33 * sizeof(vector128)); /* set MSR_VEC in the MSR value in the frame to indicate that sc->v_reg) * contains valid data. @@ -130,16 +133,16 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, vrsave = 0; if (cpu_has_feature(CPU_FTR_ALTIVEC)) { vrsave = mfspr(SPRN_VRSAVE); - current->thread.vrsave = vrsave; + tsk->thread.vrsave = vrsave; } err |= __put_user(vrsave, (u32 __user *)&v_regs[33]); #else /* CONFIG_ALTIVEC */ err |= __put_user(0, &sc->v_regs); #endif /* CONFIG_ALTIVEC */ - flush_fp_to_thread(current); + flush_fp_to_thread(tsk); /* copy fpr regs and fpscr */ - err |= copy_fpr_to_user(&sc->fp_regs, current); + err |= copy_fpr_to_user(&sc->fp_regs, tsk); /* * Clear the MSR VSX bit to indicate there is no valid state attached @@ -152,10 +155,10 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, * then out to userspace. Update v_regs to point after the * VMX data. */ - if (current->thread.used_vsr && ctx_has_vsx_region) { - flush_vsx_to_thread(current); + if (tsk->thread.used_vsr && ctx_has_vsx_region) { + flush_vsx_to_thread(tsk); v_regs += ELF_NVRREG; - err |= copy_vsx_to_user(v_regs, current); + err |= copy_vsx_to_user(v_regs, tsk); /* set MSR_VSX in the MSR value in the frame to * indicate that sc->vs_reg) contains valid data. */ @@ -188,7 +191,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, */ static long setup_tm_sigcontexts(struct sigcontext __user *sc, struct sigcontext __user *tm_sc, - struct pt_regs *regs, + struct task_struct *tsk, int signr, sigset_t *set, unsigned long handler) { /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the @@ -203,9 +206,12 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, elf_vrreg_t __user *v_regs = sigcontext_vmx_regs(sc); elf_vrreg_t __user *tm_v_regs = sigcontext_vmx_regs(tm_sc); #endif - unsigned long msr = regs->msr; + struct pt_regs *regs = tsk->thread.regs; + unsigned long msr = tsk->thread.ckpt_regs.msr; long err = 0; + BUG_ON(tsk != current); + BUG_ON(!MSR_TM_ACTIVE(regs->msr)); /* Remove TM bits from thread's MSR. The MSR in the sigcontext @@ -215,28 +221,28 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, */ regs->msr &= ~MSR_TS_MASK; - flush_fp_to_thread(current); + flush_fp_to_thread(tsk); #ifdef CONFIG_ALTIVEC err |= __put_user(v_regs, &sc->v_regs); err |= __put_user(tm_v_regs, &tm_sc->v_regs); /* save altivec registers */ - if (current->thread.used_vr) { - flush_altivec_to_thread(current); + if (tsk->thread.used_vr) { + flush_altivec_to_thread(tsk); /* Copy 33 vec registers (vr0..31 and vscr) to the stack */ - err |= __copy_to_user(v_regs, ¤t->thread.vr_state, + err |= __copy_to_user(v_regs, &tsk->thread.vr_state, 33 * sizeof(vector128)); /* If VEC was enabled there are transactional VRs valid too, * else they're a copy of the checkpointed VRs. */ if (msr & MSR_VEC) err |= __copy_to_user(tm_v_regs, - ¤t->thread.transact_vr, + &tsk->thread.transact_vr, 33 * sizeof(vector128)); else err |= __copy_to_user(tm_v_regs, - ¤t->thread.vr_state, + &tsk->thread.vr_state, 33 * sizeof(vector128)); /* set MSR_VEC in the MSR value in the frame to indicate @@ -248,13 +254,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, * use altivec. */ if (cpu_has_feature(CPU_FTR_ALTIVEC)) - current->thread.vrsave = mfspr(SPRN_VRSAVE); - err |= __put_user(current->thread.vrsave, (u32 __user *)&v_regs[33]); + tsk->thread.vrsave = mfspr(SPRN_VRSAVE); + err |= __put_user(tsk->thread.vrsave, (u32 __user *)&v_regs[33]); if (msr & MSR_VEC) - err |= __put_user(current->thread.transact_vrsave, + err |= __put_user(tsk->thread.transact_vrsave, (u32 __user *)&tm_v_regs[33]); else - err |= __put_user(current->thread.vrsave, + err |= __put_user(tsk->thread.vrsave, (u32 __user *)&tm_v_regs[33]); #else /* CONFIG_ALTIVEC */ @@ -263,11 +269,11 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, #endif /* CONFIG_ALTIVEC */ /* copy fpr regs and fpscr */ - err |= copy_fpr_to_user(&sc->fp_regs, current); + err |= copy_fpr_to_user(&sc->fp_regs, tsk); if (msr & MSR_FP) - err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, current); + err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, tsk); else - err |= copy_fpr_to_user(&tm_sc->fp_regs, current); + err |= copy_fpr_to_user(&tm_sc->fp_regs, tsk); #ifdef CONFIG_VSX /* @@ -275,17 +281,17 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, * then out to userspace. Update v_regs to point after the * VMX data. */ - if (current->thread.used_vsr) { - flush_vsx_to_thread(current); + if (tsk->thread.used_vsr) { + flush_vsx_to_thread(tsk); v_regs += ELF_NVRREG; tm_v_regs += ELF_NVRREG; - err |= copy_vsx_to_user(v_regs, current); + err |= copy_vsx_to_user(v_regs, tsk); if (msr & MSR_VSX) - err |= copy_transact_vsx_to_user(tm_v_regs, current); + err |= copy_transact_vsx_to_user(tm_v_regs, tsk); else - err |= copy_vsx_to_user(tm_v_regs, current); + err |= copy_vsx_to_user(tm_v_regs, tsk); /* set MSR_VSX in the MSR value in the frame to * indicate that sc->vs_reg) contains valid data. @@ -299,7 +305,7 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, WARN_ON(!FULL_REGS(regs)); err |= __copy_to_user(&tm_sc->gp_regs, regs, GP_REGS_SIZE); err |= __copy_to_user(&sc->gp_regs, - ¤t->thread.ckpt_regs, GP_REGS_SIZE); + &tsk->thread.ckpt_regs, GP_REGS_SIZE); err |= __put_user(msr, &tm_sc->gp_regs[PT_MSR]); err |= __put_user(msr, &sc->gp_regs[PT_MSR]); err |= __put_user(signr, &sc->signal); @@ -315,7 +321,7 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, * Restore the sigcontext from the signal frame. */ -static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, +static long restore_sigcontext(struct task_struct *tsk, sigset_t *set, int sig, struct sigcontext __user *sc) { #ifdef CONFIG_ALTIVEC @@ -324,10 +330,13 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, unsigned long err = 0; unsigned long save_r13 = 0; unsigned long msr; + struct pt_regs *regs = tsk->thread.regs; #ifdef CONFIG_VSX int i; #endif + BUG_ON(tsk != current); + /* If this is not a signal return, we preserve the TLS in r13 */ if (!sig) save_r13 = regs->gpr[13]; @@ -357,7 +366,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, /* * Force reload of FP/VEC. - * This has to be done before copying stuff into current->thread.fpr/vr + * This has to be done before copying stuff into tsk->thread.fpr/vr * for the reasons explained in the previous comment. */ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC | MSR_VSX); @@ -370,22 +379,22 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, return -EFAULT; /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ if (v_regs != NULL && (msr & MSR_VEC) != 0) { - err |= __copy_from_user(¤t->thread.vr_state, v_regs, + err |= __copy_from_user(&tsk->thread.vr_state, v_regs, 33 * sizeof(vector128)); - current->thread.used_vr = true; + tsk->thread.used_vr = true; + } else if (tsk->thread.used_vr) { + memset(&tsk->thread.vr_state, 0, 33 * sizeof(vector128)); } - else if (current->thread.used_vr) - memset(¤t->thread.vr_state, 0, 33 * sizeof(vector128)); /* Always get VRSAVE back */ if (v_regs != NULL) - err |= __get_user(current->thread.vrsave, (u32 __user *)&v_regs[33]); + err |= __get_user(tsk->thread.vrsave, (u32 __user *)&v_regs[33]); else - current->thread.vrsave = 0; + tsk->thread.vrsave = 0; if (cpu_has_feature(CPU_FTR_ALTIVEC)) - mtspr(SPRN_VRSAVE, current->thread.vrsave); + mtspr(SPRN_VRSAVE, tsk->thread.vrsave); #endif /* CONFIG_ALTIVEC */ /* restore floating point */ - err |= copy_fpr_from_user(current, &sc->fp_regs); + err |= copy_fpr_from_user(tsk, &sc->fp_regs); #ifdef CONFIG_VSX /* * Get additional VSX data. Update v_regs to point after the @@ -394,11 +403,12 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, */ v_regs += ELF_NVRREG; if ((msr & MSR_VSX) != 0) { - err |= copy_vsx_from_user(current, v_regs); - current->thread.used_vsr = true; - } else + err |= copy_vsx_from_user(tsk, v_regs); + tsk->thread.used_vsr = true; + } else { for (i = 0; i < 32 ; i++) - current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0; + tsk->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0; + } #endif return err; } @@ -408,7 +418,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, * Restore the two sigcontexts from the frame of a transactional processes. */ -static long restore_tm_sigcontexts(struct pt_regs *regs, +static long restore_tm_sigcontexts(struct task_struct *tsk, struct sigcontext __user *sc, struct sigcontext __user *tm_sc) { @@ -417,12 +427,16 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, #endif unsigned long err = 0; unsigned long msr; + struct pt_regs *regs = tsk->thread.regs; #ifdef CONFIG_VSX int i; #endif + + BUG_ON(tsk != current); + /* copy the GPRs */ err |= __copy_from_user(regs->gpr, tm_sc->gp_regs, sizeof(regs->gpr)); - err |= __copy_from_user(¤t->thread.ckpt_regs, sc->gp_regs, + err |= __copy_from_user(&tsk->thread.ckpt_regs, sc->gp_regs, sizeof(regs->gpr)); /* @@ -434,7 +448,7 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, * we don't need to re-copy them here. */ err |= __get_user(regs->nip, &tm_sc->gp_regs[PT_NIP]); - err |= __get_user(current->thread.tm_tfhar, &sc->gp_regs[PT_NIP]); + err |= __get_user(tsk->thread.tm_tfhar, &sc->gp_regs[PT_NIP]); /* get MSR separately, transfer the LE bit if doing signal return */ err |= __get_user(msr, &sc->gp_regs[PT_MSR]); @@ -453,13 +467,13 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, err |= __get_user(regs->link, &tm_sc->gp_regs[PT_LNK]); err |= __get_user(regs->xer, &tm_sc->gp_regs[PT_XER]); err |= __get_user(regs->ccr, &tm_sc->gp_regs[PT_CCR]); - err |= __get_user(current->thread.ckpt_regs.ctr, + err |= __get_user(tsk->thread.ckpt_regs.ctr, &sc->gp_regs[PT_CTR]); - err |= __get_user(current->thread.ckpt_regs.link, + err |= __get_user(tsk->thread.ckpt_regs.link, &sc->gp_regs[PT_LNK]); - err |= __get_user(current->thread.ckpt_regs.xer, + err |= __get_user(tsk->thread.ckpt_regs.xer, &sc->gp_regs[PT_XER]); - err |= __get_user(current->thread.ckpt_regs.ccr, + err |= __get_user(tsk->thread.ckpt_regs.ccr, &sc->gp_regs[PT_CCR]); /* These regs are not checkpointed; they can go in 'regs'. */ @@ -470,7 +484,7 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, /* * Force reload of FP/VEC. - * This has to be done before copying stuff into current->thread.fpr/vr + * This has to be done before copying stuff into tsk->thread.fpr/vr * for the reasons explained in the previous comment. */ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC | MSR_VSX); @@ -487,33 +501,33 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, return -EFAULT; /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ if (v_regs != NULL && tm_v_regs != NULL && (msr & MSR_VEC) != 0) { - err |= __copy_from_user(¤t->thread.vr_state, v_regs, + err |= __copy_from_user(&tsk->thread.vr_state, v_regs, 33 * sizeof(vector128)); - err |= __copy_from_user(¤t->thread.transact_vr, tm_v_regs, + err |= __copy_from_user(&tsk->thread.transact_vr, tm_v_regs, 33 * sizeof(vector128)); current->thread.used_vr = true; } - else if (current->thread.used_vr) { - memset(¤t->thread.vr_state, 0, 33 * sizeof(vector128)); - memset(¤t->thread.transact_vr, 0, 33 * sizeof(vector128)); + else if (tsk->thread.used_vr) { + memset(&tsk->thread.vr_state, 0, 33 * sizeof(vector128)); + memset(&tsk->thread.transact_vr, 0, 33 * sizeof(vector128)); } /* Always get VRSAVE back */ if (v_regs != NULL && tm_v_regs != NULL) { - err |= __get_user(current->thread.vrsave, + err |= __get_user(tsk->thread.vrsave, (u32 __user *)&v_regs[33]); - err |= __get_user(current->thread.transact_vrsave, + err |= __get_user(tsk->thread.transact_vrsave, (u32 __user *)&tm_v_regs[33]); } else { - current->thread.vrsave = 0; - current->thread.transact_vrsave = 0; + tsk->thread.vrsave = 0; + tsk->thread.transact_vrsave = 0; } if (cpu_has_feature(CPU_FTR_ALTIVEC)) - mtspr(SPRN_VRSAVE, current->thread.vrsave); + mtspr(SPRN_VRSAVE, tsk->thread.vrsave); #endif /* CONFIG_ALTIVEC */ /* restore floating point */ - err |= copy_fpr_from_user(current, &sc->fp_regs); - err |= copy_transact_fpr_from_user(current, &tm_sc->fp_regs); + err |= copy_fpr_from_user(tsk, &sc->fp_regs); + err |= copy_transact_fpr_from_user(tsk, &tm_sc->fp_regs); #ifdef CONFIG_VSX /* * Get additional VSX data. Update v_regs to point after the @@ -523,30 +537,30 @@ static long restore_tm_sigcontexts(struct pt_regs *regs, if (v_regs && ((msr & MSR_VSX) != 0)) { v_regs += ELF_NVRREG; tm_v_regs += ELF_NVRREG; - err |= copy_vsx_from_user(current, v_regs); - err |= copy_transact_vsx_from_user(current, tm_v_regs); - current->thread.used_vsr = true; + err |= copy_vsx_from_user(tsk, v_regs); + err |= copy_transact_vsx_from_user(tsk, tm_v_regs); + tsk->thread.used_vsr = true; } else { for (i = 0; i < 32 ; i++) { - current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0; - current->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = 0; + tsk->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0; + tsk->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = 0; } } #endif tm_enable(); /* Make sure the transaction is marked as failed */ - current->thread.tm_texasr |= TEXASR_FS; + tsk->thread.tm_texasr |= TEXASR_FS; /* This loads the checkpointed FP/VEC state, if used */ - tm_recheckpoint(¤t->thread, msr); + tm_recheckpoint(&tsk->thread, msr); /* This loads the speculative FP/VEC state, if used */ if (msr & MSR_FP) { - do_load_up_transact_fpu(¤t->thread); - regs->msr |= (MSR_FP | current->thread.fpexc_mode); + do_load_up_transact_fpu(&tsk->thread); + regs->msr |= (MSR_FP | tsk->thread.fpexc_mode); } #ifdef CONFIG_ALTIVEC if (msr & MSR_VEC) { - do_load_up_transact_altivec(¤t->thread); + do_load_up_transact_altivec(&tsk->thread); regs->msr |= MSR_VEC; } #endif @@ -600,6 +614,8 @@ int sys_swapcontext(struct ucontext __user *old_ctx, unsigned long new_msr = 0; int ctx_has_vsx_region = 0; + BUG_ON(regs != current->thread.regs); + if (new_ctx && get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR])) return -EFAULT; @@ -622,7 +638,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx, if (old_ctx != NULL) { if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size) - || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0, + || setup_sigcontext(&old_ctx->uc_mcontext, current, 0, NULL, 0, ctx_has_vsx_region) || __copy_to_user(&old_ctx->uc_sigmask, ¤t->blocked, sizeof(sigset_t))) @@ -650,7 +666,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx, if (__copy_from_user(&set, &new_ctx->uc_sigmask, sizeof(set))) do_exit(SIGSEGV); set_current_blocked(&set); - if (restore_sigcontext(regs, NULL, 0, &new_ctx->uc_mcontext)) + if (restore_sigcontext(current, NULL, 0, &new_ctx->uc_mcontext)) do_exit(SIGSEGV); /* This returns like rt_sigreturn */ @@ -673,6 +689,8 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long msr; #endif + BUG_ON(current->thread.regs != regs); + /* Always make any pending restarted system calls return -EINTR */ current->restart_block.fn = do_no_restart_syscall; @@ -704,14 +722,14 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, struct ucontext __user *uc_transact; if (__get_user(uc_transact, &uc->uc_link)) goto badframe; - if (restore_tm_sigcontexts(regs, &uc->uc_mcontext, + if (restore_tm_sigcontexts(current, &uc->uc_mcontext, &uc_transact->uc_mcontext)) goto badframe; } else /* Fall through, for non-TM restore */ #endif - if (restore_sigcontext(regs, NULL, 1, &uc->uc_mcontext)) + if (restore_sigcontext(current, NULL, 1, &uc->uc_mcontext)) goto badframe; if (restore_altstack(&uc->uc_stack)) @@ -730,13 +748,17 @@ badframe: return 0; } -int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) +int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, + struct task_struct *tsk) { struct rt_sigframe __user *frame; unsigned long newsp = 0; long err = 0; + struct pt_regs *regs = tsk->thread.regs; + + BUG_ON(tsk != current); - frame = get_sigframe(ksig, get_tm_stackpointer(regs), sizeof(*frame), 0); + frame = get_sigframe(ksig, get_tm_stackpointer(tsk), sizeof(*frame), 0); if (unlikely(frame == NULL)) goto badframe; @@ -757,14 +779,13 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs err |= __put_user(&frame->uc_transact, &frame->uc.uc_link); err |= setup_tm_sigcontexts(&frame->uc.uc_mcontext, &frame->uc_transact.uc_mcontext, - regs, ksig->sig, - NULL, + tsk, ksig->sig, NULL, (unsigned long)ksig->ka.sa.sa_handler); } else #endif { err |= __put_user(0, &frame->uc.uc_link); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, ksig->sig, + err |= setup_sigcontext(&frame->uc.uc_mcontext, tsk, ksig->sig, NULL, (unsigned long)ksig->ka.sa.sa_handler, 1); } @@ -773,11 +794,11 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs goto badframe; /* Make sure signal handler doesn't get spurious FP exceptions */ - current->thread.fp_state.fpscr = 0; + tsk->thread.fp_state.fpscr = 0; /* Set up to return from userspace. */ - if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { - regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp; + if (vdso64_rt_sigtramp && tsk->mm->context.vdso_base) { + regs->link = tsk->mm->context.vdso_base + vdso64_rt_sigtramp; } else { err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); if (err) @@ -827,7 +848,7 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs badframe: if (show_unhandled_signals) printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32, - current->comm, current->pid, "setup_rt_frame", + tsk->comm, tsk->pid, "setup_rt_frame", (long)frame, regs->nip, regs->link); return 1; -- cgit v1.2.3 From dc3106690b20305c3df06b42456fe386dd632ac9 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:24 +1000 Subject: powerpc: tm: Always use fp_state and vr_state to store live registers There is currently an inconsistency as to how the entire CPU register state is saved and restored when a thread uses transactional memory (TM). Using transactional memory results in the CPU having duplicated (almost) all of its register state. This duplication results in a set of registers which can be considered 'live', those being currently modified by the instructions being executed and another set that is frozen at a point in time. On context switch, both sets of state have to be saved and (later) restored. These two states are often called a variety of different things. Common terms for the state which only exists after the CPU has entered a transaction (performed a TBEGIN instruction) in hardware are 'transactional' or 'speculative'. Between a TBEGIN and a TEND or TABORT (or an event that causes the hardware to abort), regardless of the use of TSUSPEND the transactional state can be referred to as the live state. The second state is often to referred to as the 'checkpointed' state and is a duplication of the live state when the TBEGIN instruction is executed. This state is kept in the hardware and will be rolled back to on transaction failure. Currently all the registers stored in pt_regs are ALWAYS the live registers, that is, when a thread has transactional registers their values are stored in pt_regs and the checkpointed state is in ckpt_regs. A strange opposite is true for fp_state/vr_state. When a thread is non transactional fp_state/vr_state holds the live registers. When a thread has initiated a transaction fp_state/vr_state holds the checkpointed state and transact_fp/transact_vr become the structure which holds the live state (at this point it is a transactional state). This method creates confusion as to where the live state is, in some circumstances it requires extra work to determine where to put the live state and prevents the use of common functions designed (probably before TM) to save the live state. With this patch pt_regs, fp_state and vr_state all represent the same thing and the other structures [pending rename] are for checkpointed state. Acked-by: Simon Guo Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/processor.h | 7 +- arch/powerpc/kernel/process.c | 83 +++-------- arch/powerpc/kernel/ptrace.c | 278 +++++++++-------------------------- arch/powerpc/kernel/signal_32.c | 50 +++---- arch/powerpc/kernel/signal_64.c | 54 +++---- arch/powerpc/kernel/tm.S | 94 ++++++------ arch/powerpc/kernel/traps.c | 12 +- 7 files changed, 197 insertions(+), 381 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 68e3bf57b027..feab2ce72940 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -267,16 +267,13 @@ struct thread_struct { unsigned long tm_dscr; /* - * Transactional FP and VSX 0-31 register set. - * NOTE: the sense of these is the opposite of the integer ckpt_regs! + * Checkpointed FP and VSX 0-31 register set. * * When a transaction is active/signalled/scheduled etc., *regs is the * most recent set of/speculated GPRs with ckpt_regs being the older * checkpointed regs to which we roll back if transaction aborts. * - * However, fpr[] is the checkpointed 'base state' of FP regs, and - * transact_fpr[] is the new set of transactional values. - * VRs work the same way. + * These are analogous to how ckpt_regs and pt_regs work */ struct thread_fp_state transact_fp; struct thread_vr_state transact_vr; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 45b6ea069f92..6e9a0543da12 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -815,26 +815,6 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a, static void tm_reclaim_thread(struct thread_struct *thr, struct thread_info *ti, uint8_t cause) { - unsigned long msr_diff = 0; - - /* - * If FP/VSX registers have been already saved to the - * thread_struct, move them to the transact_fp array. - * We clear the TIF_RESTORE_TM bit since after the reclaim - * the thread will no longer be transactional. - */ - if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) { - msr_diff = thr->ckpt_regs.msr & ~thr->regs->msr; - if (msr_diff & MSR_FP) - memcpy(&thr->transact_fp, &thr->fp_state, - sizeof(struct thread_fp_state)); - if (msr_diff & MSR_VEC) - memcpy(&thr->transact_vr, &thr->vr_state, - sizeof(struct thread_vr_state)); - clear_ti_thread_flag(ti, TIF_RESTORE_TM); - msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1; - } - /* * Use the current MSR TM suspended bit to track if we have * checkpointed state outstanding. @@ -853,15 +833,9 @@ static void tm_reclaim_thread(struct thread_struct *thr, if (!MSR_TM_SUSPENDED(mfmsr())) return; - tm_reclaim(thr, thr->regs->msr, cause); + giveup_all(container_of(thr, struct task_struct, thread)); - /* Having done the reclaim, we now have the checkpointed - * FP/VSX values in the registers. These might be valid - * even if we have previously called enable_kernel_fp() or - * flush_fp_to_thread(), so update thr->regs->msr to - * indicate their current validity. - */ - thr->regs->msr |= msr_diff; + tm_reclaim(thr, thr->ckpt_regs.msr, cause); } void tm_reclaim_current(uint8_t cause) @@ -890,14 +864,6 @@ static inline void tm_reclaim_task(struct task_struct *tsk) if (!MSR_TM_ACTIVE(thr->regs->msr)) goto out_and_saveregs; - /* Stash the original thread MSR, as giveup_fpu et al will - * modify it. We hold onto it to see whether the task used - * FP & vector regs. If the TIF_RESTORE_TM flag is set, - * ckpt_regs.msr is already set. - */ - if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM)) - thr->ckpt_regs.msr = thr->regs->msr; - TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " "ccr=%lx, msr=%lx, trap=%lx)\n", tsk->pid, thr->regs->nip, @@ -955,7 +921,7 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new) * If the task was using FP, we non-lazily reload both the original and * the speculative FP register states. This is because the kernel * doesn't see if/when a TM rollback occurs, so if we take an FP - * unavoidable later, we are unable to determine which set of FP regs + * unavailable later, we are unable to determine which set of FP regs * need to be restored. */ if (!new->thread.regs) @@ -971,35 +937,27 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new) "(new->msr 0x%lx, new->origmsr 0x%lx)\n", new->pid, new->thread.regs->msr, msr); - /* This loads the checkpointed FP/VEC state, if used */ tm_recheckpoint(&new->thread, msr); - /* This loads the speculative FP/VEC state, if used */ - if (msr & MSR_FP) { - do_load_up_transact_fpu(&new->thread); - new->thread.regs->msr |= - (MSR_FP | new->thread.fpexc_mode); - } -#ifdef CONFIG_ALTIVEC - if (msr & MSR_VEC) { - do_load_up_transact_altivec(&new->thread); - new->thread.regs->msr |= MSR_VEC; - } -#endif - /* We may as well turn on VSX too since all the state is restored now */ - if (msr & MSR_VSX) - new->thread.regs->msr |= MSR_VSX; + /* + * The checkpointed state has been restored but the live state has + * not, ensure all the math functionality is turned off to trigger + * restore_math() to reload. + */ + new->thread.regs->msr &= ~(MSR_FP | MSR_VEC | MSR_VSX); TM_DEBUG("*** tm_recheckpoint of pid %d complete " "(kernel msr 0x%lx)\n", new->pid, mfmsr()); } -static inline void __switch_to_tm(struct task_struct *prev) +static inline void __switch_to_tm(struct task_struct *prev, + struct task_struct *new) { if (cpu_has_feature(CPU_FTR_TM)) { tm_enable(); tm_reclaim_task(prev); + tm_recheckpoint_new_task(new); } } @@ -1021,6 +979,12 @@ void restore_tm_state(struct pt_regs *regs) { unsigned long msr_diff; + /* + * This is the only moment we should clear TIF_RESTORE_TM as + * it is here that ckpt_regs.msr and pt_regs.msr become the same + * again, anything else could lead to an incorrect ckpt_msr being + * saved and therefore incorrect signal contexts. + */ clear_thread_flag(TIF_RESTORE_TM); if (!MSR_TM_ACTIVE(regs->msr)) return; @@ -1042,7 +1006,7 @@ void restore_tm_state(struct pt_regs *regs) #else #define tm_recheckpoint_new_task(new) -#define __switch_to_tm(prev) +#define __switch_to_tm(prev, new) #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ static inline void save_sprs(struct thread_struct *t) @@ -1183,11 +1147,11 @@ struct task_struct *__switch_to(struct task_struct *prev, */ save_sprs(&prev->thread); - __switch_to_tm(prev); - /* Save FPU, Altivec, VSX and SPE state */ giveup_all(prev); + __switch_to_tm(prev, new); + /* * We can't take a PMU exception inside _switch() since there is a * window where the kernel stack SLB and the kernel stack are out @@ -1195,8 +1159,6 @@ struct task_struct *__switch_to(struct task_struct *prev, */ hard_irq_disable(); - tm_recheckpoint_new_task(new); - /* * Call restore_sprs() before calling _switch(). If we move it after * _switch() then we miss out on calling it for new tasks. The reason @@ -1432,8 +1394,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) * tm_recheckpoint_new_task() (on the same task) to restore the * checkpointed state back and the TM mode. */ - __switch_to_tm(src); - tm_recheckpoint_new_task(src); + __switch_to_tm(src, src); *dst = *src; diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index a17c6723e454..7ae744fe8cb1 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -403,13 +403,9 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, } /* - * When the transaction is active, 'transact_fp' holds the current running - * value of all FPR registers and 'fp_state' holds the last checkpointed - * value of all FPR registers for the current transaction. When transaction - * is not active 'fp_state' holds the current running state of all the FPR - * registers. So this function which returns the current running values of - * all the FPR registers, needs to know whether any transaction is active - * or not. + * Regardless of transactions, 'fp_state' holds the current running + * value of all FPR registers and 'transact_fp' holds the last checkpointed + * value of all FPR registers for the current transaction. * * Userspace interface buffer layout: * @@ -417,13 +413,6 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, * u64 fpr[32]; * u64 fpscr; * }; - * - * There are two config options CONFIG_VSX and CONFIG_PPC_TRANSACTIONAL_MEM - * which determines the final code in this function. All the combinations of - * these two config options are possible except the one below as transactional - * memory config pulls in CONFIG_VSX automatically. - * - * !defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM) */ static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, @@ -432,50 +421,29 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, #ifdef CONFIG_VSX u64 buf[33]; int i; -#endif - flush_fp_to_thread(target); -#if defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM) - /* copy to local buffer then write that out */ - if (MSR_TM_ACTIVE(target->thread.regs->msr)) { - flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); - for (i = 0; i < 32 ; i++) - buf[i] = target->thread.TS_TRANS_FPR(i); - buf[32] = target->thread.transact_fp.fpscr; - } else { - for (i = 0; i < 32 ; i++) - buf[i] = target->thread.TS_FPR(i); - buf[32] = target->thread.fp_state.fpscr; - } - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); -#endif + flush_fp_to_thread(target); -#if defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM) /* copy to local buffer then write that out */ for (i = 0; i < 32 ; i++) buf[i] = target->thread.TS_FPR(i); buf[32] = target->thread.fp_state.fpscr; return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); -#endif - -#if !defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM) +#else BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) != offsetof(struct thread_fp_state, fpr[32])); + flush_fp_to_thread(target); + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.fp_state, 0, -1); #endif } /* - * When the transaction is active, 'transact_fp' holds the current running - * value of all FPR registers and 'fp_state' holds the last checkpointed - * value of all FPR registers for the current transaction. When transaction - * is not active 'fp_state' holds the current running state of all the FPR - * registers. So this function which setss the current running values of - * all the FPR registers, needs to know whether any transaction is active - * or not. + * Regardless of transactions, 'fp_state' holds the current running + * value of all FPR registers and 'transact_fp' holds the last checkpointed + * value of all FPR registers for the current transaction. * * Userspace interface buffer layout: * @@ -484,12 +452,6 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, * u64 fpscr; * }; * - * There are two config options CONFIG_VSX and CONFIG_PPC_TRANSACTIONAL_MEM - * which determines the final code in this function. All the combinations of - * these two config options are possible except the one below as transactional - * memory config pulls in CONFIG_VSX automatically. - * - * !defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM) */ static int fpr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, @@ -498,44 +460,24 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, #ifdef CONFIG_VSX u64 buf[33]; int i; -#endif + flush_fp_to_thread(target); -#if defined(CONFIG_VSX) && defined(CONFIG_PPC_TRANSACTIONAL_MEM) /* copy to local buffer then write that out */ i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1); if (i) return i; - if (MSR_TM_ACTIVE(target->thread.regs->msr)) { - flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); - for (i = 0; i < 32 ; i++) - target->thread.TS_TRANS_FPR(i) = buf[i]; - target->thread.transact_fp.fpscr = buf[32]; - } else { - for (i = 0; i < 32 ; i++) - target->thread.TS_FPR(i) = buf[i]; - target->thread.fp_state.fpscr = buf[32]; - } - return 0; -#endif - -#if defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM) - /* copy to local buffer then write that out */ - i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1); - if (i) - return i; for (i = 0; i < 32 ; i++) target->thread.TS_FPR(i) = buf[i]; target->thread.fp_state.fpscr = buf[32]; return 0; -#endif - -#if !defined(CONFIG_VSX) && !defined(CONFIG_PPC_TRANSACTIONAL_MEM) +#else BUILD_BUG_ON(offsetof(struct thread_fp_state, fpscr) != offsetof(struct thread_fp_state, fpr[32])); + flush_fp_to_thread(target); + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.fp_state, 0, -1); #endif @@ -563,13 +505,10 @@ static int vr_active(struct task_struct *target, } /* - * When the transaction is active, 'transact_vr' holds the current running - * value of all the VMX registers and 'vr_state' holds the last checkpointed - * value of all the VMX registers for the current transaction to fall back - * on in case it aborts. When transaction is not active 'vr_state' holds - * the current running state of all the VMX registers. So this function which - * gets the current running values of all the VMX registers, needs to know - * whether any transaction is active or not. + * Regardless of transactions, 'vr_state' holds the current running + * value of all the VMX registers and 'transact_vr' holds the last + * checkpointed value of all the VMX registers for the current + * transaction to fall back on in case it aborts. * * Userspace interface buffer layout: * @@ -583,7 +522,6 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { - struct thread_vr_state *addr; int ret; flush_altivec_to_thread(target); @@ -591,19 +529,8 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset, BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) != offsetof(struct thread_vr_state, vr[32])); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(target->thread.regs->msr)) { - flush_fp_to_thread(target); - flush_tmregs_to_thread(target); - addr = &target->thread.transact_vr; - } else { - addr = &target->thread.vr_state; - } -#else - addr = &target->thread.vr_state; -#endif ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - addr, 0, + &target->thread.vr_state, 0, 33 * sizeof(vector128)); if (!ret) { /* @@ -615,14 +542,7 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset, } vrsave; memset(&vrsave, 0, sizeof(vrsave)); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(target->thread.regs->msr)) - vrsave.word = target->thread.transact_vrsave; - else - vrsave.word = target->thread.vrsave; -#else vrsave.word = target->thread.vrsave; -#endif ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, 33 * sizeof(vector128), -1); @@ -632,13 +552,10 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset, } /* - * When the transaction is active, 'transact_vr' holds the current running - * value of all the VMX registers and 'vr_state' holds the last checkpointed - * value of all the VMX registers for the current transaction to fall back - * on in case it aborts. When transaction is not active 'vr_state' holds - * the current running state of all the VMX registers. So this function which - * sets the current running values of all the VMX registers, needs to know - * whether any transaction is active or not. + * Regardless of transactions, 'vr_state' holds the current running + * value of all the VMX registers and 'transact_vr' holds the last + * checkpointed value of all the VMX registers for the current + * transaction to fall back on in case it aborts. * * Userspace interface buffer layout: * @@ -652,7 +569,6 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - struct thread_vr_state *addr; int ret; flush_altivec_to_thread(target); @@ -660,19 +576,8 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset, BUILD_BUG_ON(offsetof(struct thread_vr_state, vscr) != offsetof(struct thread_vr_state, vr[32])); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(target->thread.regs->msr)) { - flush_fp_to_thread(target); - flush_tmregs_to_thread(target); - addr = &target->thread.transact_vr; - } else { - addr = &target->thread.vr_state; - } -#else - addr = &target->thread.vr_state; -#endif ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - addr, 0, + &target->thread.vr_state, 0, 33 * sizeof(vector128)); if (!ret && count > 0) { /* @@ -684,27 +589,12 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset, } vrsave; memset(&vrsave, 0, sizeof(vrsave)); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(target->thread.regs->msr)) - vrsave.word = target->thread.transact_vrsave; - else - vrsave.word = target->thread.vrsave; -#else vrsave.word = target->thread.vrsave; -#endif + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave, 33 * sizeof(vector128), -1); - if (!ret) { - -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(target->thread.regs->msr)) - target->thread.transact_vrsave = vrsave.word; - else - target->thread.vrsave = vrsave.word; -#else + if (!ret) target->thread.vrsave = vrsave.word; -#endif - } } return ret; @@ -726,13 +616,10 @@ static int vsr_active(struct task_struct *target, } /* - * When the transaction is active, 'transact_fp' holds the current running - * value of all FPR registers and 'fp_state' holds the last checkpointed - * value of all FPR registers for the current transaction. When transaction - * is not active 'fp_state' holds the current running state of all the FPR - * registers. So this function which returns the current running values of - * all the FPR registers, needs to know whether any transaction is active - * or not. + * Regardless of transactions, 'fp_state' holds the current running + * value of all FPR registers and 'transact_fp' holds the last + * checkpointed value of all FPR registers for the current + * transaction. * * Userspace interface buffer layout: * @@ -747,27 +634,14 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset, u64 buf[32]; int ret, i; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); -#endif flush_vsx_to_thread(target); -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(target->thread.regs->msr)) { - for (i = 0; i < 32 ; i++) - buf[i] = target->thread. - transact_fp.fpr[i][TS_VSRLOWOFFSET]; - } else { - for (i = 0; i < 32 ; i++) - buf[i] = target->thread. - fp_state.fpr[i][TS_VSRLOWOFFSET]; - } -#else for (i = 0; i < 32 ; i++) buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; -#endif + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); @@ -775,12 +649,10 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset, } /* - * When the transaction is active, 'transact_fp' holds the current running - * value of all FPR registers and 'fp_state' holds the last checkpointed - * value of all FPR registers for the current transaction. When transaction - * is not active 'fp_state' holds the current running state of all the FPR - * registers. So this function which sets the current running values of all - * the FPR registers, needs to know whether any transaction is active or not. + * Regardless of transactions, 'fp_state' holds the current running + * value of all FPR registers and 'transact_fp' holds the last + * checkpointed value of all FPR registers for the current + * transaction. * * Userspace interface buffer layout: * @@ -795,31 +667,16 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset, u64 buf[32]; int ret,i; -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); -#endif flush_vsx_to_thread(target); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); - -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (MSR_TM_ACTIVE(target->thread.regs->msr)) { - for (i = 0; i < 32 ; i++) - target->thread.transact_fp. - fpr[i][TS_VSRLOWOFFSET] = buf[i]; - } else { + if (!ret) for (i = 0; i < 32 ; i++) - target->thread.fp_state. - fpr[i][TS_VSRLOWOFFSET] = buf[i]; - } -#else - for (i = 0; i < 32 ; i++) - target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; -#endif - + target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; return ret; } @@ -945,9 +802,9 @@ static int tm_cgpr_get(struct task_struct *target, if (!MSR_TM_ACTIVE(target->thread.regs->msr)) return -ENODATA; + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &target->thread.ckpt_regs, @@ -1010,9 +867,9 @@ static int tm_cgpr_set(struct task_struct *target, if (!MSR_TM_ACTIVE(target->thread.regs->msr)) return -ENODATA; + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &target->thread.ckpt_regs, @@ -1088,7 +945,7 @@ static int tm_cfpr_active(struct task_struct *target, * * This function gets in transaction checkpointed FPR registers. * - * When the transaction is active 'fp_state' holds the checkpointed + * When the transaction is active 'transact_fp' holds the checkpointed * values for the current transaction to fall back on if it aborts * in between. This function gets those checkpointed FPR registers. * The userspace interface buffer layout is as follows. @@ -1112,14 +969,14 @@ static int tm_cfpr_get(struct task_struct *target, if (!MSR_TM_ACTIVE(target->thread.regs->msr)) return -ENODATA; + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); /* copy to local buffer then write that out */ for (i = 0; i < 32 ; i++) - buf[i] = target->thread.TS_FPR(i); - buf[32] = target->thread.fp_state.fpscr; + buf[i] = target->thread.TS_TRANS_FPR(i); + buf[32] = target->thread.transact_fp.fpscr; return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); } @@ -1134,7 +991,7 @@ static int tm_cfpr_get(struct task_struct *target, * * This function sets in transaction checkpointed FPR registers. * - * When the transaction is active 'fp_state' holds the checkpointed + * When the transaction is active 'transact_fp' holds the checkpointed * FPR register values for the current transaction to fall back on * if it aborts in between. This function sets these checkpointed * FPR registers. The userspace interface buffer layout is as follows. @@ -1158,17 +1015,17 @@ static int tm_cfpr_set(struct task_struct *target, if (!MSR_TM_ACTIVE(target->thread.regs->msr)) return -ENODATA; + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); /* copy to local buffer then write that out */ i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1); if (i) return i; for (i = 0; i < 32 ; i++) - target->thread.TS_FPR(i) = buf[i]; - target->thread.fp_state.fpscr = buf[32]; + target->thread.TS_TRANS_FPR(i) = buf[i]; + target->thread.transact_fp.fpscr = buf[32]; return 0; } @@ -1203,7 +1060,7 @@ static int tm_cvmx_active(struct task_struct *target, * * This function gets in transaction checkpointed VMX registers. * - * When the transaction is active 'vr_state' and 'vr_save' hold + * When the transaction is active 'transact_vr' and 'transact_vrsave' hold * the checkpointed values for the current transaction to fall * back on if it aborts in between. The userspace interface buffer * layout is as follows. @@ -1230,12 +1087,12 @@ static int tm_cvmx_get(struct task_struct *target, return -ENODATA; /* Flush the state */ + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.vr_state, 0, + &target->thread.transact_vr, 0, 33 * sizeof(vector128)); if (!ret) { /* @@ -1246,7 +1103,7 @@ static int tm_cvmx_get(struct task_struct *target, u32 word; } vrsave; memset(&vrsave, 0, sizeof(vrsave)); - vrsave.word = target->thread.vrsave; + vrsave.word = target->thread.transact_vrsave; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, 33 * sizeof(vector128), -1); } @@ -1265,7 +1122,7 @@ static int tm_cvmx_get(struct task_struct *target, * * This function sets in transaction checkpointed VMX registers. * - * When the transaction is active 'vr_state' and 'vr_save' hold + * When the transaction is active 'transact_vr' and 'transact_vrsave' hold * the checkpointed values for the current transaction to fall * back on if it aborts in between. The userspace interface buffer * layout is as follows. @@ -1291,12 +1148,12 @@ static int tm_cvmx_set(struct task_struct *target, if (!MSR_TM_ACTIVE(target->thread.regs->msr)) return -ENODATA; + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.vr_state, 0, + &target->thread.transact_vr, 0, 33 * sizeof(vector128)); if (!ret && count > 0) { /* @@ -1307,11 +1164,11 @@ static int tm_cvmx_set(struct task_struct *target, u32 word; } vrsave; memset(&vrsave, 0, sizeof(vrsave)); - vrsave.word = target->thread.vrsave; + vrsave.word = target->thread.transact_vrsave; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave, 33 * sizeof(vector128), -1); if (!ret) - target->thread.vrsave = vrsave.word; + target->thread.transact_vrsave = vrsave.word; } return ret; @@ -1349,7 +1206,7 @@ static int tm_cvsx_active(struct task_struct *target, * * This function gets in transaction checkpointed VSX registers. * - * When the transaction is active 'fp_state' holds the checkpointed + * When the transaction is active 'transact_fp' holds the checkpointed * values for the current transaction to fall back on if it aborts * in between. This function gets those checkpointed VSX registers. * The userspace interface buffer layout is as follows. @@ -1373,13 +1230,13 @@ static int tm_cvsx_get(struct task_struct *target, return -ENODATA; /* Flush the state */ + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); flush_vsx_to_thread(target); for (i = 0; i < 32 ; i++) - buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET]; + buf[i] = target->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET]; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); @@ -1397,7 +1254,7 @@ static int tm_cvsx_get(struct task_struct *target, * * This function sets in transaction checkpointed VSX registers. * - * When the transaction is active 'fp_state' holds the checkpointed + * When the transaction is active 'transact_fp' holds the checkpointed * VSX register values for the current transaction to fall back on * if it aborts in between. This function sets these checkpointed * FPR registers. The userspace interface buffer layout is as follows. @@ -1421,15 +1278,16 @@ static int tm_cvsx_set(struct task_struct *target, return -ENODATA; /* Flush the state */ + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); flush_vsx_to_thread(target); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); - for (i = 0; i < 32 ; i++) - target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; + if (!ret) + for (i = 0; i < 32 ; i++) + target->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = buf[i]; return ret; } @@ -1485,9 +1343,9 @@ static int tm_spr_get(struct task_struct *target, return -ENODEV; /* Flush the states */ + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); /* TFHAR register */ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, @@ -1541,9 +1399,9 @@ static int tm_spr_set(struct task_struct *target, return -ENODEV; /* Flush the states */ + flush_tmregs_to_thread(target); flush_fp_to_thread(target); flush_altivec_to_thread(target); - flush_tmregs_to_thread(target); /* TFHAR register */ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 9637f8eb5204..3b9356bb4457 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -526,9 +526,6 @@ static int save_tm_user_regs(struct pt_regs *regs, */ regs->msr &= ~MSR_TS_MASK; - /* Make sure floating point registers are stored in regs */ - flush_fp_to_thread(current); - /* Save both sets of general registers */ if (save_general_regs(¤t->thread.ckpt_regs, frame) || save_general_regs(regs, tm_frame)) @@ -546,18 +543,17 @@ static int save_tm_user_regs(struct pt_regs *regs, #ifdef CONFIG_ALTIVEC /* save altivec registers */ if (current->thread.used_vr) { - flush_altivec_to_thread(current); - if (__copy_to_user(&frame->mc_vregs, ¤t->thread.vr_state, + if (__copy_to_user(&frame->mc_vregs, ¤t->thread.transact_vr, ELF_NVRREG * sizeof(vector128))) return 1; if (msr & MSR_VEC) { if (__copy_to_user(&tm_frame->mc_vregs, - ¤t->thread.transact_vr, + ¤t->thread.vr_state, ELF_NVRREG * sizeof(vector128))) return 1; } else { if (__copy_to_user(&tm_frame->mc_vregs, - ¤t->thread.vr_state, + ¤t->thread.transact_vr, ELF_NVRREG * sizeof(vector128))) return 1; } @@ -574,28 +570,28 @@ static int save_tm_user_regs(struct pt_regs *regs, * most significant bits of that same vector. --BenH */ if (cpu_has_feature(CPU_FTR_ALTIVEC)) - current->thread.vrsave = mfspr(SPRN_VRSAVE); - if (__put_user(current->thread.vrsave, + current->thread.transact_vrsave = mfspr(SPRN_VRSAVE); + if (__put_user(current->thread.transact_vrsave, (u32 __user *)&frame->mc_vregs[32])) return 1; if (msr & MSR_VEC) { - if (__put_user(current->thread.transact_vrsave, + if (__put_user(current->thread.vrsave, (u32 __user *)&tm_frame->mc_vregs[32])) return 1; } else { - if (__put_user(current->thread.vrsave, + if (__put_user(current->thread.transact_vrsave, (u32 __user *)&tm_frame->mc_vregs[32])) return 1; } #endif /* CONFIG_ALTIVEC */ - if (copy_fpr_to_user(&frame->mc_fregs, current)) + if (copy_transact_fpr_to_user(&frame->mc_fregs, current)) return 1; if (msr & MSR_FP) { - if (copy_transact_fpr_to_user(&tm_frame->mc_fregs, current)) + if (copy_fpr_to_user(&tm_frame->mc_fregs, current)) return 1; } else { - if (copy_fpr_to_user(&tm_frame->mc_fregs, current)) + if (copy_transact_fpr_to_user(&tm_frame->mc_fregs, current)) return 1; } @@ -607,15 +603,14 @@ static int save_tm_user_regs(struct pt_regs *regs, * contains valid data */ if (current->thread.used_vsr) { - flush_vsx_to_thread(current); - if (copy_vsx_to_user(&frame->mc_vsregs, current)) + if (copy_transact_vsx_to_user(&frame->mc_vsregs, current)) return 1; if (msr & MSR_VSX) { - if (copy_transact_vsx_to_user(&tm_frame->mc_vsregs, + if (copy_vsx_to_user(&tm_frame->mc_vsregs, current)) return 1; } else { - if (copy_vsx_to_user(&tm_frame->mc_vsregs, current)) + if (copy_transact_vsx_to_user(&tm_frame->mc_vsregs, current)) return 1; } @@ -797,9 +792,9 @@ static long restore_tm_user_regs(struct pt_regs *regs, regs->msr &= ~MSR_VEC; if (msr & MSR_VEC) { /* restore altivec registers from the stack */ - if (__copy_from_user(¤t->thread.vr_state, &sr->mc_vregs, + if (__copy_from_user(¤t->thread.transact_vr, &sr->mc_vregs, sizeof(sr->mc_vregs)) || - __copy_from_user(¤t->thread.transact_vr, + __copy_from_user(¤t->thread.vr_state, &tm_sr->mc_vregs, sizeof(sr->mc_vregs))) return 1; @@ -812,13 +807,13 @@ static long restore_tm_user_regs(struct pt_regs *regs, } /* Always get VRSAVE back */ - if (__get_user(current->thread.vrsave, + if (__get_user(current->thread.transact_vrsave, (u32 __user *)&sr->mc_vregs[32]) || - __get_user(current->thread.transact_vrsave, + __get_user(current->thread.vrsave, (u32 __user *)&tm_sr->mc_vregs[32])) return 1; if (cpu_has_feature(CPU_FTR_ALTIVEC)) - mtspr(SPRN_VRSAVE, current->thread.vrsave); + mtspr(SPRN_VRSAVE, current->thread.transact_vrsave); #endif /* CONFIG_ALTIVEC */ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); @@ -834,8 +829,8 @@ static long restore_tm_user_regs(struct pt_regs *regs, * Restore altivec registers from the stack to a local * buffer, then write this out to the thread_struct */ - if (copy_vsx_from_user(current, &sr->mc_vsregs) || - copy_transact_vsx_from_user(current, &tm_sr->mc_vsregs)) + if (copy_vsx_from_user(current, &tm_sr->mc_vsregs) || + copy_transact_vsx_from_user(current, &sr->mc_vsregs)) return 1; current->thread.used_vsr = true; } else if (current->thread.used_vsr) @@ -884,13 +879,14 @@ static long restore_tm_user_regs(struct pt_regs *regs, tm_recheckpoint(¤t->thread, msr); /* This loads the speculative FP/VEC state, if used */ + msr_check_and_set(msr & (MSR_FP | MSR_VEC)); if (msr & MSR_FP) { - do_load_up_transact_fpu(¤t->thread); + load_fp_state(¤t->thread.fp_state); regs->msr |= (MSR_FP | current->thread.fpexc_mode); } #ifdef CONFIG_ALTIVEC if (msr & MSR_VEC) { - do_load_up_transact_altivec(¤t->thread); + load_vr_state(¤t->thread.vr_state); regs->msr |= MSR_VEC; } #endif diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index befa10af0c17..af58af520472 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -221,28 +221,25 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, */ regs->msr &= ~MSR_TS_MASK; - flush_fp_to_thread(tsk); - #ifdef CONFIG_ALTIVEC err |= __put_user(v_regs, &sc->v_regs); err |= __put_user(tm_v_regs, &tm_sc->v_regs); /* save altivec registers */ if (tsk->thread.used_vr) { - flush_altivec_to_thread(tsk); /* Copy 33 vec registers (vr0..31 and vscr) to the stack */ - err |= __copy_to_user(v_regs, &tsk->thread.vr_state, + err |= __copy_to_user(v_regs, &tsk->thread.transact_vr, 33 * sizeof(vector128)); /* If VEC was enabled there are transactional VRs valid too, * else they're a copy of the checkpointed VRs. */ if (msr & MSR_VEC) err |= __copy_to_user(tm_v_regs, - &tsk->thread.transact_vr, + &tsk->thread.vr_state, 33 * sizeof(vector128)); else err |= __copy_to_user(tm_v_regs, - &tsk->thread.vr_state, + &tsk->thread.transact_vr, 33 * sizeof(vector128)); /* set MSR_VEC in the MSR value in the frame to indicate @@ -254,13 +251,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, * use altivec. */ if (cpu_has_feature(CPU_FTR_ALTIVEC)) - tsk->thread.vrsave = mfspr(SPRN_VRSAVE); - err |= __put_user(tsk->thread.vrsave, (u32 __user *)&v_regs[33]); + tsk->thread.transact_vrsave = mfspr(SPRN_VRSAVE); + err |= __put_user(tsk->thread.transact_vrsave, (u32 __user *)&v_regs[33]); if (msr & MSR_VEC) - err |= __put_user(tsk->thread.transact_vrsave, + err |= __put_user(tsk->thread.vrsave, (u32 __user *)&tm_v_regs[33]); else - err |= __put_user(tsk->thread.vrsave, + err |= __put_user(tsk->thread.transact_vrsave, (u32 __user *)&tm_v_regs[33]); #else /* CONFIG_ALTIVEC */ @@ -269,11 +266,11 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, #endif /* CONFIG_ALTIVEC */ /* copy fpr regs and fpscr */ - err |= copy_fpr_to_user(&sc->fp_regs, tsk); + err |= copy_transact_fpr_to_user(&sc->fp_regs, tsk); if (msr & MSR_FP) - err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, tsk); - else err |= copy_fpr_to_user(&tm_sc->fp_regs, tsk); + else + err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, tsk); #ifdef CONFIG_VSX /* @@ -282,16 +279,15 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, * VMX data. */ if (tsk->thread.used_vsr) { - flush_vsx_to_thread(tsk); v_regs += ELF_NVRREG; tm_v_regs += ELF_NVRREG; - err |= copy_vsx_to_user(v_regs, tsk); + err |= copy_transact_vsx_to_user(v_regs, tsk); if (msr & MSR_VSX) - err |= copy_transact_vsx_to_user(tm_v_regs, tsk); - else err |= copy_vsx_to_user(tm_v_regs, tsk); + else + err |= copy_transact_vsx_to_user(tm_v_regs, tsk); /* set MSR_VSX in the MSR value in the frame to * indicate that sc->vs_reg) contains valid data. @@ -501,9 +497,9 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, return -EFAULT; /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ if (v_regs != NULL && tm_v_regs != NULL && (msr & MSR_VEC) != 0) { - err |= __copy_from_user(&tsk->thread.vr_state, v_regs, + err |= __copy_from_user(&tsk->thread.transact_vr, v_regs, 33 * sizeof(vector128)); - err |= __copy_from_user(&tsk->thread.transact_vr, tm_v_regs, + err |= __copy_from_user(&tsk->thread.vr_state, tm_v_regs, 33 * sizeof(vector128)); current->thread.used_vr = true; } @@ -513,9 +509,9 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, } /* Always get VRSAVE back */ if (v_regs != NULL && tm_v_regs != NULL) { - err |= __get_user(tsk->thread.vrsave, - (u32 __user *)&v_regs[33]); err |= __get_user(tsk->thread.transact_vrsave, + (u32 __user *)&v_regs[33]); + err |= __get_user(tsk->thread.vrsave, (u32 __user *)&tm_v_regs[33]); } else { @@ -526,8 +522,8 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, mtspr(SPRN_VRSAVE, tsk->thread.vrsave); #endif /* CONFIG_ALTIVEC */ /* restore floating point */ - err |= copy_fpr_from_user(tsk, &sc->fp_regs); - err |= copy_transact_fpr_from_user(tsk, &tm_sc->fp_regs); + err |= copy_fpr_from_user(tsk, &tm_sc->fp_regs); + err |= copy_transact_fpr_from_user(tsk, &sc->fp_regs); #ifdef CONFIG_VSX /* * Get additional VSX data. Update v_regs to point after the @@ -537,8 +533,8 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, if (v_regs && ((msr & MSR_VSX) != 0)) { v_regs += ELF_NVRREG; tm_v_regs += ELF_NVRREG; - err |= copy_vsx_from_user(tsk, v_regs); - err |= copy_transact_vsx_from_user(tsk, tm_v_regs); + err |= copy_vsx_from_user(tsk, tm_v_regs); + err |= copy_transact_vsx_from_user(tsk, v_regs); tsk->thread.used_vsr = true; } else { for (i = 0; i < 32 ; i++) { @@ -553,17 +549,15 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, /* This loads the checkpointed FP/VEC state, if used */ tm_recheckpoint(&tsk->thread, msr); - /* This loads the speculative FP/VEC state, if used */ + msr_check_and_set(msr & (MSR_FP | MSR_VEC)); if (msr & MSR_FP) { - do_load_up_transact_fpu(&tsk->thread); + load_fp_state(&tsk->thread.fp_state); regs->msr |= (MSR_FP | tsk->thread.fpexc_mode); } -#ifdef CONFIG_ALTIVEC if (msr & MSR_VEC) { - do_load_up_transact_altivec(&tsk->thread); + load_vr_state(&tsk->thread.vr_state); regs->msr |= MSR_VEC; } -#endif return err; } diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S index 298afcf3bf2a..7b7088d8d130 100644 --- a/arch/powerpc/kernel/tm.S +++ b/arch/powerpc/kernel/tm.S @@ -108,6 +108,7 @@ _GLOBAL(tm_reclaim) /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. */ std r3, STK_PARAM(R3)(r1) + std r4, STK_PARAM(R4)(r1) SAVE_NVGPRS(r1) /* We need to setup MSR for VSX register save instructions. */ @@ -126,43 +127,6 @@ _GLOBAL(tm_reclaim) mtmsrd r15 std r14, TM_FRAME_L0(r1) - /* Stash the stack pointer away for use after reclaim */ - std r1, PACAR1(r13) - - /* ******************** FPR/VR/VSRs ************ - * Before reclaiming, capture the current/transactional FPR/VR - * versions /if used/. - * - * (If VSX used, FP and VMX are implied. Or, we don't need to look - * at MSR.VSX as copying FP regs if .FP, vector regs if .VMX covers it.) - * - * We're passed the thread's MSR as parameter 2. - * - * We enabled VEC/FP/VSX in the msr above, so we can execute these - * instructions! - */ - andis. r0, r4, MSR_VEC@h - beq dont_backup_vec - - addi r7, r3, THREAD_TRANSACT_VRSTATE - SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 transact vr state */ - mfvscr v0 - li r6, VRSTATE_VSCR - stvx v0, r7, r6 -dont_backup_vec: - mfspr r0, SPRN_VRSAVE - std r0, THREAD_TRANSACT_VRSAVE(r3) - - andi. r0, r4, MSR_FP - beq dont_backup_fp - - addi r7, r3, THREAD_TRANSACT_FPSTATE - SAVE_32FPRS_VSRS(0, R6, R7) /* r6 scratch, r7 transact fp state */ - - mffs fr0 - stfd fr0,FPSTATE_FPSCR(r7) - -dont_backup_fp: /* Do sanity check on MSR to make sure we are suspended */ li r7, (MSR_TS_S)@higher srdi r6, r14, 32 @@ -170,6 +134,9 @@ dont_backup_fp: 1: tdeqi r6, 0 EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0 + /* Stash the stack pointer away for use after reclaim */ + std r1, PACAR1(r13) + /* Clear MSR RI since we are about to change r1, EE is already off. */ li r4, 0 mtmsrd r4, 1 @@ -273,6 +240,43 @@ dont_backup_fp: * MSR. */ + + /* ******************** FPR/VR/VSRs ************ + * After reclaiming, capture the checkpointed FPRs/VRs /if used/. + * + * (If VSX used, FP and VMX are implied. Or, we don't need to look + * at MSR.VSX as copying FP regs if .FP, vector regs if .VMX covers it.) + * + * We're passed the thread's MSR as the second parameter + * + * We enabled VEC/FP/VSX in the msr above, so we can execute these + * instructions! + */ + ld r4, STK_PARAM(R4)(r1) /* Second parameter, MSR * */ + mr r3, r12 + andis. r0, r4, MSR_VEC@h + beq dont_backup_vec + + addi r7, r3, THREAD_TRANSACT_VRSTATE + SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 transact vr state */ + mfvscr v0 + li r6, VRSTATE_VSCR + stvx v0, r7, r6 +dont_backup_vec: + mfspr r0, SPRN_VRSAVE + std r0, THREAD_TRANSACT_VRSAVE(r3) + + andi. r0, r4, MSR_FP + beq dont_backup_fp + + addi r7, r3, THREAD_TRANSACT_FPSTATE + SAVE_32FPRS_VSRS(0, R6, R7) /* r6 scratch, r7 transact fp state */ + + mffs fr0 + stfd fr0,FPSTATE_FPSCR(r7) + +dont_backup_fp: + /* TM regs, incl TEXASR -- these live in thread_struct. Note they've * been updated by the treclaim, to explain to userland the failure * cause (aborted). @@ -288,6 +292,7 @@ dont_backup_fp: /* Restore original MSR/IRQ state & clear TM mode */ ld r14, TM_FRAME_L0(r1) /* Orig MSR */ + li r15, 0 rldimi r14, r15, MSR_TS_LG, (63-MSR_TS_LG)-1 mtmsrd r14 @@ -356,28 +361,29 @@ _GLOBAL(__tm_recheckpoint) mtmsr r5 #ifdef CONFIG_ALTIVEC - /* FP and VEC registers: These are recheckpointed from thread.fpr[] - * and thread.vr[] respectively. The thread.transact_fpr[] version - * is more modern, and will be loaded subsequently by any FPUnavailable - * trap. + /* + * FP and VEC registers: These are recheckpointed from + * thread.ckfp_state and thread.ckvr_state respectively. The + * thread.fp_state[] version holds the 'live' (transactional) + * and will be loaded subsequently by any FPUnavailable trap. */ andis. r0, r4, MSR_VEC@h beq dont_restore_vec - addi r8, r3, THREAD_VRSTATE + addi r8, r3, THREAD_TRANSACT_VRSTATE li r5, VRSTATE_VSCR lvx v0, r8, r5 mtvscr v0 REST_32VRS(0, r5, r8) /* r5 scratch, r8 ptr */ dont_restore_vec: - ld r5, THREAD_VRSAVE(r3) + ld r5, THREAD_TRANSACT_VRSAVE(r3) mtspr SPRN_VRSAVE, r5 #endif andi. r0, r4, MSR_FP beq dont_restore_fp - addi r8, r3, THREAD_FPSTATE + addi r8, r3, THREAD_TRANSACT_FPSTATE lfd fr0, FPSTATE_FPSCR(r8) MTFSF_L(fr0) REST_32FPRS_VSRS(0, R4, R8) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6b108ed29c20..487e1b442473 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1522,7 +1522,8 @@ void fp_unavailable_tm(struct pt_regs *regs) /* If VMX is in use, get the transactional values back */ if (regs->msr & MSR_VEC) { - do_load_up_transact_altivec(¤t->thread); + msr_check_and_set(MSR_VEC); + load_vr_state(¤t->thread.vr_state); /* At this point all the VSX state is loaded, so enable it */ regs->msr |= MSR_VSX; } @@ -1543,7 +1544,8 @@ void altivec_unavailable_tm(struct pt_regs *regs) current->thread.used_vr = 1; if (regs->msr & MSR_FP) { - do_load_up_transact_fpu(¤t->thread); + msr_check_and_set(MSR_FP); + load_fp_state(¤t->thread.fp_state); regs->msr |= MSR_VSX; } } @@ -1582,10 +1584,12 @@ void vsx_unavailable_tm(struct pt_regs *regs) */ tm_recheckpoint(¤t->thread, regs->msr & ~orig_msr); + msr_check_and_set(orig_msr & (MSR_FP | MSR_VEC)); + if (orig_msr & MSR_FP) - do_load_up_transact_fpu(¤t->thread); + load_fp_state(¤t->thread.fp_state); if (orig_msr & MSR_VEC) - do_load_up_transact_altivec(¤t->thread); + load_vr_state(¤t->thread.vr_state); } #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ -- cgit v1.2.3 From 000ec280e3dd5c77a5227db27bfda1511e26db9a Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:25 +1000 Subject: powerpc: tm: Rename transct_(*) to ck(\1)_state Make the structures being used for checkpointed state named consistently with the pt_regs/ckpt_regs. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/processor.h | 8 ++--- arch/powerpc/kernel/asm-offsets.c | 12 ++++---- arch/powerpc/kernel/fpu.S | 2 +- arch/powerpc/kernel/process.c | 4 +-- arch/powerpc/kernel/ptrace.c | 46 +++++++++++++-------------- arch/powerpc/kernel/signal.h | 8 ++--- arch/powerpc/kernel/signal_32.c | 60 ++++++++++++++++++------------------ arch/powerpc/kernel/signal_64.c | 32 +++++++++---------- arch/powerpc/kernel/tm.S | 12 ++++---- arch/powerpc/kernel/vector.S | 4 +-- 10 files changed, 94 insertions(+), 94 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index feab2ce72940..b3e0cfcc84f6 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -147,7 +147,7 @@ typedef struct { } mm_segment_t; #define TS_FPR(i) fp_state.fpr[i][TS_FPROFFSET] -#define TS_TRANS_FPR(i) transact_fp.fpr[i][TS_FPROFFSET] +#define TS_CKFPR(i) ckfp_state.fpr[i][TS_FPROFFSET] /* FP and VSX 0-31 register set */ struct thread_fp_state { @@ -275,9 +275,9 @@ struct thread_struct { * * These are analogous to how ckpt_regs and pt_regs work */ - struct thread_fp_state transact_fp; - struct thread_vr_state transact_vr; - unsigned long transact_vrsave; + struct thread_fp_state ckfp_state; /* Checkpointed FP state */ + struct thread_vr_state ckvr_state; /* Checkpointed VR state */ + unsigned long ckvrsave; /* Checkpointed VRSAVE */ #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ #ifdef CONFIG_KVM_BOOK3S_32_HANDLER void* kvm_shadow_vcpu; /* KVM internal data */ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index b89d14c0352c..dd0fc339ba40 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -142,12 +142,12 @@ int main(void) DEFINE(THREAD_TM_PPR, offsetof(struct thread_struct, tm_ppr)); DEFINE(THREAD_TM_DSCR, offsetof(struct thread_struct, tm_dscr)); DEFINE(PT_CKPT_REGS, offsetof(struct thread_struct, ckpt_regs)); - DEFINE(THREAD_TRANSACT_VRSTATE, offsetof(struct thread_struct, - transact_vr)); - DEFINE(THREAD_TRANSACT_VRSAVE, offsetof(struct thread_struct, - transact_vrsave)); - DEFINE(THREAD_TRANSACT_FPSTATE, offsetof(struct thread_struct, - transact_fp)); + DEFINE(THREAD_CKVRSTATE, offsetof(struct thread_struct, + ckvr_state)); + DEFINE(THREAD_CKVRSAVE, offsetof(struct thread_struct, + ckvrsave)); + DEFINE(THREAD_CKFPSTATE, offsetof(struct thread_struct, + ckfp_state)); /* Local pt_regs on stack for Transactional Memory funcs. */ DEFINE(TM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 15da2b5df85e..181c18707f08 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -68,7 +68,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) SYNC MTMSRD(r5) - addi r7,r3,THREAD_TRANSACT_FPSTATE + addi r7,r3,THREAD_CKFPSTATE lfd fr0,FPSTATE_FPSCR(r7) MTFSF_L(fr0) REST_32FPVSRS(0, R4, R7) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 6e9a0543da12..e22033005d15 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -851,8 +851,8 @@ static inline void tm_reclaim_task(struct task_struct *tsk) * * In switching we need to maintain a 2nd register state as * oldtask->thread.ckpt_regs. We tm_reclaim(oldproc); this saves the - * checkpointed (tbegin) state in ckpt_regs and saves the transactional - * (current) FPRs into oldtask->thread.transact_fpr[]. + * checkpointed (tbegin) state in ckpt_regs, ckfp_state and + * ckvr_state * * We also context switch (save) TFHAR/TEXASR/TFIAR in here. */ diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7ae744fe8cb1..b1ec62f2cc31 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -404,7 +404,7 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, /* * Regardless of transactions, 'fp_state' holds the current running - * value of all FPR registers and 'transact_fp' holds the last checkpointed + * value of all FPR registers and 'ckfp_state' holds the last checkpointed * value of all FPR registers for the current transaction. * * Userspace interface buffer layout: @@ -442,7 +442,7 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, /* * Regardless of transactions, 'fp_state' holds the current running - * value of all FPR registers and 'transact_fp' holds the last checkpointed + * value of all FPR registers and 'ckfp_state' holds the last checkpointed * value of all FPR registers for the current transaction. * * Userspace interface buffer layout: @@ -506,7 +506,7 @@ static int vr_active(struct task_struct *target, /* * Regardless of transactions, 'vr_state' holds the current running - * value of all the VMX registers and 'transact_vr' holds the last + * value of all the VMX registers and 'ckvr_state' holds the last * checkpointed value of all the VMX registers for the current * transaction to fall back on in case it aborts. * @@ -553,7 +553,7 @@ static int vr_get(struct task_struct *target, const struct user_regset *regset, /* * Regardless of transactions, 'vr_state' holds the current running - * value of all the VMX registers and 'transact_vr' holds the last + * value of all the VMX registers and 'ckvr_state' holds the last * checkpointed value of all the VMX registers for the current * transaction to fall back on in case it aborts. * @@ -617,7 +617,7 @@ static int vsr_active(struct task_struct *target, /* * Regardless of transactions, 'fp_state' holds the current running - * value of all FPR registers and 'transact_fp' holds the last + * value of all FPR registers and 'ckfp_state' holds the last * checkpointed value of all FPR registers for the current * transaction. * @@ -650,7 +650,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset, /* * Regardless of transactions, 'fp_state' holds the current running - * value of all FPR registers and 'transact_fp' holds the last + * value of all FPR registers and 'ckfp_state' holds the last * checkpointed value of all FPR registers for the current * transaction. * @@ -945,7 +945,7 @@ static int tm_cfpr_active(struct task_struct *target, * * This function gets in transaction checkpointed FPR registers. * - * When the transaction is active 'transact_fp' holds the checkpointed + * When the transaction is active 'ckfp_state' holds the checkpointed * values for the current transaction to fall back on if it aborts * in between. This function gets those checkpointed FPR registers. * The userspace interface buffer layout is as follows. @@ -975,8 +975,8 @@ static int tm_cfpr_get(struct task_struct *target, /* copy to local buffer then write that out */ for (i = 0; i < 32 ; i++) - buf[i] = target->thread.TS_TRANS_FPR(i); - buf[32] = target->thread.transact_fp.fpscr; + buf[i] = target->thread.TS_CKFPR(i); + buf[32] = target->thread.ckfp_state.fpscr; return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); } @@ -991,7 +991,7 @@ static int tm_cfpr_get(struct task_struct *target, * * This function sets in transaction checkpointed FPR registers. * - * When the transaction is active 'transact_fp' holds the checkpointed + * When the transaction is active 'ckfp_state' holds the checkpointed * FPR register values for the current transaction to fall back on * if it aborts in between. This function sets these checkpointed * FPR registers. The userspace interface buffer layout is as follows. @@ -1024,8 +1024,8 @@ static int tm_cfpr_set(struct task_struct *target, if (i) return i; for (i = 0; i < 32 ; i++) - target->thread.TS_TRANS_FPR(i) = buf[i]; - target->thread.transact_fp.fpscr = buf[32]; + target->thread.TS_CKFPR(i) = buf[i]; + target->thread.ckfp_state.fpscr = buf[32]; return 0; } @@ -1060,7 +1060,7 @@ static int tm_cvmx_active(struct task_struct *target, * * This function gets in transaction checkpointed VMX registers. * - * When the transaction is active 'transact_vr' and 'transact_vrsave' hold + * When the transaction is active 'ckvr_state' and 'ckvrsave' hold * the checkpointed values for the current transaction to fall * back on if it aborts in between. The userspace interface buffer * layout is as follows. @@ -1092,7 +1092,7 @@ static int tm_cvmx_get(struct task_struct *target, flush_altivec_to_thread(target); ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.transact_vr, 0, + &target->thread.ckvr_state, 0, 33 * sizeof(vector128)); if (!ret) { /* @@ -1103,7 +1103,7 @@ static int tm_cvmx_get(struct task_struct *target, u32 word; } vrsave; memset(&vrsave, 0, sizeof(vrsave)); - vrsave.word = target->thread.transact_vrsave; + vrsave.word = target->thread.ckvrsave; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, 33 * sizeof(vector128), -1); } @@ -1122,7 +1122,7 @@ static int tm_cvmx_get(struct task_struct *target, * * This function sets in transaction checkpointed VMX registers. * - * When the transaction is active 'transact_vr' and 'transact_vrsave' hold + * When the transaction is active 'ckvr_state' and 'ckvrsave' hold * the checkpointed values for the current transaction to fall * back on if it aborts in between. The userspace interface buffer * layout is as follows. @@ -1153,7 +1153,7 @@ static int tm_cvmx_set(struct task_struct *target, flush_altivec_to_thread(target); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &target->thread.transact_vr, 0, + &target->thread.ckvr_state, 0, 33 * sizeof(vector128)); if (!ret && count > 0) { /* @@ -1164,11 +1164,11 @@ static int tm_cvmx_set(struct task_struct *target, u32 word; } vrsave; memset(&vrsave, 0, sizeof(vrsave)); - vrsave.word = target->thread.transact_vrsave; + vrsave.word = target->thread.ckvrsave; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave, 33 * sizeof(vector128), -1); if (!ret) - target->thread.transact_vrsave = vrsave.word; + target->thread.ckvrsave = vrsave.word; } return ret; @@ -1206,7 +1206,7 @@ static int tm_cvsx_active(struct task_struct *target, * * This function gets in transaction checkpointed VSX registers. * - * When the transaction is active 'transact_fp' holds the checkpointed + * When the transaction is active 'ckfp_state' holds the checkpointed * values for the current transaction to fall back on if it aborts * in between. This function gets those checkpointed VSX registers. * The userspace interface buffer layout is as follows. @@ -1236,7 +1236,7 @@ static int tm_cvsx_get(struct task_struct *target, flush_vsx_to_thread(target); for (i = 0; i < 32 ; i++) - buf[i] = target->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET]; + buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET]; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); @@ -1254,7 +1254,7 @@ static int tm_cvsx_get(struct task_struct *target, * * This function sets in transaction checkpointed VSX registers. * - * When the transaction is active 'transact_fp' holds the checkpointed + * When the transaction is active 'ckfp_state' holds the checkpointed * VSX register values for the current transaction to fall back on * if it aborts in between. This function sets these checkpointed * FPR registers. The userspace interface buffer layout is as follows. @@ -1287,7 +1287,7 @@ static int tm_cvsx_set(struct task_struct *target, buf, 0, 32 * sizeof(double)); if (!ret) for (i = 0; i < 32 ; i++) - target->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = buf[i]; + target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; return ret; } diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h index 254ca074504f..7c59d88b9d86 100644 --- a/arch/powerpc/kernel/signal.h +++ b/arch/powerpc/kernel/signal.h @@ -23,22 +23,22 @@ extern int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, extern unsigned long copy_fpr_to_user(void __user *to, struct task_struct *task); -extern unsigned long copy_transact_fpr_to_user(void __user *to, +extern unsigned long copy_ckfpr_to_user(void __user *to, struct task_struct *task); extern unsigned long copy_fpr_from_user(struct task_struct *task, void __user *from); -extern unsigned long copy_transact_fpr_from_user(struct task_struct *task, +extern unsigned long copy_ckfpr_from_user(struct task_struct *task, void __user *from); extern unsigned long get_tm_stackpointer(struct task_struct *tsk); #ifdef CONFIG_VSX extern unsigned long copy_vsx_to_user(void __user *to, struct task_struct *task); -extern unsigned long copy_transact_vsx_to_user(void __user *to, +extern unsigned long copy_ckvsx_to_user(void __user *to, struct task_struct *task); extern unsigned long copy_vsx_from_user(struct task_struct *task, void __user *from); -extern unsigned long copy_transact_vsx_from_user(struct task_struct *task, +extern unsigned long copy_ckvsx_from_user(struct task_struct *task, void __user *from); #endif diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 3b9356bb4457..27aa913ac91d 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -316,7 +316,7 @@ unsigned long copy_vsx_from_user(struct task_struct *task, } #ifdef CONFIG_PPC_TRANSACTIONAL_MEM -unsigned long copy_transact_fpr_to_user(void __user *to, +unsigned long copy_ckfpr_to_user(void __user *to, struct task_struct *task) { u64 buf[ELF_NFPREG]; @@ -324,12 +324,12 @@ unsigned long copy_transact_fpr_to_user(void __user *to, /* save FPR copy to local buffer then write to the thread_struct */ for (i = 0; i < (ELF_NFPREG - 1) ; i++) - buf[i] = task->thread.TS_TRANS_FPR(i); - buf[i] = task->thread.transact_fp.fpscr; + buf[i] = task->thread.TS_CKFPR(i); + buf[i] = task->thread.ckfp_state.fpscr; return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double)); } -unsigned long copy_transact_fpr_from_user(struct task_struct *task, +unsigned long copy_ckfpr_from_user(struct task_struct *task, void __user *from) { u64 buf[ELF_NFPREG]; @@ -338,13 +338,13 @@ unsigned long copy_transact_fpr_from_user(struct task_struct *task, if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double))) return 1; for (i = 0; i < (ELF_NFPREG - 1) ; i++) - task->thread.TS_TRANS_FPR(i) = buf[i]; - task->thread.transact_fp.fpscr = buf[i]; + task->thread.TS_CKFPR(i) = buf[i]; + task->thread.ckfp_state.fpscr = buf[i]; return 0; } -unsigned long copy_transact_vsx_to_user(void __user *to, +unsigned long copy_ckvsx_to_user(void __user *to, struct task_struct *task) { u64 buf[ELF_NVSRHALFREG]; @@ -352,11 +352,11 @@ unsigned long copy_transact_vsx_to_user(void __user *to, /* save FPR copy to local buffer then write to the thread_struct */ for (i = 0; i < ELF_NVSRHALFREG; i++) - buf[i] = task->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET]; + buf[i] = task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET]; return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double)); } -unsigned long copy_transact_vsx_from_user(struct task_struct *task, +unsigned long copy_ckvsx_from_user(struct task_struct *task, void __user *from) { u64 buf[ELF_NVSRHALFREG]; @@ -365,7 +365,7 @@ unsigned long copy_transact_vsx_from_user(struct task_struct *task, if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double))) return 1; for (i = 0; i < ELF_NVSRHALFREG ; i++) - task->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = buf[i]; + task->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = buf[i]; return 0; } #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ @@ -385,17 +385,17 @@ inline unsigned long copy_fpr_from_user(struct task_struct *task, } #ifdef CONFIG_PPC_TRANSACTIONAL_MEM -inline unsigned long copy_transact_fpr_to_user(void __user *to, +inline unsigned long copy_ckfpr_to_user(void __user *to, struct task_struct *task) { - return __copy_to_user(to, task->thread.transact_fp.fpr, + return __copy_to_user(to, task->thread.ckfp_state.fpr, ELF_NFPREG * sizeof(double)); } -inline unsigned long copy_transact_fpr_from_user(struct task_struct *task, +inline unsigned long copy_ckfpr_from_user(struct task_struct *task, void __user *from) { - return __copy_from_user(task->thread.transact_fp.fpr, from, + return __copy_from_user(task->thread.ckfp_state.fpr, from, ELF_NFPREG * sizeof(double)); } #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ @@ -543,7 +543,7 @@ static int save_tm_user_regs(struct pt_regs *regs, #ifdef CONFIG_ALTIVEC /* save altivec registers */ if (current->thread.used_vr) { - if (__copy_to_user(&frame->mc_vregs, ¤t->thread.transact_vr, + if (__copy_to_user(&frame->mc_vregs, ¤t->thread.ckvr_state, ELF_NVRREG * sizeof(vector128))) return 1; if (msr & MSR_VEC) { @@ -553,7 +553,7 @@ static int save_tm_user_regs(struct pt_regs *regs, return 1; } else { if (__copy_to_user(&tm_frame->mc_vregs, - ¤t->thread.transact_vr, + ¤t->thread.ckvr_state, ELF_NVRREG * sizeof(vector128))) return 1; } @@ -570,8 +570,8 @@ static int save_tm_user_regs(struct pt_regs *regs, * most significant bits of that same vector. --BenH */ if (cpu_has_feature(CPU_FTR_ALTIVEC)) - current->thread.transact_vrsave = mfspr(SPRN_VRSAVE); - if (__put_user(current->thread.transact_vrsave, + current->thread.ckvrsave = mfspr(SPRN_VRSAVE); + if (__put_user(current->thread.ckvrsave, (u32 __user *)&frame->mc_vregs[32])) return 1; if (msr & MSR_VEC) { @@ -579,19 +579,19 @@ static int save_tm_user_regs(struct pt_regs *regs, (u32 __user *)&tm_frame->mc_vregs[32])) return 1; } else { - if (__put_user(current->thread.transact_vrsave, + if (__put_user(current->thread.ckvrsave, (u32 __user *)&tm_frame->mc_vregs[32])) return 1; } #endif /* CONFIG_ALTIVEC */ - if (copy_transact_fpr_to_user(&frame->mc_fregs, current)) + if (copy_ckfpr_to_user(&frame->mc_fregs, current)) return 1; if (msr & MSR_FP) { if (copy_fpr_to_user(&tm_frame->mc_fregs, current)) return 1; } else { - if (copy_transact_fpr_to_user(&tm_frame->mc_fregs, current)) + if (copy_ckfpr_to_user(&tm_frame->mc_fregs, current)) return 1; } @@ -603,14 +603,14 @@ static int save_tm_user_regs(struct pt_regs *regs, * contains valid data */ if (current->thread.used_vsr) { - if (copy_transact_vsx_to_user(&frame->mc_vsregs, current)) + if (copy_ckvsx_to_user(&frame->mc_vsregs, current)) return 1; if (msr & MSR_VSX) { if (copy_vsx_to_user(&tm_frame->mc_vsregs, current)) return 1; } else { - if (copy_transact_vsx_to_user(&tm_frame->mc_vsregs, current)) + if (copy_ckvsx_to_user(&tm_frame->mc_vsregs, current)) return 1; } @@ -792,7 +792,7 @@ static long restore_tm_user_regs(struct pt_regs *regs, regs->msr &= ~MSR_VEC; if (msr & MSR_VEC) { /* restore altivec registers from the stack */ - if (__copy_from_user(¤t->thread.transact_vr, &sr->mc_vregs, + if (__copy_from_user(¤t->thread.ckvr_state, &sr->mc_vregs, sizeof(sr->mc_vregs)) || __copy_from_user(¤t->thread.vr_state, &tm_sr->mc_vregs, @@ -802,24 +802,24 @@ static long restore_tm_user_regs(struct pt_regs *regs, } else if (current->thread.used_vr) { memset(¤t->thread.vr_state, 0, ELF_NVRREG * sizeof(vector128)); - memset(¤t->thread.transact_vr, 0, + memset(¤t->thread.ckvr_state, 0, ELF_NVRREG * sizeof(vector128)); } /* Always get VRSAVE back */ - if (__get_user(current->thread.transact_vrsave, + if (__get_user(current->thread.ckvrsave, (u32 __user *)&sr->mc_vregs[32]) || __get_user(current->thread.vrsave, (u32 __user *)&tm_sr->mc_vregs[32])) return 1; if (cpu_has_feature(CPU_FTR_ALTIVEC)) - mtspr(SPRN_VRSAVE, current->thread.transact_vrsave); + mtspr(SPRN_VRSAVE, current->thread.ckvrsave); #endif /* CONFIG_ALTIVEC */ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); if (copy_fpr_from_user(current, &sr->mc_fregs) || - copy_transact_fpr_from_user(current, &tm_sr->mc_fregs)) + copy_ckfpr_from_user(current, &tm_sr->mc_fregs)) return 1; #ifdef CONFIG_VSX @@ -830,13 +830,13 @@ static long restore_tm_user_regs(struct pt_regs *regs, * buffer, then write this out to the thread_struct */ if (copy_vsx_from_user(current, &tm_sr->mc_vsregs) || - copy_transact_vsx_from_user(current, &sr->mc_vsregs)) + copy_ckvsx_from_user(current, &sr->mc_vsregs)) return 1; current->thread.used_vsr = true; } else if (current->thread.used_vsr) for (i = 0; i < 32 ; i++) { current->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0; - current->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = 0; + current->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = 0; } #endif /* CONFIG_VSX */ diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index af58af520472..96698fdf93b4 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -228,7 +228,7 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, /* save altivec registers */ if (tsk->thread.used_vr) { /* Copy 33 vec registers (vr0..31 and vscr) to the stack */ - err |= __copy_to_user(v_regs, &tsk->thread.transact_vr, + err |= __copy_to_user(v_regs, &tsk->thread.ckvr_state, 33 * sizeof(vector128)); /* If VEC was enabled there are transactional VRs valid too, * else they're a copy of the checkpointed VRs. @@ -239,7 +239,7 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, 33 * sizeof(vector128)); else err |= __copy_to_user(tm_v_regs, - &tsk->thread.transact_vr, + &tsk->thread.ckvr_state, 33 * sizeof(vector128)); /* set MSR_VEC in the MSR value in the frame to indicate @@ -251,13 +251,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, * use altivec. */ if (cpu_has_feature(CPU_FTR_ALTIVEC)) - tsk->thread.transact_vrsave = mfspr(SPRN_VRSAVE); - err |= __put_user(tsk->thread.transact_vrsave, (u32 __user *)&v_regs[33]); + tsk->thread.ckvrsave = mfspr(SPRN_VRSAVE); + err |= __put_user(tsk->thread.ckvrsave, (u32 __user *)&v_regs[33]); if (msr & MSR_VEC) err |= __put_user(tsk->thread.vrsave, (u32 __user *)&tm_v_regs[33]); else - err |= __put_user(tsk->thread.transact_vrsave, + err |= __put_user(tsk->thread.ckvrsave, (u32 __user *)&tm_v_regs[33]); #else /* CONFIG_ALTIVEC */ @@ -266,11 +266,11 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, #endif /* CONFIG_ALTIVEC */ /* copy fpr regs and fpscr */ - err |= copy_transact_fpr_to_user(&sc->fp_regs, tsk); + err |= copy_ckfpr_to_user(&sc->fp_regs, tsk); if (msr & MSR_FP) err |= copy_fpr_to_user(&tm_sc->fp_regs, tsk); else - err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, tsk); + err |= copy_ckfpr_to_user(&tm_sc->fp_regs, tsk); #ifdef CONFIG_VSX /* @@ -282,12 +282,12 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, v_regs += ELF_NVRREG; tm_v_regs += ELF_NVRREG; - err |= copy_transact_vsx_to_user(v_regs, tsk); + err |= copy_ckvsx_to_user(v_regs, tsk); if (msr & MSR_VSX) err |= copy_vsx_to_user(tm_v_regs, tsk); else - err |= copy_transact_vsx_to_user(tm_v_regs, tsk); + err |= copy_ckvsx_to_user(tm_v_regs, tsk); /* set MSR_VSX in the MSR value in the frame to * indicate that sc->vs_reg) contains valid data. @@ -497,7 +497,7 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, return -EFAULT; /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ if (v_regs != NULL && tm_v_regs != NULL && (msr & MSR_VEC) != 0) { - err |= __copy_from_user(&tsk->thread.transact_vr, v_regs, + err |= __copy_from_user(&tsk->thread.ckvr_state, v_regs, 33 * sizeof(vector128)); err |= __copy_from_user(&tsk->thread.vr_state, tm_v_regs, 33 * sizeof(vector128)); @@ -505,25 +505,25 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, } else if (tsk->thread.used_vr) { memset(&tsk->thread.vr_state, 0, 33 * sizeof(vector128)); - memset(&tsk->thread.transact_vr, 0, 33 * sizeof(vector128)); + memset(&tsk->thread.ckvr_state, 0, 33 * sizeof(vector128)); } /* Always get VRSAVE back */ if (v_regs != NULL && tm_v_regs != NULL) { - err |= __get_user(tsk->thread.transact_vrsave, + err |= __get_user(tsk->thread.ckvrsave, (u32 __user *)&v_regs[33]); err |= __get_user(tsk->thread.vrsave, (u32 __user *)&tm_v_regs[33]); } else { tsk->thread.vrsave = 0; - tsk->thread.transact_vrsave = 0; + tsk->thread.ckvrsave = 0; } if (cpu_has_feature(CPU_FTR_ALTIVEC)) mtspr(SPRN_VRSAVE, tsk->thread.vrsave); #endif /* CONFIG_ALTIVEC */ /* restore floating point */ err |= copy_fpr_from_user(tsk, &tm_sc->fp_regs); - err |= copy_transact_fpr_from_user(tsk, &sc->fp_regs); + err |= copy_ckfpr_from_user(tsk, &sc->fp_regs); #ifdef CONFIG_VSX /* * Get additional VSX data. Update v_regs to point after the @@ -534,12 +534,12 @@ static long restore_tm_sigcontexts(struct task_struct *tsk, v_regs += ELF_NVRREG; tm_v_regs += ELF_NVRREG; err |= copy_vsx_from_user(tsk, tm_v_regs); - err |= copy_transact_vsx_from_user(tsk, v_regs); + err |= copy_ckvsx_from_user(tsk, v_regs); tsk->thread.used_vsr = true; } else { for (i = 0; i < 32 ; i++) { tsk->thread.fp_state.fpr[i][TS_VSRLOWOFFSET] = 0; - tsk->thread.transact_fp.fpr[i][TS_VSRLOWOFFSET] = 0; + tsk->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET] = 0; } } #endif diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S index 7b7088d8d130..3a2d04134da9 100644 --- a/arch/powerpc/kernel/tm.S +++ b/arch/powerpc/kernel/tm.S @@ -257,19 +257,19 @@ _GLOBAL(tm_reclaim) andis. r0, r4, MSR_VEC@h beq dont_backup_vec - addi r7, r3, THREAD_TRANSACT_VRSTATE + addi r7, r3, THREAD_CKVRSTATE SAVE_32VRS(0, r6, r7) /* r6 scratch, r7 transact vr state */ mfvscr v0 li r6, VRSTATE_VSCR stvx v0, r7, r6 dont_backup_vec: mfspr r0, SPRN_VRSAVE - std r0, THREAD_TRANSACT_VRSAVE(r3) + std r0, THREAD_CKVRSAVE(r3) andi. r0, r4, MSR_FP beq dont_backup_fp - addi r7, r3, THREAD_TRANSACT_FPSTATE + addi r7, r3, THREAD_CKFPSTATE SAVE_32FPRS_VSRS(0, R6, R7) /* r6 scratch, r7 transact fp state */ mffs fr0 @@ -370,20 +370,20 @@ _GLOBAL(__tm_recheckpoint) andis. r0, r4, MSR_VEC@h beq dont_restore_vec - addi r8, r3, THREAD_TRANSACT_VRSTATE + addi r8, r3, THREAD_CKVRSTATE li r5, VRSTATE_VSCR lvx v0, r8, r5 mtvscr v0 REST_32VRS(0, r5, r8) /* r5 scratch, r8 ptr */ dont_restore_vec: - ld r5, THREAD_TRANSACT_VRSAVE(r3) + ld r5, THREAD_CKVRSAVE(r3) mtspr SPRN_VRSAVE, r5 #endif andi. r0, r4, MSR_FP beq dont_restore_fp - addi r8, r3, THREAD_TRANSACT_FPSTATE + addi r8, r3, THREAD_CKFPSTATE lfd fr0, FPSTATE_FPSCR(r8) MTFSF_L(fr0) REST_32FPRS_VSRS(0, R4, R8) diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 616a6d854638..7dc402126b30 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -23,10 +23,10 @@ _GLOBAL(do_load_up_transact_altivec) li r4,1 stw r4,THREAD_USED_VR(r3) - li r10,THREAD_TRANSACT_VRSTATE+VRSTATE_VSCR + li r10,THREAD_CKVRSTATE+VRSTATE_VSCR lvx v0,r10,r3 mtvscr v0 - addi r10,r3,THREAD_TRANSACT_VRSTATE + addi r10,r3,THREAD_CKVRSTATE REST_32VRS(0,r4,r10) blr -- cgit v1.2.3 From d986d6f4d0ee30ad096ed7e59670f56ca8f23b57 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:26 +1000 Subject: powerpc: Remove do_load_up_transact_{fpu,altivec} Previous rework of TM code leaves these functions unused Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/tm.h | 5 ----- arch/powerpc/kernel/fpu.S | 26 -------------------------- arch/powerpc/kernel/vector.S | 25 ------------------------- 3 files changed, 56 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h index c22d704b6d41..82e06ca3a49b 100644 --- a/arch/powerpc/include/asm/tm.h +++ b/arch/powerpc/include/asm/tm.h @@ -9,11 +9,6 @@ #ifndef __ASSEMBLY__ -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM -extern void do_load_up_transact_fpu(struct thread_struct *thread); -extern void do_load_up_transact_altivec(struct thread_struct *thread); -#endif - extern void tm_enable(void); extern void tm_reclaim(struct thread_struct *thread, unsigned long orig_msr, uint8_t cause); diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 181c18707f08..08d14b096eb9 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S @@ -50,32 +50,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \ #define REST_32FPVSRS(n,c,base) __REST_32FPVSRS(n,__REG_##c,__REG_##base) #define SAVE_32FPVSRS(n,c,base) __SAVE_32FPVSRS(n,__REG_##c,__REG_##base) -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM -/* void do_load_up_transact_fpu(struct thread_struct *thread) - * - * This is similar to load_up_fpu but for the transactional version of the FP - * register set. It doesn't mess with the task MSR or valid flags. - * Furthermore, we don't do lazy FP with TM currently. - */ -_GLOBAL(do_load_up_transact_fpu) - mfmsr r6 - ori r5,r6,MSR_FP -#ifdef CONFIG_VSX -BEGIN_FTR_SECTION - oris r5,r5,MSR_VSX@h -END_FTR_SECTION_IFSET(CPU_FTR_VSX) -#endif - SYNC - MTMSRD(r5) - - addi r7,r3,THREAD_CKFPSTATE - lfd fr0,FPSTATE_FPSCR(r7) - MTFSF_L(fr0) - REST_32FPVSRS(0, R4, R7) - - blr -#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ - /* * Load state from memory into FP registers including FPSCR. * Assumes the caller has enabled FP in the MSR. diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 7dc402126b30..bc85bdff4e01 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S @@ -7,31 +7,6 @@ #include #include -#ifdef CONFIG_PPC_TRANSACTIONAL_MEM -/* void do_load_up_transact_altivec(struct thread_struct *thread) - * - * This is similar to load_up_altivec but for the transactional version of the - * vector regs. It doesn't mess with the task MSR or valid flags. - * Furthermore, VEC laziness is not supported with TM currently. - */ -_GLOBAL(do_load_up_transact_altivec) - mfmsr r6 - oris r5,r6,MSR_VEC@h - MTMSRD(r5) - isync - - li r4,1 - stw r4,THREAD_USED_VR(r3) - - li r10,THREAD_CKVRSTATE+VRSTATE_VSCR - lvx v0,r10,r3 - mtvscr v0 - addi r10,r3,THREAD_CKVRSTATE - REST_32VRS(0,r4,r10) - - blr -#endif - /* * Load state from memory into VMX registers including VSCR. * Assumes the caller has enabled VMX in the MSR. -- cgit v1.2.3 From 5d176f751ee3c6eededd984ad409bff201f436a7 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Wed, 14 Sep 2016 18:02:16 +1000 Subject: powerpc: tm: Enable transactional memory (TM) lazily for userspace Currently the MSR TM bit is always set if the hardware is TM capable. This adds extra overhead as it means the TM SPRS (TFHAR, TEXASR and TFAIR) must be swapped for each process regardless of if they use TM. For processes that don't use TM the TM MSR bit can be turned off allowing the kernel to avoid the expensive swap of the TM registers. A TM unavailable exception will occur if a thread does use TM and the kernel will enable MSR_TM and leave it so for some time afterwards. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/processor.h | 1 + arch/powerpc/kernel/process.c | 28 +++++++++++++++++++++++----- arch/powerpc/kernel/traps.c | 9 +++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index b3e0cfcc84f6..c07c31b0e89e 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -257,6 +257,7 @@ struct thread_struct { int used_spe; /* set if process has used spe */ #endif /* CONFIG_SPE */ #ifdef CONFIG_PPC_TRANSACTIONAL_MEM + u8 load_tm; u64 tm_tfhar; /* Transaction fail handler addr */ u64 tm_texasr; /* Transaction exception & summary */ u64 tm_tfiar; /* Transaction fail instr address reg */ diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e22033005d15..9e7c10fe205f 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -812,6 +812,12 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a, } #ifdef CONFIG_PPC_TRANSACTIONAL_MEM + +static inline bool tm_enabled(struct task_struct *tsk) +{ + return tsk && tsk->thread.regs && (tsk->thread.regs->msr & MSR_TM); +} + static void tm_reclaim_thread(struct thread_struct *thr, struct thread_info *ti, uint8_t cause) { @@ -892,6 +898,9 @@ void tm_recheckpoint(struct thread_struct *thread, { unsigned long flags; + if (!(thread->regs->msr & MSR_TM)) + return; + /* We really can't be interrupted here as the TEXASR registers can't * change and later in the trecheckpoint code, we have a userspace R1. * So let's hard disable over this region. @@ -924,7 +933,7 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new) * unavailable later, we are unable to determine which set of FP regs * need to be restored. */ - if (!new->thread.regs) + if (!tm_enabled(new)) return; if (!MSR_TM_ACTIVE(new->thread.regs->msr)){ @@ -955,8 +964,16 @@ static inline void __switch_to_tm(struct task_struct *prev, struct task_struct *new) { if (cpu_has_feature(CPU_FTR_TM)) { - tm_enable(); - tm_reclaim_task(prev); + if (tm_enabled(prev) || tm_enabled(new)) + tm_enable(); + + if (tm_enabled(prev)) { + prev->thread.load_tm++; + tm_reclaim_task(prev); + if (!MSR_TM_ACTIVE(prev->thread.regs->msr) && prev->thread.load_tm == 0) + prev->thread.regs->msr &= ~MSR_TM; + } + tm_recheckpoint_new_task(new); } } @@ -1393,6 +1410,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) * transitions the CPU out of TM mode. Hence we need to call * tm_recheckpoint_new_task() (on the same task) to restore the * checkpointed state back and the TM mode. + * + * Can't pass dst because it isn't ready. Doesn't matter, passing + * dst is only important for __switch_to() */ __switch_to_tm(src, src); @@ -1636,8 +1656,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) current->thread.used_spe = 0; #endif /* CONFIG_SPE */ #ifdef CONFIG_PPC_TRANSACTIONAL_MEM - if (cpu_has_feature(CPU_FTR_TM)) - regs->msr |= MSR_TM; current->thread.tm_tfhar = 0; current->thread.tm_texasr = 0; current->thread.tm_tfiar = 0; diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 2f5ef5a80353..a1f8f5641e9e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1392,6 +1392,15 @@ void vsx_unavailable_exception(struct pt_regs *regs) #ifdef CONFIG_PPC64 static void tm_unavailable(struct pt_regs *regs) { +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM + if (user_mode(regs)) { + current->thread.load_tm++; + regs->msr |= MSR_TM; + tm_enable(); + tm_restore_sprs(¤t->thread); + return; + } +#endif pr_emerg("Unrecoverable TM Unavailable Exception " "%lx at %lx\n", regs->trap, regs->nip); die("Unrecoverable TM Unavailable Exception", regs, SIGABRT); -- cgit v1.2.3 From ce0761419faefbe9e450749ccc879ff88843af12 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Sat, 24 Sep 2016 02:05:01 +0530 Subject: powerpc/bpf: Implement support for tail calls Tail calls allow JIT'ed eBPF programs to call into other JIT'ed eBPF programs. This can be achieved either by: (1) retaining the stack setup by the first eBPF program and having all subsequent eBPF programs re-using it, or, (2) by unwinding/tearing down the stack and having each eBPF program deal with its own stack as it sees fit. To ensure that this does not create loops, there is a limit to how many tail calls can be done (currently 32). This requires the JIT'ed code to maintain a count of the number of tail calls done so far. Approach (1) is simple, but requires every eBPF program to have (almost) the same prologue/epilogue, regardless of whether they need it. This is inefficient for small eBPF programs which may not sometimes need a prologue at all. As such, to minimize impact of tail call implementation, we use approach (2) here which needs each eBPF program in the chain to use its own prologue/epilogue. This is not ideal when many tail calls are involved and when all the eBPF programs in the chain have similar prologue/epilogue. However, the impact is restricted to programs that do tail calls. Individual eBPF programs are not affected. We maintain the tail call count in a fixed location on the stack and updated tail call count values are passed in through this. The very first eBPF program in a chain sets this up to 0 (the first 2 instructions). Subsequent tail calls skip the first two eBPF JIT instructions to maintain the count. For programs that don't do tail calls themselves, the first two instructions are NOPs. Signed-off-by: Naveen N. Rao Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc-opcode.h | 2 + arch/powerpc/net/bpf_jit.h | 2 + arch/powerpc/net/bpf_jit64.h | 1 + arch/powerpc/net/bpf_jit_comp64.c | 149 +++++++++++++++++++++++++++------- 4 files changed, 126 insertions(+), 28 deletions(-) (limited to 'arch/powerpc/include/asm') diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 127ebf5862b4..54ff8ce7fa96 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -236,6 +236,7 @@ #define PPC_INST_STWU 0x94000000 #define PPC_INST_MFLR 0x7c0802a6 #define PPC_INST_MTLR 0x7c0803a6 +#define PPC_INST_MTCTR 0x7c0903a6 #define PPC_INST_CMPWI 0x2c000000 #define PPC_INST_CMPDI 0x2c200000 #define PPC_INST_CMPW 0x7c000000 @@ -250,6 +251,7 @@ #define PPC_INST_SUB 0x7c000050 #define PPC_INST_BLR 0x4e800020 #define PPC_INST_BLRL 0x4e800021 +#define PPC_INST_BCTR 0x4e800420 #define PPC_INST_MULLD 0x7c0001d2 #define PPC_INST_MULLW 0x7c0001d6 #define PPC_INST_MULHWU 0x7c000016 diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h index d5301b6f20d0..89f70073dec8 100644 --- a/arch/powerpc/net/bpf_jit.h +++ b/arch/powerpc/net/bpf_jit.h @@ -40,6 +40,8 @@ #define PPC_BLR() EMIT(PPC_INST_BLR) #define PPC_BLRL() EMIT(PPC_INST_BLRL) #define PPC_MTLR(r) EMIT(PPC_INST_MTLR | ___PPC_RT(r)) +#define PPC_BCTR() EMIT(PPC_INST_BCTR) +#define PPC_MTCTR(r) EMIT(PPC_INST_MTCTR | ___PPC_RT(r)) #define PPC_ADDI(d, a, i) EMIT(PPC_INST_ADDI | ___PPC_RT(d) | \ ___PPC_RA(a) | IMM_L(i)) #define PPC_MR(d, a) PPC_OR(d, a, a) diff --git a/arch/powerpc/net/bpf_jit64.h b/arch/powerpc/net/bpf_jit64.h index a1645d7a4033..038e00bf2b77 100644 --- a/arch/powerpc/net/bpf_jit64.h +++ b/arch/powerpc/net/bpf_jit64.h @@ -88,6 +88,7 @@ DECLARE_LOAD_FUNC(sk_load_byte); #define SEEN_FUNC 0x1000 /* might call external helpers */ #define SEEN_STACK 0x2000 /* uses BPF stack */ #define SEEN_SKB 0x4000 /* uses sk_buff */ +#define SEEN_TAILCALL 0x8000 /* uses tail calls */ struct codegen_context { /* diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 5f8c91fa612e..3ec29d6fba60 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "bpf_jit64.h" @@ -77,6 +78,11 @@ static int bpf_jit_stack_local(struct codegen_context *ctx) return -(BPF_PPC_STACK_SAVE + 16); } +static int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx) +{ + return bpf_jit_stack_local(ctx) + 8; +} + static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg) { if (reg >= BPF_PPC_NVR_MIN && reg < 32) @@ -102,33 +108,25 @@ static void bpf_jit_emit_skb_loads(u32 *image, struct codegen_context *ctx) PPC_BPF_LL(b2p[SKB_DATA_REG], 3, offsetof(struct sk_buff, data)); } -static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func) +static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) { -#ifdef PPC64_ELF_ABI_v1 - /* func points to the function descriptor */ - PPC_LI64(b2p[TMP_REG_2], func); - /* Load actual entry point from function descriptor */ - PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0); - /* ... and move it to LR */ - PPC_MTLR(b2p[TMP_REG_1]); + int i; + /* - * Load TOC from function descriptor at offset 8. - * We can clobber r2 since we get called through a - * function pointer (so caller will save/restore r2) - * and since we don't use a TOC ourself. + * Initialize tail_call_cnt if we do tail calls. + * Otherwise, put in NOPs so that it can be skipped when we are + * invoked through a tail call. */ - PPC_BPF_LL(2, b2p[TMP_REG_2], 8); -#else - /* We can clobber r12 */ - PPC_FUNC_ADDR(12, func); - PPC_MTLR(12); -#endif - PPC_BLRL(); -} + if (ctx->seen & SEEN_TAILCALL) { + PPC_LI(b2p[TMP_REG_1], 0); + /* this goes in the redzone */ + PPC_BPF_STL(b2p[TMP_REG_1], 1, -(BPF_PPC_STACK_SAVE + 8)); + } else { + PPC_NOP(); + PPC_NOP(); + } -static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) -{ - int i; +#define BPF_TAILCALL_PROLOGUE_SIZE 8 if (bpf_has_stack_frame(ctx)) { /* @@ -170,13 +168,10 @@ static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) STACK_FRAME_MIN_SIZE + MAX_BPF_STACK); } -static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) +static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx) { int i; - /* Move result to r3 */ - PPC_MR(3, b2p[BPF_REG_0]); - /* Restore NVRs */ for (i = BPF_REG_6; i <= BPF_REG_10; i++) if (bpf_is_seen_register(ctx, i)) @@ -198,10 +193,105 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) PPC_MTLR(0); } } +} + +static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) +{ + bpf_jit_emit_common_epilogue(image, ctx); + + /* Move result to r3 */ + PPC_MR(3, b2p[BPF_REG_0]); PPC_BLR(); } +static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func) +{ +#ifdef PPC64_ELF_ABI_v1 + /* func points to the function descriptor */ + PPC_LI64(b2p[TMP_REG_2], func); + /* Load actual entry point from function descriptor */ + PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0); + /* ... and move it to LR */ + PPC_MTLR(b2p[TMP_REG_1]); + /* + * Load TOC from function descriptor at offset 8. + * We can clobber r2 since we get called through a + * function pointer (so caller will save/restore r2) + * and since we don't use a TOC ourself. + */ + PPC_BPF_LL(2, b2p[TMP_REG_2], 8); +#else + /* We can clobber r12 */ + PPC_FUNC_ADDR(12, func); + PPC_MTLR(12); +#endif + PPC_BLRL(); +} + +static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out) +{ + /* + * By now, the eBPF program has already setup parameters in r3, r4 and r5 + * r3/BPF_REG_1 - pointer to ctx -- passed as is to the next bpf program + * r4/BPF_REG_2 - pointer to bpf_array + * r5/BPF_REG_3 - index in bpf_array + */ + int b2p_bpf_array = b2p[BPF_REG_2]; + int b2p_index = b2p[BPF_REG_3]; + + /* + * if (index >= array->map.max_entries) + * goto out; + */ + PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries)); + PPC_CMPLW(b2p_index, b2p[TMP_REG_1]); + PPC_BCC(COND_GE, out); + + /* + * if (tail_call_cnt > MAX_TAIL_CALL_CNT) + * goto out; + */ + PPC_LD(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); + PPC_CMPLWI(b2p[TMP_REG_1], MAX_TAIL_CALL_CNT); + PPC_BCC(COND_GT, out); + + /* + * tail_call_cnt++; + */ + PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 1); + PPC_BPF_STL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); + + /* prog = array->ptrs[index]; */ + PPC_MULI(b2p[TMP_REG_1], b2p_index, 8); + PPC_ADD(b2p[TMP_REG_1], b2p[TMP_REG_1], b2p_bpf_array); + PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_array, ptrs)); + + /* + * if (prog == NULL) + * goto out; + */ + PPC_CMPLDI(b2p[TMP_REG_1], 0); + PPC_BCC(COND_EQ, out); + + /* goto *(prog->bpf_func + prologue_size); */ + PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_prog, bpf_func)); +#ifdef PPC64_ELF_ABI_v1 + /* skip past the function descriptor */ + PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], + FUNCTION_DESCR_SIZE + BPF_TAILCALL_PROLOGUE_SIZE); +#else + PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], BPF_TAILCALL_PROLOGUE_SIZE); +#endif + PPC_MTCTR(b2p[TMP_REG_1]); + + /* tear down stack, restore NVRs, ... */ + bpf_jit_emit_common_epilogue(image, ctx); + + PPC_BCTR(); + /* out: */ +} + /* Assemble the body code between the prologue & epilogue */ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, struct codegen_context *ctx, @@ -846,9 +936,12 @@ common_load: break; /* - * TODO: Tail call + * Tail call */ case BPF_JMP | BPF_CALL | BPF_X: + ctx->seen |= SEEN_TAILCALL; + bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]); + break; default: /* -- cgit v1.2.3