17c8c0b82SPatrick Mooney /*- 27c8c0b82SPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 37c8c0b82SPatrick Mooney * 47c8c0b82SPatrick Mooney * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 57c8c0b82SPatrick Mooney * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 67c8c0b82SPatrick Mooney * All rights reserved. 77c8c0b82SPatrick Mooney * 87c8c0b82SPatrick Mooney * Redistribution and use in source and binary forms, with or without 97c8c0b82SPatrick Mooney * modification, are permitted provided that the following conditions 107c8c0b82SPatrick Mooney * are met: 117c8c0b82SPatrick Mooney * 1. Redistributions of source code must retain the above copyright 127c8c0b82SPatrick Mooney * notice, this list of conditions and the following disclaimer. 137c8c0b82SPatrick Mooney * 2. Redistributions in binary form must reproduce the above copyright 147c8c0b82SPatrick Mooney * notice, this list of conditions and the following disclaimer in the 157c8c0b82SPatrick Mooney * documentation and/or other materials provided with the distribution. 167c8c0b82SPatrick Mooney * 177c8c0b82SPatrick Mooney * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 187c8c0b82SPatrick Mooney * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 197c8c0b82SPatrick Mooney * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 207c8c0b82SPatrick Mooney * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 217c8c0b82SPatrick Mooney * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 227c8c0b82SPatrick Mooney * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 237c8c0b82SPatrick Mooney * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 247c8c0b82SPatrick Mooney * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 257c8c0b82SPatrick Mooney * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 267c8c0b82SPatrick Mooney * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 277c8c0b82SPatrick Mooney * SUCH DAMAGE. 287c8c0b82SPatrick Mooney * 297c8c0b82SPatrick Mooney * $FreeBSD$ 307c8c0b82SPatrick Mooney */ 317c8c0b82SPatrick Mooney /* 327c8c0b82SPatrick Mooney * This file and its contents are supplied under the terms of the 337c8c0b82SPatrick Mooney * Common Development and Distribution License ("CDDL"), version 1.0. 347c8c0b82SPatrick Mooney * You may only use this file in accordance with the terms of version 357c8c0b82SPatrick Mooney * 1.0 of the CDDL. 367c8c0b82SPatrick Mooney * 377c8c0b82SPatrick Mooney * A full copy of the text of the CDDL should have accompanied this 387c8c0b82SPatrick Mooney * source. A copy of the CDDL is also available via the Internet at 397c8c0b82SPatrick Mooney * http://www.illumos.org/license/CDDL. 407c8c0b82SPatrick Mooney * 417c8c0b82SPatrick Mooney * Copyright 2014 Pluribus Networks Inc. 427c8c0b82SPatrick Mooney * Copyright 2017 Joyent, Inc. 437c8c0b82SPatrick Mooney * Copyright 2021 Oxide Computer Company 447c8c0b82SPatrick Mooney */ 457c8c0b82SPatrick Mooney 467c8c0b82SPatrick Mooney #include <sys/cdefs.h> 477c8c0b82SPatrick Mooney __FBSDID("$FreeBSD$"); 487c8c0b82SPatrick Mooney 497c8c0b82SPatrick Mooney #include <sys/param.h> 507c8c0b82SPatrick Mooney #include <sys/queue.h> 517c8c0b82SPatrick Mooney #include <sys/mutex.h> 527c8c0b82SPatrick Mooney #include <sys/systm.h> 537c8c0b82SPatrick Mooney #include <sys/kernel.h> 54*8130f8e1SPatrick Mooney #include <sys/kmem.h> 557c8c0b82SPatrick Mooney #include <sys/cpuset.h> 567c8c0b82SPatrick Mooney 577c8c0b82SPatrick Mooney #include <x86/apicreg.h> 587c8c0b82SPatrick Mooney #include <machine/vmm.h> 597c8c0b82SPatrick Mooney 607c8c0b82SPatrick Mooney #include "vmm_lapic.h" 617c8c0b82SPatrick Mooney #include "vlapic.h" 627c8c0b82SPatrick Mooney #include "vioapic.h" 637c8c0b82SPatrick Mooney 647c8c0b82SPatrick Mooney #define IOREGSEL 0x00 657c8c0b82SPatrick Mooney #define IOWIN 0x10 667c8c0b82SPatrick Mooney 677c8c0b82SPatrick Mooney #define REDIR_ENTRIES 32 687c8c0b82SPatrick Mooney #define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS)) 697c8c0b82SPatrick Mooney 707c8c0b82SPatrick Mooney struct ioapic_stats { 717c8c0b82SPatrick Mooney uint64_t is_interrupts; 727c8c0b82SPatrick Mooney uint64_t is_saturate_low; 737c8c0b82SPatrick Mooney uint64_t is_saturate_high; 747c8c0b82SPatrick Mooney }; 757c8c0b82SPatrick Mooney 767c8c0b82SPatrick Mooney struct vioapic { 777c8c0b82SPatrick Mooney struct vm *vm; 787c8c0b82SPatrick Mooney kmutex_t lock; 797c8c0b82SPatrick Mooney uint32_t id; 807c8c0b82SPatrick Mooney uint32_t ioregsel; 817c8c0b82SPatrick Mooney struct { 827c8c0b82SPatrick Mooney uint64_t reg; 837c8c0b82SPatrick Mooney /* 847c8c0b82SPatrick Mooney * The sum of pin asserts (+1) and deasserts (-1) are tracked in 857c8c0b82SPatrick Mooney * 'acnt'. It is clamped to prevent overflow or underflow 867c8c0b82SPatrick Mooney * should emulation consumers feed it an invalid set of 877c8c0b82SPatrick Mooney * transitions. 887c8c0b82SPatrick Mooney */ 897c8c0b82SPatrick Mooney uint_t acnt; 907c8c0b82SPatrick Mooney } rtbl[REDIR_ENTRIES]; 917c8c0b82SPatrick Mooney struct ioapic_stats stats; 927c8c0b82SPatrick Mooney }; 937c8c0b82SPatrick Mooney 947c8c0b82SPatrick Mooney #define VIOAPIC_LOCK(vioapic) mutex_enter(&((vioapic)->lock)) 957c8c0b82SPatrick Mooney #define VIOAPIC_UNLOCK(vioapic) mutex_exit(&((vioapic)->lock)) 967c8c0b82SPatrick Mooney #define VIOAPIC_LOCKED(vioapic) MUTEX_HELD(&((vioapic)->lock)) 977c8c0b82SPatrick Mooney 987c8c0b82SPatrick Mooney 997c8c0b82SPatrick Mooney static void 1007c8c0b82SPatrick Mooney vioapic_send_intr(struct vioapic *vioapic, int pin) 1017c8c0b82SPatrick Mooney { 1027c8c0b82SPatrick Mooney int vector, delmode; 1037c8c0b82SPatrick Mooney uint32_t low, high, dest; 1047c8c0b82SPatrick Mooney bool level, phys; 1057c8c0b82SPatrick Mooney 1067c8c0b82SPatrick Mooney VERIFY(pin >= 0 && pin < REDIR_ENTRIES); 1077c8c0b82SPatrick Mooney ASSERT(VIOAPIC_LOCKED(vioapic)); 1087c8c0b82SPatrick Mooney 1097c8c0b82SPatrick Mooney low = vioapic->rtbl[pin].reg; 1107c8c0b82SPatrick Mooney high = vioapic->rtbl[pin].reg >> 32; 1117c8c0b82SPatrick Mooney 1127c8c0b82SPatrick Mooney if ((low & IOART_INTMASK) == IOART_INTMSET) { 113d4f59ae5SPatrick Mooney /* Pin is masked */ 1147c8c0b82SPatrick Mooney return; 1157c8c0b82SPatrick Mooney } 1167c8c0b82SPatrick Mooney 1177c8c0b82SPatrick Mooney phys = ((low & IOART_DESTMOD) == IOART_DESTPHY); 1187c8c0b82SPatrick Mooney delmode = low & IOART_DELMOD; 1197c8c0b82SPatrick Mooney level = low & IOART_TRGRLVL ? true : false; 1207c8c0b82SPatrick Mooney if (level) { 1217c8c0b82SPatrick Mooney if ((low & IOART_REM_IRR) != 0) { 122d4f59ae5SPatrick Mooney /* IRR already pending */ 1237c8c0b82SPatrick Mooney return; 1247c8c0b82SPatrick Mooney } 1257c8c0b82SPatrick Mooney vioapic->rtbl[pin].reg |= IOART_REM_IRR; 1267c8c0b82SPatrick Mooney } 1277c8c0b82SPatrick Mooney 1287c8c0b82SPatrick Mooney vector = low & IOART_INTVEC; 1297c8c0b82SPatrick Mooney dest = high >> APIC_ID_SHIFT; 1307c8c0b82SPatrick Mooney vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector); 1317c8c0b82SPatrick Mooney vioapic->stats.is_interrupts++; 1327c8c0b82SPatrick Mooney } 1337c8c0b82SPatrick Mooney 1347c8c0b82SPatrick Mooney static int 1357c8c0b82SPatrick Mooney vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate) 1367c8c0b82SPatrick Mooney { 1377c8c0b82SPatrick Mooney uint_t oldcnt, newcnt; 1387c8c0b82SPatrick Mooney bool needintr = false; 1397c8c0b82SPatrick Mooney int err = 0; 1407c8c0b82SPatrick Mooney 1417c8c0b82SPatrick Mooney VERIFY(pin >= 0 && pin < REDIR_ENTRIES); 1427c8c0b82SPatrick Mooney ASSERT(VIOAPIC_LOCKED(vioapic)); 1437c8c0b82SPatrick Mooney 1447c8c0b82SPatrick Mooney oldcnt = newcnt = vioapic->rtbl[pin].acnt; 1457c8c0b82SPatrick Mooney if (newstate) { 1467c8c0b82SPatrick Mooney if (newcnt != UINT_MAX) { 1477c8c0b82SPatrick Mooney newcnt++; 1487c8c0b82SPatrick Mooney } else { 1497c8c0b82SPatrick Mooney err = E2BIG; 1507c8c0b82SPatrick Mooney DTRACE_PROBE2(vioapic__sat_high, 1517c8c0b82SPatrick Mooney struct vioapic *, vioapic, int, pin); 1527c8c0b82SPatrick Mooney vioapic->stats.is_saturate_high++; 1537c8c0b82SPatrick Mooney } 1547c8c0b82SPatrick Mooney } else { 1557c8c0b82SPatrick Mooney if (newcnt != 0) { 1567c8c0b82SPatrick Mooney newcnt--; 1577c8c0b82SPatrick Mooney } else { 1587c8c0b82SPatrick Mooney err = ERANGE; 1597c8c0b82SPatrick Mooney DTRACE_PROBE2(vioapic__sat_low, 1607c8c0b82SPatrick Mooney struct vioapic *, vioapic, int, pin); 1617c8c0b82SPatrick Mooney vioapic->stats.is_saturate_low++; 1627c8c0b82SPatrick Mooney } 1637c8c0b82SPatrick Mooney } 1647c8c0b82SPatrick Mooney vioapic->rtbl[pin].acnt = newcnt; 1657c8c0b82SPatrick Mooney 1667c8c0b82SPatrick Mooney if (oldcnt == 0 && newcnt == 1) { 1677c8c0b82SPatrick Mooney needintr = true; 1687c8c0b82SPatrick Mooney DTRACE_PROBE2(vioapic__assert, struct vioapic *, vioapic, 1697c8c0b82SPatrick Mooney int, pin); 1707c8c0b82SPatrick Mooney } else if (oldcnt == 1 && newcnt == 0) { 1717c8c0b82SPatrick Mooney DTRACE_PROBE2(vioapic__deassert, struct vioapic *, vioapic, 1727c8c0b82SPatrick Mooney int, pin); 1737c8c0b82SPatrick Mooney } 1747c8c0b82SPatrick Mooney 1757c8c0b82SPatrick Mooney if (needintr) { 1767c8c0b82SPatrick Mooney vioapic_send_intr(vioapic, pin); 1777c8c0b82SPatrick Mooney } 1787c8c0b82SPatrick Mooney return (err); 1797c8c0b82SPatrick Mooney } 1807c8c0b82SPatrick Mooney 1817c8c0b82SPatrick Mooney enum irqstate { 1827c8c0b82SPatrick Mooney IRQSTATE_ASSERT, 1837c8c0b82SPatrick Mooney IRQSTATE_DEASSERT, 1847c8c0b82SPatrick Mooney IRQSTATE_PULSE 1857c8c0b82SPatrick Mooney }; 1867c8c0b82SPatrick Mooney 1877c8c0b82SPatrick Mooney static int 1887c8c0b82SPatrick Mooney vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate) 1897c8c0b82SPatrick Mooney { 1907c8c0b82SPatrick Mooney struct vioapic *vioapic; 1917c8c0b82SPatrick Mooney int err = 0; 1927c8c0b82SPatrick Mooney 1937c8c0b82SPatrick Mooney if (irq < 0 || irq >= REDIR_ENTRIES) 1947c8c0b82SPatrick Mooney return (EINVAL); 1957c8c0b82SPatrick Mooney 1967c8c0b82SPatrick Mooney vioapic = vm_ioapic(vm); 1977c8c0b82SPatrick Mooney 1987c8c0b82SPatrick Mooney VIOAPIC_LOCK(vioapic); 1997c8c0b82SPatrick Mooney switch (irqstate) { 2007c8c0b82SPatrick Mooney case IRQSTATE_ASSERT: 2017c8c0b82SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, true); 2027c8c0b82SPatrick Mooney break; 2037c8c0b82SPatrick Mooney case IRQSTATE_DEASSERT: 2047c8c0b82SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, false); 2057c8c0b82SPatrick Mooney break; 2067c8c0b82SPatrick Mooney case IRQSTATE_PULSE: 2077c8c0b82SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, true); 2087c8c0b82SPatrick Mooney if (err == 0) { 2097c8c0b82SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, false); 2107c8c0b82SPatrick Mooney } 2117c8c0b82SPatrick Mooney break; 2127c8c0b82SPatrick Mooney default: 2137c8c0b82SPatrick Mooney panic("vioapic_set_irqstate: invalid irqstate %d", irqstate); 2147c8c0b82SPatrick Mooney } 2157c8c0b82SPatrick Mooney VIOAPIC_UNLOCK(vioapic); 2167c8c0b82SPatrick Mooney 2177c8c0b82SPatrick Mooney return (err); 2187c8c0b82SPatrick Mooney } 2197c8c0b82SPatrick Mooney 2207c8c0b82SPatrick Mooney int 2217c8c0b82SPatrick Mooney vioapic_assert_irq(struct vm *vm, int irq) 2227c8c0b82SPatrick Mooney { 2237c8c0b82SPatrick Mooney 2247c8c0b82SPatrick Mooney return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT)); 2257c8c0b82SPatrick Mooney } 2267c8c0b82SPatrick Mooney 2277c8c0b82SPatrick Mooney int 2287c8c0b82SPatrick Mooney vioapic_deassert_irq(struct vm *vm, int irq) 2297c8c0b82SPatrick Mooney { 2307c8c0b82SPatrick Mooney 2317c8c0b82SPatrick Mooney return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT)); 2327c8c0b82SPatrick Mooney } 2337c8c0b82SPatrick Mooney 2347c8c0b82SPatrick Mooney int 2357c8c0b82SPatrick Mooney vioapic_pulse_irq(struct vm *vm, int irq) 2367c8c0b82SPatrick Mooney { 2377c8c0b82SPatrick Mooney 2387c8c0b82SPatrick Mooney return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE)); 2397c8c0b82SPatrick Mooney } 2407c8c0b82SPatrick Mooney 2417c8c0b82SPatrick Mooney static uint32_t 2427c8c0b82SPatrick Mooney vioapic_read(struct vioapic *vioapic, int vcpuid, uint32_t addr) 2437c8c0b82SPatrick Mooney { 2447c8c0b82SPatrick Mooney int regnum, pin, rshift; 2457c8c0b82SPatrick Mooney 2467c8c0b82SPatrick Mooney regnum = addr & 0xff; 2477c8c0b82SPatrick Mooney switch (regnum) { 2487c8c0b82SPatrick Mooney case IOAPIC_ID: 2497c8c0b82SPatrick Mooney return (vioapic->id); 2507c8c0b82SPatrick Mooney break; 2517c8c0b82SPatrick Mooney case IOAPIC_VER: 2527c8c0b82SPatrick Mooney return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11); 2537c8c0b82SPatrick Mooney break; 2547c8c0b82SPatrick Mooney case IOAPIC_ARB: 2557c8c0b82SPatrick Mooney return (vioapic->id); 2567c8c0b82SPatrick Mooney break; 2577c8c0b82SPatrick Mooney default: 2587c8c0b82SPatrick Mooney break; 2597c8c0b82SPatrick Mooney } 2607c8c0b82SPatrick Mooney 2617c8c0b82SPatrick Mooney /* redirection table entries */ 2627c8c0b82SPatrick Mooney if (regnum >= IOAPIC_REDTBL && 2637c8c0b82SPatrick Mooney regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 2647c8c0b82SPatrick Mooney pin = (regnum - IOAPIC_REDTBL) / 2; 2657c8c0b82SPatrick Mooney if ((regnum - IOAPIC_REDTBL) % 2) 2667c8c0b82SPatrick Mooney rshift = 32; 2677c8c0b82SPatrick Mooney else 2687c8c0b82SPatrick Mooney rshift = 0; 2697c8c0b82SPatrick Mooney 2707c8c0b82SPatrick Mooney return (vioapic->rtbl[pin].reg >> rshift); 2717c8c0b82SPatrick Mooney } 2727c8c0b82SPatrick Mooney 2737c8c0b82SPatrick Mooney return (0); 2747c8c0b82SPatrick Mooney } 2757c8c0b82SPatrick Mooney 2767c8c0b82SPatrick Mooney static void 2777c8c0b82SPatrick Mooney vioapic_write(struct vioapic *vioapic, int vcpuid, uint32_t addr, uint32_t data) 2787c8c0b82SPatrick Mooney { 2797c8c0b82SPatrick Mooney uint64_t data64, mask64; 2807c8c0b82SPatrick Mooney int regnum, pin, lshift; 2817c8c0b82SPatrick Mooney 2827c8c0b82SPatrick Mooney regnum = addr & 0xff; 2837c8c0b82SPatrick Mooney switch (regnum) { 2847c8c0b82SPatrick Mooney case IOAPIC_ID: 2857c8c0b82SPatrick Mooney vioapic->id = data & APIC_ID_MASK; 2867c8c0b82SPatrick Mooney break; 2877c8c0b82SPatrick Mooney case IOAPIC_VER: 2887c8c0b82SPatrick Mooney case IOAPIC_ARB: 2897c8c0b82SPatrick Mooney /* readonly */ 2907c8c0b82SPatrick Mooney break; 2917c8c0b82SPatrick Mooney default: 2927c8c0b82SPatrick Mooney break; 2937c8c0b82SPatrick Mooney } 2947c8c0b82SPatrick Mooney 2957c8c0b82SPatrick Mooney /* redirection table entries */ 2967c8c0b82SPatrick Mooney if (regnum >= IOAPIC_REDTBL && 2977c8c0b82SPatrick Mooney regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) { 2987c8c0b82SPatrick Mooney pin = (regnum - IOAPIC_REDTBL) / 2; 2997c8c0b82SPatrick Mooney if ((regnum - IOAPIC_REDTBL) % 2) 3007c8c0b82SPatrick Mooney lshift = 32; 3017c8c0b82SPatrick Mooney else 3027c8c0b82SPatrick Mooney lshift = 0; 3037c8c0b82SPatrick Mooney 3047c8c0b82SPatrick Mooney data64 = (uint64_t)data << lshift; 3057c8c0b82SPatrick Mooney mask64 = (uint64_t)0xffffffff << lshift; 3067c8c0b82SPatrick Mooney vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS; 3077c8c0b82SPatrick Mooney vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS; 3087c8c0b82SPatrick Mooney 3097c8c0b82SPatrick Mooney /* 3107c8c0b82SPatrick Mooney * Switching from level to edge triggering will clear the IRR 3117c8c0b82SPatrick Mooney * bit. This is what FreeBSD will do in order to EOI an 3127c8c0b82SPatrick Mooney * interrupt when the IO-APIC doesn't support targeted EOI (see 3137c8c0b82SPatrick Mooney * _ioapic_eoi_source). 3147c8c0b82SPatrick Mooney */ 3157c8c0b82SPatrick Mooney if ((vioapic->rtbl[pin].reg & IOART_TRGRMOD) == IOART_TRGREDG && 3167c8c0b82SPatrick Mooney (vioapic->rtbl[pin].reg & IOART_REM_IRR) != 0) 3177c8c0b82SPatrick Mooney vioapic->rtbl[pin].reg &= ~IOART_REM_IRR; 3187c8c0b82SPatrick Mooney 3197c8c0b82SPatrick Mooney /* 3207c8c0b82SPatrick Mooney * Generate an interrupt if the following conditions are met: 3217c8c0b82SPatrick Mooney * - pin trigger mode is level 3227c8c0b82SPatrick Mooney * - pin level is asserted 3237c8c0b82SPatrick Mooney */ 3247c8c0b82SPatrick Mooney if ((vioapic->rtbl[pin].reg & IOART_TRGRMOD) == IOART_TRGRLVL && 3257c8c0b82SPatrick Mooney (vioapic->rtbl[pin].acnt > 0)) { 3267c8c0b82SPatrick Mooney vioapic_send_intr(vioapic, pin); 3277c8c0b82SPatrick Mooney } 3287c8c0b82SPatrick Mooney } 3297c8c0b82SPatrick Mooney } 3307c8c0b82SPatrick Mooney 3317c8c0b82SPatrick Mooney static int 3327c8c0b82SPatrick Mooney vioapic_mmio_rw(struct vioapic *vioapic, int vcpuid, uint64_t gpa, 3337c8c0b82SPatrick Mooney uint64_t *data, int size, bool doread) 3347c8c0b82SPatrick Mooney { 3357c8c0b82SPatrick Mooney uint64_t offset; 3367c8c0b82SPatrick Mooney 3377c8c0b82SPatrick Mooney offset = gpa - VIOAPIC_BASE; 3387c8c0b82SPatrick Mooney 3397c8c0b82SPatrick Mooney /* 3407c8c0b82SPatrick Mooney * The IOAPIC specification allows 32-bit wide accesses to the 3417c8c0b82SPatrick Mooney * IOREGSEL (offset 0) and IOWIN (offset 16) registers. 3427c8c0b82SPatrick Mooney */ 3437c8c0b82SPatrick Mooney if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) { 3447c8c0b82SPatrick Mooney if (doread) 3457c8c0b82SPatrick Mooney *data = 0; 3467c8c0b82SPatrick Mooney return (0); 3477c8c0b82SPatrick Mooney } 3487c8c0b82SPatrick Mooney 3497c8c0b82SPatrick Mooney VIOAPIC_LOCK(vioapic); 3507c8c0b82SPatrick Mooney if (offset == IOREGSEL) { 3517c8c0b82SPatrick Mooney if (doread) 3527c8c0b82SPatrick Mooney *data = vioapic->ioregsel; 3537c8c0b82SPatrick Mooney else 3547c8c0b82SPatrick Mooney vioapic->ioregsel = *data; 3557c8c0b82SPatrick Mooney } else { 3567c8c0b82SPatrick Mooney if (doread) { 3577c8c0b82SPatrick Mooney *data = vioapic_read(vioapic, vcpuid, 3587c8c0b82SPatrick Mooney vioapic->ioregsel); 3597c8c0b82SPatrick Mooney } else { 3607c8c0b82SPatrick Mooney vioapic_write(vioapic, vcpuid, vioapic->ioregsel, 3617c8c0b82SPatrick Mooney *data); 3627c8c0b82SPatrick Mooney } 3637c8c0b82SPatrick Mooney } 3647c8c0b82SPatrick Mooney VIOAPIC_UNLOCK(vioapic); 3657c8c0b82SPatrick Mooney 3667c8c0b82SPatrick Mooney return (0); 3677c8c0b82SPatrick Mooney } 3687c8c0b82SPatrick Mooney 3697c8c0b82SPatrick Mooney int 3707c8c0b82SPatrick Mooney vioapic_mmio_read(struct vm *vm, int vcpuid, uint64_t gpa, uint64_t *rval, 3717c8c0b82SPatrick Mooney int size) 3727c8c0b82SPatrick Mooney { 3737c8c0b82SPatrick Mooney int error; 3747c8c0b82SPatrick Mooney struct vioapic *vioapic; 3757c8c0b82SPatrick Mooney 3767c8c0b82SPatrick Mooney vioapic = vm_ioapic(vm); 3777c8c0b82SPatrick Mooney error = vioapic_mmio_rw(vioapic, vcpuid, gpa, rval, size, true); 3787c8c0b82SPatrick Mooney return (error); 3797c8c0b82SPatrick Mooney } 3807c8c0b82SPatrick Mooney 3817c8c0b82SPatrick Mooney int 3827c8c0b82SPatrick Mooney vioapic_mmio_write(struct vm *vm, int vcpuid, uint64_t gpa, uint64_t wval, 3837c8c0b82SPatrick Mooney int size) 3847c8c0b82SPatrick Mooney { 3857c8c0b82SPatrick Mooney int error; 3867c8c0b82SPatrick Mooney struct vioapic *vioapic; 3877c8c0b82SPatrick Mooney 3887c8c0b82SPatrick Mooney vioapic = vm_ioapic(vm); 3897c8c0b82SPatrick Mooney error = vioapic_mmio_rw(vioapic, vcpuid, gpa, &wval, size, false); 3907c8c0b82SPatrick Mooney return (error); 3917c8c0b82SPatrick Mooney } 3927c8c0b82SPatrick Mooney 3937c8c0b82SPatrick Mooney void 3947c8c0b82SPatrick Mooney vioapic_process_eoi(struct vm *vm, int vcpuid, int vector) 3957c8c0b82SPatrick Mooney { 3967c8c0b82SPatrick Mooney struct vioapic *vioapic; 3977c8c0b82SPatrick Mooney int pin; 3987c8c0b82SPatrick Mooney 3997c8c0b82SPatrick Mooney KASSERT(vector >= 0 && vector < 256, 4007c8c0b82SPatrick Mooney ("vioapic_process_eoi: invalid vector %d", vector)); 4017c8c0b82SPatrick Mooney 4027c8c0b82SPatrick Mooney vioapic = vm_ioapic(vm); 4037c8c0b82SPatrick Mooney 4047c8c0b82SPatrick Mooney /* 4057c8c0b82SPatrick Mooney * XXX keep track of the pins associated with this vector instead 4067c8c0b82SPatrick Mooney * of iterating on every single pin each time. 4077c8c0b82SPatrick Mooney */ 4087c8c0b82SPatrick Mooney VIOAPIC_LOCK(vioapic); 4097c8c0b82SPatrick Mooney for (pin = 0; pin < REDIR_ENTRIES; pin++) { 4107c8c0b82SPatrick Mooney if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0) 4117c8c0b82SPatrick Mooney continue; 4127c8c0b82SPatrick Mooney if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector) 4137c8c0b82SPatrick Mooney continue; 4147c8c0b82SPatrick Mooney vioapic->rtbl[pin].reg &= ~IOART_REM_IRR; 4157c8c0b82SPatrick Mooney if (vioapic->rtbl[pin].acnt > 0) { 416d4f59ae5SPatrick Mooney /* Pin asserted at EOI */ 4177c8c0b82SPatrick Mooney vioapic_send_intr(vioapic, pin); 4187c8c0b82SPatrick Mooney } 4197c8c0b82SPatrick Mooney } 4207c8c0b82SPatrick Mooney VIOAPIC_UNLOCK(vioapic); 4217c8c0b82SPatrick Mooney } 4227c8c0b82SPatrick Mooney 4237c8c0b82SPatrick Mooney struct vioapic * 4247c8c0b82SPatrick Mooney vioapic_init(struct vm *vm) 4257c8c0b82SPatrick Mooney { 4267c8c0b82SPatrick Mooney int i; 4277c8c0b82SPatrick Mooney struct vioapic *vioapic; 4287c8c0b82SPatrick Mooney 429*8130f8e1SPatrick Mooney vioapic = kmem_zalloc(sizeof (struct vioapic), KM_SLEEP); 4307c8c0b82SPatrick Mooney 4317c8c0b82SPatrick Mooney vioapic->vm = vm; 4327c8c0b82SPatrick Mooney mutex_init(&vioapic->lock, NULL, MUTEX_ADAPTIVE, NULL); 4337c8c0b82SPatrick Mooney 4347c8c0b82SPatrick Mooney /* Initialize all redirection entries to mask all interrupts */ 4357c8c0b82SPatrick Mooney for (i = 0; i < REDIR_ENTRIES; i++) 4367c8c0b82SPatrick Mooney vioapic->rtbl[i].reg = 0x0001000000010000UL; 4377c8c0b82SPatrick Mooney 4387c8c0b82SPatrick Mooney return (vioapic); 4397c8c0b82SPatrick Mooney } 4407c8c0b82SPatrick Mooney 4417c8c0b82SPatrick Mooney void 4427c8c0b82SPatrick Mooney vioapic_cleanup(struct vioapic *vioapic) 4437c8c0b82SPatrick Mooney { 4447c8c0b82SPatrick Mooney mutex_destroy(&vioapic->lock); 445*8130f8e1SPatrick Mooney kmem_free(vioapic, sizeof (*vioapic)); 4467c8c0b82SPatrick Mooney } 4477c8c0b82SPatrick Mooney 4487c8c0b82SPatrick Mooney int 4497c8c0b82SPatrick Mooney vioapic_pincount(struct vm *vm) 4507c8c0b82SPatrick Mooney { 4517c8c0b82SPatrick Mooney 4527c8c0b82SPatrick Mooney return (REDIR_ENTRIES); 4537c8c0b82SPatrick Mooney } 454