diff options
Diffstat (limited to 'virt/kvm')
-rw-r--r-- | virt/kvm/ioapic.c | 58 | ||||
-rw-r--r-- | virt/kvm/ioapic.h | 1 |
2 files changed, 59 insertions, 0 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 27ae8dd64e29..9d76baa78e89 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -90,6 +90,62 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, | |||
90 | return result; | 90 | return result; |
91 | } | 91 | } |
92 | 92 | ||
93 | static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic) | ||
94 | { | ||
95 | ioapic->rtc_status.pending_eoi = 0; | ||
96 | bitmap_zero(ioapic->rtc_status.dest_map, KVM_MAX_VCPUS); | ||
97 | } | ||
98 | |||
99 | static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) | ||
100 | { | ||
101 | bool new_val, old_val; | ||
102 | struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; | ||
103 | union kvm_ioapic_redirect_entry *e; | ||
104 | |||
105 | e = &ioapic->redirtbl[RTC_GSI]; | ||
106 | if (!kvm_apic_match_dest(vcpu, NULL, 0, e->fields.dest_id, | ||
107 | e->fields.dest_mode)) | ||
108 | return; | ||
109 | |||
110 | new_val = kvm_apic_pending_eoi(vcpu, e->fields.vector); | ||
111 | old_val = test_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map); | ||
112 | |||
113 | if (new_val == old_val) | ||
114 | return; | ||
115 | |||
116 | if (new_val) { | ||
117 | __set_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map); | ||
118 | ioapic->rtc_status.pending_eoi++; | ||
119 | } else { | ||
120 | __clear_bit(vcpu->vcpu_id, ioapic->rtc_status.dest_map); | ||
121 | ioapic->rtc_status.pending_eoi--; | ||
122 | } | ||
123 | |||
124 | WARN_ON(ioapic->rtc_status.pending_eoi < 0); | ||
125 | } | ||
126 | |||
127 | void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu) | ||
128 | { | ||
129 | struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic; | ||
130 | |||
131 | spin_lock(&ioapic->lock); | ||
132 | __rtc_irq_eoi_tracking_restore_one(vcpu); | ||
133 | spin_unlock(&ioapic->lock); | ||
134 | } | ||
135 | |||
136 | static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic) | ||
137 | { | ||
138 | struct kvm_vcpu *vcpu; | ||
139 | int i; | ||
140 | |||
141 | if (RTC_GSI >= IOAPIC_NUM_PINS) | ||
142 | return; | ||
143 | |||
144 | rtc_irq_eoi_tracking_reset(ioapic); | ||
145 | kvm_for_each_vcpu(i, vcpu, ioapic->kvm) | ||
146 | __rtc_irq_eoi_tracking_restore_one(vcpu); | ||
147 | } | ||
148 | |||
93 | static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) | 149 | static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) |
94 | { | 150 | { |
95 | union kvm_ioapic_redirect_entry *pent; | 151 | union kvm_ioapic_redirect_entry *pent; |
@@ -428,6 +484,7 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic) | |||
428 | ioapic->ioregsel = 0; | 484 | ioapic->ioregsel = 0; |
429 | ioapic->irr = 0; | 485 | ioapic->irr = 0; |
430 | ioapic->id = 0; | 486 | ioapic->id = 0; |
487 | rtc_irq_eoi_tracking_reset(ioapic); | ||
431 | update_handled_vectors(ioapic); | 488 | update_handled_vectors(ioapic); |
432 | } | 489 | } |
433 | 490 | ||
@@ -494,6 +551,7 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state) | |||
494 | memcpy(ioapic, state, sizeof(struct kvm_ioapic_state)); | 551 | memcpy(ioapic, state, sizeof(struct kvm_ioapic_state)); |
495 | update_handled_vectors(ioapic); | 552 | update_handled_vectors(ioapic); |
496 | kvm_ioapic_make_eoibitmap_request(kvm); | 553 | kvm_ioapic_make_eoibitmap_request(kvm); |
554 | kvm_rtc_eoi_tracking_restore_all(ioapic); | ||
497 | spin_unlock(&ioapic->lock); | 555 | spin_unlock(&ioapic->lock); |
498 | return 0; | 556 | return 0; |
499 | } | 557 | } |
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h index 761e5b57099e..313fc4ea61d9 100644 --- a/virt/kvm/ioapic.h +++ b/virt/kvm/ioapic.h | |||
@@ -79,6 +79,7 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) | |||
79 | return kvm->arch.vioapic; | 79 | return kvm->arch.vioapic; |
80 | } | 80 | } |
81 | 81 | ||
82 | void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu); | ||
82 | int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | 83 | int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, |
83 | int short_hand, int dest, int dest_mode); | 84 | int short_hand, int dest, int dest_mode); |
84 | int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); | 85 | int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); |