1 /* 2 * irq.c: API for in kernel interrupt controller 3 * Copyright (c) 2007, Intel Corporation. 4 * Copyright 2009 Red Hat, Inc. and/or its affiliates. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along with 16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 17 * Place - Suite 330, Boston, MA 02111-1307 USA. 18 * Authors: 19 * Yaozu (Eddie) Dong <Eddie.dong@intel.com> 20 * 21 */ 22 23 #include <linux/module.h> 24 #include <linux/kvm_host.h> 25 26 #include "irq.h" 27 #include "i8254.h" 28 #include "x86.h" 29 30 /* 31 * check if there are pending timer events 32 * to be processed. 33 */ 34 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 35 { 36 return apic_has_pending_timer(vcpu); 37 } 38 EXPORT_SYMBOL(kvm_cpu_has_pending_timer); 39 40 /* 41 * check if there is a pending userspace external interrupt 42 */ 43 static int pending_userspace_extint(struct kvm_vcpu *v) 44 { 45 return v->arch.pending_external_vector != -1; 46 } 47 48 /* 49 * check if there is pending interrupt from 50 * non-APIC source without intack. 51 */ 52 static int kvm_cpu_has_extint(struct kvm_vcpu *v) 53 { 54 u8 accept = kvm_apic_accept_pic_intr(v); 55 56 if (accept) { 57 if (irqchip_split(v->kvm)) 58 return pending_userspace_extint(v); 59 else 60 return pic_irqchip(v->kvm)->output; 61 } else 62 return 0; 63 } 64 65 /* 66 * check if there is injectable interrupt: 67 * when virtual interrupt delivery enabled, 68 * interrupt from apic will handled by hardware, 69 * we don't need to check it here. 70 */ 71 int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) 72 { 73 if (!lapic_in_kernel(v)) 74 return v->arch.interrupt.pending; 75 76 if (kvm_cpu_has_extint(v)) 77 return 1; 78 79 if (kvm_vcpu_apic_vid_enabled(v)) 80 return 0; 81 82 return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ 83 } 84 85 /* 86 * check if there is pending interrupt without 87 * intack. 88 */ 89 int kvm_cpu_has_interrupt(struct kvm_vcpu *v) 90 { 91 if (!lapic_in_kernel(v)) 92 return v->arch.interrupt.pending; 93 94 if (kvm_cpu_has_extint(v)) 95 return 1; 96 97 return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ 98 } 99 EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); 100 101 /* 102 * Read pending interrupt(from non-APIC source) 103 * vector and intack. 104 */ 105 static int kvm_cpu_get_extint(struct kvm_vcpu *v) 106 { 107 if (kvm_cpu_has_extint(v)) { 108 if (irqchip_split(v->kvm)) { 109 int vector = v->arch.pending_external_vector; 110 111 v->arch.pending_external_vector = -1; 112 return vector; 113 } else 114 return kvm_pic_read_irq(v->kvm); /* PIC */ 115 } else 116 return -1; 117 } 118 119 /* 120 * Read pending interrupt vector and intack. 121 */ 122 int kvm_cpu_get_interrupt(struct kvm_vcpu *v) 123 { 124 int vector; 125 126 if (!lapic_in_kernel(v)) 127 return v->arch.interrupt.nr; 128 129 vector = kvm_cpu_get_extint(v); 130 131 if (vector != -1) 132 return vector; /* PIC */ 133 134 return kvm_get_apic_interrupt(v); /* APIC */ 135 } 136 EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); 137 138 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) 139 { 140 kvm_inject_apic_timer_irqs(vcpu); 141 /* TODO: PIT, RTC etc. */ 142 } 143 EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); 144 145 void __kvm_migrate_timers(struct kvm_vcpu *vcpu) 146 { 147 __kvm_migrate_apic_timer(vcpu); 148 __kvm_migrate_pit_timer(vcpu); 149 } 150