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