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 | } |