Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm/arm64: Report PMU overflow interrupts to userspace irqchip

When not using an in-kernel VGIC, but instead emulating an interrupt
controller in userspace, we should report the PMU overflow status to
that userspace interrupt controller using the KVM_CAP_ARM_USER_IRQ
feature.

Reviewed-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

authored by

Christoffer Dall and committed by
Christoffer Dall
3dbbdf78 d9e13977

+51 -11
+9 -4
arch/arm/kvm/arm.c
··· 635 635 636 636 /* 637 637 * If we have a singal pending, or need to notify a userspace 638 - * irqchip about timer level changes, then we exit (and update 639 - * the timer level state in kvm_timer_update_run below). 638 + * irqchip about timer or PMU level changes, then we exit (and 639 + * update the timer level state in kvm_timer_update_run 640 + * below). 640 641 */ 641 642 if (signal_pending(current) || 642 - kvm_timer_should_notify_user(vcpu)) { 643 + kvm_timer_should_notify_user(vcpu) || 644 + kvm_pmu_should_notify_user(vcpu)) { 643 645 ret = -EINTR; 644 646 run->exit_reason = KVM_EXIT_INTR; 645 647 } ··· 714 712 } 715 713 716 714 /* Tell userspace about in-kernel device output levels */ 717 - kvm_timer_update_run(vcpu); 715 + if (unlikely(!irqchip_in_kernel(vcpu->kvm))) { 716 + kvm_timer_update_run(vcpu); 717 + kvm_pmu_update_run(vcpu); 718 + } 718 719 719 720 if (vcpu->sigset_active) 720 721 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+7
include/kvm/arm_pmu.h
··· 50 50 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val); 51 51 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu); 52 52 void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu); 53 + bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu); 54 + void kvm_pmu_update_run(struct kvm_vcpu *vcpu); 53 55 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val); 54 56 void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val); 55 57 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data, ··· 87 85 static inline void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {} 88 86 static inline void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {} 89 87 static inline void kvm_pmu_sync_hwstate(struct kvm_vcpu *vcpu) {} 88 + static inline bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu) 89 + { 90 + return false; 91 + } 92 + static inline void kvm_pmu_update_run(struct kvm_vcpu *vcpu) {} 90 93 static inline void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {} 91 94 static inline void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {} 92 95 static inline void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu,
-3
virt/kvm/arm/arch_timer.c
··· 193 193 struct arch_timer_context *ptimer = vcpu_ptimer(vcpu); 194 194 struct kvm_sync_regs *regs = &vcpu->run->s.regs; 195 195 196 - if (likely(irqchip_in_kernel(vcpu->kvm))) 197 - return; 198 - 199 196 /* Populate the device bitmap with the timer states */ 200 197 regs->device_irq_level &= ~(KVM_ARM_DEV_EL1_VTIMER | 201 198 KVM_ARM_DEV_EL1_PTIMER);
+35 -4
virt/kvm/arm/pmu.c
··· 230 230 return; 231 231 232 232 overflow = !!kvm_pmu_overflow_status(vcpu); 233 - if (pmu->irq_level != overflow) { 234 - pmu->irq_level = overflow; 235 - kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, 236 - pmu->irq_num, overflow); 233 + if (pmu->irq_level == overflow) 234 + return; 235 + 236 + pmu->irq_level = overflow; 237 + 238 + if (likely(irqchip_in_kernel(vcpu->kvm))) { 239 + int ret; 240 + ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, 241 + pmu->irq_num, overflow); 242 + WARN_ON(ret); 237 243 } 244 + } 245 + 246 + bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu) 247 + { 248 + struct kvm_pmu *pmu = &vcpu->arch.pmu; 249 + struct kvm_sync_regs *sregs = &vcpu->run->s.regs; 250 + bool run_level = sregs->device_irq_level & KVM_ARM_DEV_PMU; 251 + 252 + if (likely(irqchip_in_kernel(vcpu->kvm))) 253 + return false; 254 + 255 + return pmu->irq_level != run_level; 256 + } 257 + 258 + /* 259 + * Reflect the PMU overflow interrupt output level into the kvm_run structure 260 + */ 261 + void kvm_pmu_update_run(struct kvm_vcpu *vcpu) 262 + { 263 + struct kvm_sync_regs *regs = &vcpu->run->s.regs; 264 + 265 + /* Populate the timer bitmap for user space */ 266 + regs->device_irq_level &= ~KVM_ARM_DEV_PMU; 267 + if (vcpu->arch.pmu.irq_level) 268 + regs->device_irq_level |= KVM_ARM_DEV_PMU; 238 269 } 239 270 240 271 /**