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>
Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.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>
Ethan Carter Edwards <ethan@ethancedwards.com> Ethan Edwards <ethancarteredwards@gmail.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.
* 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
allowed.
@ -3512,7 +3512,7 @@ Kernel parameters
* [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.
@ -3543,11 +3543,9 @@ Kernel parameters
* max_sec_128: Set transfer size limit to 128 sectors.
* max_sec_1024: Set or clear transfer size limit to
1024 sectors.
* max_sec_1024: Set transfer size limit to 1024 sectors.
* max_sec_lba48: Set or clear transfer size limit to
65535 sectors.
* max_sec_lba48: Set transfer size limit to 65535 sectors.
* 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
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/:

View File

@ -5143,6 +5143,7 @@ L: netdev@vger.kernel.org
L: openwrt-devel@lists.openwrt.org (subscribers-only)
S: Supported
F: Documentation/devicetree/bindings/net/dsa/brcm,b53.yaml
F: Documentation/networking/dsa/b53.rst
F: drivers/net/dsa/b53/*
F: drivers/net/dsa/bcm_sf2*
F: include/linux/dsa/brcm.h
@ -14907,7 +14908,7 @@ M: Damien Le Moal <dlemoal@kernel.org>
M: Niklas Cassel <cassel@kernel.org>
L: linux-ide@vger.kernel.org
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/devicetree/bindings/ata/
F: drivers/ata/
@ -17210,31 +17211,6 @@ F: include/trace/events/ksm.h
F: mm/ksm.c
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)
M: Andrew Morton <akpm@linux-foundation.org>
R: Kairui Song <kasong@tencent.com>
@ -17257,6 +17233,25 @@ F: include/linux/mmzone.h
F: mm/vmscan.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
M: Andrew Morton <akpm@linux-foundation.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
F: Documentation/ABI/testing/sysfs-kernel-mm
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/admin-guide/mm/
F: Documentation/mm/
@ -17280,7 +17274,6 @@ F: drivers/char/mem.c
F: include/linux/cma.h
F: include/linux/dmapool.h
F: include/linux/ioremap.h
F: include/linux/memory-tiers.h
F: include/linux/page_idle.h
F: mm/backing-dev.c
F: mm/cma.c
@ -17292,7 +17285,6 @@ F: mm/early_ioremap.c
F: mm/fadvise.c
F: mm/ioremap.c
F: mm/mapping_dirty_helpers.c
F: mm/memory-tiers.c
F: mm/page_idle.c
F: mm/pgalloc-track.h
F: mm/process_vm_access.c
@ -17309,6 +17301,27 @@ F: mm/numa.c
F: mm/numa_emulation.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
M: Michal Hocko <mhocko@suse.com>
R: David Rientjes <rientjes@google.com>
@ -18897,7 +18910,7 @@ F: net/core/drop_monitor.c
NETWORKING DRIVERS
M: Andrew Lunn <andrew+netdev@lunn.ch>
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: Paolo Abeni <pabeni@redhat.com>
L: netdev@vger.kernel.org
@ -19014,7 +19027,7 @@ K: struct\s+phy_port|phy_port_
NETWORKING [GENERAL]
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: Paolo Abeni <pabeni@redhat.com>
R: Simon Horman <horms@kernel.org>
@ -19240,7 +19253,7 @@ F: net/ipv6/seg6*
F: tools/testing/selftests/net/srv6*
NETWORKING [TCP]
M: Eric Dumazet <edumazet@google.com>
M: Eric Dumazet <edumazet@kernel.org>
M: Neal Cardwell <ncardwell@google.com>
R: Kuniyuki Iwashima <kuniyu@google.com>
L: netdev@vger.kernel.org
@ -19273,7 +19286,7 @@ F: net/tls/
F: tools/testing/selftests/net/tls.c
NETWORKING [SOCKETS]
M: Eric Dumazet <edumazet@google.com>
M: Eric Dumazet <edumazet@kernel.org>
M: Kuniyuki Iwashima <kuniyu@google.com>
M: Paolo Abeni <pabeni@redhat.com>
M: Willem de Bruijn <willemb@google.com>
@ -20570,6 +20583,7 @@ ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
M: Mark Fasheh <mark@fasheh.com>
M: Joel Becker <jlbec@evilplan.org>
M: Joseph Qi <joseph.qi@linux.alibaba.com>
R: Heming Zhao <heming.zhao@suse.com>
L: ocfs2-devel@lists.linux.dev
S: Supported
W: http://ocfs2.wiki.kernel.org

View File

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

View File

@ -331,13 +331,9 @@ config ARC_FPU_SAVE_RESTORE
for floating point exceptions and rounding modes. These are
preserved across task context switch when enabled.
config ARC_CANT_LLSC
def_bool n
config ARC_HAS_LLSC
bool "Insn: LLOCK/SCOND (efficient atomic ops)"
default y
depends on !ARC_CANT_LLSC
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
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)
{
s64 prev;

View File

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

View File

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

View File

@ -12,7 +12,6 @@
#include <linux/spinlock.h>
#include <linux/sched/mm.h>
#include <linux/interrupt.h>
#include <linux/profile.h>
#include <linux/mm.h>
#include <linux/cpu.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
* VMID.
*/
struct kvm_s2_mmu *nested_mmus;
struct kvm_s2_mmu **nested_mmus;
size_t nested_mmus_size;
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_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 void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu);
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;
r = kvm_get_cap_for_kvm_ioctl(ioctl, &ext);
if (WARN_ON_ONCE(r < 0))
if (r < 0)
return false;
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);
#endif
kvm_init_nested(kvm);
ret = kvm_share_hyp(kvm, kvm + 1);
if (ret)
return ret;
@ -252,6 +250,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (ret)
goto err_free_cpumask;
ret = kvm_init_nested(kvm);
if (ret)
goto err_uninit_mmu;
if (is_protected_kvm_enabled()) {
/*
* 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:
kvm_uninit_stage2_mmu(kvm);
kvm_destroy_nested(kvm);
err_free_cpumask:
free_cpumask_var(kvm->arch.supported_cpus);
err_unshare_kvm:
@ -337,6 +340,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_unshare_hyp(kvm, kvm + 1);
kvm_destroy_nested(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)
{
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;
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_COSP_RCTX, HFGITR, COSPRCTX, 1),
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_BRB_IALL, HFGITR, nBRBIALL, 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);
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_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_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd);
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,
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);
#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);
}
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)
{
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;
}
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)
/* 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)

View File

@ -25,6 +25,7 @@ struct memblock_region hyp_memory[HYP_MEMBLOCK_REGIONS];
unsigned int hyp_memblock_nr;
static u64 __io_map_base;
static u64 __io_map_next;
struct hyp_fixmap_slot {
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);
if (!start || start < __io_map_base)
if (!start || start < __io_map_next)
return -EINVAL;
/* 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)
return -ENOMEM;
__io_map_base = cur;
__io_map_next = cur;
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.
* @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.
*
* 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;
hyp_spin_lock(&pkvm_pgd_lock);
addr = __io_map_base;
addr = __io_map_next;
ret = __pkvm_alloc_private_va_range(addr, size);
hyp_spin_unlock(&pkvm_pgd_lock);
@ -341,7 +342,7 @@ static int create_fixblock(void)
return -EINVAL;
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);
if (ret)
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 ^= BIT(hyp_va_bits - 2);
__io_map_next = __io_map_base;
__hyp_vmemmap = __io_map_base | BIT(hyp_va_bits - 3);
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)
{
unsigned long addr, prev_base;
unsigned long addr, prev_next;
size_t size;
int ret;
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
* an alignment of our allocation on the order of the size.
*/
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);
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,
NVHE_STACK_SIZE, phys, PAGE_HYP);
if (ret)
__io_map_base = prev_base;
__io_map_next = prev_next;
}
hyp_spin_unlock(&pkvm_pgd_lock);
@ -470,6 +472,65 @@ int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr)
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)
{
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))
hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1;
return;
goto out;
}
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))
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);
kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
}
bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_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)
@ -398,10 +399,10 @@ static void unpin_host_sve_state(struct pkvm_hyp_vcpu *hyp_vcpu)
{
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;
sve_state = hyp_vcpu->vcpu.arch.sve_state;
hyp_unpin_shared_mem(sve_state,
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;
size_t sve_state_size;
void *sve_state;
int ret = 0;
int ret;
if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
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. */
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));
if (!sve_state || !sve_state_size) {
ret = -EINVAL;
goto err;
}
if (!sve_vl_valid(sve_max_vl) || !sve_state)
return -EINVAL;
sve_state_size = sve_state_size_from_vl(sve_max_vl);
ret = hyp_pin_shared_mem(sve_state, sve_state + sve_state_size);
if (ret)
goto err;
return ret;
vcpu->arch.sve_state = sve_state;
vcpu->arch.sve_max_vl = sve_max_vl;
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)

