From 81de6f5cc49043ac5e2135ad996dfb05f2bd2a32 Mon Sep 17 00:00:00 2001 From: neel Date: Fri, 1 Feb 2013 03:49:09 +0000 Subject: Fix a broken assumption in the passthru implementation that the MSI-X table can only be located at the beginning or the end of the BAR. If the MSI-table is located in the middle of a BAR then we will split the BAR into two and create two mappings - one before the table and one after the table - leaving a hole in place of the table so accesses to it can be trapped and emulated. Obtained from: NetApp --- usr.sbin/bhyve/pci_passthru.c | 60 ++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 23 deletions(-) (limited to 'usr.sbin/bhyve/pci_passthru.c') diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c index 131f08a..08a9a58 100644 --- a/usr.sbin/bhyve/pci_passthru.c +++ b/usr.sbin/bhyve/pci_passthru.c @@ -355,14 +355,18 @@ msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc, static int init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) { - int idx; - size_t table_size; + int b, s, f; + int error, idx; + size_t len, remaining, table_size; vm_paddr_t start; - size_t len; struct pci_devinst *pi = sc->psc_pi; assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0); + b = sc->psc_sel.pc_bus; + s = sc->psc_sel.pc_dev; + f = sc->psc_sel.pc_func; + /* * If the MSI-X table BAR maps memory intended for * other uses, it is at least assured that the table @@ -372,34 +376,44 @@ init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar && ((pi->pi_msix.pba_offset - pi->pi_msix.table_offset) < 4096)) { /* Need to also emulate the PBA, not supported yet */ - printf("Unsupported MSI-X configuration: %d/%d/%d\n", - sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, - sc->psc_sel.pc_func); + printf("Unsupported MSI-X configuration: %d/%d/%d\n", b, s, f); return (-1); } - /* - * May need to split the BAR into 3 regions: - * Before the MSI-X table, the MSI-X table, and after it - * XXX for now, assume that the table is not in the middle - */ + /* Compute the MSI-X table size */ table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; + table_size = roundup2(table_size, 4096); + idx = pi->pi_msix.table_bar; + start = pi->pi_bar[idx].addr; + remaining = pi->pi_bar[idx].size; - /* Round up to page size */ - table_size = roundup2(table_size, 4096); - if (pi->pi_msix.table_offset == 0) { - /* Map everything after the MSI-X table */ - start = pi->pi_bar[idx].addr + table_size; - len = pi->pi_bar[idx].size - table_size; - } else { - /* Map everything before the MSI-X table */ - start = pi->pi_bar[idx].addr; + /* Map everything before the MSI-X table */ + if (pi->pi_msix.table_offset > 0) { len = pi->pi_msix.table_offset; + error = vm_map_pptdev_mmio(ctx, b, s, f, start, len, base); + if (error) + return (error); + + base += len; + start += len; + remaining -= len; } - return (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, - sc->psc_sel.pc_dev, sc->psc_sel.pc_func, - start, len, base + table_size)); + + /* 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); } static int -- cgit v1.1