Handle PBA that shares a page with MSI-X table for passthrough devices.
If the PBA shares a page with the MSI-X table, map the shared page via /dev/mem and emulate accesses to the portion of the PBA in the shared page by accessing the mapped page. Reviewed by: grehan MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D5919
This commit is contained in:
parent
4478441145
commit
5c40acf8b5
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=297932
@ -142,6 +142,8 @@ struct pci_devinst {
|
||||
int pba_size;
|
||||
int function_mask;
|
||||
struct msix_table_entry *table; /* allocated at runtime */
|
||||
void *pba_page;
|
||||
int pba_page_offset;
|
||||
} pi_msix;
|
||||
|
||||
void *pi_arg; /* devemu-private data */
|
||||
|
@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/pciio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@ -59,6 +60,10 @@ __FBSDID("$FreeBSD$");
|
||||
#define _PATH_DEVIO "/dev/io"
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_MEM
|
||||
#define _PATH_MEM "/dev/mem"
|
||||
#endif
|
||||
|
||||
#define LEGACY_SUPPORT 1
|
||||
|
||||
#define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
|
||||
@ -66,6 +71,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
static int pcifd = -1;
|
||||
static int iofd = -1;
|
||||
static int memfd = -1;
|
||||
|
||||
struct passthru_softc {
|
||||
struct pci_devinst *psc_pi;
|
||||
@ -279,6 +285,35 @@ msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
|
||||
int index;
|
||||
|
||||
pi = sc->psc_pi;
|
||||
if (offset >= pi->pi_msix.pba_offset &&
|
||||
offset < pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
|
||||
switch(size) {
|
||||
case 1:
|
||||
src8 = (uint8_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
data = *src8;
|
||||
break;
|
||||
case 2:
|
||||
src16 = (uint16_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
data = *src16;
|
||||
break;
|
||||
case 4:
|
||||
src32 = (uint32_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
data = *src32;
|
||||
break;
|
||||
case 8:
|
||||
src64 = (uint64_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
data = *src64;
|
||||
break;
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
|
||||
if (offset < pi->pi_msix.table_offset)
|
||||
return (-1);
|
||||
|
||||
@ -320,12 +355,44 @@ msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc,
|
||||
{
|
||||
struct pci_devinst *pi;
|
||||
struct msix_table_entry *entry;
|
||||
uint32_t *dest;
|
||||
uint8_t *dest8;
|
||||
uint16_t *dest16;
|
||||
uint32_t *dest32;
|
||||
uint64_t *dest64;
|
||||
size_t entry_offset;
|
||||
uint32_t vector_control;
|
||||
int error, index;
|
||||
|
||||
pi = sc->psc_pi;
|
||||
if (offset >= pi->pi_msix.pba_offset &&
|
||||
offset < pi->pi_msix.pba_offset + pi->pi_msix.pba_size) {
|
||||
switch(size) {
|
||||
case 1:
|
||||
dest8 = (uint8_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
*dest8 = data;
|
||||
break;
|
||||
case 2:
|
||||
dest16 = (uint16_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
*dest16 = data;
|
||||
break;
|
||||
case 4:
|
||||
dest32 = (uint32_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
*dest32 = data;
|
||||
break;
|
||||
case 8:
|
||||
dest64 = (uint64_t *)(pi->pi_msix.pba_page + offset -
|
||||
pi->pi_msix.pba_page_offset);
|
||||
*dest64 = data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset < pi->pi_msix.table_offset)
|
||||
return;
|
||||
|
||||
@ -342,8 +409,8 @@ msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc,
|
||||
assert(entry_offset % 4 == 0);
|
||||
|
||||
vector_control = entry->vector_control;
|
||||
dest = (uint32_t *)((void *)entry + entry_offset);
|
||||
*dest = data;
|
||||
dest32 = (uint32_t *)((void *)entry + entry_offset);
|
||||
*dest32 = data;
|
||||
/* If MSI-X hasn't been enabled, do nothing */
|
||||
if (pi->pi_msix.enabled) {
|
||||
/* If the entry is masked, don't set it up */
|
||||
@ -386,28 +453,44 @@ init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base)
|
||||
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;
|
||||
|
||||
if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar) {
|
||||
pba_offset = pi->pi_msix.pba_offset;
|
||||
pba_size = pi->pi_msix.pba_size;
|
||||
if (pba_offset >= table_offset + table_size ||
|
||||
table_offset >= pba_offset + pba_size) {
|
||||
/*
|
||||
* The PBA can reside in the same BAR as the MSI-x
|
||||
* tables as long as it does not overlap with any
|
||||
* naturally aligned page occupied by the tables.
|
||||
* If the PBA does not share a page with the MSI-x
|
||||
* tables, no PBA emulation is required.
|
||||
*/
|
||||
pi->pi_msix.pba_page = NULL;
|
||||
pi->pi_msix.pba_page_offset = 0;
|
||||
} else {
|
||||
/* Need to also emulate the PBA, not supported yet */
|
||||
printf("Unsupported MSI-X configuration: %d/%d/%d\n",
|
||||
b, s, f);
|
||||
return (-1);
|
||||
/*
|
||||
* The PBA overlaps with either the first or last
|
||||
* page of the MSI-X table region. Map the
|
||||
* appropriate page.
|
||||
*/
|
||||
if (pba_offset <= table_offset)
|
||||
pi->pi_msix.pba_page_offset = table_offset;
|
||||
else
|
||||
pi->pi_msix.pba_page_offset = table_offset +
|
||||
table_size - 4096;
|
||||
pi->pi_msix.pba_page = mmap(NULL, 4096, PROT_READ |
|
||||
PROT_WRITE, MAP_SHARED, memfd, start +
|
||||
pi->pi_msix.pba_page_offset);
|
||||
if (pi->pi_msix.pba_page == MAP_FAILED) {
|
||||
printf(
|
||||
"Failed to map PBA page for MSI-X on %d/%d/%d: %s\n",
|
||||
b, s, f, strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (table_offset > 0) {
|
||||
len = table_offset;
|
||||
@ -572,6 +655,12 @@ passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (memfd < 0) {
|
||||
memfd = open(_PATH_MEM, O_RDWR, 0);
|
||||
if (memfd < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (opts == NULL ||
|
||||
sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3)
|
||||
goto done;
|
||||
|
Loading…
Reference in New Issue
Block a user