Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Cross-merge networking fixes after downstream PR (net-7.3-rc6).

Conflicts:

net/mac80211/tx.c
net/mac80211/ieee80211_i.h
  8effab902fa34 ("wifi: mac80211: prevent AP VLAN tx from other interfaces")
  78b843974f ("wifi: mac80211: report multicast transmission from lookup_ra_sta()")
https://lore.kernel.org/arJmcuhpJ69wAvYK@sirena.co.uk

drivers/net/ethernet/realtek/r8169_main.c
  3cdeaef175 ("r8169: disable EEE on RTL8168h/8111h")
  8a3c76523e ("r8169: add support for phylink")
https://lore.kernel.org/ar5vAxEqS8tO8aVT@sirena.org.uk

Adjacent changes:

rust/kernel/net/netlink.rs
  5e59169237 ("rust: net: netlink: Migrate to zerocopy's IntoBytes")
  0923198be4 ("rust: net: netlink: validate attribute length before casting to `c_int`")

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-09-17 14:24:32 -07:00
commit f49defea76
396 changed files with 5794 additions and 1742 deletions

View File

@ -288,6 +288,8 @@ Ed L. Cashin <ecashin@coraid.com>
Elliot Berman <quic_eberman@quicinc.com> <eberman@codeaurora.org> Elliot Berman <quic_eberman@quicinc.com> <eberman@codeaurora.org>
Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com> Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com>
Enric Balletbo i Serra <eballetbo@kernel.org> <eballetbo@iseebcn.com> Enric Balletbo i Serra <eballetbo@kernel.org> <eballetbo@iseebcn.com>
Eric Dumazet <edumazet@kernel.org> <edumazet@google.com>
Eric Dumazet <edumazet@kernel.org> <eric.dumazet@gmail.com>
Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com> Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com>
Ethan Carter Edwards <ethan@ethancedwards.com> Ethan Edwards <ethancarteredwards@gmail.com> Ethan Carter Edwards <ethan@ethancedwards.com> Ethan Edwards <ethancarteredwards@gmail.com>
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@microchip.com> Eugen Hristev <ehristev@kernel.org> <eugen.hristev@microchip.com>

View File

@ -3494,7 +3494,7 @@ Kernel parameters
* SATA link speed limit: 1.5Gbps or 3.0Gbps. * SATA link speed limit: 1.5Gbps or 3.0Gbps.
* Transfer mode: pio[0-7], mwdma[0-4] and udma[0-7]. * Transfer mode: pio[0-6], mwdma[0-4] and udma[0-7].
udma[/][16,25,33,44,66,100,133] notation is also udma[/][16,25,33,44,66,100,133] notation is also
allowed. allowed.
@ -3512,7 +3512,7 @@ Kernel parameters
* [no]ncqtrim: Enable or disable queued DSM TRIM. * [no]ncqtrim: Enable or disable queued DSM TRIM.
* [no]ncqati: Enable or disable NCQ trim on ATI chipset. * [no]ncqati: Enable or disable NCQ on ATI chipsets.
* [no]trim: Enable or disable (unqueued) TRIM. * [no]trim: Enable or disable (unqueued) TRIM.
@ -3543,11 +3543,9 @@ Kernel parameters
* max_sec_128: Set transfer size limit to 128 sectors. * max_sec_128: Set transfer size limit to 128 sectors.
* max_sec_1024: Set or clear transfer size limit to * max_sec_1024: Set transfer size limit to 1024 sectors.
1024 sectors.
* max_sec_lba48: Set or clear transfer size limit to * max_sec_lba48: Set transfer size limit to 65535 sectors.
65535 sectors.
* external: Mark port as external (hotplug-capable). * external: Mark port as external (hotplug-capable).

View File

@ -67,7 +67,7 @@ Entries specific to zPCI functions and entries that hold zPCI information.
A physical function that currently supports a virtual function cannot be A physical function that currently supports a virtual function cannot be
powered off until all virtual functions are removed with: powered off until all virtual functions are removed with:
echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvfs
* /sys/bus/pci/devices/DDDD:BB:dd.f/: * /sys/bus/pci/devices/DDDD:BB:dd.f/:

View File

@ -5143,6 +5143,7 @@ L: netdev@vger.kernel.org
L: openwrt-devel@lists.openwrt.org (subscribers-only) L: openwrt-devel@lists.openwrt.org (subscribers-only)
S: Supported S: Supported
F: Documentation/devicetree/bindings/net/dsa/brcm,b53.yaml F: Documentation/devicetree/bindings/net/dsa/brcm,b53.yaml
F: Documentation/networking/dsa/b53.rst
F: drivers/net/dsa/b53/* F: drivers/net/dsa/b53/*
F: drivers/net/dsa/bcm_sf2* F: drivers/net/dsa/bcm_sf2*
F: include/linux/dsa/brcm.h F: include/linux/dsa/brcm.h
@ -14907,7 +14908,7 @@ M: Damien Le Moal <dlemoal@kernel.org>
M: Niklas Cassel <cassel@kernel.org> M: Niklas Cassel <cassel@kernel.org>
L: linux-ide@vger.kernel.org L: linux-ide@vger.kernel.org
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux.git for-next
F: Documentation/ABI/testing/sysfs-ata F: Documentation/ABI/testing/sysfs-ata
F: Documentation/devicetree/bindings/ata/ F: Documentation/devicetree/bindings/ata/
F: drivers/ata/ F: drivers/ata/
@ -17210,31 +17211,6 @@ F: include/trace/events/ksm.h
F: mm/ksm.c F: mm/ksm.c
F: mm/mm_slot.h F: mm/mm_slot.h
MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Zi Yan <ziy@nvidia.com>
R: Matthew Brost <matthew.brost@intel.com>
R: Joshua Hahn <joshua.hahnjy@gmail.com>
R: Rakie Kim <rakie.kim@sk.com>
R: Byungchul Park <byungchul@sk.com>
R: Gregory Price <gourry@gourry.net>
R: Ying Huang <ying.huang@linux.alibaba.com>
R: Alistair Popple <apopple@nvidia.com>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy-weighted-interleave
F: include/linux/mempolicy.h
F: include/uapi/linux/mempolicy.h
F: include/linux/migrate.h
F: include/linux/migrate_mode.h
F: mm/mempolicy.c
F: mm/migrate.c
F: mm/migrate_device.c
MEMORY MANAGEMENT - MGLRU (MULTI-GEN LRU) MEMORY MANAGEMENT - MGLRU (MULTI-GEN LRU)
M: Andrew Morton <akpm@linux-foundation.org> M: Andrew Morton <akpm@linux-foundation.org>
R: Kairui Song <kasong@tencent.com> R: Kairui Song <kasong@tencent.com>
@ -17257,6 +17233,25 @@ F: include/linux/mmzone.h
F: mm/vmscan.c F: mm/vmscan.c
F: mm/workingset.c F: mm/workingset.c
MEMORY MANAGEMENT - MIGRATION
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
R: Zi Yan <ziy@nvidia.com>
R: Matthew Brost <matthew.brost@intel.com>
R: Joshua Hahn <joshua.hahnjy@gmail.com>
R: Byungchul Park <byungchul@sk.com>
R: Gregory Price <gourry@gourry.net>
R: Ying Huang <ying.huang@linux.alibaba.com>
R: Alistair Popple <apopple@nvidia.com>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F: include/linux/migrate.h
F: include/linux/migrate_mode.h
F: mm/migrate.c
F: mm/migrate_device.c
MEMORY MANAGEMENT - MISC MEMORY MANAGEMENT - MISC
M: Andrew Morton <akpm@linux-foundation.org> M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org> M: David Hildenbrand <david@kernel.org>
@ -17272,7 +17267,6 @@ W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F: Documentation/ABI/testing/sysfs-kernel-mm F: Documentation/ABI/testing/sysfs-kernel-mm
F: Documentation/ABI/testing/sysfs-kernel-mm-cma F: Documentation/ABI/testing/sysfs-kernel-mm-cma
F: Documentation/ABI/testing/sysfs-kernel-mm-memory-tiers
F: Documentation/ABI/testing/sysfs-kernel-mm-numa F: Documentation/ABI/testing/sysfs-kernel-mm-numa
F: Documentation/admin-guide/mm/ F: Documentation/admin-guide/mm/
F: Documentation/mm/ F: Documentation/mm/
@ -17280,7 +17274,6 @@ F: drivers/char/mem.c
F: include/linux/cma.h F: include/linux/cma.h
F: include/linux/dmapool.h F: include/linux/dmapool.h
F: include/linux/ioremap.h F: include/linux/ioremap.h
F: include/linux/memory-tiers.h
F: include/linux/page_idle.h F: include/linux/page_idle.h
F: mm/backing-dev.c F: mm/backing-dev.c
F: mm/cma.c F: mm/cma.c
@ -17292,7 +17285,6 @@ F: mm/early_ioremap.c
F: mm/fadvise.c F: mm/fadvise.c
F: mm/ioremap.c F: mm/ioremap.c
F: mm/mapping_dirty_helpers.c F: mm/mapping_dirty_helpers.c
F: mm/memory-tiers.c
F: mm/page_idle.c F: mm/page_idle.c
F: mm/pgalloc-track.h F: mm/pgalloc-track.h
F: mm/process_vm_access.c F: mm/process_vm_access.c
@ -17309,6 +17301,27 @@ F: mm/numa.c
F: mm/numa_emulation.c F: mm/numa_emulation.c
F: mm/numa_memblks.c F: mm/numa_memblks.c
MEMORY MANAGEMENT - NUMA PLACEMENT
M: Andrew Morton <akpm@linux-foundation.org>
M: David Hildenbrand <david@kernel.org>
M: Gregory Price <gourry@gourry.net>
R: Zi Yan <ziy@nvidia.com>
R: Joshua Hahn <joshua.hahnjy@gmail.com>
R: Rakie Kim <rakie.kim@sk.com>
R: Ying Huang <ying.huang@linux.alibaba.com>
L: linux-mm@kvack.org
S: Maintained
W: http://www.linux-mm.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F: Documentation/ABI/testing/sysfs-kernel-mm-memory-tiers
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy-weighted-interleave
F: include/linux/memory-tiers.h
F: include/linux/mempolicy.h
F: include/uapi/linux/mempolicy.h
F: mm/memory-tiers.c
F: mm/mempolicy.c
MEMORY MANAGEMENT - OOM KILLER MEMORY MANAGEMENT - OOM KILLER
M: Michal Hocko <mhocko@suse.com> M: Michal Hocko <mhocko@suse.com>
R: David Rientjes <rientjes@google.com> R: David Rientjes <rientjes@google.com>
@ -18897,7 +18910,7 @@ F: net/core/drop_monitor.c
NETWORKING DRIVERS NETWORKING DRIVERS
M: Andrew Lunn <andrew+netdev@lunn.ch> M: Andrew Lunn <andrew+netdev@lunn.ch>
M: "David S. Miller" <davem@davemloft.net> M: "David S. Miller" <davem@davemloft.net>
M: Eric Dumazet <edumazet@google.com> M: Eric Dumazet <edumazet@kernel.org>
M: Jakub Kicinski <kuba@kernel.org> M: Jakub Kicinski <kuba@kernel.org>
M: Paolo Abeni <pabeni@redhat.com> M: Paolo Abeni <pabeni@redhat.com>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
@ -19014,7 +19027,7 @@ K: struct\s+phy_port|phy_port_
NETWORKING [GENERAL] NETWORKING [GENERAL]
M: "David S. Miller" <davem@davemloft.net> M: "David S. Miller" <davem@davemloft.net>
M: Eric Dumazet <edumazet@google.com> M: Eric Dumazet <edumazet@kernel.org>
M: Jakub Kicinski <kuba@kernel.org> M: Jakub Kicinski <kuba@kernel.org>
M: Paolo Abeni <pabeni@redhat.com> M: Paolo Abeni <pabeni@redhat.com>
R: Simon Horman <horms@kernel.org> R: Simon Horman <horms@kernel.org>
@ -19240,7 +19253,7 @@ F: net/ipv6/seg6*
F: tools/testing/selftests/net/srv6* F: tools/testing/selftests/net/srv6*
NETWORKING [TCP] NETWORKING [TCP]
M: Eric Dumazet <edumazet@google.com> M: Eric Dumazet <edumazet@kernel.org>
M: Neal Cardwell <ncardwell@google.com> M: Neal Cardwell <ncardwell@google.com>
R: Kuniyuki Iwashima <kuniyu@google.com> R: Kuniyuki Iwashima <kuniyu@google.com>
L: netdev@vger.kernel.org L: netdev@vger.kernel.org
@ -19273,7 +19286,7 @@ F: net/tls/
F: tools/testing/selftests/net/tls.c F: tools/testing/selftests/net/tls.c
NETWORKING [SOCKETS] NETWORKING [SOCKETS]
M: Eric Dumazet <edumazet@google.com> M: Eric Dumazet <edumazet@kernel.org>
M: Kuniyuki Iwashima <kuniyu@google.com> M: Kuniyuki Iwashima <kuniyu@google.com>
M: Paolo Abeni <pabeni@redhat.com> M: Paolo Abeni <pabeni@redhat.com>
M: Willem de Bruijn <willemb@google.com> M: Willem de Bruijn <willemb@google.com>
@ -20570,6 +20583,7 @@ ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
M: Mark Fasheh <mark@fasheh.com> M: Mark Fasheh <mark@fasheh.com>
M: Joel Becker <jlbec@evilplan.org> M: Joel Becker <jlbec@evilplan.org>
M: Joseph Qi <joseph.qi@linux.alibaba.com> M: Joseph Qi <joseph.qi@linux.alibaba.com>
R: Heming Zhao <heming.zhao@suse.com>
L: ocfs2-devel@lists.linux.dev L: ocfs2-devel@lists.linux.dev
S: Supported S: Supported
W: http://ocfs2.wiki.kernel.org W: http://ocfs2.wiki.kernel.org

View File

@ -2,7 +2,7 @@
VERSION = 7 VERSION = 7
PATCHLEVEL = 3 PATCHLEVEL = 3
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -rc4 EXTRAVERSION = -rc5
NAME = Baby Opossum Posse NAME = Baby Opossum Posse
# *DOCUMENTATION* # *DOCUMENTATION*

View File

@ -331,13 +331,9 @@ config ARC_FPU_SAVE_RESTORE
for floating point exceptions and rounding modes. These are for floating point exceptions and rounding modes. These are
preserved across task context switch when enabled. preserved across task context switch when enabled.
config ARC_CANT_LLSC
def_bool n
config ARC_HAS_LLSC config ARC_HAS_LLSC
bool "Insn: LLOCK/SCOND (efficient atomic ops)" bool "Insn: LLOCK/SCOND (efficient atomic ops)"
default y default y
depends on !ARC_CANT_LLSC
if ISA_ARCV2 if ISA_ARCV2

View File

@ -156,6 +156,12 @@ static inline u64 __arch_cmpxchg64_relaxed(volatile void *ptr, u64 old, u64 new)
} }
#define arch_cmpxchg64_relaxed __arch_cmpxchg64_relaxed #define arch_cmpxchg64_relaxed __arch_cmpxchg64_relaxed
static inline s64 arch_atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new)
{
return arch_cmpxchg64_relaxed(&v->counter, old, new);
}
#define arch_atomic64_cmpxchg_relaxed arch_atomic64_cmpxchg_relaxed
static inline s64 arch_atomic64_xchg(atomic64_t *ptr, s64 new) static inline s64 arch_atomic64_xchg(atomic64_t *ptr, s64 new)
{ {
s64 prev; s64 prev;

View File

@ -46,7 +46,7 @@
__typeof__(*(ptr)) _n_ = (new); \ __typeof__(*(ptr)) _n_ = (new); \
__typeof__(*(ptr)) _prev_; \ __typeof__(*(ptr)) _prev_; \
\ \
switch(sizeof((_p_))) { \ switch (sizeof(*(_p_))) { \
case 1: \ case 1: \
_prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \ _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \
break; \ break; \
@ -102,7 +102,7 @@
__typeof__(ptr) _p_ = (ptr); \ __typeof__(ptr) _p_ = (ptr); \
__typeof__(*(ptr)) _val_ = (val); \ __typeof__(*(ptr)) _val_ = (val); \
\ \
switch(sizeof(*(_p_))) { \ switch (sizeof(*(_p_))) { \
case 4: \ case 4: \
_val_ = __arch_xchg(_p_, _val_); \ _val_ = __arch_xchg(_p_, _val_); \
break; \ break; \

View File

@ -593,6 +593,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
cpu_id); cpu_id);
} else { } else {
freq = clk_get_rate(cpu_clk); freq = clk_get_rate(cpu_clk);
clk_put(cpu_clk);
} }
if (freq) if (freq)
seq_printf(m, "CPU speed\t: %lu.%02lu Mhz\n", seq_printf(m, "CPU speed\t: %lu.%02lu Mhz\n",

View File

@ -12,7 +12,6 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/profile.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/irq.h> #include <linux/irq.h>

View File

@ -322,7 +322,7 @@ struct kvm_arch {
* Stage 2 paging state for VMs with nested S2 using a virtual * Stage 2 paging state for VMs with nested S2 using a virtual
* VMID. * VMID.
*/ */
struct kvm_s2_mmu *nested_mmus; struct kvm_s2_mmu **nested_mmus;
size_t nested_mmus_size; size_t nested_mmus_size;
int nested_mmus_next; int nested_mmus_next;

View File

@ -66,7 +66,8 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)
extern bool forward_smc_trap(struct kvm_vcpu *vcpu); extern bool forward_smc_trap(struct kvm_vcpu *vcpu);
extern bool forward_debug_exception(struct kvm_vcpu *vcpu); extern bool forward_debug_exception(struct kvm_vcpu *vcpu);
extern void kvm_init_nested(struct kvm *kvm); extern int kvm_init_nested(struct kvm *kvm);
extern void kvm_destroy_nested(struct kvm *kvm);
extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu); extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu);
extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu); extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu);
extern struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu); extern struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu);

View File

@ -65,8 +65,7 @@ static inline bool kvm_pkvm_ioctl_allowed(struct kvm *kvm, unsigned int ioctl)
int r; int r;
r = kvm_get_cap_for_kvm_ioctl(ioctl, &ext); r = kvm_get_cap_for_kvm_ioctl(ioctl, &ext);
if (r < 0)
if (WARN_ON_ONCE(r < 0))
return false; return false;
return kvm_pkvm_ext_allowed(kvm, ext); return kvm_pkvm_ext_allowed(kvm, ext);

View File

@ -236,8 +236,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
#endif #endif
kvm_init_nested(kvm);
ret = kvm_share_hyp(kvm, kvm + 1); ret = kvm_share_hyp(kvm, kvm + 1);
if (ret) if (ret)
return ret; return ret;
@ -252,6 +250,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (ret) if (ret)
goto err_free_cpumask; goto err_free_cpumask;
ret = kvm_init_nested(kvm);
if (ret)
goto err_uninit_mmu;
if (is_protected_kvm_enabled()) { if (is_protected_kvm_enabled()) {
/* /*
* If any failures occur after this is successful, make sure to * If any failures occur after this is successful, make sure to
@ -280,6 +282,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
err_uninit_mmu: err_uninit_mmu:
kvm_uninit_stage2_mmu(kvm); kvm_uninit_stage2_mmu(kvm);
kvm_destroy_nested(kvm);
err_free_cpumask: err_free_cpumask:
free_cpumask_var(kvm->arch.supported_cpus); free_cpumask_var(kvm->arch.supported_cpus);
err_unshare_kvm: err_unshare_kvm:
@ -337,6 +340,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_unshare_hyp(kvm, kvm + 1); kvm_unshare_hyp(kvm, kvm + 1);
kvm_destroy_nested(kvm);
kvm_arm_teardown_hypercalls(kvm); kvm_arm_teardown_hypercalls(kvm);
} }
@ -1129,7 +1133,7 @@ static int kvm_vcpu_suspend(struct kvm_vcpu *vcpu)
static int check_vcpu_requests(struct kvm_vcpu *vcpu) static int check_vcpu_requests(struct kvm_vcpu *vcpu)
{ {
if (kvm_request_pending(vcpu)) { if (kvm_request_pending(vcpu)) {
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu))
return -EIO; return -EIO;
if (kvm_check_request(KVM_REQ_SLEEP, vcpu)) if (kvm_check_request(KVM_REQ_SLEEP, vcpu))

View File

@ -1445,7 +1445,7 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
SR_FGT(OP_AT_S1E1A, HFGITR, ATS1E1A, 1), SR_FGT(OP_AT_S1E1A, HFGITR, ATS1E1A, 1),
SR_FGT(OP_COSP_RCTX, HFGITR, COSPRCTX, 1), SR_FGT(OP_COSP_RCTX, HFGITR, COSPRCTX, 1),
SR_FGT(OP_GCSPUSHX, HFGITR, nGCSEPP, 0), SR_FGT(OP_GCSPUSHX, HFGITR, nGCSEPP, 0),
SR_FGT(OP_GCSPOPX, HFGITR, nGCSEPP, 0), SR_FGT(OP_GCSPOPCX, HFGITR, nGCSEPP, 0),
SR_FGT(OP_GCSPUSHM, HFGITR, nGCSPUSHM_EL1, 0), SR_FGT(OP_GCSPUSHM, HFGITR, nGCSPUSHM_EL1, 0),
SR_FGT(OP_BRB_IALL, HFGITR, nBRBIALL, 0), SR_FGT(OP_BRB_IALL, HFGITR, nBRBIALL, 0),
SR_FGT(OP_BRB_INJ, HFGITR, nBRBINJ, 0), SR_FGT(OP_BRB_INJ, HFGITR, nBRBINJ, 0),

View File

@ -52,8 +52,10 @@ int __pkvm_host_test_clear_young_guest(u64 gfn, u64 nr_pages, bool mkold, struct
int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu); int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu);
bool addr_is_memory(phys_addr_t phys); bool addr_is_memory(phys_addr_t phys);
bool addr_is_hyp_text(phys_addr_t phys);
int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot); int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot);
int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id); int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id);
bool host_stage2_pte_is_hyp_owned(kvm_pte_t pte);
int kvm_host_prepare_stage2(void *pgt_pool_base); int kvm_host_prepare_stage2(void *pgt_pool_base);
int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd); int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd);
void kvm_guest_destroy_stage2(struct pkvm_hyp_vm *vm); void kvm_guest_destroy_stage2(struct pkvm_hyp_vm *vm);

View File

@ -29,6 +29,7 @@ int __pkvm_create_private_mapping(phys_addr_t phys, size_t size,
enum kvm_pgtable_prot prot, enum kvm_pgtable_prot prot,
unsigned long *haddr); unsigned long *haddr);
int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr); int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr);
int pkvm_check_host_ownership(void);
int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr); int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr);
#endif /* __KVM_HYP_MM_H */ #endif /* __KVM_HYP_MM_H */

View File

@ -450,6 +450,14 @@ bool addr_is_memory(phys_addr_t phys)
return !!find_mem_range(phys, &range); return !!find_mem_range(phys, &range);
} }
bool addr_is_hyp_text(phys_addr_t phys)
{
phys_addr_t start = ALIGN_DOWN(__hyp_pa(__hyp_text_start), PAGE_SIZE);
phys_addr_t end = PAGE_ALIGN(__hyp_pa(__hyp_text_end));
return phys >= start && phys < end;
}
static bool is_in_mem_range(u64 addr, struct kvm_mem_range *range) static bool is_in_mem_range(u64 addr, struct kvm_mem_range *range)
{ {
return range->start <= addr && addr < range->end; return range->start <= addr && addr < range->end;
@ -633,6 +641,18 @@ int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id)
return ret; return ret;
} }
bool host_stage2_pte_is_hyp_owned(kvm_pte_t pte)
{
if (kvm_pte_valid(pte))
return false;
if (FIELD_GET(KVM_INVALID_PTE_TYPE_MASK, pte) !=
KVM_HOST_INVALID_PTE_TYPE_DONATION)
return false;
return FIELD_GET(KVM_HOST_DONATION_PTE_OWNER_MASK, pte) == PKVM_ID_HYP;
}
#define KVM_HOST_PTE_OWNER_GUEST_HANDLE_MASK GENMASK(15, 0) #define KVM_HOST_PTE_OWNER_GUEST_HANDLE_MASK GENMASK(15, 0)
/* We need 40 bits for the GFN to cover a 52-bit IPA with 4k pages and LPA2 */ /* We need 40 bits for the GFN to cover a 52-bit IPA with 4k pages and LPA2 */
#define KVM_HOST_PTE_OWNER_GUEST_GFN_MASK GENMASK(55, 16) #define KVM_HOST_PTE_OWNER_GUEST_GFN_MASK GENMASK(55, 16)

