1 1.15 martin /* $NetBSD: virtio_mmio.c,v 1.15 2025/07/26 14:18:14 martin Exp $ */ 2 1.1 jakllsch /* $OpenBSD: virtio_mmio.c,v 1.2 2017/02/24 17:12:31 patrick Exp $ */ 3 1.1 jakllsch 4 1.12 thorpej /*- 5 1.12 thorpej * Copyright (c) 2024 The NetBSD Foundation, Inc. 6 1.12 thorpej * All rights reserved. 7 1.12 thorpej * 8 1.12 thorpej * This code is derived from software contributed to The NetBSD Foundation 9 1.12 thorpej * by Jason R. Thorpe. 10 1.12 thorpej * 11 1.12 thorpej * Redistribution and use in source and binary forms, with or without 12 1.12 thorpej * modification, are permitted provided that the following conditions 13 1.12 thorpej * are met: 14 1.12 thorpej * 1. Redistributions of source code must retain the above copyright 15 1.12 thorpej * notice, this list of conditions and the following disclaimer. 16 1.12 thorpej * 2. Redistributions in binary form must reproduce the above copyright 17 1.12 thorpej * notice, this list of conditions and the following disclaimer in the 18 1.12 thorpej * documentation and/or other materials provided with the distribution. 19 1.12 thorpej * 20 1.12 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.12 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.12 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.12 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.12 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.12 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.12 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.12 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.12 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.12 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.12 thorpej * POSSIBILITY OF SUCH DAMAGE. 31 1.12 thorpej */ 32 1.12 thorpej 33 1.1 jakllsch /* 34 1.1 jakllsch * Copyright (c) 2014 Patrick Wildt <patrick (at) blueri.se> 35 1.1 jakllsch * Copyright (c) 2012 Stefan Fritsch. 36 1.1 jakllsch * Copyright (c) 2010 Minoura Makoto. 37 1.1 jakllsch * All rights reserved. 38 1.1 jakllsch * 39 1.1 jakllsch * Redistribution and use in source and binary forms, with or without 40 1.1 jakllsch * modification, are permitted provided that the following conditions 41 1.1 jakllsch * are met: 42 1.1 jakllsch * 1. Redistributions of source code must retain the above copyright 43 1.1 jakllsch * notice, this list of conditions and the following disclaimer. 44 1.1 jakllsch * 2. Redistributions in binary form must reproduce the above copyright 45 1.1 jakllsch * notice, this list of conditions and the following disclaimer in the 46 1.1 jakllsch * documentation and/or other materials provided with the distribution. 47 1.1 jakllsch * 48 1.1 jakllsch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 49 1.1 jakllsch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 50 1.1 jakllsch * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 51 1.1 jakllsch * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 52 1.1 jakllsch * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 53 1.1 jakllsch * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 54 1.1 jakllsch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 55 1.1 jakllsch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 56 1.1 jakllsch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 57 1.1 jakllsch * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 1.1 jakllsch */ 59 1.1 jakllsch 60 1.1 jakllsch #include <sys/cdefs.h> 61 1.15 martin __KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.15 2025/07/26 14:18:14 martin Exp $"); 62 1.1 jakllsch 63 1.1 jakllsch #include <sys/param.h> 64 1.1 jakllsch #include <sys/systm.h> 65 1.1 jakllsch #include <sys/kernel.h> 66 1.1 jakllsch #include <sys/device.h> 67 1.1 jakllsch #include <sys/mutex.h> 68 1.1 jakllsch 69 1.1 jakllsch #define VIRTIO_PRIVATE 70 1.1 jakllsch #include <dev/virtio/virtio_mmiovar.h> 71 1.1 jakllsch 72 1.1 jakllsch #define VIRTIO_MMIO_MAGIC ('v' | 'i' << 8 | 'r' << 16 | 't' << 24) 73 1.1 jakllsch 74 1.1 jakllsch #define VIRTIO_MMIO_MAGIC_VALUE 0x000 75 1.1 jakllsch #define VIRTIO_MMIO_VERSION 0x004 76 1.1 jakllsch #define VIRTIO_MMIO_DEVICE_ID 0x008 77 1.1 jakllsch #define VIRTIO_MMIO_VENDOR_ID 0x00c 78 1.12 thorpej #define VIRTIO_MMIO_DEVICE_FEATURES 0x010 /* "HostFeatures" in v1 */ 79 1.12 thorpej #define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 /* "HostFeaturesSel" in v1 */ 80 1.12 thorpej #define VIRTIO_MMIO_DRIVER_FEATURES 0x020 /* "GuestFeatures" in v1 */ 81 1.12 thorpej #define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 /* "GuestFeaturesSel" in v1 */ 82 1.12 thorpej #define VIRTIO_MMIO_V1_GUEST_PAGE_SIZE 0x028 83 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_SEL 0x030 84 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 85 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_NUM 0x038 86 1.12 thorpej #define VIRTIO_MMIO_V1_QUEUE_ALIGN 0x03c 87 1.12 thorpej #define VIRTIO_MMIO_V1_QUEUE_PFN 0x040 88 1.12 thorpej #define VIRTIO_MMIO_QUEUE_READY 0x044 89 1.1 jakllsch #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 90 1.1 jakllsch #define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 91 1.1 jakllsch #define VIRTIO_MMIO_INTERRUPT_ACK 0x064 92 1.1 jakllsch #define VIRTIO_MMIO_STATUS 0x070 93 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_DESC_LOW 0x080 94 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_DESC_HIGH 0x084 95 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_AVAIL_LOW 0x090 96 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_AVAIL_HIGH 0x094 97 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_USED_LOW 0x0a0 98 1.12 thorpej #define VIRTIO_MMIO_V2_QUEUE_USED_HIGH 0x0a4 99 1.12 thorpej #define VIRTIO_MMIO_V2_CONFIG_GEN 0x0fc 100 1.1 jakllsch #define VIRTIO_MMIO_CONFIG 0x100 101 1.1 jakllsch 102 1.1 jakllsch /* 103 1.4 reinoud * MMIO configuration space for virtio-mmio v1 is in guest byte order. 104 1.4 reinoud * 105 1.11 rin * XXX For big-endian aarch64 and arm, see note in virtio_pci.c. 106 1.3 jmcneill */ 107 1.4 reinoud 108 1.11 rin #if (defined(__aarch64__) || defined(__arm__)) && BYTE_ORDER == BIG_ENDIAN 109 1.5 reinoud # define READ_ENDIAN LITTLE_ENDIAN 110 1.5 reinoud # define STRUCT_ENDIAN BIG_ENDIAN 111 1.5 reinoud #elif BYTE_ORDER == BIG_ENDIAN 112 1.5 reinoud # define READ_ENDIAN BIG_ENDIAN 113 1.5 reinoud # define STRUCT_ENDIAN BIG_ENDIAN 114 1.3 jmcneill #else 115 1.5 reinoud # define READ_ENDIAN LITTLE_ENDIAN 116 1.5 reinoud # define STRUCT_ENDIAN LITTLE_ENDIAN 117 1.3 jmcneill #endif 118 1.3 jmcneill 119 1.1 jakllsch 120 1.1 jakllsch static void virtio_mmio_kick(struct virtio_softc *, uint16_t); 121 1.1 jakllsch static uint16_t virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t); 122 1.12 thorpej static void virtio_mmio_v1_setup_queue(struct virtio_softc *, uint16_t, uint64_t); 123 1.12 thorpej static void virtio_mmio_v2_setup_queue(struct virtio_softc *, uint16_t, uint64_t); 124 1.13 thorpej static int virtio_mmio_get_status(struct virtio_softc *); 125 1.1 jakllsch static void virtio_mmio_set_status(struct virtio_softc *, int); 126 1.4 reinoud static void virtio_mmio_negotiate_features(struct virtio_softc *, uint64_t); 127 1.7 yamaguch static int virtio_mmio_alloc_interrupts(struct virtio_softc *); 128 1.1 jakllsch static void virtio_mmio_free_interrupts(struct virtio_softc *); 129 1.7 yamaguch static int virtio_mmio_setup_interrupts(struct virtio_softc *, int); 130 1.1 jakllsch 131 1.12 thorpej static uint32_t 132 1.12 thorpej virtio_mmio_reg_read(struct virtio_mmio_softc *sc, bus_addr_t reg) 133 1.12 thorpej { 134 1.12 thorpej uint32_t val; 135 1.12 thorpej 136 1.12 thorpej val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); 137 1.12 thorpej if (sc->sc_le_regs) { 138 1.12 thorpej val = le32toh(val); 139 1.12 thorpej } 140 1.12 thorpej return val; 141 1.12 thorpej } 142 1.12 thorpej 143 1.12 thorpej static void 144 1.12 thorpej virtio_mmio_reg_write(struct virtio_mmio_softc *sc, bus_addr_t reg, 145 1.12 thorpej uint32_t val) 146 1.12 thorpej { 147 1.12 thorpej if (sc->sc_le_regs) { 148 1.12 thorpej val = htole32(val); 149 1.12 thorpej } 150 1.12 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val); 151 1.12 thorpej } 152 1.12 thorpej 153 1.12 thorpej static void 154 1.12 thorpej virtio_mmio_v2_set_addr(struct virtio_mmio_softc *sc, bus_addr_t reg, 155 1.12 thorpej uint64_t addr) 156 1.12 thorpej { 157 1.12 thorpej virtio_mmio_reg_write(sc, reg, BUS_ADDR_LO32(addr)); 158 1.12 thorpej virtio_mmio_reg_write(sc, reg + 4, BUS_ADDR_HI32(addr)); 159 1.12 thorpej } 160 1.12 thorpej 161 1.12 thorpej static const struct virtio_ops virtio_mmio_v1_ops = { 162 1.1 jakllsch .kick = virtio_mmio_kick, 163 1.1 jakllsch .read_queue_size = virtio_mmio_read_queue_size, 164 1.12 thorpej .setup_queue = virtio_mmio_v1_setup_queue, 165 1.12 thorpej .set_status = virtio_mmio_set_status, 166 1.12 thorpej .neg_features = virtio_mmio_negotiate_features, 167 1.12 thorpej .alloc_interrupts = virtio_mmio_alloc_interrupts, 168 1.12 thorpej .free_interrupts = virtio_mmio_free_interrupts, 169 1.12 thorpej .setup_interrupts = virtio_mmio_setup_interrupts, 170 1.12 thorpej }; 171 1.12 thorpej 172 1.12 thorpej static const struct virtio_ops virtio_mmio_v2_ops = { 173 1.12 thorpej .kick = virtio_mmio_kick, 174 1.12 thorpej .read_queue_size = virtio_mmio_read_queue_size, 175 1.12 thorpej .setup_queue = virtio_mmio_v2_setup_queue, 176 1.1 jakllsch .set_status = virtio_mmio_set_status, 177 1.1 jakllsch .neg_features = virtio_mmio_negotiate_features, 178 1.7 yamaguch .alloc_interrupts = virtio_mmio_alloc_interrupts, 179 1.7 yamaguch .free_interrupts = virtio_mmio_free_interrupts, 180 1.1 jakllsch .setup_interrupts = virtio_mmio_setup_interrupts, 181 1.1 jakllsch }; 182 1.1 jakllsch 183 1.1 jakllsch static uint16_t 184 1.1 jakllsch virtio_mmio_read_queue_size(struct virtio_softc *vsc, uint16_t idx) 185 1.1 jakllsch { 186 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; 187 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_SEL, idx); 188 1.12 thorpej return virtio_mmio_reg_read(sc, VIRTIO_MMIO_QUEUE_NUM_MAX); 189 1.1 jakllsch } 190 1.1 jakllsch 191 1.1 jakllsch static void 192 1.12 thorpej virtio_mmio_v1_setup_queue(struct virtio_softc *vsc, uint16_t idx, 193 1.12 thorpej uint64_t addr) 194 1.1 jakllsch { 195 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; 196 1.1 jakllsch 197 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_SEL, idx); 198 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_NUM, 199 1.12 thorpej virtio_mmio_reg_read(sc, VIRTIO_MMIO_QUEUE_NUM_MAX)); 200 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_V1_QUEUE_ALIGN, 201 1.1 jakllsch VIRTIO_PAGE_SIZE); 202 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_V1_QUEUE_PFN, 203 1.4 reinoud addr / VIRTIO_PAGE_SIZE); 204 1.1 jakllsch } 205 1.1 jakllsch 206 1.1 jakllsch static void 207 1.12 thorpej virtio_mmio_v2_setup_queue(struct virtio_softc *vsc, uint16_t idx, 208 1.12 thorpej uint64_t addr) 209 1.12 thorpej { 210 1.12 thorpej struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; 211 1.14 isaki struct virtqueue *vq; 212 1.12 thorpej 213 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_SEL, idx); 214 1.12 thorpej if (addr == 0) { 215 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_READY, 0); 216 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_DESC_LOW, 0); 217 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_AVAIL_LOW, 0); 218 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_USED_LOW, 0); 219 1.12 thorpej } else { 220 1.14 isaki vq = &vsc->sc_vqs[idx]; 221 1.14 isaki KASSERT(vq->vq_index == idx); 222 1.14 isaki 223 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_NUM, 224 1.12 thorpej virtio_mmio_reg_read(sc, VIRTIO_MMIO_QUEUE_NUM_MAX)); 225 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_DESC_LOW, 226 1.12 thorpej addr); 227 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_AVAIL_LOW, 228 1.12 thorpej addr + vq->vq_availoffset); 229 1.12 thorpej virtio_mmio_v2_set_addr(sc, VIRTIO_MMIO_V2_QUEUE_USED_LOW, 230 1.12 thorpej addr + vq->vq_usedoffset); 231 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_READY, 1); 232 1.12 thorpej } 233 1.12 thorpej } 234 1.12 thorpej 235 1.13 thorpej static int 236 1.13 thorpej virtio_mmio_get_status(struct virtio_softc *vsc) 237 1.13 thorpej { 238 1.13 thorpej struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; 239 1.13 thorpej 240 1.13 thorpej return virtio_mmio_reg_read(sc, VIRTIO_MMIO_STATUS); 241 1.13 thorpej } 242 1.13 thorpej 243 1.12 thorpej static void 244 1.1 jakllsch virtio_mmio_set_status(struct virtio_softc *vsc, int status) 245 1.1 jakllsch { 246 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; 247 1.1 jakllsch int old = 0; 248 1.1 jakllsch 249 1.1 jakllsch if (status != 0) 250 1.12 thorpej old = virtio_mmio_reg_read(sc, VIRTIO_MMIO_STATUS); 251 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_STATUS, status|old); 252 1.1 jakllsch } 253 1.1 jakllsch 254 1.6 reinoud bool 255 1.6 reinoud virtio_mmio_common_probe_present(struct virtio_mmio_softc *sc) 256 1.6 reinoud { 257 1.6 reinoud uint32_t magic; 258 1.6 reinoud 259 1.12 thorpej /* XXX */ 260 1.6 reinoud magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 261 1.6 reinoud VIRTIO_MMIO_MAGIC_VALUE); 262 1.6 reinoud return (magic == VIRTIO_MMIO_MAGIC); 263 1.6 reinoud } 264 1.6 reinoud 265 1.12 thorpej 266 1.1 jakllsch void 267 1.1 jakllsch virtio_mmio_common_attach(struct virtio_mmio_softc *sc) 268 1.1 jakllsch { 269 1.1 jakllsch struct virtio_softc *vsc = &sc->sc_sc; 270 1.4 reinoud device_t self = vsc->sc_dev; 271 1.13 thorpej uint32_t id, magic; 272 1.13 thorpej int virtio_vers; 273 1.1 jakllsch 274 1.1 jakllsch magic = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 275 1.1 jakllsch VIRTIO_MMIO_MAGIC_VALUE); 276 1.1 jakllsch if (magic != VIRTIO_MMIO_MAGIC) { 277 1.12 thorpej if (magic == le32toh(VIRTIO_MMIO_MAGIC)) { 278 1.12 thorpej sc->sc_le_regs = true; 279 1.12 thorpej } else { 280 1.12 thorpej aprint_error_dev(vsc->sc_dev, 281 1.12 thorpej "wrong magic value 0x%08x; giving up\n", magic); 282 1.12 thorpej return; 283 1.12 thorpej } 284 1.1 jakllsch } 285 1.12 thorpej vsc->sc_bus_endian = READ_ENDIAN; 286 1.12 thorpej vsc->sc_struct_endian = STRUCT_ENDIAN; 287 1.1 jakllsch 288 1.13 thorpej sc->sc_mmio_vers = virtio_mmio_reg_read(sc, VIRTIO_MMIO_VERSION); 289 1.13 thorpej switch (sc->sc_mmio_vers) { 290 1.12 thorpej case 1: 291 1.12 thorpej /* we could use PAGE_SIZE, but virtio(4) assumes 4KiB for now */ 292 1.12 thorpej virtio_mmio_reg_write(sc, 293 1.12 thorpej VIRTIO_MMIO_V1_GUEST_PAGE_SIZE, VIRTIO_PAGE_SIZE); 294 1.12 thorpej vsc->sc_ops = &virtio_mmio_v1_ops; 295 1.13 thorpej /* 296 1.13 thorpej * MMIO v1 ("legacy") is documented in the VirtIO 0.9.x 297 1.13 thorpej * draft(s) and uses the same page-oriented queue setup, 298 1.13 thorpej * so that's what we'll report as the VirtIO version. 299 1.13 thorpej */ 300 1.13 thorpej virtio_vers = 0; 301 1.12 thorpej break; 302 1.12 thorpej 303 1.12 thorpej case 2: 304 1.12 thorpej vsc->sc_ops = &virtio_mmio_v2_ops; 305 1.13 thorpej /* 306 1.13 thorpej * MMIO v2 is documented in the VirtIO 1.0 spec. 307 1.13 thorpej */ 308 1.13 thorpej virtio_vers = 1; 309 1.12 thorpej break; 310 1.12 thorpej 311 1.12 thorpej default: 312 1.1 jakllsch aprint_error_dev(vsc->sc_dev, 313 1.13 thorpej "unknown version 0x%08x; giving up\n", sc->sc_mmio_vers); 314 1.1 jakllsch return; 315 1.1 jakllsch } 316 1.13 thorpej aprint_normal_dev(self, "VirtIO-MMIO-v%u\n", sc->sc_mmio_vers); 317 1.1 jakllsch 318 1.12 thorpej id = virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_ID); 319 1.12 thorpej if (id == 0) { 320 1.12 thorpej /* no device connected. */ 321 1.1 jakllsch return; 322 1.12 thorpej } 323 1.1 jakllsch 324 1.13 thorpej virtio_print_device_type(self, id, virtio_vers); 325 1.4 reinoud 326 1.4 reinoud /* set up our device config tag */ 327 1.4 reinoud vsc->sc_devcfg_iosize = sc->sc_iosize - VIRTIO_MMIO_CONFIG; 328 1.4 reinoud vsc->sc_devcfg_iot = sc->sc_iot; 329 1.4 reinoud if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 330 1.4 reinoud VIRTIO_MMIO_CONFIG, vsc->sc_devcfg_iosize, 331 1.4 reinoud &vsc->sc_devcfg_ioh)) { 332 1.4 reinoud aprint_error_dev(self, "can't map config i/o space\n"); 333 1.4 reinoud return; 334 1.4 reinoud } 335 1.1 jakllsch 336 1.1 jakllsch virtio_device_reset(vsc); 337 1.1 jakllsch virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); 338 1.1 jakllsch virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); 339 1.1 jakllsch 340 1.1 jakllsch /* XXX: use softc as aux... */ 341 1.1 jakllsch vsc->sc_childdevid = id; 342 1.1 jakllsch vsc->sc_child = NULL; 343 1.1 jakllsch } 344 1.1 jakllsch 345 1.1 jakllsch int 346 1.1 jakllsch virtio_mmio_common_detach(struct virtio_mmio_softc *sc, int flags) 347 1.1 jakllsch { 348 1.1 jakllsch struct virtio_softc *vsc = &sc->sc_sc; 349 1.1 jakllsch int r; 350 1.1 jakllsch 351 1.9 yamaguch r = config_detach_children(vsc->sc_dev, flags); 352 1.8 yamaguch if (r != 0) 353 1.8 yamaguch return r; 354 1.8 yamaguch 355 1.10 yamaguch KASSERT(vsc->sc_child == NULL); 356 1.1 jakllsch KASSERT(vsc->sc_vqs == NULL); 357 1.1 jakllsch KASSERT(sc->sc_ih == NULL); 358 1.1 jakllsch 359 1.1 jakllsch if (sc->sc_iosize) { 360 1.1 jakllsch bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); 361 1.1 jakllsch sc->sc_iosize = 0; 362 1.1 jakllsch } 363 1.1 jakllsch 364 1.1 jakllsch return 0; 365 1.1 jakllsch } 366 1.1 jakllsch 367 1.1 jakllsch /* 368 1.1 jakllsch * Feature negotiation. 369 1.13 thorpej * 370 1.13 thorpej * We fold pre-VirtIO-1.0 feature negotiation into this single routine 371 1.13 thorpej * because the "legacy" (MMIO-v1) also had the feature sel registers. 372 1.1 jakllsch */ 373 1.4 reinoud static void 374 1.4 reinoud virtio_mmio_negotiate_features(struct virtio_softc *vsc, uint64_t 375 1.12 thorpej driver_features) 376 1.1 jakllsch { 377 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; 378 1.13 thorpej device_t self = vsc->sc_dev; 379 1.13 thorpej uint64_t saved_driver_features = driver_features; 380 1.13 thorpej uint64_t device_features, negotiated; 381 1.13 thorpej uint32_t device_status; 382 1.13 thorpej 383 1.13 thorpej driver_features |= VIRTIO_F_VERSION_1; 384 1.13 thorpej vsc->sc_active_features = 0; 385 1.1 jakllsch 386 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0); 387 1.13 thorpej device_features = virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_FEATURES); 388 1.13 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 1); 389 1.13 thorpej device_features |= (uint64_t) 390 1.13 thorpej virtio_mmio_reg_read(sc, VIRTIO_MMIO_DEVICE_FEATURES) << 32; 391 1.13 thorpej 392 1.13 thorpej /* notify on empty is 0.9 only */ 393 1.13 thorpej if (device_features & VIRTIO_F_VERSION_1) { 394 1.13 thorpej driver_features &= ~VIRTIO_F_NOTIFY_ON_EMPTY; 395 1.13 thorpej } else { 396 1.13 thorpej /* 397 1.13 thorpej * Require version 1 for MMIO-v2 transport. 398 1.13 thorpej */ 399 1.13 thorpej if (sc->sc_mmio_vers >= 2) { 400 1.13 thorpej aprint_error_dev(self, "MMIO-v%u requires version 1\n", 401 1.13 thorpej sc->sc_mmio_vers); 402 1.13 thorpej virtio_mmio_set_status(vsc, 403 1.13 thorpej VIRTIO_CONFIG_DEVICE_STATUS_FAILED); 404 1.13 thorpej return; 405 1.13 thorpej } 406 1.13 thorpej /* 407 1.13 thorpej * If the driver requires version 1, but the device doesn't 408 1.13 thorpej * support it, fail now. 409 1.13 thorpej */ 410 1.13 thorpej if (saved_driver_features & VIRTIO_F_VERSION_1) { 411 1.13 thorpej aprint_error_dev(self, "device rejected version 1\n"); 412 1.13 thorpej virtio_mmio_set_status(vsc, 413 1.13 thorpej VIRTIO_CONFIG_DEVICE_STATUS_FAILED); 414 1.13 thorpej return; 415 1.13 thorpej } 416 1.13 thorpej } 417 1.13 thorpej 418 1.13 thorpej negotiated = device_features & driver_features; 419 1.13 thorpej 420 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0); 421 1.13 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES, 422 1.13 thorpej (uint32_t)negotiated); 423 1.13 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1); 424 1.13 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_DRIVER_FEATURES, 425 1.13 thorpej (uint32_t)(negotiated >> 32)); 426 1.13 thorpej 427 1.13 thorpej /* 428 1.13 thorpej * FEATURES_OK status is not present pre-1.0. 429 1.13 thorpej */ 430 1.13 thorpej if (device_features & VIRTIO_F_VERSION_1) { 431 1.13 thorpej virtio_mmio_set_status(vsc, 432 1.13 thorpej VIRTIO_CONFIG_DEVICE_STATUS_FEATURES_OK); 433 1.13 thorpej device_status = virtio_mmio_get_status(vsc); 434 1.13 thorpej if ((device_status & 435 1.13 thorpej VIRTIO_CONFIG_DEVICE_STATUS_FEATURES_OK) == 0) { 436 1.13 thorpej aprint_error_dev(self, "feature negotiation failed\n"); 437 1.13 thorpej virtio_mmio_set_status(vsc, 438 1.13 thorpej VIRTIO_CONFIG_DEVICE_STATUS_FAILED); 439 1.13 thorpej return; 440 1.13 thorpej } 441 1.13 thorpej } 442 1.13 thorpej 443 1.13 thorpej if (negotiated & VIRTIO_F_VERSION_1) { 444 1.13 thorpej /* 445 1.13 thorpej * All VirtIO 1.0 access is little-endian. 446 1.13 thorpej */ 447 1.13 thorpej vsc->sc_bus_endian = LITTLE_ENDIAN; 448 1.13 thorpej vsc->sc_struct_endian = LITTLE_ENDIAN; 449 1.15 martin 450 1.15 martin vsc->sc_version_1 = true; 451 1.13 thorpej } 452 1.4 reinoud 453 1.13 thorpej vsc->sc_active_features = negotiated; 454 1.1 jakllsch } 455 1.1 jakllsch 456 1.1 jakllsch /* 457 1.1 jakllsch * Interrupt handler. 458 1.1 jakllsch */ 459 1.1 jakllsch int 460 1.1 jakllsch virtio_mmio_intr(void *arg) 461 1.1 jakllsch { 462 1.1 jakllsch struct virtio_mmio_softc *sc = arg; 463 1.1 jakllsch struct virtio_softc *vsc = &sc->sc_sc; 464 1.1 jakllsch int isr, r = 0; 465 1.1 jakllsch 466 1.1 jakllsch /* check and ack the interrupt */ 467 1.12 thorpej isr = virtio_mmio_reg_read(sc, VIRTIO_MMIO_INTERRUPT_STATUS); 468 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_INTERRUPT_ACK, isr); 469 1.13 thorpej if ((isr & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) && 470 1.1 jakllsch (vsc->sc_config_change != NULL)) 471 1.1 jakllsch r = (vsc->sc_config_change)(vsc); 472 1.13 thorpej if ((isr & VIRTIO_CONFIG_ISR_QUEUE_INTERRUPT) && 473 1.1 jakllsch (vsc->sc_intrhand != NULL)) { 474 1.1 jakllsch if (vsc->sc_soft_ih != NULL) 475 1.1 jakllsch softint_schedule(vsc->sc_soft_ih); 476 1.1 jakllsch else 477 1.1 jakllsch r |= (vsc->sc_intrhand)(vsc); 478 1.1 jakllsch } 479 1.1 jakllsch 480 1.1 jakllsch return r; 481 1.1 jakllsch } 482 1.1 jakllsch 483 1.1 jakllsch static void 484 1.1 jakllsch virtio_mmio_kick(struct virtio_softc *vsc, uint16_t idx) 485 1.1 jakllsch { 486 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; 487 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_NOTIFY, idx); 488 1.1 jakllsch } 489 1.1 jakllsch 490 1.1 jakllsch static int 491 1.7 yamaguch virtio_mmio_alloc_interrupts(struct virtio_softc *vsc) 492 1.1 jakllsch { 493 1.1 jakllsch struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc; 494 1.1 jakllsch 495 1.7 yamaguch return sc->sc_alloc_interrupts(sc); 496 1.1 jakllsch } 497 1.1 jakllsch 498 1.1 jakllsch static void 499 1.1 jakllsch virtio_mmio_free_interrupts(struct virtio_softc *vsc) 500 1.1 jakllsch { 501 1.1 jakllsch struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc; 502 1.1 jakllsch 503 1.1 jakllsch sc->sc_free_interrupts(sc); 504 1.1 jakllsch } 505 1.7 yamaguch 506 1.7 yamaguch static int 507 1.7 yamaguch virtio_mmio_setup_interrupts(struct virtio_softc *vsc __unused, 508 1.7 yamaguch int reinit __unused) 509 1.7 yamaguch { 510 1.7 yamaguch 511 1.7 yamaguch return 0; 512 1.7 yamaguch } 513