14c87aefeSPatrick Mooney /*- 24c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c87aefeSPatrick Mooney * 44c87aefeSPatrick Mooney * Copyright (c) 2011 NetApp, Inc. 54c87aefeSPatrick Mooney * All rights reserved. 64c87aefeSPatrick Mooney * 74c87aefeSPatrick Mooney * Redistribution and use in source and binary forms, with or without 84c87aefeSPatrick Mooney * modification, are permitted provided that the following conditions 94c87aefeSPatrick Mooney * are met: 104c87aefeSPatrick Mooney * 1. Redistributions of source code must retain the above copyright 114c87aefeSPatrick Mooney * notice, this list of conditions and the following disclaimer. 124c87aefeSPatrick Mooney * 2. Redistributions in binary form must reproduce the above copyright 134c87aefeSPatrick Mooney * notice, this list of conditions and the following disclaimer in the 144c87aefeSPatrick Mooney * documentation and/or other materials provided with the distribution. 154c87aefeSPatrick Mooney * 164c87aefeSPatrick Mooney * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 174c87aefeSPatrick Mooney * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184c87aefeSPatrick Mooney * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194c87aefeSPatrick Mooney * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 204c87aefeSPatrick Mooney * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214c87aefeSPatrick Mooney * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224c87aefeSPatrick Mooney * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234c87aefeSPatrick Mooney * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244c87aefeSPatrick Mooney * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254c87aefeSPatrick Mooney * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264c87aefeSPatrick Mooney * SUCH DAMAGE. 274c87aefeSPatrick Mooney * 284c87aefeSPatrick Mooney * $FreeBSD$ 294c87aefeSPatrick Mooney */ 304c87aefeSPatrick Mooney 314c87aefeSPatrick Mooney #include <sys/cdefs.h> 324c87aefeSPatrick Mooney __FBSDID("$FreeBSD$"); 334c87aefeSPatrick Mooney 344c87aefeSPatrick Mooney #include <sys/param.h> 354c87aefeSPatrick Mooney #include <sys/types.h> 364c87aefeSPatrick Mooney #include <sys/mman.h> 374c87aefeSPatrick Mooney #include <sys/pciio.h> 384c87aefeSPatrick Mooney #include <sys/ioctl.h> 39d7b72f7bSAndy Fiddaman #include <sys/stat.h> 404c87aefeSPatrick Mooney 41eb9a1df2SHans Rosenfeld #include <sys/pci.h> 42eb9a1df2SHans Rosenfeld 434c87aefeSPatrick Mooney #include <dev/io/iodev.h> 444c87aefeSPatrick Mooney #include <dev/pci/pcireg.h> 454c87aefeSPatrick Mooney 464c87aefeSPatrick Mooney #include <machine/iodev.h> 474c87aefeSPatrick Mooney 484c87aefeSPatrick Mooney #include <stdio.h> 494c87aefeSPatrick Mooney #include <stdlib.h> 504c87aefeSPatrick Mooney #include <string.h> 514c87aefeSPatrick Mooney #include <err.h> 524c87aefeSPatrick Mooney #include <errno.h> 534c87aefeSPatrick Mooney #include <fcntl.h> 544c87aefeSPatrick Mooney #include <sysexits.h> 554c87aefeSPatrick Mooney #include <unistd.h> 564c87aefeSPatrick Mooney 574c87aefeSPatrick Mooney #include <machine/vmm.h> 584c87aefeSPatrick Mooney #include <vmmapi.h> 59eb9a1df2SHans Rosenfeld #include <sys/ppt_dev.h> 602b948146SAndy Fiddaman 612b948146SAndy Fiddaman #include "config.h" 622b948146SAndy Fiddaman #include "debug.h" 63d7b72f7bSAndy Fiddaman #include "pci_passthru.h" 644c87aefeSPatrick Mooney #include "mem.h" 654c87aefeSPatrick Mooney 664c87aefeSPatrick Mooney #define LEGACY_SUPPORT 1 674c87aefeSPatrick Mooney 684c87aefeSPatrick Mooney #define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1) 694c87aefeSPatrick Mooney #define MSIX_CAPLEN 12 704c87aefeSPatrick Mooney 714c87aefeSPatrick Mooney struct passthru_softc { 724c87aefeSPatrick Mooney struct pci_devinst *psc_pi; 73d7b72f7bSAndy Fiddaman /* ROM is handled like a BAR */ 74d7b72f7bSAndy Fiddaman struct pcibar psc_bar[PCI_BARMAX_WITH_ROM + 1]; 754c87aefeSPatrick Mooney struct { 764c87aefeSPatrick Mooney int capoff; 774c87aefeSPatrick Mooney int msgctrl; 784c87aefeSPatrick Mooney int emulated; 794c87aefeSPatrick Mooney } psc_msi; 804c87aefeSPatrick Mooney struct { 814c87aefeSPatrick Mooney int capoff; 824c87aefeSPatrick Mooney } psc_msix; 83eb9a1df2SHans Rosenfeld int pptfd; 84eb9a1df2SHans Rosenfeld int msi_limit; 85eb9a1df2SHans Rosenfeld int msix_limit; 864c87aefeSPatrick Mooney }; 874c87aefeSPatrick Mooney 884c87aefeSPatrick Mooney static int 894c87aefeSPatrick Mooney msi_caplen(int msgctrl) 904c87aefeSPatrick Mooney { 914c87aefeSPatrick Mooney int len; 924c87aefeSPatrick Mooney 934c87aefeSPatrick Mooney len = 10; /* minimum length of msi capability */ 944c87aefeSPatrick Mooney 954c87aefeSPatrick Mooney if (msgctrl & PCIM_MSICTRL_64BIT) 964c87aefeSPatrick Mooney len += 4; 974c87aefeSPatrick Mooney 984c87aefeSPatrick Mooney #if 0 994c87aefeSPatrick Mooney /* 1004c87aefeSPatrick Mooney * Ignore the 'mask' and 'pending' bits in the MSI capability. 1014c87aefeSPatrick Mooney * We'll let the guest manipulate them directly. 1024c87aefeSPatrick Mooney */ 1034c87aefeSPatrick Mooney if (msgctrl & PCIM_MSICTRL_VECTOR) 1044c87aefeSPatrick Mooney len += 10; 1054c87aefeSPatrick Mooney #endif 1064c87aefeSPatrick Mooney 1074c87aefeSPatrick Mooney return (len); 1084c87aefeSPatrick Mooney } 1094c87aefeSPatrick Mooney 1104c87aefeSPatrick Mooney static uint32_t 111d7b72f7bSAndy Fiddaman passthru_read_config(const struct passthru_softc *sc, long reg, int width) 1124c87aefeSPatrick Mooney { 113eb9a1df2SHans Rosenfeld struct ppt_cfg_io pi; 1144c87aefeSPatrick Mooney 115eb9a1df2SHans Rosenfeld pi.pci_off = reg; 116eb9a1df2SHans Rosenfeld pi.pci_width = width; 1174c87aefeSPatrick Mooney 118eb9a1df2SHans Rosenfeld if (ioctl(sc->pptfd, PPT_CFG_READ, &pi) != 0) { 119eb9a1df2SHans Rosenfeld return (0); 120eb9a1df2SHans Rosenfeld } 121eb9a1df2SHans Rosenfeld return (pi.pci_data); 1224c87aefeSPatrick Mooney } 1234c87aefeSPatrick Mooney 1244c87aefeSPatrick Mooney static void 125d7b72f7bSAndy Fiddaman passthru_write_config(const struct passthru_softc *sc, long reg, int width, 126eb9a1df2SHans Rosenfeld uint32_t data) 1274c87aefeSPatrick Mooney { 128eb9a1df2SHans Rosenfeld struct ppt_cfg_io pi; 1294c87aefeSPatrick Mooney 130eb9a1df2SHans Rosenfeld pi.pci_off = reg; 131eb9a1df2SHans Rosenfeld pi.pci_width = width; 132eb9a1df2SHans Rosenfeld pi.pci_data = data; 1334c87aefeSPatrick Mooney 134eb9a1df2SHans Rosenfeld (void) ioctl(sc->pptfd, PPT_CFG_WRITE, &pi); 135eb9a1df2SHans Rosenfeld } 136eb9a1df2SHans Rosenfeld 137d7b72f7bSAndy Fiddaman uint32_t 138d7b72f7bSAndy Fiddaman read_config(struct pci_devinst *pi, long reg, int width) 139d7b72f7bSAndy Fiddaman { 140d7b72f7bSAndy Fiddaman struct passthru_softc *sc = pi->pi_arg; 141d7b72f7bSAndy Fiddaman 142d7b72f7bSAndy Fiddaman return (passthru_read_config(sc, reg, width)); 143d7b72f7bSAndy Fiddaman } 144d7b72f7bSAndy Fiddaman 145d7b72f7bSAndy Fiddaman void 146d7b72f7bSAndy Fiddaman write_config(struct pci_devinst *pi, long reg, int width, uint32_t data) 147d7b72f7bSAndy Fiddaman { 148d7b72f7bSAndy Fiddaman struct passthru_softc *sc = pi->pi_arg; 149d7b72f7bSAndy Fiddaman 150d7b72f7bSAndy Fiddaman passthru_write_config(sc, reg, width, data); 151d7b72f7bSAndy Fiddaman } 152d7b72f7bSAndy Fiddaman 153eb9a1df2SHans Rosenfeld static int 154eb9a1df2SHans Rosenfeld passthru_get_bar(struct passthru_softc *sc, int bar, enum pcibar_type *type, 155eb9a1df2SHans Rosenfeld uint64_t *base, uint64_t *size) 156eb9a1df2SHans Rosenfeld { 157eb9a1df2SHans Rosenfeld struct ppt_bar_query pb; 158eb9a1df2SHans Rosenfeld 159eb9a1df2SHans Rosenfeld pb.pbq_baridx = bar; 160eb9a1df2SHans Rosenfeld 161eb9a1df2SHans Rosenfeld if (ioctl(sc->pptfd, PPT_BAR_QUERY, &pb) != 0) { 162eb9a1df2SHans Rosenfeld return (-1); 163eb9a1df2SHans Rosenfeld } 164eb9a1df2SHans Rosenfeld 165eb9a1df2SHans Rosenfeld switch (pb.pbq_type) { 166eb9a1df2SHans Rosenfeld case PCI_ADDR_IO: 167eb9a1df2SHans Rosenfeld *type = PCIBAR_IO; 168eb9a1df2SHans Rosenfeld break; 169eb9a1df2SHans Rosenfeld case PCI_ADDR_MEM32: 170eb9a1df2SHans Rosenfeld *type = PCIBAR_MEM32; 171eb9a1df2SHans Rosenfeld break; 172eb9a1df2SHans Rosenfeld case PCI_ADDR_MEM64: 173eb9a1df2SHans Rosenfeld *type = PCIBAR_MEM64; 174eb9a1df2SHans Rosenfeld break; 175eb9a1df2SHans Rosenfeld default: 176eb9a1df2SHans Rosenfeld err(1, "unrecognized BAR type: %u\n", pb.pbq_type); 177eb9a1df2SHans Rosenfeld break; 178eb9a1df2SHans Rosenfeld } 179eb9a1df2SHans Rosenfeld 180eb9a1df2SHans Rosenfeld *base = pb.pbq_base; 181eb9a1df2SHans Rosenfeld *size = pb.pbq_size; 182eb9a1df2SHans Rosenfeld return (0); 183eb9a1df2SHans Rosenfeld } 184eb9a1df2SHans Rosenfeld 185eb9a1df2SHans Rosenfeld static int 186eb9a1df2SHans Rosenfeld passthru_dev_open(const char *path, int *pptfdp) 187eb9a1df2SHans Rosenfeld { 188eb9a1df2SHans Rosenfeld int pptfd; 189eb9a1df2SHans Rosenfeld 190eb9a1df2SHans Rosenfeld if ((pptfd = open(path, O_RDWR)) < 0) { 191eb9a1df2SHans Rosenfeld return (errno); 192eb9a1df2SHans Rosenfeld } 193eb9a1df2SHans Rosenfeld 194eb9a1df2SHans Rosenfeld /* XXX: verify fd with ioctl? */ 195eb9a1df2SHans Rosenfeld *pptfdp = pptfd; 196eb9a1df2SHans Rosenfeld return (0); 1974c87aefeSPatrick Mooney } 1984c87aefeSPatrick Mooney 1994c87aefeSPatrick Mooney #ifdef LEGACY_SUPPORT 2004c87aefeSPatrick Mooney static int 2014c87aefeSPatrick Mooney passthru_add_msicap(struct pci_devinst *pi, int msgnum, int nextptr) 2024c87aefeSPatrick Mooney { 203*59d65d31SAndy Fiddaman int capoff; 2044c87aefeSPatrick Mooney struct msicap msicap; 2054c87aefeSPatrick Mooney u_char *capdata; 2064c87aefeSPatrick Mooney 2074c87aefeSPatrick Mooney pci_populate_msicap(&msicap, msgnum, nextptr); 2084c87aefeSPatrick Mooney 2094c87aefeSPatrick Mooney /* 2104c87aefeSPatrick Mooney * XXX 2114c87aefeSPatrick Mooney * Copy the msi capability structure in the last 16 bytes of the 2124c87aefeSPatrick Mooney * config space. This is wrong because it could shadow something 2134c87aefeSPatrick Mooney * useful to the device. 2144c87aefeSPatrick Mooney */ 2154c87aefeSPatrick Mooney capoff = 256 - roundup(sizeof(msicap), 4); 2164c87aefeSPatrick Mooney capdata = (u_char *)&msicap; 217*59d65d31SAndy Fiddaman for (size_t i = 0; i < sizeof(msicap); i++) 2184c87aefeSPatrick Mooney pci_set_cfgdata8(pi, capoff + i, capdata[i]); 2194c87aefeSPatrick Mooney 2204c87aefeSPatrick Mooney return (capoff); 2214c87aefeSPatrick Mooney } 2224c87aefeSPatrick Mooney #endif /* LEGACY_SUPPORT */ 2234c87aefeSPatrick Mooney 224eb9a1df2SHans Rosenfeld static void 225eb9a1df2SHans Rosenfeld passthru_intr_limit(struct passthru_softc *sc, struct msixcap *msixcap) 226eb9a1df2SHans Rosenfeld { 227eb9a1df2SHans Rosenfeld struct pci_devinst *pi = sc->psc_pi; 228eb9a1df2SHans Rosenfeld int off; 229eb9a1df2SHans Rosenfeld 230eb9a1df2SHans Rosenfeld /* Reduce the number of MSI vectors if higher than OS limit */ 231eb9a1df2SHans Rosenfeld if ((off = sc->psc_msi.capoff) != 0 && sc->msi_limit != -1) { 232eb9a1df2SHans Rosenfeld int msi_limit, mmc; 233eb9a1df2SHans Rosenfeld 234eb9a1df2SHans Rosenfeld msi_limit = 235eb9a1df2SHans Rosenfeld sc->msi_limit > 16 ? PCIM_MSICTRL_MMC_32 : 236eb9a1df2SHans Rosenfeld sc->msi_limit > 8 ? PCIM_MSICTRL_MMC_16 : 237eb9a1df2SHans Rosenfeld sc->msi_limit > 4 ? PCIM_MSICTRL_MMC_8 : 238eb9a1df2SHans Rosenfeld sc->msi_limit > 2 ? PCIM_MSICTRL_MMC_4 : 239eb9a1df2SHans Rosenfeld sc->msi_limit > 1 ? PCIM_MSICTRL_MMC_2 : 240eb9a1df2SHans Rosenfeld PCIM_MSICTRL_MMC_1; 241eb9a1df2SHans Rosenfeld mmc = sc->psc_msi.msgctrl & PCIM_MSICTRL_MMC_MASK; 242eb9a1df2SHans Rosenfeld 243eb9a1df2SHans Rosenfeld if (mmc > msi_limit) { 244eb9a1df2SHans Rosenfeld sc->psc_msi.msgctrl &= ~PCIM_MSICTRL_MMC_MASK; 245eb9a1df2SHans Rosenfeld sc->psc_msi.msgctrl |= msi_limit; 246eb9a1df2SHans Rosenfeld pci_set_cfgdata16(pi, off + 2, sc->psc_msi.msgctrl); 247eb9a1df2SHans Rosenfeld } 248eb9a1df2SHans Rosenfeld } 249eb9a1df2SHans Rosenfeld 250eb9a1df2SHans Rosenfeld /* Reduce the number of MSI-X vectors if higher than OS limit */ 251eb9a1df2SHans Rosenfeld if ((off = sc->psc_msix.capoff) != 0 && sc->msix_limit != -1) { 252eb9a1df2SHans Rosenfeld if (MSIX_TABLE_COUNT(msixcap->msgctrl) > sc->msix_limit) { 253eb9a1df2SHans Rosenfeld msixcap->msgctrl &= ~PCIM_MSIXCTRL_TABLE_SIZE; 254eb9a1df2SHans Rosenfeld msixcap->msgctrl |= sc->msix_limit - 1; 255eb9a1df2SHans Rosenfeld pci_set_cfgdata16(pi, off + 2, msixcap->msgctrl); 256eb9a1df2SHans Rosenfeld } 257eb9a1df2SHans Rosenfeld } 258eb9a1df2SHans Rosenfeld } 259eb9a1df2SHans Rosenfeld 2604c87aefeSPatrick Mooney static int 2614c87aefeSPatrick Mooney cfginitmsi(struct passthru_softc *sc) 2624c87aefeSPatrick Mooney { 2634c87aefeSPatrick Mooney int i, ptr, capptr, cap, sts, caplen, table_size; 2644c87aefeSPatrick Mooney uint32_t u32; 265eb9a1df2SHans Rosenfeld struct pci_devinst *pi = sc->psc_pi; 2664c87aefeSPatrick Mooney struct msixcap msixcap; 267*59d65d31SAndy Fiddaman char *msixcap_ptr; 2684c87aefeSPatrick Mooney 2694c87aefeSPatrick Mooney /* 2704c87aefeSPatrick Mooney * Parse the capabilities and cache the location of the MSI 2714c87aefeSPatrick Mooney * and MSI-X capabilities. 2724c87aefeSPatrick Mooney */ 273d7b72f7bSAndy Fiddaman sts = passthru_read_config(sc, PCIR_STATUS, 2); 2744c87aefeSPatrick Mooney if (sts & PCIM_STATUS_CAPPRESENT) { 275d7b72f7bSAndy Fiddaman ptr = passthru_read_config(sc, PCIR_CAP_PTR, 1); 2764c87aefeSPatrick Mooney while (ptr != 0 && ptr != 0xff) { 277d7b72f7bSAndy Fiddaman cap = passthru_read_config(sc, ptr + PCICAP_ID, 1); 2784c87aefeSPatrick Mooney if (cap == PCIY_MSI) { 2794c87aefeSPatrick Mooney /* 2804c87aefeSPatrick Mooney * Copy the MSI capability into the config 2814c87aefeSPatrick Mooney * space of the emulated pci device 2824c87aefeSPatrick Mooney */ 2834c87aefeSPatrick Mooney sc->psc_msi.capoff = ptr; 284d7b72f7bSAndy Fiddaman sc->psc_msi.msgctrl = passthru_read_config(sc, 2854c87aefeSPatrick Mooney ptr + 2, 2); 2864c87aefeSPatrick Mooney sc->psc_msi.emulated = 0; 2874c87aefeSPatrick Mooney caplen = msi_caplen(sc->psc_msi.msgctrl); 2884c87aefeSPatrick Mooney capptr = ptr; 2894c87aefeSPatrick Mooney while (caplen > 0) { 290d7b72f7bSAndy Fiddaman u32 = passthru_read_config(sc, 291d7b72f7bSAndy Fiddaman capptr, 4); 2924c87aefeSPatrick Mooney pci_set_cfgdata32(pi, capptr, u32); 2934c87aefeSPatrick Mooney caplen -= 4; 2944c87aefeSPatrick Mooney capptr += 4; 2954c87aefeSPatrick Mooney } 2964c87aefeSPatrick Mooney } else if (cap == PCIY_MSIX) { 2974c87aefeSPatrick Mooney /* 2984c87aefeSPatrick Mooney * Copy the MSI-X capability 2994c87aefeSPatrick Mooney */ 3004c87aefeSPatrick Mooney sc->psc_msix.capoff = ptr; 3014c87aefeSPatrick Mooney caplen = 12; 302*59d65d31SAndy Fiddaman msixcap_ptr = (char *)&msixcap; 3034c87aefeSPatrick Mooney capptr = ptr; 3044c87aefeSPatrick Mooney while (caplen > 0) { 305d7b72f7bSAndy Fiddaman u32 = passthru_read_config(sc, 306d7b72f7bSAndy Fiddaman capptr, 4); 307*59d65d31SAndy Fiddaman memcpy(msixcap_ptr, &u32, 4); 3084c87aefeSPatrick Mooney pci_set_cfgdata32(pi, capptr, u32); 3094c87aefeSPatrick Mooney caplen -= 4; 3104c87aefeSPatrick Mooney capptr += 4; 311*59d65d31SAndy Fiddaman msixcap_ptr += 4; 3124c87aefeSPatrick Mooney } 3134c87aefeSPatrick Mooney } 314d7b72f7bSAndy Fiddaman ptr = passthru_read_config(sc, ptr + PCICAP_NEXTPTR, 1); 3154c87aefeSPatrick Mooney } 3164c87aefeSPatrick Mooney } 3174c87aefeSPatrick Mooney 318eb9a1df2SHans Rosenfeld passthru_intr_limit(sc, &msixcap); 319eb9a1df2SHans Rosenfeld 3204c87aefeSPatrick Mooney if (sc->psc_msix.capoff != 0) { 3214c87aefeSPatrick Mooney pi->pi_msix.pba_bar = 3224c87aefeSPatrick Mooney msixcap.pba_info & PCIM_MSIX_BIR_MASK; 3234c87aefeSPatrick Mooney pi->pi_msix.pba_offset = 3244c87aefeSPatrick Mooney msixcap.pba_info & ~PCIM_MSIX_BIR_MASK; 3254c87aefeSPatrick Mooney pi->pi_msix.table_bar = 3264c87aefeSPatrick Mooney msixcap.table_info & PCIM_MSIX_BIR_MASK; 3274c87aefeSPatrick Mooney pi->pi_msix.table_offset = 3284c87aefeSPatrick Mooney msixcap.table_info & ~PCIM_MSIX_BIR_MASK; 3294c87aefeSPatrick Mooney pi->pi_msix.table_count = MSIX_TABLE_COUNT(msixcap.msgctrl); 3304c87aefeSPatrick Mooney pi->pi_msix.pba_size = PBA_SIZE(pi->pi_msix.table_count); 3314c87aefeSPatrick Mooney 3324c87aefeSPatrick Mooney /* Allocate the emulated MSI-X table array */ 3334c87aefeSPatrick Mooney table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; 3344c87aefeSPatrick Mooney pi->pi_msix.table = calloc(1, table_size); 3354c87aefeSPatrick Mooney 3364c87aefeSPatrick Mooney /* Mask all table entries */ 3374c87aefeSPatrick Mooney for (i = 0; i < pi->pi_msix.table_count; i++) { 3384c87aefeSPatrick Mooney pi->pi_msix.table[i].vector_control |= 3394c87aefeSPatrick Mooney PCIM_MSIX_VCTRL_MASK; 3404c87aefeSPatrick Mooney } 3414c87aefeSPatrick Mooney } 3424c87aefeSPatrick Mooney 3434c87aefeSPatrick Mooney #ifdef LEGACY_SUPPORT 3444c87aefeSPatrick Mooney /* 3454c87aefeSPatrick Mooney * If the passthrough device does not support MSI then craft a 3464c87aefeSPatrick Mooney * MSI capability for it. We link the new MSI capability at the 3474c87aefeSPatrick Mooney * head of the list of capabilities. 3484c87aefeSPatrick Mooney */ 3494c87aefeSPatrick Mooney if ((sts & PCIM_STATUS_CAPPRESENT) != 0 && sc->psc_msi.capoff == 0) { 3504c87aefeSPatrick Mooney int origptr, msiptr; 351d7b72f7bSAndy Fiddaman origptr = passthru_read_config(sc, PCIR_CAP_PTR, 1); 3524c87aefeSPatrick Mooney msiptr = passthru_add_msicap(pi, 1, origptr); 3534c87aefeSPatrick Mooney sc->psc_msi.capoff = msiptr; 3544c87aefeSPatrick Mooney sc->psc_msi.msgctrl = pci_get_cfgdata16(pi, msiptr + 2); 3554c87aefeSPatrick Mooney sc->psc_msi.emulated = 1; 3564c87aefeSPatrick Mooney pci_set_cfgdata8(pi, PCIR_CAP_PTR, msiptr); 3574c87aefeSPatrick Mooney } 3584c87aefeSPatrick Mooney #endif 3594c87aefeSPatrick Mooney 3604c87aefeSPatrick Mooney /* Make sure one of the capabilities is present */ 3616dc98349SAndy Fiddaman if (sc->psc_msi.capoff == 0 && sc->psc_msix.capoff == 0) 3624c87aefeSPatrick Mooney return (-1); 3636dc98349SAndy Fiddaman else 3644c87aefeSPatrick Mooney return (0); 3654c87aefeSPatrick Mooney } 3664c87aefeSPatrick Mooney 3674c87aefeSPatrick Mooney static uint64_t 3686dc98349SAndy Fiddaman msix_table_read(struct passthru_softc *sc, uint64_t offset, int size) 3694c87aefeSPatrick Mooney { 3704c87aefeSPatrick Mooney struct pci_devinst *pi; 3714c87aefeSPatrick Mooney struct msix_table_entry *entry; 3724c87aefeSPatrick Mooney uint8_t *src8; 3734c87aefeSPatrick Mooney uint16_t *src16; 3744c87aefeSPatrick Mooney uint32_t *src32; 3754c87aefeSPatrick Mooney uint64_t *src64; 3764c87aefeSPatrick Mooney uint64_t data; 3774c87aefeSPatrick Mooney size_t entry_offset; 3786dc98349SAndy Fiddaman uint32_t table_offset; 3796dc98349SAndy Fiddaman int index, table_count; 3804c87aefeSPatrick Mooney 3814c87aefeSPatrick Mooney pi = sc->psc_pi; 3826dc98349SAndy Fiddaman 3836dc98349SAndy Fiddaman table_offset = pi->pi_msix.table_offset; 3846dc98349SAndy Fiddaman table_count = pi->pi_msix.table_count; 3856dc98349SAndy Fiddaman if (offset < table_offset || 3866dc98349SAndy Fiddaman offset >= table_offset + table_count * MSIX_TABLE_ENTRY_SIZE) { 3874c87aefeSPatrick Mooney switch (size) { 3884c87aefeSPatrick Mooney case 1: 3896dc98349SAndy Fiddaman src8 = (uint8_t *)(pi->pi_msix.mapped_addr + offset); 3904c87aefeSPatrick Mooney data = *src8; 3914c87aefeSPatrick Mooney break; 3924c87aefeSPatrick Mooney case 2: 3936dc98349SAndy Fiddaman src16 = (uint16_t *)(pi->pi_msix.mapped_addr + offset); 3944c87aefeSPatrick Mooney data = *src16; 3954c87aefeSPatrick Mooney break; 3964c87aefeSPatrick Mooney case 4: 3976dc98349SAndy Fiddaman src32 = (uint32_t *)(pi->pi_msix.mapped_addr + offset); 3984c87aefeSPatrick Mooney data = *src32; 3994c87aefeSPatrick Mooney break; 4004c87aefeSPatrick Mooney case 8: 4016dc98349SAndy Fiddaman src64 = (uint64_t *)(pi->pi_msix.mapped_addr + offset); 4024c87aefeSPatrick Mooney data = *src64; 4034c87aefeSPatrick Mooney break; 4044c87aefeSPatrick Mooney default: 4054c87aefeSPatrick Mooney return (-1); 4064c87aefeSPatrick Mooney } 4074c87aefeSPatrick Mooney return (data); 4084c87aefeSPatrick Mooney } 4094c87aefeSPatrick Mooney 4106dc98349SAndy Fiddaman offset -= table_offset; 4114c87aefeSPatrick Mooney index = offset / MSIX_TABLE_ENTRY_SIZE; 4126dc98349SAndy Fiddaman assert(index < table_count); 4134c87aefeSPatrick Mooney 4144c87aefeSPatrick Mooney entry = &pi->pi_msix.table[index]; 4154c87aefeSPatrick Mooney entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; 4164c87aefeSPatrick Mooney 4174c87aefeSPatrick Mooney switch (size) { 4184c87aefeSPatrick Mooney case 1: 4196dc98349SAndy Fiddaman src8 = (uint8_t *)((uint8_t *)entry + entry_offset); 4204c87aefeSPatrick Mooney data = *src8; 4214c87aefeSPatrick Mooney break; 4224c87aefeSPatrick Mooney case 2: 4236dc98349SAndy Fiddaman src16 = (uint16_t *)((uint8_t *)entry + entry_offset); 4244c87aefeSPatrick Mooney data = *src16; 4254c87aefeSPatrick Mooney break; 4264c87aefeSPatrick Mooney case 4: 4276dc98349SAndy Fiddaman src32 = (uint32_t *)((uint8_t *)entry + entry_offset); 4284c87aefeSPatrick Mooney data = *src32; 4294c87aefeSPatrick Mooney break; 4304c87aefeSPatrick Mooney case 8: 4316dc98349SAndy Fiddaman src64 = (uint64_t *)((uint8_t *)entry + entry_offset); 4324c87aefeSPatrick Mooney data = *src64; 4334c87aefeSPatrick Mooney break; 4344c87aefeSPatrick Mooney default: 4354c87aefeSPatrick Mooney return (-1); 4364c87aefeSPatrick Mooney } 4374c87aefeSPatrick Mooney 4384c87aefeSPatrick Mooney return (data); 4394c87aefeSPatrick Mooney } 4404c87aefeSPatrick Mooney 4414c87aefeSPatrick Mooney static void 442*59d65d31SAndy Fiddaman msix_table_write(struct vmctx *ctx, struct passthru_softc *sc, 4436dc98349SAndy Fiddaman uint64_t offset, int size, uint64_t data) 4444c87aefeSPatrick Mooney { 4454c87aefeSPatrick Mooney struct pci_devinst *pi; 4464c87aefeSPatrick Mooney struct msix_table_entry *entry; 4474c87aefeSPatrick Mooney uint8_t *dest8; 4484c87aefeSPatrick Mooney uint16_t *dest16; 4494c87aefeSPatrick Mooney uint32_t *dest32; 4504c87aefeSPatrick Mooney uint64_t *dest64; 4514c87aefeSPatrick Mooney size_t entry_offset; 4526dc98349SAndy Fiddaman uint32_t table_offset, vector_control; 4536dc98349SAndy Fiddaman int index, table_count; 4544c87aefeSPatrick Mooney 4554c87aefeSPatrick Mooney pi = sc->psc_pi; 4566dc98349SAndy Fiddaman 4576dc98349SAndy Fiddaman table_offset = pi->pi_msix.table_offset; 4586dc98349SAndy Fiddaman table_count = pi->pi_msix.table_count; 4596dc98349SAndy Fiddaman if (offset < table_offset || 4606dc98349SAndy Fiddaman offset >= table_offset + table_count * MSIX_TABLE_ENTRY_SIZE) { 4614c87aefeSPatrick Mooney switch (size) { 4624c87aefeSPatrick Mooney case 1: 4636dc98349SAndy Fiddaman dest8 = (uint8_t *)(pi->pi_msix.mapped_addr + offset); 4644c87aefeSPatrick Mooney *dest8 = data; 4654c87aefeSPatrick Mooney break; 4664c87aefeSPatrick Mooney case 2: 4676dc98349SAndy Fiddaman dest16 = (uint16_t *)(pi->pi_msix.mapped_addr + offset); 4684c87aefeSPatrick Mooney *dest16 = data; 4694c87aefeSPatrick Mooney break; 4704c87aefeSPatrick Mooney case 4: 4716dc98349SAndy Fiddaman dest32 = (uint32_t *)(pi->pi_msix.mapped_addr + offset); 4724c87aefeSPatrick Mooney *dest32 = data; 4734c87aefeSPatrick Mooney break; 4744c87aefeSPatrick Mooney case 8: 4756dc98349SAndy Fiddaman dest64 = (uint64_t *)(pi->pi_msix.mapped_addr + offset); 4764c87aefeSPatrick Mooney *dest64 = data; 4774c87aefeSPatrick Mooney break; 4784c87aefeSPatrick Mooney } 4794c87aefeSPatrick Mooney return; 4804c87aefeSPatrick Mooney } 4814c87aefeSPatrick Mooney 4826dc98349SAndy Fiddaman offset -= table_offset; 4834c87aefeSPatrick Mooney index = offset / MSIX_TABLE_ENTRY_SIZE; 4846dc98349SAndy Fiddaman assert(index < table_count); 4854c87aefeSPatrick Mooney 4864c87aefeSPatrick Mooney entry = &pi->pi_msix.table[index]; 4874c87aefeSPatrick Mooney entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; 4884c87aefeSPatrick Mooney 4894c87aefeSPatrick Mooney /* Only 4 byte naturally-aligned writes are supported */ 4904c87aefeSPatrick Mooney assert(size == 4); 4914c87aefeSPatrick Mooney assert(entry_offset % 4 == 0); 4924c87aefeSPatrick Mooney 4934c87aefeSPatrick Mooney vector_control = entry->vector_control; 494*59d65d31SAndy Fiddaman dest32 = (uint32_t *)((uint8_t *)entry + entry_offset); 4954c87aefeSPatrick Mooney *dest32 = data; 4964c87aefeSPatrick Mooney /* If MSI-X hasn't been enabled, do nothing */ 4974c87aefeSPatrick Mooney if (pi->pi_msix.enabled) { 4984c87aefeSPatrick Mooney /* If the entry is masked, don't set it up */ 4994c87aefeSPatrick Mooney if ((entry->vector_control & PCIM_MSIX_VCTRL_MASK) == 0 || 5004c87aefeSPatrick Mooney (vector_control & PCIM_MSIX_VCTRL_MASK) == 0) { 501*59d65d31SAndy Fiddaman (void) vm_setup_pptdev_msix(ctx, 0, sc->pptfd, 502eb9a1df2SHans Rosenfeld index, entry->addr, entry->msg_data, 503eb9a1df2SHans Rosenfeld entry->vector_control); 5044c87aefeSPatrick Mooney } 5054c87aefeSPatrick Mooney } 5064c87aefeSPatrick Mooney } 5074c87aefeSPatrick Mooney 5084c87aefeSPatrick Mooney static int 509*59d65d31SAndy Fiddaman init_msix_table(struct vmctx *ctx __unused, struct passthru_softc *sc) 5104c87aefeSPatrick Mooney { 5114c87aefeSPatrick Mooney struct pci_devinst *pi = sc->psc_pi; 5126dc98349SAndy Fiddaman uint32_t table_size, table_offset; 5136dc98349SAndy Fiddaman int i; 5144c87aefeSPatrick Mooney 5156dc98349SAndy Fiddaman i = pci_msix_table_bar(pi); 5166dc98349SAndy Fiddaman assert(i >= 0); 5174c87aefeSPatrick Mooney 5184c87aefeSPatrick Mooney /* 5196dc98349SAndy Fiddaman * Map the region of the BAR containing the MSI-X table. This is 5206dc98349SAndy Fiddaman * necessary for two reasons: 5216dc98349SAndy Fiddaman * 1. The PBA may reside in the first or last page containing the MSI-X 5226dc98349SAndy Fiddaman * table. 5236dc98349SAndy Fiddaman * 2. While PCI devices are not supposed to use the page(s) containing 5246dc98349SAndy Fiddaman * the MSI-X table for other purposes, some do in practice. 5254c87aefeSPatrick Mooney */ 5266dc98349SAndy Fiddaman 5276dc98349SAndy Fiddaman /* 5286dc98349SAndy Fiddaman * Mapping pptfd provides access to the BAR containing the MSI-X 5297c8c0b82SPatrick Mooney * table. See ppt_devmap() in usr/src/uts/intel/io/vmm/io/ppt.c 5306dc98349SAndy Fiddaman * 5316dc98349SAndy Fiddaman * This maps the whole BAR and then mprotect(PROT_NONE) is used below 5326dc98349SAndy Fiddaman * to prevent access to pages that don't contain the MSI-X table. 5336dc98349SAndy Fiddaman * When porting this, it was tempting to just map the MSI-X table pages 5346dc98349SAndy Fiddaman * but that would mean updating everywhere that assumes that 5356dc98349SAndy Fiddaman * pi->pi_msix.mapped_addr points to the start of the BAR. For now, 5366dc98349SAndy Fiddaman * keep closer to upstream. 5376dc98349SAndy Fiddaman */ 5386dc98349SAndy Fiddaman pi->pi_msix.mapped_size = sc->psc_bar[i].size; 5396dc98349SAndy Fiddaman pi->pi_msix.mapped_addr = (uint8_t *)mmap(NULL, pi->pi_msix.mapped_size, 5406dc98349SAndy Fiddaman PROT_READ | PROT_WRITE, MAP_SHARED, sc->pptfd, 0); 5416dc98349SAndy Fiddaman if (pi->pi_msix.mapped_addr == MAP_FAILED) { 5426dc98349SAndy Fiddaman warn("Failed to map MSI-X table BAR on %d", sc->pptfd); 5436dc98349SAndy Fiddaman return (-1); 5446dc98349SAndy Fiddaman } 5456dc98349SAndy Fiddaman 5464c87aefeSPatrick Mooney table_offset = rounddown2(pi->pi_msix.table_offset, 4096); 5474c87aefeSPatrick Mooney 5484c87aefeSPatrick Mooney table_size = pi->pi_msix.table_offset - table_offset; 5494c87aefeSPatrick Mooney table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; 5504c87aefeSPatrick Mooney table_size = roundup2(table_size, 4096); 5514c87aefeSPatrick Mooney 5524c87aefeSPatrick Mooney /* 5536dc98349SAndy Fiddaman * Unmap any pages not containing the table, we do not need to emulate 5546dc98349SAndy Fiddaman * accesses to them. Avoid releasing address space to help ensure that 5556dc98349SAndy Fiddaman * a buggy out-of-bounds access causes a crash. 5564c87aefeSPatrick Mooney */ 5576dc98349SAndy Fiddaman if (table_offset != 0) 5586dc98349SAndy Fiddaman if (mprotect((caddr_t)pi->pi_msix.mapped_addr, table_offset, 5596dc98349SAndy Fiddaman PROT_NONE) != 0) 5606dc98349SAndy Fiddaman warn("Failed to unmap MSI-X table BAR region"); 5616dc98349SAndy Fiddaman if (table_offset + table_size != pi->pi_msix.mapped_size) 5626dc98349SAndy Fiddaman if (mprotect((caddr_t) 5636dc98349SAndy Fiddaman pi->pi_msix.mapped_addr + table_offset + table_size, 5646dc98349SAndy Fiddaman pi->pi_msix.mapped_size - (table_offset + table_size), 5656dc98349SAndy Fiddaman PROT_NONE) != 0) 5666dc98349SAndy Fiddaman warn("Failed to unmap MSI-X table BAR region"); 5674c87aefeSPatrick Mooney 5684c87aefeSPatrick Mooney return (0); 5694c87aefeSPatrick Mooney } 5704c87aefeSPatrick Mooney 5714c87aefeSPatrick Mooney static int 572*59d65d31SAndy Fiddaman cfginitbar(struct vmctx *ctx __unused, struct passthru_softc *sc) 5734c87aefeSPatrick Mooney { 574eb9a1df2SHans Rosenfeld struct pci_devinst *pi = sc->psc_pi; 575eb9a1df2SHans Rosenfeld uint_t i; 5764c87aefeSPatrick Mooney 5774c87aefeSPatrick Mooney /* 5784c87aefeSPatrick Mooney * Initialize BAR registers 5794c87aefeSPatrick Mooney */ 5804c87aefeSPatrick Mooney for (i = 0; i <= PCI_BARMAX; i++) { 581eb9a1df2SHans Rosenfeld enum pcibar_type bartype; 582eb9a1df2SHans Rosenfeld uint64_t base, size; 583eb9a1df2SHans Rosenfeld int error; 5844c87aefeSPatrick Mooney 585eb9a1df2SHans Rosenfeld if (passthru_get_bar(sc, i, &bartype, &base, &size) != 0) { 5864c87aefeSPatrick Mooney continue; 5874c87aefeSPatrick Mooney } 5884c87aefeSPatrick Mooney 5894c87aefeSPatrick Mooney if (bartype != PCIBAR_IO) { 5904c87aefeSPatrick Mooney if (((base | size) & PAGE_MASK) != 0) { 591eb9a1df2SHans Rosenfeld warnx("passthru device %d BAR %d: " 5924c87aefeSPatrick Mooney "base %#lx or size %#lx not page aligned\n", 593eb9a1df2SHans Rosenfeld sc->pptfd, i, base, size); 5944c87aefeSPatrick Mooney return (-1); 5954c87aefeSPatrick Mooney } 5964c87aefeSPatrick Mooney } 5974c87aefeSPatrick Mooney 5984c87aefeSPatrick Mooney /* Cache information about the "real" BAR */ 5994c87aefeSPatrick Mooney sc->psc_bar[i].type = bartype; 6004c87aefeSPatrick Mooney sc->psc_bar[i].size = size; 6014c87aefeSPatrick Mooney sc->psc_bar[i].addr = base; 6026dc98349SAndy Fiddaman sc->psc_bar[i].lobits = 0; 6034c87aefeSPatrick Mooney 6044c87aefeSPatrick Mooney /* Allocate the BAR in the guest I/O or MMIO space */ 6056960cd89SAndy Fiddaman error = pci_emul_alloc_bar(pi, i, bartype, size); 6064c87aefeSPatrick Mooney if (error) 6074c87aefeSPatrick Mooney return (-1); 6084c87aefeSPatrick Mooney 6096dc98349SAndy Fiddaman /* Use same lobits as physical bar */ 610d7b72f7bSAndy Fiddaman uint8_t lobits = passthru_read_config(sc, PCIR_BAR(i), 0x01); 6116dc98349SAndy Fiddaman if (bartype == PCIBAR_MEM32 || bartype == PCIBAR_MEM64) { 6126dc98349SAndy Fiddaman lobits &= ~PCIM_BAR_MEM_BASE; 6136dc98349SAndy Fiddaman } else { 6146dc98349SAndy Fiddaman lobits &= ~PCIM_BAR_IO_BASE; 6154c87aefeSPatrick Mooney } 6166dc98349SAndy Fiddaman sc->psc_bar[i].lobits = lobits; 6176dc98349SAndy Fiddaman pi->pi_bar[i].lobits = lobits; 6184c87aefeSPatrick Mooney 6194c87aefeSPatrick Mooney /* 6204c87aefeSPatrick Mooney * 64-bit BAR takes up two slots so skip the next one. 6214c87aefeSPatrick Mooney */ 6224c87aefeSPatrick Mooney if (bartype == PCIBAR_MEM64) { 6234c87aefeSPatrick Mooney i++; 6244c87aefeSPatrick Mooney assert(i <= PCI_BARMAX); 6254c87aefeSPatrick Mooney sc->psc_bar[i].type = PCIBAR_MEMHI64; 6264c87aefeSPatrick Mooney } 6274c87aefeSPatrick Mooney } 6284c87aefeSPatrick Mooney return (0); 6294c87aefeSPatrick Mooney } 6304c87aefeSPatrick Mooney 6314c87aefeSPatrick Mooney static int 632eb9a1df2SHans Rosenfeld cfginit(struct vmctx *ctx, struct passthru_softc *sc) 6334c87aefeSPatrick Mooney { 634e4321372SMichael Zeller struct pci_devinst *pi = sc->psc_pi; 6356dc98349SAndy Fiddaman int error; 636e4321372SMichael Zeller 6374c87aefeSPatrick Mooney if (cfginitmsi(sc) != 0) { 638eb9a1df2SHans Rosenfeld warnx("failed to initialize MSI for PCI %d", sc->pptfd); 639eb9a1df2SHans Rosenfeld return (-1); 6404c87aefeSPatrick Mooney } 6414c87aefeSPatrick Mooney 6424c87aefeSPatrick Mooney if (cfginitbar(ctx, sc) != 0) { 643eb9a1df2SHans Rosenfeld warnx("failed to initialize BARs for PCI %d", sc->pptfd); 644eb9a1df2SHans Rosenfeld return (-1); 6454c87aefeSPatrick Mooney } 6464c87aefeSPatrick Mooney 647d7b72f7bSAndy Fiddaman passthru_write_config(sc, PCIR_COMMAND, 2, 648d7b72f7bSAndy Fiddaman pci_get_cfgdata16(pi, PCIR_COMMAND)); 649e4321372SMichael Zeller 6506dc98349SAndy Fiddaman /* 6516dc98349SAndy Fiddaman * We need to do this after PCIR_COMMAND got possibly updated, e.g., 6526dc98349SAndy Fiddaman * a BAR was enabled. 6536dc98349SAndy Fiddaman */ 6546dc98349SAndy Fiddaman if (pci_msix_table_bar(pi) >= 0) { 6556dc98349SAndy Fiddaman error = init_msix_table(ctx, sc); 6566dc98349SAndy Fiddaman if (error != 0) { 6576dc98349SAndy Fiddaman warnx("failed to initialize MSI-X table for PCI %d", 6586dc98349SAndy Fiddaman sc->pptfd); 6596dc98349SAndy Fiddaman goto done; 6606dc98349SAndy Fiddaman } 6616dc98349SAndy Fiddaman } 6626dc98349SAndy Fiddaman 6636dc98349SAndy Fiddaman error = 0; /* success */ 6646dc98349SAndy Fiddaman done: 6656dc98349SAndy Fiddaman return (error); 6664c87aefeSPatrick Mooney } 6674c87aefeSPatrick Mooney 6684c87aefeSPatrick Mooney static int 669d7b72f7bSAndy Fiddaman passthru_legacy_config(nvlist_t *nvl, const char *opt) 6702b948146SAndy Fiddaman { 671d7b72f7bSAndy Fiddaman char *config, *name, *tofree, *value; 672d7b72f7bSAndy Fiddaman 673d7b72f7bSAndy Fiddaman if (opt == NULL) 6742b948146SAndy Fiddaman return (0); 6752b948146SAndy Fiddaman 676d7b72f7bSAndy Fiddaman config = tofree = strdup(opt); 677d7b72f7bSAndy Fiddaman while ((name = strsep(&config, ",")) != NULL) { 678d7b72f7bSAndy Fiddaman value = strchr(name, '='); 679d7b72f7bSAndy Fiddaman if (value != NULL) { 680d7b72f7bSAndy Fiddaman *value++ = '\0'; 681d7b72f7bSAndy Fiddaman set_config_value_node(nvl, name, value); 682d7b72f7bSAndy Fiddaman } else { 683d7b72f7bSAndy Fiddaman if (strncmp(name, "/dev/ppt", 8) != 0) { 684d7b72f7bSAndy Fiddaman EPRINTLN("passthru: invalid path \"%s\"", name); 685d7b72f7bSAndy Fiddaman free(tofree); 686d7b72f7bSAndy Fiddaman return (-1); 687d7b72f7bSAndy Fiddaman } 688d7b72f7bSAndy Fiddaman set_config_value_node(nvl, "path", name); 689d7b72f7bSAndy Fiddaman } 690d7b72f7bSAndy Fiddaman } 691d7b72f7bSAndy Fiddaman free(tofree); 692d7b72f7bSAndy Fiddaman return (0); 693d7b72f7bSAndy Fiddaman } 694d7b72f7bSAndy Fiddaman 695d7b72f7bSAndy Fiddaman static int 696*59d65d31SAndy Fiddaman passthru_init_rom(struct vmctx *const ctx __unused, 697*59d65d31SAndy Fiddaman struct passthru_softc *const sc, const char *const romfile) 698d7b72f7bSAndy Fiddaman { 699d7b72f7bSAndy Fiddaman if (romfile == NULL) { 700d7b72f7bSAndy Fiddaman return (0); 701d7b72f7bSAndy Fiddaman } 702d7b72f7bSAndy Fiddaman 703d7b72f7bSAndy Fiddaman const int fd = open(romfile, O_RDONLY); 704d7b72f7bSAndy Fiddaman if (fd < 0) { 705d7b72f7bSAndy Fiddaman warnx("%s: can't open romfile \"%s\"", __func__, romfile); 706d7b72f7bSAndy Fiddaman return (-1); 707d7b72f7bSAndy Fiddaman } 708d7b72f7bSAndy Fiddaman 709d7b72f7bSAndy Fiddaman struct stat sbuf; 710d7b72f7bSAndy Fiddaman if (fstat(fd, &sbuf) < 0) { 711d7b72f7bSAndy Fiddaman warnx("%s: can't fstat romfile \"%s\"", __func__, romfile); 712d7b72f7bSAndy Fiddaman close(fd); 713d7b72f7bSAndy Fiddaman return (-1); 714d7b72f7bSAndy Fiddaman } 715d7b72f7bSAndy Fiddaman const uint64_t rom_size = sbuf.st_size; 716d7b72f7bSAndy Fiddaman 717d7b72f7bSAndy Fiddaman void *const rom_data = mmap(NULL, rom_size, PROT_READ, MAP_SHARED, fd, 718d7b72f7bSAndy Fiddaman 0); 719d7b72f7bSAndy Fiddaman if (rom_data == MAP_FAILED) { 720d7b72f7bSAndy Fiddaman warnx("%s: unable to mmap romfile \"%s\" (%d)", __func__, 721d7b72f7bSAndy Fiddaman romfile, errno); 722d7b72f7bSAndy Fiddaman close(fd); 723d7b72f7bSAndy Fiddaman return (-1); 724d7b72f7bSAndy Fiddaman } 725d7b72f7bSAndy Fiddaman 726d7b72f7bSAndy Fiddaman void *rom_addr; 727d7b72f7bSAndy Fiddaman int error = pci_emul_alloc_rom(sc->psc_pi, rom_size, &rom_addr); 728d7b72f7bSAndy Fiddaman if (error) { 729d7b72f7bSAndy Fiddaman warnx("%s: failed to alloc rom segment", __func__); 730d7b72f7bSAndy Fiddaman munmap(rom_data, rom_size); 731d7b72f7bSAndy Fiddaman close(fd); 732d7b72f7bSAndy Fiddaman return (error); 733d7b72f7bSAndy Fiddaman } 734d7b72f7bSAndy Fiddaman memcpy(rom_addr, rom_data, rom_size); 735d7b72f7bSAndy Fiddaman 736d7b72f7bSAndy Fiddaman sc->psc_bar[PCI_ROM_IDX].type = PCIBAR_ROM; 737d7b72f7bSAndy Fiddaman sc->psc_bar[PCI_ROM_IDX].addr = (uint64_t)rom_addr; 738d7b72f7bSAndy Fiddaman sc->psc_bar[PCI_ROM_IDX].size = rom_size; 739d7b72f7bSAndy Fiddaman 740d7b72f7bSAndy Fiddaman munmap(rom_data, rom_size); 741d7b72f7bSAndy Fiddaman close(fd); 7422b948146SAndy Fiddaman 7432b948146SAndy Fiddaman return (0); 7442b948146SAndy Fiddaman } 7452b948146SAndy Fiddaman 7462b948146SAndy Fiddaman static int 7472b948146SAndy Fiddaman passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) 7484c87aefeSPatrick Mooney { 749eb9a1df2SHans Rosenfeld int error, memflags, pptfd; 7504c87aefeSPatrick Mooney struct passthru_softc *sc; 7512b948146SAndy Fiddaman const char *path; 7524c87aefeSPatrick Mooney 753a73f8412SToomas Soome pptfd = -1; 7544c87aefeSPatrick Mooney sc = NULL; 7554c87aefeSPatrick Mooney error = 1; 7564c87aefeSPatrick Mooney 7574c87aefeSPatrick Mooney memflags = vm_get_memflags(ctx); 7584c87aefeSPatrick Mooney if (!(memflags & VM_MEM_F_WIRED)) { 7594c87aefeSPatrick Mooney warnx("passthru requires guest memory to be wired"); 7604c87aefeSPatrick Mooney goto done; 7614c87aefeSPatrick Mooney } 7624c87aefeSPatrick Mooney 7632b948146SAndy Fiddaman path = get_config_value_node(nvl, "path"); 7642b948146SAndy Fiddaman if (path == NULL || passthru_dev_open(path, &pptfd) != 0) { 7654c87aefeSPatrick Mooney warnx("invalid passthru options"); 7664c87aefeSPatrick Mooney goto done; 7674c87aefeSPatrick Mooney } 7684c87aefeSPatrick Mooney 769eb9a1df2SHans Rosenfeld if (vm_assign_pptdev(ctx, pptfd) != 0) { 770eb9a1df2SHans Rosenfeld warnx("PCI device at %d is not using the ppt driver", pptfd); 7714c87aefeSPatrick Mooney goto done; 7724c87aefeSPatrick Mooney } 7734c87aefeSPatrick Mooney 7744c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct passthru_softc)); 7754c87aefeSPatrick Mooney 7764c87aefeSPatrick Mooney pi->pi_arg = sc; 7774c87aefeSPatrick Mooney sc->psc_pi = pi; 778eb9a1df2SHans Rosenfeld sc->pptfd = pptfd; 779eb9a1df2SHans Rosenfeld 780eb9a1df2SHans Rosenfeld if ((error = vm_get_pptdev_limits(ctx, pptfd, &sc->msi_limit, 781eb9a1df2SHans Rosenfeld &sc->msix_limit)) != 0) 782eb9a1df2SHans Rosenfeld goto done; 7834c87aefeSPatrick Mooney 7844c87aefeSPatrick Mooney /* initialize config space */ 785d7b72f7bSAndy Fiddaman if ((error = cfginit(ctx, sc)) != 0) 786d7b72f7bSAndy Fiddaman goto done; 787d7b72f7bSAndy Fiddaman 788d7b72f7bSAndy Fiddaman /* initialize ROM */ 789d7b72f7bSAndy Fiddaman if ((error = passthru_init_rom(ctx, sc, 790d7b72f7bSAndy Fiddaman get_config_value_node(nvl, "rom"))) != 0) { 791d7b72f7bSAndy Fiddaman goto done; 792d7b72f7bSAndy Fiddaman } 793d7b72f7bSAndy Fiddaman 7944c87aefeSPatrick Mooney done: 7954c87aefeSPatrick Mooney if (error) { 7964c87aefeSPatrick Mooney free(sc); 797a73f8412SToomas Soome if (pptfd != -1) 798eb9a1df2SHans Rosenfeld vm_unassign_pptdev(ctx, pptfd); 7994c87aefeSPatrick Mooney } 8004c87aefeSPatrick Mooney return (error); 8014c87aefeSPatrick Mooney } 8024c87aefeSPatrick Mooney 8034c87aefeSPatrick Mooney static int 8044c87aefeSPatrick Mooney bar_access(int coff) 8054c87aefeSPatrick Mooney { 806d7b72f7bSAndy Fiddaman if ((coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) || 807d7b72f7bSAndy Fiddaman coff == PCIR_BIOS) 8084c87aefeSPatrick Mooney return (1); 8094c87aefeSPatrick Mooney else 8104c87aefeSPatrick Mooney return (0); 8114c87aefeSPatrick Mooney } 8124c87aefeSPatrick Mooney 8134c87aefeSPatrick Mooney static int 8144c87aefeSPatrick Mooney msicap_access(struct passthru_softc *sc, int coff) 8154c87aefeSPatrick Mooney { 8164c87aefeSPatrick Mooney int caplen; 8174c87aefeSPatrick Mooney 8184c87aefeSPatrick Mooney if (sc->psc_msi.capoff == 0) 8194c87aefeSPatrick Mooney return (0); 8204c87aefeSPatrick Mooney 8214c87aefeSPatrick Mooney caplen = msi_caplen(sc->psc_msi.msgctrl); 8224c87aefeSPatrick Mooney 8234c87aefeSPatrick Mooney if (coff >= sc->psc_msi.capoff && coff < sc->psc_msi.capoff + caplen) 8244c87aefeSPatrick Mooney return (1); 8254c87aefeSPatrick Mooney else 8264c87aefeSPatrick Mooney return (0); 8274c87aefeSPatrick Mooney } 8284c87aefeSPatrick Mooney 8294c87aefeSPatrick Mooney static int 8304c87aefeSPatrick Mooney msixcap_access(struct passthru_softc *sc, int coff) 8314c87aefeSPatrick Mooney { 8324c87aefeSPatrick Mooney if (sc->psc_msix.capoff == 0) 8334c87aefeSPatrick Mooney return (0); 8344c87aefeSPatrick Mooney 8354c87aefeSPatrick Mooney return (coff >= sc->psc_msix.capoff && 8364c87aefeSPatrick Mooney coff < sc->psc_msix.capoff + MSIX_CAPLEN); 8374c87aefeSPatrick Mooney } 8384c87aefeSPatrick Mooney 8394c87aefeSPatrick Mooney static int 840*59d65d31SAndy Fiddaman passthru_cfgread(struct vmctx *ctx __unused, struct pci_devinst *pi, int coff, 841*59d65d31SAndy Fiddaman int bytes, uint32_t *rv) 8424c87aefeSPatrick Mooney { 8434c87aefeSPatrick Mooney struct passthru_softc *sc; 8444c87aefeSPatrick Mooney 8454c87aefeSPatrick Mooney sc = pi->pi_arg; 8464c87aefeSPatrick Mooney 8474c87aefeSPatrick Mooney /* 8484c87aefeSPatrick Mooney * PCI BARs and MSI capability is emulated. 8494c87aefeSPatrick Mooney */ 8506dc98349SAndy Fiddaman if (bar_access(coff) || msicap_access(sc, coff) || 8516dc98349SAndy Fiddaman msixcap_access(sc, coff)) 8524c87aefeSPatrick Mooney return (-1); 8534c87aefeSPatrick Mooney 854eb9a1df2SHans Rosenfeld /* 855eb9a1df2SHans Rosenfeld * MSI-X is also emulated since a limit on interrupts may be imposed by 856eb9a1df2SHans Rosenfeld * the OS, altering the perceived register state. 857eb9a1df2SHans Rosenfeld */ 858eb9a1df2SHans Rosenfeld if (msixcap_access(sc, coff)) 859eb9a1df2SHans Rosenfeld return (-1); 860eb9a1df2SHans Rosenfeld 8614c87aefeSPatrick Mooney #ifdef LEGACY_SUPPORT 8624c87aefeSPatrick Mooney /* 8634c87aefeSPatrick Mooney * Emulate PCIR_CAP_PTR if this device does not support MSI capability 8644c87aefeSPatrick Mooney * natively. 8654c87aefeSPatrick Mooney */ 8664c87aefeSPatrick Mooney if (sc->psc_msi.emulated) { 8674c87aefeSPatrick Mooney if (coff >= PCIR_CAP_PTR && coff < PCIR_CAP_PTR + 4) 8684c87aefeSPatrick Mooney return (-1); 8694c87aefeSPatrick Mooney } 8704c87aefeSPatrick Mooney #endif 8714c87aefeSPatrick Mooney 872e4321372SMichael Zeller /* 873e4321372SMichael Zeller * Emulate the command register. If a single read reads both the 874e4321372SMichael Zeller * command and status registers, read the status register from the 875e4321372SMichael Zeller * device's config space. 876e4321372SMichael Zeller */ 877e4321372SMichael Zeller if (coff == PCIR_COMMAND) { 878e4321372SMichael Zeller if (bytes <= 2) 879e4321372SMichael Zeller return (-1); 880b518543bSAndy Fiddaman *rv = passthru_read_config(sc, PCIR_STATUS, 2) << 16 | 881b518543bSAndy Fiddaman pci_get_cfgdata16(pi, PCIR_COMMAND); 882e4321372SMichael Zeller return (0); 883e4321372SMichael Zeller } 884e4321372SMichael Zeller 8854c87aefeSPatrick Mooney /* Everything else just read from the device's config space */ 886d7b72f7bSAndy Fiddaman *rv = passthru_read_config(sc, coff, bytes); 8874c87aefeSPatrick Mooney 8884c87aefeSPatrick Mooney return (0); 8894c87aefeSPatrick Mooney } 8904c87aefeSPatrick Mooney 8914c87aefeSPatrick Mooney static int 892*59d65d31SAndy Fiddaman passthru_cfgwrite(struct vmctx *ctx, struct pci_devinst *pi, int coff, 893*59d65d31SAndy Fiddaman int bytes, uint32_t val) 8944c87aefeSPatrick Mooney { 8954c87aefeSPatrick Mooney int error, msix_table_entries, i; 8964c87aefeSPatrick Mooney struct passthru_softc *sc; 897e4321372SMichael Zeller uint16_t cmd_old; 8984c87aefeSPatrick Mooney 8994c87aefeSPatrick Mooney sc = pi->pi_arg; 9004c87aefeSPatrick Mooney 9014c87aefeSPatrick Mooney /* 9024c87aefeSPatrick Mooney * PCI BARs are emulated 9034c87aefeSPatrick Mooney */ 9044c87aefeSPatrick Mooney if (bar_access(coff)) 9054c87aefeSPatrick Mooney return (-1); 9064c87aefeSPatrick Mooney 9074c87aefeSPatrick Mooney /* 9084c87aefeSPatrick Mooney * MSI capability is emulated 9094c87aefeSPatrick Mooney */ 9104c87aefeSPatrick Mooney if (msicap_access(sc, coff)) { 911154972afSPatrick Mooney pci_emul_capwrite(pi, coff, bytes, val, sc->psc_msi.capoff, 912154972afSPatrick Mooney PCIY_MSI); 913*59d65d31SAndy Fiddaman error = vm_setup_pptdev_msi(ctx, 0, sc->pptfd, 914eb9a1df2SHans Rosenfeld pi->pi_msi.addr, pi->pi_msi.msg_data, pi->pi_msi.maxmsgnum); 9154c87aefeSPatrick Mooney if (error != 0) 9164c87aefeSPatrick Mooney err(1, "vm_setup_pptdev_msi"); 9174c87aefeSPatrick Mooney return (0); 9184c87aefeSPatrick Mooney } 9194c87aefeSPatrick Mooney 9204c87aefeSPatrick Mooney if (msixcap_access(sc, coff)) { 921154972afSPatrick Mooney pci_emul_capwrite(pi, coff, bytes, val, sc->psc_msix.capoff, 922154972afSPatrick Mooney PCIY_MSIX); 9234c87aefeSPatrick Mooney if (pi->pi_msix.enabled) { 9244c87aefeSPatrick Mooney msix_table_entries = pi->pi_msix.table_count; 9254c87aefeSPatrick Mooney for (i = 0; i < msix_table_entries; i++) { 926*59d65d31SAndy Fiddaman error = vm_setup_pptdev_msix(ctx, 0, 927eb9a1df2SHans Rosenfeld sc->pptfd, i, 9284c87aefeSPatrick Mooney pi->pi_msix.table[i].addr, 9294c87aefeSPatrick Mooney pi->pi_msix.table[i].msg_data, 9304c87aefeSPatrick Mooney pi->pi_msix.table[i].vector_control); 9314c87aefeSPatrick Mooney 9324c87aefeSPatrick Mooney if (error) 9334c87aefeSPatrick Mooney err(1, "vm_setup_pptdev_msix"); 9344c87aefeSPatrick Mooney } 9356960cd89SAndy Fiddaman } else { 9366960cd89SAndy Fiddaman error = vm_disable_pptdev_msix(ctx, sc->pptfd); 9376960cd89SAndy Fiddaman if (error) 9386960cd89SAndy Fiddaman err(1, "vm_disable_pptdev_msix"); 9394c87aefeSPatrick Mooney } 9404c87aefeSPatrick Mooney return (0); 9414c87aefeSPatrick Mooney } 9424c87aefeSPatrick Mooney 9434c87aefeSPatrick Mooney #ifdef LEGACY_SUPPORT 9444c87aefeSPatrick Mooney /* 9454c87aefeSPatrick Mooney * If this device does not support MSI natively then we cannot let 9464c87aefeSPatrick Mooney * the guest disable legacy interrupts from the device. It is the 9474c87aefeSPatrick Mooney * legacy interrupt that is triggering the virtual MSI to the guest. 9484c87aefeSPatrick Mooney */ 9494c87aefeSPatrick Mooney if (sc->psc_msi.emulated && pci_msi_enabled(pi)) { 9504c87aefeSPatrick Mooney if (coff == PCIR_COMMAND && bytes == 2) 9514c87aefeSPatrick Mooney val &= ~PCIM_CMD_INTxDIS; 9524c87aefeSPatrick Mooney } 9534c87aefeSPatrick Mooney #endif 9544c87aefeSPatrick Mooney 955d7b72f7bSAndy Fiddaman passthru_write_config(sc, coff, bytes, val); 956e4321372SMichael Zeller if (coff == PCIR_COMMAND) { 957e4321372SMichael Zeller cmd_old = pci_get_cfgdata16(pi, PCIR_COMMAND); 958e4321372SMichael Zeller if (bytes == 1) 959e4321372SMichael Zeller pci_set_cfgdata8(pi, PCIR_COMMAND, val); 960e4321372SMichael Zeller else if (bytes == 2) 961e4321372SMichael Zeller pci_set_cfgdata16(pi, PCIR_COMMAND, val); 962e4321372SMichael Zeller pci_emul_cmd_changed(pi, cmd_old); 963e4321372SMichael Zeller } 9644c87aefeSPatrick Mooney 9654c87aefeSPatrick Mooney return (0); 9664c87aefeSPatrick Mooney } 9674c87aefeSPatrick Mooney 9684c87aefeSPatrick Mooney static void 969*59d65d31SAndy Fiddaman passthru_write(struct vmctx *ctx, struct pci_devinst *pi, int baridx, 9704c87aefeSPatrick Mooney uint64_t offset, int size, uint64_t value) 9714c87aefeSPatrick Mooney { 972eb9a1df2SHans Rosenfeld struct passthru_softc *sc = pi->pi_arg; 9734c87aefeSPatrick Mooney 9744c87aefeSPatrick Mooney if (baridx == pci_msix_table_bar(pi)) { 975*59d65d31SAndy Fiddaman msix_table_write(ctx, sc, offset, size, value); 9764c87aefeSPatrick Mooney } else { 977eb9a1df2SHans Rosenfeld struct ppt_bar_io pbi; 9784c87aefeSPatrick Mooney 979eb9a1df2SHans Rosenfeld assert(pi->pi_bar[baridx].type == PCIBAR_IO); 980eb9a1df2SHans Rosenfeld 981eb9a1df2SHans Rosenfeld pbi.pbi_bar = baridx; 982eb9a1df2SHans Rosenfeld pbi.pbi_width = size; 983eb9a1df2SHans Rosenfeld pbi.pbi_off = offset; 984eb9a1df2SHans Rosenfeld pbi.pbi_data = value; 985eb9a1df2SHans Rosenfeld (void) ioctl(sc->pptfd, PPT_BAR_WRITE, &pbi); 9864c87aefeSPatrick Mooney } 9874c87aefeSPatrick Mooney } 9884c87aefeSPatrick Mooney 9894c87aefeSPatrick Mooney static uint64_t 990*59d65d31SAndy Fiddaman passthru_read(struct vmctx *ctx __unused, struct pci_devinst *pi, int baridx, 9914c87aefeSPatrick Mooney uint64_t offset, int size) 9924c87aefeSPatrick Mooney { 993eb9a1df2SHans Rosenfeld struct passthru_softc *sc = pi->pi_arg; 9944c87aefeSPatrick Mooney uint64_t val; 9954c87aefeSPatrick Mooney 9964c87aefeSPatrick Mooney if (baridx == pci_msix_table_bar(pi)) { 9976dc98349SAndy Fiddaman val = msix_table_read(sc, offset, size); 9984c87aefeSPatrick Mooney } else { 999eb9a1df2SHans Rosenfeld struct ppt_bar_io pbi; 1000eb9a1df2SHans Rosenfeld 10014c87aefeSPatrick Mooney assert(pi->pi_bar[baridx].type == PCIBAR_IO); 10024c87aefeSPatrick Mooney 1003eb9a1df2SHans Rosenfeld pbi.pbi_bar = baridx; 1004eb9a1df2SHans Rosenfeld pbi.pbi_width = size; 1005eb9a1df2SHans Rosenfeld pbi.pbi_off = offset; 1006eb9a1df2SHans Rosenfeld if (ioctl(sc->pptfd, PPT_BAR_READ, &pbi) == 0) { 1007eb9a1df2SHans Rosenfeld val = pbi.pbi_data; 1008eb9a1df2SHans Rosenfeld } else { 1009eb9a1df2SHans Rosenfeld val = 0; 1010eb9a1df2SHans Rosenfeld } 10114c87aefeSPatrick Mooney } 10124c87aefeSPatrick Mooney 10134c87aefeSPatrick Mooney return (val); 10144c87aefeSPatrick Mooney } 10154c87aefeSPatrick Mooney 10162b948146SAndy Fiddaman static void 10172b948146SAndy Fiddaman passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, 10182b948146SAndy Fiddaman int enabled, uint64_t address) 10192b948146SAndy Fiddaman { 10202b948146SAndy Fiddaman struct passthru_softc *sc; 10212b948146SAndy Fiddaman size_t remaining; 10222b948146SAndy Fiddaman uint32_t table_size, table_offset; 10232b948146SAndy Fiddaman 10242b948146SAndy Fiddaman sc = pi->pi_arg; 10252b948146SAndy Fiddaman table_offset = rounddown2(pi->pi_msix.table_offset, 4096); 10262b948146SAndy Fiddaman if (table_offset > 0) { 10272b948146SAndy Fiddaman if (!enabled) { 10282b948146SAndy Fiddaman if (vm_unmap_pptdev_mmio(ctx, sc->pptfd, address, 10292b948146SAndy Fiddaman table_offset) != 0) 10302b948146SAndy Fiddaman warnx("pci_passthru: unmap_pptdev_mmio failed"); 10312b948146SAndy Fiddaman } else { 10322b948146SAndy Fiddaman if (vm_map_pptdev_mmio(ctx, sc->pptfd, address, 10332b948146SAndy Fiddaman table_offset, sc->psc_bar[baridx].addr) != 0) 10342b948146SAndy Fiddaman warnx("pci_passthru: map_pptdev_mmio failed"); 10352b948146SAndy Fiddaman } 10362b948146SAndy Fiddaman } 10372b948146SAndy Fiddaman table_size = pi->pi_msix.table_offset - table_offset; 10382b948146SAndy Fiddaman table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; 10392b948146SAndy Fiddaman table_size = roundup2(table_size, 4096); 10402b948146SAndy Fiddaman remaining = pi->pi_bar[baridx].size - table_offset - table_size; 10412b948146SAndy Fiddaman if (remaining > 0) { 10422b948146SAndy Fiddaman address += table_offset + table_size; 10432b948146SAndy Fiddaman if (!enabled) { 10442b948146SAndy Fiddaman if (vm_unmap_pptdev_mmio(ctx, sc->pptfd, address, 10452b948146SAndy Fiddaman remaining) != 0) 10462b948146SAndy Fiddaman warnx("pci_passthru: unmap_pptdev_mmio failed"); 10472b948146SAndy Fiddaman } else { 10482b948146SAndy Fiddaman if (vm_map_pptdev_mmio(ctx, sc->pptfd, address, 10492b948146SAndy Fiddaman remaining, sc->psc_bar[baridx].addr + 10502b948146SAndy Fiddaman table_offset + table_size) != 0) 10512b948146SAndy Fiddaman warnx("pci_passthru: map_pptdev_mmio failed"); 10522b948146SAndy Fiddaman } 10532b948146SAndy Fiddaman } 10542b948146SAndy Fiddaman } 10552b948146SAndy Fiddaman 10562b948146SAndy Fiddaman static void 10572b948146SAndy Fiddaman passthru_mmio_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, 10582b948146SAndy Fiddaman int enabled, uint64_t address) 10592b948146SAndy Fiddaman { 10602b948146SAndy Fiddaman struct passthru_softc *sc; 10612b948146SAndy Fiddaman 10622b948146SAndy Fiddaman sc = pi->pi_arg; 10632b948146SAndy Fiddaman if (!enabled) { 10642b948146SAndy Fiddaman if (vm_unmap_pptdev_mmio(ctx, sc->pptfd, address, 10652b948146SAndy Fiddaman sc->psc_bar[baridx].size) != 0) 10662b948146SAndy Fiddaman warnx("pci_passthru: unmap_pptdev_mmio failed"); 10672b948146SAndy Fiddaman } else { 10682b948146SAndy Fiddaman if (vm_map_pptdev_mmio(ctx, sc->pptfd, address, 10692b948146SAndy Fiddaman sc->psc_bar[baridx].size, sc->psc_bar[baridx].addr) != 0) 10702b948146SAndy Fiddaman warnx("pci_passthru: map_pptdev_mmio failed"); 10712b948146SAndy Fiddaman } 10722b948146SAndy Fiddaman } 10732b948146SAndy Fiddaman 10742b948146SAndy Fiddaman static void 1075d7b72f7bSAndy Fiddaman passthru_addr_rom(struct pci_devinst *const pi, const int idx, 1076d7b72f7bSAndy Fiddaman const int enabled) 1077d7b72f7bSAndy Fiddaman { 1078d7b72f7bSAndy Fiddaman const uint64_t addr = pi->pi_bar[idx].addr; 1079d7b72f7bSAndy Fiddaman const uint64_t size = pi->pi_bar[idx].size; 1080d7b72f7bSAndy Fiddaman 1081d7b72f7bSAndy Fiddaman if (!enabled) { 1082d7b72f7bSAndy Fiddaman if (vm_munmap_memseg(pi->pi_vmctx, addr, size) != 0) { 1083d7b72f7bSAndy Fiddaman errx(4, "%s: munmap_memseg @ [%016lx - %016lx] failed", 1084d7b72f7bSAndy Fiddaman __func__, addr, addr + size); 1085d7b72f7bSAndy Fiddaman } 1086d7b72f7bSAndy Fiddaman 1087d7b72f7bSAndy Fiddaman } else { 1088d7b72f7bSAndy Fiddaman if (vm_mmap_memseg(pi->pi_vmctx, addr, VM_PCIROM, 1089d7b72f7bSAndy Fiddaman pi->pi_romoffset, size, PROT_READ | PROT_EXEC) != 0) { 10904f3f3e9aSAndy Fiddaman errx(4, "%s: mmap_memseg @ [%016lx - %016lx] failed", 1091d7b72f7bSAndy Fiddaman __func__, addr, addr + size); 1092d7b72f7bSAndy Fiddaman } 1093d7b72f7bSAndy Fiddaman } 1094d7b72f7bSAndy Fiddaman } 1095d7b72f7bSAndy Fiddaman 1096d7b72f7bSAndy Fiddaman static void 10972b948146SAndy Fiddaman passthru_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, 10982b948146SAndy Fiddaman int enabled, uint64_t address) 10992b948146SAndy Fiddaman { 1100d7b72f7bSAndy Fiddaman switch (pi->pi_bar[baridx].type) { 1101d7b72f7bSAndy Fiddaman case PCIBAR_IO: 1102d7b72f7bSAndy Fiddaman /* IO BARs are emulated */ 1103d7b72f7bSAndy Fiddaman break; 1104d7b72f7bSAndy Fiddaman case PCIBAR_ROM: 1105d7b72f7bSAndy Fiddaman passthru_addr_rom(pi, baridx, enabled); 1106d7b72f7bSAndy Fiddaman break; 1107d7b72f7bSAndy Fiddaman case PCIBAR_MEM32: 1108d7b72f7bSAndy Fiddaman case PCIBAR_MEM64: 11092b948146SAndy Fiddaman if (baridx == pci_msix_table_bar(pi)) 11102b948146SAndy Fiddaman passthru_msix_addr(ctx, pi, baridx, enabled, address); 11112b948146SAndy Fiddaman else 11122b948146SAndy Fiddaman passthru_mmio_addr(ctx, pi, baridx, enabled, address); 1113d7b72f7bSAndy Fiddaman break; 1114d7b72f7bSAndy Fiddaman default: 1115d7b72f7bSAndy Fiddaman errx(4, "%s: invalid BAR type %d", __func__, 1116d7b72f7bSAndy Fiddaman pi->pi_bar[baridx].type); 1117d7b72f7bSAndy Fiddaman } 11182b948146SAndy Fiddaman } 11192b948146SAndy Fiddaman 11204f3f3e9aSAndy Fiddaman static const struct pci_devemu passthru = { 11214c87aefeSPatrick Mooney .pe_emu = "passthru", 11224c87aefeSPatrick Mooney .pe_init = passthru_init, 11232b948146SAndy Fiddaman .pe_legacy_config = passthru_legacy_config, 11244c87aefeSPatrick Mooney .pe_cfgwrite = passthru_cfgwrite, 11254c87aefeSPatrick Mooney .pe_cfgread = passthru_cfgread, 11264c87aefeSPatrick Mooney .pe_barwrite = passthru_write, 11274c87aefeSPatrick Mooney .pe_barread = passthru_read, 11282b948146SAndy Fiddaman .pe_baraddr = passthru_addr, 11294c87aefeSPatrick Mooney }; 11304c87aefeSPatrick Mooney PCI_EMUL_SET(passthru); 1131