Unverified Commit a83e7947 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!793 LoongArch: kvm: add pv ipi support

Merge Pull Request from: @Hongchen_Zhang 
 
PV IPI with less VM exit can improve performance than
iocsr emulation when sending ipi interrupt to multi cpus.
    
This patch supports:
1. sending PV IPI by hypercall
2. recording and updating steal time for VM
 
 
Link:https://gitee.com/openeuler/kernel/pulls/793

 

Reviewed-by: default avatarGuo Dongtai <guodongtai@kylinos.cn>
Reviewed-by: default avatarKevin Zhu <zhukeqian1@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parents b6923261 204e7666
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -560,6 +560,25 @@ config ARCH_ENABLE_THP_MIGRATION
	def_bool y
	depends on TRANSPARENT_HUGEPAGE

config PARAVIRT
	bool "Enable paravirtualization code"
	help
	  This changes the kernel so it can modify itself when it is run
	  under a hypervisor, potentially improving performance significantly
	  over full virtualization.

config PARAVIRT_TIME_ACCOUNTING
	bool "Paravirtual steal time accounting"
	select PARAVIRT
	default n
	help
	  Select this option to enable fine granularity task steal time
	  accounting. Time spent executing other tasks in parallel with
	  the current vCPU is discounted from the vCPU capacity. To account for
	  that, there can be a small performance impact.

	  If in doubt, say N here.

config ARCH_MEMORY_PROBE
	def_bool y
	depends on MEMORY_HOTPLUG
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ CONFIG_BPF_SYSCALL=y
CONFIG_USERFAULTFD=y
CONFIG_PERF_EVENTS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PARAVIRT_TIME_ACCOUNTING=y
CONFIG_CPU_HAS_LSX=y
CONFIG_CPU_HAS_LASX=y
CONFIG_NUMA=y
+146 −0
Original line number Diff line number Diff line
@@ -2,6 +2,10 @@
#ifndef _ASM_LOONGARCH_KVM_PARA_H
#define _ASM_LOONGARCH_KVM_PARA_H

#include <uapi/asm/kvm_para.h>

#define KVM_HYPERCALL ".word 0x002b8000"

/*
 * Hypcall code field
 */
@@ -25,6 +29,148 @@
#define KVM_RET_SUC	1
#define KVM_RET_NOT_SUPPORTED	-1

/*
 * Hypercalls interface for KVM.
 *
 * a0: function identifier
 * a1-a6: args
 * Return value will be placed in v0.
 * Up to 6 arguments are passed in a1, a2, a3, a4, a5, a6.
 */
static inline long kvm_hypercall0(u64 fid)
{
	register long ret asm("v0");
	register unsigned long fun asm("a0") = fid;

	__asm__ __volatile__(
		KVM_HYPERCALL
		: "=r" (ret)
		: "r" (fun)
		: "memory"
	);

	return ret;
}

static inline long kvm_hypercall1(u64 fid, unsigned long arg0)
{
	register long ret asm("v0");
	register unsigned long fun asm("a0") = fid;
	register unsigned long a1 asm("a1") = arg0;

	__asm__ __volatile__(
		KVM_HYPERCALL
		: "=r" (ret)
		: "r" (fun), "r" (a1)
		: "memory"
	);

	return ret;
}

static inline long kvm_hypercall2(u64 fid,
					unsigned long arg0, unsigned long arg1)
{
	register long ret asm("v0");
	register unsigned long fun asm("a0") = fid;
	register unsigned long a1 asm("a1") = arg0;
	register unsigned long a2 asm("a2") = arg1;

	__asm__ __volatile__(
		KVM_HYPERCALL
		: "=r" (ret)
		: "r" (fun), "r" (a1), "r" (a2)
		: "memory"
	);

	return ret;
}

static inline long kvm_hypercall3(u64 fid,
	unsigned long arg0, unsigned long arg1, unsigned long arg2)
{
	register long ret asm("v0");
	register unsigned long fun asm("a0") = fid;
	register unsigned long a1 asm("a1") = arg0;
	register unsigned long a2 asm("a2") = arg1;
	register unsigned long a3 asm("a3") = arg2;

	__asm__ __volatile__(
		KVM_HYPERCALL
		: "=r" (ret)
		: "r" (fun), "r" (a1), "r" (a2), "r" (a3)
		: "memory"
	);

	return ret;
}

