Commit 70609c14 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'powerpc-6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc fixes from Michael Ellerman:

 - Fix 32-bit syscall wrappers with 64-bit arguments of unaligned
   register-pairs. Notably this broke ftruncate64 & pread/write64, which
   can lead to file corruption.

 - Fix lost interrupts when returning to soft-masked context on 64-bit.

 - Fix build failure when CONFIG_DTL=n.

Thanks to Nicholas Piggin, Jason A. Donenfeld, Guenter Roeck, Arnd
Bergmann, and Sachin Sant.

* tag 'powerpc-6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/pseries: Fix CONFIG_DTL=n build
  powerpc/64s/interrupt: Fix lost interrupts when returning to soft-masked context
  powerpc/32: fix syscall wrappers with 64-bit arguments of unaligned register-pairs
parents 2130b87b 90d5ce82
...@@ -89,6 +89,22 @@ long compat_sys_rt_sigreturn(void); ...@@ -89,6 +89,22 @@ long compat_sys_rt_sigreturn(void);
* responsible for combining parameter pairs. * responsible for combining parameter pairs.
*/ */
#ifdef CONFIG_PPC32
long sys_ppc_pread64(unsigned int fd,
char __user *ubuf, compat_size_t count,
u32 reg6, u32 pos1, u32 pos2);
long sys_ppc_pwrite64(unsigned int fd,
const char __user *ubuf, compat_size_t count,
u32 reg6, u32 pos1, u32 pos2);
long sys_ppc_readahead(int fd, u32 r4,
u32 offset1, u32 offset2, u32 count);
long sys_ppc_truncate64(const char __user *path, u32 reg4,
unsigned long len1, unsigned long len2);
long sys_ppc_ftruncate64(unsigned int fd, u32 reg4,
unsigned long len1, unsigned long len2);
long sys_ppc32_fadvise64(int fd, u32 unused, u32 offset1, u32 offset2,
size_t len, int advice);
#endif
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
long compat_sys_mmap2(unsigned long addr, size_t len, long compat_sys_mmap2(unsigned long addr, size_t len,
unsigned long prot, unsigned long flags, unsigned long prot, unsigned long flags,
......
...@@ -73,6 +73,7 @@ obj-y := cputable.o syscalls.o \ ...@@ -73,6 +73,7 @@ obj-y := cputable.o syscalls.o \
obj-y += ptrace/ obj-y += ptrace/
obj-$(CONFIG_PPC64) += setup_64.o irq_64.o\ obj-$(CONFIG_PPC64) += setup_64.o irq_64.o\
paca.o nvram_64.o note.o paca.o nvram_64.o note.o
obj-$(CONFIG_PPC32) += sys_ppc32.o
obj-$(CONFIG_COMPAT) += sys_ppc32.o signal_32.o obj-$(CONFIG_COMPAT) += sys_ppc32.o signal_32.o
obj-$(CONFIG_VDSO32) += vdso32_wrapper.o obj-$(CONFIG_VDSO32) += vdso32_wrapper.o
obj-$(CONFIG_PPC_WATCHDOG) += watchdog.o obj-$(CONFIG_PPC_WATCHDOG) += watchdog.o
......
...@@ -538,7 +538,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel) ...@@ -538,7 +538,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel)
beq .Lfast_kernel_interrupt_return_\srr\() // EE already disabled beq .Lfast_kernel_interrupt_return_\srr\() // EE already disabled
lbz r11,PACAIRQHAPPENED(r13) lbz r11,PACAIRQHAPPENED(r13)
andi. r10,r11,PACA_IRQ_MUST_HARD_MASK andi. r10,r11,PACA_IRQ_MUST_HARD_MASK
beq 1f // No HARD_MASK pending beq .Lfast_kernel_interrupt_return_\srr\() // No HARD_MASK pending
/* Must clear MSR_EE from _MSR */ /* Must clear MSR_EE from _MSR */
#ifdef CONFIG_PPC_BOOK3S #ifdef CONFIG_PPC_BOOK3S
...@@ -555,12 +555,23 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel) ...@@ -555,12 +555,23 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel)
b .Lfast_kernel_interrupt_return_\srr\() b .Lfast_kernel_interrupt_return_\srr\()
.Linterrupt_return_\srr\()_soft_enabled: .Linterrupt_return_\srr\()_soft_enabled:
/*
* In the soft-enabled case, need to double-check that we have no
* pending interrupts that might have come in before we reached the
* restart section of code, and restart the exit so those can be
* handled.
*
* If there are none, it is be possible that the interrupt still
* has PACA_IRQ_HARD_DIS set, which needs to be cleared for the
* interrupted context. This clear will not clobber a new pending
* interrupt coming in, because we're in the restart section, so
* such would return to the restart location.
*/
#ifdef CONFIG_PPC_BOOK3S #ifdef CONFIG_PPC_BOOK3S
lbz r11,PACAIRQHAPPENED(r13) lbz r11,PACAIRQHAPPENED(r13)
andi. r11,r11,(~PACA_IRQ_HARD_DIS)@l andi. r11,r11,(~PACA_IRQ_HARD_DIS)@l
bne- interrupt_return_\srr\()_kernel_restart bne- interrupt_return_\srr\()_kernel_restart
#endif #endif
1:
li r11,0 li r11,0
stb r11,PACAIRQHAPPENED(r13) // clear the possible HARD_DIS stb r11,PACAIRQHAPPENED(r13) // clear the possible HARD_DIS
......
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* sys_ppc32.c: Conversion between 32bit and 64bit native syscalls. * sys_ppc32.c: 32-bit system calls with complex calling conventions.
* *
* Copyright (C) 2001 IBM * Copyright (C) 2001 IBM
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* *
* These routines maintain argument size conversion between 32bit and 64bit * 32-bit system calls with 64-bit arguments pass those in register pairs.
* environment. * This must be specially dealt with on 64-bit kernels. The compat_arg_u64_dual
* in generic compat syscalls is not always usable because the register
* pairing is constrained depending on preceding arguments.
*
* An analogous problem exists on 32-bit kernels with ARCH_HAS_SYSCALL_WRAPPER,
* the defined system call functions take the pt_regs as an argument, and there
* is a mapping macro which maps registers to arguments
* (SC_POWERPC_REGS_TO_ARGS) which also does not deal with these 64-bit
* arguments.
*
* This file contains these system calls.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -47,7 +57,17 @@ ...@@ -47,7 +57,17 @@
#include <asm/syscalls.h> #include <asm/syscalls.h>
#include <asm/switch_to.h> #include <asm/switch_to.h>
COMPAT_SYSCALL_DEFINE6(ppc_pread64, #ifdef CONFIG_PPC32
#define PPC32_SYSCALL_DEFINE4 SYSCALL_DEFINE4
#define PPC32_SYSCALL_DEFINE5 SYSCALL_DEFINE5
#define PPC32_SYSCALL_DEFINE6 SYSCALL_DEFINE6
#else
#define PPC32_SYSCALL_DEFINE4 COMPAT_SYSCALL_DEFINE4
#define PPC32_SYSCALL_DEFINE5 COMPAT_SYSCALL_DEFINE5
#define PPC32_SYSCALL_DEFINE6 COMPAT_SYSCALL_DEFINE6
#endif
PPC32_SYSCALL_DEFINE6(ppc_pread64,
unsigned int, fd, unsigned int, fd,
char __user *, ubuf, compat_size_t, count, char __user *, ubuf, compat_size_t, count,
u32, reg6, u32, pos1, u32, pos2) u32, reg6, u32, pos1, u32, pos2)
...@@ -55,7 +75,7 @@ COMPAT_SYSCALL_DEFINE6(ppc_pread64, ...@@ -55,7 +75,7 @@ COMPAT_SYSCALL_DEFINE6(ppc_pread64,
return ksys_pread64(fd, ubuf, count, merge_64(pos1, pos2)); return ksys_pread64(fd, ubuf, count, merge_64(pos1, pos2));
} }
COMPAT_SYSCALL_DEFINE6(ppc_pwrite64, PPC32_SYSCALL_DEFINE6(ppc_pwrite64,
unsigned int, fd, unsigned int, fd,
const char __user *, ubuf, compat_size_t, count, const char __user *, ubuf, compat_size_t, count,
u32, reg6, u32, pos1, u32, pos2) u32, reg6, u32, pos1, u32, pos2)
...@@ -63,28 +83,28 @@ COMPAT_SYSCALL_DEFINE6(ppc_pwrite64, ...@@ -63,28 +83,28 @@ COMPAT_SYSCALL_DEFINE6(ppc_pwrite64,
return ksys_pwrite64(fd, ubuf, count, merge_64(pos1, pos2)); return ksys_pwrite64(fd, ubuf, count, merge_64(pos1, pos2));
} }
COMPAT_SYSCALL_DEFINE5(ppc_readahead, PPC32_SYSCALL_DEFINE5(ppc_readahead,
int, fd, u32, r4, int, fd, u32, r4,
u32, offset1, u32, offset2, u32, count) u32, offset1, u32, offset2, u32, count)
{ {
return ksys_readahead(fd, merge_64(offset1, offset2), count); return ksys_readahead(fd, merge_64(offset1, offset2), count);
} }
COMPAT_SYSCALL_DEFINE4(ppc_truncate64, PPC32_SYSCALL_DEFINE4(ppc_truncate64,
const char __user *, path, u32, reg4, const char __user *, path, u32, reg4,
unsigned long, len1, unsigned long, len2) unsigned long, len1, unsigned long, len2)
{ {
return ksys_truncate(path, merge_64(len1, len2)); return ksys_truncate(path, merge_64(len1, len2));
} }
COMPAT_SYSCALL_DEFINE4(ppc_ftruncate64, PPC32_SYSCALL_DEFINE4(ppc_ftruncate64,
unsigned int, fd, u32, reg4, unsigned int, fd, u32, reg4,
unsigned long, len1, unsigned long, len2) unsigned long, len1, unsigned long, len2)
{ {
return ksys_ftruncate(fd, merge_64(len1, len2)); return ksys_ftruncate(fd, merge_64(len1, len2));
} }
COMPAT_SYSCALL_DEFINE6(ppc32_fadvise64, PPC32_SYSCALL_DEFINE6(ppc32_fadvise64,
int, fd, u32, unused, u32, offset1, u32, offset2, int, fd, u32, unused, u32, offset1, u32, offset2,
size_t, len, int, advice) size_t, len, int, advice)
{ {
......
...@@ -228,8 +228,10 @@ ...@@ -228,8 +228,10 @@
176 64 rt_sigtimedwait sys_rt_sigtimedwait 176 64 rt_sigtimedwait sys_rt_sigtimedwait
177 nospu rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo 177 nospu rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
178 nospu rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend 178 nospu rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
179 common pread64 sys_pread64 compat_sys_ppc_pread64 179 32 pread64 sys_ppc_pread64 compat_sys_ppc_pread64
180 common pwrite64 sys_pwrite64 compat_sys_ppc_pwrite64 179 64 pread64 sys_pread64
180 32 pwrite64 sys_ppc_pwrite64 compat_sys_ppc_pwrite64
180 64 pwrite64 sys_pwrite64
181 common chown sys_chown 181 common chown sys_chown
182 common getcwd sys_getcwd 182 common getcwd sys_getcwd
183 common capget sys_capget 183 common capget sys_capget
...@@ -242,10 +244,11 @@ ...@@ -242,10 +244,11 @@
188 common putpmsg sys_ni_syscall 188 common putpmsg sys_ni_syscall
189 nospu vfork sys_vfork 189 nospu vfork sys_vfork
190 common ugetrlimit sys_getrlimit compat_sys_getrlimit 190 common ugetrlimit sys_getrlimit compat_sys_getrlimit
191 common readahead sys_readahead compat_sys_ppc_readahead 191 32 readahead sys_ppc_readahead compat_sys_ppc_readahead
191 64 readahead sys_readahead
192 32 mmap2 sys_mmap2 compat_sys_mmap2 192 32 mmap2 sys_mmap2 compat_sys_mmap2
193 32 truncate64 sys_truncate64 compat_sys_ppc_truncate64 193 32 truncate64 sys_ppc_truncate64 compat_sys_ppc_truncate64
194 32 ftruncate64 sys_ftruncate64 compat_sys_ppc_ftruncate64 194 32 ftruncate64 sys_ppc_ftruncate64 compat_sys_ppc_ftruncate64
195 32 stat64 sys_stat64 195 32 stat64 sys_stat64
196 32 lstat64 sys_lstat64 196 32 lstat64 sys_lstat64
197 32 fstat64 sys_fstat64 197 32 fstat64 sys_fstat64
...@@ -288,7 +291,8 @@ ...@@ -288,7 +291,8 @@
230 common io_submit sys_io_submit compat_sys_io_submit 230 common io_submit sys_io_submit compat_sys_io_submit
231 common io_cancel sys_io_cancel 231 common io_cancel sys_io_cancel
232 nospu set_tid_address sys_set_tid_address 232 nospu set_tid_address sys_set_tid_address
233 common fadvise64 sys_fadvise64 compat_sys_ppc32_fadvise64 233 32 fadvise64 sys_ppc32_fadvise64 compat_sys_ppc32_fadvise64
233 64 fadvise64 sys_fadvise64
234 nospu exit_group sys_exit_group 234 nospu exit_group sys_exit_group
235 nospu lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie 235 nospu lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
236 common epoll_create sys_epoll_create 236 common epoll_create sys_epoll_create
......
...@@ -7,7 +7,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ ...@@ -7,7 +7,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
setup.o iommu.o event_sources.o ras.o \ setup.o iommu.o event_sources.o ras.o \
firmware.o power.o dlpar.o mobility.o rng.o \ firmware.o power.o dlpar.o mobility.o rng.o \
pci.o pci_dlpar.o eeh_pseries.o msi.o \ pci.o pci_dlpar.o eeh_pseries.o msi.o \
papr_platform_attributes.o papr_platform_attributes.o dtl.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_KEXEC_CORE) += kexec.o obj-$(CONFIG_KEXEC_CORE) += kexec.o
obj-$(CONFIG_PSERIES_ENERGY) += pseries_energy.o obj-$(CONFIG_PSERIES_ENERGY) += pseries_energy.o
...@@ -19,7 +19,6 @@ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o ...@@ -19,7 +19,6 @@ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_HVCS) += hvcserver.o
obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_DTL) += dtl.o
obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o
obj-$(CONFIG_LPARCFG) += lparcfg.o obj-$(CONFIG_LPARCFG) += lparcfg.o
obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_IBMVIO) += vio.o
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <asm/plpar_wrappers.h> #include <asm/plpar_wrappers.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#ifdef CONFIG_DTL
struct dtl { struct dtl {
struct dtl_entry *buf; struct dtl_entry *buf;
int cpu; int cpu;
...@@ -57,78 +58,6 @@ static DEFINE_PER_CPU(struct dtl_ring, dtl_rings); ...@@ -57,78 +58,6 @@ static DEFINE_PER_CPU(struct dtl_ring, dtl_rings);
static atomic_t dtl_count; static atomic_t dtl_count;
/*
* Scan the dispatch trace log and count up the stolen time.
* Should be called with interrupts disabled.
*/
static notrace u64 scan_dispatch_log(u64 stop_tb)
{
u64 i = local_paca->dtl_ridx;
struct dtl_entry *dtl = local_paca->dtl_curr;
struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
struct lppaca *vpa = local_paca->lppaca_ptr;
u64 tb_delta;
u64 stolen = 0;
u64 dtb;
if (!dtl)
return 0;
if (i == be64_to_cpu(vpa->dtl_idx))
return 0;
while (i < be64_to_cpu(vpa->dtl_idx)) {
dtb = be64_to_cpu(dtl->timebase);
tb_delta = be32_to_cpu(dtl->enqueue_to_dispatch_time) +
be32_to_cpu(dtl->ready_to_enqueue_time);
barrier();
if (i + N_DISPATCH_LOG < be64_to_cpu(vpa->dtl_idx)) {
/* buffer has overflowed */
i = be64_to_cpu(vpa->dtl_idx) - N_DISPATCH_LOG;
dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG);
continue;
}
if (dtb > stop_tb)
break;
if (dtl_consumer)
dtl_consumer(dtl, i);
stolen += tb_delta;
++i;
++dtl;
if (dtl == dtl_end)
dtl = local_paca->dispatch_log;
}
local_paca->dtl_ridx = i;
local_paca->dtl_curr = dtl;
return stolen;
}
/*
* Accumulate stolen time by scanning the dispatch trace log.
* Called on entry from user mode.
*/
void notrace pseries_accumulate_stolen_time(void)
{
u64 sst, ust;
struct cpu_accounting_data *acct = &local_paca->accounting;
sst = scan_dispatch_log(acct->starttime_user);
ust = scan_dispatch_log(acct->starttime);
acct->stime -= sst;
acct->utime -= ust;
acct->steal_time += ust + sst;
}
u64 pseries_calculate_stolen_time(u64 stop_tb)
{
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
return 0;
if (get_paca()->dtl_ridx != be64_to_cpu(get_lppaca()->dtl_idx))
return scan_dispatch_log(stop_tb);
return 0;
}
/* /*
* The cpu accounting code controls the DTL ring buffer, and we get * The cpu accounting code controls the DTL ring buffer, and we get
* given entries as they are processed. * given entries as they are processed.
...@@ -436,3 +365,81 @@ static int dtl_init(void) ...@@ -436,3 +365,81 @@ static int dtl_init(void)
return 0; return 0;
} }
machine_arch_initcall(pseries, dtl_init); machine_arch_initcall(pseries, dtl_init);
#endif /* CONFIG_DTL */
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
/*
* Scan the dispatch trace log and count up the stolen time.
* Should be called with interrupts disabled.
*/
static notrace u64 scan_dispatch_log(u64 stop_tb)
{
u64 i = local_paca->dtl_ridx;
struct dtl_entry *dtl = local_paca->dtl_curr;
struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
struct lppaca *vpa = local_paca->lppaca_ptr;
u64 tb_delta;
u64 stolen = 0;
u64 dtb;
if (!dtl)
return 0;
if (i == be64_to_cpu(vpa->dtl_idx))
return 0;
while (i < be64_to_cpu(vpa->dtl_idx)) {
dtb = be64_to_cpu(dtl->timebase);
tb_delta = be32_to_cpu(dtl->enqueue_to_dispatch_time) +
be32_to_cpu(dtl->ready_to_enqueue_time);
barrier();
if (i + N_DISPATCH_LOG < be64_to_cpu(vpa->dtl_idx)) {
/* buffer has overflowed */
i = be64_to_cpu(vpa->dtl_idx) - N_DISPATCH_LOG;
dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG);
continue;
}
if (dtb > stop_tb)
break;
#ifdef CONFIG_DTL
if (dtl_consumer)
dtl_consumer(dtl, i);
#endif
stolen += tb_delta;
++i;
++dtl;
if (dtl == dtl_end)
dtl = local_paca->dispatch_log;
}
local_paca->dtl_ridx = i;
local_paca->dtl_curr = dtl;
return stolen;
}
/*
* Accumulate stolen time by scanning the dispatch trace log.
* Called on entry from user mode.
*/
void notrace pseries_accumulate_stolen_time(void)
{
u64 sst, ust;
struct cpu_accounting_data *acct = &local_paca->accounting;
sst = scan_dispatch_log(acct->starttime_user);
ust = scan_dispatch_log(acct->starttime);
acct->stime -= sst;
acct->utime -= ust;
acct->steal_time += ust + sst;
}
u64 pseries_calculate_stolen_time(u64 stop_tb)
{
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
return 0;
if (get_paca()->dtl_ridx != be64_to_cpu(get_lppaca()->dtl_idx))
return scan_dispatch_log(stop_tb);
return 0;
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment