Message ID | 20221215170046.2010255-8-atishp@rivosinc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM perf support | expand |
On Thu, Dec 15, 2022 at 09:00:42AM -0800, Atish Patra wrote: > SBI PMU extension allows KVM guests to configure/start/stop/query about > the PMU counters in virtualized enviornment as well. > > In order to allow that, KVM implements the entire SBI PMU extension. > > Signed-off-by: Atish Patra <atishp@rivosinc.com> > --- > arch/riscv/kvm/Makefile | 2 +- > arch/riscv/kvm/vcpu_sbi.c | 11 +++++ > arch/riscv/kvm/vcpu_sbi_pmu.c | 86 +++++++++++++++++++++++++++++++++++ > 3 files changed, 98 insertions(+), 1 deletion(-) > create mode 100644 arch/riscv/kvm/vcpu_sbi_pmu.c > > diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile > index 5de1053..278e97c 100644 > --- a/arch/riscv/kvm/Makefile > +++ b/arch/riscv/kvm/Makefile > @@ -25,4 +25,4 @@ kvm-y += vcpu_sbi_base.o > kvm-y += vcpu_sbi_replace.o > kvm-y += vcpu_sbi_hsm.o > kvm-y += vcpu_timer.o > -kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o > +kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o > diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c > index 50c5472..3b8b84e8 100644 > --- a/arch/riscv/kvm/vcpu_sbi.c > +++ b/arch/riscv/kvm/vcpu_sbi.c > @@ -20,6 +20,16 @@ static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01 = { > }; > #endif > > +#ifdef CONFIG_RISCV_PMU_SBI > +extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu; > +#else > +static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = { > + .extid_start = -1UL, > + .extid_end = -1UL, > + .handler = NULL, > +}; > +#endif > + > static const struct kvm_vcpu_sbi_extension *sbi_ext[] = { > &vcpu_sbi_ext_v01, > &vcpu_sbi_ext_base, > @@ -28,6 +38,7 @@ static const struct kvm_vcpu_sbi_extension *sbi_ext[] = { > &vcpu_sbi_ext_rfence, > &vcpu_sbi_ext_srst, > &vcpu_sbi_ext_hsm, > + &vcpu_sbi_ext_pmu, > &vcpu_sbi_ext_experimental, > &vcpu_sbi_ext_vendor, > }; > diff --git a/arch/riscv/kvm/vcpu_sbi_pmu.c b/arch/riscv/kvm/vcpu_sbi_pmu.c > new file mode 100644 > index 0000000..223752f > --- /dev/null > +++ b/arch/riscv/kvm/vcpu_sbi_pmu.c > @@ -0,0 +1,86 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2022 Rivos Inc > + * > + * Authors: > + * Atish Patra <atishp@rivosinc.com> > + */ > + > +#include <linux/errno.h> > +#include <linux/err.h> > +#include <linux/kvm_host.h> > +#include <asm/csr.h> > +#include <asm/sbi.h> > +#include <asm/kvm_vcpu_sbi.h> > + > +static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, > + struct kvm_vcpu_sbi_ext_data *edata, > + struct kvm_cpu_trap *utrap) > +{ > + int ret = 0; > + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > + unsigned long funcid = cp->a6; > + uint64_t temp; > + > + /* Return not supported if PMU is not initialized */ > + if (!kvpmu->init_done) > + return -EINVAL; > + > + switch (funcid) { > + case SBI_EXT_PMU_NUM_COUNTERS: > + ret = kvm_riscv_vcpu_pmu_num_ctrs(vcpu, edata); > + break; > + case SBI_EXT_PMU_COUNTER_GET_INFO: > + ret = kvm_riscv_vcpu_pmu_ctr_info(vcpu, cp->a0, edata); > + break; > + case SBI_EXT_PMU_COUNTER_CFG_MATCH: > +#if defined(CONFIG_32BIT) > + temp = ((uint64_t)cp->a5 << 32) | cp->a4; > +#else > + temp = cp->a4; > +#endif > + ret = kvm_riscv_vcpu_pmu_ctr_cfg_match(vcpu, cp->a0, cp->a1, > + cp->a2, cp->a3, temp, edata); > + break; > + case SBI_EXT_PMU_COUNTER_START: > +#if defined(CONFIG_32BIT) > + temp = ((uint64_t)cp->a4 << 32) | cp->a3; > +#else > + temp = cp->a3; > +#endif > + ret = kvm_riscv_vcpu_pmu_ctr_start(vcpu, cp->a0, cp->a1, cp->a2, > + temp, edata); > + break; > + case SBI_EXT_PMU_COUNTER_STOP: > + ret = kvm_riscv_vcpu_pmu_ctr_stop(vcpu, cp->a0, cp->a1, cp->a2, edata); > + break; > + case SBI_EXT_PMU_COUNTER_FW_READ: > + ret = kvm_riscv_vcpu_pmu_ctr_read(vcpu, cp->a0, edata); > + break; > + default: > + edata->err_val = SBI_ERR_NOT_SUPPORTED; > + } > + > + > + return ret; > +} > + > +unsigned long kvm_sbi_ext_pmu_probe(struct kvm_vcpu *vcpu, unsigned long extid) > +{ > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > + > + /* > + * PMU Extension is only available to guests if privilege mode filtering > + * is available. Otherwise, guest will always count events while the > + * execution is in hypervisor mode. > + */ > + return kvpmu->init_done && riscv_isa_extension_available(NULL, SSCOFPMF); Assuming we're only supporting homogeneous systems, then can't we just check for Sscofpmf at PMU init time? When the extension isn't present we'd fail to init and then here init_done wouldn't be set. > +} > + > +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = { > + .extid_start = SBI_EXT_PMU, > + .extid_end = SBI_EXT_PMU, > + .handler = kvm_sbi_ext_pmu_handler, > + .probe = kvm_sbi_ext_pmu_probe, > +}; > -- > 2.25.1 > Thanks, drew
On Thu, Jan 12, 2023 at 7:29 AM Andrew Jones <ajones@ventanamicro.com> wrote: > > On Thu, Dec 15, 2022 at 09:00:42AM -0800, Atish Patra wrote: > > SBI PMU extension allows KVM guests to configure/start/stop/query about > > the PMU counters in virtualized enviornment as well. > > > > In order to allow that, KVM implements the entire SBI PMU extension. > > > > Signed-off-by: Atish Patra <atishp@rivosinc.com> > > --- > > arch/riscv/kvm/Makefile | 2 +- > > arch/riscv/kvm/vcpu_sbi.c | 11 +++++ > > arch/riscv/kvm/vcpu_sbi_pmu.c | 86 +++++++++++++++++++++++++++++++++++ > > 3 files changed, 98 insertions(+), 1 deletion(-) > > create mode 100644 arch/riscv/kvm/vcpu_sbi_pmu.c > > > > diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile > > index 5de1053..278e97c 100644 > > --- a/arch/riscv/kvm/Makefile > > +++ b/arch/riscv/kvm/Makefile > > @@ -25,4 +25,4 @@ kvm-y += vcpu_sbi_base.o > > kvm-y += vcpu_sbi_replace.o > > kvm-y += vcpu_sbi_hsm.o > > kvm-y += vcpu_timer.o > > -kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o > > +kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o > > diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c > > index 50c5472..3b8b84e8 100644 > > --- a/arch/riscv/kvm/vcpu_sbi.c > > +++ b/arch/riscv/kvm/vcpu_sbi.c > > @@ -20,6 +20,16 @@ static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01 = { > > }; > > #endif > > > > +#ifdef CONFIG_RISCV_PMU_SBI > > +extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu; > > +#else > > +static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = { > > + .extid_start = -1UL, > > + .extid_end = -1UL, > > + .handler = NULL, > > +}; > > +#endif > > + > > static const struct kvm_vcpu_sbi_extension *sbi_ext[] = { > > &vcpu_sbi_ext_v01, > > &vcpu_sbi_ext_base, > > @@ -28,6 +38,7 @@ static const struct kvm_vcpu_sbi_extension *sbi_ext[] = { > > &vcpu_sbi_ext_rfence, > > &vcpu_sbi_ext_srst, > > &vcpu_sbi_ext_hsm, > > + &vcpu_sbi_ext_pmu, > > &vcpu_sbi_ext_experimental, > > &vcpu_sbi_ext_vendor, > > }; > > diff --git a/arch/riscv/kvm/vcpu_sbi_pmu.c b/arch/riscv/kvm/vcpu_sbi_pmu.c > > new file mode 100644 > > index 0000000..223752f > > --- /dev/null > > +++ b/arch/riscv/kvm/vcpu_sbi_pmu.c > > @@ -0,0 +1,86 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2022 Rivos Inc > > + * > > + * Authors: > > + * Atish Patra <atishp@rivosinc.com> > > + */ > > + > > +#include <linux/errno.h> > > +#include <linux/err.h> > > +#include <linux/kvm_host.h> > > +#include <asm/csr.h> > > +#include <asm/sbi.h> > > +#include <asm/kvm_vcpu_sbi.h> > > + > > +static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, > > + struct kvm_vcpu_sbi_ext_data *edata, > > + struct kvm_cpu_trap *utrap) > > +{ > > + int ret = 0; > > + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > + unsigned long funcid = cp->a6; > > + uint64_t temp; > > + > > + /* Return not supported if PMU is not initialized */ > > + if (!kvpmu->init_done) > > + return -EINVAL; > > + > > + switch (funcid) { > > + case SBI_EXT_PMU_NUM_COUNTERS: > > + ret = kvm_riscv_vcpu_pmu_num_ctrs(vcpu, edata); > > + break; > > + case SBI_EXT_PMU_COUNTER_GET_INFO: > > + ret = kvm_riscv_vcpu_pmu_ctr_info(vcpu, cp->a0, edata); > > + break; > > + case SBI_EXT_PMU_COUNTER_CFG_MATCH: > > +#if defined(CONFIG_32BIT) > > + temp = ((uint64_t)cp->a5 << 32) | cp->a4; > > +#else > > + temp = cp->a4; > > +#endif > > + ret = kvm_riscv_vcpu_pmu_ctr_cfg_match(vcpu, cp->a0, cp->a1, > > + cp->a2, cp->a3, temp, edata); > > + break; > > + case SBI_EXT_PMU_COUNTER_START: > > +#if defined(CONFIG_32BIT) > > + temp = ((uint64_t)cp->a4 << 32) | cp->a3; > > +#else > > + temp = cp->a3; > > +#endif > > + ret = kvm_riscv_vcpu_pmu_ctr_start(vcpu, cp->a0, cp->a1, cp->a2, > > + temp, edata); > > + break; > > + case SBI_EXT_PMU_COUNTER_STOP: > > + ret = kvm_riscv_vcpu_pmu_ctr_stop(vcpu, cp->a0, cp->a1, cp->a2, edata); > > + break; > > + case SBI_EXT_PMU_COUNTER_FW_READ: > > + ret = kvm_riscv_vcpu_pmu_ctr_read(vcpu, cp->a0, edata); > > + break; > > + default: > > + edata->err_val = SBI_ERR_NOT_SUPPORTED; > > + } > > + > > + > > + return ret; > > +} > > + > > +unsigned long kvm_sbi_ext_pmu_probe(struct kvm_vcpu *vcpu, unsigned long extid) > > +{ > > + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); > > + > > + /* > > + * PMU Extension is only available to guests if privilege mode filtering > > + * is available. Otherwise, guest will always count events while the > > + * execution is in hypervisor mode. > > + */ > > + return kvpmu->init_done && riscv_isa_extension_available(NULL, SSCOFPMF); > > Assuming we're only supporting homogeneous systems, then can't we just > check for Sscofpmf at PMU init time? When the extension isn't present > we'd fail to init and then here init_done wouldn't be set. > Sure. We can do that too. Will revise it v3. > > +} > > + > > +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = { > > + .extid_start = SBI_EXT_PMU, > > + .extid_end = SBI_EXT_PMU, > > + .handler = kvm_sbi_ext_pmu_handler, > > + .probe = kvm_sbi_ext_pmu_probe, > > +}; > > -- > > 2.25.1 > > > > Thanks, > drew
diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index 5de1053..278e97c 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -25,4 +25,4 @@ kvm-y += vcpu_sbi_base.o kvm-y += vcpu_sbi_replace.o kvm-y += vcpu_sbi_hsm.o kvm-y += vcpu_timer.o -kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o +kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 50c5472..3b8b84e8 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -20,6 +20,16 @@ static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01 = { }; #endif +#ifdef CONFIG_RISCV_PMU_SBI +extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu; +#else +static const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = { + .extid_start = -1UL, + .extid_end = -1UL, + .handler = NULL, +}; +#endif + static const struct kvm_vcpu_sbi_extension *sbi_ext[] = { &vcpu_sbi_ext_v01, &vcpu_sbi_ext_base, @@ -28,6 +38,7 @@ static const struct kvm_vcpu_sbi_extension *sbi_ext[] = { &vcpu_sbi_ext_rfence, &vcpu_sbi_ext_srst, &vcpu_sbi_ext_hsm, + &vcpu_sbi_ext_pmu, &vcpu_sbi_ext_experimental, &vcpu_sbi_ext_vendor, }; diff --git a/arch/riscv/kvm/vcpu_sbi_pmu.c b/arch/riscv/kvm/vcpu_sbi_pmu.c new file mode 100644 index 0000000..223752f --- /dev/null +++ b/arch/riscv/kvm/vcpu_sbi_pmu.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Rivos Inc + * + * Authors: + * Atish Patra <atishp@rivosinc.com> + */ + +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/kvm_host.h> +#include <asm/csr.h> +#include <asm/sbi.h> +#include <asm/kvm_vcpu_sbi.h> + +static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_vcpu_sbi_ext_data *edata, + struct kvm_cpu_trap *utrap) +{ + int ret = 0; + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); + unsigned long funcid = cp->a6; + uint64_t temp; + + /* Return not supported if PMU is not initialized */ + if (!kvpmu->init_done) + return -EINVAL; + + switch (funcid) { + case SBI_EXT_PMU_NUM_COUNTERS: + ret = kvm_riscv_vcpu_pmu_num_ctrs(vcpu, edata); + break; + case SBI_EXT_PMU_COUNTER_GET_INFO: + ret = kvm_riscv_vcpu_pmu_ctr_info(vcpu, cp->a0, edata); + break; + case SBI_EXT_PMU_COUNTER_CFG_MATCH: +#if defined(CONFIG_32BIT) + temp = ((uint64_t)cp->a5 << 32) | cp->a4; +#else + temp = cp->a4; +#endif + ret = kvm_riscv_vcpu_pmu_ctr_cfg_match(vcpu, cp->a0, cp->a1, + cp->a2, cp->a3, temp, edata); + break; + case SBI_EXT_PMU_COUNTER_START: +#if defined(CONFIG_32BIT) + temp = ((uint64_t)cp->a4 << 32) | cp->a3; +#else + temp = cp->a3; +#endif + ret = kvm_riscv_vcpu_pmu_ctr_start(vcpu, cp->a0, cp->a1, cp->a2, + temp, edata); + break; + case SBI_EXT_PMU_COUNTER_STOP: + ret = kvm_riscv_vcpu_pmu_ctr_stop(vcpu, cp->a0, cp->a1, cp->a2, edata); + break; + case SBI_EXT_PMU_COUNTER_FW_READ: + ret = kvm_riscv_vcpu_pmu_ctr_read(vcpu, cp->a0, edata); + break; + default: + edata->err_val = SBI_ERR_NOT_SUPPORTED; + } + + + return ret; +} + +unsigned long kvm_sbi_ext_pmu_probe(struct kvm_vcpu *vcpu, unsigned long extid) +{ + struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu); + + /* + * PMU Extension is only available to guests if privilege mode filtering + * is available. Otherwise, guest will always count events while the + * execution is in hypervisor mode. + */ + return kvpmu->init_done && riscv_isa_extension_available(NULL, SSCOFPMF); +} + +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu = { + .extid_start = SBI_EXT_PMU, + .extid_end = SBI_EXT_PMU, + .handler = kvm_sbi_ext_pmu_handler, + .probe = kvm_sbi_ext_pmu_probe, +};
SBI PMU extension allows KVM guests to configure/start/stop/query about the PMU counters in virtualized enviornment as well. In order to allow that, KVM implements the entire SBI PMU extension. Signed-off-by: Atish Patra <atishp@rivosinc.com> --- arch/riscv/kvm/Makefile | 2 +- arch/riscv/kvm/vcpu_sbi.c | 11 +++++ arch/riscv/kvm/vcpu_sbi_pmu.c | 86 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/kvm/vcpu_sbi_pmu.c