diff options
| author | Gleb Natapov <gleb@redhat.com> | 2009-08-24 04:54:19 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2009-12-03 02:32:06 -0500 |
| commit | 1a6e4a8c276e122dbeb6f9c610f29735e4236bfd (patch) | |
| tree | a954fc1865f41cd79e5336c59904de1213e141d5 /virt | |
| parent | 79c727d4371aa9af47b0cdbcad53742b5a7919ea (diff) | |
KVM: Move irq sharing information to irqchip level
This removes assumptions that max GSIs is smaller than number of pins.
Sharing is tracked on pin level not GSI level.
[avi: no PIC on ia64]
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'virt')
| -rw-r--r-- | virt/kvm/ioapic.h | 1 | ||||
| -rw-r--r-- | virt/kvm/irq_comm.c | 59 |
2 files changed, 37 insertions, 23 deletions
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h index 7080b713c160..6e461ade6365 100644 --- a/virt/kvm/ioapic.h +++ b/virt/kvm/ioapic.h | |||
| @@ -41,6 +41,7 @@ struct kvm_ioapic { | |||
| 41 | u32 irr; | 41 | u32 irr; |
| 42 | u32 pad; | 42 | u32 pad; |
| 43 | union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS]; | 43 | union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS]; |
| 44 | unsigned long irq_states[IOAPIC_NUM_PINS]; | ||
| 44 | struct kvm_io_device dev; | 45 | struct kvm_io_device dev; |
| 45 | struct kvm *kvm; | 46 | struct kvm *kvm; |
| 46 | void (*ack_notifier)(void *opaque, int irq); | 47 | void (*ack_notifier)(void *opaque, int irq); |
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 001663ff401a..9783f5c43dae 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c | |||
| @@ -31,20 +31,39 @@ | |||
| 31 | 31 | ||
| 32 | #include "ioapic.h" | 32 | #include "ioapic.h" |
| 33 | 33 | ||
| 34 | static inline int kvm_irq_line_state(unsigned long *irq_state, | ||
| 35 | int irq_source_id, int level) | ||
| 36 | { | ||
| 37 | /* Logical OR for level trig interrupt */ | ||
| 38 | if (level) | ||
| 39 | set_bit(irq_source_id, irq_state); | ||
| 40 | else | ||
| 41 | clear_bit(irq_source_id, irq_state); | ||
| 42 | |||
| 43 | return !!(*irq_state); | ||
| 44 | } | ||
| 45 | |||
| 34 | static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, | 46 | static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, |
| 35 | struct kvm *kvm, int level) | 47 | struct kvm *kvm, int irq_source_id, int level) |
| 36 | { | 48 | { |
| 37 | #ifdef CONFIG_X86 | 49 | #ifdef CONFIG_X86 |
| 38 | return kvm_pic_set_irq(pic_irqchip(kvm), e->irqchip.pin, level); | 50 | struct kvm_pic *pic = pic_irqchip(kvm); |
| 51 | level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin], | ||
| 52 | irq_source_id, level); | ||
| 53 | return kvm_pic_set_irq(pic, e->irqchip.pin, level); | ||
| 39 | #else | 54 | #else |
| 40 | return -1; | 55 | return -1; |
| 41 | #endif | 56 | #endif |
| 42 | } | 57 | } |
| 43 | 58 | ||
| 44 | static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, | 59 | static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, |
| 45 | struct kvm *kvm, int level) | 60 | struct kvm *kvm, int irq_source_id, int level) |
| 46 | { | 61 | { |
| 47 | return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); | 62 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; |
| 63 | level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin], | ||
| 64 | irq_source_id, level); | ||
| 65 | |||
| 66 | return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level); | ||
| 48 | } | 67 | } |
| 49 | 68 | ||
| 50 | inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) | 69 | inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) |
| @@ -96,10 +115,13 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, | |||
| 96 | } | 115 | } |
| 97 | 116 | ||
| 98 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | 117 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, |
| 99 | struct kvm *kvm, int level) | 118 | struct kvm *kvm, int irq_source_id, int level) |
| 100 | { | 119 | { |
| 101 | struct kvm_lapic_irq irq; | 120 | struct kvm_lapic_irq irq; |
| 102 | 121 | ||
| 122 | if (!level) | ||
| 123 | return -1; | ||
| 124 | |||
| 103 | trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data); | 125 | trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data); |
| 104 | 126 | ||
| 105 | irq.dest_id = (e->msi.address_lo & | 127 | irq.dest_id = (e->msi.address_lo & |
| @@ -125,34 +147,19 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | |||
| 125 | int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) | 147 | int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) |
| 126 | { | 148 | { |
| 127 | struct kvm_kernel_irq_routing_entry *e; | 149 | struct kvm_kernel_irq_routing_entry *e; |
| 128 | unsigned long *irq_state, sig_level; | ||
| 129 | int ret = -1; | 150 | int ret = -1; |
| 130 | 151 | ||
| 131 | trace_kvm_set_irq(irq, level, irq_source_id); | 152 | trace_kvm_set_irq(irq, level, irq_source_id); |
| 132 | 153 | ||
| 133 | WARN_ON(!mutex_is_locked(&kvm->irq_lock)); | 154 | WARN_ON(!mutex_is_locked(&kvm->irq_lock)); |
| 134 | 155 | ||
| 135 | if (irq < KVM_IOAPIC_NUM_PINS) { | ||
| 136 | irq_state = (unsigned long *)&kvm->arch.irq_states[irq]; | ||
| 137 | |||
| 138 | /* Logical OR for level trig interrupt */ | ||
| 139 | if (level) | ||
| 140 | set_bit(irq_source_id, irq_state); | ||
| 141 | else | ||
| 142 | clear_bit(irq_source_id, irq_state); | ||
| 143 | sig_level = !!(*irq_state); | ||
| 144 | } else if (!level) | ||
| 145 | return ret; | ||
| 146 | else /* Deal with MSI/MSI-X */ | ||
| 147 | sig_level = 1; | ||
| 148 | |||
| 149 | /* Not possible to detect if the guest uses the PIC or the | 156 | /* Not possible to detect if the guest uses the PIC or the |
| 150 | * IOAPIC. So set the bit in both. The guest will ignore | 157 | * IOAPIC. So set the bit in both. The guest will ignore |
| 151 | * writes to the unused one. | 158 | * writes to the unused one. |
| 152 | */ | 159 | */ |
| 153 | list_for_each_entry(e, &kvm->irq_routing, link) | 160 | list_for_each_entry(e, &kvm->irq_routing, link) |
| 154 | if (e->gsi == irq) { | 161 | if (e->gsi == irq) { |
| 155 | int r = e->set(e, kvm, sig_level); | 162 | int r = e->set(e, kvm, irq_source_id, level); |
| 156 | if (r < 0) | 163 | if (r < 0) |
| 157 | continue; | 164 | continue; |
| 158 | 165 | ||
| @@ -232,8 +239,14 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) | |||
| 232 | printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); | 239 | printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); |
| 233 | return; | 240 | return; |
| 234 | } | 241 | } |
| 235 | for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) | 242 | for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) { |
| 236 | clear_bit(irq_source_id, &kvm->arch.irq_states[i]); | 243 | clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]); |
| 244 | if (i >= 16) | ||
| 245 | continue; | ||
| 246 | #ifdef CONFIG_X86 | ||
| 247 | clear_bit(irq_source_id, &pic_irqchip(kvm)->irq_states[i]); | ||
| 248 | #endif | ||
| 249 | } | ||
| 237 | clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); | 250 | clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); |
| 238 | mutex_unlock(&kvm->irq_lock); | 251 | mutex_unlock(&kvm->irq_lock); |
| 239 | } | 252 | } |
