Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/virtio/mmio/virtio_mmio.c
Show All 31 Lines | |||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
/* | /* | ||||
* VirtIO MMIO interface. | * VirtIO MMIO interface. | ||||
* This driver is heavily based on VirtIO PCI interface driver. | * This driver is heavily based on VirtIO PCI interface driver. | ||||
*/ | */ | ||||
/* | |||||
* FDT example: | |||||
* virtio_block@1000 { | |||||
* compatible = "virtio,mmio"; | |||||
* reg = <0x1000 0x100>; | |||||
* interrupts = <63>; | |||||
* interrupt-parent = <&GIC>; | |||||
* }; | |||||
*/ | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <dev/fdt/fdt_common.h> | |||||
#include <dev/ofw/openfirm.h> | |||||
#include <dev/ofw/ofw_bus.h> | |||||
#include <dev/ofw/ofw_bus_subr.h> | |||||
#include <dev/virtio/virtio.h> | #include <dev/virtio/virtio.h> | ||||
#include <dev/virtio/virtqueue.h> | #include <dev/virtio/virtqueue.h> | ||||
#include <dev/virtio/mmio/virtio_mmio.h> | #include <dev/virtio/mmio/virtio_mmio.h> | ||||
#include "virtio_mmio_if.h" | #include "virtio_mmio_if.h" | ||||
#include "virtio_bus_if.h" | #include "virtio_bus_if.h" | ||||
#include "virtio_if.h" | #include "virtio_if.h" | ||||
#define PAGE_SHIFT 12 | #define PAGE_SHIFT 12 | ||||
struct vtmmio_virtqueue { | struct vtmmio_virtqueue { | ||||
struct virtqueue *vtv_vq; | struct virtqueue *vtv_vq; | ||||
int vtv_no_intr; | int vtv_no_intr; | ||||
}; | }; | ||||
struct vtmmio_softc { | |||||
device_t dev; | |||||
device_t platform; | |||||
struct resource *res[2]; | |||||
uint64_t vtmmio_features; | |||||
uint32_t vtmmio_flags; | |||||
/* This "bus" will only ever have one child. */ | |||||
device_t vtmmio_child_dev; | |||||
struct virtio_feature_desc *vtmmio_child_feat_desc; | |||||
int vtmmio_nvqs; | |||||
struct vtmmio_virtqueue *vtmmio_vqs; | |||||
void *ih; | |||||
}; | |||||
static int vtmmio_probe(device_t); | |||||
static int vtmmio_attach(device_t); | |||||
static int vtmmio_detach(device_t); | static int vtmmio_detach(device_t); | ||||
static int vtmmio_suspend(device_t); | static int vtmmio_suspend(device_t); | ||||
static int vtmmio_resume(device_t); | static int vtmmio_resume(device_t); | ||||
static int vtmmio_shutdown(device_t); | static int vtmmio_shutdown(device_t); | ||||
static void vtmmio_driver_added(device_t, driver_t *); | static void vtmmio_driver_added(device_t, driver_t *); | ||||
static void vtmmio_child_detached(device_t, device_t); | static void vtmmio_child_detached(device_t, device_t); | ||||
static int vtmmio_read_ivar(device_t, device_t, int, uintptr_t *); | static int vtmmio_read_ivar(device_t, device_t, int, uintptr_t *); | ||||
static int vtmmio_write_ivar(device_t, device_t, int, uintptr_t); | static int vtmmio_write_ivar(device_t, device_t, int, uintptr_t); | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | #define vtmmio_read_config_1(sc, o) \ | ||||
bus_read_1((sc)->res[0], (o)) | bus_read_1((sc)->res[0], (o)) | ||||
#define vtmmio_read_config_2(sc, o) \ | #define vtmmio_read_config_2(sc, o) \ | ||||
bus_read_2((sc)->res[0], (o)) | bus_read_2((sc)->res[0], (o)) | ||||
#define vtmmio_read_config_4(sc, o) \ | #define vtmmio_read_config_4(sc, o) \ | ||||
bus_read_4((sc)->res[0], (o)) | bus_read_4((sc)->res[0], (o)) | ||||
static device_method_t vtmmio_methods[] = { | static device_method_t vtmmio_methods[] = { | ||||
/* Device interface. */ | /* Device interface. */ | ||||
DEVMETHOD(device_probe, vtmmio_probe), | |||||
DEVMETHOD(device_attach, vtmmio_attach), | DEVMETHOD(device_attach, vtmmio_attach), | ||||
DEVMETHOD(device_detach, vtmmio_detach), | DEVMETHOD(device_detach, vtmmio_detach), | ||||
DEVMETHOD(device_suspend, vtmmio_suspend), | DEVMETHOD(device_suspend, vtmmio_suspend), | ||||
DEVMETHOD(device_resume, vtmmio_resume), | DEVMETHOD(device_resume, vtmmio_resume), | ||||
DEVMETHOD(device_shutdown, vtmmio_shutdown), | DEVMETHOD(device_shutdown, vtmmio_shutdown), | ||||
/* Bus interface. */ | /* Bus interface. */ | ||||
DEVMETHOD(bus_driver_added, vtmmio_driver_added), | DEVMETHOD(bus_driver_added, vtmmio_driver_added), | ||||
Show All 12 Lines | static device_method_t vtmmio_methods[] = { | ||||
DEVMETHOD(virtio_bus_reinit_complete, vtmmio_reinit_complete), | DEVMETHOD(virtio_bus_reinit_complete, vtmmio_reinit_complete), | ||||
DEVMETHOD(virtio_bus_notify_vq, vtmmio_notify_virtqueue), | DEVMETHOD(virtio_bus_notify_vq, vtmmio_notify_virtqueue), | ||||
DEVMETHOD(virtio_bus_read_device_config, vtmmio_read_dev_config), | DEVMETHOD(virtio_bus_read_device_config, vtmmio_read_dev_config), | ||||
DEVMETHOD(virtio_bus_write_device_config, vtmmio_write_dev_config), | DEVMETHOD(virtio_bus_write_device_config, vtmmio_write_dev_config), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t vtmmio_driver = { | DEFINE_CLASS_0(virtio_mmio, vtmmio_driver, vtmmio_methods, | ||||
"virtio_mmio", | sizeof(struct vtmmio_softc)); | ||||
vtmmio_methods, | |||||
sizeof(struct vtmmio_softc) | |||||
}; | |||||
devclass_t vtmmio_devclass; | |||||
DRIVER_MODULE(virtio_mmio, simplebus, vtmmio_driver, vtmmio_devclass, 0, 0); | |||||
DRIVER_MODULE(virtio_mmio, ofwbus, vtmmio_driver, vtmmio_devclass, 0, 0); | |||||
MODULE_VERSION(virtio_mmio, 1); | MODULE_VERSION(virtio_mmio, 1); | ||||
MODULE_DEPEND(virtio_mmio, simplebus, 1, 1, 1); | |||||
MODULE_DEPEND(virtio_mmio, virtio, 1, 1, 1); | |||||
static int | static int | ||||
vtmmio_setup_intr(device_t dev, enum intr_type type) | vtmmio_setup_intr(device_t dev, enum intr_type type) | ||||
{ | { | ||||
struct vtmmio_softc *sc; | struct vtmmio_softc *sc; | ||||
int rid; | int rid; | ||||
int err; | int err; | ||||
Show All 20 Lines | if (bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE, | ||||
NULL, vtmmio_vq_intr, sc, &sc->ih)) { | NULL, vtmmio_vq_intr, sc, &sc->ih)) { | ||||
device_printf(dev, "Can't setup the interrupt\n"); | device_printf(dev, "Can't setup the interrupt\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | int | ||||
vtmmio_probe(device_t dev) | |||||
{ | |||||
if (!ofw_bus_status_okay(dev)) | |||||
return (ENXIO); | |||||
if (!ofw_bus_is_compatible(dev, "virtio,mmio")) | |||||
return (ENXIO); | |||||
device_set_desc(dev, "VirtIO MMIO adapter"); | |||||
return (BUS_PROBE_DEFAULT); | |||||
} | |||||
static int | |||||
vtmmio_setup_platform(struct vtmmio_softc *sc) | |||||
{ | |||||
phandle_t platform_node; | |||||
struct fdt_ic *ic; | |||||
phandle_t xref; | |||||
phandle_t node; | |||||
sc->platform = NULL; | |||||
if ((node = ofw_bus_get_node(sc->dev)) == -1) | |||||
return (ENXIO); | |||||
if (OF_searchencprop(node, "platform", &xref, | |||||
sizeof(xref)) == -1) { | |||||
return (ENXIO); | |||||
} | |||||
platform_node = OF_node_from_xref(xref); | |||||
SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) { | |||||
if (ic->iph == platform_node) { | |||||
sc->platform = ic->dev; | |||||
break; | |||||
} | |||||
} | |||||
if (sc->platform == NULL) { | |||||
/* No platform-specific device. Ignore it. */ | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
vtmmio_attach(device_t dev) | vtmmio_attach(device_t dev) | ||||
{ | { | ||||
struct vtmmio_softc *sc; | struct vtmmio_softc *sc; | ||||
device_t child; | device_t child; | ||||
int rid; | int rid; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->dev = dev; | sc->dev = dev; | ||||
vtmmio_setup_platform(sc); | |||||
rid = 0; | rid = 0; | ||||
sc->res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | sc->res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | ||||
RF_ACTIVE); | RF_ACTIVE); | ||||
if (!sc->res[0]) { | if (!sc->res[0]) { | ||||
device_printf(dev, "Cannot allocate memory window.\n"); | device_printf(dev, "Cannot allocate memory window.\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 556 Lines • Show Last 20 Lines |