Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Documentation/virt/kvm/arm/hypercalls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ The pseudo-firmware bitmap register are as follows:
Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP:
The bit represents the Precision Time Protocol KVM service.

Bit-2: KVM_REG_ARM_VENDOR_HYP_BIT_IPIV:
The bit represents the ARM_SMCCC_VENDOR_PV_SGI_FEATURES and
ARM_SMCCC_VENDOR_PV_SGI_ENABLE function-ids.

Errors:

======= =============================================================
Expand Down
33 changes: 33 additions & 0 deletions Documentation/virt/kvm/arm/pvsgi.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.. SPDX-License-Identifier: GPL-2.0

Paravirtualized SGI support for HiSilicon
==========================================

KVM/arm64 provides some hypervisor service calls to support a paravirtualized
SGI(software generated interrupt) in HiSilicon Hip12 SoC.

Some SMCCC compatible hypercalls are defined:

* PV_SGI_FEATURES: 0xC6000090
* PV_SGI_ENABLE: 0xC6000091

The existence of the PV_SGI hypercall should be probed using the SMCCC 1.1
ARCH_FEATURES mechanism before calling it.

PV_SGI_FEATURES

============= ======== ==========
Function ID: (uint32) 0xC6000090
PV_call_id: (uint32) The function to query for support.
Currently only PV_SGI_ENABLE is supported.
Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if the relevant
PV-sgi feature is supported by the hypervisor.
============= ======== ==========

PV_SGI_ENABLE

============= ======== ==========
Function ID: (uint32) 0xC6000091
Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if this feature
has been enabled.
============= ======== ==========
12 changes: 12 additions & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2256,6 +2256,18 @@ config ARM64_HDBSS

endmenu # "ARMv9.5 architectural features"

config ARM64_HISI_IPIV
bool "Enable support for IPIV"
default y
depends on ACPI
depends on ARM64
help
IPIV optimizes vSGI on the basis of GICv4.1. The vCPU on the sending
side of vSGI needs to trap to Hypervisor. IPIv sends vSGI without
traping, improving performance.

The feature will only be enabled if CPU in the system and Guest OS
support this feature. If unsure, say Y.

config ARM64_SVE
bool "ARM Scalable Vector Extension support"
Expand Down
1 change: 0 additions & 1 deletion arch/arm64/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,5 @@ bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);
extern bool force_wfi_trap;
extern bool kvm_ncsnp_support;
extern bool kvm_dvmbm_support;
extern bool kvm_ipiv_support;

#endif /* __ARM64_KVM_HOST_H__ */
5 changes: 5 additions & 0 deletions arch/arm64/include/uapi/asm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,11 @@ enum {
enum {
KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT = 0,
KVM_REG_ARM_VENDOR_HYP_BIT_PTP = 1,
/*
* If the mainline conflicts, do not change the
* current sequence, add in sequence.
*/
KVM_REG_ARM_VENDOR_HYP_BIT_IPIV = 2,
#ifdef __KERNEL__
KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT,
#endif
Expand Down
37 changes: 28 additions & 9 deletions arch/arm64/kvm/arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ bool kvm_ncsnp_support;
/* Capability of DVMBM */
bool kvm_dvmbm_support;

/* Capability of IPIV */
bool kvm_ipiv_support;

static DEFINE_PER_CPU(unsigned char, kvm_hyp_initialized);
DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);

Expand Down Expand Up @@ -195,6 +192,14 @@ static int kvm_cap_arm_enable_hdbss(struct kvm *kvm,
}
#endif

#ifdef CONFIG_ARM64_HISI_IPIV
static int kvm_hisi_ipiv_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
{
kvm->arch.vgic.its_vm.enable_ipiv_from_vmm = true;
return 0;
}
#endif

int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
struct kvm_enable_cap *cap)
{
Expand Down Expand Up @@ -246,6 +251,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK:
r = kvm_cap_arm_enable_hdbss(kvm, cap);
break;
#endif
#ifdef CONFIG_ARM64_HISI_IPIV
case KVM_CAP_ARM_HISI_IPIV:
r = kvm_hisi_ipiv_enable_cap(kvm, cap);
break;
#endif
default:
r = -EINVAL;
Expand Down Expand Up @@ -352,7 +362,9 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_arm_teardown_hypercalls(kvm);
}

#ifdef CONFIG_ARM64_HISI_IPIV
extern struct static_key_false ipiv_enable;
#endif