View File

@ -217,7 +217,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
case PKVM_PAGE_OWNED:
set_hyp_state(page, PKVM_PAGE_OWNED);
/* 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);
return host_stage2_idmap_locked(phys, PAGE_SIZE, KVM_PGTABLE_PROT_R);
} else {
@ -269,6 +269,16 @@ static int fix_host_ownership(void)
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;
}
@ -324,6 +334,10 @@ void __noreturn __pkvm_init_finalise(void)
if (ret)
goto out;
ret = pkvm_check_host_ownership();
if (ret)
goto out;
ret = hyp_ffa_init(ffa_proxy_pages);
if (ret)
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;
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;
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
* 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,
int (*fn)(struct kvm_pgtable *, u64, u64),
bool resched)
{
struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
bool lock_dropped = false;
phys_addr_t addr = start;
int ret;
u64 next;
do {
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)
return -EINVAL;
return lock_dropped ? 0 : -EINVAL;
next = stage2_range_addr_end(addr, end);
ret = fn(pgt, addr, next - addr);
if (ret)
break;
if (resched && next != end)
if (resched && next != end) {
cond_resched_rwlock_write(&kvm->mmu_lock);
lock_dropped = true;
}
} while (addr = next, addr != end);
return ret;

View File

@ -45,11 +45,24 @@ struct vncr_tlb {
*/
#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;
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)
@ -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)
{
struct kvm *kvm = vcpu->kvm;
struct kvm_s2_mmu *tmp;
int num_mmus, ret = 0;
int num_mmus;
lockdep_assert_held(&kvm->arch.config_lock);
if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features) &&
!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)
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;
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)
return -ENOMEM;
ret = -ENOMEM;
write_lock(&kvm->mmu_lock);
if (kvm->arch.nested_mmus_size) {
memcpy(tmp, kvm->arch.nested_mmus,
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];
for (i = 0; !ret && i < S2_MMU_PER_VCPU; i++) {
ret = init_nested_s2_mmu(kvm, &tmp[i]);
if (ret)
break;
}
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;
}
@ -742,7 +745,7 @@ void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
write_lock(&kvm->mmu_lock);
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))
continue;
@ -784,7 +787,7 @@ struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu)
* if S2 translation is disabled.
*/
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))
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;
i < (kvm->arch.nested_mmus_size + kvm->arch.nested_mmus_next);
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)
break;
@ -1260,6 +1263,17 @@ void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val)
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)
{
int i;
@ -1270,13 +1284,13 @@ void kvm_nested_s2_wp(struct kvm *kvm)
return;
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))
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)
@ -1289,13 +1303,13 @@ void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block)
return;
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))
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)
@ -1308,7 +1322,7 @@ void kvm_nested_s2_flush(struct kvm *kvm)
return;
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))
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)
{
int i;
for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
for (int 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)))
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);
}

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;
switch (rd->Op2) {
case 0b001:
case 0b100:
return &dbg->dbg_bvr[rd->CRm];
case 0b101:

View File

@ -1658,7 +1658,7 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
unsigned long val)
{
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;
/* 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;
}
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 &= ~clearbits;
@ -1691,7 +1693,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
*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 */
mutex_lock(&its->its_lock);
switch (table_type) {
@ -1702,6 +1705,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
vgic_its_free_collection_list(kvm, its);
break;
}
/* A concurrent injection may have cached a translation. */
vgic_its_invalidate_cache(its);
mutex_unlock(&its->its_lock);
}
}
@ -2019,18 +2024,22 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev,
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 *next;
u32 next_offset;
struct its_device *next = dev;
if (list_is_last(&dev->dev_list, h))
return 0;
next = list_next_entry(dev, dev_list);
next_offset = next->device_id - dev->device_id;
/*
* Point at the next device vgic_its_save_device_tables() saves. It
* sorts device_list first, so the subtraction cannot underflow.
*/
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)
@ -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
*
* @its: ITS handle
* @baser: GITS_BASER<dev> the caller is saving against
* @dev: ITS device
* @ptr: GPA
*/
static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
gpa_t ptr)
static int vgic_its_save_dte(struct vgic_its *its, u64 baser,
struct its_device *dev, gpa_t ptr)
{
u64 val, itt_addr_field;
u32 next_offset;
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 |
((u64)next_offset << KVM_ITS_DTE_NEXT_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;
gpa_t eaddr;
/* Don't fail a save that userspace must be able to issue. */
if (!vgic_its_check_id(its, baser,
dev->device_id, &eaddr))
return -EINVAL;
continue;
ret = vgic_its_save_itt(its, dev);
if (ret)
return ret;
ret = vgic_its_save_dte(its, dev, eaddr);
ret = vgic_its_save_dte(its, baser, dev, eaddr);
if (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;
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);
if (ret)
return ret;

View File

@ -188,12 +188,24 @@
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
#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_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_EXT) | \
(_AC(1, UL) << IRQ_PMU_OVF))
(_AC(1, UL) << IRQ_S_EXT))
#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 */
#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)
return -ENODEV;
if (mutex_lock_killable(&vcpu->mutex))
return -EINTR;
imsic = vcpu->arch.aia_context.imsic_state;
if (!imsic)
return -ENODEV;
if (!imsic) {
rc = -ENODEV;
goto out_unlock;
}
isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type);
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,
isel, write, val);
out_unlock:
mutex_unlock(&vcpu->mutex);
return rc;
}

