vioapic.c revision 284900
155682Smarkm/*-
255682Smarkm * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
355682Smarkm * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm * 1. Redistributions of source code must retain the above copyright
1055682Smarkm *    notice, this list of conditions and the following disclaimer.
1155682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1255682Smarkm *    notice, this list of conditions and the following disclaimer in the
1355682Smarkm *    documentation and/or other materials provided with the distribution.
1455682Smarkm *
1555682Smarkm * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1755682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1855682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
1955682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2055682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2155682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2255682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2355682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2455682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2555682Smarkm * SUCH DAMAGE.
2655682Smarkm *
2755682Smarkm * $FreeBSD: stable/10/sys/amd64/vmm/io/vioapic.c 284900 2015-06-28 03:22:26Z neel $
2855682Smarkm */
2955682Smarkm
3055682Smarkm#include <sys/cdefs.h>
3155682Smarkm__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/io/vioapic.c 284900 2015-06-28 03:22:26Z neel $");
3255682Smarkm
3355682Smarkm#include <sys/param.h>
3455682Smarkm#include <sys/queue.h>
3555682Smarkm#include <sys/lock.h>
3655682Smarkm#include <sys/mutex.h>
3755682Smarkm#include <sys/systm.h>
3855682Smarkm#include <sys/kernel.h>
3955682Smarkm#include <sys/malloc.h>
4055682Smarkm
4155682Smarkm#include <x86/apicreg.h>
4255682Smarkm#include <machine/vmm.h>
4355682Smarkm
4455682Smarkm#include "vmm_ktr.h"
4555682Smarkm#include "vmm_lapic.h"
4655682Smarkm#include "vlapic.h"
4755682Smarkm#include "vioapic.h"
4855682Smarkm
4955682Smarkm#define	IOREGSEL	0x00
5055682Smarkm#define	IOWIN		0x10
5155682Smarkm
5255682Smarkm#define	REDIR_ENTRIES	24
53233294Sstas#define	RTBL_RO_BITS	((uint64_t)(IOART_REM_IRR | IOART_DELIVS))
5455682Smarkm
5555682Smarkmstruct vioapic {
5655682Smarkm	struct vm	*vm;
5755682Smarkm	struct mtx	mtx;
5855682Smarkm	uint32_t	id;
5955682Smarkm	uint32_t	ioregsel;
6055682Smarkm	struct {
6155682Smarkm		uint64_t reg;
6255682Smarkm		int	 acnt;	/* sum of pin asserts (+1) and deasserts (-1) */
6355682Smarkm	} rtbl[REDIR_ENTRIES];
6455682Smarkm};
6555682Smarkm
6655682Smarkm#define	VIOAPIC_LOCK(vioapic)		mtx_lock_spin(&((vioapic)->mtx))
6755682Smarkm#define	VIOAPIC_UNLOCK(vioapic)		mtx_unlock_spin(&((vioapic)->mtx))
6855682Smarkm#define	VIOAPIC_LOCKED(vioapic)		mtx_owned(&((vioapic)->mtx))
6955682Smarkm
7055682Smarkmstatic MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
7155682Smarkm
7255682Smarkm#define	VIOAPIC_CTR1(vioapic, fmt, a1)					\
7355682Smarkm	VM_CTR1((vioapic)->vm, fmt, a1)
7455682Smarkm
7555682Smarkm#define	VIOAPIC_CTR2(vioapic, fmt, a1, a2)				\
7655682Smarkm	VM_CTR2((vioapic)->vm, fmt, a1, a2)
7755682Smarkm
7855682Smarkm#define	VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3)				\
7955682Smarkm	VM_CTR3((vioapic)->vm, fmt, a1, a2, a3)
8055682Smarkm
8155682Smarkm#define	VIOAPIC_CTR4(vioapic, fmt, a1, a2, a3, a4)			\
8255682Smarkm	VM_CTR4((vioapic)->vm, fmt, a1, a2, a3, a4)
8355682Smarkm
8478527Sassar#ifdef KTR
8578527Sassarstatic const char *
8678527Sassarpinstate_str(bool asserted)
8755682Smarkm{
8855682Smarkm
8955682Smarkm	if (asserted)
9055682Smarkm		return ("asserted");
9190926Snectar	else
9290926Snectar		return ("deasserted");
9390926Snectar}
9490926Snectar#endif
9555682Smarkm
9655682Smarkmstatic void
9755682Smarkmvioapic_send_intr(struct vioapic *vioapic, int pin)
9855682Smarkm{
9955682Smarkm	int vector, delmode;
10055682Smarkm	uint32_t low, high, dest;
10155682Smarkm	bool level, phys;
10255682Smarkm
10355682Smarkm	KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
10455682Smarkm	    ("vioapic_set_pinstate: invalid pin number %d", pin));
10555682Smarkm
10655682Smarkm	KASSERT(VIOAPIC_LOCKED(vioapic),
10755682Smarkm	    ("vioapic_set_pinstate: vioapic is not locked"));
10855682Smarkm
10955682Smarkm	low = vioapic->rtbl[pin].reg;
11055682Smarkm	high = vioapic->rtbl[pin].reg >> 32;
11155682Smarkm
11255682Smarkm	if ((low & IOART_INTMASK) == IOART_INTMSET) {
11355682Smarkm		VIOAPIC_CTR1(vioapic, "ioapic pin%d: masked", pin);
11455682Smarkm		return;
11555682Smarkm	}
11655682Smarkm
11755682Smarkm	phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
11855682Smarkm	delmode = low & IOART_DELMOD;
11955682Smarkm	level = low & IOART_TRGRLVL ? true : false;
12055682Smarkm	if (level)
12155682Smarkm		vioapic->rtbl[pin].reg |= IOART_REM_IRR;
12255682Smarkm
12355682Smarkm	vector = low & IOART_INTVEC;
12455682Smarkm	dest = high >> APIC_ID_SHIFT;
12555682Smarkm	vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector);
12655682Smarkm}
12755682Smarkm
12855682Smarkmstatic void
12955682Smarkmvioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
13055682Smarkm{
13155682Smarkm	int oldcnt, newcnt;
13255682Smarkm	bool needintr;
13355682Smarkm
13455682Smarkm	KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
13555682Smarkm	    ("vioapic_set_pinstate: invalid pin number %d", pin));
13655682Smarkm
13755682Smarkm	KASSERT(VIOAPIC_LOCKED(vioapic),
13855682Smarkm	    ("vioapic_set_pinstate: vioapic is not locked"));
13955682Smarkm
14055682Smarkm	oldcnt = vioapic->rtbl[pin].acnt;
14155682Smarkm	if (newstate)
14255682Smarkm		vioapic->rtbl[pin].acnt++;
14355682Smarkm	else
14455682Smarkm		vioapic->rtbl[pin].acnt--;
14555682Smarkm	newcnt = vioapic->rtbl[pin].acnt;
14655682Smarkm
14755682Smarkm	if (newcnt < 0) {
14855682Smarkm		VIOAPIC_CTR2(vioapic, "ioapic pin%d: bad acnt %d",
14978527Sassar		    pin, newcnt);
15055682Smarkm	}
15155682Smarkm
15255682Smarkm	needintr = false;
15355682Smarkm	if (oldcnt == 0 && newcnt == 1) {
15455682Smarkm		needintr = true;
15578527Sassar		VIOAPIC_CTR1(vioapic, "ioapic pin%d: asserted", pin);
15678527Sassar	} else if (oldcnt == 1 && newcnt == 0) {
15778527Sassar		VIOAPIC_CTR1(vioapic, "ioapic pin%d: deasserted", pin);
15878527Sassar	} else {
15955682Smarkm		VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s, ignored, acnt %d",
16055682Smarkm		    pin, pinstate_str(newstate), newcnt);
16155682Smarkm	}
16255682Smarkm
16355682Smarkm	if (needintr)
16455682Smarkm		vioapic_send_intr(vioapic, pin);
16555682Smarkm}
16655682Smarkm
167233294Sstasenum irqstate {
168233294Sstas	IRQSTATE_ASSERT,
169233294Sstas	IRQSTATE_DEASSERT,
170233294Sstas	IRQSTATE_PULSE
17155682Smarkm};
17255682Smarkm
17355682Smarkmstatic int
17455682Smarkmvioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
17555682Smarkm{
17655682Smarkm	struct vioapic *vioapic;
17778527Sassar
17855682Smarkm	if (irq < 0 || irq >= REDIR_ENTRIES)
17955682Smarkm		return (EINVAL);
18055682Smarkm
18155682Smarkm	vioapic = vm_ioapic(vm);
18255682Smarkm
18355682Smarkm	VIOAPIC_LOCK(vioapic);
18455682Smarkm	switch (irqstate) {
18555682Smarkm	case IRQSTATE_ASSERT:
18655682Smarkm		vioapic_set_pinstate(vioapic, irq, true);
18755682Smarkm		break;
18855682Smarkm	case IRQSTATE_DEASSERT:
18955682Smarkm		vioapic_set_pinstate(vioapic, irq, false);
19055682Smarkm		break;
19155682Smarkm	case IRQSTATE_PULSE:
192233294Sstas		vioapic_set_pinstate(vioapic, irq, true);
19355682Smarkm		vioapic_set_pinstate(vioapic, irq, false);
19455682Smarkm		break;
19555682Smarkm	default:
19655682Smarkm		panic("vioapic_set_irqstate: invalid irqstate %d", irqstate);
19755682Smarkm	}
19855682Smarkm	VIOAPIC_UNLOCK(vioapic);
19955682Smarkm
20055682Smarkm	return (0);
20155682Smarkm}
20255682Smarkm
203233294Sstasint
204233294Sstasvioapic_assert_irq(struct vm *vm, int irq)
20555682Smarkm{
20655682Smarkm
20755682Smarkm	return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
20855682Smarkm}
20955682Smarkm
21055682Smarkmint
21155682Smarkmvioapic_deassert_irq(struct vm *vm, int irq)
21255682Smarkm{
21355682Smarkm
21455682Smarkm	return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
21555682Smarkm}
21655682Smarkm
21755682Smarkmint
21855682Smarkmvioapic_pulse_irq(struct vm *vm, int irq)
21955682Smarkm{
22055682Smarkm
22155682Smarkm	return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE));
22255682Smarkm}
22355682Smarkm
22455682Smarkm/*
22555682Smarkm * Reset the vlapic's trigger-mode register to reflect the ioapic pin
22655682Smarkm * configuration.
22755682Smarkm */
22878527Sassarstatic void
22955682Smarkmvioapic_update_tmr(struct vm *vm, int vcpuid, void *arg)
23055682Smarkm{
23155682Smarkm	struct vioapic *vioapic;
23255682Smarkm	struct vlapic *vlapic;
23355682Smarkm	uint32_t low, high, dest;
23455682Smarkm	int delmode, pin, vector;
23555682Smarkm	bool level, phys;
23655682Smarkm
23755682Smarkm	vlapic = vm_lapic(vm, vcpuid);
23855682Smarkm	vioapic = vm_ioapic(vm);
23955682Smarkm
24055682Smarkm	VIOAPIC_LOCK(vioapic);
241233294Sstas	/*
24255682Smarkm	 * Reset all vectors to be edge-triggered.
24355682Smarkm	 */
24455682Smarkm	vlapic_reset_tmr(vlapic);
24555682Smarkm	for (pin = 0; pin < REDIR_ENTRIES; pin++) {
24655682Smarkm		low = vioapic->rtbl[pin].reg;
24755682Smarkm		high = vioapic->rtbl[pin].reg >> 32;
24855682Smarkm
24955682Smarkm		level = low & IOART_TRGRLVL ? true : false;
25055682Smarkm		if (!level)
25155682Smarkm			continue;
25255682Smarkm
25355682Smarkm		/*
25455682Smarkm		 * For a level-triggered 'pin' let the vlapic figure out if
25555682Smarkm		 * an assertion on this 'pin' would result in an interrupt
25655682Smarkm		 * being delivered to it. If yes, then it will modify the
25755682Smarkm		 * TMR bit associated with this vector to level-triggered.
25855682Smarkm		 */
25955682Smarkm		phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
26055682Smarkm		delmode = low & IOART_DELMOD;
261233294Sstas		vector = low & IOART_INTVEC;
26255682Smarkm		dest = high >> APIC_ID_SHIFT;
26355682Smarkm		vlapic_set_tmr_level(vlapic, dest, phys, delmode, vector);
26455682Smarkm	}
26555682Smarkm	VIOAPIC_UNLOCK(vioapic);
26655682Smarkm}
26755682Smarkm
26855682Smarkmstatic uint32_t
26955682Smarkmvioapic_read(struct vioapic *vioapic, int vcpuid, uint32_t addr)
27055682Smarkm{
27155682Smarkm	int regnum, pin, rshift;
27255682Smarkm
27355682Smarkm	regnum = addr & 0xff;
27455682Smarkm	switch (regnum) {
27555682Smarkm	case IOAPIC_ID:
27655682Smarkm		return (vioapic->id);
27755682Smarkm		break;
27855682Smarkm	case IOAPIC_VER:
27955682Smarkm		return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11);
28055682Smarkm		break;
28155682Smarkm	case IOAPIC_ARB:
28255682Smarkm		return (vioapic->id);
28355682Smarkm		break;
28455682Smarkm	default:
28555682Smarkm		break;
28655682Smarkm	}
28755682Smarkm
28855682Smarkm	/* redirection table entries */
289233294Sstas	if (regnum >= IOAPIC_REDTBL &&
29055682Smarkm	    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
29155682Smarkm		pin = (regnum - IOAPIC_REDTBL) / 2;
29255682Smarkm		if ((regnum - IOAPIC_REDTBL) % 2)
29355682Smarkm			rshift = 32;
29455682Smarkm		else
29555682Smarkm			rshift = 0;
29655682Smarkm
29755682Smarkm		return (vioapic->rtbl[pin].reg >> rshift);
29855682Smarkm	}
29955682Smarkm
30055682Smarkm	return (0);
30155682Smarkm}
30255682Smarkm
30355682Smarkmstatic void
30455682Smarkmvioapic_write(struct vioapic *vioapic, int vcpuid, uint32_t addr, uint32_t data)
30555682Smarkm{
30655682Smarkm	uint64_t data64, mask64;
30755682Smarkm	uint64_t last, changed;
30855682Smarkm	int regnum, pin, lshift;
30955682Smarkm	cpuset_t allvcpus;
31055682Smarkm
31155682Smarkm	regnum = addr & 0xff;
31255682Smarkm	switch (regnum) {
31355682Smarkm	case IOAPIC_ID:
314233294Sstas		vioapic->id = data & APIC_ID_MASK;
31555682Smarkm		break;
31655682Smarkm	case IOAPIC_VER:
31755682Smarkm	case IOAPIC_ARB:
31855682Smarkm		/* readonly */
31955682Smarkm		break;
32055682Smarkm	default:
32155682Smarkm		break;
32255682Smarkm	}
32355682Smarkm
32455682Smarkm	/* redirection table entries */
32555682Smarkm	if (regnum >= IOAPIC_REDTBL &&
32655682Smarkm	    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
32755682Smarkm		pin = (regnum - IOAPIC_REDTBL) / 2;
32855682Smarkm		if ((regnum - IOAPIC_REDTBL) % 2)
32955682Smarkm			lshift = 32;
33055682Smarkm		else
33155682Smarkm			lshift = 0;
33255682Smarkm
33355682Smarkm		last = vioapic->rtbl[pin].reg;
33455682Smarkm
33555682Smarkm		data64 = (uint64_t)data << lshift;
33655682Smarkm		mask64 = (uint64_t)0xffffffff << lshift;
33755682Smarkm		vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS;
33855682Smarkm		vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS;
33955682Smarkm
34055682Smarkm		VIOAPIC_CTR2(vioapic, "ioapic pin%d: redir table entry %#lx",
34155682Smarkm		    pin, vioapic->rtbl[pin].reg);
34255682Smarkm
34355682Smarkm		/*
34455682Smarkm		 * If any fields in the redirection table entry (except mask
34555682Smarkm		 * or polarity) have changed then rendezvous all the vcpus
34655682Smarkm		 * to update their vlapic trigger-mode registers.
34755682Smarkm		 */
34855682Smarkm		changed = last ^ vioapic->rtbl[pin].reg;
34955682Smarkm		if (changed & ~(IOART_INTMASK | IOART_INTPOL)) {
35055682Smarkm			VIOAPIC_CTR1(vioapic, "ioapic pin%d: recalculate "
35155682Smarkm			    "vlapic trigger-mode register", pin);
35255682Smarkm			VIOAPIC_UNLOCK(vioapic);
35355682Smarkm			allvcpus = vm_active_cpus(vioapic->vm);
35455682Smarkm			vm_smp_rendezvous(vioapic->vm, vcpuid, allvcpus,
35555682Smarkm			    vioapic_update_tmr, NULL);
356233294Sstas			VIOAPIC_LOCK(vioapic);
35755682Smarkm		}
35855682Smarkm
35955682Smarkm		/*
36055682Smarkm		 * Generate an interrupt if the following conditions are met:
36155682Smarkm		 * - pin is not masked
36255682Smarkm		 * - previous interrupt has been EOIed
363233294Sstas		 * - pin level is asserted
364233294Sstas		 */
36555682Smarkm		if ((vioapic->rtbl[pin].reg & IOART_INTMASK) == IOART_INTMCLR &&
36655682Smarkm		    (vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0 &&
36755682Smarkm		    (vioapic->rtbl[pin].acnt > 0)) {
36855682Smarkm			VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at rtbl "
36955682Smarkm			    "write, acnt %d", pin, vioapic->rtbl[pin].acnt);
37055682Smarkm			vioapic_send_intr(vioapic, pin);
37155682Smarkm		}
37255682Smarkm	}
37355682Smarkm}
37455682Smarkm
37555682Smarkmstatic int
37655682Smarkmvioapic_mmio_rw(struct vioapic *vioapic, int vcpuid, uint64_t gpa,
37755682Smarkm    uint64_t *data, int size, bool doread)
37855682Smarkm{
37955682Smarkm	uint64_t offset;
38055682Smarkm
38155682Smarkm	offset = gpa - VIOAPIC_BASE;
38255682Smarkm
38355682Smarkm	/*
38455682Smarkm	 * The IOAPIC specification allows 32-bit wide accesses to the
38555682Smarkm	 * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
38655682Smarkm	 */
387233294Sstas	if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
38855682Smarkm		if (doread)
38955682Smarkm			*data = 0;
39055682Smarkm		return (0);
39155682Smarkm	}
39255682Smarkm
39355682Smarkm	VIOAPIC_LOCK(vioapic);
39455682Smarkm	if (offset == IOREGSEL) {
395233294Sstas		if (doread)
39655682Smarkm			*data = vioapic->ioregsel;
39755682Smarkm		else
39855682Smarkm			vioapic->ioregsel = *data;
39955682Smarkm	} else {
40055682Smarkm		if (doread) {
40155682Smarkm			*data = vioapic_read(vioapic, vcpuid,
40255682Smarkm			    vioapic->ioregsel);
40355682Smarkm		} else {
40455682Smarkm			vioapic_write(vioapic, vcpuid, vioapic->ioregsel,
40555682Smarkm			    *data);
40655682Smarkm		}
40755682Smarkm	}
40855682Smarkm	VIOAPIC_UNLOCK(vioapic);
40978527Sassar
41055682Smarkm	return (0);
41155682Smarkm}
41255682Smarkm
41355682Smarkmint
41455682Smarkmvioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval,
41555682Smarkm    int size, void *arg)
41655682Smarkm{
41755682Smarkm	int error;
41855682Smarkm	struct vioapic *vioapic;
41955682Smarkm
42055682Smarkm	vioapic = vm_ioapic(vm);
42155682Smarkm	error = vioapic_mmio_rw(vioapic, vcpuid, gpa, rval, size, true);
42255682Smarkm	return (error);
42378527Sassar}
42455682Smarkm
42555682Smarkmint
42655682Smarkmvioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval,
42755682Smarkm    int size, void *arg)
42855682Smarkm{
42955682Smarkm	int error;
43055682Smarkm	struct vioapic *vioapic;
43155682Smarkm
43255682Smarkm	vioapic = vm_ioapic(vm);
43355682Smarkm	error = vioapic_mmio_rw(vioapic, vcpuid, gpa, &wval, size, false);
43455682Smarkm	return (error);
43555682Smarkm}
43655682Smarkm
43755682Smarkmvoid
43855682Smarkmvioapic_process_eoi(struct vm *vm, int vcpuid, int vector)
43955682Smarkm{
44055682Smarkm	struct vioapic *vioapic;
44155682Smarkm	int pin;
44255682Smarkm
44355682Smarkm	KASSERT(vector >= 0 && vector < 256,
44455682Smarkm	    ("vioapic_process_eoi: invalid vector %d", vector));
44555682Smarkm
44655682Smarkm	vioapic = vm_ioapic(vm);
44755682Smarkm	VIOAPIC_CTR1(vioapic, "ioapic processing eoi for vector %d", vector);
44855682Smarkm
44955682Smarkm	/*
45055682Smarkm	 * XXX keep track of the pins associated with this vector instead
451233294Sstas	 * of iterating on every single pin each time.
45255682Smarkm	 */
45355682Smarkm	VIOAPIC_LOCK(vioapic);
45455682Smarkm	for (pin = 0; pin < REDIR_ENTRIES; pin++) {
45555682Smarkm		if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0)
45655682Smarkm			continue;
45755682Smarkm		if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector)
45855682Smarkm			continue;
45955682Smarkm		vioapic->rtbl[pin].reg &= ~IOART_REM_IRR;
46055682Smarkm		if (vioapic->rtbl[pin].acnt > 0) {
46155682Smarkm			VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at eoi, "
46255682Smarkm			    "acnt %d", pin, vioapic->rtbl[pin].acnt);
46355682Smarkm			vioapic_send_intr(vioapic, pin);
46455682Smarkm		}
46555682Smarkm	}
46655682Smarkm	VIOAPIC_UNLOCK(vioapic);
46778527Sassar}
46855682Smarkm
46955682Smarkmstruct vioapic *
47055682Smarkmvioapic_init(struct vm *vm)
471233294Sstas{
47255682Smarkm	int i;
47355682Smarkm	struct vioapic *vioapic;
47455682Smarkm
47555682Smarkm	vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
476233294Sstas
477233294Sstas	vioapic->vm = vm;
47855682Smarkm	mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_SPIN);
47955682Smarkm
48078527Sassar	/* Initialize all redirection entries to mask all interrupts */
481233294Sstas	for (i = 0; i < REDIR_ENTRIES; i++)
48255682Smarkm		vioapic->rtbl[i].reg = 0x0001000000010000UL;
48355682Smarkm
48455682Smarkm	return (vioapic);
48555682Smarkm}
48655682Smarkm
48755682Smarkmvoid
48855682Smarkmvioapic_cleanup(struct vioapic *vioapic)
48955682Smarkm{
49055682Smarkm
49155682Smarkm	free(vioapic, M_VIOAPIC);
49255682Smarkm}
49355682Smarkm
49478527Sassarint
49555682Smarkmvioapic_pincount(struct vm *vm)
49655682Smarkm{
49755682Smarkm
49855682Smarkm	return (REDIR_ENTRIES);
49955682Smarkm}
50055682Smarkm