Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_passthru.c
Show First 20 Lines • Show All 432 Lines • ▼ Show 20 Lines | if (pi->pi_msix.enabled) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) | init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) | ||||
{ | { | ||||
int b, s, f; | int b, s, f; | ||||
int error, idx; | int idx; | ||||
size_t len, remaining; | size_t remaining; | ||||
uint32_t table_size, table_offset; | uint32_t table_size, table_offset; | ||||
uint32_t pba_size, pba_offset; | uint32_t pba_size, pba_offset; | ||||
vm_paddr_t start; | vm_paddr_t start; | ||||
struct pci_devinst *pi = sc->psc_pi; | struct pci_devinst *pi = sc->psc_pi; | ||||
assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0); | assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0); | ||||
b = sc->psc_sel.pc_bus; | b = sc->psc_sel.pc_bus; | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (pba_offset >= table_offset + table_size || | ||||
warn( | warn( | ||||
"Failed to map PBA page for MSI-X on %d/%d/%d", | "Failed to map PBA page for MSI-X on %d/%d/%d", | ||||
b, s, f); | b, s, f); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* Map everything before the MSI-X table */ | |||||
if (table_offset > 0) { | |||||
len = table_offset; | |||||
error = vm_map_pptdev_mmio(ctx, b, s, f, start, len, base); | |||||
if (error) | |||||
return (error); | |||||
base += len; | |||||
start += len; | |||||
remaining -= len; | |||||
} | |||||
/* Skip the MSI-X table */ | |||||
base += table_size; | |||||
start += table_size; | |||||
remaining -= table_size; | |||||
/* Map everything beyond the end of the MSI-X table */ | |||||
if (remaining > 0) { | |||||
len = remaining; | |||||
error = vm_map_pptdev_mmio(ctx, b, s, f, start, len, base); | |||||
if (error) | |||||
return (error); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
cfginitbar(struct vmctx *ctx, struct passthru_softc *sc) | cfginitbar(struct vmctx *ctx, struct passthru_softc *sc) | ||||
{ | { | ||||
int i, error; | int i, error; | ||||
struct pci_devinst *pi; | struct pci_devinst *pi; | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | for (i = 0; i <= PCI_BARMAX; i++) { | ||||
if (error) | if (error) | ||||
return (-1); | return (-1); | ||||
/* The MSI-X table needs special handling */ | /* The MSI-X table needs special handling */ | ||||
if (i == pci_msix_table_bar(pi)) { | if (i == pci_msix_table_bar(pi)) { | ||||
error = init_msix_table(ctx, sc, base); | error = init_msix_table(ctx, sc, base); | ||||
if (error) | if (error) | ||||
return (-1); | return (-1); | ||||
} else if (bartype != PCIBAR_IO) { | |||||
/* Map the physical BAR in the guest MMIO space */ | |||||
error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, | |||||
sc->psc_sel.pc_dev, sc->psc_sel.pc_func, | |||||
pi->pi_bar[i].addr, pi->pi_bar[i].size, base); | |||||
if (error) | |||||
return (-1); | |||||
} | } | ||||
/* | /* | ||||
* 64-bit BAR takes up two slots so skip the next one. | * 64-bit BAR takes up two slots so skip the next one. | ||||
*/ | */ | ||||
if (bartype == PCIBAR_MEM64) { | if (bartype == PCIBAR_MEM64) { | ||||
i++; | i++; | ||||
assert(i <= PCI_BARMAX); | assert(i <= PCI_BARMAX); | ||||
▲ Show 20 Lines • Show All 339 Lines • ▼ Show 20 Lines | if (baridx == pci_msix_table_bar(pi)) { | ||||
(void)ioctl(iofd, IODEV_PIO, &pio); | (void)ioctl(iofd, IODEV_PIO, &pio); | ||||
val = pio.val; | val = pio.val; | ||||
} | } | ||||
return (val); | return (val); | ||||
} | } | ||||
static void | |||||
passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, | |||||
int enabled, uint64_t address) | |||||
{ | |||||
struct passthru_softc *sc; | |||||
size_t remaining; | |||||
uint32_t table_size, table_offset; | |||||
sc = pi->pi_arg; | |||||
table_offset = rounddown2(pi->pi_msix.table_offset, 4096); | |||||
if (table_offset > 0) { | |||||
if (!enabled) { | |||||
if (vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus, | |||||
sc->psc_sel.pc_dev, | |||||
sc->psc_sel.pc_func, address, | |||||
table_offset) != 0) | |||||
warnx("pci_passthru: unmap_pptdev_mmio failed"); | |||||
} else { | |||||
if (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, | |||||
sc->psc_sel.pc_dev, | |||||
sc->psc_sel.pc_func, address, | |||||
table_offset, | |||||
sc->psc_bar[baridx].addr) != 0) | |||||
warnx("pci_passthru: map_pptdev_mmio failed"); | |||||
} | |||||
} | |||||
table_size = pi->pi_msix.table_offset - table_offset; | |||||
table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; | |||||
table_size = roundup2(table_size, 4096); | |||||
remaining = pi->pi_bar[baridx].size - table_offset - table_size; | |||||
if (remaining > 0) { | |||||
address += table_offset + table_size; | |||||
if (!enabled) { | |||||
if (vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus, | |||||
sc->psc_sel.pc_dev, | |||||
sc->psc_sel.pc_func, address, | |||||
remaining) != 0) | |||||
warnx("pci_passthru: unmap_pptdev_mmio failed"); | |||||
} else { | |||||
if (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, | |||||
sc->psc_sel.pc_dev, | |||||
sc->psc_sel.pc_func, address, | |||||
remaining, | |||||
sc->psc_bar[baridx].addr + | |||||
table_offset + table_size) != 0) | |||||
warnx("pci_passthru: map_pptdev_mmio failed"); | |||||
} | |||||
} | |||||
} | |||||
static void | |||||
passthru_mmio_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, | |||||
int enabled, uint64_t address) | |||||
{ | |||||
struct passthru_softc *sc; | |||||
sc = pi->pi_arg; | |||||
if (!enabled) { | |||||
if (vm_unmap_pptdev_mmio(ctx, sc->psc_sel.pc_bus, | |||||
sc->psc_sel.pc_dev, | |||||
sc->psc_sel.pc_func, address, | |||||
sc->psc_bar[baridx].size) != 0) | |||||
warnx("pci_passthru: unmap_pptdev_mmio failed"); | |||||
} else { | |||||
if (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, | |||||
sc->psc_sel.pc_dev, | |||||
sc->psc_sel.pc_func, address, | |||||
sc->psc_bar[baridx].size, | |||||
sc->psc_bar[baridx].addr) != 0) | |||||
warnx("pci_passthru: map_pptdev_mmio failed"); | |||||
} | |||||
} | |||||
static void | |||||
passthru_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, | |||||
int enabled, uint64_t address) | |||||
{ | |||||
if (pi->pi_bar[baridx].type == PCIBAR_IO) | |||||
return; | |||||
if (baridx == pci_msix_table_bar(pi)) | |||||
passthru_msix_addr(ctx, pi, baridx, enabled, address); | |||||
else | |||||
passthru_mmio_addr(ctx, pi, baridx, enabled, address); | |||||
} | |||||
struct pci_devemu passthru = { | struct pci_devemu passthru = { | ||||
.pe_emu = "passthru", | .pe_emu = "passthru", | ||||
.pe_init = passthru_init, | .pe_init = passthru_init, | ||||
.pe_cfgwrite = passthru_cfgwrite, | .pe_cfgwrite = passthru_cfgwrite, | ||||
.pe_cfgread = passthru_cfgread, | .pe_cfgread = passthru_cfgread, | ||||
.pe_barwrite = passthru_write, | .pe_barwrite = passthru_write, | ||||
.pe_barread = passthru_read, | .pe_barread = passthru_read, | ||||
.pe_baraddr = passthru_addr, | |||||
}; | }; | ||||
PCI_EMUL_SET(passthru); | PCI_EMUL_SET(passthru); |