int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
Expand Down Expand Up @@ -469,12 +481,14 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r = system_supports_hdbss();
break;
#endif
case KVM_CAP_ARM_IPIV_MODE:
#ifdef CONFIG_ARM64_HISI_IPIV
case KVM_CAP_ARM_HISI_IPIV:
if (static_branch_unlikely(&ipiv_enable))
r = 1;
else
r = 0;
break;
#endif
default:
r = 0;
}
Expand Down Expand Up @@ -1405,6 +1419,16 @@ static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu,
if (test_bit(KVM_ARM_VCPU_HAS_EL2, &features))
return -EINVAL;

#ifdef CONFIG_ARM64_HISI_IPIV
if (static_branch_unlikely(&ipiv_enable) &&
vcpu->kvm->arch.vgic.its_vm.enable_ipiv_from_vmm &&
vcpu->vcpu_id != vcpu->vcpu_idx) {
kvm_err("IPIV ERROR: vcpu_id %d != vcpu_idx %d\n",
vcpu->vcpu_id, vcpu->vcpu_idx);
return -EINVAL;
}
#endif

return 0;
}

Expand Down Expand Up @@ -2659,13 +2683,8 @@ static __init int kvm_arm_init(void)
probe_hisi_cpu_type();
kvm_ncsnp_support = hisi_ncsnp_supported();
kvm_dvmbm_support = hisi_dvmbm_supported();
kvm_ipiv_support = hisi_ipiv_supported();
kvm_info("KVM ncsnp %s\n", kvm_ncsnp_support ? "enabled" : "disabled");
kvm_info("KVM dvmbm %s\n", kvm_dvmbm_support ? "enabled" : "disabled");
kvm_info("KVM ipiv %s\n", kvm_ipiv_support ? "enabled" : "disabled");

if (kvm_ipiv_support)
ipiv_gicd_init();

if (kvm_dvmbm_support)
kvm_get_pg_cfg();
Expand Down
38 changes: 36 additions & 2 deletions arch/arm64/kvm/hisilicon/hisi_virt.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
static enum hisi_cpu_type cpu_type = UNKNOWN_HI_TYPE;

static bool dvmbm_enabled;

#ifdef CONFIG_ARM64_HISI_IPIV
static bool ipiv_enabled;
#endif

static const char * const hisi_cpu_type_str[] = {
"Hisi1612",
Expand Down Expand Up @@ -158,6 +161,7 @@ static void hardware_disable_dvmbm(void *data)
write_sysreg_s(val, SYS_LSUDVM_CTRL_EL2);
}

#ifdef CONFIG_ARM64_HISI_IPIV
static int __init early_ipiv_enable(char *buf)
{
return strtobool(buf, &ipiv_enabled);
Expand All @@ -175,12 +179,17 @@ bool hisi_ipiv_supported(void)
return false;
}

if (!gic_get_ipiv_status()) {
kvm_info("Hisi ipiv is disabled by BIOS\n");
return false;
}

/* User provided kernel command-line parameter */
if (!ipiv_enabled || !is_kernel_in_hyp_mode())
return false;

/* Enable IPIV feature if necessary */
if (!is_gicv4p1()) {
if (!kvm_vgic_global_state.has_gicv4_1) {
kvm_info("Hisi ipiv needs to enable GICv4p1!\n");
return false;
}
Expand All @@ -189,11 +198,36 @@ bool hisi_ipiv_supported(void)
return true;
}

extern struct static_key_false ipiv_enable;

bool hisi_ipiv_supported_per_vm(struct kvm_vcpu *vcpu)
{
/* IPIV is supported by the hardware */
if (!static_branch_unlikely(&ipiv_enable))
return false;

/* vSGI passthrough is configured */
if (!vcpu->kvm->arch.vgic.nassgireq)
return false;

/* IPIV is enabled by the user */
if (!vcpu->kvm->arch.vgic.its_vm.enable_ipiv_from_vmm)
return false;

return true;
}

void hisi_ipiv_enable_per_vm(struct kvm_vcpu *vcpu)
{
/* Enable IPIV feature */
vcpu->kvm->arch.vgic.its_vm.enable_ipiv_from_guest = true;
}

void ipiv_gicd_init(void)
{
gic_dist_enable_ipiv();
}

#endif /* CONFIG_ARM64_HISI_IPIV */

