Home | History | Annotate | Line # | Download | only in pci
virtio.c revision 1.63.2.1
      1  1.63.2.1    martin /*	$NetBSD: virtio.c,v 1.63.2.1 2023/01/13 19:11:31 martin Exp $	*/
      2       1.1   hannken 
      3       1.1   hannken /*
      4      1.43   reinoud  * Copyright (c) 2020 The NetBSD Foundation, Inc.
      5      1.43   reinoud  * Copyright (c) 2012 Stefan Fritsch, Alexander Fiveg.
      6       1.1   hannken  * Copyright (c) 2010 Minoura Makoto.
      7       1.1   hannken  * All rights reserved.
      8       1.1   hannken  *
      9       1.1   hannken  * Redistribution and use in source and binary forms, with or without
     10       1.1   hannken  * modification, are permitted provided that the following conditions
     11       1.1   hannken  * are met:
     12       1.1   hannken  * 1. Redistributions of source code must retain the above copyright
     13       1.1   hannken  *    notice, this list of conditions and the following disclaimer.
     14       1.1   hannken  * 2. Redistributions in binary form must reproduce the above copyright
     15       1.1   hannken  *    notice, this list of conditions and the following disclaimer in the
     16       1.1   hannken  *    documentation and/or other materials provided with the distribution.
     17       1.1   hannken  *
     18       1.1   hannken  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19       1.1   hannken  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20       1.1   hannken  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21       1.1   hannken  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22       1.1   hannken  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23       1.1   hannken  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24       1.1   hannken  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25       1.1   hannken  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26       1.1   hannken  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27       1.1   hannken  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28       1.1   hannken  */
     29       1.1   hannken 
     30       1.1   hannken #include <sys/cdefs.h>
     31  1.63.2.1    martin __KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.63.2.1 2023/01/13 19:11:31 martin Exp $");
     32       1.1   hannken 
     33       1.1   hannken #include <sys/param.h>
     34       1.1   hannken #include <sys/systm.h>
     35       1.1   hannken #include <sys/kernel.h>
     36       1.1   hannken #include <sys/atomic.h>
     37       1.1   hannken #include <sys/bus.h>
     38       1.1   hannken #include <sys/device.h>
     39       1.1   hannken #include <sys/kmem.h>
     40      1.18  pgoyette #include <sys/module.h>
     41       1.1   hannken 
     42      1.22  jdolecek #define VIRTIO_PRIVATE
     43      1.22  jdolecek 
     44      1.29    cherry #include <dev/pci/virtioreg.h> /* XXX: move to non-pci */
     45      1.29    cherry #include <dev/pci/virtiovar.h> /* XXX: move to non-pci */
     46       1.1   hannken 
     47       1.1   hannken #define MINSEG_INDIRECT		2 /* use indirect if nsegs >= this value */
     48       1.1   hannken 
     49      1.43   reinoud /* incomplete list */
     50      1.43   reinoud static const char *virtio_device_name[] = {
     51      1.43   reinoud 	"unknown (0)",			/*  0 */
     52      1.43   reinoud 	"network",			/*  1 */
     53      1.43   reinoud 	"block",			/*  2 */
     54      1.43   reinoud 	"console",			/*  3 */
     55      1.43   reinoud 	"entropy",			/*  4 */
     56      1.43   reinoud 	"memory balloon",		/*  5 */
     57      1.43   reinoud 	"I/O memory",			/*  6 */
     58      1.43   reinoud 	"remote processor messaging",	/*  7 */
     59      1.43   reinoud 	"SCSI",				/*  8 */
     60      1.43   reinoud 	"9P transport",			/*  9 */
     61      1.43   reinoud };
     62      1.43   reinoud #define NDEVNAMES	__arraycount(virtio_device_name)
     63      1.43   reinoud 
     64       1.1   hannken static void	virtio_init_vq(struct virtio_softc *,
     65       1.1   hannken 		    struct virtqueue *, const bool);
     66       1.1   hannken 
     67      1.29    cherry void
     68       1.1   hannken virtio_set_status(struct virtio_softc *sc, int status)
     69       1.1   hannken {
     70      1.31  jakllsch 	sc->sc_ops->set_status(sc, status);
     71      1.11     ozaki }
     72      1.11     ozaki 
     73       1.1   hannken /*
     74       1.1   hannken  * Reset the device.
     75       1.1   hannken  */
     76       1.1   hannken /*
     77       1.1   hannken  * To reset the device to a known state, do following:
     78       1.1   hannken  *	virtio_reset(sc);	     // this will stop the device activity
     79       1.1   hannken  *	<dequeue finished requests>; // virtio_dequeue() still can be called
     80       1.1   hannken  *	<revoke pending requests in the vqs if any>;
     81      1.42  jakllsch  *	virtio_reinit_start(sc);     // dequeue prohibitted
     82       1.1   hannken  *	newfeatures = virtio_negotiate_features(sc, requestedfeatures);
     83       1.1   hannken  *	<some other initialization>;
     84       1.1   hannken  *	virtio_reinit_end(sc);	     // device activated; enqueue allowed
     85       1.1   hannken  * Once attached, feature negotiation can only be allowed after virtio_reset.
     86       1.1   hannken  */
     87       1.1   hannken void
     88       1.1   hannken virtio_reset(struct virtio_softc *sc)
     89       1.1   hannken {
     90       1.1   hannken 	virtio_device_reset(sc);
     91       1.1   hannken }
     92       1.1   hannken 
     93      1.53  yamaguch int
     94       1.1   hannken virtio_reinit_start(struct virtio_softc *sc)
     95       1.1   hannken {
     96      1.51  yamaguch 	int i, r;
     97       1.1   hannken 
     98       1.1   hannken 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_ACK);
     99       1.1   hannken 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER);
    100       1.1   hannken 	for (i = 0; i < sc->sc_nvqs; i++) {
    101       1.1   hannken 		int n;
    102       1.1   hannken 		struct virtqueue *vq = &sc->sc_vqs[i];
    103      1.31  jakllsch 		n = sc->sc_ops->read_queue_size(sc, vq->vq_index);
    104       1.1   hannken 		if (n == 0)	/* vq disappeared */
    105       1.1   hannken 			continue;
    106       1.1   hannken 		if (n != vq->vq_num) {
    107       1.1   hannken 			panic("%s: virtqueue size changed, vq index %d\n",
    108      1.59  riastrad 			    device_xname(sc->sc_dev),
    109      1.59  riastrad 			    vq->vq_index);
    110       1.1   hannken 		}
    111       1.1   hannken 		virtio_init_vq(sc, vq, true);
    112      1.31  jakllsch 		sc->sc_ops->setup_queue(sc, vq->vq_index,
    113      1.43   reinoud 		    vq->vq_dmamap->dm_segs[0].ds_addr);
    114      1.11     ozaki 	}
    115      1.51  yamaguch 
    116      1.51  yamaguch 	r = sc->sc_ops->setup_interrupts(sc, 1);
    117      1.53  yamaguch 	if (r != 0)
    118      1.53  yamaguch 		goto fail;
    119      1.53  yamaguch 
    120      1.53  yamaguch 	return 0;
    121      1.53  yamaguch 
    122      1.53  yamaguch fail:
    123      1.53  yamaguch 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
    124      1.53  yamaguch 
    125      1.53  yamaguch 	return 1;
    126       1.1   hannken }
    127       1.1   hannken 
    128       1.1   hannken void
    129       1.1   hannken virtio_reinit_end(struct virtio_softc *sc)
    130       1.1   hannken {
    131       1.1   hannken 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK);
    132       1.1   hannken }
    133       1.1   hannken 
    134       1.1   hannken /*
    135       1.1   hannken  * Feature negotiation.
    136       1.1   hannken  */
    137      1.43   reinoud void
    138      1.43   reinoud virtio_negotiate_features(struct virtio_softc *sc, uint64_t guest_features)
    139       1.1   hannken {
    140       1.1   hannken 	if (!(device_cfdata(sc->sc_dev)->cf_flags & 1) &&
    141       1.1   hannken 	    !(device_cfdata(sc->sc_child)->cf_flags & 1)) /* XXX */
    142       1.1   hannken 		guest_features |= VIRTIO_F_RING_INDIRECT_DESC;
    143      1.43   reinoud 	sc->sc_ops->neg_features(sc, guest_features);
    144      1.43   reinoud 	if (sc->sc_active_features & VIRTIO_F_RING_INDIRECT_DESC)
    145       1.1   hannken 		sc->sc_indirect = true;
    146       1.1   hannken 	else
    147       1.1   hannken 		sc->sc_indirect = false;
    148      1.43   reinoud }
    149       1.1   hannken 
    150       1.1   hannken 
    151       1.1   hannken /*
    152      1.43   reinoud  * Device configuration registers readers/writers
    153       1.1   hannken  */
    154      1.43   reinoud #if 0
    155      1.43   reinoud #define DPRINTFR(n, fmt, val, index, num) \
    156      1.43   reinoud 	printf("\n%s (", n); \
    157      1.43   reinoud 	for (int i = 0; i < num; i++) \
    158      1.43   reinoud 		printf("%02x ", bus_space_read_1(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index+i)); \
    159      1.43   reinoud 	printf(") -> "); printf(fmt, val); printf("\n");
    160      1.45   reinoud #define DPRINTFR2(n, fmt, val_s, val_n) \
    161      1.45   reinoud 	printf("%s ", n); \
    162      1.45   reinoud 	printf("\n        stream "); printf(fmt, val_s); printf(" norm "); printf(fmt, val_n); printf("\n");
    163      1.43   reinoud #else
    164      1.43   reinoud #define DPRINTFR(n, fmt, val, index, num)
    165      1.45   reinoud #define DPRINTFR2(n, fmt, val_s, val_n)
    166      1.43   reinoud #endif
    167      1.43   reinoud 
    168      1.45   reinoud 
    169       1.1   hannken uint8_t
    170      1.59  riastrad virtio_read_device_config_1(struct virtio_softc *sc, int index)
    171      1.59  riastrad {
    172      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    173      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    174      1.43   reinoud 	uint8_t val;
    175      1.45   reinoud 
    176      1.45   reinoud 	val = bus_space_read_1(iot, ioh, index);
    177      1.45   reinoud 
    178      1.43   reinoud 	DPRINTFR("read_1", "%02x", val, index, 1);
    179      1.43   reinoud 	return val;
    180      1.43   reinoud }
    181      1.43   reinoud 
    182      1.43   reinoud uint16_t
    183      1.59  riastrad virtio_read_device_config_2(struct virtio_softc *sc, int index)
    184      1.59  riastrad {
    185      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    186      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    187      1.43   reinoud 	uint16_t val;
    188      1.45   reinoud 
    189      1.45   reinoud 	val = bus_space_read_2(iot, ioh, index);
    190      1.45   reinoud 	if (BYTE_ORDER != sc->sc_bus_endian)
    191      1.45   reinoud 		val = bswap16(val);
    192      1.45   reinoud 
    193      1.43   reinoud 	DPRINTFR("read_2", "%04x", val, index, 2);
    194      1.45   reinoud 	DPRINTFR2("read_2", "%04x",
    195      1.59  riastrad 	    bus_space_read_stream_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh,
    196      1.59  riastrad 		index),
    197      1.59  riastrad 	    bus_space_read_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index));
    198      1.43   reinoud 	return val;
    199      1.43   reinoud }
    200      1.43   reinoud 
    201      1.43   reinoud uint32_t
    202      1.59  riastrad virtio_read_device_config_4(struct virtio_softc *sc, int index)
    203      1.59  riastrad {
    204      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    205      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    206      1.43   reinoud 	uint32_t val;
    207      1.45   reinoud 
    208      1.45   reinoud 	val = bus_space_read_4(iot, ioh, index);
    209      1.45   reinoud 	if (BYTE_ORDER != sc->sc_bus_endian)
    210      1.45   reinoud 		val = bswap32(val);
    211      1.45   reinoud 
    212      1.43   reinoud 	DPRINTFR("read_4", "%08x", val, index, 4);
    213      1.45   reinoud 	DPRINTFR2("read_4", "%08x",
    214      1.59  riastrad 	    bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh,
    215      1.59  riastrad 		index),
    216      1.59  riastrad 	    bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index));
    217      1.43   reinoud 	return val;
    218      1.43   reinoud }
    219      1.43   reinoud 
    220      1.46   reinoud /*
    221      1.46   reinoud  * The Virtio spec explicitly tells that reading and writing 8 bytes are not
    222      1.46   reinoud  * considered atomic and no triggers may be connected to reading or writing
    223      1.47   reinoud  * it. We access it using two 32 reads. See virtio spec 4.1.3.1.
    224      1.46   reinoud  */
    225      1.43   reinoud uint64_t
    226      1.59  riastrad virtio_read_device_config_8(struct virtio_softc *sc, int index)
    227      1.59  riastrad {
    228      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    229      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    230      1.46   reinoud 	union {
    231      1.46   reinoud 		uint64_t u64;
    232      1.47   reinoud 		uint32_t l[2];
    233      1.46   reinoud 	} v;
    234      1.46   reinoud 	uint64_t val;
    235      1.46   reinoud 
    236      1.47   reinoud 	v.l[0] = bus_space_read_4(iot, ioh, index);
    237      1.47   reinoud 	v.l[1] = bus_space_read_4(iot, ioh, index + 4);
    238      1.47   reinoud 	if (sc->sc_bus_endian != sc->sc_struct_endian) {
    239      1.47   reinoud 		v.l[0] = bswap32(v.l[0]);
    240      1.47   reinoud 		v.l[1] = bswap32(v.l[1]);
    241      1.47   reinoud 	}
    242      1.46   reinoud 	val = v.u64;
    243      1.45   reinoud 
    244      1.46   reinoud 	if (BYTE_ORDER != sc->sc_struct_endian)
    245      1.46   reinoud 		val = bswap64(val);
    246      1.45   reinoud 
    247      1.63    simonb 	DPRINTFR("read_8", "%08"PRIx64, val, index, 8);
    248      1.45   reinoud 	DPRINTFR2("read_8 low ", "%08x",
    249      1.59  riastrad 	    bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh,
    250      1.59  riastrad 		index),
    251      1.59  riastrad 	    bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index));
    252      1.45   reinoud 	DPRINTFR2("read_8 high ", "%08x",
    253      1.59  riastrad 	    bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh,
    254      1.59  riastrad 		index + 4),
    255      1.59  riastrad 	    bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index + 4));
    256      1.43   reinoud 	return val;
    257       1.1   hannken }
    258       1.1   hannken 
    259      1.43   reinoud /*
    260      1.43   reinoud  * In the older virtio spec, device config registers are host endian. On newer
    261      1.45   reinoud  * they are little endian. Some newer devices however explicitly specify their
    262      1.55    andvar  * register to always be little endian. These functions cater for these.
    263      1.43   reinoud  */
    264       1.1   hannken uint16_t
    265      1.59  riastrad virtio_read_device_config_le_2(struct virtio_softc *sc, int index)
    266      1.59  riastrad {
    267      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    268      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    269      1.43   reinoud 	uint16_t val;
    270      1.43   reinoud 
    271      1.45   reinoud 	val = bus_space_read_2(iot, ioh, index);
    272      1.45   reinoud 	if (sc->sc_bus_endian != LITTLE_ENDIAN)
    273      1.45   reinoud 		val = bswap16(val);
    274      1.45   reinoud 
    275      1.45   reinoud 	DPRINTFR("read_le_2", "%04x", val, index, 2);
    276      1.45   reinoud 	DPRINTFR2("read_le_2", "%04x",
    277      1.59  riastrad 	    bus_space_read_stream_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0),
    278      1.59  riastrad 	    bus_space_read_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0));
    279      1.43   reinoud 	return val;
    280       1.1   hannken }
    281       1.1   hannken 
    282       1.1   hannken uint32_t
    283      1.59  riastrad virtio_read_device_config_le_4(struct virtio_softc *sc, int index)
    284      1.59  riastrad {
    285      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    286      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    287      1.43   reinoud 	uint32_t val;
    288      1.43   reinoud 
    289      1.45   reinoud 	val = bus_space_read_4(iot, ioh, index);
    290      1.45   reinoud 	if (sc->sc_bus_endian != LITTLE_ENDIAN)
    291      1.45   reinoud 		val = bswap32(val);
    292      1.45   reinoud 
    293      1.43   reinoud 	DPRINTFR("read_le_4", "%08x", val, index, 4);
    294      1.45   reinoud 	DPRINTFR2("read_le_4", "%08x",
    295      1.59  riastrad 	    bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0),
    296      1.59  riastrad 	    bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0));
    297      1.43   reinoud 	return val;
    298      1.43   reinoud }
    299      1.43   reinoud 
    300      1.43   reinoud void
    301      1.43   reinoud virtio_write_device_config_1(struct virtio_softc *sc, int index, uint8_t value)
    302       1.1   hannken {
    303      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    304      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    305      1.45   reinoud 
    306      1.45   reinoud 	bus_space_write_1(iot, ioh, index, value);
    307       1.1   hannken }
    308       1.1   hannken 
    309      1.43   reinoud void
    310      1.59  riastrad virtio_write_device_config_2(struct virtio_softc *sc, int index,
    311      1.59  riastrad     uint16_t value)
    312       1.1   hannken {
    313      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    314      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    315      1.45   reinoud 
    316      1.45   reinoud 	if (BYTE_ORDER != sc->sc_bus_endian)
    317      1.45   reinoud 		value = bswap16(value);
    318      1.45   reinoud 	bus_space_write_2(iot, ioh, index, value);
    319       1.1   hannken }
    320       1.1   hannken 
    321       1.1   hannken void
    322      1.59  riastrad virtio_write_device_config_4(struct virtio_softc *sc, int index,
    323      1.59  riastrad     uint32_t value)
    324       1.1   hannken {
    325      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    326      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    327      1.45   reinoud 
    328      1.45   reinoud 	if (BYTE_ORDER != sc->sc_bus_endian)
    329      1.45   reinoud 		value = bswap32(value);
    330      1.45   reinoud 	bus_space_write_4(iot, ioh, index, value);
    331       1.1   hannken }
    332       1.1   hannken 
    333      1.46   reinoud /*
    334      1.46   reinoud  * The Virtio spec explicitly tells that reading and writing 8 bytes are not
    335      1.46   reinoud  * considered atomic and no triggers may be connected to reading or writing
    336      1.47   reinoud  * it. We access it using two 32 bit writes. For good measure it is stated to
    337      1.47   reinoud  * always write lsb first just in case of a hypervisor bug. See See virtio
    338      1.47   reinoud  * spec 4.1.3.1.
    339      1.46   reinoud  */
    340       1.1   hannken void
    341      1.59  riastrad virtio_write_device_config_8(struct virtio_softc *sc, int index,
    342      1.59  riastrad     uint64_t value)
    343       1.1   hannken {
    344      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    345      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    346      1.46   reinoud 	union {
    347      1.46   reinoud 		uint64_t u64;
    348      1.47   reinoud 		uint32_t l[2];
    349      1.46   reinoud 	} v;
    350      1.46   reinoud 
    351      1.46   reinoud 	if (BYTE_ORDER != sc->sc_struct_endian)
    352      1.46   reinoud 		value = bswap64(value);
    353      1.46   reinoud 
    354      1.46   reinoud 	v.u64 = value;
    355      1.47   reinoud 	if (sc->sc_bus_endian != sc->sc_struct_endian) {
    356      1.47   reinoud 		v.l[0] = bswap32(v.l[0]);
    357      1.47   reinoud 		v.l[1] = bswap32(v.l[1]);
    358      1.47   reinoud 	}
    359      1.47   reinoud 
    360      1.47   reinoud 	if (sc->sc_struct_endian == LITTLE_ENDIAN) {
    361      1.47   reinoud 		bus_space_write_4(iot, ioh, index,     v.l[0]);
    362      1.47   reinoud 		bus_space_write_4(iot, ioh, index + 4, v.l[1]);
    363      1.47   reinoud 	} else {
    364      1.47   reinoud 		bus_space_write_4(iot, ioh, index + 4, v.l[1]);
    365      1.47   reinoud 		bus_space_write_4(iot, ioh, index,     v.l[0]);
    366      1.47   reinoud 	}
    367       1.1   hannken }
    368       1.1   hannken 
    369      1.43   reinoud /*
    370      1.43   reinoud  * In the older virtio spec, device config registers are host endian. On newer
    371      1.45   reinoud  * they are little endian. Some newer devices however explicitly specify their
    372      1.55    andvar  * register to always be little endian. These functions cater for these.
    373      1.43   reinoud  */
    374       1.1   hannken void
    375      1.59  riastrad virtio_write_device_config_le_2(struct virtio_softc *sc, int index,
    376      1.59  riastrad     uint16_t value)
    377       1.1   hannken {
    378      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    379      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    380      1.45   reinoud 
    381      1.45   reinoud 	if (sc->sc_bus_endian != LITTLE_ENDIAN)
    382      1.45   reinoud 		value = bswap16(value);
    383      1.45   reinoud 	bus_space_write_2(iot, ioh, index, value);
    384       1.1   hannken }
    385       1.1   hannken 
    386       1.1   hannken void
    387      1.59  riastrad virtio_write_device_config_le_4(struct virtio_softc *sc, int index,
    388      1.59  riastrad     uint32_t value)
    389      1.43   reinoud {
    390      1.45   reinoud 	bus_space_tag_t	   iot = sc->sc_devcfg_iot;
    391      1.45   reinoud 	bus_space_handle_t ioh = sc->sc_devcfg_ioh;
    392      1.45   reinoud 
    393      1.45   reinoud 	if (sc->sc_bus_endian != LITTLE_ENDIAN)
    394      1.45   reinoud 		value = bswap32(value);
    395      1.45   reinoud 	bus_space_write_4(iot, ioh, index, value);
    396      1.43   reinoud }
    397      1.43   reinoud 
    398      1.45   reinoud 
    399      1.43   reinoud /*
    400      1.43   reinoud  * data structures endian helpers
    401      1.43   reinoud  */
    402      1.59  riastrad uint16_t
    403      1.59  riastrad virtio_rw16(struct virtio_softc *sc, uint16_t val)
    404       1.1   hannken {
    405      1.43   reinoud 	KASSERT(sc);
    406      1.45   reinoud 	return BYTE_ORDER != sc->sc_struct_endian ? bswap16(val) : val;
    407       1.1   hannken }
    408       1.1   hannken 
    409      1.59  riastrad uint32_t
    410      1.59  riastrad virtio_rw32(struct virtio_softc *sc, uint32_t val)
    411      1.43   reinoud {
    412      1.43   reinoud 	KASSERT(sc);
    413      1.45   reinoud 	return BYTE_ORDER != sc->sc_struct_endian ? bswap32(val) : val;
    414      1.43   reinoud }
    415      1.43   reinoud 
    416      1.59  riastrad uint64_t
    417      1.59  riastrad virtio_rw64(struct virtio_softc *sc, uint64_t val)
    418      1.43   reinoud {
    419      1.43   reinoud 	KASSERT(sc);
    420      1.45   reinoud 	return BYTE_ORDER != sc->sc_struct_endian ? bswap64(val) : val;
    421      1.43   reinoud }
    422      1.43   reinoud 
    423      1.43   reinoud 
    424       1.1   hannken /*
    425       1.1   hannken  * Interrupt handler.
    426       1.1   hannken  */
    427       1.8     ozaki static void
    428       1.8     ozaki virtio_soft_intr(void *arg)
    429       1.8     ozaki {
    430       1.8     ozaki 	struct virtio_softc *sc = arg;
    431       1.8     ozaki 
    432       1.8     ozaki 	KASSERT(sc->sc_intrhand != NULL);
    433       1.8     ozaki 
    434      1.54       uwe 	(*sc->sc_intrhand)(sc);
    435       1.8     ozaki }
    436       1.8     ozaki 
    437       1.1   hannken /*
    438       1.1   hannken  * dmamap sync operations for a virtqueue.
    439       1.1   hannken  */
    440       1.1   hannken static inline void
    441       1.1   hannken vq_sync_descs(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    442       1.1   hannken {
    443      1.57  riastrad 
    444      1.62     skrll 	/* availoffset == sizeof(vring_desc) * vq_num */
    445       1.1   hannken 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap, 0, vq->vq_availoffset,
    446      1.57  riastrad 	    ops);
    447       1.1   hannken }
    448       1.1   hannken 
    449       1.1   hannken static inline void
    450      1.57  riastrad vq_sync_aring_all(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    451       1.1   hannken {
    452      1.43   reinoud 	uint16_t hdrlen = offsetof(struct vring_avail, ring);
    453  1.63.2.1    martin 	size_t payloadlen = vq->vq_num * sizeof(uint16_t);
    454      1.57  riastrad 	size_t usedlen = 0;
    455      1.57  riastrad 
    456      1.43   reinoud 	if (sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX)
    457      1.57  riastrad 		usedlen = sizeof(uint16_t);
    458      1.57  riastrad 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    459      1.57  riastrad 	    vq->vq_availoffset, hdrlen + payloadlen + usedlen, ops);
    460      1.57  riastrad }
    461      1.57  riastrad 
    462      1.57  riastrad static inline void
    463      1.57  riastrad vq_sync_aring_header(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    464      1.57  riastrad {
    465      1.57  riastrad 	uint16_t hdrlen = offsetof(struct vring_avail, ring);
    466      1.57  riastrad 
    467      1.57  riastrad 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    468      1.57  riastrad 	    vq->vq_availoffset, hdrlen, ops);
    469      1.57  riastrad }
    470      1.57  riastrad 
    471      1.57  riastrad static inline void
    472      1.57  riastrad vq_sync_aring_payload(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    473      1.57  riastrad {
    474      1.57  riastrad 	uint16_t hdrlen = offsetof(struct vring_avail, ring);
    475  1.63.2.1    martin 	size_t payloadlen = vq->vq_num * sizeof(uint16_t);
    476      1.43   reinoud 
    477       1.1   hannken 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    478      1.57  riastrad 	    vq->vq_availoffset + hdrlen, payloadlen, ops);
    479       1.1   hannken }
    480       1.1   hannken 
    481       1.1   hannken static inline void
    482      1.57  riastrad vq_sync_aring_used(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    483      1.57  riastrad {
    484      1.57  riastrad 	uint16_t hdrlen = offsetof(struct vring_avail, ring);
    485  1.63.2.1    martin 	size_t payloadlen = vq->vq_num * sizeof(uint16_t);
    486      1.57  riastrad 	size_t usedlen = sizeof(uint16_t);
    487      1.57  riastrad 
    488      1.57  riastrad 	if ((sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX) == 0)
    489      1.57  riastrad 		return;
    490      1.57  riastrad 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    491      1.57  riastrad 	    vq->vq_availoffset + hdrlen + payloadlen, usedlen, ops);
    492      1.57  riastrad }
    493      1.57  riastrad 
    494      1.57  riastrad static inline void
    495      1.57  riastrad vq_sync_uring_all(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    496       1.1   hannken {
    497      1.43   reinoud 	uint16_t hdrlen = offsetof(struct vring_used, ring);
    498  1.63.2.1    martin 	size_t payloadlen = vq->vq_num * sizeof(struct vring_used_elem);
    499      1.57  riastrad 	size_t availlen = 0;
    500      1.57  riastrad 
    501      1.43   reinoud 	if (sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX)
    502      1.57  riastrad 		availlen = sizeof(uint16_t);
    503      1.57  riastrad 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    504      1.57  riastrad 	    vq->vq_usedoffset, hdrlen + payloadlen + availlen, ops);
    505      1.57  riastrad }
    506      1.57  riastrad 
    507      1.57  riastrad static inline void
    508      1.57  riastrad vq_sync_uring_header(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    509      1.57  riastrad {
    510      1.57  riastrad 	uint16_t hdrlen = offsetof(struct vring_used, ring);
    511      1.43   reinoud 
    512       1.1   hannken 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    513      1.57  riastrad 	    vq->vq_usedoffset, hdrlen, ops);
    514      1.57  riastrad }
    515      1.57  riastrad 
    516      1.57  riastrad static inline void
    517      1.57  riastrad vq_sync_uring_payload(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    518      1.57  riastrad {
    519      1.57  riastrad 	uint16_t hdrlen = offsetof(struct vring_used, ring);
    520  1.63.2.1    martin 	size_t payloadlen = vq->vq_num * sizeof(struct vring_used_elem);
    521      1.57  riastrad 
    522      1.57  riastrad 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    523      1.57  riastrad 	    vq->vq_usedoffset + hdrlen, payloadlen, ops);
    524      1.57  riastrad }
    525      1.57  riastrad 
    526      1.57  riastrad static inline void
    527      1.57  riastrad vq_sync_uring_avail(struct virtio_softc *sc, struct virtqueue *vq, int ops)
    528      1.57  riastrad {
    529      1.57  riastrad 	uint16_t hdrlen = offsetof(struct vring_used, ring);
    530  1.63.2.1    martin 	size_t payloadlen = vq->vq_num * sizeof(struct vring_used_elem);
    531      1.57  riastrad 	size_t availlen = sizeof(uint16_t);
    532      1.57  riastrad 
    533      1.57  riastrad 	if ((sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX) == 0)
    534      1.57  riastrad 		return;
    535      1.57  riastrad 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    536      1.57  riastrad 	    vq->vq_usedoffset + hdrlen + payloadlen, availlen, ops);
    537       1.1   hannken }
    538       1.1   hannken 
    539       1.1   hannken static inline void
    540       1.1   hannken vq_sync_indirect(struct virtio_softc *sc, struct virtqueue *vq, int slot,
    541      1.57  riastrad     int ops)
    542       1.1   hannken {
    543      1.57  riastrad 	int offset = vq->vq_indirectoffset +
    544      1.57  riastrad 	    sizeof(struct vring_desc) * vq->vq_maxnsegs * slot;
    545       1.1   hannken 
    546       1.1   hannken 	bus_dmamap_sync(sc->sc_dmat, vq->vq_dmamap,
    547      1.57  riastrad 	    offset, sizeof(struct vring_desc) * vq->vq_maxnsegs, ops);
    548       1.1   hannken }
    549       1.1   hannken 
    550      1.41  yamaguch bool
    551      1.41  yamaguch virtio_vq_is_enqueued(struct virtio_softc *sc, struct virtqueue *vq)
    552      1.37  yamaguch {
    553      1.37  yamaguch 
    554      1.37  yamaguch 	if (vq->vq_queued) {
    555      1.37  yamaguch 		vq->vq_queued = 0;
    556      1.57  riastrad 		vq_sync_aring_all(sc, vq, BUS_DMASYNC_POSTWRITE);
    557      1.37  yamaguch 	}
    558      1.37  yamaguch 
    559      1.57  riastrad 	vq_sync_uring_header(sc, vq, BUS_DMASYNC_POSTREAD);
    560      1.57  riastrad 	if (vq->vq_used_idx == virtio_rw16(sc, vq->vq_used->idx))
    561      1.57  riastrad 		return 0;
    562      1.57  riastrad 	vq_sync_uring_payload(sc, vq, BUS_DMASYNC_POSTREAD);
    563      1.57  riastrad 	return 1;
    564      1.37  yamaguch }
    565      1.37  yamaguch 
    566      1.56  riastrad /*
    567      1.56  riastrad  * Scan vq, bus_dmamap_sync for the vqs (not for the payload),
    568      1.56  riastrad  * and calls (*vq_done)() if some entries are consumed.
    569      1.56  riastrad  *
    570      1.56  riastrad  * Can be used as sc_intrhand.
    571      1.56  riastrad  */
    572       1.1   hannken int
    573       1.1   hannken virtio_vq_intr(struct virtio_softc *sc)
    574       1.1   hannken {
    575       1.1   hannken 	struct virtqueue *vq;
    576       1.1   hannken 	int i, r = 0;
    577       1.1   hannken 
    578       1.1   hannken 	for (i = 0; i < sc->sc_nvqs; i++) {
    579       1.1   hannken 		vq = &sc->sc_vqs[i];
    580      1.41  yamaguch 		if (virtio_vq_is_enqueued(sc, vq) == 1) {
    581      1.41  yamaguch 			if (vq->vq_done)
    582      1.54       uwe 				r |= (*vq->vq_done)(vq);
    583      1.41  yamaguch 		}
    584       1.1   hannken 	}
    585       1.1   hannken 
    586       1.1   hannken 	return r;
    587       1.1   hannken }
    588       1.1   hannken 
    589      1.41  yamaguch int
    590      1.41  yamaguch virtio_vq_intrhand(struct virtio_softc *sc)
    591      1.37  yamaguch {
    592      1.41  yamaguch 	struct virtqueue *vq;
    593      1.41  yamaguch 	int i, r = 0;
    594      1.41  yamaguch 
    595      1.41  yamaguch 	for (i = 0; i < sc->sc_nvqs; i++) {
    596      1.41  yamaguch 		vq = &sc->sc_vqs[i];
    597      1.54       uwe 		r |= (*vq->vq_intrhand)(vq->vq_intrhand_arg);
    598      1.41  yamaguch 	}
    599      1.37  yamaguch 
    600      1.41  yamaguch 	return r;
    601      1.37  yamaguch }
    602      1.37  yamaguch 
    603      1.43   reinoud 
    604      1.43   reinoud /*
    605      1.43   reinoud  * Increase the event index in order to delay interrupts.
    606      1.43   reinoud  */
    607      1.43   reinoud int
    608      1.43   reinoud virtio_postpone_intr(struct virtio_softc *sc, struct virtqueue *vq,
    609      1.59  riastrad     uint16_t nslots)
    610      1.43   reinoud {
    611      1.43   reinoud 	uint16_t	idx, nused;
    612      1.43   reinoud 
    613      1.43   reinoud 	idx = vq->vq_used_idx + nslots;
    614      1.43   reinoud 
    615      1.43   reinoud 	/* set the new event index: avail_ring->used_event = idx */
    616      1.43   reinoud 	*vq->vq_used_event = virtio_rw16(sc, idx);
    617      1.57  riastrad 	vq_sync_aring_used(vq->vq_owner, vq, BUS_DMASYNC_PREWRITE);
    618      1.43   reinoud 	vq->vq_queued++;
    619      1.43   reinoud 
    620      1.43   reinoud 	nused = (uint16_t)
    621      1.59  riastrad 	    (virtio_rw16(sc, vq->vq_used->idx) - vq->vq_used_idx);
    622      1.43   reinoud 	KASSERT(nused <= vq->vq_num);
    623      1.43   reinoud 
    624      1.43   reinoud 	return nslots < nused;
    625      1.43   reinoud }
    626      1.43   reinoud 
    627      1.43   reinoud /*
    628      1.43   reinoud  * Postpone interrupt until 3/4 of the available descriptors have been
    629      1.43   reinoud  * consumed.
    630      1.43   reinoud  */
    631      1.43   reinoud int
    632      1.43   reinoud virtio_postpone_intr_smart(struct virtio_softc *sc, struct virtqueue *vq)
    633      1.43   reinoud {
    634      1.43   reinoud 	uint16_t	nslots;
    635      1.43   reinoud 
    636      1.43   reinoud 	nslots = (uint16_t)
    637      1.59  riastrad 	    (virtio_rw16(sc, vq->vq_avail->idx) - vq->vq_used_idx) * 3 / 4;
    638      1.43   reinoud 
    639      1.43   reinoud 	return virtio_postpone_intr(sc, vq, nslots);
    640      1.43   reinoud }
    641      1.43   reinoud 
    642      1.43   reinoud /*
    643      1.43   reinoud  * Postpone interrupt until all of the available descriptors have been
    644      1.43   reinoud  * consumed.
    645      1.43   reinoud  */
    646      1.43   reinoud int
    647      1.43   reinoud virtio_postpone_intr_far(struct virtio_softc *sc, struct virtqueue *vq)
    648      1.43   reinoud {
    649      1.43   reinoud 	uint16_t	nslots;
    650      1.43   reinoud 
    651      1.43   reinoud 	nslots = (uint16_t)
    652      1.59  riastrad 	    (virtio_rw16(sc, vq->vq_avail->idx) - vq->vq_used_idx);
    653      1.43   reinoud 
    654      1.43   reinoud 	return virtio_postpone_intr(sc, vq, nslots);
    655      1.43   reinoud }
    656      1.43   reinoud 
    657       1.1   hannken /*
    658       1.1   hannken  * Start/stop vq interrupt.  No guarantee.
    659       1.1   hannken  */
    660       1.1   hannken void
    661       1.1   hannken virtio_stop_vq_intr(struct virtio_softc *sc, struct virtqueue *vq)
    662       1.1   hannken {
    663      1.57  riastrad 
    664      1.43   reinoud 	if (sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX) {
    665      1.43   reinoud 		/*
    666      1.43   reinoud 		 * No way to disable the interrupt completely with
    667      1.43   reinoud 		 * RingEventIdx. Instead advance used_event by half the
    668      1.43   reinoud 		 * possible value. This won't happen soon and is far enough in
    669      1.43   reinoud 		 * the past to not trigger a spurios interrupt.
    670      1.43   reinoud 		 */
    671      1.43   reinoud 		*vq->vq_used_event = virtio_rw16(sc, vq->vq_used_idx + 0x8000);
    672      1.57  riastrad 		vq_sync_aring_used(sc, vq, BUS_DMASYNC_PREWRITE);
    673      1.43   reinoud 	} else {
    674      1.57  riastrad 		vq->vq_avail->flags |=
    675      1.57  riastrad 		    virtio_rw16(sc, VRING_AVAIL_F_NO_INTERRUPT);
    676      1.57  riastrad 		vq_sync_aring_header(sc, vq, BUS_DMASYNC_PREWRITE);
    677      1.43   reinoud 	}
    678       1.1   hannken 	vq->vq_queued++;
    679       1.1   hannken }
    680       1.1   hannken 
    681      1.43   reinoud int
    682       1.1   hannken virtio_start_vq_intr(struct virtio_softc *sc, struct virtqueue *vq)
    683       1.1   hannken {
    684      1.57  riastrad 
    685      1.43   reinoud 	if (sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX) {
    686      1.43   reinoud 		/*
    687      1.43   reinoud 		 * If event index feature is negotiated, enabling interrupts
    688      1.43   reinoud 		 * is done through setting the latest consumed index in the
    689      1.43   reinoud 		 * used_event field
    690      1.43   reinoud 		 */
    691      1.43   reinoud 		*vq->vq_used_event = virtio_rw16(sc, vq->vq_used_idx);
    692      1.57  riastrad 		vq_sync_aring_used(sc, vq, BUS_DMASYNC_PREWRITE);
    693      1.43   reinoud 	} else {
    694      1.57  riastrad 		vq->vq_avail->flags &=
    695      1.57  riastrad 		    ~virtio_rw16(sc, VRING_AVAIL_F_NO_INTERRUPT);
    696      1.57  riastrad 		vq_sync_aring_header(sc, vq, BUS_DMASYNC_PREWRITE);
    697      1.43   reinoud 	}
    698       1.1   hannken 	vq->vq_queued++;
    699      1.43   reinoud 
    700      1.57  riastrad 	vq_sync_uring_header(sc, vq, BUS_DMASYNC_POSTREAD);
    701      1.57  riastrad 	if (vq->vq_used_idx == virtio_rw16(sc, vq->vq_used->idx))
    702      1.57  riastrad 		return 0;
    703      1.57  riastrad 	vq_sync_uring_payload(sc, vq, BUS_DMASYNC_POSTREAD);
    704      1.57  riastrad 	return 1;
    705       1.1   hannken }
    706       1.1   hannken 
    707       1.1   hannken /*
    708       1.1   hannken  * Initialize vq structure.
    709       1.1   hannken  */
    710       1.1   hannken static void
    711      1.15   msaitoh virtio_init_vq(struct virtio_softc *sc, struct virtqueue *vq,
    712      1.15   msaitoh     const bool reinit)
    713       1.1   hannken {
    714       1.1   hannken 	int i, j;
    715       1.1   hannken 	int vq_size = vq->vq_num;
    716       1.1   hannken 
    717       1.1   hannken 	memset(vq->vq_vaddr, 0, vq->vq_bytesize);
    718       1.1   hannken 
    719       1.1   hannken 	/* build the indirect descriptor chain */
    720       1.1   hannken 	if (vq->vq_indirect != NULL) {
    721       1.1   hannken 		struct vring_desc *vd;
    722       1.1   hannken 
    723       1.1   hannken 		for (i = 0; i < vq_size; i++) {
    724       1.1   hannken 			vd = vq->vq_indirect;
    725       1.1   hannken 			vd += vq->vq_maxnsegs * i;
    726      1.59  riastrad 			for (j = 0; j < vq->vq_maxnsegs - 1; j++) {
    727      1.43   reinoud 				vd[j].next = virtio_rw16(sc, j + 1);
    728      1.23    martin 			}
    729       1.1   hannken 		}
    730       1.1   hannken 	}
    731       1.1   hannken 
    732       1.1   hannken 	/* free slot management */
    733       1.1   hannken 	SIMPLEQ_INIT(&vq->vq_freelist);
    734       1.1   hannken 	for (i = 0; i < vq_size; i++) {
    735      1.59  riastrad 		SIMPLEQ_INSERT_TAIL(&vq->vq_freelist, &vq->vq_entries[i],
    736      1.59  riastrad 		    qe_list);
    737       1.1   hannken 		vq->vq_entries[i].qe_index = i;
    738       1.1   hannken 	}
    739       1.1   hannken 	if (!reinit)
    740       1.1   hannken 		mutex_init(&vq->vq_freelist_lock, MUTEX_SPIN, sc->sc_ipl);
    741       1.1   hannken 
    742       1.1   hannken 	/* enqueue/dequeue status */
    743       1.1   hannken 	vq->vq_avail_idx = 0;
    744       1.1   hannken 	vq->vq_used_idx = 0;
    745       1.1   hannken 	vq->vq_queued = 0;
    746       1.1   hannken 	if (!reinit) {
    747       1.1   hannken 		mutex_init(&vq->vq_aring_lock, MUTEX_SPIN, sc->sc_ipl);
    748       1.1   hannken 		mutex_init(&vq->vq_uring_lock, MUTEX_SPIN, sc->sc_ipl);
    749       1.1   hannken 	}
    750      1.57  riastrad 	vq_sync_uring_all(sc, vq, BUS_DMASYNC_PREREAD);
    751       1.1   hannken 	vq->vq_queued++;
    752       1.1   hannken }
    753      1.48     skrll 
    754       1.1   hannken /*
    755       1.1   hannken  * Allocate/free a vq.
    756       1.1   hannken  */
    757       1.1   hannken int
    758      1.15   msaitoh virtio_alloc_vq(struct virtio_softc *sc, struct virtqueue *vq, int index,
    759      1.15   msaitoh     int maxsegsize, int maxnsegs, const char *name)
    760       1.1   hannken {
    761       1.1   hannken 	int vq_size, allocsize1, allocsize2, allocsize3, allocsize = 0;
    762      1.43   reinoud 	int rsegs, r, hdrlen;
    763      1.61     skrll #define VIRTQUEUE_ALIGN(n)	roundup(n, VIRTIO_PAGE_SIZE)
    764       1.1   hannken 
    765      1.22  jdolecek 	/* Make sure callers allocate vqs in order */
    766      1.22  jdolecek 	KASSERT(sc->sc_nvqs == index);
    767      1.22  jdolecek 
    768       1.1   hannken 	memset(vq, 0, sizeof(*vq));
    769       1.1   hannken 
    770      1.31  jakllsch 	vq_size = sc->sc_ops->read_queue_size(sc, index);
    771       1.1   hannken 	if (vq_size == 0) {
    772       1.1   hannken 		aprint_error_dev(sc->sc_dev,
    773      1.59  riastrad 		    "virtqueue not exist, index %d for %s\n",
    774      1.59  riastrad 		    index, name);
    775       1.1   hannken 		goto err;
    776       1.1   hannken 	}
    777      1.43   reinoud 
    778      1.43   reinoud 	hdrlen = sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX ? 3 : 2;
    779      1.43   reinoud 
    780       1.1   hannken 	/* allocsize1: descriptor table + avail ring + pad */
    781      1.62     skrll 	allocsize1 = VIRTQUEUE_ALIGN(sizeof(struct vring_desc) * vq_size
    782      1.62     skrll 	    + sizeof(uint16_t) * (hdrlen + vq_size));
    783       1.1   hannken 	/* allocsize2: used ring + pad */
    784      1.43   reinoud 	allocsize2 = VIRTQUEUE_ALIGN(sizeof(uint16_t) * hdrlen
    785      1.62     skrll 	    + sizeof(struct vring_used_elem) * vq_size);
    786       1.1   hannken 	/* allocsize3: indirect table */
    787       1.1   hannken 	if (sc->sc_indirect && maxnsegs >= MINSEG_INDIRECT)
    788       1.1   hannken 		allocsize3 = sizeof(struct vring_desc) * maxnsegs * vq_size;
    789       1.1   hannken 	else
    790       1.1   hannken 		allocsize3 = 0;
    791       1.1   hannken 	allocsize = allocsize1 + allocsize2 + allocsize3;
    792       1.1   hannken 
    793       1.1   hannken 	/* alloc and map the memory */
    794       1.1   hannken 	r = bus_dmamem_alloc(sc->sc_dmat, allocsize, VIRTIO_PAGE_SIZE, 0,
    795      1.59  riastrad 	    &vq->vq_segs[0], 1, &rsegs, BUS_DMA_WAITOK);
    796       1.1   hannken 	if (r != 0) {
    797       1.1   hannken 		aprint_error_dev(sc->sc_dev,
    798      1.59  riastrad 		    "virtqueue %d for %s allocation failed, "
    799      1.59  riastrad 		    "error code %d\n", index, name, r);
    800       1.1   hannken 		goto err;
    801       1.1   hannken 	}
    802      1.43   reinoud 	r = bus_dmamem_map(sc->sc_dmat, &vq->vq_segs[0], rsegs, allocsize,
    803      1.59  riastrad 	    &vq->vq_vaddr, BUS_DMA_WAITOK);
    804       1.1   hannken 	if (r != 0) {
    805       1.1   hannken 		aprint_error_dev(sc->sc_dev,
    806      1.59  riastrad 		    "virtqueue %d for %s map failed, "
    807      1.59  riastrad 		    "error code %d\n", index, name, r);
    808       1.1   hannken 		goto err;
    809       1.1   hannken 	}
    810       1.1   hannken 	r = bus_dmamap_create(sc->sc_dmat, allocsize, 1, allocsize, 0,
    811      1.59  riastrad 	    BUS_DMA_WAITOK, &vq->vq_dmamap);
    812       1.1   hannken 	if (r != 0) {
    813       1.1   hannken 		aprint_error_dev(sc->sc_dev,
    814      1.59  riastrad 		    "virtqueue %d for %s dmamap creation failed, "
    815      1.59  riastrad 		    "error code %d\n", index, name, r);
    816       1.1   hannken 		goto err;
    817       1.1   hannken 	}
    818       1.1   hannken 	r = bus_dmamap_load(sc->sc_dmat, vq->vq_dmamap,
    819      1.59  riastrad 	    vq->vq_vaddr, allocsize, NULL, BUS_DMA_WAITOK);
    820       1.1   hannken 	if (r != 0) {
    821       1.1   hannken 		aprint_error_dev(sc->sc_dev,
    822      1.59  riastrad 		    "virtqueue %d for %s dmamap load failed, "
    823      1.59  riastrad 		    "error code %d\n", index, name, r);
    824       1.1   hannken 		goto err;
    825       1.1   hannken 	}
    826       1.1   hannken 
    827       1.1   hannken 	/* remember addresses and offsets for later use */
    828       1.1   hannken 	vq->vq_owner = sc;
    829       1.1   hannken 	vq->vq_num = vq_size;
    830       1.1   hannken 	vq->vq_index = index;
    831       1.1   hannken 	vq->vq_desc = vq->vq_vaddr;
    832      1.62     skrll 	vq->vq_availoffset = sizeof(struct vring_desc) * vq_size;
    833      1.59  riastrad 	vq->vq_avail = (void *)(((char *)vq->vq_desc) + vq->vq_availoffset);
    834      1.59  riastrad 	vq->vq_used_event = (uint16_t *)((char *)vq->vq_avail +
    835      1.59  riastrad 	    offsetof(struct vring_avail, ring[vq->vq_num]));
    836       1.1   hannken 	vq->vq_usedoffset = allocsize1;
    837      1.59  riastrad 	vq->vq_used = (void *)(((char *)vq->vq_desc) + vq->vq_usedoffset);
    838      1.43   reinoud 	vq->vq_avail_event = (uint16_t *)((char *)vq->vq_used +
    839      1.59  riastrad 	    offsetof(struct vring_used, ring[vq->vq_num]));
    840      1.43   reinoud 
    841       1.1   hannken 	if (allocsize3 > 0) {
    842       1.1   hannken 		vq->vq_indirectoffset = allocsize1 + allocsize2;
    843      1.59  riastrad 		vq->vq_indirect = (void *)(((char *)vq->vq_desc)
    844      1.59  riastrad 		    + vq->vq_indirectoffset);
    845       1.1   hannken 	}
    846       1.1   hannken 	vq->vq_bytesize = allocsize;
    847       1.1   hannken 	vq->vq_maxsegsize = maxsegsize;
    848       1.1   hannken 	vq->vq_maxnsegs = maxnsegs;
    849       1.1   hannken 
    850       1.1   hannken 	/* free slot management */
    851      1.62     skrll 	vq->vq_entries = kmem_zalloc(sizeof(struct vq_entry) * vq_size,
    852      1.59  riastrad 	    KM_SLEEP);
    853       1.1   hannken 	virtio_init_vq(sc, vq, false);
    854       1.1   hannken 
    855      1.43   reinoud 	/* set the vq address */
    856      1.43   reinoud 	sc->sc_ops->setup_queue(sc, index,
    857      1.43   reinoud 	    vq->vq_dmamap->dm_segs[0].ds_addr);
    858      1.43   reinoud 
    859       1.1   hannken 	aprint_verbose_dev(sc->sc_dev,
    860      1.59  riastrad 	    "allocated %u byte for virtqueue %d for %s, size %d\n",
    861      1.59  riastrad 	    allocsize, index, name, vq_size);
    862       1.1   hannken 	if (allocsize3 > 0)
    863       1.1   hannken 		aprint_verbose_dev(sc->sc_dev,
    864      1.59  riastrad 		    "using %d byte (%d entries) indirect descriptors\n",
    865      1.59  riastrad 		    allocsize3, maxnsegs * vq_size);
    866      1.22  jdolecek 
    867      1.22  jdolecek 	sc->sc_nvqs++;
    868      1.22  jdolecek 
    869       1.1   hannken 	return 0;
    870       1.1   hannken 
    871       1.1   hannken err:
    872      1.34  jakllsch 	sc->sc_ops->setup_queue(sc, index, 0);
    873       1.1   hannken 	if (vq->vq_dmamap)
    874       1.1   hannken 		bus_dmamap_destroy(sc->sc_dmat, vq->vq_dmamap);
    875       1.1   hannken 	if (vq->vq_vaddr)
    876       1.1   hannken 		bus_dmamem_unmap(sc->sc_dmat, vq->vq_vaddr, allocsize);
    877       1.1   hannken 	if (vq->vq_segs[0].ds_addr)
    878       1.1   hannken 		bus_dmamem_free(sc->sc_dmat, &vq->vq_segs[0], 1);
    879       1.1   hannken 	memset(vq, 0, sizeof(*vq));
    880       1.1   hannken 
    881       1.1   hannken 	return -1;
    882       1.1   hannken }
    883       1.1   hannken 
    884       1.1   hannken int
    885       1.1   hannken virtio_free_vq(struct virtio_softc *sc, struct virtqueue *vq)
    886       1.1   hannken {
    887       1.1   hannken 	struct vq_entry *qe;
    888       1.1   hannken 	int i = 0;
    889       1.1   hannken 
    890       1.1   hannken 	/* device must be already deactivated */
    891       1.1   hannken 	/* confirm the vq is empty */
    892       1.1   hannken 	SIMPLEQ_FOREACH(qe, &vq->vq_freelist, qe_list) {
    893       1.1   hannken 		i++;
    894       1.1   hannken 	}
    895       1.1   hannken 	if (i != vq->vq_num) {
    896       1.1   hannken 		printf("%s: freeing non-empty vq, index %d\n",
    897      1.59  riastrad 		    device_xname(sc->sc_dev), vq->vq_index);
    898       1.1   hannken 		return EBUSY;
    899       1.1   hannken 	}
    900       1.1   hannken 
    901       1.1   hannken 	/* tell device that there's no virtqueue any longer */
    902      1.31  jakllsch 	sc->sc_ops->setup_queue(sc, vq->vq_index, 0);
    903       1.1   hannken 
    904      1.57  riastrad 	vq_sync_aring_all(sc, vq, BUS_DMASYNC_POSTWRITE);
    905      1.57  riastrad 
    906      1.14  christos 	kmem_free(vq->vq_entries, sizeof(*vq->vq_entries) * vq->vq_num);
    907       1.1   hannken 	bus_dmamap_unload(sc->sc_dmat, vq->vq_dmamap);
    908       1.1   hannken 	bus_dmamap_destroy(sc->sc_dmat, vq->vq_dmamap);
    909       1.1   hannken 	bus_dmamem_unmap(sc->sc_dmat, vq->vq_vaddr, vq->vq_bytesize);
    910       1.1   hannken 	bus_dmamem_free(sc->sc_dmat, &vq->vq_segs[0], 1);
    911       1.1   hannken 	mutex_destroy(&vq->vq_freelist_lock);
    912       1.1   hannken 	mutex_destroy(&vq->vq_uring_lock);
    913       1.1   hannken 	mutex_destroy(&vq->vq_aring_lock);
    914       1.1   hannken 	memset(vq, 0, sizeof(*vq));
    915       1.1   hannken 
    916      1.22  jdolecek 	sc->sc_nvqs--;
    917      1.22  jdolecek 
    918       1.1   hannken 	return 0;
    919       1.1   hannken }
    920       1.1   hannken 
    921       1.1   hannken /*
    922       1.1   hannken  * Free descriptor management.
    923       1.1   hannken  */
    924       1.1   hannken static struct vq_entry *
    925       1.1   hannken vq_alloc_entry(struct virtqueue *vq)
    926       1.1   hannken {
    927       1.1   hannken 	struct vq_entry *qe;
    928       1.1   hannken 
    929       1.1   hannken 	mutex_enter(&vq->vq_freelist_lock);
    930       1.1   hannken 	if (SIMPLEQ_EMPTY(&vq->vq_freelist)) {
    931       1.1   hannken 		mutex_exit(&vq->vq_freelist_lock);
    932       1.1   hannken 		return NULL;
    933       1.1   hannken 	}
    934       1.1   hannken 	qe = SIMPLEQ_FIRST(&vq->vq_freelist);
    935       1.1   hannken 	SIMPLEQ_REMOVE_HEAD(&vq->vq_freelist, qe_list);
    936       1.1   hannken 	mutex_exit(&vq->vq_freelist_lock);
    937       1.1   hannken 
    938       1.1   hannken 	return qe;
    939       1.1   hannken }
    940       1.1   hannken 
    941       1.1   hannken static void
    942       1.1   hannken vq_free_entry(struct virtqueue *vq, struct vq_entry *qe)
    943       1.1   hannken {
    944       1.1   hannken 	mutex_enter(&vq->vq_freelist_lock);
    945       1.1   hannken 	SIMPLEQ_INSERT_TAIL(&vq->vq_freelist, qe, qe_list);
    946       1.1   hannken 	mutex_exit(&vq->vq_freelist_lock);
    947       1.1   hannken 
    948       1.1   hannken 	return;
    949       1.1   hannken }
    950       1.1   hannken 
    951       1.1   hannken /*
    952       1.1   hannken  * Enqueue several dmamaps as a single request.
    953       1.1   hannken  */
    954       1.1   hannken /*
    955       1.1   hannken  * Typical usage:
    956       1.1   hannken  *  <queue size> number of followings are stored in arrays
    957       1.1   hannken  *  - command blocks (in dmamem) should be pre-allocated and mapped
    958       1.1   hannken  *  - dmamaps for command blocks should be pre-allocated and loaded
    959       1.1   hannken  *  - dmamaps for payload should be pre-allocated
    960       1.1   hannken  *      r = virtio_enqueue_prep(sc, vq, &slot);		// allocate a slot
    961       1.1   hannken  *	if (r)		// currently 0 or EAGAIN
    962      1.59  riastrad  *		return r;
    963       1.1   hannken  *	r = bus_dmamap_load(dmat, dmamap_payload[slot], data, count, ..);
    964       1.1   hannken  *	if (r) {
    965      1.59  riastrad  *		virtio_enqueue_abort(sc, vq, slot);
    966      1.59  riastrad  *		return r;
    967       1.1   hannken  *	}
    968      1.48     skrll  *	r = virtio_enqueue_reserve(sc, vq, slot,
    969      1.59  riastrad  *	    dmamap_payload[slot]->dm_nsegs + 1);
    970       1.1   hannken  *							// ^ +1 for command
    971       1.1   hannken  *	if (r) {	// currently 0 or EAGAIN
    972      1.59  riastrad  *		bus_dmamap_unload(dmat, dmamap_payload[slot]);
    973      1.59  riastrad  *		return r;				// do not call abort()
    974       1.1   hannken  *	}
    975       1.1   hannken  *	<setup and prepare commands>
    976       1.1   hannken  *	bus_dmamap_sync(dmat, dmamap_cmd[slot],... BUS_DMASYNC_PREWRITE);
    977       1.1   hannken  *	bus_dmamap_sync(dmat, dmamap_payload[slot],...);
    978       1.1   hannken  *	virtio_enqueue(sc, vq, slot, dmamap_cmd[slot], false);
    979       1.1   hannken  *	virtio_enqueue(sc, vq, slot, dmamap_payload[slot], iswrite);
    980       1.1   hannken  *	virtio_enqueue_commit(sc, vq, slot, true);
    981       1.1   hannken  */
    982       1.1   hannken 
    983       1.1   hannken /*
    984       1.1   hannken  * enqueue_prep: allocate a slot number
    985       1.1   hannken  */
    986       1.1   hannken int
    987       1.1   hannken virtio_enqueue_prep(struct virtio_softc *sc, struct virtqueue *vq, int *slotp)
    988       1.1   hannken {
    989       1.1   hannken 	struct vq_entry *qe1;
    990       1.1   hannken 
    991       1.1   hannken 	KASSERT(slotp != NULL);
    992       1.1   hannken 
    993       1.1   hannken 	qe1 = vq_alloc_entry(vq);
    994       1.1   hannken 	if (qe1 == NULL)
    995       1.1   hannken 		return EAGAIN;
    996       1.1   hannken 	/* next slot is not allocated yet */
    997       1.1   hannken 	qe1->qe_next = -1;
    998       1.1   hannken 	*slotp = qe1->qe_index;
    999       1.1   hannken 
   1000       1.1   hannken 	return 0;
   1001       1.1   hannken }
   1002       1.1   hannken 
   1003       1.1   hannken /*
   1004       1.1   hannken  * enqueue_reserve: allocate remaining slots and build the descriptor chain.
   1005       1.1   hannken  */
   1006       1.1   hannken int
   1007       1.1   hannken virtio_enqueue_reserve(struct virtio_softc *sc, struct virtqueue *vq,
   1008      1.59  riastrad     int slot, int nsegs)
   1009       1.1   hannken {
   1010       1.1   hannken 	int indirect;
   1011       1.1   hannken 	struct vq_entry *qe1 = &vq->vq_entries[slot];
   1012       1.1   hannken 
   1013       1.1   hannken 	KASSERT(qe1->qe_next == -1);
   1014       1.1   hannken 	KASSERT(1 <= nsegs && nsegs <= vq->vq_num);
   1015       1.1   hannken 
   1016       1.1   hannken 	if ((vq->vq_indirect != NULL) &&
   1017       1.1   hannken 	    (nsegs >= MINSEG_INDIRECT) &&
   1018       1.1   hannken 	    (nsegs <= vq->vq_maxnsegs))
   1019       1.1   hannken 		indirect = 1;
   1020       1.1   hannken 	else
   1021       1.1   hannken 		indirect = 0;
   1022       1.1   hannken 	qe1->qe_indirect = indirect;
   1023       1.1   hannken 
   1024       1.1   hannken 	if (indirect) {
   1025       1.1   hannken 		struct vring_desc *vd;
   1026      1.43   reinoud 		uint64_t addr;
   1027       1.1   hannken 		int i;
   1028       1.1   hannken 
   1029       1.1   hannken 		vd = &vq->vq_desc[qe1->qe_index];
   1030      1.43   reinoud 		addr = vq->vq_dmamap->dm_segs[0].ds_addr
   1031      1.59  riastrad 		    + vq->vq_indirectoffset;
   1032      1.43   reinoud 		addr += sizeof(struct vring_desc)
   1033      1.59  riastrad 		    * vq->vq_maxnsegs * qe1->qe_index;
   1034      1.43   reinoud 		vd->addr  = virtio_rw64(sc, addr);
   1035      1.43   reinoud 		vd->len   = virtio_rw32(sc, sizeof(struct vring_desc) * nsegs);
   1036      1.43   reinoud 		vd->flags = virtio_rw16(sc, VRING_DESC_F_INDIRECT);
   1037       1.1   hannken 
   1038       1.1   hannken 		vd = vq->vq_indirect;
   1039       1.1   hannken 		vd += vq->vq_maxnsegs * qe1->qe_index;
   1040       1.1   hannken 		qe1->qe_desc_base = vd;
   1041       1.1   hannken 
   1042      1.59  riastrad 		for (i = 0; i < nsegs - 1; i++) {
   1043      1.43   reinoud 			vd[i].flags = virtio_rw16(sc, VRING_DESC_F_NEXT);
   1044       1.1   hannken 		}
   1045      1.43   reinoud 		vd[i].flags  = virtio_rw16(sc, 0);
   1046       1.1   hannken 		qe1->qe_next = 0;
   1047       1.1   hannken 
   1048       1.1   hannken 		return 0;
   1049       1.1   hannken 	} else {
   1050       1.1   hannken 		struct vring_desc *vd;
   1051       1.1   hannken 		struct vq_entry *qe;
   1052       1.1   hannken 		int i, s;
   1053       1.1   hannken 
   1054       1.1   hannken 		vd = &vq->vq_desc[0];
   1055       1.1   hannken 		qe1->qe_desc_base = vd;
   1056       1.1   hannken 		qe1->qe_next = qe1->qe_index;
   1057       1.1   hannken 		s = slot;
   1058       1.1   hannken 		for (i = 0; i < nsegs - 1; i++) {
   1059       1.1   hannken 			qe = vq_alloc_entry(vq);
   1060       1.1   hannken 			if (qe == NULL) {
   1061      1.43   reinoud 				vd[s].flags = virtio_rw16(sc, 0);
   1062       1.1   hannken 				virtio_enqueue_abort(sc, vq, slot);
   1063       1.1   hannken 				return EAGAIN;
   1064       1.1   hannken 			}
   1065      1.43   reinoud 			vd[s].flags = virtio_rw16(sc, VRING_DESC_F_NEXT);
   1066      1.43   reinoud 			vd[s].next  = virtio_rw16(sc, qe->qe_index);
   1067       1.1   hannken 			s = qe->qe_index;
   1068       1.1   hannken 		}
   1069      1.43   reinoud 		vd[s].flags = virtio_rw16(sc, 0);
   1070       1.1   hannken 
   1071       1.1   hannken 		return 0;
   1072       1.1   hannken 	}
   1073       1.1   hannken }
   1074       1.1   hannken 
   1075       1.1   hannken /*
   1076       1.1   hannken  * enqueue: enqueue a single dmamap.
   1077       1.1   hannken  */
   1078       1.1   hannken int
   1079       1.1   hannken virtio_enqueue(struct virtio_softc *sc, struct virtqueue *vq, int slot,
   1080      1.59  riastrad     bus_dmamap_t dmamap, bool write)
   1081       1.1   hannken {
   1082       1.1   hannken 	struct vq_entry *qe1 = &vq->vq_entries[slot];
   1083       1.1   hannken 	struct vring_desc *vd = qe1->qe_desc_base;
   1084       1.1   hannken 	int i;
   1085       1.1   hannken 	int s = qe1->qe_next;
   1086       1.1   hannken 
   1087       1.1   hannken 	KASSERT(s >= 0);
   1088       1.1   hannken 	KASSERT(dmamap->dm_nsegs > 0);
   1089       1.1   hannken 
   1090       1.1   hannken 	for (i = 0; i < dmamap->dm_nsegs; i++) {
   1091      1.43   reinoud 		vd[s].addr = virtio_rw64(sc, dmamap->dm_segs[i].ds_addr);
   1092      1.43   reinoud 		vd[s].len  = virtio_rw32(sc, dmamap->dm_segs[i].ds_len);
   1093       1.1   hannken 		if (!write)
   1094      1.43   reinoud 			vd[s].flags |= virtio_rw16(sc, VRING_DESC_F_WRITE);
   1095      1.43   reinoud 		s = virtio_rw16(sc, vd[s].next);
   1096       1.1   hannken 	}
   1097       1.1   hannken 	qe1->qe_next = s;
   1098       1.1   hannken 
   1099       1.1   hannken 	return 0;
   1100       1.1   hannken }
   1101       1.1   hannken 
   1102       1.1   hannken int
   1103       1.1   hannken virtio_enqueue_p(struct virtio_softc *sc, struct virtqueue *vq, int slot,
   1104      1.59  riastrad     bus_dmamap_t dmamap, bus_addr_t start, bus_size_t len,
   1105      1.59  riastrad     bool write)
   1106       1.1   hannken {
   1107       1.1   hannken 	struct vq_entry *qe1 = &vq->vq_entries[slot];
   1108       1.1   hannken 	struct vring_desc *vd = qe1->qe_desc_base;
   1109       1.1   hannken 	int s = qe1->qe_next;
   1110       1.1   hannken 
   1111       1.1   hannken 	KASSERT(s >= 0);
   1112       1.1   hannken 	KASSERT(dmamap->dm_nsegs == 1); /* XXX */
   1113      1.59  riastrad 	KASSERT(dmamap->dm_segs[0].ds_len > start);
   1114      1.59  riastrad 	KASSERT(dmamap->dm_segs[0].ds_len >= start + len);
   1115       1.1   hannken 
   1116      1.43   reinoud 	vd[s].addr = virtio_rw64(sc, dmamap->dm_segs[0].ds_addr + start);
   1117      1.43   reinoud 	vd[s].len  = virtio_rw32(sc, len);
   1118       1.1   hannken 	if (!write)
   1119      1.43   reinoud 		vd[s].flags |= virtio_rw16(sc, VRING_DESC_F_WRITE);
   1120      1.43   reinoud 	qe1->qe_next = virtio_rw16(sc, vd[s].next);
   1121       1.1   hannken 
   1122       1.1   hannken 	return 0;
   1123       1.1   hannken }
   1124       1.1   hannken 
   1125       1.1   hannken /*
   1126       1.1   hannken  * enqueue_commit: add it to the aring.
   1127       1.1   hannken  */
   1128       1.1   hannken int
   1129       1.1   hannken virtio_enqueue_commit(struct virtio_softc *sc, struct virtqueue *vq, int slot,
   1130      1.59  riastrad     bool notifynow)
   1131       1.1   hannken {
   1132       1.1   hannken 	struct vq_entry *qe1;
   1133       1.1   hannken 
   1134       1.1   hannken 	if (slot < 0) {
   1135       1.1   hannken 		mutex_enter(&vq->vq_aring_lock);
   1136       1.1   hannken 		goto notify;
   1137       1.1   hannken 	}
   1138       1.1   hannken 	vq_sync_descs(sc, vq, BUS_DMASYNC_PREWRITE);
   1139       1.1   hannken 	qe1 = &vq->vq_entries[slot];
   1140       1.1   hannken 	if (qe1->qe_indirect)
   1141       1.1   hannken 		vq_sync_indirect(sc, vq, slot, BUS_DMASYNC_PREWRITE);
   1142       1.1   hannken 	mutex_enter(&vq->vq_aring_lock);
   1143      1.43   reinoud 	vq->vq_avail->ring[(vq->vq_avail_idx++) % vq->vq_num] =
   1144      1.57  riastrad 	    virtio_rw16(sc, slot);
   1145       1.1   hannken 
   1146       1.1   hannken notify:
   1147       1.1   hannken 	if (notifynow) {
   1148      1.43   reinoud 		uint16_t o, n, t;
   1149      1.43   reinoud 		uint16_t flags;
   1150      1.57  riastrad 
   1151  1.63.2.1    martin 		o = virtio_rw16(sc, vq->vq_avail->idx) - 1;
   1152      1.43   reinoud 		n = vq->vq_avail_idx;
   1153      1.43   reinoud 
   1154      1.57  riastrad 		/*
   1155      1.57  riastrad 		 * Prepare for `device->CPU' (host->guest) transfer
   1156      1.57  riastrad 		 * into the buffer.  This must happen before we commit
   1157      1.57  riastrad 		 * the vq->vq_avail->idx update to ensure we're not
   1158      1.57  riastrad 		 * still using the buffer in case program-prior loads
   1159      1.57  riastrad 		 * or stores in it get delayed past the store to
   1160      1.57  riastrad 		 * vq->vq_avail->idx.
   1161      1.57  riastrad 		 */
   1162      1.57  riastrad 		vq_sync_uring_all(sc, vq, BUS_DMASYNC_PREREAD);
   1163      1.57  riastrad 
   1164      1.57  riastrad 		/* ensure payload is published, then avail idx */
   1165      1.57  riastrad 		vq_sync_aring_payload(sc, vq, BUS_DMASYNC_PREWRITE);
   1166      1.43   reinoud 		vq->vq_avail->idx = virtio_rw16(sc, vq->vq_avail_idx);
   1167      1.57  riastrad 		vq_sync_aring_header(sc, vq, BUS_DMASYNC_PREWRITE);
   1168       1.1   hannken 		vq->vq_queued++;
   1169      1.43   reinoud 
   1170      1.43   reinoud 		if (sc->sc_active_features & VIRTIO_F_RING_EVENT_IDX) {
   1171      1.57  riastrad 			vq_sync_uring_avail(sc, vq, BUS_DMASYNC_POSTREAD);
   1172      1.43   reinoud 			t = virtio_rw16(sc, *vq->vq_avail_event) + 1;
   1173      1.43   reinoud 			if ((uint16_t) (n - t) < (uint16_t) (n - o))
   1174      1.43   reinoud 				sc->sc_ops->kick(sc, vq->vq_index);
   1175      1.43   reinoud 		} else {
   1176      1.57  riastrad 			vq_sync_uring_header(sc, vq, BUS_DMASYNC_POSTREAD);
   1177      1.43   reinoud 			flags = virtio_rw16(sc, vq->vq_used->flags);
   1178      1.43   reinoud 			if (!(flags & VRING_USED_F_NO_NOTIFY))
   1179      1.43   reinoud 				sc->sc_ops->kick(sc, vq->vq_index);
   1180      1.43   reinoud 		}
   1181       1.1   hannken 	}
   1182       1.1   hannken 	mutex_exit(&vq->vq_aring_lock);
   1183       1.1   hannken 
   1184       1.1   hannken 	return 0;
   1185       1.1   hannken }
   1186       1.1   hannken 
   1187       1.1   hannken /*
   1188       1.1   hannken  * enqueue_abort: rollback.
   1189       1.1   hannken  */
   1190       1.1   hannken int
   1191       1.1   hannken virtio_enqueue_abort(struct virtio_softc *sc, struct virtqueue *vq, int slot)
   1192       1.1   hannken {
   1193       1.1   hannken 	struct vq_entry *qe = &vq->vq_entries[slot];
   1194       1.1   hannken 	struct vring_desc *vd;
   1195       1.1   hannken 	int s;
   1196       1.1   hannken 
   1197       1.1   hannken 	if (qe->qe_next < 0) {
   1198       1.1   hannken 		vq_free_entry(vq, qe);
   1199       1.1   hannken 		return 0;
   1200       1.1   hannken 	}
   1201       1.1   hannken 
   1202       1.1   hannken 	s = slot;
   1203       1.1   hannken 	vd = &vq->vq_desc[0];
   1204      1.43   reinoud 	while (virtio_rw16(sc, vd[s].flags) & VRING_DESC_F_NEXT) {
   1205      1.43   reinoud 		s = virtio_rw16(sc, vd[s].next);
   1206       1.1   hannken 		vq_free_entry(vq, qe);
   1207       1.1   hannken 		qe = &vq->vq_entries[s];
   1208       1.1   hannken 	}
   1209       1.1   hannken 	vq_free_entry(vq, qe);
   1210       1.1   hannken 	return 0;
   1211       1.1   hannken }
   1212       1.1   hannken 
   1213       1.1   hannken /*
   1214       1.1   hannken  * Dequeue a request.
   1215       1.1   hannken  */
   1216       1.1   hannken /*
   1217       1.1   hannken  * dequeue: dequeue a request from uring; dmamap_sync for uring is
   1218       1.1   hannken  *	    already done in the interrupt handler.
   1219       1.1   hannken  */
   1220       1.1   hannken int
   1221       1.1   hannken virtio_dequeue(struct virtio_softc *sc, struct virtqueue *vq,
   1222      1.59  riastrad     int *slotp, int *lenp)
   1223       1.1   hannken {
   1224       1.1   hannken 	uint16_t slot, usedidx;
   1225       1.1   hannken 	struct vq_entry *qe;
   1226       1.1   hannken 
   1227      1.43   reinoud 	if (vq->vq_used_idx == virtio_rw16(sc, vq->vq_used->idx))
   1228       1.1   hannken 		return ENOENT;
   1229       1.1   hannken 	mutex_enter(&vq->vq_uring_lock);
   1230       1.1   hannken 	usedidx = vq->vq_used_idx++;
   1231       1.1   hannken 	mutex_exit(&vq->vq_uring_lock);
   1232       1.1   hannken 	usedidx %= vq->vq_num;
   1233      1.43   reinoud 	slot = virtio_rw32(sc, vq->vq_used->ring[usedidx].id);
   1234       1.1   hannken 	qe = &vq->vq_entries[slot];
   1235       1.1   hannken 
   1236       1.1   hannken 	if (qe->qe_indirect)
   1237       1.1   hannken 		vq_sync_indirect(sc, vq, slot, BUS_DMASYNC_POSTWRITE);
   1238       1.1   hannken 
   1239       1.1   hannken 	if (slotp)
   1240       1.1   hannken 		*slotp = slot;
   1241       1.1   hannken 	if (lenp)
   1242      1.43   reinoud 		*lenp = virtio_rw32(sc, vq->vq_used->ring[usedidx].len);
   1243       1.1   hannken 
   1244       1.1   hannken 	return 0;
   1245       1.1   hannken }
   1246       1.1   hannken 
   1247       1.1   hannken /*
   1248       1.1   hannken  * dequeue_commit: complete dequeue; the slot is recycled for future use.
   1249       1.1   hannken  *                 if you forget to call this the slot will be leaked.
   1250       1.1   hannken  */
   1251       1.1   hannken int
   1252       1.1   hannken virtio_dequeue_commit(struct virtio_softc *sc, struct virtqueue *vq, int slot)
   1253       1.1   hannken {
   1254       1.1   hannken 	struct vq_entry *qe = &vq->vq_entries[slot];
   1255       1.1   hannken 	struct vring_desc *vd = &vq->vq_desc[0];
   1256       1.1   hannken 	int s = slot;
   1257       1.1   hannken 
   1258      1.43   reinoud 	while (virtio_rw16(sc, vd[s].flags) & VRING_DESC_F_NEXT) {
   1259      1.43   reinoud 		s = virtio_rw16(sc, vd[s].next);
   1260       1.1   hannken 		vq_free_entry(vq, qe);
   1261       1.1   hannken 		qe = &vq->vq_entries[s];
   1262       1.1   hannken 	}
   1263       1.1   hannken 	vq_free_entry(vq, qe);
   1264       1.1   hannken 
   1265       1.1   hannken 	return 0;
   1266       1.1   hannken }
   1267      1.18  pgoyette 
   1268      1.22  jdolecek /*
   1269      1.22  jdolecek  * Attach a child, fill all the members.
   1270      1.22  jdolecek  */
   1271      1.22  jdolecek void
   1272      1.48     skrll virtio_child_attach_start(struct virtio_softc *sc, device_t child, int ipl,
   1273      1.59  riastrad     struct virtqueue *vqs,
   1274      1.59  riastrad     virtio_callback config_change,
   1275      1.59  riastrad     virtio_callback intr_hand,
   1276      1.59  riastrad     int req_flags, int req_features, const char *feat_bits)
   1277      1.22  jdolecek {
   1278      1.43   reinoud 	char buf[1024];
   1279      1.22  jdolecek 
   1280      1.22  jdolecek 	sc->sc_child = child;
   1281      1.22  jdolecek 	sc->sc_ipl = ipl;
   1282      1.22  jdolecek 	sc->sc_vqs = vqs;
   1283      1.22  jdolecek 	sc->sc_config_change = config_change;
   1284      1.22  jdolecek 	sc->sc_intrhand = intr_hand;
   1285      1.22  jdolecek 	sc->sc_flags = req_flags;
   1286      1.22  jdolecek 
   1287      1.43   reinoud 	virtio_negotiate_features(sc, req_features);
   1288      1.43   reinoud 	snprintb(buf, sizeof(buf), feat_bits, sc->sc_active_features);
   1289      1.43   reinoud 	aprint_normal(": features: %s\n", buf);
   1290      1.22  jdolecek 	aprint_naive("\n");
   1291      1.22  jdolecek }
   1292      1.22  jdolecek 
   1293      1.37  yamaguch void
   1294      1.37  yamaguch virtio_child_attach_set_vqs(struct virtio_softc *sc,
   1295      1.37  yamaguch     struct virtqueue *vqs, int nvq_pairs)
   1296      1.37  yamaguch {
   1297      1.39  yamaguch 
   1298      1.39  yamaguch 	KASSERT(nvq_pairs == 1 ||
   1299      1.43   reinoud 	    (sc->sc_flags & VIRTIO_F_INTR_SOFTINT) == 0);
   1300      1.37  yamaguch 	if (nvq_pairs > 1)
   1301      1.37  yamaguch 		sc->sc_child_mq = true;
   1302      1.37  yamaguch 
   1303      1.37  yamaguch 	sc->sc_vqs = vqs;
   1304      1.37  yamaguch }
   1305      1.37  yamaguch 
   1306      1.22  jdolecek int
   1307      1.22  jdolecek virtio_child_attach_finish(struct virtio_softc *sc)
   1308      1.22  jdolecek {
   1309      1.22  jdolecek 	int r;
   1310      1.22  jdolecek 
   1311      1.44   reinoud 	sc->sc_finished_called = true;
   1312      1.50  yamaguch 	r = sc->sc_ops->alloc_interrupts(sc);
   1313      1.50  yamaguch 	if (r != 0) {
   1314      1.59  riastrad 		aprint_error_dev(sc->sc_dev,
   1315      1.59  riastrad 		    "failed to allocate interrupts\n");
   1316      1.50  yamaguch 		goto fail;
   1317      1.50  yamaguch 	}
   1318      1.50  yamaguch 
   1319      1.51  yamaguch 	r = sc->sc_ops->setup_interrupts(sc, 0);
   1320      1.22  jdolecek 	if (r != 0) {
   1321      1.22  jdolecek 		aprint_error_dev(sc->sc_dev, "failed to setup interrupts\n");
   1322      1.52  yamaguch 		goto fail;
   1323      1.31  jakllsch 	}
   1324      1.31  jakllsch 
   1325      1.31  jakllsch 	KASSERT(sc->sc_soft_ih == NULL);
   1326      1.43   reinoud 	if (sc->sc_flags & VIRTIO_F_INTR_SOFTINT) {
   1327      1.48     skrll 		u_int flags = SOFTINT_NET;
   1328      1.43   reinoud 		if (sc->sc_flags & VIRTIO_F_INTR_MPSAFE)
   1329      1.31  jakllsch 			flags |= SOFTINT_MPSAFE;
   1330      1.31  jakllsch 
   1331      1.59  riastrad 		sc->sc_soft_ih = softint_establish(flags, virtio_soft_intr,
   1332      1.59  riastrad 		    sc);
   1333      1.31  jakllsch 		if (sc->sc_soft_ih == NULL) {
   1334      1.31  jakllsch 			sc->sc_ops->free_interrupts(sc);
   1335      1.31  jakllsch 			aprint_error_dev(sc->sc_dev,
   1336      1.31  jakllsch 			    "failed to establish soft interrupt\n");
   1337      1.31  jakllsch 			goto fail;
   1338      1.31  jakllsch 		}
   1339      1.22  jdolecek 	}
   1340      1.22  jdolecek 
   1341      1.22  jdolecek 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK);
   1342      1.31  jakllsch 	return 0;
   1343      1.22  jdolecek 
   1344      1.31  jakllsch fail:
   1345      1.37  yamaguch 	if (sc->sc_soft_ih) {
   1346      1.37  yamaguch 		softint_disestablish(sc->sc_soft_ih);
   1347      1.37  yamaguch 		sc->sc_soft_ih = NULL;
   1348      1.37  yamaguch 	}
   1349      1.37  yamaguch 
   1350      1.52  yamaguch 	sc->sc_ops->free_interrupts(sc);
   1351      1.52  yamaguch 
   1352      1.31  jakllsch 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
   1353      1.31  jakllsch 	return 1;
   1354      1.22  jdolecek }
   1355      1.22  jdolecek 
   1356      1.22  jdolecek void
   1357      1.22  jdolecek virtio_child_detach(struct virtio_softc *sc)
   1358      1.22  jdolecek {
   1359      1.22  jdolecek 	sc->sc_child = NULL;
   1360      1.22  jdolecek 	sc->sc_vqs = NULL;
   1361      1.22  jdolecek 
   1362      1.22  jdolecek 	virtio_device_reset(sc);
   1363      1.22  jdolecek 
   1364      1.31  jakllsch 	sc->sc_ops->free_interrupts(sc);
   1365      1.31  jakllsch 
   1366      1.31  jakllsch 	if (sc->sc_soft_ih) {
   1367      1.31  jakllsch 		softint_disestablish(sc->sc_soft_ih);
   1368      1.31  jakllsch 		sc->sc_soft_ih = NULL;
   1369      1.31  jakllsch 	}
   1370      1.22  jdolecek }
   1371      1.22  jdolecek 
   1372      1.22  jdolecek void
   1373      1.22  jdolecek virtio_child_attach_failed(struct virtio_softc *sc)
   1374      1.22  jdolecek {
   1375      1.22  jdolecek 	virtio_child_detach(sc);
   1376      1.22  jdolecek 
   1377      1.22  jdolecek 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
   1378      1.22  jdolecek 
   1379      1.22  jdolecek 	sc->sc_child = VIRTIO_CHILD_FAILED;
   1380      1.22  jdolecek }
   1381      1.22  jdolecek 
   1382      1.22  jdolecek bus_dma_tag_t
   1383      1.22  jdolecek virtio_dmat(struct virtio_softc *sc)
   1384      1.22  jdolecek {
   1385      1.22  jdolecek 	return sc->sc_dmat;
   1386      1.22  jdolecek }
   1387      1.22  jdolecek 
   1388      1.22  jdolecek device_t
   1389      1.22  jdolecek virtio_child(struct virtio_softc *sc)
   1390      1.22  jdolecek {
   1391      1.22  jdolecek 	return sc->sc_child;
   1392      1.22  jdolecek }
   1393      1.22  jdolecek 
   1394      1.22  jdolecek int
   1395      1.22  jdolecek virtio_intrhand(struct virtio_softc *sc)
   1396      1.22  jdolecek {
   1397      1.54       uwe 	return (*sc->sc_intrhand)(sc);
   1398      1.22  jdolecek }
   1399      1.22  jdolecek 
   1400      1.43   reinoud uint64_t
   1401      1.22  jdolecek virtio_features(struct virtio_softc *sc)
   1402      1.22  jdolecek {
   1403      1.43   reinoud 	return sc->sc_active_features;
   1404      1.22  jdolecek }
   1405      1.22  jdolecek 
   1406      1.35  jakllsch int
   1407      1.43   reinoud virtio_attach_failed(struct virtio_softc *sc)
   1408      1.35  jakllsch {
   1409      1.43   reinoud 	device_t self = sc->sc_dev;
   1410      1.35  jakllsch 
   1411      1.43   reinoud 	/* no error if its not connected, but its failed */
   1412      1.43   reinoud 	if (sc->sc_childdevid == 0)
   1413      1.43   reinoud 		return 1;
   1414      1.36  jmcneill 
   1415      1.43   reinoud 	if (sc->sc_child == NULL) {
   1416      1.43   reinoud 		aprint_error_dev(self,
   1417      1.59  riastrad 		    "no matching child driver; not configured\n");
   1418      1.43   reinoud 		return 1;
   1419      1.43   reinoud 	}
   1420      1.35  jakllsch 
   1421      1.43   reinoud 	if (sc->sc_child == VIRTIO_CHILD_FAILED) {
   1422      1.43   reinoud 		aprint_error_dev(self, "virtio configuration failed\n");
   1423      1.43   reinoud 		return 1;
   1424      1.43   reinoud 	}
   1425      1.44   reinoud 
   1426      1.44   reinoud 	/* sanity check */
   1427      1.44   reinoud 	if (!sc->sc_finished_called) {
   1428      1.44   reinoud 		aprint_error_dev(self, "virtio internal error, child driver "
   1429      1.59  riastrad 		    "signaled OK but didn't initialize interrupts\n");
   1430      1.44   reinoud 		return 1;
   1431      1.44   reinoud 	}
   1432      1.44   reinoud 
   1433      1.43   reinoud 	return 0;
   1434      1.43   reinoud }
   1435      1.43   reinoud 
   1436      1.43   reinoud void
   1437      1.43   reinoud virtio_print_device_type(device_t self, int id, int revision)
   1438      1.43   reinoud {
   1439      1.58  riastrad 	aprint_normal_dev(self, "%s device (id %d, rev. 0x%02x)\n",
   1440      1.58  riastrad 	    (id < NDEVNAMES ? virtio_device_name[id] : "Unknown"),
   1441      1.58  riastrad 	    id,
   1442      1.58  riastrad 	    revision);
   1443      1.35  jakllsch }
   1444      1.35  jakllsch 
   1445      1.43   reinoud 
   1446      1.32  jakllsch MODULE(MODULE_CLASS_DRIVER, virtio, NULL);
   1447      1.48     skrll 
   1448      1.18  pgoyette #ifdef _MODULE
   1449      1.18  pgoyette #include "ioconf.c"
   1450      1.18  pgoyette #endif
   1451      1.48     skrll 
   1452      1.18  pgoyette static int
   1453      1.18  pgoyette virtio_modcmd(modcmd_t cmd, void *opaque)
   1454      1.18  pgoyette {
   1455      1.18  pgoyette 	int error = 0;
   1456      1.48     skrll 
   1457      1.18  pgoyette #ifdef _MODULE
   1458      1.18  pgoyette 	switch (cmd) {
   1459      1.18  pgoyette 	case MODULE_CMD_INIT:
   1460      1.48     skrll 		error = config_init_component(cfdriver_ioconf_virtio,
   1461      1.48     skrll 		    cfattach_ioconf_virtio, cfdata_ioconf_virtio);
   1462      1.18  pgoyette 		break;
   1463      1.18  pgoyette 	case MODULE_CMD_FINI:
   1464      1.48     skrll 		error = config_fini_component(cfdriver_ioconf_virtio,
   1465      1.18  pgoyette 		    cfattach_ioconf_virtio, cfdata_ioconf_virtio);
   1466      1.18  pgoyette 		break;
   1467      1.18  pgoyette 	default:
   1468      1.18  pgoyette 		error = ENOTTY;
   1469      1.18  pgoyette 		break;
   1470      1.18  pgoyette 	}
   1471      1.18  pgoyette #endif
   1472      1.48     skrll 
   1473      1.48     skrll 	return error;
   1474      1.18  pgoyette }
   1475