Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/virtio/pci/virtio_pci_legacy.c
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
#include "virtio_bus_if.h" | #include "virtio_bus_if.h" | ||||
#include "virtio_pci_if.h" | #include "virtio_pci_if.h" | ||||
#include "virtio_if.h" | #include "virtio_if.h" | ||||
struct vtpci_legacy_softc { | struct vtpci_legacy_softc { | ||||
device_t vtpci_dev; | device_t vtpci_dev; | ||||
struct vtpci_common vtpci_common; | struct vtpci_common vtpci_common; | ||||
struct resource *vtpci_res; | 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); | static int vtpci_legacy_probe(device_t); | ||||
static int vtpci_legacy_attach(device_t); | static int vtpci_legacy_attach(device_t); | ||||
static int vtpci_legacy_detach(device_t); | static int vtpci_legacy_detach(device_t); | ||||
static int vtpci_legacy_suspend(device_t); | static int vtpci_legacy_suspend(device_t); | ||||
static int vtpci_legacy_resume(device_t); | static int vtpci_legacy_resume(device_t); | ||||
static int vtpci_legacy_shutdown(device_t); | static int vtpci_legacy_shutdown(device_t); | ||||
Show All 20 Lines | |||||
static int vtpci_legacy_setup_interrupts(device_t, enum intr_type); | static int vtpci_legacy_setup_interrupts(device_t, enum intr_type); | ||||
static void vtpci_legacy_stop(device_t); | static void vtpci_legacy_stop(device_t); | ||||
static int vtpci_legacy_reinit(device_t, uint64_t); | static int vtpci_legacy_reinit(device_t, uint64_t); | ||||
static void vtpci_legacy_reinit_complete(device_t); | static void vtpci_legacy_reinit_complete(device_t); | ||||
static void vtpci_legacy_notify_vq(device_t, uint16_t, bus_size_t); | 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_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 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 int vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *); | ||||
static void vtpci_legacy_free_resources(struct vtpci_legacy_softc *); | static void vtpci_legacy_free_resources(struct vtpci_legacy_softc *); | ||||
static void vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *); | static void vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *); | ||||
static uint8_t vtpci_legacy_get_status(struct vtpci_legacy_softc *); | static uint8_t vtpci_legacy_get_status(struct vtpci_legacy_softc *); | ||||
static void vtpci_legacy_set_status(struct vtpci_legacy_softc *, uint8_t); | static void vtpci_legacy_set_status(struct vtpci_legacy_softc *, uint8_t); | ||||
static void vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *, int); | static void vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *, int); | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | vtpci_legacy_attach(device_t dev) | ||||
int error; | int error; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->vtpci_dev = dev; | sc->vtpci_dev = dev; | ||||
vtpci_init(&sc->vtpci_common, dev, false); | vtpci_init(&sc->vtpci_common, dev, false); | ||||
error = vtpci_legacy_alloc_resources(sc); | error = vtpci_legacy_alloc_resources(sc); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "cannot map I/O space\n"); | device_printf(dev, "cannot map I/O space\n"); | ||||
bryanv: This error message isn't necessarily correct, and if the MSIX allocs fail, we don't release BAR… | |||||
return (error); | 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); | vtpci_legacy_reset(sc); | ||||
/* Tell the host we've noticed this device. */ | /* Tell the host we've noticed this device. */ | ||||
vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); | vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK); | ||||
error = vtpci_add_child(&sc->vtpci_common); | error = vtpci_add_child(&sc->vtpci_common); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
Show All 17 Lines | vtpci_legacy_detach(device_t dev) | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
error = vtpci_delete_child(&sc->vtpci_common); | error = vtpci_delete_child(&sc->vtpci_common); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
vtpci_legacy_reset(sc); | vtpci_legacy_reset(sc); | ||||
vtpci_legacy_teardown_msix(sc); | |||||
vtpci_legacy_free_resources(sc); | vtpci_legacy_free_resources(sc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
vtpci_legacy_suspend(device_t dev) | vtpci_legacy_suspend(device_t dev) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | if (length >= 4) { | ||||
vtpci_legacy_write_config_2(sc, off, *(uint16_t *)s); | vtpci_legacy_write_config_2(sc, off, *(uint16_t *)s); | ||||
} else { | } else { | ||||
size = 1; | size = 1; | ||||
vtpci_legacy_write_config_1(sc, off, *s); | vtpci_legacy_write_config_1(sc, off, *s); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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 | static int | ||||
vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc) | vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
int rid; | int rid; | ||||
dev = sc->vtpci_dev; | dev = sc->vtpci_dev; | ||||
rid = PCIR_BAR(0); | rid = PCIR_BAR(0); | ||||
if ((sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, | if ((sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, | ||||
&rid, RF_ACTIVE)) == NULL) | &rid, RF_ACTIVE)) == NULL) | ||||
return (ENXIO); | 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); | return (0); | ||||
} | } | ||||
static void | static void | ||||
vtpci_legacy_free_resources(struct vtpci_legacy_softc *sc) | vtpci_legacy_free_resources(struct vtpci_legacy_softc *sc) | ||||
{ | { | ||||
device_t dev; | device_t dev; | ||||
dev = sc->vtpci_dev; | 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) { | if (sc->vtpci_res != NULL) { | ||||
bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), | bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), | ||||
sc->vtpci_res); | sc->vtpci_res); | ||||
sc->vtpci_res = NULL; | sc->vtpci_res = NULL; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 149 Lines • Show Last 20 Lines |
This error message isn't necessarily correct, and if the MSIX allocs fail, we don't release BAR 0 (both are existing issues before this change).
Moving the MSIX stuff out of vtpci_legacy_alloc_resources() and calling vtpci_legacy_setup_msix() from this function probably fits the existing flow the best, so we can jump to fail to do the cleanup.