xref: /illumos-gate/usr/src/cmd/bhyve/pci_emul.c (revision 32640292)
1bf21cd93STycho Nightingale /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney  *
4bf21cd93STycho Nightingale  * Copyright (c) 2011 NetApp, Inc.
5bf21cd93STycho Nightingale  * All rights reserved.
6bf21cd93STycho Nightingale  *
7bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
8bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
9bf21cd93STycho Nightingale  * are met:
10bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
11bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
12bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
13bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
14bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
15bf21cd93STycho Nightingale  *
16bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26bf21cd93STycho Nightingale  * SUCH DAMAGE.
27bf21cd93STycho Nightingale  */
28bf21cd93STycho Nightingale /*
29bf21cd93STycho Nightingale  * This file and its contents are supplied under the terms of the
30bf21cd93STycho Nightingale  * Common Development and Distribution License ("CDDL"), version 1.0.
31bf21cd93STycho Nightingale  * You may only use this file in accordance with the terms of version
32bf21cd93STycho Nightingale  * 1.0 of the CDDL.
33bf21cd93STycho Nightingale  *
34bf21cd93STycho Nightingale  * A full copy of the text of the CDDL should have accompanied this
35bf21cd93STycho Nightingale  * source.  A copy of the CDDL is also available via the Internet at
36bf21cd93STycho Nightingale  * http://www.illumos.org/license/CDDL.
37bf21cd93STycho Nightingale  *
38bf21cd93STycho Nightingale  * Copyright 2014 Pluribus Networks Inc.
394c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
40bf21cd93STycho Nightingale  */
41bf21cd93STycho Nightingale 
42bf21cd93STycho Nightingale #include <sys/cdefs.h>
43bf21cd93STycho Nightingale 
44bf21cd93STycho Nightingale #include <sys/param.h>
45bf21cd93STycho Nightingale #include <sys/linker_set.h>
46d7b72f7bSAndy Fiddaman #include <sys/mman.h>
47bf21cd93STycho Nightingale 
48bf21cd93STycho Nightingale #include <ctype.h>
496dc98349SAndy Fiddaman #include <err.h>
504c87aefeSPatrick Mooney #include <errno.h>
51bf21cd93STycho Nightingale #include <pthread.h>
52bf21cd93STycho Nightingale #include <stdio.h>
53bf21cd93STycho Nightingale #include <stdlib.h>
54bf21cd93STycho Nightingale #include <string.h>
55bf21cd93STycho Nightingale #include <strings.h>
56bf21cd93STycho Nightingale #include <assert.h>
57bf21cd93STycho Nightingale #include <stdbool.h>
586dc98349SAndy Fiddaman #include <sysexits.h>
59bf21cd93STycho Nightingale 
60bf21cd93STycho Nightingale #include <machine/vmm.h>
61bf21cd93STycho Nightingale #include <vmmapi.h>
62bf21cd93STycho Nightingale 
63bf21cd93STycho Nightingale #include "acpi.h"
64bf21cd93STycho Nightingale #include "bhyverun.h"
652b948146SAndy Fiddaman #include "config.h"
66154972afSPatrick Mooney #include "debug.h"
67bf21cd93STycho Nightingale #include "inout.h"
68bf21cd93STycho Nightingale #include "ioapic.h"
69bf21cd93STycho Nightingale #include "mem.h"
70bf21cd93STycho Nightingale #include "pci_emul.h"
71bf21cd93STycho Nightingale #include "pci_irq.h"
72bf21cd93STycho Nightingale #include "pci_lpc.h"
73*32640292SAndy Fiddaman #include "pci_passthru.h"
74*32640292SAndy Fiddaman #include "qemu_fwcfg.h"
75bf21cd93STycho Nightingale 
764c87aefeSPatrick Mooney #define CONF1_ADDR_PORT	   0x0cf8
774c87aefeSPatrick Mooney #define CONF1_DATA_PORT	   0x0cfc
78bf21cd93STycho Nightingale 
79bf21cd93STycho Nightingale #define CONF1_ENABLE	   0x80000000ul
80bf21cd93STycho Nightingale 
81bf21cd93STycho Nightingale #define	MAXBUSES	(PCI_BUSMAX + 1)
82bf21cd93STycho Nightingale #define MAXSLOTS	(PCI_SLOTMAX + 1)
83bf21cd93STycho Nightingale #define	MAXFUNCS	(PCI_FUNCMAX + 1)
84bf21cd93STycho Nightingale 
856dc98349SAndy Fiddaman #define	GB		(1024 * 1024 * 1024UL)
866dc98349SAndy Fiddaman 
87bf21cd93STycho Nightingale struct funcinfo {
882b948146SAndy Fiddaman 	nvlist_t *fi_config;
892b948146SAndy Fiddaman 	struct pci_devemu *fi_pde;
90bf21cd93STycho Nightingale 	struct pci_devinst *fi_devi;
91bf21cd93STycho Nightingale };
92bf21cd93STycho Nightingale 
93bf21cd93STycho Nightingale struct intxinfo {
94bf21cd93STycho Nightingale 	int	ii_count;
95bf21cd93STycho Nightingale 	int	ii_pirq_pin;
96bf21cd93STycho Nightingale 	int	ii_ioapic_irq;
97bf21cd93STycho Nightingale };
98bf21cd93STycho Nightingale 
99bf21cd93STycho Nightingale struct slotinfo {
100bf21cd93STycho Nightingale 	struct intxinfo si_intpins[4];
101bf21cd93STycho Nightingale 	struct funcinfo si_funcs[MAXFUNCS];
102bf21cd93STycho Nightingale };
103bf21cd93STycho Nightingale 
104bf21cd93STycho Nightingale struct businfo {
105bf21cd93STycho Nightingale 	uint16_t iobase, iolimit;		/* I/O window */
106bf21cd93STycho Nightingale 	uint32_t membase32, memlimit32;		/* mmio window below 4GB */
107bf21cd93STycho Nightingale 	uint64_t membase64, memlimit64;		/* mmio window above 4GB */
108bf21cd93STycho Nightingale 	struct slotinfo slotinfo[MAXSLOTS];
109bf21cd93STycho Nightingale };
110bf21cd93STycho Nightingale 
111bf21cd93STycho Nightingale static struct businfo *pci_businfo[MAXBUSES];
112bf21cd93STycho Nightingale 
113bf21cd93STycho Nightingale SET_DECLARE(pci_devemu_set, struct pci_devemu);
114bf21cd93STycho Nightingale 
115bf21cd93STycho Nightingale static uint64_t pci_emul_iobase;
116d7b72f7bSAndy Fiddaman static uint8_t *pci_emul_rombase;
117d7b72f7bSAndy Fiddaman static uint64_t pci_emul_romoffset;
118d7b72f7bSAndy Fiddaman static uint8_t *pci_emul_romlim;
119bf21cd93STycho Nightingale static uint64_t pci_emul_membase32;
120bf21cd93STycho Nightingale static uint64_t pci_emul_membase64;
1216dc98349SAndy Fiddaman static uint64_t pci_emul_memlim64;
1226dc98349SAndy Fiddaman 
1236dc98349SAndy Fiddaman struct pci_bar_allocation {
1246dc98349SAndy Fiddaman 	TAILQ_ENTRY(pci_bar_allocation) chain;
1256dc98349SAndy Fiddaman 	struct pci_devinst *pdi;
1266dc98349SAndy Fiddaman 	int idx;
1276dc98349SAndy Fiddaman 	enum pcibar_type type;
1286dc98349SAndy Fiddaman 	uint64_t size;
1296dc98349SAndy Fiddaman };
13059d65d31SAndy Fiddaman 
13159d65d31SAndy Fiddaman static TAILQ_HEAD(pci_bar_list, pci_bar_allocation) pci_bars =
13259d65d31SAndy Fiddaman     TAILQ_HEAD_INITIALIZER(pci_bars);
133bf21cd93STycho Nightingale 
134*32640292SAndy Fiddaman struct boot_device {
135*32640292SAndy Fiddaman 	TAILQ_ENTRY(boot_device) boot_device_chain;
136*32640292SAndy Fiddaman 	struct pci_devinst *pdi;
137*32640292SAndy Fiddaman 	int bootindex;
138*32640292SAndy Fiddaman };
139*32640292SAndy Fiddaman static TAILQ_HEAD(boot_list, boot_device) boot_devices = TAILQ_HEAD_INITIALIZER(
140*32640292SAndy Fiddaman     boot_devices);
141*32640292SAndy Fiddaman 
142bf21cd93STycho Nightingale #define	PCI_EMUL_IOBASE		0x2000
143bf21cd93STycho Nightingale #define	PCI_EMUL_IOLIMIT	0x10000
144bf21cd93STycho Nightingale 
145d7b72f7bSAndy Fiddaman #define PCI_EMUL_ROMSIZE 0x10000000
146d7b72f7bSAndy Fiddaman 
147bf21cd93STycho Nightingale #define	PCI_EMUL_ECFG_BASE	0xE0000000		    /* 3.5GB */
148bf21cd93STycho Nightingale #define	PCI_EMUL_ECFG_SIZE	(MAXBUSES * 1024 * 1024)    /* 1MB per bus */
149bf21cd93STycho Nightingale SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE);
150bf21cd93STycho Nightingale 
1516dc98349SAndy Fiddaman /*
1526dc98349SAndy Fiddaman  * OVMF always uses 0xC0000000 as base address for 32 bit PCI MMIO. Don't
1536dc98349SAndy Fiddaman  * change this address without changing it in OVMF.
1546dc98349SAndy Fiddaman  */
1556dc98349SAndy Fiddaman #define PCI_EMUL_MEMBASE32 0xC0000000
156bf21cd93STycho Nightingale #define	PCI_EMUL_MEMLIMIT32	PCI_EMUL_ECFG_BASE
1576dc98349SAndy Fiddaman #define	PCI_EMUL_MEMSIZE64	(32*GB)
158bf21cd93STycho Nightingale 
1592b948146SAndy Fiddaman static struct pci_devemu *pci_emul_finddev(const char *name);
160bf21cd93STycho Nightingale static void pci_lintr_route(struct pci_devinst *pi);
161bf21cd93STycho Nightingale static void pci_lintr_update(struct pci_devinst *pi);
162*32640292SAndy Fiddaman static void pci_cfgrw(int in, int bus, int slot, int func, int coff,
163*32640292SAndy Fiddaman     int bytes, uint32_t *val);
164bf21cd93STycho Nightingale 
1654c87aefeSPatrick Mooney static __inline void
CFGWRITE(struct pci_devinst * pi,int coff,uint32_t val,int bytes)1664c87aefeSPatrick Mooney CFGWRITE(struct pci_devinst *pi, int coff, uint32_t val, int bytes)
1674c87aefeSPatrick Mooney {
1684c87aefeSPatrick Mooney 
1694c87aefeSPatrick Mooney 	if (bytes == 1)
1704c87aefeSPatrick Mooney 		pci_set_cfgdata8(pi, coff, val);
1714c87aefeSPatrick Mooney 	else if (bytes == 2)
1724c87aefeSPatrick Mooney 		pci_set_cfgdata16(pi, coff, val);
1734c87aefeSPatrick Mooney 	else
1744c87aefeSPatrick Mooney 		pci_set_cfgdata32(pi, coff, val);
1754c87aefeSPatrick Mooney }
1764c87aefeSPatrick Mooney 
1774c87aefeSPatrick Mooney static __inline uint32_t
CFGREAD(struct pci_devinst * pi,int coff,int bytes)1784c87aefeSPatrick Mooney CFGREAD(struct pci_devinst *pi, int coff, int bytes)
1794c87aefeSPatrick Mooney {
1804c87aefeSPatrick Mooney 
1814c87aefeSPatrick Mooney 	if (bytes == 1)
1824c87aefeSPatrick Mooney 		return (pci_get_cfgdata8(pi, coff));
1834c87aefeSPatrick Mooney 	else if (bytes == 2)
1844c87aefeSPatrick Mooney 		return (pci_get_cfgdata16(pi, coff));
1854c87aefeSPatrick Mooney 	else
1864c87aefeSPatrick Mooney 		return (pci_get_cfgdata32(pi, coff));
1874c87aefeSPatrick Mooney }
1884c87aefeSPatrick Mooney 
1894f3f3e9aSAndy Fiddaman static int
is_pcir_bar(int coff)1904f3f3e9aSAndy Fiddaman is_pcir_bar(int coff)
1914f3f3e9aSAndy Fiddaman {
1924f3f3e9aSAndy Fiddaman 	return (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1));
1934f3f3e9aSAndy Fiddaman }
1944f3f3e9aSAndy Fiddaman 
1954f3f3e9aSAndy Fiddaman static int
is_pcir_bios(int coff)1964f3f3e9aSAndy Fiddaman is_pcir_bios(int coff)
1974f3f3e9aSAndy Fiddaman {
1984f3f3e9aSAndy Fiddaman 	return (coff >= PCIR_BIOS && coff < PCIR_BIOS + 4);
1994f3f3e9aSAndy Fiddaman }
2004f3f3e9aSAndy Fiddaman 
201bf21cd93STycho Nightingale /*
202bf21cd93STycho Nightingale  * I/O access
203bf21cd93STycho Nightingale  */
204bf21cd93STycho Nightingale 
205bf21cd93STycho Nightingale /*
206bf21cd93STycho Nightingale  * Slot options are in the form:
207bf21cd93STycho Nightingale  *
208bf21cd93STycho Nightingale  *  <bus>:<slot>:<func>,<emul>[,<config>]
209bf21cd93STycho Nightingale  *  <slot>[:<func>],<emul>[,<config>]
210bf21cd93STycho Nightingale  *
211bf21cd93STycho Nightingale  *  slot is 0..31
212bf21cd93STycho Nightingale  *  func is 0..7
213bf21cd93STycho Nightingale  *  emul is a string describing the type of PCI device e.g. virtio-net
214bf21cd93STycho Nightingale  *  config is an optional string, depending on the device, that can be
215bf21cd93STycho Nightingale  *  used for configuration.
216bf21cd93STycho Nightingale  *   Examples are:
217bf21cd93STycho Nightingale  *     1,virtio-net,tap0
218bf21cd93STycho Nightingale  *     3:0,dummy
219bf21cd93STycho Nightingale  */
220bf21cd93STycho Nightingale static void
pci_parse_slot_usage(char * aopt)221bf21cd93STycho Nightingale pci_parse_slot_usage(char *aopt)
222bf21cd93STycho Nightingale {
223bf21cd93STycho Nightingale 
224154972afSPatrick Mooney 	EPRINTLN("Invalid PCI slot info field \"%s\"", aopt);
225bf21cd93STycho Nightingale }
226bf21cd93STycho Nightingale 
2272b948146SAndy Fiddaman /*
2282b948146SAndy Fiddaman  * Helper function to parse a list of comma-separated options where
2292b948146SAndy Fiddaman  * each option is formatted as "name[=value]".  If no value is
2302b948146SAndy Fiddaman  * provided, the option is treated as a boolean and is given a value
2312b948146SAndy Fiddaman  * of true.
2322b948146SAndy Fiddaman  */
2332b948146SAndy Fiddaman int
pci_parse_legacy_config(nvlist_t * nvl,const char * opt)2342b948146SAndy Fiddaman pci_parse_legacy_config(nvlist_t *nvl, const char *opt)
2352b948146SAndy Fiddaman {
2362b948146SAndy Fiddaman 	char *config, *name, *tofree, *value;
2372b948146SAndy Fiddaman 
2382b948146SAndy Fiddaman 	if (opt == NULL)
2392b948146SAndy Fiddaman 		return (0);
2402b948146SAndy Fiddaman 
2412b948146SAndy Fiddaman 	config = tofree = strdup(opt);
2422b948146SAndy Fiddaman 	while ((name = strsep(&config, ",")) != NULL) {
2432b948146SAndy Fiddaman 		value = strchr(name, '=');
2442b948146SAndy Fiddaman 		if (value != NULL) {
2452b948146SAndy Fiddaman 			*value = '\0';
2462b948146SAndy Fiddaman 			value++;
2472b948146SAndy Fiddaman 			set_config_value_node(nvl, name, value);
2482b948146SAndy Fiddaman 		} else
2492b948146SAndy Fiddaman 			set_config_bool_node(nvl, name, true);
2502b948146SAndy Fiddaman 	}
2512b948146SAndy Fiddaman 	free(tofree);
2522b948146SAndy Fiddaman 	return (0);
2532b948146SAndy Fiddaman }
2542b948146SAndy Fiddaman 
2552b948146SAndy Fiddaman /*
2562b948146SAndy Fiddaman  * PCI device configuration is stored in MIBs that encode the device's
2572b948146SAndy Fiddaman  * location:
2582b948146SAndy Fiddaman  *
2592b948146SAndy Fiddaman  * pci.<bus>.<slot>.<func>
2602b948146SAndy Fiddaman  *
2612b948146SAndy Fiddaman  * Where "bus", "slot", and "func" are all decimal values without
2622b948146SAndy Fiddaman  * leading zeroes.  Each valid device must have a "device" node which
2632b948146SAndy Fiddaman  * identifies the driver model of the device.
2642b948146SAndy Fiddaman  *
2652b948146SAndy Fiddaman  * Device backends can provide a parser for the "config" string.  If
2662b948146SAndy Fiddaman  * a custom parser is not provided, pci_parse_legacy_config() is used
2672b948146SAndy Fiddaman  * to parse the string.
2682b948146SAndy Fiddaman  */
269bf21cd93STycho Nightingale int
pci_parse_slot(char * opt)270bf21cd93STycho Nightingale pci_parse_slot(char *opt)
271bf21cd93STycho Nightingale {
2722b948146SAndy Fiddaman 	char node_name[sizeof("pci.XXX.XX.X")];
2732b948146SAndy Fiddaman 	struct pci_devemu *pde;
274bf21cd93STycho Nightingale 	char *emul, *config, *str, *cp;
275bf21cd93STycho Nightingale 	int error, bnum, snum, fnum;
2762b948146SAndy Fiddaman 	nvlist_t *nvl;
277bf21cd93STycho Nightingale 
278bf21cd93STycho Nightingale 	error = -1;
279bf21cd93STycho Nightingale 	str = strdup(opt);
280bf21cd93STycho Nightingale 
281bf21cd93STycho Nightingale 	emul = config = NULL;
282bf21cd93STycho Nightingale 	if ((cp = strchr(str, ',')) != NULL) {
283bf21cd93STycho Nightingale 		*cp = '\0';
284bf21cd93STycho Nightingale 		emul = cp + 1;
285bf21cd93STycho Nightingale 		if ((cp = strchr(emul, ',')) != NULL) {
286bf21cd93STycho Nightingale 			*cp = '\0';
287bf21cd93STycho Nightingale 			config = cp + 1;
288bf21cd93STycho Nightingale 		}
289bf21cd93STycho Nightingale 	} else {
290bf21cd93STycho Nightingale 		pci_parse_slot_usage(opt);
291bf21cd93STycho Nightingale 		goto done;
292bf21cd93STycho Nightingale 	}
293bf21cd93STycho Nightingale 
294bf21cd93STycho Nightingale 	/* <bus>:<slot>:<func> */
295bf21cd93STycho Nightingale 	if (sscanf(str, "%d:%d:%d", &bnum, &snum, &fnum) != 3) {
296bf21cd93STycho Nightingale 		bnum = 0;
297bf21cd93STycho Nightingale 		/* <slot>:<func> */
298bf21cd93STycho Nightingale 		if (sscanf(str, "%d:%d", &snum, &fnum) != 2) {
299bf21cd93STycho Nightingale 			fnum = 0;
300bf21cd93STycho Nightingale 			/* <slot> */
301bf21cd93STycho Nightingale 			if (sscanf(str, "%d", &snum) != 1) {
302bf21cd93STycho Nightingale 				snum = -1;
303bf21cd93STycho Nightingale 			}
304bf21cd93STycho Nightingale 		}
305bf21cd93STycho Nightingale 	}
306bf21cd93STycho Nightingale 
307bf21cd93STycho Nightingale 	if (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS ||
308bf21cd93STycho Nightingale 	    fnum < 0 || fnum >= MAXFUNCS) {
309bf21cd93STycho Nightingale 		pci_parse_slot_usage(opt);
310bf21cd93STycho Nightingale 		goto done;
311bf21cd93STycho Nightingale 	}
312bf21cd93STycho Nightingale 
3132b948146SAndy Fiddaman 	pde = pci_emul_finddev(emul);
3142b948146SAndy Fiddaman 	if (pde == NULL) {
3152b948146SAndy Fiddaman 		EPRINTLN("pci slot %d:%d:%d: unknown device \"%s\"", bnum, snum,
3162b948146SAndy Fiddaman 		    fnum, emul);
317bf21cd93STycho Nightingale 		goto done;
318bf21cd93STycho Nightingale 	}
319bf21cd93STycho Nightingale 
3202b948146SAndy Fiddaman 	snprintf(node_name, sizeof(node_name), "pci.%d.%d.%d", bnum, snum,
3212b948146SAndy Fiddaman 	    fnum);
3222b948146SAndy Fiddaman 	nvl = find_config_node(node_name);
3232b948146SAndy Fiddaman 	if (nvl != NULL) {
3242b948146SAndy Fiddaman 		EPRINTLN("pci slot %d:%d:%d already occupied!", bnum, snum,
3252b948146SAndy Fiddaman 		    fnum);
326bf21cd93STycho Nightingale 		goto done;
327bf21cd93STycho Nightingale 	}
3282b948146SAndy Fiddaman 	nvl = create_config_node(node_name);
3292b948146SAndy Fiddaman 	if (pde->pe_alias != NULL)
3302b948146SAndy Fiddaman 		set_config_value_node(nvl, "device", pde->pe_alias);
3312b948146SAndy Fiddaman 	else
3322b948146SAndy Fiddaman 		set_config_value_node(nvl, "device", pde->pe_emu);
333bf21cd93STycho Nightingale 
3342b948146SAndy Fiddaman 	if (pde->pe_legacy_config != NULL)
3352b948146SAndy Fiddaman 		error = pde->pe_legacy_config(nvl, config);
3362b948146SAndy Fiddaman 	else
3372b948146SAndy Fiddaman 		error = pci_parse_legacy_config(nvl, config);
338bf21cd93STycho Nightingale done:
3392b948146SAndy Fiddaman 	free(str);
340bf21cd93STycho Nightingale 	return (error);
341bf21cd93STycho Nightingale }
342bf21cd93STycho Nightingale 
3434c87aefeSPatrick Mooney void
pci_print_supported_devices(void)3444f3f3e9aSAndy Fiddaman pci_print_supported_devices(void)
3454c87aefeSPatrick Mooney {
3464c87aefeSPatrick Mooney 	struct pci_devemu **pdpp, *pdp;
3474c87aefeSPatrick Mooney 
3484c87aefeSPatrick Mooney 	SET_FOREACH(pdpp, pci_devemu_set) {
3494c87aefeSPatrick Mooney 		pdp = *pdpp;
3504c87aefeSPatrick Mooney 		printf("%s\n", pdp->pe_emu);
3514c87aefeSPatrick Mooney 	}
3524c87aefeSPatrick Mooney }
3534c87aefeSPatrick Mooney 
354*32640292SAndy Fiddaman uint32_t
pci_config_read_reg(const struct pcisel * const host_sel,nvlist_t * nvl,const uint32_t reg,const uint8_t size,const uint32_t def)355*32640292SAndy Fiddaman pci_config_read_reg(const struct pcisel *const host_sel, nvlist_t *nvl,
356*32640292SAndy Fiddaman     const uint32_t reg, const uint8_t size, const uint32_t def)
357*32640292SAndy Fiddaman {
358*32640292SAndy Fiddaman 	const char *config;
359*32640292SAndy Fiddaman 	const nvlist_t *pci_regs;
360*32640292SAndy Fiddaman 
361*32640292SAndy Fiddaman 	assert(size == 1 || size == 2 || size == 4);
362*32640292SAndy Fiddaman 
363*32640292SAndy Fiddaman 	pci_regs = find_relative_config_node(nvl, "pcireg");
364*32640292SAndy Fiddaman 	if (pci_regs == NULL) {
365*32640292SAndy Fiddaman 		return def;
366*32640292SAndy Fiddaman 	}
367*32640292SAndy Fiddaman 
368*32640292SAndy Fiddaman 	switch (reg) {
369*32640292SAndy Fiddaman 	case PCIR_DEVICE:
370*32640292SAndy Fiddaman 		config = get_config_value_node(pci_regs, "device");
371*32640292SAndy Fiddaman 		break;
372*32640292SAndy Fiddaman 	case PCIR_VENDOR:
373*32640292SAndy Fiddaman 		config = get_config_value_node(pci_regs, "vendor");
374*32640292SAndy Fiddaman 		break;
375*32640292SAndy Fiddaman 	case PCIR_REVID:
376*32640292SAndy Fiddaman 		config = get_config_value_node(pci_regs, "revid");
377*32640292SAndy Fiddaman 		break;
378*32640292SAndy Fiddaman 	case PCIR_SUBVEND_0:
379*32640292SAndy Fiddaman 		config = get_config_value_node(pci_regs, "subvendor");
380*32640292SAndy Fiddaman 		break;
381*32640292SAndy Fiddaman 	case PCIR_SUBDEV_0:
382*32640292SAndy Fiddaman 		config = get_config_value_node(pci_regs, "subdevice");
383*32640292SAndy Fiddaman 		break;
384*32640292SAndy Fiddaman 	default:
385*32640292SAndy Fiddaman 		return (-1);
386*32640292SAndy Fiddaman 	}
387*32640292SAndy Fiddaman 
388*32640292SAndy Fiddaman 	if (config == NULL) {
389*32640292SAndy Fiddaman 		return def;
390*32640292SAndy Fiddaman 	} else if (host_sel != NULL && strcmp(config, "host") == 0) {
391*32640292SAndy Fiddaman 		return read_config(host_sel, reg, size);
392*32640292SAndy Fiddaman 	} else {
393*32640292SAndy Fiddaman 		return strtol(config, NULL, 16);
394*32640292SAndy Fiddaman 	}
395*32640292SAndy Fiddaman }
396*32640292SAndy Fiddaman 
397bf21cd93STycho Nightingale static int
pci_valid_pba_offset(struct pci_devinst * pi,uint64_t offset)398bf21cd93STycho Nightingale pci_valid_pba_offset(struct pci_devinst *pi, uint64_t offset)
399bf21cd93STycho Nightingale {
400bf21cd93STycho Nightingale 
401bf21cd93STycho Nightingale 	if (offset < pi->pi_msix.pba_offset)
402bf21cd93STycho Nightingale 		return (0);
403bf21cd93STycho Nightingale 
404bf21cd93STycho Nightingale 	if (offset >= pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
405bf21cd93STycho Nightingale 		return (0);
406bf21cd93STycho Nightingale 	}
407bf21cd93STycho Nightingale 
408bf21cd93STycho Nightingale 	return (1);
409bf21cd93STycho Nightingale }
410bf21cd93STycho Nightingale 
411bf21cd93STycho Nightingale int
pci_emul_msix_twrite(struct pci_devinst * pi,uint64_t offset,int size,uint64_t value)412bf21cd93STycho Nightingale pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,
413bf21cd93STycho Nightingale 		     uint64_t value)
414bf21cd93STycho Nightingale {
415bf21cd93STycho Nightingale 	int msix_entry_offset;
416bf21cd93STycho Nightingale 	int tab_index;
417bf21cd93STycho Nightingale 	char *dest;
418bf21cd93STycho Nightingale 
419bf21cd93STycho Nightingale 	/* support only 4 or 8 byte writes */
420bf21cd93STycho Nightingale 	if (size != 4 && size != 8)
421bf21cd93STycho Nightingale 		return (-1);
422bf21cd93STycho Nightingale 
423bf21cd93STycho Nightingale 	/*
424bf21cd93STycho Nightingale 	 * Return if table index is beyond what device supports
425bf21cd93STycho Nightingale 	 */
426bf21cd93STycho Nightingale 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
427bf21cd93STycho Nightingale 	if (tab_index >= pi->pi_msix.table_count)
428bf21cd93STycho Nightingale 		return (-1);
429bf21cd93STycho Nightingale 
430bf21cd93STycho Nightingale 	msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
431bf21cd93STycho Nightingale 
432bf21cd93STycho Nightingale 	/* support only aligned writes */
433bf21cd93STycho Nightingale 	if ((msix_entry_offset % size) != 0)
434bf21cd93STycho Nightingale 		return (-1);
435bf21cd93STycho Nightingale 
436bf21cd93STycho Nightingale 	dest = (char *)(pi->pi_msix.table + tab_index);
437bf21cd93STycho Nightingale 	dest += msix_entry_offset;
438bf21cd93STycho Nightingale 
439bf21cd93STycho Nightingale 	if (size == 4)
440bf21cd93STycho Nightingale 		*((uint32_t *)dest) = value;
441bf21cd93STycho Nightingale 	else
442bf21cd93STycho Nightingale 		*((uint64_t *)dest) = value;
443bf21cd93STycho Nightingale 
444bf21cd93STycho Nightingale 	return (0);
445bf21cd93STycho Nightingale }
446bf21cd93STycho Nightingale 
447bf21cd93STycho Nightingale uint64_t
pci_emul_msix_tread(struct pci_devinst * pi,uint64_t offset,int size)448bf21cd93STycho Nightingale pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size)
449bf21cd93STycho Nightingale {
450bf21cd93STycho Nightingale 	char *dest;
451bf21cd93STycho Nightingale 	int msix_entry_offset;
452bf21cd93STycho Nightingale 	int tab_index;
453bf21cd93STycho Nightingale 	uint64_t retval = ~0;
454bf21cd93STycho Nightingale 
455bf21cd93STycho Nightingale 	/*
456bf21cd93STycho Nightingale 	 * The PCI standard only allows 4 and 8 byte accesses to the MSI-X
4574c87aefeSPatrick Mooney 	 * table but we also allow 1 byte access to accommodate reads from
458bf21cd93STycho Nightingale 	 * ddb.
459bf21cd93STycho Nightingale 	 */
460bf21cd93STycho Nightingale 	if (size != 1 && size != 4 && size != 8)
461bf21cd93STycho Nightingale 		return (retval);
462bf21cd93STycho Nightingale 
463bf21cd93STycho Nightingale 	msix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
464bf21cd93STycho Nightingale 
465bf21cd93STycho Nightingale 	/* support only aligned reads */
466bf21cd93STycho Nightingale 	if ((msix_entry_offset % size) != 0) {
467bf21cd93STycho Nightingale 		return (retval);
468bf21cd93STycho Nightingale 	}
469bf21cd93STycho Nightingale 
470bf21cd93STycho Nightingale 	tab_index = offset / MSIX_TABLE_ENTRY_SIZE;
471bf21cd93STycho Nightingale 
472bf21cd93STycho Nightingale 	if (tab_index < pi->pi_msix.table_count) {
473bf21cd93STycho Nightingale 		/* valid MSI-X Table access */
474bf21cd93STycho Nightingale 		dest = (char *)(pi->pi_msix.table + tab_index);
475bf21cd93STycho Nightingale 		dest += msix_entry_offset;
476bf21cd93STycho Nightingale 
477bf21cd93STycho Nightingale 		if (size == 1)
478bf21cd93STycho Nightingale 			retval = *((uint8_t *)dest);
479bf21cd93STycho Nightingale 		else if (size == 4)
480bf21cd93STycho Nightingale 			retval = *((uint32_t *)dest);
481bf21cd93STycho Nightingale 		else
482bf21cd93STycho Nightingale 			retval = *((uint64_t *)dest);
483bf21cd93STycho Nightingale 	} else if (pci_valid_pba_offset(pi, offset)) {
484bf21cd93STycho Nightingale 		/* return 0 for PBA access */
485bf21cd93STycho Nightingale 		retval = 0;
486bf21cd93STycho Nightingale 	}
487bf21cd93STycho Nightingale 
488bf21cd93STycho Nightingale 	return (retval);
489bf21cd93STycho Nightingale }
490bf21cd93STycho Nightingale 
491bf21cd93STycho Nightingale int
pci_msix_table_bar(struct pci_devinst * pi)492bf21cd93STycho Nightingale pci_msix_table_bar(struct pci_devinst *pi)
493bf21cd93STycho Nightingale {
494bf21cd93STycho Nightingale 
495bf21cd93STycho Nightingale 	if (pi->pi_msix.table != NULL)
496bf21cd93STycho Nightingale 		return (pi->pi_msix.table_bar);
497bf21cd93STycho Nightingale 	else
498bf21cd93STycho Nightingale 		return (-1);
499bf21cd93STycho Nightingale }
500bf21cd93STycho Nightingale 
501bf21cd93STycho Nightingale int
pci_msix_pba_bar(struct pci_devinst * pi)502bf21cd93STycho Nightingale pci_msix_pba_bar(struct pci_devinst *pi)
503bf21cd93STycho Nightingale {
504bf21cd93STycho Nightingale 
505bf21cd93STycho Nightingale 	if (pi->pi_msix.table != NULL)
506bf21cd93STycho Nightingale 		return (pi->pi_msix.pba_bar);
507bf21cd93STycho Nightingale 	else
508bf21cd93STycho Nightingale 		return (-1);
509bf21cd93STycho Nightingale }
510bf21cd93STycho Nightingale 
511bf21cd93STycho Nightingale static int
pci_emul_io_handler(struct vmctx * ctx __unused,int in,int port,int bytes,uint32_t * eax,void * arg)512*32640292SAndy Fiddaman pci_emul_io_handler(struct vmctx *ctx __unused, int in, int port,
51359d65d31SAndy Fiddaman     int bytes, uint32_t *eax, void *arg)
514bf21cd93STycho Nightingale {
515bf21cd93STycho Nightingale 	struct pci_devinst *pdi = arg;
516bf21cd93STycho Nightingale 	struct pci_devemu *pe = pdi->pi_d;
517bf21cd93STycho Nightingale 	uint64_t offset;
518bf21cd93STycho Nightingale 	int i;
519bf21cd93STycho Nightingale 
52059d65d31SAndy Fiddaman 	assert(port >= 0);
52159d65d31SAndy Fiddaman 
522bf21cd93STycho Nightingale 	for (i = 0; i <= PCI_BARMAX; i++) {
523bf21cd93STycho Nightingale 		if (pdi->pi_bar[i].type == PCIBAR_IO &&
52459d65d31SAndy Fiddaman 		    (uint64_t)port >= pdi->pi_bar[i].addr &&
52559d65d31SAndy Fiddaman 		    (uint64_t)port + bytes <=
52659d65d31SAndy Fiddaman 		    pdi->pi_bar[i].addr + pdi->pi_bar[i].size) {
527bf21cd93STycho Nightingale 			offset = port - pdi->pi_bar[i].addr;
528bf21cd93STycho Nightingale 			if (in)
529*32640292SAndy Fiddaman 				*eax = (*pe->pe_barread)(pdi, i,
530bf21cd93STycho Nightingale 							 offset, bytes);
531bf21cd93STycho Nightingale 			else
532*32640292SAndy Fiddaman 				(*pe->pe_barwrite)(pdi, i, offset,
533bf21cd93STycho Nightingale 						   bytes, *eax);
534bf21cd93STycho Nightingale 			return (0);
535bf21cd93STycho Nightingale 		}
536bf21cd93STycho Nightingale 	}
537bf21cd93STycho Nightingale 	return (-1);
538bf21cd93STycho Nightingale }
539bf21cd93STycho Nightingale 
540bf21cd93STycho Nightingale static int
pci_emul_mem_handler(struct vcpu * vcpu __unused,int dir,uint64_t addr,int size,uint64_t * val,void * arg1,long arg2)541*32640292SAndy Fiddaman pci_emul_mem_handler(struct vcpu *vcpu __unused, int dir,
54259d65d31SAndy Fiddaman     uint64_t addr, int size, uint64_t *val, void *arg1, long arg2)
543bf21cd93STycho Nightingale {
544bf21cd93STycho Nightingale 	struct pci_devinst *pdi = arg1;
545bf21cd93STycho Nightingale 	struct pci_devemu *pe = pdi->pi_d;
546bf21cd93STycho Nightingale 	uint64_t offset;
547bf21cd93STycho Nightingale 	int bidx = (int) arg2;
548bf21cd93STycho Nightingale 
549bf21cd93STycho Nightingale 	assert(bidx <= PCI_BARMAX);
550bf21cd93STycho Nightingale 	assert(pdi->pi_bar[bidx].type == PCIBAR_MEM32 ||
551bf21cd93STycho Nightingale 	       pdi->pi_bar[bidx].type == PCIBAR_MEM64);
552bf21cd93STycho Nightingale 	assert(addr >= pdi->pi_bar[bidx].addr &&
553bf21cd93STycho Nightingale 	       addr + size <= pdi->pi_bar[bidx].addr + pdi->pi_bar[bidx].size);
554bf21cd93STycho Nightingale 
555bf21cd93STycho Nightingale 	offset = addr - pdi->pi_bar[bidx].addr;
556bf21cd93STycho Nightingale 
557bf21cd93STycho Nightingale 	if (dir == MEM_F_WRITE) {
558bf21cd93STycho Nightingale 		if (size == 8) {
559*32640292SAndy Fiddaman 			(*pe->pe_barwrite)(pdi, bidx, offset,
560bf21cd93STycho Nightingale 					   4, *val & 0xffffffff);
561*32640292SAndy Fiddaman 			(*pe->pe_barwrite)(pdi, bidx, offset + 4,
562bf21cd93STycho Nightingale 					   4, *val >> 32);
563bf21cd93STycho Nightingale 		} else {
564*32640292SAndy Fiddaman 			(*pe->pe_barwrite)(pdi, bidx, offset,
565bf21cd93STycho Nightingale 					   size, *val);
566bf21cd93STycho Nightingale 		}
567bf21cd93STycho Nightingale 	} else {
568bf21cd93STycho Nightingale 		if (size == 8) {
569*32640292SAndy Fiddaman 			*val = (*pe->pe_barread)(pdi, bidx,
570bf21cd93STycho Nightingale 						 offset, 4);
571*32640292SAndy Fiddaman 			*val |= (*pe->pe_barread)(pdi, bidx,
572bf21cd93STycho Nightingale 						  offset + 4, 4) << 32;
573bf21cd93STycho Nightingale 		} else {
574*32640292SAndy Fiddaman 			*val = (*pe->pe_barread)(pdi, bidx,
575bf21cd93STycho Nightingale 						 offset, size);
576bf21cd93STycho Nightingale 		}
577bf21cd93STycho Nightingale 	}
578bf21cd93STycho Nightingale 
579bf21cd93STycho Nightingale 	return (0);
580bf21cd93STycho Nightingale }
581bf21cd93STycho Nightingale 
582bf21cd93STycho Nightingale 
583bf21cd93STycho Nightingale static int
pci_emul_alloc_resource(uint64_t * baseptr,uint64_t limit,uint64_t size,uint64_t * addr)584bf21cd93STycho Nightingale pci_emul_alloc_resource(uint64_t *baseptr, uint64_t limit, uint64_t size,
585bf21cd93STycho Nightingale 			uint64_t *addr)
586bf21cd93STycho Nightingale {
587bf21cd93STycho Nightingale 	uint64_t base;
588bf21cd93STycho Nightingale 
589bf21cd93STycho Nightingale 	assert((size & (size - 1)) == 0);	/* must be a power of 2 */
590bf21cd93STycho Nightingale 
591bf21cd93STycho Nightingale 	base = roundup2(*baseptr, size);
592bf21cd93STycho Nightingale 
593bf21cd93STycho Nightingale 	if (base + size <= limit) {
594bf21cd93STycho Nightingale 		*addr = base;
595bf21cd93STycho Nightingale 		*baseptr = base + size;
596bf21cd93STycho Nightingale 		return (0);
597bf21cd93STycho Nightingale 	} else
598bf21cd93STycho Nightingale 		return (-1);
599bf21cd93STycho Nightingale }
600bf21cd93STycho Nightingale 
601bf21cd93STycho Nightingale /*
602bf21cd93STycho Nightingale  * Register (or unregister) the MMIO or I/O region associated with the BAR
603bf21cd93STycho Nightingale  * register 'idx' of an emulated pci device.
604bf21cd93STycho Nightingale  */
605bf21cd93STycho Nightingale static void
modify_bar_registration(struct pci_devinst * pi,int idx,int registration)606bf21cd93STycho Nightingale modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
607bf21cd93STycho Nightingale {
6082b948146SAndy Fiddaman 	struct pci_devemu *pe;
609bf21cd93STycho Nightingale 	int error;
610bf21cd93STycho Nightingale 	struct inout_port iop;
611bf21cd93STycho Nightingale 	struct mem_range mr;
612bf21cd93STycho Nightingale 
6132b948146SAndy Fiddaman 	pe = pi->pi_d;
614bf21cd93STycho Nightingale 	switch (pi->pi_bar[idx].type) {
615bf21cd93STycho Nightingale 	case PCIBAR_IO:
616bf21cd93STycho Nightingale 		bzero(&iop, sizeof(struct inout_port));
617bf21cd93STycho Nightingale 		iop.name = pi->pi_name;
618bf21cd93STycho Nightingale 		iop.port = pi->pi_bar[idx].addr;
619bf21cd93STycho Nightingale 		iop.size = pi->pi_bar[idx].size;
620bf21cd93STycho Nightingale 		if (registration) {
621bf21cd93STycho Nightingale 			iop.flags = IOPORT_F_INOUT;
622bf21cd93STycho Nightingale 			iop.handler = pci_emul_io_handler;
623bf21cd93STycho Nightingale 			iop.arg = pi;
624bf21cd93STycho Nightingale 			error = register_inout(&iop);
6254c87aefeSPatrick Mooney 		} else
626bf21cd93STycho Nightingale 			error = unregister_inout(&iop);
627bf21cd93STycho Nightingale 		break;
628bf21cd93STycho Nightingale 	case PCIBAR_MEM32:
629bf21cd93STycho Nightingale 	case PCIBAR_MEM64:
630bf21cd93STycho Nightingale 		bzero(&mr, sizeof(struct mem_range));
631bf21cd93STycho Nightingale 		mr.name = pi->pi_name;
632bf21cd93STycho Nightingale 		mr.base = pi->pi_bar[idx].addr;
633bf21cd93STycho Nightingale 		mr.size = pi->pi_bar[idx].size;
634bf21cd93STycho Nightingale 		if (registration) {
635bf21cd93STycho Nightingale 			mr.flags = MEM_F_RW;
636bf21cd93STycho Nightingale 			mr.handler = pci_emul_mem_handler;
637bf21cd93STycho Nightingale 			mr.arg1 = pi;
638bf21cd93STycho Nightingale 			mr.arg2 = idx;
639bf21cd93STycho Nightingale 			error = register_mem(&mr);
640bf21cd93STycho Nightingale 		} else
641bf21cd93STycho Nightingale 			error = unregister_mem(&mr);
642bf21cd93STycho Nightingale 		break;
643d7b72f7bSAndy Fiddaman 	case PCIBAR_ROM:
644d7b72f7bSAndy Fiddaman 		error = 0;
645d7b72f7bSAndy Fiddaman 		break;
646bf21cd93STycho Nightingale 	default:
647bf21cd93STycho Nightingale 		error = EINVAL;
648bf21cd93STycho Nightingale 		break;
649bf21cd93STycho Nightingale 	}
650bf21cd93STycho Nightingale 	assert(error == 0);
651*32640292SAndy Fiddaman 
652*32640292SAndy Fiddaman 	if (pe->pe_baraddr != NULL)
653*32640292SAndy Fiddaman 		(*pe->pe_baraddr)(pi, idx, registration, pi->pi_bar[idx].addr);
654bf21cd93STycho Nightingale }
655bf21cd93STycho Nightingale 
656bf21cd93STycho Nightingale static void
unregister_bar(struct pci_devinst * pi,int idx)657bf21cd93STycho Nightingale unregister_bar(struct pci_devinst *pi, int idx)
658bf21cd93STycho Nightingale {
659bf21cd93STycho Nightingale 
660bf21cd93STycho Nightingale 	modify_bar_registration(pi, idx, 0);
661bf21cd93STycho Nightingale }
662bf21cd93STycho Nightingale 
663bf21cd93STycho Nightingale static void
register_bar(struct pci_devinst * pi,int idx)664bf21cd93STycho Nightingale register_bar(struct pci_devinst *pi, int idx)
665bf21cd93STycho Nightingale {
666bf21cd93STycho Nightingale 
667bf21cd93STycho Nightingale 	modify_bar_registration(pi, idx, 1);
668bf21cd93STycho Nightingale }
669bf21cd93STycho Nightingale 
670d7b72f7bSAndy Fiddaman /* Is the ROM enabled for the emulated pci device? */
671d7b72f7bSAndy Fiddaman static int
romen(struct pci_devinst * pi)672d7b72f7bSAndy Fiddaman romen(struct pci_devinst *pi)
673d7b72f7bSAndy Fiddaman {
674d7b72f7bSAndy Fiddaman 	return (pi->pi_bar[PCI_ROM_IDX].lobits & PCIM_BIOS_ENABLE) ==
675d7b72f7bSAndy Fiddaman 	    PCIM_BIOS_ENABLE;
676d7b72f7bSAndy Fiddaman }
677d7b72f7bSAndy Fiddaman 
678bf21cd93STycho Nightingale /* Are we decoding i/o port accesses for the emulated pci device? */
679bf21cd93STycho Nightingale static int
porten(struct pci_devinst * pi)680bf21cd93STycho Nightingale porten(struct pci_devinst *pi)
681bf21cd93STycho Nightingale {
682bf21cd93STycho Nightingale 	uint16_t cmd;
683bf21cd93STycho Nightingale 
684bf21cd93STycho Nightingale 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
685bf21cd93STycho Nightingale 
686bf21cd93STycho Nightingale 	return (cmd & PCIM_CMD_PORTEN);
687bf21cd93STycho Nightingale }
688bf21cd93STycho Nightingale 
689bf21cd93STycho Nightingale /* Are we decoding memory accesses for the emulated pci device? */
690bf21cd93STycho Nightingale static int
memen(struct pci_devinst * pi)691bf21cd93STycho Nightingale memen(struct pci_devinst *pi)
692bf21cd93STycho Nightingale {
693bf21cd93STycho Nightingale 	uint16_t cmd;
694bf21cd93STycho Nightingale 
695bf21cd93STycho Nightingale 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
696bf21cd93STycho Nightingale 
697bf21cd93STycho Nightingale 	return (cmd & PCIM_CMD_MEMEN);
698bf21cd93STycho Nightingale }
699bf21cd93STycho Nightingale 
700bf21cd93STycho Nightingale /*
701bf21cd93STycho Nightingale  * Update the MMIO or I/O address that is decoded by the BAR register.
702bf21cd93STycho Nightingale  *
703bf21cd93STycho Nightingale  * If the pci device has enabled the address space decoding then intercept
704bf21cd93STycho Nightingale  * the address range decoded by the BAR register.
705bf21cd93STycho Nightingale  */
706bf21cd93STycho Nightingale static void
update_bar_address(struct pci_devinst * pi,uint64_t addr,int idx,int type)7074c87aefeSPatrick Mooney update_bar_address(struct pci_devinst *pi, uint64_t addr, int idx, int type)
708bf21cd93STycho Nightingale {
709bf21cd93STycho Nightingale 	int decode;
710bf21cd93STycho Nightingale 
711bf21cd93STycho Nightingale 	if (pi->pi_bar[idx].type == PCIBAR_IO)
712bf21cd93STycho Nightingale 		decode = porten(pi);
713bf21cd93STycho Nightingale 	else
714bf21cd93STycho Nightingale 		decode = memen(pi);
715bf21cd93STycho Nightingale 
716bf21cd93STycho Nightingale 	if (decode)
717bf21cd93STycho Nightingale 		unregister_bar(pi, idx);
718bf21cd93STycho Nightingale 
719bf21cd93STycho Nightingale 	switch (type) {
720bf21cd93STycho Nightingale 	case PCIBAR_IO:
721bf21cd93STycho Nightingale 	case PCIBAR_MEM32:
722bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr = addr;
723bf21cd93STycho Nightingale 		break;
724bf21cd93STycho Nightingale 	case PCIBAR_MEM64:
725bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr &= ~0xffffffffUL;
726bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr |= addr;
727bf21cd93STycho Nightingale 		break;
728bf21cd93STycho Nightingale 	case PCIBAR_MEMHI64:
729bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr &= 0xffffffff;
730bf21cd93STycho Nightingale 		pi->pi_bar[idx].addr |= addr;
731bf21cd93STycho Nightingale 		break;
732bf21cd93STycho Nightingale 	default:
733bf21cd93STycho Nightingale 		assert(0);
734bf21cd93STycho Nightingale 	}
735bf21cd93STycho Nightingale 
736bf21cd93STycho Nightingale 	if (decode)
737bf21cd93STycho Nightingale 		register_bar(pi, idx);
738bf21cd93STycho Nightingale }
739bf21cd93STycho Nightingale 
740bf21cd93STycho Nightingale int
pci_emul_alloc_bar(struct pci_devinst * pdi,int idx,enum pcibar_type type,uint64_t size)7416960cd89SAndy Fiddaman pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
7426960cd89SAndy Fiddaman     uint64_t size)
743bf21cd93STycho Nightingale {
744d7b72f7bSAndy Fiddaman 	assert((type == PCIBAR_ROM) || (idx >= 0 && idx <= PCI_BARMAX));
745d7b72f7bSAndy Fiddaman 	assert((type != PCIBAR_ROM) || (idx == PCI_ROM_IDX));
746bf21cd93STycho Nightingale 
747bf21cd93STycho Nightingale 	if ((size & (size - 1)) != 0)
748bf21cd93STycho Nightingale 		size = 1UL << flsl(size);	/* round up to a power of 2 */
749bf21cd93STycho Nightingale 
750bf21cd93STycho Nightingale 	/* Enforce minimum BAR sizes required by the PCI standard */
751bf21cd93STycho Nightingale 	if (type == PCIBAR_IO) {
752bf21cd93STycho Nightingale 		if (size < 4)
753bf21cd93STycho Nightingale 			size = 4;
754d7b72f7bSAndy Fiddaman 	} else if (type == PCIBAR_ROM) {
755d7b72f7bSAndy Fiddaman 		if (size < ~PCIM_BIOS_ADDR_MASK + 1)
756d7b72f7bSAndy Fiddaman 			size = ~PCIM_BIOS_ADDR_MASK + 1;
757bf21cd93STycho Nightingale 	} else {
758bf21cd93STycho Nightingale 		if (size < 16)
759bf21cd93STycho Nightingale 			size = 16;
760bf21cd93STycho Nightingale 	}
761bf21cd93STycho Nightingale 
7626dc98349SAndy Fiddaman 	/*
7636dc98349SAndy Fiddaman 	 * To reduce fragmentation of the MMIO space, we allocate the BARs by
7646dc98349SAndy Fiddaman 	 * size. Therefore, don't allocate the BAR yet. We create a list of all
7656dc98349SAndy Fiddaman 	 * BAR allocation which is sorted by BAR size. When all PCI devices are
7666dc98349SAndy Fiddaman 	 * initialized, we will assign an address to the BARs.
7676dc98349SAndy Fiddaman 	 */
7686dc98349SAndy Fiddaman 
7696dc98349SAndy Fiddaman 	/* create a new list entry */
7706dc98349SAndy Fiddaman 	struct pci_bar_allocation *const new_bar = malloc(sizeof(*new_bar));
7716dc98349SAndy Fiddaman 	memset(new_bar, 0, sizeof(*new_bar));
7726dc98349SAndy Fiddaman 	new_bar->pdi = pdi;
7736dc98349SAndy Fiddaman 	new_bar->idx = idx;
7746dc98349SAndy Fiddaman 	new_bar->type = type;
7756dc98349SAndy Fiddaman 	new_bar->size = size;
7766dc98349SAndy Fiddaman 
7776dc98349SAndy Fiddaman 	/*
7786dc98349SAndy Fiddaman 	 * Search for a BAR which size is lower than the size of our newly
7796dc98349SAndy Fiddaman 	 * allocated BAR.
7806dc98349SAndy Fiddaman 	 */
7816dc98349SAndy Fiddaman 	struct pci_bar_allocation *bar = NULL;
7826dc98349SAndy Fiddaman 	TAILQ_FOREACH(bar, &pci_bars, chain) {
7836dc98349SAndy Fiddaman 		if (bar->size < size) {
7846dc98349SAndy Fiddaman 			break;
7856dc98349SAndy Fiddaman 		}
7866dc98349SAndy Fiddaman 	}
7876dc98349SAndy Fiddaman 
7886dc98349SAndy Fiddaman 	if (bar == NULL) {
7896dc98349SAndy Fiddaman 		/*
7906dc98349SAndy Fiddaman 		 * Either the list is empty or new BAR is the smallest BAR of
7916dc98349SAndy Fiddaman 		 * the list. Append it to the end of our list.
7926dc98349SAndy Fiddaman 		 */
7936dc98349SAndy Fiddaman 		TAILQ_INSERT_TAIL(&pci_bars, new_bar, chain);
7946dc98349SAndy Fiddaman 	} else {
7956dc98349SAndy Fiddaman 		/*
7966dc98349SAndy Fiddaman 		 * The found BAR is smaller than our new BAR. For that reason,
7976dc98349SAndy Fiddaman 		 * insert our new BAR before the found BAR.
7986dc98349SAndy Fiddaman 		 */
7996dc98349SAndy Fiddaman 		TAILQ_INSERT_BEFORE(bar, new_bar, chain);
8006dc98349SAndy Fiddaman 	}
8016dc98349SAndy Fiddaman 
8026dc98349SAndy Fiddaman 	/*
8036dc98349SAndy Fiddaman 	 * pci_passthru devices synchronize their physical and virtual command
8046dc98349SAndy Fiddaman 	 * register on init. For that reason, the virtual cmd reg should be
8056dc98349SAndy Fiddaman 	 * updated as early as possible.
8066dc98349SAndy Fiddaman 	 */
8076dc98349SAndy Fiddaman 	uint16_t enbit = 0;
8086dc98349SAndy Fiddaman 	switch (type) {
8096dc98349SAndy Fiddaman 	case PCIBAR_IO:
8106dc98349SAndy Fiddaman 		enbit = PCIM_CMD_PORTEN;
8116dc98349SAndy Fiddaman 		break;
8126dc98349SAndy Fiddaman 	case PCIBAR_MEM64:
8136dc98349SAndy Fiddaman 	case PCIBAR_MEM32:
8146dc98349SAndy Fiddaman 		enbit = PCIM_CMD_MEMEN;
8156dc98349SAndy Fiddaman 		break;
8166dc98349SAndy Fiddaman 	default:
8176dc98349SAndy Fiddaman 		enbit = 0;
8186dc98349SAndy Fiddaman 		break;
8196dc98349SAndy Fiddaman 	}
8206dc98349SAndy Fiddaman 
8216dc98349SAndy Fiddaman 	const uint16_t cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND);
8226dc98349SAndy Fiddaman 	pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit);
8236dc98349SAndy Fiddaman 
8246dc98349SAndy Fiddaman 	return (0);
8256dc98349SAndy Fiddaman }
8266dc98349SAndy Fiddaman 
8276dc98349SAndy Fiddaman static int
pci_emul_assign_bar(struct pci_devinst * const pdi,const int idx,const enum pcibar_type type,const uint64_t size)8286dc98349SAndy Fiddaman pci_emul_assign_bar(struct pci_devinst *const pdi, const int idx,
8296dc98349SAndy Fiddaman     const enum pcibar_type type, const uint64_t size)
8306dc98349SAndy Fiddaman {
8316dc98349SAndy Fiddaman 	int error;
8326dc98349SAndy Fiddaman 	uint64_t *baseptr, limit, addr, mask, lobits, bar;
8336dc98349SAndy Fiddaman 
834bf21cd93STycho Nightingale 	switch (type) {
835bf21cd93STycho Nightingale 	case PCIBAR_NONE:
836bf21cd93STycho Nightingale 		baseptr = NULL;
8376dc98349SAndy Fiddaman 		addr = mask = lobits = 0;
838bf21cd93STycho Nightingale 		break;
839bf21cd93STycho Nightingale 	case PCIBAR_IO:
840bf21cd93STycho Nightingale 		baseptr = &pci_emul_iobase;
841bf21cd93STycho Nightingale 		limit = PCI_EMUL_IOLIMIT;
842bf21cd93STycho Nightingale 		mask = PCIM_BAR_IO_BASE;
843bf21cd93STycho Nightingale 		lobits = PCIM_BAR_IO_SPACE;
844bf21cd93STycho Nightingale 		break;
845bf21cd93STycho Nightingale 	case PCIBAR_MEM64:
846bf21cd93STycho Nightingale 		/*
847bf21cd93STycho Nightingale 		 * XXX
848bf21cd93STycho Nightingale 		 * Some drivers do not work well if the 64-bit BAR is allocated
849bf21cd93STycho Nightingale 		 * above 4GB. Allow for this by allocating small requests under
850bf21cd93STycho Nightingale 		 * 4GB unless then allocation size is larger than some arbitrary
8516960cd89SAndy Fiddaman 		 * number (128MB currently).
852bf21cd93STycho Nightingale 		 */
8536960cd89SAndy Fiddaman 		if (size > 128 * 1024 * 1024) {
8546960cd89SAndy Fiddaman 			baseptr = &pci_emul_membase64;
8556dc98349SAndy Fiddaman 			limit = pci_emul_memlim64;
856bf21cd93STycho Nightingale 			mask = PCIM_BAR_MEM_BASE;
857bf21cd93STycho Nightingale 			lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |
858bf21cd93STycho Nightingale 				 PCIM_BAR_MEM_PREFETCH;
859bf21cd93STycho Nightingale 		} else {
860bf21cd93STycho Nightingale 			baseptr = &pci_emul_membase32;
861bf21cd93STycho Nightingale 			limit = PCI_EMUL_MEMLIMIT32;
862bf21cd93STycho Nightingale 			mask = PCIM_BAR_MEM_BASE;
863bf21cd93STycho Nightingale 			lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64;
864bf21cd93STycho Nightingale 		}
865bf21cd93STycho Nightingale 		break;
866bf21cd93STycho Nightingale 	case PCIBAR_MEM32:
867bf21cd93STycho Nightingale 		baseptr = &pci_emul_membase32;
868bf21cd93STycho Nightingale 		limit = PCI_EMUL_MEMLIMIT32;
869bf21cd93STycho Nightingale 		mask = PCIM_BAR_MEM_BASE;
870bf21cd93STycho Nightingale 		lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
871bf21cd93STycho Nightingale 		break;
872d7b72f7bSAndy Fiddaman 	case PCIBAR_ROM:
873d7b72f7bSAndy Fiddaman 		/* do not claim memory for ROM. OVMF will do it for us. */
874d7b72f7bSAndy Fiddaman 		baseptr = NULL;
875d7b72f7bSAndy Fiddaman 		limit = 0;
876d7b72f7bSAndy Fiddaman 		mask = PCIM_BIOS_ADDR_MASK;
877d7b72f7bSAndy Fiddaman 		lobits = 0;
878d7b72f7bSAndy Fiddaman 		break;
879bf21cd93STycho Nightingale 	default:
880bf21cd93STycho Nightingale 		printf("pci_emul_alloc_base: invalid bar type %d\n", type);
8814c87aefeSPatrick Mooney #ifdef FreeBSD
882bf21cd93STycho Nightingale 		assert(0);
8834c87aefeSPatrick Mooney #else
8844c87aefeSPatrick Mooney 		abort();
8854c87aefeSPatrick Mooney #endif
886bf21cd93STycho Nightingale 	}
887bf21cd93STycho Nightingale 
888bf21cd93STycho Nightingale 	if (baseptr != NULL) {
889bf21cd93STycho Nightingale 		error = pci_emul_alloc_resource(baseptr, limit, size, &addr);
890bf21cd93STycho Nightingale 		if (error != 0)
891bf21cd93STycho Nightingale 			return (error);
8924f3f3e9aSAndy Fiddaman 	} else {
8934f3f3e9aSAndy Fiddaman 		addr = 0;
894bf21cd93STycho Nightingale 	}
895bf21cd93STycho Nightingale 
896bf21cd93STycho Nightingale 	pdi->pi_bar[idx].type = type;
897bf21cd93STycho Nightingale 	pdi->pi_bar[idx].addr = addr;
898bf21cd93STycho Nightingale 	pdi->pi_bar[idx].size = size;
8996dc98349SAndy Fiddaman 	/*
9006dc98349SAndy Fiddaman 	 * passthru devices are using same lobits as physical device they set
9016dc98349SAndy Fiddaman 	 * this property
9026dc98349SAndy Fiddaman 	 */
9036dc98349SAndy Fiddaman 	if (pdi->pi_bar[idx].lobits != 0) {
9046dc98349SAndy Fiddaman 		lobits = pdi->pi_bar[idx].lobits;
9056dc98349SAndy Fiddaman 	} else {
9066dc98349SAndy Fiddaman 		pdi->pi_bar[idx].lobits = lobits;
9076dc98349SAndy Fiddaman 	}
908bf21cd93STycho Nightingale 
909bf21cd93STycho Nightingale 	/* Initialize the BAR register in config space */
910bf21cd93STycho Nightingale 	bar = (addr & mask) | lobits;
911bf21cd93STycho Nightingale 	pci_set_cfgdata32(pdi, PCIR_BAR(idx), bar);
912bf21cd93STycho Nightingale 
913bf21cd93STycho Nightingale 	if (type == PCIBAR_MEM64) {
914bf21cd93STycho Nightingale 		assert(idx + 1 <= PCI_BARMAX);
915bf21cd93STycho Nightingale 		pdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64;
916bf21cd93STycho Nightingale 		pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
917bf21cd93STycho Nightingale 	}
9184c87aefeSPatrick Mooney 
919d7b72f7bSAndy Fiddaman 	if (type != PCIBAR_ROM) {
920d7b72f7bSAndy Fiddaman 		register_bar(pdi, idx);
921d7b72f7bSAndy Fiddaman 	}
922d7b72f7bSAndy Fiddaman 
923d7b72f7bSAndy Fiddaman 	return (0);
924d7b72f7bSAndy Fiddaman }
925d7b72f7bSAndy Fiddaman 
926d7b72f7bSAndy Fiddaman int
pci_emul_alloc_rom(struct pci_devinst * const pdi,const uint64_t size,void ** const addr)927d7b72f7bSAndy Fiddaman pci_emul_alloc_rom(struct pci_devinst *const pdi, const uint64_t size,
928d7b72f7bSAndy Fiddaman     void **const addr)
929d7b72f7bSAndy Fiddaman {
930d7b72f7bSAndy Fiddaman 	/* allocate ROM space once on first call */
931d7b72f7bSAndy Fiddaman 	if (pci_emul_rombase == 0) {
932d7b72f7bSAndy Fiddaman 		pci_emul_rombase = vm_create_devmem(pdi->pi_vmctx, VM_PCIROM,
933d7b72f7bSAndy Fiddaman 		    "pcirom", PCI_EMUL_ROMSIZE);
934d7b72f7bSAndy Fiddaman 		if (pci_emul_rombase == MAP_FAILED) {
935d7b72f7bSAndy Fiddaman 			warnx("%s: failed to create rom segment", __func__);
936d7b72f7bSAndy Fiddaman 			return (-1);
937d7b72f7bSAndy Fiddaman 		}
938d7b72f7bSAndy Fiddaman 		pci_emul_romlim = pci_emul_rombase + PCI_EMUL_ROMSIZE;
939d7b72f7bSAndy Fiddaman 		pci_emul_romoffset = 0;
940d7b72f7bSAndy Fiddaman 	}
941d7b72f7bSAndy Fiddaman 
942d7b72f7bSAndy Fiddaman 	/* ROM size should be a power of 2 and greater than 2 KB */
943d7b72f7bSAndy Fiddaman 	const uint64_t rom_size = MAX(1UL << flsl(size),
944d7b72f7bSAndy Fiddaman 	    ~PCIM_BIOS_ADDR_MASK + 1);
945d7b72f7bSAndy Fiddaman 
946d7b72f7bSAndy Fiddaman 	/* check if ROM fits into ROM space */
947d7b72f7bSAndy Fiddaman 	if (pci_emul_romoffset + rom_size > PCI_EMUL_ROMSIZE) {
948d7b72f7bSAndy Fiddaman 		warnx("%s: no space left in rom segment:", __func__);
949d7b72f7bSAndy Fiddaman 		warnx("%16lu bytes left",
950d7b72f7bSAndy Fiddaman 		    PCI_EMUL_ROMSIZE - pci_emul_romoffset);
951d7b72f7bSAndy Fiddaman 		warnx("%16lu bytes required by %d/%d/%d", rom_size, pdi->pi_bus,
952d7b72f7bSAndy Fiddaman 		    pdi->pi_slot, pdi->pi_func);
953d7b72f7bSAndy Fiddaman 		return (-1);
954d7b72f7bSAndy Fiddaman 	}
955d7b72f7bSAndy Fiddaman 
956d7b72f7bSAndy Fiddaman 	/* allocate ROM BAR */
957d7b72f7bSAndy Fiddaman 	const int error = pci_emul_alloc_bar(pdi, PCI_ROM_IDX, PCIBAR_ROM,
958d7b72f7bSAndy Fiddaman 	    rom_size);
959d7b72f7bSAndy Fiddaman 	if (error)
960d7b72f7bSAndy Fiddaman 		return error;
961d7b72f7bSAndy Fiddaman 
962d7b72f7bSAndy Fiddaman 	/* return address */
963d7b72f7bSAndy Fiddaman 	*addr = pci_emul_rombase + pci_emul_romoffset;
964d7b72f7bSAndy Fiddaman 
965d7b72f7bSAndy Fiddaman 	/* save offset into ROM Space */
966d7b72f7bSAndy Fiddaman 	pdi->pi_romoffset = pci_emul_romoffset;
967d7b72f7bSAndy Fiddaman 
968d7b72f7bSAndy Fiddaman 	/* increase offset for next ROM */
969d7b72f7bSAndy Fiddaman 	pci_emul_romoffset += rom_size;
970bf21cd93STycho Nightingale 
971bf21cd93STycho Nightingale 	return (0);
972bf21cd93STycho Nightingale }
973bf21cd93STycho Nightingale 
974*32640292SAndy Fiddaman int
pci_emul_add_boot_device(struct pci_devinst * pi,int bootindex)975*32640292SAndy Fiddaman pci_emul_add_boot_device(struct pci_devinst *pi, int bootindex)
976*32640292SAndy Fiddaman {
977*32640292SAndy Fiddaman 	struct boot_device *new_device, *device;
978*32640292SAndy Fiddaman 
979*32640292SAndy Fiddaman 	/* don't permit a negative bootindex */
980*32640292SAndy Fiddaman 	if (bootindex < 0) {
981*32640292SAndy Fiddaman 		errx(4, "Invalid bootindex %d for %s", bootindex, pi->pi_name);
982*32640292SAndy Fiddaman 	}
983*32640292SAndy Fiddaman 
984*32640292SAndy Fiddaman 	/* alloc new boot device */
985*32640292SAndy Fiddaman 	new_device = calloc(1, sizeof(struct boot_device));
986*32640292SAndy Fiddaman 	if (new_device == NULL) {
987*32640292SAndy Fiddaman 		return (ENOMEM);
988*32640292SAndy Fiddaman 	}
989*32640292SAndy Fiddaman 	new_device->pdi = pi;
990*32640292SAndy Fiddaman 	new_device->bootindex = bootindex;
991*32640292SAndy Fiddaman 
992*32640292SAndy Fiddaman 	/* search for boot device with higher boot index */
993*32640292SAndy Fiddaman 	TAILQ_FOREACH(device, &boot_devices, boot_device_chain) {
994*32640292SAndy Fiddaman 		if (device->bootindex == bootindex) {
995*32640292SAndy Fiddaman 			errx(4,
996*32640292SAndy Fiddaman 			    "Could not set bootindex %d for %s. Bootindex already occupied by %s",
997*32640292SAndy Fiddaman 			    bootindex, pi->pi_name, device->pdi->pi_name);
998*32640292SAndy Fiddaman 		} else if (device->bootindex > bootindex) {
999*32640292SAndy Fiddaman 			break;
1000*32640292SAndy Fiddaman 		}
1001*32640292SAndy Fiddaman 	}
1002*32640292SAndy Fiddaman 
1003*32640292SAndy Fiddaman 	/* add boot device to queue */
1004*32640292SAndy Fiddaman 	if (device == NULL) {
1005*32640292SAndy Fiddaman 		TAILQ_INSERT_TAIL(&boot_devices, new_device, boot_device_chain);
1006*32640292SAndy Fiddaman 	} else {
1007*32640292SAndy Fiddaman 		TAILQ_INSERT_BEFORE(device, new_device, boot_device_chain);
1008*32640292SAndy Fiddaman 	}
1009*32640292SAndy Fiddaman 
1010*32640292SAndy Fiddaman 	return (0);
1011*32640292SAndy Fiddaman }
1012*32640292SAndy Fiddaman 
1013bf21cd93STycho Nightingale #define	CAP_START_OFFSET	0x40
1014bf21cd93STycho Nightingale static int
pci_emul_add_capability(struct pci_devinst * pi,u_char * capdata,int caplen)1015bf21cd93STycho Nightingale pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)
1016bf21cd93STycho Nightingale {
1017bf21cd93STycho Nightingale 	int i, capoff, reallen;
1018bf21cd93STycho Nightingale 	uint16_t sts;
1019bf21cd93STycho Nightingale 
1020bf21cd93STycho Nightingale 	assert(caplen > 0);
1021bf21cd93STycho Nightingale 
1022bf21cd93STycho Nightingale 	reallen = roundup2(caplen, 4);		/* dword aligned */
1023bf21cd93STycho Nightingale 
1024bf21cd93STycho Nightingale 	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
1025bf21cd93STycho Nightingale 	if ((sts & PCIM_STATUS_CAPPRESENT) == 0)
1026bf21cd93STycho Nightingale 		capoff = CAP_START_OFFSET;
1027bf21cd93STycho Nightingale 	else
1028bf21cd93STycho Nightingale 		capoff = pi->pi_capend + 1;
1029bf21cd93STycho Nightingale 
1030bf21cd93STycho Nightingale 	/* Check if we have enough space */
1031bf21cd93STycho Nightingale 	if (capoff + reallen > PCI_REGMAX + 1)
1032bf21cd93STycho Nightingale 		return (-1);
1033bf21cd93STycho Nightingale 
1034bf21cd93STycho Nightingale 	/* Set the previous capability pointer */
1035bf21cd93STycho Nightingale 	if ((sts & PCIM_STATUS_CAPPRESENT) == 0) {
1036bf21cd93STycho Nightingale 		pci_set_cfgdata8(pi, PCIR_CAP_PTR, capoff);
1037bf21cd93STycho Nightingale 		pci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT);
1038bf21cd93STycho Nightingale 	} else
1039bf21cd93STycho Nightingale 		pci_set_cfgdata8(pi, pi->pi_prevcap + 1, capoff);
1040bf21cd93STycho Nightingale 
1041bf21cd93STycho Nightingale 	/* Copy the capability */
1042bf21cd93STycho Nightingale 	for (i = 0; i < caplen; i++)
1043bf21cd93STycho Nightingale 		pci_set_cfgdata8(pi, capoff + i, capdata[i]);
1044bf21cd93STycho Nightingale 
1045bf21cd93STycho Nightingale 	/* Set the next capability pointer */
1046bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, capoff + 1, 0);
1047bf21cd93STycho Nightingale 
1048bf21cd93STycho Nightingale 	pi->pi_prevcap = capoff;
1049bf21cd93STycho Nightingale 	pi->pi_capend = capoff + reallen - 1;
1050bf21cd93STycho Nightingale 	return (0);
1051bf21cd93STycho Nightingale }
1052bf21cd93STycho Nightingale 
1053bf21cd93STycho Nightingale static struct pci_devemu *
pci_emul_finddev(const char * name)10542b948146SAndy Fiddaman pci_emul_finddev(const char *name)
1055bf21cd93STycho Nightingale {
1056bf21cd93STycho Nightingale 	struct pci_devemu **pdpp, *pdp;
1057bf21cd93STycho Nightingale 
1058bf21cd93STycho Nightingale 	SET_FOREACH(pdpp, pci_devemu_set) {
1059bf21cd93STycho Nightingale 		pdp = *pdpp;
1060bf21cd93STycho Nightingale 		if (!strcmp(pdp->pe_emu, name)) {
1061bf21cd93STycho Nightingale 			return (pdp);
1062bf21cd93STycho Nightingale 		}
1063bf21cd93STycho Nightingale 	}
1064bf21cd93STycho Nightingale 
1065bf21cd93STycho Nightingale 	return (NULL);
1066bf21cd93STycho Nightingale }
1067bf21cd93STycho Nightingale 
1068bf21cd93STycho Nightingale static int
pci_emul_init(struct vmctx * ctx,struct pci_devemu * pde,int bus,int slot,int func,struct funcinfo * fi)1069bf21cd93STycho Nightingale pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot,
1070bf21cd93STycho Nightingale     int func, struct funcinfo *fi)
1071bf21cd93STycho Nightingale {
1072bf21cd93STycho Nightingale 	struct pci_devinst *pdi;
1073bf21cd93STycho Nightingale 	int err;
1074bf21cd93STycho Nightingale 
1075bf21cd93STycho Nightingale 	pdi = calloc(1, sizeof(struct pci_devinst));
1076bf21cd93STycho Nightingale 
1077bf21cd93STycho Nightingale 	pdi->pi_vmctx = ctx;
1078bf21cd93STycho Nightingale 	pdi->pi_bus = bus;
1079bf21cd93STycho Nightingale 	pdi->pi_slot = slot;
1080bf21cd93STycho Nightingale 	pdi->pi_func = func;
1081bf21cd93STycho Nightingale 	pthread_mutex_init(&pdi->pi_lintr.lock, NULL);
1082bf21cd93STycho Nightingale 	pdi->pi_lintr.pin = 0;
1083bf21cd93STycho Nightingale 	pdi->pi_lintr.state = IDLE;
1084bf21cd93STycho Nightingale 	pdi->pi_lintr.pirq_pin = 0;
1085bf21cd93STycho Nightingale 	pdi->pi_lintr.ioapic_irq = 0;
1086bf21cd93STycho Nightingale 	pdi->pi_d = pde;
1087*32640292SAndy Fiddaman 	snprintf(pdi->pi_name, PI_NAMESZ, "%s@pci.%d.%d.%d", pde->pe_emu, bus,
1088*32640292SAndy Fiddaman 	    slot, func);
1089bf21cd93STycho Nightingale 
1090bf21cd93STycho Nightingale 	/* Disable legacy interrupts */
1091bf21cd93STycho Nightingale 	pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
1092bf21cd93STycho Nightingale 	pci_set_cfgdata8(pdi, PCIR_INTPIN, 0);
1093bf21cd93STycho Nightingale 
109484659b24SMichael Zeller 	pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN);
1095bf21cd93STycho Nightingale 
1096*32640292SAndy Fiddaman 	err = (*pde->pe_init)(pdi, fi->fi_config);
1097bf21cd93STycho Nightingale 	if (err == 0)
1098bf21cd93STycho Nightingale 		fi->fi_devi = pdi;
1099bf21cd93STycho Nightingale 	else
1100bf21cd93STycho Nightingale 		free(pdi);
1101bf21cd93STycho Nightingale 
1102bf21cd93STycho Nightingale 	return (err);
1103bf21cd93STycho Nightingale }
1104bf21cd93STycho Nightingale 
1105bf21cd93STycho Nightingale void
pci_populate_msicap(struct msicap * msicap,int msgnum,int nextptr)1106bf21cd93STycho Nightingale pci_populate_msicap(struct msicap *msicap, int msgnum, int nextptr)
1107bf21cd93STycho Nightingale {
1108bf21cd93STycho Nightingale 	int mmc;
1109bf21cd93STycho Nightingale 
1110bf21cd93STycho Nightingale 	/* Number of msi messages must be a power of 2 between 1 and 32 */
1111bf21cd93STycho Nightingale 	assert((msgnum & (msgnum - 1)) == 0 && msgnum >= 1 && msgnum <= 32);
1112bf21cd93STycho Nightingale 	mmc = ffs(msgnum) - 1;
1113bf21cd93STycho Nightingale 
1114bf21cd93STycho Nightingale 	bzero(msicap, sizeof(struct msicap));
1115bf21cd93STycho Nightingale 	msicap->capid = PCIY_MSI;
1116bf21cd93STycho Nightingale 	msicap->nextptr = nextptr;
1117bf21cd93STycho Nightingale 	msicap->msgctrl = PCIM_MSICTRL_64BIT | (mmc << 1);
1118bf21cd93STycho Nightingale }
1119bf21cd93STycho Nightingale 
1120bf21cd93STycho Nightingale int
pci_emul_add_msicap(struct pci_devinst * pi,int msgnum)1121bf21cd93STycho Nightingale pci_emul_add_msicap(struct pci_devinst *pi, int msgnum)
1122bf21cd93STycho Nightingale {
1123bf21cd93STycho Nightingale 	struct msicap msicap;
1124bf21cd93STycho Nightingale 
1125bf21cd93STycho Nightingale 	pci_populate_msicap(&msicap, msgnum, 0);
1126bf21cd93STycho Nightingale 
1127bf21cd93STycho Nightingale 	return (pci_emul_add_capability(pi, (u_char *)&msicap, sizeof(msicap)));
1128bf21cd93STycho Nightingale }
1129bf21cd93STycho Nightingale 
1130bf21cd93STycho Nightingale static void
pci_populate_msixcap(struct msixcap * msixcap,int msgnum,int barnum,uint32_t msix_tab_size)1131bf21cd93STycho Nightingale pci_populate_msixcap(struct msixcap *msixcap, int msgnum, int barnum,
1132bf21cd93STycho Nightingale 		     uint32_t msix_tab_size)
1133bf21cd93STycho Nightingale {
1134bf21cd93STycho Nightingale 
1135bf21cd93STycho Nightingale 	assert(msix_tab_size % 4096 == 0);
1136bf21cd93STycho Nightingale 
1137bf21cd93STycho Nightingale 	bzero(msixcap, sizeof(struct msixcap));
1138bf21cd93STycho Nightingale 	msixcap->capid = PCIY_MSIX;
1139bf21cd93STycho Nightingale 
1140bf21cd93STycho Nightingale 	/*
1141bf21cd93STycho Nightingale 	 * Message Control Register, all fields set to
1142bf21cd93STycho Nightingale 	 * zero except for the Table Size.
1143bf21cd93STycho Nightingale 	 * Note: Table size N is encoded as N-1
1144bf21cd93STycho Nightingale 	 */
1145bf21cd93STycho Nightingale 	msixcap->msgctrl = msgnum - 1;
1146bf21cd93STycho Nightingale 
1147bf21cd93STycho Nightingale 	/*
1148bf21cd93STycho Nightingale 	 * MSI-X BAR setup:
1149bf21cd93STycho Nightingale 	 * - MSI-X table start at offset 0
1150bf21cd93STycho Nightingale 	 * - PBA table starts at a 4K aligned offset after the MSI-X table
1151bf21cd93STycho Nightingale 	 */
1152bf21cd93STycho Nightingale 	msixcap->table_info = barnum & PCIM_MSIX_BIR_MASK;
1153bf21cd93STycho Nightingale 	msixcap->pba_info = msix_tab_size | (barnum & PCIM_MSIX_BIR_MASK);
1154bf21cd93STycho Nightingale }
1155bf21cd93STycho Nightingale 
1156bf21cd93STycho Nightingale static void
pci_msix_table_init(struct pci_devinst * pi,int table_entries)1157bf21cd93STycho Nightingale pci_msix_table_init(struct pci_devinst *pi, int table_entries)
1158bf21cd93STycho Nightingale {
1159bf21cd93STycho Nightingale 	int i, table_size;
1160bf21cd93STycho Nightingale 
1161bf21cd93STycho Nightingale 	assert(table_entries > 0);
1162bf21cd93STycho Nightingale 	assert(table_entries <= MAX_MSIX_TABLE_ENTRIES);
1163bf21cd93STycho Nightingale 
1164bf21cd93STycho Nightingale 	table_size = table_entries * MSIX_TABLE_ENTRY_SIZE;
1165bf21cd93STycho Nightingale 	pi->pi_msix.table = calloc(1, table_size);
1166bf21cd93STycho Nightingale 
1167bf21cd93STycho Nightingale 	/* set mask bit of vector control register */
1168bf21cd93STycho Nightingale 	for (i = 0; i < table_entries; i++)
1169bf21cd93STycho Nightingale 		pi->pi_msix.table[i].vector_control |= PCIM_MSIX_VCTRL_MASK;
1170bf21cd93STycho Nightingale }
1171bf21cd93STycho Nightingale 
1172bf21cd93STycho Nightingale int
pci_emul_add_msixcap(struct pci_devinst * pi,int msgnum,int barnum)1173bf21cd93STycho Nightingale pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum)
1174bf21cd93STycho Nightingale {
1175bf21cd93STycho Nightingale 	uint32_t tab_size;
1176bf21cd93STycho Nightingale 	struct msixcap msixcap;
1177bf21cd93STycho Nightingale 
1178bf21cd93STycho Nightingale 	assert(msgnum >= 1 && msgnum <= MAX_MSIX_TABLE_ENTRIES);
1179bf21cd93STycho Nightingale 	assert(barnum >= 0 && barnum <= PCIR_MAX_BAR_0);
11804c87aefeSPatrick Mooney 
1181bf21cd93STycho Nightingale 	tab_size = msgnum * MSIX_TABLE_ENTRY_SIZE;
1182bf21cd93STycho Nightingale 
1183bf21cd93STycho Nightingale 	/* Align table size to nearest 4K */
1184bf21cd93STycho Nightingale 	tab_size = roundup2(tab_size, 4096);
1185bf21cd93STycho Nightingale 
1186bf21cd93STycho Nightingale 	pi->pi_msix.table_bar = barnum;
1187bf21cd93STycho Nightingale 	pi->pi_msix.pba_bar   = barnum;
1188bf21cd93STycho Nightingale 	pi->pi_msix.table_offset = 0;
1189bf21cd93STycho Nightingale 	pi->pi_msix.table_count = msgnum;
1190bf21cd93STycho Nightingale 	pi->pi_msix.pba_offset = tab_size;
1191bf21cd93STycho Nightingale 	pi->pi_msix.pba_size = PBA_SIZE(msgnum);
1192bf21cd93STycho Nightingale 
1193bf21cd93STycho Nightingale 	pci_msix_table_init(pi, msgnum);
1194bf21cd93STycho Nightingale 
1195bf21cd93STycho Nightingale 	pci_populate_msixcap(&msixcap, msgnum, barnum, tab_size);
1196bf21cd93STycho Nightingale 
1197bf21cd93STycho Nightingale 	/* allocate memory for MSI-X Table and PBA */
1198bf21cd93STycho Nightingale 	pci_emul_alloc_bar(pi, barnum, PCIBAR_MEM32,
1199bf21cd93STycho Nightingale 				tab_size + pi->pi_msix.pba_size);
1200bf21cd93STycho Nightingale 
1201bf21cd93STycho Nightingale 	return (pci_emul_add_capability(pi, (u_char *)&msixcap,
1202bf21cd93STycho Nightingale 					sizeof(msixcap)));
1203bf21cd93STycho Nightingale }
1204bf21cd93STycho Nightingale 
1205154972afSPatrick Mooney static void
msixcap_cfgwrite(struct pci_devinst * pi,int capoff,int offset,int bytes,uint32_t val)1206bf21cd93STycho Nightingale msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
1207bf21cd93STycho Nightingale 		 int bytes, uint32_t val)
1208bf21cd93STycho Nightingale {
1209bf21cd93STycho Nightingale 	uint16_t msgctrl, rwmask;
12104c87aefeSPatrick Mooney 	int off;
12114c87aefeSPatrick Mooney 
1212bf21cd93STycho Nightingale 	off = offset - capoff;
1213bf21cd93STycho Nightingale 	/* Message Control Register */
1214bf21cd93STycho Nightingale 	if (off == 2 && bytes == 2) {
1215bf21cd93STycho Nightingale 		rwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK;
1216bf21cd93STycho Nightingale 		msgctrl = pci_get_cfgdata16(pi, offset);
1217bf21cd93STycho Nightingale 		msgctrl &= ~rwmask;
1218bf21cd93STycho Nightingale 		msgctrl |= val & rwmask;
1219bf21cd93STycho Nightingale 		val = msgctrl;
1220bf21cd93STycho Nightingale 
1221bf21cd93STycho Nightingale 		pi->pi_msix.enabled = val & PCIM_MSIXCTRL_MSIX_ENABLE;
1222bf21cd93STycho Nightingale 		pi->pi_msix.function_mask = val & PCIM_MSIXCTRL_FUNCTION_MASK;
1223bf21cd93STycho Nightingale 		pci_lintr_update(pi);
12244c87aefeSPatrick Mooney 	}
12254c87aefeSPatrick Mooney 
1226bf21cd93STycho Nightingale 	CFGWRITE(pi, offset, val, bytes);
1227bf21cd93STycho Nightingale }
1228bf21cd93STycho Nightingale 
1229154972afSPatrick Mooney static void
msicap_cfgwrite(struct pci_devinst * pi,int capoff,int offset,int bytes,uint32_t val)1230bf21cd93STycho Nightingale msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
1231bf21cd93STycho Nightingale 		int bytes, uint32_t val)
1232bf21cd93STycho Nightingale {
1233bf21cd93STycho Nightingale 	uint16_t msgctrl, rwmask, msgdata, mme;
1234bf21cd93STycho Nightingale 	uint32_t addrlo;
1235bf21cd93STycho Nightingale 
1236bf21cd93STycho Nightingale 	/*
1237bf21cd93STycho Nightingale 	 * If guest is writing to the message control register make sure
1238bf21cd93STycho Nightingale 	 * we do not overwrite read-only fields.
1239bf21cd93STycho Nightingale 	 */
1240bf21cd93STycho Nightingale 	if ((offset - capoff) == 2 && bytes == 2) {
1241bf21cd93STycho Nightingale 		rwmask = PCIM_MSICTRL_MME_MASK | PCIM_MSICTRL_MSI_ENABLE;
1242bf21cd93STycho Nightingale 		msgctrl = pci_get_cfgdata16(pi, offset);
1243bf21cd93STycho Nightingale 		msgctrl &= ~rwmask;
1244bf21cd93STycho Nightingale 		msgctrl |= val & rwmask;
1245bf21cd93STycho Nightingale 		val = msgctrl;
1246bf21cd93STycho Nightingale 	}
1247bf21cd93STycho Nightingale 	CFGWRITE(pi, offset, val, bytes);
1248154972afSPatrick Mooney 
1249154972afSPatrick Mooney 	msgctrl = pci_get_cfgdata16(pi, capoff + 2);
1250154972afSPatrick Mooney 	addrlo = pci_get_cfgdata32(pi, capoff + 4);
1251154972afSPatrick Mooney 	if (msgctrl & PCIM_MSICTRL_64BIT)
1252154972afSPatrick Mooney 		msgdata = pci_get_cfgdata16(pi, capoff + 12);
1253154972afSPatrick Mooney 	else
1254154972afSPatrick Mooney 		msgdata = pci_get_cfgdata16(pi, capoff + 8);
1255154972afSPatrick Mooney 
1256154972afSPatrick Mooney 	mme = msgctrl & PCIM_MSICTRL_MME_MASK;
1257154972afSPatrick Mooney 	pi->pi_msi.enabled = msgctrl & PCIM_MSICTRL_MSI_ENABLE ? 1 : 0;
1258154972afSPatrick Mooney 	if (pi->pi_msi.enabled) {
1259154972afSPatrick Mooney 		pi->pi_msi.addr = addrlo;
1260154972afSPatrick Mooney 		pi->pi_msi.msg_data = msgdata;
1261154972afSPatrick Mooney 		pi->pi_msi.maxmsgnum = 1 << (mme >> 4);
1262154972afSPatrick Mooney 	} else {
1263154972afSPatrick Mooney 		pi->pi_msi.maxmsgnum = 0;
1264154972afSPatrick Mooney 	}
1265154972afSPatrick Mooney 	pci_lintr_update(pi);
1266bf21cd93STycho Nightingale }
1267bf21cd93STycho Nightingale 
126859d65d31SAndy Fiddaman static void
pciecap_cfgwrite(struct pci_devinst * pi,int capoff __unused,int offset,int bytes,uint32_t val)126959d65d31SAndy Fiddaman pciecap_cfgwrite(struct pci_devinst *pi, int capoff __unused, int offset,
127059d65d31SAndy Fiddaman     int bytes, uint32_t val)
1271bf21cd93STycho Nightingale {
1272bf21cd93STycho Nightingale 
1273bf21cd93STycho Nightingale 	/* XXX don't write to the readonly parts */
1274bf21cd93STycho Nightingale 	CFGWRITE(pi, offset, val, bytes);
1275bf21cd93STycho Nightingale }
1276bf21cd93STycho Nightingale 
1277bf21cd93STycho Nightingale #define	PCIECAP_VERSION	0x2
1278bf21cd93STycho Nightingale int
pci_emul_add_pciecap(struct pci_devinst * pi,int type)1279bf21cd93STycho Nightingale pci_emul_add_pciecap(struct pci_devinst *pi, int type)
1280bf21cd93STycho Nightingale {
1281bf21cd93STycho Nightingale 	int err;
1282bf21cd93STycho Nightingale 	struct pciecap pciecap;
1283bf21cd93STycho Nightingale 
1284bf21cd93STycho Nightingale 	bzero(&pciecap, sizeof(pciecap));
1285bf21cd93STycho Nightingale 
128684659b24SMichael Zeller 	/*
128784659b24SMichael Zeller 	 * Use the integrated endpoint type for endpoints on a root complex bus.
128884659b24SMichael Zeller 	 *
128984659b24SMichael Zeller 	 * NB: bhyve currently only supports a single PCI bus that is the root
129084659b24SMichael Zeller 	 * complex bus, so all endpoints are integrated.
129184659b24SMichael Zeller 	 */
129284659b24SMichael Zeller 	if ((type == PCIEM_TYPE_ENDPOINT) && (pi->pi_bus == 0))
129384659b24SMichael Zeller 		type = PCIEM_TYPE_ROOT_INT_EP;
129484659b24SMichael Zeller 
1295bf21cd93STycho Nightingale 	pciecap.capid = PCIY_EXPRESS;
129684659b24SMichael Zeller 	pciecap.pcie_capabilities = PCIECAP_VERSION | type;
129784659b24SMichael Zeller 	if (type != PCIEM_TYPE_ROOT_INT_EP) {
129884659b24SMichael Zeller 		pciecap.link_capabilities = 0x411;	/* gen1, x1 */
129984659b24SMichael Zeller 		pciecap.link_status = 0x11;		/* gen1, x1 */
130084659b24SMichael Zeller 	}
1301bf21cd93STycho Nightingale 
1302bf21cd93STycho Nightingale 	err = pci_emul_add_capability(pi, (u_char *)&pciecap, sizeof(pciecap));
1303bf21cd93STycho Nightingale 	return (err);
1304bf21cd93STycho Nightingale }
1305bf21cd93STycho Nightingale 
1306bf21cd93STycho Nightingale /*
1307bf21cd93STycho Nightingale  * This function assumes that 'coff' is in the capabilities region of the
1308154972afSPatrick Mooney  * config space. A capoff parameter of zero will force a search for the
1309154972afSPatrick Mooney  * offset and type.
1310bf21cd93STycho Nightingale  */
1311154972afSPatrick Mooney void
pci_emul_capwrite(struct pci_devinst * pi,int offset,int bytes,uint32_t val,uint8_t capoff,int capid)1312154972afSPatrick Mooney pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val,
1313154972afSPatrick Mooney     uint8_t capoff, int capid)
1314bf21cd93STycho Nightingale {
1315154972afSPatrick Mooney 	uint8_t nextoff;
1316bf21cd93STycho Nightingale 
1317bf21cd93STycho Nightingale 	/* Do not allow un-aligned writes */
1318bf21cd93STycho Nightingale 	if ((offset & (bytes - 1)) != 0)
1319bf21cd93STycho Nightingale 		return;
1320bf21cd93STycho Nightingale 
1321154972afSPatrick Mooney 	if (capoff == 0) {
1322154972afSPatrick Mooney 		/* Find the capability that we want to update */
1323154972afSPatrick Mooney 		capoff = CAP_START_OFFSET;
1324154972afSPatrick Mooney 		while (1) {
1325154972afSPatrick Mooney 			nextoff = pci_get_cfgdata8(pi, capoff + 1);
1326154972afSPatrick Mooney 			if (nextoff == 0)
1327154972afSPatrick Mooney 				break;
1328154972afSPatrick Mooney 			if (offset >= capoff && offset < nextoff)
1329154972afSPatrick Mooney 				break;
1330bf21cd93STycho Nightingale 
1331154972afSPatrick Mooney 			capoff = nextoff;
1332154972afSPatrick Mooney 		}
1333154972afSPatrick Mooney 		assert(offset >= capoff);
1334154972afSPatrick Mooney 		capid = pci_get_cfgdata8(pi, capoff);
1335bf21cd93STycho Nightingale 	}
1336bf21cd93STycho Nightingale 
1337bf21cd93STycho Nightingale 	/*
1338bf21cd93STycho Nightingale 	 * Capability ID and Next Capability Pointer are readonly.
1339bf21cd93STycho Nightingale 	 * However, some o/s's do 4-byte writes that include these.
1340bf21cd93STycho Nightingale 	 * For this case, trim the write back to 2 bytes and adjust
1341bf21cd93STycho Nightingale 	 * the data.
1342bf21cd93STycho Nightingale 	 */
1343bf21cd93STycho Nightingale 	if (offset == capoff || offset == capoff + 1) {
1344bf21cd93STycho Nightingale 		if (offset == capoff && bytes == 4) {
1345bf21cd93STycho Nightingale 			bytes = 2;
1346bf21cd93STycho Nightingale 			offset += 2;
1347bf21cd93STycho Nightingale 			val >>= 16;
1348bf21cd93STycho Nightingale 		} else
1349bf21cd93STycho Nightingale 			return;
1350bf21cd93STycho Nightingale 	}
1351bf21cd93STycho Nightingale 
1352bf21cd93STycho Nightingale 	switch (capid) {
1353bf21cd93STycho Nightingale 	case PCIY_MSI:
1354bf21cd93STycho Nightingale 		msicap_cfgwrite(pi, capoff, offset, bytes, val);
1355bf21cd93STycho Nightingale 		break;
1356bf21cd93STycho Nightingale 	case PCIY_MSIX:
1357bf21cd93STycho Nightingale 		msixcap_cfgwrite(pi, capoff, offset, bytes, val);
1358bf21cd93STycho Nightingale 		break;
1359bf21cd93STycho Nightingale 	case PCIY_EXPRESS:
1360bf21cd93STycho Nightingale 		pciecap_cfgwrite(pi, capoff, offset, bytes, val);
1361bf21cd93STycho Nightingale 		break;
1362bf21cd93STycho Nightingale 	default:
1363bf21cd93STycho Nightingale 		break;
1364bf21cd93STycho Nightingale 	}
1365bf21cd93STycho Nightingale }
1366bf21cd93STycho Nightingale 
1367bf21cd93STycho Nightingale static int
pci_emul_iscap(struct pci_devinst * pi,int offset)1368bf21cd93STycho Nightingale pci_emul_iscap(struct pci_devinst *pi, int offset)
1369bf21cd93STycho Nightingale {
1370bf21cd93STycho Nightingale 	uint16_t sts;
1371bf21cd93STycho Nightingale 
1372bf21cd93STycho Nightingale 	sts = pci_get_cfgdata16(pi, PCIR_STATUS);
1373bf21cd93STycho Nightingale 	if ((sts & PCIM_STATUS_CAPPRESENT) != 0) {
1374bf21cd93STycho Nightingale 		if (offset >= CAP_START_OFFSET && offset <= pi->pi_capend)
1375bf21cd93STycho Nightingale 			return (1);
1376bf21cd93STycho Nightingale 	}
1377bf21cd93STycho Nightingale 	return (0);
1378bf21cd93STycho Nightingale }
1379bf21cd93STycho Nightingale 
1380bf21cd93STycho Nightingale static int
pci_emul_fallback_handler(struct vcpu * vcpu __unused,int dir,uint64_t addr __unused,int size __unused,uint64_t * val,void * arg1 __unused,long arg2 __unused)1381*32640292SAndy Fiddaman pci_emul_fallback_handler(struct vcpu *vcpu __unused, int dir,
1382*32640292SAndy Fiddaman     uint64_t addr __unused, int size __unused, uint64_t *val,
138359d65d31SAndy Fiddaman     void *arg1 __unused, long arg2 __unused)
1384bf21cd93STycho Nightingale {
1385bf21cd93STycho Nightingale 	/*
1386bf21cd93STycho Nightingale 	 * Ignore writes; return 0xff's for reads. The mem read code
1387bf21cd93STycho Nightingale 	 * will take care of truncating to the correct size.
1388bf21cd93STycho Nightingale 	 */
1389bf21cd93STycho Nightingale 	if (dir == MEM_F_READ) {
1390bf21cd93STycho Nightingale 		*val = 0xffffffffffffffff;
1391bf21cd93STycho Nightingale 	}
1392bf21cd93STycho Nightingale 
1393bf21cd93STycho Nightingale 	return (0);
1394bf21cd93STycho Nightingale }
1395bf21cd93STycho Nightingale 
1396bf21cd93STycho Nightingale static int
pci_emul_ecfg_handler(struct vcpu * vcpu __unused,int dir,uint64_t addr,int bytes,uint64_t * val,void * arg1 __unused,long arg2 __unused)1397*32640292SAndy Fiddaman pci_emul_ecfg_handler(struct vcpu *vcpu __unused, int dir, uint64_t addr,
1398*32640292SAndy Fiddaman     int bytes, uint64_t *val, void *arg1 __unused, long arg2 __unused)
1399bf21cd93STycho Nightingale {
1400bf21cd93STycho Nightingale 	int bus, slot, func, coff, in;
1401bf21cd93STycho Nightingale 
1402bf21cd93STycho Nightingale 	coff = addr & 0xfff;
1403bf21cd93STycho Nightingale 	func = (addr >> 12) & 0x7;
1404bf21cd93STycho Nightingale 	slot = (addr >> 15) & 0x1f;
1405bf21cd93STycho Nightingale 	bus = (addr >> 20) & 0xff;
1406bf21cd93STycho Nightingale 	in = (dir == MEM_F_READ);
1407bf21cd93STycho Nightingale 	if (in)
1408bf21cd93STycho Nightingale 		*val = ~0UL;
1409*32640292SAndy Fiddaman 	pci_cfgrw(in, bus, slot, func, coff, bytes, (uint32_t *)val);
1410bf21cd93STycho Nightingale 	return (0);
1411bf21cd93STycho Nightingale }
1412bf21cd93STycho Nightingale 
1413bf21cd93STycho Nightingale uint64_t
pci_ecfg_base(void)1414bf21cd93STycho Nightingale pci_ecfg_base(void)
1415bf21cd93STycho Nightingale {
1416bf21cd93STycho Nightingale 
1417bf21cd93STycho Nightingale 	return (PCI_EMUL_ECFG_BASE);
1418bf21cd93STycho Nightingale }
1419bf21cd93STycho Nightingale 
1420*32640292SAndy Fiddaman static int
init_bootorder(void)1421*32640292SAndy Fiddaman init_bootorder(void)
1422*32640292SAndy Fiddaman {
1423*32640292SAndy Fiddaman 	struct boot_device *device;
1424*32640292SAndy Fiddaman 	FILE *fp;
1425*32640292SAndy Fiddaman 	char *bootorder;
1426*32640292SAndy Fiddaman 	size_t bootorder_len;
1427*32640292SAndy Fiddaman 
1428*32640292SAndy Fiddaman 	if (TAILQ_EMPTY(&boot_devices))
1429*32640292SAndy Fiddaman 		return (0);
1430*32640292SAndy Fiddaman 
1431*32640292SAndy Fiddaman 	fp = open_memstream(&bootorder, &bootorder_len);
1432*32640292SAndy Fiddaman 	TAILQ_FOREACH(device, &boot_devices, boot_device_chain) {
1433*32640292SAndy Fiddaman 		fprintf(fp, "/pci@i0cf8/pci@%d,%d\n",
1434*32640292SAndy Fiddaman 		    device->pdi->pi_slot, device->pdi->pi_func);
1435*32640292SAndy Fiddaman 	}
1436*32640292SAndy Fiddaman 	fclose(fp);
1437*32640292SAndy Fiddaman 
1438*32640292SAndy Fiddaman 	return (qemu_fwcfg_add_file("bootorder", bootorder_len, bootorder));
1439*32640292SAndy Fiddaman }
1440*32640292SAndy Fiddaman 
1441bf21cd93STycho Nightingale #define	BUSIO_ROUNDUP		32
14426dc98349SAndy Fiddaman #define	BUSMEM32_ROUNDUP	(1024 * 1024)
14436dc98349SAndy Fiddaman #define	BUSMEM64_ROUNDUP	(512 * 1024 * 1024)
1444bf21cd93STycho Nightingale 
1445bf21cd93STycho Nightingale int
init_pci(struct vmctx * ctx)1446bf21cd93STycho Nightingale init_pci(struct vmctx *ctx)
1447bf21cd93STycho Nightingale {
14482b948146SAndy Fiddaman 	char node_name[sizeof("pci.XXX.XX.X")];
1449bf21cd93STycho Nightingale 	struct mem_range mr;
1450bf21cd93STycho Nightingale 	struct pci_devemu *pde;
1451bf21cd93STycho Nightingale 	struct businfo *bi;
1452bf21cd93STycho Nightingale 	struct slotinfo *si;
1453bf21cd93STycho Nightingale 	struct funcinfo *fi;
14542b948146SAndy Fiddaman 	nvlist_t *nvl;
14552b948146SAndy Fiddaman 	const char *emul;
1456bf21cd93STycho Nightingale 	size_t lowmem;
1457bf21cd93STycho Nightingale 	int bus, slot, func;
1458bf21cd93STycho Nightingale 	int error;
1459bf21cd93STycho Nightingale 
14606dc98349SAndy Fiddaman 	if (vm_get_lowmem_limit(ctx) > PCI_EMUL_MEMBASE32)
14616dc98349SAndy Fiddaman 		errx(EX_OSERR, "Invalid lowmem limit");
14626dc98349SAndy Fiddaman 
1463bf21cd93STycho Nightingale 	pci_emul_iobase = PCI_EMUL_IOBASE;
14646dc98349SAndy Fiddaman 	pci_emul_membase32 = PCI_EMUL_MEMBASE32;
14656dc98349SAndy Fiddaman 
14666dc98349SAndy Fiddaman 	pci_emul_membase64 = 4*GB + vm_get_highmem_size(ctx);
14676dc98349SAndy Fiddaman 	pci_emul_membase64 = roundup2(pci_emul_membase64, PCI_EMUL_MEMSIZE64);
14686dc98349SAndy Fiddaman 	pci_emul_memlim64 = pci_emul_membase64 + PCI_EMUL_MEMSIZE64;
1469bf21cd93STycho Nightingale 
1470*32640292SAndy Fiddaman 	TAILQ_INIT(&boot_devices);
1471*32640292SAndy Fiddaman 
1472bf21cd93STycho Nightingale 	for (bus = 0; bus < MAXBUSES; bus++) {
14732b948146SAndy Fiddaman 		snprintf(node_name, sizeof(node_name), "pci.%d", bus);
14742b948146SAndy Fiddaman 		nvl = find_config_node(node_name);
14752b948146SAndy Fiddaman 		if (nvl == NULL)
1476bf21cd93STycho Nightingale 			continue;
14772b948146SAndy Fiddaman 		pci_businfo[bus] = calloc(1, sizeof(struct businfo));
14782b948146SAndy Fiddaman 		bi = pci_businfo[bus];
14792b948146SAndy Fiddaman 
14804c87aefeSPatrick Mooney 		/*
1481bf21cd93STycho Nightingale 		 * Keep track of the i/o and memory resources allocated to
1482bf21cd93STycho Nightingale 		 * this bus.
1483bf21cd93STycho Nightingale 		 */
1484bf21cd93STycho Nightingale 		bi->iobase = pci_emul_iobase;
1485bf21cd93STycho Nightingale 		bi->membase32 = pci_emul_membase32;
1486bf21cd93STycho Nightingale 		bi->membase64 = pci_emul_membase64;
1487bf21cd93STycho Nightingale 
14886dc98349SAndy Fiddaman 		/* first run: init devices */
1489bf21cd93STycho Nightingale 		for (slot = 0; slot < MAXSLOTS; slot++) {
1490bf21cd93STycho Nightingale 			si = &bi->slotinfo[slot];
1491bf21cd93STycho Nightingale 			for (func = 0; func < MAXFUNCS; func++) {
1492bf21cd93STycho Nightingale 				fi = &si->si_funcs[func];
14932b948146SAndy Fiddaman 				snprintf(node_name, sizeof(node_name),
14942b948146SAndy Fiddaman 				    "pci.%d.%d.%d", bus, slot, func);
14952b948146SAndy Fiddaman 				nvl = find_config_node(node_name);
14962b948146SAndy Fiddaman 				if (nvl == NULL)
1497bf21cd93STycho Nightingale 					continue;
14982b948146SAndy Fiddaman 
14992b948146SAndy Fiddaman 				fi->fi_config = nvl;
15002b948146SAndy Fiddaman 				emul = get_config_value_node(nvl, "device");
15012b948146SAndy Fiddaman 				if (emul == NULL) {
15022b948146SAndy Fiddaman 					EPRINTLN("pci slot %d:%d:%d: missing "
15032b948146SAndy Fiddaman 					    "\"device\" value", bus, slot, func);
15042b948146SAndy Fiddaman 					return (EINVAL);
15052b948146SAndy Fiddaman 				}
15062b948146SAndy Fiddaman 				pde = pci_emul_finddev(emul);
15072b948146SAndy Fiddaman 				if (pde == NULL) {
15082b948146SAndy Fiddaman 					EPRINTLN("pci slot %d:%d:%d: unknown "
15092b948146SAndy Fiddaman 					    "device \"%s\"", bus, slot, func,
15102b948146SAndy Fiddaman 					    emul);
15112b948146SAndy Fiddaman 					return (EINVAL);
15122b948146SAndy Fiddaman 				}
15132b948146SAndy Fiddaman 				if (pde->pe_alias != NULL) {
15142b948146SAndy Fiddaman 					EPRINTLN("pci slot %d:%d:%d: legacy "
15152b948146SAndy Fiddaman 					    "device \"%s\", use \"%s\" instead",
15162b948146SAndy Fiddaman 					    bus, slot, func, emul,
15172b948146SAndy Fiddaman 					    pde->pe_alias);
15182b948146SAndy Fiddaman 					return (EINVAL);
15192b948146SAndy Fiddaman 				}
15202b948146SAndy Fiddaman 				fi->fi_pde = pde;
1521bf21cd93STycho Nightingale 				error = pci_emul_init(ctx, pde, bus, slot,
1522bf21cd93STycho Nightingale 				    func, fi);
1523bf21cd93STycho Nightingale 				if (error)
1524bf21cd93STycho Nightingale 					return (error);
1525bf21cd93STycho Nightingale 			}
1526bf21cd93STycho Nightingale 		}
1527bf21cd93STycho Nightingale 
15286dc98349SAndy Fiddaman 		/* second run: assign BARs and free list */
15296dc98349SAndy Fiddaman 		struct pci_bar_allocation *bar;
15306dc98349SAndy Fiddaman 		struct pci_bar_allocation *bar_tmp;
15316dc98349SAndy Fiddaman 		TAILQ_FOREACH_SAFE(bar, &pci_bars, chain, bar_tmp) {
15326dc98349SAndy Fiddaman 			pci_emul_assign_bar(bar->pdi, bar->idx, bar->type,
15336dc98349SAndy Fiddaman 			    bar->size);
15346dc98349SAndy Fiddaman 			free(bar);
15356dc98349SAndy Fiddaman 		}
15366dc98349SAndy Fiddaman 		TAILQ_INIT(&pci_bars);
15376dc98349SAndy Fiddaman 
1538bf21cd93STycho Nightingale 		/*
1539bf21cd93STycho Nightingale 		 * Add some slop to the I/O and memory resources decoded by
1540bf21cd93STycho Nightingale 		 * this bus to give a guest some flexibility if it wants to
1541bf21cd93STycho Nightingale 		 * reprogram the BARs.
1542bf21cd93STycho Nightingale 		 */
1543bf21cd93STycho Nightingale 		pci_emul_iobase += BUSIO_ROUNDUP;
1544bf21cd93STycho Nightingale 		pci_emul_iobase = roundup2(pci_emul_iobase, BUSIO_ROUNDUP);
1545bf21cd93STycho Nightingale 		bi->iolimit = pci_emul_iobase;
1546bf21cd93STycho Nightingale 
15476dc98349SAndy Fiddaman 		pci_emul_membase32 += BUSMEM32_ROUNDUP;
1548bf21cd93STycho Nightingale 		pci_emul_membase32 = roundup2(pci_emul_membase32,
15496dc98349SAndy Fiddaman 		    BUSMEM32_ROUNDUP);
1550bf21cd93STycho Nightingale 		bi->memlimit32 = pci_emul_membase32;
1551bf21cd93STycho Nightingale 
15526dc98349SAndy Fiddaman 		pci_emul_membase64 += BUSMEM64_ROUNDUP;
1553bf21cd93STycho Nightingale 		pci_emul_membase64 = roundup2(pci_emul_membase64,
15546dc98349SAndy Fiddaman 		    BUSMEM64_ROUNDUP);
1555bf21cd93STycho Nightingale 		bi->memlimit64 = pci_emul_membase64;
1556bf21cd93STycho Nightingale 	}
1557bf21cd93STycho Nightingale 
1558bf21cd93STycho Nightingale 	/*
1559bf21cd93STycho Nightingale 	 * PCI backends are initialized before routing INTx interrupts
1560bf21cd93STycho Nightingale 	 * so that LPC devices are able to reserve ISA IRQs before
1561bf21cd93STycho Nightingale 	 * routing PIRQ pins.
1562bf21cd93STycho Nightingale 	 */
1563bf21cd93STycho Nightingale 	for (bus = 0; bus < MAXBUSES; bus++) {
1564bf21cd93STycho Nightingale 		if ((bi = pci_businfo[bus]) == NULL)
1565bf21cd93STycho Nightingale 			continue;
1566bf21cd93STycho Nightingale 
1567bf21cd93STycho Nightingale 		for (slot = 0; slot < MAXSLOTS; slot++) {
1568bf21cd93STycho Nightingale 			si = &bi->slotinfo[slot];
1569bf21cd93STycho Nightingale 			for (func = 0; func < MAXFUNCS; func++) {
1570bf21cd93STycho Nightingale 				fi = &si->si_funcs[func];
1571bf21cd93STycho Nightingale 				if (fi->fi_devi == NULL)
1572bf21cd93STycho Nightingale 					continue;
1573bf21cd93STycho Nightingale 				pci_lintr_route(fi->fi_devi);
1574bf21cd93STycho Nightingale 			}
1575bf21cd93STycho Nightingale 		}
1576bf21cd93STycho Nightingale 	}
1577bf21cd93STycho Nightingale 	lpc_pirq_routed();
1578bf21cd93STycho Nightingale 
1579*32640292SAndy Fiddaman 	if ((error = init_bootorder()) != 0) {
1580*32640292SAndy Fiddaman 		warnx("%s: Unable to init bootorder", __func__);
1581*32640292SAndy Fiddaman 		return (error);
1582*32640292SAndy Fiddaman 	}
1583*32640292SAndy Fiddaman 
1584bf21cd93STycho Nightingale 	/*
1585bf21cd93STycho Nightingale 	 * The guest physical memory map looks like the following:
1586bf21cd93STycho Nightingale 	 * [0,		    lowmem)		guest system memory
15876dc98349SAndy Fiddaman 	 * [lowmem,	    0xC0000000)		memory hole (may be absent)
15886dc98349SAndy Fiddaman 	 * [0xC0000000,     0xE0000000)		PCI hole (32-bit BAR allocation)
1589bf21cd93STycho Nightingale 	 * [0xE0000000,	    0xF0000000)		PCI extended config window
1590bf21cd93STycho Nightingale 	 * [0xF0000000,	    4GB)		LAPIC, IOAPIC, HPET, firmware
1591bf21cd93STycho Nightingale 	 * [4GB,	    4GB + highmem)
1592bf21cd93STycho Nightingale 	 */
1593bf21cd93STycho Nightingale 
1594bf21cd93STycho Nightingale 	/*
1595bf21cd93STycho Nightingale 	 * Accesses to memory addresses that are not allocated to system
1596bf21cd93STycho Nightingale 	 * memory or PCI devices return 0xff's.
1597bf21cd93STycho Nightingale 	 */
1598bf21cd93STycho Nightingale 	lowmem = vm_get_lowmem_size(ctx);
1599bf21cd93STycho Nightingale 	bzero(&mr, sizeof(struct mem_range));
1600bf21cd93STycho Nightingale 	mr.name = "PCI hole";
1601bf21cd93STycho Nightingale 	mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
1602bf21cd93STycho Nightingale 	mr.base = lowmem;
1603bf21cd93STycho Nightingale 	mr.size = (4ULL * 1024 * 1024 * 1024) - lowmem;
1604bf21cd93STycho Nightingale 	mr.handler = pci_emul_fallback_handler;
1605bf21cd93STycho Nightingale 	error = register_mem_fallback(&mr);
1606bf21cd93STycho Nightingale 	assert(error == 0);
1607bf21cd93STycho Nightingale 
1608bf21cd93STycho Nightingale 	/* PCI extended config space */
1609bf21cd93STycho Nightingale 	bzero(&mr, sizeof(struct mem_range));
1610bf21cd93STycho Nightingale 	mr.name = "PCI ECFG";
1611bf21cd93STycho Nightingale 	mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
1612bf21cd93STycho Nightingale 	mr.base = PCI_EMUL_ECFG_BASE;
1613bf21cd93STycho Nightingale 	mr.size = PCI_EMUL_ECFG_SIZE;
1614bf21cd93STycho Nightingale 	mr.handler = pci_emul_ecfg_handler;
1615bf21cd93STycho Nightingale 	error = register_mem(&mr);
1616bf21cd93STycho Nightingale 	assert(error == 0);
1617bf21cd93STycho Nightingale 
1618bf21cd93STycho Nightingale 	return (0);
1619bf21cd93STycho Nightingale }
1620bf21cd93STycho Nightingale 
1621bf21cd93STycho Nightingale static void
pci_apic_prt_entry(int bus __unused,int slot,int pin,int pirq_pin __unused,int ioapic_irq,void * arg __unused)162259d65d31SAndy Fiddaman pci_apic_prt_entry(int bus __unused, int slot, int pin, int pirq_pin __unused,
162359d65d31SAndy Fiddaman     int ioapic_irq, void *arg __unused)
1624bf21cd93STycho Nightingale {
1625bf21cd93STycho Nightingale 
1626bf21cd93STycho Nightingale 	dsdt_line("  Package ()");
1627bf21cd93STycho Nightingale 	dsdt_line("  {");
1628bf21cd93STycho Nightingale 	dsdt_line("    0x%X,", slot << 16 | 0xffff);
1629bf21cd93STycho Nightingale 	dsdt_line("    0x%02X,", pin - 1);
1630bf21cd93STycho Nightingale 	dsdt_line("    Zero,");
1631bf21cd93STycho Nightingale 	dsdt_line("    0x%X", ioapic_irq);
1632bf21cd93STycho Nightingale 	dsdt_line("  },");
1633bf21cd93STycho Nightingale }
1634bf21cd93STycho Nightingale 
1635bf21cd93STycho Nightingale static void
pci_pirq_prt_entry(int bus __unused,int slot,int pin,int pirq_pin,int ioapic_irq __unused,void * arg __unused)163659d65d31SAndy Fiddaman pci_pirq_prt_entry(int bus __unused, int slot, int pin, int pirq_pin,
163759d65d31SAndy Fiddaman     int ioapic_irq __unused, void *arg __unused)
1638bf21cd93STycho Nightingale {
1639bf21cd93STycho Nightingale 	char *name;
1640bf21cd93STycho Nightingale 
1641bf21cd93STycho Nightingale 	name = lpc_pirq_name(pirq_pin);
1642bf21cd93STycho Nightingale 	if (name == NULL)
1643bf21cd93STycho Nightingale 		return;
1644bf21cd93STycho Nightingale 	dsdt_line("  Package ()");
1645bf21cd93STycho Nightingale 	dsdt_line("  {");
1646bf21cd93STycho Nightingale 	dsdt_line("    0x%X,", slot << 16 | 0xffff);
1647bf21cd93STycho Nightingale 	dsdt_line("    0x%02X,", pin - 1);
1648bf21cd93STycho Nightingale 	dsdt_line("    %s,", name);
1649bf21cd93STycho Nightingale 	dsdt_line("    0x00");
1650bf21cd93STycho Nightingale 	dsdt_line("  },");
1651bf21cd93STycho Nightingale 	free(name);
1652bf21cd93STycho Nightingale }
1653bf21cd93STycho Nightingale 
1654bf21cd93STycho Nightingale /*
1655bf21cd93STycho Nightingale  * A bhyve virtual machine has a flat PCI hierarchy with a root port
1656bf21cd93STycho Nightingale  * corresponding to each PCI bus.
1657bf21cd93STycho Nightingale  */
1658bf21cd93STycho Nightingale static void
pci_bus_write_dsdt(int bus)1659bf21cd93STycho Nightingale pci_bus_write_dsdt(int bus)
1660bf21cd93STycho Nightingale {
1661bf21cd93STycho Nightingale 	struct businfo *bi;
1662bf21cd93STycho Nightingale 	struct slotinfo *si;
1663bf21cd93STycho Nightingale 	struct pci_devinst *pi;
1664bf21cd93STycho Nightingale 	int count, func, slot;
1665bf21cd93STycho Nightingale 
1666bf21cd93STycho Nightingale 	/*
1667bf21cd93STycho Nightingale 	 * If there are no devices on this 'bus' then just return.
1668bf21cd93STycho Nightingale 	 */
1669bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) == NULL) {
1670bf21cd93STycho Nightingale 		/*
1671bf21cd93STycho Nightingale 		 * Bus 0 is special because it decodes the I/O ports used
1672bf21cd93STycho Nightingale 		 * for PCI config space access even if there are no devices
1673bf21cd93STycho Nightingale 		 * on it.
1674bf21cd93STycho Nightingale 		 */
1675bf21cd93STycho Nightingale 		if (bus != 0)
1676bf21cd93STycho Nightingale 			return;
1677bf21cd93STycho Nightingale 	}
1678bf21cd93STycho Nightingale 
1679bf21cd93STycho Nightingale 	dsdt_line("  Device (PC%02X)", bus);
1680bf21cd93STycho Nightingale 	dsdt_line("  {");
1681bf21cd93STycho Nightingale 	dsdt_line("    Name (_HID, EisaId (\"PNP0A03\"))");
1682bf21cd93STycho Nightingale 
1683bf21cd93STycho Nightingale 	dsdt_line("    Method (_BBN, 0, NotSerialized)");
1684bf21cd93STycho Nightingale 	dsdt_line("    {");
1685bf21cd93STycho Nightingale 	dsdt_line("        Return (0x%08X)", bus);
1686bf21cd93STycho Nightingale 	dsdt_line("    }");
1687bf21cd93STycho Nightingale 	dsdt_line("    Name (_CRS, ResourceTemplate ()");
1688bf21cd93STycho Nightingale 	dsdt_line("    {");
1689bf21cd93STycho Nightingale 	dsdt_line("      WordBusNumber (ResourceProducer, MinFixed, "
1690bf21cd93STycho Nightingale 	    "MaxFixed, PosDecode,");
1691bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Granularity");
1692bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Minimum", bus);
1693bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Maximum", bus);
1694bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Translation Offset");
1695bf21cd93STycho Nightingale 	dsdt_line("        0x0001,             // Length");
1696bf21cd93STycho Nightingale 	dsdt_line("        ,, )");
1697bf21cd93STycho Nightingale 
1698bf21cd93STycho Nightingale 	if (bus == 0) {
1699bf21cd93STycho Nightingale 		dsdt_indent(3);
1700bf21cd93STycho Nightingale 		dsdt_fixed_ioport(0xCF8, 8);
1701bf21cd93STycho Nightingale 		dsdt_unindent(3);
1702bf21cd93STycho Nightingale 
1703bf21cd93STycho Nightingale 		dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1704bf21cd93STycho Nightingale 		    "PosDecode, EntireRange,");
1705bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Granularity");
1706bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Range Minimum");
1707bf21cd93STycho Nightingale 		dsdt_line("        0x0CF7,             // Range Maximum");
1708bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Translation Offset");
1709bf21cd93STycho Nightingale 		dsdt_line("        0x0CF8,             // Length");
1710bf21cd93STycho Nightingale 		dsdt_line("        ,, , TypeStatic)");
1711bf21cd93STycho Nightingale 
1712bf21cd93STycho Nightingale 		dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1713bf21cd93STycho Nightingale 		    "PosDecode, EntireRange,");
1714bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Granularity");
1715bf21cd93STycho Nightingale 		dsdt_line("        0x0D00,             // Range Minimum");
1716bf21cd93STycho Nightingale 		dsdt_line("        0x%04X,             // Range Maximum",
1717bf21cd93STycho Nightingale 		    PCI_EMUL_IOBASE - 1);
1718bf21cd93STycho Nightingale 		dsdt_line("        0x0000,             // Translation Offset");
1719bf21cd93STycho Nightingale 		dsdt_line("        0x%04X,             // Length",
1720bf21cd93STycho Nightingale 		    PCI_EMUL_IOBASE - 0x0D00);
1721bf21cd93STycho Nightingale 		dsdt_line("        ,, , TypeStatic)");
1722bf21cd93STycho Nightingale 
1723bf21cd93STycho Nightingale 		if (bi == NULL) {
1724bf21cd93STycho Nightingale 			dsdt_line("    })");
1725bf21cd93STycho Nightingale 			goto done;
1726bf21cd93STycho Nightingale 		}
1727bf21cd93STycho Nightingale 	}
1728bf21cd93STycho Nightingale 	assert(bi != NULL);
1729bf21cd93STycho Nightingale 
1730bf21cd93STycho Nightingale 	/* i/o window */
1731bf21cd93STycho Nightingale 	dsdt_line("      WordIO (ResourceProducer, MinFixed, MaxFixed, "
1732bf21cd93STycho Nightingale 	    "PosDecode, EntireRange,");
1733bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Granularity");
1734bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Minimum", bi->iobase);
1735bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Range Maximum",
1736bf21cd93STycho Nightingale 	    bi->iolimit - 1);
1737bf21cd93STycho Nightingale 	dsdt_line("        0x0000,             // Translation Offset");
1738bf21cd93STycho Nightingale 	dsdt_line("        0x%04X,             // Length",
1739bf21cd93STycho Nightingale 	    bi->iolimit - bi->iobase);
1740bf21cd93STycho Nightingale 	dsdt_line("        ,, , TypeStatic)");
1741bf21cd93STycho Nightingale 
1742bf21cd93STycho Nightingale 	/* mmio window (32-bit) */
1743bf21cd93STycho Nightingale 	dsdt_line("      DWordMemory (ResourceProducer, PosDecode, "
1744bf21cd93STycho Nightingale 	    "MinFixed, MaxFixed, NonCacheable, ReadWrite,");
1745bf21cd93STycho Nightingale 	dsdt_line("        0x00000000,         // Granularity");
1746bf21cd93STycho Nightingale 	dsdt_line("        0x%08X,         // Range Minimum\n", bi->membase32);
1747bf21cd93STycho Nightingale 	dsdt_line("        0x%08X,         // Range Maximum\n",
1748bf21cd93STycho Nightingale 	    bi->memlimit32 - 1);
1749bf21cd93STycho Nightingale 	dsdt_line("        0x00000000,         // Translation Offset");
1750bf21cd93STycho Nightingale 	dsdt_line("        0x%08X,         // Length\n",
1751bf21cd93STycho Nightingale 	    bi->memlimit32 - bi->membase32);
1752bf21cd93STycho Nightingale 	dsdt_line("        ,, , AddressRangeMemory, TypeStatic)");
1753bf21cd93STycho Nightingale 
1754bf21cd93STycho Nightingale 	/* mmio window (64-bit) */
1755bf21cd93STycho Nightingale 	dsdt_line("      QWordMemory (ResourceProducer, PosDecode, "
1756bf21cd93STycho Nightingale 	    "MinFixed, MaxFixed, NonCacheable, ReadWrite,");
1757bf21cd93STycho Nightingale 	dsdt_line("        0x0000000000000000, // Granularity");
1758bf21cd93STycho Nightingale 	dsdt_line("        0x%016lX, // Range Minimum\n", bi->membase64);
1759bf21cd93STycho Nightingale 	dsdt_line("        0x%016lX, // Range Maximum\n",
1760bf21cd93STycho Nightingale 	    bi->memlimit64 - 1);
1761bf21cd93STycho Nightingale 	dsdt_line("        0x0000000000000000, // Translation Offset");
1762bf21cd93STycho Nightingale 	dsdt_line("        0x%016lX, // Length\n",
1763bf21cd93STycho Nightingale 	    bi->memlimit64 - bi->membase64);
1764bf21cd93STycho Nightingale 	dsdt_line("        ,, , AddressRangeMemory, TypeStatic)");
1765bf21cd93STycho Nightingale 	dsdt_line("    })");
1766bf21cd93STycho Nightingale 
1767bf21cd93STycho Nightingale 	count = pci_count_lintr(bus);
1768bf21cd93STycho Nightingale 	if (count != 0) {
1769bf21cd93STycho Nightingale 		dsdt_indent(2);
1770bf21cd93STycho Nightingale 		dsdt_line("Name (PPRT, Package ()");
1771bf21cd93STycho Nightingale 		dsdt_line("{");
1772bf21cd93STycho Nightingale 		pci_walk_lintr(bus, pci_pirq_prt_entry, NULL);
17734c87aefeSPatrick Mooney 		dsdt_line("})");
1774bf21cd93STycho Nightingale 		dsdt_line("Name (APRT, Package ()");
1775bf21cd93STycho Nightingale 		dsdt_line("{");
1776bf21cd93STycho Nightingale 		pci_walk_lintr(bus, pci_apic_prt_entry, NULL);
17774c87aefeSPatrick Mooney 		dsdt_line("})");
1778bf21cd93STycho Nightingale 		dsdt_line("Method (_PRT, 0, NotSerialized)");
1779bf21cd93STycho Nightingale 		dsdt_line("{");
1780bf21cd93STycho Nightingale 		dsdt_line("  If (PICM)");
1781bf21cd93STycho Nightingale 		dsdt_line("  {");
1782bf21cd93STycho Nightingale 		dsdt_line("    Return (APRT)");
1783bf21cd93STycho Nightingale 		dsdt_line("  }");
1784bf21cd93STycho Nightingale 		dsdt_line("  Else");
1785bf21cd93STycho Nightingale 		dsdt_line("  {");
1786bf21cd93STycho Nightingale 		dsdt_line("    Return (PPRT)");
1787bf21cd93STycho Nightingale 		dsdt_line("  }");
1788bf21cd93STycho Nightingale 		dsdt_line("}");
1789bf21cd93STycho Nightingale 		dsdt_unindent(2);
1790bf21cd93STycho Nightingale 	}
1791bf21cd93STycho Nightingale 
1792bf21cd93STycho Nightingale 	dsdt_indent(2);
1793bf21cd93STycho Nightingale 	for (slot = 0; slot < MAXSLOTS; slot++) {
1794bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
1795bf21cd93STycho Nightingale 		for (func = 0; func < MAXFUNCS; func++) {
1796bf21cd93STycho Nightingale 			pi = si->si_funcs[func].fi_devi;
1797bf21cd93STycho Nightingale 			if (pi != NULL && pi->pi_d->pe_write_dsdt != NULL)
1798bf21cd93STycho Nightingale 				pi->pi_d->pe_write_dsdt(pi);
1799bf21cd93STycho Nightingale 		}
1800bf21cd93STycho Nightingale 	}
1801bf21cd93STycho Nightingale 	dsdt_unindent(2);
1802bf21cd93STycho Nightingale done:
1803bf21cd93STycho Nightingale 	dsdt_line("  }");
1804bf21cd93STycho Nightingale }
1805bf21cd93STycho Nightingale 
1806bf21cd93STycho Nightingale void
pci_write_dsdt(void)1807bf21cd93STycho Nightingale pci_write_dsdt(void)
1808bf21cd93STycho Nightingale {
1809bf21cd93STycho Nightingale 	int bus;
1810bf21cd93STycho Nightingale 
1811bf21cd93STycho Nightingale 	dsdt_indent(1);
1812bf21cd93STycho Nightingale 	dsdt_line("Name (PICM, 0x00)");
1813bf21cd93STycho Nightingale 	dsdt_line("Method (_PIC, 1, NotSerialized)");
1814bf21cd93STycho Nightingale 	dsdt_line("{");
1815bf21cd93STycho Nightingale 	dsdt_line("  Store (Arg0, PICM)");
1816bf21cd93STycho Nightingale 	dsdt_line("}");
1817bf21cd93STycho Nightingale 	dsdt_line("");
1818bf21cd93STycho Nightingale 	dsdt_line("Scope (_SB)");
1819bf21cd93STycho Nightingale 	dsdt_line("{");
1820bf21cd93STycho Nightingale 	for (bus = 0; bus < MAXBUSES; bus++)
1821bf21cd93STycho Nightingale 		pci_bus_write_dsdt(bus);
1822bf21cd93STycho Nightingale 	dsdt_line("}");
1823bf21cd93STycho Nightingale 	dsdt_unindent(1);
1824bf21cd93STycho Nightingale }
1825bf21cd93STycho Nightingale 
1826bf21cd93STycho Nightingale int
pci_bus_configured(int bus)1827bf21cd93STycho Nightingale pci_bus_configured(int bus)
1828bf21cd93STycho Nightingale {
1829bf21cd93STycho Nightingale 	assert(bus >= 0 && bus < MAXBUSES);
1830bf21cd93STycho Nightingale 	return (pci_businfo[bus] != NULL);
1831bf21cd93STycho Nightingale }
1832bf21cd93STycho Nightingale 
1833bf21cd93STycho Nightingale int
pci_msi_enabled(struct pci_devinst * pi)1834bf21cd93STycho Nightingale pci_msi_enabled(struct pci_devinst *pi)
1835bf21cd93STycho Nightingale {
1836bf21cd93STycho Nightingale 	return (pi->pi_msi.enabled);
1837bf21cd93STycho Nightingale }
1838bf21cd93STycho Nightingale 
1839bf21cd93STycho Nightingale int
pci_msi_maxmsgnum(struct pci_devinst * pi)1840bf21cd93STycho Nightingale pci_msi_maxmsgnum(struct pci_devinst *pi)
1841bf21cd93STycho Nightingale {
1842bf21cd93STycho Nightingale 	if (pi->pi_msi.enabled)
1843bf21cd93STycho Nightingale 		return (pi->pi_msi.maxmsgnum);
1844bf21cd93STycho Nightingale 	else
1845bf21cd93STycho Nightingale 		return (0);
1846bf21cd93STycho Nightingale }
1847bf21cd93STycho Nightingale 
1848bf21cd93STycho Nightingale int
pci_msix_enabled(struct pci_devinst * pi)1849bf21cd93STycho Nightingale pci_msix_enabled(struct pci_devinst *pi)
1850bf21cd93STycho Nightingale {
1851bf21cd93STycho Nightingale 
1852bf21cd93STycho Nightingale 	return (pi->pi_msix.enabled && !pi->pi_msi.enabled);
1853bf21cd93STycho Nightingale }
1854bf21cd93STycho Nightingale 
1855bf21cd93STycho Nightingale void
pci_generate_msix(struct pci_devinst * pi,int index)1856bf21cd93STycho Nightingale pci_generate_msix(struct pci_devinst *pi, int index)
1857bf21cd93STycho Nightingale {
1858bf21cd93STycho Nightingale 	struct msix_table_entry *mte;
1859bf21cd93STycho Nightingale 
1860bf21cd93STycho Nightingale 	if (!pci_msix_enabled(pi))
1861bf21cd93STycho Nightingale 		return;
1862bf21cd93STycho Nightingale 
1863bf21cd93STycho Nightingale 	if (pi->pi_msix.function_mask)
1864bf21cd93STycho Nightingale 		return;
1865bf21cd93STycho Nightingale 
1866bf21cd93STycho Nightingale 	if (index >= pi->pi_msix.table_count)
1867bf21cd93STycho Nightingale 		return;
1868bf21cd93STycho Nightingale 
1869bf21cd93STycho Nightingale 	mte = &pi->pi_msix.table[index];
1870bf21cd93STycho Nightingale 	if ((mte->vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
1871bf21cd93STycho Nightingale 		/* XXX Set PBA bit if interrupt is disabled */
1872bf21cd93STycho Nightingale 		vm_lapic_msi(pi->pi_vmctx, mte->addr, mte->msg_data);
1873bf21cd93STycho Nightingale 	}
1874bf21cd93STycho Nightingale }
1875bf21cd93STycho Nightingale 
1876bf21cd93STycho Nightingale void
pci_generate_msi(struct pci_devinst * pi,int index)1877bf21cd93STycho Nightingale pci_generate_msi(struct pci_devinst *pi, int index)
1878bf21cd93STycho Nightingale {
1879bf21cd93STycho Nightingale 
1880bf21cd93STycho Nightingale 	if (pci_msi_enabled(pi) && index < pci_msi_maxmsgnum(pi)) {
1881bf21cd93STycho Nightingale 		vm_lapic_msi(pi->pi_vmctx, pi->pi_msi.addr,
1882bf21cd93STycho Nightingale 			     pi->pi_msi.msg_data + index);
1883bf21cd93STycho Nightingale 	}
1884bf21cd93STycho Nightingale }
1885bf21cd93STycho Nightingale 
1886bf21cd93STycho Nightingale static bool
pci_lintr_permitted(struct pci_devinst * pi)1887bf21cd93STycho Nightingale pci_lintr_permitted(struct pci_devinst *pi)
1888bf21cd93STycho Nightingale {
1889bf21cd93STycho Nightingale 	uint16_t cmd;
1890bf21cd93STycho Nightingale 
1891bf21cd93STycho Nightingale 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
1892bf21cd93STycho Nightingale 	return (!(pi->pi_msi.enabled || pi->pi_msix.enabled ||
1893bf21cd93STycho Nightingale 		(cmd & PCIM_CMD_INTxDIS)));
1894bf21cd93STycho Nightingale }
1895bf21cd93STycho Nightingale 
1896bf21cd93STycho Nightingale void
pci_lintr_request(struct pci_devinst * pi)1897bf21cd93STycho Nightingale pci_lintr_request(struct pci_devinst *pi)
1898bf21cd93STycho Nightingale {
1899bf21cd93STycho Nightingale 	struct businfo *bi;
1900bf21cd93STycho Nightingale 	struct slotinfo *si;
1901bf21cd93STycho Nightingale 	int bestpin, bestcount, pin;
1902bf21cd93STycho Nightingale 
1903bf21cd93STycho Nightingale 	bi = pci_businfo[pi->pi_bus];
1904bf21cd93STycho Nightingale 	assert(bi != NULL);
1905bf21cd93STycho Nightingale 
1906bf21cd93STycho Nightingale 	/*
1907bf21cd93STycho Nightingale 	 * Just allocate a pin from our slot.  The pin will be
1908bf21cd93STycho Nightingale 	 * assigned IRQs later when interrupts are routed.
1909bf21cd93STycho Nightingale 	 */
1910bf21cd93STycho Nightingale 	si = &bi->slotinfo[pi->pi_slot];
1911bf21cd93STycho Nightingale 	bestpin = 0;
1912bf21cd93STycho Nightingale 	bestcount = si->si_intpins[0].ii_count;
1913bf21cd93STycho Nightingale 	for (pin = 1; pin < 4; pin++) {
1914bf21cd93STycho Nightingale 		if (si->si_intpins[pin].ii_count < bestcount) {
1915bf21cd93STycho Nightingale 			bestpin = pin;
1916bf21cd93STycho Nightingale 			bestcount = si->si_intpins[pin].ii_count;
1917bf21cd93STycho Nightingale 		}
1918bf21cd93STycho Nightingale 	}
1919bf21cd93STycho Nightingale 
1920bf21cd93STycho Nightingale 	si->si_intpins[bestpin].ii_count++;
1921bf21cd93STycho Nightingale 	pi->pi_lintr.pin = bestpin + 1;
1922bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_INTPIN, bestpin + 1);
1923bf21cd93STycho Nightingale }
1924bf21cd93STycho Nightingale 
1925bf21cd93STycho Nightingale static void
pci_lintr_route(struct pci_devinst * pi)1926bf21cd93STycho Nightingale pci_lintr_route(struct pci_devinst *pi)
1927bf21cd93STycho Nightingale {
1928bf21cd93STycho Nightingale 	struct businfo *bi;
1929bf21cd93STycho Nightingale 	struct intxinfo *ii;
1930bf21cd93STycho Nightingale 
1931bf21cd93STycho Nightingale 	if (pi->pi_lintr.pin == 0)
1932bf21cd93STycho Nightingale 		return;
1933bf21cd93STycho Nightingale 
1934bf21cd93STycho Nightingale 	bi = pci_businfo[pi->pi_bus];
1935bf21cd93STycho Nightingale 	assert(bi != NULL);
1936bf21cd93STycho Nightingale 	ii = &bi->slotinfo[pi->pi_slot].si_intpins[pi->pi_lintr.pin - 1];
1937bf21cd93STycho Nightingale 
1938bf21cd93STycho Nightingale 	/*
1939bf21cd93STycho Nightingale 	 * Attempt to allocate an I/O APIC pin for this intpin if one
1940bf21cd93STycho Nightingale 	 * is not yet assigned.
1941bf21cd93STycho Nightingale 	 */
1942bf21cd93STycho Nightingale 	if (ii->ii_ioapic_irq == 0)
19434c87aefeSPatrick Mooney 		ii->ii_ioapic_irq = ioapic_pci_alloc_irq(pi);
1944bf21cd93STycho Nightingale 	assert(ii->ii_ioapic_irq > 0);
1945bf21cd93STycho Nightingale 
1946bf21cd93STycho Nightingale 	/*
1947bf21cd93STycho Nightingale 	 * Attempt to allocate a PIRQ pin for this intpin if one is
1948bf21cd93STycho Nightingale 	 * not yet assigned.
1949bf21cd93STycho Nightingale 	 */
1950bf21cd93STycho Nightingale 	if (ii->ii_pirq_pin == 0)
19514c87aefeSPatrick Mooney 		ii->ii_pirq_pin = pirq_alloc_pin(pi);
1952bf21cd93STycho Nightingale 	assert(ii->ii_pirq_pin > 0);
1953bf21cd93STycho Nightingale 
1954bf21cd93STycho Nightingale 	pi->pi_lintr.ioapic_irq = ii->ii_ioapic_irq;
1955bf21cd93STycho Nightingale 	pi->pi_lintr.pirq_pin = ii->ii_pirq_pin;
1956bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_INTLINE, pirq_irq(ii->ii_pirq_pin));
1957bf21cd93STycho Nightingale }
1958bf21cd93STycho Nightingale 
1959bf21cd93STycho Nightingale void
pci_lintr_assert(struct pci_devinst * pi)1960bf21cd93STycho Nightingale pci_lintr_assert(struct pci_devinst *pi)
1961bf21cd93STycho Nightingale {
1962bf21cd93STycho Nightingale 
1963bf21cd93STycho Nightingale 	assert(pi->pi_lintr.pin > 0);
1964bf21cd93STycho Nightingale 
1965bf21cd93STycho Nightingale 	pthread_mutex_lock(&pi->pi_lintr.lock);
1966bf21cd93STycho Nightingale 	if (pi->pi_lintr.state == IDLE) {
1967bf21cd93STycho Nightingale 		if (pci_lintr_permitted(pi)) {
1968bf21cd93STycho Nightingale 			pi->pi_lintr.state = ASSERTED;
1969bf21cd93STycho Nightingale 			pci_irq_assert(pi);
1970bf21cd93STycho Nightingale 		} else
1971bf21cd93STycho Nightingale 			pi->pi_lintr.state = PENDING;
1972bf21cd93STycho Nightingale 	}
1973bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pi->pi_lintr.lock);
1974bf21cd93STycho Nightingale }
1975bf21cd93STycho Nightingale 
1976bf21cd93STycho Nightingale void
pci_lintr_deassert(struct pci_devinst * pi)1977bf21cd93STycho Nightingale pci_lintr_deassert(struct pci_devinst *pi)
1978bf21cd93STycho Nightingale {
1979bf21cd93STycho Nightingale 
1980bf21cd93STycho Nightingale 	assert(pi->pi_lintr.pin > 0);
1981bf21cd93STycho Nightingale 
1982bf21cd93STycho Nightingale 	pthread_mutex_lock(&pi->pi_lintr.lock);
1983bf21cd93STycho Nightingale 	if (pi->pi_lintr.state == ASSERTED) {
1984bf21cd93STycho Nightingale 		pi->pi_lintr.state = IDLE;
1985bf21cd93STycho Nightingale 		pci_irq_deassert(pi);
1986bf21cd93STycho Nightingale 	} else if (pi->pi_lintr.state == PENDING)
1987bf21cd93STycho Nightingale 		pi->pi_lintr.state = IDLE;
1988bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pi->pi_lintr.lock);
1989bf21cd93STycho Nightingale }
1990bf21cd93STycho Nightingale 
1991bf21cd93STycho Nightingale static void
pci_lintr_update(struct pci_devinst * pi)1992bf21cd93STycho Nightingale pci_lintr_update(struct pci_devinst *pi)
1993bf21cd93STycho Nightingale {
1994bf21cd93STycho Nightingale 
1995bf21cd93STycho Nightingale 	pthread_mutex_lock(&pi->pi_lintr.lock);
1996bf21cd93STycho Nightingale 	if (pi->pi_lintr.state == ASSERTED && !pci_lintr_permitted(pi)) {
1997bf21cd93STycho Nightingale 		pci_irq_deassert(pi);
1998bf21cd93STycho Nightingale 		pi->pi_lintr.state = PENDING;
1999bf21cd93STycho Nightingale 	} else if (pi->pi_lintr.state == PENDING && pci_lintr_permitted(pi)) {
2000bf21cd93STycho Nightingale 		pi->pi_lintr.state = ASSERTED;
2001bf21cd93STycho Nightingale 		pci_irq_assert(pi);
2002bf21cd93STycho Nightingale 	}
2003bf21cd93STycho Nightingale 	pthread_mutex_unlock(&pi->pi_lintr.lock);
2004b22a70abSPatrick Mooney #ifndef __FreeBSD__
2005b22a70abSPatrick Mooney 	if (pi->pi_d->pe_lintrupdate != NULL) {
2006b22a70abSPatrick Mooney 		pi->pi_d->pe_lintrupdate(pi);
2007b22a70abSPatrick Mooney 	}
2008b22a70abSPatrick Mooney #endif /* __FreeBSD__ */
2009bf21cd93STycho Nightingale }
2010bf21cd93STycho Nightingale 
2011bf21cd93STycho Nightingale int
pci_count_lintr(int bus)2012bf21cd93STycho Nightingale pci_count_lintr(int bus)
2013bf21cd93STycho Nightingale {
2014bf21cd93STycho Nightingale 	int count, slot, pin;
2015bf21cd93STycho Nightingale 	struct slotinfo *slotinfo;
2016bf21cd93STycho Nightingale 
2017bf21cd93STycho Nightingale 	count = 0;
2018bf21cd93STycho Nightingale 	if (pci_businfo[bus] != NULL) {
2019bf21cd93STycho Nightingale 		for (slot = 0; slot < MAXSLOTS; slot++) {
2020bf21cd93STycho Nightingale 			slotinfo = &pci_businfo[bus]->slotinfo[slot];
2021bf21cd93STycho Nightingale 			for (pin = 0; pin < 4; pin++) {
2022bf21cd93STycho Nightingale 				if (slotinfo->si_intpins[pin].ii_count != 0)
2023bf21cd93STycho Nightingale 					count++;
2024bf21cd93STycho Nightingale 			}
2025bf21cd93STycho Nightingale 		}
2026bf21cd93STycho Nightingale 	}
2027bf21cd93STycho Nightingale 	return (count);
2028bf21cd93STycho Nightingale }
2029bf21cd93STycho Nightingale 
2030bf21cd93STycho Nightingale void
pci_walk_lintr(int bus,pci_lintr_cb cb,void * arg)2031bf21cd93STycho Nightingale pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg)
2032bf21cd93STycho Nightingale {
2033bf21cd93STycho Nightingale 	struct businfo *bi;
2034bf21cd93STycho Nightingale 	struct slotinfo *si;
2035bf21cd93STycho Nightingale 	struct intxinfo *ii;
2036bf21cd93STycho Nightingale 	int slot, pin;
2037bf21cd93STycho Nightingale 
2038bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) == NULL)
2039bf21cd93STycho Nightingale 		return;
2040bf21cd93STycho Nightingale 
2041bf21cd93STycho Nightingale 	for (slot = 0; slot < MAXSLOTS; slot++) {
2042bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
2043bf21cd93STycho Nightingale 		for (pin = 0; pin < 4; pin++) {
2044bf21cd93STycho Nightingale 			ii = &si->si_intpins[pin];
2045bf21cd93STycho Nightingale 			if (ii->ii_count != 0)
2046bf21cd93STycho Nightingale 				cb(bus, slot, pin + 1, ii->ii_pirq_pin,
2047bf21cd93STycho Nightingale 				    ii->ii_ioapic_irq, arg);
2048bf21cd93STycho Nightingale 		}
2049bf21cd93STycho Nightingale 	}
2050bf21cd93STycho Nightingale }
2051bf21cd93STycho Nightingale 
2052bf21cd93STycho Nightingale /*
2053bf21cd93STycho Nightingale  * Return 1 if the emulated device in 'slot' is a multi-function device.
2054bf21cd93STycho Nightingale  * Return 0 otherwise.
2055bf21cd93STycho Nightingale  */
2056bf21cd93STycho Nightingale static int
pci_emul_is_mfdev(int bus,int slot)2057bf21cd93STycho Nightingale pci_emul_is_mfdev(int bus, int slot)
2058bf21cd93STycho Nightingale {
2059bf21cd93STycho Nightingale 	struct businfo *bi;
2060bf21cd93STycho Nightingale 	struct slotinfo *si;
2061bf21cd93STycho Nightingale 	int f, numfuncs;
2062bf21cd93STycho Nightingale 
2063bf21cd93STycho Nightingale 	numfuncs = 0;
2064bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) != NULL) {
2065bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
2066bf21cd93STycho Nightingale 		for (f = 0; f < MAXFUNCS; f++) {
2067bf21cd93STycho Nightingale 			if (si->si_funcs[f].fi_devi != NULL) {
2068bf21cd93STycho Nightingale 				numfuncs++;
2069bf21cd93STycho Nightingale 			}
2070bf21cd93STycho Nightingale 		}
2071bf21cd93STycho Nightingale 	}
2072bf21cd93STycho Nightingale 	return (numfuncs > 1);
2073bf21cd93STycho Nightingale }
2074bf21cd93STycho Nightingale 
2075bf21cd93STycho Nightingale /*
2076bf21cd93STycho Nightingale  * Ensure that the PCIM_MFDEV bit is properly set (or unset) depending on
2077bf21cd93STycho Nightingale  * whether or not is a multi-function being emulated in the pci 'slot'.
2078bf21cd93STycho Nightingale  */
2079bf21cd93STycho Nightingale static void
pci_emul_hdrtype_fixup(int bus,int slot,int off,int bytes,uint32_t * rv)2080bf21cd93STycho Nightingale pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv)
2081bf21cd93STycho Nightingale {
2082bf21cd93STycho Nightingale 	int mfdev;
2083bf21cd93STycho Nightingale 
2084bf21cd93STycho Nightingale 	if (off <= PCIR_HDRTYPE && off + bytes > PCIR_HDRTYPE) {
2085bf21cd93STycho Nightingale 		mfdev = pci_emul_is_mfdev(bus, slot);
2086bf21cd93STycho Nightingale 		switch (bytes) {
2087bf21cd93STycho Nightingale 		case 1:
2088bf21cd93STycho Nightingale 		case 2:
2089bf21cd93STycho Nightingale 			*rv &= ~PCIM_MFDEV;
2090bf21cd93STycho Nightingale 			if (mfdev) {
2091bf21cd93STycho Nightingale 				*rv |= PCIM_MFDEV;
2092bf21cd93STycho Nightingale 			}
2093bf21cd93STycho Nightingale 			break;
2094bf21cd93STycho Nightingale 		case 4:
2095bf21cd93STycho Nightingale 			*rv &= ~(PCIM_MFDEV << 16);
2096bf21cd93STycho Nightingale 			if (mfdev) {
2097bf21cd93STycho Nightingale 				*rv |= (PCIM_MFDEV << 16);
2098bf21cd93STycho Nightingale 			}
2099bf21cd93STycho Nightingale 			break;
2100bf21cd93STycho Nightingale 		}
2101bf21cd93STycho Nightingale 	}
2102bf21cd93STycho Nightingale }
2103bf21cd93STycho Nightingale 
210484659b24SMichael Zeller /*
210584659b24SMichael Zeller  * Update device state in response to changes to the PCI command
210684659b24SMichael Zeller  * register.
210784659b24SMichael Zeller  */
210884659b24SMichael Zeller void
pci_emul_cmd_changed(struct pci_devinst * pi,uint16_t old)210984659b24SMichael Zeller pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old)
2110bf21cd93STycho Nightingale {
211184659b24SMichael Zeller 	int i;
211284659b24SMichael Zeller 	uint16_t changed, new;
2113bf21cd93STycho Nightingale 
211484659b24SMichael Zeller 	new = pci_get_cfgdata16(pi, PCIR_COMMAND);
211584659b24SMichael Zeller 	changed = old ^ new;
2116bf21cd93STycho Nightingale 
2117bf21cd93STycho Nightingale 	/*
2118bf21cd93STycho Nightingale 	 * If the MMIO or I/O address space decoding has changed then
2119bf21cd93STycho Nightingale 	 * register/unregister all BARs that decode that address space.
2120bf21cd93STycho Nightingale 	 */
2121d7b72f7bSAndy Fiddaman 	for (i = 0; i <= PCI_BARMAX_WITH_ROM; i++) {
2122bf21cd93STycho Nightingale 		switch (pi->pi_bar[i].type) {
2123bf21cd93STycho Nightingale 			case PCIBAR_NONE:
2124bf21cd93STycho Nightingale 			case PCIBAR_MEMHI64:
2125bf21cd93STycho Nightingale 				break;
2126bf21cd93STycho Nightingale 			case PCIBAR_IO:
2127bf21cd93STycho Nightingale 				/* I/O address space decoding changed? */
21284c87aefeSPatrick Mooney 				if (changed & PCIM_CMD_PORTEN) {
212984659b24SMichael Zeller 					if (new & PCIM_CMD_PORTEN)
2130bf21cd93STycho Nightingale 						register_bar(pi, i);
2131bf21cd93STycho Nightingale 					else
2132bf21cd93STycho Nightingale 						unregister_bar(pi, i);
2133bf21cd93STycho Nightingale 				}
2134bf21cd93STycho Nightingale 				break;
2135d7b72f7bSAndy Fiddaman 			case PCIBAR_ROM:
2136d7b72f7bSAndy Fiddaman 				/* skip (un-)register of ROM if it disabled */
2137d7b72f7bSAndy Fiddaman 				if (!romen(pi))
2138d7b72f7bSAndy Fiddaman 					break;
2139d7b72f7bSAndy Fiddaman 				/* fallthrough */
2140bf21cd93STycho Nightingale 			case PCIBAR_MEM32:
2141bf21cd93STycho Nightingale 			case PCIBAR_MEM64:
2142bf21cd93STycho Nightingale 				/* MMIO address space decoding changed? */
21434c87aefeSPatrick Mooney 				if (changed & PCIM_CMD_MEMEN) {
214484659b24SMichael Zeller 					if (new & PCIM_CMD_MEMEN)
2145bf21cd93STycho Nightingale 						register_bar(pi, i);
2146bf21cd93STycho Nightingale 					else
2147bf21cd93STycho Nightingale 						unregister_bar(pi, i);
2148bf21cd93STycho Nightingale 				}
21494c87aefeSPatrick Mooney 				break;
2150bf21cd93STycho Nightingale 			default:
21514c87aefeSPatrick Mooney 				assert(0);
2152bf21cd93STycho Nightingale 		}
2153bf21cd93STycho Nightingale 	}
2154bf21cd93STycho Nightingale 
2155bf21cd93STycho Nightingale 	/*
2156bf21cd93STycho Nightingale 	 * If INTx has been unmasked and is pending, assert the
2157bf21cd93STycho Nightingale 	 * interrupt.
2158bf21cd93STycho Nightingale 	 */
2159bf21cd93STycho Nightingale 	pci_lintr_update(pi);
21604c87aefeSPatrick Mooney }
2161bf21cd93STycho Nightingale 
216284659b24SMichael Zeller static void
pci_emul_cmdsts_write(struct pci_devinst * pi,int coff,uint32_t new,int bytes)216384659b24SMichael Zeller pci_emul_cmdsts_write(struct pci_devinst *pi, int coff, uint32_t new, int bytes)
216484659b24SMichael Zeller {
216584659b24SMichael Zeller 	int rshift;
216684659b24SMichael Zeller 	uint32_t cmd, old, readonly;
216784659b24SMichael Zeller 
216884659b24SMichael Zeller 	cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);	/* stash old value */
216984659b24SMichael Zeller 
217084659b24SMichael Zeller 	/*
217184659b24SMichael Zeller 	 * From PCI Local Bus Specification 3.0 sections 6.2.2 and 6.2.3.
217284659b24SMichael Zeller 	 *
217384659b24SMichael Zeller 	 * XXX Bits 8, 11, 12, 13, 14 and 15 in the status register are
217484659b24SMichael Zeller 	 * 'write 1 to clear'. However these bits are not set to '1' by
217584659b24SMichael Zeller 	 * any device emulation so it is simpler to treat them as readonly.
217684659b24SMichael Zeller 	 */
217784659b24SMichael Zeller 	rshift = (coff & 0x3) * 8;
217884659b24SMichael Zeller 	readonly = 0xFFFFF880 >> rshift;
217984659b24SMichael Zeller 
218084659b24SMichael Zeller 	old = CFGREAD(pi, coff, bytes);
218184659b24SMichael Zeller 	new &= ~readonly;
218284659b24SMichael Zeller 	new |= (old & readonly);
218384659b24SMichael Zeller 	CFGWRITE(pi, coff, new, bytes);			/* update config */
218484659b24SMichael Zeller 
218584659b24SMichael Zeller 	pci_emul_cmd_changed(pi, cmd);
218684659b24SMichael Zeller }
218784659b24SMichael Zeller 
2188bf21cd93STycho Nightingale static void
pci_cfgrw(int in,int bus,int slot,int func,int coff,int bytes,uint32_t * valp)2189*32640292SAndy Fiddaman pci_cfgrw(int in, int bus, int slot, int func, int coff, int bytes,
2190*32640292SAndy Fiddaman     uint32_t *valp)
2191bf21cd93STycho Nightingale {
2192bf21cd93STycho Nightingale 	struct businfo *bi;
2193bf21cd93STycho Nightingale 	struct slotinfo *si;
2194bf21cd93STycho Nightingale 	struct pci_devinst *pi;
2195bf21cd93STycho Nightingale 	struct pci_devemu *pe;
2196bf21cd93STycho Nightingale 	int idx, needcfg;
21974c87aefeSPatrick Mooney 	uint64_t addr, mask;
21984c87aefeSPatrick Mooney 	uint64_t bar = 0;
2199bf21cd93STycho Nightingale 
2200bf21cd93STycho Nightingale 	if ((bi = pci_businfo[bus]) != NULL) {
2201bf21cd93STycho Nightingale 		si = &bi->slotinfo[slot];
2202bf21cd93STycho Nightingale 		pi = si->si_funcs[func].fi_devi;
2203bf21cd93STycho Nightingale 	} else
2204bf21cd93STycho Nightingale 		pi = NULL;
2205bf21cd93STycho Nightingale 
2206bf21cd93STycho Nightingale 	/*
2207bf21cd93STycho Nightingale 	 * Just return if there is no device at this slot:func or if the
2208bf21cd93STycho Nightingale 	 * the guest is doing an un-aligned access.
2209bf21cd93STycho Nightingale 	 */
2210bf21cd93STycho Nightingale 	if (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) ||
2211bf21cd93STycho Nightingale 	    (coff & (bytes - 1)) != 0) {
2212bf21cd93STycho Nightingale 		if (in)
2213*32640292SAndy Fiddaman 			*valp = 0xffffffff;
2214bf21cd93STycho Nightingale 		return;
2215bf21cd93STycho Nightingale 	}
2216bf21cd93STycho Nightingale 
2217bf21cd93STycho Nightingale 	/*
2218bf21cd93STycho Nightingale 	 * Ignore all writes beyond the standard config space and return all
2219bf21cd93STycho Nightingale 	 * ones on reads.
2220bf21cd93STycho Nightingale 	 */
2221bf21cd93STycho Nightingale 	if (coff >= PCI_REGMAX + 1) {
2222bf21cd93STycho Nightingale 		if (in) {
2223*32640292SAndy Fiddaman 			*valp = 0xffffffff;
2224bf21cd93STycho Nightingale 			/*
2225bf21cd93STycho Nightingale 			 * Extended capabilities begin at offset 256 in config
2226bf21cd93STycho Nightingale 			 * space. Absence of extended capabilities is signaled
2227bf21cd93STycho Nightingale 			 * with all 0s in the extended capability header at
2228bf21cd93STycho Nightingale 			 * offset 256.
2229bf21cd93STycho Nightingale 			 */
2230bf21cd93STycho Nightingale 			if (coff <= PCI_REGMAX + 4)
2231*32640292SAndy Fiddaman 				*valp = 0x00000000;
2232bf21cd93STycho Nightingale 		}
2233bf21cd93STycho Nightingale 		return;
2234bf21cd93STycho Nightingale 	}
2235bf21cd93STycho Nightingale 
2236bf21cd93STycho Nightingale 	pe = pi->pi_d;
2237bf21cd93STycho Nightingale 
2238bf21cd93STycho Nightingale 	/*
2239bf21cd93STycho Nightingale 	 * Config read
2240bf21cd93STycho Nightingale 	 */
2241bf21cd93STycho Nightingale 	if (in) {
2242bf21cd93STycho Nightingale 		/* Let the device emulation override the default handler */
2243bf21cd93STycho Nightingale 		if (pe->pe_cfgread != NULL) {
2244*32640292SAndy Fiddaman 			needcfg = pe->pe_cfgread(pi, coff, bytes, valp);
2245bf21cd93STycho Nightingale 		} else {
2246bf21cd93STycho Nightingale 			needcfg = 1;
2247bf21cd93STycho Nightingale 		}
2248bf21cd93STycho Nightingale 
22494c87aefeSPatrick Mooney 		if (needcfg)
2250*32640292SAndy Fiddaman 			*valp = CFGREAD(pi, coff, bytes);
2251bf21cd93STycho Nightingale 
2252*32640292SAndy Fiddaman 		pci_emul_hdrtype_fixup(bus, slot, coff, bytes, valp);
2253bf21cd93STycho Nightingale 	} else {
2254bf21cd93STycho Nightingale 		/* Let the device emulation override the default handler */
2255bf21cd93STycho Nightingale 		if (pe->pe_cfgwrite != NULL &&
2256*32640292SAndy Fiddaman 		    (*pe->pe_cfgwrite)(pi, coff, bytes, *valp) == 0)
2257bf21cd93STycho Nightingale 			return;
2258bf21cd93STycho Nightingale 
2259bf21cd93STycho Nightingale 		/*
2260d7b72f7bSAndy Fiddaman 		 * Special handling for write to BAR and ROM registers
2261bf21cd93STycho Nightingale 		 */
22624f3f3e9aSAndy Fiddaman 		if (is_pcir_bar(coff) || is_pcir_bios(coff)) {
2263bf21cd93STycho Nightingale 			/*
2264bf21cd93STycho Nightingale 			 * Ignore writes to BAR registers that are not
2265bf21cd93STycho Nightingale 			 * 4-byte aligned.
2266bf21cd93STycho Nightingale 			 */
2267bf21cd93STycho Nightingale 			if (bytes != 4 || (coff & 0x3) != 0)
2268bf21cd93STycho Nightingale 				return;
22694f3f3e9aSAndy Fiddaman 
22704f3f3e9aSAndy Fiddaman 			if (is_pcir_bar(coff)) {
2271d7b72f7bSAndy Fiddaman 				idx = (coff - PCIR_BAR(0)) / 4;
22724f3f3e9aSAndy Fiddaman 			} else if (is_pcir_bios(coff)) {
2273d7b72f7bSAndy Fiddaman 				idx = PCI_ROM_IDX;
2274d7b72f7bSAndy Fiddaman 			} else {
22754f3f3e9aSAndy Fiddaman 				errx(4, "%s: invalid BAR offset %d", __func__,
22764f3f3e9aSAndy Fiddaman 				    coff);
2277d7b72f7bSAndy Fiddaman 			}
22784f3f3e9aSAndy Fiddaman 
2279bf21cd93STycho Nightingale 			mask = ~(pi->pi_bar[idx].size - 1);
2280bf21cd93STycho Nightingale 			switch (pi->pi_bar[idx].type) {
2281bf21cd93STycho Nightingale 			case PCIBAR_NONE:
2282bf21cd93STycho Nightingale 				pi->pi_bar[idx].addr = bar = 0;
2283bf21cd93STycho Nightingale 				break;
2284bf21cd93STycho Nightingale 			case PCIBAR_IO:
2285*32640292SAndy Fiddaman 				addr = *valp & mask;
2286bf21cd93STycho Nightingale 				addr &= 0xffff;
22876dc98349SAndy Fiddaman 				bar = addr | pi->pi_bar[idx].lobits;
2288bf21cd93STycho Nightingale 				/*
2289bf21cd93STycho Nightingale 				 * Register the new BAR value for interception
2290bf21cd93STycho Nightingale 				 */
2291bf21cd93STycho Nightingale 				if (addr != pi->pi_bar[idx].addr) {
2292bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx,
2293bf21cd93STycho Nightingale 							   PCIBAR_IO);
2294bf21cd93STycho Nightingale 				}
2295bf21cd93STycho Nightingale 				break;
2296bf21cd93STycho Nightingale 			case PCIBAR_MEM32:
2297*32640292SAndy Fiddaman 				addr = bar = *valp & mask;
22986dc98349SAndy Fiddaman 				bar |= pi->pi_bar[idx].lobits;
2299bf21cd93STycho Nightingale 				if (addr != pi->pi_bar[idx].addr) {
2300bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx,
2301bf21cd93STycho Nightingale 							   PCIBAR_MEM32);
2302bf21cd93STycho Nightingale 				}
2303bf21cd93STycho Nightingale 				break;
2304bf21cd93STycho Nightingale 			case PCIBAR_MEM64:
2305*32640292SAndy Fiddaman 				addr = bar = *valp & mask;
23066dc98349SAndy Fiddaman 				bar |= pi->pi_bar[idx].lobits;
2307bf21cd93STycho Nightingale 				if (addr != (uint32_t)pi->pi_bar[idx].addr) {
2308bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx,
2309bf21cd93STycho Nightingale 							   PCIBAR_MEM64);
2310bf21cd93STycho Nightingale 				}
2311bf21cd93STycho Nightingale 				break;
2312bf21cd93STycho Nightingale 			case PCIBAR_MEMHI64:
2313bf21cd93STycho Nightingale 				mask = ~(pi->pi_bar[idx - 1].size - 1);
2314*32640292SAndy Fiddaman 				addr = ((uint64_t)*valp << 32) & mask;
2315bf21cd93STycho Nightingale 				bar = addr >> 32;
2316bf21cd93STycho Nightingale 				if (bar != pi->pi_bar[idx - 1].addr >> 32) {
2317bf21cd93STycho Nightingale 					update_bar_address(pi, addr, idx - 1,
2318bf21cd93STycho Nightingale 							   PCIBAR_MEMHI64);
2319bf21cd93STycho Nightingale 				}
2320bf21cd93STycho Nightingale 				break;
2321d7b72f7bSAndy Fiddaman 			case PCIBAR_ROM:
2322*32640292SAndy Fiddaman 				addr = bar = *valp & mask;
2323d7b72f7bSAndy Fiddaman 				if (memen(pi) && romen(pi)) {
2324d7b72f7bSAndy Fiddaman 					unregister_bar(pi, idx);
2325d7b72f7bSAndy Fiddaman 				}
2326d7b72f7bSAndy Fiddaman 				pi->pi_bar[idx].addr = addr;
2327*32640292SAndy Fiddaman 				pi->pi_bar[idx].lobits = *valp &
2328d7b72f7bSAndy Fiddaman 				    PCIM_BIOS_ENABLE;
2329d7b72f7bSAndy Fiddaman 				/* romen could have changed it value */
2330d7b72f7bSAndy Fiddaman 				if (memen(pi) && romen(pi)) {
2331d7b72f7bSAndy Fiddaman 					register_bar(pi, idx);
2332d7b72f7bSAndy Fiddaman 				}
2333d7b72f7bSAndy Fiddaman 				bar |= pi->pi_bar[idx].lobits;
2334d7b72f7bSAndy Fiddaman 				break;
2335bf21cd93STycho Nightingale 			default:
2336bf21cd93STycho Nightingale 				assert(0);
2337bf21cd93STycho Nightingale 			}
2338bf21cd93STycho Nightingale 			pci_set_cfgdata32(pi, coff, bar);
2339bf21cd93STycho Nightingale 
2340bf21cd93STycho Nightingale 		} else if (pci_emul_iscap(pi, coff)) {
2341*32640292SAndy Fiddaman 			pci_emul_capwrite(pi, coff, bytes, *valp, 0, 0);
23424c87aefeSPatrick Mooney 		} else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) {
2343*32640292SAndy Fiddaman 			pci_emul_cmdsts_write(pi, coff, *valp, bytes);
2344bf21cd93STycho Nightingale 		} else {
2345*32640292SAndy Fiddaman 			CFGWRITE(pi, coff, *valp, bytes);
2346bf21cd93STycho Nightingale 		}
2347bf21cd93STycho Nightingale 	}
2348bf21cd93STycho Nightingale }
2349bf21cd93STycho Nightingale 
2350bf21cd93STycho Nightingale static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff;
2351bf21cd93STycho Nightingale 
2352bf21cd93STycho Nightingale static int
pci_emul_cfgaddr(struct vmctx * ctx __unused,int in,int port __unused,int bytes,uint32_t * eax,void * arg __unused)235359d65d31SAndy Fiddaman pci_emul_cfgaddr(struct vmctx *ctx __unused, int in,
235459d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg __unused)
2355bf21cd93STycho Nightingale {
2356bf21cd93STycho Nightingale 	uint32_t x;
2357bf21cd93STycho Nightingale 
2358bf21cd93STycho Nightingale 	if (bytes != 4) {
2359bf21cd93STycho Nightingale 		if (in)
2360bf21cd93STycho Nightingale 			*eax = (bytes == 2) ? 0xffff : 0xff;
2361bf21cd93STycho Nightingale 		return (0);
2362bf21cd93STycho Nightingale 	}
2363bf21cd93STycho Nightingale 
2364bf21cd93STycho Nightingale 	if (in) {
2365bf21cd93STycho Nightingale 		x = (cfgbus << 16) | (cfgslot << 11) | (cfgfunc << 8) | cfgoff;
2366bf21cd93STycho Nightingale 		if (cfgenable)
2367bf21cd93STycho Nightingale 			x |= CONF1_ENABLE;
2368bf21cd93STycho Nightingale 		*eax = x;
2369bf21cd93STycho Nightingale 	} else {
2370bf21cd93STycho Nightingale 		x = *eax;
2371bf21cd93STycho Nightingale 		cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;
23726dc98349SAndy Fiddaman 		cfgoff = (x & PCI_REGMAX) & ~0x03;
2373bf21cd93STycho Nightingale 		cfgfunc = (x >> 8) & PCI_FUNCMAX;
2374bf21cd93STycho Nightingale 		cfgslot = (x >> 11) & PCI_SLOTMAX;
2375bf21cd93STycho Nightingale 		cfgbus = (x >> 16) & PCI_BUSMAX;
2376bf21cd93STycho Nightingale 	}
2377bf21cd93STycho Nightingale 
2378bf21cd93STycho Nightingale 	return (0);
2379bf21cd93STycho Nightingale }
2380bf21cd93STycho Nightingale INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_INOUT, pci_emul_cfgaddr);
2381bf21cd93STycho Nightingale 
2382bf21cd93STycho Nightingale static int
pci_emul_cfgdata(struct vmctx * ctx __unused,int in,int port,int bytes,uint32_t * eax,void * arg __unused)2383*32640292SAndy Fiddaman pci_emul_cfgdata(struct vmctx *ctx __unused, int in, int port,
238459d65d31SAndy Fiddaman     int bytes, uint32_t *eax, void *arg __unused)
2385bf21cd93STycho Nightingale {
2386bf21cd93STycho Nightingale 	int coff;
2387bf21cd93STycho Nightingale 
2388bf21cd93STycho Nightingale 	assert(bytes == 1 || bytes == 2 || bytes == 4);
2389bf21cd93STycho Nightingale 
2390bf21cd93STycho Nightingale 	coff = cfgoff + (port - CONF1_DATA_PORT);
2391bf21cd93STycho Nightingale 	if (cfgenable) {
2392*32640292SAndy Fiddaman 		pci_cfgrw(in, cfgbus, cfgslot, cfgfunc, coff, bytes, eax);
2393bf21cd93STycho Nightingale 	} else {
2394bf21cd93STycho Nightingale 		/* Ignore accesses to cfgdata if not enabled by cfgaddr */
2395bf21cd93STycho Nightingale 		if (in)
2396bf21cd93STycho Nightingale 			*eax = 0xffffffff;
2397bf21cd93STycho Nightingale 	}
2398bf21cd93STycho Nightingale 	return (0);
2399bf21cd93STycho Nightingale }
2400bf21cd93STycho Nightingale 
2401bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+0, IOPORT_F_INOUT, pci_emul_cfgdata);
2402bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+1, IOPORT_F_INOUT, pci_emul_cfgdata);
2403bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+2, IOPORT_F_INOUT, pci_emul_cfgdata);
2404bf21cd93STycho Nightingale INOUT_PORT(pci_cfgdata, CONF1_DATA_PORT+3, IOPORT_F_INOUT, pci_emul_cfgdata);
2405bf21cd93STycho Nightingale 
2406bf21cd93STycho Nightingale #define PCI_EMUL_TEST
2407bf21cd93STycho Nightingale #ifdef PCI_EMUL_TEST
2408bf21cd93STycho Nightingale /*
2409bf21cd93STycho Nightingale  * Define a dummy test device
2410bf21cd93STycho Nightingale  */
2411bf21cd93STycho Nightingale #define DIOSZ	8
2412bf21cd93STycho Nightingale #define DMEMSZ	4096
2413bf21cd93STycho Nightingale struct pci_emul_dsoftc {
24144c87aefeSPatrick Mooney 	uint8_t	  ioregs[DIOSZ];
24154c87aefeSPatrick Mooney 	uint8_t	  memregs[2][DMEMSZ];
2416bf21cd93STycho Nightingale };
2417bf21cd93STycho Nightingale 
2418bf21cd93STycho Nightingale #define	PCI_EMUL_MSI_MSGS	 4
2419bf21cd93STycho Nightingale #define	PCI_EMUL_MSIX_MSGS	16
2420bf21cd93STycho Nightingale 
2421bf21cd93STycho Nightingale static int
pci_emul_dinit(struct pci_devinst * pi,nvlist_t * nvl __unused)2422*32640292SAndy Fiddaman pci_emul_dinit(struct pci_devinst *pi, nvlist_t *nvl __unused)
2423bf21cd93STycho Nightingale {
2424bf21cd93STycho Nightingale 	int error;
2425bf21cd93STycho Nightingale 	struct pci_emul_dsoftc *sc;
2426bf21cd93STycho Nightingale 
2427bf21cd93STycho Nightingale 	sc = calloc(1, sizeof(struct pci_emul_dsoftc));
2428bf21cd93STycho Nightingale 
2429bf21cd93STycho Nightingale 	pi->pi_arg = sc;
2430bf21cd93STycho Nightingale 
2431bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_DEVICE, 0x0001);
2432bf21cd93STycho Nightingale 	pci_set_cfgdata16(pi, PCIR_VENDOR, 0x10DD);
2433bf21cd93STycho Nightingale 	pci_set_cfgdata8(pi, PCIR_CLASS, 0x02);
2434bf21cd93STycho Nightingale 
2435bf21cd93STycho Nightingale 	error = pci_emul_add_msicap(pi, PCI_EMUL_MSI_MSGS);
2436bf21cd93STycho Nightingale 	assert(error == 0);
2437bf21cd93STycho Nightingale 
2438bf21cd93STycho Nightingale 	error = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, DIOSZ);
2439bf21cd93STycho Nightingale 	assert(error == 0);
2440bf21cd93STycho Nightingale 
2441bf21cd93STycho Nightingale 	error = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, DMEMSZ);
2442bf21cd93STycho Nightingale 	assert(error == 0);
2443bf21cd93STycho Nightingale 
24444c87aefeSPatrick Mooney 	error = pci_emul_alloc_bar(pi, 2, PCIBAR_MEM32, DMEMSZ);
24454c87aefeSPatrick Mooney 	assert(error == 0);
24464c87aefeSPatrick Mooney 
2447bf21cd93STycho Nightingale 	return (0);
2448bf21cd93STycho Nightingale }
2449bf21cd93STycho Nightingale 
2450bf21cd93STycho Nightingale static void
pci_emul_diow(struct pci_devinst * pi,int baridx,uint64_t offset,int size,uint64_t value)2451*32640292SAndy Fiddaman pci_emul_diow(struct pci_devinst *pi, int baridx, uint64_t offset, int size,
245259d65d31SAndy Fiddaman     uint64_t value)
2453bf21cd93STycho Nightingale {
2454bf21cd93STycho Nightingale 	int i;
2455bf21cd93STycho Nightingale 	struct pci_emul_dsoftc *sc = pi->pi_arg;
2456bf21cd93STycho Nightingale 
2457bf21cd93STycho Nightingale 	if (baridx == 0) {
2458bf21cd93STycho Nightingale 		if (offset + size > DIOSZ) {
2459bf21cd93STycho Nightingale 			printf("diow: iow too large, offset %ld size %d\n",
2460bf21cd93STycho Nightingale 			       offset, size);
2461bf21cd93STycho Nightingale 			return;
2462bf21cd93STycho Nightingale 		}
2463bf21cd93STycho Nightingale 
2464bf21cd93STycho Nightingale 		if (size == 1) {
2465bf21cd93STycho Nightingale 			sc->ioregs[offset] = value & 0xff;
2466bf21cd93STycho Nightingale 		} else if (size == 2) {
2467bf21cd93STycho Nightingale 			*(uint16_t *)&sc->ioregs[offset] = value & 0xffff;
2468bf21cd93STycho Nightingale 		} else if (size == 4) {
2469bf21cd93STycho Nightingale 			*(uint32_t *)&sc->ioregs[offset] = value;
2470bf21cd93STycho Nightingale 		} else {
2471bf21cd93STycho Nightingale 			printf("diow: iow unknown size %d\n", size);
2472bf21cd93STycho Nightingale 		}
2473bf21cd93STycho Nightingale 
2474bf21cd93STycho Nightingale 		/*
2475bf21cd93STycho Nightingale 		 * Special magic value to generate an interrupt
2476bf21cd93STycho Nightingale 		 */
2477bf21cd93STycho Nightingale 		if (offset == 4 && size == 4 && pci_msi_enabled(pi))
2478bf21cd93STycho Nightingale 			pci_generate_msi(pi, value % pci_msi_maxmsgnum(pi));
2479bf21cd93STycho Nightingale 
2480bf21cd93STycho Nightingale 		if (value == 0xabcdef) {
2481bf21cd93STycho Nightingale 			for (i = 0; i < pci_msi_maxmsgnum(pi); i++)
2482bf21cd93STycho Nightingale 				pci_generate_msi(pi, i);
2483bf21cd93STycho Nightingale 		}
2484bf21cd93STycho Nightingale 	}
2485bf21cd93STycho Nightingale 
24864c87aefeSPatrick Mooney 	if (baridx == 1 || baridx == 2) {
2487bf21cd93STycho Nightingale 		if (offset + size > DMEMSZ) {
2488bf21cd93STycho Nightingale 			printf("diow: memw too large, offset %ld size %d\n",
2489bf21cd93STycho Nightingale 			       offset, size);
2490bf21cd93STycho Nightingale 			return;
2491bf21cd93STycho Nightingale 		}
2492bf21cd93STycho Nightingale 
24934c87aefeSPatrick Mooney 		i = baridx - 1;		/* 'memregs' index */
24944c87aefeSPatrick Mooney 
2495bf21cd93STycho Nightingale 		if (size == 1) {
24964c87aefeSPatrick Mooney 			sc->memregs[i][offset] = value;
2497bf21cd93STycho Nightingale 		} else if (size == 2) {
24984c87aefeSPatrick Mooney 			*(uint16_t *)&sc->memregs[i][offset] = value;
2499bf21cd93STycho Nightingale 		} else if (size == 4) {
25004c87aefeSPatrick Mooney 			*(uint32_t *)&sc->memregs[i][offset] = value;
2501bf21cd93STycho Nightingale 		} else if (size == 8) {
25024c87aefeSPatrick Mooney 			*(uint64_t *)&sc->memregs[i][offset] = value;
2503bf21cd93STycho Nightingale 		} else {
2504bf21cd93STycho Nightingale 			printf("diow: memw unknown size %d\n", size);
2505bf21cd93STycho Nightingale 		}
25064c87aefeSPatrick Mooney 
2507bf21cd93STycho Nightingale 		/*
2508bf21cd93STycho Nightingale 		 * magic interrupt ??
2509bf21cd93STycho Nightingale 		 */
2510bf21cd93STycho Nightingale 	}
2511bf21cd93STycho Nightingale 
25124c87aefeSPatrick Mooney 	if (baridx > 2 || baridx < 0) {
2513bf21cd93STycho Nightingale 		printf("diow: unknown bar idx %d\n", baridx);
2514bf21cd93STycho Nightingale 	}
2515bf21cd93STycho Nightingale }
2516bf21cd93STycho Nightingale 
2517bf21cd93STycho Nightingale static uint64_t
pci_emul_dior(struct pci_devinst * pi,int baridx,uint64_t offset,int size)2518*32640292SAndy Fiddaman pci_emul_dior(struct pci_devinst *pi, int baridx, uint64_t offset, int size)
2519bf21cd93STycho Nightingale {
2520bf21cd93STycho Nightingale 	struct pci_emul_dsoftc *sc = pi->pi_arg;
2521bf21cd93STycho Nightingale 	uint32_t value;
25224c87aefeSPatrick Mooney 	int i;
2523bf21cd93STycho Nightingale 
25244c87aefeSPatrick Mooney 	value = 0;
2525bf21cd93STycho Nightingale 	if (baridx == 0) {
2526bf21cd93STycho Nightingale 		if (offset + size > DIOSZ) {
2527bf21cd93STycho Nightingale 			printf("dior: ior too large, offset %ld size %d\n",
2528bf21cd93STycho Nightingale 			       offset, size);
2529bf21cd93STycho Nightingale 			return (0);
2530bf21cd93STycho Nightingale 		}
25314c87aefeSPatrick Mooney 
25324c87aefeSPatrick Mooney 		value = 0;
2533bf21cd93STycho Nightingale 		if (size == 1) {
2534bf21cd93STycho Nightingale 			value = sc->ioregs[offset];
2535bf21cd93STycho Nightingale 		} else if (size == 2) {
2536bf21cd93STycho Nightingale 			value = *(uint16_t *) &sc->ioregs[offset];
2537bf21cd93STycho Nightingale 		} else if (size == 4) {
2538bf21cd93STycho Nightingale 			value = *(uint32_t *) &sc->ioregs[offset];
2539bf21cd93STycho Nightingale 		} else {
2540bf21cd93STycho Nightingale 			printf("dior: ior unknown size %d\n", size);
2541bf21cd93STycho Nightingale 		}
2542bf21cd93STycho Nightingale 	}
25434c87aefeSPatrick Mooney 
25444c87aefeSPatrick Mooney 	if (baridx == 1 || baridx == 2) {
2545bf21cd93STycho Nightingale 		if (offset + size > DMEMSZ) {
2546bf21cd93STycho Nightingale 			printf("dior: memr too large, offset %ld size %d\n",
2547bf21cd93STycho Nightingale 			       offset, size);
2548bf21cd93STycho Nightingale 			return (0);
2549bf21cd93STycho Nightingale 		}
25504c87aefeSPatrick Mooney 
25514c87aefeSPatrick Mooney 		i = baridx - 1;		/* 'memregs' index */
25524c87aefeSPatrick Mooney 
2553bf21cd93STycho Nightingale 		if (size == 1) {
25544c87aefeSPatrick Mooney 			value = sc->memregs[i][offset];
2555bf21cd93STycho Nightingale 		} else if (size == 2) {
25564c87aefeSPatrick Mooney 			value = *(uint16_t *) &sc->memregs[i][offset];
2557bf21cd93STycho Nightingale 		} else if (size == 4) {
25584c87aefeSPatrick Mooney 			value = *(uint32_t *) &sc->memregs[i][offset];
2559bf21cd93STycho Nightingale 		} else if (size == 8) {
25604c87aefeSPatrick Mooney 			value = *(uint64_t *) &sc->memregs[i][offset];
2561bf21cd93STycho Nightingale 		} else {
2562bf21cd93STycho Nightingale 			printf("dior: ior unknown size %d\n", size);
2563bf21cd93STycho Nightingale 		}
2564bf21cd93STycho Nightingale 	}
2565bf21cd93STycho Nightingale 
2566bf21cd93STycho Nightingale 
25674c87aefeSPatrick Mooney 	if (baridx > 2 || baridx < 0) {
2568bf21cd93STycho Nightingale 		printf("dior: unknown bar idx %d\n", baridx);
2569bf21cd93STycho Nightingale 		return (0);
2570bf21cd93STycho Nightingale 	}
2571bf21cd93STycho Nightingale 
2572bf21cd93STycho Nightingale 	return (value);
2573bf21cd93STycho Nightingale }
2574bf21cd93STycho Nightingale 
25754f3f3e9aSAndy Fiddaman static const struct pci_devemu pci_dummy = {
2576bf21cd93STycho Nightingale 	.pe_emu = "dummy",
2577bf21cd93STycho Nightingale 	.pe_init = pci_emul_dinit,
2578bf21cd93STycho Nightingale 	.pe_barwrite = pci_emul_diow,
25792b948146SAndy Fiddaman 	.pe_barread = pci_emul_dior,
2580bf21cd93STycho Nightingale };
2581bf21cd93STycho Nightingale PCI_EMUL_SET(pci_dummy);
2582bf21cd93STycho Nightingale 
2583bf21cd93STycho Nightingale #endif /* PCI_EMUL_TEST */
2584