diff options
Diffstat (limited to 'virt/kvm/ioapic.c')
| -rw-r--r-- | virt/kvm/ioapic.c | 25 | 
1 files changed, 19 insertions, 6 deletions
| diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index d4b601547f1f..2458a1dc2ba9 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -97,6 +97,14 @@ static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)  	bitmap_zero(ioapic->rtc_status.dest_map, KVM_MAX_VCPUS);  } +static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic); + +static void rtc_status_pending_eoi_check_valid(struct kvm_ioapic *ioapic) +{ +	if (WARN_ON(ioapic->rtc_status.pending_eoi < 0)) +		kvm_rtc_eoi_tracking_restore_all(ioapic); +} +  static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)  {  	bool new_val, old_val; @@ -120,9 +128,8 @@ static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)  	} else {  		__clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map);  		ioapic->rtc_status.pending_eoi--; +		rtc_status_pending_eoi_check_valid(ioapic);  	} - -	WARN_ON(ioapic->rtc_status.pending_eoi < 0);  }  void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) @@ -149,10 +156,10 @@ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic)  static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu)  { -	if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) +	if (test_and_clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map)) {  		--ioapic->rtc_status.pending_eoi; - -	WARN_ON(ioapic->rtc_status.pending_eoi < 0); +		rtc_status_pending_eoi_check_valid(ioapic); +	}  }  static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic) @@ -353,10 +360,16 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)  		ioapic->irr &= ~(1 << irq);  	if (irq == RTC_GSI && line_status) { +		/* +		 * pending_eoi cannot ever become negative (see +		 * rtc_status_pending_eoi_check_valid) and the caller +		 * ensures that it is only called if it is >= zero, namely +		 * if rtc_irq_check_coalesced returns false). +		 */  		BUG_ON(ioapic->rtc_status.pending_eoi != 0);  		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,  				ioapic->rtc_status.dest_map); -		ioapic->rtc_status.pending_eoi = ret; +		ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);  	} else  		ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL); |