View File

@ -627,6 +627,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
int ret;
kvm_pfn_t hfn;
bool is_hugetlb;
bool unused = false;
bool writable;
unsigned int vma_pageshift;
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);
return 0;
}
if (is_sigpending_pfn(hfn))
return -EINTR;
if (is_error_noslot_pfn(hfn))
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);
if (mmu_invalidate_retry(kvm, mmu_seq))
if (mmu_invalidate_retry(kvm, mmu_seq)) {
unused = true;
goto out_unlock;
}
/*
* 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");
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);
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 = cpu_to_lelong(page_num);
WRITE_ONCE(*entp, cpu_to_lelong(page_num));
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)

View File

@ -491,8 +491,7 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
bool ret;
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
ie = vsip_to_hvip(vcpu->arch.guest_csr.vsie) & (unsigned long)mask;
ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
(unsigned long)mask;
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 */
if (ret < 0) {
if (ret < 0 && ret != -EINTR) {
kvm_err("VCPU exit error %d\n", ret);
kvm_err("SEPC=0x%lx SSTATUS=0x%lx HSTATUS=0x%lx\n",
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)) {
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;
} else
*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);
if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
reg_val &= VSIP_VALID_MASK;
reg_val <<= VSIP_TO_HVIP_SHIFT;
}
if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
reg_val = vsip_to_hvip(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;
pmc->counter_val = kvpmu->fw_event[fevent_code].value;
*out_val = pmc->counter_val;
} 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 {
return -EINVAL;
}
*out_val = pmc->counter_val;
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);
if (!kvpmu->sdata) {
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);
int i, pmc_index, sbiret = 0;
u64 enabled, running;
struct kvm_pmc *pmc;
int fevent_code;
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;
}
if (!kvpmu->fw_event[fevent_code].started)
if (!kvpmu->fw_event[fevent_code].started) {
sbiret = SBI_ERR_ALREADY_STOPPED;
kvpmu->fw_event[fevent_code].started = false;
} else {
kvpmu->fw_event[fevent_code].started = false;
pmc->counter_val = kvpmu->fw_event[fevent_code].value;
}
} else if (pmc->perf_event) {
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;
} else {
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 (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
* 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)
kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata,
sizeof(struct riscv_pmu_snapshot_data));
if (shmem_needs_update &&
kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata,
sizeof(struct riscv_pmu_snapshot_data)))
sbiret = SBI_ERR_FAILURE;
out:
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);
if (ret >= 0) {
retdata->out_val = ret;
retdata->err_val = 0;
ret = 0;
}
return 0;
break;
case SBI_EXT_HSM_HART_SUSPEND:
switch (lower_32_bits(cp->a0)) {
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)
{
if (!t->init_done || !t->next_set)
if (!t->init_done)
return -EINVAL;
hrtimer_cancel(&t->hrt);
if (!t->next_set)
return -EINVAL;
t->next_set = false;
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) \
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)); \
return 0; \
} \
@ -493,7 +497,7 @@ static debug_info_t __refdata var = \
static debug_info_t __used __section(".s390dbf_info") *VNAME(var, info) = &var; \
__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 */

View File