View File

@ -25,6 +25,7 @@ struct memblock_region hyp_memory[HYP_MEMBLOCK_REGIONS];
unsigned int hyp_memblock_nr; unsigned int hyp_memblock_nr;
static u64 __io_map_base; static u64 __io_map_base;
static u64 __io_map_next;
struct hyp_fixmap_slot { struct hyp_fixmap_slot {
u64 addr; u64 addr;
@ -50,7 +51,7 @@ static int __pkvm_alloc_private_va_range(unsigned long start, size_t size)
hyp_assert_lock_held(&pkvm_pgd_lock); hyp_assert_lock_held(&pkvm_pgd_lock);
if (!start || start < __io_map_base) if (!start || start < __io_map_next)
return -EINVAL; return -EINVAL;
/* The allocated size is always a multiple of PAGE_SIZE */ /* The allocated size is always a multiple of PAGE_SIZE */
@ -60,7 +61,7 @@ static int __pkvm_alloc_private_va_range(unsigned long start, size_t size)
if (cur > __hyp_vmemmap) if (cur > __hyp_vmemmap)
return -ENOMEM; return -ENOMEM;
__io_map_base = cur; __io_map_next = cur;
return 0; return 0;
} }
@ -70,7 +71,7 @@ static int __pkvm_alloc_private_va_range(unsigned long start, size_t size)
* @size: The size of the VA range to reserve. * @size: The size of the VA range to reserve.
* @haddr: The hypervisor virtual start address of the allocation. * @haddr: The hypervisor virtual start address of the allocation.
* *
* The private virtual address (VA) range is allocated above __io_map_base * The private virtual address (VA) range is allocated above __io_map_next
* and aligned based on the order of @size. * and aligned based on the order of @size.
* *
* Return: 0 on success or negative error code on failure. * Return: 0 on success or negative error code on failure.
@ -81,7 +82,7 @@ int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr)
int ret; int ret;
hyp_spin_lock(&pkvm_pgd_lock); hyp_spin_lock(&pkvm_pgd_lock);
addr = __io_map_base; addr = __io_map_next;
ret = __pkvm_alloc_private_va_range(addr, size); ret = __pkvm_alloc_private_va_range(addr, size);
hyp_spin_unlock(&pkvm_pgd_lock); hyp_spin_unlock(&pkvm_pgd_lock);
@ -341,7 +342,7 @@ static int create_fixblock(void)
return -EINVAL; return -EINVAL;
hyp_spin_lock(&pkvm_pgd_lock); hyp_spin_lock(&pkvm_pgd_lock);
addr = ALIGN(__io_map_base, PMD_SIZE); addr = ALIGN(__io_map_next, PMD_SIZE);
ret = __pkvm_alloc_private_va_range(addr, PMD_SIZE); ret = __pkvm_alloc_private_va_range(addr, PMD_SIZE);
if (ret) if (ret)
goto unlock; goto unlock;
@ -426,6 +427,7 @@ int hyp_create_idmap(u32 hyp_va_bits)
*/ */
__io_map_base = start & BIT(hyp_va_bits - 2); __io_map_base = start & BIT(hyp_va_bits - 2);
__io_map_base ^= BIT(hyp_va_bits - 2); __io_map_base ^= BIT(hyp_va_bits - 2);
__io_map_next = __io_map_base;
__hyp_vmemmap = __io_map_base | BIT(hyp_va_bits - 3); __hyp_vmemmap = __io_map_base | BIT(hyp_va_bits - 3);
return __pkvm_create_mappings(start, end - start, start, PAGE_HYP_EXEC); return __pkvm_create_mappings(start, end - start, start, PAGE_HYP_EXEC);
@ -433,19 +435,19 @@ int hyp_create_idmap(u32 hyp_va_bits)
int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr) int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr)
{ {
unsigned long addr, prev_base; unsigned long addr, prev_next;
size_t size; size_t size;
int ret; int ret;
hyp_spin_lock(&pkvm_pgd_lock); hyp_spin_lock(&pkvm_pgd_lock);
prev_base = __io_map_base; prev_next = __io_map_next;
/* /*
* Efficient stack verification using the NVHE_STACK_SHIFT bit implies * Efficient stack verification using the NVHE_STACK_SHIFT bit implies
* an alignment of our allocation on the order of the size. * an alignment of our allocation on the order of the size.
*/ */
size = NVHE_STACK_SIZE * 2; size = NVHE_STACK_SIZE * 2;
addr = ALIGN(__io_map_base, size); addr = ALIGN(__io_map_next, size);
ret = __pkvm_alloc_private_va_range(addr, size); ret = __pkvm_alloc_private_va_range(addr, size);
if (!ret) { if (!ret) {
@ -461,7 +463,7 @@ int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr)
ret = kvm_pgtable_hyp_map(&pkvm_pgtable, addr + NVHE_STACK_SIZE, ret = kvm_pgtable_hyp_map(&pkvm_pgtable, addr + NVHE_STACK_SIZE,
NVHE_STACK_SIZE, phys, PAGE_HYP); NVHE_STACK_SIZE, phys, PAGE_HYP);
if (ret) if (ret)
__io_map_base = prev_base; __io_map_next = prev_next;
} }
hyp_spin_unlock(&pkvm_pgd_lock); hyp_spin_unlock(&pkvm_pgd_lock);
@ -470,6 +472,65 @@ int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr)
return ret; return ret;
} }
static int check_page_ownership(phys_addr_t phys)
{
kvm_pte_t pte;
bool host_ok;
int ret;
if (addr_is_memory(phys)) {
struct hyp_page *page = hyp_phys_to_page(phys);
if (get_hyp_state(page) != PKVM_PAGE_OWNED ||
get_host_state(page) != PKVM_NOPAGE)
return -EPERM;
}
ret = kvm_pgtable_get_leaf(&host_mmu.pgt, phys, &pte, NULL);
if (ret)
return ret;
/* Hyp text may stay host-readable, see fix_host_ownership_walker(). */
if (kvm_pte_valid(pte) && addr_is_hyp_text(phys))
host_ok = !(kvm_pgtable_stage2_pte_prot(pte) & KVM_PGTABLE_PROT_W);
else
host_ok = host_stage2_pte_is_hyp_owned(pte);
return host_ok ? 0 : -EPERM;
}
static int check_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
enum kvm_pgtable_walk_flags visit)
{
phys_addr_t phys, end;
int ret;
if (!kvm_pte_valid(ctx->old))
return 0;
phys = kvm_pte_to_phys(ctx->old);
end = phys + kvm_granule_size(ctx->level);
for (; phys < end; phys += PAGE_SIZE) {
ret = check_page_ownership(phys);
if (ret)
return ret;
}
return 0;
}
int pkvm_check_host_ownership(void)
{
struct kvm_pgtable_walker walker = {
.cb = check_host_ownership_walker,
.flags = KVM_PGTABLE_WALK_LEAF,
};
/* The private range and the vmemmap share one quarter of the VA space. */
return kvm_pgtable_walk(&pkvm_pgtable, __io_map_base,
BIT(pkvm_pgtable.ia_bits - 2), &walker);
}
static void *admit_host_page(void *arg) static void *admit_host_page(void *arg)
{ {
struct kvm_hyp_memcache *host_mc = arg; struct kvm_hyp_memcache *host_mc = arg;

View File

@ -360,7 +360,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags)) if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags))
hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1; hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1;
return; goto out;
} }
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE)) if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE))
@ -379,13 +379,14 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_GENERIC)) if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_GENERIC))
set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features); set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features);
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE)) { if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE))
set_bit(KVM_ARM_VCPU_SVE, allowed_features); set_bit(KVM_ARM_VCPU_SVE, allowed_features);
kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
}
bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features, bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features,
allowed_features, KVM_VCPU_MAX_FEATURES); allowed_features, KVM_VCPU_MAX_FEATURES);
out:
__assign_bit(KVM_ARCH_FLAG_GUEST_HAS_SVE, &kvm->arch.flags,
kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_SVE));
} }
static void unpin_host_vcpu(struct kvm_vcpu *host_vcpu) static void unpin_host_vcpu(struct kvm_vcpu *host_vcpu)
@ -398,10 +399,10 @@ static void unpin_host_sve_state(struct pkvm_hyp_vcpu *hyp_vcpu)
{ {
void *sve_state; void *sve_state;
if (!vcpu_has_feature(&hyp_vcpu->vcpu, KVM_ARM_VCPU_SVE)) sve_state = hyp_vcpu->vcpu.arch.sve_state;
if (!sve_state)
return; return;
sve_state = hyp_vcpu->vcpu.arch.sve_state;
hyp_unpin_shared_mem(sve_state, hyp_unpin_shared_mem(sve_state,
sve_state + vcpu_sve_state_size(&hyp_vcpu->vcpu)); sve_state + vcpu_sve_state_size(&hyp_vcpu->vcpu));
} }
@ -450,7 +451,7 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
unsigned int sve_max_vl; unsigned int sve_max_vl;
size_t sve_state_size; size_t sve_state_size;
void *sve_state; void *sve_state;
int ret = 0; int ret;
if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) { if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED); vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED);
@ -459,25 +460,21 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
/* Limit guest vector length to the maximum supported by the host. */ /* Limit guest vector length to the maximum supported by the host. */
sve_max_vl = min(READ_ONCE(host_vcpu->arch.sve_max_vl), kvm_host_sve_max_vl); sve_max_vl = min(READ_ONCE(host_vcpu->arch.sve_max_vl), kvm_host_sve_max_vl);
sve_state_size = sve_state_size_from_vl(sve_max_vl);
sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state)); sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state));
if (!sve_state || !sve_state_size) { if (!sve_vl_valid(sve_max_vl) || !sve_state)
ret = -EINVAL; return -EINVAL;
goto err;
} sve_state_size = sve_state_size_from_vl(sve_max_vl);
ret = hyp_pin_shared_mem(sve_state, sve_state + sve_state_size); ret = hyp_pin_shared_mem(sve_state, sve_state + sve_state_size);
if (ret) if (ret)
goto err; return ret;
vcpu->arch.sve_state = sve_state; vcpu->arch.sve_state = sve_state;
vcpu->arch.sve_max_vl = sve_max_vl; vcpu->arch.sve_max_vl = sve_max_vl;
return 0; return 0;
err:
clear_bit(KVM_ARM_VCPU_SVE, vcpu->kvm->arch.vcpu_features);
return ret;
} }
static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu) static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)

View File

@ -217,7 +217,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
case PKVM_PAGE_OWNED: case PKVM_PAGE_OWNED:
set_hyp_state(page, PKVM_PAGE_OWNED); set_hyp_state(page, PKVM_PAGE_OWNED);
/* hyp text is RO in the host stage-2 to be inspected on panic. */ /* hyp text is RO in the host stage-2 to be inspected on panic. */
if (prot == PAGE_HYP_EXEC) { if (addr_is_hyp_text(phys)) {
set_host_state(page, PKVM_NOPAGE); set_host_state(page, PKVM_NOPAGE);
return host_stage2_idmap_locked(phys, PAGE_SIZE, KVM_PGTABLE_PROT_R); return host_stage2_idmap_locked(phys, PAGE_SIZE, KVM_PGTABLE_PROT_R);
} else { } else {
@ -269,6 +269,16 @@ static int fix_host_ownership(void)
return ret; return ret;
} }
/* The stacks sit in the private VA range, not the linear map. */
for (i = 0; i < hyp_nr_cpus; i++) {
struct kvm_nvhe_init_params *params = per_cpu_ptr(&kvm_init_params, i);
u64 start = params->stack_hyp_va - NVHE_STACK_SIZE;
ret = kvm_pgtable_walk(&pkvm_pgtable, start, NVHE_STACK_SIZE, &walker);
if (ret)
return ret;
}
return 0; return 0;
} }
@ -324,6 +334,10 @@ void __noreturn __pkvm_init_finalise(void)
if (ret) if (ret)
goto out; goto out;
ret = pkvm_check_host_ownership();
if (ret)
goto out;
ret = hyp_ffa_init(ffa_proxy_pages); ret = hyp_ffa_init(ffa_proxy_pages);
if (ret) if (ret)
goto out; goto out;

View File

@ -185,7 +185,8 @@ static int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user
start = filter.base; start = filter.base;
end = start + filter.nr_functions - 1; end = start + filter.nr_functions - 1;
if (end < start || filter.action >= NR_SMCCC_FILTER_ACTIONS) if (!filter.nr_functions || end < start ||
filter.action >= NR_SMCCC_FILTER_ACTIONS)
return -EINVAL; return -EINVAL;
mutex_lock(&kvm->arch.config_lock); mutex_lock(&kvm->arch.config_lock);

View File

@ -59,27 +59,36 @@ static phys_addr_t stage2_range_addr_end(phys_addr_t addr, phys_addr_t end)
* long will also starve other vCPUs. We have to also make sure that the page * long will also starve other vCPUs. We have to also make sure that the page
* tables are not freed while we released the lock. * tables are not freed while we released the lock.
*/ */
static int stage2_apply_range(struct kvm_s2_mmu *mmu, phys_addr_t addr, static int stage2_apply_range(struct kvm_s2_mmu *mmu, phys_addr_t start,
phys_addr_t end, phys_addr_t end,
int (*fn)(struct kvm_pgtable *, u64, u64), int (*fn)(struct kvm_pgtable *, u64, u64),
bool resched) bool resched)
{ {
struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
bool lock_dropped = false;
phys_addr_t addr = start;
int ret; int ret;
u64 next; u64 next;
do { do {
struct kvm_pgtable *pgt = mmu->pgt; struct kvm_pgtable *pgt = mmu->pgt;
/*
* We may be raced on PGT teardown when we release the
* kvm->mmu_lock. That's fine as the PGT is legitimately no
* longer present.
*/
if (!pgt) if (!pgt)
return -EINVAL; return lock_dropped ? 0 : -EINVAL;
next = stage2_range_addr_end(addr, end); next = stage2_range_addr_end(addr, end);
ret = fn(pgt, addr, next - addr); ret = fn(pgt, addr, next - addr);
if (ret) if (ret)
break; break;
if (resched && next != end) if (resched && next != end) {
cond_resched_rwlock_write(&kvm->mmu_lock); cond_resched_rwlock_write(&kvm->mmu_lock);
lock_dropped = true;
}
} while (addr = next, addr != end); } while (addr = next, addr != end);
return ret; return ret;

View File

@ -45,11 +45,24 @@ struct vncr_tlb {
*/ */
#define S2_MMU_PER_VCPU 2 #define S2_MMU_PER_VCPU 2
void kvm_init_nested(struct kvm *kvm) int kvm_init_nested(struct kvm *kvm)
{ {
kvm->arch.nested_mmus = NULL; kvm->arch.nested_mmus = kvmalloc_objs(struct kvm_s2_mmu *,
KVM_MAX_VCPUS * S2_MMU_PER_VCPU,
GFP_KERNEL_ACCOUNT);
kvm->arch.nested_mmus_size = 0; kvm->arch.nested_mmus_size = 0;
atomic_set(&kvm->arch.vncr_tlb_count, 0); atomic_set(&kvm->arch.vncr_tlb_count, 0);
return kvm->arch.nested_mmus ? 0 : -ENOMEM;
}
void kvm_destroy_nested(struct kvm *kvm)
{
for (int i = 0; i < kvm->arch.nested_mmus_size; i+= S2_MMU_PER_VCPU)
kvfree(kvm->arch.nested_mmus[i]);
kvm->arch.nested_mmus_size = 0;
kvfree(kvm->arch.nested_mmus);
} }
static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu) static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
@ -70,8 +83,9 @@ static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu) int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu)
{ {
struct kvm *kvm = vcpu->kvm; struct kvm *kvm = vcpu->kvm;
struct kvm_s2_mmu *tmp; int num_mmus;
int num_mmus, ret = 0;
lockdep_assert_held(&kvm->arch.config_lock);
if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features) && if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features) &&
!cpus_have_final_cap(ARM64_HAS_HCR_NV1)) !cpus_have_final_cap(ARM64_HAS_HCR_NV1))
@ -84,51 +98,40 @@ int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu)
if (!vcpu->arch.ctxt.vncr_array) if (!vcpu->arch.ctxt.vncr_array)
return -ENOMEM; return -ENOMEM;
/*
* Let's treat memory allocation failures as benign: If we fail to
* allocate anything, return an error and keep the allocated array
* alive. Userspace may try to recover by initializing the vcpu
* again, and there is no reason to affect the whole VM for this.
*/
num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU; num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU;
if (num_mmus > kvm->arch.nested_mmus_size) { if (num_mmus > kvm->arch.nested_mmus_size) {
tmp = kvzalloc_objs(*tmp, num_mmus, GFP_KERNEL_ACCOUNT); struct kvm_s2_mmu *tmp;
int i, ret = 0;
tmp = kvzalloc_objs(*tmp, S2_MMU_PER_VCPU, GFP_KERNEL_ACCOUNT);
if (!tmp) if (!tmp)
return -ENOMEM; ret = -ENOMEM;
write_lock(&kvm->mmu_lock); for (i = 0; !ret && i < S2_MMU_PER_VCPU; i++) {
ret = init_nested_s2_mmu(kvm, &tmp[i]);
if (kvm->arch.nested_mmus_size) { if (ret)
memcpy(tmp, kvm->arch.nested_mmus, break;
size_mul(sizeof(*tmp), kvm->arch.nested_mmus_size));
for (int i = 0; i < kvm->arch.nested_mmus_size; i++)
tmp[i].pgt->mmu = &tmp[i];
} }
swap(kvm->arch.nested_mmus, tmp); if (ret) {
while (--i >= 0)
kvm_free_stage2_pgd(&tmp[i]);
write_unlock(&kvm->mmu_lock); kvfree(tmp);
free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
vcpu->arch.ctxt.vncr_array = NULL;
return ret;
}
kvfree(tmp); guard(write_lock)(&kvm->mmu_lock);
for (i = 0; i < S2_MMU_PER_VCPU; i++)
kvm->arch.nested_mmus[i + kvm->arch.nested_mmus_size] = &tmp[i];
kvm->arch.nested_mmus_size += S2_MMU_PER_VCPU;
} }
for (int i = kvm->arch.nested_mmus_size; !ret && i < num_mmus; i++)
ret = init_nested_s2_mmu(kvm, &kvm->arch.nested_mmus[i]);
if (ret) {
for (int i = kvm->arch.nested_mmus_size; i < num_mmus; i++)
kvm_free_stage2_pgd(&kvm->arch.nested_mmus[i]);
free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
vcpu->arch.ctxt.vncr_array = NULL;
return ret;
}
kvm->arch.nested_mmus_size = num_mmus;
return 0; return 0;
} }
@ -742,7 +745,7 @@ void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
write_lock(&kvm->mmu_lock); write_lock(&kvm->mmu_lock);
for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { for (int i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
if (!kvm_s2_mmu_valid(mmu)) if (!kvm_s2_mmu_valid(mmu))
continue; continue;
@ -784,7 +787,7 @@ struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu)
* if S2 translation is disabled. * if S2 translation is disabled.
*/ */
for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { for (int i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
if (!kvm_s2_mmu_valid(mmu)) if (!kvm_s2_mmu_valid(mmu))
continue; continue;
@ -823,7 +826,7 @@ static struct kvm_s2_mmu *get_s2_mmu_nested(struct kvm_vcpu *vcpu)
for (i = kvm->arch.nested_mmus_next; for (i = kvm->arch.nested_mmus_next;
i < (kvm->arch.nested_mmus_size + kvm->arch.nested_mmus_next); i < (kvm->arch.nested_mmus_size + kvm->arch.nested_mmus_next);
i++) { i++) {
s2_mmu = &kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size]; s2_mmu = kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size];
if (atomic_read(&s2_mmu->refcnt) == 0) if (atomic_read(&s2_mmu->refcnt) == 0)
break; break;
@ -1260,6 +1263,17 @@ void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val)
invalidate_vncr_va(vcpu->kvm, &scope); invalidate_vncr_va(vcpu->kvm, &scope);
} }
static void kvm_invalidate_vncr_ipa_all(struct kvm *kvm)
{
struct kvm_pgtable *pgt = kvm->arch.mmu.pgt;
lockdep_assert_held_write(&kvm->mmu_lock);
/* if the mmu lock was dropped, pgt teardown may have raced. */
if (pgt)
kvm_invalidate_vncr_ipa(kvm, 0, BIT(pgt->ia_bits));
}
void kvm_nested_s2_wp(struct kvm *kvm) void kvm_nested_s2_wp(struct kvm *kvm)
{ {
int i; int i;
@ -1270,13 +1284,13 @@ void kvm_nested_s2_wp(struct kvm *kvm)
return; return;
for (i = 0; i < kvm->arch.nested_mmus_size; i++) { for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
if (kvm_s2_mmu_valid(mmu)) if (kvm_s2_mmu_valid(mmu))
kvm_stage2_wp_range(mmu, 0, kvm_phys_size(mmu)); kvm_stage2_wp_range(mmu, 0, kvm_phys_size(mmu));
} }
kvm_invalidate_vncr_ipa(kvm, 0, BIT(kvm->arch.mmu.pgt->ia_bits)); kvm_invalidate_vncr_ipa_all(kvm);
} }
void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block) void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block)
@ -1289,13 +1303,13 @@ void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block)
return; return;
for (i = 0; i < kvm->arch.nested_mmus_size; i++) { for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
if (kvm_s2_mmu_valid(mmu)) if (kvm_s2_mmu_valid(mmu))
kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), may_block); kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), may_block);
} }
kvm_invalidate_vncr_ipa(kvm, 0, BIT(kvm->arch.mmu.pgt->ia_bits)); kvm_invalidate_vncr_ipa_all(kvm);
} }
void kvm_nested_s2_flush(struct kvm *kvm) void kvm_nested_s2_flush(struct kvm *kvm)
@ -1308,7 +1322,7 @@ void kvm_nested_s2_flush(struct kvm *kvm)
return; return;
for (i = 0; i < kvm->arch.nested_mmus_size; i++) { for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
if (kvm_s2_mmu_valid(mmu)) if (kvm_s2_mmu_valid(mmu))
kvm_stage2_flush_range(mmu, 0, kvm_phys_size(mmu)); kvm_stage2_flush_range(mmu, 0, kvm_phys_size(mmu));
@ -1317,17 +1331,12 @@ void kvm_nested_s2_flush(struct kvm *kvm)
void kvm_arch_flush_shadow_all(struct kvm *kvm) void kvm_arch_flush_shadow_all(struct kvm *kvm)
{ {
int i; for (int i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
if (!WARN_ON(atomic_read(&mmu->refcnt))) if (!WARN_ON(atomic_read(&mmu->refcnt)))
kvm_free_stage2_pgd(mmu); kvm_free_stage2_pgd(mmu);
} }
kvfree(kvm->arch.nested_mmus);
kvm->arch.nested_mmus = NULL;
kvm->arch.nested_mmus_size = 0;
kvm_uninit_stage2_mmu(kvm); kvm_uninit_stage2_mmu(kvm);
} }

