Re: [PATCH] KVM: x86/pmu: Add Intel PMU supported fixed counters bit mask

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Mar 21, 2023 at 4:28 AM Like Xu <like.xu.linux@xxxxxxxxx> wrote:
>
> From: Like Xu <likexu@xxxxxxxxxxx>
>
> Per Intel SDM, fixed-function performance counter 'i' is supported if:
>
>         FxCtr[i]_is_supported := ECX[i] || (EDX[4:0] > i);
>
> which means that the KVM user space can use EDX to limit the number of
> fixed counters and at the same time, using ECX to enable part of other
> KVM supported fixed counters.
>
> Add a bitmap (instead of always checking the vcpu's CPUIDs) to keep track
> of the guest available fixed counters and perform the semantic checks.
>
> Signed-off-by: Like Xu <likexu@xxxxxxxxxxx>
> ---
>  arch/x86/include/asm/kvm_host.h |  2 ++
>  arch/x86/kvm/pmu.h              |  8 +++++
>  arch/x86/kvm/vmx/pmu_intel.c    | 53 +++++++++++++++++++++------------
>  3 files changed, 44 insertions(+), 19 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index a45de1118a42..14689e583127 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -565,6 +565,8 @@ struct kvm_pmu {
>          */
>         bool need_cleanup;
>
> +       DECLARE_BITMAP(supported_fixed_pmc_idx, KVM_PMC_MAX_FIXED);
> +
>         /*
>          * The total number of programmed perf_events and it helps to avoid
>          * redundant check before cleanup if guest don't use vPMU at all.
> diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
> index be62c16f2265..9f4504e5e9d5 100644
> --- a/arch/x86/kvm/pmu.h
> +++ b/arch/x86/kvm/pmu.h
> @@ -111,6 +111,11 @@ static inline struct kvm_pmc *get_gp_pmc(struct kvm_pmu *pmu, u32 msr,
>         return NULL;
>  }
>
> +static inline bool fixed_ctr_is_supported(struct kvm_pmu *pmu, unsigned int idx)
> +{
> +       return test_bit(idx, pmu->supported_fixed_pmc_idx);
> +}
> +
>  /* returns fixed PMC with the specified MSR */
>  static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
>  {
> @@ -120,6 +125,9 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
>                 u32 index = array_index_nospec(msr - base,
>                                                pmu->nr_arch_fixed_counters);
>
> +               if (!fixed_ctr_is_supported(pmu, index))
> +                       return NULL;
> +
>                 return &pmu->fixed_counters[index];
>         }
>
> diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
> index e8a3be0b9df9..12f4b2fe7756 100644
> --- a/arch/x86/kvm/vmx/pmu_intel.c
> +++ b/arch/x86/kvm/vmx/pmu_intel.c
> @@ -43,13 +43,16 @@ static int fixed_pmc_events[] = {1, 0, 7};
>  static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
>  {
>         struct kvm_pmc *pmc;
> -       u8 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl;
> +       u8 new_ctrl, old_ctrl, old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl;
>         int i;
>
>         pmu->fixed_ctr_ctrl = data;
>         for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
> -               u8 new_ctrl = fixed_ctrl_field(data, i);
> -               u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
> +               if (!fixed_ctr_is_supported(pmu, i))
> +                       continue;
> +
> +               new_ctrl = fixed_ctrl_field(data, i);
> +               old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
>
>                 if (old_ctrl == new_ctrl)
>                         continue;
> @@ -125,6 +128,9 @@ static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
>
>         idx &= ~(3u << 30);
>
> +       if (fixed && !fixed_ctr_is_supported(pmu, idx))
> +               return false;
> +
>         return fixed ? idx < pmu->nr_arch_fixed_counters
>                      : idx < pmu->nr_arch_gp_counters;
>  }
> @@ -145,7 +151,7 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
>                 counters = pmu->gp_counters;
>                 num_counters = pmu->nr_arch_gp_counters;
>         }
> -       if (idx >= num_counters)
> +       if (idx >= num_counters || (fixed && !fixed_ctr_is_supported(pmu, idx)))
>                 return NULL;
>         *mask &= pmu->counter_bitmask[fixed ? KVM_PMC_FIXED : KVM_PMC_GP];
>         return &counters[array_index_nospec(idx, num_counters)];
> @@ -500,6 +506,9 @@ static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu)
>         int i;
>
>         for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
> +               if (!fixed_ctr_is_supported(pmu, i))
> +                       continue;
> +
>                 pmc = &pmu->fixed_counters[i];
>                 event = fixed_pmc_events[array_index_nospec(i, size)];
>                 pmc->eventsel = (intel_arch_events[event].unit_mask << 8) |
> @@ -520,6 +529,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
>
>         pmu->nr_arch_gp_counters = 0;
>         pmu->nr_arch_fixed_counters = 0;
> +       bitmap_zero(pmu->supported_fixed_pmc_idx, KVM_PMC_MAX_FIXED);
>         pmu->counter_bitmask[KVM_PMC_GP] = 0;
>         pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
>         pmu->version = 0;
> @@ -551,13 +561,24 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
>         pmu->available_event_types = ~entry->ebx &
>                                         ((1ull << eax.split.mask_length) - 1);
>
> -       if (pmu->version == 1) {
> -               pmu->nr_arch_fixed_counters = 0;
> -       } else {
> +       counter_mask = ~(BIT_ULL(pmu->nr_arch_gp_counters) - 1);
> +       bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters);
> +
> +       if (pmu->version > 1) {
>                 pmu->nr_arch_fixed_counters =
> -                       min3(ARRAY_SIZE(fixed_pmc_events),
> -                            (size_t) edx.split.num_counters_fixed,
> -                            (size_t)kvm_pmu_cap.num_counters_fixed);
> +                       min_t(int, ARRAY_SIZE(fixed_pmc_events),
> +                             kvm_pmu_cap.num_counters_fixed);
> +               for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
> +                       /* FxCtr[i]_is_supported := CPUID.0xA.ECX[i] || (EDX[4:0] > i) */

This is true only when pmu->version >= 5.

>From the SDM, volume 3, section 20.2.5 Architectural Performance
Monitoring Version 5:

With Architectural Performance Monitoring Version 5, register
CPUID.0AH.ECX indicates Fixed Counter enumeration. It is a bit mask
which enumerates the supported Fixed Counters in a processor. If bit
'i' is set, it implies that Fixed Counter 'i' is supported. Software
is recommended to use the following logic to check if a Fixed Counter
is supported on a given processor: FxCtr[i]_is_supported := ECX[i] ||
(EDX[4:0] > i);

Prior to PMU version 5, all fixed counters from 0 through <number of
fixed counters - 1> are supported.

> +                       if (!(entry->ecx & BIT_ULL(i) ||
> +                             edx.split.num_counters_fixed > i))
> +                               continue;
> +
> +                       set_bit(i, pmu->supported_fixed_pmc_idx);
> +                       set_bit(INTEL_PMC_MAX_GENERIC + i, pmu->all_valid_pmc_idx);
> +                       pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4));
> +                       counter_mask &= ~BIT_ULL(INTEL_PMC_MAX_GENERIC + i);
> +               }
>                 edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed,
>                                                   kvm_pmu_cap.bit_width_fixed);
>                 pmu->counter_bitmask[KVM_PMC_FIXED] =
> @@ -565,10 +586,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
>                 setup_fixed_pmc_eventsel(pmu);
>         }
>
> -       for (i = 0; i < pmu->nr_arch_fixed_counters; i++)
> -               pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4));
> -       counter_mask = ~(((1ull << pmu->nr_arch_gp_counters) - 1) |
> -               (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED));
>         pmu->global_ctrl_mask = counter_mask;
>         pmu->global_ovf_ctrl_mask = pmu->global_ctrl_mask
>                         & ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF |
> @@ -585,11 +602,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
>                 pmu->raw_event_mask |= (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED);
>         }
>
> -       bitmap_set(pmu->all_valid_pmc_idx,
> -               0, pmu->nr_arch_gp_counters);
> -       bitmap_set(pmu->all_valid_pmc_idx,
> -               INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters);
> -
>         perf_capabilities = vcpu_get_perf_capabilities(vcpu);
>         if (cpuid_model_is_consistent(vcpu) &&
>             (perf_capabilities & PMU_CAP_LBR_FMT))
> @@ -605,6 +617,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
>                         pmu->pebs_enable_mask = counter_mask;
>                         pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE;
>                         for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
> +                               if (!fixed_ctr_is_supported(pmu, i))
> +                                       continue;
> +
>                                 pmu->fixed_ctr_ctrl_mask &=
>                                         ~(1ULL << (INTEL_PMC_IDX_FIXED + i * 4));
>                         }
>
> base-commit: d8708b80fa0e6e21bc0c9e7276ad0bccef73b6e7
> --
> 2.40.0
>




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux