summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@joyent.com>2017-11-27 15:11:47 +0100
committerHans Rosenfeld <hans.rosenfeld@joyent.com>2017-12-22 19:47:36 +0100
commit234ea8a869bd1c0f2ae866f69a6fe06349479115 (patch)
tree1970a5c9410469c6d86cfa0eed5936c2ad555c90
parentb1dbb425b7a90c29a8d4e861b928fb7ff9aa34bb (diff)
downloadillumos-joyent-dev-bhyve-ppt.tar.gz
make iommu and ppt workdev-bhyve-ppt
-rw-r--r--manifest1
-rw-r--r--usr/src/cmd/bhyve/Makefile.com2
-rw-r--r--usr/src/cmd/bhyve/pci_passthru.c219
-rw-r--r--usr/src/uts/i86pc/Makefile.files6
-rw-r--r--usr/src/uts/i86pc/Makefile.i86pc1
-rw-r--r--usr/src/uts/i86pc/io/vmm/intel/vtd.c90
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/iommu.c26
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/ppt.c311
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/ppt.conf14
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/ppt_sol_glue.c177
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/sol_iommu.c86
-rw-r--r--usr/src/uts/i86pc/io/vmm/io/sol_ppt.c92
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c37
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c15
-rw-r--r--usr/src/uts/i86pc/ppt/Makefile75
-rw-r--r--usr/src/uts/i86pc/vmm/Makefile4
-rw-r--r--usr/src/uts/intel/ia32/ml/modstubs.s17
17 files changed, 959 insertions, 214 deletions
diff --git a/manifest b/manifest
index a46536c94e..4a8da9a468 100644
--- a/manifest
+++ b/manifest
@@ -4574,6 +4574,7 @@ f usr/kernel/drv/amd64/lxautofs 0755 root sys
f usr/kernel/drv/amd64/nsmb 0755 root sys
f usr/kernel/drv/amd64/pm 0755 root sys
f usr/kernel/drv/amd64/pool 0755 root sys
+f usr/kernel/drv/amd64/ppt 0755 root sys
f usr/kernel/drv/amd64/ptm 0755 root sys
f usr/kernel/drv/amd64/pts 0755 root sys
f usr/kernel/drv/amd64/signalfd 0755 root sys
diff --git a/usr/src/cmd/bhyve/Makefile.com b/usr/src/cmd/bhyve/Makefile.com
index aacf8421a1..c1c4113a95 100644
--- a/usr/src/cmd/bhyve/Makefile.com
+++ b/usr/src/cmd/bhyve/Makefile.com
@@ -81,7 +81,7 @@ CPPFLAGS = -I$(COMPAT)/freebsd -I$(CONTRIB)/freebsd \
-I$(SRC)/uts/i86pc \
-I$(SRC)/lib/libdladm/common \
-DWITHOUT_CAPSICUM
-LDLIBS += -lsocket -lnsl -ldlpi -ldladm -lkstat -lmd -luuid -lvmmapi -lz
+LDLIBS += -lsocket -lnsl -ldlpi -ldladm -lkstat -lmd -luuid -lvmmapi -lz -ldevinfo
POST_PROCESS += ; $(GENSETDEFS) $@
diff --git a/usr/src/cmd/bhyve/pci_passthru.c b/usr/src/cmd/bhyve/pci_passthru.c
index f314679d91..fd07e0f99b 100644
--- a/usr/src/cmd/bhyve/pci_passthru.c
+++ b/usr/src/cmd/bhyve/pci_passthru.c
@@ -38,6 +38,10 @@ __FBSDID("$FreeBSD$");
#include <sys/pciio.h>
#include <sys/ioctl.h>
+#include <sys/pci.h>
+#include <sys/pci_tools.h>
+#include <libdevinfo.h>
+
#include <dev/io/iodev.h>
#include <dev/pci/pcireg.h>
@@ -57,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include "pci_emul.h"
#include "mem.h"
+#ifdef __FreeBSD__
#ifndef _PATH_DEVPCI
#define _PATH_DEVPCI "/dev/pci"
#endif
@@ -64,6 +69,7 @@ __FBSDID("$FreeBSD$");
#ifndef _PATH_DEVIO
#define _PATH_DEVIO "/dev/io"
#endif
+#endif
#ifndef _PATH_MEM
#define _PATH_MEM "/dev/mem"
@@ -74,8 +80,10 @@ __FBSDID("$FreeBSD$");
#define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
#define MSIX_CAPLEN 12
+#ifdef __FreeBSD__
static int pcifd = -1;
static int iofd = -1;
+#endif
static int memfd = -1;
struct passthru_softc {
@@ -90,6 +98,8 @@ struct passthru_softc {
int capoff;
} psc_msix;
struct pcisel psc_sel;
+ di_node_t devnode;
+ int nexfd;
};
static int
@@ -115,12 +125,51 @@ msi_caplen(int msgctrl)
}
static uint32_t
-read_config(const struct pcisel *sel, long reg, int width)
+pcitool_reg_rw(const struct passthru_softc *sc, int bar, uint64_t reg, int width,
+ uint64_t data, int req)
+{
+ struct pcitool_reg pr = { 0 };
+
+ pr.user_version = PCITOOL_VERSION;
+ pr.acc_attr = PCITOOL_ACC_ATTR_ENDN_LTL;
+ pr.barnum = bar;
+ pr.bus_no = sc->psc_sel.pc_bus;
+ pr.dev_no = sc->psc_sel.pc_dev;
+ pr.func_no = sc->psc_sel.pc_func;
+ pr.offset = reg;
+ pr.data = data;
+
+ switch (width) {
+ case 1:
+ pr.acc_attr += PCITOOL_ACC_ATTR_SIZE_1;
+ break;
+ case 2:
+ pr.acc_attr += PCITOOL_ACC_ATTR_SIZE_2;
+ break;
+ case 4:
+ pr.acc_attr += PCITOOL_ACC_ATTR_SIZE_4;
+ break;
+ case 8:
+ pr.acc_attr += PCITOOL_ACC_ATTR_SIZE_8;
+ break;
+ default:
+ return (0);
+ }
+
+ if (ioctl(sc->nexfd, req, &pr) != 0)
+ return (0);
+ else
+ return (pr.data);
+}
+
+static uint32_t
+read_config(const struct passthru_softc *sc, long reg, int width)
{
+#ifdef __FreeBSD__
struct pci_io pi;
bzero(&pi, sizeof(pi));
- pi.pi_sel = *sel;
+ pi.pi_sel = sc->sel;
pi.pi_reg = reg;
pi.pi_width = width;
@@ -128,20 +177,29 @@ read_config(const struct pcisel *sel, long reg, int width)
return (0); /* XXX */
else
return (pi.pi_data);
+#else
+ return (pcitool_reg_rw(sc, PCITOOL_CONFIG, reg, width, 0,
+ PCITOOL_DEVICE_GET_REG));
+#endif
}
static void
-write_config(const struct pcisel *sel, long reg, int width, uint32_t data)
+write_config(const struct passthru_softc *sc, long reg, int width, uint32_t data)
{
+#ifdef __FreeBSD__
struct pci_io pi;
bzero(&pi, sizeof(pi));
- pi.pi_sel = *sel;
+ pi.pi_sel = sc->sel;
pi.pi_reg = reg;
pi.pi_width = width;
pi.pi_data = data;
(void)ioctl(pcifd, PCIOCWRITE, &pi); /* XXX */
+#else
+ (void) pcitool_reg_rw(sc, PCITOOL_CONFIG, reg, width, data,
+ PCITOOL_DEVICE_SET_REG);
+#endif
}
#ifdef LEGACY_SUPPORT
@@ -186,24 +244,24 @@ cfginitmsi(struct passthru_softc *sc)
* Parse the capabilities and cache the location of the MSI
* and MSI-X capabilities.
*/
- sts = read_config(&sel, PCIR_STATUS, 2);
+ sts = read_config(sc, PCIR_STATUS, 2);
if (sts & PCIM_STATUS_CAPPRESENT) {
- ptr = read_config(&sel, PCIR_CAP_PTR, 1);
+ ptr = read_config(sc, PCIR_CAP_PTR, 1);
while (ptr != 0 && ptr != 0xff) {
- cap = read_config(&sel, ptr + PCICAP_ID, 1);
+ cap = read_config(sc, ptr + PCICAP_ID, 1);
if (cap == PCIY_MSI) {
/*
* Copy the MSI capability into the config
* space of the emulated pci device
*/
sc->psc_msi.capoff = ptr;
- sc->psc_msi.msgctrl = read_config(&sel,
+ sc->psc_msi.msgctrl = read_config(sc,
ptr + 2, 2);
sc->psc_msi.emulated = 0;
caplen = msi_caplen(sc->psc_msi.msgctrl);
capptr = ptr;
while (caplen > 0) {
- u32 = read_config(&sel, capptr, 4);
+ u32 = read_config(sc, capptr, 4);
pci_set_cfgdata32(pi, capptr, u32);
caplen -= 4;
capptr += 4;
@@ -217,7 +275,7 @@ cfginitmsi(struct passthru_softc *sc)
msixcap_ptr = (uint32_t*) &msixcap;
capptr = ptr;
while (caplen > 0) {
- u32 = read_config(&sel, capptr, 4);
+ u32 = read_config(sc, capptr, 4);
*msixcap_ptr = u32;
pci_set_cfgdata32(pi, capptr, u32);
caplen -= 4;
@@ -225,7 +283,7 @@ cfginitmsi(struct passthru_softc *sc)
msixcap_ptr++;
}
}
- ptr = read_config(&sel, ptr + PCICAP_NEXTPTR, 1);
+ ptr = read_config(sc, ptr + PCICAP_NEXTPTR, 1);
}
}
@@ -260,7 +318,7 @@ cfginitmsi(struct passthru_softc *sc)
*/
if ((sts & PCIM_STATUS_CAPPRESENT) != 0 && sc->psc_msi.capoff == 0) {
int origptr, msiptr;
- origptr = read_config(&sel, PCIR_CAP_PTR, 1);
+ origptr = read_config(sc, PCIR_CAP_PTR, 1);
msiptr = passthru_add_msicap(pi, 1, origptr);
sc->psc_msi.capoff = msiptr;
sc->psc_msi.msgctrl = pci_get_cfgdata16(pi, msiptr + 2);
@@ -525,11 +583,55 @@ init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base)
}
static int
+devinfo_getbar(di_node_t node, int bar, enum pcibar_type *type, uint64_t *base,
+ uint64_t *size)
+{
+ int len, i;
+ int *regbuf;
+ int num;
+
+ len = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
+ "assigned-addresses", &regbuf);
+
+ for (i = 0; i < len;
+ i += sizeof (pci_regspec_t) / sizeof (uint_t)) {
+ pci_regspec_t *reg = (pci_regspec_t *)&regbuf[i];
+
+ if (PCI_REG_REG_G(reg->pci_phys_hi) < PCI_CONF_BASE0 ||
+ PCI_REG_REG_G(reg->pci_phys_hi) > PCI_CONF_BASE5)
+ continue;
+ num = PCI_REG_REG_G(reg->pci_phys_hi) >> 2;
+ if (num != bar)
+ continue;
+
+ *base = ((uint64_t)reg->pci_phys_mid << 32) | reg->pci_phys_low;
+ *size = ((uint64_t)reg->pci_size_hi << 32) | reg->pci_size_low;
+ switch (reg->pci_phys_hi & PCI_REG_ADDR_M) {
+ case PCI_ADDR_IO:
+ *type = PCIBAR_IO;
+ break;
+ case PCI_ADDR_MEM32:
+ *type = PCIBAR_MEM32;
+ break;
+ case PCI_ADDR_MEM64:
+ *type = PCIBAR_MEM64;
+ break;
+ }
+
+ return (0);
+ }
+
+ return (-1);
+}
+
+static int
cfginitbar(struct vmctx *ctx, struct passthru_softc *sc)
{
int i, error;
struct pci_devinst *pi;
+#ifdef __FreeBSD__
struct pci_bar_io bar;
+#endif
enum pcibar_type bartype;
uint64_t base, size;
@@ -539,6 +641,7 @@ cfginitbar(struct vmctx *ctx, struct passthru_softc *sc)
* Initialize BAR registers
*/
for (i = 0; i <= PCI_BARMAX; i++) {
+#ifdef __FreeBSD__
bzero(&bar, sizeof(bar));
bar.pbi_sel = sc->psc_sel;
bar.pbi_reg = PCIR_BAR(i);
@@ -561,6 +664,10 @@ cfginitbar(struct vmctx *ctx, struct passthru_softc *sc)
base = bar.pbi_base & PCIM_BAR_MEM_BASE;
}
size = bar.pbi_length;
+#else
+ if (devinfo_getbar(sc->devnode, i, &bartype, &base, &size) != 0)
+ continue;
+#endif
if (bartype != PCIBAR_IO) {
if (((base | size) & PAGE_MASK) != 0) {
@@ -640,6 +747,60 @@ done:
}
static int
+devinfo_open(char *path, di_node_t *devnode, int *bus, int *slot, int *func)
+{
+ di_node_t rootnode, nexnode, node;
+ char *devfspath, *tmp;
+ int nexfd;
+ int len, *regbuf;
+ pci_regspec_t *reg;
+
+ rootnode = di_init("/", DINFOCPYALL);
+
+ if (rootnode == DI_NODE_NIL)
+ return (-1);
+
+ for (*devnode = di_drv_first_node("ppt", rootnode);
+ *devnode != DI_NODE_NIL;
+ *devnode = di_drv_next_node(*devnode)) {
+ devfspath = di_devfs_path(*devnode);
+ if (strcmp(devfspath, path) == 0) {
+ /*
+ * Walk up device path. Last node before the root node
+ * is the nexus node.
+ */
+ node = di_parent_node(*devnode);
+ while (node != rootnode) {
+ nexnode = node;
+ node = di_parent_node(node);
+ }
+
+ di_devfs_path_free(devfspath);
+ break;
+ }
+ di_devfs_path_free(path);
+ }
+
+ if (*devnode == DI_NODE_NIL || nexnode == rootnode)
+ return (-1);
+
+ devfspath = di_devfs_path(nexnode);
+ (void) asprintf(&tmp, "/devices%s:reg", devfspath);
+ nexfd = open(tmp, O_RDWR);
+ free(tmp);
+ di_devfs_path_free(devfspath);
+
+ len = di_prop_lookup_ints(DDI_DEV_T_ANY, *devnode, "reg", &regbuf);
+ reg = (pci_regspec_t *)regbuf;
+
+ *bus = (uchar_t)PCI_REG_BUS_G(reg->pci_phys_hi);
+ *slot = (uchar_t)PCI_REG_DEV_G(reg->pci_phys_hi);
+ *func = (uchar_t)PCI_REG_FUNC_G(reg->pci_phys_hi);
+
+ return (nexfd);
+}
+
+static int
passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
{
int bus, slot, func, error, memflags;
@@ -649,6 +810,8 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
cap_ioctl_t pci_ioctls[] = { PCIOCREAD, PCIOCWRITE, PCIOCGETBAR };
cap_ioctl_t io_ioctls[] = { IODEV_PIO };
#endif
+ di_node_t devnode;
+ int nexfd;
sc = NULL;
error = 1;
@@ -663,6 +826,7 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
goto done;
}
+#ifdef __FreeBSD__
if (pcifd < 0) {
pcifd = open(_PATH_DEVPCI, O_RDWR, 0);
if (pcifd < 0) {
@@ -670,6 +834,7 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
goto done;
}
}
+#endif
#ifndef WITHOUT_CAPSICUM
if (cap_rights_limit(pcifd, &rights) == -1 && errno != ENOSYS)
@@ -678,6 +843,7 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
errx(EX_OSERR, "Unable to apply rights for sandbox");
#endif
+#ifdef __FreeBSD__
if (iofd < 0) {
iofd = open(_PATH_DEVIO, O_RDWR, 0);
if (iofd < 0) {
@@ -685,6 +851,7 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
goto done;
}
}
+#endif
#ifndef WITHOUT_CAPSICUM
if (cap_rights_limit(iofd, &rights) == -1 && errno != ENOSYS)
@@ -708,11 +875,19 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
errx(EX_OSERR, "Unable to apply rights for sandbox");
#endif
+#ifdef __FreeBSD__
if (opts == NULL ||
sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3) {
warnx("invalid passthru options");
goto done;
}
+#else
+ if (opts == NULL ||
+ (nexfd = devinfo_open(opts, &devnode, &bus, &slot, &func)) == -1) {
+ warnx("invalid passthru options");
+ goto done;
+ }
+#endif
if (vm_assign_pptdev(ctx, bus, slot, func) != 0) {
warnx("PCI device at %d/%d/%d is not using the ppt(4) driver",
@@ -724,6 +899,8 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
pi->pi_arg = sc;
sc->psc_pi = pi;
+ sc->devnode = devnode;
+ sc->nexfd = nexfd;
/* initialize config space */
if ((error = cfginit(ctx, pi, bus, slot, func)) != 0)
@@ -799,7 +976,7 @@ passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
#endif
/* Everything else just read from the device's config space */
- *rv = read_config(&sc->psc_sel, coff, bytes);
+ *rv = read_config(sc, coff, bytes);
return (0);
}
@@ -865,7 +1042,7 @@ passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
}
#endif
- write_config(&sc->psc_sel, coff, bytes, val);
+ write_config(sc, coff, bytes, val);
return (0);
}
@@ -875,7 +1052,9 @@ passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
uint64_t offset, int size, uint64_t value)
{
struct passthru_softc *sc;
+#ifdef __FreeBSD__
struct iodev_pio_req pio;
+#endif
sc = pi->pi_arg;
@@ -883,6 +1062,7 @@ passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
msix_table_write(ctx, vcpu, sc, offset, size, value);
} else {
assert(pi->pi_bar[baridx].type == PCIBAR_IO);
+#ifdef __FreeBSD__
bzero(&pio, sizeof(struct iodev_pio_req));
pio.access = IODEV_PIO_WRITE;
pio.port = sc->psc_bar[baridx].addr + offset;
@@ -890,6 +1070,10 @@ passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
pio.val = value;
(void)ioctl(iofd, IODEV_PIO, &pio);
+#else
+ (void) pcitool_reg_rw(sc, baridx, offset, size, value,
+ PCITOOL_DEVICE_SET_REG);
+#endif
}
}
@@ -898,7 +1082,9 @@ passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
uint64_t offset, int size)
{
struct passthru_softc *sc;
+#ifdef __FreeBSD__
struct iodev_pio_req pio;
+#endif
uint64_t val;
sc = pi->pi_arg;
@@ -907,6 +1093,7 @@ passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
val = msix_table_read(sc, offset, size);
} else {
assert(pi->pi_bar[baridx].type == PCIBAR_IO);
+#ifdef __FreeBSD__
bzero(&pio, sizeof(struct iodev_pio_req));
pio.access = IODEV_PIO_READ;
pio.port = sc->psc_bar[baridx].addr + offset;
@@ -916,6 +1103,10 @@ passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
(void)ioctl(iofd, IODEV_PIO, &pio);
val = pio.val;
+#else
+ val = pcitool_reg_rw(sc, baridx, offset, size, 0,
+ PCITOOL_DEVICE_GET_REG);
+#endif
}
return (val);
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files
index 4e8c4313d7..7f19c231f1 100644
--- a/usr/src/uts/i86pc/Makefile.files
+++ b/usr/src/uts/i86pc/Makefile.files
@@ -247,6 +247,7 @@ VMM_OBJS += vmm.o \
vmm_stat.o \
vmm_util.o \
x86.o \
+ iommu.o \
vdev.o \
vatpic.o \
vatpit.o \
@@ -260,19 +261,20 @@ VMM_OBJS += vmm.o \
vmx_msr.o \
vmx.o \
vmx_support.o \
+ vtd.o \
svm.o \
svm_msr.o \
npt.o \
vmcb.o \
svm_support.o \
amdv.o \
- iommu.o \
- sol_ppt.o \
vmm_sol_vm.o \
vmm_sol_glue.o
VIONA_OBJS += viona.o
+PPT_OBJS += ppt.o ppt_sol_glue.o
+
#
# Build up defines and paths.
#
diff --git a/usr/src/uts/i86pc/Makefile.i86pc b/usr/src/uts/i86pc/Makefile.i86pc
index b5673b182b..68cca2de49 100644
--- a/usr/src/uts/i86pc/Makefile.i86pc
+++ b/usr/src/uts/i86pc/Makefile.i86pc
@@ -268,6 +268,7 @@ DRV_KMODS += fipe
# XXX: should be DRV_KMODS_64, but that doesn't work
DRV_KMODS += vmm
DRV_KMODS += viona
+DRV_KMODS += ppt
DRV_KMODS += cpudrv
diff --git a/usr/src/uts/i86pc/io/vmm/intel/vtd.c b/usr/src/uts/i86pc/io/vmm/intel/vtd.c
index f3b7a98a9d..73779733d0 100644
--- a/usr/src/uts/i86pc/io/vmm/intel/vtd.c
+++ b/usr/src/uts/i86pc/io/vmm/intel/vtd.c
@@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$");
#include <machine/vmparam.h>
#include <contrib/dev/acpica/include/acpi.h>
+#include <sys/sunndi.h>
+
#include "io/iommu.h"
/*
@@ -235,19 +237,94 @@ vtd_translation_disable(struct vtdmap *vtdmap)
;
}
+static void *
+vtd_map(ACPI_DMAR_HARDWARE_UNIT *drhd, int unit)
+{
+ struct ddi_parent_private_data *pdptr;
+ struct regspec reg;
+ dev_info_t *dip;
+ caddr_t regs;
+ ddi_acc_handle_t hdl;
+ int error;
+
+ static ddi_device_acc_attr_t regs_attr = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_NEVERSWAP_ACC,
+ DDI_STRICTORDER_ACC,
+ };
+
+ dip = ddi_add_child(ddi_root_node(), "vtd",
+ DEVI_SID_NODEID, unit);
+
+#if 0
+ drhd->dr_dip = dip;
+#endif
+
+ reg.regspec_bustype = 0;
+ reg.regspec_addr = drhd->Address;
+ reg.regspec_size = PAGE_SIZE;
+
+ /*
+ * update the reg properties
+ *
+ * reg property will be used for register
+ * set access
+ *
+ * refer to the bus_map of root nexus driver
+ * I/O or memory mapping:
+ *
+ * <bustype=0, addr=x, len=x>: memory
+ * <bustype=1, addr=x, len=x>: i/o
+ * <bustype>1, addr=0, len=x>: x86-compatibility i/o
+ */
+ (void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
+ dip, "reg", (int *)&reg,
+ sizeof (struct regspec) / sizeof (int));
+
+ /*
+ * This is an artificially constructed dev_info, and we
+ * need to set a few more things to be able to use it
+ * for ddi_dma_alloc_handle/free_handle.
+ */
+ ddi_set_driver(dip, ddi_get_driver(ddi_root_node()));
+ DEVI(dip)->devi_bus_dma_allochdl =
+ DEVI(ddi_get_driver((ddi_root_node())));
+
+ pdptr = kmem_zalloc(sizeof (struct ddi_parent_private_data)
+ + sizeof (struct regspec), KM_SLEEP);
+ pdptr->par_nreg = 1;
+ pdptr->par_reg = (struct regspec *)(pdptr + 1);
+ pdptr->par_reg->regspec_bustype = 0;
+ pdptr->par_reg->regspec_addr = drhd->Address;
+ pdptr->par_reg->regspec_size = PAGE_SIZE;
+ ddi_set_parent_data(dip, pdptr);
+
+ error = ddi_regs_map_setup(dip, 0, &regs, 0, PAGE_SIZE, &regs_attr,
+ &hdl);
+
+ if (error != DDI_SUCCESS)
+ return (NULL);
+
+ return (regs);
+}
+
static int
vtd_init(void)
{
int i, units, remaining;
struct vtdmap *vtdmap;
vm_paddr_t ctx_paddr;
- char *end, envname[32];
+ char *end;
+#ifdef __FreeBSD__
+ char envname[32];
unsigned long mapaddr;
+#endif
ACPI_STATUS status;
ACPI_TABLE_DMAR *dmar;
ACPI_DMAR_HEADER *hdr;
ACPI_DMAR_HARDWARE_UNIT *drhd;
+#ifdef __FreeBSD__
/*
* Allow the user to override the ACPI DMAR table by specifying the
* physical address of each remapping unit.
@@ -266,7 +343,9 @@ vtd_init(void)
if (units > 0)
goto skip_dmar;
-
+#else
+ units = 0;
+#endif
/* Search for DMAR table. */
status = AcpiGetTable(ACPI_SIG_DMAR, 0, (ACPI_TABLE_HEADER **)&dmar);
if (ACPI_FAILURE(status))
@@ -289,7 +368,12 @@ vtd_init(void)
break;
drhd = (ACPI_DMAR_HARDWARE_UNIT *)hdr;
+#ifdef __FreeBSD__
vtdmaps[units++] = (struct vtdmap *)PHYS_TO_DMAP(drhd->Address);
+#else
+ vtdmaps[units] = (struct vtdmap *)vtd_map(drhd, units);
+ units++;
+#endif
if (units >= DRHD_MAX_UNITS)
break;
remaining -= hdr->Length;
@@ -298,7 +382,9 @@ vtd_init(void)
if (units <= 0)
return (ENXIO);
+#ifdef __FreeBSD__
skip_dmar:
+#endif
drhd_num = units;
vtdmap = vtdmaps[0];
diff --git a/usr/src/uts/i86pc/io/vmm/io/iommu.c b/usr/src/uts/i86pc/io/vmm/io/iommu.c
index 75cf1eccee..11ad6ebabd 100644
--- a/usr/src/uts/i86pc/io/vmm/io/iommu.c
+++ b/usr/src/uts/i86pc/io/vmm/io/iommu.c
@@ -41,6 +41,10 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/md_var.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/pci.h>
+
#include "vmm_util.h"
#include "vmm_mem.h"
#include "iommu.h"
@@ -58,7 +62,9 @@ SYSCTL_INT(_hw_vmm_iommu, OID_AUTO, enable, CTLFLAG_RDTUN, &iommu_enable, 0,
static struct iommu_ops *ops;
static void *host_domain;
+#ifdef __FreeBSD__
static eventhandler_tag add_tag, delete_tag;
+#endif
static __inline int
IOMMU_INIT(void)
@@ -154,6 +160,7 @@ IOMMU_DISABLE(void)
(*ops->disable)();
}
+#ifdef __FreeBSD__
static void
iommu_pci_add(void *arg, device_t dev)
{
@@ -168,6 +175,16 @@ iommu_pci_delete(void *arg, device_t dev)
iommu_remove_device(host_domain, pci_get_rid(dev));
}
+#endif
+
+static int
+iommu_find_device(dev_info_t *dip, void *unused)
+{
+ if (pcie_is_pci_device(dip))
+ iommu_add_device(host_domain, pci_get_rid(dip));
+
+ return (DDI_WALK_CONTINUE);
+}
static void
iommu_init(void)
@@ -211,6 +228,7 @@ iommu_init(void)
*/
iommu_create_mapping(host_domain, 0, 0, maxaddr);
+#ifdef __FreeBSD__
add_tag = EVENTHANDLER_REGISTER(pci_add_device, iommu_pci_add, NULL, 0);
delete_tag = EVENTHANDLER_REGISTER(pci_delete_device, iommu_pci_delete,
NULL, 0);
@@ -227,6 +245,9 @@ iommu_init(void)
}
}
}
+#else
+ ddi_walk_devs(ddi_root_node(), iommu_find_device, NULL);
+#endif
IOMMU_ENABLE();
}
@@ -234,7 +255,7 @@ iommu_init(void)
void
iommu_cleanup(void)
{
-
+#ifdef __FreeBSD__
if (add_tag != NULL) {
EVENTHANDLER_DEREGISTER(pci_add_device, add_tag);
add_tag = NULL;
@@ -243,6 +264,7 @@ iommu_cleanup(void)
EVENTHANDLER_DEREGISTER(pci_delete_device, delete_tag);
delete_tag = NULL;
}
+#endif
IOMMU_DISABLE();
IOMMU_DESTROY_DOMAIN(host_domain);
IOMMU_CLEANUP();
@@ -251,7 +273,7 @@ iommu_cleanup(void)
void *
iommu_create_domain(vm_paddr_t maxaddr)
{
- static volatile int iommu_initted;
+ static volatile u_int iommu_initted;
if (iommu_initted < 2) {
if (atomic_cmpset_int(&iommu_initted, 0, 1)) {
diff --git a/usr/src/uts/i86pc/io/vmm/io/ppt.c b/usr/src/uts/i86pc/io/vmm/io/ppt.c
index 4c9ff47458..bcf09209ed 100644
--- a/usr/src/uts/i86pc/io/vmm/io/ppt.c
+++ b/usr/src/uts/i86pc/io/vmm/io/ppt.c
@@ -36,18 +36,26 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/pciio.h>
+#ifdef __FreeBSD__
#include <sys/rman.h>
+#endif
#include <sys/smp.h>
#include <sys/sysctl.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
+#ifdef __FreeBSD__
#include <machine/resource.h>
+#endif
#include <machine/vmm.h>
#include <machine/vmm_dev.h>
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
#include "vmm_lapic.h"
#include "vmm_ktr.h"
@@ -89,20 +97,31 @@ struct pptdev {
struct pptseg mmio[MAX_MMIOSEGS];
struct {
int num_msgs; /* guest state */
-
+#ifdef __FreeBSD__
int startrid; /* host state */
struct resource *res[MAX_MSIMSGS];
void *cookie[MAX_MSIMSGS];
+#else
+ boolean_t is_fixed;
+ size_t inth_sz;
+ ddi_intr_handle_t *inth;
+#endif
struct pptintr_arg arg[MAX_MSIMSGS];
} msi;
struct {
int num_msgs;
+#ifdef __FreeBSD__
int startrid;
int msix_table_rid;
struct resource *msix_table_res;
struct resource **res;
void **cookie;
+#else
+ size_t inth_sz;
+ size_t arg_sz;
+ ddi_intr_handle_t *inth;
+#endif
struct pptintr_arg *arg;
} msix;
};
@@ -116,6 +135,7 @@ SYSCTL_INT(_hw_vmm_ppt, OID_AUTO, devices, CTLFLAG_RD, &num_pptdevs, 0,
static TAILQ_HEAD(, pptdev) pptdev_list = TAILQ_HEAD_INITIALIZER(pptdev_list);
+#ifdef __FreeBSD__
static int
ppt_probe(device_t dev)
{
@@ -146,6 +166,7 @@ ppt_probe(device_t dev)
*/
return (BUS_PROBE_NOWILDCARD);
}
+#endif
static int
ppt_attach(device_t dev)
@@ -158,8 +179,10 @@ ppt_attach(device_t dev)
TAILQ_INSERT_TAIL(&pptdev_list, ppt, next);
ppt->dev = dev;
+#ifdef __FreeBSD__
if (bootverbose)
device_printf(dev, "attached\n");
+#endif
return (0);
}
@@ -179,6 +202,7 @@ ppt_detach(device_t dev)
return (0);
}
+#ifdef __FreeBSD__
static device_method_t ppt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ppt_probe),
@@ -190,6 +214,112 @@ static device_method_t ppt_methods[] = {
static devclass_t ppt_devclass;
DEFINE_CLASS_0(ppt, ppt_driver, ppt_methods, sizeof(struct pptdev));
DRIVER_MODULE(ppt, pci, ppt_driver, ppt_devclass, NULL, NULL);
+#endif
+
+static void *ppt_state;
+
+static int
+ppt_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ struct pptdev *ppt;
+
+ if (cmd != DDI_ATTACH)
+ return (DDI_FAILURE);
+
+ ddi_soft_state_zalloc(ppt_state, ddi_get_instance(dip));
+
+ ppt = ddi_get_soft_state(ppt_state, ddi_get_instance(dip));
+ ppt->dev = dip;
+
+ ddi_set_driver_private(dip, ppt);
+
+ if (ppt_attach(dip) == 0)
+ return (DDI_SUCCESS);
+
+ ddi_set_driver_private(dip, NULL);
+
+ ddi_soft_state_free(ppt_state, ddi_get_instance(dip));
+
+ return (DDI_FAILURE);
+}
+
+static int
+ppt_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ if (cmd != DDI_DETACH)
+ return (DDI_FAILURE);
+
+ if (ppt_detach(dip) != 0)
+ return (DDI_FAILURE);
+
+ ddi_set_driver_private(dip, NULL);
+
+ ddi_soft_state_free(ppt_state, ddi_get_instance(dip));
+
+ return (DDI_SUCCESS);
+}
+
+static struct dev_ops ppt_ops = {
+ DEVO_REV,
+ 0,
+ ddi_no_info,
+ nulldev, /* identify */
+ nulldev, /* probe */
+ ppt_ddi_attach,
+ ppt_ddi_detach,
+ nodev, /* reset */
+ (struct cb_ops *)NULL,
+ (struct bus_ops *)NULL
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ "ppt",
+ &ppt_ops
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ &modldrv,
+ NULL
+};
+
+int
+_init(void)
+{
+ int error;
+
+ error = ddi_soft_state_init(&ppt_state, sizeof (struct pptdev), 0);
+ if (error)
+ return (error);
+
+ error = mod_install(&modlinkage);
+ if (error)
+ ddi_soft_state_fini(&ppt_state);
+
+ return (error);
+}
+
+int
+_fini(void)
+{
+ int error;
+
+ error = mod_remove(&modlinkage);
+ if (error)
+ return (error);
+
+ ddi_soft_state_fini(&ppt_state);
+
+ return (0);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
static struct pptdev *
ppt_find(int bus, int slot, int func)
@@ -228,13 +358,17 @@ static void
ppt_teardown_msi(struct pptdev *ppt)
{
int i, rid;
+#ifdef __FreeBSD__
void *cookie;
struct resource *res;
+#endif
+ int intr_cap = 0;
if (ppt->msi.num_msgs == 0)
return;
for (i = 0; i < ppt->msi.num_msgs; i++) {
+#ifdef __FreeBSD__
rid = ppt->msi.startrid + i;
res = ppt->msi.res[i];
cookie = ppt->msi.cookie[i];
@@ -247,10 +381,29 @@ ppt_teardown_msi(struct pptdev *ppt)
ppt->msi.res[i] = NULL;
ppt->msi.cookie[i] = NULL;
+#else
+ (void) ddi_intr_get_cap(ppt->msi.inth[i], &intr_cap);
+ if (intr_cap & DDI_INTR_FLAG_BLOCK)
+ ddi_intr_block_disable(&ppt->msi.inth[i], 1);
+ else
+ ddi_intr_disable(ppt->msi.inth[i]);
+
+ ddi_intr_remove_handler(ppt->msi.inth[i]);
+ ddi_intr_free(ppt->msi.inth[i]);
+
+ ppt->msi.inth[i] = NULL;
+#endif
}
+#ifdef __FreeBSD__
if (ppt->msi.startrid == 1)
pci_release_msi(ppt->dev);
+#else
+ kmem_free(ppt->msi.inth, ppt->msi.inth_sz);
+ ppt->msi.inth = NULL;
+ ppt->msi.inth_sz = 0;
+ ppt->msi.is_fixed = B_FALSE;
+#endif
ppt->msi.num_msgs = 0;
}
@@ -258,6 +411,7 @@ ppt_teardown_msi(struct pptdev *ppt)
static void
ppt_teardown_msix_intr(struct pptdev *ppt, int idx)
{
+#ifdef __FreeBSD__
int rid;
struct resource *res;
void *cookie;
@@ -274,6 +428,22 @@ ppt_teardown_msix_intr(struct pptdev *ppt, int idx)
ppt->msix.res[idx] = NULL;
ppt->msix.cookie[idx] = NULL;
+#else
+ if (ppt->msix.inth != NULL && ppt->msix.inth[idx] != NULL) {
+ int intr_cap;
+
+ (void) ddi_intr_get_cap(ppt->msix.inth[idx], &intr_cap);
+ if (intr_cap & DDI_INTR_FLAG_BLOCK)
+ ddi_intr_block_disable(&ppt->msix.inth[idx], 1);
+ else
+ ddi_intr_disable(ppt->msix.inth[idx]);
+
+ ddi_intr_remove_handler(ppt->msix.inth[idx]);
+ ddi_intr_free(ppt->msix.inth[idx]);
+
+ ppt->msix.inth[idx] = NULL;
+ }
+#endif
}
static void
@@ -287,6 +457,7 @@ ppt_teardown_msix(struct pptdev *ppt)
for (i = 0; i < ppt->msix.num_msgs; i++)
ppt_teardown_msix_intr(ppt, i);
+#ifdef __FreeBSD__
if (ppt->msix.msix_table_res) {
bus_release_resource(ppt->dev, SYS_RES_MEMORY,
ppt->msix.msix_table_rid,
@@ -300,6 +471,16 @@ ppt_teardown_msix(struct pptdev *ppt)
free(ppt->msix.arg, M_PPTMSIX);
pci_release_msi(ppt->dev);
+#else
+ if (ppt->msix.inth) {
+ kmem_free(ppt->msix.inth, ppt->msix.inth_sz);
+ ppt->msix.inth = NULL;
+ ppt->msix.inth_sz = 0;
+ kmem_free(ppt->msix.arg, ppt->msix.arg_sz);
+ ppt->msix.arg = NULL;
+ ppt->msix.arg_sz = 0;
+ }
+#endif
ppt->msix.num_msgs = 0;
}
@@ -453,13 +634,18 @@ ppt_map_mmio(struct vm *vm, int bus, int slot, int func,
return (ENOENT);
}
+#ifdef __FreeBSD__
static int
pptintr(void *arg)
+#else
+static uint_t
+pptintr(char *arg, char *unused)
+#endif
{
struct pptdev *ppt;
struct pptintr_arg *pptarg;
- pptarg = arg;
+ pptarg = (struct pptintr_arg *)arg;
ppt = pptarg->pptdev;
if (ppt->vm != NULL)
@@ -475,10 +661,14 @@ pptintr(void *arg)
* For legacy interrupts give other filters a chance in case
* the interrupt was not generated by the passthrough device.
*/
+#ifdef __FreeBSD__
if (ppt->msi.startrid == 0)
return (FILTER_STRAY);
else
return (FILTER_HANDLED);
+#else
+ return (ppt->msi.is_fixed ? DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
+#endif
}
int
@@ -487,6 +677,7 @@ ppt_setup_msi(struct vm *vm, int vcpu, int bus, int slot, int func,
{
int i, rid, flags;
int msi_count, startrid, error, tmp;
+ int intr_type, intr_cap = 0;
struct pptdev *ppt;
if (numvec < 0 || numvec > MAX_MSIMSGS)
@@ -504,6 +695,7 @@ ppt_setup_msi(struct vm *vm, int vcpu, int bus, int slot, int func,
if (numvec == 0) /* nothing more to do */
return (0);
+#ifdef __FreeBSD__
flags = RF_ACTIVE;
msi_count = pci_msi_count(ppt->dev);
if (msi_count == 0) {
@@ -563,6 +755,65 @@ ppt_setup_msi(struct vm *vm, int vcpu, int bus, int slot, int func,
if (error != 0)
break;
}
+#else
+ if (ddi_intr_get_navail(ppt->dev, DDI_INTR_TYPE_MSI, &msi_count) !=
+ DDI_SUCCESS) {
+ if (ddi_intr_get_navail(ppt->dev, DDI_INTR_TYPE_FIXED,
+ &msi_count) != DDI_SUCCESS)
+ return (EINVAL);
+
+ intr_type = DDI_INTR_TYPE_FIXED;
+ ppt->msi.is_fixed = B_TRUE;
+ } else {
+ intr_type = DDI_INTR_TYPE_MSI;
+ }
+
+ /*
+ * The device must be capable of supporting the number of vectors
+ * the guest wants to allocate.
+ */
+ if (numvec > msi_count)
+ return (EINVAL);
+
+ ppt->msi.inth_sz = numvec * sizeof (ddi_intr_handle_t);
+ ppt->msi.inth = kmem_zalloc(ppt->msi.inth_sz, KM_SLEEP);
+ if (ddi_intr_alloc(ppt->dev, ppt->msi.inth, intr_type, 0,
+ numvec, &msi_count, 0) != DDI_SUCCESS) {
+ kmem_free(ppt->msi.inth, ppt->msi.inth_sz);
+ return (EINVAL);
+ }
+
+ /*
+ * Again, make sure we actually got as many vectors as the guest wanted
+ * to allocate.
+ */
+ if (numvec != msi_count) {
+ ppt_teardown_msi(ppt);
+ return (EINVAL);
+ }
+ /*
+ * Set up & enable interrupt handler for each vector.
+ */
+ for (i = 0; i < numvec; i++) {
+ ppt->msi.num_msgs = i + 1;
+ ppt->msi.arg[i].pptdev = ppt;
+ ppt->msi.arg[i].addr = addr;
+ ppt->msi.arg[i].msg_data = msg + i;
+
+ if (ddi_intr_add_handler(ppt->msi.inth[i], pptintr,
+ &ppt->msi.arg[i], NULL) != DDI_SUCCESS)
+ break;
+
+ (void) ddi_intr_get_cap(ppt->msi.inth[i], &intr_cap);
+ if (intr_cap & DDI_INTR_FLAG_BLOCK)
+ error = ddi_intr_block_enable(&ppt->msi.inth[i], 1);
+ else
+ error = ddi_intr_enable(ppt->msi.inth[i]);
+
+ if (error != DDI_SUCCESS)
+ break;
+ }
+#endif
if (i < numvec) {
ppt_teardown_msi(ppt);
@@ -580,6 +831,7 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
struct pci_devinfo *dinfo;
int numvec, alloced, rid, error;
size_t res_size, cookie_size, arg_size;
+ int intr_cap;
ppt = ppt_find(bus, slot, func);
if (ppt == NULL)
@@ -587,6 +839,7 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
if (ppt->vm != vm) /* Make sure we own this device */
return (EBUSY);
+#ifdef __FreeBSD__
dinfo = device_get_ivars(ppt->dev);
if (!dinfo)
return (ENXIO);
@@ -631,11 +884,46 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
return (error == 0 ? ENOSPC: error);
}
}
+#else
+ /*
+ * First-time configuration:
+ * Allocate the MSI-X table
+ * Allocate the IRQ resources
+ * Set up some variables in ppt->msix
+ */
+ if (ppt->msix.num_msgs == 0) {
+ if (ddi_intr_get_navail(ppt->dev, DDI_INTR_TYPE_MSIX, &numvec) !=
+ DDI_SUCCESS)
+ return (EINVAL);
+
+ ppt->msix.num_msgs = numvec;
+ ppt->msix.arg_sz = numvec * sizeof(ppt->msix.arg[0]);
+ ppt->msix.arg = kmem_zalloc(ppt->msix.arg_sz, KM_SLEEP);
+ ppt->msix.inth_sz = numvec * sizeof(ddi_intr_handle_t);
+ ppt->msix.inth = kmem_zalloc(ppt->msix.inth_sz, KM_SLEEP);
+
+ if (ddi_intr_alloc(ppt->dev, ppt->msix.inth, DDI_INTR_TYPE_MSIX,
+ 0, numvec, &alloced, 0) != DDI_SUCCESS) {
+ kmem_free(ppt->msix.arg, ppt->msix.arg_sz);
+ kmem_free(ppt->msix.inth, ppt->msix.inth_sz);
+ ppt->msix.arg = NULL;
+ ppt->msix.inth = NULL;
+ ppt->msix.arg_sz = ppt->msix.inth_sz = 0;
+ return (EINVAL);
+ }
+
+ if (numvec != alloced) {
+ ppt_teardown_msix(ppt);
+ return (EINVAL);
+ }
+ }
+#endif
if ((vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
/* Tear down the IRQ if it's already set up */
ppt_teardown_msix_intr(ppt, idx);
+#ifdef __FreeBSD__
/* Allocate the IRQ resource */
ppt->msix.cookie[idx] = NULL;
rid = ppt->msix.startrid + idx;
@@ -643,12 +931,13 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
&rid, RF_ACTIVE);
if (ppt->msix.res[idx] == NULL)
return (ENXIO);
-
+#endif
ppt->msix.arg[idx].pptdev = ppt;
ppt->msix.arg[idx].addr = addr;
ppt->msix.arg[idx].msg_data = msg;
/* Setup the MSI-X interrupt */
+#ifdef __FreeBSD__
error = bus_setup_intr(ppt->dev, ppt->msix.res[idx],
INTR_TYPE_NET | INTR_MPSAFE,
pptintr, NULL, &ppt->msix.arg[idx],
@@ -661,6 +950,22 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
ppt->msix.res[idx] = NULL;
return (ENXIO);
}
+#else
+ if (ddi_intr_add_handler(ppt->msix.inth[idx], pptintr,
+ &ppt->msix.arg[idx], NULL) != DDI_SUCCESS)
+ return (ENXIO);
+
+ (void) ddi_intr_get_cap(ppt->msix.inth[idx], &intr_cap);
+ if (intr_cap & DDI_INTR_FLAG_BLOCK)
+ error = ddi_intr_block_enable(&ppt->msix.inth[idx], 1);
+ else
+ error = ddi_intr_enable(ppt->msix.inth[idx]);
+
+ if (error != DDI_SUCCESS) {
+ ddi_intr_remove_handler(ppt->msix.inth[idx]);
+ return (ENXIO);
+ }
+#endif
} else {
/* Masked, tear it down if it's already been set up */
ppt_teardown_msix_intr(ppt, idx);
diff --git a/usr/src/uts/i86pc/io/vmm/io/ppt.conf b/usr/src/uts/i86pc/io/vmm/io/ppt.conf
new file mode 100644
index 0000000000..698cecb6f8
--- /dev/null
+++ b/usr/src/uts/i86pc/io/vmm/io/ppt.conf
@@ -0,0 +1,14 @@
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Joyent, Inc.
+#
+
diff --git a/usr/src/uts/i86pc/io/vmm/io/ppt_sol_glue.c b/usr/src/uts/i86pc/io/vmm/io/ppt_sol_glue.c
new file mode 100644
index 0000000000..3fa38d209f
--- /dev/null
+++ b/usr/src/uts/i86pc/io/vmm/io/ppt_sol_glue.c
@@ -0,0 +1,177 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+/*
+ * PCI/PCIe interfaces needed by ppt
+ */
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/pcie.h>
+#include <sys/pci_cap.h>
+
+#include <sys/bus.h>
+#include <dev/pci/pcivar.h>
+
+static bool
+pcie_wait_for_pending_transactions(dev_info_t *dip, u_int max_delay)
+{
+ uint16_t cap_ptr, devsts;
+ ddi_acc_handle_t hdl;
+
+ if (pci_config_setup(dip, &hdl) != DDI_SUCCESS)
+ return (false);
+
+ if (PCI_CAP_LOCATE(hdl, PCI_CAP_ID_PCI_E, &cap_ptr) != DDI_SUCCESS) {
+ pci_config_teardown(&hdl);
+ return (false);
+ }
+
+ devsts = PCI_CAP_GET16(hdl, NULL, cap_ptr, PCIE_DEVSTS);
+ while ((devsts & PCIE_DEVSTS_TRANS_PENDING) != 0) {
+ if (max_delay == 0) {
+ pci_config_teardown(&hdl);
+ return (false);
+ }
+
+ /* Poll once every 100 milliseconds up to the timeout. */
+ if (max_delay > 100) {
+ delay(drv_usectohz(100 * 1000));
+ max_delay -= 100;
+ } else {
+ delay(drv_usectohz(max_delay * 1000));
+ max_delay = 0;
+ }
+ devsts = PCI_CAP_GET16(hdl, NULL, cap_ptr, PCIE_DEVSTS);
+ }
+
+ pci_config_teardown(&hdl);
+ return (true);
+}
+
+int
+pcie_get_max_completion_timeout(device_t dev)
+{
+ dev_info_t *dip = dev;
+ int timo = 0;
+ uint16_t cap_ptr;
+ ddi_acc_handle_t hdl;
+ int timo_ranges[] = { /* timeout ranges */
+ 50000, /* 50ms */
+ 100, /* 100us */
+ 10000, /* 10ms */
+ 0,
+ 0,
+ 55000, /* 55ms */
+ 210000, /* 210ms */
+ 0,
+ 0,
+ 900000, /* 900ms */
+ 3500000, /* 3.5s */
+ 0,
+ 0,
+ 13000000, /* 13s */
+ 64000000, /* 64s */
+ 0
+ };
+
+ if (pci_config_setup(dip, &hdl) != DDI_SUCCESS)
+ return (50000); /* default 50ms */
+
+ if (PCI_CAP_LOCATE(hdl, PCI_CAP_ID_PCI_E, &cap_ptr) != DDI_SUCCESS)
+ goto out;
+
+ if ((PCI_CAP_GET16(hdl, NULL, cap_ptr, PCIE_PCIECAP) &
+ PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0)
+ goto out;
+
+ if ((PCI_CAP_GET16(hdl, NULL, cap_ptr, PCIE_DEVCAP2) &
+ PCIE_DEVCTL2_COM_TO_RANGE_MASK) == 0)
+ goto out;
+
+ timo = timo_ranges[PCI_CAP_GET16(hdl, NULL, cap_ptr, PCIE_DEVCTL2) &
+ PCIE_DEVCAP2_COM_TO_RANGE_MASK];
+
+out:
+ if (timo == 0)
+ timo = 50000; /* default 50ms */
+
+ pci_config_teardown(&hdl);
+ return (timo);
+}
+
+bool
+pcie_flr(device_t dev, u_int max_delay, bool force)
+{
+ dev_info_t *dip = dev;
+ bool ret = false;
+ uint16_t cap_ptr, ctl, cmd;
+ ddi_acc_handle_t hdl;
+ int compl_delay;
+
+ if (pci_config_setup(dip, &hdl) != DDI_SUCCESS)
+ return (false);
+
+ if (PCI_CAP_LOCATE(hdl, PCI_CAP_ID_PCI_E, &cap_ptr) != DDI_SUCCESS)
+ goto fail;
+
+ if ((PCI_CAP_GET16(hdl, NULL, cap_ptr, PCIE_DEVCAP) & PCIE_DEVCAP_FLR)
+ == 0)
+ goto fail;
+
+ /*
+ * Disable busmastering to prevent generation of new
+ * transactions while waiting for the device to go idle. If
+ * the idle timeout fails, the command register is restored
+ * which will re-enable busmastering.
+ */
+ cmd = pci_config_get16(hdl, PCI_CONF_COMM);
+ pci_config_put16(hdl, PCI_CONF_COMM, cmd & ~PCI_COMM_ME);
+ if (!pcie_wait_for_pending_transactions(dev, max_delay)) {
+ if (!force) {
+ pci_config_put16(hdl, PCI_CONF_COMM, cmd);
+ goto fail;
+ }
+ dev_err(dip, CE_WARN,
+ "?Resetting with transactions pending after %d ms\n",
+ max_delay);
+
+ /*
+ * Extend the post-FLR delay to cover the maximum
+ * Completion Timeout delay of anything in flight
+ * during the FLR delay. Enforce a minimum delay of
+ * at least 10ms.
+ */
+ compl_delay = pcie_get_max_completion_timeout(dev) / 1000;
+ if (compl_delay < 10)
+ compl_delay = 10;
+ } else
+ compl_delay = 0;
+
+ /* Initiate the reset. */
+ ctl = PCI_CAP_GET16(hdl, NULL, cap_ptr, PCIE_DEVCTL);
+ (void) PCI_CAP_PUT16(hdl, NULL, cap_ptr, PCIE_DEVCTL,
+ ctl | PCIE_DEVCTL_INITIATE_FLR);
+
+ /* Wait for at least 100ms */
+ delay(drv_usectohz((100 + compl_delay) * 1000));
+
+ pci_config_teardown(&hdl);
+ return (true);
+
+fail:
+ pci_config_teardown(&hdl);
+ return (ret);
+}
diff --git a/usr/src/uts/i86pc/io/vmm/io/sol_iommu.c b/usr/src/uts/i86pc/io/vmm/io/sol_iommu.c
deleted file mode 100644
index 989e88e17b..0000000000
--- a/usr/src/uts/i86pc/io/vmm/io/sol_iommu.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This file and its contents are supplied under the terms of the
- * Common Development and Distribution License ("CDDL"), version 1.0.
- * You may only use this file in accordance with the terms of version
- * 1.0 of the CDDL.
- *
- * A full copy of the text of the CDDL should have accompanied this
- * source. A copy of the CDDL is also available via the Internet at
- * http://www.illumos.org/license/CDDL.
- */
-
-/*
- * Copyright 2017 Joyent, Inc.
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/cmn_err.h>
-
-/*
- * IOMMU Stub
- *
- * Until proper iommu support can be wired into bhyve, stub out all the
- * functions to either fail, if reasonable, or panic.
- */
-
-void
-iommu_cleanup(void)
-{
-}
-
-void *
-iommu_host_domain(void)
-{
- return (NULL);
-}
-
-/*ARGSUSED*/
-void *
-iommu_create_domain(vm_paddr_t maxaddr)
-{
- return (NULL);
-}
-
-/*ARGSUSED*/
-void
-iommu_destroy_domain(void *dom)
-{
- panic("unimplemented");
-}
-
-/*ARGSUSED*/
-void
-iommu_create_mapping(void *dom, vm_paddr_t gpa, vm_paddr_t hpa, size_t len)
-{
- panic("unimplemented");
-}
-
-/*ARGSUSED*/
-void
-iommu_remove_mapping(void *dom, vm_paddr_t gpa, size_t len)
-{
- panic("unimplemented");
-}
-
-/*ARGSUSED*/
-void
-iommu_add_device(void *dom, uint16_t rid)
-{
- panic("unimplemented");
-}
-
-/*ARGSUSED*/
-void
-iommu_remove_device(void *dom, uint16_t rid)
-{
- panic("unimplemented");
-}
-
-/*ARGSUSED*/
-void
-iommu_invalidate_tlb(void *domain)
-{
- panic("unimplemented");
-}
-
diff --git a/usr/src/uts/i86pc/io/vmm/io/sol_ppt.c b/usr/src/uts/i86pc/io/vmm/io/sol_ppt.c
deleted file mode 100644
index ba8bf9de36..0000000000
--- a/usr/src/uts/i86pc/io/vmm/io/sol_ppt.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * This file and its contents are supplied under the terms of the
- * Common Development and Distribution License ("CDDL"), version 1.0.
- * You may only use this file in accordance with the terms of version
- * 1.0 of the CDDL.
- *
- * A full copy of the text of the CDDL should have accompanied this
- * source. A copy of the CDDL is also available via the Internet at
- * http://www.illumos.org/license/CDDL.
- */
-
-/*
- * Copyright 2017 Joyent, Inc.
- */
-
-#include <sys/types.h>
-#include <sys/errno.h>
-#include <sys/cmn_err.h>
-
-#include <sys/vmm.h>
-
-/*
- * PCI Pass-Through Stub
- *
- * Until proper passthrough support can be wired into bhyve, stub out all the
- * functions to either fail.
- */
-
-int
-ppt_unassign_all(struct vm *vm)
-{
- return (0);
-}
-
-/*ARGSUSED*/
-int
-ppt_map_mmio(struct vm *vm, int bus, int slot, int func, vm_paddr_t gpa,
- size_t len, vm_paddr_t hpa)
-{
- return (ENXIO);
-}
-
-/*ARGSUSED*/
-int
-ppt_setup_msi(struct vm *vm, int vcpu, int bus, int slot, int func,
- uint64_t addr, uint64_t msg, int numvec)
-{
- return (ENXIO);
-}
-
-/*ARGSUSED*/
-int
-ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func, int idx,
- uint64_t addr, uint64_t msg, uint32_t vector_control)
-{
- return (ENXIO);
-}
-
-/*ARGSUSED*/
-int
-ppt_assigned_devices(struct vm *vm)
-{
- return (0);
-}
-
-/*ARGSUSED*/
-boolean_t
-ppt_is_mmio(struct vm *vm, vm_paddr_t gpa)
-{
- return (B_FALSE);
-}
-
-/*ARGSUSED*/
-int
-ppt_avail_devices(void)
-{
- return (0);
-}
-
-/*ARGSUSED*/
-int
-ppt_assign_device(struct vm *vm, int bus, int slot, int func)
-{
- return (ENOENT);
-}
-
-/*ARGSUSED*/
-int
-ppt_unassign_device(struct vm *vm, int bus, int slot, int func)
-{
- return (ENXIO);
-}
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
index 77e547e564..2e3d15222d 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
@@ -31,6 +31,7 @@
#include <vm/vm.h>
#include <vm/seg_dev.h>
+#include "io/ppt.h"
#include "io/vatpic.h"
#include "io/vioapic.h"
#include "io/vrtc.h"
@@ -584,48 +585,60 @@ vmmdev_do_ioctl(vmm_softc_t *sc, int cmd, intptr_t arg, int md,
break;
}
- /* XXXJOY: punt on these for now */
case VM_PPTDEV_MSI: {
struct vm_pptdev_msi pptmsi;
-
if (ddi_copyin(datap, &pptmsi, sizeof (pptmsi), md)) {
error = EFAULT;
break;
}
- return (ENOTTY);
+ error = ppt_setup_msi(sc->vmm_vm, pptmsi.vcpu, pptmsi.bus,
+ pptmsi.slot, pptmsi.func, pptmsi.addr, pptmsi.msg,
+ pptmsi.numvec);
+ break;
}
case VM_PPTDEV_MSIX: {
struct vm_pptdev_msix pptmsix;
-
if (ddi_copyin(datap, &pptmsix, sizeof (pptmsix), md)) {
error = EFAULT;
break;
}
- return (ENOTTY);
+ error = ppt_setup_msix(sc->vmm_vm, pptmsix.vcpu, pptmsix.bus,
+ pptmsix.slot, pptmsix.func, pptmsix.idx, pptmsix.addr,
+ pptmsix.msg, pptmsix.vector_control);
+ break;
}
case VM_MAP_PPTDEV_MMIO: {
struct vm_pptdev_mmio pptmmio;
-
if (ddi_copyin(datap, &pptmmio, sizeof (pptmmio), md)) {
error = EFAULT;
break;
}
- return (ENOTTY);
+ error = ppt_map_mmio(sc->vmm_vm, pptmmio.bus, pptmmio.slot,
+ pptmmio.func, pptmmio.gpa, pptmmio.len, pptmmio.hpa);
+ break;
+ }
+ case VM_BIND_PPTDEV: {
+ struct vm_pptdev pptdev;
+ if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
+ error = EFAULT;
+ break;
+ }
+ error = vm_assign_pptdev(sc->vmm_vm, pptdev.bus, pptdev.slot,
+ pptdev.func);
+ break;
}
- case VM_BIND_PPTDEV:
case VM_UNBIND_PPTDEV: {
struct vm_pptdev pptdev;
-
if (ddi_copyin(datap, &pptdev, sizeof (pptdev), md)) {
error = EFAULT;
break;
}
- return (ENOTTY);
+ error = vm_unassign_pptdev(sc->vmm_vm, pptdev.bus, pptdev.slot,
+ pptdev.func);
+ break;
}
-
case VM_INJECT_EXCEPTION: {
struct vm_exception vmexc;
-
if (ddi_copyin(datap, &vmexc, sizeof (vmexc), md)) {
error = EFAULT;
break;
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c
index 4c33909d16..8ade66e819 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_glue.c
@@ -76,9 +76,12 @@
#include <sys/psm_defs.h>
#include <sys/smp_impldefs.h>
+#include <sys/x86_archext.h>
+
#include <machine/cpufunc.h>
#include <machine/fpu.h>
#include <machine/md_var.h>
+#include <machine/pmap.h>
#include <machine/specialreg.h>
#include <machine/vmm.h>
#include <sys/vmm_impl.h>
@@ -100,6 +103,18 @@ u_char const bin2bcd_data[] = {
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
};
+void
+pmap_invalidate_cache(void)
+{
+ cpuset_t cpuset;
+
+ kpreempt_disable();
+ cpuset_all_but(&cpuset, CPU->cpu_id);
+ xc_call(NULL, NULL, NULL, CPUSET2BV(cpuset), (xc_func_t)invalidate_cache);
+ invalidate_cache();
+ kpreempt_enable();
+}
+
vm_paddr_t
pmap_kextract(vm_offset_t va)
{
diff --git a/usr/src/uts/i86pc/ppt/Makefile b/usr/src/uts/i86pc/ppt/Makefile
new file mode 100644
index 0000000000..3d4de2a8f9
--- /dev/null
+++ b/usr/src/uts/i86pc/ppt/Makefile
@@ -0,0 +1,75 @@
+#
+# COPYRIGHT 2013 Pluribus Networks Inc.
+#
+# All rights reserved. This copyright notice is Copyright Management
+# Information under 17 USC 1202 and is included to protect this work and
+# deter copyright infringement. Removal or alteration of this Copyright
+# Management Information without the express written permission from
+# Pluribus Networks Inc is prohibited, and any such unauthorized removal
+# or alteration will be a violation of federal law.
+
+#
+# Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE = ppt
+OBJECTS = $(PPT_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(PPT_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(USR_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/i86pc/io/vmm/io
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# Overrides and additions
+#
+ALL_BUILDS = $(ALL_BUILDSONLY64)
+DEF_BUILDS = $(DEF_BUILDSONLY64)
+PRE_INC_PATH = -I$(COMPAT)/freebsd -I$(COMPAT)/freebsd/amd64 \
+ -I$(CONTRIB)/freebsd -I$(CONTRIB)/freebsd/amd64
+INC_PATH += -I$(UTSBASE)/i86pc/io/vmm -I$(UTSBASE)/i86pc/io/vmm/io
+AS_INC_PATH += -I$(UTSBASE)/i86pc/io/vmm -I$(OBJS_DIR)
+
+LDFLAGS += -dy -N drv/vmm -N misc/pcie
+
+$(OBJS_DIR)/ppt.o := CERRWARN += -_gcc=-Wno-unused-variable
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+lint: $(LINT_DEPS)
+
+modlintlib: $(MODLINTLIB_DEPS)
+
+clean.lint: $(CLEAN_LINT_DEPS)
+
+install: $(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/i86pc/Makefile.targ
diff --git a/usr/src/uts/i86pc/vmm/Makefile b/usr/src/uts/i86pc/vmm/Makefile
index 603821d008..368f32ddb6 100644
--- a/usr/src/uts/i86pc/vmm/Makefile
+++ b/usr/src/uts/i86pc/vmm/Makefile
@@ -88,6 +88,10 @@ CFLAGS += -_gcc=-Wno-format
$(OBJS_DIR)/vmm.o := CERRWARN += -_gcc=-Wno-pointer-sign -_gcc=-Wno-type-limits
$(OBJS_DIR)/svm.o := CERRWARN += -_gcc=-Wno-pointer-sign -_gcc=-Wno-type-limits
+$(OBJS_DIR)/vmx.o := CERRWARN += -_gcc=-Wno-unused-variable
+$(OBJS_DIR)/iommu.o := CERRWARN += -_gcc=-Wno-unused-variable
+
+LDFLAGS += -dy -N misc/acpica -N misc/pcie
OFFSETS_VMX = $(CONF_SRCDIR)/intel/offsets.in
OFFSETS_SVM = $(CONF_SRCDIR)/amd/offsets.in
diff --git a/usr/src/uts/intel/ia32/ml/modstubs.s b/usr/src/uts/intel/ia32/ml/modstubs.s
index f2bc9b9a8a..764816e8b8 100644
--- a/usr/src/uts/intel/ia32/ml/modstubs.s
+++ b/usr/src/uts/intel/ia32/ml/modstubs.s
@@ -1429,6 +1429,23 @@ fcnname/**/_info: \
END_MODULE(apix);
#endif
+/*
+ * Stubs for ppt module (bhyve PCI passthrough driver)
+ */
+#ifndef PPT_MODULE
+ MODULE(ppt,drv);
+ WSTUB(ppt, ppt_unassign_all, nomod_zero);
+ WSTUB(ppt, ppt_map_mmio, nomod_einval);
+ WSTUB(ppt, ppt_setup_msi, nomod_einval);
+ WSTUB(ppt, ppt_setup_msix, nomod_einval);
+ WSTUB(ppt, ppt_assigned_devices, nomod_zero);
+ WSTUB(ppt, ppt_is_mmio, nomod_zero);
+ WSTUB(ppt, ppt_avail_devices, nomod_zero);
+ WSTUB(ppt, ppt_assign_device, nomod_einval);
+ WSTUB(ppt, ppt_unassign_device, nomod_einval);
+ END_MODULE(ppt);
+#endif
+
/ this is just a marker for the area of text that contains stubs
ENTRY_NP(stubs_end)