View File

@ -926,6 +926,7 @@ static u64 *demux_wb_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd)
struct kvm_guest_debug_arch *dbg = &vcpu->arch.vcpu_debug_state; struct kvm_guest_debug_arch *dbg = &vcpu->arch.vcpu_debug_state;
switch (rd->Op2) { switch (rd->Op2) {
case 0b001:
case 0b100: case 0b100:
return &dbg->dbg_bvr[rd->CRm]; return &dbg->dbg_bvr[rd->CRm];
case 0b101: case 0b101:

View File

@ -1658,7 +1658,7 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
unsigned long val) unsigned long val)
{ {
const struct vgic_its_abi *abi = vgic_its_get_abi(its); const struct vgic_its_abi *abi = vgic_its_get_abi(its);
u64 entry_size, table_type; u64 old, entry_size, table_type;
u64 reg, *regptr, clearbits = 0; u64 reg, *regptr, clearbits = 0;
/* When GITS_CTLR.Enable is 1, we ignore write accesses. */ /* When GITS_CTLR.Enable is 1, we ignore write accesses. */
@ -1681,7 +1681,9 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
return; return;
} }
reg = update_64bit_reg(*regptr, addr & 7, len, val); old = *regptr;
reg = update_64bit_reg(old, addr & 7, len, val);
reg &= ~GITS_BASER_RO_MASK; reg &= ~GITS_BASER_RO_MASK;
reg &= ~clearbits; reg &= ~clearbits;
@ -1691,7 +1693,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
*regptr = reg; *regptr = reg;
if (!(reg & GITS_BASER_VALID)) { /* The ITS driver rewrites an unchanged GITS_BASER<n> on resume. */
if (reg != old) {
/* Take the its_lock to prevent a race with a save/restore */ /* Take the its_lock to prevent a race with a save/restore */
mutex_lock(&its->its_lock); mutex_lock(&its->its_lock);
switch (table_type) { switch (table_type) {
@ -1702,6 +1705,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
vgic_its_free_collection_list(kvm, its); vgic_its_free_collection_list(kvm, its);
break; break;
} }
/* A concurrent injection may have cached a translation. */
vgic_its_invalidate_cache(its);
mutex_unlock(&its->its_lock); mutex_unlock(&its->its_lock);
} }
} }
@ -2019,18 +2024,22 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev,
return ret; return ret;
} }
static u32 compute_next_devid_offset(struct list_head *h, static u32 compute_next_devid_offset(struct vgic_its *its, u64 baser,
struct its_device *dev) struct its_device *dev)
{ {
struct its_device *next; struct its_device *next = dev;
u32 next_offset;
if (list_is_last(&dev->dev_list, h)) /*
return 0; * Point at the next device vgic_its_save_device_tables() saves. It
next = list_next_entry(dev, dev_list); * sorts device_list first, so the subtraction cannot underflow.
next_offset = next->device_id - dev->device_id; */
list_for_each_entry_continue(next, &its->device_list, dev_list) {
if (vgic_its_check_id(its, baser, next->device_id, NULL))
return min_t(u32, next->device_id - dev->device_id,
VITS_DTE_MAX_DEVID_OFFSET);
}
return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET); return 0;
} }
static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite) static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
@ -2271,17 +2280,18 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
* vgic_its_save_dte - Save a device table entry at a given GPA * vgic_its_save_dte - Save a device table entry at a given GPA
* *
* @its: ITS handle * @its: ITS handle
* @baser: GITS_BASER<dev> the caller is saving against
* @dev: ITS device * @dev: ITS device
* @ptr: GPA * @ptr: GPA
*/ */
static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev, static int vgic_its_save_dte(struct vgic_its *its, u64 baser,
gpa_t ptr) struct its_device *dev, gpa_t ptr)
{ {
u64 val, itt_addr_field; u64 val, itt_addr_field;
u32 next_offset; u32 next_offset;
itt_addr_field = dev->itt_addr >> 8; itt_addr_field = dev->itt_addr >> 8;
next_offset = compute_next_devid_offset(&its->device_list, dev); next_offset = compute_next_devid_offset(its, baser, dev);
val = (1ULL << KVM_ITS_DTE_VALID_SHIFT | val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) | ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
(itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) | (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
@ -2380,15 +2390,16 @@ static int vgic_its_save_device_tables(struct vgic_its *its)
int ret; int ret;
gpa_t eaddr; gpa_t eaddr;
/* Don't fail a save that userspace must be able to issue. */
if (!vgic_its_check_id(its, baser, if (!vgic_its_check_id(its, baser,
dev->device_id, &eaddr)) dev->device_id, &eaddr))
return -EINVAL; continue;
ret = vgic_its_save_itt(its, dev); ret = vgic_its_save_itt(its, dev);
if (ret) if (ret)
return ret; return ret;
ret = vgic_its_save_dte(its, dev, eaddr); ret = vgic_its_save_dte(its, baser, dev, eaddr);
if (ret) if (ret)
return ret; return ret;
} }
@ -2541,9 +2552,6 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
list_for_each_entry(collection, &its->collection_list, coll_list) { list_for_each_entry(collection, &its->collection_list, coll_list) {
if (!vgic_its_check_id(its, baser, collection->collection_id, NULL))
return -EINVAL;
ret = vgic_its_save_cte(its, collection, gpa); ret = vgic_its_save_cte(its, collection, gpa);
if (ret) if (ret)
return ret; return ret;

View File

@ -188,12 +188,24 @@
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT #define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
#endif #endif
/* VSIP & HVIP relation */ /*
* VSIP & HVIP relation
*
* The bit positions are same between VSIP and HVIP for interrupt
* numbers 13-63, where there's a shift for the SSI, STI and SEI.
*/
#define VSIP_TO_HVIP_SHIFT (IRQ_VS_SOFT - IRQ_S_SOFT) #define VSIP_TO_HVIP_SHIFT (IRQ_VS_SOFT - IRQ_S_SOFT)
#define VSIP_VALID_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \ #define VSIP_BIAS_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \
(_AC(1, UL) << IRQ_S_TIMER) | \ (_AC(1, UL) << IRQ_S_TIMER) | \
(_AC(1, UL) << IRQ_S_EXT) | \ (_AC(1, UL) << IRQ_S_EXT))
(_AC(1, UL) << IRQ_PMU_OVF)) #define VSIP_NO_BIAS_MASK (_AC(1, UL) << IRQ_PMU_OVF)
#define VSIP_VALID_MASK (VSIP_BIAS_MASK | VSIP_NO_BIAS_MASK)
#define vsip_to_hvip(_vsip) ((((_vsip) & VSIP_BIAS_MASK) << \
VSIP_TO_HVIP_SHIFT) | \
((_vsip) & VSIP_NO_BIAS_MASK))
#define hvip_to_vsip(_hvip) ((((_hvip) >> VSIP_TO_HVIP_SHIFT) & \
VSIP_BIAS_MASK) | \
((_hvip) & VSIP_NO_BIAS_MASK))
/* AIA CSR bits */ /* AIA CSR bits */
#define TOPI_IID_SHIFT 16 #define TOPI_IID_SHIFT 16

View File

@ -965,9 +965,14 @@ int kvm_riscv_aia_imsic_rw_attr(struct kvm *kvm, unsigned long type,
if (!vcpu) if (!vcpu)
return -ENODEV; return -ENODEV;
if (mutex_lock_killable(&vcpu->mutex))
return -EINTR;
imsic = vcpu->arch.aia_context.imsic_state; imsic = vcpu->arch.aia_context.imsic_state;
if (!imsic) if (!imsic) {
return -ENODEV; rc = -ENODEV;
goto out_unlock;
}
isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type); isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type);
read_lock_irqsave(&imsic->vsfile_lock, flags); read_lock_irqsave(&imsic->vsfile_lock, flags);
@ -991,6 +996,8 @@ int kvm_riscv_aia_imsic_rw_attr(struct kvm *kvm, unsigned long type,
rc = imsic_vsfile_rw(vsfile_hgei, vsfile_cpu, imsic->nr_eix, rc = imsic_vsfile_rw(vsfile_hgei, vsfile_cpu, imsic->nr_eix,
isel, write, val); isel, write, val);
out_unlock:
mutex_unlock(&vcpu->mutex);
return rc; return rc;
} }

View File

@ -627,6 +627,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
int ret; int ret;
kvm_pfn_t hfn; kvm_pfn_t hfn;
bool is_hugetlb; bool is_hugetlb;
bool unused = false;
bool writable; bool writable;
unsigned int vma_pageshift; unsigned int vma_pageshift;
gfn_t gfn = gpa >> PAGE_SHIFT; gfn_t gfn = gpa >> PAGE_SHIFT;
@ -707,6 +708,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
vma_pageshift, current); vma_pageshift, current);
return 0; return 0;
} }
if (is_sigpending_pfn(hfn))
return -EINTR;
if (is_error_noslot_pfn(hfn)) if (is_error_noslot_pfn(hfn))
return -EFAULT; return -EFAULT;
@ -719,8 +722,10 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
write_lock(&kvm->mmu_lock); write_lock(&kvm->mmu_lock);
if (mmu_invalidate_retry(kvm, mmu_seq)) if (mmu_invalidate_retry(kvm, mmu_seq)) {
unused = true;
goto out_unlock; goto out_unlock;
}
/* /*
* Check if we are backed by a THP and thus use block mapping if * Check if we are backed by a THP and thus use block mapping if
@ -743,7 +748,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
kvm_err("Failed to map in G-stage\n"); kvm_err("Failed to map in G-stage\n");
out_unlock: out_unlock:
kvm_release_faultin_page(kvm, page, ret && ret != -EEXIST, writable); kvm_release_faultin_page(kvm, page,
unused || (ret && ret != -EEXIST), writable);
write_unlock(&kvm->mmu_lock); write_unlock(&kvm->mmu_lock);
return ret; return ret;
} }

View File

@ -42,12 +42,24 @@ void __kvm_riscv_nacl_hfence(void *shmem,
} }
} }
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i); /*
*entp = cpu_to_lelong(control); * Per SBI v3.0 section 15.1.2, the Page_Number and Page_Count
* words must be updated before the Config word with its Pending
* bit set. WRITE_ONCE() stops the compiler from reordering the
* stores and smp_wmb() makes the parameter words globally
* visible to the SBI implementation (or NACL hardware) before
* the Pending bit is set.
*/
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i); entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
*entp = cpu_to_lelong(page_num); WRITE_ONCE(*entp, cpu_to_lelong(page_num));
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i); entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
*entp = cpu_to_lelong(page_count); WRITE_ONCE(*entp, cpu_to_lelong(page_count));
/* Ensure the parameter words are visible before the Pending bit */
smp_wmb();
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
WRITE_ONCE(*entp, cpu_to_lelong(control));
} }
int kvm_riscv_nacl_enable(void) int kvm_riscv_nacl_enable(void)

View File

@ -491,8 +491,7 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
bool ret; bool ret;
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK) ie = vsip_to_hvip(vcpu->arch.guest_csr.vsie) & (unsigned long)mask;
<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK & ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
(unsigned long)mask; (unsigned long)mask;
ret = vcpu->arch.irqs_pending[0] & ie; ret = vcpu->arch.irqs_pending[0] & ie;

View File

