virtio_pci_legacy: Use the table BAR and PBA BAR from MSI-X cap

The MSI-X resource shouldn't be assumed to be always on BAR1.
The Virtio v1.1 Spec did not specify that MSI-X table and PBA BAR has to
be BAR1 either.

Reported by:	Yuan Rui <number201724@me.com>
MFC after:	2 weeks
Reviewed by:	bryanv, jhb
Approved by:	philip (mentor)
Differential Revision:	https://reviews.freebsd.org/D28817
This commit is contained in:
Ka Ho Ng 2021-03-20 15:40:52 +08:00
parent 9c5aac8f2e
commit faf9a4e914

View File

@ -60,7 +60,8 @@ struct vtpci_legacy_softc {
device_t vtpci_dev;
struct vtpci_common vtpci_common;
struct resource *vtpci_res;
struct resource *vtpci_msix_res;
struct resource *vtpci_msix_table_res;
struct resource *vtpci_msix_pba_res;
};
static int vtpci_legacy_probe(device_t);
@ -97,6 +98,8 @@ static void vtpci_legacy_notify_vq(device_t, uint16_t, bus_size_t);
static void vtpci_legacy_read_dev_config(device_t, bus_size_t, void *, int);
static void vtpci_legacy_write_dev_config(device_t, bus_size_t, void *, int);
static bool vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc);
static void vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc);
static int vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *);
static void vtpci_legacy_free_resources(struct vtpci_legacy_softc *);
@ -232,6 +235,13 @@ vtpci_legacy_attach(device_t dev)
return (error);
}
if (vtpci_is_msix_available(&sc->vtpci_common) &&
!vtpci_legacy_setup_msix(sc)) {
device_printf(dev, "cannot setup MSI-x resources\n");
error = ENXIO;
goto fail;
}
vtpci_legacy_reset(sc);
/* Tell the host we've noticed this device. */
@ -265,6 +275,7 @@ vtpci_legacy_detach(device_t dev)
return (error);
vtpci_legacy_reset(sc);
vtpci_legacy_teardown_msix(sc);
vtpci_legacy_free_resources(sc);
return (0);
@ -539,6 +550,54 @@ vtpci_legacy_write_dev_config(device_t dev, bus_size_t offset,
}
}
static bool
vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc)
{
device_t dev;
int rid, table_rid;
dev = sc->vtpci_dev;
rid = table_rid = pci_msix_table_bar(dev);
if (rid != PCIR_BAR(0)) {
sc->vtpci_msix_table_res = bus_alloc_resource_any(
dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (sc->vtpci_msix_table_res == NULL)
return (false);
}
rid = pci_msix_pba_bar(dev);
if (rid != table_rid && rid != PCIR_BAR(0)) {
sc->vtpci_msix_pba_res = bus_alloc_resource_any(
dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (sc->vtpci_msix_pba_res == NULL)
return (false);
}
return (true);
}
static void
vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc)
{
device_t dev;
dev = sc->vtpci_dev;
if (sc->vtpci_msix_pba_res != NULL) {
bus_release_resource(dev, SYS_RES_MEMORY,
rman_get_rid(sc->vtpci_msix_pba_res),
sc->vtpci_msix_pba_res);
sc->vtpci_msix_pba_res = NULL;
}
if (sc->vtpci_msix_table_res != NULL) {
bus_release_resource(dev, SYS_RES_MEMORY,
rman_get_rid(sc->vtpci_msix_table_res),
sc->vtpci_msix_table_res);
sc->vtpci_msix_table_res = NULL;
}
}
static int
vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc)
{
@ -552,13 +611,6 @@ vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc)
&rid, RF_ACTIVE)) == NULL)
return (ENXIO);
if (vtpci_is_msix_available(&sc->vtpci_common)) {
rid = PCIR_BAR(1);
if ((sc->vtpci_msix_res = bus_alloc_resource_any(dev,
SYS_RES_MEMORY, &rid, RF_ACTIVE)) == NULL)
return (ENXIO);
}
return (0);
}
@ -569,12 +621,6 @@ vtpci_legacy_free_resources(struct vtpci_legacy_softc *sc)
dev = sc->vtpci_dev;
if (sc->vtpci_msix_res != NULL) {
bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(1),
sc->vtpci_msix_res);
sc->vtpci_msix_res = NULL;
}
if (sc->vtpci_res != NULL) {
bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0),
sc->vtpci_res);