static inline long kvm_hypercall4(u64 fid,
	unsigned long arg0, unsigned long arg1, unsigned long arg2,
	unsigned long arg3)
{
	register long ret asm("v0");
	register unsigned long fun asm("a0") = fid;
	register unsigned long a1 asm("a1") = arg0;
	register unsigned long a2 asm("a2") = arg1;
	register unsigned long a3 asm("a3") = arg2;
	register unsigned long a4 asm("a4") = arg3;

	__asm__ __volatile__(
		KVM_HYPERCALL
		: "=r" (ret)
		: "i"(fun), "r" (a1), "r" (a2), "r" (a3), "r" (a4)
		: "memory"
	);

	return ret;
}

static inline long kvm_hypercall5(u64 fid,
	unsigned long arg0, unsigned long arg1, unsigned long arg2,
	unsigned long arg3, unsigned long arg4)
{
	register long ret asm("v0");
	register unsigned long fun asm("a0") = fid;
	register unsigned long a1 asm("a1") = arg0;
	register unsigned long a2 asm("a2") = arg1;
	register unsigned long a3 asm("a3") = arg2;
	register unsigned long a4 asm("a4") = arg3;
	register unsigned long a5 asm("a5") = arg4;

	__asm__ __volatile__(
		KVM_HYPERCALL
		: "=r" (ret)
		: "i"(fun), "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5)
		: "memory"
	);

	return ret;
}

static inline long kvm_hypercall6(u64 fid,
	unsigned long arg0, unsigned long arg1, unsigned long arg2,
	unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
	register long ret asm("v0");
	register unsigned long fun asm("a0") = fid;
	register unsigned long a1 asm("a1") = arg0;
	register unsigned long a2 asm("a2") = arg1;
	register unsigned long a3 asm("a3") = arg2;
	register unsigned long a4 asm("a4") = arg3;
	register unsigned long a5 asm("a5") = arg4;
	register unsigned long a6 asm("a6") = arg5;

	__asm__ __volatile__(
		KVM_HYPERCALL
		: "=r" (ret)
		: "i"(fun), "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6)
		: "memory"
	);

	return ret;
}

static inline bool kvm_check_and_clear_guest_paused(void)
{
	return false;
+0 −2
Original line number Diff line number Diff line
@@ -14,8 +14,6 @@
#include <asm/addrspace.h>
#include <asm/bootinfo.h>

extern const struct plat_smp_ops loongson3_smp_ops;

#define LOONGSON_REG(x) \
	(*(volatile u32 *)((char *)TO_UNCACHE(LOONGSON_REG_BASE) + (x)))

+58 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_LOONGARCH_PARAVIRT_H
#define _ASM_LOONGARCH_PARAVIRT_H
#include <asm/kvm_para.h>

#ifdef CONFIG_PARAVIRT
static inline bool kvm_para_available(void)
{
	return true;
}
struct static_key;
extern struct static_key paravirt_steal_enabled;
extern struct static_key paravirt_steal_rq_enabled;

struct pv_time_ops {
	unsigned long long (*steal_clock)(int cpu);
};
struct kvm_steal_time {
	__u64 steal;
	__u32 version;
	__u32 flags;
	__u32 pad[12];
};
extern struct pv_time_ops pv_time_ops;

static inline u64 paravirt_steal_clock(int cpu)
{
	return pv_time_ops.steal_clock(cpu);
}

static inline bool pv_feature_support(int feature)
{
	return kvm_hypercall1(KVM_HC_FUNC_FEATURE, feature) == KVM_RET_SUC;
}
static inline void pv_notify_host(int feature, unsigned long data)
{
	kvm_hypercall2(KVM_HC_FUNC_NOTIFY, feature, data);
}

int __init pv_time_init(void);
int __init pv_ipi_init(void);
#else
static inline bool kvm_para_available(void)
{
	return false;
}

static inline int pv_time_init(void)
{
	return 0;
}

static inline int pv_ipi_init(void)
{
	return 0;
}
#endif
#endif /* _ASM_LOONGARCH_PARAVIRT_H */
Loading