Module Name: src Committed By: jakllsch Date: Wed Jun 6 20:35:37 UTC 2018
Modified Files: src/sys/dev/fdt: files.fdt src/sys/dev/virtio: files.virtio Added Files: src/sys/dev/fdt: virtio_mmio_fdt.c src/sys/dev/virtio: virtio_mmio.c virtio_mmiovar.h Log Message: Add Virtio MMIO transport. Adapted in part from OpenBSD. To generate a diff of this commit: cvs rdiff -u -r1.28 -r1.29 src/sys/dev/fdt/files.fdt cvs rdiff -u -r0 -r1.1 src/sys/dev/fdt/virtio_mmio_fdt.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/virtio/files.virtio cvs rdiff -u -r0 -r1.1 src/sys/dev/virtio/virtio_mmio.c \ src/sys/dev/virtio/virtio_mmiovar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/fdt/files.fdt diff -u src/sys/dev/fdt/files.fdt:1.28 src/sys/dev/fdt/files.fdt:1.29 --- src/sys/dev/fdt/files.fdt:1.28 Fri Jun 1 22:11:53 2018 +++ src/sys/dev/fdt/files.fdt Wed Jun 6 20:35:36 2018 @@ -1,4 +1,4 @@ -# $NetBSD: files.fdt,v 1.28 2018/06/01 22:11:53 jmcneill Exp $ +# $NetBSD: files.fdt,v 1.29 2018/06/06 20:35:36 jakllsch Exp $ include "external/bsd/libfdt/conf/files.libfdt" @@ -91,3 +91,7 @@ file dev/fdt/dw_apb_uart.c dw_apb_uart # Designware USB3 XHCI attach xhci at fdt with dwc3_fdt file dev/fdt/dwc3_fdt.c dwc3_fdt + +# Virtio virtio,mmio +attach virtio at fdt with virtio_mmio_fdt: virtio_mmio +file dev/fdt/virtio_mmio_fdt.c virtio_mmio_fdt Index: src/sys/dev/virtio/files.virtio diff -u src/sys/dev/virtio/files.virtio:1.1 src/sys/dev/virtio/files.virtio:1.2 --- src/sys/dev/virtio/files.virtio:1.1 Wed Jun 6 18:10:35 2018 +++ src/sys/dev/virtio/files.virtio Wed Jun 6 20:35:36 2018 @@ -1,4 +1,6 @@ -# $NetBSD: files.virtio,v 1.1 2018/06/06 18:10:35 jakllsch Exp $ +# $NetBSD: files.virtio,v 1.2 2018/06/06 20:35:36 jakllsch Exp $ # XXX the contents of the following included file should be moved here include "dev/pci/files.virtio" + +file dev/virtio/virtio_mmio.c virtio_mmio Added files: Index: src/sys/dev/fdt/virtio_mmio_fdt.c diff -u /dev/null src/sys/dev/fdt/virtio_mmio_fdt.c:1.1 --- /dev/null Wed Jun 6 20:35:37 2018 +++ src/sys/dev/fdt/virtio_mmio_fdt.c Wed Jun 6 20:35:36 2018 @@ -0,0 +1,193 @@ +/* $NetBSD: virtio_mmio_fdt.c,v 1.1 2018/06/06 20:35:36 jakllsch Exp $ */ + +/* + * Copyright (c) 2018 Jonathan A. Kollasch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: virtio_mmio_fdt.c,v 1.1 2018/06/06 20:35:36 jakllsch Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> + +#include <sys/device.h> + +#include <dev/fdt/fdtvar.h> + +#define VIRTIO_PRIVATE +#include <dev/virtio/virtio_mmiovar.h> + +static int virtio_mmio_fdt_match(device_t, cfdata_t, void *); +static void virtio_mmio_fdt_attach(device_t, device_t, void *); +static int virtio_mmio_fdt_rescan(device_t, const char *, const int *); +static int virtio_mmio_fdt_detach(device_t, int); + +static int virtio_mmio_fdt_setup_interrupts(struct virtio_mmio_softc *); +static void virtio_mmio_fdt_free_interrupts(struct virtio_mmio_softc *); + +struct virtio_mmio_fdt_softc { + struct virtio_mmio_softc sc_msc; + int sc_phandle; +}; + +CFATTACH_DECL3_NEW(virtio_mmio_fdt, sizeof(struct virtio_mmio_fdt_softc), + virtio_mmio_fdt_match, virtio_mmio_fdt_attach, virtio_mmio_fdt_detach, NULL, + virtio_mmio_fdt_rescan, (void *)voidop, DVF_DETACH_SHUTDOWN); + +static const char * const compatible[] = { + "virtio,mmio", + NULL +}; + +static int +virtio_mmio_fdt_match(device_t parent, cfdata_t match, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +virtio_mmio_fdt_attach(device_t parent, device_t self, void *aux) +{ + struct virtio_mmio_fdt_softc * const fsc = device_private(self); + struct virtio_mmio_softc * const msc = &fsc->sc_msc; + struct virtio_softc * const vsc = &msc->sc_sc; + struct fdt_attach_args * const faa = aux; + bus_addr_t addr; + bus_size_t size; + int error; + + aprint_normal("\n"); + aprint_naive("\n"); + + if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { + aprint_error_dev(self, "couldn't get registers\n"); + return; + } + + fsc->sc_phandle = faa->faa_phandle; + msc->sc_iot = faa->faa_bst; + vsc->sc_dev = self; + vsc->sc_dmat = faa->faa_dmat; + + error = bus_space_map(msc->sc_iot, addr, size, 0, &msc->sc_ioh); + if (error) { + aprint_error_dev(self, "couldn't map %#llx: %d", + (uint64_t)addr, error); + return; + } + msc->sc_iosize = size; + + msc->sc_setup_interrupts = virtio_mmio_fdt_setup_interrupts; + msc->sc_free_interrupts = virtio_mmio_fdt_free_interrupts; + + virtio_mmio_common_attach(msc); + virtio_mmio_fdt_rescan(self, "virtio", NULL); +} + +/* ARGSUSED */ +static int +virtio_mmio_fdt_rescan(device_t self, const char *attr, const int *scan_flags) +{ + struct virtio_mmio_fdt_softc * const fsc = device_private(self); + struct virtio_mmio_softc * const msc = &fsc->sc_msc; + struct virtio_softc * const vsc = &msc->sc_sc; + struct virtio_attach_args va; + + if (vsc->sc_child) /* Child already attached? */ + return 0; + memset(&va, 0, sizeof(va)); + va.sc_childdevid = vsc->sc_childdevid; + + config_found_ia(self, attr, &va, NULL); + + if (vsc->sc_child == NULL) { + aprint_error_dev(self, + "no matching child driver; not configured\n"); + return 0; + } + + if (vsc->sc_child == VIRTIO_CHILD_FAILED) { + aprint_error_dev(self, "virtio configuration failed\n"); + return 0; + } + + /* + * Make sure child drivers initialize interrupts via call + * to virtio_child_attach_finish(). + */ + KASSERT(msc->sc_ih != NULL); + + return 0; +} + +static int +virtio_mmio_fdt_detach(device_t self, int flags) +{ + struct virtio_mmio_fdt_softc * const fsc = device_private(self); + struct virtio_mmio_softc * const msc = &fsc->sc_msc; + + return virtio_mmio_common_detach(msc, flags); +} + +static int +virtio_mmio_fdt_setup_interrupts(struct virtio_mmio_softc *msc) +{ + struct virtio_mmio_fdt_softc * const fsc = (void *)msc; + struct virtio_softc * const vsc = &msc->sc_sc; + char intrstr[128]; + int flags = 0; + + if (!fdtbus_intr_str(fsc->sc_phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(vsc->sc_dev, "failed to decode interrupt\n"); + return -1; + } + + if (vsc->sc_flags & VIRTIO_F_PCI_INTR_MPSAFE) + flags |= FDT_INTR_MPSAFE; + + msc->sc_ih = fdtbus_intr_establish(fsc->sc_phandle, 0, vsc->sc_ipl, + flags, virtio_mmio_intr, msc); + if (msc->sc_ih == NULL) { + aprint_error_dev(vsc->sc_dev, + "failed to establish interrupt on %s\n", intrstr); + return -1; + } + aprint_normal_dev(vsc->sc_dev, "interrupting on %s\n", intrstr); + + return 0; +} + +static void +virtio_mmio_fdt_free_interrupts(struct virtio_mmio_softc *msc) +{ + struct virtio_mmio_fdt_softc * const fsc = (void *)msc; + + if (msc->sc_ih != NULL) { + fdtbus_intr_disestablish(fsc->sc_phandle, msc->sc_ih); + msc->sc_ih = NULL; + } +} Index: src/sys/dev/virtio/virtio_mmio.c diff -u /dev/null src/sys/dev/virtio/virtio_mmio.c:1.1 --- /dev/null Wed Jun 6 20:35:37 2018 +++ src/sys/dev/virtio/virtio_mmio.c Wed Jun 6 20:35:36 2018 @@ -0,0 +1,363 @@ +/* $NetBSD: virtio_mmio.c,v 1.1 2018/06/06 20:35:36 jakllsch Exp $ */ +/* $OpenBSD: virtio_mmio.c,v 1.2 2017/02/24 17:12:31 patrick Exp $ */ + +/* + * Copyright (c) 2014 Patrick Wildt <patr...@blueri.se> + * Copyright (c) 2012 Stefan Fritsch. + * Copyright (c) 2010 Minoura Makoto. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.1 2018/06/06 20:35:36 jakllsch Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/mutex.h> + +#define VIRTIO_PRIVATE +#include <dev/virtio/virtio_mmiovar.h> + +#define VIRTIO_MMIO_MAGIC ('v' | 'i' << 8 | 'r' << 16 | 't' << 24) + +#define VIRTIO_MMIO_MAGIC_VALUE 0x000 +#define VIRTIO_MMIO_VERSION 0x004 +#define VIRTIO_MMIO_DEVICE_ID 0x008 +#define VIRTIO_MMIO_VENDOR_ID 0x00c +#define VIRTIO_MMIO_HOST_FEATURES 0x010 +#define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014 +#define VIRTIO_MMIO_GUEST_FEATURES 0x020 +#define VIRTIO_MMIO_GUEST_FEATURES_SEL 0x024 +#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 +#define VIRTIO_MMIO_QUEUE_SEL 0x030 +#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 +#define VIRTIO_MMIO_QUEUE_NUM 0x038 +#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c +#define VIRTIO_MMIO_QUEUE_PFN 0x040 +#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 +#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 +#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 +#define VIRTIO_MMIO_STATUS 0x070 +#define VIRTIO_MMIO_CONFIG 0x100 + +#define VIRTIO_MMIO_INT_VRING (1 << 0) +#define VIRTIO_MMIO_INT_CONFIG (1 << 1) + +/* + * XXX: Before being used on big endian arches, the access to config registers + * XXX: needs to be reviewed/fixed. The non-device specific registers are + * XXX: PCI-endian while the device specific registers are native endian. + */ + +static void virtio_mmio_kick(struct virtio_softc *, uint16_t); +static uint8_t virtio_mmio_read_device_config_1(struct virtio_softc *, int); +static uint16_t virtio_mmio_read_device_config_2(struct virtio_softc *, int); +static uint32_t virtio_mmio_read_device_config_4(struct virtio_softc *, int); +static uint64_t virtio_mmio_read_device_config_8(struct virtio_softc *, int); +static void virtio_mmio_write_device_config_1(struct virtio_softc *, int, uint8_t); +static void virtio_mmio_write_device_config_2(struct virtio_softc *, int, uint16_t); +static void virtio_mmio_write_device_config_4(struct virtio_softc *, int, uint32_t); +static void virtio_mmio_write_device_config_8(struct virtio_softc *, int, uint64_t); +static uint16_t virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t); +static void virtio_mmio_setup_queue(struct virtio_softc *, uint16_t, uint32_t); +static void virtio_mmio_set_status(struct virtio_softc *, int); +static uint32_t virtio_mmio_negotiate_features(struct virtio_softc *, uint32_t); +static int virtio_mmio_setup_interrupts(struct virtio_softc *); +static void virtio_mmio_free_interrupts(struct virtio_softc *); + +static const struct virtio_ops virtio_mmio_ops = { + .kick = virtio_mmio_kick, + .read_dev_cfg_1 = virtio_mmio_read_device_config_1, + .read_dev_cfg_2 = virtio_mmio_read_device_config_2, + .read_dev_cfg_4 = virtio_mmio_read_device_config_4, + .read_dev_cfg_8 = virtio_mmio_read_device_config_8, + .write_dev_cfg_1 = virtio_mmio_write_device_config_1, + .write_dev_cfg_2 = virtio_mmio_write_device_config_2, + .write_dev_cfg_4 = virtio_mmio_write_device_config_4, + .write_dev_cfg_8 = virtio_mmio_write_device_config_8, + .read_queue_size = virtio_mmio_read_queue_size, + .setup_queue = virtio_mmio_setup_queue, + .set_status = virtio_mmio_set_status, + .neg_features = virtio_mmio_negotiate_features, + .setup_interrupts = virtio_mmio_setup_interrupts, + .free_interrupts = virtio_mmio_free_interrupts, +}; + +static uint16_t +virtio_mmio_read_queue_size(struct virtio_softc *vsc, uint16_t idx) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx); + return bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_QUEUE_NUM_MAX); +} + +static void +virtio_mmio_setup_queue(struct virtio_softc *vsc, uint16_t idx, uint32_t addr) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NUM, + bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NUM_MAX)); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_ALIGN, + VIRTIO_PAGE_SIZE); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_PFN, addr); +} + +static void +virtio_mmio_set_status(struct virtio_softc *vsc, int status) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + int old = 0; + + if (status != 0) + old = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_STATUS); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_STATUS, + status|old); +} + +void +virtio_mmio_common_attach(struct virtio_mmio_softc *sc) +{ + struct virtio_softc *vsc = &sc->sc_sc; + uint32_t id, magic, ver; + + magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_MAGIC_VALUE); + if (magic != VIRTIO_MMIO_MAGIC) { + aprint_error_dev(vsc->sc_dev, + "wrong magic value 0x%08x; giving up\n", magic); + return; + } + + ver = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_VERSION); + if (ver != 1) { + aprint_error_dev(vsc->sc_dev, + "unknown version 0x%02x; giving up\n", ver); + return; + } + + id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_DEVICE_ID); + aprint_verbose_dev(vsc->sc_dev, "Virtio ID 0x%08x\n", id); + + /* we could use PAGE_SIZE, but virtio(4) assumes 4KiB for now */ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_GUEST_PAGE_SIZE, + VIRTIO_PAGE_SIZE); + + /* No device connected. */ + if (id == 0) + return; + + vsc->sc_ops = &virtio_mmio_ops; + + virtio_device_reset(vsc); + virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); + virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); + + /* XXX: use softc as aux... */ + vsc->sc_childdevid = id; + vsc->sc_child = NULL; +} + +int +virtio_mmio_common_detach(struct virtio_mmio_softc *sc, int flags) +{ + struct virtio_softc *vsc = &sc->sc_sc; + int r; + + if (vsc->sc_child != NULL && vsc->sc_child != VIRTIO_CHILD_FAILED) { + r = config_detach(vsc->sc_child, flags); + if (r) + return r; + } + KASSERT(vsc->sc_child == NULL || vsc->sc_child == VIRTIO_CHILD_FAILED); + KASSERT(vsc->sc_vqs == NULL); + KASSERT(sc->sc_ih == NULL); + + if (sc->sc_iosize) { + bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); + sc->sc_iosize = 0; + } + + return 0; +} + +/* + * Feature negotiation. + */ +static uint32_t +virtio_mmio_negotiate_features(struct virtio_softc *vsc, uint32_t + guest_features) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + uint32_t r; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_HOST_FEATURES_SEL, 0); + r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_HOST_FEATURES); + r &= guest_features; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_GUEST_FEATURES_SEL, 0); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_GUEST_FEATURES, r); + return r; +} + +/* + * Device configuration registers. + */ +static uint8_t +virtio_mmio_read_device_config_1(struct virtio_softc *vsc, int index) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + return bus_space_read_1(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index); +} + +static uint16_t +virtio_mmio_read_device_config_2(struct virtio_softc *vsc, int index) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + return bus_space_read_2(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index); +} + +static uint32_t +virtio_mmio_read_device_config_4(struct virtio_softc *vsc, int index) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + return bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index); +} + +static uint64_t +virtio_mmio_read_device_config_8(struct virtio_softc *vsc, int index) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + uint64_t r; + + r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index + sizeof(uint32_t)); + r <<= 32; + r += bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index); + return r; +} + +static void +virtio_mmio_write_device_config_1(struct virtio_softc *vsc, + int index, uint8_t value) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + bus_space_write_1(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index, value); +} + +static void +virtio_mmio_write_device_config_2(struct virtio_softc *vsc, + int index, uint16_t value) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + bus_space_write_2(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index, value); +} + +static void +virtio_mmio_write_device_config_4(struct virtio_softc *vsc, + int index, uint32_t value) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index, value); +} + +static void +virtio_mmio_write_device_config_8(struct virtio_softc *vsc, + int index, uint64_t value) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index, + value & 0xffffffff); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_CONFIG + index + sizeof(uint32_t), + value >> 32); +} + +/* + * Interrupt handler. + */ +int +virtio_mmio_intr(void *arg) +{ + struct virtio_mmio_softc *sc = arg; + struct virtio_softc *vsc = &sc->sc_sc; + int isr, r = 0; + + /* check and ack the interrupt */ + isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_INTERRUPT_STATUS); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + VIRTIO_MMIO_INTERRUPT_ACK, isr); + if ((isr & VIRTIO_MMIO_INT_CONFIG) && + (vsc->sc_config_change != NULL)) + r = (vsc->sc_config_change)(vsc); + if ((isr & VIRTIO_MMIO_INT_VRING) && + (vsc->sc_intrhand != NULL)) { + if (vsc->sc_soft_ih != NULL) + softint_schedule(vsc->sc_soft_ih); + else + r |= (vsc->sc_intrhand)(vsc); + } + + return r; +} + +static void +virtio_mmio_kick(struct virtio_softc *vsc, uint16_t idx) +{ + struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_NOTIFY, + idx); +} + +static int +virtio_mmio_setup_interrupts(struct virtio_softc *vsc) +{ + struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc; + + return sc->sc_setup_interrupts(sc); +} + +static void +virtio_mmio_free_interrupts(struct virtio_softc *vsc) +{ + struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc; + + sc->sc_free_interrupts(sc); +} Index: src/sys/dev/virtio/virtio_mmiovar.h diff -u /dev/null src/sys/dev/virtio/virtio_mmiovar.h:1.1 --- /dev/null Wed Jun 6 20:35:37 2018 +++ src/sys/dev/virtio/virtio_mmiovar.h Wed Jun 6 20:35:36 2018 @@ -0,0 +1,51 @@ +/* $NetBSD: virtio_mmiovar.h,v 1.1 2018/06/06 20:35:36 jakllsch Exp $ */ +/* + * Copyright (c) 2018 Jonathan A. Kollasch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _VIRTIO_MMIOVAR_H_ +#define _VIRTIO_MMIOREG_H_ + +#include <dev/pci/virtiovar.h> /* XXX: move to non-pci */ + +struct virtio_mmio_softc { + struct virtio_softc sc_sc; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_size_t sc_iosize; + + void *sc_ih; + + int (*sc_setup_interrupts)(struct virtio_mmio_softc *); + void (*sc_free_interrupts)(struct virtio_mmio_softc *); + +}; + +void virtio_mmio_common_attach(struct virtio_mmio_softc *); +int virtio_mmio_common_detach(struct virtio_mmio_softc *, int); +int virtio_mmio_intr(void *); + +#endif /* _VIRTIO_MMIOREG_H_ */