aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/irq_comm.c
diff options
context:
space:
mode:
authorSheng Yang <sheng@linux.intel.com>2008-10-15 08:15:06 -0400
committerAvi Kivity <avi@redhat.com>2008-10-28 08:21:34 -0400
commit5550af4df179e52753d3a43a788a113ad8cd95cd (patch)
treef19274a4f7e345e70e7da713f44c1dcccdb134e8 /virt/kvm/irq_comm.c
parent6ad9f15c94822c3f067a7d443f3b414e08b34460 (diff)
KVM: Fix guest shared interrupt with in-kernel irqchip
Every call of kvm_set_irq() should offer an irq_source_id, which is allocated by kvm_request_irq_source_id(). Based on irq_source_id, we identify the irq source and implement logical OR for shared level interrupts. The allocated irq_source_id can be freed by kvm_free_irq_source_id(). Currently, we support at most sizeof(unsigned long) different irq sources. [Amit: - rebase to kvm.git HEAD - move definition of KVM_USERSPACE_IRQ_SOURCE_ID to common file - move kvm_request_irq_source_id to the update_irq ioctl] [Xiantao: - Add kvm/ia64 stuff and make it work for kvm/ia64 guests] Signed-off-by: Sheng Yang <sheng@linux.intel.com> Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Xiantao Zhang <xiantao.zhang@intel.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'virt/kvm/irq_comm.c')
-rw-r--r--virt/kvm/irq_comm.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index d0169f5e6047..55ad76ee2d09 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -25,15 +25,23 @@
25#include "ioapic.h" 25#include "ioapic.h"
26 26
27/* This should be called with the kvm->lock mutex held */ 27/* This should be called with the kvm->lock mutex held */
28void kvm_set_irq(struct kvm *kvm, int irq, int level) 28void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
29{ 29{
30 unsigned long *irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
31
32 /* Logical OR for level trig interrupt */
33 if (level)
34 set_bit(irq_source_id, irq_state);
35 else
36 clear_bit(irq_source_id, irq_state);
37
30 /* Not possible to detect if the guest uses the PIC or the 38 /* Not possible to detect if the guest uses the PIC or the
31 * IOAPIC. So set the bit in both. The guest will ignore 39 * IOAPIC. So set the bit in both. The guest will ignore
32 * writes to the unused one. 40 * writes to the unused one.
33 */ 41 */
34 kvm_ioapic_set_irq(kvm->arch.vioapic, irq, level); 42 kvm_ioapic_set_irq(kvm->arch.vioapic, irq, !!(*irq_state));
35#ifdef CONFIG_X86 43#ifdef CONFIG_X86
36 kvm_pic_set_irq(pic_irqchip(kvm), irq, level); 44 kvm_pic_set_irq(pic_irqchip(kvm), irq, !!(*irq_state));
37#endif 45#endif
38} 46}
39 47
@@ -58,3 +66,31 @@ void kvm_unregister_irq_ack_notifier(struct kvm *kvm,
58{ 66{
59 hlist_del(&kian->link); 67 hlist_del(&kian->link);
60} 68}
69
70/* The caller must hold kvm->lock mutex */
71int kvm_request_irq_source_id(struct kvm *kvm)
72{
73 unsigned long *bitmap = &kvm->arch.irq_sources_bitmap;
74 int irq_source_id = find_first_zero_bit(bitmap,
75 sizeof(kvm->arch.irq_sources_bitmap));
76 if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) {
77 printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n");
78 irq_source_id = -EFAULT;
79 } else
80 set_bit(irq_source_id, bitmap);
81 return irq_source_id;
82}
83
84void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
85{
86 int i;
87
88 if (irq_source_id <= 0 ||
89 irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) {
90 printk(KERN_ERR "kvm: IRQ source ID out of range!\n");
91 return;
92 }
93 for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
94 clear_bit(irq_source_id, &kvm->arch.irq_states[i]);
95 clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
96}