@ -434,7 +434,8 @@ static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
debug_info_free(rc);
} while (1);
if (mode == NO_AREAS)
/* debug_register_static() failure leaves areas NULL, bounds intact */
if (mode == NO_AREAS || !in->areas)
goto out;
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;
size_t size, offset = 0;
if (!id)
return -EINVAL;
/* Need space for '\0' byte */
if (buf_size < 1)
return 0;
@ -950,8 +954,12 @@ EXPORT_SYMBOL(debug_register);
*
* Note: This function is called automatically via an initcall generated by
* 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;
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) {
pr_err("Tried to register debug feature %s too early\n",
id->name);
return;
return -EINVAL;
}
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;
raw_spin_unlock_irqrestore(&id->lock, flags);
return;
return -ENOMEM;
}
/* 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);
_debug_register(id);
mutex_unlock(&debug_mutex);
return 0;
}
/* 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;
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) {
*secret = list->secrets[i].hdr;
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_item_hdr *secret)
{
u16 start_idx = 0;
u16 start_idx;
u16 list_rc;
int ret;
list->next_secret_idx = 0;
do {
start_idx = list->next_secret_idx;
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_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);
if (ret == 0)
return ret;
start_idx = list->next_secret_idx;
} while (list_rc == UVC_RC_MORE_DATA && start_idx < list->next_secret_idx);
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;
int rc;
again:
skey->skey = 0;
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
if (rc)
return rc;
if (!ptep) {
union crste crste;
union crste crste = READ_ONCE(*crstep);
crste = READ_ONCE(*crstep);
if (!crste.h.fc || !crste.s.fc1.pr)
if (!crste_leaf(crste) && !crste.h.i)
goto again;
if (!crste.s.fc1.pr)
return 0;
skey->skey = page_get_storage_key(large_crste_to_phys(crste, gfn));
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;
int rc;
again:
rc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
&crstep, &ptep);
if (rc)
return rc;
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;
}
@ -718,15 +728,22 @@ int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gf
union pte *ptep;
int rc;
again:
rc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
&crstep, &ptep);
if (rc)
return rc;
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)
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);
}
@ -768,7 +785,7 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
int rc;
skey->skey = 0;
again:
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
if (rc)
return rc;
@ -776,9 +793,12 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
if (!ptep) {
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;
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;
}
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 */
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)
{
struct slot_priv *p = walk->priv;
union crste dummy = { .val = p->token };
union pte new_pte, pte = READ_ONCE(*ptep);
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. */
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)
{
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.h.tt = crste.h.tt;
new_crste = mc ? _CRSTE_EMPTY(crste.h.tt) : _CRSTE_HOLE(crste.h.tt);
/* Table entry already in the desired state. */
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)
return 0;
/* 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 = {
@ -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, },
};
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end,
u16 type, u16 param)
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end)
{
struct slot_priv priv = {
.token = _CRSTE_TOK(0, type, param).val,
.mc = mc,
};
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)

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);
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,
u16 type, u16 param);
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end);
#if KVM_S390_MANAGES_S390_GUEST
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;
}
static inline int dat_delete_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start,
unsigned long npages)
static inline int dat_delete_slot(union asce asce, gfn_t start, 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,
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)

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)
{
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;
origin = crste_origin_large(*crstep);
origin = crste_origin_large(crste);
cur = ((max(gfn, walk->start) - gfn) << PAGE_SHIFT) + origin;
end = ((min(next, walk->end) - gfn) << PAGE_SHIFT) + origin;
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,
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)
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
* 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)
return -EINVAL;
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;
}
if (!kvm_s390_is_migration_mode(kvm))
return 0;
/*
* Turn off migration mode when:
* - userspace creates a new memslot with dirty logging off,
* - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and
* dirty logging is turned off.
* 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))
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 (kvm->arch.migration_mode) {
/*
* Turn off migration mode when:
* - userspace creates a new memslot with dirty logging off,
* - userspace modifies an existing memslot (MOVE or FLAGS_ONLY)
* and dirty logging is turned off.
* 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))
WARN(kvm_s390_vm_stop_migration(kvm),
"Failed to stop migration mode");
}
if (change == KVM_MR_FLAGS_ONLY)
return;
mc = kvm_s390_new_mmu_cache();
if (!mc) {
rc = -ENOMEM;
goto out;
return 0;
if (change != KVM_MR_DELETE) {
/* Enough capacity to add a new memslot */
mc = kvm_s390_new_mmu_cache();
if (!mc)
return -ENOMEM;
}
scoped_guard(write_lock, &kvm->mmu_lock) {
kvm_s390_update_cmma_dirty(kvm, old);
switch (change) {
case KVM_MR_DELETE:
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
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:
if (change == KVM_MR_DELETE || change == KVM_MR_MOVE)
rc = dat_delete_slot(kvm->arch.gmap->asce, old->base_gfn, old->npages);
if (!rc && (change == KVM_MR_MOVE || change == KVM_MR_CREATE))
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)
pr_warn("failed to commit memory region\n");
/*
* Can only be triggered if dat_{create,delete}_slot() found an
* 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,
struct kvm_memory_slot *new,
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 */

View File

@ -1589,12 +1589,25 @@ static inline int ___gaccess_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg
parent = READ_ONCE(sg->parent);
if (!parent)
return -EAGAIN;
retry:
scoped_guard(spinlock, &parent->children_lock) {
if (READ_ONCE(sg->parent) != parent)
return -EAGAIN;
sg->invalidated = false;
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)
kvm_s390_release_faultin_array(vcpu->kvm, walk->raw_entries, false);
return rc;

View File

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

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;
}
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, };
@ -5781,7 +5781,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *old,
const struct kvm_memory_slot *new,
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);
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);

View File

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

View File

@ -87,9 +87,23 @@ static struct debug_view debug_log_view = {
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
* @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
* @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.
*/
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 pci_driver *driver = NULL;
struct pci_dev *pdev = NULL;
char *buf, *end;
int ret;
if (!zdev || !zdev->zbus)
if (!zdev)
return -ENODEV;
/* 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);
if (!report)
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;
end = report->data.log_data + ZPCI_REPORT_DATA_SIZE;
buf += scnprintf(buf, end - buf, "report: %s\n", operation);
buf += scnprintf(buf, end - buf, "status: %s\n", status);
buf += scnprintf(buf, end - buf, "state: %s\n",
(pdev) ? zpci_state_str(pdev->error_state) : "n/a");
buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a");
if (pdev)
buf += zpci_report_pdev(pdev, buf, end - buf);
ret = debug_dump(pci_debug_msg_id, &debug_log_view, buf, end - buf, true);
if (ret < 0)
pr_err("Reading PCI debug messages failed with code %d\n", ret);

View File

@ -8,9 +8,11 @@
*/
#ifndef __S390_PCI_REPORT_H
#define __S390_PCI_REPORT_H
#include <linux/pci.h>
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 */

View File

@ -74,6 +74,14 @@ int svsm_perform_call_protocol(struct svsm_call *call)
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);
do {
@ -321,7 +329,6 @@ int snp_svsm_vtpm_send_command(u8 *buffer)
{
struct svsm_call call = {};
call.caa = svsm_get_caa();
call.rax = SVSM_VTPM_CALL(SVSM_VTPM_CMD);
call.rcx = __pa(buffer);
@ -345,7 +352,6 @@ bool snp_svsm_vtpm_probe(void)
if (!snp_vmpl)
return false;
call.caa = svsm_get_caa();
call.rax = SVSM_VTPM_CALL(SVSM_VTPM_QUERY);
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))
continue;
perf_clear_branch_entry_bitfields(br+nr);
br[nr].from = from;
br[nr].to = to;
br[nr] = (struct perf_branch_entry){
.from = from,
.to = to,
};
nr++;
}
empty:

