aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-08-24 04:54:19 -0400
committerAvi Kivity <avi@redhat.com>2009-12-03 02:32:06 -0500
commit1a6e4a8c276e122dbeb6f9c610f29735e4236bfd (patch)
treea954fc1865f41cd79e5336c59904de1213e141d5
parent79c727d4371aa9af47b0cdbcad53742b5a7919ea (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>
-rw-r--r--arch/x86/include/asm/kvm_host.h1
-rw-r--r--arch/x86/kvm/irq.h1
-rw-r--r--include/linux/kvm_host.h2
-rw-r--r--virt/kvm/ioapic.h1
-rw-r--r--virt/kvm/irq_comm.c59
5 files changed, 39 insertions, 25 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 0b113f2b58cf..35d3236c9de4 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -410,7 +410,6 @@ struct kvm_arch{
410 gpa_t ept_identity_map_addr; 410 gpa_t ept_identity_map_addr;
411 411
412 unsigned long irq_sources_bitmap; 412 unsigned long irq_sources_bitmap;
413 unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
414 u64 vm_init_tsc; 413 u64 vm_init_tsc;
415}; 414};
416 415
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 7d6058a2fd38..c025a2362aae 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -71,6 +71,7 @@ struct kvm_pic {
71 int output; /* intr from master PIC */ 71 int output; /* intr from master PIC */
72 struct kvm_io_device dev; 72 struct kvm_io_device dev;
73 void (*ack_notifier)(void *opaque, int irq); 73 void (*ack_notifier)(void *opaque, int irq);
74 unsigned long irq_states[16];
74}; 75};
75 76
76struct kvm_pic *kvm_create_pic(struct kvm *kvm); 77struct kvm_pic *kvm_create_pic(struct kvm *kvm);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index b7bbb5ddd7ae..1c7f8c49e4e8 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -120,7 +120,7 @@ struct kvm_kernel_irq_routing_entry {
120 u32 gsi; 120 u32 gsi;
121 u32 type; 121 u32 type;
122 int (*set)(struct kvm_kernel_irq_routing_entry *e, 122 int (*set)(struct kvm_kernel_irq_routing_entry *e,
123 struct kvm *kvm, int level); 123 struct kvm *kvm, int irq_source_id, int level);
124 union { 124 union {
125 struct { 125 struct {
126 unsigned irqchip; 126 unsigned irqchip;
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
34static 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
34static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, 46static 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
44static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, 59static 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
50inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) 69inline 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
98static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, 117static 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,
125int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) 147int 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}