@ -283,7 +283,7 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
} }
/* Print details in-case of error */ /* Print details in-case of error */
if (ret < 0) { if (ret < 0 && ret != -EINTR) {
kvm_err("VCPU exit error %d\n", ret); kvm_err("VCPU exit error %d\n", ret);
kvm_err("SEPC=0x%lx SSTATUS=0x%lx HSTATUS=0x%lx\n", kvm_err("SEPC=0x%lx SSTATUS=0x%lx HSTATUS=0x%lx\n",
vcpu->arch.guest_context.sepc, vcpu->arch.guest_context.sepc,

View File

@ -272,7 +272,7 @@ static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,
if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
kvm_riscv_vcpu_flush_interrupts(vcpu); kvm_riscv_vcpu_flush_interrupts(vcpu);
*out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK; *out_val = hvip_to_vsip(csr->hvip);
*out_val |= csr->hvip & ~IRQ_LOCAL_MASK; *out_val |= csr->hvip & ~IRQ_LOCAL_MASK;
} else } else
*out_val = ((unsigned long *)csr)[reg_num]; *out_val = ((unsigned long *)csr)[reg_num];
@ -293,10 +293,8 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
reg_num = array_index_nospec(reg_num, regs_max); reg_num = array_index_nospec(reg_num, regs_max);
if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
reg_val &= VSIP_VALID_MASK; reg_val = vsip_to_hvip(reg_val);
reg_val <<= VSIP_TO_HVIP_SHIFT;
}
((unsigned long *)csr)[reg_num] = reg_val; ((unsigned long *)csr)[reg_num] = reg_val;

View File

@ -270,12 +270,13 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
return -EINVAL; return -EINVAL;
pmc->counter_val = kvpmu->fw_event[fevent_code].value; pmc->counter_val = kvpmu->fw_event[fevent_code].value;
*out_val = pmc->counter_val;
} else if (pmc->perf_event) { } else if (pmc->perf_event) {
pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running); *out_val = pmc->counter_val +
perf_event_read_value(pmc->perf_event, &enabled, &running);
} else { } else {
return -EINVAL; return -EINVAL;
} }
*out_val = pmc->counter_val;
return 0; return 0;
} }
@ -454,6 +455,14 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s
} }
} }
/*
* Clear any previously installed snapshot area to avoid leaking
* the old sdata and to keep sdata/snapshot_addr consistent if
* the re-install fails below.
*/
if (kvpmu->snapshot_addr != INVALID_GPA)
kvm_pmu_clear_snapshot_area(vcpu);
kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC | __GFP_ACCOUNT); kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC | __GFP_ACCOUNT);
if (!kvpmu->sdata) { if (!kvpmu->sdata) {
sbiret = SBI_ERR_FAILURE; sbiret = SBI_ERR_FAILURE;
@ -645,7 +654,6 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
{ {
struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
int i, pmc_index, sbiret = 0; int i, pmc_index, sbiret = 0;
u64 enabled, running;
struct kvm_pmc *pmc; struct kvm_pmc *pmc;
int fevent_code; int fevent_code;
bool snap_flag_set = flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT; bool snap_flag_set = flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT;
@ -675,14 +683,19 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
goto out; goto out;
} }
if (!kvpmu->fw_event[fevent_code].started) if (!kvpmu->fw_event[fevent_code].started) {
sbiret = SBI_ERR_ALREADY_STOPPED; sbiret = SBI_ERR_ALREADY_STOPPED;
} else {
kvpmu->fw_event[fevent_code].started = false; kvpmu->fw_event[fevent_code].started = false;
pmc->counter_val = kvpmu->fw_event[fevent_code].value;
}
} else if (pmc->perf_event) { } else if (pmc->perf_event) {
if (pmc->started) { if (pmc->started) {
/* Stop counting the counter */ /*
perf_event_disable(pmc->perf_event); * Stop the counter and fold the live count into counter_val.
* Reset the event value to avoid redundant accumulation.
*/
pmc->counter_val += perf_event_pause(pmc->perf_event, true);
pmc->started = false; pmc->started = false;
} else { } else {
sbiret = SBI_ERR_ALREADY_STOPPED; sbiret = SBI_ERR_ALREADY_STOPPED;
@ -696,11 +709,6 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
} }
if (snap_flag_set && !sbiret) { if (snap_flag_set && !sbiret) {
if (pmc->cinfo.type == SBI_PMU_CTR_TYPE_FW)
pmc->counter_val = kvpmu->fw_event[fevent_code].value;
else if (pmc->perf_event)
pmc->counter_val += perf_event_read_value(pmc->perf_event,
&enabled, &running);
/* /*
* The counter and overflow indices in the snapshot region are w.r.to * The counter and overflow indices in the snapshot region are w.r.to
* cbase. Modify the set bit in the counter mask instead of the pmc_index * cbase. Modify the set bit in the counter mask instead of the pmc_index
@ -727,9 +735,10 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
} }
} }
if (shmem_needs_update) if (shmem_needs_update &&
kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata, kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata,
sizeof(struct riscv_pmu_snapshot_data)); sizeof(struct riscv_pmu_snapshot_data)))
sbiret = SBI_ERR_FAILURE;
out: out:
retdata->err_val = sbiret; retdata->err_val = sbiret;

View File

@ -95,9 +95,9 @@ static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
ret = kvm_sbi_hsm_vcpu_get_status(vcpu); ret = kvm_sbi_hsm_vcpu_get_status(vcpu);
if (ret >= 0) { if (ret >= 0) {
retdata->out_val = ret; retdata->out_val = ret;
retdata->err_val = 0; ret = 0;
} }
return 0; break;
case SBI_EXT_HSM_HART_SUSPEND: case SBI_EXT_HSM_HART_SUSPEND:
switch (lower_32_bits(cp->a0)) { switch (lower_32_bits(cp->a0)) {
case SBI_HSM_SUSPEND_RET_DEFAULT: case SBI_HSM_SUSPEND_RET_DEFAULT:

View File

@ -61,10 +61,13 @@ static enum hrtimer_restart kvm_riscv_vcpu_hrtimer_expired(struct hrtimer *h)
static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t) static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t)
{ {
if (!t->init_done || !t->next_set) if (!t->init_done)
return -EINVAL; return -EINVAL;
hrtimer_cancel(&t->hrt); hrtimer_cancel(&t->hrt);
if (!t->next_set)
return -EINVAL;
t->next_set = false; t->next_set = false;
return 0; return 0;

View File

@ -460,7 +460,11 @@ static int VNAME(var, active_entries)[EARLY_AREAS] __initdata
#define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view) \ #define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view) \
static int __init VNAME(var, reg)(void) \ static int __init VNAME(var, reg)(void) \
{ \ { \
debug_register_static(&var, (pages), (areas)); \ int rc; \
\
rc = debug_register_static(&var, (pages), (areas)); \
if (rc) \
return rc; \
debug_register_view(&var, (view)); \ debug_register_view(&var, (view)); \
return 0; \ return 0; \
} \ } \
@ -493,7 +497,7 @@ static debug_info_t __refdata var = \
static debug_info_t __used __section(".s390dbf_info") *VNAME(var, info) = &var; \ static debug_info_t __used __section(".s390dbf_info") *VNAME(var, info) = &var; \
__REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view) __REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view)
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas); int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
#endif /* MODULE */ #endif /* MODULE */

View File

@ -434,7 +434,8 @@ static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
debug_info_free(rc); debug_info_free(rc);
} while (1); } while (1);
if (mode == NO_AREAS) /* debug_register_static() failure leaves areas NULL, bounds intact */
if (mode == NO_AREAS || !in->areas)
goto out; goto out;
for (i = 0; i < in->nr_areas; i++) { for (i = 0; i < in->nr_areas; i++) {
@ -823,6 +824,9 @@ ssize_t debug_dump(debug_info_t *id, struct debug_view *view,
file_private_info_t *p_info; file_private_info_t *p_info;
size_t size, offset = 0; size_t size, offset = 0;
if (!id)
return -EINVAL;
/* Need space for '\0' byte */ /* Need space for '\0' byte */
if (buf_size < 1) if (buf_size < 1)
return 0; return 0;
@ -950,8 +954,12 @@ EXPORT_SYMBOL(debug_register);
* *
* Note: This function is called automatically via an initcall generated by * Note: This function is called automatically via an initcall generated by
* DEFINE_STATIC_DEBUG_INFO. * DEFINE_STATIC_DEBUG_INFO.
*
* Return:
* - 0 on success
* - negative error code on failure
*/ */
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas) int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
{ {
unsigned long flags; unsigned long flags;
debug_info_t *copy; debug_info_t *copy;
@ -959,7 +967,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
if (!initialized) { if (!initialized) {
pr_err("Tried to register debug feature %s too early\n", pr_err("Tried to register debug feature %s too early\n",
id->name); id->name);
return; return -EINVAL;
} }
debug_get_param(id->name, &id->level, &pages_per_area, false); debug_get_param(id->name, &id->level, &pages_per_area, false);
@ -975,7 +983,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
id->active_entries = NULL; id->active_entries = NULL;
raw_spin_unlock_irqrestore(&id->lock, flags); raw_spin_unlock_irqrestore(&id->lock, flags);
return; return -ENOMEM;
} }
/* Replace static trace area with dynamic copy. */ /* Replace static trace area with dynamic copy. */
@ -993,6 +1001,8 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
mutex_lock(&debug_mutex); mutex_lock(&debug_mutex);
_debug_register(id); _debug_register(id);
mutex_unlock(&debug_mutex); mutex_unlock(&debug_mutex);
return 0;
} }
/* Remove debugfs entries. */ /* Remove debugfs entries. */

View File

@ -825,7 +825,7 @@ static int find_secret_in_page(const u8 secret_id[UV_SECRET_ID_LEN],
{ {
u16 i; u16 i;
for (i = 0; i < list->total_num_secrets; i++) { for (i = 0; i < list->num_secr_stored; i++) {
if (memcmp(secret_id, list->secrets[i].id, UV_SECRET_ID_LEN) == 0) { if (memcmp(secret_id, list->secrets[i].id, UV_SECRET_ID_LEN) == 0) {
*secret = list->secrets[i].hdr; *secret = list->secrets[i].hdr;
return 0; return 0;
@ -846,11 +846,14 @@ int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
struct uv_secret_list *list, struct uv_secret_list *list,
struct uv_secret_list_item_hdr *secret) struct uv_secret_list_item_hdr *secret)
{ {
u16 start_idx = 0; u16 start_idx;
u16 list_rc; u16 list_rc;
int ret; int ret;
list->next_secret_idx = 0;
do { do {
start_idx = list->next_secret_idx;
uv_list_secrets(list, start_idx, &list_rc, NULL); uv_list_secrets(list, start_idx, &list_rc, NULL);
if (list_rc != UVC_RC_EXECUTED && list_rc != UVC_RC_MORE_DATA) { if (list_rc != UVC_RC_EXECUTED && list_rc != UVC_RC_MORE_DATA) {
if (list_rc == UVC_RC_INV_CMD) if (list_rc == UVC_RC_INV_CMD)
@ -861,7 +864,6 @@ int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
ret = find_secret_in_page(secret_id, list, secret); ret = find_secret_in_page(secret_id, list, secret);
if (ret == 0) if (ret == 0)
return ret; return ret;
start_idx = list->next_secret_idx;
} while (list_rc == UVC_RC_MORE_DATA && start_idx < list->next_secret_idx); } while (list_rc == UVC_RC_MORE_DATA && start_idx < list->next_secret_idx);
return -ENOENT; return -ENOENT;

View File

@ -621,17 +621,20 @@ int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)
union pte *ptep; union pte *ptep;
int rc; int rc;
again:
skey->skey = 0; skey->skey = 0;
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep); rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
if (rc) if (rc)
return rc; return rc;
if (!ptep) { if (!ptep) {
union crste crste; union crste crste = READ_ONCE(*crstep);
crste = READ_ONCE(*crstep); if (!crste_leaf(crste) && !crste.h.i)
if (!crste.h.fc || !crste.s.fc1.pr) goto again;
if (!crste.s.fc1.pr)
return 0; return 0;
skey->skey = page_get_storage_key(large_crste_to_phys(crste, gfn)); skey->skey = page_get_storage_key(large_crste_to_phys(crste, gfn));
return 0; return 0;
} }
@ -662,13 +665,20 @@ int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gf
union pte *ptep; union pte *ptep;
int rc; int rc;
again:
rc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE, rc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
&crstep, &ptep); &crstep, &ptep);
if (rc) if (rc)
return rc; return rc;
if (!ptep) { if (!ptep) {
page_set_storage_key(large_crste_to_phys(*crstep, gfn), skey.skey, !nq); union crste crste = READ_ONCE(*crstep);
/* A large page has been split concurrently, try again */
if (!crste_leaf(crste))
goto again;
page_set_storage_key(large_crste_to_phys(crste, gfn), skey.skey, !nq);
return 0; return 0;
} }
@ -718,15 +728,22 @@ int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gf
union pte *ptep; union pte *ptep;
int rc; int rc;
again:
rc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE, rc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
&crstep, &ptep); &crstep, &ptep);
if (rc) if (rc)
return rc; return rc;
if (!ptep) { if (!ptep) {
union crste crste = READ_ONCE(*crstep);
/* A large page has been split concurrently, try again */
if (!crste_leaf(crste))
goto again;
if (!oldkey) if (!oldkey)
oldkey = &prev; oldkey = &prev;
return page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,
return page_cond_set_storage_key(large_crste_to_phys(crste, gfn), skey, oldkey,
nq, mr, mc); nq, mr, mc);
} }
@ -768,7 +785,7 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
int rc; int rc;
skey->skey = 0; skey->skey = 0;
again:
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep); rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
if (rc) if (rc)
return rc; return rc;
@ -776,9 +793,12 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
if (!ptep) { if (!ptep) {
union crste crste = READ_ONCE(*crstep); union crste crste = READ_ONCE(*crstep);
if (!crste.h.fc || !crste.s.fc1.pr) /* A large page has been split concurrently, try again */
if (!crste_leaf(crste) && !crste.h.i)
goto again;
if (!crste.s.fc1.pr)
return 0; return 0;
skey->skey = page_reset_referenced(large_crste_to_phys(*crstep, gfn)) << 1; skey->skey = page_reset_referenced(large_crste_to_phys(crste, gfn)) << 1;
return 0; return 0;
} }
old = pgste_get_lock(ptep); old = pgste_get_lock(ptep);
@ -846,19 +866,12 @@ long dat_reset_skeys(union asce asce, gfn_t start)
} }
#endif /* KVM_S390_MANAGES_S390_GUEST */ #endif /* KVM_S390_MANAGES_S390_GUEST */
struct slot_priv {
unsigned long token;
struct kvm_s390_mmu_cache *mc;
};
static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk) static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
{ {
struct slot_priv *p = walk->priv;
union crste dummy = { .val = p->token };
union pte new_pte, pte = READ_ONCE(*ptep); union pte new_pte, pte = READ_ONCE(*ptep);
union pgste pgste; union pgste pgste;
new_pte = _PTE_TOK(dummy.tok.type, dummy.tok.par); new_pte = walk->priv ? _PTE_EMPTY : _PTE_TOK(_DAT_TOKEN_PIC, PGM_ADDRESSING);
/* Table entry already in the desired state. */ /* Table entry already in the desired state. */
if (pte.val == new_pte.val) if (pte.val == new_pte.val)
@ -875,10 +888,9 @@ static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_wal
static long _dat_slot_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk) static long _dat_slot_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
{ {
union crste new_crste, crste = READ_ONCE(*crstep); union crste new_crste, crste = READ_ONCE(*crstep);
struct slot_priv *p = walk->priv; struct kvm_s390_mmu_cache *mc = walk->priv;
new_crste.val = p->token; new_crste = mc ? _CRSTE_EMPTY(crste.h.tt) : _CRSTE_HOLE(crste.h.tt);
new_crste.h.tt = crste.h.tt;
/* Table entry already in the desired state. */ /* Table entry already in the desired state. */
if (crste.val == new_crste.val) if (crste.val == new_crste.val)
@ -902,7 +914,10 @@ static long _dat_slot_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct d
if (!crste.h.fc && !crste.h.i) if (!crste.h.fc && !crste.h.i)
return 0; return 0;
/* Split (install a lower level table), and handle things there. */ /* Split (install a lower level table), and handle things there. */
return dat_split_crste(p->mc, crstep, gfn, walk->asce, false); if (mc)
return dat_split_crste(mc, crstep, gfn, walk->asce, false);
/* A large page should never cross memslots boundaries */
return -EINVAL;
} }
static const struct dat_walk_ops dat_slot_ops = { static const struct dat_walk_ops dat_slot_ops = {
@ -910,16 +925,10 @@ static const struct dat_walk_ops dat_slot_ops = {
.crste_ops = { _dat_slot_crste, _dat_slot_crste, _dat_slot_crste, _dat_slot_crste, }, .crste_ops = { _dat_slot_crste, _dat_slot_crste, _dat_slot_crste, _dat_slot_crste, },
}; };
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end, int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end)
u16 type, u16 param)
{ {
struct slot_priv priv = {
.token = _CRSTE_TOK(0, type, param).val,
.mc = mc,
};
return _dat_walk_gfn_range(start, end, asce, &dat_slot_ops, return _dat_walk_gfn_range(start, end, asce, &dat_slot_ops,
DAT_WALK_IGN_HOLES | DAT_WALK_ANY, &priv); DAT_WALK_IGN_HOLES | DAT_WALK_ANY, mc);
} }
static void pgste_set_unlock_multiple(union pte *first, int n, union pgste *pgstes) static void pgste_set_unlock_multiple(union pte *first, int n, union pgste *pgstes)

View File

@ -547,8 +547,7 @@ long dat_reset_skeys(union asce asce, gfn_t start);
unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param); unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param);
void dat_set_ptval(struct page_table *table, struct ptval_param param, unsigned long val); void dat_set_ptval(struct page_table *table, struct ptval_param param, unsigned long val);
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end, int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end);
u16 type, u16 param);
#if KVM_S390_MANAGES_S390_GUEST #if KVM_S390_MANAGES_S390_GUEST
int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn); int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);
@ -973,16 +972,15 @@ static inline int get_level(union crste *crstep, union pte *ptep)
return ptep ? TABLE_TYPE_PAGE_TABLE : crstep->h.tt; return ptep ? TABLE_TYPE_PAGE_TABLE : crstep->h.tt;
} }
static inline int dat_delete_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, static inline int dat_delete_slot(union asce asce, gfn_t start, unsigned long npages)
unsigned long npages)
{ {
return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_PIC, PGM_ADDRESSING); return dat_set_slot(NULL, asce, start, start + npages);
} }
static inline int dat_create_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, static inline int dat_create_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start,
unsigned long npages) unsigned long npages)
{ {
return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_NONE, 0); return dat_set_slot(mc, asce, start, start + npages);
} }
static inline bool crste_is_ucas(union crste crste) static inline bool crste_is_ucas(union crste crste)

View File

@ -994,11 +994,13 @@ static long _destroy_pages_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct da
static long _destroy_pages_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk) static long _destroy_pages_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
{ {
phys_addr_t origin, cur, end; phys_addr_t origin, cur, end;
union crste crste;
if (!crstep->h.fc || !crstep->s.fc1.pr) crste = READ_ONCE(*crstep);
if (!crste.h.fc || !crste.s.fc1.pr)
return 0; return 0;
origin = crste_origin_large(*crstep); origin = crste_origin_large(crste);
cur = ((max(gfn, walk->start) - gfn) << PAGE_SHIFT) + origin; cur = ((max(gfn, walk->start) - gfn) << PAGE_SHIFT) + origin;
end = ((min(next, walk->end) - gfn) << PAGE_SHIFT) + origin; end = ((min(next, walk->end) - gfn) << PAGE_SHIFT) + origin;
for ( ; cur < end; cur += PAGE_SIZE) for ( ; cur < end; cur += PAGE_SIZE)

View File

@ -47,6 +47,9 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *new, struct kvm_memory_slot *new,
enum kvm_mr_change change) enum kvm_mr_change change)
{ {
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
int rc = 0;
if (kvm_is_ucontrol(kvm) && new && new->id < KVM_USER_MEM_SLOTS) if (kvm_is_ucontrol(kvm) && new && new->id < KVM_USER_MEM_SLOTS)
return -EINVAL; return -EINVAL;
@ -61,6 +64,10 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
* and munmap() stuff in this slot after doing this call at any * and munmap() stuff in this slot after doing this call at any
* time. * time.
*/ */
if (change != KVM_MR_MOVE && change != KVM_MR_CREATE) {
WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
return -EINVAL;
}
if (new->userspace_addr & ~PAGE_MASK) if (new->userspace_addr & ~PAGE_MASK)
return -EINVAL; return -EINVAL;
if ((new->base_gfn + new->npages) * PAGE_SIZE > kvm->arch.mem_limit) if ((new->base_gfn + new->npages) * PAGE_SIZE > kvm->arch.mem_limit)
@ -69,65 +76,41 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
return -EINVAL; return -EINVAL;
} }
if (!kvm_s390_is_migration_mode(kvm)) if (kvm->arch.migration_mode) {
return 0; /*
* Turn off migration mode when:
/* * - userspace creates a new memslot with dirty logging off,
* Turn off migration mode when: * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY)
* - userspace creates a new memslot with dirty logging off, * and dirty logging is turned off.
* - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and * Migration mode expects dirty page logging being enabled to
* dirty logging is turned off. * store its dirty bitmap.
* Migration mode expects dirty page logging being enabled to store */
* its dirty bitmap. if (change != KVM_MR_DELETE &&
*/ !(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
if (change != KVM_MR_DELETE && WARN(kvm_s390_vm_stop_migration(kvm),
!(new->flags & KVM_MEM_LOG_DIRTY_PAGES)) "Failed to stop migration mode");
WARN(kvm_s390_vm_stop_migration(kvm), }
"Failed to stop migration mode");
return 0;
}
void s390_kvm_mmu_commit_memory_region(struct kvm *kvm,
struct kvm_memory_slot *old,
const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
int rc = 0;
guard(mutex)(&kvm->slots_arch_lock);
if (change == KVM_MR_FLAGS_ONLY) if (change == KVM_MR_FLAGS_ONLY)
return; return 0;
if (change != KVM_MR_DELETE) {
mc = kvm_s390_new_mmu_cache(); /* Enough capacity to add a new memslot */
if (!mc) { mc = kvm_s390_new_mmu_cache();
rc = -ENOMEM; if (!mc)
goto out; return -ENOMEM;
} }
scoped_guard(write_lock, &kvm->mmu_lock) { scoped_guard(write_lock, &kvm->mmu_lock) {
kvm_s390_update_cmma_dirty(kvm, old); kvm_s390_update_cmma_dirty(kvm, old);
switch (change) { if (change == KVM_MR_DELETE || change == KVM_MR_MOVE)
case KVM_MR_DELETE: rc = dat_delete_slot(kvm->arch.gmap->asce, old->base_gfn, old->npages);
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages); if (!rc && (change == KVM_MR_MOVE || change == KVM_MR_CREATE))
break;
case KVM_MR_MOVE:
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
if (rc)
break;
fallthrough;
case KVM_MR_CREATE:
rc = dat_create_slot(mc, kvm->arch.gmap->asce, new->base_gfn, new->npages); rc = dat_create_slot(mc, kvm->arch.gmap->asce, new->base_gfn, new->npages);
break;
case KVM_MR_FLAGS_ONLY:
break;
default:
WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
}
} }
out: /*
if (rc) * Can only be triggered if dat_{create,delete}_slot() found an
pr_warn("failed to commit memory region\n"); * internal inconsistency or if the mmu cache ran out of memory;
* both should be impossible.
*/
KVM_BUG_ON(rc, kvm);
return rc;
} }

View File

@ -10,9 +10,5 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
const struct kvm_memory_slot *old, const struct kvm_memory_slot *old,
struct kvm_memory_slot *new, struct kvm_memory_slot *new,
enum kvm_mr_change change); enum kvm_mr_change change);
void s390_kvm_mmu_commit_memory_region(struct kvm *kvm,
struct kvm_memory_slot *old,
const struct kvm_memory_slot *new,
enum kvm_mr_change change);
#endif /* ARCH_KVM_GMAP_KVM_MMU_H */ #endif /* ARCH_KVM_GMAP_KVM_MMU_H */

View File

@ -1589,12 +1589,25 @@ static inline int ___gaccess_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg
parent = READ_ONCE(sg->parent); parent = READ_ONCE(sg->parent);
if (!parent) if (!parent)
return -EAGAIN; return -EAGAIN;
retry:
scoped_guard(spinlock, &parent->children_lock) { scoped_guard(spinlock, &parent->children_lock) {
if (READ_ONCE(sg->parent) != parent) if (READ_ONCE(sg->parent) != parent)
return -EAGAIN; return -EAGAIN;
sg->invalidated = false; sg->invalidated = false;
rc = _gaccess_do_shadow(vcpu->arch.mc, sg, saddr, walk); rc = _gaccess_do_shadow(vcpu->arch.mc, sg, saddr, walk);
} }
if (rc == -ENOENT) {
struct kvm_memory_slot *slot;
struct guest_fault *entries;
entries = get_entries(walk);
slot = kvm_vcpu_gfn_to_memslot(vcpu, entries[LEVEL_MEM].gfn);
if (!slot)
return PGM_ADDRESSING;
rc = gmap_link(vcpu->arch.mc, parent, entries + LEVEL_MEM, slot);
if (!rc)
goto retry;
}
if (!rc) if (!rc)
kvm_s390_release_faultin_array(vcpu->kvm, walk->raw_entries, false); kvm_s390_release_faultin_array(vcpu->kvm, walk->raw_entries, false);
return rc; return rc;

View File

@ -2984,61 +2984,58 @@ static int adapter_indicators_set(struct kvm *kvm,
struct s390_io_adapter *adapter, struct s390_io_adapter *adapter,
struct kvm_s390_adapter_int *adapter_int) struct kvm_s390_adapter_int *adapter_int)
{ {
unsigned long bit;
int summary_set, idx;
struct s390_map_info *ind_info, *summary_info; struct s390_map_info *ind_info, *summary_info;
void *map;
struct page *ind_page, *summary_page; struct page *ind_page, *summary_page;
unsigned long flags; unsigned long bit;
int summary_set;
void *map;
ind_page = NULL; ind_page = NULL;
spin_lock_irqsave(&adapter->maps_lock, flags); scoped_guard(spinlock_irqsave, &adapter->maps_lock) {
ind_info = get_map_info(adapter, adapter_int->ind_addr); ind_info = get_map_info(adapter, adapter_int->ind_addr);
if (ind_info) {
map = page_address(ind_info->page);
bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
set_bit(bit, map);
}
}
if (!ind_info) { if (!ind_info) {
spin_unlock_irqrestore(&adapter->maps_lock, flags);
ind_page = pin_map_page(kvm, adapter_int->ind_addr, 0); ind_page = pin_map_page(kvm, adapter_int->ind_addr, 0);
if (!ind_page) if (!ind_page)
return -1; return -1;
idx = srcu_read_lock(&kvm->srcu);
map = page_address(ind_page); map = page_address(ind_page);
bit = get_ind_bit(adapter_int->ind_addr, bit = get_ind_bit(adapter_int->ind_addr,
adapter_int->ind_offset, adapter->swap); adapter_int->ind_offset, adapter->swap);
set_bit(bit, map); set_bit(bit, map);
mark_page_dirty(kvm, adapter_int->ind_gaddr >> PAGE_SHIFT);
set_page_dirty_lock(ind_page); set_page_dirty_lock(ind_page);
srcu_read_unlock(&kvm->srcu, idx);
unpin_user_page(ind_page); unpin_user_page(ind_page);
} else {
map = page_address(ind_info->page);
bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
set_bit(bit, map);
spin_unlock_irqrestore(&adapter->maps_lock, flags);
} }
scoped_guard(srcu, &kvm->srcu)
mark_page_dirty(kvm, gpa_to_gfn(adapter_int->ind_gaddr));
spin_lock_irqsave(&adapter->maps_lock, flags); scoped_guard(spinlock_irqsave, &adapter->maps_lock) {
summary_info = get_map_info(adapter, adapter_int->summary_addr); summary_info = get_map_info(adapter, adapter_int->summary_addr);
if (summary_info) {
map = page_address(summary_info->page);
bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
adapter->swap);
summary_set = test_and_set_bit(bit, map);
}
}
if (!summary_info) { if (!summary_info) {
spin_unlock_irqrestore(&adapter->maps_lock, flags);
summary_page = pin_map_page(kvm, adapter_int->summary_addr, 0); summary_page = pin_map_page(kvm, adapter_int->summary_addr, 0);
if (!summary_page) if (!summary_page)
return -1; return -1;
idx = srcu_read_lock(&kvm->srcu);
map = page_address(summary_page); map = page_address(summary_page);
bit = get_ind_bit(adapter_int->summary_addr, bit = get_ind_bit(adapter_int->summary_addr,
adapter_int->summary_offset, adapter->swap); adapter_int->summary_offset, adapter->swap);
summary_set = test_and_set_bit(bit, map); summary_set = test_and_set_bit(bit, map);
mark_page_dirty(kvm, adapter_int->summary_gaddr >> PAGE_SHIFT);
set_page_dirty_lock(summary_page); set_page_dirty_lock(summary_page);
srcu_read_unlock(&kvm->srcu, idx);
unpin_user_page(summary_page); unpin_user_page(summary_page);
} else {
map = page_address(summary_info->page);
bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
adapter->swap);
summary_set = test_and_set_bit(bit, map);
spin_unlock_irqrestore(&adapter->maps_lock, flags);
} }
scoped_guard(srcu, &kvm->srcu)
mark_page_dirty(kvm, gpa_to_gfn(adapter_int->summary_gaddr));
return summary_set ? 0 : 1; return summary_set ? 0 : 1;
} }
@ -3048,26 +3045,29 @@ static int adapter_indicators_set_fast(struct kvm *kvm,
struct kvm_s390_adapter_int *adapter_int, struct kvm_s390_adapter_int *adapter_int,
int setbit) int setbit)
{ {
struct s390_map_info *ind_info, *summary_info;
unsigned long bit; unsigned long bit;
int summary_set; int summary_set;
struct s390_map_info *ind_info, *summary_info;
void *map; void *map;
spin_lock(&adapter->maps_lock); guard(srcu)(&kvm->srcu);
guard(spinlock)(&adapter->maps_lock);
ind_info = get_map_info(adapter, adapter_int->ind_addr); ind_info = get_map_info(adapter, adapter_int->ind_addr);
if (!ind_info) { if (!ind_info)
spin_unlock(&adapter->maps_lock);
return -EWOULDBLOCK; return -EWOULDBLOCK;
}
map = page_address(ind_info->page); map = page_address(ind_info->page);
bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap); bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
if (setbit) if (setbit) {
set_bit(bit, map); set_bit(bit, map);
summary_info = get_map_info(adapter, adapter_int->summary_addr); mark_page_dirty(kvm, gpa_to_gfn(adapter_int->ind_gaddr));
if (!summary_info) {
spin_unlock(&adapter->maps_lock);
return -EWOULDBLOCK;
} }
summary_info = get_map_info(adapter, adapter_int->summary_addr);
if (!summary_info)
return -EWOULDBLOCK;
map = page_address(summary_info->page); map = page_address(summary_info->page);
bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset, bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
adapter->swap); adapter->swap);
@ -3077,7 +3077,8 @@ static int adapter_indicators_set_fast(struct kvm *kvm,
summary_set = test_and_set_bit(bit, map); summary_set = test_and_set_bit(bit, map);
else else
summary_set = test_and_clear_bit(bit, map); summary_set = test_and_clear_bit(bit, map);
spin_unlock(&adapter->maps_lock); mark_page_dirty(kvm, gpa_to_gfn(adapter_int->summary_gaddr));
return summary_set ? 0 : 1; return summary_set ? 0 : 1;
} }
@ -3228,9 +3229,9 @@ int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len
break; break;
} }
} }
if (storestatus) { if (storestatus) {
n = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR); scoped_guard(srcu, &vcpu->kvm->srcu)
n = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR);
return r ? r : n; return r ? r : n;
} }

