Commit f4e40ea9 authored by Song Gao's avatar Song Gao Committed by Huacai Chen
Browse files

LoongArch: KVM: Add PMU support for guest



On LoongArch, the host and guest have their own PMU CSRs registers and
they share PMU hardware resources. A set of PMU CSRs consists of a CTRL
register and a CNTR register. We can set which PMU CSRs are used by the
guest by writing to the GCFG register [24:26] bits.

On KVM side:
- Save the host PMU CSRs into structure kvm_context.
- If the host supports the PMU feature.
  - When entering guest mode, save the host PMU CSRs and restore the guest PMU CSRs.
  - When exiting guest mode, save the guest PMU CSRs and restore the host PMU CSRs.

Reviewed-by: default avatarBibo Mao <maobibo@loongson.cn>
Signed-off-by: default avatarSong Gao <gaosong@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent acc7f20d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
		: [val] "+r" (__v)				\
		: [reg] "i" (csr)				\
		: "memory");					\
	__v;							\
})

#define gcsr_xchg(v, m, csr)					\
@@ -181,6 +182,8 @@ __BUILD_GCSR_OP(tlbidx)
#define kvm_save_hw_gcsr(csr, gid)	(csr->csrs[gid] = gcsr_read(gid))
#define kvm_restore_hw_gcsr(csr, gid)	(gcsr_write(csr->csrs[gid], gid))

#define kvm_read_clear_hw_gcsr(csr, gid)	(csr->csrs[gid] = gcsr_write(0, gid))

int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu);

static __always_inline unsigned long kvm_read_sw_gcsr(struct loongarch_csrs *csr, int gid)
@@ -208,4 +211,7 @@ static __always_inline void kvm_change_sw_gcsr(struct loongarch_csrs *csr,
	csr->csrs[gid] |= val & _mask;
}

#define KVM_PMU_EVENT_ENABLED	(CSR_PERFCTRL_PLV0 | CSR_PERFCTRL_PLV1 | \
					CSR_PERFCTRL_PLV2 | CSR_PERFCTRL_PLV3)

#endif	/* __ASM_LOONGARCH_KVM_CSR_H__ */
+21 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#define KVM_HALT_POLL_NS_DEFAULT	500000
#define KVM_REQ_TLB_FLUSH_GPA		KVM_ARCH_REQ(0)
#define KVM_REQ_STEAL_UPDATE		KVM_ARCH_REQ(1)
#define KVM_REQ_PMU			KVM_ARCH_REQ(2)

#define KVM_GUESTDBG_SW_BP_MASK		\
	(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)
@@ -60,9 +61,13 @@ struct kvm_arch_memory_slot {
	unsigned long flags;
};

#define HOST_MAX_PMNUM			16
struct kvm_context {
	unsigned long vpid_cache;
	struct kvm_vcpu *last_vcpu;
	/* Host PMU CSR */
	u64 perf_ctrl[HOST_MAX_PMNUM];
	u64 perf_cntr[HOST_MAX_PMNUM];
};

struct kvm_world_switch {
@@ -134,8 +139,9 @@ enum emulation_result {
#define KVM_LARCH_LSX		(0x1 << 1)
#define KVM_LARCH_LASX		(0x1 << 2)
#define KVM_LARCH_LBT		(0x1 << 3)
#define KVM_LARCH_SWCSR_LATEST	(0x1 << 4)
#define KVM_LARCH_HWCSR_USABLE	(0x1 << 5)
#define KVM_LARCH_PMU		(0x1 << 4)
#define KVM_LARCH_SWCSR_LATEST	(0x1 << 5)
#define KVM_LARCH_HWCSR_USABLE	(0x1 << 6)

struct kvm_vcpu_arch {
	/*
@@ -174,6 +180,9 @@ struct kvm_vcpu_arch {
	/* CSR state */
	struct loongarch_csrs *csr;

	/* Guest max PMU CSR id */
	int max_pmu_csrid;

	/* GPR used as IO source/target */
	u32 io_gpr;

@@ -246,6 +255,16 @@ static inline bool kvm_guest_has_lbt(struct kvm_vcpu_arch *arch)
	return arch->cpucfg[2] & (CPUCFG2_X86BT | CPUCFG2_ARMBT | CPUCFG2_MIPSBT);
}

static inline bool kvm_guest_has_pmu(struct kvm_vcpu_arch *arch)
{
	return arch->cpucfg[6] & CPUCFG6_PMP;
}

static inline int kvm_get_pmu_num(struct kvm_vcpu_arch *arch)
{
	return (arch->cpucfg[6] & CPUCFG6_PMNUM) >> CPUCFG6_PMNUM_SHIFT;
}

/* Debug: dump vcpu state */
int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);

+1 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@
#define  CPUCFG6_PMP			BIT(0)
#define  CPUCFG6_PAMVER			GENMASK(3, 1)
#define  CPUCFG6_PMNUM			GENMASK(7, 4)
#define  CPUCFG6_PMNUM_SHIFT		4
#define  CPUCFG6_PMBITS			GENMASK(13, 8)
#define  CPUCFG6_UPM			BIT(14)

+1 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ struct kvm_fpu {
#define  KVM_LOONGARCH_VM_FEAT_X86BT	2
#define  KVM_LOONGARCH_VM_FEAT_ARMBT	3
#define  KVM_LOONGARCH_VM_FEAT_MIPSBT	4
#define  KVM_LOONGARCH_VM_FEAT_PMU	5

/* Device Control API on vcpu fd */
#define KVM_LOONGARCH_VCPU_CPUCFG	0
+8 −0
Original line number Diff line number Diff line
@@ -127,6 +127,14 @@ static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst)
	rj = inst.reg2csr_format.rj;
	csrid = inst.reg2csr_format.csr;

	if (csrid >= LOONGARCH_CSR_PERFCTRL0 && csrid <= vcpu->arch.max_pmu_csrid) {
		if (kvm_guest_has_pmu(&vcpu->arch)) {
			vcpu->arch.pc -= 4;
			kvm_make_request(KVM_REQ_PMU, vcpu);
			return EMULATE_DONE;
		}
	}

	/* Process CSR ops */
	switch (rj) {
	case 0: /* process csrrd */
Loading