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 | ||
64 | void kvm_unregister_irq_ack_notifier(struct kvm *kvm, | |
65 | struct kvm_irq_ack_notifier *kian) | |
66 | { | |
67 | hlist_del(&kian->link); | |
68 | } | |
5550af4d SY |
69 | |
70 | /* The caller must hold kvm->lock mutex */ | |
71 | int 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 | ||
84 | void 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 | } |