xref: /freebsd/usr.sbin/bhyve/pci_emul.c (revision 56282675)
1366f6083SPeter Grehan /*-
21de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
31de7b4b8SPedro F. Giffuni  *
4366f6083SPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
5366f6083SPeter Grehan  * All rights reserved.
6366f6083SPeter Grehan  *
7366f6083SPeter Grehan  * Redistribution and use in source and binary forms, with or without
8366f6083SPeter Grehan  * modification, are permitted provided that the following conditions
9366f6083SPeter Grehan  * are met:
10366f6083SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
11366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer.
12366f6083SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
13366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
14366f6083SPeter Grehan  *    documentation and/or other materials provided with the distribution.
15366f6083SPeter Grehan  *
16366f6083SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17366f6083SPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18366f6083SPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19366f6083SPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20366f6083SPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21366f6083SPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22366f6083SPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23366f6083SPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24366f6083SPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25366f6083SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26366f6083SPeter Grehan  * SUCH DAMAGE.
27366f6083SPeter Grehan  *
28366f6083SPeter Grehan  * $FreeBSD$
29366f6083SPeter Grehan  */
30366f6083SPeter Grehan 
31366f6083SPeter Grehan #include <sys/cdefs.h>
32366f6083SPeter Grehan __FBSDID("$FreeBSD$");
33366f6083SPeter Grehan 
34366f6083SPeter Grehan #include <sys/param.h>
35366f6083SPeter Grehan #include <sys/linker_set.h>
36366f6083SPeter Grehan 
37366f6083SPeter Grehan #include <ctype.h>
387e12dfe5SEnji Cooper #include <errno.h>
393cbf3585SJohn Baldwin #include <pthread.h>
40366f6083SPeter Grehan #include <stdio.h>
41366f6083SPeter Grehan #include <stdlib.h>
42366f6083SPeter Grehan #include <string.h>
43366f6083SPeter Grehan #include <strings.h>
44366f6083SPeter Grehan #include <assert.h>
45028d9311SNeel Natu #include <stdbool.h>
46366f6083SPeter Grehan 
47366f6083SPeter Grehan #include <machine/vmm.h>
48366f6083SPeter Grehan #include <vmmapi.h>
49366f6083SPeter Grehan 
50e6c8bc29SJohn Baldwin #include "acpi.h"
51e285ef8dSPeter Grehan #include "bhyverun.h"
52366f6083SPeter Grehan #include "inout.h"
533cbf3585SJohn Baldwin #include "ioapic.h"
544d1e669cSPeter Grehan #include "mem.h"
55366f6083SPeter Grehan #include "pci_emul.h"
56b3e9732aSJohn Baldwin #include "pci_irq.h"
57e6c8bc29SJohn Baldwin #include "pci_lpc.h"
58366f6083SPeter Grehan 
59366f6083SPeter Grehan #define CONF1_ADDR_PORT	   0x0cf8
60366f6083SPeter Grehan #define CONF1_DATA_PORT	   0x0cfc
61366f6083SPeter Grehan 
6275543036SPeter Grehan #define CONF1_ENABLE	   0x80000000ul
6375543036SPeter Grehan 
64d84882caSNeel Natu #define	MAXBUSES	(PCI_BUSMAX + 1)
6599d65389SNeel Natu #define MAXSLOTS	(PCI_SLOTMAX + 1)
6699d65389SNeel Natu #define	MAXFUNCS	(PCI_FUNCMAX + 1)
67366f6083SPeter Grehan 
683cbf3585SJohn Baldwin struct funcinfo {
693cbf3585SJohn Baldwin 	char	*fi_name;
703cbf3585SJohn Baldwin 	char	*fi_param;
713cbf3585SJohn Baldwin 	struct pci_devinst *fi_devi;
723cbf3585SJohn Baldwin };
733cbf3585SJohn Baldwin 
743cbf3585SJohn Baldwin struct intxinfo {
753cbf3585SJohn Baldwin 	int	ii_count;
76b3e9732aSJohn Baldwin 	int	ii_pirq_pin;
773cbf3585SJohn Baldwin 	int	ii_ioapic_irq;
783cbf3585SJohn Baldwin };
793cbf3585SJohn Baldwin 
803cbf3585SJohn Baldwin struct slotinfo {
813cbf3585SJohn Baldwin 	struct intxinfo si_intpins[4];
823cbf3585SJohn Baldwin 	struct funcinfo si_funcs[MAXFUNCS];
83d84882caSNeel Natu };
84d84882caSNeel Natu 
85d84882caSNeel Natu struct businfo {
86d84882caSNeel Natu 	uint16_t iobase, iolimit;		/* I/O window */
87d84882caSNeel Natu 	uint32_t membase32, memlimit32;		/* mmio window below 4GB */
88d84882caSNeel Natu 	uint64_t membase64, memlimit64;		/* mmio window above 4GB */
89d84882caSNeel Natu 	struct slotinfo slotinfo[MAXSLOTS];
90d84882caSNeel Natu };
91d84882caSNeel Natu 
92d84882caSNeel Natu static struct businfo *pci_businfo[MAXBUSES];
93366f6083SPeter Grehan 
94366f6083SPeter Grehan SET_DECLARE(pci_devemu_set, struct pci_devemu);
95366f6083SPeter Grehan 
96366f6083SPeter Grehan static uint64_t pci_emul_iobase;
97366f6083SPeter Grehan static uint64_t pci_emul_membase32;
98366f6083SPeter Grehan static uint64_t pci_emul_membase64;
99366f6083SPeter Grehan 
100366f6083SPeter Grehan #define	PCI_EMUL_IOBASE		0x2000
101366f6083SPeter Grehan #define	PCI_EMUL_IOLIMIT	0x10000
102366f6083SPeter Grehan 
10312a6eb99SNeel Natu #define	PCI_EMUL_ECFG_BASE	0xE0000000		    /* 3.5GB */
10412a6eb99SNeel Natu #define	PCI_EMUL_ECFG_SIZE	(MAXBUSES * 1024 * 1024)    /* 1MB per bus */
10512a6eb99SNeel Natu SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE);
10612a6eb99SNeel Natu 
10712a6eb99SNeel Natu #define	PCI_EMUL_MEMLIMIT32	PCI_EMUL_ECFG_BASE
108366f6083SPeter Grehan 
109366f6083SPeter Grehan #define	PCI_EMUL_MEMBASE64	0xD000000000UL
110366f6083SPeter Grehan #define	PCI_EMUL_MEMLIMIT64	0xFD00000000UL
111366f6083SPeter Grehan 
112b05c77ffSNeel Natu static struct pci_devemu *pci_emul_finddev(char *name);
113b3e9732aSJohn Baldwin static void pci_lintr_route(struct pci_devinst *pi);
1143cbf3585SJohn Baldwin static void pci_lintr_update(struct pci_devinst *pi);
11512a6eb99SNeel Natu static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot,
11612a6eb99SNeel Natu     int func, int coff, int bytes, uint32_t *val);
117366f6083SPeter Grehan 
11854335630SNeel Natu static __inline void
11954335630SNeel Natu CFGWRITE(struct pci_devinst *pi, int coff, uint32_t val, int bytes)
12054335630SNeel Natu {
12154335630SNeel Natu 
12254335630SNeel Natu 	if (bytes == 1)
12354335630SNeel Natu 		pci_set_cfgdata8(pi, coff, val);
12454335630SNeel Natu 	else if (bytes == 2)
12554335630SNeel Natu 		pci_set_cfgdata16(pi, coff, val);
12654335630SNeel Natu 	else
12754335630SNeel Natu 		pci_set_cfgdata32(pi, coff, val);
12854335630SNeel Natu }
12954335630SNeel Natu 
13054335630SNeel Natu static __inline uint32_t
13154335630SNeel Natu CFGREAD(struct pci_devinst *pi, int coff, int bytes)
13254335630SNeel Natu {
13354335630SNeel Natu 
13454335630SNeel Natu 	if (bytes == 1)
13554335630SNeel Natu 		return (pci_get_cfgdata8(pi, coff));
13654335630SNeel Natu 	else if (bytes == 2)
13754335630SNeel Natu 		return (pci_get_cfgdata16(pi, coff));
13854335630SNeel Natu 	else
13954335630SNeel Natu 		return (pci_get_cfgdata32(pi, coff));
14054335630SNeel Natu }
14154335630SNeel Natu 
142366f6083SPeter Grehan /*
143366f6083SPeter Grehan  * I/O access
144366f6083SPeter Grehan  */
145366f6083SPeter Grehan 
146366f6083SPeter Grehan /*
147366f6083SPeter Grehan  * Slot options are in the form:
148366f6083SPeter Grehan  *
149d84882caSNeel Natu  *  <bus>:<slot>:<func>,<emul>[,<config>]
15099d65389SNeel Natu  *  <slot>[:<func>],<emul>[,<config>]
151366f6083SPeter Grehan  *
152366f6083SPeter Grehan  *  slot is 0..31
15399d65389SNeel Natu  *  func is 0..7
154366f6083SPeter Grehan  *  emul is a string describing the type of PCI device e.g. virtio-net
155366f6083SPeter Grehan  *  config is an optional string, depending on the device, that can be
156366f6083SPeter Grehan  *  used for configuration.
157366f6083SPeter Grehan  *   Examples are:
158366f6083SPeter Grehan  *     1,virtio-net,tap0
15999d65389SNeel Natu  *     3:0,dummy
160366f6083SPeter Grehan  */
161366f6083SPeter Grehan static void
162366f6083SPeter Grehan pci_parse_slot_usage(char *aopt)
163366f6083SPeter Grehan {
164b05c77ffSNeel Natu 
165b05c77ffSNeel Natu 	fprintf(stderr, "Invalid PCI slot info field \"%s\"\n", aopt);
166366f6083SPeter Grehan }
167366f6083SPeter Grehan 
168b05c77ffSNeel Natu int
169d2bc4816SJohn Baldwin pci_parse_slot(char *opt)
170366f6083SPeter Grehan {
171d84882caSNeel Natu 	struct businfo *bi;
172d84882caSNeel Natu 	struct slotinfo *si;
173d84882caSNeel Natu 	char *emul, *config, *str, *cp;
174d84882caSNeel Natu 	int error, bnum, snum, fnum;
175366f6083SPeter Grehan 
176b05c77ffSNeel Natu 	error = -1;
177d84882caSNeel Natu 	str = strdup(opt);
17899d65389SNeel Natu 
179d84882caSNeel Natu 	emul = config = NULL;
180d84882caSNeel Natu 	if ((cp = strchr(str, ',')) != NULL) {
181d84882caSNeel Natu 		*cp = '\0';
182d84882caSNeel Natu 		emul = cp + 1;
183d84882caSNeel Natu 		if ((cp = strchr(emul, ',')) != NULL) {
184d84882caSNeel Natu 			*cp = '\0';
185d84882caSNeel Natu 			config = cp + 1;
18699d65389SNeel Natu 		}
187d84882caSNeel Natu 	} else {
188b05c77ffSNeel Natu 		pci_parse_slot_usage(opt);
189b05c77ffSNeel Natu 		goto done;
190366f6083SPeter Grehan 	}
191366f6083SPeter Grehan 
192d84882caSNeel Natu 	/* <bus>:<slot>:<func> */
193d84882caSNeel Natu 	if (sscanf(str, "%d:%d:%d", &bnum, &snum, &fnum) != 3) {
194d84882caSNeel Natu 		bnum = 0;
195d84882caSNeel Natu 		/* <slot>:<func> */
196d84882caSNeel Natu 		if (sscanf(str, "%d:%d", &snum, &fnum) != 2) {
197d84882caSNeel Natu 			fnum = 0;
198d84882caSNeel Natu 			/* <slot> */
199d84882caSNeel Natu 			if (sscanf(str, "%d", &snum) != 1) {
200d84882caSNeel Natu 				snum = -1;
201d84882caSNeel Natu 			}
202d84882caSNeel Natu 		}
203d84882caSNeel Natu 	}
204b05c77ffSNeel Natu 
205d84882caSNeel Natu 	if (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS ||
206d84882caSNeel Natu 	    fnum < 0 || fnum >= MAXFUNCS) {
207b05c77ffSNeel Natu 		pci_parse_slot_usage(opt);
208b05c77ffSNeel Natu 		goto done;
209b05c77ffSNeel Natu 	}
210b05c77ffSNeel Natu 
211d84882caSNeel Natu 	if (pci_businfo[bnum] == NULL)
212d84882caSNeel Natu 		pci_businfo[bnum] = calloc(1, sizeof(struct businfo));
213d84882caSNeel Natu 
214d84882caSNeel Natu 	bi = pci_businfo[bnum];
215d84882caSNeel Natu 	si = &bi->slotinfo[snum];
216d84882caSNeel Natu 
217d84882caSNeel Natu 	if (si->si_funcs[fnum].fi_name != NULL) {
218b05c77ffSNeel Natu 		fprintf(stderr, "pci slot %d:%d already occupied!\n",
219b05c77ffSNeel Natu 			snum, fnum);
220b05c77ffSNeel Natu 		goto done;
221b05c77ffSNeel Natu 	}
222b05c77ffSNeel Natu 
223b05c77ffSNeel Natu 	if (pci_emul_finddev(emul) == NULL) {
224b05c77ffSNeel Natu 		fprintf(stderr, "pci slot %d:%d: unknown device \"%s\"\n",
225b05c77ffSNeel Natu 			snum, fnum, emul);
226b05c77ffSNeel Natu 		goto done;
227b05c77ffSNeel Natu 	}
228b05c77ffSNeel Natu 
229b05c77ffSNeel Natu 	error = 0;
230d84882caSNeel Natu 	si->si_funcs[fnum].fi_name = emul;
231d84882caSNeel Natu 	si->si_funcs[fnum].fi_param = config;
232b05c77ffSNeel Natu 
233b05c77ffSNeel Natu done:
23492046bf1SMarcelo Araujo 	if (error)
235d84882caSNeel Natu 		free(str);
236b05c77ffSNeel Natu 
237b05c77ffSNeel Natu 	return (error);
238366f6083SPeter Grehan }
239366f6083SPeter Grehan 
240657d2158SMarcelo Araujo void
241657d2158SMarcelo Araujo pci_print_supported_devices()
242657d2158SMarcelo Araujo {
243657d2158SMarcelo Araujo 	struct pci_devemu **pdpp, *pdp;
244657d2158SMarcelo Araujo 
245657d2158SMarcelo Araujo 	SET_FOREACH(pdpp, pci_devemu_set) {
246657d2158SMarcelo Araujo 		pdp = *pdpp;
247657d2158SMarcelo Araujo 		printf("%s\n", pdp->pe_emu);
248657d2158SMarcelo Araujo 	}
249657d2158SMarcelo Araujo }
250657d2158SMarcelo Araujo 
251366f6083SPeter Grehan static int
252c9b4e987SNeel Natu pci_valid_pba_offset(struct pci_devinst *pi, uint64_t offset)
253c9b4e987SNeel Natu {
254c9b4e987SNeel Natu 
255c9b4e987SNeel Natu 	if (offset < pi->pi_msix.pba_offset)
256c9b4e987SNeel Natu 		return (0);
257c9b4e987SNeel Natu 
258c9b4e987SNeel Natu 	if (offset >= pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
259c9b4e987SNeel Natu 		return (0);
260c9b4e987SNeel Natu 	}
261c9b4e987SNeel Natu 
262c9b4e987SNeel Natu 	return (1);
263c9b4e987SNeel Natu }
264c9b4e987SNeel Natu 
265c9b4e987SNeel Natu int
266c9b4e987SNeel Natu pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,
267c9b4e987SNeel Natu 		     uint64_t value)
268c9b4e987SNeel Natu {
269c9b4e987SNeel Natu 	int msix_entry_offset;
270c9b4e987SNeel Natu 	int tab_index;
271c9b4e987SNeel Natu 	char *dest;
272c9b4e987SNeel Natu 
273c9b4e987SNeel Natu 	/* support only 4 or 8 byte writes */
274c9b4e987SNeel Natu 	if (size != 4 && size != 8)
275c9b4e987SNeel Natu 		return (-1);
276c9b4e987SNeel Natu 
277c9b4e987SNeel Natu 	/*
278c9b4e987SNeel Natu 	 * Return if table index is beyond what device supports
279c9b4e987SNeel Natu 	 */
280c9b4e987SNeel Natu 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
281c9b4e987SNeel Natu 	if (tab_index >= pi->pi_msix.table_count)
282c9b4e987SNeel Natu 		return (-1);
283c9b4e987SNeel Natu 
284c9b4e987SNeel Natu 	msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
285c9b4e987SNeel Natu 
286c9b4e987SNeel Natu 	/* support only aligned writes */
287c9b4e987SNeel Natu 	if ((msix_entry_offset % size) != 0)
288c9b4e987SNeel Natu 		return (-1);
289c9b4e987SNeel Natu 
290c9b4e987SNeel Natu 	dest = (char *)(pi->pi_msix.table + tab_index);
291c9b4e987SNeel Natu 	dest += msix_entry_offset;
292c9b4e987SNeel Natu 
293c9b4e987SNeel Natu 	if (size == 4)
294c9b4e987SNeel Natu 		*((uint32_t *)dest) = value;
295c9b4e987SNeel Natu 	else
296c9b4e987SNeel Natu 		*((uint64_t *)dest) = value;
297c9b4e987SNeel Natu 
298c9b4e987SNeel Natu 	return (0);
299c9b4e987SNeel Natu }
300c9b4e987SNeel Natu 
301c9b4e987SNeel Natu uint64_t
302c9b4e987SNeel Natu pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size)
303c9b4e987SNeel Natu {
304c9b4e987SNeel Natu 	char *dest;
305c9b4e987SNeel Natu 	int msix_entry_offset;
306c9b4e987SNeel Natu 	int tab_index;
307c9b4e987SNeel Natu 	uint64_t retval = ~0;
308c9b4e987SNeel Natu 
3096a52209fSNeel Natu 	/*
3106a52209fSNeel Natu 	 * The PCI standard only allows 4 and 8 byte accesses to the MSI-X
311463a577bSEitan Adler 	 * table but we also allow 1 byte access to accommodate reads from
3126a52209fSNeel Natu 	 * ddb.
3136a52209fSNeel Natu 	 */
3146a52209fSNeel Natu 	if (size != 1 && size != 4 && size != 8)
315c9b4e987SNeel Natu 		return (retval);
316c9b4e987SNeel Natu 
317c9b4e987SNeel Natu 	msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
318c9b4e987SNeel Natu 
319c9b4e987SNeel Natu 	/* support only aligned reads */
320c9b4e987SNeel Natu 	if ((msix_entry_offset % size) != 0) {
321c9b4e987SNeel Natu 		return (retval);
322c9b4e987SNeel Natu 	}
323c9b4e987SNeel Natu 
324c9b4e987SNeel Natu 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
325c9b4e987SNeel Natu 
326c9b4e987SNeel Natu 	if (tab_index < pi->pi_msix.table_count) {
327c9b4e987SNeel Natu 		/* valid MSI-X Table access */
328c9b4e987SNeel Natu 		dest = (char *)(pi->pi_msix.table + tab_index);
329c9b4e987SNeel Natu 		dest += msix_entry_offset;
330c9b4e987SNeel Natu 
3316a52209fSNeel Natu 		if (size == 1)
3326a52209fSNeel Natu 			retval = *((uint8_t *)dest);
3336a52209fSNeel Natu 		else if (size == 4)
334c9b4e987SNeel Natu 			retval = *((uint32_t *)dest);
335c9b4e987SNeel Natu 		else
336c9b4e987SNeel Natu 			retval = *((uint64_t *)dest);
337c9b4e987SNeel Natu 	} else if (pci_valid_pba_offset(pi, offset)) {
338c9b4e987SNeel Natu 		/* return 0 for PBA access */
339c9b4e987SNeel Natu 		retval = 0;
340c9b4e987SNeel Natu 	}
341c9b4e987SNeel Natu 
342c9b4e987SNeel Natu 	return (retval);
343c9b4e987SNeel Natu }
344c9b4e987SNeel Natu 
345aa12663fSNeel Natu int
346aa12663fSNeel Natu pci_msix_table_bar(struct pci_devinst *pi)
347aa12663fSNeel Natu {
348aa12663fSNeel Natu 
349aa12663fSNeel Natu 	if (pi->pi_msix.table != NULL)
350aa12663fSNeel Natu 		return (pi->pi_msix.table_bar);
351aa12663fSNeel Natu 	else
352aa12663fSNeel Natu 		return (-1);
353aa12663fSNeel Natu }
354aa12663fSNeel Natu 
355aa12663fSNeel Natu int
356aa12663fSNeel Natu pci_msix_pba_bar(struct pci_devinst *pi)
357aa12663fSNeel Natu {
358aa12663fSNeel Natu 
359aa12663fSNeel Natu 	if (pi->pi_msix.table != NULL)
360aa12663fSNeel Natu 		return (pi->pi_msix.pba_bar);
361aa12663fSNeel Natu 	else
362aa12663fSNeel Natu 		return (-1);
363aa12663fSNeel Natu }
364aa12663fSNeel Natu 
365c9b4e987SNeel Natu static int
3664d1e669cSPeter Grehan pci_emul_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
367366f6083SPeter Grehan 		    uint32_t *eax, void *arg)
368366f6083SPeter Grehan {
369366f6083SPeter Grehan 	struct pci_devinst *pdi = arg;
370366f6083SPeter Grehan 	struct pci_devemu *pe = pdi->pi_d;
3714d1e669cSPeter Grehan 	uint64_t offset;
3724d1e669cSPeter Grehan 	int i;
373366f6083SPeter Grehan 
374366f6083SPeter Grehan 	for (i = 0; i <= PCI_BARMAX; i++) {
375366f6083SPeter Grehan 		if (pdi->pi_bar[i].type == PCIBAR_IO &&
376366f6083SPeter Grehan 		    port >= pdi->pi_bar[i].addr &&
377c9b4e987SNeel Natu 		    port + bytes <= pdi->pi_bar[i].addr + pdi->pi_bar[i].size) {
378366f6083SPeter Grehan 			offset = port - pdi->pi_bar[i].addr;
379366f6083SPeter Grehan 			if (in)
3804d1e669cSPeter Grehan 				*eax = (*pe->pe_barread)(ctx, vcpu, pdi, i,
3814d1e669cSPeter Grehan 							 offset, bytes);
382366f6083SPeter Grehan 			else
3834d1e669cSPeter Grehan 				(*pe->pe_barwrite)(ctx, vcpu, pdi, i, offset,
3844d1e669cSPeter Grehan 						   bytes, *eax);
385366f6083SPeter Grehan 			return (0);
386366f6083SPeter Grehan 		}
387366f6083SPeter Grehan 	}
388366f6083SPeter Grehan 	return (-1);
389366f6083SPeter Grehan }
390366f6083SPeter Grehan 
391366f6083SPeter Grehan static int
3924d1e669cSPeter Grehan pci_emul_mem_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
3934d1e669cSPeter Grehan 		     int size, uint64_t *val, void *arg1, long arg2)
3944d1e669cSPeter Grehan {
3954d1e669cSPeter Grehan 	struct pci_devinst *pdi = arg1;
3964d1e669cSPeter Grehan 	struct pci_devemu *pe = pdi->pi_d;
3974d1e669cSPeter Grehan 	uint64_t offset;
3984d1e669cSPeter Grehan 	int bidx = (int) arg2;
3994d1e669cSPeter Grehan 
4004d1e669cSPeter Grehan 	assert(bidx <= PCI_BARMAX);
4014d1e669cSPeter Grehan 	assert(pdi->pi_bar[bidx].type == PCIBAR_MEM32 ||
4024d1e669cSPeter Grehan 	       pdi->pi_bar[bidx].type == PCIBAR_MEM64);
4034d1e669cSPeter Grehan 	assert(addr >= pdi->pi_bar[bidx].addr &&
4044d1e669cSPeter Grehan 	       addr + size <= pdi->pi_bar[bidx].addr + pdi->pi_bar[bidx].size);
4054d1e669cSPeter Grehan 
4064d1e669cSPeter Grehan 	offset = addr - pdi->pi_bar[bidx].addr;
4074d1e669cSPeter Grehan 
408b6ae8b05STycho Nightingale 	if (dir == MEM_F_WRITE) {
40967b6ffaaSTycho Nightingale 		if (size == 8) {
410b6ae8b05STycho Nightingale 			(*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset,
411b6ae8b05STycho Nightingale 					   4, *val & 0xffffffff);
412b6ae8b05STycho Nightingale 			(*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset + 4,
413b6ae8b05STycho Nightingale 					   4, *val >> 32);
414b6ae8b05STycho Nightingale 		} else {
415b6ae8b05STycho Nightingale 			(*pe->pe_barwrite)(ctx, vcpu, pdi, bidx, offset,
416b6ae8b05STycho Nightingale 					   size, *val);
417b6ae8b05STycho Nightingale 		}
418b6ae8b05STycho Nightingale 	} else {
41967b6ffaaSTycho Nightingale 		if (size == 8) {
420b6ae8b05STycho Nightingale 			*val = (*pe->pe_barread)(ctx, vcpu, pdi, bidx,
421b6ae8b05STycho Nightingale 						 offset, 4);
422b6ae8b05STycho Nightingale 			*val |= (*pe->pe_barread)(ctx, vcpu, pdi, bidx,
423b6ae8b05STycho Nightingale 						  offset + 4, 4) << 32;
424b6ae8b05STycho Nightingale 		} else {
425b6ae8b05STycho Nightingale 			*val = (*pe->pe_barread)(ctx, vcpu, pdi, bidx,
426b6ae8b05STycho Nightingale 						 offset, size);
427b6ae8b05STycho Nightingale 		}
428b6ae8b05STycho Nightingale 	}
4294d1e669cSPeter Grehan 
4304d1e669cSPeter Grehan 	return (0);
4314d1e669cSPeter Grehan }
4324d1e669cSPeter Grehan 
4334d1e669cSPeter Grehan 
4344d1e669cSPeter Grehan static int
435366f6083SPeter Grehan pci_emul_alloc_resource(uint64_t *baseptr, uint64_t limit, uint64_t size,
436366f6083SPeter Grehan 			uint64_t *addr)
437366f6083SPeter Grehan {
438366f6083SPeter Grehan 	uint64_t base;
439366f6083SPeter Grehan 
440366f6083SPeter Grehan 	assert((size & (size - 1)) == 0);	/* must be a power of 2 */
441366f6083SPeter Grehan 
442366f6083SPeter Grehan 	base = roundup2(*baseptr, size);
443366f6083SPeter Grehan 
444366f6083SPeter Grehan 	if (base + size <= limit) {
445366f6083SPeter Grehan 		*addr = base;
446366f6083SPeter Grehan 		*baseptr = base + size;
447366f6083SPeter Grehan 		return (0);
448366f6083SPeter Grehan 	} else
449366f6083SPeter Grehan 		return (-1);
450366f6083SPeter Grehan }
451366f6083SPeter Grehan 
452366f6083SPeter Grehan int
4534d1e669cSPeter Grehan pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
4544d1e669cSPeter Grehan 		   uint64_t size)
4554d1e669cSPeter Grehan {
4564d1e669cSPeter Grehan 
4574d1e669cSPeter Grehan 	return (pci_emul_alloc_pbar(pdi, idx, 0, type, size));
4584d1e669cSPeter Grehan }
4594d1e669cSPeter Grehan 
460028d9311SNeel Natu /*
461028d9311SNeel Natu  * Register (or unregister) the MMIO or I/O region associated with the BAR
462028d9311SNeel Natu  * register 'idx' of an emulated pci device.
463028d9311SNeel Natu  */
464028d9311SNeel Natu static void
465028d9311SNeel Natu modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
466028d9311SNeel Natu {
467028d9311SNeel Natu 	int error;
468028d9311SNeel Natu 	struct inout_port iop;
469028d9311SNeel Natu 	struct mem_range mr;
470028d9311SNeel Natu 
471028d9311SNeel Natu 	switch (pi->pi_bar[idx].type) {
472028d9311SNeel Natu 	case PCIBAR_IO:
473028d9311SNeel Natu 		bzero(&iop, sizeof(struct inout_port));
474028d9311SNeel Natu 		iop.name = pi->pi_name;
475028d9311SNeel Natu 		iop.port = pi->pi_bar[idx].addr;
476028d9311SNeel Natu 		iop.size = pi->pi_bar[idx].size;
477028d9311SNeel Natu 		if (registration) {
478028d9311SNeel Natu 			iop.flags = IOPORT_F_INOUT;
479028d9311SNeel Natu 			iop.handler = pci_emul_io_handler;
480028d9311SNeel Natu 			iop.arg = pi;
481028d9311SNeel Natu 			error = register_inout(&iop);
482028d9311SNeel Natu 		} else
483028d9311SNeel Natu 			error = unregister_inout(&iop);
484028d9311SNeel Natu 		break;
485028d9311SNeel Natu 	case PCIBAR_MEM32:
486028d9311SNeel Natu 	case PCIBAR_MEM64:
487028d9311SNeel Natu 		bzero(&mr, sizeof(struct mem_range));
488028d9311SNeel Natu 		mr.name = pi->pi_name;
489028d9311SNeel Natu 		mr.base = pi->pi_bar[idx].addr;
490028d9311SNeel Natu 		mr.size = pi->pi_bar[idx].size;
491028d9311SNeel Natu 		if (registration) {
492028d9311SNeel Natu 			mr.flags = MEM_F_RW;
493028d9311SNeel Natu 			mr.handler = pci_emul_mem_handler;
494028d9311SNeel Natu 			mr.arg1 = pi;
495028d9311SNeel Natu 			mr.arg2 = idx;
496028d9311SNeel Natu 			error = register_mem(&mr);
497028d9311SNeel Natu 		} else
498028d9311SNeel Natu 			error = unregister_mem(&mr);
499028d9311SNeel Natu 		break;
500028d9311SNeel Natu 	default:
501028d9311SNeel Natu 		error = EINVAL;
502028d9311SNeel Natu 		break;
503028d9311SNeel Natu 	}
504028d9311SNeel Natu 	assert(error == 0);
505028d9311SNeel Natu }
506028d9311SNeel Natu 
507028d9311SNeel Natu static void
508028d9311SNeel Natu unregister_bar(struct pci_devinst *pi, int idx)
509028d9311SNeel Natu {
510028d9311SNeel Natu 
511028d9311SNeel Natu 	modify_bar_registration(pi, idx, 0);
512028d9311SNeel Natu }
513028d9311SNeel Natu 
514028d9311SNeel Natu static void
515028d9311SNeel Natu register_bar(struct pci_devinst *pi, int idx)
516028d9311SNeel Natu {
517028d9311SNeel Natu 
518028d9311SNeel Natu 	modify_bar_registration(pi, idx, 1);
519028d9311SNeel Natu }
520028d9311SNeel Natu 
521028d9311SNeel Natu /* Are we decoding i/o port accesses for the emulated pci device? */
522028d9311SNeel Natu static int
523028d9311SNeel Natu porten(struct pci_devinst *pi)
524028d9311SNeel Natu {
525028d9311SNeel Natu 	uint16_t cmd;
526028d9311SNeel Natu 
527028d9311SNeel Natu 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
528028d9311SNeel Natu 
529028d9311SNeel Natu 	return (cmd & PCIM_CMD_PORTEN);
530028d9311SNeel Natu }
531028d9311SNeel Natu 
532028d9311SNeel Natu /* Are we decoding memory accesses for the emulated pci device? */
533028d9311SNeel Natu static int
534028d9311SNeel Natu memen(struct pci_devinst *pi)
535028d9311SNeel Natu {
536028d9311SNeel Natu 	uint16_t cmd;
537028d9311SNeel Natu 
538028d9311SNeel Natu 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
539028d9311SNeel Natu 
540028d9311SNeel Natu 	return (cmd & PCIM_CMD_MEMEN);
541028d9311SNeel Natu }
542028d9311SNeel Natu 
543028d9311SNeel Natu /*
544028d9311SNeel Natu  * Update the MMIO or I/O address that is decoded by the BAR register.
545028d9311SNeel Natu  *
546028d9311SNeel Natu  * If the pci device has enabled the address space decoding then intercept
547028d9311SNeel Natu  * the address range decoded by the BAR register.
548028d9311SNeel Natu  */
549028d9311SNeel Natu static void
550028d9311SNeel Natu update_bar_address(struct pci_devinst *pi, uint64_t addr, int idx, int type)
551028d9311SNeel Natu {
552028d9311SNeel Natu 	int decode;
553028d9311SNeel Natu 
554028d9311SNeel Natu 	if (pi->pi_bar[idx].type == PCIBAR_IO)
555028d9311SNeel Natu 		decode = porten(pi);
556028d9311SNeel Natu 	else
557028d9311SNeel Natu 		decode = memen(pi);
558028d9311SNeel Natu 
559028d9311SNeel Natu 	if (decode)
560028d9311SNeel Natu 		unregister_bar(pi, idx);
561028d9311SNeel Natu 
562028d9311SNeel Natu 	switch (type) {
563028d9311SNeel Natu 	case PCIBAR_IO:
564028d9311SNeel Natu 	case PCIBAR_MEM32:
565028d9311SNeel Natu 		pi->pi_bar[idx].addr = addr;
566028d9311SNeel Natu 		break;
567028d9311SNeel Natu 	case PCIBAR_MEM64:
568028d9311SNeel Natu 		pi->pi_bar[idx].addr &= ~0xffffffffUL;
569028d9311SNeel Natu 		pi->pi_bar[idx].addr |= addr;
570028d9311SNeel Natu 		break;
571028d9311SNeel Natu 	case PCIBAR_MEMHI64:
572028d9311SNeel Natu 		pi->pi_bar[idx].addr &= 0xffffffff;
573028d9311SNeel Natu 		pi->pi_bar[idx].addr |= addr;
574028d9311SNeel Natu 		break;
575028d9311SNeel Natu 	default:
576028d9311SNeel Natu 		assert(0);
577028d9311SNeel Natu 	}
578028d9311SNeel Natu 
579028d9311SNeel Natu 	if (decode)
580028d9311SNeel Natu 		register_bar(pi, idx);
581028d9311SNeel Natu }
582028d9311SNeel Natu 
5834d1e669cSPeter Grehan int
5844d1e669cSPeter Grehan pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
585366f6083SPeter Grehan 		    enum pcibar_type type, uint64_t size)
586366f6083SPeter Grehan {
587028d9311SNeel Natu 	int error;
588366f6083SPeter Grehan 	uint64_t *baseptr, limit, addr, mask, lobits, bar;
5892729c9bbSJohn Baldwin 	uint16_t cmd, enbit;
590366f6083SPeter Grehan 
591366f6083SPeter Grehan 	assert(idx >= 0 && idx <= PCI_BARMAX);
592366f6083SPeter Grehan 
593366f6083SPeter Grehan 	if ((size & (size - 1)) != 0)
594366f6083SPeter Grehan 		size = 1UL << flsl(size);	/* round up to a power of 2 */
595366f6083SPeter Grehan 
596028d9311SNeel Natu 	/* Enforce minimum BAR sizes required by the PCI standard */
597028d9311SNeel Natu 	if (type == PCIBAR_IO) {
598028d9311SNeel Natu 		if (size < 4)
599028d9311SNeel Natu 			size = 4;
600028d9311SNeel Natu 	} else {
601028d9311SNeel Natu 		if (size < 16)
602028d9311SNeel Natu 			size = 16;
603028d9311SNeel Natu 	}
604028d9311SNeel Natu 
605366f6083SPeter Grehan 	switch (type) {
606366f6083SPeter Grehan 	case PCIBAR_NONE:
607366f6083SPeter Grehan 		baseptr = NULL;
6082729c9bbSJohn Baldwin 		addr = mask = lobits = enbit = 0;
609366f6083SPeter Grehan 		break;
610366f6083SPeter Grehan 	case PCIBAR_IO:
611366f6083SPeter Grehan 		baseptr = &pci_emul_iobase;
612366f6083SPeter Grehan 		limit = PCI_EMUL_IOLIMIT;
613366f6083SPeter Grehan 		mask = PCIM_BAR_IO_BASE;
614366f6083SPeter Grehan 		lobits = PCIM_BAR_IO_SPACE;
6152729c9bbSJohn Baldwin 		enbit = PCIM_CMD_PORTEN;
616366f6083SPeter Grehan 		break;
617366f6083SPeter Grehan 	case PCIBAR_MEM64:
618366f6083SPeter Grehan 		/*
619366f6083SPeter Grehan 		 * XXX
620366f6083SPeter Grehan 		 * Some drivers do not work well if the 64-bit BAR is allocated
621366f6083SPeter Grehan 		 * above 4GB. Allow for this by allocating small requests under
622366f6083SPeter Grehan 		 * 4GB unless then allocation size is larger than some arbitrary
623366f6083SPeter Grehan 		 * number (32MB currently).
624366f6083SPeter Grehan 		 */
625366f6083SPeter Grehan 		if (size > 32 * 1024 * 1024) {
626366f6083SPeter Grehan 			/*
627366f6083SPeter Grehan 			 * XXX special case for device requiring peer-peer DMA
628366f6083SPeter Grehan 			 */
629366f6083SPeter Grehan 			if (size == 0x100000000UL)
630366f6083SPeter Grehan 				baseptr = &hostbase;
631366f6083SPeter Grehan 			else
632366f6083SPeter Grehan 				baseptr = &pci_emul_membase64;
633366f6083SPeter Grehan 			limit = PCI_EMUL_MEMLIMIT64;
634366f6083SPeter Grehan 			mask = PCIM_BAR_MEM_BASE;
635366f6083SPeter Grehan 			lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
636366f6083SPeter Grehan 				 PCIM_BAR_MEM_PREFETCH;
637366f6083SPeter Grehan 			break;
63825d4944eSNeel Natu 		} else {
63925d4944eSNeel Natu 			baseptr = &pci_emul_membase32;
64025d4944eSNeel Natu 			limit = PCI_EMUL_MEMLIMIT32;
64125d4944eSNeel Natu 			mask = PCIM_BAR_MEM_BASE;
64225d4944eSNeel Natu 			lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64;
643366f6083SPeter Grehan 		}
6442729c9bbSJohn Baldwin 		enbit = PCIM_CMD_MEMEN;
64525d4944eSNeel Natu 		break;
646366f6083SPeter Grehan 	case PCIBAR_MEM32:
647366f6083SPeter Grehan 		baseptr = &pci_emul_membase32;
648366f6083SPeter Grehan 		limit = PCI_EMUL_MEMLIMIT32;
649366f6083SPeter Grehan 		mask = PCIM_BAR_MEM_BASE;
650366f6083SPeter Grehan 		lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
6512729c9bbSJohn Baldwin 		enbit = PCIM_CMD_MEMEN;
652366f6083SPeter Grehan 		break;
653366f6083SPeter Grehan 	default:
654366f6083SPeter Grehan 		printf("pci_emul_alloc_base: invalid bar type %d\n", type);
655366f6083SPeter Grehan 		assert(0);
656366f6083SPeter Grehan 	}
657366f6083SPeter Grehan 
658366f6083SPeter Grehan 	if (baseptr != NULL) {
659366f6083SPeter Grehan 		error = pci_emul_alloc_resource(baseptr, limit, size, &addr);
660366f6083SPeter Grehan 		if (error != 0)
661366f6083SPeter Grehan 			return (error);
662366f6083SPeter Grehan 	}
663366f6083SPeter Grehan 
664366f6083SPeter Grehan 	pdi->pi_bar[idx].type = type;
665366f6083SPeter Grehan 	pdi->pi_bar[idx].addr = addr;
666366f6083SPeter Grehan 	pdi->pi_bar[idx].size = size;
667366f6083SPeter Grehan 
668366f6083SPeter Grehan 	/* Initialize the BAR register in config space */
669366f6083SPeter Grehan 	bar = (addr & mask) | lobits;
670366f6083SPeter Grehan 	pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar);
671366f6083SPeter Grehan 
672366f6083SPeter Grehan 	if (type == PCIBAR_MEM64) {
673366f6083SPeter Grehan 		assert(idx + 1 <= PCI_BARMAX);
674366f6083SPeter Grehan 		pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64;
675366f6083SPeter Grehan 		pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
676366f6083SPeter Grehan 	}
677366f6083SPeter Grehan 
6782729c9bbSJohn Baldwin 	cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND);
6792729c9bbSJohn Baldwin 	if ((cmd & enbit) != enbit)
6802729c9bbSJohn Baldwin 		pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit);
681028d9311SNeel Natu 	register_bar(pdi, idx);
682366f6083SPeter Grehan 
683366f6083SPeter Grehan 	return (0);
684366f6083SPeter Grehan }
685366f6083SPeter Grehan 
686366f6083SPeter Grehan #define	CAP_START_OFFSET	0x40
687366f6083SPeter Grehan static int
688366f6083SPeter Grehan pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)
689366f6083SPeter Grehan {
690a96b8b80SJohn Baldwin 	int i, capoff, reallen;
691366f6083SPeter Grehan 	uint16_t sts;
692366f6083SPeter Grehan 
693a96b8b80SJohn Baldwin 	assert(caplen > 0);
694366f6083SPeter Grehan 
695366f6083SPeter Grehan 	reallen = roundup2(caplen, 4);		/* dword aligned */
696366f6083SPeter Grehan 
697366f6083SPeter Grehan 	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
698a96b8b80SJohn Baldwin 	if ((sts & PCIM_STATUS_CAPPRESENT) == 0)
699366f6083SPeter Grehan 		capoff = CAP_START_OFFSET;
700a96b8b80SJohn Baldwin 	else
701a96b8b80SJohn Baldwin 		capoff = pi->pi_capend + 1;
702366f6083SPeter Grehan 
703366f6083SPeter Grehan 	/* Check if we have enough space */
704a96b8b80SJohn Baldwin 	if (capoff + reallen > PCI_REGMAX + 1)
705366f6083SPeter Grehan 		return (-1);
706366f6083SPeter Grehan 
707a96b8b80SJohn Baldwin 	/* Set the previous capability pointer */
708a96b8b80SJohn Baldwin 	if ((sts & PCIM_STATUS_CAPPRESENT) == 0) {
709a96b8b80SJohn Baldwin 		pci_set_cfgdata8(pi, PCIR_CAP_PTR, capoff);
710a96b8b80SJohn Baldwin 		pci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT);
711a96b8b80SJohn Baldwin 	} else
712a96b8b80SJohn Baldwin 		pci_set_cfgdata8(pi, pi->pi_prevcap + 1, capoff);
713a96b8b80SJohn Baldwin 
714366f6083SPeter Grehan 	/* Copy the capability */
715366f6083SPeter Grehan 	for (i = 0; i < caplen; i++)
716366f6083SPeter Grehan 		pci_set_cfgdata8(pi, capoff + i, capdata[i]);
717366f6083SPeter Grehan 
718366f6083SPeter Grehan 	/* Set the next capability pointer */
719a96b8b80SJohn Baldwin 	pci_set_cfgdata8(pi, capoff + 1, 0);
720366f6083SPeter Grehan 
721a96b8b80SJohn Baldwin 	pi->pi_prevcap = capoff;
722a96b8b80SJohn Baldwin 	pi->pi_capend = capoff + reallen - 1;
723366f6083SPeter Grehan 	return (0);
724366f6083SPeter Grehan }
725366f6083SPeter Grehan 
726366f6083SPeter Grehan static struct pci_devemu *
727366f6083SPeter Grehan pci_emul_finddev(char *name)
728366f6083SPeter Grehan {
729366f6083SPeter Grehan 	struct pci_devemu **pdpp, *pdp;
730366f6083SPeter Grehan 
731366f6083SPeter Grehan 	SET_FOREACH(pdpp, pci_devemu_set) {
732366f6083SPeter Grehan 		pdp = *pdpp;
733366f6083SPeter Grehan 		if (!strcmp(pdp->pe_emu, name)) {
734366f6083SPeter Grehan 			return (pdp);
735366f6083SPeter Grehan 		}
736366f6083SPeter Grehan 	}
737366f6083SPeter Grehan 
738366f6083SPeter Grehan 	return (NULL);
739366f6083SPeter Grehan }
740366f6083SPeter Grehan 
741a38e2a64SPeter Grehan static int
742d84882caSNeel Natu pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot,
743d84882caSNeel Natu     int func, struct funcinfo *fi)
744366f6083SPeter Grehan {
745366f6083SPeter Grehan 	struct pci_devinst *pdi;
746a38e2a64SPeter Grehan 	int err;
747a38e2a64SPeter Grehan 
748994f858aSXin LI 	pdi = calloc(1, sizeof(struct pci_devinst));
749366f6083SPeter Grehan 
750366f6083SPeter Grehan 	pdi->pi_vmctx = ctx;
751d84882caSNeel Natu 	pdi->pi_bus = bus;
752366f6083SPeter Grehan 	pdi->pi_slot = slot;
75399d65389SNeel Natu 	pdi->pi_func = func;
7543cbf3585SJohn Baldwin 	pthread_mutex_init(&pdi->pi_lintr.lock, NULL);
7553cbf3585SJohn Baldwin 	pdi->pi_lintr.pin = 0;
7563cbf3585SJohn Baldwin 	pdi->pi_lintr.state = IDLE;
757b3e9732aSJohn Baldwin 	pdi->pi_lintr.pirq_pin = 0;
7583cbf3585SJohn Baldwin 	pdi->pi_lintr.ioapic_irq = 0;
759366f6083SPeter Grehan 	pdi->pi_d = pde;
760366f6083SPeter Grehan 	snprintf(pdi->pi_name, PI_NAMESZ, "%s-pci-%d", pde->pe_emu, slot);
761366f6083SPeter Grehan 
762366f6083SPeter Grehan 	/* Disable legacy interrupts */
763366f6083SPeter Grehan 	pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
764366f6083SPeter Grehan 	pci_set_cfgdata8(pdi, PCIR_INTPIN, 0);
765366f6083SPeter Grehan 
7662729c9bbSJohn Baldwin 	pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN);
767366f6083SPeter Grehan 
768d84882caSNeel Natu 	err = (*pde->pe_init)(ctx, pdi, fi->fi_param);
769d84882caSNeel Natu 	if (err == 0)
770d84882caSNeel Natu 		fi->fi_devi = pdi;
771d84882caSNeel Natu 	else
772366f6083SPeter Grehan 		free(pdi);
773a38e2a64SPeter Grehan 
774a38e2a64SPeter Grehan 	return (err);
775366f6083SPeter Grehan }
776366f6083SPeter Grehan 
777366f6083SPeter Grehan void
778366f6083SPeter Grehan pci_populate_msicap(struct msicap *msicap, int msgnum, int nextptr)
779366f6083SPeter Grehan {
780366f6083SPeter Grehan 	int mmc;
781366f6083SPeter Grehan 
782366f6083SPeter Grehan 	/* Number of msi messages must be a power of 2 between 1 and 32 */
783366f6083SPeter Grehan 	assert((msgnum & (msgnum - 1)) == 0 && msgnum >= 1 && msgnum <= 32);
784366f6083SPeter Grehan 	mmc = ffs(msgnum) - 1;
785366f6083SPeter Grehan 
786366f6083SPeter Grehan 	bzero(msicap, sizeof(struct msicap));
787366f6083SPeter Grehan 	msicap->capid = PCIY_MSI;
788366f6083SPeter Grehan 	msicap->nextptr = nextptr;
789366f6083SPeter Grehan 	msicap->msgctrl = PCIM_MSICTRL_64BIT | (mmc << 1);
790366f6083SPeter Grehan }
791366f6083SPeter Grehan 
792366f6083SPeter Grehan int
793366f6083SPeter Grehan pci_emul_add_msicap(struct pci_devinst *pi, int msgnum)
794366f6083SPeter Grehan {
795366f6083SPeter Grehan 	struct msicap msicap;
796366f6083SPeter Grehan 
797366f6083SPeter Grehan 	pci_populate_msicap(&msicap, msgnum, 0);
798366f6083SPeter Grehan 
799366f6083SPeter Grehan 	return (pci_emul_add_capability(pi, (u_char *)&msicap, sizeof(msicap)));
800366f6083SPeter Grehan }
801366f6083SPeter Grehan 
802c9b4e987SNeel Natu static void
803c9b4e987SNeel Natu pci_populate_msixcap(struct msixcap *msixcap, int msgnum, int barnum,
804a96b8b80SJohn Baldwin 		     uint32_t msix_tab_size)
805c9b4e987SNeel Natu {
806c9b4e987SNeel Natu 
807c9b4e987SNeel Natu 	assert(msix_tab_size % 4096 == 0);
808c9b4e987SNeel Natu 
809c9b4e987SNeel Natu 	bzero(msixcap, sizeof(struct msixcap));
810c9b4e987SNeel Natu 	msixcap->capid = PCIY_MSIX;
811c9b4e987SNeel Natu 
812c9b4e987SNeel Natu 	/*
813c9b4e987SNeel Natu 	 * Message Control Register, all fields set to
814c9b4e987SNeel Natu 	 * zero except for the Table Size.
815c9b4e987SNeel Natu 	 * Note: Table size N is encoded as N-1
816c9b4e987SNeel Natu 	 */
817c9b4e987SNeel Natu 	msixcap->msgctrl = msgnum - 1;
818c9b4e987SNeel Natu 
819c9b4e987SNeel Natu 	/*
820c9b4e987SNeel Natu 	 * MSI-X BAR setup:
821c9b4e987SNeel Natu 	 * - MSI-X table start at offset 0
822c9b4e987SNeel Natu 	 * - PBA table starts at a 4K aligned offset after the MSI-X table
823c9b4e987SNeel Natu 	 */
824c9b4e987SNeel Natu 	msixcap->table_info = barnum & PCIM_MSIX_BIR_MASK;
825c9b4e987SNeel Natu 	msixcap->pba_info = msix_tab_size | (barnum & PCIM_MSIX_BIR_MASK);
826c9b4e987SNeel Natu }
827c9b4e987SNeel Natu 
828c9b4e987SNeel Natu static void
829c9b4e987SNeel Natu pci_msix_table_init(struct pci_devinst *pi, int table_entries)
830c9b4e987SNeel Natu {
831c9b4e987SNeel Natu 	int i, table_size;
832c9b4e987SNeel Natu 
833c9b4e987SNeel Natu 	assert(table_entries > 0);
834c9b4e987SNeel Natu 	assert(table_entries <= MAX_MSIX_TABLE_ENTRIES);
835c9b4e987SNeel Natu 
836c9b4e987SNeel Natu 	table_size = table_entries * MSIX_TABLE_ENTRY_SIZE;
837994f858aSXin LI 	pi->pi_msix.table = calloc(1, table_size);
838c9b4e987SNeel Natu 
839c9b4e987SNeel Natu 	/* set mask bit of vector control register */
840c9b4e987SNeel Natu 	for (i = 0; i < table_entries; i++)
841c9b4e987SNeel Natu 		pi->pi_msix.table[i].vector_control |= PCIM_MSIX_VCTRL_MASK;
842c9b4e987SNeel Natu }
843c9b4e987SNeel Natu 
844c9b4e987SNeel Natu int
845c9b4e987SNeel Natu pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum)
846c9b4e987SNeel Natu {
847c9b4e987SNeel Natu 	uint32_t tab_size;
848c9b4e987SNeel Natu 	struct msixcap msixcap;
849c9b4e987SNeel Natu 
850c9b4e987SNeel Natu 	assert(msgnum >= 1 && msgnum <= MAX_MSIX_TABLE_ENTRIES);
851c9b4e987SNeel Natu 	assert(barnum >= 0 && barnum <= PCIR_MAX_BAR_0);
852c9b4e987SNeel Natu 
853c9b4e987SNeel Natu 	tab_size = msgnum * MSIX_TABLE_ENTRY_SIZE;
854c9b4e987SNeel Natu 
855c9b4e987SNeel Natu 	/* Align table size to nearest 4K */
856c9b4e987SNeel Natu 	tab_size = roundup2(tab_size, 4096);
857c9b4e987SNeel Natu 
858c9b4e987SNeel Natu 	pi->pi_msix.table_bar = barnum;
859c9b4e987SNeel Natu 	pi->pi_msix.pba_bar   = barnum;
860c9b4e987SNeel Natu 	pi->pi_msix.table_offset = 0;
861c9b4e987SNeel Natu 	pi->pi_msix.table_count = msgnum;
862c9b4e987SNeel Natu 	pi->pi_msix.pba_offset = tab_size;
8637a902ec0SNeel Natu 	pi->pi_msix.pba_size = PBA_SIZE(msgnum);
864c9b4e987SNeel Natu 
865c9b4e987SNeel Natu 	pci_msix_table_init(pi, msgnum);
866c9b4e987SNeel Natu 
867a96b8b80SJohn Baldwin 	pci_populate_msixcap(&msixcap, msgnum, barnum, tab_size);
868c9b4e987SNeel Natu 
869c9b4e987SNeel Natu 	/* allocate memory for MSI-X Table and PBA */
870c9b4e987SNeel Natu 	pci_emul_alloc_bar(pi, barnum, PCIBAR_MEM32,
871c9b4e987SNeel Natu 				tab_size + pi->pi_msix.pba_size);
872c9b4e987SNeel Natu 
873c9b4e987SNeel Natu 	return (pci_emul_add_capability(pi, (u_char *)&msixcap,
874c9b4e987SNeel Natu 					sizeof(msixcap)));
875c9b4e987SNeel Natu }
876c9b4e987SNeel Natu 
877366f6083SPeter Grehan void
878cd942e0fSPeter Grehan msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
879cd942e0fSPeter Grehan 		 int bytes, uint32_t val)
880cd942e0fSPeter Grehan {
881cd942e0fSPeter Grehan 	uint16_t msgctrl, rwmask;
882d74fdc6aSMarcelo Araujo 	int off;
883cd942e0fSPeter Grehan 
884cd942e0fSPeter Grehan 	off = offset - capoff;
885cd942e0fSPeter Grehan 	/* Message Control Register */
886cd942e0fSPeter Grehan 	if (off == 2 && bytes == 2) {
887cd942e0fSPeter Grehan 		rwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK;
888cd942e0fSPeter Grehan 		msgctrl = pci_get_cfgdata16(pi, offset);
889cd942e0fSPeter Grehan 		msgctrl &= ~rwmask;
890cd942e0fSPeter Grehan 		msgctrl |= val & rwmask;
891cd942e0fSPeter Grehan 		val = msgctrl;
892cd942e0fSPeter Grehan 
893cd942e0fSPeter Grehan 		pi->pi_msix.enabled = val & PCIM_MSIXCTRL_MSIX_ENABLE;
894c9b4e987SNeel Natu 		pi->pi_msix.function_mask = val & PCIM_MSIXCTRL_FUNCTION_MASK;
8953cbf3585SJohn Baldwin 		pci_lintr_update(pi);
896cd942e0fSPeter Grehan 	}
897cd942e0fSPeter Grehan 
898cd942e0fSPeter Grehan 	CFGWRITE(pi, offset, val, bytes);
899cd942e0fSPeter Grehan }
900cd942e0fSPeter Grehan 
901cd942e0fSPeter Grehan void
902366f6083SPeter Grehan msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
903366f6083SPeter Grehan 		int bytes, uint32_t val)
904366f6083SPeter Grehan {
905366f6083SPeter Grehan 	uint16_t msgctrl, rwmask, msgdata, mme;
906366f6083SPeter Grehan 	uint32_t addrlo;
907366f6083SPeter Grehan 
908366f6083SPeter Grehan 	/*
909366f6083SPeter Grehan 	 * If guest is writing to the message control register make sure
910366f6083SPeter Grehan 	 * we do not overwrite read-only fields.
911366f6083SPeter Grehan 	 */
912366f6083SPeter Grehan 	if ((offset - capoff) == 2 && bytes == 2) {
913366f6083SPeter Grehan 		rwmask = PCIM_MSICTRL_MME_MASK | PCIM_MSICTRL_MSI_ENABLE;
914366f6083SPeter Grehan 		msgctrl = pci_get_cfgdata16(pi, offset);
915366f6083SPeter Grehan 		msgctrl &= ~rwmask;
916366f6083SPeter Grehan 		msgctrl |= val & rwmask;
917366f6083SPeter Grehan 		val = msgctrl;
918366f6083SPeter Grehan 
919366f6083SPeter Grehan 		addrlo = pci_get_cfgdata32(pi, capoff + 4);
920366f6083SPeter Grehan 		if (msgctrl & PCIM_MSICTRL_64BIT)
921366f6083SPeter Grehan 			msgdata = pci_get_cfgdata16(pi, capoff + 12);
922366f6083SPeter Grehan 		else
923366f6083SPeter Grehan 			msgdata = pci_get_cfgdata16(pi, capoff + 8);
924366f6083SPeter Grehan 
925366f6083SPeter Grehan 		mme = msgctrl & PCIM_MSICTRL_MME_MASK;
926366f6083SPeter Grehan 		pi->pi_msi.enabled = msgctrl & PCIM_MSICTRL_MSI_ENABLE ? 1 : 0;
927366f6083SPeter Grehan 		if (pi->pi_msi.enabled) {
9284f8be175SNeel Natu 			pi->pi_msi.addr = addrlo;
9294f8be175SNeel Natu 			pi->pi_msi.msg_data = msgdata;
9304f8be175SNeel Natu 			pi->pi_msi.maxmsgnum = 1 << (mme >> 4);
931366f6083SPeter Grehan 		} else {
9324f8be175SNeel Natu 			pi->pi_msi.maxmsgnum = 0;
933366f6083SPeter Grehan 		}
9343cbf3585SJohn Baldwin 		pci_lintr_update(pi);
935366f6083SPeter Grehan 	}
936366f6083SPeter Grehan 
937366f6083SPeter Grehan 	CFGWRITE(pi, offset, val, bytes);
938366f6083SPeter Grehan }
939366f6083SPeter Grehan 
94074f80b23SNeel Natu void
94174f80b23SNeel Natu pciecap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
94274f80b23SNeel Natu 		 int bytes, uint32_t val)
94374f80b23SNeel Natu {
94474f80b23SNeel Natu 
94574f80b23SNeel Natu 	/* XXX don't write to the readonly parts */
94674f80b23SNeel Natu 	CFGWRITE(pi, offset, val, bytes);
94774f80b23SNeel Natu }
94874f80b23SNeel Natu 
94974f80b23SNeel Natu #define	PCIECAP_VERSION	0x2
95074f80b23SNeel Natu int
95174f80b23SNeel Natu pci_emul_add_pciecap(struct pci_devinst *pi, int type)
95274f80b23SNeel Natu {
95374f80b23SNeel Natu 	int err;
95474f80b23SNeel Natu 	struct pciecap pciecap;
95574f80b23SNeel Natu 
95674f80b23SNeel Natu 	if (type != PCIEM_TYPE_ROOT_PORT)
95774f80b23SNeel Natu 		return (-1);
95874f80b23SNeel Natu 
95974f80b23SNeel Natu 	bzero(&pciecap, sizeof(pciecap));
96074f80b23SNeel Natu 
96174f80b23SNeel Natu 	pciecap.capid = PCIY_EXPRESS;
962f0dfbcccSChuck Tuffli 	pciecap.pcie_capabilities = PCIECAP_VERSION | PCIEM_TYPE_ROOT_PORT;
96374f80b23SNeel Natu 	pciecap.link_capabilities = 0x411;	/* gen1, x1 */
96474f80b23SNeel Natu 	pciecap.link_status = 0x11;		/* gen1, x1 */
96574f80b23SNeel Natu 
96674f80b23SNeel Natu 	err = pci_emul_add_capability(pi, (u_char *)&pciecap, sizeof(pciecap));
96774f80b23SNeel Natu 	return (err);
96874f80b23SNeel Natu }
96974f80b23SNeel Natu 
970366f6083SPeter Grehan /*
971366f6083SPeter Grehan  * This function assumes that 'coff' is in the capabilities region of the
972366f6083SPeter Grehan  * config space.
973366f6083SPeter Grehan  */
974366f6083SPeter Grehan static void
975366f6083SPeter Grehan pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
976366f6083SPeter Grehan {
977366f6083SPeter Grehan 	int capid;
978366f6083SPeter Grehan 	uint8_t capoff, nextoff;
979366f6083SPeter Grehan 
980366f6083SPeter Grehan 	/* Do not allow un-aligned writes */
981366f6083SPeter Grehan 	if ((offset & (bytes - 1)) != 0)
982366f6083SPeter Grehan 		return;
983366f6083SPeter Grehan 
984366f6083SPeter Grehan 	/* Find the capability that we want to update */
985366f6083SPeter Grehan 	capoff = CAP_START_OFFSET;
986366f6083SPeter Grehan 	while (1) {
987366f6083SPeter Grehan 		nextoff = pci_get_cfgdata8(pi, capoff + 1);
988a96b8b80SJohn Baldwin 		if (nextoff == 0)
989a96b8b80SJohn Baldwin 			break;
990366f6083SPeter Grehan 		if (offset >= capoff && offset < nextoff)
991366f6083SPeter Grehan 			break;
992366f6083SPeter Grehan 
993366f6083SPeter Grehan 		capoff = nextoff;
994366f6083SPeter Grehan 	}
995366f6083SPeter Grehan 	assert(offset >= capoff);
996366f6083SPeter Grehan 
997366f6083SPeter Grehan 	/*
9982a8d400aSPeter Grehan 	 * Capability ID and Next Capability Pointer are readonly.
9992a8d400aSPeter Grehan 	 * However, some o/s's do 4-byte writes that include these.
10002a8d400aSPeter Grehan 	 * For this case, trim the write back to 2 bytes and adjust
10012a8d400aSPeter Grehan 	 * the data.
1002366f6083SPeter Grehan 	 */
10032a8d400aSPeter Grehan 	if (offset == capoff || offset == capoff + 1) {
10042a8d400aSPeter Grehan 		if (offset == capoff && bytes == 4) {
10052a8d400aSPeter Grehan 			bytes = 2;
10062a8d400aSPeter Grehan 			offset += 2;
10072a8d400aSPeter Grehan 			val >>= 16;
10082a8d400aSPeter Grehan 		} else
1009366f6083SPeter Grehan 			return;
10102a8d400aSPeter Grehan 	}
1011366f6083SPeter Grehan 
1012a96b8b80SJohn Baldwin 	capid = pci_get_cfgdata8(pi, capoff);
1013366f6083SPeter Grehan 	switch (capid) {
1014366f6083SPeter Grehan 	case PCIY_MSI:
1015366f6083SPeter Grehan 		msicap_cfgwrite(pi, capoff, offset, bytes, val);
1016366f6083SPeter Grehan 		break;
1017c9b4e987SNeel Natu 	case PCIY_MSIX:
1018c9b4e987SNeel Natu 		msixcap_cfgwrite(pi, capoff, offset, bytes, val);
1019c9b4e987SNeel Natu 		break;
102074f80b23SNeel Natu 	case PCIY_EXPRESS:
102174f80b23SNeel Natu 		pciecap_cfgwrite(pi, capoff, offset, bytes, val);
102274f80b23SNeel Natu 		break;
1023366f6083SPeter Grehan 	default:
1024366f6083SPeter Grehan 		break;
1025366f6083SPeter Grehan 	}
1026366f6083SPeter Grehan }
1027366f6083SPeter Grehan 
1028366f6083SPeter Grehan static int
1029366f6083SPeter Grehan pci_emul_iscap(struct pci_devinst *pi, int offset)
1030366f6083SPeter Grehan {
1031366f6083SPeter Grehan 	uint16_t sts;
1032366f6083SPeter Grehan 
1033366f6083SPeter Grehan 	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
1034366f6083SPeter Grehan 	if ((sts & PCIM_STATUS_CAPPRESENT) != 0) {
1035a96b8b80SJohn Baldwin 		if (offset >= CAP_START_OFFSET && offset <= pi->pi_capend)
1036a96b8b80SJohn Baldwin 			return (1);
1037366f6083SPeter Grehan 	}
1038a96b8b80SJohn Baldwin 	return (0);
1039366f6083SPeter Grehan }
1040366f6083SPeter Grehan 
10410ab13648SPeter Grehan static int
10420ab13648SPeter Grehan pci_emul_fallback_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
10430ab13648SPeter Grehan 			  int size, uint64_t *val, void *arg1, long arg2)
10440ab13648SPeter Grehan {
10450ab13648SPeter Grehan 	/*
10460ab13648SPeter Grehan 	 * Ignore writes; return 0xff's for reads. The mem read code
10470ab13648SPeter Grehan 	 * will take care of truncating to the correct size.
10480ab13648SPeter Grehan 	 */
10490ab13648SPeter Grehan 	if (dir == MEM_F_READ) {
10500ab13648SPeter Grehan 		*val = 0xffffffffffffffff;
10510ab13648SPeter Grehan 	}
10520ab13648SPeter Grehan 
10530ab13648SPeter Grehan 	return (0);
10540ab13648SPeter Grehan }
10550ab13648SPeter Grehan 
105612a6eb99SNeel Natu static int
105712a6eb99SNeel Natu pci_emul_ecfg_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
105812a6eb99SNeel Natu     int bytes, uint64_t *val, void *arg1, long arg2)
105912a6eb99SNeel Natu {
106012a6eb99SNeel Natu 	int bus, slot, func, coff, in;
106112a6eb99SNeel Natu 
106212a6eb99SNeel Natu 	coff = addr & 0xfff;
106312a6eb99SNeel Natu 	func = (addr >> 12) & 0x7;
106412a6eb99SNeel Natu 	slot = (addr >> 15) & 0x1f;
106512a6eb99SNeel Natu 	bus = (addr >> 20) & 0xff;
106612a6eb99SNeel Natu 	in = (dir == MEM_F_READ);
106712a6eb99SNeel Natu 	if (in)
106812a6eb99SNeel Natu 		*val = ~0UL;
106912a6eb99SNeel Natu 	pci_cfgrw(ctx, vcpu, in, bus, slot, func, coff, bytes, (uint32_t *)val);
107012a6eb99SNeel Natu 	return (0);
107112a6eb99SNeel Natu }
107212a6eb99SNeel Natu 
107312a6eb99SNeel Natu uint64_t
107412a6eb99SNeel Natu pci_ecfg_base(void)
107512a6eb99SNeel Natu {
107612a6eb99SNeel Natu 
107712a6eb99SNeel Natu 	return (PCI_EMUL_ECFG_BASE);
107812a6eb99SNeel Natu }
107912a6eb99SNeel Natu 
1080d84882caSNeel Natu #define	BUSIO_ROUNDUP		32
1081d84882caSNeel Natu #define	BUSMEM_ROUNDUP		(1024 * 1024)
1082d84882caSNeel Natu 
1083a38e2a64SPeter Grehan int
1084366f6083SPeter Grehan init_pci(struct vmctx *ctx)
1085366f6083SPeter Grehan {
108612a6eb99SNeel Natu 	struct mem_range mr;
1087366f6083SPeter Grehan 	struct pci_devemu *pde;
1088d84882caSNeel Natu 	struct businfo *bi;
1089d84882caSNeel Natu 	struct slotinfo *si;
10903cbf3585SJohn Baldwin 	struct funcinfo *fi;
10919f08548dSNeel Natu 	size_t lowmem;
1092d84882caSNeel Natu 	int bus, slot, func;
10930ab13648SPeter Grehan 	int error;
1094366f6083SPeter Grehan 
1095366f6083SPeter Grehan 	pci_emul_iobase = PCI_EMUL_IOBASE;
10969f08548dSNeel Natu 	pci_emul_membase32 = vm_get_lowmem_limit(ctx);
1097366f6083SPeter Grehan 	pci_emul_membase64 = PCI_EMUL_MEMBASE64;
1098366f6083SPeter Grehan 
1099d84882caSNeel Natu 	for (bus = 0; bus < MAXBUSES; bus++) {
1100d84882caSNeel Natu 		if ((bi = pci_businfo[bus]) == NULL)
1101d84882caSNeel Natu 			continue;
1102d84882caSNeel Natu 		/*
1103d84882caSNeel Natu 		 * Keep track of the i/o and memory resources allocated to
1104d84882caSNeel Natu 		 * this bus.
1105d84882caSNeel Natu 		 */
1106d84882caSNeel Natu 		bi->iobase = pci_emul_iobase;
1107d84882caSNeel Natu 		bi->membase32 = pci_emul_membase32;
1108d84882caSNeel Natu 		bi->membase64 = pci_emul_membase64;
1109d84882caSNeel Natu 
111099d65389SNeel Natu 		for (slot = 0; slot < MAXSLOTS; slot++) {
1111d84882caSNeel Natu 			si = &bi->slotinfo[slot];
111299d65389SNeel Natu 			for (func = 0; func < MAXFUNCS; func++) {
1113d84882caSNeel Natu 				fi = &si->si_funcs[func];
1114d84882caSNeel Natu 				if (fi->fi_name == NULL)
1115d84882caSNeel Natu 					continue;
11163cbf3585SJohn Baldwin 				pde = pci_emul_finddev(fi->fi_name);
1117b05c77ffSNeel Natu 				assert(pde != NULL);
1118d84882caSNeel Natu 				error = pci_emul_init(ctx, pde, bus, slot,
1119d84882caSNeel Natu 				    func, fi);
1120a38e2a64SPeter Grehan 				if (error)
1121a38e2a64SPeter Grehan 					return (error);
1122366f6083SPeter Grehan 			}
1123366f6083SPeter Grehan 		}
1124d84882caSNeel Natu 
1125d84882caSNeel Natu 		/*
1126d84882caSNeel Natu 		 * Add some slop to the I/O and memory resources decoded by
1127d84882caSNeel Natu 		 * this bus to give a guest some flexibility if it wants to
1128d84882caSNeel Natu 		 * reprogram the BARs.
1129d84882caSNeel Natu 		 */
1130d84882caSNeel Natu 		pci_emul_iobase += BUSIO_ROUNDUP;
1131d84882caSNeel Natu 		pci_emul_iobase = roundup2(pci_emul_iobase, BUSIO_ROUNDUP);
1132d84882caSNeel Natu 		bi->iolimit = pci_emul_iobase;
1133d84882caSNeel Natu 
1134d84882caSNeel Natu 		pci_emul_membase32 += BUSMEM_ROUNDUP;
1135d84882caSNeel Natu 		pci_emul_membase32 = roundup2(pci_emul_membase32,
1136d84882caSNeel Natu 		    BUSMEM_ROUNDUP);
1137d84882caSNeel Natu 		bi->memlimit32 = pci_emul_membase32;
1138d84882caSNeel Natu 
1139d84882caSNeel Natu 		pci_emul_membase64 += BUSMEM_ROUNDUP;
1140d84882caSNeel Natu 		pci_emul_membase64 = roundup2(pci_emul_membase64,
1141d84882caSNeel Natu 		    BUSMEM_ROUNDUP);
1142d84882caSNeel Natu 		bi->memlimit64 = pci_emul_membase64;
1143366f6083SPeter Grehan 	}
11440038ee98SPeter Grehan 
11450038ee98SPeter Grehan 	/*
1146b3e9732aSJohn Baldwin 	 * PCI backends are initialized before routing INTx interrupts
1147b3e9732aSJohn Baldwin 	 * so that LPC devices are able to reserve ISA IRQs before
1148b3e9732aSJohn Baldwin 	 * routing PIRQ pins.
1149b3e9732aSJohn Baldwin 	 */
1150b3e9732aSJohn Baldwin 	for (bus = 0; bus < MAXBUSES; bus++) {
1151b3e9732aSJohn Baldwin 		if ((bi = pci_businfo[bus]) == NULL)
1152b3e9732aSJohn Baldwin 			continue;
1153b3e9732aSJohn Baldwin 
1154b3e9732aSJohn Baldwin 		for (slot = 0; slot < MAXSLOTS; slot++) {
1155b3e9732aSJohn Baldwin 			si = &bi->slotinfo[slot];
1156b3e9732aSJohn Baldwin 			for (func = 0; func < MAXFUNCS; func++) {
1157b3e9732aSJohn Baldwin 				fi = &si->si_funcs[func];
1158b3e9732aSJohn Baldwin 				if (fi->fi_devi == NULL)
1159b3e9732aSJohn Baldwin 					continue;
1160b3e9732aSJohn Baldwin 				pci_lintr_route(fi->fi_devi);
1161b3e9732aSJohn Baldwin 			}
1162b3e9732aSJohn Baldwin 		}
1163b3e9732aSJohn Baldwin 	}
1164b3e9732aSJohn Baldwin 	lpc_pirq_routed();
1165b3e9732aSJohn Baldwin 
1166b3e9732aSJohn Baldwin 	/*
11679f08548dSNeel Natu 	 * The guest physical memory map looks like the following:
11689f08548dSNeel Natu 	 * [0,		    lowmem)		guest system memory
11699f08548dSNeel Natu 	 * [lowmem,	    lowmem_limit)	memory hole (may be absent)
117012a6eb99SNeel Natu 	 * [lowmem_limit,   0xE0000000)		PCI hole (32-bit BAR allocation)
117112a6eb99SNeel Natu 	 * [0xE0000000,	    0xF0000000)		PCI extended config window
117212a6eb99SNeel Natu 	 * [0xF0000000,	    4GB)		LAPIC, IOAPIC, HPET, firmware
11739f08548dSNeel Natu 	 * [4GB,	    4GB + highmem)
117412a6eb99SNeel Natu 	 */
117512a6eb99SNeel Natu 
117612a6eb99SNeel Natu 	/*
11779f08548dSNeel Natu 	 * Accesses to memory addresses that are not allocated to system
11789f08548dSNeel Natu 	 * memory or PCI devices return 0xff's.
11790ab13648SPeter Grehan 	 */
1180be679db4SNeel Natu 	lowmem = vm_get_lowmem_size(ctx);
118112a6eb99SNeel Natu 	bzero(&mr, sizeof(struct mem_range));
118212a6eb99SNeel Natu 	mr.name = "PCI hole";
118312a6eb99SNeel Natu 	mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
118412a6eb99SNeel Natu 	mr.base = lowmem;
118512a6eb99SNeel Natu 	mr.size = (4ULL * 1024 * 1024 * 1024) - lowmem;
118612a6eb99SNeel Natu 	mr.handler = pci_emul_fallback_handler;
118712a6eb99SNeel Natu 	error = register_mem_fallback(&mr);
118812a6eb99SNeel Natu 	assert(error == 0);
11899f08548dSNeel Natu 
119012a6eb99SNeel Natu 	/* PCI extended config space */
119112a6eb99SNeel Natu 	bzero(&mr, sizeof(struct mem_range));
119212a6eb99SNeel Natu 	mr.name = "PCI ECFG";
119312a6eb99SNeel Natu 	mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
119412a6eb99SNeel Natu 	mr.base = PCI_EMUL_ECFG_BASE;
119512a6eb99SNeel Natu 	mr.size = PCI_EMUL_ECFG_SIZE;
119612a6eb99SNeel Natu 	mr.handler = pci_emul_ecfg_handler;
119712a6eb99SNeel Natu 	error = register_mem(&mr);
11980ab13648SPeter Grehan 	assert(error == 0);
1199a38e2a64SPeter Grehan 
1200a38e2a64SPeter Grehan 	return (0);
1201366f6083SPeter Grehan }
1202366f6083SPeter Grehan 
12033cbf3585SJohn Baldwin static void
1204b3e9732aSJohn Baldwin pci_apic_prt_entry(int bus, int slot, int pin, int pirq_pin, int ioapic_irq,
1205b3e9732aSJohn Baldwin     void *arg)
12063cbf3585SJohn Baldwin {
12073cbf3585SJohn Baldwin 
1208b3e9732aSJohn Baldwin 	dsdt_line("  Package ()");
12093cbf3585SJohn Baldwin 	dsdt_line("  {");
12103cbf3585SJohn Baldwin 	dsdt_line("    0x%X,", slot << 16 | 0xffff);
12113cbf3585SJohn Baldwin 	dsdt_line("    0x%02X,", pin - 1);
12123cbf3585SJohn Baldwin 	dsdt_line("    Zero,");
12133cbf3585SJohn Baldwin 	dsdt_line("    0x%X", ioapic_irq);
1214b3e9732aSJohn Baldwin 	dsdt_line("  },");
1215b3e9732aSJohn Baldwin }
1216b3e9732aSJohn Baldwin 
1217b3e9732aSJohn Baldwin static void
1218b3e9732aSJohn Baldwin pci_pirq_prt_entry(int bus, int slot, int pin, int pirq_pin, int ioapic_irq,
1219b3e9732aSJohn Baldwin     void *arg)
1220b3e9732aSJohn Baldwin {
1221b3e9732aSJohn Baldwin 	char *name;
1222b3e9732aSJohn Baldwin 
1223b3e9732aSJohn Baldwin 	name = lpc_pirq_name(pirq_pin);
1224b3e9732aSJohn Baldwin 	if (name == NULL)
1225b3e9732aSJohn Baldwin 		return;
1226b3e9732aSJohn Baldwin 	dsdt_line("  Package ()");
1227b3e9732aSJohn Baldwin 	dsdt_line("  {");
1228b3e9732aSJohn Baldwin 	dsdt_line("    0x%X,", slot << 16 | 0xffff);
1229b3e9732aSJohn Baldwin 	dsdt_line("    0x%02X,", pin - 1);
1230b3e9732aSJohn Baldwin 	dsdt_line("    %s,", name);
1231b3e9732aSJohn Baldwin 	dsdt_line("    0x00");
1232b3e9732aSJohn Baldwin 	dsdt_line("  },");
1233b3e9732aSJohn Baldwin 	free(name);
12343cbf3585SJohn Baldwin }
12353cbf3585SJohn Baldwin 
1236d84882caSNeel Natu /*
1237d84882caSNeel Natu  * A bhyve virtual machine has a flat PCI hierarchy with a root port
1238d84882caSNeel Natu  * corresponding to each PCI bus.
1239d84882caSNeel Natu  */
1240d84882caSNeel Natu static void
1241d84882caSNeel Natu pci_bus_write_dsdt(int bus)
1242e6c8bc29SJohn Baldwin {
1243d84882caSNeel Natu 	struct businfo *bi;
1244d84882caSNeel Natu 	struct slotinfo *si;
1245e6c8bc29SJohn Baldwin 	struct pci_devinst *pi;
1246b3e9732aSJohn Baldwin 	int count, func, slot;
1247e6c8bc29SJohn Baldwin 
1248d84882caSNeel Natu 	/*
1249d84882caSNeel Natu 	 * If there are no devices on this 'bus' then just return.
1250d84882caSNeel Natu 	 */
1251d84882caSNeel Natu 	if ((bi = pci_businfo[bus]) == NULL) {
1252d84882caSNeel Natu 		/*
1253d84882caSNeel Natu 		 * Bus 0 is special because it decodes the I/O ports used
1254d84882caSNeel Natu 		 * for PCI config space access even if there are no devices
1255d84882caSNeel Natu 		 * on it.
1256d84882caSNeel Natu 		 */
1257d84882caSNeel Natu 		if (bus != 0)
1258d84882caSNeel Natu 			return;
1259d84882caSNeel Natu 	}
1260d84882caSNeel Natu 
1261d84882caSNeel Natu 	dsdt_line("  Device (PC%02X)", bus);
1262e6c8bc29SJohn Baldwin 	dsdt_line("  {");
1263e6c8bc29SJohn Baldwin 	dsdt_line("    Name (_HID, EisaId (\"PNP0A03\"))");
1264e6c8bc29SJohn Baldwin 	dsdt_line("    Name (_ADR, Zero)");
1265d84882caSNeel Natu 
1266d84882caSNeel Natu 	dsdt_line("    Method (_BBN, 0, NotSerialized)");
1267d84882caSNeel Natu 	dsdt_line("    {");
1268d84882caSNeel Natu 	dsdt_line("        Return (0x%08X)", bus);
1269d84882caSNeel Natu 	dsdt_line("    }");
1270e6c8bc29SJohn Baldwin 	dsdt_line("    Name (_CRS, ResourceTemplate ()");
1271e6c8bc29SJohn Baldwin 	dsdt_line("    {");
1272e6c8bc29SJohn Baldwin 	dsdt_line("      WordBusNumber (ResourceProducer, MinFixed, "
1273e6c8bc29SJohn Baldwin 	    "MaxFixed, PosDecode,");
1274e6c8bc29SJohn Baldwin 	dsdt_line("        0x0000,             // Granularity");
1275d84882caSNeel Natu 	dsdt_line("        0x%04X,             // Range Minimum", bus);
1276d84882caSNeel Natu 	dsdt_line("        0x%04X,             // Range Maximum", bus);
1277e6c8bc29SJohn Baldwin 	dsdt_line("        0x0000,             // Translation Offset");
1278d84882caSNeel Natu 	dsdt_line("        0x0001,             // Length");
1279e6c8bc29SJohn Baldwin 	dsdt_line("        ,, )");
1280d84882caSNeel Natu 
1281d84882caSNeel Natu 	if (bus == 0) {
1282e6c8bc29SJohn Baldwin 		dsdt_indent(3);
1283e6c8bc29SJohn Baldwin 		dsdt_fixed_ioport(0xCF8, 8);
1284e6c8bc29SJohn Baldwin 		dsdt_unindent(3);
1285d84882caSNeel Natu 
1286e6c8bc29SJohn Baldwin 		dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1287e6c8bc29SJohn Baldwin 		    "PosDecode, EntireRange,");
1288e6c8bc29SJohn Baldwin 		dsdt_line("        0x0000,             // Granularity");
1289e6c8bc29SJohn Baldwin 		dsdt_line("        0x0000,             // Range Minimum");
1290e6c8bc29SJohn Baldwin 		dsdt_line("        0x0CF7,             // Range Maximum");
1291e6c8bc29SJohn Baldwin 		dsdt_line("        0x0000,             // Translation Offset");
1292e6c8bc29SJohn Baldwin 		dsdt_line("        0x0CF8,             // Length");
1293e6c8bc29SJohn Baldwin 		dsdt_line("        ,, , TypeStatic)");
1294d84882caSNeel Natu 
1295e6c8bc29SJohn Baldwin 		dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1296e6c8bc29SJohn Baldwin 		    "PosDecode, EntireRange,");
1297e6c8bc29SJohn Baldwin 		dsdt_line("        0x0000,             // Granularity");
1298e6c8bc29SJohn Baldwin 		dsdt_line("        0x0D00,             // Range Minimum");
1299d84882caSNeel Natu 		dsdt_line("        0x%04X,             // Range Maximum",
1300d84882caSNeel Natu 		    PCI_EMUL_IOBASE - 1);
1301e6c8bc29SJohn Baldwin 		dsdt_line("        0x0000,             // Translation Offset");
1302d84882caSNeel Natu 		dsdt_line("        0x%04X,             // Length",
1303d84882caSNeel Natu 		    PCI_EMUL_IOBASE - 0x0D00);
1304e6c8bc29SJohn Baldwin 		dsdt_line("        ,, , TypeStatic)");
1305d84882caSNeel Natu 
1306d84882caSNeel Natu 		if (bi == NULL) {
1307d84882caSNeel Natu 			dsdt_line("    })");
1308d84882caSNeel Natu 			goto done;
1309d84882caSNeel Natu 		}
1310d84882caSNeel Natu 	}
1311d84882caSNeel Natu 	assert(bi != NULL);
1312d84882caSNeel Natu 
1313d84882caSNeel Natu 	/* i/o window */
1314d84882caSNeel Natu 	dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1315d84882caSNeel Natu 	    "PosDecode, EntireRange,");
1316d84882caSNeel Natu 	dsdt_line("        0x0000,             // Granularity");
1317d84882caSNeel Natu 	dsdt_line("        0x%04X,             // Range Minimum", bi->iobase);
1318d84882caSNeel Natu 	dsdt_line("        0x%04X,             // Range Maximum",
1319d84882caSNeel Natu 	    bi->iolimit - 1);
1320d84882caSNeel Natu 	dsdt_line("        0x0000,             // Translation Offset");
1321d84882caSNeel Natu 	dsdt_line("        0x%04X,             // Length",
1322d84882caSNeel Natu 	    bi->iolimit - bi->iobase);
1323d84882caSNeel Natu 	dsdt_line("        ,, , TypeStatic)");
1324d84882caSNeel Natu 
1325d84882caSNeel Natu 	/* mmio window (32-bit) */
1326e6c8bc29SJohn Baldwin 	dsdt_line("      DWordMemory (ResourceProducer, PosDecode, "
1327e6c8bc29SJohn Baldwin 	    "MinFixed, MaxFixed, NonCacheable, ReadWrite,");
1328e6c8bc29SJohn Baldwin 	dsdt_line("        0x00000000,         // Granularity");
1329d84882caSNeel Natu 	dsdt_line("        0x%08X,         // Range Minimum\n", bi->membase32);
1330e6c8bc29SJohn Baldwin 	dsdt_line("        0x%08X,         // Range Maximum\n",
1331d84882caSNeel Natu 	    bi->memlimit32 - 1);
1332e6c8bc29SJohn Baldwin 	dsdt_line("        0x00000000,         // Translation Offset");
1333d84882caSNeel Natu 	dsdt_line("        0x%08X,         // Length\n",
1334d84882caSNeel Natu 	    bi->memlimit32 - bi->membase32);
1335e6c8bc29SJohn Baldwin 	dsdt_line("        ,, , AddressRangeMemory, TypeStatic)");
1336d84882caSNeel Natu 
1337d84882caSNeel Natu 	/* mmio window (64-bit) */
1338e6c8bc29SJohn Baldwin 	dsdt_line("      QWordMemory (ResourceProducer, PosDecode, "
1339e6c8bc29SJohn Baldwin 	    "MinFixed, MaxFixed, NonCacheable, ReadWrite,");
1340e6c8bc29SJohn Baldwin 	dsdt_line("        0x0000000000000000, // Granularity");
1341d84882caSNeel Natu 	dsdt_line("        0x%016lX, // Range Minimum\n", bi->membase64);
1342e6c8bc29SJohn Baldwin 	dsdt_line("        0x%016lX, // Range Maximum\n",
1343d84882caSNeel Natu 	    bi->memlimit64 - 1);
1344e6c8bc29SJohn Baldwin 	dsdt_line("        0x0000000000000000, // Translation Offset");
1345e6c8bc29SJohn Baldwin 	dsdt_line("        0x%016lX, // Length\n",
1346d84882caSNeel Natu 	    bi->memlimit64 - bi->membase64);
1347e6c8bc29SJohn Baldwin 	dsdt_line("        ,, , AddressRangeMemory, TypeStatic)");
1348e6c8bc29SJohn Baldwin 	dsdt_line("    })");
1349d84882caSNeel Natu 
1350d84882caSNeel Natu 	count = pci_count_lintr(bus);
13513cbf3585SJohn Baldwin 	if (count != 0) {
13523cbf3585SJohn Baldwin 		dsdt_indent(2);
1353b3e9732aSJohn Baldwin 		dsdt_line("Name (PPRT, Package ()");
13543cbf3585SJohn Baldwin 		dsdt_line("{");
1355b3e9732aSJohn Baldwin 		pci_walk_lintr(bus, pci_pirq_prt_entry, NULL);
13563cbf3585SJohn Baldwin 		dsdt_line("})");
1357b3e9732aSJohn Baldwin 		dsdt_line("Name (APRT, Package ()");
1358b3e9732aSJohn Baldwin 		dsdt_line("{");
1359b3e9732aSJohn Baldwin 		pci_walk_lintr(bus, pci_apic_prt_entry, NULL);
1360b3e9732aSJohn Baldwin 		dsdt_line("})");
1361b3e9732aSJohn Baldwin 		dsdt_line("Method (_PRT, 0, NotSerialized)");
1362b3e9732aSJohn Baldwin 		dsdt_line("{");
1363b3e9732aSJohn Baldwin 		dsdt_line("  If (PICM)");
1364b3e9732aSJohn Baldwin 		dsdt_line("  {");
1365b3e9732aSJohn Baldwin 		dsdt_line("    Return (APRT)");
1366b3e9732aSJohn Baldwin 		dsdt_line("  }");
1367b3e9732aSJohn Baldwin 		dsdt_line("  Else");
1368b3e9732aSJohn Baldwin 		dsdt_line("  {");
1369b3e9732aSJohn Baldwin 		dsdt_line("    Return (PPRT)");
1370b3e9732aSJohn Baldwin 		dsdt_line("  }");
1371b3e9732aSJohn Baldwin 		dsdt_line("}");
13723cbf3585SJohn Baldwin 		dsdt_unindent(2);
13733cbf3585SJohn Baldwin 	}
1374e6c8bc29SJohn Baldwin 
1375e6c8bc29SJohn Baldwin 	dsdt_indent(2);
1376e6c8bc29SJohn Baldwin 	for (slot = 0; slot < MAXSLOTS; slot++) {
1377d84882caSNeel Natu 		si = &bi->slotinfo[slot];
1378e6c8bc29SJohn Baldwin 		for (func = 0; func < MAXFUNCS; func++) {
1379d84882caSNeel Natu 			pi = si->si_funcs[func].fi_devi;
1380e6c8bc29SJohn Baldwin 			if (pi != NULL && pi->pi_d->pe_write_dsdt != NULL)
1381e6c8bc29SJohn Baldwin 				pi->pi_d->pe_write_dsdt(pi);
1382e6c8bc29SJohn Baldwin 		}
1383e6c8bc29SJohn Baldwin 	}
1384e6c8bc29SJohn Baldwin 	dsdt_unindent(2);
1385d84882caSNeel Natu done:
1386e6c8bc29SJohn Baldwin 	dsdt_line("  }");
1387e6c8bc29SJohn Baldwin }
1388e6c8bc29SJohn Baldwin 
1389d84882caSNeel Natu void
1390d84882caSNeel Natu pci_write_dsdt(void)
1391d84882caSNeel Natu {
1392d84882caSNeel Natu 	int bus;
1393d84882caSNeel Natu 
1394b3e9732aSJohn Baldwin 	dsdt_indent(1);
1395b3e9732aSJohn Baldwin 	dsdt_line("Name (PICM, 0x00)");
1396b3e9732aSJohn Baldwin 	dsdt_line("Method (_PIC, 1, NotSerialized)");
1397b3e9732aSJohn Baldwin 	dsdt_line("{");
1398b3e9732aSJohn Baldwin 	dsdt_line("  Store (Arg0, PICM)");
1399b3e9732aSJohn Baldwin 	dsdt_line("}");
1400b3e9732aSJohn Baldwin 	dsdt_line("");
1401b3e9732aSJohn Baldwin 	dsdt_line("Scope (_SB)");
1402b3e9732aSJohn Baldwin 	dsdt_line("{");
1403d84882caSNeel Natu 	for (bus = 0; bus < MAXBUSES; bus++)
1404d84882caSNeel Natu 		pci_bus_write_dsdt(bus);
1405b3e9732aSJohn Baldwin 	dsdt_line("}");
1406b3e9732aSJohn Baldwin 	dsdt_unindent(1);
1407d84882caSNeel Natu }
1408d84882caSNeel Natu 
1409366f6083SPeter Grehan int
1410b100acf2SNeel Natu pci_bus_configured(int bus)
1411b100acf2SNeel Natu {
1412b100acf2SNeel Natu 	assert(bus >= 0 && bus < MAXBUSES);
1413b100acf2SNeel Natu 	return (pci_businfo[bus] != NULL);
1414b100acf2SNeel Natu }
1415b100acf2SNeel Natu 
1416b100acf2SNeel Natu int
1417366f6083SPeter Grehan pci_msi_enabled(struct pci_devinst *pi)
1418366f6083SPeter Grehan {
1419366f6083SPeter Grehan 	return (pi->pi_msi.enabled);
1420366f6083SPeter Grehan }
1421366f6083SPeter Grehan 
1422366f6083SPeter Grehan int
14234f8be175SNeel Natu pci_msi_maxmsgnum(struct pci_devinst *pi)
1424366f6083SPeter Grehan {
1425366f6083SPeter Grehan 	if (pi->pi_msi.enabled)
14264f8be175SNeel Natu 		return (pi->pi_msi.maxmsgnum);
1427366f6083SPeter Grehan 	else
1428366f6083SPeter Grehan 		return (0);
1429366f6083SPeter Grehan }
1430366f6083SPeter Grehan 
1431c9b4e987SNeel Natu int
1432c9b4e987SNeel Natu pci_msix_enabled(struct pci_devinst *pi)
1433c9b4e987SNeel Natu {
1434c9b4e987SNeel Natu 
1435c9b4e987SNeel Natu 	return (pi->pi_msix.enabled && !pi->pi_msi.enabled);
1436c9b4e987SNeel Natu }
1437c9b4e987SNeel Natu 
1438c9b4e987SNeel Natu void
1439c9b4e987SNeel Natu pci_generate_msix(struct pci_devinst *pi, int index)
1440c9b4e987SNeel Natu {
1441c9b4e987SNeel Natu 	struct msix_table_entry *mte;
1442c9b4e987SNeel Natu 
1443c9b4e987SNeel Natu 	if (!pci_msix_enabled(pi))
1444c9b4e987SNeel Natu 		return;
1445c9b4e987SNeel Natu 
1446c9b4e987SNeel Natu 	if (pi->pi_msix.function_mask)
1447c9b4e987SNeel Natu 		return;
1448c9b4e987SNeel Natu 
1449c9b4e987SNeel Natu 	if (index >= pi->pi_msix.table_count)
1450c9b4e987SNeel Natu 		return;
1451c9b4e987SNeel Natu 
1452c9b4e987SNeel Natu 	mte = &pi->pi_msix.table[index];
1453c9b4e987SNeel Natu 	if ((mte->vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
1454c9b4e987SNeel Natu 		/* XXX Set PBA bit if interrupt is disabled */
14554f8be175SNeel Natu 		vm_lapic_msi(pi->pi_vmctx, mte->addr, mte->msg_data);
1456c9b4e987SNeel Natu 	}
1457c9b4e987SNeel Natu }
1458c9b4e987SNeel Natu 
1459366f6083SPeter Grehan void
14604f8be175SNeel Natu pci_generate_msi(struct pci_devinst *pi, int index)
1461366f6083SPeter Grehan {
1462366f6083SPeter Grehan 
14634f8be175SNeel Natu 	if (pci_msi_enabled(pi) && index < pci_msi_maxmsgnum(pi)) {
14644f8be175SNeel Natu 		vm_lapic_msi(pi->pi_vmctx, pi->pi_msi.addr,
14654f8be175SNeel Natu 			     pi->pi_msi.msg_data + index);
1466366f6083SPeter Grehan 	}
1467366f6083SPeter Grehan }
1468366f6083SPeter Grehan 
14693cbf3585SJohn Baldwin static bool
14703cbf3585SJohn Baldwin pci_lintr_permitted(struct pci_devinst *pi)
14710038ee98SPeter Grehan {
14723cbf3585SJohn Baldwin 	uint16_t cmd;
14730038ee98SPeter Grehan 
14743cbf3585SJohn Baldwin 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
14753cbf3585SJohn Baldwin 	return (!(pi->pi_msi.enabled || pi->pi_msix.enabled ||
14763cbf3585SJohn Baldwin 		(cmd & PCIM_CMD_INTxDIS)));
14773cbf3585SJohn Baldwin }
14783cbf3585SJohn Baldwin 
1479b3e9732aSJohn Baldwin void
14803cbf3585SJohn Baldwin pci_lintr_request(struct pci_devinst *pi)
14813cbf3585SJohn Baldwin {
1482d84882caSNeel Natu 	struct businfo *bi;
14833cbf3585SJohn Baldwin 	struct slotinfo *si;
1484b3e9732aSJohn Baldwin 	int bestpin, bestcount, pin;
14853cbf3585SJohn Baldwin 
1486d84882caSNeel Natu 	bi = pci_businfo[pi->pi_bus];
1487d84882caSNeel Natu 	assert(bi != NULL);
1488d84882caSNeel Natu 
14893cbf3585SJohn Baldwin 	/*
1490b3e9732aSJohn Baldwin 	 * Just allocate a pin from our slot.  The pin will be
1491b3e9732aSJohn Baldwin 	 * assigned IRQs later when interrupts are routed.
14923cbf3585SJohn Baldwin 	 */
1493d84882caSNeel Natu 	si = &bi->slotinfo[pi->pi_slot];
14943cbf3585SJohn Baldwin 	bestpin = 0;
14953cbf3585SJohn Baldwin 	bestcount = si->si_intpins[0].ii_count;
14963cbf3585SJohn Baldwin 	for (pin = 1; pin < 4; pin++) {
14973cbf3585SJohn Baldwin 		if (si->si_intpins[pin].ii_count < bestcount) {
14983cbf3585SJohn Baldwin 			bestpin = pin;
14993cbf3585SJohn Baldwin 			bestcount = si->si_intpins[pin].ii_count;
15003cbf3585SJohn Baldwin 		}
15013cbf3585SJohn Baldwin 	}
15023cbf3585SJohn Baldwin 
15033cbf3585SJohn Baldwin 	si->si_intpins[bestpin].ii_count++;
15043cbf3585SJohn Baldwin 	pi->pi_lintr.pin = bestpin + 1;
15053cbf3585SJohn Baldwin 	pci_set_cfgdata8(pi, PCIR_INTPIN, bestpin + 1);
1506b3e9732aSJohn Baldwin }
1507b3e9732aSJohn Baldwin 
1508b3e9732aSJohn Baldwin static void
1509b3e9732aSJohn Baldwin pci_lintr_route(struct pci_devinst *pi)
1510b3e9732aSJohn Baldwin {
1511b3e9732aSJohn Baldwin 	struct businfo *bi;
1512b3e9732aSJohn Baldwin 	struct intxinfo *ii;
1513b3e9732aSJohn Baldwin 
1514b3e9732aSJohn Baldwin 	if (pi->pi_lintr.pin == 0)
1515b3e9732aSJohn Baldwin 		return;
1516b3e9732aSJohn Baldwin 
1517b3e9732aSJohn Baldwin 	bi = pci_businfo[pi->pi_bus];
1518b3e9732aSJohn Baldwin 	assert(bi != NULL);
1519b3e9732aSJohn Baldwin 	ii = &bi->slotinfo[pi->pi_slot].si_intpins[pi->pi_lintr.pin - 1];
1520b3e9732aSJohn Baldwin 
1521b3e9732aSJohn Baldwin 	/*
1522b3e9732aSJohn Baldwin 	 * Attempt to allocate an I/O APIC pin for this intpin if one
1523b3e9732aSJohn Baldwin 	 * is not yet assigned.
1524b3e9732aSJohn Baldwin 	 */
1525b3e9732aSJohn Baldwin 	if (ii->ii_ioapic_irq == 0)
15261b4496d0SAlexander Motin 		ii->ii_ioapic_irq = ioapic_pci_alloc_irq(pi);
1527b3e9732aSJohn Baldwin 	assert(ii->ii_ioapic_irq > 0);
1528b3e9732aSJohn Baldwin 
1529b3e9732aSJohn Baldwin 	/*
1530b3e9732aSJohn Baldwin 	 * Attempt to allocate a PIRQ pin for this intpin if one is
1531b3e9732aSJohn Baldwin 	 * not yet assigned.
1532b3e9732aSJohn Baldwin 	 */
1533b3e9732aSJohn Baldwin 	if (ii->ii_pirq_pin == 0)
15341b4496d0SAlexander Motin 		ii->ii_pirq_pin = pirq_alloc_pin(pi);
1535b3e9732aSJohn Baldwin 	assert(ii->ii_pirq_pin > 0);
1536b3e9732aSJohn Baldwin 
1537b3e9732aSJohn Baldwin 	pi->pi_lintr.ioapic_irq = ii->ii_ioapic_irq;
1538b3e9732aSJohn Baldwin 	pi->pi_lintr.pirq_pin = ii->ii_pirq_pin;
1539b3e9732aSJohn Baldwin 	pci_set_cfgdata8(pi, PCIR_INTLINE, pirq_irq(ii->ii_pirq_pin));
15400038ee98SPeter Grehan }
15410038ee98SPeter Grehan 
15420038ee98SPeter Grehan void
15430038ee98SPeter Grehan pci_lintr_assert(struct pci_devinst *pi)
15440038ee98SPeter Grehan {
15450038ee98SPeter Grehan 
15463cbf3585SJohn Baldwin 	assert(pi->pi_lintr.pin > 0);
1547ac7304a7SNeel Natu 
15483cbf3585SJohn Baldwin 	pthread_mutex_lock(&pi->pi_lintr.lock);
15493cbf3585SJohn Baldwin 	if (pi->pi_lintr.state == IDLE) {
15503cbf3585SJohn Baldwin 		if (pci_lintr_permitted(pi)) {
15513cbf3585SJohn Baldwin 			pi->pi_lintr.state = ASSERTED;
1552b3e9732aSJohn Baldwin 			pci_irq_assert(pi);
15533cbf3585SJohn Baldwin 		} else
15543cbf3585SJohn Baldwin 			pi->pi_lintr.state = PENDING;
15550038ee98SPeter Grehan 	}
15563cbf3585SJohn Baldwin 	pthread_mutex_unlock(&pi->pi_lintr.lock);
1557ac7304a7SNeel Natu }
15580038ee98SPeter Grehan 
15590038ee98SPeter Grehan void
15600038ee98SPeter Grehan pci_lintr_deassert(struct pci_devinst *pi)
15610038ee98SPeter Grehan {
15620038ee98SPeter Grehan 
15633cbf3585SJohn Baldwin 	assert(pi->pi_lintr.pin > 0);
1564ac7304a7SNeel Natu 
15653cbf3585SJohn Baldwin 	pthread_mutex_lock(&pi->pi_lintr.lock);
15663cbf3585SJohn Baldwin 	if (pi->pi_lintr.state == ASSERTED) {
15673cbf3585SJohn Baldwin 		pi->pi_lintr.state = IDLE;
1568b3e9732aSJohn Baldwin 		pci_irq_deassert(pi);
15693cbf3585SJohn Baldwin 	} else if (pi->pi_lintr.state == PENDING)
15703cbf3585SJohn Baldwin 		pi->pi_lintr.state = IDLE;
15713cbf3585SJohn Baldwin 	pthread_mutex_unlock(&pi->pi_lintr.lock);
15723cbf3585SJohn Baldwin }
15733cbf3585SJohn Baldwin 
15743cbf3585SJohn Baldwin static void
15753cbf3585SJohn Baldwin pci_lintr_update(struct pci_devinst *pi)
15763cbf3585SJohn Baldwin {
15773cbf3585SJohn Baldwin 
15783cbf3585SJohn Baldwin 	pthread_mutex_lock(&pi->pi_lintr.lock);
15793cbf3585SJohn Baldwin 	if (pi->pi_lintr.state == ASSERTED && !pci_lintr_permitted(pi)) {
1580b3e9732aSJohn Baldwin 		pci_irq_deassert(pi);
15813cbf3585SJohn Baldwin 		pi->pi_lintr.state = PENDING;
15823cbf3585SJohn Baldwin 	} else if (pi->pi_lintr.state == PENDING && pci_lintr_permitted(pi)) {
15833cbf3585SJohn Baldwin 		pi->pi_lintr.state = ASSERTED;
1584b3e9732aSJohn Baldwin 		pci_irq_assert(pi);
15853cbf3585SJohn Baldwin 	}
15863cbf3585SJohn Baldwin 	pthread_mutex_unlock(&pi->pi_lintr.lock);
15873cbf3585SJohn Baldwin }
15883cbf3585SJohn Baldwin 
15893cbf3585SJohn Baldwin int
1590d84882caSNeel Natu pci_count_lintr(int bus)
15913cbf3585SJohn Baldwin {
15923cbf3585SJohn Baldwin 	int count, slot, pin;
1593d84882caSNeel Natu 	struct slotinfo *slotinfo;
15943cbf3585SJohn Baldwin 
15953cbf3585SJohn Baldwin 	count = 0;
1596d84882caSNeel Natu 	if (pci_businfo[bus] != NULL) {
15973cbf3585SJohn Baldwin 		for (slot = 0; slot < MAXSLOTS; slot++) {
1598d84882caSNeel Natu 			slotinfo = &pci_businfo[bus]->slotinfo[slot];
15993cbf3585SJohn Baldwin 			for (pin = 0; pin < 4; pin++) {
1600d84882caSNeel Natu 				if (slotinfo->si_intpins[pin].ii_count != 0)
16013cbf3585SJohn Baldwin 					count++;
16023cbf3585SJohn Baldwin 			}
16033cbf3585SJohn Baldwin 		}
1604d84882caSNeel Natu 	}
16053cbf3585SJohn Baldwin 	return (count);
16063cbf3585SJohn Baldwin }
16073cbf3585SJohn Baldwin 
16083cbf3585SJohn Baldwin void
1609d84882caSNeel Natu pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg)
16103cbf3585SJohn Baldwin {
1611d84882caSNeel Natu 	struct businfo *bi;
1612d84882caSNeel Natu 	struct slotinfo *si;
16133cbf3585SJohn Baldwin 	struct intxinfo *ii;
16143cbf3585SJohn Baldwin 	int slot, pin;
16153cbf3585SJohn Baldwin 
1616d84882caSNeel Natu 	if ((bi = pci_businfo[bus]) == NULL)
1617d84882caSNeel Natu 		return;
1618d84882caSNeel Natu 
16193cbf3585SJohn Baldwin 	for (slot = 0; slot < MAXSLOTS; slot++) {
1620d84882caSNeel Natu 		si = &bi->slotinfo[slot];
16213cbf3585SJohn Baldwin 		for (pin = 0; pin < 4; pin++) {
1622d84882caSNeel Natu 			ii = &si->si_intpins[pin];
16233cbf3585SJohn Baldwin 			if (ii->ii_count != 0)
1624b3e9732aSJohn Baldwin 				cb(bus, slot, pin + 1, ii->ii_pirq_pin,
1625b3e9732aSJohn Baldwin 				    ii->ii_ioapic_irq, arg);
16263cbf3585SJohn Baldwin 		}
16270038ee98SPeter Grehan 	}
1628ac7304a7SNeel Natu }
16290038ee98SPeter Grehan 
163099d65389SNeel Natu /*
163199d65389SNeel Natu  * Return 1 if the emulated device in 'slot' is a multi-function device.
163299d65389SNeel Natu  * Return 0 otherwise.
163399d65389SNeel Natu  */
163499d65389SNeel Natu static int
1635d84882caSNeel Natu pci_emul_is_mfdev(int bus, int slot)
163699d65389SNeel Natu {
1637d84882caSNeel Natu 	struct businfo *bi;
1638d84882caSNeel Natu 	struct slotinfo *si;
163999d65389SNeel Natu 	int f, numfuncs;
16400038ee98SPeter Grehan 
164199d65389SNeel Natu 	numfuncs = 0;
1642d84882caSNeel Natu 	if ((bi = pci_businfo[bus]) != NULL) {
1643d84882caSNeel Natu 		si = &bi->slotinfo[slot];
164499d65389SNeel Natu 		for (f = 0; f < MAXFUNCS; f++) {
1645d84882caSNeel Natu 			if (si->si_funcs[f].fi_devi != NULL) {
164699d65389SNeel Natu 				numfuncs++;
164799d65389SNeel Natu 			}
164899d65389SNeel Natu 		}
1649d84882caSNeel Natu 	}
165099d65389SNeel Natu 	return (numfuncs > 1);
165199d65389SNeel Natu }
165299d65389SNeel Natu 
165399d65389SNeel Natu /*
165499d65389SNeel Natu  * Ensure that the PCIM_MFDEV bit is properly set (or unset) depending on
165599d65389SNeel Natu  * whether or not is a multi-function being emulated in the pci 'slot'.
165699d65389SNeel Natu  */
165799d65389SNeel Natu static void
1658d84882caSNeel Natu pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv)
165999d65389SNeel Natu {
166099d65389SNeel Natu 	int mfdev;
166199d65389SNeel Natu 
166299d65389SNeel Natu 	if (off <= PCIR_HDRTYPE && off + bytes > PCIR_HDRTYPE) {
1663d84882caSNeel Natu 		mfdev = pci_emul_is_mfdev(bus, slot);
166499d65389SNeel Natu 		switch (bytes) {
166599d65389SNeel Natu 		case 1:
166699d65389SNeel Natu 		case 2:
166799d65389SNeel Natu 			*rv &= ~PCIM_MFDEV;
166899d65389SNeel Natu 			if (mfdev) {
166999d65389SNeel Natu 				*rv |= PCIM_MFDEV;
167099d65389SNeel Natu 			}
167199d65389SNeel Natu 			break;
167299d65389SNeel Natu 		case 4:
167399d65389SNeel Natu 			*rv &= ~(PCIM_MFDEV << 16);
167499d65389SNeel Natu 			if (mfdev) {
167599d65389SNeel Natu 				*rv |= (PCIM_MFDEV << 16);
167699d65389SNeel Natu 			}
167799d65389SNeel Natu 			break;
167899d65389SNeel Natu 		}
167999d65389SNeel Natu 	}
168099d65389SNeel Natu }
16810038ee98SPeter Grehan 
168256282675SJohn Baldwin /*
168356282675SJohn Baldwin  * Update device state in response to changes to the PCI command
168456282675SJohn Baldwin  * register.
168556282675SJohn Baldwin  */
168656282675SJohn Baldwin void
168756282675SJohn Baldwin pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old)
168856282675SJohn Baldwin {
168956282675SJohn Baldwin 	int i;
169056282675SJohn Baldwin 	uint16_t changed, new;
169156282675SJohn Baldwin 
169256282675SJohn Baldwin 	new = pci_get_cfgdata16(pi, PCIR_COMMAND);
169356282675SJohn Baldwin 	changed = old ^ new;
169456282675SJohn Baldwin 
169556282675SJohn Baldwin 	/*
169656282675SJohn Baldwin 	 * If the MMIO or I/O address space decoding has changed then
169756282675SJohn Baldwin 	 * register/unregister all BARs that decode that address space.
169856282675SJohn Baldwin 	 */
169956282675SJohn Baldwin 	for (i = 0; i <= PCI_BARMAX; i++) {
170056282675SJohn Baldwin 		switch (pi->pi_bar[i].type) {
170156282675SJohn Baldwin 			case PCIBAR_NONE:
170256282675SJohn Baldwin 			case PCIBAR_MEMHI64:
170356282675SJohn Baldwin 				break;
170456282675SJohn Baldwin 			case PCIBAR_IO:
170556282675SJohn Baldwin 				/* I/O address space decoding changed? */
170656282675SJohn Baldwin 				if (changed & PCIM_CMD_PORTEN) {
170756282675SJohn Baldwin 					if (new & PCIM_CMD_PORTEN)
170856282675SJohn Baldwin 						register_bar(pi, i);
170956282675SJohn Baldwin 					else
171056282675SJohn Baldwin 						unregister_bar(pi, i);
171156282675SJohn Baldwin 				}
171256282675SJohn Baldwin 				break;
171356282675SJohn Baldwin 			case PCIBAR_MEM32:
171456282675SJohn Baldwin 			case PCIBAR_MEM64:
171556282675SJohn Baldwin 				/* MMIO address space decoding changed? */
171656282675SJohn Baldwin 				if (changed & PCIM_CMD_MEMEN) {
171756282675SJohn Baldwin 					if (new & PCIM_CMD_MEMEN)
171856282675SJohn Baldwin 						register_bar(pi, i);
171956282675SJohn Baldwin 					else
172056282675SJohn Baldwin 						unregister_bar(pi, i);
172156282675SJohn Baldwin 				}
172256282675SJohn Baldwin 				break;
172356282675SJohn Baldwin 			default:
172456282675SJohn Baldwin 				assert(0);
172556282675SJohn Baldwin 		}
172656282675SJohn Baldwin 	}
172756282675SJohn Baldwin 
172856282675SJohn Baldwin 	/*
172956282675SJohn Baldwin 	 * If INTx has been unmasked and is pending, assert the
173056282675SJohn Baldwin 	 * interrupt.
173156282675SJohn Baldwin 	 */
173256282675SJohn Baldwin 	pci_lintr_update(pi);
173356282675SJohn Baldwin }
173456282675SJohn Baldwin 
1735028d9311SNeel Natu static void
173654335630SNeel Natu pci_emul_cmdsts_write(struct pci_devinst *pi, int coff, uint32_t new, int bytes)
1737028d9311SNeel Natu {
173856282675SJohn Baldwin 	int rshift;
173956282675SJohn Baldwin 	uint32_t cmd, old, readonly;
174054335630SNeel Natu 
174154335630SNeel Natu 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);	/* stash old value */
1742028d9311SNeel Natu 
1743028d9311SNeel Natu 	/*
174454335630SNeel Natu 	 * From PCI Local Bus Specification 3.0 sections 6.2.2 and 6.2.3.
174554335630SNeel Natu 	 *
174654335630SNeel Natu 	 * XXX Bits 8, 11, 12, 13, 14 and 15 in the status register are
174754335630SNeel Natu 	 * 'write 1 to clear'. However these bits are not set to '1' by
174854335630SNeel Natu 	 * any device emulation so it is simpler to treat them as readonly.
1749028d9311SNeel Natu 	 */
175054335630SNeel Natu 	rshift = (coff & 0x3) * 8;
175154335630SNeel Natu 	readonly = 0xFFFFF880 >> rshift;
1752028d9311SNeel Natu 
175354335630SNeel Natu 	old = CFGREAD(pi, coff, bytes);
175454335630SNeel Natu 	new &= ~readonly;
175554335630SNeel Natu 	new |= (old & readonly);
175654335630SNeel Natu 	CFGWRITE(pi, coff, new, bytes);			/* update config */
175754335630SNeel Natu 
175856282675SJohn Baldwin 	pci_emul_cmd_changed(pi, cmd);
1759028d9311SNeel Natu }
1760028d9311SNeel Natu 
176112a6eb99SNeel Natu static void
176212a6eb99SNeel Natu pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
176312a6eb99SNeel Natu     int coff, int bytes, uint32_t *eax)
1764366f6083SPeter Grehan {
1765d84882caSNeel Natu 	struct businfo *bi;
1766d84882caSNeel Natu 	struct slotinfo *si;
1767366f6083SPeter Grehan 	struct pci_devinst *pi;
1768366f6083SPeter Grehan 	struct pci_devemu *pe;
176912a6eb99SNeel Natu 	int idx, needcfg;
1770028d9311SNeel Natu 	uint64_t addr, bar, mask;
1771366f6083SPeter Grehan 
177212a6eb99SNeel Natu 	if ((bi = pci_businfo[bus]) != NULL) {
177312a6eb99SNeel Natu 		si = &bi->slotinfo[slot];
177412a6eb99SNeel Natu 		pi = si->si_funcs[func].fi_devi;
1775d84882caSNeel Natu 	} else
177690415e0bSNeel Natu 		pi = NULL;
177790415e0bSNeel Natu 
177899d65389SNeel Natu 	/*
177912a6eb99SNeel Natu 	 * Just return if there is no device at this slot:func or if the
178012a6eb99SNeel Natu 	 * the guest is doing an un-aligned access.
178199d65389SNeel Natu 	 */
178212a6eb99SNeel Natu 	if (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) ||
178312a6eb99SNeel Natu 	    (coff & (bytes - 1)) != 0) {
1784366f6083SPeter Grehan 		if (in)
1785366f6083SPeter Grehan 			*eax = 0xffffffff;
178612a6eb99SNeel Natu 		return;
178712a6eb99SNeel Natu 	}
178812a6eb99SNeel Natu 
178912a6eb99SNeel Natu 	/*
179012a6eb99SNeel Natu 	 * Ignore all writes beyond the standard config space and return all
179112a6eb99SNeel Natu 	 * ones on reads.
179212a6eb99SNeel Natu 	 */
179312a6eb99SNeel Natu 	if (coff >= PCI_REGMAX + 1) {
179412a6eb99SNeel Natu 		if (in) {
179512a6eb99SNeel Natu 			*eax = 0xffffffff;
179612a6eb99SNeel Natu 			/*
179712a6eb99SNeel Natu 			 * Extended capabilities begin at offset 256 in config
179812a6eb99SNeel Natu 			 * space. Absence of extended capabilities is signaled
179912a6eb99SNeel Natu 			 * with all 0s in the extended capability header at
180012a6eb99SNeel Natu 			 * offset 256.
180112a6eb99SNeel Natu 			 */
180212a6eb99SNeel Natu 			if (coff <= PCI_REGMAX + 4)
180312a6eb99SNeel Natu 				*eax = 0x00000000;
180412a6eb99SNeel Natu 		}
180512a6eb99SNeel Natu 		return;
1806366f6083SPeter Grehan 	}
1807366f6083SPeter Grehan 
1808366f6083SPeter Grehan 	pe = pi->pi_d;
1809366f6083SPeter Grehan 
1810366f6083SPeter Grehan 	/*
1811366f6083SPeter Grehan 	 * Config read
1812366f6083SPeter Grehan 	 */
1813366f6083SPeter Grehan 	if (in) {
1814366f6083SPeter Grehan 		/* Let the device emulation override the default handler */
181599d65389SNeel Natu 		if (pe->pe_cfgread != NULL) {
181612a6eb99SNeel Natu 			needcfg = pe->pe_cfgread(ctx, vcpu, pi, coff, bytes,
181712a6eb99SNeel Natu 			    eax);
181899d65389SNeel Natu 		} else {
181999d65389SNeel Natu 			needcfg = 1;
182099d65389SNeel Natu 		}
1821366f6083SPeter Grehan 
182254335630SNeel Natu 		if (needcfg)
182354335630SNeel Natu 			*eax = CFGREAD(pi, coff, bytes);
182499d65389SNeel Natu 
182512a6eb99SNeel Natu 		pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax);
1826366f6083SPeter Grehan 	} else {
1827366f6083SPeter Grehan 		/* Let the device emulation override the default handler */
1828366f6083SPeter Grehan 		if (pe->pe_cfgwrite != NULL &&
1829366f6083SPeter Grehan 		    (*pe->pe_cfgwrite)(ctx, vcpu, pi, coff, bytes, *eax) == 0)
183012a6eb99SNeel Natu 			return;
1831366f6083SPeter Grehan 
1832366f6083SPeter Grehan 		/*
1833366f6083SPeter Grehan 		 * Special handling for write to BAR registers
1834366f6083SPeter Grehan 		 */
1835366f6083SPeter Grehan 		if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) {
1836366f6083SPeter Grehan 			/*
1837366f6083SPeter Grehan 			 * Ignore writes to BAR registers that are not
1838366f6083SPeter Grehan 			 * 4-byte aligned.
1839366f6083SPeter Grehan 			 */
1840366f6083SPeter Grehan 			if (bytes != 4 || (coff & 0x3) != 0)
184112a6eb99SNeel Natu 				return;
1842366f6083SPeter Grehan 			idx = (coff - PCIR_BAR(0)) / 4;
1843028d9311SNeel Natu 			mask = ~(pi->pi_bar[idx].size - 1);
1844366f6083SPeter Grehan 			switch (pi->pi_bar[idx].type) {
1845366f6083SPeter Grehan 			case PCIBAR_NONE:
1846028d9311SNeel Natu 				pi->pi_bar[idx].addr = bar = 0;
1847366f6083SPeter Grehan 				break;
1848366f6083SPeter Grehan 			case PCIBAR_IO:
1849028d9311SNeel Natu 				addr = *eax & mask;
1850028d9311SNeel Natu 				addr &= 0xffff;
1851028d9311SNeel Natu 				bar = addr | PCIM_BAR_IO_SPACE;
1852028d9311SNeel Natu 				/*
1853028d9311SNeel Natu 				 * Register the new BAR value for interception
1854028d9311SNeel Natu 				 */
1855028d9311SNeel Natu 				if (addr != pi->pi_bar[idx].addr) {
1856028d9311SNeel Natu 					update_bar_address(pi, addr, idx,
1857028d9311SNeel Natu 							   PCIBAR_IO);
1858028d9311SNeel Natu 				}
1859366f6083SPeter Grehan 				break;
1860366f6083SPeter Grehan 			case PCIBAR_MEM32:
1861028d9311SNeel Natu 				addr = bar = *eax & mask;
1862366f6083SPeter Grehan 				bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
1863028d9311SNeel Natu 				if (addr != pi->pi_bar[idx].addr) {
1864028d9311SNeel Natu 					update_bar_address(pi, addr, idx,
1865028d9311SNeel Natu 							   PCIBAR_MEM32);
1866028d9311SNeel Natu 				}
1867366f6083SPeter Grehan 				break;
1868366f6083SPeter Grehan 			case PCIBAR_MEM64:
1869028d9311SNeel Natu 				addr = bar = *eax & mask;
1870366f6083SPeter Grehan 				bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
1871366f6083SPeter Grehan 				       PCIM_BAR_MEM_PREFETCH;
1872028d9311SNeel Natu 				if (addr != (uint32_t)pi->pi_bar[idx].addr) {
1873028d9311SNeel Natu 					update_bar_address(pi, addr, idx,
1874028d9311SNeel Natu 							   PCIBAR_MEM64);
1875028d9311SNeel Natu 				}
1876366f6083SPeter Grehan 				break;
1877366f6083SPeter Grehan 			case PCIBAR_MEMHI64:
1878366f6083SPeter Grehan 				mask = ~(pi->pi_bar[idx - 1].size - 1);
1879028d9311SNeel Natu 				addr = ((uint64_t)*eax << 32) & mask;
1880028d9311SNeel Natu 				bar = addr >> 32;
1881028d9311SNeel Natu 				if (bar != pi->pi_bar[idx - 1].addr >> 32) {
1882028d9311SNeel Natu 					update_bar_address(pi, addr, idx - 1,
1883028d9311SNeel Natu 							   PCIBAR_MEMHI64);
1884028d9311SNeel Natu 				}
1885366f6083SPeter Grehan 				break;
1886366f6083SPeter Grehan 			default:
1887366f6083SPeter Grehan 				assert(0);
1888366f6083SPeter Grehan 			}
1889366f6083SPeter Grehan 			pci_set_cfgdata32(pi, coff, bar);
1890cd942e0fSPeter Grehan 
1891366f6083SPeter Grehan 		} else if (pci_emul_iscap(pi, coff)) {
1892366f6083SPeter Grehan 			pci_emul_capwrite(pi, coff, bytes, *eax);
189354335630SNeel Natu 		} else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) {
189454335630SNeel Natu 			pci_emul_cmdsts_write(pi, coff, *eax, bytes);
1895366f6083SPeter Grehan 		} else {
1896366f6083SPeter Grehan 			CFGWRITE(pi, coff, *eax, bytes);
1897366f6083SPeter Grehan 		}
1898366f6083SPeter Grehan 	}
189912a6eb99SNeel Natu }
1900366f6083SPeter Grehan 
190112a6eb99SNeel Natu static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff;
190212a6eb99SNeel Natu 
190312a6eb99SNeel Natu static int
190412a6eb99SNeel Natu pci_emul_cfgaddr(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
190512a6eb99SNeel Natu 		 uint32_t *eax, void *arg)
190612a6eb99SNeel Natu {
190712a6eb99SNeel Natu 	uint32_t x;
190812a6eb99SNeel Natu 
190912a6eb99SNeel Natu 	if (bytes != 4) {
191012a6eb99SNeel Natu 		if (in)
191112a6eb99SNeel Natu 			*eax = (bytes == 2) ? 0xffff : 0xff;
191212a6eb99SNeel Natu 		return (0);
191312a6eb99SNeel Natu 	}
191412a6eb99SNeel Natu 
191512a6eb99SNeel Natu 	if (in) {
191612a6eb99SNeel Natu 		x = (cfgbus << 16) | (cfgslot << 11) | (cfgfunc << 8) | cfgoff;
191712a6eb99SNeel Natu 		if (cfgenable)
191812a6eb99SNeel Natu 			x |= CONF1_ENABLE;
191912a6eb99SNeel Natu 		*eax = x;
192012a6eb99SNeel Natu 	} else {
192112a6eb99SNeel Natu 		x = *eax;
192212a6eb99SNeel Natu 		cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;
192312a6eb99SNeel Natu 		cfgoff = x & PCI_REGMAX;
192412a6eb99SNeel Natu 		cfgfunc = (x >> 8) & PCI_FUNCMAX;
192512a6eb99SNeel Natu 		cfgslot = (x >> 11) & PCI_SLOTMAX;
192612a6eb99SNeel Natu 		cfgbus = (x >> 16) & PCI_BUSMAX;
192712a6eb99SNeel Natu 	}
192812a6eb99SNeel Natu 
192912a6eb99SNeel Natu 	return (0);
193012a6eb99SNeel Natu }
193112a6eb99SNeel Natu INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_INOUT, pci_emul_cfgaddr);
193212a6eb99SNeel Natu 
193312a6eb99SNeel Natu static int
193412a6eb99SNeel Natu pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
193512a6eb99SNeel Natu 		 uint32_t *eax, void *arg)
193612a6eb99SNeel Natu {
193712a6eb99SNeel Natu 	int coff;
193812a6eb99SNeel Natu 
193912a6eb99SNeel Natu 	assert(bytes == 1 || bytes == 2 || bytes == 4);
194012a6eb99SNeel Natu 
194112a6eb99SNeel Natu 	coff = cfgoff + (port - CONF1_DATA_PORT);
194212a6eb99SNeel Natu 	if (cfgenable) {
194312a6eb99SNeel Natu 		pci_cfgrw(ctx, vcpu, in, cfgbus, cfgslot, cfgfunc, coff, bytes,
194412a6eb99SNeel Natu 		    eax);
194512a6eb99SNeel Natu 	} else {
194612a6eb99SNeel Natu 		/* Ignore accesses to cfgdata if not enabled by cfgaddr */
194712a6eb99SNeel Natu 		if (in)
194812a6eb99SNeel Natu 			*eax = 0xffffffff;
194912a6eb99SNeel Natu 	}
1950366f6083SPeter Grehan 	return (0);
1951366f6083SPeter Grehan }
1952366f6083SPeter Grehan 
1953366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+0, IOPORT_F_INOUT, pci_emul_cfgdata);
1954366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+1, IOPORT_F_INOUT, pci_emul_cfgdata);
1955366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+2, IOPORT_F_INOUT, pci_emul_cfgdata);
1956366f6083SPeter Grehan INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+3, IOPORT_F_INOUT, pci_emul_cfgdata);
1957366f6083SPeter Grehan 
1958366f6083SPeter Grehan #define PCI_EMUL_TEST
1959366f6083SPeter Grehan #ifdef PCI_EMUL_TEST
1960366f6083SPeter Grehan /*
1961366f6083SPeter Grehan  * Define a dummy test device
1962366f6083SPeter Grehan  */
1963d84882caSNeel Natu #define DIOSZ	8
19644d1e669cSPeter Grehan #define DMEMSZ	4096
1965366f6083SPeter Grehan struct pci_emul_dsoftc {
19664d1e669cSPeter Grehan 	uint8_t	  ioregs[DIOSZ];
1967fd4e0d4cSNeel Natu 	uint8_t	  memregs[2][DMEMSZ];
1968366f6083SPeter Grehan };
1969366f6083SPeter Grehan 
19704d1e669cSPeter Grehan #define	PCI_EMUL_MSI_MSGS	 4
19714d1e669cSPeter Grehan #define	PCI_EMUL_MSIX_MSGS	16
1972366f6083SPeter Grehan 
1973b67e81dbSJohn Baldwin static int
1974366f6083SPeter Grehan pci_emul_dinit(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
1975366f6083SPeter Grehan {
1976366f6083SPeter Grehan 	int error;
1977366f6083SPeter Grehan 	struct pci_emul_dsoftc *sc;
1978366f6083SPeter Grehan 
1979994f858aSXin LI 	sc = calloc(1, sizeof(struct pci_emul_dsoftc));
1980366f6083SPeter Grehan 
1981366f6083SPeter Grehan 	pi->pi_arg = sc;
1982366f6083SPeter Grehan 
1983366f6083SPeter Grehan 	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x0001);
1984366f6083SPeter Grehan 	pci_set_cfgdata16(pi, PCIR_VENDOR, 0x10DD);
1985366f6083SPeter Grehan 	pci_set_cfgdata8(pi, PCIR_CLASS, 0x02);
1986366f6083SPeter Grehan 
19874d1e669cSPeter Grehan 	error = pci_emul_add_msicap(pi, PCI_EMUL_MSI_MSGS);
1988366f6083SPeter Grehan 	assert(error == 0);
1989366f6083SPeter Grehan 
19904d1e669cSPeter Grehan 	error = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, DIOSZ);
19914d1e669cSPeter Grehan 	assert(error == 0);
19924d1e669cSPeter Grehan 
19934d1e669cSPeter Grehan 	error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, DMEMSZ);
1994366f6083SPeter Grehan 	assert(error == 0);
1995366f6083SPeter Grehan 
1996fd4e0d4cSNeel Natu 	error = pci_emul_alloc_bar(pi, 2, PCIBAR_MEM32, DMEMSZ);
1997fd4e0d4cSNeel Natu 	assert(error == 0);
1998fd4e0d4cSNeel Natu 
1999366f6083SPeter Grehan 	return (0);
2000366f6083SPeter Grehan }
2001366f6083SPeter Grehan 
2002b67e81dbSJohn Baldwin static void
20034d1e669cSPeter Grehan pci_emul_diow(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
20044d1e669cSPeter Grehan 	      uint64_t offset, int size, uint64_t value)
2005366f6083SPeter Grehan {
2006366f6083SPeter Grehan 	int i;
2007366f6083SPeter Grehan 	struct pci_emul_dsoftc *sc = pi->pi_arg;
2008366f6083SPeter Grehan 
20094d1e669cSPeter Grehan 	if (baridx == 0) {
20104d1e669cSPeter Grehan 		if (offset + size > DIOSZ) {
20114d1e669cSPeter Grehan 			printf("diow: iow too large, offset %ld size %d\n",
20124d1e669cSPeter Grehan 			       offset, size);
2013366f6083SPeter Grehan 			return;
2014366f6083SPeter Grehan 		}
2015366f6083SPeter Grehan 
2016366f6083SPeter Grehan 		if (size == 1) {
20174d1e669cSPeter Grehan 			sc->ioregs[offset] = value & 0xff;
2018366f6083SPeter Grehan 		} else if (size == 2) {
20194d1e669cSPeter Grehan 			*(uint16_t *)&sc->ioregs[offset] = value & 0xffff;
20204d1e669cSPeter Grehan 		} else if (size == 4) {
20214d1e669cSPeter Grehan 			*(uint32_t *)&sc->ioregs[offset] = value;
2022366f6083SPeter Grehan 		} else {
20234d1e669cSPeter Grehan 			printf("diow: iow unknown size %d\n", size);
2024366f6083SPeter Grehan 		}
2025366f6083SPeter Grehan 
2026366f6083SPeter Grehan 		/*
2027366f6083SPeter Grehan 		 * Special magic value to generate an interrupt
2028366f6083SPeter Grehan 		 */
2029366f6083SPeter Grehan 		if (offset == 4 && size == 4 && pci_msi_enabled(pi))
20304f8be175SNeel Natu 			pci_generate_msi(pi, value % pci_msi_maxmsgnum(pi));
2031366f6083SPeter Grehan 
2032366f6083SPeter Grehan 		if (value == 0xabcdef) {
20334f8be175SNeel Natu 			for (i = 0; i < pci_msi_maxmsgnum(pi); i++)
2034366f6083SPeter Grehan 				pci_generate_msi(pi, i);
2035366f6083SPeter Grehan 		}
2036366f6083SPeter Grehan 	}
2037366f6083SPeter Grehan 
2038fd4e0d4cSNeel Natu 	if (baridx == 1 || baridx == 2) {
20394d1e669cSPeter Grehan 		if (offset + size > DMEMSZ) {
20404d1e669cSPeter Grehan 			printf("diow: memw too large, offset %ld size %d\n",
20414d1e669cSPeter Grehan 			       offset, size);
20424d1e669cSPeter Grehan 			return;
20434d1e669cSPeter Grehan 		}
20444d1e669cSPeter Grehan 
2045fd4e0d4cSNeel Natu 		i = baridx - 1;		/* 'memregs' index */
2046fd4e0d4cSNeel Natu 
20474d1e669cSPeter Grehan 		if (size == 1) {
2048fd4e0d4cSNeel Natu 			sc->memregs[i][offset] = value;
20494d1e669cSPeter Grehan 		} else if (size == 2) {
2050fd4e0d4cSNeel Natu 			*(uint16_t *)&sc->memregs[i][offset] = value;
20514d1e669cSPeter Grehan 		} else if (size == 4) {
2052fd4e0d4cSNeel Natu 			*(uint32_t *)&sc->memregs[i][offset] = value;
20534d1e669cSPeter Grehan 		} else if (size == 8) {
2054fd4e0d4cSNeel Natu 			*(uint64_t *)&sc->memregs[i][offset] = value;
20554d1e669cSPeter Grehan 		} else {
20564d1e669cSPeter Grehan 			printf("diow: memw unknown size %d\n", size);
20574d1e669cSPeter Grehan 		}
20584d1e669cSPeter Grehan 
20594d1e669cSPeter Grehan 		/*
20604d1e669cSPeter Grehan 		 * magic interrupt ??
20614d1e669cSPeter Grehan 		 */
20624d1e669cSPeter Grehan 	}
20634d1e669cSPeter Grehan 
20649f3dba68SPedro F. Giffuni 	if (baridx > 2 || baridx < 0) {
20654d1e669cSPeter Grehan 		printf("diow: unknown bar idx %d\n", baridx);
20664d1e669cSPeter Grehan 	}
20674d1e669cSPeter Grehan }
20684d1e669cSPeter Grehan 
20694d1e669cSPeter Grehan static uint64_t
20704d1e669cSPeter Grehan pci_emul_dior(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
20714d1e669cSPeter Grehan 	      uint64_t offset, int size)
2072366f6083SPeter Grehan {
2073366f6083SPeter Grehan 	struct pci_emul_dsoftc *sc = pi->pi_arg;
2074366f6083SPeter Grehan 	uint32_t value;
2075fd4e0d4cSNeel Natu 	int i;
2076366f6083SPeter Grehan 
20774d1e669cSPeter Grehan 	if (baridx == 0) {
20784d1e669cSPeter Grehan 		if (offset + size > DIOSZ) {
20794d1e669cSPeter Grehan 			printf("dior: ior too large, offset %ld size %d\n",
20804d1e669cSPeter Grehan 			       offset, size);
2081366f6083SPeter Grehan 			return (0);
2082366f6083SPeter Grehan 		}
2083366f6083SPeter Grehan 
20846e43f3edSPedro F. Giffuni 		value = 0;
2085366f6083SPeter Grehan 		if (size == 1) {
20864d1e669cSPeter Grehan 			value = sc->ioregs[offset];
2087366f6083SPeter Grehan 		} else if (size == 2) {
20884d1e669cSPeter Grehan 			value = *(uint16_t *) &sc->ioregs[offset];
20894d1e669cSPeter Grehan 		} else if (size == 4) {
20904d1e669cSPeter Grehan 			value = *(uint32_t *) &sc->ioregs[offset];
2091366f6083SPeter Grehan 		} else {
20924d1e669cSPeter Grehan 			printf("dior: ior unknown size %d\n", size);
20934d1e669cSPeter Grehan 		}
20944d1e669cSPeter Grehan 	}
20954d1e669cSPeter Grehan 
2096fd4e0d4cSNeel Natu 	if (baridx == 1 || baridx == 2) {
20974d1e669cSPeter Grehan 		if (offset + size > DMEMSZ) {
20984d1e669cSPeter Grehan 			printf("dior: memr too large, offset %ld size %d\n",
20994d1e669cSPeter Grehan 			       offset, size);
21004d1e669cSPeter Grehan 			return (0);
21014d1e669cSPeter Grehan 		}
21024d1e669cSPeter Grehan 
2103fd4e0d4cSNeel Natu 		i = baridx - 1;		/* 'memregs' index */
2104fd4e0d4cSNeel Natu 
21054d1e669cSPeter Grehan 		if (size == 1) {
2106fd4e0d4cSNeel Natu 			value = sc->memregs[i][offset];
21074d1e669cSPeter Grehan 		} else if (size == 2) {
2108fd4e0d4cSNeel Natu 			value = *(uint16_t *) &sc->memregs[i][offset];
21094d1e669cSPeter Grehan 		} else if (size == 4) {
2110fd4e0d4cSNeel Natu 			value = *(uint32_t *) &sc->memregs[i][offset];
21114d1e669cSPeter Grehan 		} else if (size == 8) {
2112fd4e0d4cSNeel Natu 			value = *(uint64_t *) &sc->memregs[i][offset];
21134d1e669cSPeter Grehan 		} else {
21144d1e669cSPeter Grehan 			printf("dior: ior unknown size %d\n", size);
21154d1e669cSPeter Grehan 		}
21164d1e669cSPeter Grehan 	}
21174d1e669cSPeter Grehan 
21184d1e669cSPeter Grehan 
21199f3dba68SPedro F. Giffuni 	if (baridx > 2 || baridx < 0) {
21204d1e669cSPeter Grehan 		printf("dior: unknown bar idx %d\n", baridx);
21214d1e669cSPeter Grehan 		return (0);
2122366f6083SPeter Grehan 	}
2123366f6083SPeter Grehan 
2124366f6083SPeter Grehan 	return (value);
2125366f6083SPeter Grehan }
2126366f6083SPeter Grehan 
2127366f6083SPeter Grehan struct pci_devemu pci_dummy = {
2128366f6083SPeter Grehan 	.pe_emu = "dummy",
2129366f6083SPeter Grehan 	.pe_init = pci_emul_dinit,
21304d1e669cSPeter Grehan 	.pe_barwrite = pci_emul_diow,
21314d1e669cSPeter Grehan 	.pe_barread = pci_emul_dior
2132366f6083SPeter Grehan };
2133366f6083SPeter Grehan PCI_EMUL_SET(pci_dummy);
2134366f6083SPeter Grehan 
2135366f6083SPeter Grehan #endif /* PCI_EMUL_TEST */
2136