View File

@ -184,13 +184,6 @@ void amd_pmu_lbr_read(void)
entry.to.split.reserved)
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
* the valid and spec bits.
@ -208,7 +201,14 @@ void amd_pmu_lbr_read(void)
* speculative and took the correct path
*/
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++;
}

View File

@ -506,6 +506,8 @@ static struct event_constraint intel_pnc_event_constraints[] = {
INTEL_EVENT_CONSTRAINT(0xce, 0x1),
INTEL_UEVENT_CONSTRAINT(0x01b1, 0x8),
INTEL_UEVENT_CONSTRAINT(0x01b2, 0xf),
INTEL_UEVENT_CONSTRAINT(0x02b2, 0xf),
INTEL_UEVENT_CONSTRAINT(0x0847, 0xf),
INTEL_UEVENT_CONSTRAINT(0x0446, 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(0x042a, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2),
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_EXTRA_REG(0x02c6, MSR_PEBS_FRONTEND, 0x9, 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;
u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl);
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
* 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;
global_ctrl = (*nr)++;
@ -5327,41 +5340,68 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
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;
/*
* 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){
.msr = MSR_IA32_DS_AREA,
.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) {
arr[(*nr)++] = (struct perf_guest_switch_msr){
.msr = MSR_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){
.msr = MSR_IA32_PEBS_ENABLE,
.host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask,
.guest = pebs_mask & ~cpuc->intel_ctrl_host_mask & kvm_pmu->pebs_enable,
};
if (arr[pebs_enable].host) {
/* 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;
}
/*
* Do NOT mess with PEBS_ENABLED. As above, disabling counters via
* PERF_GLOBAL_CTRL is sufficient, and loading a stale PEBS_ENABLED,
* e.g. on VM-Exit, can put the system in a bad state. Simply enable
* counters in PERF_GLOBAL_CTRL, as perf load PEBS_ENABLED with the
* full value, i.e. perf *also* relies on PERF_GLOBAL_CTRL.
*/
arr[global_ctrl].guest |= guest_pebs_mask;
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(offmodule_rsp, "config1:0-63");
PMU_FORMAT_ATTR(ldlat, "config1:0-15");
PMU_FORMAT_ATTR(frontend, "config1:0-23");
@ -6609,6 +6651,20 @@ static struct attribute *skl_format_attr[] = {
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 = {
.name = "core",
.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_cp, hybrid_big);
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(frontend, hybrid_big);
@ -7512,6 +7569,23 @@ static struct attribute *mtl_hybrid_extra_attr[] = {
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)
{
struct device *dev = kobj_to_dev(kobj);
@ -8549,6 +8623,8 @@ __init int intel_pmu_init(void)
case INTEL_DIAMONDRAPIDS_X:
intel_pmu_init_pnc(NULL);
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, ");
name = "panthercove";
@ -8557,13 +8633,12 @@ __init int intel_pmu_init(void)
glc_common:
intel_pmu_init_glc(NULL);
intel_pmu_pebs_data_source_skl(true);
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
hsw_format_attr : nhm_format_attr;
glc_base:
x86_pmu.pebs_ept = 1;
x86_pmu.hw_config = hsw_hw_config;
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;
mem_attr = glc_events_attrs;
td_attr = glc_td_events_attrs;
@ -8785,7 +8860,7 @@ __init int intel_pmu_init(void)
mem_attr = mtl_hybrid_mem_attrs;
tsx_attr = adl_hybrid_tsx_attrs;
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.*/
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.*/
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX];
intel_pmu_init_arw(&pmu->pmu);
intel_pmu_pebs_data_source_lnl();
break;
default:

View File

@ -277,8 +277,8 @@ static u64 pnc_pebs_l2_hit_data_source[PNC_PEBS_DATA_SOURCE_MAX] = {
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, 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, MISS), /* 0x0a: Cross Core Prefetch Promotion */
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* 0x09: Prefetch Promotion */
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* 0x0a: Cross Core Prefetch Promotion */
0, /* 0x0b: Reserved */
0, /* 0x0c: 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,
u8 dse, bool tlb, bool lock, bool blk)
{
union perf_mem_data_src src;
u64 val;
WARN_ON_ONCE(is_hybrid() &&
@ -470,7 +471,16 @@ static u64 __grt_latency_data(struct perf_event *event, u64 status,
else
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)
@ -528,7 +538,11 @@ static u64 arw_latency_data(struct perf_event *event, u64 status)
val |= P(BLK, NA);
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);
return src.val;
@ -563,7 +577,11 @@ static u64 lnc_latency_data(struct perf_event *event, u64 status)
val |= P(BLK, NA);
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);
return src.val;
@ -621,7 +639,11 @@ u64 pnc_latency_data(struct perf_event *event, u64 status)
val |= P(BLK, NA);
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);
return src.val;
@ -1291,22 +1313,22 @@ struct event_constraint intel_glm_pebs_event_constraints[] = {
struct event_constraint intel_grt_pebs_event_constraints[] = {
/* Allow all events as PEBS with no flags */
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0x3),
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0x3f),
INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0x3),
INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0x3f),
EVENT_CONSTRAINT_END
};
struct event_constraint intel_cmt_pebs_event_constraints[] = {
/* Allow all events as PEBS with no flags */
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0x3),
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xff),
INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0x3),
INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0xff),
EVENT_CONSTRAINT_END
};
struct event_constraint intel_dkt_pebs_event_constraints[] = {
/* Allow all events as PEBS with no flags */
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0xff),
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xff),
INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0xff),
INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0xff),
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(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_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
@ -1526,18 +1532,6 @@ struct event_constraint intel_lnc_pebs_event_constraints[] = {
struct event_constraint intel_pnc_pebs_event_constraints[] = {
INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0xfc),
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

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);
perf_clear_branch_entry_bitfields(br);
br->from = msr_lastbranch.from;
br->to = msr_lastbranch.to;
*br = (struct perf_branch_entry){
.from = msr_lastbranch.from,
.to = msr_lastbranch.to,
};
br++;
}
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)
out--;
perf_clear_branch_entry_bitfields(br+out);
br[out].from = from;
br[out].to = to;
br[out].mispred = mis;
br[out].predicted = pred;
br[out].in_tx = in_tx;
br[out].abort = abort;
br[out].cycles = cycles;
br[out] = (struct perf_branch_entry){
.from = from,
.to = to,
.mispred = mis,
.predicted = pred,
.in_tx = in_tx,
.abort = abort,
.cycles = cycles,
};
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 lbr_entry *lbr;
u64 from, to, info;
bool mispred;
int 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);
info = rdlbr_info(i, lbr);
perf_clear_branch_entry_bitfields(e);
mispred = get_lbr_mispred(info);
e->from = from;
e->to = to;
e->mispred = get_lbr_mispred(info);
e->predicted = !e->mispred;
e->in_tx = !!(info & LBR_INFO_IN_TX);
e->abort = !!(info & LBR_INFO_ABORT);
e->cycles = get_lbr_cycles(info);
e->type = get_lbr_br_type(info);
/*
* Leverage the reserved field of cpuc->lbr_entries[i] to
* temporarily store the branch counters information.
* The later code will 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;
*e = (struct perf_branch_entry){
.from = from,
.to = to,
.mispred = mispred,
.predicted = !mispred,
.in_tx = !!(info & LBR_INFO_IN_TX),
.abort = !!(info & LBR_INFO_ABORT),
.cycles = get_lbr_cycles(info),
.type = get_lbr_br_type(info),
/*
* Leverage the reserved field of
* cpuc->lbr_entries[i] to temporarily store the
* branch counters information. The later code will
* decide what content can be disclosed to the perf
* tool. Pleae see intel_pmu_lbr_counters_reorder().
*/
.reserved = (info >> LBR_INFO_BR_CNTR_OFFSET) &
LBR_INFO_BR_CNTR_FULL_MASK,
};
}
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, \
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) \
__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)

