1bf21cd93STycho Nightingale /*-
2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney *
4bf21cd93STycho Nightingale * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5bf21cd93STycho Nightingale * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
6bf21cd93STycho Nightingale * All rights reserved.
7bf21cd93STycho Nightingale *
8bf21cd93STycho Nightingale * Redistribution and use in source and binary forms, with or without
9bf21cd93STycho Nightingale * modification, are permitted provided that the following conditions
10bf21cd93STycho Nightingale * are met:
11bf21cd93STycho Nightingale * 1. Redistributions of source code must retain the above copyright
12bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer.
13bf21cd93STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright
14bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer in the
15bf21cd93STycho Nightingale * documentation and/or other materials provided with the distribution.
16bf21cd93STycho Nightingale *
17bf21cd93STycho Nightingale * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
18bf21cd93STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19bf21cd93STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20bf21cd93STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
21bf21cd93STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22bf21cd93STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23bf21cd93STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24bf21cd93STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25bf21cd93STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26bf21cd93STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27bf21cd93STycho Nightingale * SUCH DAMAGE.
28bf21cd93STycho Nightingale */
29bf21cd93STycho Nightingale /*
30bf21cd93STycho Nightingale * This file and its contents are supplied under the terms of the
31bf21cd93STycho Nightingale * Common Development and Distribution License ("CDDL"), version 1.0.
32bf21cd93STycho Nightingale * You may only use this file in accordance with the terms of version
33bf21cd93STycho Nightingale * 1.0 of the CDDL.
34bf21cd93STycho Nightingale *
35bf21cd93STycho Nightingale * A full copy of the text of the CDDL should have accompanied this
36bf21cd93STycho Nightingale * source. A copy of the CDDL is also available via the Internet at
37bf21cd93STycho Nightingale * http://www.illumos.org/license/CDDL.
38bf21cd93STycho Nightingale *
39bf21cd93STycho Nightingale * Copyright 2014 Pluribus Networks Inc.
404c87aefeSPatrick Mooney * Copyright 2017 Joyent, Inc.
41c6282d59SPatrick Mooney * Copyright 2021 Oxide Computer Company
42bf21cd93STycho Nightingale */
43bf21cd93STycho Nightingale
44bf21cd93STycho Nightingale #include <sys/cdefs.h>
45bf21cd93STycho Nightingale
46bf21cd93STycho Nightingale #include <sys/param.h>
47bf21cd93STycho Nightingale #include <sys/queue.h>
48bf21cd93STycho Nightingale #include <sys/mutex.h>
49bf21cd93STycho Nightingale #include <sys/systm.h>
50bf21cd93STycho Nightingale #include <sys/kernel.h>
518130f8e1SPatrick Mooney #include <sys/kmem.h>
524c87aefeSPatrick Mooney #include <sys/cpuset.h>
53bf21cd93STycho Nightingale
54bf21cd93STycho Nightingale #include <x86/apicreg.h>
55bf21cd93STycho Nightingale #include <machine/vmm.h>
56d515dd77SPatrick Mooney #include <sys/vmm_data.h>
57bf21cd93STycho Nightingale
58bf21cd93STycho Nightingale #include "vmm_lapic.h"
59bf21cd93STycho Nightingale #include "vlapic.h"
60bf21cd93STycho Nightingale #include "vioapic.h"
61bf21cd93STycho Nightingale
62bf21cd93STycho Nightingale #define IOREGSEL 0x00
63bf21cd93STycho Nightingale #define IOWIN 0x10
64bf21cd93STycho Nightingale
654c87aefeSPatrick Mooney #define REDIR_ENTRIES 32
66bf21cd93STycho Nightingale #define RTBL_RO_BITS ((uint64_t)(IOART_REM_IRR | IOART_DELIVS))
67bf21cd93STycho Nightingale
68c6282d59SPatrick Mooney struct ioapic_stats {
69c6282d59SPatrick Mooney uint64_t is_interrupts;
70c6282d59SPatrick Mooney uint64_t is_saturate_low;
71c6282d59SPatrick Mooney uint64_t is_saturate_high;
72c6282d59SPatrick Mooney };
73c6282d59SPatrick Mooney
74bf21cd93STycho Nightingale struct vioapic {
75bf21cd93STycho Nightingale struct vm *vm;
76fb29dee0SPatrick Mooney kmutex_t lock;
77bf21cd93STycho Nightingale uint32_t id;
78bf21cd93STycho Nightingale uint32_t ioregsel;
79bf21cd93STycho Nightingale struct {
80bf21cd93STycho Nightingale uint64_t reg;
81c6282d59SPatrick Mooney /*
82c6282d59SPatrick Mooney * The sum of pin asserts (+1) and deasserts (-1) are tracked in
83c6282d59SPatrick Mooney * 'acnt'. It is clamped to prevent overflow or underflow
84c6282d59SPatrick Mooney * should emulation consumers feed it an invalid set of
85c6282d59SPatrick Mooney * transitions.
86c6282d59SPatrick Mooney */
87c6282d59SPatrick Mooney uint_t acnt;
88bf21cd93STycho Nightingale } rtbl[REDIR_ENTRIES];
89c6282d59SPatrick Mooney struct ioapic_stats stats;
90bf21cd93STycho Nightingale };
91bf21cd93STycho Nightingale
92fb29dee0SPatrick Mooney #define VIOAPIC_LOCK(vioapic) mutex_enter(&((vioapic)->lock))
93fb29dee0SPatrick Mooney #define VIOAPIC_UNLOCK(vioapic) mutex_exit(&((vioapic)->lock))
94fb29dee0SPatrick Mooney #define VIOAPIC_LOCKED(vioapic) MUTEX_HELD(&((vioapic)->lock))
95bf21cd93STycho Nightingale
96bf21cd93STycho Nightingale
97bf21cd93STycho Nightingale static void
vioapic_send_intr(struct vioapic * vioapic,int pin)98bf21cd93STycho Nightingale vioapic_send_intr(struct vioapic *vioapic, int pin)
99bf21cd93STycho Nightingale {
100bf21cd93STycho Nightingale int vector, delmode;
101bf21cd93STycho Nightingale uint32_t low, high, dest;
102bf21cd93STycho Nightingale bool level, phys;
103bf21cd93STycho Nightingale
104c6282d59SPatrick Mooney VERIFY(pin >= 0 && pin < REDIR_ENTRIES);
105c6282d59SPatrick Mooney ASSERT(VIOAPIC_LOCKED(vioapic));
106bf21cd93STycho Nightingale
107bf21cd93STycho Nightingale low = vioapic->rtbl[pin].reg;
108bf21cd93STycho Nightingale high = vioapic->rtbl[pin].reg >> 32;
109bf21cd93STycho Nightingale
110bf21cd93STycho Nightingale if ((low & IOART_INTMASK) == IOART_INTMSET) {
111d4f59ae5SPatrick Mooney /* Pin is masked */
112bf21cd93STycho Nightingale return;
113bf21cd93STycho Nightingale }
114bf21cd93STycho Nightingale
115bf21cd93STycho Nightingale phys = ((low & IOART_DESTMOD) == IOART_DESTPHY);
116bf21cd93STycho Nightingale delmode = low & IOART_DELMOD;
117bf21cd93STycho Nightingale level = low & IOART_TRGRLVL ? true : false;
1182b948146SAndy Fiddaman if (level) {
1192b948146SAndy Fiddaman if ((low & IOART_REM_IRR) != 0) {
120d4f59ae5SPatrick Mooney /* IRR already pending */
1212b948146SAndy Fiddaman return;
1222b948146SAndy Fiddaman }
123bf21cd93STycho Nightingale vioapic->rtbl[pin].reg |= IOART_REM_IRR;
1242b948146SAndy Fiddaman }
125bf21cd93STycho Nightingale
126bf21cd93STycho Nightingale vector = low & IOART_INTVEC;
127bf21cd93STycho Nightingale dest = high >> APIC_ID_SHIFT;
128bf21cd93STycho Nightingale vlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector);
129c6282d59SPatrick Mooney vioapic->stats.is_interrupts++;
130bf21cd93STycho Nightingale }
131bf21cd93STycho Nightingale
132c6282d59SPatrick Mooney static int
vioapic_set_pinstate(struct vioapic * vioapic,int pin,bool newstate)133bf21cd93STycho Nightingale vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
134bf21cd93STycho Nightingale {
135c6282d59SPatrick Mooney uint_t oldcnt, newcnt;
136c6282d59SPatrick Mooney bool needintr = false;
137c6282d59SPatrick Mooney int err = 0;
138c6282d59SPatrick Mooney
139c6282d59SPatrick Mooney VERIFY(pin >= 0 && pin < REDIR_ENTRIES);
140c6282d59SPatrick Mooney ASSERT(VIOAPIC_LOCKED(vioapic));
141c6282d59SPatrick Mooney
142c6282d59SPatrick Mooney oldcnt = newcnt = vioapic->rtbl[pin].acnt;
143c6282d59SPatrick Mooney if (newstate) {
144c6282d59SPatrick Mooney if (newcnt != UINT_MAX) {
145c6282d59SPatrick Mooney newcnt++;
146c6282d59SPatrick Mooney } else {
147c6282d59SPatrick Mooney err = E2BIG;
148c6282d59SPatrick Mooney DTRACE_PROBE2(vioapic__sat_high,
149c6282d59SPatrick Mooney struct vioapic *, vioapic, int, pin);
150c6282d59SPatrick Mooney vioapic->stats.is_saturate_high++;
151c6282d59SPatrick Mooney }
152c6282d59SPatrick Mooney } else {
153c6282d59SPatrick Mooney if (newcnt != 0) {
154c6282d59SPatrick Mooney newcnt--;
155c6282d59SPatrick Mooney } else {
156c6282d59SPatrick Mooney err = ERANGE;
157c6282d59SPatrick Mooney DTRACE_PROBE2(vioapic__sat_low,
158c6282d59SPatrick Mooney struct vioapic *, vioapic, int, pin);
159c6282d59SPatrick Mooney vioapic->stats.is_saturate_low++;
160c6282d59SPatrick Mooney }
161bf21cd93STycho Nightingale }
162c6282d59SPatrick Mooney vioapic->rtbl[pin].acnt = newcnt;
163bf21cd93STycho Nightingale
164bf21cd93STycho Nightingale if (oldcnt == 0 && newcnt == 1) {
165bf21cd93STycho Nightingale needintr = true;
166c6282d59SPatrick Mooney DTRACE_PROBE2(vioapic__assert, struct vioapic *, vioapic,
167c6282d59SPatrick Mooney int, pin);
168bf21cd93STycho Nightingale } else if (oldcnt == 1 && newcnt == 0) {
169c6282d59SPatrick Mooney DTRACE_PROBE2(vioapic__deassert, struct vioapic *, vioapic,
170c6282d59SPatrick Mooney int, pin);
171bf21cd93STycho Nightingale }
172bf21cd93STycho Nightingale
173c6282d59SPatrick Mooney if (needintr) {
174bf21cd93STycho Nightingale vioapic_send_intr(vioapic, pin);
175c6282d59SPatrick Mooney }
176c6282d59SPatrick Mooney return (err);
177bf21cd93STycho Nightingale }
178bf21cd93STycho Nightingale
179bf21cd93STycho Nightingale enum irqstate {
180bf21cd93STycho Nightingale IRQSTATE_ASSERT,
181bf21cd93STycho Nightingale IRQSTATE_DEASSERT,
182bf21cd93STycho Nightingale IRQSTATE_PULSE
183bf21cd93STycho Nightingale };
184bf21cd93STycho Nightingale
185bf21cd93STycho Nightingale static int
vioapic_set_irqstate(struct vm * vm,int irq,enum irqstate irqstate)186bf21cd93STycho Nightingale vioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
187bf21cd93STycho Nightingale {
188bf21cd93STycho Nightingale struct vioapic *vioapic;
189c6282d59SPatrick Mooney int err = 0;
190bf21cd93STycho Nightingale
191bf21cd93STycho Nightingale if (irq < 0 || irq >= REDIR_ENTRIES)
192bf21cd93STycho Nightingale return (EINVAL);
193bf21cd93STycho Nightingale
194bf21cd93STycho Nightingale vioapic = vm_ioapic(vm);
195bf21cd93STycho Nightingale
196bf21cd93STycho Nightingale VIOAPIC_LOCK(vioapic);
197bf21cd93STycho Nightingale switch (irqstate) {
198bf21cd93STycho Nightingale case IRQSTATE_ASSERT:
199c6282d59SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, true);
200bf21cd93STycho Nightingale break;
201bf21cd93STycho Nightingale case IRQSTATE_DEASSERT:
202c6282d59SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, false);
203bf21cd93STycho Nightingale break;
204bf21cd93STycho Nightingale case IRQSTATE_PULSE:
205c6282d59SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, true);
206c6282d59SPatrick Mooney if (err == 0) {
207c6282d59SPatrick Mooney err = vioapic_set_pinstate(vioapic, irq, false);
208c6282d59SPatrick Mooney }
209bf21cd93STycho Nightingale break;
210bf21cd93STycho Nightingale default:
211bf21cd93STycho Nightingale panic("vioapic_set_irqstate: invalid irqstate %d", irqstate);
212bf21cd93STycho Nightingale }
213bf21cd93STycho Nightingale VIOAPIC_UNLOCK(vioapic);
214bf21cd93STycho Nightingale
215c6282d59SPatrick Mooney return (err);
216bf21cd93STycho Nightingale }
217bf21cd93STycho Nightingale
218bf21cd93STycho Nightingale int
vioapic_assert_irq(struct vm * vm,int irq)219bf21cd93STycho Nightingale vioapic_assert_irq(struct vm *vm, int irq)
220bf21cd93STycho Nightingale {
221bf21cd93STycho Nightingale
222bf21cd93STycho Nightingale return (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
223bf21cd93STycho Nightingale }
224bf21cd93STycho Nightingale
225bf21cd93STycho Nightingale int
vioapic_deassert_irq(struct vm * vm,int irq)226bf21cd93STycho Nightingale vioapic_deassert_irq(struct vm *vm, int irq)
227bf21cd93STycho Nightingale {
228bf21cd93STycho Nightingale
229bf21cd93STycho Nightingale return (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
230bf21cd93STycho Nightingale }
231bf21cd93STycho Nightingale
232bf21cd93STycho Nightingale int
vioapic_pulse_irq(struct vm * vm,int irq)233bf21cd93STycho Nightingale vioapic_pulse_irq(struct vm *vm, int irq)
234bf21cd93STycho Nightingale {
235bf21cd93STycho Nightingale
236bf21cd93STycho Nightingale return (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE));
237bf21cd93STycho Nightingale }
238bf21cd93STycho Nightingale
239bf21cd93STycho Nightingale static uint32_t
vioapic_read(struct vioapic * vioapic,int vcpuid,uint32_t addr)240bf21cd93STycho Nightingale vioapic_read(struct vioapic *vioapic, int vcpuid, uint32_t addr)
241bf21cd93STycho Nightingale {
242bf21cd93STycho Nightingale int regnum, pin, rshift;
243bf21cd93STycho Nightingale
244bf21cd93STycho Nightingale regnum = addr & 0xff;
245bf21cd93STycho Nightingale switch (regnum) {
246bf21cd93STycho Nightingale case IOAPIC_ID:
247bf21cd93STycho Nightingale return (vioapic->id);
248bf21cd93STycho Nightingale break;
249bf21cd93STycho Nightingale case IOAPIC_VER:
250bf21cd93STycho Nightingale return (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11);
251bf21cd93STycho Nightingale break;
252bf21cd93STycho Nightingale case IOAPIC_ARB:
253bf21cd93STycho Nightingale return (vioapic->id);
254bf21cd93STycho Nightingale break;
255bf21cd93STycho Nightingale default:
256bf21cd93STycho Nightingale break;
257bf21cd93STycho Nightingale }
258bf21cd93STycho Nightingale
259bf21cd93STycho Nightingale /* redirection table entries */
260bf21cd93STycho Nightingale if (regnum >= IOAPIC_REDTBL &&
261bf21cd93STycho Nightingale regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
262bf21cd93STycho Nightingale pin = (regnum - IOAPIC_REDTBL) / 2;
263bf21cd93STycho Nightingale if ((regnum - IOAPIC_REDTBL) % 2)
264bf21cd93STycho Nightingale rshift = 32;
265bf21cd93STycho Nightingale else
266bf21cd93STycho Nightingale rshift = 0;
267bf21cd93STycho Nightingale
268bf21cd93STycho Nightingale return (vioapic->rtbl[pin].reg >> rshift);
269bf21cd93STycho Nightingale }
270bf21cd93STycho Nightingale
271bf21cd93STycho Nightingale return (0);
272bf21cd93STycho Nightingale }
273bf21cd93STycho Nightingale
274bf21cd93STycho Nightingale static void
vioapic_write(struct vioapic * vioapic,int vcpuid,uint32_t addr,uint32_t data)275bf21cd93STycho Nightingale vioapic_write(struct vioapic *vioapic, int vcpuid, uint32_t addr, uint32_t data)
276bf21cd93STycho Nightingale {
277bf21cd93STycho Nightingale uint64_t data64, mask64;
278bf21cd93STycho Nightingale int regnum, pin, lshift;
279bf21cd93STycho Nightingale
280bf21cd93STycho Nightingale regnum = addr & 0xff;
281bf21cd93STycho Nightingale switch (regnum) {
282bf21cd93STycho Nightingale case IOAPIC_ID:
283bf21cd93STycho Nightingale vioapic->id = data & APIC_ID_MASK;
284bf21cd93STycho Nightingale break;
285bf21cd93STycho Nightingale case IOAPIC_VER:
286bf21cd93STycho Nightingale case IOAPIC_ARB:
287bf21cd93STycho Nightingale /* readonly */
288bf21cd93STycho Nightingale break;
289bf21cd93STycho Nightingale default:
290bf21cd93STycho Nightingale break;
291bf21cd93STycho Nightingale }
292bf21cd93STycho Nightingale
293bf21cd93STycho Nightingale /* redirection table entries */
294bf21cd93STycho Nightingale if (regnum >= IOAPIC_REDTBL &&
295bf21cd93STycho Nightingale regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
296bf21cd93STycho Nightingale pin = (regnum - IOAPIC_REDTBL) / 2;
297bf21cd93STycho Nightingale if ((regnum - IOAPIC_REDTBL) % 2)
298bf21cd93STycho Nightingale lshift = 32;
299bf21cd93STycho Nightingale else
300bf21cd93STycho Nightingale lshift = 0;
301bf21cd93STycho Nightingale
302bf21cd93STycho Nightingale data64 = (uint64_t)data << lshift;
303bf21cd93STycho Nightingale mask64 = (uint64_t)0xffffffff << lshift;
304bf21cd93STycho Nightingale vioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS;
305bf21cd93STycho Nightingale vioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS;
306bf21cd93STycho Nightingale
3072b948146SAndy Fiddaman /*
3082b948146SAndy Fiddaman * Switching from level to edge triggering will clear the IRR
3092b948146SAndy Fiddaman * bit. This is what FreeBSD will do in order to EOI an
3102b948146SAndy Fiddaman * interrupt when the IO-APIC doesn't support targeted EOI (see
3112b948146SAndy Fiddaman * _ioapic_eoi_source).
3122b948146SAndy Fiddaman */
3132b948146SAndy Fiddaman if ((vioapic->rtbl[pin].reg & IOART_TRGRMOD) == IOART_TRGREDG &&
3142b948146SAndy Fiddaman (vioapic->rtbl[pin].reg & IOART_REM_IRR) != 0)
3152b948146SAndy Fiddaman vioapic->rtbl[pin].reg &= ~IOART_REM_IRR;
3162b948146SAndy Fiddaman
317bf21cd93STycho Nightingale /*
318bf21cd93STycho Nightingale * Generate an interrupt if the following conditions are met:
3192b948146SAndy Fiddaman * - pin trigger mode is level
320bf21cd93STycho Nightingale * - pin level is asserted
321bf21cd93STycho Nightingale */
3222b948146SAndy Fiddaman if ((vioapic->rtbl[pin].reg & IOART_TRGRMOD) == IOART_TRGRLVL &&
323bf21cd93STycho Nightingale (vioapic->rtbl[pin].acnt > 0)) {
324bf21cd93STycho Nightingale vioapic_send_intr(vioapic, pin);
325bf21cd93STycho Nightingale }
326bf21cd93STycho Nightingale }
327bf21cd93STycho Nightingale }
328bf21cd93STycho Nightingale
329bf21cd93STycho Nightingale static int
vioapic_mmio_rw(struct vioapic * vioapic,int vcpuid,uint64_t gpa,uint64_t * data,int size,bool doread)330bf21cd93STycho Nightingale vioapic_mmio_rw(struct vioapic *vioapic, int vcpuid, uint64_t gpa,
331bf21cd93STycho Nightingale uint64_t *data, int size, bool doread)
332bf21cd93STycho Nightingale {
333bf21cd93STycho Nightingale uint64_t offset;
334bf21cd93STycho Nightingale
335bf21cd93STycho Nightingale offset = gpa - VIOAPIC_BASE;
336bf21cd93STycho Nightingale
337bf21cd93STycho Nightingale /*
338bf21cd93STycho Nightingale * The IOAPIC specification allows 32-bit wide accesses to the
339bf21cd93STycho Nightingale * IOREGSEL (offset 0) and IOWIN (offset 16) registers.
340bf21cd93STycho Nightingale */
341bf21cd93STycho Nightingale if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
342bf21cd93STycho Nightingale if (doread)
343bf21cd93STycho Nightingale *data = 0;
344bf21cd93STycho Nightingale return (0);
345bf21cd93STycho Nightingale }
346bf21cd93STycho Nightingale
347bf21cd93STycho Nightingale VIOAPIC_LOCK(vioapic);
348bf21cd93STycho Nightingale if (offset == IOREGSEL) {
349bf21cd93STycho Nightingale if (doread)
350bf21cd93STycho Nightingale *data = vioapic->ioregsel;
351bf21cd93STycho Nightingale else
352bf21cd93STycho Nightingale vioapic->ioregsel = *data;
353bf21cd93STycho Nightingale } else {
354bf21cd93STycho Nightingale if (doread) {
355bf21cd93STycho Nightingale *data = vioapic_read(vioapic, vcpuid,
356bf21cd93STycho Nightingale vioapic->ioregsel);
357bf21cd93STycho Nightingale } else {
358bf21cd93STycho Nightingale vioapic_write(vioapic, vcpuid, vioapic->ioregsel,
359bf21cd93STycho Nightingale *data);
360bf21cd93STycho Nightingale }
361bf21cd93STycho Nightingale }
362bf21cd93STycho Nightingale VIOAPIC_UNLOCK(vioapic);
363bf21cd93STycho Nightingale
364bf21cd93STycho Nightingale return (0);
365bf21cd93STycho Nightingale }
366bf21cd93STycho Nightingale
367bf21cd93STycho Nightingale int
vioapic_mmio_read(struct vm * vm,int vcpuid,uint64_t gpa,uint64_t * rval,int size)3683e1c5f3aSPatrick Mooney vioapic_mmio_read(struct vm *vm, int vcpuid, uint64_t gpa, uint64_t *rval,
3693e1c5f3aSPatrick Mooney int size)
370bf21cd93STycho Nightingale {
371bf21cd93STycho Nightingale int error;
372bf21cd93STycho Nightingale struct vioapic *vioapic;
373bf21cd93STycho Nightingale
374bf21cd93STycho Nightingale vioapic = vm_ioapic(vm);
375bf21cd93STycho Nightingale error = vioapic_mmio_rw(vioapic, vcpuid, gpa, rval, size, true);
376bf21cd93STycho Nightingale return (error);
377bf21cd93STycho Nightingale }
378bf21cd93STycho Nightingale
379bf21cd93STycho Nightingale int
vioapic_mmio_write(struct vm * vm,int vcpuid,uint64_t gpa,uint64_t wval,int size)3803e1c5f3aSPatrick Mooney vioapic_mmio_write(struct vm *vm, int vcpuid, uint64_t gpa, uint64_t wval,
3813e1c5f3aSPatrick Mooney int size)
382bf21cd93STycho Nightingale {
383bf21cd93STycho Nightingale int error;
384bf21cd93STycho Nightingale struct vioapic *vioapic;
385bf21cd93STycho Nightingale
386bf21cd93STycho Nightingale vioapic = vm_ioapic(vm);
387bf21cd93STycho Nightingale error = vioapic_mmio_rw(vioapic, vcpuid, gpa, &wval, size, false);
388bf21cd93STycho Nightingale return (error);
389bf21cd93STycho Nightingale }
390bf21cd93STycho Nightingale
391bf21cd93STycho Nightingale void
vioapic_process_eoi(struct vm * vm,int vcpuid,int vector)392bf21cd93STycho Nightingale vioapic_process_eoi(struct vm *vm, int vcpuid, int vector)
393bf21cd93STycho Nightingale {
394bf21cd93STycho Nightingale struct vioapic *vioapic;
395bf21cd93STycho Nightingale int pin;
396bf21cd93STycho Nightingale
397bf21cd93STycho Nightingale KASSERT(vector >= 0 && vector < 256,
398bf21cd93STycho Nightingale ("vioapic_process_eoi: invalid vector %d", vector));
399bf21cd93STycho Nightingale
400bf21cd93STycho Nightingale vioapic = vm_ioapic(vm);
401bf21cd93STycho Nightingale
402bf21cd93STycho Nightingale /*
403bf21cd93STycho Nightingale * XXX keep track of the pins associated with this vector instead
404bf21cd93STycho Nightingale * of iterating on every single pin each time.
405bf21cd93STycho Nightingale */
406bf21cd93STycho Nightingale VIOAPIC_LOCK(vioapic);
407bf21cd93STycho Nightingale for (pin = 0; pin < REDIR_ENTRIES; pin++) {
408bf21cd93STycho Nightingale if ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0)
409bf21cd93STycho Nightingale continue;
410bf21cd93STycho Nightingale if ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector)
411bf21cd93STycho Nightingale continue;
412bf21cd93STycho Nightingale vioapic->rtbl[pin].reg &= ~IOART_REM_IRR;
413bf21cd93STycho Nightingale if (vioapic->rtbl[pin].acnt > 0) {
414d4f59ae5SPatrick Mooney /* Pin asserted at EOI */
415bf21cd93STycho Nightingale vioapic_send_intr(vioapic, pin);
416bf21cd93STycho Nightingale }
417bf21cd93STycho Nightingale }
418bf21cd93STycho Nightingale VIOAPIC_UNLOCK(vioapic);
419bf21cd93STycho Nightingale }
420bf21cd93STycho Nightingale
421bf21cd93STycho Nightingale struct vioapic *
vioapic_init(struct vm * vm)422bf21cd93STycho Nightingale vioapic_init(struct vm *vm)
423bf21cd93STycho Nightingale {
424bf21cd93STycho Nightingale int i;
425bf21cd93STycho Nightingale struct vioapic *vioapic;
426bf21cd93STycho Nightingale
4278130f8e1SPatrick Mooney vioapic = kmem_zalloc(sizeof (struct vioapic), KM_SLEEP);
428bf21cd93STycho Nightingale
429bf21cd93STycho Nightingale vioapic->vm = vm;
430fb29dee0SPatrick Mooney mutex_init(&vioapic->lock, NULL, MUTEX_ADAPTIVE, NULL);
431bf21cd93STycho Nightingale
432bf21cd93STycho Nightingale /* Initialize all redirection entries to mask all interrupts */
433bf21cd93STycho Nightingale for (i = 0; i < REDIR_ENTRIES; i++)
434bf21cd93STycho Nightingale vioapic->rtbl[i].reg = 0x0001000000010000UL;
435bf21cd93STycho Nightingale
436bf21cd93STycho Nightingale return (vioapic);
437bf21cd93STycho Nightingale }
438bf21cd93STycho Nightingale
439bf21cd93STycho Nightingale void
vioapic_cleanup(struct vioapic * vioapic)440bf21cd93STycho Nightingale vioapic_cleanup(struct vioapic *vioapic)
441bf21cd93STycho Nightingale {
442fb29dee0SPatrick Mooney mutex_destroy(&vioapic->lock);
4438130f8e1SPatrick Mooney kmem_free(vioapic, sizeof (*vioapic));
444bf21cd93STycho Nightingale }
445bf21cd93STycho Nightingale
446bf21cd93STycho Nightingale int
vioapic_pincount(struct vm * vm)447bf21cd93STycho Nightingale vioapic_pincount(struct vm *vm)
448bf21cd93STycho Nightingale {
449bf21cd93STycho Nightingale
450bf21cd93STycho Nightingale return (REDIR_ENTRIES);
451bf21cd93STycho Nightingale }
452d515dd77SPatrick Mooney
453d515dd77SPatrick Mooney static int
vioapic_data_read(void * datap,const vmm_data_req_t * req)454d515dd77SPatrick Mooney vioapic_data_read(void *datap, const vmm_data_req_t *req)
455d515dd77SPatrick Mooney {
456d515dd77SPatrick Mooney VERIFY3U(req->vdr_class, ==, VDC_IOAPIC);
457d515dd77SPatrick Mooney VERIFY3U(req->vdr_version, ==, 1);
458a77feb92SPatrick Mooney VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_ioapic_v1));
459d515dd77SPatrick Mooney
460d515dd77SPatrick Mooney struct vioapic *vioapic = datap;
461d515dd77SPatrick Mooney struct vdi_ioapic_v1 *out = req->vdr_data;
462d515dd77SPatrick Mooney
463d515dd77SPatrick Mooney VIOAPIC_LOCK(vioapic);
464d515dd77SPatrick Mooney out->vi_id = vioapic->id;
465d515dd77SPatrick Mooney out->vi_reg_sel = vioapic->ioregsel;
466d515dd77SPatrick Mooney for (uint_t i = 0; i < REDIR_ENTRIES; i++) {
467d515dd77SPatrick Mooney out->vi_pin_reg[i] = vioapic->rtbl[i].reg;
468d515dd77SPatrick Mooney out->vi_pin_level[i] = vioapic->rtbl[i].acnt;
469d515dd77SPatrick Mooney }
470d515dd77SPatrick Mooney VIOAPIC_UNLOCK(vioapic);
471d515dd77SPatrick Mooney
472d515dd77SPatrick Mooney return (0);
473d515dd77SPatrick Mooney }
474d515dd77SPatrick Mooney
475d515dd77SPatrick Mooney static int
vioapic_data_write(void * datap,const vmm_data_req_t * req)476d515dd77SPatrick Mooney vioapic_data_write(void *datap, const vmm_data_req_t *req)
477d515dd77SPatrick Mooney {
478d515dd77SPatrick Mooney VERIFY3U(req->vdr_class, ==, VDC_IOAPIC);
479d515dd77SPatrick Mooney VERIFY3U(req->vdr_version, ==, 1);
480a77feb92SPatrick Mooney VERIFY3U(req->vdr_len, >=, sizeof (struct vdi_ioapic_v1));
481d515dd77SPatrick Mooney
482d515dd77SPatrick Mooney struct vioapic *vioapic = datap;
483d515dd77SPatrick Mooney const struct vdi_ioapic_v1 *src = req->vdr_data;
484d515dd77SPatrick Mooney
485d515dd77SPatrick Mooney VIOAPIC_LOCK(vioapic);
486d515dd77SPatrick Mooney vioapic->id = src->vi_id;
487d515dd77SPatrick Mooney vioapic->ioregsel = src->vi_reg_sel;
488d515dd77SPatrick Mooney for (uint_t i = 0; i < REDIR_ENTRIES; i++) {
489d515dd77SPatrick Mooney vioapic->rtbl[i].reg = src->vi_pin_reg[i] & ~RTBL_RO_BITS;
490d515dd77SPatrick Mooney vioapic->rtbl[i].acnt = src->vi_pin_level[i];
491d515dd77SPatrick Mooney }
492d515dd77SPatrick Mooney VIOAPIC_UNLOCK(vioapic);
493d515dd77SPatrick Mooney
494d515dd77SPatrick Mooney return (0);
495d515dd77SPatrick Mooney }
496d515dd77SPatrick Mooney
497d515dd77SPatrick Mooney static const vmm_data_version_entry_t ioapic_v1 = {
498d515dd77SPatrick Mooney .vdve_class = VDC_IOAPIC,
499d515dd77SPatrick Mooney .vdve_version = 1,
500d515dd77SPatrick Mooney .vdve_len_expect = sizeof (struct vdi_ioapic_v1),
501d515dd77SPatrick Mooney .vdve_readf = vioapic_data_read,
502d515dd77SPatrick Mooney .vdve_writef = vioapic_data_write,
503d515dd77SPatrick Mooney };
504d515dd77SPatrick Mooney VMM_DATA_VERSION(ioapic_v1);
505