virtio_mmio.c revision 1.14 1 1.14 isaki /* $NetBSD: virtio_mmio.c,v 1.14 2024/03/09 11:55:59 isaki 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.14 isaki __KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.14 2024/03/09 11:55:59 isaki 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.13 thorpej }
450 1.4 reinoud
451 1.13 thorpej vsc->sc_active_features = negotiated;
452 1.1 jakllsch }
453 1.1 jakllsch
454 1.1 jakllsch /*
455 1.1 jakllsch * Interrupt handler.
456 1.1 jakllsch */
457 1.1 jakllsch int
458 1.1 jakllsch virtio_mmio_intr(void *arg)
459 1.1 jakllsch {
460 1.1 jakllsch struct virtio_mmio_softc *sc = arg;
461 1.1 jakllsch struct virtio_softc *vsc = &sc->sc_sc;
462 1.1 jakllsch int isr, r = 0;
463 1.1 jakllsch
464 1.1 jakllsch /* check and ack the interrupt */
465 1.12 thorpej isr = virtio_mmio_reg_read(sc, VIRTIO_MMIO_INTERRUPT_STATUS);
466 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_INTERRUPT_ACK, isr);
467 1.13 thorpej if ((isr & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) &&
468 1.1 jakllsch (vsc->sc_config_change != NULL))
469 1.1 jakllsch r = (vsc->sc_config_change)(vsc);
470 1.13 thorpej if ((isr & VIRTIO_CONFIG_ISR_QUEUE_INTERRUPT) &&
471 1.1 jakllsch (vsc->sc_intrhand != NULL)) {
472 1.1 jakllsch if (vsc->sc_soft_ih != NULL)
473 1.1 jakllsch softint_schedule(vsc->sc_soft_ih);
474 1.1 jakllsch else
475 1.1 jakllsch r |= (vsc->sc_intrhand)(vsc);
476 1.1 jakllsch }
477 1.1 jakllsch
478 1.1 jakllsch return r;
479 1.1 jakllsch }
480 1.1 jakllsch
481 1.1 jakllsch static void
482 1.1 jakllsch virtio_mmio_kick(struct virtio_softc *vsc, uint16_t idx)
483 1.1 jakllsch {
484 1.1 jakllsch struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc;
485 1.12 thorpej virtio_mmio_reg_write(sc, VIRTIO_MMIO_QUEUE_NOTIFY, idx);
486 1.1 jakllsch }
487 1.1 jakllsch
488 1.1 jakllsch static int
489 1.7 yamaguch virtio_mmio_alloc_interrupts(struct virtio_softc *vsc)
490 1.1 jakllsch {
491 1.1 jakllsch struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc;
492 1.1 jakllsch
493 1.7 yamaguch return sc->sc_alloc_interrupts(sc);
494 1.1 jakllsch }
495 1.1 jakllsch
496 1.1 jakllsch static void
497 1.1 jakllsch virtio_mmio_free_interrupts(struct virtio_softc *vsc)
498 1.1 jakllsch {
499 1.1 jakllsch struct virtio_mmio_softc * const sc = (struct virtio_mmio_softc *)vsc;
500 1.1 jakllsch
501 1.1 jakllsch sc->sc_free_interrupts(sc);
502 1.1 jakllsch }
503 1.7 yamaguch
504 1.7 yamaguch static int
505 1.7 yamaguch virtio_mmio_setup_interrupts(struct virtio_softc *vsc __unused,
506 1.7 yamaguch int reinit __unused)
507 1.7 yamaguch {
508 1.7 yamaguch
509 1.7 yamaguch return 0;
510 1.7 yamaguch }
511