View File

@ -5766,7 +5766,7 @@ static long cmma_d_count_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_
return 0; return 0;
} }
void kvm_s390_update_cmma_dirty(struct kvm *kvm, struct kvm_memory_slot *old) void kvm_s390_update_cmma_dirty(struct kvm *kvm, const struct kvm_memory_slot *old)
{ {
const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, }; const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
@ -5781,7 +5781,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *old,
const struct kvm_memory_slot *new, const struct kvm_memory_slot *new,
enum kvm_mr_change change) enum kvm_mr_change change)
{ {
s390_kvm_mmu_commit_memory_region(kvm, old, new, change);
} }
/** /**

View File

@ -472,7 +472,7 @@ int __kvm_s390_mprotect_many(struct gmap *gmap, gpa_t gpa, u8 npages, unsigned i
unsigned long bits); unsigned long bits);
bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu); bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu);
void kvm_s390_update_cmma_dirty(struct kvm *kvm, struct kvm_memory_slot *old); void kvm_s390_update_cmma_dirty(struct kvm *kvm, const struct kvm_memory_slot *old);
int kvm_s390_vm_stop_migration(struct kvm *kvm); int kvm_s390_vm_stop_migration(struct kvm *kvm);

View File

@ -226,6 +226,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev,
device_lock(&pdev->dev); device_lock(&pdev->dev);
if (pdev->error_state == pci_channel_io_perm_failure) { if (pdev->error_state == pci_channel_io_perm_failure) {
ers_res = PCI_ERS_RESULT_DISCONNECT; ers_res = PCI_ERS_RESULT_DISCONNECT;
status_str = "skipped (permanent failure)";
goto out_unlock; goto out_unlock;
} }
pdev->error_state = pci_channel_io_frozen; pdev->error_state = pci_channel_io_frozen;
@ -297,8 +298,8 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev,
driver->err_handler->resume(pdev); driver->err_handler->resume(pdev);
pci_uevent_ers(pdev, PCI_ERS_RESULT_RECOVERED); pci_uevent_ers(pdev, PCI_ERS_RESULT_RECOVERED);
out_unlock: out_unlock:
zpci_report_status(zdev, pdev, "recovery", status_str);
device_unlock(&pdev->dev); device_unlock(&pdev->dev);
zpci_report_status(zdev, "recovery", status_str);
return ers_res; return ers_res;
} }
@ -361,8 +362,10 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
__zpci_event_print_error(pdev, ccdf); __zpci_event_print_error(pdev, ccdf);
if (!pdev) if (!pdev) {
zpci_report_status(zdev, NULL, "error event", "no pdev bound");
goto no_pdev; goto no_pdev;
}
switch (ccdf->pec) { switch (ccdf->pec) {
case 0x002a: /* Error event concerns FMB */ case 0x002a: /* Error event concerns FMB */

View File

@ -87,9 +87,23 @@ static struct debug_view debug_log_view = {
NULL NULL
}; };
static ssize_t zpci_report_pdev(struct pci_dev *pdev, char *buf, size_t size)
{
struct pci_driver *driver;
const char *start = buf;
char *end = buf + size;
device_lock_assert(&pdev->dev);
buf += scnprintf(buf, end - buf, "state: %s\n", zpci_state_str(pdev->error_state));
driver = to_pci_driver(pdev->dev.driver);
buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a");
return buf - start;
}
/** /**
* zpci_report_status - Report the status of operations on a PCI device * zpci_report_status - Report the status of operations on a PCI device
* @zdev: The PCI device for which to report status * @zdev: The zPCI device for which to report status
* @pdev: The PCI device associated with the zdev if any, NULL otherwise
* @operation: A string representing the operation reported * @operation: A string representing the operation reported
* @status: A string representing the status of the operation * @status: A string representing the status of the operation
* *
@ -103,15 +117,14 @@ static struct debug_view debug_log_view = {
* *
* Return: 0 on success an error code < 0 otherwise. * Return: 0 on success an error code < 0 otherwise.
*/ */
int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status) int zpci_report_status(struct zpci_dev *zdev, struct pci_dev *pdev,
const char *operation, const char *status)
{ {
struct zpci_report_error *report; struct zpci_report_error *report;
struct pci_driver *driver = NULL;
struct pci_dev *pdev = NULL;
char *buf, *end; char *buf, *end;
int ret; int ret;
if (!zdev || !zdev->zbus) if (!zdev)
return -ENODEV; return -ENODEV;
/* Protected virtualization hosts get nothing from us */ /* Protected virtualization hosts get nothing from us */
@ -121,18 +134,13 @@ int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char
report = (void *)get_zeroed_page(GFP_KERNEL); report = (void *)get_zeroed_page(GFP_KERNEL);
if (!report) if (!report)
return -ENOMEM; return -ENOMEM;
if (zdev->zbus->bus)
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
if (pdev)
driver = to_pci_driver(pdev->dev.driver);
buf = report->data.log_data; buf = report->data.log_data;
end = report->data.log_data + ZPCI_REPORT_DATA_SIZE; end = report->data.log_data + ZPCI_REPORT_DATA_SIZE;
buf += scnprintf(buf, end - buf, "report: %s\n", operation); buf += scnprintf(buf, end - buf, "report: %s\n", operation);
buf += scnprintf(buf, end - buf, "status: %s\n", status); buf += scnprintf(buf, end - buf, "status: %s\n", status);
buf += scnprintf(buf, end - buf, "state: %s\n", if (pdev)
(pdev) ? zpci_state_str(pdev->error_state) : "n/a"); buf += zpci_report_pdev(pdev, buf, end - buf);
buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a");
ret = debug_dump(pci_debug_msg_id, &debug_log_view, buf, end - buf, true); ret = debug_dump(pci_debug_msg_id, &debug_log_view, buf, end - buf, true);
if (ret < 0) if (ret < 0)
pr_err("Reading PCI debug messages failed with code %d\n", ret); pr_err("Reading PCI debug messages failed with code %d\n", ret);

View File

@ -8,9 +8,11 @@
*/ */
#ifndef __S390_PCI_REPORT_H #ifndef __S390_PCI_REPORT_H
#define __S390_PCI_REPORT_H #define __S390_PCI_REPORT_H
#include <linux/pci.h>
struct zpci_dev; struct zpci_dev;
int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status); int zpci_report_status(struct zpci_dev *zdev, struct pci_dev *pdev,
const char *operation, const char *status);
#endif /* __S390_PCI_REPORT_H */ #endif /* __S390_PCI_REPORT_H */

View File

@ -74,6 +74,14 @@ int svsm_perform_call_protocol(struct svsm_call *call)
flags = native_local_irq_save(); flags = native_local_irq_save();
/*
* 'caa' is a per-CPU variable. To avoid using a stale or incorrect
* 'caa' if the task is preempted or migrated to another CPU after it
* is fetched, always fetch 'caa' and then issue the SVSM call with
* interrupts disabled. This ensures the correct 'caa' is used.
*/
call->caa = svsm_get_caa();
ghcb = __sev_get_ghcb(&state); ghcb = __sev_get_ghcb(&state);
do { do {
@ -321,7 +329,6 @@ int snp_svsm_vtpm_send_command(u8 *buffer)
{ {
struct svsm_call call = {}; struct svsm_call call = {};
call.caa = svsm_get_caa();
call.rax = SVSM_VTPM_CALL(SVSM_VTPM_CMD); call.rax = SVSM_VTPM_CALL(SVSM_VTPM_CMD);
call.rcx = __pa(buffer); call.rcx = __pa(buffer);
@ -345,7 +352,6 @@ bool snp_svsm_vtpm_probe(void)
if (!snp_vmpl) if (!snp_vmpl)
return false; return false;
call.caa = svsm_get_caa();
call.rax = SVSM_VTPM_CALL(SVSM_VTPM_QUERY); call.rax = SVSM_VTPM_CALL(SVSM_VTPM_QUERY);
if (svsm_perform_call_protocol(&call)) if (svsm_perform_call_protocol(&call))

View File

@ -343,11 +343,10 @@ void amd_brs_drain(void)
if (!amd_brs_match_plm(event, from, to)) if (!amd_brs_match_plm(event, from, to))
continue; continue;
perf_clear_branch_entry_bitfields(br+nr); br[nr] = (struct perf_branch_entry){
.from = from,
br[nr].from = from; .to = to,
br[nr].to = to; };
nr++; nr++;
} }
empty: empty:

View File

@ -184,13 +184,6 @@ void amd_pmu_lbr_read(void)
entry.to.split.reserved) entry.to.split.reserved)
continue; continue;
perf_clear_branch_entry_bitfields(br + out);
br[out].from = sign_ext_branch_ip(entry.from.split.ip);
br[out].to = sign_ext_branch_ip(entry.to.split.ip);
br[out].mispred = entry.from.split.mispredict;
br[out].predicted = !br[out].mispred;
/* /*
* Set branch speculation information using the status of * Set branch speculation information using the status of
* the valid and spec bits. * the valid and spec bits.
@ -208,7 +201,14 @@ void amd_pmu_lbr_read(void)
* speculative and took the correct path * speculative and took the correct path
*/ */
idx = (entry.to.split.valid << 1) | entry.to.split.spec; idx = (entry.to.split.valid << 1) | entry.to.split.spec;
br[out].spec = lbr_spec_map[idx];
br[out] = (struct perf_branch_entry){
.from = sign_ext_branch_ip(entry.from.split.ip),
.to = sign_ext_branch_ip(entry.to.split.ip),
.mispred = entry.from.split.mispredict,
.predicted = !entry.from.split.mispredict,
.spec = lbr_spec_map[idx],
};
out++; out++;
} }

View File

@ -506,6 +506,8 @@ static struct event_constraint intel_pnc_event_constraints[] = {
INTEL_EVENT_CONSTRAINT(0xce, 0x1), INTEL_EVENT_CONSTRAINT(0xce, 0x1),
INTEL_UEVENT_CONSTRAINT(0x01b1, 0x8), INTEL_UEVENT_CONSTRAINT(0x01b1, 0x8),
INTEL_UEVENT_CONSTRAINT(0x01b2, 0xf),
INTEL_UEVENT_CONSTRAINT(0x02b2, 0xf),
INTEL_UEVENT_CONSTRAINT(0x0847, 0xf), INTEL_UEVENT_CONSTRAINT(0x0847, 0xf),
INTEL_UEVENT_CONSTRAINT(0x0446, 0xf), INTEL_UEVENT_CONSTRAINT(0x0446, 0xf),
INTEL_UEVENT_CONSTRAINT(0x0846, 0xf), INTEL_UEVENT_CONSTRAINT(0x0846, 0xf),
@ -520,6 +522,14 @@ static struct extra_reg intel_pnc_extra_regs[] __read_mostly = {
INTEL_UEVENT_EXTRA_REG(0x022a, MSR_OMR_1, 0x40ffffff0000ffffull, OMR_1), INTEL_UEVENT_EXTRA_REG(0x022a, MSR_OMR_1, 0x40ffffff0000ffffull, OMR_1),
INTEL_UEVENT_EXTRA_REG(0x042a, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2), INTEL_UEVENT_EXTRA_REG(0x042a, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2),
INTEL_UEVENT_EXTRA_REG(0x082a, MSR_OMR_3, 0x40ffffff0000ffffull, OMR_3), INTEL_UEVENT_EXTRA_REG(0x082a, MSR_OMR_3, 0x40ffffff0000ffffull, OMR_3),
INTEL_UEVENT_EXTRA_REG(0x014f, MSR_OMR_0, 0x40ffffff0000ffffull, OMR_0),
INTEL_UEVENT_EXTRA_REG(0x024f, MSR_OMR_1, 0x40ffffff0000ffffull, OMR_1),
INTEL_UEVENT_EXTRA_REG(0x044f, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2),
INTEL_UEVENT_EXTRA_REG(0x084f, MSR_OMR_3, 0x40ffffff0000ffffull, OMR_3),
INTEL_UEVENT_EXTRA_REG(0x01d6, MSR_OMR_0, 0x40ffffff0000ffffull, OMR_0),
INTEL_UEVENT_EXTRA_REG(0x02d6, MSR_OMR_1, 0x40ffffff0000ffffull, OMR_1),
INTEL_UEVENT_EXTRA_REG(0x04d6, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2),
INTEL_UEVENT_EXTRA_REG(0x08d6, MSR_OMR_3, 0x40ffffff0000ffffull, OMR_3),
INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd), INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
INTEL_UEVENT_EXTRA_REG(0x02c6, MSR_PEBS_FRONTEND, 0x9, FE), INTEL_UEVENT_EXTRA_REG(0x02c6, MSR_PEBS_FRONTEND, 0x9, FE),
INTEL_UEVENT_EXTRA_REG(0x03c6, MSR_PEBS_FRONTEND, 0x7fff1f, FE), INTEL_UEVENT_EXTRA_REG(0x03c6, MSR_PEBS_FRONTEND, 0x7fff1f, FE),
@ -5292,12 +5302,15 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
struct kvm_pmu *kvm_pmu = (struct kvm_pmu *)data; struct kvm_pmu *kvm_pmu = (struct kvm_pmu *)data;
u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl); u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl);
u64 pebs_mask = cpuc->pebs_enabled & x86_pmu.pebs_capable; u64 pebs_mask = cpuc->pebs_enabled & x86_pmu.pebs_capable;
int global_ctrl, pebs_enable; u64 guest_pebs_mask;
int global_ctrl;
/* /*
* In addition to obeying exclude_guest/exclude_host, remove bits being * In addition to obeying exclude_guest/exclude_host, remove bits being
* used for PEBS when running a guest, because PEBS writes to virtual * used for PEBS when running a guest, because PEBS writes to virtual
* addresses (not physical addresses). * addresses (not physical addresses). If the guest wants to utilize
* PEBS, and PEBS can be safely enabled in the guest, bits for the guest's
* PEBS-enabled counters will be OR'd back in as appropriate.
*/ */
*nr = 0; *nr = 0;
global_ctrl = (*nr)++; global_ctrl = (*nr)++;
@ -5327,41 +5340,68 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
return arr; return arr;
} }
if (!kvm_pmu || !x86_pmu.pebs_ept) /*
* If the CPU doesn't support PEBS in the guest, then there's nothing
* more to do as disabling PMCs via PERF_GLOBAL_CTRL is sufficient on
* CPUs with guest/host isolation.
*/
if (!x86_pmu.pebs_ept)
return arr; return arr;
/*
* Restrict guest PEBS events to counters that (a) perf supports, (b)
* the guest wants to use for PEBS, (c) are not excluded from counting
* in the guest, and (d) _are_ excluded from counting in the host.
*/
guest_pebs_mask = pebs_mask & intel_ctrl & kvm_pmu->pebs_enable &
~cpuc->intel_ctrl_host_mask &
cpuc->intel_ctrl_guest_mask;
/*
* Disable counters where the guest PMC is different than the host PMC
* being used on behalf of the guest, as the PEBS record includes
* PERF_GLOBAL_STATUS, i.e. the guest will see overflow status for the
* wrong counter(s).
*/
guest_pebs_mask &= ~kvm_pmu->host_cross_mapped_mask;
/*
* FIXME: Allow guest and host usage of PEBS events to co-exist instead
* of disabling guest PEBS entirely if the host is using PEBS.
* What exactly goes wrong if guest and host are using PEBS is
* unknown.
*/
if (pebs_mask & ~cpuc->intel_ctrl_guest_mask)
guest_pebs_mask = 0;
/*
* Context switch DS_AREA and PEBS_DATA_CFG if and only if PEBS will be
* active in the guest; if no records will be generated while the guest
* is running, then simply keep the host values resident in hardware.
*/
arr[(*nr)++] = (struct perf_guest_switch_msr){ arr[(*nr)++] = (struct perf_guest_switch_msr){
.msr = MSR_IA32_DS_AREA, .msr = MSR_IA32_DS_AREA,
.host = (unsigned long)cpuc->ds, .host = (unsigned long)cpuc->ds,
.guest = kvm_pmu->ds_area, .guest = guest_pebs_mask ? kvm_pmu->ds_area : (unsigned long)cpuc->ds,
}; };
if (x86_pmu.intel_cap.pebs_baseline) { if (x86_pmu.intel_cap.pebs_baseline) {
arr[(*nr)++] = (struct perf_guest_switch_msr){ arr[(*nr)++] = (struct perf_guest_switch_msr){
.msr = MSR_PEBS_DATA_CFG, .msr = MSR_PEBS_DATA_CFG,
.host = cpuc->active_pebs_data_cfg, .host = cpuc->active_pebs_data_cfg,
.guest = kvm_pmu->pebs_data_cfg, .guest = guest_pebs_mask ? kvm_pmu->pebs_data_cfg :
cpuc->active_pebs_data_cfg,
}; };
} }
pebs_enable = (*nr)++; /*
arr[pebs_enable] = (struct perf_guest_switch_msr){ * Do NOT mess with PEBS_ENABLED. As above, disabling counters via
.msr = MSR_IA32_PEBS_ENABLE, * PERF_GLOBAL_CTRL is sufficient, and loading a stale PEBS_ENABLED,
.host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask, * e.g. on VM-Exit, can put the system in a bad state. Simply enable
.guest = pebs_mask & ~cpuc->intel_ctrl_host_mask & kvm_pmu->pebs_enable, * counters in PERF_GLOBAL_CTRL, as perf load PEBS_ENABLED with the
}; * full value, i.e. perf *also* relies on PERF_GLOBAL_CTRL.
*/
if (arr[pebs_enable].host) { arr[global_ctrl].guest |= guest_pebs_mask;
/* Disable guest PEBS if host PEBS is enabled. */
arr[pebs_enable].guest = 0;
} else {
/* Disable guest PEBS thoroughly for cross-mapped PEBS counters. */
arr[pebs_enable].guest &= ~kvm_pmu->host_cross_mapped_mask;
arr[global_ctrl].guest &= ~kvm_pmu->host_cross_mapped_mask;
/* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */
arr[global_ctrl].guest |= arr[pebs_enable].guest;
}
return arr; return arr;
} }
@ -6561,6 +6601,8 @@ static void intel_pmu_filter(struct pmu *pmu, int cpu, bool *ret)
PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63"); PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
PMU_FORMAT_ATTR(offmodule_rsp, "config1:0-63");
PMU_FORMAT_ATTR(ldlat, "config1:0-15"); PMU_FORMAT_ATTR(ldlat, "config1:0-15");
PMU_FORMAT_ATTR(frontend, "config1:0-23"); PMU_FORMAT_ATTR(frontend, "config1:0-23");
@ -6609,6 +6651,20 @@ static struct attribute *skl_format_attr[] = {
NULL, NULL,
}; };
static struct attribute *pnc_format_attr_rtm[] = {
&format_attr_in_tx.attr,
&format_attr_in_tx_cp.attr,
&format_attr_offmodule_rsp.attr,
&format_attr_ldlat.attr,
NULL
};
static struct attribute *pnc_format_attr[] = {
&format_attr_offmodule_rsp.attr,
&format_attr_ldlat.attr,
NULL
};
static __initconst const struct x86_pmu core_pmu = { static __initconst const struct x86_pmu core_pmu = {
.name = "core", .name = "core",
.handle_irq = x86_pmu_handle_irq, .handle_irq = x86_pmu_handle_irq,
@ -7474,6 +7530,7 @@ static struct attribute *adl_hybrid_tsx_attrs[] = {
FORMAT_ATTR_HYBRID(in_tx, hybrid_big); FORMAT_ATTR_HYBRID(in_tx, hybrid_big);
FORMAT_ATTR_HYBRID(in_tx_cp, hybrid_big); FORMAT_ATTR_HYBRID(in_tx_cp, hybrid_big);
FORMAT_ATTR_HYBRID(offcore_rsp, hybrid_big_small_tiny); FORMAT_ATTR_HYBRID(offcore_rsp, hybrid_big_small_tiny);
FORMAT_ATTR_HYBRID(offmodule_rsp, hybrid_big_small_tiny);
FORMAT_ATTR_HYBRID(ldlat, hybrid_big_small_tiny); FORMAT_ATTR_HYBRID(ldlat, hybrid_big_small_tiny);
FORMAT_ATTR_HYBRID(frontend, hybrid_big); FORMAT_ATTR_HYBRID(frontend, hybrid_big);
@ -7512,6 +7569,23 @@ static struct attribute *mtl_hybrid_extra_attr[] = {
NULL NULL
}; };
static struct attribute *nvl_hybrid_extra_attr_rtm[] = {
ADL_HYBRID_RTM_FORMAT_ATTR,
FORMAT_HYBRID_PTR(offmodule_rsp),
FORMAT_HYBRID_PTR(ldlat),
FORMAT_HYBRID_PTR(frontend),
FORMAT_HYBRID_PTR(snoop_rsp),
NULL
};
static struct attribute *nvl_hybrid_extra_attr[] = {
FORMAT_HYBRID_PTR(offmodule_rsp),
FORMAT_HYBRID_PTR(ldlat),
FORMAT_HYBRID_PTR(frontend),
FORMAT_HYBRID_PTR(snoop_rsp),
NULL
};
static bool is_attr_for_this_pmu(struct kobject *kobj, struct attribute *attr) static bool is_attr_for_this_pmu(struct kobject *kobj, struct attribute *attr)
{ {
struct device *dev = kobj_to_dev(kobj); struct device *dev = kobj_to_dev(kobj);
@ -8549,6 +8623,8 @@ __init int intel_pmu_init(void)
case INTEL_DIAMONDRAPIDS_X: case INTEL_DIAMONDRAPIDS_X:
intel_pmu_init_pnc(NULL); intel_pmu_init_pnc(NULL);
x86_pmu.pebs_latency_data = pnc_latency_data; x86_pmu.pebs_latency_data = pnc_latency_data;
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
pnc_format_attr_rtm : pnc_format_attr;
pr_cont("Panthercove events, "); pr_cont("Panthercove events, ");
name = "panthercove"; name = "panthercove";
@ -8557,13 +8633,12 @@ __init int intel_pmu_init(void)
glc_common: glc_common:
intel_pmu_init_glc(NULL); intel_pmu_init_glc(NULL);
intel_pmu_pebs_data_source_skl(true); intel_pmu_pebs_data_source_skl(true);
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
hsw_format_attr : nhm_format_attr;
glc_base: glc_base:
x86_pmu.pebs_ept = 1; x86_pmu.pebs_ept = 1;
x86_pmu.hw_config = hsw_hw_config; x86_pmu.hw_config = hsw_hw_config;
x86_pmu.get_event_constraints = glc_get_event_constraints; x86_pmu.get_event_constraints = glc_get_event_constraints;
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
hsw_format_attr : nhm_format_attr;
extra_skl_attr = skl_format_attr; extra_skl_attr = skl_format_attr;
mem_attr = glc_events_attrs; mem_attr = glc_events_attrs;
td_attr = glc_td_events_attrs; td_attr = glc_td_events_attrs;
@ -8785,7 +8860,7 @@ __init int intel_pmu_init(void)
mem_attr = mtl_hybrid_mem_attrs; mem_attr = mtl_hybrid_mem_attrs;
tsx_attr = adl_hybrid_tsx_attrs; tsx_attr = adl_hybrid_tsx_attrs;
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ? extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr; nvl_hybrid_extra_attr_rtm : nvl_hybrid_extra_attr;
/* Initialize big core specific PerfMon capabilities.*/ /* Initialize big core specific PerfMon capabilities.*/
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX]; pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX];
@ -8794,8 +8869,6 @@ __init int intel_pmu_init(void)
/* Initialize Atom core specific PerfMon capabilities.*/ /* Initialize Atom core specific PerfMon capabilities.*/
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX]; pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX];
intel_pmu_init_arw(&pmu->pmu); intel_pmu_init_arw(&pmu->pmu);
intel_pmu_pebs_data_source_lnl();
break; break;
default: default:

