diff options
author | Gleb Natapov <gleb@redhat.com> | 2009-06-11 04:06:51 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:32:57 -0400 |
commit | 33e4c68656a2e461b296ce714ec322978de85412 (patch) | |
tree | 9fbadb2c192cc22dca24dc6dfac6804dba5e70e8 /arch/x86/kvm/lapic.c | |
parent | 6edf14d8d0df144d6928799040f46fa37b5460ae (diff) |
KVM: Optimize searching for highest IRR
Most of the time IRR is empty, so instead of scanning the whole IRR on
each VM entry keep a variable that tells us if IRR is not empty. IRR
will have to be scanned twice on each IRQ delivery, but this is much
more rare than VM entry.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index b1694dc45729..3bde43c3789e 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -165,29 +165,46 @@ static int find_highest_vector(void *bitmap) | |||
165 | 165 | ||
166 | static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) | 166 | static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) |
167 | { | 167 | { |
168 | apic->irr_pending = true; | ||
168 | return apic_test_and_set_vector(vec, apic->regs + APIC_IRR); | 169 | return apic_test_and_set_vector(vec, apic->regs + APIC_IRR); |
169 | } | 170 | } |
170 | 171 | ||
171 | static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) | 172 | static inline int apic_search_irr(struct kvm_lapic *apic) |
172 | { | 173 | { |
173 | apic_clear_vector(vec, apic->regs + APIC_IRR); | 174 | return find_highest_vector(apic->regs + APIC_IRR); |
174 | } | 175 | } |
175 | 176 | ||
176 | static inline int apic_find_highest_irr(struct kvm_lapic *apic) | 177 | static inline int apic_find_highest_irr(struct kvm_lapic *apic) |
177 | { | 178 | { |
178 | int result; | 179 | int result; |
179 | 180 | ||
180 | result = find_highest_vector(apic->regs + APIC_IRR); | 181 | if (!apic->irr_pending) |
182 | return -1; | ||
183 | |||
184 | result = apic_search_irr(apic); | ||
181 | ASSERT(result == -1 || result >= 16); | 185 | ASSERT(result == -1 || result >= 16); |
182 | 186 | ||
183 | return result; | 187 | return result; |
184 | } | 188 | } |
185 | 189 | ||
190 | static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) | ||
191 | { | ||
192 | apic->irr_pending = false; | ||
193 | apic_clear_vector(vec, apic->regs + APIC_IRR); | ||
194 | if (apic_search_irr(apic) != -1) | ||
195 | apic->irr_pending = true; | ||
196 | } | ||
197 | |||
186 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) | 198 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) |
187 | { | 199 | { |
188 | struct kvm_lapic *apic = vcpu->arch.apic; | 200 | struct kvm_lapic *apic = vcpu->arch.apic; |
189 | int highest_irr; | 201 | int highest_irr; |
190 | 202 | ||
203 | /* This may race with setting of irr in __apic_accept_irq() and | ||
204 | * value returned may be wrong, but kvm_vcpu_kick() in __apic_accept_irq | ||
205 | * will cause vmexit immediately and the value will be recalculated | ||
206 | * on the next vmentry. | ||
207 | */ | ||
191 | if (!apic) | 208 | if (!apic) |
192 | return 0; | 209 | return 0; |
193 | highest_irr = apic_find_highest_irr(apic); | 210 | highest_irr = apic_find_highest_irr(apic); |
@@ -843,6 +860,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
843 | apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); | 860 | apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); |
844 | apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); | 861 | apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); |
845 | } | 862 | } |
863 | apic->irr_pending = false; | ||
846 | update_divide_count(apic); | 864 | update_divide_count(apic); |
847 | atomic_set(&apic->lapic_timer.pending, 0); | 865 | atomic_set(&apic->lapic_timer.pending, 0); |
848 | if (kvm_vcpu_is_bsp(vcpu)) | 866 | if (kvm_vcpu_is_bsp(vcpu)) |