5aa09297a3
The csr_fun defines a count parameter which defines the total number
CSRs emulated in KVM starting from the base. This value should be
equal to total number of counters possible for trap/emulation (32).
Fixes: a9ac6c3752
("RISC-V: KVM: Implement trap & emulate for hpmcounters")
Signed-off-by: Atish Patra <atishp@rivosinc.com>
Link: https://lore.kernel.org/r/20240816-kvm_pmu_fixes-v1-2-cdfce386dd93@rivosinc.com
Signed-off-by: Anup Patel <anup@brainfault.org>
133 lines
4.5 KiB
C
133 lines
4.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2023 Rivos Inc
|
|
*
|
|
* Authors:
|
|
* Atish Patra <atishp@rivosinc.com>
|
|
*/
|
|
|
|
#ifndef __KVM_VCPU_RISCV_PMU_H
|
|
#define __KVM_VCPU_RISCV_PMU_H
|
|
|
|
#include <linux/perf/riscv_pmu.h>
|
|
#include <asm/kvm_vcpu_insn.h>
|
|
#include <asm/sbi.h>
|
|
|
|
#ifdef CONFIG_RISCV_PMU_SBI
|
|
#define RISCV_KVM_MAX_FW_CTRS 32
|
|
#define RISCV_KVM_MAX_HW_CTRS 32
|
|
#define RISCV_KVM_MAX_COUNTERS (RISCV_KVM_MAX_HW_CTRS + RISCV_KVM_MAX_FW_CTRS)
|
|
static_assert(RISCV_KVM_MAX_COUNTERS <= 64);
|
|
|
|
struct kvm_fw_event {
|
|
/* Current value of the event */
|
|
u64 value;
|
|
|
|
/* Event monitoring status */
|
|
bool started;
|
|
};
|
|
|
|
/* Per virtual pmu counter data */
|
|
struct kvm_pmc {
|
|
u8 idx;
|
|
struct perf_event *perf_event;
|
|
u64 counter_val;
|
|
union sbi_pmu_ctr_info cinfo;
|
|
/* Event monitoring status */
|
|
bool started;
|
|
/* Monitoring event ID */
|
|
unsigned long event_idx;
|
|
struct kvm_vcpu *vcpu;
|
|
};
|
|
|
|
/* PMU data structure per vcpu */
|
|
struct kvm_pmu {
|
|
struct kvm_pmc pmc[RISCV_KVM_MAX_COUNTERS];
|
|
struct kvm_fw_event fw_event[RISCV_KVM_MAX_FW_CTRS];
|
|
/* Number of the virtual firmware counters available */
|
|
int num_fw_ctrs;
|
|
/* Number of the virtual hardware counters available */
|
|
int num_hw_ctrs;
|
|
/* A flag to indicate that pmu initialization is done */
|
|
bool init_done;
|
|
/* Bit map of all the virtual counter used */
|
|
DECLARE_BITMAP(pmc_in_use, RISCV_KVM_MAX_COUNTERS);
|
|
/* Bit map of all the virtual counter overflown */
|
|
DECLARE_BITMAP(pmc_overflown, RISCV_KVM_MAX_COUNTERS);
|
|
/* The address of the counter snapshot area (guest physical address) */
|
|
gpa_t snapshot_addr;
|
|
/* The actual data of the snapshot */
|
|
struct riscv_pmu_snapshot_data *sdata;
|
|
};
|
|
|
|
#define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu_context)
|
|
#define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu_context))
|
|
|
|
#if defined(CONFIG_32BIT)
|
|
#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \
|
|
{.base = CSR_CYCLEH, .count = 32, .func = kvm_riscv_vcpu_pmu_read_hpm }, \
|
|
{.base = CSR_CYCLE, .count = 32, .func = kvm_riscv_vcpu_pmu_read_hpm },
|
|
#else
|
|
#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \
|
|
{.base = CSR_CYCLE, .count = 32, .func = kvm_riscv_vcpu_pmu_read_hpm },
|
|
#endif
|
|
|
|
int kvm_riscv_vcpu_pmu_incr_fw(struct kvm_vcpu *vcpu, unsigned long fid);
|
|
int kvm_riscv_vcpu_pmu_read_hpm(struct kvm_vcpu *vcpu, unsigned int csr_num,
|
|
unsigned long *val, unsigned long new_val,
|
|
unsigned long wr_mask);
|
|
|
|
int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_return *retdata);
|
|
int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx,
|
|
struct kvm_vcpu_sbi_return *retdata);
|
|
int kvm_riscv_vcpu_pmu_ctr_start(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|
unsigned long ctr_mask, unsigned long flags, u64 ival,
|
|
struct kvm_vcpu_sbi_return *retdata);
|
|
int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|
unsigned long ctr_mask, unsigned long flags,
|
|
struct kvm_vcpu_sbi_return *retdata);
|
|
int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|
unsigned long ctr_mask, unsigned long flags,
|
|
unsigned long eidx, u64 evtdata,
|
|
struct kvm_vcpu_sbi_return *retdata);
|
|
int kvm_riscv_vcpu_pmu_fw_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
|
|
struct kvm_vcpu_sbi_return *retdata);
|
|
int kvm_riscv_vcpu_pmu_fw_ctr_read_hi(struct kvm_vcpu *vcpu, unsigned long cidx,
|
|
struct kvm_vcpu_sbi_return *retdata);
|
|
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);
|
|
void kvm_riscv_vcpu_pmu_deinit(struct kvm_vcpu *vcpu);
|
|
void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu);
|
|
|
|
#else
|
|
struct kvm_pmu {
|
|
};
|
|
|
|
static inline int kvm_riscv_vcpu_pmu_read_legacy(struct kvm_vcpu *vcpu, unsigned int csr_num,
|
|
unsigned long *val, unsigned long new_val,
|
|
unsigned long wr_mask)
|
|
{
|
|
if (csr_num == CSR_CYCLE || csr_num == CSR_INSTRET) {
|
|
*val = 0;
|
|
return KVM_INSN_CONTINUE_NEXT_SEPC;
|
|
} else {
|
|
return KVM_INSN_ILLEGAL_TRAP;
|
|
}
|
|
}
|
|
|
|
#define KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS \
|
|
{.base = CSR_CYCLE, .count = 3, .func = kvm_riscv_vcpu_pmu_read_legacy },
|
|
|
|
static inline void kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu) {}
|
|
static inline int kvm_riscv_vcpu_pmu_incr_fw(struct kvm_vcpu *vcpu, unsigned long fid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void kvm_riscv_vcpu_pmu_deinit(struct kvm_vcpu *vcpu) {}
|
|
static inline void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu) {}
|
|
#endif /* CONFIG_RISCV_PMU_SBI */
|
|
#endif /* !__KVM_VCPU_RISCV_PMU_H */
|