Commit e309fd11 authored by Atish Patra's avatar Atish Patra Committed by Anup Patel
Browse files

RISC-V: KVM: Implement get event info function



The new get_event_info funciton allows the guest to query the presence
of multiple events with single SBI call. Currently, the perf driver
in linux guest invokes it for all the standard SBI PMU events. Support
the SBI function implementation in KVM as well.

Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
Signed-off-by: default avatarAtish Patra <atishp@rivosinc.com>
Acked-by: default avatarPaul Walmsley <pjw@kernel.org>
Link: https://lore.kernel.org/r/20250909-pmu_event_info-v6-7-d8f80cacb884@rivosinc.com


Signed-off-by: default avatarAnup Patel <anup@brainfault.org>
parent 41f4d0cc
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -98,6 +98,9 @@ void kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu);
int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long saddr_low,
				      unsigned long saddr_high, unsigned long flags,
				      struct kvm_vcpu_sbi_return *retdata);
int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low,
				  unsigned long saddr_high, unsigned long num_events,
				  unsigned long flags, struct kvm_vcpu_sbi_return *retdata);
void kvm_riscv_vcpu_pmu_deinit(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu);

+59 −0
Original line number Diff line number Diff line
@@ -449,6 +449,65 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s
	return 0;
}

int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low,
				  unsigned long saddr_high, unsigned long num_events,
				  unsigned long flags, struct kvm_vcpu_sbi_return *retdata)
{
	struct riscv_pmu_event_info *einfo = NULL;
	int shmem_size = num_events * sizeof(*einfo);
	gpa_t shmem;
	u32 eidx, etype;
	u64 econfig;
	int ret;

	if (flags != 0 || (saddr_low & (SZ_16 - 1) || num_events == 0)) {
		ret = SBI_ERR_INVALID_PARAM;
		goto out;
	}

	shmem = saddr_low;
	if (saddr_high != 0) {
		if (IS_ENABLED(CONFIG_32BIT)) {
			shmem |= ((gpa_t)saddr_high << 32);
		} else {
			ret = SBI_ERR_INVALID_ADDRESS;
			goto out;
		}
	}

	einfo = kzalloc(shmem_size, GFP_KERNEL);
	if (!einfo)
		return -ENOMEM;

	ret = kvm_vcpu_read_guest(vcpu, shmem, einfo, shmem_size);
	if (ret) {
		ret = SBI_ERR_FAILURE;
		goto free_mem;
	}

	for (int i = 0; i < num_events; i++) {
		eidx = einfo[i].event_idx;
		etype = kvm_pmu_get_perf_event_type(eidx);
		econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data);
		ret = riscv_pmu_get_event_info(etype, econfig, NULL);
		einfo[i].output = (ret > 0) ? 1 : 0;
	}

	ret = kvm_vcpu_write_guest(vcpu, shmem, einfo, shmem_size);
	if (ret) {
		ret = SBI_ERR_INVALID_ADDRESS;
		goto free_mem;
	}

	ret = 0;
free_mem:
	kfree(einfo);
out:
	retdata->err_val = ret;

	return 0;
}

int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu,
				struct kvm_vcpu_sbi_return *retdata)
{
+3 −0
Original line number Diff line number Diff line
@@ -73,6 +73,9 @@ static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
	case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM:
		ret = kvm_riscv_vcpu_pmu_snapshot_set_shmem(vcpu, cp->a0, cp->a1, cp->a2, retdata);
		break;
	case SBI_EXT_PMU_EVENT_GET_INFO:
		ret = kvm_riscv_vcpu_pmu_event_info(vcpu, cp->a0, cp->a1, cp->a2, cp->a3, retdata);
		break;
	default:
		retdata->err_val = SBI_ERR_NOT_SUPPORTED;
	}