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
This commit is contained in:
parent
aa12663f49
commit
2b89a04496
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246191
@ -56,9 +56,18 @@ __FBSDID("$FreeBSD$");
|
||||
/* XXX locking */
|
||||
|
||||
#define MAX_PPTDEVS (sizeof(pptdevs) / sizeof(pptdevs[0]))
|
||||
#define MAX_MMIOSEGS (PCIR_MAX_BAR_0 + 1)
|
||||
#define MAX_MSIMSGS 32
|
||||
|
||||
/*
|
||||
* If the MSI-X table is located in the middle of a BAR then that MMIO
|
||||
* region gets split into two segments - one segment above the MSI-X table
|
||||
* and the other segment below the MSI-X table - with a hole in place of
|
||||
* the MSI-X table so accesses to it can be trapped and emulated.
|
||||
*
|
||||
* So, allocate a MMIO segment for each BAR register + 1 additional segment.
|
||||
*/
|
||||
#define MAX_MMIOSEGS ((PCIR_MAX_BAR_0 + 1) + 1)
|
||||
|
||||
MALLOC_DEFINE(M_PPTMSIX, "pptmsix", "Passthru MSI-X resources");
|
||||
|
||||
struct pptintr_arg { /* pptintr(pptintr_arg) */
|
||||
|
@ -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;
|
||||
idx = pi->pi_msix.table_bar;
|
||||
|
||||
/* 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;
|
||||
|
||||
idx = pi->pi_msix.table_bar;
|
||||
start = pi->pi_bar[idx].addr;
|
||||
remaining = pi->pi_bar[idx].size;
|
||||
|
||||
/* 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
|
||||
|
Loading…
Reference in New Issue
Block a user