diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-30 08:24:12 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-07-30 08:24:12 -0700 |
| commit | b96890b3e5e0995a4bcf731bb9d6af2bbdf8ec42 (patch) | |
| tree | ed86e894f889c221ba71b3ff7898a0ba62d6c00d | |
| parent | 11028ab62899e4191e074ee364c712b77823a9c4 (diff) | |
| parent | 5732bd17feb9ddf843591c4d038eb6de1f8daf4c (diff) | |
Merge tag 'powerpc-7.2-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc fixes from Madhavan Srinivasan:
- ensure vpa,slb_shadow & dtl are unregistered during crash
- fix nap return address corruption on async interrupt exit in 970
platform
- fix exit_flags field placement in pt_regs for ptrace
- fix map failure path in dma_ioc0_map_pages() in ps3 platfrom
- MAINTAINERS: Michael Ellerman demotes himself to reviewer
- misc fixes and cleanup
Thanks to Amit Machhiwal, Andreas Schwab, Anushree Mathur, Athira
Rajeev, Christophe Leroy (CS GROUP), Dmitry V. Levin, Geert
Uytterhoeven, John Ogness, Michael Ellerman, Mukesh Kumar Chaurasiya
(IBM), Ritesh Harjani (IBM), Thorsten Blum, and Vaibhav Jain
* tag 'powerpc-7.2-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
MAINTAINERS: Demote myself to reviewer
powerpc/serial: Fix include guard comment
powerpc/perf: Use strstarts() to simplify is_thread_imc_pmu()
powerpc/ps3: Fix map failure path in dma_ioc0_map_pages()
powerpc/ps3: Remove unused struct table in setup_areas()
powerpc/boot: Fix treeboot-akebono CPU node lookup check
powerpc/boot: Fix treeboot-currituck CPU node lookup check
powerpc/boot: Fix simpleboot CPU node lookup check
powerpc: Fix exit_flags field placement in pt_regs for ptrace
powerpc/970: fix nap return address corruption on async interrupt exit
powerpc/pseries: Skip vpa_init() for boot cpu in smp_setup_cpu()
powerpc/pseries: Ensure vpa,slb_shadow & dtl are unregistered during crash
| -rw-r--r-- | MAINTAINERS | 2 | ||||
| -rw-r--r-- | arch/powerpc/boot/simpleboot.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/boot/treeboot-akebono.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/boot/treeboot-currituck.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/entry-common.h | 15 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/interrupt.h | 1 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/ptrace.h | 3 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/serial.h | 4 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/thread_info.h | 1 | ||||
| -rw-r--r-- | arch/powerpc/include/uapi/asm/ptrace.h | 14 | ||||
| -rw-r--r-- | arch/powerpc/kernel/interrupt.c | 32 | ||||
| -rw-r--r-- | arch/powerpc/kernel/ptrace/ptrace.c | 1 | ||||
| -rw-r--r-- | arch/powerpc/kernel/signal.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/perf/imc-pmu.c | 5 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/mm.c | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/ps3/spu.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/kexec.c | 13 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/smp.c | 7 |
18 files changed, 55 insertions, 54 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 62d53465ef9b..67a7a8603cbd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14887,7 +14887,7 @@ X: drivers/macintosh/via-macii.c LINUX FOR POWERPC (32-BIT AND 64-BIT) M: Madhavan Srinivasan <maddy@linux.ibm.com> -M: Michael Ellerman <mpe@ellerman.id.au> +R: Michael Ellerman <mpe@ellerman.id.au> R: Nicholas Piggin <npiggin@gmail.com> R: Christophe Leroy (CS GROUP) <chleroy@kernel.org> L: linuxppc-dev@lists.ozlabs.org diff --git a/arch/powerpc/boot/simpleboot.c b/arch/powerpc/boot/simpleboot.c index c80691d83880..27591df41e9e 100644 --- a/arch/powerpc/boot/simpleboot.c +++ b/arch/powerpc/boot/simpleboot.c @@ -68,7 +68,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, /* finally, setup the timebase */ node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", "cpu", sizeof("cpu")); - if (!node) + if (node < 0) fatal("Cannot find cpu node\n"); timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); if (timebase && (size == 4)) diff --git a/arch/powerpc/boot/treeboot-akebono.c b/arch/powerpc/boot/treeboot-akebono.c index e3cc2599869c..1b529037480f 100644 --- a/arch/powerpc/boot/treeboot-akebono.c +++ b/arch/powerpc/boot/treeboot-akebono.c @@ -146,7 +146,7 @@ void platform_init(char *userdata) node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", "cpu", sizeof("cpu")); - if (!node) + if (node < 0) fatal("Cannot find cpu node\n"); timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); if (timebase && (size == 4)) diff --git a/arch/powerpc/boot/treeboot-currituck.c b/arch/powerpc/boot/treeboot-currituck.c index d53e8a592f81..5b5363b74f9f 100644 --- a/arch/powerpc/boot/treeboot-currituck.c +++ b/arch/powerpc/boot/treeboot-currituck.c @@ -102,7 +102,7 @@ void platform_init(void) node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type", "cpu", sizeof("cpu")); - if (!node) + if (node < 0) fatal("Cannot find cpu node\n"); timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size); if (timebase && (size == 4)) diff --git a/arch/powerpc/include/asm/entry-common.h b/arch/powerpc/include/asm/entry-common.h index fc636c42e89a..c5adb5006361 100644 --- a/arch/powerpc/include/asm/entry-common.h +++ b/arch/powerpc/include/asm/entry-common.h @@ -66,6 +66,13 @@ static inline void srr_regs_clobbered(void) static inline void nap_adjust_return(struct pt_regs *regs) { #ifdef CONFIG_PPC_970_NAP + /* + * Adjust the nap return address before irq_exit_rcu(). irq_exit_rcu() + * may invoke softirqs with interrupts re-enabled, allowing a nested + * async interrupt to arrive. If _TLF_NAPPING is still set at that + * point, the nested interrupt would erroneously redirect its own + * return address to power4_idle_nap_return, corrupting the stack. + */ if (unlikely(test_thread_local_flags(_TLF_NAPPING))) { /* Can avoid a test-and-clear because NMIs do not call this */ clear_thread_local_flags(_TLF_NAPPING); @@ -286,14 +293,6 @@ static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs) static inline void arch_interrupt_async_exit_prepare(struct pt_regs *regs) { - /* - * Adjust at exit so the main handler sees the true NIA. This must - * come before irq_exit() because irq_exit can enable interrupts, and - * if another interrupt is taken before nap_adjust_return has run - * here, then that interrupt would return directly to idle nap return. - */ - nap_adjust_return(regs); - arch_interrupt_exit_prepare(regs); } diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h index fb42a664ae54..1b45a49e9bed 100644 --- a/arch/powerpc/include/asm/interrupt.h +++ b/arch/powerpc/include/asm/interrupt.h @@ -246,6 +246,7 @@ interrupt_handler void func(struct pt_regs *regs) \ instrumentation_begin(); \ irq_enter_rcu(); \ ____##func (regs); \ + nap_adjust_return(regs); \ irq_exit_rcu(); \ instrumentation_end(); \ arch_interrupt_async_exit_prepare(regs); \ diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index fdeb97421785..d53c4dd4d8b6 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -53,9 +53,6 @@ struct pt_regs unsigned long esr; }; unsigned long result; - unsigned long exit_flags; - /* Maintain 16 byte interrupt stack alignment */ - unsigned long __pt_regs_pad[3]; }; }; #if defined(CONFIG_PPC64) || defined(CONFIG_PPC_KUAP) diff --git a/arch/powerpc/include/asm/serial.h b/arch/powerpc/include/asm/serial.h index cd6c18d0e66e..c3eb4a64b3f5 100644 --- a/arch/powerpc/include/asm/serial.h +++ b/arch/powerpc/include/asm/serial.h @@ -1,6 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - */ #ifndef _ASM_POWERPC_SERIAL_H #define _ASM_POWERPC_SERIAL_H @@ -18,4 +16,4 @@ extern void find_legacy_serial_ports(void); #define find_legacy_serial_ports() do { } while (0) #endif -#endif /* _PPC64_SERIAL_H */ +#endif /* _ASM_POWERPC_SERIAL_H */ diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index ee3b9adb5b67..0487e94d3416 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -57,6 +57,7 @@ struct thread_info { #ifdef CONFIG_SMP unsigned int cpu; #endif + unsigned long exit_flags; /* Exit Flags for entry/exit */ unsigned long syscall_work; /* SYSCALL_WORK_ flags */ unsigned long local_flags; /* private flags for thread */ #ifdef CONFIG_LIVEPATCH_64 diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h index a393b7f2760a..01e630149d48 100644 --- a/arch/powerpc/include/uapi/asm/ptrace.h +++ b/arch/powerpc/include/uapi/asm/ptrace.h @@ -55,8 +55,6 @@ struct pt_regs unsigned long dar; /* Fault registers */ unsigned long dsisr; /* on 4xx/Book-E used for ESR */ unsigned long result; /* Result of a system call */ - unsigned long exit_flags; /* System call exit flags */ - unsigned long __pt_regs_pad[3]; /* Maintain 16 byte interrupt stack alignment */ }; #endif /* __ASSEMBLER__ */ @@ -116,12 +114,10 @@ struct pt_regs #define PT_DAR 41 #define PT_DSISR 42 #define PT_RESULT 43 -#define PT_EXIT_FLAGS 44 -#define PT_PAD 47 /* 3 times */ -#define PT_DSCR 48 -#define PT_REGS_COUNT 48 +#define PT_DSCR 44 +#define PT_REGS_COUNT 44 -#define PT_FPR0 (PT_REGS_COUNT + 4) /* each FP reg occupies 2 slots in this space */ +#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */ #ifndef __powerpc64__ @@ -133,7 +129,7 @@ struct pt_regs #define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */ -#define PT_VR0 (PT_FPSCR + 2) /* <82> each Vector reg occupies 2 slots in 64-bit */ +#define PT_VR0 82 /* each Vector reg occupies 2 slots in 64-bit */ #define PT_VSCR (PT_VR0 + 32*2 + 1) #define PT_VRSAVE (PT_VR0 + 33*2) @@ -141,7 +137,7 @@ struct pt_regs /* * Only store first 32 VSRs here. The second 32 VSRs in VR0-31 */ -#define PT_VSR0 (PT_VRSAVE + 2) /* each VSR reg occupies 2 slots in 64-bit */ +#define PT_VSR0 150 /* each VSR reg occupies 2 slots in 64-bit */ #define PT_VSR31 (PT_VSR0 + 2*31) #endif /* __powerpc64__ */ diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c index f04978080837..5b88bf72786c 100644 --- a/arch/powerpc/kernel/interrupt.c +++ b/arch/powerpc/kernel/interrupt.c @@ -89,15 +89,17 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, long scv) { unsigned long ti_flags; + unsigned long ret = 0; bool is_not_scv = !IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !scv; kuap_assert_locked(); regs->result = r3; - regs->exit_flags = 0; - ti_flags = read_thread_flags(); + /* Clear exit_flags so only flags set during this exit are visible */ + current->thread_info.exit_flags = 0; + ti_flags = read_thread_flags(); if (unlikely(r3 >= (unsigned long)-MAX_ERRNO) && is_not_scv) { if (likely(!(ti_flags & (_TIF_NOERROR | _TIF_RESTOREALL)))) { r3 = -r3; @@ -107,7 +109,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, if (unlikely(ti_flags & _TIF_PERSYSCALL_MASK)) { if (ti_flags & _TIF_RESTOREALL) - regs->exit_flags = _TIF_RESTOREALL; + ret = _TIF_RESTOREALL; else regs->gpr[3] = r3; clear_bits(_TIF_PERSYSCALL_MASK, ¤t_thread_info()->flags); @@ -116,7 +118,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3, } if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) { - regs->exit_flags |= _TIF_RESTOREALL; + ret |= _TIF_RESTOREALL; } syscall_exit_to_user_mode(regs); @@ -132,17 +134,19 @@ again: /* Restore user access locks last */ kuap_user_restore(regs); - + ret |= current->thread_info.exit_flags; #ifdef CONFIG_PPC64 - regs->exit_result = regs->exit_flags; + regs->exit_result = ret; #endif - return regs->exit_flags; + return ret; } #ifdef CONFIG_PPC64 notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *regs) { + unsigned long ret; + /* * This is called when detecting a soft-pending interrupt as well as * an alternate-return interrupt. So we can't just have the alternate @@ -167,9 +171,11 @@ again: } kuap_user_restore(regs); - regs->exit_result |= regs->exit_flags; + ret = current_thread_info()->exit_flags & _TIF_RESTOREALL; + current_thread_info()->exit_flags &= ~_TIF_RESTOREALL; + regs->exit_result |= ret; - return regs->exit_result; + return ret; } #endif @@ -186,8 +192,10 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs) */ kuap_assert_locked(); + /* Clear exit_flags so only flags set during this exit are visible */ + current_thread_info()->exit_flags = 0; + local_irq_disable(); - regs->exit_flags = 0; again: check_return_regs_valid(regs); user_enter_irqoff(); @@ -200,9 +208,7 @@ again: /* Restore user access locks last */ kuap_user_restore(regs); - - ret = regs->exit_flags; - + ret = current_thread_info()->exit_flags & _TIF_RESTOREALL; #ifdef CONFIG_PPC64 regs->exit_result = ret; #endif diff --git a/arch/powerpc/kernel/ptrace/ptrace.c b/arch/powerpc/kernel/ptrace/ptrace.c index 316d4f5ead8e..6cd180bc36ab 100644 --- a/arch/powerpc/kernel/ptrace/ptrace.c +++ b/arch/powerpc/kernel/ptrace/ptrace.c @@ -291,7 +291,6 @@ void __init pt_regs_check(void) CHECK_REG(PT_DAR, dar); CHECK_REG(PT_DSISR, dsisr); CHECK_REG(PT_RESULT, result); - CHECK_REG(PT_EXIT_FLAGS, exit_flags); #undef CHECK_REG BUILD_BUG_ON(PT_REGS_COUNT != sizeof(struct user_pt_regs) / sizeof(unsigned long)); diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index bb42a8b6c642..cc6498501610 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -356,6 +356,6 @@ void signal_fault(struct task_struct *tsk, struct pt_regs *regs, void arch_do_signal_or_restart(struct pt_regs *regs) { BUG_ON(regs != current->thread.regs); - regs->exit_flags |= _TIF_RESTOREALL; + current_thread_info()->exit_flags |= _TIF_RESTOREALL; do_signal(current); } diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index e3822f36c419..1d2db6d3e226 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -1023,10 +1023,7 @@ static int thread_imc_event_init(struct perf_event *event) static bool is_thread_imc_pmu(struct perf_event *event) { - if (!strncmp(event->pmu->name, "thread_imc", strlen("thread_imc"))) - return true; - - return false; + return strstarts(event->pmu->name, "thread_imc"); } static __be64 *get_event_base_addr(struct perf_event *event) diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 20fc5b68faee..315a32fd75b1 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -615,6 +615,7 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, fail_map: for (iopage--; 0 <= iopage; iopage--) { + offset = (1 << r->page_size) * iopage; lv1_put_iopte(0, c->bus_addr + offset, c->lpar_addr + offset, diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index e4e0b45e1b9d..a71c0b0cfb07 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -191,8 +191,6 @@ static void spu_unmap(struct spu *spu) static int __init setup_areas(struct spu *spu) { - struct table {char* name; unsigned long addr; unsigned long size;}; - spu_pdata(spu)->shadow = ioremap_prot(spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), pgprot_noncached_wc(PAGE_KERNEL_RO)); diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 431be156ca9b..29f7c97ff193 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -20,12 +20,15 @@ void pseries_kexec_cpu_down(int crash_shutdown, int secondary) { /* - * Don't risk a hypervisor call if we're crashing - * XXX: Why? The hypervisor is not crashing. It might be better - * to at least attempt unregister to avoid the hypervisor stepping - * on our memory. + * Ensure vpa/slb_shadow/dtl cleanup even while we are crashing. + * Why? The hypervisor is not crashing so at least attempt unregister to + * avoid the hypervisor stepping on our memory. If hypervisor or kexec + * kernel steps on the old memory allocated to these areas before the + * new kexec-kernel happens to allocate and register new areas, + * the hypervisor will see invalid content which may cause + * unexpected behavior. */ - if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { + if (firmware_has_feature(FW_FEATURE_SPLPAR)) { int ret; int cpu = smp_processor_id(); int hwcpu = hard_smp_processor_id(); diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index db99725e752b..bf3d7ed3be01 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -128,7 +128,12 @@ static void smp_setup_cpu(int cpu) else if (cpu != boot_cpuid) xics_setup_cpu(); - if (firmware_has_feature(FW_FEATURE_SPLPAR)) + /* + * Initialize VPA on non-boot cpus since boot-cpu vpa was + * already initialized in pSeries_setup_arch() + */ + if (firmware_has_feature(FW_FEATURE_SPLPAR) && + cpu != boot_cpuid) vpa_init(cpu); cpumask_clear_cpu(cpu, of_spin_mask); |
