xref: /freebsd/usr.sbin/bhyve/pci_passthru.c (revision f8a6ec2d572758da6cfd29fcb4ecf4430463661d)
1366f6083SPeter Grehan /*-
21de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
31de7b4b8SPedro F. Giffuni  *
4366f6083SPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
5366f6083SPeter Grehan  * All rights reserved.
6366f6083SPeter Grehan  *
7366f6083SPeter Grehan  * Redistribution and use in source and binary forms, with or without
8366f6083SPeter Grehan  * modification, are permitted provided that the following conditions
9366f6083SPeter Grehan  * are met:
10366f6083SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
11366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer.
12366f6083SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
13366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
14366f6083SPeter Grehan  *    documentation and/or other materials provided with the distribution.
15366f6083SPeter Grehan  *
16366f6083SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17366f6083SPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18366f6083SPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19366f6083SPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20366f6083SPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21366f6083SPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22366f6083SPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23366f6083SPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24366f6083SPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25366f6083SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26366f6083SPeter Grehan  * SUCH DAMAGE.
27366f6083SPeter Grehan  *
28366f6083SPeter Grehan  * $FreeBSD$
29366f6083SPeter Grehan  */
30366f6083SPeter Grehan 
31366f6083SPeter Grehan #include <sys/cdefs.h>
32366f6083SPeter Grehan __FBSDID("$FreeBSD$");
33366f6083SPeter Grehan 
34366f6083SPeter Grehan #include <sys/param.h>
3500ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
3600ef17beSBartek Rutkowski #include <sys/capsicum.h>
3700ef17beSBartek Rutkowski #endif
38366f6083SPeter Grehan #include <sys/types.h>
395c40acf8SJohn Baldwin #include <sys/mman.h>
40366f6083SPeter Grehan #include <sys/pciio.h>
41366f6083SPeter Grehan #include <sys/ioctl.h>
42366f6083SPeter Grehan 
43366f6083SPeter Grehan #include <dev/io/iodev.h>
442e81a7e8SNeel Natu #include <dev/pci/pcireg.h>
452e81a7e8SNeel Natu 
46366f6083SPeter Grehan #include <machine/iodev.h>
47366f6083SPeter Grehan 
48abfa3c39SMarcelo Araujo #ifndef WITHOUT_CAPSICUM
49abfa3c39SMarcelo Araujo #include <capsicum_helpers.h>
50abfa3c39SMarcelo Araujo #endif
51366f6083SPeter Grehan #include <stdio.h>
52366f6083SPeter Grehan #include <stdlib.h>
53366f6083SPeter Grehan #include <string.h>
54cff92ffdSJohn Baldwin #include <err.h>
5500ef17beSBartek Rutkowski #include <errno.h>
56366f6083SPeter Grehan #include <fcntl.h>
5700ef17beSBartek Rutkowski #include <sysexits.h>
58366f6083SPeter Grehan #include <unistd.h>
59366f6083SPeter Grehan 
60366f6083SPeter Grehan #include <machine/vmm.h>
61366f6083SPeter Grehan #include <vmmapi.h>
62621b5090SJohn Baldwin 
63621b5090SJohn Baldwin #include "config.h"
64621b5090SJohn Baldwin #include "debug.h"
65366f6083SPeter Grehan #include "pci_emul.h"
664d1e669cSPeter Grehan #include "mem.h"
67366f6083SPeter Grehan 
68366f6083SPeter Grehan #ifndef _PATH_DEVPCI
69366f6083SPeter Grehan #define	_PATH_DEVPCI	"/dev/pci"
70366f6083SPeter Grehan #endif
71366f6083SPeter Grehan 
72366f6083SPeter Grehan #ifndef	_PATH_DEVIO
73366f6083SPeter Grehan #define	_PATH_DEVIO	"/dev/io"
74366f6083SPeter Grehan #endif
75366f6083SPeter Grehan 
765c40acf8SJohn Baldwin #ifndef _PATH_MEM
775c40acf8SJohn Baldwin #define	_PATH_MEM	"/dev/mem"
785c40acf8SJohn Baldwin #endif
795c40acf8SJohn Baldwin 
80366f6083SPeter Grehan #define	LEGACY_SUPPORT	1
81366f6083SPeter Grehan 
822e81a7e8SNeel Natu #define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
83cd942e0fSPeter Grehan #define MSIX_CAPLEN 12
84cd942e0fSPeter Grehan 
85366f6083SPeter Grehan static int pcifd = -1;
86366f6083SPeter Grehan static int iofd = -1;
875c40acf8SJohn Baldwin static int memfd = -1;
88366f6083SPeter Grehan 
89366f6083SPeter Grehan struct passthru_softc {
90366f6083SPeter Grehan 	struct pci_devinst *psc_pi;
91366f6083SPeter Grehan 	struct pcibar psc_bar[PCI_BARMAX + 1];
92366f6083SPeter Grehan 	struct {
93366f6083SPeter Grehan 		int		capoff;
94366f6083SPeter Grehan 		int		msgctrl;
95366f6083SPeter Grehan 		int		emulated;
96366f6083SPeter Grehan 	} psc_msi;
97cd942e0fSPeter Grehan 	struct {
98cd942e0fSPeter Grehan 		int		capoff;
99cd942e0fSPeter Grehan 	} psc_msix;
100366f6083SPeter Grehan 	struct pcisel psc_sel;
101366f6083SPeter Grehan };
102366f6083SPeter Grehan 
103366f6083SPeter Grehan static int
104366f6083SPeter Grehan msi_caplen(int msgctrl)
105366f6083SPeter Grehan {
106366f6083SPeter Grehan 	int len;
107366f6083SPeter Grehan 
108366f6083SPeter Grehan 	len = 10;		/* minimum length of msi capability */
109366f6083SPeter Grehan 
110366f6083SPeter Grehan 	if (msgctrl & PCIM_MSICTRL_64BIT)
111366f6083SPeter Grehan 		len += 4;
112366f6083SPeter Grehan 
113366f6083SPeter Grehan #if 0
114366f6083SPeter Grehan 	/*
115366f6083SPeter Grehan 	 * Ignore the 'mask' and 'pending' bits in the MSI capability.
116366f6083SPeter Grehan 	 * We'll let the guest manipulate them directly.
117366f6083SPeter Grehan 	 */
118366f6083SPeter Grehan 	if (msgctrl & PCIM_MSICTRL_VECTOR)
119366f6083SPeter Grehan 		len += 10;
120366f6083SPeter Grehan #endif
121366f6083SPeter Grehan 
122366f6083SPeter Grehan 	return (len);
123366f6083SPeter Grehan }
124366f6083SPeter Grehan 
125366f6083SPeter Grehan static uint32_t
126366f6083SPeter Grehan read_config(const struct pcisel *sel, long reg, int width)
127366f6083SPeter Grehan {
128366f6083SPeter Grehan 	struct pci_io pi;
129366f6083SPeter Grehan 
130366f6083SPeter Grehan 	bzero(&pi, sizeof(pi));
131366f6083SPeter Grehan 	pi.pi_sel = *sel;
132366f6083SPeter Grehan 	pi.pi_reg = reg;
133366f6083SPeter Grehan 	pi.pi_width = width;
134366f6083SPeter Grehan 
135366f6083SPeter Grehan 	if (ioctl(pcifd, PCIOCREAD, &pi) < 0)
136366f6083SPeter Grehan 		return (0);				/* XXX */
137366f6083SPeter Grehan 	else
138366f6083SPeter Grehan 		return (pi.pi_data);
139366f6083SPeter Grehan }
140366f6083SPeter Grehan 
141366f6083SPeter Grehan static void
142366f6083SPeter Grehan write_config(const struct pcisel *sel, long reg, int width, uint32_t data)
143366f6083SPeter Grehan {
144366f6083SPeter Grehan 	struct pci_io pi;
145366f6083SPeter Grehan 
146366f6083SPeter Grehan 	bzero(&pi, sizeof(pi));
147366f6083SPeter Grehan 	pi.pi_sel = *sel;
148366f6083SPeter Grehan 	pi.pi_reg = reg;
149366f6083SPeter Grehan 	pi.pi_width = width;
150366f6083SPeter Grehan 	pi.pi_data = data;
151366f6083SPeter Grehan 
152366f6083SPeter Grehan 	(void)ioctl(pcifd, PCIOCWRITE, &pi);		/* XXX */
153366f6083SPeter Grehan }
154366f6083SPeter Grehan 
155366f6083SPeter Grehan #ifdef LEGACY_SUPPORT
156366f6083SPeter Grehan static int
157366f6083SPeter Grehan passthru_add_msicap(struct pci_devinst *pi, int msgnum, int nextptr)
158366f6083SPeter Grehan {
159366f6083SPeter Grehan 	int capoff, i;
160366f6083SPeter Grehan 	struct msicap msicap;
161366f6083SPeter Grehan 	u_char *capdata;
162366f6083SPeter Grehan 
163366f6083SPeter Grehan 	pci_populate_msicap(&msicap, msgnum, nextptr);
164366f6083SPeter Grehan 
165366f6083SPeter Grehan 	/*
166366f6083SPeter Grehan 	 * XXX
167366f6083SPeter Grehan 	 * Copy the msi capability structure in the last 16 bytes of the
168366f6083SPeter Grehan 	 * config space. This is wrong because it could shadow something
169366f6083SPeter Grehan 	 * useful to the device.
170366f6083SPeter Grehan 	 */
171366f6083SPeter Grehan 	capoff = 256 - roundup(sizeof(msicap), 4);
172366f6083SPeter Grehan 	capdata = (u_char *)&msicap;
173366f6083SPeter Grehan 	for (i = 0; i < sizeof(msicap); i++)
174366f6083SPeter Grehan 		pci_set_cfgdata8(pi, capoff + i, capdata[i]);
175366f6083SPeter Grehan 
176366f6083SPeter Grehan 	return (capoff);
177366f6083SPeter Grehan }
178366f6083SPeter Grehan #endif	/* LEGACY_SUPPORT */
179366f6083SPeter Grehan 
180366f6083SPeter Grehan static int
181366f6083SPeter Grehan cfginitmsi(struct passthru_softc *sc)
182366f6083SPeter Grehan {
1832e81a7e8SNeel Natu 	int i, ptr, capptr, cap, sts, caplen, table_size;
184366f6083SPeter Grehan 	uint32_t u32;
185366f6083SPeter Grehan 	struct pcisel sel;
186366f6083SPeter Grehan 	struct pci_devinst *pi;
187cd942e0fSPeter Grehan 	struct msixcap msixcap;
188cd942e0fSPeter Grehan 	uint32_t *msixcap_ptr;
189366f6083SPeter Grehan 
190366f6083SPeter Grehan 	pi = sc->psc_pi;
191366f6083SPeter Grehan 	sel = sc->psc_sel;
192366f6083SPeter Grehan 
193366f6083SPeter Grehan 	/*
194366f6083SPeter Grehan 	 * Parse the capabilities and cache the location of the MSI
195cd942e0fSPeter Grehan 	 * and MSI-X capabilities.
196366f6083SPeter Grehan 	 */
197366f6083SPeter Grehan 	sts = read_config(&sel, PCIR_STATUS, 2);
198366f6083SPeter Grehan 	if (sts & PCIM_STATUS_CAPPRESENT) {
199366f6083SPeter Grehan 		ptr = read_config(&sel, PCIR_CAP_PTR, 1);
200366f6083SPeter Grehan 		while (ptr != 0 && ptr != 0xff) {
201366f6083SPeter Grehan 			cap = read_config(&sel, ptr + PCICAP_ID, 1);
202366f6083SPeter Grehan 			if (cap == PCIY_MSI) {
203366f6083SPeter Grehan 				/*
204366f6083SPeter Grehan 				 * Copy the MSI capability into the config
205366f6083SPeter Grehan 				 * space of the emulated pci device
206366f6083SPeter Grehan 				 */
207366f6083SPeter Grehan 				sc->psc_msi.capoff = ptr;
208366f6083SPeter Grehan 				sc->psc_msi.msgctrl = read_config(&sel,
209366f6083SPeter Grehan 								  ptr + 2, 2);
210366f6083SPeter Grehan 				sc->psc_msi.emulated = 0;
211366f6083SPeter Grehan 				caplen = msi_caplen(sc->psc_msi.msgctrl);
212cd942e0fSPeter Grehan 				capptr = ptr;
213366f6083SPeter Grehan 				while (caplen > 0) {
214cd942e0fSPeter Grehan 					u32 = read_config(&sel, capptr, 4);
215cd942e0fSPeter Grehan 					pci_set_cfgdata32(pi, capptr, u32);
216366f6083SPeter Grehan 					caplen -= 4;
217cd942e0fSPeter Grehan 					capptr += 4;
218366f6083SPeter Grehan 				}
219cd942e0fSPeter Grehan 			} else if (cap == PCIY_MSIX) {
220cd942e0fSPeter Grehan 				/*
221cd942e0fSPeter Grehan 				 * Copy the MSI-X capability
222cd942e0fSPeter Grehan 				 */
223cd942e0fSPeter Grehan 				sc->psc_msix.capoff = ptr;
224cd942e0fSPeter Grehan 				caplen = 12;
225cd942e0fSPeter Grehan 				msixcap_ptr = (uint32_t*) &msixcap;
226cd942e0fSPeter Grehan 				capptr = ptr;
227cd942e0fSPeter Grehan 				while (caplen > 0) {
228cd942e0fSPeter Grehan 					u32 = read_config(&sel, capptr, 4);
229cd942e0fSPeter Grehan 					*msixcap_ptr = u32;
230cd942e0fSPeter Grehan 					pci_set_cfgdata32(pi, capptr, u32);
231cd942e0fSPeter Grehan 					caplen -= 4;
232cd942e0fSPeter Grehan 					capptr += 4;
233cd942e0fSPeter Grehan 					msixcap_ptr++;
234cd942e0fSPeter Grehan 				}
235366f6083SPeter Grehan 			}
236366f6083SPeter Grehan 			ptr = read_config(&sel, ptr + PCICAP_NEXTPTR, 1);
237366f6083SPeter Grehan 		}
238366f6083SPeter Grehan 	}
239366f6083SPeter Grehan 
2404d1e669cSPeter Grehan 	if (sc->psc_msix.capoff != 0) {
2414d1e669cSPeter Grehan 		pi->pi_msix.pba_bar =
2422e81a7e8SNeel Natu 		    msixcap.pba_info & PCIM_MSIX_BIR_MASK;
2434d1e669cSPeter Grehan 		pi->pi_msix.pba_offset =
2442e81a7e8SNeel Natu 		    msixcap.pba_info & ~PCIM_MSIX_BIR_MASK;
2454d1e669cSPeter Grehan 		pi->pi_msix.table_bar =
2462e81a7e8SNeel Natu 		    msixcap.table_info & PCIM_MSIX_BIR_MASK;
2474d1e669cSPeter Grehan 		pi->pi_msix.table_offset =
2482e81a7e8SNeel Natu 		    msixcap.table_info & ~PCIM_MSIX_BIR_MASK;
249cd942e0fSPeter Grehan 		pi->pi_msix.table_count = MSIX_TABLE_COUNT(msixcap.msgctrl);
2507a902ec0SNeel Natu 		pi->pi_msix.pba_size = PBA_SIZE(pi->pi_msix.table_count);
2512e81a7e8SNeel Natu 
2522e81a7e8SNeel Natu 		/* Allocate the emulated MSI-X table array */
2532e81a7e8SNeel Natu 		table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE;
254994f858aSXin LI 		pi->pi_msix.table = calloc(1, table_size);
2552e81a7e8SNeel Natu 
2562e81a7e8SNeel Natu 		/* Mask all table entries */
2572e81a7e8SNeel Natu 		for (i = 0; i < pi->pi_msix.table_count; i++) {
2582e81a7e8SNeel Natu 			pi->pi_msix.table[i].vector_control |=
2592e81a7e8SNeel Natu 						PCIM_MSIX_VCTRL_MASK;
2602e81a7e8SNeel Natu 		}
2614d1e669cSPeter Grehan 	}
262cd942e0fSPeter Grehan 
263366f6083SPeter Grehan #ifdef LEGACY_SUPPORT
264366f6083SPeter Grehan 	/*
265366f6083SPeter Grehan 	 * If the passthrough device does not support MSI then craft a
266366f6083SPeter Grehan 	 * MSI capability for it. We link the new MSI capability at the
267366f6083SPeter Grehan 	 * head of the list of capabilities.
268366f6083SPeter Grehan 	 */
269366f6083SPeter Grehan 	if ((sts & PCIM_STATUS_CAPPRESENT) != 0 && sc->psc_msi.capoff == 0) {
270366f6083SPeter Grehan 		int origptr, msiptr;
271366f6083SPeter Grehan 		origptr = read_config(&sel, PCIR_CAP_PTR, 1);
272366f6083SPeter Grehan 		msiptr = passthru_add_msicap(pi, 1, origptr);
273366f6083SPeter Grehan 		sc->psc_msi.capoff = msiptr;
274366f6083SPeter Grehan 		sc->psc_msi.msgctrl = pci_get_cfgdata16(pi, msiptr + 2);
275366f6083SPeter Grehan 		sc->psc_msi.emulated = 1;
276366f6083SPeter Grehan 		pci_set_cfgdata8(pi, PCIR_CAP_PTR, msiptr);
277366f6083SPeter Grehan 	}
278366f6083SPeter Grehan #endif
279366f6083SPeter Grehan 
280cd942e0fSPeter Grehan 	/* Make sure one of the capabilities is present */
281cd942e0fSPeter Grehan 	if (sc->psc_msi.capoff == 0 && sc->psc_msix.capoff == 0)
282366f6083SPeter Grehan 		return (-1);
283366f6083SPeter Grehan 	else
284366f6083SPeter Grehan 		return (0);
285366f6083SPeter Grehan }
286366f6083SPeter Grehan 
2874d1e669cSPeter Grehan static uint64_t
2884d1e669cSPeter Grehan msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
289cd942e0fSPeter Grehan {
290cd942e0fSPeter Grehan 	struct pci_devinst *pi;
2914d1e669cSPeter Grehan 	struct msix_table_entry *entry;
292cd942e0fSPeter Grehan 	uint8_t *src8;
293cd942e0fSPeter Grehan 	uint16_t *src16;
294cd942e0fSPeter Grehan 	uint32_t *src32;
295cd942e0fSPeter Grehan 	uint64_t *src64;
2964d1e669cSPeter Grehan 	uint64_t data;
2974d1e669cSPeter Grehan 	size_t entry_offset;
2984d1e669cSPeter Grehan 	int index;
299cd942e0fSPeter Grehan 
300cd942e0fSPeter Grehan 	pi = sc->psc_pi;
30124be3f51SJohn Baldwin 	if (pi->pi_msix.pba_page != NULL && offset >= pi->pi_msix.pba_offset &&
3025c40acf8SJohn Baldwin 	    offset < pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
3035c40acf8SJohn Baldwin 		switch(size) {
3045c40acf8SJohn Baldwin 		case 1:
3055c40acf8SJohn Baldwin 			src8 = (uint8_t *)(pi->pi_msix.pba_page + offset -
3065c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
3075c40acf8SJohn Baldwin 			data = *src8;
3085c40acf8SJohn Baldwin 			break;
3095c40acf8SJohn Baldwin 		case 2:
3105c40acf8SJohn Baldwin 			src16 = (uint16_t *)(pi->pi_msix.pba_page + offset -
3115c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
3125c40acf8SJohn Baldwin 			data = *src16;
3135c40acf8SJohn Baldwin 			break;
3145c40acf8SJohn Baldwin 		case 4:
3155c40acf8SJohn Baldwin 			src32 = (uint32_t *)(pi->pi_msix.pba_page + offset -
3165c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
3175c40acf8SJohn Baldwin 			data = *src32;
3185c40acf8SJohn Baldwin 			break;
3195c40acf8SJohn Baldwin 		case 8:
3205c40acf8SJohn Baldwin 			src64 = (uint64_t *)(pi->pi_msix.pba_page + offset -
3215c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
3225c40acf8SJohn Baldwin 			data = *src64;
3235c40acf8SJohn Baldwin 			break;
3245c40acf8SJohn Baldwin 		default:
3255c40acf8SJohn Baldwin 			return (-1);
3265c40acf8SJohn Baldwin 		}
3275c40acf8SJohn Baldwin 		return (data);
3285c40acf8SJohn Baldwin 	}
3295c40acf8SJohn Baldwin 
3307a902ec0SNeel Natu 	if (offset < pi->pi_msix.table_offset)
3317a902ec0SNeel Natu 		return (-1);
3322e81a7e8SNeel Natu 
3337a902ec0SNeel Natu 	offset -= pi->pi_msix.table_offset;
334cd942e0fSPeter Grehan 	index = offset / MSIX_TABLE_ENTRY_SIZE;
3352e81a7e8SNeel Natu 	if (index >= pi->pi_msix.table_count)
3362e81a7e8SNeel Natu 		return (-1);
3372e81a7e8SNeel Natu 
338cd942e0fSPeter Grehan 	entry = &pi->pi_msix.table[index];
3392e81a7e8SNeel Natu 	entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
340cd942e0fSPeter Grehan 
341cd942e0fSPeter Grehan 	switch(size) {
342cd942e0fSPeter Grehan 	case 1:
343cd942e0fSPeter Grehan 		src8 = (uint8_t *)((void *)entry + entry_offset);
3444d1e669cSPeter Grehan 		data = *src8;
345cd942e0fSPeter Grehan 		break;
346cd942e0fSPeter Grehan 	case 2:
347cd942e0fSPeter Grehan 		src16 = (uint16_t *)((void *)entry + entry_offset);
3484d1e669cSPeter Grehan 		data = *src16;
349cd942e0fSPeter Grehan 		break;
350cd942e0fSPeter Grehan 	case 4:
351cd942e0fSPeter Grehan 		src32 = (uint32_t *)((void *)entry + entry_offset);
3524d1e669cSPeter Grehan 		data = *src32;
353cd942e0fSPeter Grehan 		break;
354cd942e0fSPeter Grehan 	case 8:
355cd942e0fSPeter Grehan 		src64 = (uint64_t *)((void *)entry + entry_offset);
3564d1e669cSPeter Grehan 		data = *src64;
357cd942e0fSPeter Grehan 		break;
358cd942e0fSPeter Grehan 	default:
359cd942e0fSPeter Grehan 		return (-1);
360cd942e0fSPeter Grehan 	}
361cd942e0fSPeter Grehan 
3624d1e669cSPeter Grehan 	return (data);
363cd942e0fSPeter Grehan }
364cd942e0fSPeter Grehan 
3654d1e669cSPeter Grehan static void
3664d1e669cSPeter Grehan msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc,
3674d1e669cSPeter Grehan 		 uint64_t offset, int size, uint64_t data)
368cd942e0fSPeter Grehan {
369cd942e0fSPeter Grehan 	struct pci_devinst *pi;
370cd942e0fSPeter Grehan 	struct msix_table_entry *entry;
3715c40acf8SJohn Baldwin 	uint8_t *dest8;
3725c40acf8SJohn Baldwin 	uint16_t *dest16;
3735c40acf8SJohn Baldwin 	uint32_t *dest32;
3745c40acf8SJohn Baldwin 	uint64_t *dest64;
3754d1e669cSPeter Grehan 	size_t entry_offset;
376cd942e0fSPeter Grehan 	uint32_t vector_control;
37798e21e80SEnji Cooper 	int index;
378cd942e0fSPeter Grehan 
379cd942e0fSPeter Grehan 	pi = sc->psc_pi;
38024be3f51SJohn Baldwin 	if (pi->pi_msix.pba_page != NULL && offset >= pi->pi_msix.pba_offset &&
3815c40acf8SJohn Baldwin 	    offset < pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
3825c40acf8SJohn Baldwin 		switch(size) {
3835c40acf8SJohn Baldwin 		case 1:
3845c40acf8SJohn Baldwin 			dest8 = (uint8_t *)(pi->pi_msix.pba_page + offset -
3855c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
3865c40acf8SJohn Baldwin 			*dest8 = data;
3875c40acf8SJohn Baldwin 			break;
3885c40acf8SJohn Baldwin 		case 2:
3895c40acf8SJohn Baldwin 			dest16 = (uint16_t *)(pi->pi_msix.pba_page + offset -
3905c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
3915c40acf8SJohn Baldwin 			*dest16 = data;
3925c40acf8SJohn Baldwin 			break;
3935c40acf8SJohn Baldwin 		case 4:
3945c40acf8SJohn Baldwin 			dest32 = (uint32_t *)(pi->pi_msix.pba_page + offset -
3955c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
3965c40acf8SJohn Baldwin 			*dest32 = data;
3975c40acf8SJohn Baldwin 			break;
3985c40acf8SJohn Baldwin 		case 8:
3995c40acf8SJohn Baldwin 			dest64 = (uint64_t *)(pi->pi_msix.pba_page + offset -
4005c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
4015c40acf8SJohn Baldwin 			*dest64 = data;
4025c40acf8SJohn Baldwin 			break;
4035c40acf8SJohn Baldwin 		default:
4045c40acf8SJohn Baldwin 			break;
4055c40acf8SJohn Baldwin 		}
4065c40acf8SJohn Baldwin 		return;
4075c40acf8SJohn Baldwin 	}
4085c40acf8SJohn Baldwin 
4097a902ec0SNeel Natu 	if (offset < pi->pi_msix.table_offset)
4107a902ec0SNeel Natu 		return;
4114b5e84f6SNeel Natu 
4127a902ec0SNeel Natu 	offset -= pi->pi_msix.table_offset;
413cd942e0fSPeter Grehan 	index = offset / MSIX_TABLE_ENTRY_SIZE;
4142e81a7e8SNeel Natu 	if (index >= pi->pi_msix.table_count)
4152e81a7e8SNeel Natu 		return;
4162e81a7e8SNeel Natu 
417cd942e0fSPeter Grehan 	entry = &pi->pi_msix.table[index];
4182e81a7e8SNeel Natu 	entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
419cd942e0fSPeter Grehan 
420cd942e0fSPeter Grehan 	/* Only 4 byte naturally-aligned writes are supported */
4214d1e669cSPeter Grehan 	assert(size == 4);
4224d1e669cSPeter Grehan 	assert(entry_offset % 4 == 0);
4234d1e669cSPeter Grehan 
424cd942e0fSPeter Grehan 	vector_control = entry->vector_control;
4255c40acf8SJohn Baldwin 	dest32 = (uint32_t *)((void *)entry + entry_offset);
4265c40acf8SJohn Baldwin 	*dest32 = data;
427cd942e0fSPeter Grehan 	/* If MSI-X hasn't been enabled, do nothing */
428cd942e0fSPeter Grehan 	if (pi->pi_msix.enabled) {
429cd942e0fSPeter Grehan 		/* If the entry is masked, don't set it up */
430cd942e0fSPeter Grehan 		if ((entry->vector_control & PCIM_MSIX_VCTRL_MASK) == 0 ||
431cd942e0fSPeter Grehan 		    (vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
43298e21e80SEnji Cooper 			(void)vm_setup_pptdev_msix(ctx, vcpu,
43355888cfaSNeel Natu 			    sc->psc_sel.pc_bus, sc->psc_sel.pc_dev,
43455888cfaSNeel Natu 			    sc->psc_sel.pc_func, index, entry->addr,
43555888cfaSNeel Natu 			    entry->msg_data, entry->vector_control);
436cd942e0fSPeter Grehan 		}
437cd942e0fSPeter Grehan 	}
438cd942e0fSPeter Grehan }
439cd942e0fSPeter Grehan 
440cd942e0fSPeter Grehan static int
441cd942e0fSPeter Grehan init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base)
442cd942e0fSPeter Grehan {
4432b89a044SNeel Natu 	int b, s, f;
444*f8a6ec2dSD Scott Phillips 	int idx;
445*f8a6ec2dSD Scott Phillips 	size_t remaining;
4467a902ec0SNeel Natu 	uint32_t table_size, table_offset;
4477a902ec0SNeel Natu 	uint32_t pba_size, pba_offset;
448cd942e0fSPeter Grehan 	vm_paddr_t start;
449cd942e0fSPeter Grehan 	struct pci_devinst *pi = sc->psc_pi;
450cd942e0fSPeter Grehan 
451aa12663fSNeel Natu 	assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0);
452aa12663fSNeel Natu 
4532b89a044SNeel Natu 	b = sc->psc_sel.pc_bus;
4542b89a044SNeel Natu 	s = sc->psc_sel.pc_dev;
4552b89a044SNeel Natu 	f = sc->psc_sel.pc_func;
4562b89a044SNeel Natu 
457cd942e0fSPeter Grehan 	/*
458cd942e0fSPeter Grehan 	 * If the MSI-X table BAR maps memory intended for
459cd942e0fSPeter Grehan 	 * other uses, it is at least assured that the table
460cd942e0fSPeter Grehan 	 * either resides in its own page within the region,
461cd942e0fSPeter Grehan 	 * or it resides in a page shared with only the PBA.
462cd942e0fSPeter Grehan 	 */
4637a902ec0SNeel Natu 	table_offset = rounddown2(pi->pi_msix.table_offset, 4096);
4647a902ec0SNeel Natu 
4657a902ec0SNeel Natu 	table_size = pi->pi_msix.table_offset - table_offset;
4667a902ec0SNeel Natu 	table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE;
4677a902ec0SNeel Natu 	table_size = roundup2(table_size, 4096);
4687a902ec0SNeel Natu 
4695c40acf8SJohn Baldwin 	idx = pi->pi_msix.table_bar;
4705c40acf8SJohn Baldwin 	start = pi->pi_bar[idx].addr;
4715c40acf8SJohn Baldwin 	remaining = pi->pi_bar[idx].size;
4725c40acf8SJohn Baldwin 
4737a902ec0SNeel Natu 	if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar) {
4747a902ec0SNeel Natu 		pba_offset = pi->pi_msix.pba_offset;
4757a902ec0SNeel Natu 		pba_size = pi->pi_msix.pba_size;
4767a902ec0SNeel Natu 		if (pba_offset >= table_offset + table_size ||
4777a902ec0SNeel Natu 		    table_offset >= pba_offset + pba_size) {
4787a902ec0SNeel Natu 			/*
4795c40acf8SJohn Baldwin 			 * If the PBA does not share a page with the MSI-x
4805c40acf8SJohn Baldwin 			 * tables, no PBA emulation is required.
4817a902ec0SNeel Natu 			 */
4825c40acf8SJohn Baldwin 			pi->pi_msix.pba_page = NULL;
4835c40acf8SJohn Baldwin 			pi->pi_msix.pba_page_offset = 0;
4847a902ec0SNeel Natu 		} else {
4855c40acf8SJohn Baldwin 			/*
4865c40acf8SJohn Baldwin 			 * The PBA overlaps with either the first or last
4875c40acf8SJohn Baldwin 			 * page of the MSI-X table region.  Map the
4885c40acf8SJohn Baldwin 			 * appropriate page.
4895c40acf8SJohn Baldwin 			 */
4905c40acf8SJohn Baldwin 			if (pba_offset <= table_offset)
4915c40acf8SJohn Baldwin 				pi->pi_msix.pba_page_offset = table_offset;
4925c40acf8SJohn Baldwin 			else
4935c40acf8SJohn Baldwin 				pi->pi_msix.pba_page_offset = table_offset +
4945c40acf8SJohn Baldwin 				    table_size - 4096;
4955c40acf8SJohn Baldwin 			pi->pi_msix.pba_page = mmap(NULL, 4096, PROT_READ |
4965c40acf8SJohn Baldwin 			    PROT_WRITE, MAP_SHARED, memfd, start +
4975c40acf8SJohn Baldwin 			    pi->pi_msix.pba_page_offset);
4985c40acf8SJohn Baldwin 			if (pi->pi_msix.pba_page == MAP_FAILED) {
499cff92ffdSJohn Baldwin 				warn(
500cff92ffdSJohn Baldwin 			    "Failed to map PBA page for MSI-X on %d/%d/%d",
501cff92ffdSJohn Baldwin 				    b, s, f);
502cd942e0fSPeter Grehan 				return (-1);
503cd942e0fSPeter Grehan 			}
5047a902ec0SNeel Natu 		}
5055c40acf8SJohn Baldwin 	}
5062b89a044SNeel Natu 
5072b89a044SNeel Natu 	return (0);
508cd942e0fSPeter Grehan }
509cd942e0fSPeter Grehan 
510cd942e0fSPeter Grehan static int
511366f6083SPeter Grehan cfginitbar(struct vmctx *ctx, struct passthru_softc *sc)
512366f6083SPeter Grehan {
513366f6083SPeter Grehan 	int i, error;
514366f6083SPeter Grehan 	struct pci_devinst *pi;
515366f6083SPeter Grehan 	struct pci_bar_io bar;
516366f6083SPeter Grehan 	enum pcibar_type bartype;
5177a902ec0SNeel Natu 	uint64_t base, size;
518366f6083SPeter Grehan 
519366f6083SPeter Grehan 	pi = sc->psc_pi;
520366f6083SPeter Grehan 
521366f6083SPeter Grehan 	/*
522366f6083SPeter Grehan 	 * Initialize BAR registers
523366f6083SPeter Grehan 	 */
524366f6083SPeter Grehan 	for (i = 0; i <= PCI_BARMAX; i++) {
525366f6083SPeter Grehan 		bzero(&bar, sizeof(bar));
526366f6083SPeter Grehan 		bar.pbi_sel = sc->psc_sel;
527366f6083SPeter Grehan 		bar.pbi_reg = PCIR_BAR(i);
528366f6083SPeter Grehan 
529366f6083SPeter Grehan 		if (ioctl(pcifd, PCIOCGETBAR, &bar) < 0)
530366f6083SPeter Grehan 			continue;
531366f6083SPeter Grehan 
532366f6083SPeter Grehan 		if (PCI_BAR_IO(bar.pbi_base)) {
533366f6083SPeter Grehan 			bartype = PCIBAR_IO;
534366f6083SPeter Grehan 			base = bar.pbi_base & PCIM_BAR_IO_BASE;
535366f6083SPeter Grehan 		} else {
536366f6083SPeter Grehan 			switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) {
537366f6083SPeter Grehan 			case PCIM_BAR_MEM_64:
538366f6083SPeter Grehan 				bartype = PCIBAR_MEM64;
539366f6083SPeter Grehan 				break;
540366f6083SPeter Grehan 			default:
541366f6083SPeter Grehan 				bartype = PCIBAR_MEM32;
542366f6083SPeter Grehan 				break;
543366f6083SPeter Grehan 			}
544366f6083SPeter Grehan 			base = bar.pbi_base & PCIM_BAR_MEM_BASE;
545366f6083SPeter Grehan 		}
5467a902ec0SNeel Natu 		size = bar.pbi_length;
5477a902ec0SNeel Natu 
5487a902ec0SNeel Natu 		if (bartype != PCIBAR_IO) {
5497a902ec0SNeel Natu 			if (((base | size) & PAGE_MASK) != 0) {
550cff92ffdSJohn Baldwin 				warnx("passthru device %d/%d/%d BAR %d: "
5517a902ec0SNeel Natu 				    "base %#lx or size %#lx not page aligned\n",
5527a902ec0SNeel Natu 				    sc->psc_sel.pc_bus, sc->psc_sel.pc_dev,
5537a902ec0SNeel Natu 				    sc->psc_sel.pc_func, i, base, size);
5547a902ec0SNeel Natu 				return (-1);
5557a902ec0SNeel Natu 			}
5567a902ec0SNeel Natu 		}
557366f6083SPeter Grehan 
558366f6083SPeter Grehan 		/* Cache information about the "real" BAR */
559366f6083SPeter Grehan 		sc->psc_bar[i].type = bartype;
5607a902ec0SNeel Natu 		sc->psc_bar[i].size = size;
561366f6083SPeter Grehan 		sc->psc_bar[i].addr = base;
562366f6083SPeter Grehan 
563366f6083SPeter Grehan 		/* Allocate the BAR in the guest I/O or MMIO space */
564038f5c7bSKonstantin Belousov 		error = pci_emul_alloc_bar(pi, i, bartype, size);
565366f6083SPeter Grehan 		if (error)
566366f6083SPeter Grehan 			return (-1);
567366f6083SPeter Grehan 
568cd942e0fSPeter Grehan 		/* The MSI-X table needs special handling */
569aa12663fSNeel Natu 		if (i == pci_msix_table_bar(pi)) {
570cd942e0fSPeter Grehan 			error = init_msix_table(ctx, sc, base);
571cd942e0fSPeter Grehan 			if (error)
572cd942e0fSPeter Grehan 				return (-1);
573366f6083SPeter Grehan 		}
574366f6083SPeter Grehan 
575366f6083SPeter Grehan 		/*
576366f6083SPeter Grehan 		 * 64-bit BAR takes up two slots so skip the next one.
577366f6083SPeter Grehan 		 */
578366f6083SPeter Grehan 		if (bartype == PCIBAR_MEM64) {
579366f6083SPeter Grehan 			i++;
580366f6083SPeter Grehan 			assert(i <= PCI_BARMAX);
581366f6083SPeter Grehan 			sc->psc_bar[i].type = PCIBAR_MEMHI64;
582366f6083SPeter Grehan 		}
583366f6083SPeter Grehan 	}
584366f6083SPeter Grehan 	return (0);
585366f6083SPeter Grehan }
586366f6083SPeter Grehan 
587366f6083SPeter Grehan static int
588366f6083SPeter Grehan cfginit(struct vmctx *ctx, struct pci_devinst *pi, int bus, int slot, int func)
589366f6083SPeter Grehan {
590366f6083SPeter Grehan 	int error;
591366f6083SPeter Grehan 	struct passthru_softc *sc;
592366f6083SPeter Grehan 
593366f6083SPeter Grehan 	error = 1;
594366f6083SPeter Grehan 	sc = pi->pi_arg;
595366f6083SPeter Grehan 
596366f6083SPeter Grehan 	bzero(&sc->psc_sel, sizeof(struct pcisel));
597366f6083SPeter Grehan 	sc->psc_sel.pc_bus = bus;
598366f6083SPeter Grehan 	sc->psc_sel.pc_dev = slot;
599366f6083SPeter Grehan 	sc->psc_sel.pc_func = func;
600366f6083SPeter Grehan 
601cff92ffdSJohn Baldwin 	if (cfginitmsi(sc) != 0) {
602cff92ffdSJohn Baldwin 		warnx("failed to initialize MSI for PCI %d/%d/%d",
603cff92ffdSJohn Baldwin 		    bus, slot, func);
604cd942e0fSPeter Grehan 		goto done;
605cff92ffdSJohn Baldwin 	}
606cd942e0fSPeter Grehan 
607cff92ffdSJohn Baldwin 	if (cfginitbar(ctx, sc) != 0) {
608cff92ffdSJohn Baldwin 		warnx("failed to initialize BARs for PCI %d/%d/%d",
609cff92ffdSJohn Baldwin 		    bus, slot, func);
610366f6083SPeter Grehan 		goto done;
611cff92ffdSJohn Baldwin 	}
612366f6083SPeter Grehan 
61356282675SJohn Baldwin 	pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(&sc->psc_sel,
61456282675SJohn Baldwin 	    PCIR_COMMAND, 2));
61556282675SJohn Baldwin 
616366f6083SPeter Grehan 	error = 0;				/* success */
617366f6083SPeter Grehan done:
618366f6083SPeter Grehan 	return (error);
619366f6083SPeter Grehan }
620366f6083SPeter Grehan 
621366f6083SPeter Grehan static int
622621b5090SJohn Baldwin passthru_legacy_config(nvlist_t *nvl, const char *opts)
623621b5090SJohn Baldwin {
624621b5090SJohn Baldwin 	char value[16];
625621b5090SJohn Baldwin 	int bus, slot, func;
626621b5090SJohn Baldwin 
627621b5090SJohn Baldwin 	if (opts == NULL)
628621b5090SJohn Baldwin 		return (0);
629621b5090SJohn Baldwin 
630621b5090SJohn Baldwin 	if (sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3) {
631621b5090SJohn Baldwin 		EPRINTLN("passthru: invalid options \"%s\"", opts);
632621b5090SJohn Baldwin 		return (-1);
633621b5090SJohn Baldwin 	}
634621b5090SJohn Baldwin 
635621b5090SJohn Baldwin 	snprintf(value, sizeof(value), "%d", bus);
636621b5090SJohn Baldwin 	set_config_value_node(nvl, "bus", value);
637621b5090SJohn Baldwin 	snprintf(value, sizeof(value), "%d", slot);
638621b5090SJohn Baldwin 	set_config_value_node(nvl, "slot", value);
639621b5090SJohn Baldwin 	snprintf(value, sizeof(value), "%d", func);
640621b5090SJohn Baldwin 	set_config_value_node(nvl, "func", value);
641621b5090SJohn Baldwin 	return (0);
642621b5090SJohn Baldwin }
643621b5090SJohn Baldwin 
644621b5090SJohn Baldwin static int
645621b5090SJohn Baldwin passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl)
646366f6083SPeter Grehan {
6479b1aa8d6SNeel Natu 	int bus, slot, func, error, memflags;
648366f6083SPeter Grehan 	struct passthru_softc *sc;
649621b5090SJohn Baldwin 	const char *value;
65000ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
65100ef17beSBartek Rutkowski 	cap_rights_t rights;
65200ef17beSBartek Rutkowski 	cap_ioctl_t pci_ioctls[] = { PCIOCREAD, PCIOCWRITE, PCIOCGETBAR };
65300ef17beSBartek Rutkowski 	cap_ioctl_t io_ioctls[] = { IODEV_PIO };
65400ef17beSBartek Rutkowski #endif
655366f6083SPeter Grehan 
656366f6083SPeter Grehan 	sc = NULL;
657366f6083SPeter Grehan 	error = 1;
658366f6083SPeter Grehan 
65900ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
66000ef17beSBartek Rutkowski 	cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE);
66100ef17beSBartek Rutkowski #endif
66200ef17beSBartek Rutkowski 
6639b1aa8d6SNeel Natu 	memflags = vm_get_memflags(ctx);
6649b1aa8d6SNeel Natu 	if (!(memflags & VM_MEM_F_WIRED)) {
665cff92ffdSJohn Baldwin 		warnx("passthru requires guest memory to be wired");
666dbb15211SSean Chittenden 		return (error);
6679b1aa8d6SNeel Natu 	}
6689b1aa8d6SNeel Natu 
669366f6083SPeter Grehan 	if (pcifd < 0) {
670366f6083SPeter Grehan 		pcifd = open(_PATH_DEVPCI, O_RDWR, 0);
671cff92ffdSJohn Baldwin 		if (pcifd < 0) {
672cff92ffdSJohn Baldwin 			warn("failed to open %s", _PATH_DEVPCI);
673dbb15211SSean Chittenden 			return (error);
674366f6083SPeter Grehan 		}
675cff92ffdSJohn Baldwin 	}
676366f6083SPeter Grehan 
67700ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
678abfa3c39SMarcelo Araujo 	if (caph_rights_limit(pcifd, &rights) == -1)
67900ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
680abfa3c39SMarcelo Araujo 	if (caph_ioctls_limit(pcifd, pci_ioctls, nitems(pci_ioctls)) == -1)
68100ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
68200ef17beSBartek Rutkowski #endif
68300ef17beSBartek Rutkowski 
684366f6083SPeter Grehan 	if (iofd < 0) {
685366f6083SPeter Grehan 		iofd = open(_PATH_DEVIO, O_RDWR, 0);
686cff92ffdSJohn Baldwin 		if (iofd < 0) {
687cff92ffdSJohn Baldwin 			warn("failed to open %s", _PATH_DEVIO);
688dbb15211SSean Chittenden 			return (error);
689366f6083SPeter Grehan 		}
690cff92ffdSJohn Baldwin 	}
691366f6083SPeter Grehan 
69200ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
693abfa3c39SMarcelo Araujo 	if (caph_rights_limit(iofd, &rights) == -1)
69400ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
695abfa3c39SMarcelo Araujo 	if (caph_ioctls_limit(iofd, io_ioctls, nitems(io_ioctls)) == -1)
69600ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
69700ef17beSBartek Rutkowski #endif
69800ef17beSBartek Rutkowski 
6995c40acf8SJohn Baldwin 	if (memfd < 0) {
7005c40acf8SJohn Baldwin 		memfd = open(_PATH_MEM, O_RDWR, 0);
701cff92ffdSJohn Baldwin 		if (memfd < 0) {
702cff92ffdSJohn Baldwin 			warn("failed to open %s", _PATH_MEM);
703dbb15211SSean Chittenden 			return (error);
7045c40acf8SJohn Baldwin 		}
705cff92ffdSJohn Baldwin 	}
7065c40acf8SJohn Baldwin 
70700ef17beSBartek Rutkowski #ifndef WITHOUT_CAPSICUM
70800ef17beSBartek Rutkowski 	cap_rights_clear(&rights, CAP_IOCTL);
709007e172dSGleb Smirnoff 	cap_rights_set(&rights, CAP_MMAP_RW);
710abfa3c39SMarcelo Araujo 	if (caph_rights_limit(memfd, &rights) == -1)
71100ef17beSBartek Rutkowski 		errx(EX_OSERR, "Unable to apply rights for sandbox");
71200ef17beSBartek Rutkowski #endif
71300ef17beSBartek Rutkowski 
714621b5090SJohn Baldwin #define GET_INT_CONFIG(var, name) do {					\
715621b5090SJohn Baldwin 	value = get_config_value_node(nvl, name);			\
716621b5090SJohn Baldwin 	if (value == NULL) {						\
717621b5090SJohn Baldwin 		EPRINTLN("passthru: missing required %s setting", name); \
718621b5090SJohn Baldwin 		return (error);						\
719621b5090SJohn Baldwin 	}								\
720621b5090SJohn Baldwin 	var = atoi(value);						\
721621b5090SJohn Baldwin } while (0)
722621b5090SJohn Baldwin 
723621b5090SJohn Baldwin 	GET_INT_CONFIG(bus, "bus");
724621b5090SJohn Baldwin 	GET_INT_CONFIG(slot, "slot");
725621b5090SJohn Baldwin 	GET_INT_CONFIG(func, "func");
726366f6083SPeter Grehan 
727cff92ffdSJohn Baldwin 	if (vm_assign_pptdev(ctx, bus, slot, func) != 0) {
728cff92ffdSJohn Baldwin 		warnx("PCI device at %d/%d/%d is not using the ppt(4) driver",
729cff92ffdSJohn Baldwin 		    bus, slot, func);
730366f6083SPeter Grehan 		goto done;
731cff92ffdSJohn Baldwin 	}
732366f6083SPeter Grehan 
733994f858aSXin LI 	sc = calloc(1, sizeof(struct passthru_softc));
734366f6083SPeter Grehan 
735366f6083SPeter Grehan 	pi->pi_arg = sc;
736366f6083SPeter Grehan 	sc->psc_pi = pi;
737366f6083SPeter Grehan 
738366f6083SPeter Grehan 	/* initialize config space */
739dbb15211SSean Chittenden 	error = cfginit(ctx, pi, bus, slot, func);
740366f6083SPeter Grehan done:
741366f6083SPeter Grehan 	if (error) {
742366f6083SPeter Grehan 		free(sc);
743366f6083SPeter Grehan 		vm_unassign_pptdev(ctx, bus, slot, func);
744366f6083SPeter Grehan 	}
745366f6083SPeter Grehan 	return (error);
746366f6083SPeter Grehan }
747366f6083SPeter Grehan 
748366f6083SPeter Grehan static int
749366f6083SPeter Grehan bar_access(int coff)
750366f6083SPeter Grehan {
751366f6083SPeter Grehan 	if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1))
752366f6083SPeter Grehan 		return (1);
753366f6083SPeter Grehan 	else
754366f6083SPeter Grehan 		return (0);
755366f6083SPeter Grehan }
756366f6083SPeter Grehan 
757366f6083SPeter Grehan static int
758366f6083SPeter Grehan msicap_access(struct passthru_softc *sc, int coff)
759366f6083SPeter Grehan {
760366f6083SPeter Grehan 	int caplen;
761366f6083SPeter Grehan 
762366f6083SPeter Grehan 	if (sc->psc_msi.capoff == 0)
763366f6083SPeter Grehan 		return (0);
764366f6083SPeter Grehan 
765366f6083SPeter Grehan 	caplen = msi_caplen(sc->psc_msi.msgctrl);
766366f6083SPeter Grehan 
767366f6083SPeter Grehan 	if (coff >= sc->psc_msi.capoff && coff < sc->psc_msi.capoff + caplen)
768366f6083SPeter Grehan 		return (1);
769366f6083SPeter Grehan 	else
770366f6083SPeter Grehan 		return (0);
771366f6083SPeter Grehan }
772366f6083SPeter Grehan 
773366f6083SPeter Grehan static int
774cd942e0fSPeter Grehan msixcap_access(struct passthru_softc *sc, int coff)
775cd942e0fSPeter Grehan {
776cd942e0fSPeter Grehan 	if (sc->psc_msix.capoff == 0)
777cd942e0fSPeter Grehan 		return (0);
778cd942e0fSPeter Grehan 
779cd942e0fSPeter Grehan 	return (coff >= sc->psc_msix.capoff &&
780cd942e0fSPeter Grehan 	        coff < sc->psc_msix.capoff + MSIX_CAPLEN);
781cd942e0fSPeter Grehan }
782cd942e0fSPeter Grehan 
783cd942e0fSPeter Grehan static int
7844d1e669cSPeter Grehan passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
7854d1e669cSPeter Grehan 		 int coff, int bytes, uint32_t *rv)
786366f6083SPeter Grehan {
787366f6083SPeter Grehan 	struct passthru_softc *sc;
788366f6083SPeter Grehan 
789366f6083SPeter Grehan 	sc = pi->pi_arg;
790366f6083SPeter Grehan 
791366f6083SPeter Grehan 	/*
792366f6083SPeter Grehan 	 * PCI BARs and MSI capability is emulated.
793366f6083SPeter Grehan 	 */
794366f6083SPeter Grehan 	if (bar_access(coff) || msicap_access(sc, coff))
795366f6083SPeter Grehan 		return (-1);
796366f6083SPeter Grehan 
797366f6083SPeter Grehan #ifdef LEGACY_SUPPORT
798366f6083SPeter Grehan 	/*
799366f6083SPeter Grehan 	 * Emulate PCIR_CAP_PTR if this device does not support MSI capability
800366f6083SPeter Grehan 	 * natively.
801366f6083SPeter Grehan 	 */
802366f6083SPeter Grehan 	if (sc->psc_msi.emulated) {
803366f6083SPeter Grehan 		if (coff >= PCIR_CAP_PTR && coff < PCIR_CAP_PTR + 4)
804366f6083SPeter Grehan 			return (-1);
805366f6083SPeter Grehan 	}
806366f6083SPeter Grehan #endif
807366f6083SPeter Grehan 
808c7ba149dSJohn Baldwin 	/*
809c7ba149dSJohn Baldwin 	 * Emulate the command register.  If a single read reads both the
810c7ba149dSJohn Baldwin 	 * command and status registers, read the status register from the
811c7ba149dSJohn Baldwin 	 * device's config space.
812c7ba149dSJohn Baldwin 	 */
813c7ba149dSJohn Baldwin 	if (coff == PCIR_COMMAND) {
814c7ba149dSJohn Baldwin 		if (bytes <= 2)
815c7ba149dSJohn Baldwin 			return (-1);
81621368498SPeter Grehan 		*rv = read_config(&sc->psc_sel, PCIR_STATUS, 2) << 16 |
81721368498SPeter Grehan 		    pci_get_cfgdata16(pi, PCIR_COMMAND);
818c7ba149dSJohn Baldwin 		return (0);
819c7ba149dSJohn Baldwin 	}
820c7ba149dSJohn Baldwin 
821366f6083SPeter Grehan 	/* Everything else just read from the device's config space */
822366f6083SPeter Grehan 	*rv = read_config(&sc->psc_sel, coff, bytes);
823366f6083SPeter Grehan 
824366f6083SPeter Grehan 	return (0);
825366f6083SPeter Grehan }
826366f6083SPeter Grehan 
827366f6083SPeter Grehan static int
8284d1e669cSPeter Grehan passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
8294d1e669cSPeter Grehan 		  int coff, int bytes, uint32_t val)
830366f6083SPeter Grehan {
831cd942e0fSPeter Grehan 	int error, msix_table_entries, i;
832366f6083SPeter Grehan 	struct passthru_softc *sc;
83356282675SJohn Baldwin 	uint16_t cmd_old;
834366f6083SPeter Grehan 
835366f6083SPeter Grehan 	sc = pi->pi_arg;
836366f6083SPeter Grehan 
837366f6083SPeter Grehan 	/*
838366f6083SPeter Grehan 	 * PCI BARs are emulated
839366f6083SPeter Grehan 	 */
840366f6083SPeter Grehan 	if (bar_access(coff))
841366f6083SPeter Grehan 		return (-1);
842366f6083SPeter Grehan 
843366f6083SPeter Grehan 	/*
844366f6083SPeter Grehan 	 * MSI capability is emulated
845366f6083SPeter Grehan 	 */
846366f6083SPeter Grehan 	if (msicap_access(sc, coff)) {
84721368498SPeter Grehan 		pci_emul_capwrite(pi, coff, bytes, val, sc->psc_msi.capoff,
84821368498SPeter Grehan 		    PCIY_MSI);
84955888cfaSNeel Natu 		error = vm_setup_pptdev_msi(ctx, vcpu, sc->psc_sel.pc_bus,
8504f8be175SNeel Natu 			sc->psc_sel.pc_dev, sc->psc_sel.pc_func,
8514f8be175SNeel Natu 			pi->pi_msi.addr, pi->pi_msi.msg_data,
8524f8be175SNeel Natu 			pi->pi_msi.maxmsgnum);
853cff92ffdSJohn Baldwin 		if (error != 0)
854cff92ffdSJohn Baldwin 			err(1, "vm_setup_pptdev_msi");
855366f6083SPeter Grehan 		return (0);
856366f6083SPeter Grehan 	}
857366f6083SPeter Grehan 
858cd942e0fSPeter Grehan 	if (msixcap_access(sc, coff)) {
85921368498SPeter Grehan 		pci_emul_capwrite(pi, coff, bytes, val, sc->psc_msix.capoff,
86021368498SPeter Grehan 		    PCIY_MSIX);
861cd942e0fSPeter Grehan 		if (pi->pi_msix.enabled) {
862cd942e0fSPeter Grehan 			msix_table_entries = pi->pi_msix.table_count;
863cd942e0fSPeter Grehan 			for (i = 0; i < msix_table_entries; i++) {
86455888cfaSNeel Natu 				error = vm_setup_pptdev_msix(ctx, vcpu,
8654f8be175SNeel Natu 				    sc->psc_sel.pc_bus, sc->psc_sel.pc_dev,
866cd942e0fSPeter Grehan 				    sc->psc_sel.pc_func, i,
8674f8be175SNeel Natu 				    pi->pi_msix.table[i].addr,
868cd942e0fSPeter Grehan 				    pi->pi_msix.table[i].msg_data,
8694f8be175SNeel Natu 				    pi->pi_msix.table[i].vector_control);
870cd942e0fSPeter Grehan 
871cff92ffdSJohn Baldwin 				if (error)
872cff92ffdSJohn Baldwin 					err(1, "vm_setup_pptdev_msix");
873cd942e0fSPeter Grehan 			}
8741925586eSJohn Baldwin 		} else {
8751925586eSJohn Baldwin 			error = vm_disable_pptdev_msix(ctx, sc->psc_sel.pc_bus,
8761925586eSJohn Baldwin 			    sc->psc_sel.pc_dev, sc->psc_sel.pc_func);
8771925586eSJohn Baldwin 			if (error)
8781925586eSJohn Baldwin 				err(1, "vm_disable_pptdev_msix");
879cd942e0fSPeter Grehan 		}
880cd942e0fSPeter Grehan 		return (0);
881cd942e0fSPeter Grehan 	}
882cd942e0fSPeter Grehan 
883366f6083SPeter Grehan #ifdef LEGACY_SUPPORT
884366f6083SPeter Grehan 	/*
885366f6083SPeter Grehan 	 * If this device does not support MSI natively then we cannot let
886366f6083SPeter Grehan 	 * the guest disable legacy interrupts from the device. It is the
887366f6083SPeter Grehan 	 * legacy interrupt that is triggering the virtual MSI to the guest.
888366f6083SPeter Grehan 	 */
889366f6083SPeter Grehan 	if (sc->psc_msi.emulated && pci_msi_enabled(pi)) {
890366f6083SPeter Grehan 		if (coff == PCIR_COMMAND && bytes == 2)
891366f6083SPeter Grehan 			val &= ~PCIM_CMD_INTxDIS;
892366f6083SPeter Grehan 	}
893366f6083SPeter Grehan #endif
894366f6083SPeter Grehan 
895366f6083SPeter Grehan 	write_config(&sc->psc_sel, coff, bytes, val);
89656282675SJohn Baldwin 	if (coff == PCIR_COMMAND) {
89756282675SJohn Baldwin 		cmd_old = pci_get_cfgdata16(pi, PCIR_COMMAND);
89856282675SJohn Baldwin 		if (bytes == 1)
89956282675SJohn Baldwin 			pci_set_cfgdata8(pi, PCIR_COMMAND, val);
90056282675SJohn Baldwin 		else if (bytes == 2)
90156282675SJohn Baldwin 			pci_set_cfgdata16(pi, PCIR_COMMAND, val);
90256282675SJohn Baldwin 		pci_emul_cmd_changed(pi, cmd_old);
90356282675SJohn Baldwin 	}
904366f6083SPeter Grehan 
905366f6083SPeter Grehan 	return (0);
906366f6083SPeter Grehan }
907366f6083SPeter Grehan 
908366f6083SPeter Grehan static void
9094d1e669cSPeter Grehan passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
9104d1e669cSPeter Grehan 	       uint64_t offset, int size, uint64_t value)
911366f6083SPeter Grehan {
912366f6083SPeter Grehan 	struct passthru_softc *sc;
913366f6083SPeter Grehan 	struct iodev_pio_req pio;
914366f6083SPeter Grehan 
915366f6083SPeter Grehan 	sc = pi->pi_arg;
916366f6083SPeter Grehan 
917aa12663fSNeel Natu 	if (baridx == pci_msix_table_bar(pi)) {
9184d1e669cSPeter Grehan 		msix_table_write(ctx, vcpu, sc, offset, size, value);
9194d1e669cSPeter Grehan 	} else {
9204d1e669cSPeter Grehan 		assert(pi->pi_bar[baridx].type == PCIBAR_IO);
921366f6083SPeter Grehan 		bzero(&pio, sizeof(struct iodev_pio_req));
922366f6083SPeter Grehan 		pio.access = IODEV_PIO_WRITE;
923366f6083SPeter Grehan 		pio.port = sc->psc_bar[baridx].addr + offset;
924366f6083SPeter Grehan 		pio.width = size;
925366f6083SPeter Grehan 		pio.val = value;
926366f6083SPeter Grehan 
927366f6083SPeter Grehan 		(void)ioctl(iofd, IODEV_PIO, &pio);
928366f6083SPeter Grehan 	}
9294d1e669cSPeter Grehan }
930366f6083SPeter Grehan 
9314d1e669cSPeter Grehan static uint64_t
9324d1e669cSPeter Grehan passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
9334d1e669cSPeter Grehan 	      uint64_t offset, int size)
934366f6083SPeter Grehan {
935366f6083SPeter Grehan 	struct passthru_softc *sc;
936366f6083SPeter Grehan 	struct iodev_pio_req pio;
9374d1e669cSPeter Grehan 	uint64_t val;
938366f6083SPeter Grehan 
939366f6083SPeter Grehan 	sc = pi->pi_arg;
940366f6083SPeter Grehan 
941aa12663fSNeel Natu 	if (baridx == pci_msix_table_bar(pi)) {
9424d1e669cSPeter Grehan 		val = msix_table_read(sc, offset, size);
9434d1e669cSPeter Grehan 	} else {
9444d1e669cSPeter Grehan 		assert(pi->pi_bar[baridx].type == PCIBAR_IO);
945366f6083SPeter Grehan 		bzero(&pio, sizeof(struct iodev_pio_req));
946366f6083SPeter Grehan 		pio.access = IODEV_PIO_READ;
947366f6083SPeter Grehan 		pio.port = sc->psc_bar[baridx].addr + offset;
948366f6083SPeter Grehan 		pio.width = size;
949366f6083SPeter Grehan 		pio.val = 0;
950366f6083SPeter Grehan 
951366f6083SPeter Grehan 		(void)ioctl(iofd, IODEV_PIO, &pio);
952366f6083SPeter Grehan 
9534d1e669cSPeter Grehan 		val = pio.val;
9544d1e669cSPeter Grehan 	}
9554d1e669cSPeter Grehan 
9564d1e669cSPeter Grehan 	return (val);
957366f6083SPeter Grehan }
958366f6083SPeter Grehan 
959*f8a6ec2dSD Scott Phillips static void
960*f8a6ec2dSD Scott Phillips passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
961*f8a6ec2dSD Scott Phillips 		   int enabled, uint64_t address)
962*f8a6ec2dSD Scott Phillips {
963*f8a6ec2dSD Scott Phillips 	struct passthru_softc *sc;
964*f8a6ec2dSD Scott Phillips 	size_t remaining;
965*f8a6ec2dSD Scott Phillips 	uint32_t table_size, table_offset;
966*f8a6ec2dSD Scott Phillips 
967*f8a6ec2dSD Scott Phillips 	sc = pi->pi_arg;
968*f8a6ec2dSD Scott Phillips 	table_offset = rounddown2(pi->pi_msix.table_offset, 4096);
969*f8a6ec2dSD Scott Phillips 	if (table_offset > 0) {
970*f8a6ec2dSD Scott Phillips 		if (!enabled) {
971*f8a6ec2dSD Scott Phillips 			if (vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
972*f8a6ec2dSD Scott Phillips 						 sc->psc_sel.pc_dev,
973*f8a6ec2dSD Scott Phillips 						 sc->psc_sel.pc_func, address,
974*f8a6ec2dSD Scott Phillips 						 table_offset) != 0)
975*f8a6ec2dSD Scott Phillips 				warnx("pci_passthru: unmap_pptdev_mmio failed");
976*f8a6ec2dSD Scott Phillips 		} else {
977*f8a6ec2dSD Scott Phillips 			if (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
978*f8a6ec2dSD Scott Phillips 					       sc->psc_sel.pc_dev,
979*f8a6ec2dSD Scott Phillips 					       sc->psc_sel.pc_func, address,
980*f8a6ec2dSD Scott Phillips 					       table_offset,
981*f8a6ec2dSD Scott Phillips 					       sc->psc_bar[baridx].addr) != 0)
982*f8a6ec2dSD Scott Phillips 				warnx("pci_passthru: map_pptdev_mmio failed");
983*f8a6ec2dSD Scott Phillips 		}
984*f8a6ec2dSD Scott Phillips 	}
985*f8a6ec2dSD Scott Phillips 	table_size = pi->pi_msix.table_offset - table_offset;
986*f8a6ec2dSD Scott Phillips 	table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE;
987*f8a6ec2dSD Scott Phillips 	table_size = roundup2(table_size, 4096);
988*f8a6ec2dSD Scott Phillips 	remaining = pi->pi_bar[baridx].size - table_offset - table_size;
989*f8a6ec2dSD Scott Phillips 	if (remaining > 0) {
990*f8a6ec2dSD Scott Phillips 		address += table_offset + table_size;
991*f8a6ec2dSD Scott Phillips 		if (!enabled) {
992*f8a6ec2dSD Scott Phillips 			if (vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
993*f8a6ec2dSD Scott Phillips 						 sc->psc_sel.pc_dev,
994*f8a6ec2dSD Scott Phillips 						 sc->psc_sel.pc_func, address,
995*f8a6ec2dSD Scott Phillips 						 remaining) != 0)
996*f8a6ec2dSD Scott Phillips 				warnx("pci_passthru: unmap_pptdev_mmio failed");
997*f8a6ec2dSD Scott Phillips 		} else {
998*f8a6ec2dSD Scott Phillips 			if (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
999*f8a6ec2dSD Scott Phillips 					       sc->psc_sel.pc_dev,
1000*f8a6ec2dSD Scott Phillips 					       sc->psc_sel.pc_func, address,
1001*f8a6ec2dSD Scott Phillips 					       remaining,
1002*f8a6ec2dSD Scott Phillips 					       sc->psc_bar[baridx].addr +
1003*f8a6ec2dSD Scott Phillips 					       table_offset + table_size) != 0)
1004*f8a6ec2dSD Scott Phillips 				warnx("pci_passthru: map_pptdev_mmio failed");
1005*f8a6ec2dSD Scott Phillips 		}
1006*f8a6ec2dSD Scott Phillips 	}
1007*f8a6ec2dSD Scott Phillips }
1008*f8a6ec2dSD Scott Phillips 
1009*f8a6ec2dSD Scott Phillips static void
1010*f8a6ec2dSD Scott Phillips passthru_mmio_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
1011*f8a6ec2dSD Scott Phillips 		   int enabled, uint64_t address)
1012*f8a6ec2dSD Scott Phillips {
1013*f8a6ec2dSD Scott Phillips 	struct passthru_softc *sc;
1014*f8a6ec2dSD Scott Phillips 
1015*f8a6ec2dSD Scott Phillips 	sc = pi->pi_arg;
1016*f8a6ec2dSD Scott Phillips 	if (!enabled) {
1017*f8a6ec2dSD Scott Phillips 		if (vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
1018*f8a6ec2dSD Scott Phillips 					 sc->psc_sel.pc_dev,
1019*f8a6ec2dSD Scott Phillips 					 sc->psc_sel.pc_func, address,
1020*f8a6ec2dSD Scott Phillips 					 sc->psc_bar[baridx].size) != 0)
1021*f8a6ec2dSD Scott Phillips 			warnx("pci_passthru: unmap_pptdev_mmio failed");
1022*f8a6ec2dSD Scott Phillips 	} else {
1023*f8a6ec2dSD Scott Phillips 		if (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
1024*f8a6ec2dSD Scott Phillips 				       sc->psc_sel.pc_dev,
1025*f8a6ec2dSD Scott Phillips 				       sc->psc_sel.pc_func, address,
1026*f8a6ec2dSD Scott Phillips 				       sc->psc_bar[baridx].size,
1027*f8a6ec2dSD Scott Phillips 				       sc->psc_bar[baridx].addr) != 0)
1028*f8a6ec2dSD Scott Phillips 			warnx("pci_passthru: map_pptdev_mmio failed");
1029*f8a6ec2dSD Scott Phillips 	}
1030*f8a6ec2dSD Scott Phillips }
1031*f8a6ec2dSD Scott Phillips 
1032*f8a6ec2dSD Scott Phillips static void
1033*f8a6ec2dSD Scott Phillips passthru_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx,
1034*f8a6ec2dSD Scott Phillips 	      int enabled, uint64_t address)
1035*f8a6ec2dSD Scott Phillips {
1036*f8a6ec2dSD Scott Phillips 
1037*f8a6ec2dSD Scott Phillips 	if (pi->pi_bar[baridx].type == PCIBAR_IO)
1038*f8a6ec2dSD Scott Phillips 		return;
1039*f8a6ec2dSD Scott Phillips 	if (baridx == pci_msix_table_bar(pi))
1040*f8a6ec2dSD Scott Phillips 		passthru_msix_addr(ctx, pi, baridx, enabled, address);
1041*f8a6ec2dSD Scott Phillips 	else
1042*f8a6ec2dSD Scott Phillips 		passthru_mmio_addr(ctx, pi, baridx, enabled, address);
1043*f8a6ec2dSD Scott Phillips }
1044*f8a6ec2dSD Scott Phillips 
1045366f6083SPeter Grehan struct pci_devemu passthru = {
1046366f6083SPeter Grehan 	.pe_emu		= "passthru",
1047366f6083SPeter Grehan 	.pe_init	= passthru_init,
1048621b5090SJohn Baldwin 	.pe_legacy_config = passthru_legacy_config,
1049366f6083SPeter Grehan 	.pe_cfgwrite	= passthru_cfgwrite,
1050366f6083SPeter Grehan 	.pe_cfgread	= passthru_cfgread,
10514d1e669cSPeter Grehan 	.pe_barwrite 	= passthru_write,
10524d1e669cSPeter Grehan 	.pe_barread    	= passthru_read,
1053*f8a6ec2dSD Scott Phillips 	.pe_baraddr	= passthru_addr,
1054366f6083SPeter Grehan };
1055366f6083SPeter Grehan PCI_EMUL_SET(passthru);
1056