xref: /openbmc/linux/arch/x86/kvm/ioapic.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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