View File

@ -277,8 +277,8 @@ static u64 pnc_pebs_l2_hit_data_source[PNC_PEBS_DATA_SOURCE_MAX] = {
0, /* 0x06: Reserved */ 0, /* 0x06: Reserved */
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, HIT), /* 0x07: L2 Hit Snoop HIT */ OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, HIT), /* 0x07: L2 Hit Snoop HIT */
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, HITM), /* 0x08: L2 Hit Snoop Hit Modified */ OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, HITM), /* 0x08: L2 Hit Snoop Hit Modified */
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, MISS), /* 0x09: Prefetch Promotion */ OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* 0x09: Prefetch Promotion */
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, MISS), /* 0x0a: Cross Core Prefetch Promotion */ OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* 0x0a: Cross Core Prefetch Promotion */
0, /* 0x0b: Reserved */ 0, /* 0x0b: Reserved */
0, /* 0x0c: Reserved */ 0, /* 0x0c: Reserved */
0, /* 0x0d: Reserved */ 0, /* 0x0d: Reserved */
@ -455,6 +455,7 @@ static inline void pebs_set_tlb_lock(u64 *val, bool tlb, bool lock)
static u64 __grt_latency_data(struct perf_event *event, u64 status, static u64 __grt_latency_data(struct perf_event *event, u64 status,
u8 dse, bool tlb, bool lock, bool blk) u8 dse, bool tlb, bool lock, bool blk)
{ {
union perf_mem_data_src src;
u64 val; u64 val;
WARN_ON_ONCE(is_hybrid() && WARN_ON_ONCE(is_hybrid() &&
@ -470,7 +471,16 @@ static u64 __grt_latency_data(struct perf_event *event, u64 status,
else else
val |= P(BLK, NA); val |= P(BLK, NA);
return val; src.val = val;
if (event->hw.flags &
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
src.mem_op = P(OP, LOAD);
if (event->hw.flags &
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
src.mem_op = P(OP, STORE);
return src.val;
} }
u64 grt_latency_data(struct perf_event *event, u64 status) u64 grt_latency_data(struct perf_event *event, u64 status)
@ -528,7 +538,11 @@ static u64 arw_latency_data(struct perf_event *event, u64 status)
val |= P(BLK, NA); val |= P(BLK, NA);
src.val = val; src.val = val;
if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) if (event->hw.flags &
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
src.mem_op = P(OP, LOAD);
if (event->hw.flags &
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
src.mem_op = P(OP, STORE); src.mem_op = P(OP, STORE);
return src.val; return src.val;
@ -563,7 +577,11 @@ static u64 lnc_latency_data(struct perf_event *event, u64 status)
val |= P(BLK, NA); val |= P(BLK, NA);
src.val = val; src.val = val;
if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) if (event->hw.flags &
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
src.mem_op = P(OP, LOAD);
if (event->hw.flags &
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
src.mem_op = P(OP, STORE); src.mem_op = P(OP, STORE);
return src.val; return src.val;
@ -621,7 +639,11 @@ u64 pnc_latency_data(struct perf_event *event, u64 status)
val |= P(BLK, NA); val |= P(BLK, NA);
src.val = val; src.val = val;
if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) if (event->hw.flags &
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
src.mem_op = P(OP, LOAD);
if (event->hw.flags &
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
src.mem_op = P(OP, STORE); src.mem_op = P(OP, STORE);
return src.val; return src.val;
@ -1291,22 +1313,22 @@ struct event_constraint intel_glm_pebs_event_constraints[] = {
struct event_constraint intel_grt_pebs_event_constraints[] = { struct event_constraint intel_grt_pebs_event_constraints[] = {
/* Allow all events as PEBS with no flags */ /* Allow all events as PEBS with no flags */
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0x3), INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0x3),
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0x3f), INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0x3f),
EVENT_CONSTRAINT_END EVENT_CONSTRAINT_END
}; };
struct event_constraint intel_cmt_pebs_event_constraints[] = { struct event_constraint intel_cmt_pebs_event_constraints[] = {
/* Allow all events as PEBS with no flags */ /* Allow all events as PEBS with no flags */
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0x3), INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0x3),
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xff), INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0xff),
EVENT_CONSTRAINT_END EVENT_CONSTRAINT_END
}; };
struct event_constraint intel_dkt_pebs_event_constraints[] = { struct event_constraint intel_dkt_pebs_event_constraints[] = {
/* Allow all events as PEBS with no flags */ /* Allow all events as PEBS with no flags */
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0xff), INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0xff),
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xff), INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0xff),
EVENT_CONSTRAINT_END EVENT_CONSTRAINT_END
}; };
@ -1496,24 +1518,8 @@ struct event_constraint intel_lnc_pebs_event_constraints[] = {
INTEL_FLAGS_UEVENT_CONSTRAINT(0x012a, 0x1), /* OCR.* events */ INTEL_FLAGS_UEVENT_CONSTRAINT(0x012a, 0x1), /* OCR.* events */
INTEL_FLAGS_UEVENT_CONSTRAINT(0x012b, 0x1), /* OCR.* events */ INTEL_FLAGS_UEVENT_CONSTRAINT(0x012b, 0x1), /* OCR.* events */
INTEL_FLAGS_UEVENT_CONSTRAINT(0x04a4, 0x1), /* TOPDOWN.BAD_SPEC_SLOTS */
INTEL_FLAGS_UEVENT_CONSTRAINT(0x08a4, 0x1), /* TOPDOWN.BR_MISPREDICT_SLOTS */
INTEL_FLAGS_UEVENT_CONSTRAINT(0x10a4, 0x8), /* TOPDOWN.MEMORY_BOUND_SLOTS */
INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0x3fc), INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0x3fc),
INTEL_HYBRID_STLAT_CONSTRAINT(0x2cd, 0x3), INTEL_HYBRID_STLAT_CONSTRAINT(0x2cd, 0x3),
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_INST_RETIRED.LOCK_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_INST_RETIRED.SPLIT_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_INST_RETIRED.SPLIT_STORES */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_INST_RETIRED.ALL_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_INST_RETIRED.ALL_STORES */
INTEL_FLAGS_UEVENT_CONSTRAINT(0x87d0, 0x3ff), /* MEM_INST_RETIRED.ANY */
INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD_RANGE(0xd1, 0xd4, 0xf),
INTEL_FLAGS_EVENT_CONSTRAINT(0xd0, 0xf),
/* /*
* Everything else is handled by PMU_FL_PEBS_ALL, because we * Everything else is handled by PMU_FL_PEBS_ALL, because we
@ -1526,18 +1532,6 @@ struct event_constraint intel_lnc_pebs_event_constraints[] = {
struct event_constraint intel_pnc_pebs_event_constraints[] = { struct event_constraint intel_pnc_pebs_event_constraints[] = {
INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0xfc), INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0xfc),
INTEL_HYBRID_STLAT_CONSTRAINT(0x2cd, 0x3), INTEL_HYBRID_STLAT_CONSTRAINT(0x2cd, 0x3),
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_INST_RETIRED.LOCK_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_INST_RETIRED.SPLIT_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_INST_RETIRED.SPLIT_STORES */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_INST_RETIRED.ALL_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_INST_RETIRED.ALL_STORES */
INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD_RANGE(0xd1, 0xd4, 0xf),
INTEL_FLAGS_EVENT_CONSTRAINT(0xd0, 0xf),
INTEL_FLAGS_EVENT_CONSTRAINT(0xd6, 0xf),
/* /*
* Everything else is handled by PMU_FL_PEBS_ALL, because we * Everything else is handled by PMU_FL_PEBS_ALL, because we

View File

@ -756,10 +756,10 @@ void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
rdmsrq(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr); rdmsrq(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr);
perf_clear_branch_entry_bitfields(br); *br = (struct perf_branch_entry){
.from = msr_lastbranch.from,
br->from = msr_lastbranch.from; .to = msr_lastbranch.to,
br->to = msr_lastbranch.to; };
br++; br++;
} }
cpuc->lbr_stack.nr = i; cpuc->lbr_stack.nr = i;
@ -847,14 +847,15 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
if (abort && x86_pmu.lbr_double_abort && out > 0) if (abort && x86_pmu.lbr_double_abort && out > 0)
out--; out--;
perf_clear_branch_entry_bitfields(br+out); br[out] = (struct perf_branch_entry){
br[out].from = from; .from = from,
br[out].to = to; .to = to,
br[out].mispred = mis; .mispred = mis,
br[out].predicted = pred; .predicted = pred,
br[out].in_tx = in_tx; .in_tx = in_tx,
br[out].abort = abort; .abort = abort,
br[out].cycles = cycles; .cycles = cycles,
};
out++; out++;
} }
cpuc->lbr_stack.nr = out; cpuc->lbr_stack.nr = out;
@ -905,6 +906,7 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
struct perf_branch_entry *e; struct perf_branch_entry *e;
struct lbr_entry *lbr; struct lbr_entry *lbr;
u64 from, to, info; u64 from, to, info;
bool mispred;
int i; int i;
for (i = 0; i < x86_pmu.lbr_nr; i++) { for (i = 0; i < x86_pmu.lbr_nr; i++) {
@ -921,24 +923,27 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
to = rdlbr_to(i, lbr); to = rdlbr_to(i, lbr);
info = rdlbr_info(i, lbr); info = rdlbr_info(i, lbr);
perf_clear_branch_entry_bitfields(e); mispred = get_lbr_mispred(info);
e->from = from; *e = (struct perf_branch_entry){
e->to = to; .from = from,
e->mispred = get_lbr_mispred(info); .to = to,
e->predicted = !e->mispred; .mispred = mispred,
e->in_tx = !!(info & LBR_INFO_IN_TX); .predicted = !mispred,
e->abort = !!(info & LBR_INFO_ABORT); .in_tx = !!(info & LBR_INFO_IN_TX),
e->cycles = get_lbr_cycles(info); .abort = !!(info & LBR_INFO_ABORT),
e->type = get_lbr_br_type(info); .cycles = get_lbr_cycles(info),
.type = get_lbr_br_type(info),
/* /*
* Leverage the reserved field of cpuc->lbr_entries[i] to * Leverage the reserved field of
* temporarily store the branch counters information. * cpuc->lbr_entries[i] to temporarily store the
* The later code will decide what content can be disclosed * branch counters information. The later code will
* to the perf tool. Pleae see intel_pmu_lbr_counters_reorder(). * decide what content can be disclosed to the perf
*/ * tool. Pleae see intel_pmu_lbr_counters_reorder().
e->reserved = (info >> LBR_INFO_BR_CNTR_OFFSET) & LBR_INFO_BR_CNTR_FULL_MASK; */
.reserved = (info >> LBR_INFO_BR_CNTR_OFFSET) &
LBR_INFO_BR_CNTR_FULL_MASK,
};
} }
cpuc->lbr_stack.nr = i; cpuc->lbr_stack.nr = i;

View File

@ -517,10 +517,6 @@ struct cpu_hw_events {
__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST) HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
#define INTEL_HYBRID_LAT_CONSTRAINT(c, n) \
__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LAT_HYBRID)
#define INTEL_HYBRID_LDLAT_CONSTRAINT(c, n) \ #define INTEL_HYBRID_LDLAT_CONSTRAINT(c, n) \
__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \ __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LAT_HYBRID|PERF_X86_EVENT_PEBS_LD_HSW) HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LAT_HYBRID|PERF_X86_EVENT_PEBS_LD_HSW)

View File

@ -2108,6 +2108,9 @@ bool filter_mce(struct mce *m)
static __always_inline void exc_machine_check_kernel(struct pt_regs *regs) static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
{ {
irqentry_state_t irq_state; irqentry_state_t irq_state;
unsigned long dr7;
dr7 = local_db_save();
WARN_ON_ONCE(user_mode(regs)); WARN_ON_ONCE(user_mode(regs));
@ -2116,20 +2119,26 @@ static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
* mce_check_crashing_cpu() for details. * mce_check_crashing_cpu() for details.
*/ */
if (mca_cfg.initialized && mce_check_crashing_cpu()) if (mca_cfg.initialized && mce_check_crashing_cpu())
return; goto out;
irq_state = irqentry_nmi_enter(regs); irq_state = irqentry_nmi_enter(regs);
do_machine_check(regs); do_machine_check(regs);
irqentry_nmi_exit(regs, irq_state); irqentry_nmi_exit(regs, irq_state);
out:
local_db_restore(dr7);
} }
static __always_inline void exc_machine_check_user(struct pt_regs *regs) static __always_inline void exc_machine_check_user(struct pt_regs *regs)
{ {
unsigned long dr7;
irqentry_enter_from_user_mode(regs); irqentry_enter_from_user_mode(regs);
dr7 = local_db_save();
do_machine_check(regs); do_machine_check(regs);
local_db_restore(dr7);
irqentry_exit_to_user_mode(regs); irqentry_exit_to_user_mode(regs);
} }
@ -2138,21 +2147,13 @@ static __always_inline void exc_machine_check_user(struct pt_regs *regs)
/* MCE hit kernel mode */ /* MCE hit kernel mode */
DEFINE_IDTENTRY_MCE(exc_machine_check) DEFINE_IDTENTRY_MCE(exc_machine_check)
{ {
unsigned long dr7;
dr7 = local_db_save();
exc_machine_check_kernel(regs); exc_machine_check_kernel(regs);
local_db_restore(dr7);
} }
/* The user mode variant. */ /* The user mode variant. */
DEFINE_IDTENTRY_MCE_USER(exc_machine_check) DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
{ {
unsigned long dr7;
dr7 = local_db_save();
exc_machine_check_user(regs); exc_machine_check_user(regs);
local_db_restore(dr7);
} }
#ifdef CONFIG_X86_FRED #ifdef CONFIG_X86_FRED
@ -2169,28 +2170,20 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
*/ */
DEFINE_FREDENTRY_MCE(exc_machine_check) DEFINE_FREDENTRY_MCE(exc_machine_check)
{ {
unsigned long dr7;
dr7 = local_db_save();
if (user_mode(regs)) if (user_mode(regs))
exc_machine_check_user(regs); exc_machine_check_user(regs);
else else
exc_machine_check_kernel(regs); exc_machine_check_kernel(regs);
local_db_restore(dr7);
} }
#endif #endif
#else #else
/* 32bit unified entry point */ /* 32bit unified entry point */
DEFINE_IDTENTRY_RAW(exc_machine_check) DEFINE_IDTENTRY_RAW(exc_machine_check)
{ {
unsigned long dr7;
dr7 = local_db_save();
if (user_mode(regs)) if (user_mode(regs))
exc_machine_check_user(regs); exc_machine_check_user(regs);
else else
exc_machine_check_kernel(regs); exc_machine_check_kernel(regs);
local_db_restore(dr7);
} }
#endif #endif

View File

@ -5058,7 +5058,7 @@ static int kvm_tdp_page_prefault(struct kvm_vcpu *vcpu, gpa_t gpa,
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu))
return -EIO; return -EIO;
cond_resched(); cond_resched();

View File

@ -823,14 +823,6 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
{ {
switch (msr) {
case MSR_CORE_PERF_GLOBAL_STATUS:
case MSR_CORE_PERF_GLOBAL_CTRL:
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
return kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu));
default:
break;
}
return kvm_pmu_call(msr_idx_to_pmc)(vcpu, msr) || return kvm_pmu_call(msr_idx_to_pmc)(vcpu, msr) ||
kvm_pmu_call(is_valid_msr)(vcpu, msr); kvm_pmu_call(is_valid_msr)(vcpu, msr);
} }

View File

@ -2125,13 +2125,8 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
return false; return false;
} }
if (!nested_svm_merge_msrpm(vcpu)) { if (!nested_svm_merge_msrpm(vcpu))
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
return false; return false;
}
if (kvm_hv_verify_vp_assist(vcpu)) if (kvm_hv_verify_vp_assist(vcpu))
return false; return false;

View File