View File

@ -2108,6 +2108,9 @@ bool filter_mce(struct mce *m)
static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
{
irqentry_state_t irq_state;
unsigned long dr7;
dr7 = local_db_save();
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.
*/
if (mca_cfg.initialized && mce_check_crashing_cpu())
return;
goto out;
irq_state = irqentry_nmi_enter(regs);
do_machine_check(regs);
irqentry_nmi_exit(regs, irq_state);
out:
local_db_restore(dr7);
}
static __always_inline void exc_machine_check_user(struct pt_regs *regs)
{
unsigned long dr7;
irqentry_enter_from_user_mode(regs);
dr7 = local_db_save();
do_machine_check(regs);
local_db_restore(dr7);
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 */
DEFINE_IDTENTRY_MCE(exc_machine_check)
{
unsigned long dr7;
dr7 = local_db_save();
exc_machine_check_kernel(regs);
local_db_restore(dr7);
}
/* The user mode variant. */
DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
{
unsigned long dr7;
dr7 = local_db_save();
exc_machine_check_user(regs);
local_db_restore(dr7);
}
#ifdef CONFIG_X86_FRED
@ -2169,28 +2170,20 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
*/
DEFINE_FREDENTRY_MCE(exc_machine_check)
{
unsigned long dr7;
dr7 = local_db_save();
if (user_mode(regs))
exc_machine_check_user(regs);
else
exc_machine_check_kernel(regs);
local_db_restore(dr7);
}
#endif
#else
/* 32bit unified entry point */
DEFINE_IDTENTRY_RAW(exc_machine_check)
{
unsigned long dr7;
dr7 = local_db_save();
if (user_mode(regs))
exc_machine_check_user(regs);
else
exc_machine_check_kernel(regs);
local_db_restore(dr7);
}
#endif

View File

@ -5058,7 +5058,7 @@ static int kvm_tdp_page_prefault(struct kvm_vcpu *vcpu, gpa_t gpa,
if (signal_pending(current))
return -EINTR;
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu))
if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu))
return -EIO;
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)
{
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) ||
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;
}
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;
if (!nested_svm_merge_msrpm(vcpu))
return false;
}
if (kvm_hv_verify_vp_assist(vcpu))
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->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);
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 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.
* 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)) {
ret = -ENOMEM;
@ -2980,13 +2990,17 @@ void sev_vm_destroy(struct kvm *kvm)
struct list_head *head = &sev->regions_list;
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))
return;
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
* 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 {
pr_debug_ratelimited("%s: no backing for APIC-access address in vmcs12\n",
__func__);
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
return false;
}
}
@ -3539,11 +3535,6 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
if (!nested_get_evmcs_page(vcpu)) {
pr_debug_ratelimited("%s: enlightened vmptrld failed\n",
__func__);
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
vcpu->run->internal.suberror =
KVM_INTERNAL_ERROR_EMULATION;
vcpu->run->internal.ndata = 0;
return false;
}
#endif
@ -3915,8 +3906,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
vmentry_failed:
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;
}
if (status == NVMX_VMENTRY_VMEXIT)
return 1;
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;
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:
return kvm_pmu_has_perf_global_ctrl(pmu);
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))
break;
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) {
if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu)) {
ret = -EIO;
break;
}