bool hisi_dvmbm_supported(void)
{
Expand Down
21 changes: 19 additions & 2 deletions arch/arm64/kvm/hisilicon/hisi_virt.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ enum hisi_cpu_type {
};

/* HIP12 */
#ifdef CONFIG_ARM64_HISI_IPIV
#define AIDR_EL1_IPIV_MASK GENMASK_ULL(17, 16)
#endif
/* HIP10 */
#define AIDR_EL1_DVMBM_MASK GENMASK_ULL(13, 12)
#define SYS_LSUDVM_CTRL_EL2 sys_reg(3, 4, 15, 7, 4)
Expand Down Expand Up @@ -77,9 +79,13 @@ enum hisi_cpu_type {
void probe_hisi_cpu_type(void);
bool hisi_ncsnp_supported(void);
bool hisi_dvmbm_supported(void);
#ifdef CONFIG_ARM64_HISI_IPIV
bool hisi_ipiv_supported(void);
void kvm_get_pg_cfg(void);
bool hisi_ipiv_supported_per_vm(struct kvm_vcpu *vcpu);
void hisi_ipiv_enable_per_vm(struct kvm_vcpu *vcpu);
void ipiv_gicd_init(void);
#endif /* CONFIG_ARM64_HISI_IPIV */
void kvm_get_pg_cfg(void);

int kvm_sched_affinity_vcpu_init(struct kvm_vcpu *vcpu);
void kvm_sched_affinity_vcpu_destroy(struct kvm_vcpu *vcpu);
Expand All @@ -100,17 +106,26 @@ static inline bool hisi_dvmbm_supported(void)
}
static inline void kvm_get_pg_cfg(void) {}

#ifdef CONFIG_ARM64_HISI_IPIV
static inline bool hisi_ipiv_supported(void)
{
return false;
}
#endif /* CONFIG_ARM64_HISI_IPIV */

static inline int kvm_sched_affinity_vcpu_init(struct kvm_vcpu *vcpu)
{
return 0;
}
static inline void kvm_sched_affinity_vcpu_destroy(struct kvm_vcpu *vcpu) {}
#ifdef CONFIG_ARM64_HISI_IPIV
static bool hisi_ipiv_supported_per_vm(struct kvm_vcpu *vcpu)
{
return false;
}
static void hisi_ipiv_enable_per_vm(struct kvm_vcpu *vcpu) {}
static inline void ipiv_gicd_init(void) {}
#endif /* CONFIG_ARM64_HISI_IPIV */
static inline int kvm_sched_affinity_vm_init(struct kvm *kvm)
{
return 0;
Expand All @@ -121,6 +136,8 @@ static inline void kvm_tlbi_dvmbm_vcpu_put(struct kvm_vcpu *vcpu) {}
static inline void kvm_hisi_reload_lsudvmbm(struct kvm *kvm) {}
#endif /* CONFIG_KVM_HISI_VIRT */

#ifdef CONFIG_ARM64_HISI_IPIV
extern bool gic_dist_enable_ipiv(void);
extern bool is_gicv4p1(void);
extern bool gic_get_ipiv_status(void);
#endif /* CONFIG_ARM64_HISI_IPIV */
#endif /* __HISI_VIRT_H__ */
26 changes: 26 additions & 0 deletions arch/arm64/kvm/hypercalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#include <kvm/arm_hypercalls.h>
#include <kvm/arm_psci.h>

#ifdef CONFIG_ARM64_HISI_IPIV
#include "hisilicon/hisi_virt.h"
#endif

#define KVM_ARM_SMCCC_STD_FEATURES \
GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0)
#define KVM_ARM_SMCCC_STD_HYP_FEATURES \
Expand Down Expand Up @@ -116,6 +120,12 @@ static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id)
case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP,
&smccc_feat->vendor_hyp_bmap);
#ifdef CONFIG_ARM64_HISI_IPIV
case ARM_SMCCC_VENDOR_PV_SGI_FEATURES:
case ARM_SMCCC_VENDOR_PV_SGI_ENABLE:
return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_IPIV,
&smccc_feat->vendor_hyp_bmap);
#endif
default:
return false;
}
Expand Down Expand Up @@ -342,6 +352,22 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
if (gpa != INVALID_GPA)
val[0] = gpa;
break;
#ifdef CONFIG_ARM64_HISI_IPIV
case ARM_SMCCC_VENDOR_PV_SGI_FEATURES:
if (hisi_ipiv_supported_per_vm(vcpu))
val[0] = SMCCC_RET_SUCCESS;
else
val[0] = SMCCC_RET_NOT_SUPPORTED;
break;
case ARM_SMCCC_VENDOR_PV_SGI_ENABLE:
if (hisi_ipiv_supported_per_vm(vcpu)) {
hisi_ipiv_enable_per_vm(vcpu);
val[0] = SMCCC_RET_SUCCESS;
} else {
val[0] = SMCCC_RET_NOT_SUPPORTED;
}
break;
#endif
case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;
val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;
Expand Down
Loading