blob: 60d91c9d160c5647e36a9a5253b72c96d468c3eb [file] [log] [blame]
Eddie Dong85f455f2007-07-06 12:20:49 +03001/*
2 * irq.c: API for in kernel interrupt controller
3 * Copyright (c) 2007, Intel Corporation.
Nicolas Kaiser9611c182010-10-06 14:23:22 +02004 * Copyright 2009 Red Hat, Inc. and/or its affiliates.
Eddie Dong85f455f2007-07-06 12:20:49 +03005 *
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
Paul Gortmaker1767e932016-07-13 20:19:00 -040023#include <linux/export.h>
Avi Kivityedf88412007-12-16 11:02:48 +020024#include <linux/kvm_host.h>
Eddie Dong85f455f2007-07-06 12:20:49 +030025
Eddie Dong85f455f2007-07-06 12:20:49 +030026#include "irq.h"
Sheng Yang78376992008-01-28 05:10:22 +080027#include "i8254.h"
Gleb Natapov80618232009-04-21 17:44:56 +030028#include "x86.h"
Eddie Dong85f455f2007-07-06 12:20:49 +030029
30/*
Marcelo Tosatti3d808402008-04-11 14:53:26 -030031 * check if there are pending timer events
32 * to be processed.
33 */
34int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
35{
Paolo Bonzini1e3161b42016-01-08 13:41:16 +010036 if (lapic_in_kernel(vcpu))
37 return apic_has_pending_timer(vcpu);
38
39 return 0;
Marcelo Tosatti3d808402008-04-11 14:53:26 -030040}
41EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
42
43/*
Steve Rutherford1c1a9ce2015-07-30 11:27:16 +020044 * check if there is a pending userspace external interrupt
45 */
46static int pending_userspace_extint(struct kvm_vcpu *v)
47{
48 return v->arch.pending_external_vector != -1;
49}
50
51/*
Yang Zhangc7c9c562013-01-25 10:18:51 +080052 * check if there is pending interrupt from
53 * non-APIC source without intack.
54 */
55static int kvm_cpu_has_extint(struct kvm_vcpu *v)
56{
Steve Rutherford1c1a9ce2015-07-30 11:27:16 +020057 u8 accept = kvm_apic_accept_pic_intr(v);
58
59 if (accept) {
60 if (irqchip_split(v->kvm))
61 return pending_userspace_extint(v);
62 else
63 return pic_irqchip(v->kvm)->output;
64 } else
Yang Zhangc7c9c562013-01-25 10:18:51 +080065 return 0;
66}
67
68/*
69 * check if there is injectable interrupt:
70 * when virtual interrupt delivery enabled,
71 * interrupt from apic will handled by hardware,
72 * we don't need to check it here.
73 */
74int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
75{
Paolo Bonzini35754c92015-07-29 12:05:37 +020076 if (!lapic_in_kernel(v))
Yang Zhangc7c9c562013-01-25 10:18:51 +080077 return v->arch.interrupt.pending;
78
79 if (kvm_cpu_has_extint(v))
80 return 1;
81
Andrey Smetanind62caab2015-11-10 15:36:33 +030082 if (kvm_vcpu_apicv_active(v))
Yang Zhangc7c9c562013-01-25 10:18:51 +080083 return 0;
84
85 return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
86}
87
88/*
Eddie Dong85f455f2007-07-06 12:20:49 +030089 * check if there is pending interrupt without
90 * intack.
91 */
92int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
93{
Paolo Bonzini35754c92015-07-29 12:05:37 +020094 if (!lapic_in_kernel(v))
Gleb Natapov923c61b2009-05-11 13:35:48 +030095 return v->arch.interrupt.pending;
Gleb Natapov80618232009-04-21 17:44:56 +030096
Yang Zhangc7c9c562013-01-25 10:18:51 +080097 if (kvm_cpu_has_extint(v))
98 return 1;
Gleb Natapovf3200d02012-12-10 14:05:55 +020099
100 return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
Eddie Dong85f455f2007-07-06 12:20:49 +0300101}
102EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
103
104/*
Yang Zhangc7c9c562013-01-25 10:18:51 +0800105 * Read pending interrupt(from non-APIC source)
106 * vector and intack.
107 */
108static int kvm_cpu_get_extint(struct kvm_vcpu *v)
109{
Steve Rutherford1c1a9ce2015-07-30 11:27:16 +0200110 if (kvm_cpu_has_extint(v)) {
111 if (irqchip_split(v->kvm)) {
112 int vector = v->arch.pending_external_vector;
113
114 v->arch.pending_external_vector = -1;
115 return vector;
116 } else
117 return kvm_pic_read_irq(v->kvm); /* PIC */
118 } else
119 return -1;
Yang Zhangc7c9c562013-01-25 10:18:51 +0800120}
121
122/*
Eddie Dong85f455f2007-07-06 12:20:49 +0300123 * Read pending interrupt vector and intack.
124 */
125int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
126{
Yang Zhangc7c9c562013-01-25 10:18:51 +0800127 int vector;
128
Paolo Bonzini35754c92015-07-29 12:05:37 +0200129 if (!lapic_in_kernel(v))
Gleb Natapov923c61b2009-05-11 13:35:48 +0300130 return v->arch.interrupt.nr;
Gleb Natapov80618232009-04-21 17:44:56 +0300131
Yang Zhangc7c9c562013-01-25 10:18:51 +0800132 vector = kvm_cpu_get_extint(v);
133
Wanpeng Li56cc2402014-08-05 12:42:24 +0800134 if (vector != -1)
Yang Zhangc7c9c562013-01-25 10:18:51 +0800135 return vector; /* PIC */
Gleb Natapovf3200d02012-12-10 14:05:55 +0200136
137 return kvm_get_apic_interrupt(v); /* APIC */
Eddie Dong85f455f2007-07-06 12:20:49 +0300138}
Bandan Das77b0f5d2014-04-19 18:17:45 -0400139EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
Eddie Dong97222cc2007-09-12 10:58:04 +0300140
Eddie Dong1b9778d2007-09-03 16:56:58 +0300141void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
142{
Paolo Bonzini1e3161b42016-01-08 13:41:16 +0100143 if (lapic_in_kernel(vcpu))
144 kvm_inject_apic_timer_irqs(vcpu);
Eddie Dong1b9778d2007-09-03 16:56:58 +0300145}
146EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
147
Marcelo Tosatti2f599712008-05-27 12:10:20 -0300148void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
149{
150 __kvm_migrate_apic_timer(vcpu);
151 __kvm_migrate_pit_timer(vcpu);
152}