View File

@ -8060,7 +8060,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
bool req_immediate_exit = false;
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;
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 (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;
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);
/*
* 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
/*

View File

@ -2018,12 +2018,17 @@ static int disk_revalidate_zone_resources(struct gendisk *disk,
struct blk_revalidate_zone_args *args)
{
struct queue_limits *lim = &disk->queue->limits;
unsigned long long nr_zones;
unsigned int pool_size;
int ret = 0;
args->disk = disk;
args->nr_zones =
DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors);
nr_zones = 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 */
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;
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. */
switch (cond) {
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);
disable_irq(vdev->irq);
atomic_set(&vdev->job_timeout_detected, 0);
flush_work(&vdev->irq_dct_work);
flush_work(&vdev->context_abort_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;
atomic64_set(&vdev->unique_id_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->submitted_jobs_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 ivpu_ipc_consumer job_done_consumer;
atomic_t job_timeout_counter;
atomic_t faults_detected;
atomic_t job_timeout_detected;
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
*/
job->file_priv->has_mmu_faults = true;
atomic_set(&vdev->faults_detected, 1);
queue_work(system_percpu_wq, &vdev->context_abort_work);
return true;
}
@ -1175,10 +1174,10 @@ static int reset_engine_and_mark_faulty_contexts(struct ivpu_device *vdev)
return ret;
/*
* If faults are detected, ignore guilty contexts from engine reset as NPU may not be stuck
* and could return currently running good context and faulty contexts are already marked
* If job timeout is detected, read guilty context from engine reset, for other reasons
* 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;
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);
if (file_priv) {
if (!READ_ONCE(file_priv->has_mmu_faults)) {
atomic_set(&vdev->faults_detected, 1);
ivpu_mmu_dump_event(vdev, event);
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_dev_coredump(vdev);
atomic_set(&vdev->job_timeout_detected, 1);
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->quirks |= ATA_QUIRK_NOLPM;
/* ATI specific quirk */
if ((dev->quirks & ATA_QUIRK_NO_LPM_ON_ATI) &&
ata_dev_check_adapter(dev, PCI_VENDOR_ID_ATI))
/* ATI and AMD specific quirk */
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_AMD)))
dev->quirks |= ATA_QUIRK_NOLPM;
}
@ -4136,7 +4137,7 @@ static const char * const ata_quirk_names[] = {
[__ATA_QUIRK_MAX_SEC] = "maxsec",
[__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m",
[__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_LOG_DIR] = "nologdir",
[__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 |
ATA_QUIRK_ZERO_AFTER_TRIM |
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 |
ATA_QUIRK_ZERO_AFTER_TRIM |
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 |
ATA_QUIRK_ZERO_AFTER_TRIM |
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 |
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 */
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 (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;
sb[7] = len + 14;
desc = sb + 8 + len;
} else if (desc - sb > SCSI_SENSE_BUFFERSIZE - 14) {
return;
}
desc[0] = 9;
desc[1] = 12;

View File

@ -1040,9 +1040,10 @@ static int cacheinfo_cpu_online(unsigned int cpu)
rc = cache_add_dev(cpu);
if (rc)
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);
sched_update_llc_bytes(cpu);
sched_update_llc_bytes(cpu_map);
}
return 0;
err:
free_cache_attributes(cpu);
@ -1059,10 +1060,10 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu)
cpu_cache_sysfs_exit(cpu);
free_cache_attributes(cpu);
if (nr_shared > 1)
if (nr_shared > 1) {
update_per_cpu_data_slice_size(false, cpu, cpu_map);
sched_update_llc_bytes(cpu);
sched_update_llc_bytes(cpu_map);
}
return 0;
}

View File

@ -289,7 +289,8 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
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);
@ -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
* Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
*/
while (fw->size > fw_ptr - fw->data) {
u8 cmd_plen = fw_ptr[0] + sizeof(u8);
while (fw->size > (size_t)(fw_ptr - fw->data)) {
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,
HCI_INIT_TIMEOUT);

View File

@ -1197,7 +1197,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
{
int ret;
u8 pkt_type;
u16 plen;
u32 plen;
u32 pcie_pkt_type;
void *pdata;
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))
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
* 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

View File

@ -1397,8 +1397,10 @@ static void iso_resource_auto_work(struct work_struct *work)
} else {
// Transit from allocation to reallocation, except if the client requested
// deallocation in the meantime.
scoped_guard(spinlock_irq, &client->lock)
r->todo = ISO_RES_AUTO_REALLOC;
scoped_guard(spinlock_irq, &client->lock) {
if (r->todo == ISO_RES_AUTO_ALLOC)
r->todo = ISO_RES_AUTO_REALLOC;
}
if (channel >= 0)
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)
value = ARIZONA_GPN_LVL;
return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
ret = regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
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,

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)
{
struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
u32 edge_cache = ~0U, level_cache = ~0U;
unsigned long flags;
int i;
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,
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) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
case MVEBU_GPIO_SOC_VARIANT_A8K:
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,
mvchip->level_mask_regs[0]);
mvchip->level_mask_regs[0] & level_cache);
break;
case MVEBU_GPIO_SOC_VARIANT_MV78200:
for (i = 0; i < 2; i++) {
regmap_write(mvchip->regs,
GPIO_EDGE_MASK_MV78200_OFF(i),
mvchip->edge_mask_regs[i]);
mvchip->edge_mask_regs[i] & edge_cache);
regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_MV78200_OFF(i),
mvchip->level_mask_regs[i]);
mvchip->level_mask_regs[i] & level_cache);
}
break;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
for (i = 0; i < 4; i++) {
regmap_write(mvchip->regs,
GPIO_EDGE_MASK_ARMADAXP_OFF(i),
mvchip->edge_mask_regs[i]);
mvchip->edge_mask_regs[i] & edge_cache);
regmap_write(mvchip->regs,
GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
mvchip->level_mask_regs[i]);
mvchip->level_mask_regs[i] & level_cache);
}
break;
default:

View File

