@@ -192,6 +192,8 @@ struct ARMCPUClass {
OnOffAuto has_vfp;
/* CPU has Neon */
OnOffAuto has_neon;
+ /* CPU has PMU (Performance Monitor Unit) */
+ OnOffAuto has_pmu;
/* CPU has memory protection unit */
bool has_mpu;
@@ -886,9 +886,6 @@ struct ArchCPU {
/* Current power state, access guarded by BQL */
ARMPSCIState power_state;
- /* CPU has PMU (Performance Monitor Unit) */
- bool has_pmu;
-
/* PMSAv7 MPU number of supported regions */
uint32_t pmsav7_dregion;
/* v8M SAU number of supported regions */
@@ -177,14 +177,6 @@ void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp);
*/
bool kvm_arm_aarch32_supported(void);
-/**
- * kvm_arm_pmu_supported:
- *
- * Returns: true if KVM can enable the PMU
- * and false otherwise.
- */
-bool kvm_arm_pmu_supported(void);
-
/**
* kvm_arm_sve_supported:
*
@@ -229,11 +221,6 @@ static inline bool kvm_arm_aarch32_supported(void)
return false;
}
-static inline bool kvm_arm_pmu_supported(void)
-{
- return false;
-}
-
static inline bool kvm_arm_sve_supported(void)
{
return false;
@@ -605,7 +605,6 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
MachineState *ms = MACHINE(vms);
if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
- assert(!object_property_get_bool(OBJECT(armcpu), "pmu", NULL));
return;
}
@@ -1951,9 +1950,11 @@ static void virt_cpu_post_init(VirtMachineState *vms, MemoryRegion *sysmem)
int max_cpus = MACHINE(vms)->smp.max_cpus;
bool aarch64, pmu, steal_time;
CPUState *cpu;
+ ObjectClass *cpu_class;
+ cpu_class = object_get_class(OBJECT(first_cpu));
aarch64 = object_property_get_bool(OBJECT(first_cpu), "aarch64", NULL);
- pmu = object_property_get_bool(OBJECT(first_cpu), "pmu", NULL);
+ pmu = class_property_get_bool(cpu_class, "pmu", NULL);
steal_time = object_property_get_bool(OBJECT(first_cpu),
"kvm-steal-time", NULL);
@@ -2043,6 +2044,9 @@ static void machvirt_init(MachineState *machine)
if (!vms->virt) {
class_property_set_bool(cpu_class, "has_el2", false, &error_abort);
}
+ if (vmc->no_pmu) {
+ class_property_set_bool(cpu_class, "pmu", false, &error_abort);
+ }
/*
* In accelerated mode, the memory map is computed earlier in kvm_type()
@@ -2185,10 +2189,6 @@ static void machvirt_init(MachineState *machine)
object_property_set_bool(cpuobj, "kvm-steal-time", false, NULL);
}
- if (vmc->no_pmu && object_property_find(cpuobj, "pmu")) {
- object_property_set_bool(cpuobj, "pmu", false, NULL);
- }
-
if (vmc->no_tcg_lpa2 && object_property_find(cpuobj, "lpa2")) {
object_property_set_bool(cpuobj, "lpa2", false, NULL);
}
@@ -1279,29 +1279,6 @@ static void arm_cpu_initfn(Object *obj)
static Property arm_cpu_reset_cbar_property =
DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
-static bool arm_get_pmu(Object *obj, Error **errp)
-{
- ARMCPU *cpu = ARM_CPU(obj);
-
- return cpu->has_pmu;
-}
-
-static void arm_set_pmu(Object *obj, bool value, Error **errp)
-{
- ARMCPU *cpu = ARM_CPU(obj);
-
- if (value) {
- if (kvm_enabled() && !kvm_arm_pmu_supported()) {
- error_setg(errp, "'pmu' feature not supported by KVM on this host");
- return;
- }
- set_feature(&cpu->env, ARM_FEATURE_PMU);
- } else {
- unset_feature(&cpu->env, ARM_FEATURE_PMU);
- }
- cpu->has_pmu = value;
-}
-
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu)
{
ARMCPUClass *acc = ARM_CPU_GET_CLASS(cpu);
@@ -1357,11 +1334,6 @@ static void arm_cpu_post_init(Object *obj)
}
#endif
- if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
- cpu->has_pmu = true;
- object_property_add_bool(obj, "pmu", arm_get_pmu, arm_set_pmu);
- }
-
if (arm_feature(&cpu->env, ARM_FEATURE_M_SECURITY)) {
object_property_add_link(obj, "idau", TYPE_IDAU_INTERFACE, &cpu->idau,
qdev_prop_allow_set_link_before_realize,
@@ -1586,9 +1558,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
return;
}
- if (!cpu->has_pmu) {
- unset_feature(env, ARM_FEATURE_PMU);
- }
if (arm_feature(env, ARM_FEATURE_PMU)) {
pmu_init(cpu);
@@ -2163,6 +2132,13 @@ static void arm_cpu_leaf_class_init(ObjectClass *oc, void *data)
arm_class_prop_set_auto_ofs,
(void *)(uintptr_t)offsetof(ARMCPUClass, has_el3));
}
+
+ if (arm_class_feature(acc, ARM_FEATURE_PMU)) {
+ class_property_add(oc, "pmu", "bool", NULL,
+ arm_class_prop_get_auto_ofs,
+ arm_class_prop_set_auto_ofs,
+ (void *)(uintptr_t)offsetof(ARMCPUClass, has_pmu));
+ }
#endif /* !CONFIG_USER_ONLY */
/*
@@ -2279,6 +2255,25 @@ static bool arm_cpu_class_late_init(ObjectClass *oc, Error **errp)
default:
g_assert_not_reached();
}
+
+ switch (acc->has_pmu) {
+ case ON_OFF_AUTO_AUTO:
+ acc->has_pmu = (arm_class_feature(acc, ARM_FEATURE_PMU)
+ ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF);
+ break;
+ case ON_OFF_AUTO_OFF:
+ unset_class_feature(acc, ARM_FEATURE_PMU);
+ break;
+ case ON_OFF_AUTO_ON:
+ if (!arm_class_feature(acc, ARM_FEATURE_PMU)) {
+ error_setg(errp, "'pmu' feature not supported by %s on this host",
+ current_accel_name());
+ return false;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
#endif /* !CONFIG_USER_ONLY */
if (!arm_class_feature(acc, ARM_FEATURE_M)) {
@@ -239,7 +239,13 @@ void kvm_arm_add_vcpu_properties(Object *obj)
"Set off to disable KVM steal time.");
}
-bool kvm_arm_pmu_supported(void)
+/**
+ * kvm_arm_pmu_supported:
+ *
+ * Returns: true if KVM can enable the PMU
+ * and false otherwise.
+ */
+static bool kvm_arm_pmu_supported(void)
{
return kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3);
}
@@ -1463,7 +1469,7 @@ void kvm_arm_pmu_init(CPUState *cs)
.attr = KVM_ARM_VCPU_PMU_V3_INIT,
};
- if (!ARM_CPU(cs)->has_pmu) {
+ if (!arm_feature(&ARM_CPU(cs)->env, ARM_FEATURE_PMU)) {
return;
}
if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
@@ -1480,7 +1486,7 @@ void kvm_arm_pmu_set_irq(CPUState *cs, int irq)
.attr = KVM_ARM_VCPU_PMU_V3_IRQ,
};
- if (!ARM_CPU(cs)->has_pmu) {
+ if (!arm_feature(&ARM_CPU(cs)->env, ARM_FEATURE_PMU)) {
return;
}
if (!kvm_arm_set_device_attr(cs, &attr, "PMU")) {
@@ -1594,6 +1600,9 @@ bool kvm_arm_get_host_cpu_features(ARMCPUClass *acc, Error **errp)
if (kvm_arm_pmu_supported()) {
init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
pmu_supported = true;
+ } else {
+ /* This was optimistically set in aarch64_host_class_init. */
+ unset_class_feature(acc, ARM_FEATURE_PMU);
}
if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
@@ -1877,7 +1886,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
{
int ret;
ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
uint64_t psciver;
if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
@@ -1900,13 +1908,9 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
}
- if (!kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
- cpu->has_pmu = false;
- }
- if (cpu->has_pmu) {
+ if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) {
+ assert(kvm_arm_pmu_supported());
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
- } else {
- env->features &= ~(1ULL << ARM_FEATURE_PMU);
}
if (cpu_isar_feature(aa64_sve, cpu)) {
assert(kvm_arm_sve_supported());
With the movement of the property, we can remove the field from the cpu entirely, using only the class. Properly detect support in kvm_arm_get_host_cpu_features rather than adjust much later in kvm_arch_init_vcpu. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/cpu-qom.h | 2 ++ target/arm/cpu.h | 3 --- target/arm/kvm_arm.h | 13 ---------- hw/arm/virt.c | 12 +++++----- target/arm/cpu.c | 57 ++++++++++++++++++++------------------------ target/arm/kvm.c | 24 +++++++++++-------- 6 files changed, 48 insertions(+), 63 deletions(-)