@ -2048,6 +2048,12 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm)
src->pages_locked = 0; src->pages_locked = 0;
src->es_active = false; src->es_active = false;
/*
* Do cache maintenance on the source VM as it is no longer an SEV VM,
* i.e. memory reclaim flows won't trigger cache maintenance on the VM.
*/
sev_writeback_caches(src_kvm);
list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list); list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list);
mutex_lock(&sev_mirror_lock); mutex_lock(&sev_mirror_lock);
@ -2187,6 +2193,10 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd)
* the set of CPUs from the source. If a CPU was used to run a vCPU in * the set of CPUs from the source. If a CPU was used to run a vCPU in
* the source VM but is never used for the destination VM, then the CPU * the source VM but is never used for the destination VM, then the CPU
* can only have cached memory that was accessible to the source VM. * can only have cached memory that was accessible to the source VM.
* Furthermore, KVM *must* perform cache maintenance on the source VM,
* as the source VM may have access to memory that the destination VM
* does not, i.e. KVM could skip flushes if memory is reclaimed from
* the old VM but not the new VM.
*/ */
if (!zalloc_cpumask_var(&dst_sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) { if (!zalloc_cpumask_var(&dst_sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) {
ret = -ENOMEM; ret = -ENOMEM;
@ -2980,13 +2990,17 @@ void sev_vm_destroy(struct kvm *kvm)
struct list_head *head = &sev->regions_list; struct list_head *head = &sev->regions_list;
struct list_head *pos, *q; struct list_head *pos, *q;
/*
* Free the mask even if the VM is not *currently* an SEV VM, as it may
* have been an SEV VM prior to intra-host migration.
*/
free_cpumask_var(sev->have_run_cpus);
if (!sev_guest(kvm)) if (!sev_guest(kvm))
return; return;
WARN_ON(!list_empty(&sev->mirror_vms)); WARN_ON(!list_empty(&sev->mirror_vms));
free_cpumask_var(sev->have_run_cpus);
/* /*
* If this is a mirror VM, remove it from the owner's list of a mirrors * If this is a mirror VM, remove it from the owner's list of a mirrors
* and skip ASID cleanup (the ASID is tied to the lifetime of the owner). * and skip ASID cleanup (the ASID is tied to the lifetime of the owner).

View File

@ -3465,10 +3465,6 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
} else { } else {
pr_debug_ratelimited("%s: no backing for APIC-access address in vmcs12\n", pr_debug_ratelimited("%s: no backing for APIC-access address in vmcs12\n",
__func__); __func__);
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
return false; return false;
} }
} }
@ -3539,11 +3535,6 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
if (!nested_get_evmcs_page(vcpu)) { if (!nested_get_evmcs_page(vcpu)) {
pr_debug_ratelimited("%s: enlightened vmptrld failed\n", pr_debug_ratelimited("%s: enlightened vmptrld failed\n",
__func__); __func__);
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
return false; return false;
} }
#endif #endif
@ -3915,8 +3906,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
vmentry_failed: vmentry_failed:
vcpu->arch.nested_run_pending = 0; vcpu->arch.nested_run_pending = 0;
if (status == NVMX_VMENTRY_KVM_INTERNAL_ERROR) if (status == NVMX_VMENTRY_KVM_INTERNAL_ERROR) {
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
return 0; return 0;
}
if (status == NVMX_VMENTRY_VMEXIT) if (status == NVMX_VMENTRY_VMEXIT)
return 1; return 1;
WARN_ON_ONCE(status != NVMX_VMENTRY_VMFAIL); WARN_ON_ONCE(status != NVMX_VMENTRY_VMFAIL);

View File

@ -187,6 +187,9 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
int ret; int ret;
switch (msr) { switch (msr) {
case MSR_CORE_PERF_GLOBAL_STATUS:
case MSR_CORE_PERF_GLOBAL_CTRL:
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
case MSR_CORE_PERF_FIXED_CTR_CTRL: case MSR_CORE_PERF_FIXED_CTR_CTRL:
return kvm_pmu_has_perf_global_ctrl(pmu); return kvm_pmu_has_perf_global_ctrl(pmu);
case MSR_IA32_PEBS_ENABLE: case MSR_IA32_PEBS_ENABLE:

View File

@ -1995,7 +1995,7 @@ static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu)
if (kvm_vcpu_has_events(vcpu) || signal_pending(current)) if (kvm_vcpu_has_events(vcpu) || signal_pending(current))
break; break;
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) { if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu)) {
ret = -EIO; ret = -EIO;
break; break;
} }

View File

@ -8060,7 +8060,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
bool req_immediate_exit = false; bool req_immediate_exit = false;
if (kvm_request_pending(vcpu)) { if (kvm_request_pending(vcpu)) {
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) { if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu)) {
r = -EIO; r = -EIO;
goto out; goto out;
} }
@ -8072,6 +8072,10 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) { if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
if (unlikely(!kvm_nested_call(get_nested_state_pages)(vcpu))) { if (unlikely(!kvm_nested_call(get_nested_state_pages)(vcpu))) {
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
r = 0; r = 0;
goto out; goto out;
} }

View File

@ -886,6 +886,105 @@ static void quirk_clear_strap_no_soft_reset_dev2_f0(struct pci_dev *dev)
} }
} }
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15b8, quirk_clear_strap_no_soft_reset_dev2_f0); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15b8, quirk_clear_strap_no_soft_reset_dev2_f0);
/*
* Enhanced atomic operations can cause corruption with 64-bit DMA
* on these devices.
*/
#define RX_ENH_ATOMIC_EN BIT(8)
static const u32 nbio_7_7_pcie_smn_addrs[] = {
0x111401d0,
0x111411d0,
0x111421d0,
0x111431d0,
0x111441d0,
0x112401d0,
0x112411d0,
0x112421d0,
0x112431d0,
0x112441d0,
0x112451d0,
0x113401d0,
0x114401d0,
};
static const u32 nbio_7_11_pcie_smn_addrs[] = {
0x112401d0,
0x112411d0,
0x112421d0,
0x112431d0,
0x112441d0,
0x112451d0,
0x113401d0,
0x113411d0,
0x113421d0,
0x113431d0,
0x113441d0,
0x113451d0,
};
static void quirk_amd_nbio_enhanced_atomic(struct pci_dev *host_bridge,
const u32 *smn_addrs,
size_t nr_smn_addrs)
{
bool changed = false;
size_t i;
u32 data;
int ret;
for (i = 0; i < nr_smn_addrs; i++) {
ret = amd_smn_read(0, smn_addrs[i], &data);
if (ret)
continue;
if (!(data & RX_ENH_ATOMIC_EN))
continue;
data = data & ~RX_ENH_ATOMIC_EN;
ret = amd_smn_write(0, smn_addrs[i], data);
if (ret)
continue;
if (changed)
continue;
ret = amd_smn_read(0, smn_addrs[i], &data);
if (ret)
continue;
if (data & RX_ENH_ATOMIC_EN)
continue;
changed = true;
}
if (changed)
pci_info(host_bridge, "enhanced atomics disabled\n");
}
static void quirk_amd_nbio_7_7_disable_enhanced_atomic(struct pci_dev *dev)
{
quirk_amd_nbio_enhanced_atomic(dev, nbio_7_7_pcie_smn_addrs,
ARRAY_SIZE(nbio_7_7_pcie_smn_addrs));
}
static void quirk_amd_nbio_7_11_disable_enhanced_atomic(struct pci_dev *dev)
{
quirk_amd_nbio_enhanced_atomic(dev, nbio_7_11_pcie_smn_addrs,
ARRAY_SIZE(nbio_7_11_pcie_smn_addrs));
}
/* Phoenix, Hawk Point (NBIO 7.7) */
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x14E8,
quirk_amd_nbio_7_7_disable_enhanced_atomic);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x14E8,
quirk_amd_nbio_7_7_disable_enhanced_atomic);
/* Strix, Krackan, Strix Halo (NBIO 7.11) */
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1507,
quirk_amd_nbio_7_11_disable_enhanced_atomic);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1507,
quirk_amd_nbio_7_11_disable_enhanced_atomic);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1122,
quirk_amd_nbio_7_11_disable_enhanced_atomic);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1122,
quirk_amd_nbio_7_11_disable_enhanced_atomic);
#endif #endif
/* /*

View File

@ -2018,12 +2018,17 @@ static int disk_revalidate_zone_resources(struct gendisk *disk,
struct blk_revalidate_zone_args *args) struct blk_revalidate_zone_args *args)
{ {
struct queue_limits *lim = &disk->queue->limits; struct queue_limits *lim = &disk->queue->limits;
unsigned long long nr_zones;
unsigned int pool_size; unsigned int pool_size;
int ret = 0; int ret = 0;
args->disk = disk; args->disk = disk;
args->nr_zones = nr_zones = DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors);
DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors); if (nr_zones > UINT_MAX) {
pr_warn("%s: Too many zones (%llu)\n", disk->disk_name, nr_zones);
return -EINVAL;
}
args->nr_zones = nr_zones;
/* Cached zone conditions: 1 byte per zone */ /* Cached zone conditions: 1 byte per zone */
args->zones_cond = kzalloc(args->nr_zones, GFP_NOIO); args->zones_cond = kzalloc(args->nr_zones, GFP_NOIO);
@ -2131,6 +2136,12 @@ static int blk_revalidate_zone_cond(struct blk_zone *zone, unsigned int idx,
{ {
enum blk_zone_cond cond = zone->cond; enum blk_zone_cond cond = zone->cond;
if (idx >= args->nr_zones) {
pr_warn("%s: Zone report index %u exceeds zone count %u\n",
args->disk->disk_name, idx, args->nr_zones);
return -EINVAL;
}
/* Check that the zone condition is consistent with the zone type. */ /* Check that the zone condition is consistent with the zone type. */
switch (cond) { switch (cond) {
case BLK_ZONE_COND_NOT_WP: case BLK_ZONE_COND_NOT_WP:

View File

@ -515,6 +515,7 @@ void ivpu_prepare_for_reset(struct ivpu_device *vdev)
{ {
ivpu_hw_irq_disable(vdev); ivpu_hw_irq_disable(vdev);
disable_irq(vdev->irq); disable_irq(vdev->irq);
atomic_set(&vdev->job_timeout_detected, 0);
flush_work(&vdev->irq_dct_work); flush_work(&vdev->irq_dct_work);
flush_work(&vdev->context_abort_work); flush_work(&vdev->context_abort_work);
flush_work(&vdev->job_destroy_work); flush_work(&vdev->job_destroy_work);
@ -710,7 +711,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID; vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID;
atomic64_set(&vdev->unique_id_counter, 0); atomic64_set(&vdev->unique_id_counter, 0);
atomic_set(&vdev->job_timeout_counter, 0); atomic_set(&vdev->job_timeout_counter, 0);
atomic_set(&vdev->faults_detected, 0); atomic_set(&vdev->job_timeout_detected, 0);
xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1); xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1);
xa_init_flags(&vdev->db_xa, XA_FLAGS_ALLOC1); xa_init_flags(&vdev->db_xa, XA_FLAGS_ALLOC1);

View File

@ -171,7 +171,7 @@ struct ivpu_device {
struct xarray submitted_jobs_xa; struct xarray submitted_jobs_xa;
struct ivpu_ipc_consumer job_done_consumer; struct ivpu_ipc_consumer job_done_consumer;
atomic_t job_timeout_counter; atomic_t job_timeout_counter;
atomic_t faults_detected; atomic_t job_timeout_detected;
atomic64_t unique_id_counter; atomic64_t unique_id_counter;

View File

@ -621,7 +621,6 @@ bool ivpu_job_handle_engine_error(struct ivpu_device *vdev, u32 job_id, u32 job_
* status and ensure both are handled in the same way * status and ensure both are handled in the same way
*/ */
job->file_priv->has_mmu_faults = true; job->file_priv->has_mmu_faults = true;
atomic_set(&vdev->faults_detected, 1);
queue_work(system_percpu_wq, &vdev->context_abort_work); queue_work(system_percpu_wq, &vdev->context_abort_work);
return true; return true;
} }
@ -1175,10 +1174,10 @@ static int reset_engine_and_mark_faulty_contexts(struct ivpu_device *vdev)
return ret; return ret;
/* /*
* If faults are detected, ignore guilty contexts from engine reset as NPU may not be stuck * If job timeout is detected, read guilty context from engine reset, for other reasons
* and could return currently running good context and faulty contexts are already marked * faulty context is already known
*/ */
if (atomic_cmpxchg(&vdev->faults_detected, 1, 0) == 1) if (atomic_cmpxchg(&vdev->job_timeout_detected, 1, 0) == 0)
return 0; return 0;
num_impacted_contexts = resp.payload.engine_reset_done.num_impacted_contexts; num_impacted_contexts = resp.payload.engine_reset_done.num_impacted_contexts;

View File

@ -964,7 +964,6 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev)
file_priv = xa_load(&vdev->context_xa, ssid); file_priv = xa_load(&vdev->context_xa, ssid);
if (file_priv) { if (file_priv) {
if (!READ_ONCE(file_priv->has_mmu_faults)) { if (!READ_ONCE(file_priv->has_mmu_faults)) {
atomic_set(&vdev->faults_detected, 1);
ivpu_mmu_dump_event(vdev, event); ivpu_mmu_dump_event(vdev, event);
WRITE_ONCE(file_priv->has_mmu_faults, true); WRITE_ONCE(file_priv->has_mmu_faults, true);
} }

View File

@ -229,6 +229,7 @@ static void ivpu_job_timeout_work(struct work_struct *work)
ivpu_jsm_state_dump(vdev); ivpu_jsm_state_dump(vdev);
ivpu_dev_coredump(vdev); ivpu_dev_coredump(vdev);
atomic_set(&vdev->job_timeout_detected, 1);
queue_work(system_percpu_wq, &vdev->context_abort_work); queue_work(system_percpu_wq, &vdev->context_abort_work);
} }

View File

@ -2972,9 +2972,10 @@ static void ata_dev_config_lpm(struct ata_device *dev)
(dev->id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2) (dev->id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2)
dev->quirks |= ATA_QUIRK_NOLPM; dev->quirks |= ATA_QUIRK_NOLPM;
/* ATI specific quirk */ /* ATI and AMD specific quirk */
if ((dev->quirks & ATA_QUIRK_NO_LPM_ON_ATI) && if ((dev->quirks & ATA_QUIRK_NO_LPM_ON_ATI_AND_AMD) &&
ata_dev_check_adapter(dev, PCI_VENDOR_ID_ATI)) (ata_dev_check_adapter(dev, PCI_VENDOR_ID_ATI) ||
ata_dev_check_adapter(dev, PCI_VENDOR_ID_AMD)))
dev->quirks |= ATA_QUIRK_NOLPM; dev->quirks |= ATA_QUIRK_NOLPM;
} }
@ -4136,7 +4137,7 @@ static const char * const ata_quirk_names[] = {
[__ATA_QUIRK_MAX_SEC] = "maxsec", [__ATA_QUIRK_MAX_SEC] = "maxsec",
[__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m", [__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m",
[__ATA_QUIRK_NO_NCQ_ON_ATI] = "noncqonati", [__ATA_QUIRK_NO_NCQ_ON_ATI] = "noncqonati",
[__ATA_QUIRK_NO_LPM_ON_ATI] = "nolpmonati", [__ATA_QUIRK_NO_LPM_ON_ATI_AND_AMD] = "nolpmonatiandamd",
[__ATA_QUIRK_NO_ID_DEV_LOG] = "noiddevlog", [__ATA_QUIRK_NO_ID_DEV_LOG] = "noiddevlog",
[__ATA_QUIRK_NO_LOG_DIR] = "nologdir", [__ATA_QUIRK_NO_LOG_DIR] = "nologdir",
[__ATA_QUIRK_NO_FUA] = "nofua", [__ATA_QUIRK_NO_FUA] = "nofua",
@ -4420,15 +4421,15 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
{ "Samsung SSD 860*", NULL, ATA_QUIRK_NO_NCQ_TRIM | { "Samsung SSD 860*", NULL, ATA_QUIRK_NO_NCQ_TRIM |
ATA_QUIRK_ZERO_AFTER_TRIM | ATA_QUIRK_ZERO_AFTER_TRIM |
ATA_QUIRK_NO_NCQ_ON_ATI | ATA_QUIRK_NO_NCQ_ON_ATI |
ATA_QUIRK_NO_LPM_ON_ATI }, ATA_QUIRK_NO_LPM_ON_ATI_AND_AMD },
{ "Samsung SSD 870*", NULL, ATA_QUIRK_NO_NCQ_TRIM | { "Samsung SSD 870*", NULL, ATA_QUIRK_NO_NCQ_TRIM |
ATA_QUIRK_ZERO_AFTER_TRIM | ATA_QUIRK_ZERO_AFTER_TRIM |
ATA_QUIRK_NO_NCQ_ON_ATI | ATA_QUIRK_NO_NCQ_ON_ATI |
ATA_QUIRK_NO_LPM_ON_ATI }, ATA_QUIRK_NO_LPM_ON_ATI_AND_AMD },
{ "SAMSUNG*MZ7LH*", NULL, ATA_QUIRK_NO_NCQ_TRIM | { "SAMSUNG*MZ7LH*", NULL, ATA_QUIRK_NO_NCQ_TRIM |
ATA_QUIRK_ZERO_AFTER_TRIM | ATA_QUIRK_ZERO_AFTER_TRIM |
ATA_QUIRK_NO_NCQ_ON_ATI | ATA_QUIRK_NO_NCQ_ON_ATI |
ATA_QUIRK_NO_LPM_ON_ATI }, ATA_QUIRK_NO_LPM_ON_ATI_AND_AMD },
{ "FCCT*M500*", NULL, ATA_QUIRK_NO_NCQ_TRIM | { "FCCT*M500*", NULL, ATA_QUIRK_NO_NCQ_TRIM |
ATA_QUIRK_ZERO_AFTER_TRIM }, ATA_QUIRK_ZERO_AFTER_TRIM },

View File

@ -261,12 +261,18 @@ static void ata_scsi_set_passthru_sense_fields(struct ata_queued_cmd *qc)
/* descriptor format */ /* descriptor format */
len = sb[7]; len = sb[7];
desc = (char *)scsi_sense_desc_find(sb, len + 8, 9); desc = (char *)scsi_sense_desc_find(sb, SCSI_SENSE_BUFFERSIZE, 9);
if (!desc) { if (!desc) {
if (SCSI_SENSE_BUFFERSIZE < len + 14) /*
* The descriptor is written at sb[8 + len] and is 14
* bytes long, so it needs len + 22 bytes of buffer.
*/
if (len + 22 > SCSI_SENSE_BUFFERSIZE)
return; return;
sb[7] = len + 14; sb[7] = len + 14;
desc = sb + 8 + len; desc = sb + 8 + len;
} else if (desc - sb > SCSI_SENSE_BUFFERSIZE - 14) {
return;
} }
desc[0] = 9; desc[0] = 9;
desc[1] = 12; desc[1] = 12;

View File

@ -1040,9 +1040,10 @@ static int cacheinfo_cpu_online(unsigned int cpu)
rc = cache_add_dev(cpu); rc = cache_add_dev(cpu);
if (rc) if (rc)
goto err; goto err;
if (cpu_map_shared_cache(true, cpu, &cpu_map)) if (cpu_map_shared_cache(true, cpu, &cpu_map)) {
update_per_cpu_data_slice_size(true, cpu, cpu_map); update_per_cpu_data_slice_size(true, cpu, cpu_map);
sched_update_llc_bytes(cpu); sched_update_llc_bytes(cpu_map);
}
return 0; return 0;
err: err:
free_cache_attributes(cpu); free_cache_attributes(cpu);
@ -1059,10 +1060,10 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu)
cpu_cache_sysfs_exit(cpu); cpu_cache_sysfs_exit(cpu);
free_cache_attributes(cpu); free_cache_attributes(cpu);
if (nr_shared > 1) if (nr_shared > 1) {
update_per_cpu_data_slice_size(false, cpu, cpu_map); update_per_cpu_data_slice_size(false, cpu, cpu_map);
sched_update_llc_bytes(cpu_map);
sched_update_llc_bytes(cpu); }
return 0; return 0;
} }

View File

@ -289,7 +289,8 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
goto unlock; goto unlock;
} }
bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1)); bt_dev_err(hdev, "Exception info %.*s", (int)(skb->len - 1),
(char *)(skb->data + 1));
kfree_skb(skb); kfree_skb(skb);
@ -408,8 +409,16 @@ int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
/* DDC file contains one or more DDC structure which has /* DDC file contains one or more DDC structure which has
* Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
*/ */
while (fw->size > fw_ptr - fw->data) { while (fw->size > (size_t)(fw_ptr - fw->data)) {
u8 cmd_plen = fw_ptr[0] + sizeof(u8); size_t remaining = fw->size - (fw_ptr - fw->data);
unsigned int cmd_plen = fw_ptr[0] + 1U;
if (cmd_plen < 3 || cmd_plen > U8_MAX || cmd_plen > remaining) {
bt_dev_err(hdev, "Malformed DDC record (plen=%u, remaining=%zu)",
cmd_plen, remaining);
release_firmware(fw);
return -EINVAL;
}
skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr, skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
HCI_INIT_TIMEOUT); HCI_INIT_TIMEOUT);

View File

@ -1197,7 +1197,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
{ {
int ret; int ret;
u8 pkt_type; u8 pkt_type;
u16 plen; u32 plen;
u32 pcie_pkt_type; u32 pcie_pkt_type;
void *pdata; void *pdata;
struct hci_dev *hdev = data->hdev; struct hci_dev *hdev = data->hdev;
@ -2219,6 +2219,16 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags)) if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags))
return -ENODEV; return -ENODEV;
/* Account for the 4-byte PCIe type header prepended before the
* DMA copy. Written as a subtraction to avoid wrap-around on
* attacker-controlled skb->len.
*/
if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) {
bt_dev_err(hdev, "Packet too large: %u > %u", skb->len,
BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN);
return -EMSGSIZE;
}
/* Due to the fw limitation, the type header of the packet should be /* Due to the fw limitation, the type header of the packet should be
* 4 bytes unlike 1 byte for UART. In UART, the firmware can read * 4 bytes unlike 1 byte for UART. In UART, the firmware can read
* the first byte to get the packet type and redirect the rest of data * the first byte to get the packet type and redirect the rest of data

View File

@ -1397,8 +1397,10 @@ static void iso_resource_auto_work(struct work_struct *work)
} else { } else {
// Transit from allocation to reallocation, except if the client requested // Transit from allocation to reallocation, except if the client requested
// deallocation in the meantime. // deallocation in the meantime.
scoped_guard(spinlock_irq, &client->lock) scoped_guard(spinlock_irq, &client->lock) {
r->todo = ISO_RES_AUTO_REALLOC; if (r->todo == ISO_RES_AUTO_ALLOC)
r->todo = ISO_RES_AUTO_REALLOC;
}
if (channel >= 0) if (channel >= 0)
r->params.channels_mask = BIT_ULL(channel); r->params.channels_mask = BIT_ULL(channel);

View File

@ -115,8 +115,12 @@ static int arizona_gpio_direction_out(struct gpio_chip *chip,
if (value) if (value)
value = ARIZONA_GPN_LVL; value = ARIZONA_GPN_LVL;
return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, ret = regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value); ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
if (ret < 0 && (val & ARIZONA_GPN_DIR) && persistent)
pm_runtime_put_autosuspend(chip->parent);
return ret;
} }
static int arizona_gpio_set(struct gpio_chip *chip, unsigned int offset, static int arizona_gpio_set(struct gpio_chip *chip, unsigned int offset,

View File

@ -1034,6 +1034,8 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
static int mvebu_gpio_resume(struct platform_device *pdev) static int mvebu_gpio_resume(struct platform_device *pdev)
{ {
struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev); struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
u32 edge_cache = ~0U, level_cache = ~0U;
unsigned long flags;
int i; int i;
regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
@ -1045,32 +1047,51 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
mvchip->in_pol_reg); mvchip->in_pol_reg);
/*
* genirq skips mask_irq() for a line it already considers masked, so
* unmasking one behind its back leaves an asserted level line that
* nobody masks. Restore only bits the irqchip cache still has set.
*
* Snapshot the caches under the raw spinlock, but release it before
* the regmap writes below: regmap_write() takes a sleepable lock on
* PREEMPT_RT.
*/
if (mvchip->domain) {
struct irq_chip_generic *gc;
gc = irq_get_domain_generic_chip(mvchip->domain, 0);
raw_spin_lock_irqsave(&gc->lock, flags);
level_cache = gc->chip_types[0].mask_cache_priv;
edge_cache = gc->chip_types[1].mask_cache_priv;
raw_spin_unlock_irqrestore(&gc->lock, flags);
}
switch (mvchip->soc_variant) { switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION: case MVEBU_GPIO_SOC_VARIANT_ORION:
case MVEBU_GPIO_SOC_VARIANT_A8K: case MVEBU_GPIO_SOC_VARIANT_A8K:
regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset, regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
mvchip->edge_mask_regs[0]); mvchip->edge_mask_regs[0] & edge_cache);
regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset, regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
mvchip->level_mask_regs[0]); mvchip->level_mask_regs[0] & level_cache);
break; break;
case MVEBU_GPIO_SOC_VARIANT_MV78200: case MVEBU_GPIO_SOC_VARIANT_MV78200:
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
regmap_write(mvchip->regs, regmap_write(mvchip->regs,
GPIO_EDGE_MASK_MV78200_OFF(i), GPIO_EDGE_MASK_MV78200_OFF(i),
mvchip->edge_mask_regs[i]); mvchip->edge_mask_regs[i] & edge_cache);
regmap_write(mvchip->regs, regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_MV78200_OFF(i), GPIO_LEVEL_MASK_MV78200_OFF(i),
mvchip->level_mask_regs[i]); mvchip->level_mask_regs[i] & level_cache);
} }
break; break;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
regmap_write(mvchip->regs, regmap_write(mvchip->regs,
GPIO_EDGE_MASK_ARMADAXP_OFF(i), GPIO_EDGE_MASK_ARMADAXP_OFF(i),
mvchip->edge_mask_regs[i]); mvchip->edge_mask_regs[i] & edge_cache);
regmap_write(mvchip->regs, regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_ARMADAXP_OFF(i), GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
mvchip->level_mask_regs[i]); mvchip->level_mask_regs[i] & level_cache);
} }
break; break;
default: default:

