16ef768faSPaolo Bonzini /*
26ef768faSPaolo Bonzini * Copyright (C) 2001 MandrakeSoft S.A.
36ef768faSPaolo Bonzini * Copyright 2010 Red Hat, Inc. and/or its affiliates.
46ef768faSPaolo Bonzini *
56ef768faSPaolo Bonzini * MandrakeSoft S.A.
66ef768faSPaolo Bonzini * 43, rue d'Aboukir
76ef768faSPaolo Bonzini * 75002 Paris - France
86ef768faSPaolo Bonzini * http://www.linux-mandrake.com/
96ef768faSPaolo Bonzini * http://www.mandrakesoft.com/
106ef768faSPaolo Bonzini *
116ef768faSPaolo Bonzini * This library is free software; you can redistribute it and/or
126ef768faSPaolo Bonzini * modify it under the terms of the GNU Lesser General Public
136ef768faSPaolo Bonzini * License as published by the Free Software Foundation; either
146ef768faSPaolo Bonzini * version 2 of the License, or (at your option) any later version.
156ef768faSPaolo Bonzini *
166ef768faSPaolo Bonzini * This library is distributed in the hope that it will be useful,
176ef768faSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
186ef768faSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
196ef768faSPaolo Bonzini * Lesser General Public License for more details.
206ef768faSPaolo Bonzini *
216ef768faSPaolo Bonzini * You should have received a copy of the GNU Lesser General Public
226ef768faSPaolo Bonzini * License along with this library; if not, write to the Free Software
236ef768faSPaolo Bonzini * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
246ef768faSPaolo Bonzini *
256ef768faSPaolo Bonzini * Yunhong Jiang <yunhong.jiang@intel.com>
266ef768faSPaolo Bonzini * Yaozu (Eddie) Dong <eddie.dong@intel.com>
276ef768faSPaolo Bonzini * Based on Xen 3.1 code.
286ef768faSPaolo Bonzini */
298d20bd63SSean Christopherson #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
306ef768faSPaolo Bonzini
316ef768faSPaolo Bonzini #include <linux/kvm_host.h>
326ef768faSPaolo Bonzini #include <linux/kvm.h>
336ef768faSPaolo Bonzini #include <linux/mm.h>
346ef768faSPaolo Bonzini #include <linux/highmem.h>
356ef768faSPaolo Bonzini #include <linux/smp.h>
366ef768faSPaolo Bonzini #include <linux/hrtimer.h>
376ef768faSPaolo Bonzini #include <linux/io.h>
386ef768faSPaolo Bonzini #include <linux/slab.h>
396ef768faSPaolo Bonzini #include <linux/export.h>
408c86405fSMarios Pomonis #include <linux/nospec.h>
416ef768faSPaolo Bonzini #include <asm/processor.h>
426ef768faSPaolo Bonzini #include <asm/page.h>
436ef768faSPaolo Bonzini #include <asm/current.h>
446ef768faSPaolo Bonzini #include <trace/events/kvm.h>
456ef768faSPaolo Bonzini
466ef768faSPaolo Bonzini #include "ioapic.h"
476ef768faSPaolo Bonzini #include "lapic.h"
486ef768faSPaolo Bonzini #include "irq.h"
496ef768faSPaolo Bonzini
506ef768faSPaolo Bonzini static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
516ef768faSPaolo Bonzini bool line_status);
526ef768faSPaolo Bonzini
53f458d039SSuravee Suthikulpanit static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
54f458d039SSuravee Suthikulpanit struct kvm_ioapic *ioapic,
55f458d039SSuravee Suthikulpanit int trigger_mode,
56f458d039SSuravee Suthikulpanit int pin);
57f458d039SSuravee Suthikulpanit
ioapic_read_indirect(struct kvm_ioapic * ioapic)58019024e5SJinrong Liang static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic)
596ef768faSPaolo Bonzini {
606ef768faSPaolo Bonzini unsigned long result = 0;
616ef768faSPaolo Bonzini
626ef768faSPaolo Bonzini switch (ioapic->ioregsel) {
636ef768faSPaolo Bonzini case IOAPIC_REG_VERSION:
646ef768faSPaolo Bonzini result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16)
656ef768faSPaolo Bonzini | (IOAPIC_VERSION_ID & 0xff));
666ef768faSPaolo Bonzini break;
676ef768faSPaolo Bonzini
686ef768faSPaolo Bonzini case IOAPIC_REG_APIC_ID:
696ef768faSPaolo Bonzini case IOAPIC_REG_ARB_ID:
706ef768faSPaolo Bonzini result = ((ioapic->id & 0xf) << 24);
716ef768faSPaolo Bonzini break;
726ef768faSPaolo Bonzini
736ef768faSPaolo Bonzini default:
746ef768faSPaolo Bonzini {
756ef768faSPaolo Bonzini u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
768c86405fSMarios Pomonis u64 redir_content = ~0ULL;
776ef768faSPaolo Bonzini
788c86405fSMarios Pomonis if (redir_index < IOAPIC_NUM_PINS) {
798c86405fSMarios Pomonis u32 index = array_index_nospec(
808c86405fSMarios Pomonis redir_index, IOAPIC_NUM_PINS);
818c86405fSMarios Pomonis
828c86405fSMarios Pomonis redir_content = ioapic->redirtbl[index].bits;
838c86405fSMarios Pomonis }
846ef768faSPaolo Bonzini
856ef768faSPaolo Bonzini result = (ioapic->ioregsel & 0x1) ?
866ef768faSPaolo Bonzini (redir_content >> 32) & 0xffffffff :
876ef768faSPaolo Bonzini redir_content & 0xffffffff;
886ef768faSPaolo Bonzini break;
896ef768faSPaolo Bonzini }
906ef768faSPaolo Bonzini }
916ef768faSPaolo Bonzini
926ef768faSPaolo Bonzini return result;
936ef768faSPaolo Bonzini }
946ef768faSPaolo Bonzini
rtc_irq_eoi_tracking_reset(struct kvm_ioapic * ioapic)956ef768faSPaolo Bonzini static void rtc_irq_eoi_tracking_reset(struct kvm_ioapic *ioapic)
966ef768faSPaolo Bonzini {
976ef768faSPaolo Bonzini ioapic->rtc_status.pending_eoi = 0;
98a1c42ddeSJuergen Gross bitmap_zero(ioapic->rtc_status.dest_map.map, KVM_MAX_VCPU_IDS);
996ef768faSPaolo Bonzini }
1006ef768faSPaolo Bonzini
1016ef768faSPaolo Bonzini static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic);
1026ef768faSPaolo Bonzini
rtc_status_pending_eoi_check_valid(struct kvm_ioapic * ioapic)1036ef768faSPaolo Bonzini static void rtc_status_pending_eoi_check_valid(struct kvm_ioapic *ioapic)
1046ef768faSPaolo Bonzini {
1056ef768faSPaolo Bonzini if (WARN_ON(ioapic->rtc_status.pending_eoi < 0))
1066ef768faSPaolo Bonzini kvm_rtc_eoi_tracking_restore_all(ioapic);
1076ef768faSPaolo Bonzini }
1086ef768faSPaolo Bonzini
__rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu * vcpu)1096ef768faSPaolo Bonzini static void __rtc_irq_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
1106ef768faSPaolo Bonzini {
1116ef768faSPaolo Bonzini bool new_val, old_val;
1126ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
113b0eaf450SPaolo Bonzini struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
1146ef768faSPaolo Bonzini union kvm_ioapic_redirect_entry *e;
1156ef768faSPaolo Bonzini
1166ef768faSPaolo Bonzini e = &ioapic->redirtbl[RTC_GSI];
1175c69d5c1SPeter Xu if (!kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT,
1185c69d5c1SPeter Xu e->fields.dest_id,
1195c69d5c1SPeter Xu kvm_lapic_irq_dest_mode(!!e->fields.dest_mode)))
1206ef768faSPaolo Bonzini return;
1216ef768faSPaolo Bonzini
1226ef768faSPaolo Bonzini new_val = kvm_apic_pending_eoi(vcpu, e->fields.vector);
123b0eaf450SPaolo Bonzini old_val = test_bit(vcpu->vcpu_id, dest_map->map);
1246ef768faSPaolo Bonzini
1256ef768faSPaolo Bonzini if (new_val == old_val)
1266ef768faSPaolo Bonzini return;
1276ef768faSPaolo Bonzini
1286ef768faSPaolo Bonzini if (new_val) {
129b0eaf450SPaolo Bonzini __set_bit(vcpu->vcpu_id, dest_map->map);
130b0eaf450SPaolo Bonzini dest_map->vectors[vcpu->vcpu_id] = e->fields.vector;
1316ef768faSPaolo Bonzini ioapic->rtc_status.pending_eoi++;
1326ef768faSPaolo Bonzini } else {
133b0eaf450SPaolo Bonzini __clear_bit(vcpu->vcpu_id, dest_map->map);
1346ef768faSPaolo Bonzini ioapic->rtc_status.pending_eoi--;
1356ef768faSPaolo Bonzini rtc_status_pending_eoi_check_valid(ioapic);
1366ef768faSPaolo Bonzini }
1376ef768faSPaolo Bonzini }
1386ef768faSPaolo Bonzini
kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu * vcpu)1396ef768faSPaolo Bonzini void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu)
1406ef768faSPaolo Bonzini {
1416ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
1426ef768faSPaolo Bonzini
1436ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
1446ef768faSPaolo Bonzini __rtc_irq_eoi_tracking_restore_one(vcpu);
1456ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
1466ef768faSPaolo Bonzini }
1476ef768faSPaolo Bonzini
kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic * ioapic)1486ef768faSPaolo Bonzini static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic)
1496ef768faSPaolo Bonzini {
1506ef768faSPaolo Bonzini struct kvm_vcpu *vcpu;
15146808a4cSMarc Zyngier unsigned long i;
1526ef768faSPaolo Bonzini
1536ef768faSPaolo Bonzini if (RTC_GSI >= IOAPIC_NUM_PINS)
1546ef768faSPaolo Bonzini return;
1556ef768faSPaolo Bonzini
1566ef768faSPaolo Bonzini rtc_irq_eoi_tracking_reset(ioapic);
1576ef768faSPaolo Bonzini kvm_for_each_vcpu(i, vcpu, ioapic->kvm)
1586ef768faSPaolo Bonzini __rtc_irq_eoi_tracking_restore_one(vcpu);
1596ef768faSPaolo Bonzini }
1606ef768faSPaolo Bonzini
rtc_irq_eoi(struct kvm_ioapic * ioapic,struct kvm_vcpu * vcpu,int vector)1611ec2405cSSuravee Suthikulpanit static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu,
1621ec2405cSSuravee Suthikulpanit int vector)
1636ef768faSPaolo Bonzini {
1641ec2405cSSuravee Suthikulpanit struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
1651ec2405cSSuravee Suthikulpanit
1661ec2405cSSuravee Suthikulpanit /* RTC special handling */
1671ec2405cSSuravee Suthikulpanit if (test_bit(vcpu->vcpu_id, dest_map->map) &&
1681ec2405cSSuravee Suthikulpanit (vector == dest_map->vectors[vcpu->vcpu_id]) &&
1691ec2405cSSuravee Suthikulpanit (test_and_clear_bit(vcpu->vcpu_id,
1701ec2405cSSuravee Suthikulpanit ioapic->rtc_status.dest_map.map))) {
1716ef768faSPaolo Bonzini --ioapic->rtc_status.pending_eoi;
1726ef768faSPaolo Bonzini rtc_status_pending_eoi_check_valid(ioapic);
1736ef768faSPaolo Bonzini }
1746ef768faSPaolo Bonzini }
1756ef768faSPaolo Bonzini
rtc_irq_check_coalesced(struct kvm_ioapic * ioapic)1766ef768faSPaolo Bonzini static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
1776ef768faSPaolo Bonzini {
1786ef768faSPaolo Bonzini if (ioapic->rtc_status.pending_eoi > 0)
1796ef768faSPaolo Bonzini return true; /* coalesced */
1806ef768faSPaolo Bonzini
1816ef768faSPaolo Bonzini return false;
1826ef768faSPaolo Bonzini }
1836ef768faSPaolo Bonzini
ioapic_lazy_update_eoi(struct kvm_ioapic * ioapic,int irq)184f458d039SSuravee Suthikulpanit static void ioapic_lazy_update_eoi(struct kvm_ioapic *ioapic, int irq)
185f458d039SSuravee Suthikulpanit {
18646808a4cSMarc Zyngier unsigned long i;
187f458d039SSuravee Suthikulpanit struct kvm_vcpu *vcpu;
188f458d039SSuravee Suthikulpanit union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
189f458d039SSuravee Suthikulpanit
190f458d039SSuravee Suthikulpanit kvm_for_each_vcpu(i, vcpu, ioapic->kvm) {
191f458d039SSuravee Suthikulpanit if (!kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT,
192f458d039SSuravee Suthikulpanit entry->fields.dest_id,
193f458d039SSuravee Suthikulpanit entry->fields.dest_mode) ||
194f458d039SSuravee Suthikulpanit kvm_apic_pending_eoi(vcpu, entry->fields.vector))
195f458d039SSuravee Suthikulpanit continue;
196f458d039SSuravee Suthikulpanit
197f458d039SSuravee Suthikulpanit /*
198f458d039SSuravee Suthikulpanit * If no longer has pending EOI in LAPICs, update
19977377064SVitaly Kuznetsov * EOI for this vector.
200f458d039SSuravee Suthikulpanit */
201f458d039SSuravee Suthikulpanit rtc_irq_eoi(ioapic, vcpu, entry->fields.vector);
202f458d039SSuravee Suthikulpanit break;
203f458d039SSuravee Suthikulpanit }
204f458d039SSuravee Suthikulpanit }
205f458d039SSuravee Suthikulpanit
ioapic_set_irq(struct kvm_ioapic * ioapic,unsigned int irq,int irq_level,bool line_status)2066ef768faSPaolo Bonzini static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
2076ef768faSPaolo Bonzini int irq_level, bool line_status)
2086ef768faSPaolo Bonzini {
2096ef768faSPaolo Bonzini union kvm_ioapic_redirect_entry entry;
2106ef768faSPaolo Bonzini u32 mask = 1 << irq;
2116ef768faSPaolo Bonzini u32 old_irr;
2126ef768faSPaolo Bonzini int edge, ret;
2136ef768faSPaolo Bonzini
2146ef768faSPaolo Bonzini entry = ioapic->redirtbl[irq];
2156ef768faSPaolo Bonzini edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
2166ef768faSPaolo Bonzini
2176ef768faSPaolo Bonzini if (!irq_level) {
2186ef768faSPaolo Bonzini ioapic->irr &= ~mask;
2196ef768faSPaolo Bonzini ret = 1;
2206ef768faSPaolo Bonzini goto out;
2216ef768faSPaolo Bonzini }
2226ef768faSPaolo Bonzini
2236ef768faSPaolo Bonzini /*
2248be8f932SPaolo Bonzini * AMD SVM AVIC accelerate EOI write iff the interrupt is edge
2258be8f932SPaolo Bonzini * triggered, in which case the in-kernel IOAPIC will not be able
2268be8f932SPaolo Bonzini * to receive the EOI. In this case, we do a lazy update of the
2278be8f932SPaolo Bonzini * pending EOI when trying to set IOAPIC irq.
228f458d039SSuravee Suthikulpanit */
2298be8f932SPaolo Bonzini if (edge && kvm_apicv_activated(ioapic->kvm))
230f458d039SSuravee Suthikulpanit ioapic_lazy_update_eoi(ioapic, irq);
231f458d039SSuravee Suthikulpanit
232f458d039SSuravee Suthikulpanit /*
2336ef768faSPaolo Bonzini * Return 0 for coalesced interrupts; for edge-triggered interrupts,
2346ef768faSPaolo Bonzini * this only happens if a previous edge has not been delivered due
23500116795SMiaohe Lin * to masking. For level interrupts, the remote_irr field tells
2366ef768faSPaolo Bonzini * us if the interrupt is waiting for an EOI.
2376ef768faSPaolo Bonzini *
2386ef768faSPaolo Bonzini * RTC is special: it is edge-triggered, but userspace likes to know
2396ef768faSPaolo Bonzini * if it has been already ack-ed via EOI because coalesced RTC
2406ef768faSPaolo Bonzini * interrupts lead to time drift in Windows guests. So we track
2416ef768faSPaolo Bonzini * EOI manually for the RTC interrupt.
2426ef768faSPaolo Bonzini */
2436ef768faSPaolo Bonzini if (irq == RTC_GSI && line_status &&
2446ef768faSPaolo Bonzini rtc_irq_check_coalesced(ioapic)) {
2456ef768faSPaolo Bonzini ret = 0;
2466ef768faSPaolo Bonzini goto out;
2476ef768faSPaolo Bonzini }
2486ef768faSPaolo Bonzini
2496ef768faSPaolo Bonzini old_irr = ioapic->irr;
2506ef768faSPaolo Bonzini ioapic->irr |= mask;
2517d225368SNikita Leshenko if (edge) {
2525bda6eedSWincy Van ioapic->irr_delivered &= ~mask;
2537d225368SNikita Leshenko if (old_irr == ioapic->irr) {
2546ef768faSPaolo Bonzini ret = 0;
2556ef768faSPaolo Bonzini goto out;
2566ef768faSPaolo Bonzini }
2577d225368SNikita Leshenko }
2586ef768faSPaolo Bonzini
2596ef768faSPaolo Bonzini ret = ioapic_service(ioapic, irq, line_status);
2606ef768faSPaolo Bonzini
2616ef768faSPaolo Bonzini out:
2626ef768faSPaolo Bonzini trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0);
2636ef768faSPaolo Bonzini return ret;
2646ef768faSPaolo Bonzini }
2656ef768faSPaolo Bonzini
kvm_ioapic_inject_all(struct kvm_ioapic * ioapic,unsigned long irr)2666ef768faSPaolo Bonzini static void kvm_ioapic_inject_all(struct kvm_ioapic *ioapic, unsigned long irr)
2676ef768faSPaolo Bonzini {
2686ef768faSPaolo Bonzini u32 idx;
2696ef768faSPaolo Bonzini
2706ef768faSPaolo Bonzini rtc_irq_eoi_tracking_reset(ioapic);
2716ef768faSPaolo Bonzini for_each_set_bit(idx, &irr, IOAPIC_NUM_PINS)
2726ef768faSPaolo Bonzini ioapic_set_irq(ioapic, idx, 1, true);
2736ef768faSPaolo Bonzini
2746ef768faSPaolo Bonzini kvm_rtc_eoi_tracking_restore_all(ioapic);
2756ef768faSPaolo Bonzini }
2766ef768faSPaolo Bonzini
2776ef768faSPaolo Bonzini
kvm_ioapic_scan_entry(struct kvm_vcpu * vcpu,ulong * ioapic_handled_vectors)2786308630bSAndrey Smetanin void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, ulong *ioapic_handled_vectors)
2796ef768faSPaolo Bonzini {
2806ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
2814d99ba89SJoerg Roedel struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
2826ef768faSPaolo Bonzini union kvm_ioapic_redirect_entry *e;
2836ef768faSPaolo Bonzini int index;
2846ef768faSPaolo Bonzini
2856ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
2864d99ba89SJoerg Roedel
2874d99ba89SJoerg Roedel /* Make sure we see any missing RTC EOI */
2884d99ba89SJoerg Roedel if (test_bit(vcpu->vcpu_id, dest_map->map))
2894d99ba89SJoerg Roedel __set_bit(dest_map->vectors[vcpu->vcpu_id],
2904d99ba89SJoerg Roedel ioapic_handled_vectors);
2914d99ba89SJoerg Roedel
2926ef768faSPaolo Bonzini for (index = 0; index < IOAPIC_NUM_PINS; index++) {
2936ef768faSPaolo Bonzini e = &ioapic->redirtbl[index];
2946ef768faSPaolo Bonzini if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG ||
2956ef768faSPaolo Bonzini kvm_irq_has_notifier(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index) ||
2966ef768faSPaolo Bonzini index == RTC_GSI) {
2975c69d5c1SPeter Xu u16 dm = kvm_lapic_irq_dest_mode(!!e->fields.dest_mode);
2985c69d5c1SPeter Xu
2995c69d5c1SPeter Xu if (kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT,
3005c69d5c1SPeter Xu e->fields.dest_id, dm) ||
3010fc5a36dSNikita Leshenko kvm_apic_pending_eoi(vcpu, e->fields.vector))
3026ef768faSPaolo Bonzini __set_bit(e->fields.vector,
3036308630bSAndrey Smetanin ioapic_handled_vectors);
3046ef768faSPaolo Bonzini }
3056ef768faSPaolo Bonzini }
3066ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
3076ef768faSPaolo Bonzini }
3086ef768faSPaolo Bonzini
kvm_arch_post_irq_ack_notifier_list_update(struct kvm * kvm)309993225adSDavid Hildenbrand void kvm_arch_post_irq_ack_notifier_list_update(struct kvm *kvm)
3106ef768faSPaolo Bonzini {
3110bceb15aSDavid Hildenbrand if (!ioapic_in_kernel(kvm))
3126ef768faSPaolo Bonzini return;
3136ef768faSPaolo Bonzini kvm_make_scan_ioapic_request(kvm);
3146ef768faSPaolo Bonzini }
3156ef768faSPaolo Bonzini
ioapic_write_indirect(struct kvm_ioapic * ioapic,u32 val)3166ef768faSPaolo Bonzini static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
3176ef768faSPaolo Bonzini {
3186ef768faSPaolo Bonzini unsigned index;
3196ef768faSPaolo Bonzini bool mask_before, mask_after;
3206ef768faSPaolo Bonzini union kvm_ioapic_redirect_entry *e;
3217ee30bc1SNitesh Narayan Lal int old_remote_irr, old_delivery_status, old_dest_id, old_dest_mode;
3222f9b68f5SVitaly Kuznetsov DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS);
3236ef768faSPaolo Bonzini
3246ef768faSPaolo Bonzini switch (ioapic->ioregsel) {
3256ef768faSPaolo Bonzini case IOAPIC_REG_VERSION:
3266ef768faSPaolo Bonzini /* Writes are ignored. */
3276ef768faSPaolo Bonzini break;
3286ef768faSPaolo Bonzini
3296ef768faSPaolo Bonzini case IOAPIC_REG_APIC_ID:
3306ef768faSPaolo Bonzini ioapic->id = (val >> 24) & 0xf;
3316ef768faSPaolo Bonzini break;
3326ef768faSPaolo Bonzini
3336ef768faSPaolo Bonzini case IOAPIC_REG_ARB_ID:
3346ef768faSPaolo Bonzini break;
3356ef768faSPaolo Bonzini
3366ef768faSPaolo Bonzini default:
3376ef768faSPaolo Bonzini index = (ioapic->ioregsel - 0x10) >> 1;
3386ef768faSPaolo Bonzini
3396ef768faSPaolo Bonzini if (index >= IOAPIC_NUM_PINS)
3406ef768faSPaolo Bonzini return;
34167056455SMarios Pomonis index = array_index_nospec(index, IOAPIC_NUM_PINS);
3426ef768faSPaolo Bonzini e = &ioapic->redirtbl[index];
3436ef768faSPaolo Bonzini mask_before = e->fields.mask;
344b200ddedSNikita Leshenko /* Preserve read-only fields */
345b200ddedSNikita Leshenko old_remote_irr = e->fields.remote_irr;
346b200ddedSNikita Leshenko old_delivery_status = e->fields.delivery_status;
3477ee30bc1SNitesh Narayan Lal old_dest_id = e->fields.dest_id;
3487ee30bc1SNitesh Narayan Lal old_dest_mode = e->fields.dest_mode;
3496ef768faSPaolo Bonzini if (ioapic->ioregsel & 1) {
3506ef768faSPaolo Bonzini e->bits &= 0xffffffff;
3516ef768faSPaolo Bonzini e->bits |= (u64) val << 32;
3526ef768faSPaolo Bonzini } else {
3536ef768faSPaolo Bonzini e->bits &= ~0xffffffffULL;
3546ef768faSPaolo Bonzini e->bits |= (u32) val;
3556ef768faSPaolo Bonzini }
356b200ddedSNikita Leshenko e->fields.remote_irr = old_remote_irr;
357b200ddedSNikita Leshenko e->fields.delivery_status = old_delivery_status;
358a8bfec29SNikita Leshenko
359a8bfec29SNikita Leshenko /*
360a8bfec29SNikita Leshenko * Some OSes (Linux, Xen) assume that Remote IRR bit will
361a8bfec29SNikita Leshenko * be cleared by IOAPIC hardware when the entry is configured
362a8bfec29SNikita Leshenko * as edge-triggered. This behavior is used to simulate an
363a8bfec29SNikita Leshenko * explicit EOI on IOAPICs that don't have the EOI register.
364a8bfec29SNikita Leshenko */
365a8bfec29SNikita Leshenko if (e->fields.trig_mode == IOAPIC_EDGE_TRIG)
366a8bfec29SNikita Leshenko e->fields.remote_irr = 0;
367a8bfec29SNikita Leshenko
3686ef768faSPaolo Bonzini mask_after = e->fields.mask;
3696ef768faSPaolo Bonzini if (mask_before != mask_after)
3706ef768faSPaolo Bonzini kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
371*fef8f2b9SDmytro Maluka if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
372*fef8f2b9SDmytro Maluka ioapic->irr & (1 << index) && !e->fields.mask && !e->fields.remote_irr) {
373*fef8f2b9SDmytro Maluka /*
374*fef8f2b9SDmytro Maluka * Pending status in irr may be outdated: the IRQ line may have
375*fef8f2b9SDmytro Maluka * already been deasserted by a device while the IRQ was masked.
376*fef8f2b9SDmytro Maluka * This occurs, for instance, if the interrupt is handled in a
377*fef8f2b9SDmytro Maluka * Linux guest as a oneshot interrupt (IRQF_ONESHOT). In this
378*fef8f2b9SDmytro Maluka * case the guest acknowledges the interrupt to the device in
379*fef8f2b9SDmytro Maluka * its threaded irq handler, i.e. after the EOI but before
380*fef8f2b9SDmytro Maluka * unmasking, so at the time of unmasking the IRQ line is
381*fef8f2b9SDmytro Maluka * already down but our pending irr bit is still set. In such
382*fef8f2b9SDmytro Maluka * cases, injecting this pending interrupt to the guest is
383*fef8f2b9SDmytro Maluka * buggy: the guest will receive an extra unwanted interrupt.
384*fef8f2b9SDmytro Maluka *
385*fef8f2b9SDmytro Maluka * So we need to check here if the IRQ is actually still pending.
386*fef8f2b9SDmytro Maluka * As we are generally not able to probe the IRQ line status
387*fef8f2b9SDmytro Maluka * directly, we do it through irqfd resampler. Namely, we clear
388*fef8f2b9SDmytro Maluka * the pending status and notify the resampler that this interrupt
389*fef8f2b9SDmytro Maluka * is done, without actually injecting it into the guest. If the
390*fef8f2b9SDmytro Maluka * IRQ line is actually already deasserted, we are done. If it is
391*fef8f2b9SDmytro Maluka * still asserted, a new interrupt will be shortly triggered
392*fef8f2b9SDmytro Maluka * through irqfd and injected into the guest.
393*fef8f2b9SDmytro Maluka *
394*fef8f2b9SDmytro Maluka * If, however, it's not possible to resample (no irqfd resampler
395*fef8f2b9SDmytro Maluka * registered for this irq), then unconditionally inject this
396*fef8f2b9SDmytro Maluka * pending interrupt into the guest, so the guest will not miss
397*fef8f2b9SDmytro Maluka * an interrupt, although may get an extra unwanted interrupt.
398*fef8f2b9SDmytro Maluka */
399*fef8f2b9SDmytro Maluka if (kvm_notify_irqfd_resampler(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index))
400*fef8f2b9SDmytro Maluka ioapic->irr &= ~(1 << index);
401*fef8f2b9SDmytro Maluka else
4026ef768faSPaolo Bonzini ioapic_service(ioapic, index, false);
403*fef8f2b9SDmytro Maluka }
4047ee30bc1SNitesh Narayan Lal if (e->fields.delivery_mode == APIC_DM_FIXED) {
4057ee30bc1SNitesh Narayan Lal struct kvm_lapic_irq irq;
4067ee30bc1SNitesh Narayan Lal
4077ee30bc1SNitesh Narayan Lal irq.vector = e->fields.vector;
4087ee30bc1SNitesh Narayan Lal irq.delivery_mode = e->fields.delivery_mode << 8;
409c96001c5SPeter Xu irq.dest_mode =
410c96001c5SPeter Xu kvm_lapic_irq_dest_mode(!!e->fields.dest_mode);
4110c22056fSNitesh Narayan Lal irq.level = false;
4120c22056fSNitesh Narayan Lal irq.trig_mode = e->fields.trig_mode;
4130c22056fSNitesh Narayan Lal irq.shorthand = APIC_DEST_NOSHORT;
4140c22056fSNitesh Narayan Lal irq.dest_id = e->fields.dest_id;
4150c22056fSNitesh Narayan Lal irq.msi_redir_hint = false;
4162f9b68f5SVitaly Kuznetsov bitmap_zero(vcpu_bitmap, KVM_MAX_VCPUS);
4177ee30bc1SNitesh Narayan Lal kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
4182f9b68f5SVitaly Kuznetsov vcpu_bitmap);
4197ee30bc1SNitesh Narayan Lal if (old_dest_mode != e->fields.dest_mode ||
4207ee30bc1SNitesh Narayan Lal old_dest_id != e->fields.dest_id) {
4217ee30bc1SNitesh Narayan Lal /*
4227ee30bc1SNitesh Narayan Lal * Update vcpu_bitmap with vcpus specified in
4237ee30bc1SNitesh Narayan Lal * the previous request as well. This is done to
4247ee30bc1SNitesh Narayan Lal * keep ioapic_handled_vectors synchronized.
4257ee30bc1SNitesh Narayan Lal */
4267ee30bc1SNitesh Narayan Lal irq.dest_id = old_dest_id;
427c96001c5SPeter Xu irq.dest_mode =
428c96001c5SPeter Xu kvm_lapic_irq_dest_mode(
429c96001c5SPeter Xu !!e->fields.dest_mode);
4307ee30bc1SNitesh Narayan Lal kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
4312f9b68f5SVitaly Kuznetsov vcpu_bitmap);
4327ee30bc1SNitesh Narayan Lal }
4337ee30bc1SNitesh Narayan Lal kvm_make_scan_ioapic_request_mask(ioapic->kvm,
4342f9b68f5SVitaly Kuznetsov vcpu_bitmap);
4357ee30bc1SNitesh Narayan Lal } else {
436ca8ab3f8SDavid Hildenbrand kvm_make_scan_ioapic_request(ioapic->kvm);
4377ee30bc1SNitesh Narayan Lal }
4386ef768faSPaolo Bonzini break;
4396ef768faSPaolo Bonzini }
4406ef768faSPaolo Bonzini }
4416ef768faSPaolo Bonzini
ioapic_service(struct kvm_ioapic * ioapic,int irq,bool line_status)4426ef768faSPaolo Bonzini static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
4436ef768faSPaolo Bonzini {
4446ef768faSPaolo Bonzini union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
4456ef768faSPaolo Bonzini struct kvm_lapic_irq irqe;
4466ef768faSPaolo Bonzini int ret;
4476ef768faSPaolo Bonzini
448da3fe7bdSNikita Leshenko if (entry->fields.mask ||
449da3fe7bdSNikita Leshenko (entry->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
450da3fe7bdSNikita Leshenko entry->fields.remote_irr))
4516ef768faSPaolo Bonzini return -1;
4526ef768faSPaolo Bonzini
4536ef768faSPaolo Bonzini irqe.dest_id = entry->fields.dest_id;
4546ef768faSPaolo Bonzini irqe.vector = entry->fields.vector;
455c96001c5SPeter Xu irqe.dest_mode = kvm_lapic_irq_dest_mode(!!entry->fields.dest_mode);
4566ef768faSPaolo Bonzini irqe.trig_mode = entry->fields.trig_mode;
4576ef768faSPaolo Bonzini irqe.delivery_mode = entry->fields.delivery_mode << 8;
4586ef768faSPaolo Bonzini irqe.level = 1;
459150a84feSPeter Xu irqe.shorthand = APIC_DEST_NOSHORT;
46093bbf0b8SJames Sullivan irqe.msi_redir_hint = false;
4616ef768faSPaolo Bonzini
4626ef768faSPaolo Bonzini if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
4635bda6eedSWincy Van ioapic->irr_delivered |= 1 << irq;
4646ef768faSPaolo Bonzini
4656ef768faSPaolo Bonzini if (irq == RTC_GSI && line_status) {
4666ef768faSPaolo Bonzini /*
4676ef768faSPaolo Bonzini * pending_eoi cannot ever become negative (see
4686ef768faSPaolo Bonzini * rtc_status_pending_eoi_check_valid) and the caller
4696ef768faSPaolo Bonzini * ensures that it is only called if it is >= zero, namely
4706ef768faSPaolo Bonzini * if rtc_irq_check_coalesced returns false).
4716ef768faSPaolo Bonzini */
4726ef768faSPaolo Bonzini BUG_ON(ioapic->rtc_status.pending_eoi != 0);
4736ef768faSPaolo Bonzini ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
4749e4aabe2SJoerg Roedel &ioapic->rtc_status.dest_map);
4756ef768faSPaolo Bonzini ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);
4766ef768faSPaolo Bonzini } else
4776ef768faSPaolo Bonzini ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);
4786ef768faSPaolo Bonzini
4796ef768faSPaolo Bonzini if (ret && irqe.trig_mode == IOAPIC_LEVEL_TRIG)
4806ef768faSPaolo Bonzini entry->fields.remote_irr = 1;
4816ef768faSPaolo Bonzini
4826ef768faSPaolo Bonzini return ret;
4836ef768faSPaolo Bonzini }
4846ef768faSPaolo Bonzini
kvm_ioapic_set_irq(struct kvm_ioapic * ioapic,int irq,int irq_source_id,int level,bool line_status)4856ef768faSPaolo Bonzini int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
4866ef768faSPaolo Bonzini int level, bool line_status)
4876ef768faSPaolo Bonzini {
4886ef768faSPaolo Bonzini int ret, irq_level;
4896ef768faSPaolo Bonzini
4906ef768faSPaolo Bonzini BUG_ON(irq < 0 || irq >= IOAPIC_NUM_PINS);
4916ef768faSPaolo Bonzini
4926ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
4936ef768faSPaolo Bonzini irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
4946ef768faSPaolo Bonzini irq_source_id, level);
4956ef768faSPaolo Bonzini ret = ioapic_set_irq(ioapic, irq, irq_level, line_status);
4966ef768faSPaolo Bonzini
4976ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
4986ef768faSPaolo Bonzini
4996ef768faSPaolo Bonzini return ret;
5006ef768faSPaolo Bonzini }
5016ef768faSPaolo Bonzini
kvm_ioapic_clear_all(struct kvm_ioapic * ioapic,int irq_source_id)5026ef768faSPaolo Bonzini void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id)
5036ef768faSPaolo Bonzini {
5046ef768faSPaolo Bonzini int i;
5056ef768faSPaolo Bonzini
5066ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
5076ef768faSPaolo Bonzini for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
5086ef768faSPaolo Bonzini __clear_bit(irq_source_id, &ioapic->irq_states[i]);
5096ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
5106ef768faSPaolo Bonzini }
5116ef768faSPaolo Bonzini
kvm_ioapic_eoi_inject_work(struct work_struct * work)5126ef768faSPaolo Bonzini static void kvm_ioapic_eoi_inject_work(struct work_struct *work)
5136ef768faSPaolo Bonzini {
5146ef768faSPaolo Bonzini int i;
5156ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = container_of(work, struct kvm_ioapic,
5166ef768faSPaolo Bonzini eoi_inject.work);
5176ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
5186ef768faSPaolo Bonzini for (i = 0; i < IOAPIC_NUM_PINS; i++) {
5196ef768faSPaolo Bonzini union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
5206ef768faSPaolo Bonzini
5216ef768faSPaolo Bonzini if (ent->fields.trig_mode != IOAPIC_LEVEL_TRIG)
5226ef768faSPaolo Bonzini continue;
5236ef768faSPaolo Bonzini
5246ef768faSPaolo Bonzini if (ioapic->irr & (1 << i) && !ent->fields.remote_irr)
5256ef768faSPaolo Bonzini ioapic_service(ioapic, i, false);
5266ef768faSPaolo Bonzini }
5276ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
5286ef768faSPaolo Bonzini }
5296ef768faSPaolo Bonzini
5306ef768faSPaolo Bonzini #define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000
kvm_ioapic_update_eoi_one(struct kvm_vcpu * vcpu,struct kvm_ioapic * ioapic,int trigger_mode,int pin)5311ec2405cSSuravee Suthikulpanit static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
5321ec2405cSSuravee Suthikulpanit struct kvm_ioapic *ioapic,
5331ec2405cSSuravee Suthikulpanit int trigger_mode,
5341ec2405cSSuravee Suthikulpanit int pin)
5356ef768faSPaolo Bonzini {
536c806a6adSRadim Krčmář struct kvm_lapic *apic = vcpu->arch.apic;
5371ec2405cSSuravee Suthikulpanit union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[pin];
5386ef768faSPaolo Bonzini
5396ef768faSPaolo Bonzini /*
5406ef768faSPaolo Bonzini * We are dropping lock while calling ack notifiers because ack
5416ef768faSPaolo Bonzini * notifier callbacks for assigned devices call into IOAPIC
5426ef768faSPaolo Bonzini * recursively. Since remote_irr is cleared only after call
5436ef768faSPaolo Bonzini * to notifiers if the same vector will be delivered while lock
5446ef768faSPaolo Bonzini * is dropped it will be put into irr and will be delivered
5456ef768faSPaolo Bonzini * after ack notifier returns.
5466ef768faSPaolo Bonzini */
5476ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
5481ec2405cSSuravee Suthikulpanit kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin);
5496ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
5506ef768faSPaolo Bonzini
551c806a6adSRadim Krčmář if (trigger_mode != IOAPIC_LEVEL_TRIG ||
552dfb95954SSuravee Suthikulpanit kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
5531ec2405cSSuravee Suthikulpanit return;
5546ef768faSPaolo Bonzini
5556ef768faSPaolo Bonzini ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
5566ef768faSPaolo Bonzini ent->fields.remote_irr = 0;
5571ec2405cSSuravee Suthikulpanit if (!ent->fields.mask && (ioapic->irr & (1 << pin))) {
5581ec2405cSSuravee Suthikulpanit ++ioapic->irq_eoi[pin];
5591ec2405cSSuravee Suthikulpanit if (ioapic->irq_eoi[pin] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) {
5606ef768faSPaolo Bonzini /*
5616ef768faSPaolo Bonzini * Real hardware does not deliver the interrupt
5626ef768faSPaolo Bonzini * immediately during eoi broadcast, and this
5636ef768faSPaolo Bonzini * lets a buggy guest make slow progress
5646ef768faSPaolo Bonzini * even if it does not correctly handle a
5656ef768faSPaolo Bonzini * level-triggered interrupt. Emulate this
5666ef768faSPaolo Bonzini * behavior if we detect an interrupt storm.
5676ef768faSPaolo Bonzini */
5686ef768faSPaolo Bonzini schedule_delayed_work(&ioapic->eoi_inject, HZ / 100);
5691ec2405cSSuravee Suthikulpanit ioapic->irq_eoi[pin] = 0;
5706ef768faSPaolo Bonzini trace_kvm_ioapic_delayed_eoi_inj(ent->bits);
5716ef768faSPaolo Bonzini } else {
5721ec2405cSSuravee Suthikulpanit ioapic_service(ioapic, pin, false);
5736ef768faSPaolo Bonzini }
5746ef768faSPaolo Bonzini } else {
5751ec2405cSSuravee Suthikulpanit ioapic->irq_eoi[pin] = 0;
5766ef768faSPaolo Bonzini }
5776ef768faSPaolo Bonzini }
5786ef768faSPaolo Bonzini
kvm_ioapic_update_eoi(struct kvm_vcpu * vcpu,int vector,int trigger_mode)5796ef768faSPaolo Bonzini void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode)
5806ef768faSPaolo Bonzini {
5811ec2405cSSuravee Suthikulpanit int i;
5826ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
5836ef768faSPaolo Bonzini
5846ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
5851ec2405cSSuravee Suthikulpanit rtc_irq_eoi(ioapic, vcpu, vector);
5861ec2405cSSuravee Suthikulpanit for (i = 0; i < IOAPIC_NUM_PINS; i++) {
5871ec2405cSSuravee Suthikulpanit union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
5881ec2405cSSuravee Suthikulpanit
5891ec2405cSSuravee Suthikulpanit if (ent->fields.vector != vector)
5901ec2405cSSuravee Suthikulpanit continue;
5911ec2405cSSuravee Suthikulpanit kvm_ioapic_update_eoi_one(vcpu, ioapic, trigger_mode, i);
5921ec2405cSSuravee Suthikulpanit }
5936ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
5946ef768faSPaolo Bonzini }
5956ef768faSPaolo Bonzini
to_ioapic(struct kvm_io_device * dev)5966ef768faSPaolo Bonzini static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
5976ef768faSPaolo Bonzini {
5986ef768faSPaolo Bonzini return container_of(dev, struct kvm_ioapic, dev);
5996ef768faSPaolo Bonzini }
6006ef768faSPaolo Bonzini
ioapic_in_range(struct kvm_ioapic * ioapic,gpa_t addr)6016ef768faSPaolo Bonzini static inline int ioapic_in_range(struct kvm_ioapic *ioapic, gpa_t addr)
6026ef768faSPaolo Bonzini {
6036ef768faSPaolo Bonzini return ((addr >= ioapic->base_address &&
6046ef768faSPaolo Bonzini (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
6056ef768faSPaolo Bonzini }
6066ef768faSPaolo Bonzini
ioapic_mmio_read(struct kvm_vcpu * vcpu,struct kvm_io_device * this,gpa_t addr,int len,void * val)607e32edf4fSNikolay Nikolaev static int ioapic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
608e32edf4fSNikolay Nikolaev gpa_t addr, int len, void *val)
6096ef768faSPaolo Bonzini {
6106ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = to_ioapic(this);
6116ef768faSPaolo Bonzini u32 result;
6126ef768faSPaolo Bonzini if (!ioapic_in_range(ioapic, addr))
6136ef768faSPaolo Bonzini return -EOPNOTSUPP;
6146ef768faSPaolo Bonzini
6156ef768faSPaolo Bonzini ASSERT(!(addr & 0xf)); /* check alignment */
6166ef768faSPaolo Bonzini
6176ef768faSPaolo Bonzini addr &= 0xff;
6186ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
6196ef768faSPaolo Bonzini switch (addr) {
6206ef768faSPaolo Bonzini case IOAPIC_REG_SELECT:
6216ef768faSPaolo Bonzini result = ioapic->ioregsel;
6226ef768faSPaolo Bonzini break;
6236ef768faSPaolo Bonzini
6246ef768faSPaolo Bonzini case IOAPIC_REG_WINDOW:
625019024e5SJinrong Liang result = ioapic_read_indirect(ioapic);
6266ef768faSPaolo Bonzini break;
6276ef768faSPaolo Bonzini
6286ef768faSPaolo Bonzini default:
6296ef768faSPaolo Bonzini result = 0;
6306ef768faSPaolo Bonzini break;
6316ef768faSPaolo Bonzini }
6326ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
6336ef768faSPaolo Bonzini
6346ef768faSPaolo Bonzini switch (len) {
6356ef768faSPaolo Bonzini case 8:
6366ef768faSPaolo Bonzini *(u64 *) val = result;
6376ef768faSPaolo Bonzini break;
6386ef768faSPaolo Bonzini case 1:
6396ef768faSPaolo Bonzini case 2:
6406ef768faSPaolo Bonzini case 4:
6416ef768faSPaolo Bonzini memcpy(val, (char *)&result, len);
6426ef768faSPaolo Bonzini break;
6436ef768faSPaolo Bonzini default:
6446ef768faSPaolo Bonzini printk(KERN_WARNING "ioapic: wrong length %d\n", len);
6456ef768faSPaolo Bonzini }
6466ef768faSPaolo Bonzini return 0;
6476ef768faSPaolo Bonzini }
6486ef768faSPaolo Bonzini
ioapic_mmio_write(struct kvm_vcpu * vcpu,struct kvm_io_device * this,gpa_t addr,int len,const void * val)649e32edf4fSNikolay Nikolaev static int ioapic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
650e32edf4fSNikolay Nikolaev gpa_t addr, int len, const void *val)
6516ef768faSPaolo Bonzini {
6526ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = to_ioapic(this);
6536ef768faSPaolo Bonzini u32 data;
6546ef768faSPaolo Bonzini if (!ioapic_in_range(ioapic, addr))
6556ef768faSPaolo Bonzini return -EOPNOTSUPP;
6566ef768faSPaolo Bonzini
6576ef768faSPaolo Bonzini ASSERT(!(addr & 0xf)); /* check alignment */
6586ef768faSPaolo Bonzini
6596ef768faSPaolo Bonzini switch (len) {
6606ef768faSPaolo Bonzini case 8:
6616ef768faSPaolo Bonzini case 4:
6626ef768faSPaolo Bonzini data = *(u32 *) val;
6636ef768faSPaolo Bonzini break;
6646ef768faSPaolo Bonzini case 2:
6656ef768faSPaolo Bonzini data = *(u16 *) val;
6666ef768faSPaolo Bonzini break;
6676ef768faSPaolo Bonzini case 1:
6686ef768faSPaolo Bonzini data = *(u8 *) val;
6696ef768faSPaolo Bonzini break;
6706ef768faSPaolo Bonzini default:
6716ef768faSPaolo Bonzini printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
6726ef768faSPaolo Bonzini return 0;
6736ef768faSPaolo Bonzini }
6746ef768faSPaolo Bonzini
6756ef768faSPaolo Bonzini addr &= 0xff;
6766ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
6776ef768faSPaolo Bonzini switch (addr) {
6786ef768faSPaolo Bonzini case IOAPIC_REG_SELECT:
6796ef768faSPaolo Bonzini ioapic->ioregsel = data & 0xFF; /* 8-bit register */
6806ef768faSPaolo Bonzini break;
6816ef768faSPaolo Bonzini
6826ef768faSPaolo Bonzini case IOAPIC_REG_WINDOW:
6836ef768faSPaolo Bonzini ioapic_write_indirect(ioapic, data);
6846ef768faSPaolo Bonzini break;
6856ef768faSPaolo Bonzini
6866ef768faSPaolo Bonzini default:
6876ef768faSPaolo Bonzini break;
6886ef768faSPaolo Bonzini }
6896ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
6906ef768faSPaolo Bonzini return 0;
6916ef768faSPaolo Bonzini }
6926ef768faSPaolo Bonzini
kvm_ioapic_reset(struct kvm_ioapic * ioapic)6936ef768faSPaolo Bonzini static void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
6946ef768faSPaolo Bonzini {
6956ef768faSPaolo Bonzini int i;
6966ef768faSPaolo Bonzini
6976ef768faSPaolo Bonzini cancel_delayed_work_sync(&ioapic->eoi_inject);
6986ef768faSPaolo Bonzini for (i = 0; i < IOAPIC_NUM_PINS; i++)
6996ef768faSPaolo Bonzini ioapic->redirtbl[i].fields.mask = 1;
7006ef768faSPaolo Bonzini ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
7016ef768faSPaolo Bonzini ioapic->ioregsel = 0;
7026ef768faSPaolo Bonzini ioapic->irr = 0;
7035bda6eedSWincy Van ioapic->irr_delivered = 0;
7046ef768faSPaolo Bonzini ioapic->id = 0;
7058678654eSJiri Slaby memset(ioapic->irq_eoi, 0x00, sizeof(ioapic->irq_eoi));
7066ef768faSPaolo Bonzini rtc_irq_eoi_tracking_reset(ioapic);
7076ef768faSPaolo Bonzini }
7086ef768faSPaolo Bonzini
7096ef768faSPaolo Bonzini static const struct kvm_io_device_ops ioapic_mmio_ops = {
7106ef768faSPaolo Bonzini .read = ioapic_mmio_read,
7116ef768faSPaolo Bonzini .write = ioapic_mmio_write,
7126ef768faSPaolo Bonzini };
7136ef768faSPaolo Bonzini
kvm_ioapic_init(struct kvm * kvm)7146ef768faSPaolo Bonzini int kvm_ioapic_init(struct kvm *kvm)
7156ef768faSPaolo Bonzini {
7166ef768faSPaolo Bonzini struct kvm_ioapic *ioapic;
7176ef768faSPaolo Bonzini int ret;
7186ef768faSPaolo Bonzini
719254272ceSBen Gardon ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL_ACCOUNT);
7206ef768faSPaolo Bonzini if (!ioapic)
7216ef768faSPaolo Bonzini return -ENOMEM;
7226ef768faSPaolo Bonzini spin_lock_init(&ioapic->lock);
7236ef768faSPaolo Bonzini INIT_DELAYED_WORK(&ioapic->eoi_inject, kvm_ioapic_eoi_inject_work);
7246ef768faSPaolo Bonzini kvm->arch.vioapic = ioapic;
7256ef768faSPaolo Bonzini kvm_ioapic_reset(ioapic);
7266ef768faSPaolo Bonzini kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
7276ef768faSPaolo Bonzini ioapic->kvm = kvm;
7286ef768faSPaolo Bonzini mutex_lock(&kvm->slots_lock);
7296ef768faSPaolo Bonzini ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, ioapic->base_address,
7306ef768faSPaolo Bonzini IOAPIC_MEM_LENGTH, &ioapic->dev);
7316ef768faSPaolo Bonzini mutex_unlock(&kvm->slots_lock);
7326ef768faSPaolo Bonzini if (ret < 0) {
7336ef768faSPaolo Bonzini kvm->arch.vioapic = NULL;
7346ef768faSPaolo Bonzini kfree(ioapic);
7356ef768faSPaolo Bonzini }
7366ef768faSPaolo Bonzini
7376ef768faSPaolo Bonzini return ret;
7386ef768faSPaolo Bonzini }
7396ef768faSPaolo Bonzini
kvm_ioapic_destroy(struct kvm * kvm)7406ef768faSPaolo Bonzini void kvm_ioapic_destroy(struct kvm *kvm)
7416ef768faSPaolo Bonzini {
7426ef768faSPaolo Bonzini struct kvm_ioapic *ioapic = kvm->arch.vioapic;
7436ef768faSPaolo Bonzini
744950712ebSPeter Xu if (!ioapic)
745950712ebSPeter Xu return;
746950712ebSPeter Xu
7476ef768faSPaolo Bonzini cancel_delayed_work_sync(&ioapic->eoi_inject);
74849f520b9SDavid Hildenbrand mutex_lock(&kvm->slots_lock);
7496ef768faSPaolo Bonzini kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
75049f520b9SDavid Hildenbrand mutex_unlock(&kvm->slots_lock);
7516ef768faSPaolo Bonzini kvm->arch.vioapic = NULL;
7526ef768faSPaolo Bonzini kfree(ioapic);
7536ef768faSPaolo Bonzini }
7546ef768faSPaolo Bonzini
kvm_get_ioapic(struct kvm * kvm,struct kvm_ioapic_state * state)75533392b49SDavid Hildenbrand void kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
7566ef768faSPaolo Bonzini {
7570191e92dSDavid Hildenbrand struct kvm_ioapic *ioapic = kvm->arch.vioapic;
7586ef768faSPaolo Bonzini
7596ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
7606ef768faSPaolo Bonzini memcpy(state, ioapic, sizeof(struct kvm_ioapic_state));
7615bda6eedSWincy Van state->irr &= ~ioapic->irr_delivered;
7626ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
7636ef768faSPaolo Bonzini }
7646ef768faSPaolo Bonzini
kvm_set_ioapic(struct kvm * kvm,struct kvm_ioapic_state * state)76533392b49SDavid Hildenbrand void kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
7666ef768faSPaolo Bonzini {
7670191e92dSDavid Hildenbrand struct kvm_ioapic *ioapic = kvm->arch.vioapic;
7686ef768faSPaolo Bonzini
7696ef768faSPaolo Bonzini spin_lock(&ioapic->lock);
7706ef768faSPaolo Bonzini memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
7716ef768faSPaolo Bonzini ioapic->irr = 0;
7725bda6eedSWincy Van ioapic->irr_delivered = 0;
773ca8ab3f8SDavid Hildenbrand kvm_make_scan_ioapic_request(kvm);
7746ef768faSPaolo Bonzini kvm_ioapic_inject_all(ioapic, state->irr);
7756ef768faSPaolo Bonzini spin_unlock(&ioapic->lock);
7766ef768faSPaolo Bonzini }
777