@ -79,7 +79,7 @@ static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
if (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);
/*
@ -87,7 +87,7 @@ static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
* 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 ret;
@ -158,8 +158,10 @@ static int tps65214_gpio_change_direction(struct gpio_chip *gc, unsigned int off
if (ret)
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,
TPS65214_GPIO0_DIR_MASK, direction);
TPS65214_GPIO0_DIR_MASK, val);
if (ret)
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;
}
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_IN)
if (gc->get_direction(gc, offset) == GPIO_LINE_DIRECTION_IN)
return 0;
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)
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 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)
{
int ret;
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;
return pm_runtime_resume_and_get(chip->parent);
}
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 */
static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpio_v2_line_info *info, bool atomic)
static int gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpio_v2_line_info *info, bool atomic)
{
u32 debounce_period_us;
unsigned long dflags;
const char *label;
memset(info, 0, sizeof(*info));
CLASS(gpio_chip_guard, guard)(desc);
if (!guard.gc)
return;
return -ENODEV;
memset(info, 0, sizeof(*info));
info->offset = gpiod_hwgpio(desc);
if (desc->name)
@ -2258,6 +2259,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
debounce_period_us;
info->num_attrs++;
}
return 0;
}
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 gpioline_info lineinfo;
struct gpio_v2_line_info lineinfo_v2;
int ret;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
@ -2326,7 +2330,10 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
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);
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_v2_line_info lineinfo;
int ret;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
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))
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 (watch)
@ -2489,6 +2500,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
struct lineinfo_changed_ctx *ctx;
struct gpio_desc *desc = data;
struct file *fp;
int ret;
if (!test_bit(gpiod_hwgpio(desc), cdev->watched_lines))
return NOTIFY_DONE;
@ -2519,7 +2531,13 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
ctx->chg.event_type = action;
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. */
ctx->gdev = gpio_device_get(desc->gdev);
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);
if (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 {
/*
* 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);
if (!xcc_info)
if (!xcc_info) {
acpi_dev_put(acpi_dev);
return -ENOMEM;
}
INIT_LIST_HEAD(&xcc_info->list);
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 */
r = down_write_killable(&adev->reset_domain->sem);
if (r)
if (r) {
pm_runtime_put_autosuspend(dev->dev);
return r;
}
/* hold on the scheduler */
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);
/* 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
* 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->num_hw_submission = sched_hw_submission;
ring->sched_score = sched_score;
ring->vmid_wait = dma_fence_get_stub();
ring->idx = adev->num_rings++;
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->hw_prio = hw_prio;
ring->vmid_wait = dma_fence_get_stub();
if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) {
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)
{
struct amdgpu_device *adev;
unsigned long timeout_ms;
unsigned long timeout_jiffies;
adev = queue->userq_mgr->adev;
/* Determine timeout based on queue type */
switch (queue->queue_type) {
case AMDGPU_RING_TYPE_GFX:
timeout_ms = adev->gfx_timeout;
timeout_jiffies = adev->gfx_timeout;
break;
case AMDGPU_RING_TYPE_COMPUTE:
timeout_ms = adev->compute_timeout;
timeout_jiffies = adev->compute_timeout;
break;
case AMDGPU_RING_TYPE_SDMA:
timeout_ms = adev->sdma_timeout;
timeout_jiffies = adev->sdma_timeout;
break;
default:
timeout_ms = adev->gfx_timeout;
timeout_jiffies = adev->gfx_timeout;
break;
}
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)
@ -1272,7 +1272,7 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
return ret;
}
static void
void
amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
{
struct amdgpu_usermode_queue *queue;
@ -1291,8 +1291,6 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
void
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);
}

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_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_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);
error_free_delayed:
dma_fence_put(vm->last_update);
dma_fence_put(vm->last_tlb_flush);
dma_fence_put(vm->last_unlocked);
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,
* 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;

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,
* 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;

View File

@ -35,6 +35,7 @@
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/pseudo_fs.h>
#include <linux/ptrace.h>
#include <linux/dma-buf.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
* path can drop all userspace mappings of doorbell and MMIO ranges via
* unmap_mapping_range().
* Private pseudo-filesystem for KFD, Provides a stable, module-owned
* inode whose address_space is the unmap target for all /dev/kfd
* 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)
{
struct address_space *mapping = READ_ONCE(kfd_dev_mapping);
if (mapping)
unmap_mapping_range(mapping, holebegin, holelen, 1);
if (kfd_anon_inode)
unmap_mapping_range(kfd_anon_inode->i_mapping, holebegin, holelen, 1);
}
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;
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);
err = kfd_char_dev_major;
if (err < 0)
@ -130,6 +174,8 @@ int kfd_chardev_init(void)
err_class_create:
unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
err_register_chrdev:
kfd_fs_inode_free(kfd_anon_inode);
kfd_anon_inode = NULL;
return err;
}
@ -138,6 +184,8 @@ void kfd_chardev_exit(void)
device_destroy(&kfd_class, MKDEV(kfd_char_dev_major, 0));
class_unregister(&kfd_class);
unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
kfd_fs_inode_free(kfd_anon_inode);
kfd_anon_inode = NULL;
kfd_device = NULL;
}
@ -150,12 +198,7 @@ static int kfd_open(struct inode *inode, struct file *filep)
if (iminor(inode) != 0)
return -ENODEV;
/*
* /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);
filep->f_mapping = kfd_anon_inode->i_mapping;
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:
/* Release extra reference */
if (new_stream)
if (new_stream) {
dc_stream_release(new_stream);
new_stream = NULL;
}
new_stream = NULL;
/*

View File

@ -29,14 +29,14 @@ dml_ccflags := $(CC_FLAGS_FPU)
dml_rcflags := $(CC_FLAGS_NO_FPU)
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)
frame_warn_limit := 4096
else
frame_warn_limit := 3072
endif
else
frame_warn_limit := 2048
frame_warn_limit := 3072
endif
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)
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)
frame_warn_limit := 4096
else
frame_warn_limit := 3072
endif
else
frame_warn_limit := 2056
frame_warn_limit := 3072
endif
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 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)
return 0;
else if (IS_ERR(dsi->te_gpio))

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