1565bbb86SNeel Natu /*- 2565bbb86SNeel Natu * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3565bbb86SNeel Natu * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 4565bbb86SNeel Natu * All rights reserved. 5565bbb86SNeel Natu * 6565bbb86SNeel Natu * Redistribution and use in source and binary forms, with or without 7565bbb86SNeel Natu * modification, are permitted provided that the following conditions 8565bbb86SNeel Natu * are met: 9565bbb86SNeel Natu * 1. Redistributions of source code must retain the above copyright 10565bbb86SNeel Natu * notice, this list of conditions and the following disclaimer. 11565bbb86SNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 12565bbb86SNeel Natu * notice, this list of conditions and the following disclaimer in the 13565bbb86SNeel Natu * documentation and/or other materials provided with the distribution. 14565bbb86SNeel Natu * 15565bbb86SNeel Natu * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 16565bbb86SNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17565bbb86SNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18565bbb86SNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 19565bbb86SNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20565bbb86SNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21565bbb86SNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22565bbb86SNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23565bbb86SNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24565bbb86SNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25565bbb86SNeel Natu * SUCH DAMAGE. 26565bbb86SNeel Natu * 27565bbb86SNeel Natu * $FreeBSD$ 28565bbb86SNeel Natu */ 29565bbb86SNeel Natu 30565bbb86SNeel Natu #include <sys/cdefs.h> 31565bbb86SNeel Natu __FBSDID("$FreeBSD$"); 32565bbb86SNeel Natu 33565bbb86SNeel Natu #include <sys/param.h> 34565bbb86SNeel Natu #include <sys/queue.h> 35565bbb86SNeel Natu #include <sys/cpuset.h> 36565bbb86SNeel Natu #include <sys/lock.h> 37565bbb86SNeel Natu #include <sys/mutex.h> 38565bbb86SNeel Natu #include <sys/systm.h> 39565bbb86SNeel Natu #include <sys/kernel.h> 40565bbb86SNeel Natu #include <sys/malloc.h> 41565bbb86SNeel Natu 42565bbb86SNeel Natu #include <x86/apicreg.h> 43565bbb86SNeel Natu #include <machine/vmm.h> 44565bbb86SNeel Natu 45565bbb86SNeel Natu #include "vmm_ktr.h" 46565bbb86SNeel Natu #include "vmm_lapic.h" 474f8be175SNeel Natu #include "vlapic.h" 48565bbb86SNeel Natu #include "vioapic.h" 49565bbb86SNeel Natu 50565bbb86SNeel Natu #define IOREGSEL 0x00 51565bbb86SNeel Natu #define IOWIN 0x10 52565bbb86SNeel Natu 53b5b28fc9SNeel Natu #define REDIR_ENTRIES 24 54b5b28fc9SNeel Natu #define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS)) 55565bbb86SNeel Natu 56565bbb86SNeel Natu struct vioapic { 57565bbb86SNeel Natu struct vm *vm; 58565bbb86SNeel Natu struct mtx mtx; 59565bbb86SNeel Natu uint32_t id; 60565bbb86SNeel Natu uint32_t ioregsel; 61565bbb86SNeel Natu struct { 62565bbb86SNeel Natu uint64_t reg; 63b5b28fc9SNeel Natu int acnt; /* sum of pin asserts (+1) and deasserts (-1) */ 64565bbb86SNeel Natu } rtbl[REDIR_ENTRIES]; 65565bbb86SNeel Natu }; 66565bbb86SNeel Natu 67565bbb86SNeel Natu #define VIOAPIC_LOCK(vioapic) mtx_lock(&((vioapic)->mtx)) 68565bbb86SNeel Natu #define VIOAPIC_UNLOCK(vioapic) mtx_unlock(&((vioapic)->mtx)) 69565bbb86SNeel Natu #define VIOAPIC_LOCKED(vioapic) mtx_owned(&((vioapic)->mtx)) 70565bbb86SNeel Natu 71565bbb86SNeel Natu static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic"); 72565bbb86SNeel Natu 73565bbb86SNeel Natu #define VIOAPIC_CTR1(vioapic, fmt, a1) \ 74565bbb86SNeel Natu VM_CTR1((vioapic)->vm, fmt, a1) 75565bbb86SNeel Natu 76565bbb86SNeel Natu #define VIOAPIC_CTR2(vioapic, fmt, a1, a2) \ 77565bbb86SNeel Natu VM_CTR2((vioapic)->vm, fmt, a1, a2) 78565bbb86SNeel Natu 79565bbb86SNeel Natu #define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \ 80565bbb86SNeel Natu VM_CTR3((vioapic)->vm, fmt, a1, a2, a3) 81565bbb86SNeel Natu 82b5b28fc9SNeel Natu #define VIOAPIC_CTR4(vioapic, fmt, a1, a2, a3, a4) \ 83b5b28fc9SNeel Natu VM_CTR4((vioapic)->vm, fmt, a1, a2, a3, a4) 84b5b28fc9SNeel Natu 85565bbb86SNeel Natu #ifdef KTR 86565bbb86SNeel Natu static const char * 87565bbb86SNeel Natu pinstate_str(bool asserted) 88565bbb86SNeel Natu { 89565bbb86SNeel Natu 90565bbb86SNeel Natu if (asserted) 91565bbb86SNeel Natu return ("asserted"); 92565bbb86SNeel Natu else 93565bbb86SNeel Natu return ("deasserted"); 94565bbb86SNeel Natu } 95565bbb86SNeel Natu #endif 96565bbb86SNeel Natu 97565bbb86SNeel Natu static void 98b5b28fc9SNeel Natu vioapic_send_intr(struct vioapic *vioapic, int pin) 99565bbb86SNeel Natu { 1004f8be175SNeel Natu int vector, delmode; 1014f8be175SNeel Natu uint32_t low, high, dest; 1024f8be175SNeel Natu bool level, phys; 103565bbb86SNeel Natu 104565bbb86SNeel Natu KASSERT(pin >= 0 && pin < REDIR_ENTRIES, 105565bbb86SNeel Natu ("vioapic_set_pinstate: invalid pin number %d", pin)); 106565bbb86SNeel Natu 107565bbb86SNeel Natu KASSERT(VIOAPIC_LOCKED(vioapic), 108565bbb86SNeel Natu ("vioapic_set_pinstate: vioapic is not locked")); 109565bbb86SNeel Natu 110565bbb86SNeel Natu low = vioapic->rtbl[pin].reg; 111565bbb86SNeel Natu high = vioapic->rtbl[pin].reg >> 32; 112b5b28fc9SNeel Natu 113b5b28fc9SNeel Natu if ((low & IOART_INTMASK) == IOART_INTMSET) { 114b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: masked", pin); 115b5b28fc9SNeel Natu return; 116b5b28fc9SNeel Natu } 117b5b28fc9SNeel Natu 1184f8be175SNeel Natu phys = ((low & IOART_DESTMOD) == IOART_DESTPHY); 1194f8be175SNeel Natu delmode = low & IOART_DELMOD; 120b5b28fc9SNeel Natu level = low & IOART_TRGRLVL ? true : false; 121b5b28fc9SNeel Natu if (level) 122b5b28fc9SNeel Natu vioapic->rtbl[pin].reg |= IOART_REM_IRR; 123b5b28fc9SNeel Natu 124565bbb86SNeel Natu vector = low & IOART_INTVEC; 1254f8be175SNeel Natu dest = high >> APIC_ID_SHIFT; 1264f8be175SNeel Natu vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector); 127565bbb86SNeel Natu } 128b5b28fc9SNeel Natu 129b5b28fc9SNeel Natu static void 130b5b28fc9SNeel Natu vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate) 131b5b28fc9SNeel Natu { 132b5b28fc9SNeel Natu int oldcnt, newcnt; 133b5b28fc9SNeel Natu bool needintr; 134b5b28fc9SNeel Natu 135b5b28fc9SNeel Natu KASSERT(pin >= 0 && pin < REDIR_ENTRIES, 136b5b28fc9SNeel Natu ("vioapic_set_pinstate: invalid pin number %d", pin)); 137b5b28fc9SNeel Natu 138b5b28fc9SNeel Natu KASSERT(VIOAPIC_LOCKED(vioapic), 139b5b28fc9SNeel Natu ("vioapic_set_pinstate: vioapic is not locked")); 140b5b28fc9SNeel Natu 141b5b28fc9SNeel Natu oldcnt = vioapic->rtbl[pin].acnt; 142b5b28fc9SNeel Natu if (newstate) 143b5b28fc9SNeel Natu vioapic->rtbl[pin].acnt++; 144b5b28fc9SNeel Natu else 145b5b28fc9SNeel Natu vioapic->rtbl[pin].acnt--; 146b5b28fc9SNeel Natu newcnt = vioapic->rtbl[pin].acnt; 147b5b28fc9SNeel Natu 148b5b28fc9SNeel Natu if (newcnt < 0) { 149b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: bad acnt %d", 150b5b28fc9SNeel Natu pin, newcnt); 151b5b28fc9SNeel Natu } 152b5b28fc9SNeel Natu 153b5b28fc9SNeel Natu needintr = false; 154b5b28fc9SNeel Natu if (oldcnt == 0 && newcnt == 1) { 155b5b28fc9SNeel Natu needintr = true; 156b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: asserted", pin); 157b5b28fc9SNeel Natu } else if (oldcnt == 1 && newcnt == 0) { 158b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: deasserted", pin); 159b5b28fc9SNeel Natu } else { 160b5b28fc9SNeel Natu VIOAPIC_CTR3(vioapic, "ioapic pin%d: %s, ignored, acnt %d", 161b5b28fc9SNeel Natu pin, pinstate_str(newstate), newcnt); 162b5b28fc9SNeel Natu } 163b5b28fc9SNeel Natu 164b5b28fc9SNeel Natu if (needintr) 165b5b28fc9SNeel Natu vioapic_send_intr(vioapic, pin); 166565bbb86SNeel Natu } 167565bbb86SNeel Natu 168ac7304a7SNeel Natu enum irqstate { 169ac7304a7SNeel Natu IRQSTATE_ASSERT, 170ac7304a7SNeel Natu IRQSTATE_DEASSERT, 171ac7304a7SNeel Natu IRQSTATE_PULSE 172ac7304a7SNeel Natu }; 173ac7304a7SNeel Natu 174565bbb86SNeel Natu static int 175ac7304a7SNeel Natu vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate) 176565bbb86SNeel Natu { 177565bbb86SNeel Natu struct vioapic *vioapic; 178565bbb86SNeel Natu 179565bbb86SNeel Natu if (irq < 0 || irq >= REDIR_ENTRIES) 180565bbb86SNeel Natu return (EINVAL); 181565bbb86SNeel Natu 182565bbb86SNeel Natu vioapic = vm_ioapic(vm); 183565bbb86SNeel Natu 184565bbb86SNeel Natu VIOAPIC_LOCK(vioapic); 185ac7304a7SNeel Natu switch (irqstate) { 186ac7304a7SNeel Natu case IRQSTATE_ASSERT: 187ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, true); 188ac7304a7SNeel Natu break; 189ac7304a7SNeel Natu case IRQSTATE_DEASSERT: 190ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, false); 191ac7304a7SNeel Natu break; 192ac7304a7SNeel Natu case IRQSTATE_PULSE: 193ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, true); 194ac7304a7SNeel Natu vioapic_set_pinstate(vioapic, irq, false); 195ac7304a7SNeel Natu break; 196ac7304a7SNeel Natu default: 197ac7304a7SNeel Natu panic("vioapic_set_irqstate: invalid irqstate %d", irqstate); 198ac7304a7SNeel Natu } 199565bbb86SNeel Natu VIOAPIC_UNLOCK(vioapic); 200565bbb86SNeel Natu 201565bbb86SNeel Natu return (0); 202565bbb86SNeel Natu } 203565bbb86SNeel Natu 204565bbb86SNeel Natu int 205565bbb86SNeel Natu vioapic_assert_irq(struct vm *vm, int irq) 206565bbb86SNeel Natu { 207565bbb86SNeel Natu 208ac7304a7SNeel Natu return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT)); 209565bbb86SNeel Natu } 210565bbb86SNeel Natu 211565bbb86SNeel Natu int 212565bbb86SNeel Natu vioapic_deassert_irq(struct vm *vm, int irq) 213565bbb86SNeel Natu { 214565bbb86SNeel Natu 215ac7304a7SNeel Natu return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT)); 216ac7304a7SNeel Natu } 217ac7304a7SNeel Natu 218ac7304a7SNeel Natu int 219ac7304a7SNeel Natu vioapic_pulse_irq(struct vm *vm, int irq) 220ac7304a7SNeel Natu { 221ac7304a7SNeel Natu 222ac7304a7SNeel Natu return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE)); 223565bbb86SNeel Natu } 224565bbb86SNeel Natu 225*5b8a8cd1SNeel Natu /* 226*5b8a8cd1SNeel Natu * Reset the vlapic's trigger-mode register to reflect the ioapic pin 227*5b8a8cd1SNeel Natu * configuration. 228*5b8a8cd1SNeel Natu */ 229*5b8a8cd1SNeel Natu static void 230*5b8a8cd1SNeel Natu vioapic_update_tmr(struct vm *vm, int vcpuid, void *arg) 231*5b8a8cd1SNeel Natu { 232*5b8a8cd1SNeel Natu struct vioapic *vioapic; 233*5b8a8cd1SNeel Natu struct vlapic *vlapic; 234*5b8a8cd1SNeel Natu uint32_t low, high, dest; 235*5b8a8cd1SNeel Natu int delmode, pin, vector; 236*5b8a8cd1SNeel Natu bool level, phys; 237*5b8a8cd1SNeel Natu 238*5b8a8cd1SNeel Natu vlapic = vm_lapic(vm, vcpuid); 239*5b8a8cd1SNeel Natu vioapic = vm_ioapic(vm); 240*5b8a8cd1SNeel Natu 241*5b8a8cd1SNeel Natu VIOAPIC_LOCK(vioapic); 242*5b8a8cd1SNeel Natu /* 243*5b8a8cd1SNeel Natu * Reset all vectors to be edge-triggered. 244*5b8a8cd1SNeel Natu */ 245*5b8a8cd1SNeel Natu vlapic_reset_tmr(vlapic); 246*5b8a8cd1SNeel Natu for (pin = 0; pin < REDIR_ENTRIES; pin++) { 247*5b8a8cd1SNeel Natu low = vioapic->rtbl[pin].reg; 248*5b8a8cd1SNeel Natu high = vioapic->rtbl[pin].reg >> 32; 249*5b8a8cd1SNeel Natu 250*5b8a8cd1SNeel Natu level = low & IOART_TRGRLVL ? true : false; 251*5b8a8cd1SNeel Natu if (!level) 252*5b8a8cd1SNeel Natu continue; 253*5b8a8cd1SNeel Natu 254*5b8a8cd1SNeel Natu /* 255*5b8a8cd1SNeel Natu * For a level-triggered 'pin' let the vlapic figure out if 256*5b8a8cd1SNeel Natu * an assertion on this 'pin' would result in an interrupt 257*5b8a8cd1SNeel Natu * being delivered to it. If yes, then it will modify the 258*5b8a8cd1SNeel Natu * TMR bit associated with this vector to level-triggered. 259*5b8a8cd1SNeel Natu */ 260*5b8a8cd1SNeel Natu phys = ((low & IOART_DESTMOD) == IOART_DESTPHY); 261*5b8a8cd1SNeel Natu delmode = low & IOART_DELMOD; 262*5b8a8cd1SNeel Natu vector = low & IOART_INTVEC; 263*5b8a8cd1SNeel Natu dest = high >> APIC_ID_SHIFT; 264*5b8a8cd1SNeel Natu vlapic_set_tmr_level(vlapic, dest, phys, delmode, vector); 265*5b8a8cd1SNeel Natu } 266*5b8a8cd1SNeel Natu VIOAPIC_UNLOCK(vioapic); 267*5b8a8cd1SNeel Natu } 268*5b8a8cd1SNeel Natu 269565bbb86SNeel Natu static uint32_t 270*5b8a8cd1SNeel Natu vioapic_read(struct vioapic *vioapic, int vcpuid, uint32_t addr) 271565bbb86SNeel Natu { 272565bbb86SNeel Natu int regnum, pin, rshift; 273565bbb86SNeel Natu 274565bbb86SNeel Natu regnum = addr & 0xff; 275565bbb86SNeel Natu switch (regnum) { 276565bbb86SNeel Natu case IOAPIC_ID: 277565bbb86SNeel Natu return (vioapic->id); 278565bbb86SNeel Natu break; 279565bbb86SNeel Natu case IOAPIC_VER: 280b5b28fc9SNeel Natu return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11); 281565bbb86SNeel Natu break; 282565bbb86SNeel Natu case IOAPIC_ARB: 283565bbb86SNeel Natu return (vioapic->id); 284565bbb86SNeel Natu break; 285565bbb86SNeel Natu default: 286565bbb86SNeel Natu break; 287565bbb86SNeel Natu } 288565bbb86SNeel Natu 289565bbb86SNeel Natu /* redirection table entries */ 290565bbb86SNeel Natu if (regnum >= IOAPIC_REDTBL && 291565bbb86SNeel Natu regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 292565bbb86SNeel Natu pin = (regnum - IOAPIC_REDTBL) / 2; 293565bbb86SNeel Natu if ((regnum - IOAPIC_REDTBL) % 2) 294565bbb86SNeel Natu rshift = 32; 295565bbb86SNeel Natu else 296565bbb86SNeel Natu rshift = 0; 297565bbb86SNeel Natu 298565bbb86SNeel Natu return (vioapic->rtbl[pin].reg >> rshift); 299565bbb86SNeel Natu } 300565bbb86SNeel Natu 301565bbb86SNeel Natu return (0); 302565bbb86SNeel Natu } 303565bbb86SNeel Natu 304565bbb86SNeel Natu static void 305*5b8a8cd1SNeel Natu vioapic_write(struct vioapic *vioapic, int vcpuid, uint32_t addr, uint32_t data) 306565bbb86SNeel Natu { 307b5b28fc9SNeel Natu uint64_t data64, mask64; 308*5b8a8cd1SNeel Natu uint64_t last, changed; 309565bbb86SNeel Natu int regnum, pin, lshift; 310*5b8a8cd1SNeel Natu cpuset_t allvcpus; 311565bbb86SNeel Natu 312565bbb86SNeel Natu regnum = addr & 0xff; 313565bbb86SNeel Natu switch (regnum) { 314565bbb86SNeel Natu case IOAPIC_ID: 315565bbb86SNeel Natu vioapic->id = data & APIC_ID_MASK; 316565bbb86SNeel Natu break; 317565bbb86SNeel Natu case IOAPIC_VER: 318565bbb86SNeel Natu case IOAPIC_ARB: 319565bbb86SNeel Natu /* readonly */ 320565bbb86SNeel Natu break; 321565bbb86SNeel Natu default: 322565bbb86SNeel Natu break; 323565bbb86SNeel Natu } 324565bbb86SNeel Natu 325565bbb86SNeel Natu /* redirection table entries */ 326565bbb86SNeel Natu if (regnum >= IOAPIC_REDTBL && 327565bbb86SNeel Natu regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 328565bbb86SNeel Natu pin = (regnum - IOAPIC_REDTBL) / 2; 329565bbb86SNeel Natu if ((regnum - IOAPIC_REDTBL) % 2) 330565bbb86SNeel Natu lshift = 32; 331565bbb86SNeel Natu else 332565bbb86SNeel Natu lshift = 0; 333565bbb86SNeel Natu 334*5b8a8cd1SNeel Natu last = vioapic->rtbl[pin].reg; 335*5b8a8cd1SNeel Natu 336b5b28fc9SNeel Natu data64 = (uint64_t)data << lshift; 337b5b28fc9SNeel Natu mask64 = (uint64_t)0xffffffff << lshift; 338b5b28fc9SNeel Natu vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS; 339b5b28fc9SNeel Natu vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS; 340565bbb86SNeel Natu 341b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: redir table entry %#lx", 342565bbb86SNeel Natu pin, vioapic->rtbl[pin].reg); 343565bbb86SNeel Natu 344565bbb86SNeel Natu /* 345*5b8a8cd1SNeel Natu * If any fields in the redirection table entry (except mask 346*5b8a8cd1SNeel Natu * or polarity) have changed then rendezvous all the vcpus 347*5b8a8cd1SNeel Natu * to update their vlapic trigger-mode registers. 348*5b8a8cd1SNeel Natu */ 349*5b8a8cd1SNeel Natu changed = last ^ vioapic->rtbl[pin].reg; 350*5b8a8cd1SNeel Natu if (changed & ~(IOART_INTMASK | IOART_INTPOL)) { 351*5b8a8cd1SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic pin%d: recalculate " 352*5b8a8cd1SNeel Natu "vlapic trigger-mode register", pin); 353*5b8a8cd1SNeel Natu VIOAPIC_UNLOCK(vioapic); 354*5b8a8cd1SNeel Natu allvcpus = vm_active_cpus(vioapic->vm); 355*5b8a8cd1SNeel Natu vm_smp_rendezvous(vioapic->vm, vcpuid, allvcpus, 356*5b8a8cd1SNeel Natu vioapic_update_tmr, NULL); 357*5b8a8cd1SNeel Natu VIOAPIC_LOCK(vioapic); 358*5b8a8cd1SNeel Natu } 359*5b8a8cd1SNeel Natu 360*5b8a8cd1SNeel Natu /* 361b5b28fc9SNeel Natu * Generate an interrupt if the following conditions are met: 362b5b28fc9SNeel Natu * - pin is not masked 363b5b28fc9SNeel Natu * - previous interrupt has been EOIed 364b5b28fc9SNeel Natu * - pin level is asserted 365565bbb86SNeel Natu */ 366b5b28fc9SNeel Natu if ((vioapic->rtbl[pin].reg & IOART_INTMASK) == IOART_INTMCLR && 367b5b28fc9SNeel Natu (vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0 && 368b5b28fc9SNeel Natu (vioapic->rtbl[pin].acnt > 0)) { 369b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at rtbl " 370b5b28fc9SNeel Natu "write, acnt %d", pin, vioapic->rtbl[pin].acnt); 371b5b28fc9SNeel Natu vioapic_send_intr(vioapic, pin); 372565bbb86SNeel Natu } 373565bbb86SNeel Natu } 374565bbb86SNeel Natu } 375565bbb86SNeel Natu 376565bbb86SNeel Natu static int 377*5b8a8cd1SNeel Natu vioapic_mmio_rw(struct vioapic *vioapic, int vcpuid, uint64_t gpa, 378*5b8a8cd1SNeel Natu uint64_t *data, int size, bool doread) 379565bbb86SNeel Natu { 380565bbb86SNeel Natu uint64_t offset; 381565bbb86SNeel Natu 382565bbb86SNeel Natu offset = gpa - VIOAPIC_BASE; 383565bbb86SNeel Natu 384565bbb86SNeel Natu /* 385565bbb86SNeel Natu * The IOAPIC specification allows 32-bit wide accesses to the 386565bbb86SNeel Natu * IOREGSEL (offset 0) and IOWIN (offset 16) registers. 387565bbb86SNeel Natu */ 388565bbb86SNeel Natu if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) { 389565bbb86SNeel Natu if (doread) 390565bbb86SNeel Natu *data = 0; 391565bbb86SNeel Natu return (0); 392565bbb86SNeel Natu } 393565bbb86SNeel Natu 394565bbb86SNeel Natu VIOAPIC_LOCK(vioapic); 395565bbb86SNeel Natu if (offset == IOREGSEL) { 396565bbb86SNeel Natu if (doread) 397565bbb86SNeel Natu *data = vioapic->ioregsel; 398565bbb86SNeel Natu else 399565bbb86SNeel Natu vioapic->ioregsel = *data; 400565bbb86SNeel Natu } else { 401*5b8a8cd1SNeel Natu if (doread) { 402*5b8a8cd1SNeel Natu *data = vioapic_read(vioapic, vcpuid, 403*5b8a8cd1SNeel Natu vioapic->ioregsel); 404*5b8a8cd1SNeel Natu } else { 405*5b8a8cd1SNeel Natu vioapic_write(vioapic, vcpuid, vioapic->ioregsel, 406*5b8a8cd1SNeel Natu *data); 407*5b8a8cd1SNeel Natu } 408565bbb86SNeel Natu } 409565bbb86SNeel Natu VIOAPIC_UNLOCK(vioapic); 410565bbb86SNeel Natu 411565bbb86SNeel Natu return (0); 412565bbb86SNeel Natu } 413565bbb86SNeel Natu 414565bbb86SNeel Natu int 415565bbb86SNeel Natu vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval, 416565bbb86SNeel Natu int size, void *arg) 417565bbb86SNeel Natu { 418565bbb86SNeel Natu int error; 419565bbb86SNeel Natu struct vioapic *vioapic; 420565bbb86SNeel Natu 421565bbb86SNeel Natu vioapic = vm_ioapic(vm); 422*5b8a8cd1SNeel Natu error = vioapic_mmio_rw(vioapic, vcpuid, gpa, rval, size, true); 423565bbb86SNeel Natu return (error); 424565bbb86SNeel Natu } 425565bbb86SNeel Natu 426565bbb86SNeel Natu int 427565bbb86SNeel Natu vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval, 428565bbb86SNeel Natu int size, void *arg) 429565bbb86SNeel Natu { 430565bbb86SNeel Natu int error; 431565bbb86SNeel Natu struct vioapic *vioapic; 432565bbb86SNeel Natu 433565bbb86SNeel Natu vioapic = vm_ioapic(vm); 434*5b8a8cd1SNeel Natu error = vioapic_mmio_rw(vioapic, vcpuid, gpa, &wval, size, false); 435565bbb86SNeel Natu return (error); 436565bbb86SNeel Natu } 437565bbb86SNeel Natu 438b5b28fc9SNeel Natu void 439b5b28fc9SNeel Natu vioapic_process_eoi(struct vm *vm, int vcpuid, int vector) 440b5b28fc9SNeel Natu { 441b5b28fc9SNeel Natu struct vioapic *vioapic; 442b5b28fc9SNeel Natu int pin; 443b5b28fc9SNeel Natu 444b5b28fc9SNeel Natu KASSERT(vector >= 0 && vector < 256, 445b5b28fc9SNeel Natu ("vioapic_process_eoi: invalid vector %d", vector)); 446b5b28fc9SNeel Natu 447b5b28fc9SNeel Natu vioapic = vm_ioapic(vm); 448b5b28fc9SNeel Natu VIOAPIC_CTR1(vioapic, "ioapic processing eoi for vector %d", vector); 449b5b28fc9SNeel Natu 450b5b28fc9SNeel Natu /* 451b5b28fc9SNeel Natu * XXX keep track of the pins associated with this vector instead 452b5b28fc9SNeel Natu * of iterating on every single pin each time. 453b5b28fc9SNeel Natu */ 454b5b28fc9SNeel Natu VIOAPIC_LOCK(vioapic); 455b5b28fc9SNeel Natu for (pin = 0; pin < REDIR_ENTRIES; pin++) { 456b5b28fc9SNeel Natu if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0) 457b5b28fc9SNeel Natu continue; 458b5b28fc9SNeel Natu if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector) 459b5b28fc9SNeel Natu continue; 460b5b28fc9SNeel Natu vioapic->rtbl[pin].reg &= ~IOART_REM_IRR; 461b5b28fc9SNeel Natu if (vioapic->rtbl[pin].acnt > 0) { 462b5b28fc9SNeel Natu VIOAPIC_CTR2(vioapic, "ioapic pin%d: asserted at eoi, " 463b5b28fc9SNeel Natu "acnt %d", pin, vioapic->rtbl[pin].acnt); 464b5b28fc9SNeel Natu vioapic_send_intr(vioapic, pin); 465b5b28fc9SNeel Natu } 466b5b28fc9SNeel Natu } 467b5b28fc9SNeel Natu VIOAPIC_UNLOCK(vioapic); 468b5b28fc9SNeel Natu } 469b5b28fc9SNeel Natu 470565bbb86SNeel Natu struct vioapic * 471565bbb86SNeel Natu vioapic_init(struct vm *vm) 472565bbb86SNeel Natu { 473565bbb86SNeel Natu int i; 474565bbb86SNeel Natu struct vioapic *vioapic; 475565bbb86SNeel Natu 476565bbb86SNeel Natu vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO); 477565bbb86SNeel Natu 478565bbb86SNeel Natu vioapic->vm = vm; 479565bbb86SNeel Natu mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF); 480565bbb86SNeel Natu 481565bbb86SNeel Natu /* Initialize all redirection entries to mask all interrupts */ 482565bbb86SNeel Natu for (i = 0; i < REDIR_ENTRIES; i++) 483565bbb86SNeel Natu vioapic->rtbl[i].reg = 0x0001000000010000UL; 484565bbb86SNeel Natu 485565bbb86SNeel Natu return (vioapic); 486565bbb86SNeel Natu } 487565bbb86SNeel Natu 488565bbb86SNeel Natu void 489565bbb86SNeel Natu vioapic_cleanup(struct vioapic *vioapic) 490565bbb86SNeel Natu { 491565bbb86SNeel Natu 492565bbb86SNeel Natu free(vioapic, M_VIOAPIC); 493565bbb86SNeel Natu } 494b5b28fc9SNeel Natu 495b5b28fc9SNeel Natu int 496b5b28fc9SNeel Natu vioapic_pincount(struct vm *vm) 497b5b28fc9SNeel Natu { 498b5b28fc9SNeel Natu 499b5b28fc9SNeel Natu return (REDIR_ENTRIES); 500b5b28fc9SNeel Natu } 501