Commit d47f8143 authored by lishusen's avatar lishusen
Browse files

KVM: arm64: Implement the capability of DVMBM

virt inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8TN8N


CVE: NA

----------------------------------------------------

Implement the capability of DVMBM. Before each vcpu is loaded, we
re-calculate the VM-wide sched_cpus, and if it's changed we will kick all
other vcpus out to reload the latest LSUDVMBM value to the register, and a
new request KVM_REQ_RELOAD_TLBI_DVMBM is added to implement this.

Otherwise if the sched_cpus is not changed by this single vcpu, in order
to ensure the correctness of the contents in the register, we reload the
LSUDVMBM value to the register and nothing else will be done.

Signed-off-by: default avatarQuan Zhou <zhouquan65@huawei.com>
Signed-off-by: default avatarlishusen <lishusen2@huawei.com>
parent c4ed39bb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@
#define KVM_REQ_RELOAD_PMU	KVM_ARCH_REQ(5)
#define KVM_REQ_SUSPEND		KVM_ARCH_REQ(6)
#define KVM_REQ_RESYNC_PMU_EL0	KVM_ARCH_REQ(7)
#define KVM_REQ_RELOAD_TLBI_DVMBM	KVM_ARCH_REQ(8)

#define KVM_DIRTY_LOG_MANUAL_CAPS   (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
				     KVM_DIRTY_LOG_INITIALLY_SET)
@@ -283,6 +284,7 @@ struct kvm_arch {
#ifdef CONFIG_KVM_HISI_VIRT
	spinlock_t sched_lock;
	cpumask_var_t sched_cpus;	/* Union of all vcpu's cpus_ptr */
	u64 tlbi_dvmbm;
#endif
};

+3 −0
Original line number Diff line number Diff line
@@ -836,6 +836,9 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)

		if (kvm_dirty_ring_check_request(vcpu))
			return 0;

		if (kvm_check_request(KVM_REQ_RELOAD_TLBI_DVMBM, vcpu))
			kvm_hisi_reload_lsudvmbm(vcpu->kvm);
	}

	return 1;
+113 −1
Original line number Diff line number Diff line
@@ -195,6 +195,96 @@ void kvm_sched_affinity_vcpu_destroy(struct kvm_vcpu *vcpu)
	free_cpumask_var(vcpu->arch.pre_sched_cpus);
}

static void __kvm_write_lsudvmbm(struct kvm *kvm)
{
	write_sysreg_s(kvm->arch.tlbi_dvmbm, SYS_LSUDVMBM_EL2);
}

static void kvm_write_lsudvmbm(struct kvm *kvm)
{
	spin_lock(&kvm->arch.sched_lock);
	__kvm_write_lsudvmbm(kvm);
	spin_unlock(&kvm->arch.sched_lock);
}

static int kvm_dvmbm_get_dies_info(struct kvm *kvm, u64 *vm_aff3s, int size)
{
	int num = 0, cpu;

	for_each_cpu(cpu, kvm->arch.sched_cpus) {
		bool found = false;
		u64 aff3;
		int i;

		if (num >= size)
			break;

		aff3 = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 3);
		for (i = 0; i < num; i++) {
			if (vm_aff3s[i] == aff3) {
				found = true;
				break;
			}
		}

		if (!found)
			vm_aff3s[num++] = aff3;
	}

	return num;
}

static void kvm_update_vm_lsudvmbm(struct kvm *kvm)
{
	u64 mpidr, aff3, aff2, aff1;
	u64 vm_aff3s[DVMBM_MAX_DIES];
	u64 val;
	int cpu, nr_dies;

	nr_dies = kvm_dvmbm_get_dies_info(kvm, vm_aff3s, DVMBM_MAX_DIES);
	if (nr_dies > 2) {
		val = DVMBM_RANGE_ALL_DIES << DVMBM_RANGE_SHIFT;
		goto out_update;
	}

	if (nr_dies == 1) {
		val = DVMBM_RANGE_ONE_DIE << DVMBM_RANGE_SHIFT	|
		      vm_aff3s[0] << DVMBM_DIE1_SHIFT;

		/* fulfill bits [52:0] */
		for_each_cpu(cpu, kvm->arch.sched_cpus) {
			mpidr = cpu_logical_map(cpu);
			aff2 = MPIDR_AFFINITY_LEVEL(mpidr, 2);
			aff1 = MPIDR_AFFINITY_LEVEL(mpidr, 1);

			val |= 1ULL << (aff2 * 4 + aff1);
		}

		goto out_update;
	}

	/* nr_dies == 2 */
	val = DVMBM_RANGE_TWO_DIES << DVMBM_RANGE_SHIFT	|
	      DVMBM_GRAN_CLUSTER << DVMBM_GRAN_SHIFT	|
	      vm_aff3s[0] << DVMBM_DIE1_SHIFT		|
	      vm_aff3s[1] << DVMBM_DIE2_SHIFT;

	/* and fulfill bits [43:0] */
	for_each_cpu(cpu, kvm->arch.sched_cpus) {
		mpidr = cpu_logical_map(cpu);
		aff3 = MPIDR_AFFINITY_LEVEL(mpidr, 3);
		aff2 = MPIDR_AFFINITY_LEVEL(mpidr, 2);

		if (aff3 == vm_aff3s[0])
			val |= 1ULL << (aff2 + DVMBM_DIE1_CLUSTER_SHIFT);
		else
			val |= 1ULL << (aff2 + DVMBM_DIE2_CLUSTER_SHIFT);
	}

out_update:
	kvm->arch.tlbi_dvmbm = val;
}

