diff options
| author | Marcelo Tosatti <mtosatti@redhat.com> | 2008-07-26 16:01:00 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@qumranet.com> | 2008-10-15 04:15:16 -0400 |
| commit | f52447261bc8c21dfd4635196e32d2da1352f589 (patch) | |
| tree | a0de6cefa7fbfdd07285bd60c4f61e4e2f2d4ed6 | |
| parent | 564f15378f04921d5749f27ec53d5e68a6d1d446 (diff) | |
KVM: irq ack notification
Based on a patch from: Ben-Ami Yassour <benami@il.ibm.com>
which was based on a patch from: Amit Shah <amit.shah@qumranet.com>
Notify IRQ acking on PIC/APIC emulation. The previous patch missed two things:
- Edge triggered interrupts on IOAPIC
- PIC reset with IRR/ISR set should be equivalent to ack (LAPIC probably
needs something similar).
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
CC: Amit Shah <amit.shah@qumranet.com>
CC: Ben-Ami Yassour <benami@il.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
| -rw-r--r-- | arch/x86/kvm/i8259.c | 12 | ||||
| -rw-r--r-- | arch/x86/kvm/irq.c | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/irq.h | 3 | ||||
| -rw-r--r-- | arch/x86/kvm/lapic.c | 7 | ||||
| -rw-r--r-- | virt/kvm/ioapic.c | 20 | ||||
| -rw-r--r-- | virt/kvm/ioapic.h | 3 |
6 files changed, 34 insertions, 13 deletions
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 55e179ad98ef..de704995b819 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c | |||
| @@ -159,9 +159,10 @@ static inline void pic_intack(struct kvm_kpic_state *s, int irq) | |||
| 159 | s->irr &= ~(1 << irq); | 159 | s->irr &= ~(1 << irq); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | int kvm_pic_read_irq(struct kvm_pic *s) | 162 | int kvm_pic_read_irq(struct kvm *kvm) |
| 163 | { | 163 | { |
| 164 | int irq, irq2, intno; | 164 | int irq, irq2, intno; |
| 165 | struct kvm_pic *s = pic_irqchip(kvm); | ||
| 165 | 166 | ||
| 166 | irq = pic_get_irq(&s->pics[0]); | 167 | irq = pic_get_irq(&s->pics[0]); |
| 167 | if (irq >= 0) { | 168 | if (irq >= 0) { |
| @@ -187,12 +188,21 @@ int kvm_pic_read_irq(struct kvm_pic *s) | |||
| 187 | intno = s->pics[0].irq_base + irq; | 188 | intno = s->pics[0].irq_base + irq; |
| 188 | } | 189 | } |
| 189 | pic_update_irq(s); | 190 | pic_update_irq(s); |
| 191 | kvm_notify_acked_irq(kvm, irq); | ||
| 190 | 192 | ||
| 191 | return intno; | 193 | return intno; |
| 192 | } | 194 | } |
| 193 | 195 | ||
| 194 | void kvm_pic_reset(struct kvm_kpic_state *s) | 196 | void kvm_pic_reset(struct kvm_kpic_state *s) |
| 195 | { | 197 | { |
| 198 | int irq; | ||
| 199 | struct kvm *kvm = s->pics_state->irq_request_opaque; | ||
| 200 | |||
| 201 | for (irq = 0; irq < PIC_NUM_PINS; irq++) { | ||
| 202 | if (!(s->imr & (1 << irq)) && (s->irr & (1 << irq) || | ||
| 203 | s->isr & (1 << irq))) | ||
| 204 | kvm_notify_acked_irq(kvm, irq); | ||
| 205 | } | ||
| 196 | s->last_irr = 0; | 206 | s->last_irr = 0; |
| 197 | s->irr = 0; | 207 | s->irr = 0; |
| 198 | s->imr = 0; | 208 | s->imr = 0; |
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index 90911958d853..3c508afaa285 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c | |||
| @@ -72,7 +72,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v) | |||
| 72 | if (kvm_apic_accept_pic_intr(v)) { | 72 | if (kvm_apic_accept_pic_intr(v)) { |
| 73 | s = pic_irqchip(v->kvm); | 73 | s = pic_irqchip(v->kvm); |
| 74 | s->output = 0; /* PIC */ | 74 | s->output = 0; /* PIC */ |
| 75 | vector = kvm_pic_read_irq(s); | 75 | vector = kvm_pic_read_irq(v->kvm); |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | return vector; | 78 | return vector; |
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 95fe718e3abc..479a3d2d5614 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h | |||
| @@ -63,11 +63,12 @@ struct kvm_pic { | |||
| 63 | void *irq_request_opaque; | 63 | void *irq_request_opaque; |
| 64 | int output; /* intr from master PIC */ | 64 | int output; /* intr from master PIC */ |
| 65 | struct kvm_io_device dev; | 65 | struct kvm_io_device dev; |
| 66 | void (*ack_notifier)(void *opaque, int irq); | ||
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | struct kvm_pic *kvm_create_pic(struct kvm *kvm); | 69 | struct kvm_pic *kvm_create_pic(struct kvm *kvm); |
| 69 | void kvm_pic_set_irq(void *opaque, int irq, int level); | 70 | void kvm_pic_set_irq(void *opaque, int irq, int level); |
| 70 | int kvm_pic_read_irq(struct kvm_pic *s); | 71 | int kvm_pic_read_irq(struct kvm *kvm); |
| 71 | void kvm_pic_update_irq(struct kvm_pic *s); | 72 | void kvm_pic_update_irq(struct kvm_pic *s); |
| 72 | 73 | ||
| 73 | static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) | 74 | static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 9fde0ac24268..be94f93a73f6 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
| @@ -439,7 +439,7 @@ struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, | |||
| 439 | static void apic_set_eoi(struct kvm_lapic *apic) | 439 | static void apic_set_eoi(struct kvm_lapic *apic) |
| 440 | { | 440 | { |
| 441 | int vector = apic_find_highest_isr(apic); | 441 | int vector = apic_find_highest_isr(apic); |
| 442 | 442 | int trigger_mode; | |
| 443 | /* | 443 | /* |
| 444 | * Not every write EOI will has corresponding ISR, | 444 | * Not every write EOI will has corresponding ISR, |
| 445 | * one example is when Kernel check timer on setup_IO_APIC | 445 | * one example is when Kernel check timer on setup_IO_APIC |
| @@ -451,7 +451,10 @@ static void apic_set_eoi(struct kvm_lapic *apic) | |||
| 451 | apic_update_ppr(apic); | 451 | apic_update_ppr(apic); |
| 452 | 452 | ||
| 453 | if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR)) | 453 | if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR)) |
| 454 | kvm_ioapic_update_eoi(apic->vcpu->kvm, vector); | 454 | trigger_mode = IOAPIC_LEVEL_TRIG; |
| 455 | else | ||
| 456 | trigger_mode = IOAPIC_EDGE_TRIG; | ||
| 457 | kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode); | ||
| 455 | } | 458 | } |
| 456 | 459 | ||
| 457 | static void apic_send_ipi(struct kvm_lapic *apic) | 460 | static void apic_send_ipi(struct kvm_lapic *apic) |
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index c0d22870ee9c..515cd7ce761c 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | 39 | ||
| 40 | #include "ioapic.h" | 40 | #include "ioapic.h" |
| 41 | #include "lapic.h" | 41 | #include "lapic.h" |
| 42 | #include "irq.h" | ||
| 42 | 43 | ||
| 43 | #if 0 | 44 | #if 0 |
| 44 | #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) | 45 | #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) |
| @@ -285,26 +286,31 @@ void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) | |||
| 285 | } | 286 | } |
| 286 | } | 287 | } |
| 287 | 288 | ||
| 288 | static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi) | 289 | static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi, |
| 290 | int trigger_mode) | ||
| 289 | { | 291 | { |
| 290 | union ioapic_redir_entry *ent; | 292 | union ioapic_redir_entry *ent; |
| 291 | 293 | ||
| 292 | ent = &ioapic->redirtbl[gsi]; | 294 | ent = &ioapic->redirtbl[gsi]; |
| 293 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); | ||
| 294 | 295 | ||
| 295 | ent->fields.remote_irr = 0; | 296 | kvm_notify_acked_irq(ioapic->kvm, gsi); |
| 296 | if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) | 297 | |
| 297 | ioapic_service(ioapic, gsi); | 298 | if (trigger_mode == IOAPIC_LEVEL_TRIG) { |
| 299 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); | ||
| 300 | ent->fields.remote_irr = 0; | ||
| 301 | if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) | ||
| 302 | ioapic_service(ioapic, gsi); | ||
| 303 | } | ||
| 298 | } | 304 | } |
| 299 | 305 | ||
| 300 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) | 306 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode) |
| 301 | { | 307 | { |
| 302 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; | 308 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; |
| 303 | int i; | 309 | int i; |
| 304 | 310 | ||
| 305 | for (i = 0; i < IOAPIC_NUM_PINS; i++) | 311 | for (i = 0; i < IOAPIC_NUM_PINS; i++) |
| 306 | if (ioapic->redirtbl[i].fields.vector == vector) | 312 | if (ioapic->redirtbl[i].fields.vector == vector) |
| 307 | __kvm_ioapic_update_eoi(ioapic, i); | 313 | __kvm_ioapic_update_eoi(ioapic, i, trigger_mode); |
| 308 | } | 314 | } |
| 309 | 315 | ||
| 310 | static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr, | 316 | static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr, |
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h index 7f16675fe783..b52732f493c1 100644 --- a/virt/kvm/ioapic.h +++ b/virt/kvm/ioapic.h | |||
| @@ -58,6 +58,7 @@ struct kvm_ioapic { | |||
| 58 | } redirtbl[IOAPIC_NUM_PINS]; | 58 | } redirtbl[IOAPIC_NUM_PINS]; |
| 59 | struct kvm_io_device dev; | 59 | struct kvm_io_device dev; |
| 60 | struct kvm *kvm; | 60 | struct kvm *kvm; |
| 61 | void (*ack_notifier)(void *opaque, int irq); | ||
| 61 | }; | 62 | }; |
| 62 | 63 | ||
| 63 | #ifdef DEBUG | 64 | #ifdef DEBUG |
| @@ -87,7 +88,7 @@ static inline int irqchip_in_kernel(struct kvm *kvm) | |||
| 87 | 88 | ||
| 88 | struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, | 89 | struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, |
| 89 | unsigned long bitmap); | 90 | unsigned long bitmap); |
| 90 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector); | 91 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode); |
| 91 | int kvm_ioapic_init(struct kvm *kvm); | 92 | int kvm_ioapic_init(struct kvm *kvm); |
| 92 | void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); | 93 | void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); |
| 93 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic); | 94 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic); |
