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 */ 34int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 35{ 36 return apic_has_pending_timer(vcpu); 37} 38EXPORT_SYMBOL(kvm_cpu_has_pending_timer); 39 40/* 41 * check if there is a pending userspace external interrupt 42 */ 43static 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 */ 52static 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 */ 71int 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 */ 89int 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} 99EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); 100 101/* 102 * Read pending interrupt(from non-APIC source) 103 * vector and intack. 104 */ 105static 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 */ 122int 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} 136EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); 137 138void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) 139{ 140 kvm_inject_apic_timer_irqs(vcpu); 141 /* TODO: PIT, RTC etc. */ 142} 143EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); 144 145void __kvm_migrate_timers(struct kvm_vcpu *vcpu) 146{ 147 __kvm_migrate_apic_timer(vcpu); 148 __kvm_migrate_pit_timer(vcpu); 149} 150