Changeset View
Changeset View
Standalone View
Standalone View
head/usr.sbin/bhyve/pci_passthru.c
Show All 37 Lines | |||||
#include <dev/io/iodev.h> | #include <dev/io/iodev.h> | ||||
#include <dev/pci/pcireg.h> | #include <dev/pci/pcireg.h> | ||||
#include <machine/iodev.h> | #include <machine/iodev.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <errno.h> | #include <err.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <vmmapi.h> | #include <vmmapi.h> | ||||
#include "pci_emul.h" | #include "pci_emul.h" | ||||
#include "mem.h" | #include "mem.h" | ||||
▲ Show 20 Lines • Show All 423 Lines • ▼ Show 20 Lines | if (pba_offset >= table_offset + table_size || | ||||
pi->pi_msix.pba_page_offset = table_offset; | pi->pi_msix.pba_page_offset = table_offset; | ||||
else | else | ||||
pi->pi_msix.pba_page_offset = table_offset + | pi->pi_msix.pba_page_offset = table_offset + | ||||
table_size - 4096; | table_size - 4096; | ||||
pi->pi_msix.pba_page = mmap(NULL, 4096, PROT_READ | | pi->pi_msix.pba_page = mmap(NULL, 4096, PROT_READ | | ||||
PROT_WRITE, MAP_SHARED, memfd, start + | PROT_WRITE, MAP_SHARED, memfd, start + | ||||
pi->pi_msix.pba_page_offset); | pi->pi_msix.pba_page_offset); | ||||
if (pi->pi_msix.pba_page == MAP_FAILED) { | if (pi->pi_msix.pba_page == MAP_FAILED) { | ||||
printf( | warn( | ||||
"Failed to map PBA page for MSI-X on %d/%d/%d: %s\n", | "Failed to map PBA page for MSI-X on %d/%d/%d", | ||||
b, s, f, strerror(errno)); | b, s, f); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* Map everything before the MSI-X table */ | /* Map everything before the MSI-X table */ | ||||
if (table_offset > 0) { | if (table_offset > 0) { | ||||
len = table_offset; | len = table_offset; | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (PCI_BAR_IO(bar.pbi_base)) { | ||||
break; | break; | ||||
} | } | ||||
base = bar.pbi_base & PCIM_BAR_MEM_BASE; | base = bar.pbi_base & PCIM_BAR_MEM_BASE; | ||||
} | } | ||||
size = bar.pbi_length; | size = bar.pbi_length; | ||||
if (bartype != PCIBAR_IO) { | if (bartype != PCIBAR_IO) { | ||||
if (((base | size) & PAGE_MASK) != 0) { | if (((base | size) & PAGE_MASK) != 0) { | ||||
printf("passthru device %d/%d/%d BAR %d: " | warnx("passthru device %d/%d/%d BAR %d: " | ||||
"base %#lx or size %#lx not page aligned\n", | "base %#lx or size %#lx not page aligned\n", | ||||
sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, | sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, | ||||
sc->psc_sel.pc_func, i, base, size); | sc->psc_sel.pc_func, i, base, size); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
/* Cache information about the "real" BAR */ | /* Cache information about the "real" BAR */ | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | cfginit(struct vmctx *ctx, struct pci_devinst *pi, int bus, int slot, int func) | ||||
error = 1; | error = 1; | ||||
sc = pi->pi_arg; | sc = pi->pi_arg; | ||||
bzero(&sc->psc_sel, sizeof(struct pcisel)); | bzero(&sc->psc_sel, sizeof(struct pcisel)); | ||||
sc->psc_sel.pc_bus = bus; | sc->psc_sel.pc_bus = bus; | ||||
sc->psc_sel.pc_dev = slot; | sc->psc_sel.pc_dev = slot; | ||||
sc->psc_sel.pc_func = func; | sc->psc_sel.pc_func = func; | ||||
if (cfginitmsi(sc) != 0) | if (cfginitmsi(sc) != 0) { | ||||
warnx("failed to initialize MSI for PCI %d/%d/%d", | |||||
bus, slot, func); | |||||
goto done; | goto done; | ||||
} | |||||
if (cfginitbar(ctx, sc) != 0) | if (cfginitbar(ctx, sc) != 0) { | ||||
warnx("failed to initialize BARs for PCI %d/%d/%d", | |||||
bus, slot, func); | |||||
goto done; | goto done; | ||||
} | |||||
error = 0; /* success */ | error = 0; /* success */ | ||||
done: | done: | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) | passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) | ||||
{ | { | ||||
int bus, slot, func, error, memflags; | int bus, slot, func, error, memflags; | ||||
struct passthru_softc *sc; | struct passthru_softc *sc; | ||||
sc = NULL; | sc = NULL; | ||||
error = 1; | error = 1; | ||||
memflags = vm_get_memflags(ctx); | memflags = vm_get_memflags(ctx); | ||||
if (!(memflags & VM_MEM_F_WIRED)) { | if (!(memflags & VM_MEM_F_WIRED)) { | ||||
fprintf(stderr, "passthru requires guest memory to be wired\n"); | warnx("passthru requires guest memory to be wired"); | ||||
goto done; | goto done; | ||||
} | } | ||||
if (pcifd < 0) { | if (pcifd < 0) { | ||||
pcifd = open(_PATH_DEVPCI, O_RDWR, 0); | pcifd = open(_PATH_DEVPCI, O_RDWR, 0); | ||||
if (pcifd < 0) | if (pcifd < 0) { | ||||
warn("failed to open %s", _PATH_DEVPCI); | |||||
goto done; | goto done; | ||||
} | } | ||||
} | |||||
if (iofd < 0) { | if (iofd < 0) { | ||||
iofd = open(_PATH_DEVIO, O_RDWR, 0); | iofd = open(_PATH_DEVIO, O_RDWR, 0); | ||||
if (iofd < 0) | if (iofd < 0) { | ||||
warn("failed to open %s", _PATH_DEVIO); | |||||
goto done; | goto done; | ||||
} | } | ||||
} | |||||
if (memfd < 0) { | if (memfd < 0) { | ||||
memfd = open(_PATH_MEM, O_RDWR, 0); | memfd = open(_PATH_MEM, O_RDWR, 0); | ||||
if (memfd < 0) | if (memfd < 0) { | ||||
warn("failed to open %s", _PATH_MEM); | |||||
goto done; | goto done; | ||||
} | } | ||||
} | |||||
if (opts == NULL || | if (opts == NULL || | ||||
sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3) | sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3) { | ||||
warnx("invalid passthru options"); | |||||
goto done; | goto done; | ||||
} | |||||
if (vm_assign_pptdev(ctx, bus, slot, func) != 0) | if (vm_assign_pptdev(ctx, bus, slot, func) != 0) { | ||||
warnx("PCI device at %d/%d/%d is not using the ppt(4) driver", | |||||
bus, slot, func); | |||||
goto done; | goto done; | ||||
} | |||||
sc = calloc(1, sizeof(struct passthru_softc)); | sc = calloc(1, sizeof(struct passthru_softc)); | ||||
pi->pi_arg = sc; | pi->pi_arg = sc; | ||||
sc->psc_pi = pi; | sc->psc_pi = pi; | ||||
/* initialize config space */ | /* initialize config space */ | ||||
if ((error = cfginit(ctx, pi, bus, slot, func)) != 0) | if ((error = cfginit(ctx, pi, bus, slot, func)) != 0) | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, | ||||
*/ | */ | ||||
if (msicap_access(sc, coff)) { | if (msicap_access(sc, coff)) { | ||||
msicap_cfgwrite(pi, sc->psc_msi.capoff, coff, bytes, val); | msicap_cfgwrite(pi, sc->psc_msi.capoff, coff, bytes, val); | ||||
error = vm_setup_pptdev_msi(ctx, vcpu, sc->psc_sel.pc_bus, | error = vm_setup_pptdev_msi(ctx, vcpu, sc->psc_sel.pc_bus, | ||||
sc->psc_sel.pc_dev, sc->psc_sel.pc_func, | sc->psc_sel.pc_dev, sc->psc_sel.pc_func, | ||||
pi->pi_msi.addr, pi->pi_msi.msg_data, | pi->pi_msi.addr, pi->pi_msi.msg_data, | ||||
pi->pi_msi.maxmsgnum); | pi->pi_msi.maxmsgnum); | ||||
if (error != 0) { | if (error != 0) | ||||
printf("vm_setup_pptdev_msi error %d\r\n", errno); | err(1, "vm_setup_pptdev_msi"); | ||||
exit(1); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
if (msixcap_access(sc, coff)) { | if (msixcap_access(sc, coff)) { | ||||
msixcap_cfgwrite(pi, sc->psc_msix.capoff, coff, bytes, val); | msixcap_cfgwrite(pi, sc->psc_msix.capoff, coff, bytes, val); | ||||
if (pi->pi_msix.enabled) { | if (pi->pi_msix.enabled) { | ||||
msix_table_entries = pi->pi_msix.table_count; | msix_table_entries = pi->pi_msix.table_count; | ||||
for (i = 0; i < msix_table_entries; i++) { | for (i = 0; i < msix_table_entries; i++) { | ||||
error = vm_setup_pptdev_msix(ctx, vcpu, | error = vm_setup_pptdev_msix(ctx, vcpu, | ||||
sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, | sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, | ||||
sc->psc_sel.pc_func, i, | sc->psc_sel.pc_func, i, | ||||
pi->pi_msix.table[i].addr, | pi->pi_msix.table[i].addr, | ||||
pi->pi_msix.table[i].msg_data, | pi->pi_msix.table[i].msg_data, | ||||
pi->pi_msix.table[i].vector_control); | pi->pi_msix.table[i].vector_control); | ||||
if (error) { | if (error) | ||||
printf("vm_setup_pptdev_msix error " | err(1, "vm_setup_pptdev_msix"); | ||||
"%d\r\n", errno); | |||||
exit(1); | |||||
} | |||||
} | } | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef LEGACY_SUPPORT | #ifdef LEGACY_SUPPORT | ||||
/* | /* | ||||
* If this device does not support MSI natively then we cannot let | * If this device does not support MSI natively then we cannot let | ||||
▲ Show 20 Lines • Show All 74 Lines • Show Last 20 Lines |