Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_passthru.c
Show First 20 Lines • Show All 321 Lines • ▼ Show 20 Lines | case 8: | ||||
data = *src64; | data = *src64; | ||||
break; | break; | ||||
default: | default: | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (data); | return (data); | ||||
} | } | ||||
/* Should make this an assert. */ | |||||
if (offset < pi->pi_msix.table_offset) | if (offset < pi->pi_msix.table_offset) | ||||
return (-1); | return (-1); | ||||
offset -= pi->pi_msix.table_offset; | offset -= pi->pi_msix.table_offset; | ||||
index = offset / MSIX_TABLE_ENTRY_SIZE; | index = offset / MSIX_TABLE_ENTRY_SIZE; | ||||
if (index >= pi->pi_msix.table_count) | if (index >= pi->pi_msix.table_count) | ||||
return (-1); | goto readbar; | ||||
entry = &pi->pi_msix.table[index]; | entry = &pi->pi_msix.table[index]; | ||||
entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; | entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; | ||||
switch(size) { | switch(size) { | ||||
case 1: | case 1: | ||||
src8 = (uint8_t *)((void *)entry + entry_offset); | src8 = (uint8_t *)((void *)entry + entry_offset); | ||||
data = *src8; | data = *src8; | ||||
Show All 10 Lines | case 8: | ||||
src64 = (uint64_t *)((void *)entry + entry_offset); | src64 = (uint64_t *)((void *)entry + entry_offset); | ||||
data = *src64; | data = *src64; | ||||
break; | break; | ||||
default: | default: | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (data); | return (data); | ||||
readbar: | |||||
if (pi->pi_msix.table_page != NULL && offset < 4096) { | |||||
switch(size) { | |||||
case 1: | |||||
src8 = (uint8_t *)(pi->pi_msix.table_page + offset); | |||||
data = *src8; | |||||
break; | |||||
case 2: | |||||
src16 = (uint16_t *)(pi->pi_msix.table_page + offset); | |||||
data = *src16; | |||||
break; | |||||
case 4: | |||||
src32 = (uint32_t *)(pi->pi_msix.table_page + offset); | |||||
data = *src32; | |||||
break; | |||||
case 8: | |||||
src64 = (uint64_t *)(pi->pi_msix.table_page + offset); | |||||
data = *src64; | |||||
break; | |||||
default: | |||||
return (-1); | |||||
} | } | ||||
return (data); | |||||
} | |||||
return (-1); | |||||
} | |||||
static void | static void | ||||
msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc, | msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc, | ||||
uint64_t offset, int size, uint64_t data) | uint64_t offset, int size, uint64_t data) | ||||
{ | { | ||||
struct pci_devinst *pi; | struct pci_devinst *pi; | ||||
struct msix_table_entry *entry; | struct msix_table_entry *entry; | ||||
uint8_t *dest8; | uint8_t *dest8; | ||||
uint16_t *dest16; | uint16_t *dest16; | ||||
Show All 28 Lines | case 8: | ||||
*dest64 = data; | *dest64 = data; | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
/* Should make this an assert. */ | |||||
if (offset < pi->pi_msix.table_offset) | if (offset < pi->pi_msix.table_offset) | ||||
return; | return; | ||||
offset -= pi->pi_msix.table_offset; | offset -= pi->pi_msix.table_offset; | ||||
index = offset / MSIX_TABLE_ENTRY_SIZE; | index = offset / MSIX_TABLE_ENTRY_SIZE; | ||||
if (index >= pi->pi_msix.table_count) | if (index >= pi->pi_msix.table_count) | ||||
return; | goto writebar; | ||||
entry = &pi->pi_msix.table[index]; | entry = &pi->pi_msix.table[index]; | ||||
entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; | entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; | ||||
/* Only 4 byte naturally-aligned writes are supported */ | /* Only 4 byte naturally-aligned writes are supported */ | ||||
assert(size == 4); | assert(size == 4); | ||||
assert(entry_offset % 4 == 0); | assert(entry_offset % 4 == 0); | ||||
vector_control = entry->vector_control; | vector_control = entry->vector_control; | ||||
dest32 = (uint32_t *)((void *)entry + entry_offset); | dest32 = (uint32_t *)((void *)entry + entry_offset); | ||||
*dest32 = data; | *dest32 = data; | ||||
/* If MSI-X hasn't been enabled, do nothing */ | /* If MSI-X hasn't been enabled, do nothing */ | ||||
if (pi->pi_msix.enabled) { | if (pi->pi_msix.enabled) { | ||||
/* If the entry is masked, don't set it up */ | /* If the entry is masked, don't set it up */ | ||||
if ((entry->vector_control & PCIM_MSIX_VCTRL_MASK) == 0 || | if ((entry->vector_control & PCIM_MSIX_VCTRL_MASK) == 0 || | ||||
(vector_control & PCIM_MSIX_VCTRL_MASK) == 0) { | (vector_control & PCIM_MSIX_VCTRL_MASK) == 0) { | ||||
(void)vm_setup_pptdev_msix(ctx, vcpu, | (void)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, index, entry->addr, | sc->psc_sel.pc_func, index, entry->addr, | ||||
entry->msg_data, entry->vector_control); | entry->msg_data, entry->vector_control); | ||||
} | } | ||||
} | } | ||||
writebar: | |||||
if (pi->pi_msix.table_page != NULL && offset < 4096) { | |||||
switch(size) { | |||||
case 1: | |||||
dest8 = (uint8_t *)(pi->pi_msix.table_page + offset); | |||||
*dest8 = data; | |||||
break; | |||||
case 2: | |||||
dest16 = (uint16_t *)(pi->pi_msix.table_page + offset); | |||||
*dest16 = data; | |||||
break; | |||||
case 4: | |||||
dest32 = (uint32_t *)(pi->pi_msix.table_page + offset); | |||||
*dest32 = data; | |||||
break; | |||||
case 8: | |||||
dest64 = (uint64_t *)(pi->pi_msix.table_page + offset); | |||||
*dest64 = data; | |||||
break; | |||||
default: | |||||
break; | |||||
} | } | ||||
return; | |||||
} | |||||
} | |||||
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 idx; | int idx; | ||||
size_t remaining; | size_t remaining; | ||||
uint32_t table_size, table_offset; | uint32_t table_size, table_offset; | ||||
Show All 17 Lines | init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) | ||||
table_size = pi->pi_msix.table_offset - table_offset; | table_size = pi->pi_msix.table_offset - table_offset; | ||||
table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; | table_size += pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; | ||||
table_size = roundup2(table_size, 4096); | table_size = roundup2(table_size, 4096); | ||||
idx = pi->pi_msix.table_bar; | idx = pi->pi_msix.table_bar; | ||||
start = pi->pi_bar[idx].addr; | start = pi->pi_bar[idx].addr; | ||||
remaining = pi->pi_bar[idx].size; | remaining = pi->pi_bar[idx].size; | ||||
/* | |||||
* Some device (against better documentation of the spec) | |||||
* are mapping other usable address space into the same page | |||||
* as the end of the MSI-X tables. | |||||
* At least Intel AX200 being one of them apparently. | |||||
* Map the page and fall back to it for any reads/writes outside | |||||
* the MSI-X table in msix_table_{read,write}. | |||||
*/ | |||||
pi->pi_msix.table_page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, | |||||
MAP_SHARED, memfd, sc->psc_bar[idx].addr + table_offset); | |||||
if (pi->pi_msix.table_page == MAP_FAILED) { | |||||
warn("Failed to map table page for MSI-X on %d/%d/%d", b, s, f); | |||||
return (-1); | |||||
} | |||||
if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar) { | if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar) { | ||||
pba_offset = pi->pi_msix.pba_offset; | pba_offset = pi->pi_msix.pba_offset; | ||||
pba_size = pi->pi_msix.pba_size; | pba_size = pi->pi_msix.pba_size; | ||||
if (pba_offset >= table_offset + table_size || | if (pba_offset >= table_offset + table_size || | ||||
table_offset >= pba_offset + pba_size) { | table_offset >= pba_offset + pba_size) { | ||||
/* | /* | ||||
* If the PBA does not share a page with the MSI-x | * If the PBA does not share a page with the MSI-x | ||||
▲ Show 20 Lines • Show All 576 Lines • Show Last 20 Lines |