xref: /illumos-gate/usr/src/cmd/bhyve/pci_emul.c (revision bf21cd9318e0a3a51b7f02c14a7c1b1aef2dc861)
1*bf21cd93STycho Nightingale /*-
2*bf21cd93STycho Nightingale  * Copyright (c) 2011 NetApp, Inc.
3*bf21cd93STycho Nightingale  * All rights reserved.
4*bf21cd93STycho Nightingale  *
5*bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
6*bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
7*bf21cd93STycho Nightingale  * are met:
8*bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
9*bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
10*bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
11*bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
12*bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
13*bf21cd93STycho Nightingale  *
14*bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15*bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18*bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*bf21cd93STycho Nightingale  * SUCH DAMAGE.
25*bf21cd93STycho Nightingale  *
26*bf21cd93STycho Nightingale  * $FreeBSD: head/usr.sbin/bhyve/pci_emul.c 269700 2014-08-08 03:49:01Z neel $
27*bf21cd93STycho Nightingale  */
28*bf21cd93STycho Nightingale /*
29*bf21cd93STycho Nightingale  * This file and its contents are supplied under the terms of the
30*bf21cd93STycho Nightingale  * Common Development and Distribution License ("CDDL"), version 1.0.
31*bf21cd93STycho Nightingale  * You may only use this file in accordance with the terms of version
32*bf21cd93STycho Nightingale  * 1.0 of the CDDL.
33*bf21cd93STycho Nightingale  *
34*bf21cd93STycho Nightingale  * A full copy of the text of the CDDL should have accompanied this
35*bf21cd93STycho Nightingale  * source.  A copy of the CDDL is also available via the Internet at
36*bf21cd93STycho Nightingale  * http://www.illumos.org/license/CDDL.
37*bf21cd93STycho Nightingale  *
38*bf21cd93STycho Nightingale  * Copyright 2014 Pluribus Networks Inc.
39*bf21cd93STycho Nightingale  */
40*bf21cd93STycho Nightingale 
41*bf21cd93STycho Nightingale #include <sys/cdefs.h>
42*bf21cd93STycho Nightingale __FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_emul.c 269700 2014-08-08 03:49:01Z neel $");
43*bf21cd93STycho Nightingale 
44*bf21cd93STycho Nightingale #include <sys/param.h>
45*bf21cd93STycho Nightingale #include <sys/linker_set.h>
46*bf21cd93STycho Nightingale #include <sys/errno.h>
47*bf21cd93STycho Nightingale 
48*bf21cd93STycho Nightingale #include <ctype.h>
49*bf21cd93STycho Nightingale #include <pthread.h>
50*bf21cd93STycho Nightingale #include <stdio.h>
51*bf21cd93STycho Nightingale #include <stdlib.h>
52*bf21cd93STycho Nightingale #include <string.h>
53*bf21cd93STycho Nightingale #include <strings.h>
54*bf21cd93STycho Nightingale #include <assert.h>
55*bf21cd93STycho Nightingale #include <stdbool.h>
56*bf21cd93STycho Nightingale 
57*bf21cd93STycho Nightingale #include <machine/vmm.h>
58*bf21cd93STycho Nightingale #include <vmmapi.h>
59*bf21cd93STycho Nightingale 
60*bf21cd93STycho Nightingale #include "acpi.h"
61*bf21cd93STycho Nightingale #include "bhyverun.h"
62*bf21cd93STycho Nightingale #include "inout.h"
63*bf21cd93STycho Nightingale #include "ioapic.h"
64*bf21cd93STycho Nightingale #include "mem.h"
65*bf21cd93STycho Nightingale #include "pci_emul.h"
66*bf21cd93STycho Nightingale #include "pci_irq.h"
67*bf21cd93STycho Nightingale #include "pci_lpc.h"
68*bf21cd93STycho Nightingale 
69*bf21cd93STycho Nightingale #define CONF1_ADDR_PORT    0x0cf8
70*bf21cd93STycho Nightingale #define CONF1_DATA_PORT    0x0cfc
71*bf21cd93STycho Nightingale 
72*bf21cd93STycho Nightingale #define CONF1_ENABLE	   0x80000000ul
73*bf21cd93STycho Nightingale 
74*bf21cd93STycho Nightingale #define	CFGWRITE(pi,off,val,b)						\
75*bf21cd93STycho Nightingale do {									\
76*bf21cd93STycho Nightingale 	if ((b) == 1) {							\
77*bf21cd93STycho Nightingale 		pci_set_cfgdata8((pi),(off),(val));			\
78*bf21cd93STycho Nightingale 	} else if ((b) == 2) {						\
79*bf21cd93STycho Nightingale 		pci_set_cfgdata16((pi),(off),(val));			\
80*bf21cd93STycho Nightingale 	} else {							\
81*bf21cd93STycho Nightingale 		pci_set_cfgdata32((pi),(off),(val));			\
82*bf21cd93STycho Nightingale 	}								\
83*bf21cd93STycho Nightingale } while (0)
84*bf21cd93STycho Nightingale 
85*bf21cd93STycho Nightingale #define	MAXBUSES	(PCI_BUSMAX + 1)
86*bf21cd93STycho Nightingale #define MAXSLOTS	(PCI_SLOTMAX + 1)
87*bf21cd93STycho Nightingale #define	MAXFUNCS	(PCI_FUNCMAX + 1)
88*bf21cd93STycho Nightingale 
89*bf21cd93STycho Nightingale struct funcinfo {
90*bf21cd93STycho Nightingale 	char	*fi_name;
91*bf21cd93STycho Nightingale 	char	*fi_param;
92*bf21cd93STycho Nightingale 	struct pci_devinst *fi_devi;
93*bf21cd93STycho Nightingale };
94*bf21cd93STycho Nightingale 
95*bf21cd93STycho Nightingale struct intxinfo {
96*bf21cd93STycho Nightingale 	int	ii_count;
97*bf21cd93STycho Nightingale 	int	ii_pirq_pin;
98*bf21cd93STycho Nightingale 	int	ii_ioapic_irq;
99*bf21cd93STycho Nightingale };
100*bf21cd93STycho Nightingale 
101*bf21cd93STycho Nightingale struct slotinfo {
102*bf21cd93STycho Nightingale 	struct intxinfo si_intpins[4];
103*bf21cd93STycho Nightingale 	struct funcinfo si_funcs[MAXFUNCS];
104*bf21cd93STycho Nightingale };
105*bf21cd93STycho Nightingale 
106*bf21cd93STycho Nightingale struct businfo {
107*bf21cd93STycho Nightingale 	uint16_t iobase, iolimit;		/* I/O window */
108*bf21cd93STycho Nightingale 	uint32_t membase32, memlimit32;		/* mmio window below 4GB */
109*bf21cd93STycho Nightingale 	uint64_t membase64, memlimit64;		/* mmio window above 4GB */
110*bf21cd93STycho Nightingale 	struct slotinfo slotinfo[MAXSLOTS];
111*bf21cd93STycho Nightingale };
112*bf21cd93STycho Nightingale 
113*bf21cd93STycho Nightingale static struct businfo *pci_businfo[MAXBUSES];
114*bf21cd93STycho Nightingale 
115*bf21cd93STycho Nightingale SET_DECLARE(pci_devemu_set, struct pci_devemu);
116*bf21cd93STycho Nightingale 
117*bf21cd93STycho Nightingale static uint64_t pci_emul_iobase;
118*bf21cd93STycho Nightingale static uint64_t pci_emul_membase32;
119*bf21cd93STycho Nightingale static uint64_t pci_emul_membase64;
120*bf21cd93STycho Nightingale 
121*bf21cd93STycho Nightingale #define	PCI_EMUL_IOBASE		0x2000
122*bf21cd93STycho Nightingale #define	PCI_EMUL_IOLIMIT	0x10000
123*bf21cd93STycho Nightingale 
124*bf21cd93STycho Nightingale #define	PCI_EMUL_ECFG_BASE	0xE0000000		    /* 3.5GB */
125*bf21cd93STycho Nightingale #define	PCI_EMUL_ECFG_SIZE	(MAXBUSES * 1024 * 1024)    /* 1MB per bus */
126*bf21cd93STycho Nightingale SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE);
127*bf21cd93STycho Nightingale 
128*bf21cd93STycho Nightingale #define	PCI_EMUL_MEMLIMIT32	PCI_EMUL_ECFG_BASE
129*bf21cd93STycho Nightingale 
130*bf21cd93STycho Nightingale #define	PCI_EMUL_MEMBASE64	0xD000000000UL
131*bf21cd93STycho Nightingale #define	PCI_EMUL_MEMLIMIT64	0xFD00000000UL
132*bf21cd93STycho Nightingale 
133*bf21cd93STycho Nightingale static struct pci_devemu *pci_emul_finddev(char *name);
134*bf21cd93STycho Nightingale static void pci_lintr_route(struct pci_devinst *pi);
135*bf21cd93STycho Nightingale static void pci_lintr_update(struct pci_devinst *pi);
136*bf21cd93STycho Nightingale static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot,
137*bf21cd93STycho Nightingale     int func, int coff, int bytes, uint32_t *val);
138*bf21cd93STycho Nightingale 
139*bf21cd93STycho Nightingale /*
140*bf21cd93STycho Nightingale  * I/O access
141*bf21cd93STycho Nightingale  */
142*bf21cd93STycho Nightingale 
143*bf21cd93STycho Nightingale /*
144*bf21cd93STycho Nightingale  * Slot options are in the form:
145*bf21cd93STycho Nightingale  *
146*bf21cd93STycho Nightingale  *  <bus>:<slot>:<func>,<emul>[,<config>]
147*bf21cd93STycho Nightingale  *  <slot>[:<func>],<emul>[,<config>]
148*bf21cd93STycho Nightingale  *
149*bf21cd93STycho Nightingale  *  slot is 0..31
150*bf21cd93STycho Nightingale  *  func is 0..7
151*bf21cd93STycho Nightingale  *  emul is a string describing the type of PCI device e.g. virtio-net
152*bf21cd93STycho Nightingale  *  config is an optional string, depending on the device, that can be
153*bf21cd93STycho Nightingale  *  used for configuration.
154*bf21cd93STycho Nightingale  *   Examples are:
155*bf21cd93STycho Nightingale  *     1,virtio-net,tap0
156*bf21cd93STycho Nightingale  *     3:0,dummy
157*bf21cd93STycho Nightingale  */
158*bf21cd93STycho Nightingale static void
159*bf21cd93STycho Nightingale pci_parse_slot_usage(char *aopt)
160*bf21cd93STycho Nightingale {
161*bf21cd93STycho Nightingale 
162*bf21cd93STycho Nightingale 	fprintf(stderr, "Invalid PCI slot info field \"%s\"\n", aopt);
163*bf21cd93STycho Nightingale }
164*bf21cd93STycho Nightingale 
165*bf21cd93STycho Nightingale int
166*bf21cd93STycho Nightingale pci_parse_slot(char *opt)
167*bf21cd93STycho Nightingale {
168*bf21cd93STycho Nightingale 	struct businfo *bi;
169*bf21cd93STycho Nightingale 	struct slotinfo *si;
170*bf21cd93STycho Nightingale 	char *emul, *config, *str, *cp;
171*bf21cd93STycho Nightingale 	int error, bnum, snum, fnum;
172*bf21cd93STycho Nightingale 
173*bf21cd93STycho Nightingale 	error = -1;
174*bf21cd93STycho Nightingale 	str = strdup(opt);
175*bf21cd93STycho Nightingale 
176*bf21cd93STycho Nightingale 	emul = config = NULL;
177*bf21cd93STycho Nightingale 	if ((cp = strchr(str, ',')) != NULL) {
178*bf21cd93STycho Nightingale 		*cp = '\0';
179*bf21cd93STycho Nightingale 		emul = cp + 1;
180*bf21cd93STycho Nightingale 		if ((cp = strchr(emul, ',')) != NULL) {
181*bf21cd93STycho Nightingale 			*cp = '\0';
182*bf21cd93STycho Nightingale 			config = cp + 1;
183*bf21cd93STycho Nightingale 		}
184*bf21cd93STycho Nightingale 	} else {
185*bf21cd93STycho Nightingale 		pci_parse_slot_usage(opt);
186*bf21cd93STycho Nightingale 		goto done;
187*bf21cd93STycho Nightingale 	}
188*bf21cd93STycho Nightingale 
189*bf21cd93STycho Nightingale 	/* <bus>:<slot>:<func> */
190*bf21cd93STycho Nightingale 	if (sscanf(str, "%d:%d:%d", &bnum, &snum, &fnum) != 3) {
191*bf21cd93STycho Nightingale 		bnum = 0;
192*bf21cd93STycho Nightingale 		/* <slot>:<func> */
193*bf21cd93STycho Nightingale 		if (sscanf(str, "%d:%d", &snum, &fnum) != 2) {
194*bf21cd93STycho Nightingale 			fnum = 0;
195*bf21cd93STycho Nightingale 			/* <slot> */
196*bf21cd93STycho Nightingale 			if (sscanf(str, "%d", &snum) != 1) {
197*bf21cd93STycho Nightingale 				snum = -1;
198*bf21cd93STycho Nightingale 			}
199*bf21cd93STycho Nightingale 		}
200*bf21cd93STycho Nightingale 	}
201*bf21cd93STycho Nightingale 
202*bf21cd93STycho Nightingale 	if (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS ||
203*bf21cd93STycho Nightingale 	    fnum < 0 || fnum >= MAXFUNCS) {
204*bf21cd93STycho Nightingale 		pci_parse_slot_usage(opt);
205*bf21cd93STycho Nightingale 		goto done;
206*bf21cd93STycho Nightingale 	}
207*bf21cd93STycho Nightingale 
208*bf21cd93STycho Nightingale 	if (pci_businfo[bnum] == NULL)
209*bf21cd93STycho Nightingale 		pci_businfo[bnum] = calloc(1, sizeof(struct businfo));
210*bf21cd93STycho Nightingale 
211*bf21cd93STycho Nightingale 	bi = pci_businfo[bnum];
212*bf21cd93STycho Nightingale 	si = &bi->slotinfo[snum];
213*bf21cd93STycho Nightingale 
214*bf21cd93STycho Nightingale 	if (si->si_funcs[fnum].fi_name != NULL) {
215*bf21cd93STycho Nightingale 		fprintf(stderr, "pci slot %d:%d already occupied!\n",
216*bf21cd93STycho Nightingale 			snum, fnum);
217*bf21cd93STycho Nightingale 		goto done;
218*bf21cd93STycho Nightingale 	}
219*bf21cd93STycho Nightingale 
220*bf21cd93STycho Nightingale 	if (pci_emul_finddev(emul) == NULL) {
221*bf21cd93STycho Nightingale 		fprintf(stderr, "pci slot %d:%d: unknown device \"%s\"\n",
222*bf21cd93STycho Nightingale 			snum, fnum, emul);
223*bf21cd93STycho Nightingale 		goto done;
224*bf21cd93STycho Nightingale 	}
225*bf21cd93STycho Nightingale 
226*bf21cd93STycho Nightingale 	error = 0;
227*bf21cd93STycho Nightingale 	si->si_funcs[fnum].fi_name = emul;
228*bf21cd93STycho Nightingale 	si->si_funcs[fnum].fi_param = config;
229*bf21cd93STycho Nightingale 
230*bf21cd93STycho Nightingale done:
231*bf21cd93STycho Nightingale 	if (error)
232*bf21cd93STycho Nightingale 		free(str);
233*bf21cd93STycho Nightingale 
234*bf21cd93STycho Nightingale 	return (error);
235*bf21cd93STycho Nightingale }
236*bf21cd93STycho Nightingale 
237*bf21cd93STycho Nightingale static int
238*bf21cd93STycho Nightingale pci_valid_pba_offset(struct pci_devinst *pi, uint64_t offset)
239*bf21cd93STycho Nightingale {
240*bf21cd93STycho Nightingale 
241*bf21cd93STycho Nightingale 	if (offset < pi->pi_msix.pba_offset)
242*bf21cd93STycho Nightingale 		return (0);
243*bf21cd93STycho Nightingale 
244*bf21cd93STycho Nightingale 	if (offset >= pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
245*bf21cd93STycho Nightingale 		return (0);
246*bf21cd93STycho Nightingale 	}
247*bf21cd93STycho Nightingale 
248*bf21cd93STycho Nightingale 	return (1);
249*bf21cd93STycho Nightingale }
250*bf21cd93STycho Nightingale 
251*bf21cd93STycho Nightingale int
252*bf21cd93STycho Nightingale pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,
253*bf21cd93STycho Nightingale 		     uint64_t value)
254*bf21cd93STycho Nightingale {
255*bf21cd93STycho Nightingale 	int msix_entry_offset;
256*bf21cd93STycho Nightingale 	int tab_index;
257*bf21cd93STycho Nightingale 	char *dest;
258*bf21cd93STycho Nightingale 
259*bf21cd93STycho Nightingale 	/* support only 4 or 8 byte writes */
260*bf21cd93STycho Nightingale 	if (size != 4 && size != 8)
261*bf21cd93STycho Nightingale 		return (-1);
262*bf21cd93STycho Nightingale 
263*bf21cd93STycho Nightingale 	/*
264*bf21cd93STycho Nightingale 	 * Return if table index is beyond what device supports
265*bf21cd93STycho Nightingale 	 */
266*bf21cd93STycho Nightingale 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
267*bf21cd93STycho Nightingale 	if (tab_index >= pi->pi_msix.table_count)
268*bf21cd93STycho Nightingale 		return (-1);
269*bf21cd93STycho Nightingale 
270*bf21cd93STycho Nightingale 	msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
271*bf21cd93STycho Nightingale 
272*bf21cd93STycho Nightingale 	/* support only aligned writes */
273*bf21cd93STycho Nightingale 	if ((msix_entry_offset % size) != 0)
274*bf21cd93STycho Nightingale 		return (-1);
275*bf21cd93STycho Nightingale 
276*bf21cd93STycho Nightingale 	dest = (char *)(pi->pi_msix.table + tab_index);
277*bf21cd93STycho Nightingale 	dest += msix_entry_offset;
278*bf21cd93STycho Nightingale 
279*bf21cd93STycho Nightingale 	if (size == 4)
280*bf21cd93STycho Nightingale 		*((uint32_t *)dest) = value;
281*bf21cd93STycho Nightingale 	else
282*bf21cd93STycho Nightingale 		*((uint64_t *)dest) = value;
283*bf21cd93STycho Nightingale 
284*bf21cd93STycho Nightingale 	return (0);
285*bf21cd93STycho Nightingale }
286*bf21cd93STycho Nightingale 
287*bf21cd93STycho Nightingale uint64_t
288*bf21cd93STycho Nightingale pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size)
289*bf21cd93STycho Nightingale {
290*bf21cd93STycho Nightingale 	char *dest;
291*bf21cd93STycho Nightingale 	int msix_entry_offset;
292*bf21cd93STycho Nightingale 	int tab_index;
293*bf21cd93STycho Nightingale 	uint64_t retval = ~0;
294*bf21cd93STycho Nightingale 
295*bf21cd93STycho Nightingale 	/*
296*bf21cd93STycho Nightingale 	 * The PCI standard only allows 4 and 8 byte accesses to the MSI-X
297*bf21cd93STycho Nightingale 	 * table but we also allow 1 byte access to accomodate reads from
298*bf21cd93STycho Nightingale 	 * ddb.
299*bf21cd93STycho Nightingale 	 */
300*bf21cd93STycho Nightingale 	if (size != 1 && size != 4 && size != 8)
301*bf21cd93STycho Nightingale 		return (retval);
302*bf21cd93STycho Nightingale 
303*bf21cd93STycho Nightingale 	msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
304*bf21cd93STycho Nightingale 
305*bf21cd93STycho Nightingale 	/* support only aligned reads */
306*bf21cd93STycho Nightingale 	if ((msix_entry_offset % size) != 0) {
307*bf21cd93STycho Nightingale 		return (retval);
308*bf21cd93STycho Nightingale 	}
309*bf21cd93STycho Nightingale 
310*bf21cd93STycho Nightingale 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
311*bf21cd93STycho Nightingale 
312*bf21cd93STycho Nightingale 	if (tab_index < pi->pi_msix.table_count) {
313*bf21cd93STycho Nightingale 		/* valid MSI-X Table access */
314*bf21cd93STycho Nightingale 		dest = (char *)(pi->pi_msix.table + tab_index);
315*bf21cd93STycho Nightingale 		dest += msix_entry_offset;
316*bf21cd93STycho Nightingale 
317*bf21cd93STycho Nightingale 		if (size == 1)
318*bf21cd93STycho Nightingale 			retval = *((uint8_t *)dest);
319*bf21cd93STycho Nightingale 		else if (size == 4)
320*bf21cd93STycho Nightingale 			retval = *((uint32_t *)dest);
321*bf21cd93STycho Nightingale 		else
322*bf21cd93STycho Nightingale 			retval = *((uint64_t *)dest);
323*bf21cd93STycho Nightingale 	} else if (pci_valid_pba_offset(pi, offset)) {
324*bf21cd93STycho Nightingale 		/* return 0 for PBA access */
325*bf21cd93STycho Nightingale 		retval = 0;
326*bf21cd93STycho Nightingale 	}
327*bf21cd93STycho Nightingale 
328*bf21cd93STycho Nightingale 	return (retval);
329*bf21cd93STycho Nightingale }
330*bf21cd93STycho Nightingale 
331*bf21cd93STycho Nightingale int
332*bf21cd93STycho Nightingale pci_msix_table_bar(struct pci_devinst *pi)
333*bf21cd93STycho Nightingale {
334*bf21cd93STycho Nightingale 
335*bf21cd93STycho Nightingale 	if (pi->pi_msix.table != NULL)
336*bf21cd93STycho Nightingale 		return (pi->pi_msix.table_bar);
337*bf21cd93STycho Nightingale 	else
338*bf21cd93STycho Nightingale 		return (-1);
339*bf21cd93STycho Nightingale }
340*bf21cd93STycho Nightingale 
341*bf21cd93STycho Nightingale int
342*bf21cd93STycho Nightingale pci_msix_pba_bar(struct pci_devinst *pi)
343*bf21cd93STycho Nightingale {
344*bf21cd93STycho Nightingale 
345*bf21cd93STycho Nightingale 	if (pi->pi_msix.table != NULL)
346*bf21cd93STycho Nightingale 		return (pi->pi_msix.pba_bar);
347*bf21cd93STycho Nightingale 	else
348*bf21cd93STycho Nightingale 		return (-1);
349*bf21cd93STycho Nightingale }
350*bf21cd93STycho Nightingale 
351*bf21cd93STycho Nightingale static int
352*bf21cd93STycho Nightingale pci_emul_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
353*bf21cd93STycho Nightingale 		    uint32_t *eax, void *arg)
354*bf21cd93STycho Nightingale {
355*bf21cd93STycho Nightingale 	struct pci_devinst *pdi = arg;
356*bf21cd93STycho Nightingale 	struct pci_devemu *pe = pdi->pi_d;
357*bf21cd93STycho Nightingale 	uint64_t offset;
358*bf21cd93STycho Nightingale 	int i;
359*bf21cd93STycho Nightingale 
360*bf21cd93STycho Nightingale 	for (i = 0; i <= PCI_BARMAX; i++) {
361*bf21cd93STycho Nightingale 		if (pdi->pi_bar[i].type == PCIBAR_IO &&
362*bf21cd93STycho Nightingale 		    port >= pdi->pi_bar[i].addr &&
363*bf21cd93STycho Nightingale 		    port + bytes <= pdi->pi_bar[i].addr + pdi->pi_bar[i].size) {
364*bf21cd93STycho Nightingale 			offset = port - pdi->pi_bar[i].addr;
365*bf21cd93STycho Nightingale 			if (in)
366*bf21cd93STycho Nightingale 				*eax = (*pe->pe_barread)(ctx, vcpu, pdi, i,
367*bf21cd93STycho Nightingale 							 offset, bytes);
368*bf21cd93STycho Nightingale 			else
369*bf21cd93STycho Nightingale 				(*pe->pe_barwrite)(ctx, vcpu, pdi, i, offset,
370*bf21cd93STycho Nightingale 						   bytes, *eax);
371*bf21cd93STycho Nightingale 			return (0);
372*bf21cd93STycho Nightingale 		}
373*bf21cd93STycho Nightingale 	}
374*bf21cd93STycho Nightingale 	return (-1);
375*bf21cd93STycho Nightingale }
376*bf21cd93STycho Nightingale 
377*bf21cd93STycho Nightingale static int
378*bf21cd93STycho Nightingale pci_emul_mem_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
379*bf21cd93STycho Nightingale 		     int size, uint64_t *val, void *arg1, long arg2)
380*bf21cd93STycho Nightingale {
381*bf21cd93STycho Nightingale 	struct pci_devinst *pdi = arg1;
382*bf21cd93STycho Nightingale 	struct pci_devemu *pe = pdi->pi_d;
383*bf21cd93STycho Nightingale 	uint64_t offset;
384*bf21cd93STycho Nightingale 	int bidx = (int) arg2;
385*bf21cd93STycho Nightingale 
386*bf21cd93STycho Nightingale 	assert(bidx <= PCI_BARMAX);
387*bf21cd93STycho Nightingale 	assert(pdi->pi_bar[bidx].type == PCIBAR_MEM32 ||
388*bf21cd93STycho Nightingale 	       pdi->pi_bar[bidx].type == PCIBAR_MEM64);
389*bf21cd93STycho Nightingale 	assert(addr >= pdi->pi_bar[bidx].addr &&
390*bf21cd93STycho Nightingale 	       addr + size <= pdi->pi_bar[bidx].addr + pdi->pi_bar[bidx].size);
391*bf21cd93STycho Nightingale 
392*bf21cd93STycho Nightingale 	offset = addr - pdi->pi_bar[bidx].addr;
393*bf21cd93STycho Nightingale 
394*bf21cd93STycho Nightingale 	if (dir == MEM_F_WRITE) {
395*bf21cd93STycho Nightingale 		if (size == 8) {
396*bf21cd93STycho Nightingale 			(*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset,
397*bf21cd93STycho Nightingale 					   4, *val & 0xffffffff);
398*bf21cd93STycho Nightingale 			(*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset + 4,
399*bf21cd93STycho Nightingale 					   4, *val >> 32);
400*bf21cd93STycho Nightingale 		} else {
401*bf21cd93STycho Nightingale 			(*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset,
402*bf21cd93STycho Nightingale 					   size, *val);
403*bf21cd93STycho Nightingale 		}
404*bf21cd93STycho Nightingale 	} else {
405*bf21cd93STycho Nightingale 		if (size == 8) {
406*bf21cd93STycho Nightingale 			*val = (*pe->pe_barread)(ctx, vcpu, pdi, bidx,
407*bf21cd93STycho Nightingale 						 offset, 4);
408*bf21cd93STycho Nightingale 			*val |= (*pe->pe_barread)(ctx, vcpu, pdi, bidx,
409*bf21cd93STycho Nightingale 						  offset + 4, 4) << 32;
410*bf21cd93STycho Nightingale 		} else {
411*bf21cd93STycho Nightingale 			*val = (*pe->pe_barread)(ctx, vcpu, pdi, bidx,
412*bf21cd93STycho Nightingale 						 offset, size);
413*bf21cd93STycho Nightingale 		}
414*bf21cd93STycho Nightingale 	}
415*bf21cd93STycho Nightingale 
416*bf21cd93STycho Nightingale 	return (0);
417*bf21cd93STycho Nightingale }
418*bf21cd93STycho Nightingale 
419*bf21cd93STycho Nightingale 
420*bf21cd93STycho Nightingale static int
421*bf21cd93STycho Nightingale pci_emul_alloc_resource(uint64_t *baseptr, uint64_t limit, uint64_t size,
422*bf21cd93STycho Nightingale 			uint64_t *addr)
423*bf21cd93STycho Nightingale {
424*bf21cd93STycho Nightingale 	uint64_t base;
425*bf21cd93STycho Nightingale 
426*bf21cd93STycho Nightingale 	assert((size & (size - 1)) == 0);	/* must be a power of 2 */
427*bf21cd93STycho Nightingale 
428*bf21cd93STycho Nightingale 	base = roundup2(*baseptr, size);
429*bf21cd93STycho Nightingale 
430*bf21cd93STycho Nightingale 	if (base + size <= limit) {
431*bf21cd93STycho Nightingale 		*addr = base;
432*bf21cd93STycho Nightingale 		*baseptr = base + size;
433*bf21cd93STycho Nightingale 		return (0);
434*bf21cd93STycho Nightingale 	} else
435*bf21cd93STycho Nightingale 		return (-1);
436*bf21cd93STycho Nightingale }
437*bf21cd93STycho Nightingale 
438*bf21cd93STycho Nightingale int
439*bf21cd93STycho Nightingale pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
440*bf21cd93STycho Nightingale 		   uint64_t size)
441*bf21cd93STycho Nightingale {
442*bf21cd93STycho Nightingale 
443*bf21cd93STycho Nightingale 	return (pci_emul_alloc_pbar(pdi, idx, 0, type, size));
444*bf21cd93STycho Nightingale }
445*bf21cd93STycho Nightingale 
446*bf21cd93STycho Nightingale /*
447*bf21cd93STycho Nightingale  * Register (or unregister) the MMIO or I/O region associated with the BAR
448*bf21cd93STycho Nightingale  * register 'idx' of an emulated pci device.
449*bf21cd93STycho Nightingale  */
450*bf21cd93STycho Nightingale static void
451*bf21cd93STycho Nightingale modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
452*bf21cd93STycho Nightingale {
453*bf21cd93STycho Nightingale 	int error;
454*bf21cd93STycho Nightingale 	struct inout_port iop;
455*bf21cd93STycho Nightingale 	struct mem_range mr;
456*bf21cd93STycho Nightingale 
457*bf21cd93STycho Nightingale 	switch (pi->pi_bar[idx].type) {
458*bf21cd93STycho Nightingale 	case PCIBAR_IO:
459*bf21cd93STycho Nightingale 		bzero(&iop, sizeof(struct inout_port));
460*bf21cd93STycho Nightingale 		iop.name = pi->pi_name;
461*bf21cd93STycho Nightingale 		iop.port = pi->pi_bar[idx].addr;
462*bf21cd93STycho Nightingale 		iop.size = pi->pi_bar[idx].size;
463*bf21cd93STycho Nightingale 		if (registration) {
464*bf21cd93STycho Nightingale 			iop.flags = IOPORT_F_INOUT;
465*bf21cd93STycho Nightingale 			iop.handler = pci_emul_io_handler;
466*bf21cd93STycho Nightingale 			iop.arg = pi;
467*bf21cd93STycho Nightingale 			error = register_inout(&iop);
468*bf21cd93STycho Nightingale 		} else
469*bf21cd93STycho Nightingale 			error = unregister_inout(&iop);
470*bf21cd93STycho Nightingale 		break;
471*bf21cd93STycho Nightingale 	case PCIBAR_MEM32:
472*bf21cd93STycho Nightingale 	case PCIBAR_MEM64:
473*bf21cd93STycho Nightingale 		bzero(&mr, sizeof(struct mem_range));
474*bf21cd93STycho Nightingale 		mr.name = pi->pi_name;
475*bf21cd93STycho Nightingale 		mr.base = pi->pi_bar[idx].addr;
476*bf21cd93STycho Nightingale 		mr.size = pi->pi_bar[idx].size;
477*bf21cd93STycho Nightingale 		if (registration) {
478*bf21cd93STycho Nightingale 			mr.flags = MEM_F_RW;
479*bf21cd93STycho Nightingale 			mr.handler = pci_emul_mem_handler;
480*bf21cd93STycho Nightingale 			mr.arg1 = pi;
481*bf21cd93STycho Nightingale 			mr.arg2 = idx;
482*bf21cd93STycho Nightingale 			error = register_mem(&mr);
483*bf21cd93STycho Nightingale 		} else
484*bf21cd93STycho Nightingale 			error = unregister_mem(&mr);
485*bf21cd93STycho Nightingale 		break;
486*bf21cd93STycho Nightingale 	default:
487*bf21cd93STycho Nightingale 		error = EINVAL;
488*bf21cd93STycho Nightingale 		break;
489*bf21cd93STycho Nightingale 	}
490*bf21cd93STycho Nightingale 	assert(error == 0);
491*bf21cd93STycho Nightingale }
492*bf21cd93STycho Nightingale 
493*bf21cd93STycho Nightingale static void
494*bf21cd93STycho Nightingale unregister_bar(struct pci_devinst *pi, int idx)
495*bf21cd93STycho Nightingale {
496*bf21cd93STycho Nightingale 
497*bf21cd93STycho Nightingale 	modify_bar_registration(pi, idx, 0);
498*bf21cd93STycho Nightingale }
499*bf21cd93STycho Nightingale 
500*bf21cd93STycho Nightingale static void
501*bf21cd93STycho Nightingale register_bar(struct pci_devinst *pi, int idx)
502*bf21cd93STycho Nightingale {
503*bf21cd93STycho Nightingale 
504*bf21cd93STycho Nightingale 	modify_bar_registration(pi, idx, 1);
505*bf21cd93STycho Nightingale }
506*bf21cd93STycho Nightingale 
507*bf21cd93STycho Nightingale /* Are we decoding i/o port accesses for the emulated pci device? */
508*bf21cd93STycho Nightingale static int
509*bf21cd93STycho Nightingale porten(struct pci_devinst *pi)
510*bf21cd93STycho Nightingale {
511*bf21cd93STycho Nightingale 	uint16_t cmd;
512*bf21cd93STycho Nightingale 
513*bf21cd93STycho Nightingale 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
514*bf21cd93STycho Nightingale 
515*bf21cd93STycho Nightingale 	return (cmd & PCIM_CMD_PORTEN);
516*bf21cd93STycho Nightingale }
517*bf21cd93STycho Nightingale 
518*bf21cd93STycho Nightingale /* Are we decoding memory accesses for the emulated pci device? */
519*bf21cd93STycho Nightingale static int
520*bf21cd93STycho Nightingale memen(struct pci_devinst *pi)
521*bf21cd93STycho Nightingale {
522*bf21cd93STycho Nightingale 	uint16_t cmd;
523*bf21cd93STycho Nightingale 
524*bf21cd93STycho Nightingale 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
525*bf21cd93STycho Nightingale 
526*bf21cd93STycho Nightingale 	return (cmd & PCIM_CMD_MEMEN);
527*bf21cd93STycho Nightingale }
528*bf21cd93STycho Nightingale 
529*bf21cd93STycho Nightingale /*
530*bf21cd93STycho Nightingale  * Update the MMIO or I/O address that is decoded by the BAR register.
531*bf21cd93STycho Nightingale  *
532*bf21cd93STycho Nightingale  * If the pci device has enabled the address space decoding then intercept
533*bf21cd93STycho Nightingale  * the address range decoded by the BAR register.
534*bf21cd93STycho Nightingale  */
535*bf21cd93STycho Nightingale static void
536*bf21cd93STycho Nightingale update_bar_address(struct  pci_devinst *pi, uint64_t addr, int idx, int type)
537*bf21cd93STycho Nightingale {
538*bf21cd93STycho Nightingale 	int decode;
539*bf21cd93STycho Nightingale 
540*bf21cd93STycho Nightingale 	if (pi->pi_bar[idx].type == PCIBAR_IO)
541*bf21cd93STycho Nightingale 		decode = porten(pi);
542*bf21cd93STycho Nightingale 	else
543*bf21cd93STycho Nightingale 		decode = memen(pi);
544*bf21cd93STycho Nightingale 
545*bf21cd93STycho Nightingale 	if (decode)
546*bf21cd93STycho Nightingale 		unregister_bar(pi, idx);
547*bf21cd93STycho Nightingale 
548*bf21cd93STycho Nightingale 	switch (type) {
549*bf21cd93STycho Nightingale 	case PCIBAR_IO:
550*bf21cd93STycho Nightingale 	case PCIBAR_MEM32:
551*bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr = addr;
552*bf21cd93STycho Nightingale 		break;
553*bf21cd93STycho Nightingale 	case PCIBAR_MEM64:
554*bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr &= ~0xffffffffUL;
555*bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr |= addr;
556*bf21cd93STycho Nightingale 		break;
557*bf21cd93STycho Nightingale 	case PCIBAR_MEMHI64:
558*bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr &= 0xffffffff;
559*bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr |= addr;
560*bf21cd93STycho Nightingale 		break;
561*bf21cd93STycho Nightingale 	default:
562*bf21cd93STycho Nightingale 		assert(0);
563*bf21cd93STycho Nightingale 	}
564*bf21cd93STycho Nightingale 
565*bf21cd93STycho Nightingale 	if (decode)
566*bf21cd93STycho Nightingale 		register_bar(pi, idx);
567*bf21cd93STycho Nightingale }
568*bf21cd93STycho Nightingale 
569*bf21cd93STycho Nightingale int
570*bf21cd93STycho Nightingale pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
571*bf21cd93STycho Nightingale 		    enum pcibar_type type, uint64_t size)
572*bf21cd93STycho Nightingale {
573*bf21cd93STycho Nightingale 	int error;
574*bf21cd93STycho Nightingale 	uint64_t *baseptr, limit, addr, mask, lobits, bar;
575*bf21cd93STycho Nightingale 
576*bf21cd93STycho Nightingale 	assert(idx >= 0 && idx <= PCI_BARMAX);
577*bf21cd93STycho Nightingale 
578*bf21cd93STycho Nightingale 	if ((size & (size - 1)) != 0)
579*bf21cd93STycho Nightingale 		size = 1UL << flsl(size);	/* round up to a power of 2 */
580*bf21cd93STycho Nightingale 
581*bf21cd93STycho Nightingale 	/* Enforce minimum BAR sizes required by the PCI standard */
582*bf21cd93STycho Nightingale 	if (type == PCIBAR_IO) {
583*bf21cd93STycho Nightingale 		if (size < 4)
584*bf21cd93STycho Nightingale 			size = 4;
585*bf21cd93STycho Nightingale 	} else {
586*bf21cd93STycho Nightingale 		if (size < 16)
587*bf21cd93STycho Nightingale 			size = 16;
588*bf21cd93STycho Nightingale 	}
589*bf21cd93STycho Nightingale 
590*bf21cd93STycho Nightingale 	switch (type) {
591*bf21cd93STycho Nightingale 	case PCIBAR_NONE:
592*bf21cd93STycho Nightingale 		baseptr = NULL;
593*bf21cd93STycho Nightingale 		addr = mask = lobits = 0;
594*bf21cd93STycho Nightingale 		break;
595*bf21cd93STycho Nightingale 	case PCIBAR_IO:
596*bf21cd93STycho Nightingale 		baseptr = &pci_emul_iobase;
597*bf21cd93STycho Nightingale 		limit = PCI_EMUL_IOLIMIT;
598*bf21cd93STycho Nightingale 		mask = PCIM_BAR_IO_BASE;
599*bf21cd93STycho Nightingale 		lobits = PCIM_BAR_IO_SPACE;
600*bf21cd93STycho Nightingale 		break;
601*bf21cd93STycho Nightingale 	case PCIBAR_MEM64:
602*bf21cd93STycho Nightingale 		/*
603*bf21cd93STycho Nightingale 		 * XXX
604*bf21cd93STycho Nightingale 		 * Some drivers do not work well if the 64-bit BAR is allocated
605*bf21cd93STycho Nightingale 		 * above 4GB. Allow for this by allocating small requests under
606*bf21cd93STycho Nightingale 		 * 4GB unless then allocation size is larger than some arbitrary
607*bf21cd93STycho Nightingale 		 * number (32MB currently).
608*bf21cd93STycho Nightingale 		 */
609*bf21cd93STycho Nightingale 		if (size > 32 * 1024 * 1024) {
610*bf21cd93STycho Nightingale 			/*
611*bf21cd93STycho Nightingale 			 * XXX special case for device requiring peer-peer DMA
612*bf21cd93STycho Nightingale 			 */
613*bf21cd93STycho Nightingale 			if (size == 0x100000000UL)
614*bf21cd93STycho Nightingale 				baseptr = &hostbase;
615*bf21cd93STycho Nightingale 			else
616*bf21cd93STycho Nightingale 				baseptr = &pci_emul_membase64;
617*bf21cd93STycho Nightingale 			limit = PCI_EMUL_MEMLIMIT64;
618*bf21cd93STycho Nightingale 			mask = PCIM_BAR_MEM_BASE;
619*bf21cd93STycho Nightingale 			lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
620*bf21cd93STycho Nightingale 				 PCIM_BAR_MEM_PREFETCH;
621*bf21cd93STycho Nightingale 			break;
622*bf21cd93STycho Nightingale 		} else {
623*bf21cd93STycho Nightingale 			baseptr = &pci_emul_membase32;
624*bf21cd93STycho Nightingale 			limit = PCI_EMUL_MEMLIMIT32;
625*bf21cd93STycho Nightingale 			mask = PCIM_BAR_MEM_BASE;
626*bf21cd93STycho Nightingale 			lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64;
627*bf21cd93STycho Nightingale 		}
628*bf21cd93STycho Nightingale 		break;
629*bf21cd93STycho Nightingale 	case PCIBAR_MEM32:
630*bf21cd93STycho Nightingale 		baseptr = &pci_emul_membase32;
631*bf21cd93STycho Nightingale 		limit = PCI_EMUL_MEMLIMIT32;
632*bf21cd93STycho Nightingale 		mask = PCIM_BAR_MEM_BASE;
633*bf21cd93STycho Nightingale 		lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
634*bf21cd93STycho Nightingale 		break;
635*bf21cd93STycho Nightingale 	default:
636*bf21cd93STycho Nightingale 		printf("pci_emul_alloc_base: invalid bar type %d\n", type);
637*bf21cd93STycho Nightingale 		assert(0);
638*bf21cd93STycho Nightingale 	}
639*bf21cd93STycho Nightingale 
640*bf21cd93STycho Nightingale 	if (baseptr != NULL) {
641*bf21cd93STycho Nightingale 		error = pci_emul_alloc_resource(baseptr, limit, size, &addr);
642*bf21cd93STycho Nightingale 		if (error != 0)
643*bf21cd93STycho Nightingale 			return (error);
644*bf21cd93STycho Nightingale 	}
645*bf21cd93STycho Nightingale 
646*bf21cd93STycho Nightingale 	pdi->pi_bar[idx].type = type;
647*bf21cd93STycho Nightingale 	pdi->pi_bar[idx].addr = addr;
648*bf21cd93STycho Nightingale 	pdi->pi_bar[idx].size = size;
649*bf21cd93STycho Nightingale 
650*bf21cd93STycho Nightingale 	/* Initialize the BAR register in config space */
651*bf21cd93STycho Nightingale 	bar = (addr & mask) | lobits;
652*bf21cd93STycho Nightingale 	pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar);
653*bf21cd93STycho Nightingale 
654*bf21cd93STycho Nightingale 	if (type == PCIBAR_MEM64) {
655*bf21cd93STycho Nightingale 		assert(idx + 1 <= PCI_BARMAX);
656*bf21cd93STycho Nightingale 		pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64;
657*bf21cd93STycho Nightingale 		pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
658*bf21cd93STycho Nightingale 	}
659*bf21cd93STycho Nightingale 
660*bf21cd93STycho Nightingale 	register_bar(pdi, idx);
661*bf21cd93STycho Nightingale 
662*bf21cd93STycho Nightingale 	return (0);
663*bf21cd93STycho Nightingale }
664*bf21cd93STycho Nightingale 
665*bf21cd93STycho Nightingale #define	CAP_START_OFFSET	0x40
666*bf21cd93STycho Nightingale static int
667*bf21cd93STycho Nightingale pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)
668*bf21cd93STycho Nightingale {
669*bf21cd93STycho Nightingale 	int i, capoff, reallen;
670*bf21cd93STycho Nightingale 	uint16_t sts;
671*bf21cd93STycho Nightingale 
672*bf21cd93STycho Nightingale 	assert(caplen > 0);
673*bf21cd93STycho Nightingale 
674*bf21cd93STycho Nightingale 	reallen = roundup2(caplen, 4);		/* dword aligned */
675*bf21cd93STycho Nightingale 
676*bf21cd93STycho Nightingale 	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
677*bf21cd93STycho Nightingale 	if ((sts & PCIM_STATUS_CAPPRESENT) == 0)
678*bf21cd93STycho Nightingale 		capoff = CAP_START_OFFSET;
679*bf21cd93STycho Nightingale 	else
680*bf21cd93STycho Nightingale 		capoff = pi->pi_capend + 1;
681*bf21cd93STycho Nightingale 
682*bf21cd93STycho Nightingale 	/* Check if we have enough space */
683*bf21cd93STycho Nightingale 	if (capoff + reallen > PCI_REGMAX + 1)
684*bf21cd93STycho Nightingale 		return (-1);
685*bf21cd93STycho Nightingale 
686*bf21cd93STycho Nightingale 	/* Set the previous capability pointer */
687*bf21cd93STycho Nightingale 	if ((sts & PCIM_STATUS_CAPPRESENT) == 0) {
688*bf21cd93STycho Nightingale 		pci_set_cfgdata8(pi, PCIR_CAP_PTR, capoff);
689*bf21cd93STycho Nightingale 		pci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT);
690*bf21cd93STycho Nightingale 	} else
691*bf21cd93STycho Nightingale 		pci_set_cfgdata8(pi, pi->pi_prevcap + 1, capoff);
692*bf21cd93STycho Nightingale 
693*bf21cd93STycho Nightingale 	/* Copy the capability */
694*bf21cd93STycho Nightingale 	for (i = 0; i < caplen; i++)
695*bf21cd93STycho Nightingale 		pci_set_cfgdata8(pi, capoff + i, capdata[i]);
696*bf21cd93STycho Nightingale 
697*bf21cd93STycho Nightingale 	/* Set the next capability pointer */
698*bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, capoff + 1, 0);
699*bf21cd93STycho Nightingale 
700*bf21cd93STycho Nightingale 	pi->pi_prevcap = capoff;
701*bf21cd93STycho Nightingale 	pi->pi_capend = capoff + reallen - 1;
702*bf21cd93STycho Nightingale 	return (0);
703*bf21cd93STycho Nightingale }
704*bf21cd93STycho Nightingale 
705*bf21cd93STycho Nightingale static struct pci_devemu *
706*bf21cd93STycho Nightingale pci_emul_finddev(char *name)
707*bf21cd93STycho Nightingale {
708*bf21cd93STycho Nightingale 	struct pci_devemu **pdpp, *pdp;
709*bf21cd93STycho Nightingale 
710*bf21cd93STycho Nightingale 	SET_FOREACH(pdpp, pci_devemu_set) {
711*bf21cd93STycho Nightingale 		pdp = *pdpp;
712*bf21cd93STycho Nightingale 		if (!strcmp(pdp->pe_emu, name)) {
713*bf21cd93STycho Nightingale 			return (pdp);
714*bf21cd93STycho Nightingale 		}
715*bf21cd93STycho Nightingale 	}
716*bf21cd93STycho Nightingale 
717*bf21cd93STycho Nightingale 	return (NULL);
718*bf21cd93STycho Nightingale }
719*bf21cd93STycho Nightingale 
720*bf21cd93STycho Nightingale static int
721*bf21cd93STycho Nightingale pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot,
722*bf21cd93STycho Nightingale     int func, struct funcinfo *fi)
723*bf21cd93STycho Nightingale {
724*bf21cd93STycho Nightingale 	struct pci_devinst *pdi;
725*bf21cd93STycho Nightingale 	int err;
726*bf21cd93STycho Nightingale 
727*bf21cd93STycho Nightingale 	pdi = calloc(1, sizeof(struct pci_devinst));
728*bf21cd93STycho Nightingale 
729*bf21cd93STycho Nightingale 	pdi->pi_vmctx = ctx;
730*bf21cd93STycho Nightingale 	pdi->pi_bus = bus;
731*bf21cd93STycho Nightingale 	pdi->pi_slot = slot;
732*bf21cd93STycho Nightingale 	pdi->pi_func = func;
733*bf21cd93STycho Nightingale 	pthread_mutex_init(&pdi->pi_lintr.lock, NULL);
734*bf21cd93STycho Nightingale 	pdi->pi_lintr.pin = 0;
735*bf21cd93STycho Nightingale 	pdi->pi_lintr.state = IDLE;
736*bf21cd93STycho Nightingale 	pdi->pi_lintr.pirq_pin = 0;
737*bf21cd93STycho Nightingale 	pdi->pi_lintr.ioapic_irq = 0;
738*bf21cd93STycho Nightingale 	pdi->pi_d = pde;
739*bf21cd93STycho Nightingale 	snprintf(pdi->pi_name, PI_NAMESZ, "%s-pci-%d", pde->pe_emu, slot);
740*bf21cd93STycho Nightingale 
741*bf21cd93STycho Nightingale 	/* Disable legacy interrupts */
742*bf21cd93STycho Nightingale 	pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
743*bf21cd93STycho Nightingale 	pci_set_cfgdata8(pdi, PCIR_INTPIN, 0);
744*bf21cd93STycho Nightingale 
745*bf21cd93STycho Nightingale 	pci_set_cfgdata8(pdi, PCIR_COMMAND,
746*bf21cd93STycho Nightingale 		    PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
747*bf21cd93STycho Nightingale 
748*bf21cd93STycho Nightingale 	err = (*pde->pe_init)(ctx, pdi, fi->fi_param);
749*bf21cd93STycho Nightingale 	if (err == 0)
750*bf21cd93STycho Nightingale 		fi->fi_devi = pdi;
751*bf21cd93STycho Nightingale 	else
752*bf21cd93STycho Nightingale 		free(pdi);
753*bf21cd93STycho Nightingale 
754*bf21cd93STycho Nightingale 	return (err);
755*bf21cd93STycho Nightingale }
756*bf21cd93STycho Nightingale 
757*bf21cd93STycho Nightingale void
758*bf21cd93STycho Nightingale pci_populate_msicap(struct msicap *msicap, int msgnum, int nextptr)
759*bf21cd93STycho Nightingale {
760*bf21cd93STycho Nightingale 	int mmc;
761*bf21cd93STycho Nightingale 
762*bf21cd93STycho Nightingale 	CTASSERT(sizeof(struct msicap) == 14);
763*bf21cd93STycho Nightingale 
764*bf21cd93STycho Nightingale 	/* Number of msi messages must be a power of 2 between 1 and 32 */
765*bf21cd93STycho Nightingale 	assert((msgnum & (msgnum - 1)) == 0 && msgnum >= 1 && msgnum <= 32);
766*bf21cd93STycho Nightingale 	mmc = ffs(msgnum) - 1;
767*bf21cd93STycho Nightingale 
768*bf21cd93STycho Nightingale 	bzero(msicap, sizeof(struct msicap));
769*bf21cd93STycho Nightingale 	msicap->capid = PCIY_MSI;
770*bf21cd93STycho Nightingale 	msicap->nextptr = nextptr;
771*bf21cd93STycho Nightingale 	msicap->msgctrl = PCIM_MSICTRL_64BIT | (mmc << 1);
772*bf21cd93STycho Nightingale }
773*bf21cd93STycho Nightingale 
774*bf21cd93STycho Nightingale int
775*bf21cd93STycho Nightingale pci_emul_add_msicap(struct pci_devinst *pi, int msgnum)
776*bf21cd93STycho Nightingale {
777*bf21cd93STycho Nightingale 	struct msicap msicap;
778*bf21cd93STycho Nightingale 
779*bf21cd93STycho Nightingale 	pci_populate_msicap(&msicap, msgnum, 0);
780*bf21cd93STycho Nightingale 
781*bf21cd93STycho Nightingale 	return (pci_emul_add_capability(pi, (u_char *)&msicap, sizeof(msicap)));
782*bf21cd93STycho Nightingale }
783*bf21cd93STycho Nightingale 
784*bf21cd93STycho Nightingale static void
785*bf21cd93STycho Nightingale pci_populate_msixcap(struct msixcap *msixcap, int msgnum, int barnum,
786*bf21cd93STycho Nightingale 		     uint32_t msix_tab_size)
787*bf21cd93STycho Nightingale {
788*bf21cd93STycho Nightingale 	CTASSERT(sizeof(struct msixcap) == 12);
789*bf21cd93STycho Nightingale 
790*bf21cd93STycho Nightingale 	assert(msix_tab_size % 4096 == 0);
791*bf21cd93STycho Nightingale 
792*bf21cd93STycho Nightingale 	bzero(msixcap, sizeof(struct msixcap));
793*bf21cd93STycho Nightingale 	msixcap->capid = PCIY_MSIX;
794*bf21cd93STycho Nightingale 
795*bf21cd93STycho Nightingale 	/*
796*bf21cd93STycho Nightingale 	 * Message Control Register, all fields set to
797*bf21cd93STycho Nightingale 	 * zero except for the Table Size.
798*bf21cd93STycho Nightingale 	 * Note: Table size N is encoded as N-1
799*bf21cd93STycho Nightingale 	 */
800*bf21cd93STycho Nightingale 	msixcap->msgctrl = msgnum - 1;
801*bf21cd93STycho Nightingale 
802*bf21cd93STycho Nightingale 	/*
803*bf21cd93STycho Nightingale 	 * MSI-X BAR setup:
804*bf21cd93STycho Nightingale 	 * - MSI-X table start at offset 0
805*bf21cd93STycho Nightingale 	 * - PBA table starts at a 4K aligned offset after the MSI-X table
806*bf21cd93STycho Nightingale 	 */
807*bf21cd93STycho Nightingale 	msixcap->table_info = barnum & PCIM_MSIX_BIR_MASK;
808*bf21cd93STycho Nightingale 	msixcap->pba_info = msix_tab_size | (barnum & PCIM_MSIX_BIR_MASK);
809*bf21cd93STycho Nightingale }
810*bf21cd93STycho Nightingale 
811*bf21cd93STycho Nightingale static void
812*bf21cd93STycho Nightingale pci_msix_table_init(struct pci_devinst *pi, int table_entries)
813*bf21cd93STycho Nightingale {
814*bf21cd93STycho Nightingale 	int i, table_size;
815*bf21cd93STycho Nightingale 
816*bf21cd93STycho Nightingale 	assert(table_entries > 0);
817*bf21cd93STycho Nightingale 	assert(table_entries <= MAX_MSIX_TABLE_ENTRIES);
818*bf21cd93STycho Nightingale 
819*bf21cd93STycho Nightingale 	table_size = table_entries * MSIX_TABLE_ENTRY_SIZE;
820*bf21cd93STycho Nightingale 	pi->pi_msix.table = calloc(1, table_size);
821*bf21cd93STycho Nightingale 
822*bf21cd93STycho Nightingale 	/* set mask bit of vector control register */
823*bf21cd93STycho Nightingale 	for (i = 0; i < table_entries; i++)
824*bf21cd93STycho Nightingale 		pi->pi_msix.table[i].vector_control |= PCIM_MSIX_VCTRL_MASK;
825*bf21cd93STycho Nightingale }
826*bf21cd93STycho Nightingale 
827*bf21cd93STycho Nightingale int
828*bf21cd93STycho Nightingale pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum)
829*bf21cd93STycho Nightingale {
830*bf21cd93STycho Nightingale 	uint32_t tab_size;
831*bf21cd93STycho Nightingale 	struct msixcap msixcap;
832*bf21cd93STycho Nightingale 
833*bf21cd93STycho Nightingale 	assert(msgnum >= 1 && msgnum <= MAX_MSIX_TABLE_ENTRIES);
834*bf21cd93STycho Nightingale 	assert(barnum >= 0 && barnum <= PCIR_MAX_BAR_0);
835*bf21cd93STycho Nightingale 
836*bf21cd93STycho Nightingale 	tab_size = msgnum * MSIX_TABLE_ENTRY_SIZE;
837*bf21cd93STycho Nightingale 
838*bf21cd93STycho Nightingale 	/* Align table size to nearest 4K */
839*bf21cd93STycho Nightingale 	tab_size = roundup2(tab_size, 4096);
840*bf21cd93STycho Nightingale 
841*bf21cd93STycho Nightingale 	pi->pi_msix.table_bar = barnum;
842*bf21cd93STycho Nightingale 	pi->pi_msix.pba_bar   = barnum;
843*bf21cd93STycho Nightingale 	pi->pi_msix.table_offset = 0;
844*bf21cd93STycho Nightingale 	pi->pi_msix.table_count = msgnum;
845*bf21cd93STycho Nightingale 	pi->pi_msix.pba_offset = tab_size;
846*bf21cd93STycho Nightingale 	pi->pi_msix.pba_size = PBA_SIZE(msgnum);
847*bf21cd93STycho Nightingale 
848*bf21cd93STycho Nightingale 	pci_msix_table_init(pi, msgnum);
849*bf21cd93STycho Nightingale 
850*bf21cd93STycho Nightingale 	pci_populate_msixcap(&msixcap, msgnum, barnum, tab_size);
851*bf21cd93STycho Nightingale 
852*bf21cd93STycho Nightingale 	/* allocate memory for MSI-X Table and PBA */
853*bf21cd93STycho Nightingale 	pci_emul_alloc_bar(pi, barnum, PCIBAR_MEM32,
854*bf21cd93STycho Nightingale 				tab_size + pi->pi_msix.pba_size);
855*bf21cd93STycho Nightingale 
856*bf21cd93STycho Nightingale 	return (pci_emul_add_capability(pi, (u_char *)&msixcap,
857*bf21cd93STycho Nightingale 					sizeof(msixcap)));
858*bf21cd93STycho Nightingale }
859*bf21cd93STycho Nightingale 
860*bf21cd93STycho Nightingale void
861*bf21cd93STycho Nightingale msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
862*bf21cd93STycho Nightingale 		 int bytes, uint32_t val)
863*bf21cd93STycho Nightingale {
864*bf21cd93STycho Nightingale 	uint16_t msgctrl, rwmask;
865*bf21cd93STycho Nightingale 	int off, table_bar;
866*bf21cd93STycho Nightingale 
867*bf21cd93STycho Nightingale 	off = offset - capoff;
868*bf21cd93STycho Nightingale 	table_bar = pi->pi_msix.table_bar;
869*bf21cd93STycho Nightingale 	/* Message Control Register */
870*bf21cd93STycho Nightingale 	if (off == 2 && bytes == 2) {
871*bf21cd93STycho Nightingale 		rwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK;
872*bf21cd93STycho Nightingale 		msgctrl = pci_get_cfgdata16(pi, offset);
873*bf21cd93STycho Nightingale 		msgctrl &= ~rwmask;
874*bf21cd93STycho Nightingale 		msgctrl |= val & rwmask;
875*bf21cd93STycho Nightingale 		val = msgctrl;
876*bf21cd93STycho Nightingale 
877*bf21cd93STycho Nightingale 		pi->pi_msix.enabled = val & PCIM_MSIXCTRL_MSIX_ENABLE;
878*bf21cd93STycho Nightingale 		pi->pi_msix.function_mask = val & PCIM_MSIXCTRL_FUNCTION_MASK;
879*bf21cd93STycho Nightingale 		pci_lintr_update(pi);
880*bf21cd93STycho Nightingale 	}
881*bf21cd93STycho Nightingale 
882*bf21cd93STycho Nightingale 	CFGWRITE(pi, offset, val, bytes);
883*bf21cd93STycho Nightingale }
884*bf21cd93STycho Nightingale 
885*bf21cd93STycho Nightingale void
886*bf21cd93STycho Nightingale msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
887*bf21cd93STycho Nightingale 		int bytes, uint32_t val)
888*bf21cd93STycho Nightingale {
889*bf21cd93STycho Nightingale 	uint16_t msgctrl, rwmask, msgdata, mme;
890*bf21cd93STycho Nightingale 	uint32_t addrlo;
891*bf21cd93STycho Nightingale 
892*bf21cd93STycho Nightingale 	/*
893*bf21cd93STycho Nightingale 	 * If guest is writing to the message control register make sure
894*bf21cd93STycho Nightingale 	 * we do not overwrite read-only fields.
895*bf21cd93STycho Nightingale 	 */
896*bf21cd93STycho Nightingale 	if ((offset - capoff) == 2 && bytes == 2) {
897*bf21cd93STycho Nightingale 		rwmask = PCIM_MSICTRL_MME_MASK | PCIM_MSICTRL_MSI_ENABLE;
898*bf21cd93STycho Nightingale 		msgctrl = pci_get_cfgdata16(pi, offset);
899*bf21cd93STycho Nightingale 		msgctrl &= ~rwmask;
900*bf21cd93STycho Nightingale 		msgctrl |= val & rwmask;
901*bf21cd93STycho Nightingale 		val = msgctrl;
902*bf21cd93STycho Nightingale 
903*bf21cd93STycho Nightingale 		addrlo = pci_get_cfgdata32(pi, capoff + 4);
904*bf21cd93STycho Nightingale 		if (msgctrl & PCIM_MSICTRL_64BIT)
905*bf21cd93STycho Nightingale 			msgdata = pci_get_cfgdata16(pi, capoff + 12);
906*bf21cd93STycho Nightingale 		else
907*bf21cd93STycho Nightingale 			msgdata = pci_get_cfgdata16(pi, capoff + 8);
908*bf21cd93STycho Nightingale 
909*bf21cd93STycho Nightingale 		mme = msgctrl & PCIM_MSICTRL_MME_MASK;
910*bf21cd93STycho Nightingale 		pi->pi_msi.enabled = msgctrl & PCIM_MSICTRL_MSI_ENABLE ? 1 : 0;
911*bf21cd93STycho Nightingale 		if (pi->pi_msi.enabled) {
912*bf21cd93STycho Nightingale 			pi->pi_msi.addr = addrlo;
913*bf21cd93STycho Nightingale 			pi->pi_msi.msg_data = msgdata;
914*bf21cd93STycho Nightingale 			pi->pi_msi.maxmsgnum = 1 << (mme >> 4);
915*bf21cd93STycho Nightingale 		} else {
916*bf21cd93STycho Nightingale 			pi->pi_msi.maxmsgnum = 0;
917*bf21cd93STycho Nightingale 		}
918*bf21cd93STycho Nightingale 		pci_lintr_update(pi);
919*bf21cd93STycho Nightingale 	}
920*bf21cd93STycho Nightingale 
921*bf21cd93STycho Nightingale 	CFGWRITE(pi, offset, val, bytes);
922*bf21cd93STycho Nightingale }
923*bf21cd93STycho Nightingale 
924*bf21cd93STycho Nightingale void
925*bf21cd93STycho Nightingale pciecap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
926*bf21cd93STycho Nightingale 		 int bytes, uint32_t val)
927*bf21cd93STycho Nightingale {
928*bf21cd93STycho Nightingale 
929*bf21cd93STycho Nightingale 	/* XXX don't write to the readonly parts */
930*bf21cd93STycho Nightingale 	CFGWRITE(pi, offset, val, bytes);
931*bf21cd93STycho Nightingale }
932*bf21cd93STycho Nightingale 
933*bf21cd93STycho Nightingale #define	PCIECAP_VERSION	0x2
934*bf21cd93STycho Nightingale int
935*bf21cd93STycho Nightingale pci_emul_add_pciecap(struct pci_devinst *pi, int type)
936*bf21cd93STycho Nightingale {
937*bf21cd93STycho Nightingale 	int err;
938*bf21cd93STycho Nightingale 	struct pciecap pciecap;
939*bf21cd93STycho Nightingale 
940*bf21cd93STycho Nightingale 	CTASSERT(sizeof(struct pciecap) == 60);
941*bf21cd93STycho Nightingale 
942*bf21cd93STycho Nightingale 	if (type != PCIEM_TYPE_ROOT_PORT)
943*bf21cd93STycho Nightingale 		return (-1);
944*bf21cd93STycho Nightingale 
945*bf21cd93STycho Nightingale 	bzero(&pciecap, sizeof(pciecap));
946*bf21cd93STycho Nightingale 
947*bf21cd93STycho Nightingale 	pciecap.capid = PCIY_EXPRESS;
948*bf21cd93STycho Nightingale 	pciecap.pcie_capabilities = PCIECAP_VERSION | PCIEM_TYPE_ROOT_PORT;
949*bf21cd93STycho Nightingale 	pciecap.link_capabilities = 0x411;	/* gen1, x1 */
950*bf21cd93STycho Nightingale 	pciecap.link_status = 0x11;		/* gen1, x1 */
951*bf21cd93STycho Nightingale 
952*bf21cd93STycho Nightingale 	err = pci_emul_add_capability(pi, (u_char *)&pciecap, sizeof(pciecap));
953*bf21cd93STycho Nightingale 	return (err);
954*bf21cd93STycho Nightingale }
955*bf21cd93STycho Nightingale 
956*bf21cd93STycho Nightingale /*
957*bf21cd93STycho Nightingale  * This function assumes that 'coff' is in the capabilities region of the
958*bf21cd93STycho Nightingale  * config space.
959*bf21cd93STycho Nightingale  */
960*bf21cd93STycho Nightingale static void
961*bf21cd93STycho Nightingale pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
962*bf21cd93STycho Nightingale {
963*bf21cd93STycho Nightingale 	int capid;
964*bf21cd93STycho Nightingale 	uint8_t capoff, nextoff;
965*bf21cd93STycho Nightingale 
966*bf21cd93STycho Nightingale 	/* Do not allow un-aligned writes */
967*bf21cd93STycho Nightingale 	if ((offset & (bytes - 1)) != 0)
968*bf21cd93STycho Nightingale 		return;
969*bf21cd93STycho Nightingale 
970*bf21cd93STycho Nightingale 	/* Find the capability that we want to update */
971*bf21cd93STycho Nightingale 	capoff = CAP_START_OFFSET;
972*bf21cd93STycho Nightingale 	while (1) {
973*bf21cd93STycho Nightingale 		nextoff = pci_get_cfgdata8(pi, capoff + 1);
974*bf21cd93STycho Nightingale 		if (nextoff == 0)
975*bf21cd93STycho Nightingale 			break;
976*bf21cd93STycho Nightingale 		if (offset >= capoff && offset < nextoff)
977*bf21cd93STycho Nightingale 			break;
978*bf21cd93STycho Nightingale 
979*bf21cd93STycho Nightingale 		capoff = nextoff;
980*bf21cd93STycho Nightingale 	}
981*bf21cd93STycho Nightingale 	assert(offset >= capoff);
982*bf21cd93STycho Nightingale 
983*bf21cd93STycho Nightingale 	/*
984*bf21cd93STycho Nightingale 	 * Capability ID and Next Capability Pointer are readonly.
985*bf21cd93STycho Nightingale 	 * However, some o/s's do 4-byte writes that include these.
986*bf21cd93STycho Nightingale 	 * For this case, trim the write back to 2 bytes and adjust
987*bf21cd93STycho Nightingale 	 * the data.
988*bf21cd93STycho Nightingale 	 */
989*bf21cd93STycho Nightingale 	if (offset == capoff || offset == capoff + 1) {
990*bf21cd93STycho Nightingale 		if (offset == capoff && bytes == 4) {
991*bf21cd93STycho Nightingale 			bytes = 2;
992*bf21cd93STycho Nightingale 			offset += 2;
993*bf21cd93STycho Nightingale 			val >>= 16;
994*bf21cd93STycho Nightingale 		} else
995*bf21cd93STycho Nightingale 			return;
996*bf21cd93STycho Nightingale 	}
997*bf21cd93STycho Nightingale 
998*bf21cd93STycho Nightingale 	capid = pci_get_cfgdata8(pi, capoff);
999*bf21cd93STycho Nightingale 	switch (capid) {
1000*bf21cd93STycho Nightingale 	case PCIY_MSI:
1001*bf21cd93STycho Nightingale 		msicap_cfgwrite(pi, capoff, offset, bytes, val);
1002*bf21cd93STycho Nightingale 		break;
1003*bf21cd93STycho Nightingale 	case PCIY_MSIX:
1004*bf21cd93STycho Nightingale 		msixcap_cfgwrite(pi, capoff, offset, bytes, val);
1005*bf21cd93STycho Nightingale 		break;
1006*bf21cd93STycho Nightingale 	case PCIY_EXPRESS:
1007*bf21cd93STycho Nightingale 		pciecap_cfgwrite(pi, capoff, offset, bytes, val);
1008*bf21cd93STycho Nightingale 		break;
1009*bf21cd93STycho Nightingale 	default:
1010*bf21cd93STycho Nightingale 		break;
1011*bf21cd93STycho Nightingale 	}
1012*bf21cd93STycho Nightingale }
1013*bf21cd93STycho Nightingale 
1014*bf21cd93STycho Nightingale static int
1015*bf21cd93STycho Nightingale pci_emul_iscap(struct pci_devinst *pi, int offset)
1016*bf21cd93STycho Nightingale {
1017*bf21cd93STycho Nightingale 	uint16_t sts;
1018*bf21cd93STycho Nightingale 
1019*bf21cd93STycho Nightingale 	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
1020*bf21cd93STycho Nightingale 	if ((sts & PCIM_STATUS_CAPPRESENT) != 0) {
1021*bf21cd93STycho Nightingale 		if (offset >= CAP_START_OFFSET && offset <= pi->pi_capend)
1022*bf21cd93STycho Nightingale 			return (1);
1023*bf21cd93STycho Nightingale 	}
1024*bf21cd93STycho Nightingale 	return (0);
1025*bf21cd93STycho Nightingale }
1026*bf21cd93STycho Nightingale 
1027*bf21cd93STycho Nightingale static int
1028*bf21cd93STycho Nightingale pci_emul_fallback_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
1029*bf21cd93STycho Nightingale 			  int size, uint64_t *val, void *arg1, long arg2)
1030*bf21cd93STycho Nightingale {
1031*bf21cd93STycho Nightingale 	/*
1032*bf21cd93STycho Nightingale 	 * Ignore writes; return 0xff's for reads. The mem read code
1033*bf21cd93STycho Nightingale 	 * will take care of truncating to the correct size.
1034*bf21cd93STycho Nightingale 	 */
1035*bf21cd93STycho Nightingale 	if (dir == MEM_F_READ) {
1036*bf21cd93STycho Nightingale 		*val = 0xffffffffffffffff;
1037*bf21cd93STycho Nightingale 	}
1038*bf21cd93STycho Nightingale 
1039*bf21cd93STycho Nightingale 	return (0);
1040*bf21cd93STycho Nightingale }
1041*bf21cd93STycho Nightingale 
1042*bf21cd93STycho Nightingale static int
1043*bf21cd93STycho Nightingale pci_emul_ecfg_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
1044*bf21cd93STycho Nightingale     int bytes, uint64_t *val, void *arg1, long arg2)
1045*bf21cd93STycho Nightingale {
1046*bf21cd93STycho Nightingale 	int bus, slot, func, coff, in;
1047*bf21cd93STycho Nightingale 
1048*bf21cd93STycho Nightingale 	coff = addr & 0xfff;
1049*bf21cd93STycho Nightingale 	func = (addr >> 12) & 0x7;
1050*bf21cd93STycho Nightingale 	slot = (addr >> 15) & 0x1f;
1051*bf21cd93STycho Nightingale 	bus = (addr >> 20) & 0xff;
1052*bf21cd93STycho Nightingale 	in = (dir == MEM_F_READ);
1053*bf21cd93STycho Nightingale 	if (in)
1054*bf21cd93STycho Nightingale 		*val = ~0UL;
1055*bf21cd93STycho Nightingale 	pci_cfgrw(ctx, vcpu, in, bus, slot, func, coff, bytes, (uint32_t *)val);
1056*bf21cd93STycho Nightingale 	return (0);
1057*bf21cd93STycho Nightingale }
1058*bf21cd93STycho Nightingale 
1059*bf21cd93STycho Nightingale uint64_t
1060*bf21cd93STycho Nightingale pci_ecfg_base(void)
1061*bf21cd93STycho Nightingale {
1062*bf21cd93STycho Nightingale 
1063*bf21cd93STycho Nightingale 	return (PCI_EMUL_ECFG_BASE);
1064*bf21cd93STycho Nightingale }
1065*bf21cd93STycho Nightingale 
1066*bf21cd93STycho Nightingale #define	BUSIO_ROUNDUP		32
1067*bf21cd93STycho Nightingale #define	BUSMEM_ROUNDUP		(1024 * 1024)
1068*bf21cd93STycho Nightingale 
1069*bf21cd93STycho Nightingale int
1070*bf21cd93STycho Nightingale init_pci(struct vmctx *ctx)
1071*bf21cd93STycho Nightingale {
1072*bf21cd93STycho Nightingale 	struct mem_range mr;
1073*bf21cd93STycho Nightingale 	struct pci_devemu *pde;
1074*bf21cd93STycho Nightingale 	struct businfo *bi;
1075*bf21cd93STycho Nightingale 	struct slotinfo *si;
1076*bf21cd93STycho Nightingale 	struct funcinfo *fi;
1077*bf21cd93STycho Nightingale 	size_t lowmem;
1078*bf21cd93STycho Nightingale 	int bus, slot, func;
1079*bf21cd93STycho Nightingale 	int error;
1080*bf21cd93STycho Nightingale 
1081*bf21cd93STycho Nightingale 	pci_emul_iobase = PCI_EMUL_IOBASE;
1082*bf21cd93STycho Nightingale 	pci_emul_membase32 = vm_get_lowmem_limit(ctx);
1083*bf21cd93STycho Nightingale 	pci_emul_membase64 = PCI_EMUL_MEMBASE64;
1084*bf21cd93STycho Nightingale 
1085*bf21cd93STycho Nightingale 	for (bus = 0; bus < MAXBUSES; bus++) {
1086*bf21cd93STycho Nightingale 		if ((bi = pci_businfo[bus]) == NULL)
1087*bf21cd93STycho Nightingale 			continue;
1088*bf21cd93STycho Nightingale 		/*
1089*bf21cd93STycho Nightingale 		 * Keep track of the i/o and memory resources allocated to
1090*bf21cd93STycho Nightingale 		 * this bus.
1091*bf21cd93STycho Nightingale 		 */
1092*bf21cd93STycho Nightingale 		bi->iobase = pci_emul_iobase;
1093*bf21cd93STycho Nightingale 		bi->membase32 = pci_emul_membase32;
1094*bf21cd93STycho Nightingale 		bi->membase64 = pci_emul_membase64;
1095*bf21cd93STycho Nightingale 
1096*bf21cd93STycho Nightingale 		for (slot = 0; slot < MAXSLOTS; slot++) {
1097*bf21cd93STycho Nightingale 			si = &bi->slotinfo[slot];
1098*bf21cd93STycho Nightingale 			for (func = 0; func < MAXFUNCS; func++) {
1099*bf21cd93STycho Nightingale 				fi = &si->si_funcs[func];
1100*bf21cd93STycho Nightingale 				if (fi->fi_name == NULL)
1101*bf21cd93STycho Nightingale 					continue;
1102*bf21cd93STycho Nightingale 				pde = pci_emul_finddev(fi->fi_name);
1103*bf21cd93STycho Nightingale 				assert(pde != NULL);
1104*bf21cd93STycho Nightingale 				error = pci_emul_init(ctx, pde, bus, slot,
1105*bf21cd93STycho Nightingale 				    func, fi);
1106*bf21cd93STycho Nightingale 				if (error)
1107*bf21cd93STycho Nightingale 					return (error);
1108*bf21cd93STycho Nightingale 			}
1109*bf21cd93STycho Nightingale 		}
1110*bf21cd93STycho Nightingale 
1111*bf21cd93STycho Nightingale 		/*
1112*bf21cd93STycho Nightingale 		 * Add some slop to the I/O and memory resources decoded by
1113*bf21cd93STycho Nightingale 		 * this bus to give a guest some flexibility if it wants to
1114*bf21cd93STycho Nightingale 		 * reprogram the BARs.
1115*bf21cd93STycho Nightingale 		 */
1116*bf21cd93STycho Nightingale 		pci_emul_iobase += BUSIO_ROUNDUP;
1117*bf21cd93STycho Nightingale 		pci_emul_iobase = roundup2(pci_emul_iobase, BUSIO_ROUNDUP);
1118*bf21cd93STycho Nightingale 		bi->iolimit = pci_emul_iobase;
1119*bf21cd93STycho Nightingale 
1120*bf21cd93STycho Nightingale 		pci_emul_membase32 += BUSMEM_ROUNDUP;
1121*bf21cd93STycho Nightingale 		pci_emul_membase32 = roundup2(pci_emul_membase32,
1122*bf21cd93STycho Nightingale 		    BUSMEM_ROUNDUP);
1123*bf21cd93STycho Nightingale 		bi->memlimit32 = pci_emul_membase32;
1124*bf21cd93STycho Nightingale 
1125*bf21cd93STycho Nightingale 		pci_emul_membase64 += BUSMEM_ROUNDUP;
1126*bf21cd93STycho Nightingale 		pci_emul_membase64 = roundup2(pci_emul_membase64,
1127*bf21cd93STycho Nightingale 		    BUSMEM_ROUNDUP);
1128*bf21cd93STycho Nightingale 		bi->memlimit64 = pci_emul_membase64;
1129*bf21cd93STycho Nightingale 	}
1130*bf21cd93STycho Nightingale 
1131*bf21cd93STycho Nightingale 	/*
1132*bf21cd93STycho Nightingale 	 * PCI backends are initialized before routing INTx interrupts
1133*bf21cd93STycho Nightingale 	 * so that LPC devices are able to reserve ISA IRQs before
1134*bf21cd93STycho Nightingale 	 * routing PIRQ pins.
1135*bf21cd93STycho Nightingale 	 */
1136*bf21cd93STycho Nightingale 	for (bus = 0; bus < MAXBUSES; bus++) {
1137*bf21cd93STycho Nightingale 		if ((bi = pci_businfo[bus]) == NULL)
1138*bf21cd93STycho Nightingale 			continue;
1139*bf21cd93STycho Nightingale 
1140*bf21cd93STycho Nightingale 		for (slot = 0; slot < MAXSLOTS; slot++) {
1141*bf21cd93STycho Nightingale 			si = &bi->slotinfo[slot];
1142*bf21cd93STycho Nightingale 			for (func = 0; func < MAXFUNCS; func++) {
1143*bf21cd93STycho Nightingale 				fi = &si->si_funcs[func];
1144*bf21cd93STycho Nightingale 				if (fi->fi_devi == NULL)
1145*bf21cd93STycho Nightingale 					continue;
1146*bf21cd93STycho Nightingale 				pci_lintr_route(fi->fi_devi);
1147*bf21cd93STycho Nightingale 			}
1148*bf21cd93STycho Nightingale 		}
1149*bf21cd93STycho Nightingale 	}
1150*bf21cd93STycho Nightingale 	lpc_pirq_routed();
1151*bf21cd93STycho Nightingale 
1152*bf21cd93STycho Nightingale 	/*
1153*bf21cd93STycho Nightingale 	 * The guest physical memory map looks like the following:
1154*bf21cd93STycho Nightingale 	 * [0,		    lowmem)		guest system memory
1155*bf21cd93STycho Nightingale 	 * [lowmem,	    lowmem_limit)	memory hole (may be absent)
1156*bf21cd93STycho Nightingale 	 * [lowmem_limit,   0xE0000000)		PCI hole (32-bit BAR allocation)
1157*bf21cd93STycho Nightingale 	 * [0xE0000000,	    0xF0000000)		PCI extended config window
1158*bf21cd93STycho Nightingale 	 * [0xF0000000,	    4GB)		LAPIC, IOAPIC, HPET, firmware
1159*bf21cd93STycho Nightingale 	 * [4GB,	    4GB + highmem)
1160*bf21cd93STycho Nightingale 	 */
1161*bf21cd93STycho Nightingale 
1162*bf21cd93STycho Nightingale 	/*
1163*bf21cd93STycho Nightingale 	 * Accesses to memory addresses that are not allocated to system
1164*bf21cd93STycho Nightingale 	 * memory or PCI devices return 0xff's.
1165*bf21cd93STycho Nightingale 	 */
1166*bf21cd93STycho Nightingale 	lowmem = vm_get_lowmem_size(ctx);
1167*bf21cd93STycho Nightingale 	bzero(&mr, sizeof(struct mem_range));
1168*bf21cd93STycho Nightingale 	mr.name = "PCI hole";
1169*bf21cd93STycho Nightingale 	mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
1170*bf21cd93STycho Nightingale 	mr.base = lowmem;
1171*bf21cd93STycho Nightingale 	mr.size = (4ULL * 1024 * 1024 * 1024) - lowmem;
1172*bf21cd93STycho Nightingale 	mr.handler = pci_emul_fallback_handler;
1173*bf21cd93STycho Nightingale 	error = register_mem_fallback(&mr);
1174*bf21cd93STycho Nightingale 	assert(error == 0);
1175*bf21cd93STycho Nightingale 
1176*bf21cd93STycho Nightingale 	/* PCI extended config space */
1177*bf21cd93STycho Nightingale 	bzero(&mr, sizeof(struct mem_range));
1178*bf21cd93STycho Nightingale 	mr.name = "PCI ECFG";
1179*bf21cd93STycho Nightingale 	mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
1180*bf21cd93STycho Nightingale 	mr.base = PCI_EMUL_ECFG_BASE;
1181*bf21cd93STycho Nightingale 	mr.size = PCI_EMUL_ECFG_SIZE;
1182*bf21cd93STycho Nightingale 	mr.handler = pci_emul_ecfg_handler;
1183*bf21cd93STycho Nightingale 	error = register_mem(&mr);
1184*bf21cd93STycho Nightingale 	assert(error == 0);
1185*bf21cd93STycho Nightingale 
1186*bf21cd93STycho Nightingale 	return (0);
1187*bf21cd93STycho Nightingale }
1188*bf21cd93STycho Nightingale 
1189*bf21cd93STycho Nightingale #ifdef	__FreeBSD__
1190*bf21cd93STycho Nightingale static void
1191*bf21cd93STycho Nightingale pci_apic_prt_entry(int bus, int slot, int pin, int pirq_pin, int ioapic_irq,
1192*bf21cd93STycho Nightingale     void *arg)
1193*bf21cd93STycho Nightingale {
1194*bf21cd93STycho Nightingale 
1195*bf21cd93STycho Nightingale 	dsdt_line("  Package ()");
1196*bf21cd93STycho Nightingale 	dsdt_line("  {");
1197*bf21cd93STycho Nightingale 	dsdt_line("    0x%X,", slot << 16 | 0xffff);
1198*bf21cd93STycho Nightingale 	dsdt_line("    0x%02X,", pin - 1);
1199*bf21cd93STycho Nightingale 	dsdt_line("    Zero,");
1200*bf21cd93STycho Nightingale 	dsdt_line("    0x%X", ioapic_irq);
1201*bf21cd93STycho Nightingale 	dsdt_line("  },");
1202*bf21cd93STycho Nightingale }
1203*bf21cd93STycho Nightingale 
1204*bf21cd93STycho Nightingale static void
1205*bf21cd93STycho Nightingale pci_pirq_prt_entry(int bus, int slot, int pin, int pirq_pin, int ioapic_irq,
1206*bf21cd93STycho Nightingale     void *arg)
1207*bf21cd93STycho Nightingale {
1208*bf21cd93STycho Nightingale 	char *name;
1209*bf21cd93STycho Nightingale 
1210*bf21cd93STycho Nightingale 	name = lpc_pirq_name(pirq_pin);
1211*bf21cd93STycho Nightingale 	if (name == NULL)
1212*bf21cd93STycho Nightingale 		return;
1213*bf21cd93STycho Nightingale 	dsdt_line("  Package ()");
1214*bf21cd93STycho Nightingale 	dsdt_line("  {");
1215*bf21cd93STycho Nightingale 	dsdt_line("    0x%X,", slot << 16 | 0xffff);
1216*bf21cd93STycho Nightingale 	dsdt_line("    0x%02X,", pin - 1);
1217*bf21cd93STycho Nightingale 	dsdt_line("    %s,", name);
1218*bf21cd93STycho Nightingale 	dsdt_line("    0x00");
1219*bf21cd93STycho Nightingale 	dsdt_line("  },");
1220*bf21cd93STycho Nightingale 	free(name);
1221*bf21cd93STycho Nightingale }
1222*bf21cd93STycho Nightingale 
1223*bf21cd93STycho Nightingale /*
1224*bf21cd93STycho Nightingale  * A bhyve virtual machine has a flat PCI hierarchy with a root port
1225*bf21cd93STycho Nightingale  * corresponding to each PCI bus.
1226*bf21cd93STycho Nightingale  */
1227*bf21cd93STycho Nightingale static void
1228*bf21cd93STycho Nightingale pci_bus_write_dsdt(int bus)
1229*bf21cd93STycho Nightingale {
1230*bf21cd93STycho Nightingale 	struct businfo *bi;
1231*bf21cd93STycho Nightingale 	struct slotinfo *si;
1232*bf21cd93STycho Nightingale 	struct pci_devinst *pi;
1233*bf21cd93STycho Nightingale 	int count, func, slot;
1234*bf21cd93STycho Nightingale 
1235*bf21cd93STycho Nightingale 	/*
1236*bf21cd93STycho Nightingale 	 * If there are no devices on this 'bus' then just return.
1237*bf21cd93STycho Nightingale 	 */
1238*bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) == NULL) {
1239*bf21cd93STycho Nightingale 		/*
1240*bf21cd93STycho Nightingale 		 * Bus 0 is special because it decodes the I/O ports used
1241*bf21cd93STycho Nightingale 		 * for PCI config space access even if there are no devices
1242*bf21cd93STycho Nightingale 		 * on it.
1243*bf21cd93STycho Nightingale 		 */
1244*bf21cd93STycho Nightingale 		if (bus != 0)
1245*bf21cd93STycho Nightingale 			return;
1246*bf21cd93STycho Nightingale 	}
1247*bf21cd93STycho Nightingale 
1248*bf21cd93STycho Nightingale 	dsdt_line("  Device (PC%02X)", bus);
1249*bf21cd93STycho Nightingale 	dsdt_line("  {");
1250*bf21cd93STycho Nightingale 	dsdt_line("    Name (_HID, EisaId (\"PNP0A03\"))");
1251*bf21cd93STycho Nightingale 	dsdt_line("    Name (_ADR, Zero)");
1252*bf21cd93STycho Nightingale 
1253*bf21cd93STycho Nightingale 	dsdt_line("    Method (_BBN, 0, NotSerialized)");
1254*bf21cd93STycho Nightingale 	dsdt_line("    {");
1255*bf21cd93STycho Nightingale 	dsdt_line("        Return (0x%08X)", bus);
1256*bf21cd93STycho Nightingale 	dsdt_line("    }");
1257*bf21cd93STycho Nightingale 	dsdt_line("    Name (_CRS, ResourceTemplate ()");
1258*bf21cd93STycho Nightingale 	dsdt_line("    {");
1259*bf21cd93STycho Nightingale 	dsdt_line("      WordBusNumber (ResourceProducer, MinFixed, "
1260*bf21cd93STycho Nightingale 	    "MaxFixed, PosDecode,");
1261*bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Granularity");
1262*bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Minimum", bus);
1263*bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Maximum", bus);
1264*bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Translation Offset");
1265*bf21cd93STycho Nightingale 	dsdt_line("        0x0001,             // Length");
1266*bf21cd93STycho Nightingale 	dsdt_line("        ,, )");
1267*bf21cd93STycho Nightingale 
1268*bf21cd93STycho Nightingale 	if (bus == 0) {
1269*bf21cd93STycho Nightingale 		dsdt_indent(3);
1270*bf21cd93STycho Nightingale 		dsdt_fixed_ioport(0xCF8, 8);
1271*bf21cd93STycho Nightingale 		dsdt_unindent(3);
1272*bf21cd93STycho Nightingale 
1273*bf21cd93STycho Nightingale 		dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1274*bf21cd93STycho Nightingale 		    "PosDecode, EntireRange,");
1275*bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Granularity");
1276*bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Range Minimum");
1277*bf21cd93STycho Nightingale 		dsdt_line("        0x0CF7,             // Range Maximum");
1278*bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Translation Offset");
1279*bf21cd93STycho Nightingale 		dsdt_line("        0x0CF8,             // Length");
1280*bf21cd93STycho Nightingale 		dsdt_line("        ,, , TypeStatic)");
1281*bf21cd93STycho Nightingale 
1282*bf21cd93STycho Nightingale 		dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1283*bf21cd93STycho Nightingale 		    "PosDecode, EntireRange,");
1284*bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Granularity");
1285*bf21cd93STycho Nightingale 		dsdt_line("        0x0D00,             // Range Minimum");
1286*bf21cd93STycho Nightingale 		dsdt_line("        0x%04X,             // Range Maximum",
1287*bf21cd93STycho Nightingale 		    PCI_EMUL_IOBASE - 1);
1288*bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Translation Offset");
1289*bf21cd93STycho Nightingale 		dsdt_line("        0x%04X,             // Length",
1290*bf21cd93STycho Nightingale 		    PCI_EMUL_IOBASE - 0x0D00);
1291*bf21cd93STycho Nightingale 		dsdt_line("        ,, , TypeStatic)");
1292*bf21cd93STycho Nightingale 
1293*bf21cd93STycho Nightingale 		if (bi == NULL) {
1294*bf21cd93STycho Nightingale 			dsdt_line("    })");
1295*bf21cd93STycho Nightingale 			goto done;
1296*bf21cd93STycho Nightingale 		}
1297*bf21cd93STycho Nightingale 	}
1298*bf21cd93STycho Nightingale 	assert(bi != NULL);
1299*bf21cd93STycho Nightingale 
1300*bf21cd93STycho Nightingale 	/* i/o window */
1301*bf21cd93STycho Nightingale 	dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1302*bf21cd93STycho Nightingale 	    "PosDecode, EntireRange,");
1303*bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Granularity");
1304*bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Minimum", bi->iobase);
1305*bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Maximum",
1306*bf21cd93STycho Nightingale 	    bi->iolimit - 1);
1307*bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Translation Offset");
1308*bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Length",
1309*bf21cd93STycho Nightingale 	    bi->iolimit - bi->iobase);
1310*bf21cd93STycho Nightingale 	dsdt_line("        ,, , TypeStatic)");
1311*bf21cd93STycho Nightingale 
1312*bf21cd93STycho Nightingale 	/* mmio window (32-bit) */
1313*bf21cd93STycho Nightingale 	dsdt_line("      DWordMemory (ResourceProducer, PosDecode, "
1314*bf21cd93STycho Nightingale 	    "MinFixed, MaxFixed, NonCacheable, ReadWrite,");
1315*bf21cd93STycho Nightingale 	dsdt_line("        0x00000000,         // Granularity");
1316*bf21cd93STycho Nightingale 	dsdt_line("        0x%08X,         // Range Minimum\n", bi->membase32);
1317*bf21cd93STycho Nightingale 	dsdt_line("        0x%08X,         // Range Maximum\n",
1318*bf21cd93STycho Nightingale 	    bi->memlimit32 - 1);
1319*bf21cd93STycho Nightingale 	dsdt_line("        0x00000000,         // Translation Offset");
1320*bf21cd93STycho Nightingale 	dsdt_line("        0x%08X,         // Length\n",
1321*bf21cd93STycho Nightingale 	    bi->memlimit32 - bi->membase32);
1322*bf21cd93STycho Nightingale 	dsdt_line("        ,, , AddressRangeMemory, TypeStatic)");
1323*bf21cd93STycho Nightingale 
1324*bf21cd93STycho Nightingale 	/* mmio window (64-bit) */
1325*bf21cd93STycho Nightingale 	dsdt_line("      QWordMemory (ResourceProducer, PosDecode, "
1326*bf21cd93STycho Nightingale 	    "MinFixed, MaxFixed, NonCacheable, ReadWrite,");
1327*bf21cd93STycho Nightingale 	dsdt_line("        0x0000000000000000, // Granularity");
1328*bf21cd93STycho Nightingale 	dsdt_line("        0x%016lX, // Range Minimum\n", bi->membase64);
1329*bf21cd93STycho Nightingale 	dsdt_line("        0x%016lX, // Range Maximum\n",
1330*bf21cd93STycho Nightingale 	    bi->memlimit64 - 1);
1331*bf21cd93STycho Nightingale 	dsdt_line("        0x0000000000000000, // Translation Offset");
1332*bf21cd93STycho Nightingale 	dsdt_line("        0x%016lX, // Length\n",
1333*bf21cd93STycho Nightingale 	    bi->memlimit64 - bi->membase64);
1334*bf21cd93STycho Nightingale 	dsdt_line("        ,, , AddressRangeMemory, TypeStatic)");
1335*bf21cd93STycho Nightingale 	dsdt_line("    })");
1336*bf21cd93STycho Nightingale 
1337*bf21cd93STycho Nightingale 	count = pci_count_lintr(bus);
1338*bf21cd93STycho Nightingale 	if (count != 0) {
1339*bf21cd93STycho Nightingale 		dsdt_indent(2);
1340*bf21cd93STycho Nightingale 		dsdt_line("Name (PPRT, Package ()");
1341*bf21cd93STycho Nightingale 		dsdt_line("{");
1342*bf21cd93STycho Nightingale 		pci_walk_lintr(bus, pci_pirq_prt_entry, NULL);
1343*bf21cd93STycho Nightingale  		dsdt_line("})");
1344*bf21cd93STycho Nightingale 		dsdt_line("Name (APRT, Package ()");
1345*bf21cd93STycho Nightingale 		dsdt_line("{");
1346*bf21cd93STycho Nightingale 		pci_walk_lintr(bus, pci_apic_prt_entry, NULL);
1347*bf21cd93STycho Nightingale  		dsdt_line("})");
1348*bf21cd93STycho Nightingale 		dsdt_line("Method (_PRT, 0, NotSerialized)");
1349*bf21cd93STycho Nightingale 		dsdt_line("{");
1350*bf21cd93STycho Nightingale 		dsdt_line("  If (PICM)");
1351*bf21cd93STycho Nightingale 		dsdt_line("  {");
1352*bf21cd93STycho Nightingale 		dsdt_line("    Return (APRT)");
1353*bf21cd93STycho Nightingale 		dsdt_line("  }");
1354*bf21cd93STycho Nightingale 		dsdt_line("  Else");
1355*bf21cd93STycho Nightingale 		dsdt_line("  {");
1356*bf21cd93STycho Nightingale 		dsdt_line("    Return (PPRT)");
1357*bf21cd93STycho Nightingale 		dsdt_line("  }");
1358*bf21cd93STycho Nightingale 		dsdt_line("}");
1359*bf21cd93STycho Nightingale 		dsdt_unindent(2);
1360*bf21cd93STycho Nightingale 	}
1361*bf21cd93STycho Nightingale 
1362*bf21cd93STycho Nightingale 	dsdt_indent(2);
1363*bf21cd93STycho Nightingale 	for (slot = 0; slot < MAXSLOTS; slot++) {
1364*bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
1365*bf21cd93STycho Nightingale 		for (func = 0; func < MAXFUNCS; func++) {
1366*bf21cd93STycho Nightingale 			pi = si->si_funcs[func].fi_devi;
1367*bf21cd93STycho Nightingale 			if (pi != NULL && pi->pi_d->pe_write_dsdt != NULL)
1368*bf21cd93STycho Nightingale 				pi->pi_d->pe_write_dsdt(pi);
1369*bf21cd93STycho Nightingale 		}
1370*bf21cd93STycho Nightingale 	}
1371*bf21cd93STycho Nightingale 	dsdt_unindent(2);
1372*bf21cd93STycho Nightingale done:
1373*bf21cd93STycho Nightingale 	dsdt_line("  }");
1374*bf21cd93STycho Nightingale }
1375*bf21cd93STycho Nightingale 
1376*bf21cd93STycho Nightingale void
1377*bf21cd93STycho Nightingale pci_write_dsdt(void)
1378*bf21cd93STycho Nightingale {
1379*bf21cd93STycho Nightingale 	int bus;
1380*bf21cd93STycho Nightingale 
1381*bf21cd93STycho Nightingale 	dsdt_indent(1);
1382*bf21cd93STycho Nightingale 	dsdt_line("Name (PICM, 0x00)");
1383*bf21cd93STycho Nightingale 	dsdt_line("Method (_PIC, 1, NotSerialized)");
1384*bf21cd93STycho Nightingale 	dsdt_line("{");
1385*bf21cd93STycho Nightingale 	dsdt_line("  Store (Arg0, PICM)");
1386*bf21cd93STycho Nightingale 	dsdt_line("}");
1387*bf21cd93STycho Nightingale 	dsdt_line("");
1388*bf21cd93STycho Nightingale 	dsdt_line("Scope (_SB)");
1389*bf21cd93STycho Nightingale 	dsdt_line("{");
1390*bf21cd93STycho Nightingale 	for (bus = 0; bus < MAXBUSES; bus++)
1391*bf21cd93STycho Nightingale 		pci_bus_write_dsdt(bus);
1392*bf21cd93STycho Nightingale 	dsdt_line("}");
1393*bf21cd93STycho Nightingale 	dsdt_unindent(1);
1394*bf21cd93STycho Nightingale }
1395*bf21cd93STycho Nightingale #endif
1396*bf21cd93STycho Nightingale 
1397*bf21cd93STycho Nightingale int
1398*bf21cd93STycho Nightingale pci_bus_configured(int bus)
1399*bf21cd93STycho Nightingale {
1400*bf21cd93STycho Nightingale 	assert(bus >= 0 && bus < MAXBUSES);
1401*bf21cd93STycho Nightingale 	return (pci_businfo[bus] != NULL);
1402*bf21cd93STycho Nightingale }
1403*bf21cd93STycho Nightingale 
1404*bf21cd93STycho Nightingale int
1405*bf21cd93STycho Nightingale pci_msi_enabled(struct pci_devinst *pi)
1406*bf21cd93STycho Nightingale {
1407*bf21cd93STycho Nightingale 	return (pi->pi_msi.enabled);
1408*bf21cd93STycho Nightingale }
1409*bf21cd93STycho Nightingale 
1410*bf21cd93STycho Nightingale int
1411*bf21cd93STycho Nightingale pci_msi_maxmsgnum(struct pci_devinst *pi)
1412*bf21cd93STycho Nightingale {
1413*bf21cd93STycho Nightingale 	if (pi->pi_msi.enabled)
1414*bf21cd93STycho Nightingale 		return (pi->pi_msi.maxmsgnum);
1415*bf21cd93STycho Nightingale 	else
1416*bf21cd93STycho Nightingale 		return (0);
1417*bf21cd93STycho Nightingale }
1418*bf21cd93STycho Nightingale 
1419*bf21cd93STycho Nightingale int
1420*bf21cd93STycho Nightingale pci_msix_enabled(struct pci_devinst *pi)
1421*bf21cd93STycho Nightingale {
1422*bf21cd93STycho Nightingale 
1423*bf21cd93STycho Nightingale 	return (pi->pi_msix.enabled && !pi->pi_msi.enabled);
1424*bf21cd93STycho Nightingale }
1425*bf21cd93STycho Nightingale 
1426*bf21cd93STycho Nightingale void
1427*bf21cd93STycho Nightingale pci_generate_msix(struct pci_devinst *pi, int index)
1428*bf21cd93STycho Nightingale {
1429*bf21cd93STycho Nightingale 	struct msix_table_entry *mte;
1430*bf21cd93STycho Nightingale 
1431*bf21cd93STycho Nightingale 	if (!pci_msix_enabled(pi))
1432*bf21cd93STycho Nightingale 		return;
1433*bf21cd93STycho Nightingale 
1434*bf21cd93STycho Nightingale 	if (pi->pi_msix.function_mask)
1435*bf21cd93STycho Nightingale 		return;
1436*bf21cd93STycho Nightingale 
1437*bf21cd93STycho Nightingale 	if (index >= pi->pi_msix.table_count)
1438*bf21cd93STycho Nightingale 		return;
1439*bf21cd93STycho Nightingale 
1440*bf21cd93STycho Nightingale 	mte = &pi->pi_msix.table[index];
1441*bf21cd93STycho Nightingale 	if ((mte->vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
1442*bf21cd93STycho Nightingale 		/* XXX Set PBA bit if interrupt is disabled */
1443*bf21cd93STycho Nightingale 		vm_lapic_msi(pi->pi_vmctx, mte->addr, mte->msg_data);
1444*bf21cd93STycho Nightingale 	}
1445*bf21cd93STycho Nightingale }
1446*bf21cd93STycho Nightingale 
1447*bf21cd93STycho Nightingale void
1448*bf21cd93STycho Nightingale pci_generate_msi(struct pci_devinst *pi, int index)
1449*bf21cd93STycho Nightingale {
1450*bf21cd93STycho Nightingale 
1451*bf21cd93STycho Nightingale 	if (pci_msi_enabled(pi) && index < pci_msi_maxmsgnum(pi)) {
1452*bf21cd93STycho Nightingale 		vm_lapic_msi(pi->pi_vmctx, pi->pi_msi.addr,
1453*bf21cd93STycho Nightingale 			     pi->pi_msi.msg_data + index);
1454*bf21cd93STycho Nightingale 	}
1455*bf21cd93STycho Nightingale }
1456*bf21cd93STycho Nightingale 
1457*bf21cd93STycho Nightingale static bool
1458*bf21cd93STycho Nightingale pci_lintr_permitted(struct pci_devinst *pi)
1459*bf21cd93STycho Nightingale {
1460*bf21cd93STycho Nightingale 	uint16_t cmd;
1461*bf21cd93STycho Nightingale 
1462*bf21cd93STycho Nightingale 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
1463*bf21cd93STycho Nightingale 	return (!(pi->pi_msi.enabled || pi->pi_msix.enabled ||
1464*bf21cd93STycho Nightingale 		(cmd & PCIM_CMD_INTxDIS)));
1465*bf21cd93STycho Nightingale }
1466*bf21cd93STycho Nightingale 
1467*bf21cd93STycho Nightingale void
1468*bf21cd93STycho Nightingale pci_lintr_request(struct pci_devinst *pi)
1469*bf21cd93STycho Nightingale {
1470*bf21cd93STycho Nightingale 	struct businfo *bi;
1471*bf21cd93STycho Nightingale 	struct slotinfo *si;
1472*bf21cd93STycho Nightingale 	int bestpin, bestcount, pin;
1473*bf21cd93STycho Nightingale 
1474*bf21cd93STycho Nightingale 	bi = pci_businfo[pi->pi_bus];
1475*bf21cd93STycho Nightingale 	assert(bi != NULL);
1476*bf21cd93STycho Nightingale 
1477*bf21cd93STycho Nightingale 	/*
1478*bf21cd93STycho Nightingale 	 * Just allocate a pin from our slot.  The pin will be
1479*bf21cd93STycho Nightingale 	 * assigned IRQs later when interrupts are routed.
1480*bf21cd93STycho Nightingale 	 */
1481*bf21cd93STycho Nightingale 	si = &bi->slotinfo[pi->pi_slot];
1482*bf21cd93STycho Nightingale 	bestpin = 0;
1483*bf21cd93STycho Nightingale 	bestcount = si->si_intpins[0].ii_count;
1484*bf21cd93STycho Nightingale 	for (pin = 1; pin < 4; pin++) {
1485*bf21cd93STycho Nightingale 		if (si->si_intpins[pin].ii_count < bestcount) {
1486*bf21cd93STycho Nightingale 			bestpin = pin;
1487*bf21cd93STycho Nightingale 			bestcount = si->si_intpins[pin].ii_count;
1488*bf21cd93STycho Nightingale 		}
1489*bf21cd93STycho Nightingale 	}
1490*bf21cd93STycho Nightingale 
1491*bf21cd93STycho Nightingale 	si->si_intpins[bestpin].ii_count++;
1492*bf21cd93STycho Nightingale 	pi->pi_lintr.pin = bestpin + 1;
1493*bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_INTPIN, bestpin + 1);
1494*bf21cd93STycho Nightingale }
1495*bf21cd93STycho Nightingale 
1496*bf21cd93STycho Nightingale static void
1497*bf21cd93STycho Nightingale pci_lintr_route(struct pci_devinst *pi)
1498*bf21cd93STycho Nightingale {
1499*bf21cd93STycho Nightingale 	struct businfo *bi;
1500*bf21cd93STycho Nightingale 	struct intxinfo *ii;
1501*bf21cd93STycho Nightingale 
1502*bf21cd93STycho Nightingale 	if (pi->pi_lintr.pin == 0)
1503*bf21cd93STycho Nightingale 		return;
1504*bf21cd93STycho Nightingale 
1505*bf21cd93STycho Nightingale 	bi = pci_businfo[pi->pi_bus];
1506*bf21cd93STycho Nightingale 	assert(bi != NULL);
1507*bf21cd93STycho Nightingale 	ii = &bi->slotinfo[pi->pi_slot].si_intpins[pi->pi_lintr.pin - 1];
1508*bf21cd93STycho Nightingale 
1509*bf21cd93STycho Nightingale 	/*
1510*bf21cd93STycho Nightingale 	 * Attempt to allocate an I/O APIC pin for this intpin if one
1511*bf21cd93STycho Nightingale 	 * is not yet assigned.
1512*bf21cd93STycho Nightingale 	 */
1513*bf21cd93STycho Nightingale 	if (ii->ii_ioapic_irq == 0)
1514*bf21cd93STycho Nightingale 		ii->ii_ioapic_irq = ioapic_pci_alloc_irq();
1515*bf21cd93STycho Nightingale 	assert(ii->ii_ioapic_irq > 0);
1516*bf21cd93STycho Nightingale 
1517*bf21cd93STycho Nightingale 	/*
1518*bf21cd93STycho Nightingale 	 * Attempt to allocate a PIRQ pin for this intpin if one is
1519*bf21cd93STycho Nightingale 	 * not yet assigned.
1520*bf21cd93STycho Nightingale 	 */
1521*bf21cd93STycho Nightingale 	if (ii->ii_pirq_pin == 0)
1522*bf21cd93STycho Nightingale 		ii->ii_pirq_pin = pirq_alloc_pin(pi->pi_vmctx);
1523*bf21cd93STycho Nightingale 	assert(ii->ii_pirq_pin > 0);
1524*bf21cd93STycho Nightingale 
1525*bf21cd93STycho Nightingale 	pi->pi_lintr.ioapic_irq = ii->ii_ioapic_irq;
1526*bf21cd93STycho Nightingale 	pi->pi_lintr.pirq_pin = ii->ii_pirq_pin;
1527*bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_INTLINE, pirq_irq(ii->ii_pirq_pin));
1528*bf21cd93STycho Nightingale }
1529*bf21cd93STycho Nightingale 
1530*bf21cd93STycho Nightingale void
1531*bf21cd93STycho Nightingale pci_lintr_assert(struct pci_devinst *pi)
1532*bf21cd93STycho Nightingale {
1533*bf21cd93STycho Nightingale 
1534*bf21cd93STycho Nightingale 	assert(pi->pi_lintr.pin > 0);
1535*bf21cd93STycho Nightingale 
1536*bf21cd93STycho Nightingale 	pthread_mutex_lock(&pi->pi_lintr.lock);
1537*bf21cd93STycho Nightingale 	if (pi->pi_lintr.state == IDLE) {
1538*bf21cd93STycho Nightingale 		if (pci_lintr_permitted(pi)) {
1539*bf21cd93STycho Nightingale 			pi->pi_lintr.state = ASSERTED;
1540*bf21cd93STycho Nightingale 			pci_irq_assert(pi);
1541*bf21cd93STycho Nightingale 		} else
1542*bf21cd93STycho Nightingale 			pi->pi_lintr.state = PENDING;
1543*bf21cd93STycho Nightingale 	}
1544*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pi->pi_lintr.lock);
1545*bf21cd93STycho Nightingale }
1546*bf21cd93STycho Nightingale 
1547*bf21cd93STycho Nightingale void
1548*bf21cd93STycho Nightingale pci_lintr_deassert(struct pci_devinst *pi)
1549*bf21cd93STycho Nightingale {
1550*bf21cd93STycho Nightingale 
1551*bf21cd93STycho Nightingale 	assert(pi->pi_lintr.pin > 0);
1552*bf21cd93STycho Nightingale 
1553*bf21cd93STycho Nightingale 	pthread_mutex_lock(&pi->pi_lintr.lock);
1554*bf21cd93STycho Nightingale 	if (pi->pi_lintr.state == ASSERTED) {
1555*bf21cd93STycho Nightingale 		pi->pi_lintr.state = IDLE;
1556*bf21cd93STycho Nightingale 		pci_irq_deassert(pi);
1557*bf21cd93STycho Nightingale 	} else if (pi->pi_lintr.state == PENDING)
1558*bf21cd93STycho Nightingale 		pi->pi_lintr.state = IDLE;
1559*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pi->pi_lintr.lock);
1560*bf21cd93STycho Nightingale }
1561*bf21cd93STycho Nightingale 
1562*bf21cd93STycho Nightingale static void
1563*bf21cd93STycho Nightingale pci_lintr_update(struct pci_devinst *pi)
1564*bf21cd93STycho Nightingale {
1565*bf21cd93STycho Nightingale 
1566*bf21cd93STycho Nightingale 	pthread_mutex_lock(&pi->pi_lintr.lock);
1567*bf21cd93STycho Nightingale 	if (pi->pi_lintr.state == ASSERTED && !pci_lintr_permitted(pi)) {
1568*bf21cd93STycho Nightingale 		pci_irq_deassert(pi);
1569*bf21cd93STycho Nightingale 		pi->pi_lintr.state = PENDING;
1570*bf21cd93STycho Nightingale 	} else if (pi->pi_lintr.state == PENDING && pci_lintr_permitted(pi)) {
1571*bf21cd93STycho Nightingale 		pi->pi_lintr.state = ASSERTED;
1572*bf21cd93STycho Nightingale 		pci_irq_assert(pi);
1573*bf21cd93STycho Nightingale 	}
1574*bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pi->pi_lintr.lock);
1575*bf21cd93STycho Nightingale }
1576*bf21cd93STycho Nightingale 
1577*bf21cd93STycho Nightingale int
1578*bf21cd93STycho Nightingale pci_count_lintr(int bus)
1579*bf21cd93STycho Nightingale {
1580*bf21cd93STycho Nightingale 	int count, slot, pin;
1581*bf21cd93STycho Nightingale 	struct slotinfo *slotinfo;
1582*bf21cd93STycho Nightingale 
1583*bf21cd93STycho Nightingale 	count = 0;
1584*bf21cd93STycho Nightingale 	if (pci_businfo[bus] != NULL) {
1585*bf21cd93STycho Nightingale 		for (slot = 0; slot < MAXSLOTS; slot++) {
1586*bf21cd93STycho Nightingale 			slotinfo = &pci_businfo[bus]->slotinfo[slot];
1587*bf21cd93STycho Nightingale 			for (pin = 0; pin < 4; pin++) {
1588*bf21cd93STycho Nightingale 				if (slotinfo->si_intpins[pin].ii_count != 0)
1589*bf21cd93STycho Nightingale 					count++;
1590*bf21cd93STycho Nightingale 			}
1591*bf21cd93STycho Nightingale 		}
1592*bf21cd93STycho Nightingale 	}
1593*bf21cd93STycho Nightingale 	return (count);
1594*bf21cd93STycho Nightingale }
1595*bf21cd93STycho Nightingale 
1596*bf21cd93STycho Nightingale void
1597*bf21cd93STycho Nightingale pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg)
1598*bf21cd93STycho Nightingale {
1599*bf21cd93STycho Nightingale 	struct businfo *bi;
1600*bf21cd93STycho Nightingale 	struct slotinfo *si;
1601*bf21cd93STycho Nightingale 	struct intxinfo *ii;
1602*bf21cd93STycho Nightingale 	int slot, pin;
1603*bf21cd93STycho Nightingale 
1604*bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) == NULL)
1605*bf21cd93STycho Nightingale 		return;
1606*bf21cd93STycho Nightingale 
1607*bf21cd93STycho Nightingale 	for (slot = 0; slot < MAXSLOTS; slot++) {
1608*bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
1609*bf21cd93STycho Nightingale 		for (pin = 0; pin < 4; pin++) {
1610*bf21cd93STycho Nightingale 			ii = &si->si_intpins[pin];
1611*bf21cd93STycho Nightingale 			if (ii->ii_count != 0)
1612*bf21cd93STycho Nightingale 				cb(bus, slot, pin + 1, ii->ii_pirq_pin,
1613*bf21cd93STycho Nightingale 				    ii->ii_ioapic_irq, arg);
1614*bf21cd93STycho Nightingale 		}
1615*bf21cd93STycho Nightingale 	}
1616*bf21cd93STycho Nightingale }
1617*bf21cd93STycho Nightingale 
1618*bf21cd93STycho Nightingale /*
1619*bf21cd93STycho Nightingale  * Return 1 if the emulated device in 'slot' is a multi-function device.
1620*bf21cd93STycho Nightingale  * Return 0 otherwise.
1621*bf21cd93STycho Nightingale  */
1622*bf21cd93STycho Nightingale static int
1623*bf21cd93STycho Nightingale pci_emul_is_mfdev(int bus, int slot)
1624*bf21cd93STycho Nightingale {
1625*bf21cd93STycho Nightingale 	struct businfo *bi;
1626*bf21cd93STycho Nightingale 	struct slotinfo *si;
1627*bf21cd93STycho Nightingale 	int f, numfuncs;
1628*bf21cd93STycho Nightingale 
1629*bf21cd93STycho Nightingale 	numfuncs = 0;
1630*bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) != NULL) {
1631*bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
1632*bf21cd93STycho Nightingale 		for (f = 0; f < MAXFUNCS; f++) {
1633*bf21cd93STycho Nightingale 			if (si->si_funcs[f].fi_devi != NULL) {
1634*bf21cd93STycho Nightingale 				numfuncs++;
1635*bf21cd93STycho Nightingale 			}
1636*bf21cd93STycho Nightingale 		}
1637*bf21cd93STycho Nightingale 	}
1638*bf21cd93STycho Nightingale 	return (numfuncs > 1);
1639*bf21cd93STycho Nightingale }
1640*bf21cd93STycho Nightingale 
1641*bf21cd93STycho Nightingale /*
1642*bf21cd93STycho Nightingale  * Ensure that the PCIM_MFDEV bit is properly set (or unset) depending on
1643*bf21cd93STycho Nightingale  * whether or not is a multi-function being emulated in the pci 'slot'.
1644*bf21cd93STycho Nightingale  */
1645*bf21cd93STycho Nightingale static void
1646*bf21cd93STycho Nightingale pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv)
1647*bf21cd93STycho Nightingale {
1648*bf21cd93STycho Nightingale 	int mfdev;
1649*bf21cd93STycho Nightingale 
1650*bf21cd93STycho Nightingale 	if (off <= PCIR_HDRTYPE && off + bytes > PCIR_HDRTYPE) {
1651*bf21cd93STycho Nightingale 		mfdev = pci_emul_is_mfdev(bus, slot);
1652*bf21cd93STycho Nightingale 		switch (bytes) {
1653*bf21cd93STycho Nightingale 		case 1:
1654*bf21cd93STycho Nightingale 		case 2:
1655*bf21cd93STycho Nightingale 			*rv &= ~PCIM_MFDEV;
1656*bf21cd93STycho Nightingale 			if (mfdev) {
1657*bf21cd93STycho Nightingale 				*rv |= PCIM_MFDEV;
1658*bf21cd93STycho Nightingale 			}
1659*bf21cd93STycho Nightingale 			break;
1660*bf21cd93STycho Nightingale 		case 4:
1661*bf21cd93STycho Nightingale 			*rv &= ~(PCIM_MFDEV << 16);
1662*bf21cd93STycho Nightingale 			if (mfdev) {
1663*bf21cd93STycho Nightingale 				*rv |= (PCIM_MFDEV << 16);
1664*bf21cd93STycho Nightingale 			}
1665*bf21cd93STycho Nightingale 			break;
1666*bf21cd93STycho Nightingale 		}
1667*bf21cd93STycho Nightingale 	}
1668*bf21cd93STycho Nightingale }
1669*bf21cd93STycho Nightingale 
1670*bf21cd93STycho Nightingale static uint32_t
1671*bf21cd93STycho Nightingale bits_changed(uint32_t old, uint32_t new, uint32_t mask)
1672*bf21cd93STycho Nightingale {
1673*bf21cd93STycho Nightingale 
1674*bf21cd93STycho Nightingale 	return ((old ^ new) & mask);
1675*bf21cd93STycho Nightingale }
1676*bf21cd93STycho Nightingale 
1677*bf21cd93STycho Nightingale static void
1678*bf21cd93STycho Nightingale pci_emul_cmdwrite(struct pci_devinst *pi, uint32_t new, int bytes)
1679*bf21cd93STycho Nightingale {
1680*bf21cd93STycho Nightingale 	int i;
1681*bf21cd93STycho Nightingale 	uint16_t old;
1682*bf21cd93STycho Nightingale 
1683*bf21cd93STycho Nightingale 	/*
1684*bf21cd93STycho Nightingale 	 * The command register is at an offset of 4 bytes and thus the
1685*bf21cd93STycho Nightingale 	 * guest could write 1, 2 or 4 bytes starting at this offset.
1686*bf21cd93STycho Nightingale 	 */
1687*bf21cd93STycho Nightingale 
1688*bf21cd93STycho Nightingale 	old = pci_get_cfgdata16(pi, PCIR_COMMAND);	/* stash old value */
1689*bf21cd93STycho Nightingale 	CFGWRITE(pi, PCIR_COMMAND, new, bytes);		/* update config */
1690*bf21cd93STycho Nightingale 	new = pci_get_cfgdata16(pi, PCIR_COMMAND);	/* get updated value */
1691*bf21cd93STycho Nightingale 
1692*bf21cd93STycho Nightingale 	/*
1693*bf21cd93STycho Nightingale 	 * If the MMIO or I/O address space decoding has changed then
1694*bf21cd93STycho Nightingale 	 * register/unregister all BARs that decode that address space.
1695*bf21cd93STycho Nightingale 	 */
1696*bf21cd93STycho Nightingale 	for (i = 0; i <= PCI_BARMAX; i++) {
1697*bf21cd93STycho Nightingale 		switch (pi->pi_bar[i].type) {
1698*bf21cd93STycho Nightingale 			case PCIBAR_NONE:
1699*bf21cd93STycho Nightingale 			case PCIBAR_MEMHI64:
1700*bf21cd93STycho Nightingale 				break;
1701*bf21cd93STycho Nightingale 			case PCIBAR_IO:
1702*bf21cd93STycho Nightingale 				/* I/O address space decoding changed? */
1703*bf21cd93STycho Nightingale 				if (bits_changed(old, new, PCIM_CMD_PORTEN)) {
1704*bf21cd93STycho Nightingale 					if (porten(pi))
1705*bf21cd93STycho Nightingale 						register_bar(pi, i);
1706*bf21cd93STycho Nightingale 					else
1707*bf21cd93STycho Nightingale 						unregister_bar(pi, i);
1708*bf21cd93STycho Nightingale 				}
1709*bf21cd93STycho Nightingale 				break;
1710*bf21cd93STycho Nightingale 			case PCIBAR_MEM32:
1711*bf21cd93STycho Nightingale 			case PCIBAR_MEM64:
1712*bf21cd93STycho Nightingale 				/* MMIO address space decoding changed? */
1713*bf21cd93STycho Nightingale 				if (bits_changed(old, new, PCIM_CMD_MEMEN)) {
1714*bf21cd93STycho Nightingale 					if (memen(pi))
1715*bf21cd93STycho Nightingale 						register_bar(pi, i);
1716*bf21cd93STycho Nightingale 					else
1717*bf21cd93STycho Nightingale 						unregister_bar(pi, i);
1718*bf21cd93STycho Nightingale 				}
1719*bf21cd93STycho Nightingale 				break;
1720*bf21cd93STycho Nightingale 			default:
1721*bf21cd93STycho Nightingale 				assert(0);
1722*bf21cd93STycho Nightingale 		}
1723*bf21cd93STycho Nightingale 	}
1724*bf21cd93STycho Nightingale 
1725*bf21cd93STycho Nightingale 	/*
1726*bf21cd93STycho Nightingale 	 * If INTx has been unmasked and is pending, assert the
1727*bf21cd93STycho Nightingale 	 * interrupt.
1728*bf21cd93STycho Nightingale 	 */
1729*bf21cd93STycho Nightingale 	pci_lintr_update(pi);
1730*bf21cd93STycho Nightingale }
1731*bf21cd93STycho Nightingale 
1732*bf21cd93STycho Nightingale static void
1733*bf21cd93STycho Nightingale pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
1734*bf21cd93STycho Nightingale     int coff, int bytes, uint32_t *eax)
1735*bf21cd93STycho Nightingale {
1736*bf21cd93STycho Nightingale 	struct businfo *bi;
1737*bf21cd93STycho Nightingale 	struct slotinfo *si;
1738*bf21cd93STycho Nightingale 	struct pci_devinst *pi;
1739*bf21cd93STycho Nightingale 	struct pci_devemu *pe;
1740*bf21cd93STycho Nightingale 	int idx, needcfg;
1741*bf21cd93STycho Nightingale 	uint64_t addr, bar, mask;
1742*bf21cd93STycho Nightingale 
1743*bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) != NULL) {
1744*bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
1745*bf21cd93STycho Nightingale 		pi = si->si_funcs[func].fi_devi;
1746*bf21cd93STycho Nightingale 	} else
1747*bf21cd93STycho Nightingale 		pi = NULL;
1748*bf21cd93STycho Nightingale 
1749*bf21cd93STycho Nightingale 	/*
1750*bf21cd93STycho Nightingale 	 * Just return if there is no device at this slot:func or if the
1751*bf21cd93STycho Nightingale 	 * the guest is doing an un-aligned access.
1752*bf21cd93STycho Nightingale 	 */
1753*bf21cd93STycho Nightingale 	if (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) ||
1754*bf21cd93STycho Nightingale 	    (coff & (bytes - 1)) != 0) {
1755*bf21cd93STycho Nightingale 		if (in)
1756*bf21cd93STycho Nightingale 			*eax = 0xffffffff;
1757*bf21cd93STycho Nightingale 		return;
1758*bf21cd93STycho Nightingale 	}
1759*bf21cd93STycho Nightingale 
1760*bf21cd93STycho Nightingale 	/*
1761*bf21cd93STycho Nightingale 	 * Ignore all writes beyond the standard config space and return all
1762*bf21cd93STycho Nightingale 	 * ones on reads.
1763*bf21cd93STycho Nightingale 	 */
1764*bf21cd93STycho Nightingale 	if (coff >= PCI_REGMAX + 1) {
1765*bf21cd93STycho Nightingale 		if (in) {
1766*bf21cd93STycho Nightingale 			*eax = 0xffffffff;
1767*bf21cd93STycho Nightingale 			/*
1768*bf21cd93STycho Nightingale 			 * Extended capabilities begin at offset 256 in config
1769*bf21cd93STycho Nightingale 			 * space. Absence of extended capabilities is signaled
1770*bf21cd93STycho Nightingale 			 * with all 0s in the extended capability header at
1771*bf21cd93STycho Nightingale 			 * offset 256.
1772*bf21cd93STycho Nightingale 			 */
1773*bf21cd93STycho Nightingale 			if (coff <= PCI_REGMAX + 4)
1774*bf21cd93STycho Nightingale 				*eax = 0x00000000;
1775*bf21cd93STycho Nightingale 		}
1776*bf21cd93STycho Nightingale 		return;
1777*bf21cd93STycho Nightingale 	}
1778*bf21cd93STycho Nightingale 
1779*bf21cd93STycho Nightingale 	pe = pi->pi_d;
1780*bf21cd93STycho Nightingale 
1781*bf21cd93STycho Nightingale 	/*
1782*bf21cd93STycho Nightingale 	 * Config read
1783*bf21cd93STycho Nightingale 	 */
1784*bf21cd93STycho Nightingale 	if (in) {
1785*bf21cd93STycho Nightingale 		/* Let the device emulation override the default handler */
1786*bf21cd93STycho Nightingale 		if (pe->pe_cfgread != NULL) {
1787*bf21cd93STycho Nightingale 			needcfg = pe->pe_cfgread(ctx, vcpu, pi, coff, bytes,
1788*bf21cd93STycho Nightingale 			    eax);
1789*bf21cd93STycho Nightingale 		} else {
1790*bf21cd93STycho Nightingale 			needcfg = 1;
1791*bf21cd93STycho Nightingale 		}
1792*bf21cd93STycho Nightingale 
1793*bf21cd93STycho Nightingale 		if (needcfg) {
1794*bf21cd93STycho Nightingale 			if (bytes == 1)
1795*bf21cd93STycho Nightingale 				*eax = pci_get_cfgdata8(pi, coff);
1796*bf21cd93STycho Nightingale 			else if (bytes == 2)
1797*bf21cd93STycho Nightingale 				*eax = pci_get_cfgdata16(pi, coff);
1798*bf21cd93STycho Nightingale 			else
1799*bf21cd93STycho Nightingale 				*eax = pci_get_cfgdata32(pi, coff);
1800*bf21cd93STycho Nightingale 		}
1801*bf21cd93STycho Nightingale 
1802*bf21cd93STycho Nightingale 		pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax);
1803*bf21cd93STycho Nightingale 	} else {
1804*bf21cd93STycho Nightingale 		/* Let the device emulation override the default handler */
1805*bf21cd93STycho Nightingale 		if (pe->pe_cfgwrite != NULL &&
1806*bf21cd93STycho Nightingale 		    (*pe->pe_cfgwrite)(ctx, vcpu, pi, coff, bytes, *eax) == 0)
1807*bf21cd93STycho Nightingale 			return;
1808*bf21cd93STycho Nightingale 
1809*bf21cd93STycho Nightingale 		/*
1810*bf21cd93STycho Nightingale 		 * Special handling for write to BAR registers
1811*bf21cd93STycho Nightingale 		 */
1812*bf21cd93STycho Nightingale 		if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) {
1813*bf21cd93STycho Nightingale 			/*
1814*bf21cd93STycho Nightingale 			 * Ignore writes to BAR registers that are not
1815*bf21cd93STycho Nightingale 			 * 4-byte aligned.
1816*bf21cd93STycho Nightingale 			 */
1817*bf21cd93STycho Nightingale 			if (bytes != 4 || (coff & 0x3) != 0)
1818*bf21cd93STycho Nightingale 				return;
1819*bf21cd93STycho Nightingale 			idx = (coff - PCIR_BAR(0)) / 4;
1820*bf21cd93STycho Nightingale 			mask = ~(pi->pi_bar[idx].size - 1);
1821*bf21cd93STycho Nightingale 			switch (pi->pi_bar[idx].type) {
1822*bf21cd93STycho Nightingale 			case PCIBAR_NONE:
1823*bf21cd93STycho Nightingale 				pi->pi_bar[idx].addr = bar = 0;
1824*bf21cd93STycho Nightingale 				break;
1825*bf21cd93STycho Nightingale 			case PCIBAR_IO:
1826*bf21cd93STycho Nightingale 				addr = *eax & mask;
1827*bf21cd93STycho Nightingale 				addr &= 0xffff;
1828*bf21cd93STycho Nightingale 				bar = addr | PCIM_BAR_IO_SPACE;
1829*bf21cd93STycho Nightingale 				/*
1830*bf21cd93STycho Nightingale 				 * Register the new BAR value for interception
1831*bf21cd93STycho Nightingale 				 */
1832*bf21cd93STycho Nightingale 				if (addr != pi->pi_bar[idx].addr) {
1833*bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx,
1834*bf21cd93STycho Nightingale 							   PCIBAR_IO);
1835*bf21cd93STycho Nightingale 				}
1836*bf21cd93STycho Nightingale 				break;
1837*bf21cd93STycho Nightingale 			case PCIBAR_MEM32:
1838*bf21cd93STycho Nightingale 				addr = bar = *eax & mask;
1839*bf21cd93STycho Nightingale 				bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
1840*bf21cd93STycho Nightingale 				if (addr != pi->pi_bar[idx].addr) {
1841*bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx,
1842*bf21cd93STycho Nightingale 							   PCIBAR_MEM32);
1843*bf21cd93STycho Nightingale 				}
1844*bf21cd93STycho Nightingale 				break;
1845*bf21cd93STycho Nightingale 			case PCIBAR_MEM64:
1846*bf21cd93STycho Nightingale 				addr = bar = *eax & mask;
1847*bf21cd93STycho Nightingale 				bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
1848*bf21cd93STycho Nightingale 				       PCIM_BAR_MEM_PREFETCH;
1849*bf21cd93STycho Nightingale 				if (addr != (uint32_t)pi->pi_bar[idx].addr) {
1850*bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx,
1851*bf21cd93STycho Nightingale 							   PCIBAR_MEM64);
1852*bf21cd93STycho Nightingale 				}
1853*bf21cd93STycho Nightingale 				break;
1854*bf21cd93STycho Nightingale 			case PCIBAR_MEMHI64:
1855*bf21cd93STycho Nightingale 				mask = ~(pi->pi_bar[idx - 1].size - 1);
1856*bf21cd93STycho Nightingale 				addr = ((uint64_t)*eax << 32) & mask;
1857*bf21cd93STycho Nightingale 				bar = addr >> 32;
1858*bf21cd93STycho Nightingale 				if (bar != pi->pi_bar[idx - 1].addr >> 32) {
1859*bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx - 1,
1860*bf21cd93STycho Nightingale 							   PCIBAR_MEMHI64);
1861*bf21cd93STycho Nightingale 				}
1862*bf21cd93STycho Nightingale 				break;
1863*bf21cd93STycho Nightingale 			default:
1864*bf21cd93STycho Nightingale 				assert(0);
1865*bf21cd93STycho Nightingale 			}
1866*bf21cd93STycho Nightingale 			pci_set_cfgdata32(pi, coff, bar);
1867*bf21cd93STycho Nightingale 
1868*bf21cd93STycho Nightingale 		} else if (pci_emul_iscap(pi, coff)) {
1869*bf21cd93STycho Nightingale 			pci_emul_capwrite(pi, coff, bytes, *eax);
1870*bf21cd93STycho Nightingale 		} else if (coff == PCIR_COMMAND) {
1871*bf21cd93STycho Nightingale 			pci_emul_cmdwrite(pi, *eax, bytes);
1872*bf21cd93STycho Nightingale 		} else {
1873*bf21cd93STycho Nightingale 			CFGWRITE(pi, coff, *eax, bytes);
1874*bf21cd93STycho Nightingale 		}
1875*bf21cd93STycho Nightingale 	}
1876*bf21cd93STycho Nightingale }
1877*bf21cd93STycho Nightingale 
1878*bf21cd93STycho Nightingale static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff;
1879*bf21cd93STycho Nightingale 
1880*bf21cd93STycho Nightingale static int
1881*bf21cd93STycho Nightingale pci_emul_cfgaddr(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
1882*bf21cd93STycho Nightingale 		 uint32_t *eax, void *arg)
1883*bf21cd93STycho Nightingale {
1884*bf21cd93STycho Nightingale 	uint32_t x;
1885*bf21cd93STycho Nightingale 
1886*bf21cd93STycho Nightingale 	if (bytes != 4) {
1887*bf21cd93STycho Nightingale 		if (in)
1888*bf21cd93STycho Nightingale 			*eax = (bytes == 2) ? 0xffff : 0xff;
1889*bf21cd93STycho Nightingale 		return (0);
1890*bf21cd93STycho Nightingale 	}
1891*bf21cd93STycho Nightingale 
1892*bf21cd93STycho Nightingale 	if (in) {
1893*bf21cd93STycho Nightingale 		x = (cfgbus << 16) | (cfgslot << 11) | (cfgfunc << 8) | cfgoff;
1894*bf21cd93STycho Nightingale 		if (cfgenable)
1895*bf21cd93STycho Nightingale 			x |= CONF1_ENABLE;
1896*bf21cd93STycho Nightingale 		*eax = x;
1897*bf21cd93STycho Nightingale 	} else {
1898*bf21cd93STycho Nightingale 		x = *eax;
1899*bf21cd93STycho Nightingale 		cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;
1900*bf21cd93STycho Nightingale 		cfgoff = x & PCI_REGMAX;
1901*bf21cd93STycho Nightingale 		cfgfunc = (x >> 8) & PCI_FUNCMAX;
1902*bf21cd93STycho Nightingale 		cfgslot = (x >> 11) & PCI_SLOTMAX;
1903*bf21cd93STycho Nightingale 		cfgbus = (x >> 16) & PCI_BUSMAX;
1904*bf21cd93STycho Nightingale 	}
1905*bf21cd93STycho Nightingale 
1906*bf21cd93STycho Nightingale 	return (0);
1907*bf21cd93STycho Nightingale }
1908*bf21cd93STycho Nightingale INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_INOUT, pci_emul_cfgaddr);
1909*bf21cd93STycho Nightingale 
1910*bf21cd93STycho Nightingale static int
1911*bf21cd93STycho Nightingale pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
1912*bf21cd93STycho Nightingale 		 uint32_t *eax, void *arg)
1913*bf21cd93STycho Nightingale {
1914*bf21cd93STycho Nightingale 	int coff;
1915*bf21cd93STycho Nightingale 
1916*bf21cd93STycho Nightingale 	assert(bytes == 1 || bytes == 2 || bytes == 4);
1917*bf21cd93STycho Nightingale 
1918*bf21cd93STycho Nightingale 	coff = cfgoff + (port - CONF1_DATA_PORT);
1919*bf21cd93STycho Nightingale 	if (cfgenable) {
1920*bf21cd93STycho Nightingale 		pci_cfgrw(ctx, vcpu, in, cfgbus, cfgslot, cfgfunc, coff, bytes,
1921*bf21cd93STycho Nightingale 		    eax);
1922*bf21cd93STycho Nightingale 	} else {
1923*bf21cd93STycho Nightingale 		/* Ignore accesses to cfgdata if not enabled by cfgaddr */
1924*bf21cd93STycho Nightingale 		if (in)
1925*bf21cd93STycho Nightingale 			*eax = 0xffffffff;
1926*bf21cd93STycho Nightingale 	}
1927*bf21cd93STycho Nightingale 	return (0);
1928*bf21cd93STycho Nightingale }
1929*bf21cd93STycho Nightingale 
1930*bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+0, IOPORT_F_INOUT, pci_emul_cfgdata);
1931*bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+1, IOPORT_F_INOUT, pci_emul_cfgdata);
1932*bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+2, IOPORT_F_INOUT, pci_emul_cfgdata);
1933*bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+3, IOPORT_F_INOUT, pci_emul_cfgdata);
1934*bf21cd93STycho Nightingale 
1935*bf21cd93STycho Nightingale #define PCI_EMUL_TEST
1936*bf21cd93STycho Nightingale #ifdef PCI_EMUL_TEST
1937*bf21cd93STycho Nightingale /*
1938*bf21cd93STycho Nightingale  * Define a dummy test device
1939*bf21cd93STycho Nightingale  */
1940*bf21cd93STycho Nightingale #define DIOSZ	8
1941*bf21cd93STycho Nightingale #define DMEMSZ	4096
1942*bf21cd93STycho Nightingale struct pci_emul_dsoftc {
1943*bf21cd93STycho Nightingale 	uint8_t   ioregs[DIOSZ];
1944*bf21cd93STycho Nightingale 	uint8_t	  memregs[DMEMSZ];
1945*bf21cd93STycho Nightingale };
1946*bf21cd93STycho Nightingale 
1947*bf21cd93STycho Nightingale #define	PCI_EMUL_MSI_MSGS	 4
1948*bf21cd93STycho Nightingale #define	PCI_EMUL_MSIX_MSGS	16
1949*bf21cd93STycho Nightingale 
1950*bf21cd93STycho Nightingale static int
1951*bf21cd93STycho Nightingale pci_emul_dinit(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
1952*bf21cd93STycho Nightingale {
1953*bf21cd93STycho Nightingale 	int error;
1954*bf21cd93STycho Nightingale 	struct pci_emul_dsoftc *sc;
1955*bf21cd93STycho Nightingale 
1956*bf21cd93STycho Nightingale 	sc = calloc(1, sizeof(struct pci_emul_dsoftc));
1957*bf21cd93STycho Nightingale 
1958*bf21cd93STycho Nightingale 	pi->pi_arg = sc;
1959*bf21cd93STycho Nightingale 
1960*bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x0001);
1961*bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_VENDOR, 0x10DD);
1962*bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_CLASS, 0x02);
1963*bf21cd93STycho Nightingale 
1964*bf21cd93STycho Nightingale 	error = pci_emul_add_msicap(pi, PCI_EMUL_MSI_MSGS);
1965*bf21cd93STycho Nightingale 	assert(error == 0);
1966*bf21cd93STycho Nightingale 
1967*bf21cd93STycho Nightingale 	error = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, DIOSZ);
1968*bf21cd93STycho Nightingale 	assert(error == 0);
1969*bf21cd93STycho Nightingale 
1970*bf21cd93STycho Nightingale 	error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, DMEMSZ);
1971*bf21cd93STycho Nightingale 	assert(error == 0);
1972*bf21cd93STycho Nightingale 
1973*bf21cd93STycho Nightingale 	return (0);
1974*bf21cd93STycho Nightingale }
1975*bf21cd93STycho Nightingale 
1976*bf21cd93STycho Nightingale static void
1977*bf21cd93STycho Nightingale pci_emul_diow(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
1978*bf21cd93STycho Nightingale 	      uint64_t offset, int size, uint64_t value)
1979*bf21cd93STycho Nightingale {
1980*bf21cd93STycho Nightingale 	int i;
1981*bf21cd93STycho Nightingale 	struct pci_emul_dsoftc *sc = pi->pi_arg;
1982*bf21cd93STycho Nightingale 
1983*bf21cd93STycho Nightingale 	if (baridx == 0) {
1984*bf21cd93STycho Nightingale 		if (offset + size > DIOSZ) {
1985*bf21cd93STycho Nightingale 			printf("diow: iow too large, offset %ld size %d\n",
1986*bf21cd93STycho Nightingale 			       offset, size);
1987*bf21cd93STycho Nightingale 			return;
1988*bf21cd93STycho Nightingale 		}
1989*bf21cd93STycho Nightingale 
1990*bf21cd93STycho Nightingale 		if (size == 1) {
1991*bf21cd93STycho Nightingale 			sc->ioregs[offset] = value & 0xff;
1992*bf21cd93STycho Nightingale 		} else if (size == 2) {
1993*bf21cd93STycho Nightingale 			*(uint16_t *)&sc->ioregs[offset] = value & 0xffff;
1994*bf21cd93STycho Nightingale 		} else if (size == 4) {
1995*bf21cd93STycho Nightingale 			*(uint32_t *)&sc->ioregs[offset] = value;
1996*bf21cd93STycho Nightingale 		} else {
1997*bf21cd93STycho Nightingale 			printf("diow: iow unknown size %d\n", size);
1998*bf21cd93STycho Nightingale 		}
1999*bf21cd93STycho Nightingale 
2000*bf21cd93STycho Nightingale 		/*
2001*bf21cd93STycho Nightingale 		 * Special magic value to generate an interrupt
2002*bf21cd93STycho Nightingale 		 */
2003*bf21cd93STycho Nightingale 		if (offset == 4 && size == 4 && pci_msi_enabled(pi))
2004*bf21cd93STycho Nightingale 			pci_generate_msi(pi, value % pci_msi_maxmsgnum(pi));
2005*bf21cd93STycho Nightingale 
2006*bf21cd93STycho Nightingale 		if (value == 0xabcdef) {
2007*bf21cd93STycho Nightingale 			for (i = 0; i < pci_msi_maxmsgnum(pi); i++)
2008*bf21cd93STycho Nightingale 				pci_generate_msi(pi, i);
2009*bf21cd93STycho Nightingale 		}
2010*bf21cd93STycho Nightingale 	}
2011*bf21cd93STycho Nightingale 
2012*bf21cd93STycho Nightingale 	if (baridx == 1) {
2013*bf21cd93STycho Nightingale 		if (offset + size > DMEMSZ) {
2014*bf21cd93STycho Nightingale 			printf("diow: memw too large, offset %ld size %d\n",
2015*bf21cd93STycho Nightingale 			       offset, size);
2016*bf21cd93STycho Nightingale 			return;
2017*bf21cd93STycho Nightingale 		}
2018*bf21cd93STycho Nightingale 
2019*bf21cd93STycho Nightingale 		if (size == 1) {
2020*bf21cd93STycho Nightingale 			sc->memregs[offset] = value;
2021*bf21cd93STycho Nightingale 		} else if (size == 2) {
2022*bf21cd93STycho Nightingale 			*(uint16_t *)&sc->memregs[offset] = value;
2023*bf21cd93STycho Nightingale 		} else if (size == 4) {
2024*bf21cd93STycho Nightingale 			*(uint32_t *)&sc->memregs[offset] = value;
2025*bf21cd93STycho Nightingale 		} else if (size == 8) {
2026*bf21cd93STycho Nightingale 			*(uint64_t *)&sc->memregs[offset] = value;
2027*bf21cd93STycho Nightingale 		} else {
2028*bf21cd93STycho Nightingale 			printf("diow: memw unknown size %d\n", size);
2029*bf21cd93STycho Nightingale 		}
2030*bf21cd93STycho Nightingale 
2031*bf21cd93STycho Nightingale 		/*
2032*bf21cd93STycho Nightingale 		 * magic interrupt ??
2033*bf21cd93STycho Nightingale 		 */
2034*bf21cd93STycho Nightingale 	}
2035*bf21cd93STycho Nightingale 
2036*bf21cd93STycho Nightingale 	if (baridx > 1) {
2037*bf21cd93STycho Nightingale 		printf("diow: unknown bar idx %d\n", baridx);
2038*bf21cd93STycho Nightingale 	}
2039*bf21cd93STycho Nightingale }
2040*bf21cd93STycho Nightingale 
2041*bf21cd93STycho Nightingale static uint64_t
2042*bf21cd93STycho Nightingale pci_emul_dior(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
2043*bf21cd93STycho Nightingale 	      uint64_t offset, int size)
2044*bf21cd93STycho Nightingale {
2045*bf21cd93STycho Nightingale 	struct pci_emul_dsoftc *sc = pi->pi_arg;
2046*bf21cd93STycho Nightingale 	uint32_t value;
2047*bf21cd93STycho Nightingale 
2048*bf21cd93STycho Nightingale 	if (baridx == 0) {
2049*bf21cd93STycho Nightingale 		if (offset + size > DIOSZ) {
2050*bf21cd93STycho Nightingale 			printf("dior: ior too large, offset %ld size %d\n",
2051*bf21cd93STycho Nightingale 			       offset, size);
2052*bf21cd93STycho Nightingale 			return (0);
2053*bf21cd93STycho Nightingale 		}
2054*bf21cd93STycho Nightingale 
2055*bf21cd93STycho Nightingale 		if (size == 1) {
2056*bf21cd93STycho Nightingale 			value = sc->ioregs[offset];
2057*bf21cd93STycho Nightingale 		} else if (size == 2) {
2058*bf21cd93STycho Nightingale 			value = *(uint16_t *) &sc->ioregs[offset];
2059*bf21cd93STycho Nightingale 		} else if (size == 4) {
2060*bf21cd93STycho Nightingale 			value = *(uint32_t *) &sc->ioregs[offset];
2061*bf21cd93STycho Nightingale 		} else {
2062*bf21cd93STycho Nightingale 			printf("dior: ior unknown size %d\n", size);
2063*bf21cd93STycho Nightingale 		}
2064*bf21cd93STycho Nightingale 	}
2065*bf21cd93STycho Nightingale 
2066*bf21cd93STycho Nightingale 	if (baridx == 1) {
2067*bf21cd93STycho Nightingale 		if (offset + size > DMEMSZ) {
2068*bf21cd93STycho Nightingale 			printf("dior: memr too large, offset %ld size %d\n",
2069*bf21cd93STycho Nightingale 			       offset, size);
2070*bf21cd93STycho Nightingale 			return (0);
2071*bf21cd93STycho Nightingale 		}
2072*bf21cd93STycho Nightingale 
2073*bf21cd93STycho Nightingale 		if (size == 1) {
2074*bf21cd93STycho Nightingale 			value = sc->memregs[offset];
2075*bf21cd93STycho Nightingale 		} else if (size == 2) {
2076*bf21cd93STycho Nightingale 			value = *(uint16_t *) &sc->memregs[offset];
2077*bf21cd93STycho Nightingale 		} else if (size == 4) {
2078*bf21cd93STycho Nightingale 			value = *(uint32_t *) &sc->memregs[offset];
2079*bf21cd93STycho Nightingale 		} else if (size == 8) {
2080*bf21cd93STycho Nightingale 			value = *(uint64_t *) &sc->memregs[offset];
2081*bf21cd93STycho Nightingale 		} else {
2082*bf21cd93STycho Nightingale 			printf("dior: ior unknown size %d\n", size);
2083*bf21cd93STycho Nightingale 		}
2084*bf21cd93STycho Nightingale 	}
2085*bf21cd93STycho Nightingale 
2086*bf21cd93STycho Nightingale 
2087*bf21cd93STycho Nightingale 	if (baridx > 1) {
2088*bf21cd93STycho Nightingale 		printf("dior: unknown bar idx %d\n", baridx);
2089*bf21cd93STycho Nightingale 		return (0);
2090*bf21cd93STycho Nightingale 	}
2091*bf21cd93STycho Nightingale 
2092*bf21cd93STycho Nightingale 	return (value);
2093*bf21cd93STycho Nightingale }
2094*bf21cd93STycho Nightingale 
2095*bf21cd93STycho Nightingale struct pci_devemu pci_dummy = {
2096*bf21cd93STycho Nightingale 	.pe_emu = "dummy",
2097*bf21cd93STycho Nightingale 	.pe_init = pci_emul_dinit,
2098*bf21cd93STycho Nightingale 	.pe_barwrite = pci_emul_diow,
2099*bf21cd93STycho Nightingale 	.pe_barread = pci_emul_dior
2100*bf21cd93STycho Nightingale };
2101*bf21cd93STycho Nightingale PCI_EMUL_SET(pci_dummy);
2102*bf21cd93STycho Nightingale 
2103*bf21cd93STycho Nightingale #endif /* PCI_EMUL_TEST */
2104