Commit | Line | Data |
---|---|---|
3de42dc0 XZ |
1 | /* |
2 | * irq_comm.c: Common API for in kernel interrupt controller | |
3 | * Copyright (c) 2007, Intel Corporation. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along with | |
15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | |
17 | * Authors: | |
18 | * Yaozu (Eddie) Dong <Eddie.dong@intel.com> | |
19 | * | |
20 | */ | |
21 | ||
22 | #include <linux/kvm_host.h> | |
23 | #include "irq.h" | |
24 | ||
25 | #include "ioapic.h" | |
26 | ||
27 | /* This should be called with the kvm->lock mutex held */ | |
5550af4d | 28 | void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) |
3de42dc0 | 29 | { |
5550af4d SY |
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 | ||
3de42dc0 XZ |
38 | /* Not possible to detect if the guest uses the PIC or the |
39 | * IOAPIC. So set the bit in both. The guest will ignore | |
40 | * writes to the unused one. | |
41 | */ | |
5550af4d | 42 | kvm_ioapic_set_irq(kvm->arch.vioapic, irq, !!(*irq_state)); |
3de42dc0 | 43 | #ifdef CONFIG_X86 |
5550af4d | 44 | kvm_pic_set_irq(pic_irqchip(kvm), irq, !!(*irq_state)); |
3de42dc0 XZ |
45 | #endif |
46 | } | |
47 | ||
48 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned gsi) | |
49 | { | |
50 | struct kvm_irq_ack_notifier *kian; | |
51 | struct hlist_node *n; | |
52 | ||
53 | hlist_for_each_entry(kian, n, &kvm->arch.irq_ack_notifier_list, link) | |
54 | if (kian->gsi == gsi) | |
55 | kian->irq_acked(kian); | |
56 | } | |
57 | ||
58 | void kvm_register_irq_ack_notifier(struct kvm *kvm, | |
59 | struct kvm_irq_ack_notifier *kian) | |
60 | { | |
61 | hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list); | |
62 | } | |
63 | ||
e19e30ef | 64 | void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian) |
3de42dc0 | 65 | { |
fdd897e6 | 66 | hlist_del_init(&kian->link); |
3de42dc0 | 67 | } |
5550af4d SY |
68 | |
69 | /* The caller must hold kvm->lock mutex */ | |
70 | int kvm_request_irq_source_id(struct kvm *kvm) | |
71 | { | |
72 | unsigned long *bitmap = &kvm->arch.irq_sources_bitmap; | |
73 | int irq_source_id = find_first_zero_bit(bitmap, | |
74 | sizeof(kvm->arch.irq_sources_bitmap)); | |
61552367 | 75 | |
5550af4d SY |
76 | if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { |
77 | printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n"); | |
61552367 MM |
78 | return -EFAULT; |
79 | } | |
80 | ||
81 | ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); | |
82 | set_bit(irq_source_id, bitmap); | |
83 | ||
5550af4d SY |
84 | return irq_source_id; |
85 | } | |
86 | ||
87 | void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) | |
88 | { | |
89 | int i; | |
90 | ||
61552367 MM |
91 | ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); |
92 | ||
93 | if (irq_source_id < 0 || | |
5550af4d SY |
94 | irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { |
95 | printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); | |
96 | return; | |
97 | } | |
98 | for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) | |
99 | clear_bit(irq_source_id, &kvm->arch.irq_states[i]); | |
100 | clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); | |
101 | } |