void kvm_tlbi_dvmbm_vcpu_load(struct kvm_vcpu *vcpu)
{
	struct kvm *kvm = vcpu->kvm;
@@ -209,8 +299,10 @@ void kvm_tlbi_dvmbm_vcpu_load(struct kvm_vcpu *vcpu)
	cpumask_copy(vcpu->arch.sched_cpus, current->cpus_ptr);

	if (likely(cpumask_equal(vcpu->arch.sched_cpus,
				 vcpu->arch.pre_sched_cpus)))
				 vcpu->arch.pre_sched_cpus))) {
		kvm_write_lsudvmbm(kvm);
		return;
	}

	/* Re-calculate sched_cpus for this VM */
	spin_lock(&kvm->arch.sched_lock);
@@ -231,7 +323,17 @@ void kvm_tlbi_dvmbm_vcpu_load(struct kvm_vcpu *vcpu)

	cpumask_copy(kvm->arch.sched_cpus, &mask);

	kvm_flush_remote_tlbs(kvm);

	/*
	 * Re-calculate LSUDVMBM_EL2 for this VM and kick all vcpus
	 * out to reload the LSUDVMBM configuration.
	 */
	kvm_update_vm_lsudvmbm(kvm);
	kvm_make_all_cpus_request(kvm, KVM_REQ_RELOAD_TLBI_DVMBM);

out_unlock:
	__kvm_write_lsudvmbm(kvm);
	spin_unlock(&kvm->arch.sched_lock);
}

@@ -262,3 +364,13 @@ void kvm_sched_affinity_vm_destroy(struct kvm *kvm)

	free_cpumask_var(kvm->arch.sched_cpus);
}

void kvm_hisi_reload_lsudvmbm(struct kvm *kvm)
{
	if (WARN_ON_ONCE(!kvm_dvmbm_support))
		return;

	preempt_disable();
	kvm_write_lsudvmbm(kvm);
	preempt_enable();
}
+29 −0
Original line number Diff line number Diff line
@@ -20,6 +20,33 @@ enum hisi_cpu_type {
#define SYS_LSUDVM_CTRL_EL2	sys_reg(3, 4, 15, 7, 4)
#define LSUDVM_CTLR_EL2_MASK	BIT_ULL(0)

/*
 * MPIDR_EL1 layout on HIP09
 *
 * Aff3[7:3]	- socket ID	[0-15]
 * Aff3[2:0]	- die ID	[1,3]
 * Aff2		- cluster ID	[0-9]
 * Aff1		- core ID	[0-3]
 * Aff0		- thread ID	[0,1]
 */

#define SYS_LSUDVMBM_EL2		sys_reg(3, 4, 15, 7, 5)
#define DVMBM_RANGE_SHIFT		62
#define DVMBM_RANGE_ONE_DIE		0ULL
#define DVMBM_RANGE_TWO_DIES		1ULL
#define DVMBM_RANGE_ALL_DIES		3ULL

#define DVMBM_GRAN_SHIFT		61
#define DVMBM_GRAN_CLUSTER		0ULL
#define DVMBM_GRAN_DIE			1ULL

#define DVMBM_DIE1_SHIFT		53
#define DVMBM_DIE2_SHIFT		45
#define DVMBM_DIE1_CLUSTER_SHIFT	22
#define DVMBM_DIE2_CLUSTER_SHIFT	0

#define DVMBM_MAX_DIES			32

void probe_hisi_cpu_type(void);
bool hisi_ncsnp_supported(void);
bool hisi_dvmbm_supported(void);
@@ -30,6 +57,7 @@ int kvm_sched_affinity_vm_init(struct kvm *kvm);
void kvm_sched_affinity_vm_destroy(struct kvm *kvm);
void kvm_tlbi_dvmbm_vcpu_load(struct kvm_vcpu *vcpu);
void kvm_tlbi_dvmbm_vcpu_put(struct kvm_vcpu *vcpu);
void kvm_hisi_reload_lsudvmbm(struct kvm *kvm);
#else
static inline void probe_hisi_cpu_type(void) {}
static inline bool hisi_ncsnp_supported(void)
@@ -53,6 +81,7 @@ static inline int kvm_sched_affinity_vm_init(struct kvm *kvm)
static inline void kvm_sched_affinity_vm_destroy(struct kvm *kvm) {}
static inline void kvm_tlbi_dvmbm_vcpu_load(struct kvm_vcpu *vcpu) {}
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 */

#endif /* __HISI_VIRT_H__ */