提交 a2befacf 编写于 作者: C Christoffer Dall

KVM: arm64: Allow creating the PMU without the in-kernel GIC

Since we got support for devices in userspace which allows reporting the
PMU overflow output status to userspace, we should actually allow
creating the PMU on systems without an in-kernel irqchip, which in turn
requires us to slightly clarify error codes for the ABI and move things
around for the initialization phase.
Signed-off-by: NChristoffer Dall <cdall@linaro.org>
Reviewed-by: NMarc Zyngier <marc.zyngier@arm.com>
上级 1b6502e5
...@@ -16,7 +16,9 @@ Parameters: in kvm_device_attr.addr the address for PMU overflow interrupt is a ...@@ -16,7 +16,9 @@ Parameters: in kvm_device_attr.addr the address for PMU overflow interrupt is a
Returns: -EBUSY: The PMU overflow interrupt is already set Returns: -EBUSY: The PMU overflow interrupt is already set
-ENXIO: The overflow interrupt not set when attempting to get it -ENXIO: The overflow interrupt not set when attempting to get it
-ENODEV: PMUv3 not supported -ENODEV: PMUv3 not supported
-EINVAL: Invalid PMU overflow interrupt number supplied -EINVAL: Invalid PMU overflow interrupt number supplied or
trying to set the IRQ number without using an in-kernel
irqchip.
A value describing the PMUv3 (Performance Monitor Unit v3) overflow interrupt A value describing the PMUv3 (Performance Monitor Unit v3) overflow interrupt
number for this vcpu. This interrupt could be a PPI or SPI, but the interrupt number for this vcpu. This interrupt could be a PPI or SPI, but the interrupt
...@@ -25,11 +27,11 @@ all vcpus, while as an SPI it must be a separate number per vcpu. ...@@ -25,11 +27,11 @@ all vcpus, while as an SPI it must be a separate number per vcpu.
1.2 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_INIT 1.2 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_INIT
Parameters: no additional parameter in kvm_device_attr.addr Parameters: no additional parameter in kvm_device_attr.addr
Returns: -ENODEV: PMUv3 not supported Returns: -ENODEV: PMUv3 not supported or GIC not initialized
-ENXIO: PMUv3 not properly configured as required prior to calling this -ENXIO: PMUv3 not properly configured or in-kernel irqchip not
attribute configured as required prior to calling this attribute
-EBUSY: PMUv3 already initialized -EBUSY: PMUv3 already initialized
Request the initialization of the PMUv3. This must be done after creating the Request the initialization of the PMUv3. If using the PMUv3 with an in-kernel
in-kernel irqchip. Creating a PMU with a userspace irqchip is currently not virtual GIC implementation, this must be done after initializing the in-kernel
supported. irqchip.
...@@ -35,6 +35,7 @@ struct kvm_pmu { ...@@ -35,6 +35,7 @@ struct kvm_pmu {
int irq_num; int irq_num;
struct kvm_pmc pmc[ARMV8_PMU_MAX_COUNTERS]; struct kvm_pmc pmc[ARMV8_PMU_MAX_COUNTERS];
bool ready; bool ready;
bool created;
bool irq_level; bool irq_level;
}; };
...@@ -63,6 +64,7 @@ int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, ...@@ -63,6 +64,7 @@ int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr); struct kvm_device_attr *attr);
int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr); struct kvm_device_attr *attr);
int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu);
#else #else
struct kvm_pmu { struct kvm_pmu {
}; };
...@@ -112,6 +114,10 @@ static inline int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, ...@@ -112,6 +114,10 @@ static inline int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
{ {
return -ENXIO; return -ENXIO;
} }
static inline int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
{
return 0;
}
#endif #endif
#endif #endif
...@@ -527,6 +527,10 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) ...@@ -527,6 +527,10 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
} }
ret = kvm_timer_enable(vcpu); ret = kvm_timer_enable(vcpu);
if (ret)
return ret;
ret = kvm_arm_pmu_v3_enable(vcpu);
return ret; return ret;
} }
......
...@@ -449,29 +449,50 @@ bool kvm_arm_support_pmu_v3(void) ...@@ -449,29 +449,50 @@ bool kvm_arm_support_pmu_v3(void)
return (perf_num_counters() > 0); return (perf_num_counters() > 0);
} }
static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu) int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
{ {
if (!kvm_arm_support_pmu_v3()) if (!vcpu->arch.pmu.created)
return -ENODEV; return 0;
/* /*
* We currently require an in-kernel VGIC to use the PMU emulation, * A valid interrupt configuration for the PMU is either to have a
* because we do not support forwarding PMU overflow interrupts to * properly configured interrupt number and using an in-kernel
* userspace yet. * irqchip, or to neither set an IRQ nor create an in-kernel irqchip.
*/ */
if (!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm)) if (kvm_arm_pmu_irq_initialized(vcpu) != irqchip_in_kernel(vcpu->kvm))
return -EINVAL;
kvm_pmu_vcpu_reset(vcpu);
vcpu->arch.pmu.ready = true;
return 0;
}
static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
{
if (!kvm_arm_support_pmu_v3())
return -ENODEV; return -ENODEV;
if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features) || if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features))
!kvm_arm_pmu_irq_initialized(vcpu))
return -ENXIO; return -ENXIO;
if (kvm_arm_pmu_v3_ready(vcpu)) if (vcpu->arch.pmu.created)
return -EBUSY; return -EBUSY;
kvm_pmu_vcpu_reset(vcpu); if (irqchip_in_kernel(vcpu->kvm)) {
vcpu->arch.pmu.ready = true; /*
* If using the PMU with an in-kernel virtual GIC
* implementation, we require the GIC to be already
* initialized when initializing the PMU.
*/
if (!vgic_initialized(vcpu->kvm))
return -ENODEV;
if (!kvm_arm_pmu_irq_initialized(vcpu))
return -ENXIO;
}
vcpu->arch.pmu.created = true;
return 0; return 0;
} }
...@@ -510,6 +531,9 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) ...@@ -510,6 +531,9 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
int __user *uaddr = (int __user *)(long)attr->addr; int __user *uaddr = (int __user *)(long)attr->addr;
int irq; int irq;
if (!irqchip_in_kernel(vcpu->kvm))
return -EINVAL;
if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features)) if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features))
return -ENODEV; return -ENODEV;
...@@ -544,6 +568,9 @@ int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) ...@@ -544,6 +568,9 @@ int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
int __user *uaddr = (int __user *)(long)attr->addr; int __user *uaddr = (int __user *)(long)attr->addr;
int irq; int irq;
if (!irqchip_in_kernel(vcpu->kvm))
return -EINVAL;
if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features)) if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features))
return -ENODEV; return -ENODEV;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册