View File

@ -79,7 +79,7 @@ static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
if (ret) if (ret)
return ret; return ret;
ret = !!(val & BIT(TPS65219_MFP_GPIO_STATUS_MASK)); ret = !!(val & TPS65219_MFP_GPIO_STATUS_MASK);
dev_warn(dev, "GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n", offset, ret); dev_warn(dev, "GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n", offset, ret);
/* /*
@ -87,7 +87,7 @@ static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
* status bit. * status bit.
*/ */
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT) if (gc->get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
return -ENOTSUPP; return -ENOTSUPP;
return ret; return ret;
@ -158,8 +158,10 @@ static int tps65214_gpio_change_direction(struct gpio_chip *gc, unsigned int off
if (ret) if (ret)
dev_err(dev, "GPIO%d configured as VSEL, not GPIO\n", offset); dev_err(dev, "GPIO%d configured as VSEL, not GPIO\n", offset);
val = direction == GPIO_LINE_DIRECTION_OUT ?
TPS65214_GPIO0_DIR_MASK : 0;
ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_GENERAL_CONFIG, ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_GENERAL_CONFIG,
TPS65214_GPIO0_DIR_MASK, direction); TPS65214_GPIO0_DIR_MASK, val);
if (ret) if (ret)
dev_err(dev, "Fail to change direction to %u for GPIO%d.\n", direction, offset); dev_err(dev, "Fail to change direction to %u for GPIO%d.\n", direction, offset);
@ -176,7 +178,7 @@ static int tps65219_gpio_direction_input(struct gpio_chip *gc, unsigned int offs
return -ENOTSUPP; return -ENOTSUPP;
} }
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_IN) if (gc->get_direction(gc, offset) == GPIO_LINE_DIRECTION_IN)
return 0; return 0;
return gpio->change_dir(gc, offset, GPIO_LINE_DIRECTION_IN); return gpio->change_dir(gc, offset, GPIO_LINE_DIRECTION_IN);
@ -190,7 +192,7 @@ static int tps65219_gpio_direction_output(struct gpio_chip *gc, unsigned int off
if (offset != TPS6521X_GPIO0_IDX) if (offset != TPS6521X_GPIO0_IDX)
return 0; return 0;
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT) if (gc->get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
return 0; return 0;
return gpio->change_dir(gc, offset, GPIO_LINE_DIRECTION_OUT); return gpio->change_dir(gc, offset, GPIO_LINE_DIRECTION_OUT);

View File

@ -798,15 +798,7 @@ static int zynq_gpio_runtime_resume(struct device *dev)
static int zynq_gpio_request(struct gpio_chip *chip, unsigned int offset) static int zynq_gpio_request(struct gpio_chip *chip, unsigned int offset)
{ {
int ret; return pm_runtime_resume_and_get(chip->parent);
ret = pm_runtime_get_sync(chip->parent);
/*
* If the device is already active pm_runtime_get() will return 1 on
* success, but gpio_request still needs to return 0.
*/
return ret < 0 ? ret : 0;
} }
static void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset) static void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset)

View File

@ -2172,18 +2172,19 @@ static void gpio_v2_line_info_changed_to_v1(
#endif /* CONFIG_GPIO_CDEV_V1 */ #endif /* CONFIG_GPIO_CDEV_V1 */
static void gpio_desc_to_lineinfo(struct gpio_desc *desc, static int gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpio_v2_line_info *info, bool atomic) struct gpio_v2_line_info *info, bool atomic)
{ {
u32 debounce_period_us; u32 debounce_period_us;
unsigned long dflags; unsigned long dflags;
const char *label; const char *label;
memset(info, 0, sizeof(*info));
CLASS(gpio_chip_guard, guard)(desc); CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc) if (!guard.gc)
return; return -ENODEV;
memset(info, 0, sizeof(*info));
info->offset = gpiod_hwgpio(desc); info->offset = gpiod_hwgpio(desc);
if (desc->name) if (desc->name)
@ -2258,6 +2259,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
debounce_period_us; debounce_period_us;
info->num_attrs++; info->num_attrs++;
} }
return 0;
} }
struct gpio_chardev_data { struct gpio_chardev_data {
@ -2309,6 +2312,7 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
struct gpio_desc *desc; struct gpio_desc *desc;
struct gpioline_info lineinfo; struct gpioline_info lineinfo;
struct gpio_v2_line_info lineinfo_v2; struct gpio_v2_line_info lineinfo_v2;
int ret;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT; return -EFAULT;
@ -2326,7 +2330,10 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
return -EBUSY; return -EBUSY;
} }
gpio_desc_to_lineinfo(desc, &lineinfo_v2, false); ret = gpio_desc_to_lineinfo(desc, &lineinfo_v2, false);
if (ret)
return ret;
gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo); gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
@ -2344,6 +2351,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
struct gpio_v2_line_info lineinfo; struct gpio_v2_line_info lineinfo;
int ret;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT; return -EFAULT;
@ -2363,7 +2371,10 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
if (test_and_set_bit(lineinfo.offset, cdev->watched_lines)) if (test_and_set_bit(lineinfo.offset, cdev->watched_lines))
return -EBUSY; return -EBUSY;
} }
gpio_desc_to_lineinfo(desc, &lineinfo, false);
ret = gpio_desc_to_lineinfo(desc, &lineinfo, false);
if (ret)
return ret;
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) {
if (watch) if (watch)
@ -2489,6 +2500,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
struct lineinfo_changed_ctx *ctx; struct lineinfo_changed_ctx *ctx;
struct gpio_desc *desc = data; struct gpio_desc *desc = data;
struct file *fp; struct file *fp;
int ret;
if (!test_bit(gpiod_hwgpio(desc), cdev->watched_lines)) if (!test_bit(gpiod_hwgpio(desc), cdev->watched_lines))
return NOTIFY_DONE; return NOTIFY_DONE;
@ -2519,7 +2531,13 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
ctx->chg.event_type = action; ctx->chg.event_type = action;
ctx->chg.timestamp_ns = ktime_get_ns(); ctx->chg.timestamp_ns = ktime_get_ns();
gpio_desc_to_lineinfo(desc, &ctx->chg.info, true);
ret = gpio_desc_to_lineinfo(desc, &ctx->chg.info, true);
if (ret) {
fput(fp);
return NOTIFY_DONE;
}
/* Keep the GPIO device alive until we emit the event. */ /* Keep the GPIO device alive until we emit the event. */
ctx->gdev = gpio_device_get(desc->gdev); ctx->gdev = gpio_device_get(desc->gdev);
ctx->cdev = cdev; ctx->cdev = cdev;

View File

@ -1029,6 +1029,13 @@ int gpiochip_add_hog(struct gpio_chip *gc, struct fwnode_handle *fwnode)
ret = of_gpiochip_get_lflags(gc, &gpiospec, &lflags); ret = of_gpiochip_get_lflags(gc, &gpiospec, &lflags);
if (ret) if (ret)
return ret; return ret;
/*
* If no line-name property is present, fall back to the OF
* node name as in the previous implementation.
*/
if (!name)
name = to_of_node(fwnode)->name;
} else { } else {
/* /*
* GPIO_ACTIVE_LOW is currently the only lookup flag * GPIO_ACTIVE_LOW is currently the only lookup flag

View File

@ -1167,8 +1167,10 @@ int amdgpu_acpi_enumerate_xcc(void)
} }
xcc_info = kzalloc_obj(struct amdgpu_acpi_xcc_info); xcc_info = kzalloc_obj(struct amdgpu_acpi_xcc_info);
if (!xcc_info) if (!xcc_info) {
acpi_dev_put(acpi_dev);
return -ENOMEM; return -ENOMEM;
}
INIT_LIST_HEAD(&xcc_info->list); INIT_LIST_HEAD(&xcc_info->list);
xcc_info->handle = acpi_device_handle(acpi_dev); xcc_info->handle = acpi_device_handle(acpi_dev);

View File

@ -1780,8 +1780,10 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused)
/* Avoid accidently unparking the sched thread during GPU reset */ /* Avoid accidently unparking the sched thread during GPU reset */
r = down_write_killable(&adev->reset_domain->sem); r = down_write_killable(&adev->reset_domain->sem);
if (r) if (r) {
pm_runtime_put_autosuspend(dev->dev);
return r; return r;
}
/* hold on the scheduler */ /* hold on the scheduler */
for (i = 0; i < AMDGPU_MAX_RINGS; i++) { for (i = 0; i < AMDGPU_MAX_RINGS; i++) {

View File

@ -68,6 +68,9 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work)
mutex_lock(&uq_mgr->userq_mutex); mutex_lock(&uq_mgr->userq_mutex);
/* Fence waits are not allowed in a fence signalling critical section. */
amdgpu_userq_wait_for_signal(uq_mgr);
/* /*
* This is intentionally after taking the userq_mutex since we do * This is intentionally after taking the userq_mutex since we do
* allocate memory while holding this lock, but only after ensuring that * allocate memory while holding this lock, but only after ensuring that

View File

@ -254,7 +254,6 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
ring->adev = adev; ring->adev = adev;
ring->num_hw_submission = sched_hw_submission; ring->num_hw_submission = sched_hw_submission;
ring->sched_score = sched_score; ring->sched_score = sched_score;
ring->vmid_wait = dma_fence_get_stub();
ring->idx = adev->num_rings++; ring->idx = adev->num_rings++;
adev->rings[ring->idx] = ring; adev->rings[ring->idx] = ring;
@ -374,6 +373,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
ring->max_dw = max_dw; ring->max_dw = max_dw;
ring->hw_prio = hw_prio; ring->hw_prio = hw_prio;
ring->vmid_wait = dma_fence_get_stub();
if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) { if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) {
hw_ip = ring->funcs->type; hw_ip = ring->funcs->type;

View File

@ -184,27 +184,27 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work)
void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue) void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue)
{ {
struct amdgpu_device *adev; struct amdgpu_device *adev;
unsigned long timeout_ms; unsigned long timeout_jiffies;
adev = queue->userq_mgr->adev; adev = queue->userq_mgr->adev;
/* Determine timeout based on queue type */ /* Determine timeout based on queue type */
switch (queue->queue_type) { switch (queue->queue_type) {
case AMDGPU_RING_TYPE_GFX: case AMDGPU_RING_TYPE_GFX:
timeout_ms = adev->gfx_timeout; timeout_jiffies = adev->gfx_timeout;
break; break;
case AMDGPU_RING_TYPE_COMPUTE: case AMDGPU_RING_TYPE_COMPUTE:
timeout_ms = adev->compute_timeout; timeout_jiffies = adev->compute_timeout;
break; break;
case AMDGPU_RING_TYPE_SDMA: case AMDGPU_RING_TYPE_SDMA:
timeout_ms = adev->sdma_timeout; timeout_jiffies = adev->sdma_timeout;
break; break;
default: default:
timeout_ms = adev->gfx_timeout; timeout_jiffies = adev->gfx_timeout;
break; break;
} }
queue_delayed_work(adev->reset_domain->wq, &queue->hang_detect_work, queue_delayed_work(adev->reset_domain->wq, &queue->hang_detect_work,
msecs_to_jiffies(timeout_ms)); timeout_jiffies);
} }
void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell) void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
@ -1272,7 +1272,7 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
return ret; return ret;
} }
static void void
amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr) amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
{ {
struct amdgpu_usermode_queue *queue; struct amdgpu_usermode_queue *queue;
@ -1291,8 +1291,6 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
void void
amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr) amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr)
{ {
/* Wait for any pending userqueue fence work to finish */
amdgpu_userq_wait_for_signal(uq_mgr);
amdgpu_userq_evict_all(uq_mgr); amdgpu_userq_evict_all(uq_mgr);
} }

View File

@ -162,6 +162,7 @@ void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev);
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr); void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr);
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr); void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr);
void amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr);
void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr); void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr);
void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr, void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr,

View File

@ -2678,6 +2678,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
amdgpu_bo_unref(&root_bo); amdgpu_bo_unref(&root_bo);
error_free_delayed: error_free_delayed:
dma_fence_put(vm->last_update);
dma_fence_put(vm->last_tlb_flush); dma_fence_put(vm->last_tlb_flush);
dma_fence_put(vm->last_unlocked); dma_fence_put(vm->last_unlocked);
ttm_lru_bulk_move_fini(&adev->mman.bdev, &vm->lru_bulk_move); ttm_lru_bulk_move_fini(&adev->mman.bdev, &vm->lru_bulk_move);

View File

@ -1689,7 +1689,8 @@ static int vcn_v4_0_3_reset_jpeg_pre_helper(struct amdgpu_device *adev, int inst
/* if Jobs are still pending after timeout, /* if Jobs are still pending after timeout,
* We'll handle them in the bottom helper * We'll handle them in the bottom helper
*/ */
amdgpu_fence_wait_polling(ring, wait_seq, adev->video_timeout); amdgpu_fence_wait_polling(ring, wait_seq,
jiffies_to_usecs(adev->video_timeout));
} }
return 0; return 0;

View File

@ -1335,7 +1335,8 @@ static int vcn_v5_0_1_reset_jpeg_pre_helper(struct amdgpu_device *adev, int inst
/* if Jobs are still pending after timeout, /* if Jobs are still pending after timeout,
* We'll handle them in the bottom helper * We'll handle them in the bottom helper
*/ */
amdgpu_fence_wait_polling(ring, wait_seq, adev->video_timeout); amdgpu_fence_wait_polling(ring, wait_seq,
jiffies_to_usecs(adev->video_timeout));
} }
return 0; return 0;

View File

@ -35,6 +35,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/pseudo_fs.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/dma-buf.h> #include <linux/dma-buf.h>
#include <linux/processor.h> #include <linux/processor.h>
@ -70,18 +71,54 @@ static const struct class kfd_class = {
}; };
/* /*
* Cache the address space of the chardev on first open so that the reset * Private pseudo-filesystem for KFD, Provides a stable, module-owned
* path can drop all userspace mappings of doorbell and MMIO ranges via * inode whose address_space is the unmap target for all /dev/kfd
* unmap_mapping_range(). * openers during GPU reset.
*/ */
static struct address_space *kfd_dev_mapping; static struct vfsmount *kfd_fs_mnt;
static int kfd_fs_cnt;
static int kfd_fs_init_fs_context(struct fs_context *fc)
{
return init_pseudo(fc, 0x4b464400 /* "KFD" */) ? 0 : -ENOMEM;
}
static struct file_system_type kfd_fs_type = {
.name = "kfd",
.init_fs_context = kfd_fs_init_fs_context,
.kill_sb = kill_anon_super,
};
static struct inode *kfd_fs_inode_new(void)
{
struct inode *inode;
int r;
r = simple_pin_fs(&kfd_fs_type, &kfd_fs_mnt, &kfd_fs_cnt);
if (r < 0)
return ERR_PTR(r);
inode = alloc_anon_inode(kfd_fs_mnt->mnt_sb);
if (IS_ERR(inode))
simple_release_fs(&kfd_fs_mnt, &kfd_fs_cnt);
return inode;
}
static void kfd_fs_inode_free(struct inode *inode)
{
if (inode) {
iput(inode);
simple_release_fs(&kfd_fs_mnt, &kfd_fs_cnt);
}
}
static struct inode *kfd_anon_inode;
void kfd_dev_unmap_mapping_range(loff_t const holebegin, loff_t const holelen) void kfd_dev_unmap_mapping_range(loff_t const holebegin, loff_t const holelen)
{ {
struct address_space *mapping = READ_ONCE(kfd_dev_mapping); if (kfd_anon_inode)
unmap_mapping_range(kfd_anon_inode->i_mapping, holebegin, holelen, 1);
if (mapping)
unmap_mapping_range(mapping, holebegin, holelen, 1);
} }
static inline struct kfd_process_device *kfd_lock_pdd_by_id(struct kfd_process *p, __u32 gpu_id) static inline struct kfd_process_device *kfd_lock_pdd_by_id(struct kfd_process *p, __u32 gpu_id)
@ -107,6 +144,13 @@ int kfd_chardev_init(void)
{ {
int err = 0; int err = 0;
kfd_anon_inode = kfd_fs_inode_new();
if (IS_ERR(kfd_anon_inode)) {
err = PTR_ERR(kfd_anon_inode);
kfd_anon_inode = NULL;
return err;
}
kfd_char_dev_major = register_chrdev(0, kfd_dev_name, &kfd_fops); kfd_char_dev_major = register_chrdev(0, kfd_dev_name, &kfd_fops);
err = kfd_char_dev_major; err = kfd_char_dev_major;
if (err < 0) if (err < 0)
@ -130,6 +174,8 @@ int kfd_chardev_init(void)
err_class_create: err_class_create:
unregister_chrdev(kfd_char_dev_major, kfd_dev_name); unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
err_register_chrdev: err_register_chrdev:
kfd_fs_inode_free(kfd_anon_inode);
kfd_anon_inode = NULL;
return err; return err;
} }
@ -138,6 +184,8 @@ void kfd_chardev_exit(void)
device_destroy(&kfd_class, MKDEV(kfd_char_dev_major, 0)); device_destroy(&kfd_class, MKDEV(kfd_char_dev_major, 0));
class_unregister(&kfd_class); class_unregister(&kfd_class);
unregister_chrdev(kfd_char_dev_major, kfd_dev_name); unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
kfd_fs_inode_free(kfd_anon_inode);
kfd_anon_inode = NULL;
kfd_device = NULL; kfd_device = NULL;
} }
@ -150,12 +198,7 @@ static int kfd_open(struct inode *inode, struct file *filep)
if (iminor(inode) != 0) if (iminor(inode) != 0)
return -ENODEV; return -ENODEV;
/* filep->f_mapping = kfd_anon_inode->i_mapping;
* /dev/kfd is a single chardev so all opens share one inode. Cache
* its address_space on the first open for use by the reset path.
*/
if (!READ_ONCE(kfd_dev_mapping))
cmpxchg(&kfd_dev_mapping, NULL, inode->i_mapping);
is_32bit_user_mode = in_compat_syscall(); is_32bit_user_mode = in_compat_syscall();

View File

@ -5583,8 +5583,10 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
skip_modeset: skip_modeset:
/* Release extra reference */ /* Release extra reference */
if (new_stream) if (new_stream) {
dc_stream_release(new_stream); dc_stream_release(new_stream);
new_stream = NULL;
}
new_stream = NULL; new_stream = NULL;
/* /*

View File

@ -29,14 +29,14 @@ dml_ccflags := $(CC_FLAGS_FPU)
dml_rcflags := $(CC_FLAGS_NO_FPU) dml_rcflags := $(CC_FLAGS_NO_FPU)
ifneq ($(CONFIG_FRAME_WARN),0) ifneq ($(CONFIG_FRAME_WARN),0)
ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)$(CONFIG_UBSAN)),y)
ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy) ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy)
frame_warn_limit := 4096 frame_warn_limit := 4096
else else
frame_warn_limit := 3072 frame_warn_limit := 3072
endif endif
else else
frame_warn_limit := 2048 frame_warn_limit := 3072
endif endif
ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y) ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y)

View File

@ -28,14 +28,14 @@ dml2_ccflags := $(CC_FLAGS_FPU)
dml2_rcflags := $(CC_FLAGS_NO_FPU) dml2_rcflags := $(CC_FLAGS_NO_FPU)
ifneq ($(CONFIG_FRAME_WARN),0) ifneq ($(CONFIG_FRAME_WARN),0)
ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y) ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)$(CONFIG_UBSAN)),y)
ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy) ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy)
frame_warn_limit := 4096 frame_warn_limit := 4096
else else
frame_warn_limit := 3072 frame_warn_limit := 3072
endif endif
else else
frame_warn_limit := 2056 frame_warn_limit := 3072
endif endif
ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y) ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y)

View File

@ -1862,7 +1862,7 @@ static int samsung_dsim_register_te_irq(struct samsung_dsim *dsi, struct device
int te_gpio_irq; int te_gpio_irq;
int ret; int ret;
dsi->te_gpio = devm_gpiod_get_optional(dev, "te", GPIOD_IN); dsi->te_gpio = gpiod_get_optional(dev, "te", GPIOD_IN);
if (!dsi->te_gpio) if (!dsi->te_gpio)
return 0; return 0;
else if (IS_ERR(dsi->te_gpio)) else if (IS_ERR(dsi->te_gpio))

Some files were not shown because too many files have changed in this diff Show More