Rewrite and streamline virtio device config read/write and explicitly cater for the Aarch64-eb bus problem with Qemu. This removes lots of bus_space `magic' and cleans up the code.diff -r1.44 -r1.45 src/sys/dev/pci/virtio.c
(reinoud)
--- src/sys/dev/pci/virtio.c 2021/01/20 21:59:48 1.44
+++ src/sys/dev/pci/virtio.c 2021/01/28 15:43:12 1.45
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: virtio.c,v 1.44 2021/01/20 21:59:48 reinoud Exp $ */ | 1 | /* $NetBSD: virtio.c,v 1.45 2021/01/28 15:43:12 reinoud Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. | |
5 | * Copyright (c) 2012 Stefan Fritsch, Alexander Fiveg. | 5 | * Copyright (c) 2012 Stefan Fritsch, Alexander Fiveg. | |
6 | * Copyright (c) 2010 Minoura Makoto. | 6 | * Copyright (c) 2010 Minoura Makoto. | |
7 | * All rights reserved. | 7 | * All rights reserved. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -18,27 +18,27 @@ | @@ -18,27 +18,27 @@ | |||
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | */ | 28 | */ | |
29 | 29 | |||
30 | #include <sys/cdefs.h> | 30 | #include <sys/cdefs.h> | |
31 | __KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.44 2021/01/20 21:59:48 reinoud Exp $"); | 31 | __KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.45 2021/01/28 15:43:12 reinoud Exp $"); | |
32 | 32 | |||
33 | #include <sys/param.h> | 33 | #include <sys/param.h> | |
34 | #include <sys/systm.h> | 34 | #include <sys/systm.h> | |
35 | #include <sys/kernel.h> | 35 | #include <sys/kernel.h> | |
36 | #include <sys/atomic.h> | 36 | #include <sys/atomic.h> | |
37 | #include <sys/bus.h> | 37 | #include <sys/bus.h> | |
38 | #include <sys/device.h> | 38 | #include <sys/device.h> | |
39 | #include <sys/kmem.h> | 39 | #include <sys/kmem.h> | |
40 | #include <sys/module.h> | 40 | #include <sys/module.h> | |
41 | 41 | |||
42 | #define VIRTIO_PRIVATE | 42 | #define VIRTIO_PRIVATE | |
43 | 43 | |||
44 | #include <dev/pci/virtioreg.h> /* XXX: move to non-pci */ | 44 | #include <dev/pci/virtioreg.h> /* XXX: move to non-pci */ | |
@@ -136,155 +136,265 @@ virtio_negotiate_features(struct virtio_ | @@ -136,155 +136,265 @@ virtio_negotiate_features(struct virtio_ | |||
136 | sc->sc_indirect = false; | 136 | sc->sc_indirect = false; | |
137 | } | 137 | } | |
138 | 138 | |||
139 | 139 | |||
140 | /* | 140 | /* | |
141 | * Device configuration registers readers/writers | 141 | * Device configuration registers readers/writers | |
142 | */ | 142 | */ | |
143 | #if 0 | 143 | #if 0 | |
144 | #define DPRINTFR(n, fmt, val, index, num) \ | 144 | #define DPRINTFR(n, fmt, val, index, num) \ | |
145 | printf("\n%s (", n); \ | 145 | printf("\n%s (", n); \ | |
146 | for (int i = 0; i < num; i++) \ | 146 | for (int i = 0; i < num; i++) \ | |
147 | printf("%02x ", bus_space_read_1(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index+i)); \ | 147 | printf("%02x ", bus_space_read_1(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index+i)); \ | |
148 | printf(") -> "); printf(fmt, val); printf("\n"); | 148 | printf(") -> "); printf(fmt, val); printf("\n"); | |
149 | #define DPRINTFR2(n, fmt, val_s, val_n) \ | |||
150 | printf("%s ", n); \ | |||
151 | printf("\n stream "); printf(fmt, val_s); printf(" norm "); printf(fmt, val_n); printf("\n"); | |||
149 | #else | 152 | #else | |
150 | #define DPRINTFR(n, fmt, val, index, num) | 153 | #define DPRINTFR(n, fmt, val, index, num) | |
154 | #define DPRINTFR2(n, fmt, val_s, val_n) | |||
151 | #endif | 155 | #endif | |
152 | 156 | |||
157 | ||||
153 | uint8_t | 158 | uint8_t | |
154 | virtio_read_device_config_1(struct virtio_softc *sc, int index) { | 159 | virtio_read_device_config_1(struct virtio_softc *sc, int index) { | |
160 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |||
161 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
155 | uint8_t val; | 162 | uint8_t val; | |
156 | val = sc->sc_ops->read_dev_cfg_1(sc, index); | 163 | ||
164 | val = bus_space_read_1(iot, ioh, index); | |||
165 | ||||
157 | DPRINTFR("read_1", "%02x", val, index, 1); | 166 | DPRINTFR("read_1", "%02x", val, index, 1); | |
158 | return val; | 167 | return val; | |
159 | } | 168 | } | |
160 | 169 | |||
161 | uint16_t | 170 | uint16_t | |
162 | virtio_read_device_config_2(struct virtio_softc *sc, int index) { | 171 | virtio_read_device_config_2(struct virtio_softc *sc, int index) { | |
172 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |||
173 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
163 | uint16_t val; | 174 | uint16_t val; | |
164 | val = sc->sc_ops->read_dev_cfg_2(sc, index); | 175 | ||
176 | val = bus_space_read_2(iot, ioh, index); | |||
177 | if (BYTE_ORDER != sc->sc_bus_endian) | |||
178 | val = bswap16(val); | |||
179 | ||||
165 | DPRINTFR("read_2", "%04x", val, index, 2); | 180 | DPRINTFR("read_2", "%04x", val, index, 2); | |
181 | DPRINTFR2("read_2", "%04x", | |||
182 | bus_space_read_stream_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index), | |||
183 | bus_space_read_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index)); | |||
166 | return val; | 184 | return val; | |
167 | } | 185 | } | |
168 | 186 | |||
169 | uint32_t | 187 | uint32_t | |
170 | virtio_read_device_config_4(struct virtio_softc *sc, int index) { | 188 | virtio_read_device_config_4(struct virtio_softc *sc, int index) { | |
189 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |||
190 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
171 | uint32_t val; | 191 | uint32_t val; | |
172 | val = sc->sc_ops->read_dev_cfg_4(sc, index); | 192 | ||
193 | val = bus_space_read_4(iot, ioh, index); | |||
194 | if (BYTE_ORDER != sc->sc_bus_endian) | |||
195 | val = bswap32(val); | |||
196 | ||||
173 | DPRINTFR("read_4", "%08x", val, index, 4); | 197 | DPRINTFR("read_4", "%08x", val, index, 4); | |
198 | DPRINTFR2("read_4", "%08x", | |||
199 | bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index), | |||
200 | bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index)); | |||
174 | return val; | 201 | return val; | |
175 | } | 202 | } | |
176 | 203 | |||
177 | uint64_t | 204 | uint64_t | |
178 | virtio_read_device_config_8(struct virtio_softc *sc, int index) { | 205 | virtio_read_device_config_8(struct virtio_softc *sc, int index) { | |
179 | uint64_t val; | 206 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
180 | val = sc->sc_ops->read_dev_cfg_8(sc, index); | 207 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |
208 | uint64_t val, val_0, val_1, val_l, val_h; | |||
209 | ||||
210 | val_0 = bus_space_read_4(iot, ioh, index); | |||
211 | val_1 = bus_space_read_4(iot, ioh, index + 4); | |||
212 | if (BYTE_ORDER != sc->sc_bus_endian) { | |||
213 | val_l = bswap32(val_1); | |||
214 | val_h = bswap32(val_0); | |||
215 | } else { | |||
216 | val_l = val_0; | |||
217 | val_h = val_1; | |||
218 | } | |||
219 | ||||
220 | #ifdef AARCH64EB_PROBLEM | |||
221 | /* XXX see comment at virtio_pci.c */ | |||
222 | if (sc->sc_aarch64eb_bus_problem) { | |||
223 | val_l = val_1; | |||
224 | val_h = val_0; | |||
225 | } | |||
226 | #endif | |||
227 | ||||
228 | val = val_h << 32; | |||
229 | val |= val_l; | |||
230 | ||||
181 | DPRINTFR("read_8", "%08lx", val, index, 8); | 231 | DPRINTFR("read_8", "%08lx", val, index, 8); | |
232 | DPRINTFR2("read_8 low ", "%08x", | |||
233 | bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index), | |||
234 | bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index)); | |||
235 | DPRINTFR2("read_8 high ", "%08x", | |||
236 | bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index + 4), | |||
237 | bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, index + 4)); | |||
182 | return val; | 238 | return val; | |
183 | } | 239 | } | |
184 | 240 | |||
185 | /* | 241 | /* | |
186 | * In the older virtio spec, device config registers are host endian. On newer | 242 | * In the older virtio spec, device config registers are host endian. On newer | |
187 | * they are little endian. The normal logic will cater for this. However some | 243 | * they are little endian. Some newer devices however explicitly specify their | |
188 | * devices however explicitly state that its fields are always little endian | 244 | * register to always be little endian. These fuctions cater for these. | |
189 | * and will still need to be swapped. | |||
190 | */ | 245 | */ | |
191 | uint16_t | 246 | uint16_t | |
192 | virtio_read_device_config_le_2(struct virtio_softc *sc, int index) { | 247 | virtio_read_device_config_le_2(struct virtio_softc *sc, int index) { | |
193 | bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1); | 248 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
249 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
194 | uint16_t val; | 250 | uint16_t val; | |
195 | 251 | |||
196 | val = sc->sc_ops->read_dev_cfg_2(sc, index); | 252 | val = bus_space_read_2(iot, ioh, index); | |
197 | val = virtio_v1 ? val : le16toh(val); | 253 | if (sc->sc_bus_endian != LITTLE_ENDIAN) | |
198 | DPRINTFR("read_le_2", "%08x", val, index, 2); | 254 | val = bswap16(val); | |
255 | ||||
256 | DPRINTFR("read_le_2", "%04x", val, index, 2); | |||
257 | DPRINTFR2("read_le_2", "%04x", | |||
258 | bus_space_read_stream_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0), | |||
259 | bus_space_read_2(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0)); | |||
199 | return val; | 260 | return val; | |
200 | } | 261 | } | |
201 | 262 | |||
202 | uint32_t | 263 | uint32_t | |
203 | virtio_read_device_config_le_4(struct virtio_softc *sc, int index) { | 264 | virtio_read_device_config_le_4(struct virtio_softc *sc, int index) { | |
204 | bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1); | 265 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
266 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
205 | uint32_t val; | 267 | uint32_t val; | |
206 | 268 | |||
207 | val = sc->sc_ops->read_dev_cfg_4(sc, index); | 269 | val = bus_space_read_4(iot, ioh, index); | |
208 | val = virtio_v1 ? val : le32toh(val); | 270 | if (sc->sc_bus_endian != LITTLE_ENDIAN) | |
271 | val = bswap32(val); | |||
272 | ||||
209 | DPRINTFR("read_le_4", "%08x", val, index, 4); | 273 | DPRINTFR("read_le_4", "%08x", val, index, 4); | |
274 | DPRINTFR2("read_le_4", "%08x", | |||
275 | bus_space_read_stream_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0), | |||
276 | bus_space_read_4(sc->sc_devcfg_iot, sc->sc_devcfg_ioh, 0)); | |||
210 | return val; | 277 | return val; | |
211 | } | 278 | } | |
212 | 279 | |||
213 | void | 280 | void | |
214 | virtio_write_device_config_1(struct virtio_softc *sc, int index, uint8_t value) | 281 | virtio_write_device_config_1(struct virtio_softc *sc, int index, uint8_t value) | |
215 | { | 282 | { | |
216 | sc->sc_ops->write_dev_cfg_1(sc, index, value); | 283 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
284 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
285 | ||||
286 | bus_space_write_1(iot, ioh, index, value); | |||
217 | } | 287 | } | |
218 | 288 | |||
219 | void | 289 | void | |
220 | virtio_write_device_config_2(struct virtio_softc *sc, int index, uint16_t value) | 290 | virtio_write_device_config_2(struct virtio_softc *sc, int index, uint16_t value) | |
221 | { | 291 | { | |
222 | sc->sc_ops->write_dev_cfg_2(sc, index, value); | 292 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
293 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
294 | ||||
295 | if (BYTE_ORDER != sc->sc_bus_endian) | |||
296 | value = bswap16(value); | |||
297 | bus_space_write_2(iot, ioh, index, value); | |||
223 | } | 298 | } | |
224 | 299 | |||
225 | void | 300 | void | |
226 | virtio_write_device_config_4(struct virtio_softc *sc, int index, uint32_t value) | 301 | virtio_write_device_config_4(struct virtio_softc *sc, int index, uint32_t value) | |
227 | { | 302 | { | |
228 | sc->sc_ops->write_dev_cfg_4(sc, index, value); | 303 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
304 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
305 | ||||
306 | if (BYTE_ORDER != sc->sc_bus_endian) | |||
307 | value = bswap32(value); | |||
308 | bus_space_write_4(iot, ioh, index, value); | |||
229 | } | 309 | } | |
230 | 310 | |||
231 | void | 311 | void | |
232 | virtio_write_device_config_8(struct virtio_softc *sc, int index, uint64_t value) | 312 | virtio_write_device_config_8(struct virtio_softc *sc, int index, uint64_t value) | |
233 | { | 313 | { | |
234 | sc->sc_ops->write_dev_cfg_8(sc, index, value); | 314 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
315 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |||
316 | uint64_t val_0, val_1, val_l, val_h; | |||
317 | ||||
318 | val_l = BUS_ADDR_LO32(value); | |||
319 | val_h = BUS_ADDR_HI32(value); | |||
320 | ||||
321 | if (BYTE_ORDER != sc->sc_bus_endian) { | |||
322 | val_0 = bswap32(val_h); | |||
323 | val_1 = bswap32(val_l); | |||
324 | } else { | |||
325 | val_0 = val_l; | |||
326 | val_1 = val_h; | |||
327 | } | |||
328 | ||||
329 | #ifdef AARCH64EB_PROBLEM | |||
330 | /* XXX see comment at virtio_pci.c */ | |||
331 | if (sc->sc_aarch64eb_bus_problem) { | |||
332 | val_0 = val_h; | |||
333 | val_1 = val_l; | |||
334 | } | |||
335 | #endif | |||
336 | ||||
337 | bus_space_write_4(iot, ioh, index, val_0); | |||
338 | bus_space_write_4(iot, ioh, index + 4, val_1); | |||
235 | } | 339 | } | |
236 | 340 | |||
237 | /* | 341 | /* | |
238 | * In the older virtio spec, device config registers are host endian. On newer | 342 | * In the older virtio spec, device config registers are host endian. On newer | |
239 | * they are little endian. The normal logic will cater for this. However some | 343 | * they are little endian. Some newer devices however explicitly specify their | |
240 | * devices however explicitly state that its fields are always little endian | 344 | * register to always be little endian. These fuctions cater for these. | |
241 | * and will still need to be swapped. | |||
242 | */ | 345 | */ | |
243 | void | 346 | void | |
244 | virtio_write_device_config_le_2(struct virtio_softc *sc, int index, uint16_t value) | 347 | virtio_write_device_config_le_2(struct virtio_softc *sc, int index, uint16_t value) | |
245 | { | 348 | { | |
246 | bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1); | 349 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
247 | value = virtio_v1 ? value : htole16(value); | 350 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |
248 | sc->sc_ops->write_dev_cfg_2(sc, index, value); | 351 | ||
352 | if (sc->sc_bus_endian != LITTLE_ENDIAN) | |||
353 | value = bswap16(value); | |||
354 | bus_space_write_2(iot, ioh, index, value); | |||
249 | } | 355 | } | |
250 | 356 | |||
251 | void | 357 | void | |
252 | virtio_write_device_config_le_4(struct virtio_softc *sc, int index, uint32_t value) | 358 | virtio_write_device_config_le_4(struct virtio_softc *sc, int index, uint32_t value) | |
253 | { | 359 | { | |
254 | bool virtio_v1 = (sc->sc_active_features & VIRTIO_F_VERSION_1); | 360 | bus_space_tag_t iot = sc->sc_devcfg_iot; | |
255 | value = virtio_v1 ? value : htole32(value); | 361 | bus_space_handle_t ioh = sc->sc_devcfg_ioh; | |
256 | sc->sc_ops->write_dev_cfg_4(sc, index, value); | 362 | ||
363 | if (sc->sc_bus_endian != LITTLE_ENDIAN) | |||
364 | value = bswap32(value); | |||
365 | bus_space_write_4(iot, ioh, index, value); | |||
257 | } | 366 | } | |
258 | 367 | |||
368 | ||||
259 | /* | 369 | /* | |
260 | * data structures endian helpers | 370 | * data structures endian helpers | |
261 | */ | 371 | */ | |
262 | uint16_t virtio_rw16(struct virtio_softc *sc, uint16_t val) | 372 | uint16_t virtio_rw16(struct virtio_softc *sc, uint16_t val) | |
263 | { | 373 | { | |
264 | KASSERT(sc); | 374 | KASSERT(sc); | |
265 | return (sc->sc_devcfg_swap) ? bswap16(val) : val; | 375 | return BYTE_ORDER != sc->sc_struct_endian ? bswap16(val) : val; | |
266 | } | 376 | } | |
267 | 377 | |||
268 | uint32_t virtio_rw32(struct virtio_softc *sc, uint32_t val) | 378 | uint32_t virtio_rw32(struct virtio_softc *sc, uint32_t val) | |
269 | { | 379 | { | |
270 | KASSERT(sc); | 380 | KASSERT(sc); | |
271 | return (sc->sc_devcfg_swap) ? bswap32(val) : val; | 381 | return BYTE_ORDER != sc->sc_struct_endian ? bswap32(val) : val; | |
272 | } | 382 | } | |
273 | 383 | |||
274 | uint64_t virtio_rw64(struct virtio_softc *sc, uint64_t val) | 384 | uint64_t virtio_rw64(struct virtio_softc *sc, uint64_t val) | |
275 | { | 385 | { | |
276 | KASSERT(sc); | 386 | KASSERT(sc); | |
277 | return (sc->sc_devcfg_swap) ? bswap64(val) : val; | 387 | return BYTE_ORDER != sc->sc_struct_endian ? bswap64(val) : val; | |
278 | } | 388 | } | |
279 | 389 | |||
280 | 390 | |||
281 | /* | 391 | /* | |
282 | * Interrupt handler. | 392 | * Interrupt handler. | |
283 | */ | 393 | */ | |
284 | static void | 394 | static void | |
285 | virtio_soft_intr(void *arg) | 395 | virtio_soft_intr(void *arg) | |
286 | { | 396 | { | |
287 | struct virtio_softc *sc = arg; | 397 | struct virtio_softc *sc = arg; | |
288 | 398 | |||
289 | KASSERT(sc->sc_intrhand != NULL); | 399 | KASSERT(sc->sc_intrhand != NULL); | |
290 | 400 |
--- src/sys/dev/pci/virtio_pci.c 2021/01/26 16:40:16 1.26
+++ src/sys/dev/pci/virtio_pci.c 2021/01/28 15:43:12 1.27
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: virtio_pci.c,v 1.26 2021/01/26 16:40:16 reinoud Exp $ */ | 1 | /* $NetBSD: virtio_pci.c,v 1.27 2021/01/28 15:43:12 reinoud Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. | |
5 | * Copyright (c) 2012 Stefan Fritsch. | 5 | * Copyright (c) 2012 Stefan Fritsch. | |
6 | * Copyright (c) 2010 Minoura Makoto. | 6 | * Copyright (c) 2010 Minoura Makoto. | |
7 | * All rights reserved. | 7 | * All rights reserved. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
@@ -18,27 +18,27 @@ | @@ -18,27 +18,27 @@ | |||
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | */ | 28 | */ | |
29 | 29 | |||
30 | #include <sys/cdefs.h> | 30 | #include <sys/cdefs.h> | |
31 | __KERNEL_RCSID(0, "$NetBSD: virtio_pci.c,v 1.26 2021/01/26 16:40:16 reinoud Exp $"); | 31 | __KERNEL_RCSID(0, "$NetBSD: virtio_pci.c,v 1.27 2021/01/28 15:43:12 reinoud Exp $"); | |
32 | 32 | |||
33 | #include <sys/param.h> | 33 | #include <sys/param.h> | |
34 | #include <sys/systm.h> | 34 | #include <sys/systm.h> | |
35 | #include <sys/kmem.h> | 35 | #include <sys/kmem.h> | |
36 | #include <sys/module.h> | 36 | #include <sys/module.h> | |
37 | #include <sys/endian.h> | 37 | #include <sys/endian.h> | |
38 | #include <sys/interrupt.h> | 38 | #include <sys/interrupt.h> | |
39 | 39 | |||
40 | #include <sys/device.h> | 40 | #include <sys/device.h> | |
41 | 41 | |||
42 | #include <dev/pci/pcidevs.h> | 42 | #include <dev/pci/pcidevs.h> | |
43 | #include <dev/pci/pcireg.h> | 43 | #include <dev/pci/pcireg.h> | |
44 | #include <dev/pci/pcivar.h> | 44 | #include <dev/pci/pcivar.h> | |
@@ -96,145 +96,88 @@ static void virtio_pci_kick_09(struct vi | @@ -96,145 +96,88 @@ static void virtio_pci_kick_09(struct vi | |||
96 | static uint16_t virtio_pci_read_queue_size_09(struct virtio_softc *, uint16_t); | 96 | static uint16_t virtio_pci_read_queue_size_09(struct virtio_softc *, uint16_t); | |
97 | static void virtio_pci_setup_queue_09(struct virtio_softc *, uint16_t, uint64_t); | 97 | static void virtio_pci_setup_queue_09(struct virtio_softc *, uint16_t, uint64_t); | |
98 | static void virtio_pci_set_status_09(struct virtio_softc *, int); | 98 | static void virtio_pci_set_status_09(struct virtio_softc *, int); | |
99 | static void virtio_pci_negotiate_features_09(struct virtio_softc *, uint64_t); | 99 | static void virtio_pci_negotiate_features_09(struct virtio_softc *, uint64_t); | |
100 | 100 | |||
101 | static int virtio_pci_attach_10(device_t, void *); | 101 | static int virtio_pci_attach_10(device_t, void *); | |
102 | static void virtio_pci_kick_10(struct virtio_softc *, uint16_t); | 102 | static void virtio_pci_kick_10(struct virtio_softc *, uint16_t); | |
103 | static uint16_t virtio_pci_read_queue_size_10(struct virtio_softc *, uint16_t); | 103 | static uint16_t virtio_pci_read_queue_size_10(struct virtio_softc *, uint16_t); | |
104 | static void virtio_pci_setup_queue_10(struct virtio_softc *, uint16_t, uint64_t); | 104 | static void virtio_pci_setup_queue_10(struct virtio_softc *, uint16_t, uint64_t); | |
105 | static void virtio_pci_set_status_10(struct virtio_softc *, int); | 105 | static void virtio_pci_set_status_10(struct virtio_softc *, int); | |
106 | static void virtio_pci_negotiate_features_10(struct virtio_softc *, uint64_t); | 106 | static void virtio_pci_negotiate_features_10(struct virtio_softc *, uint64_t); | |
107 | static int virtio_pci_find_cap(struct virtio_pci_softc *psc, int cfg_type, void *buf, int buflen); | 107 | static int virtio_pci_find_cap(struct virtio_pci_softc *psc, int cfg_type, void *buf, int buflen); | |
108 | 108 | |||
109 | static uint8_t virtio_pci_read_device_config_1(struct virtio_softc *, int); | |||
110 | static uint16_t virtio_pci_read_device_config_2(struct virtio_softc *, int); | |||
111 | static uint32_t virtio_pci_read_device_config_4(struct virtio_softc *, int); | |||
112 | static uint64_t virtio_pci_read_device_config_8(struct virtio_softc *, int); | |||
113 | static void virtio_pci_write_device_config_1(struct virtio_softc *, int, uint8_t); | |||
114 | static void virtio_pci_write_device_config_2(struct virtio_softc *, int, uint16_t); | |||
115 | static void virtio_pci_write_device_config_4(struct virtio_softc *, int, uint32_t); | |||
116 | static void virtio_pci_write_device_config_8(struct virtio_softc *, int, uint64_t); | |||
117 | ||||
118 | static int virtio_pci_setup_interrupts(struct virtio_softc *); | 109 | static int virtio_pci_setup_interrupts(struct virtio_softc *); | |
119 | static void virtio_pci_free_interrupts(struct virtio_softc *); | 110 | static void virtio_pci_free_interrupts(struct virtio_softc *); | |
120 | static int virtio_pci_adjust_config_region(struct virtio_pci_softc *psc); | 111 | static int virtio_pci_adjust_config_region(struct virtio_pci_softc *psc); | |
121 | static int virtio_pci_intr(void *arg); | 112 | static int virtio_pci_intr(void *arg); | |
122 | static int virtio_pci_msix_queue_intr(void *); | 113 | static int virtio_pci_msix_queue_intr(void *); | |
123 | static int virtio_pci_msix_config_intr(void *); | 114 | static int virtio_pci_msix_config_intr(void *); | |
124 | static int virtio_pci_setup_msix_vectors_09(struct virtio_softc *); | 115 | static int virtio_pci_setup_msix_vectors_09(struct virtio_softc *); | |
125 | static int virtio_pci_setup_msix_vectors_10(struct virtio_softc *); | 116 | static int virtio_pci_setup_msix_vectors_10(struct virtio_softc *); | |
126 | static int virtio_pci_setup_msix_interrupts(struct virtio_softc *, | 117 | static int virtio_pci_setup_msix_interrupts(struct virtio_softc *, | |
127 | struct pci_attach_args *); | 118 | struct pci_attach_args *); | |
128 | static int virtio_pci_setup_intx_interrupt(struct virtio_softc *, | 119 | static int virtio_pci_setup_intx_interrupt(struct virtio_softc *, | |
129 | struct pci_attach_args *); | 120 | struct pci_attach_args *); | |
130 | 121 | |||
131 | #define VIRTIO_MSIX_CONFIG_VECTOR_INDEX 0 | 122 | #define VIRTIO_MSIX_CONFIG_VECTOR_INDEX 0 | |
132 | #define VIRTIO_MSIX_QUEUE_VECTOR_INDEX 1 | 123 | #define VIRTIO_MSIX_QUEUE_VECTOR_INDEX 1 | |
133 | 124 | |||
134 | #if 0 | 125 | /* | |
135 | /* we use the legacy virtio spec, so the PCI registers are host native | 126 | * When using PCI attached virtio on aarch64-eb under Qemu, the IO space | |
136 | * byte order, not PCI (i.e. LE) byte order */ | 127 | * suddenly read BIG_ENDIAN where it should stay LITTLE_ENDIAN. The data read | |
137 | #if BYTE_ORDER == BIG_ENDIAN | 128 | * 1 byte at a time seem OK but reading bigger lengths result in swapped | |
138 | #define REG_HI_OFF 0 | 129 | * endian. This is most notable on reading 8 byters since we can't use | |
139 | #define REG_LO_OFF 4 | 130 | * bus_space_{read,write}_8() and it has to be patched there explicitly. We | |
140 | #ifndef __BUS_SPACE_HAS_STREAM_METHODS | 131 | * define the AARCH64EB_PROBLEM to signal we're vulnerable to this and set the | |
141 | #define bus_space_read_stream_1 bus_space_read_1 | 132 | * accompanied sc->sc_aarch64_eb_bus_problem variable when attaching using the | |
142 | #define bus_space_write_stream_1 bus_space_write_1 | 133 | * IO space. | |
143 | static inline uint16_t | 134 | */ | |
144 | bus_space_read_stream_2(bus_space_tag_t t, bus_space_handle_t h, | |||
145 | bus_size_t o) | |||
146 | { | |||
147 | return le16toh(bus_space_read_2(t, h, o)); | |||
148 | } | |||
149 | static inline void | |||
150 | bus_space_write_stream_2(bus_space_tag_t t, bus_space_handle_t h, | |||
151 | bus_size_t o, uint16_t v) | |||
152 | { | |||
153 | bus_space_write_2(t, h, o, htole16(v)); | |||
154 | } | |||
155 | static inline uint32_t | |||
156 | bus_space_read_stream_4(bus_space_tag_t t, bus_space_handle_t h, | |||
157 | bus_size_t o) | |||
158 | { | |||
159 | return le32toh(bus_space_read_4(t, h, o)); | |||
160 | } | |||
161 | static inline void | |||
162 | bus_space_write_stream_4(bus_space_tag_t t, bus_space_handle_t h, | |||
163 | bus_size_t o, uint32_t v) | |||
164 | { | |||
165 | bus_space_write_4(t, h, o, htole32(v)); | |||
166 | } | |||
167 | #endif | |||
168 | #else | |||
169 | #define REG_HI_OFF 4 | |||
170 | #define REG_LO_OFF 0 | |||
171 | #ifndef __BUS_SPACE_HAS_STREAM_METHODS | |||
172 | #define bus_space_read_stream_1 bus_space_read_1 | |||
173 | #define bus_space_read_stream_2 bus_space_read_2 | |||
174 | #define bus_space_read_stream_4 bus_space_read_4 | |||
175 | #define bus_space_write_stream_1 bus_space_write_1 | |||
176 | #define bus_space_write_stream_2 bus_space_write_2 | |||
177 | #define bus_space_write_stream_4 bus_space_write_4 | |||
178 | #endif | |||
179 | #endif | |||
180 | #endif | |||
181 | ||||
182 | 135 | |||
183 | #if BYTE_ORDER == LITTLE_ENDIAN | 136 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |
184 | # define VIODEVRW_SWAP_09 false | 137 | /* source of AARCH64EB_PROBLEM */ | |
185 | # define VIODEVRW_SWAP_10 false | 138 | # define READ_ENDIAN_09 BIG_ENDIAN /* XXX bug, should be LITTLE_ENDIAN */ | |
186 | #else /* big endian */ | 139 | # define READ_ENDIAN_10 BIG_ENDIAN | |
187 | # define VIODEVRW_SWAP_09 false | 140 | # define STRUCT_ENDIAN_09 BIG_ENDIAN | |
188 | # define VIODEVRW_SWAP_10 true | 141 | # define STRUCT_ENDIAN_10 LITTLE_ENDIAN | |
142 | #elif BYTE_ORDER == BIG_ENDIAN | |||
143 | # define READ_ENDIAN_09 LITTLE_ENDIAN | |||
144 | # define READ_ENDIAN_10 BIG_ENDIAN | |||
145 | # define STRUCT_ENDIAN_09 BIG_ENDIAN | |||
146 | # define STRUCT_ENDIAN_10 LITTLE_ENDIAN | |||
147 | #else /* little endian */ | |||
148 | # define READ_ENDIAN_09 LITTLE_ENDIAN | |||
149 | # define READ_ENDIAN_10 LITTLE_ENDIAN | |||
150 | # define STRUCT_ENDIAN_09 LITTLE_ENDIAN | |||
151 | # define STRUCT_ENDIAN_10 LITTLE_ENDIAN | |||
189 | #endif | 152 | #endif | |
190 | 153 | |||
191 | 154 | |||
192 | CFATTACH_DECL3_NEW(virtio_pci, sizeof(struct virtio_pci_softc), | 155 | CFATTACH_DECL3_NEW(virtio_pci, sizeof(struct virtio_pci_softc), | |
193 | virtio_pci_match, virtio_pci_attach, virtio_pci_detach, NULL, | 156 | virtio_pci_match, virtio_pci_attach, virtio_pci_detach, NULL, | |
194 | virtio_pci_rescan, NULL, DVF_DETACH_SHUTDOWN); | 157 | virtio_pci_rescan, NULL, DVF_DETACH_SHUTDOWN); | |
195 | 158 | |||
196 | static const struct virtio_ops virtio_pci_ops_09 = { | 159 | static const struct virtio_ops virtio_pci_ops_09 = { | |
197 | .kick = virtio_pci_kick_09, | 160 | .kick = virtio_pci_kick_09, | |
198 | ||||
199 | .read_dev_cfg_1 = virtio_pci_read_device_config_1, | |||
200 | .read_dev_cfg_2 = virtio_pci_read_device_config_2, | |||
201 | .read_dev_cfg_4 = virtio_pci_read_device_config_4, | |||
202 | .read_dev_cfg_8 = virtio_pci_read_device_config_8, | |||
203 | .write_dev_cfg_1 = virtio_pci_write_device_config_1, | |||
204 | .write_dev_cfg_2 = virtio_pci_write_device_config_2, | |||
205 | .write_dev_cfg_4 = virtio_pci_write_device_config_4, | |||
206 | .write_dev_cfg_8 = virtio_pci_write_device_config_8, | |||
207 | ||||
208 | .read_queue_size = virtio_pci_read_queue_size_09, | 161 | .read_queue_size = virtio_pci_read_queue_size_09, | |
209 | .setup_queue = virtio_pci_setup_queue_09, | 162 | .setup_queue = virtio_pci_setup_queue_09, | |
210 | .set_status = virtio_pci_set_status_09, | 163 | .set_status = virtio_pci_set_status_09, | |
211 | .neg_features = virtio_pci_negotiate_features_09, | 164 | .neg_features = virtio_pci_negotiate_features_09, | |
212 | .setup_interrupts = virtio_pci_setup_interrupts, | 165 | .setup_interrupts = virtio_pci_setup_interrupts, | |
213 | .free_interrupts = virtio_pci_free_interrupts, | 166 | .free_interrupts = virtio_pci_free_interrupts, | |
214 | }; | 167 | }; | |
215 | 168 | |||
216 | static const struct virtio_ops virtio_pci_ops_10 = { | 169 | static const struct virtio_ops virtio_pci_ops_10 = { | |
217 | .kick = virtio_pci_kick_10, | 170 | .kick = virtio_pci_kick_10, | |
218 | ||||
219 | .read_dev_cfg_1 = virtio_pci_read_device_config_1, | |||
220 | .read_dev_cfg_2 = virtio_pci_read_device_config_2, | |||
221 | .read_dev_cfg_4 = virtio_pci_read_device_config_4, | |||
222 | .read_dev_cfg_8 = virtio_pci_read_device_config_8, | |||
223 | .write_dev_cfg_1 = virtio_pci_write_device_config_1, | |||
224 | .write_dev_cfg_2 = virtio_pci_write_device_config_2, | |||
225 | .write_dev_cfg_4 = virtio_pci_write_device_config_4, | |||
226 | .write_dev_cfg_8 = virtio_pci_write_device_config_8, | |||
227 | ||||
228 | .read_queue_size = virtio_pci_read_queue_size_10, | 171 | .read_queue_size = virtio_pci_read_queue_size_10, | |
229 | .setup_queue = virtio_pci_setup_queue_10, | 172 | .setup_queue = virtio_pci_setup_queue_10, | |
230 | .set_status = virtio_pci_set_status_10, | 173 | .set_status = virtio_pci_set_status_10, | |
231 | .neg_features = virtio_pci_negotiate_features_10, | 174 | .neg_features = virtio_pci_negotiate_features_10, | |
232 | .setup_interrupts = virtio_pci_setup_interrupts, | 175 | .setup_interrupts = virtio_pci_setup_interrupts, | |
233 | .free_interrupts = virtio_pci_free_interrupts, | 176 | .free_interrupts = virtio_pci_free_interrupts, | |
234 | }; | 177 | }; | |
235 | 178 | |||
236 | static int | 179 | static int | |
237 | virtio_pci_match(device_t parent, cfdata_t match, void *aux) | 180 | virtio_pci_match(device_t parent, cfdata_t match, void *aux) | |
238 | { | 181 | { | |
239 | struct pci_attach_args *pa; | 182 | struct pci_attach_args *pa; | |
240 | 183 | |||
@@ -414,27 +357,31 @@ virtio_pci_attach_09(device_t self, void | @@ -414,27 +357,31 @@ virtio_pci_attach_09(device_t self, void | |||
414 | psc->sc_notify_iot = psc->sc_iot; | 357 | psc->sc_notify_iot = psc->sc_iot; | |
415 | 358 | |||
416 | /* ISR space */ | 359 | /* ISR space */ | |
417 | if (bus_space_subregion(psc->sc_iot, psc->sc_ioh, | 360 | if (bus_space_subregion(psc->sc_iot, psc->sc_ioh, | |
418 | VIRTIO_CONFIG_ISR_STATUS, 1, &psc->sc_isr_ioh)) { | 361 | VIRTIO_CONFIG_ISR_STATUS, 1, &psc->sc_isr_ioh)) { | |
419 | aprint_error_dev(self, "can't map isr i/o space\n"); | 362 | aprint_error_dev(self, "can't map isr i/o space\n"); | |
420 | return EIO; | 363 | return EIO; | |
421 | } | 364 | } | |
422 | psc->sc_isr_iosize = 1; | 365 | psc->sc_isr_iosize = 1; | |
423 | psc->sc_isr_iot = psc->sc_iot; | 366 | psc->sc_isr_iot = psc->sc_iot; | |
424 | 367 | |||
425 | /* set our version 0.9 ops */ | 368 | /* set our version 0.9 ops */ | |
426 | sc->sc_ops = &virtio_pci_ops_09; | 369 | sc->sc_ops = &virtio_pci_ops_09; | |
427 | sc->sc_devcfg_swap = VIODEVRW_SWAP_09; | 370 | sc->sc_bus_endian = READ_ENDIAN_09; | |
371 | sc->sc_struct_endian = STRUCT_ENDIAN_09; | |||
372 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |||
373 | sc->sc_aarch64eb_bus_problem = true; | |||
374 | #endif | |||
428 | return 0; | 375 | return 0; | |
429 | } | 376 | } | |
430 | 377 | |||
431 | 378 | |||
432 | static int | 379 | static int | |
433 | virtio_pci_attach_10(device_t self, void *aux) | 380 | virtio_pci_attach_10(device_t self, void *aux) | |
434 | { | 381 | { | |
435 | struct virtio_pci_softc * const psc = device_private(self); | 382 | struct virtio_pci_softc * const psc = device_private(self); | |
436 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; | 383 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; | |
437 | struct virtio_softc * const sc = &psc->sc_sc; | 384 | struct virtio_softc * const sc = &psc->sc_sc; | |
438 | pci_chipset_tag_t pc = pa->pa_pc; | 385 | pci_chipset_tag_t pc = pa->pa_pc; | |
439 | pcitag_t tag = pa->pa_tag; | 386 | pcitag_t tag = pa->pa_tag; | |
440 | 387 | |||
@@ -535,27 +482,28 @@ virtio_pci_attach_10(device_t self, void | @@ -535,27 +482,28 @@ virtio_pci_attach_10(device_t self, void | |||
535 | common.offset, common.length, &psc->sc_ioh)) { | 482 | common.offset, common.length, &psc->sc_ioh)) { | |
536 | aprint_error_dev(self, "can't map common i/o space\n"); | 483 | aprint_error_dev(self, "can't map common i/o space\n"); | |
537 | ret = EIO; | 484 | ret = EIO; | |
538 | goto err; | 485 | goto err; | |
539 | } | 486 | } | |
540 | psc->sc_iosize = common.length; | 487 | psc->sc_iosize = common.length; | |
541 | psc->sc_iot = psc->sc_bars_iot[i]; | 488 | psc->sc_iot = psc->sc_bars_iot[i]; | |
542 | psc->sc_mapped_iosize = psc->sc_bars_iosize[i]; | 489 | psc->sc_mapped_iosize = psc->sc_bars_iosize[i]; | |
543 | 490 | |||
544 | psc->sc_sc.sc_version_1 = 1; | 491 | psc->sc_sc.sc_version_1 = 1; | |
545 | 492 | |||
546 | /* set our version 1.0 ops */ | 493 | /* set our version 1.0 ops */ | |
547 | sc->sc_ops = &virtio_pci_ops_10; | 494 | sc->sc_ops = &virtio_pci_ops_10; | |
548 | sc->sc_devcfg_swap = VIODEVRW_SWAP_10; | 495 | sc->sc_bus_endian = READ_ENDIAN_10; | |
496 | sc->sc_struct_endian = STRUCT_ENDIAN_10; | |||
549 | return 0; | 497 | return 0; | |
550 | 498 | |||
551 | err: | 499 | err: | |
552 | /* undo our pci_mapreg_map()s */ | 500 | /* undo our pci_mapreg_map()s */ | |
553 | for (i = 0; i < __arraycount(bars); i++) { | 501 | for (i = 0; i < __arraycount(bars); i++) { | |
554 | if (psc->sc_bars_iosize[i] == 0) | 502 | if (psc->sc_bars_iosize[i] == 0) | |
555 | continue; | 503 | continue; | |
556 | bus_space_unmap(psc->sc_bars_iot[i], psc->sc_bars_ioh[i], | 504 | bus_space_unmap(psc->sc_bars_iot[i], psc->sc_bars_ioh[i], | |
557 | psc->sc_bars_iosize[i]); | 505 | psc->sc_bars_iosize[i]); | |
558 | } | 506 | } | |
559 | return ret; | 507 | return ret; | |
560 | } | 508 | } | |
561 | 509 | |||
@@ -845,186 +793,26 @@ virtio_pci_negotiate_features_10(struct | @@ -845,186 +793,26 @@ virtio_pci_negotiate_features_10(struct | |||
845 | } | 793 | } | |
846 | 794 | |||
847 | if ((negotiated & VIRTIO_F_VERSION_1) == 0) { | 795 | if ((negotiated & VIRTIO_F_VERSION_1) == 0) { | |
848 | aprint_error_dev(self, "host rejected version 1\n"); | 796 | aprint_error_dev(self, "host rejected version 1\n"); | |
849 | bus_space_write_1(iot, ioh, VIRTIO_CONFIG1_DEVICE_STATUS, | 797 | bus_space_write_1(iot, ioh, VIRTIO_CONFIG1_DEVICE_STATUS, | |
850 | VIRTIO_CONFIG_DEVICE_STATUS_FAILED); | 798 | VIRTIO_CONFIG_DEVICE_STATUS_FAILED); | |
851 | return; | 799 | return; | |
852 | } | 800 | } | |
853 | 801 | |||
854 | sc->sc_active_features = negotiated; | 802 | sc->sc_active_features = negotiated; | |
855 | return; | 803 | return; | |
856 | } | 804 | } | |
857 | 805 | |||
858 | /* ------------------------------------- | |||
859 | * Read/write device config code | |||
860 | * -------------------------------------*/ | |||
861 | ||||
862 | static uint8_t | |||
863 | virtio_pci_read_device_config_1(struct virtio_softc *vsc, int index) | |||
864 | { | |||
865 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
866 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
867 | ||||
868 | return bus_space_read_1(iot, ioh, index); | |||
869 | } | |||
870 | ||||
871 | static uint16_t | |||
872 | virtio_pci_read_device_config_2(struct virtio_softc *vsc, int index) | |||
873 | { | |||
874 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
875 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
876 | uint16_t val; | |||
877 | ||||
878 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |||
879 | val = bus_space_read_2(iot, ioh, index); | |||
880 | return val; | |||
881 | #else | |||
882 | val = bus_space_read_stream_2(iot, ioh, index); | |||
883 | if (vsc->sc_devcfg_swap) | |||
884 | return bswap16(val); | |||
885 | return val; | |||
886 | #endif | |||
887 | } | |||
888 | ||||
889 | static uint32_t | |||
890 | virtio_pci_read_device_config_4(struct virtio_softc *vsc, int index) | |||
891 | { | |||
892 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
893 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
894 | uint32_t val; | |||
895 | ||||
896 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |||
897 | val = bus_space_read_4(iot, ioh, index); | |||
898 | return val; | |||
899 | #else | |||
900 | val = bus_space_read_stream_4(iot, ioh, index); | |||
901 | if (vsc->sc_devcfg_swap) | |||
902 | return bswap32(val); | |||
903 | return val; | |||
904 | #endif | |||
905 | } | |||
906 | ||||
907 | static uint64_t | |||
908 | virtio_pci_read_device_config_8(struct virtio_softc *vsc, int index) | |||
909 | { | |||
910 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
911 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
912 | uint64_t val, val_h, val_l; | |||
913 | ||||
914 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |||
915 | if (vsc->sc_devcfg_swap) { | |||
916 | val_l = bus_space_read_4(iot, ioh, index); | |||
917 | val_h = bus_space_read_4(iot, ioh, index + 4); | |||
918 | } else { | |||
919 | val_h = bus_space_read_4(iot, ioh, index); | |||
920 | val_l = bus_space_read_4(iot, ioh, index + 4); | |||
921 | } | |||
922 | val = val_h << 32; | |||
923 | val |= val_l; | |||
924 | return val; | |||
925 | #elif BYTE_ORDER == BIG_ENDIAN | |||
926 | val_h = bus_space_read_stream_4(iot, ioh, index); | |||
927 | val_l = bus_space_read_stream_4(iot, ioh, index + 4); | |||
928 | val = val_h << 32; | |||
929 | val |= val_l; | |||
930 | if (vsc->sc_devcfg_swap) | |||
931 | return bswap64(val); | |||
932 | return val; | |||
933 | #else | |||
934 | val_l = bus_space_read_4(iot, ioh, index); | |||
935 | val_h = bus_space_read_4(iot, ioh, index + 4); | |||
936 | val = val_h << 32; | |||
937 | val |= val_l; | |||
938 | ||||
939 | return val; | |||
940 | #endif | |||
941 | } | |||
942 | ||||
943 | static void | |||
944 | virtio_pci_write_device_config_1(struct virtio_softc *vsc, | |||
945 | int index, uint8_t value) | |||
946 | { | |||
947 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
948 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
949 | ||||
950 | bus_space_write_1(iot, ioh, index, value); | |||
951 | } | |||
952 | ||||
953 | static void | |||
954 | virtio_pci_write_device_config_2(struct virtio_softc *vsc, | |||
955 | int index, uint16_t value) | |||
956 | { | |||
957 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
958 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
959 | ||||
960 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |||
961 | bus_space_write_2(iot, ioh, index, value); | |||
962 | #else | |||
963 | if (vsc->sc_devcfg_swap) | |||
964 | value = bswap16(value); | |||
965 | bus_space_write_stream_2(iot, ioh, index, value); | |||
966 | #endif | |||
967 | } | |||
968 | ||||
969 | static void | |||
970 | virtio_pci_write_device_config_4(struct virtio_softc *vsc, | |||
971 | int index, uint32_t value) | |||
972 | { | |||
973 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
974 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
975 | ||||
976 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |||
977 | bus_space_write_4(iot, ioh, index, value); | |||
978 | #else | |||
979 | if (vsc->sc_devcfg_swap) | |||
980 | value = bswap32(value); | |||
981 | bus_space_write_stream_4(iot, ioh, index, value); | |||
982 | #endif | |||
983 | } | |||
984 | ||||
985 | static void | |||
986 | virtio_pci_write_device_config_8(struct virtio_softc *vsc, | |||
987 | int index, uint64_t value) | |||
988 | { | |||
989 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
990 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
991 | uint64_t val_h, val_l; | |||
992 | ||||
993 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |||
994 | val_l = value & 0xffffffff; | |||
995 | val_h = value >> 32; | |||
996 | if (vsc->sc_devcfg_swap) { | |||
997 | bus_space_write_4(iot, ioh, index, val_l); | |||
998 | bus_space_write_4(iot, ioh, index + 4, val_h); | |||
999 | } else { | |||
1000 | bus_space_write_4(iot, ioh, index, val_h); | |||
1001 | bus_space_write_4(iot, ioh, index + 4, val_l); | |||
1002 | } | |||
1003 | #elif BYTE_ORDER == BIG_ENDIAN | |||
1004 | if (vsc->sc_devcfg_swap) | |||
1005 | value = bswap64(value); | |||
1006 | val_l = value & 0xffffffff; | |||
1007 | val_h = value >> 32; | |||
1008 | ||||
1009 | bus_space_write_stream_4(iot, ioh, index, val_h); | |||
1010 | bus_space_write_stream_4(iot, ioh, index + 4, val_l); | |||
1011 | #else | |||
1012 | val_l = value & 0xffffffff; | |||
1013 | val_h = value >> 32; | |||
1014 | bus_space_write_stream_4(iot, ioh, index, val_l); | |||
1015 | bus_space_write_stream_4(iot, ioh, index + 4, val_h); | |||
1016 | #endif | |||
1017 | } | |||
1018 | 806 | |||
1019 | /* ------------------------------------- | 807 | /* ------------------------------------- | |
1020 | * Generic PCI interrupt code | 808 | * Generic PCI interrupt code | |
1021 | * -------------------------------------*/ | 809 | * -------------------------------------*/ | |
1022 | 810 | |||
1023 | static int | 811 | static int | |
1024 | virtio_pci_setup_msix_vectors_10(struct virtio_softc *sc) | 812 | virtio_pci_setup_msix_vectors_10(struct virtio_softc *sc) | |
1025 | { | 813 | { | |
1026 | struct virtio_pci_softc * const psc = (struct virtio_pci_softc *)sc; | 814 | struct virtio_pci_softc * const psc = (struct virtio_pci_softc *)sc; | |
1027 | device_t self = sc->sc_dev; | 815 | device_t self = sc->sc_dev; | |
1028 | bus_space_tag_t iot = psc->sc_iot; | 816 | bus_space_tag_t iot = psc->sc_iot; | |
1029 | bus_space_handle_t ioh = psc->sc_ioh; | 817 | bus_space_handle_t ioh = psc->sc_ioh; | |
1030 | int vector, ret, qid; | 818 | int vector, ret, qid; |
--- src/sys/dev/pci/virtiovar.h 2021/01/20 21:59:48 1.18
+++ src/sys/dev/pci/virtiovar.h 2021/01/28 15:43:12 1.19
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: virtiovar.h,v 1.18 2021/01/20 21:59:48 reinoud Exp $ */ | 1 | /* $NetBSD: virtiovar.h,v 1.19 2021/01/28 15:43:12 reinoud Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2010 Minoura Makoto. | 4 | * Copyright (c) 2010 Minoura Makoto. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -125,50 +125,45 @@ struct virtqueue { | @@ -125,50 +125,45 @@ struct virtqueue { | |||
125 | /* for 1.0 */ | 125 | /* for 1.0 */ | |
126 | uint32_t vq_notify_off; | 126 | uint32_t vq_notify_off; | |
127 | }; | 127 | }; | |
128 | 128 | |||
129 | struct virtio_attach_args { | 129 | struct virtio_attach_args { | |
130 | int sc_childdevid; | 130 | int sc_childdevid; | |
131 | }; | 131 | }; | |
132 | 132 | |||
133 | typedef int (*virtio_callback)(struct virtio_softc*); | 133 | typedef int (*virtio_callback)(struct virtio_softc*); | |
134 | 134 | |||
135 | #ifdef VIRTIO_PRIVATE | 135 | #ifdef VIRTIO_PRIVATE | |
136 | struct virtio_ops { | 136 | struct virtio_ops { | |
137 | void (*kick)(struct virtio_softc *, uint16_t); | 137 | void (*kick)(struct virtio_softc *, uint16_t); | |
138 | ||||
139 | uint8_t (*read_dev_cfg_1)(struct virtio_softc *, int); | |||
140 | uint16_t (*read_dev_cfg_2)(struct virtio_softc *, int); | |||
141 | uint32_t (*read_dev_cfg_4)(struct virtio_softc *, int); | |||
142 | uint64_t (*read_dev_cfg_8)(struct virtio_softc *, int); | |||
143 | void (*write_dev_cfg_1)(struct virtio_softc *, int, uint8_t); | |||
144 | void (*write_dev_cfg_2)(struct virtio_softc *, int, uint16_t); | |||
145 | void (*write_dev_cfg_4)(struct virtio_softc *, int, uint32_t); | |||
146 | void (*write_dev_cfg_8)(struct virtio_softc *, int, uint64_t); | |||
147 | ||||
148 | uint16_t (*read_queue_size)(struct virtio_softc *, uint16_t); | 138 | uint16_t (*read_queue_size)(struct virtio_softc *, uint16_t); | |
149 | void (*setup_queue)(struct virtio_softc *, uint16_t, uint64_t); | 139 | void (*setup_queue)(struct virtio_softc *, uint16_t, uint64_t); | |
150 | void (*set_status)(struct virtio_softc *, int); | 140 | void (*set_status)(struct virtio_softc *, int); | |
151 | void (*neg_features)(struct virtio_softc *, uint64_t); | 141 | void (*neg_features)(struct virtio_softc *, uint64_t); | |
152 | int (*setup_interrupts)(struct virtio_softc *); | 142 | int (*setup_interrupts)(struct virtio_softc *); | |
153 | void (*free_interrupts)(struct virtio_softc *); | 143 | void (*free_interrupts)(struct virtio_softc *); | |
154 | }; | 144 | }; | |
155 | 145 | |||
156 | struct virtio_softc { | 146 | struct virtio_softc { | |
157 | device_t sc_dev; | 147 | device_t sc_dev; | |
158 | const struct virtio_ops *sc_ops; | 148 | const struct virtio_ops *sc_ops; | |
159 | bus_dma_tag_t sc_dmat; | 149 | bus_dma_tag_t sc_dmat; | |
160 | 150 | |||
161 | bool sc_devcfg_swap; | 151 | #define AARCH64EB_PROBLEM /* see comment in virtio_pci.c */ | |
152 | bool sc_aarch64eb_bus_problem; | |||
153 | ||||
154 | int sc_bus_endian; | |||
155 | int sc_struct_endian; | |||
156 | ||||
162 | bus_space_tag_t sc_devcfg_iot; | 157 | bus_space_tag_t sc_devcfg_iot; | |
163 | bus_space_handle_t sc_devcfg_ioh; | 158 | bus_space_handle_t sc_devcfg_ioh; | |
164 | bus_size_t sc_devcfg_iosize; | 159 | bus_size_t sc_devcfg_iosize; | |
165 | 160 | |||
166 | int sc_ipl; /* set by child */ | 161 | int sc_ipl; /* set by child */ | |
167 | void *sc_soft_ih; | 162 | void *sc_soft_ih; | |
168 | 163 | |||
169 | int sc_flags; /* set by child */ | 164 | int sc_flags; /* set by child */ | |
170 | 165 | |||
171 | uint64_t sc_active_features; | 166 | uint64_t sc_active_features; | |
172 | bool sc_indirect; | 167 | bool sc_indirect; | |
173 | bool sc_version_1; | 168 | bool sc_version_1; | |
174 | bool sc_finished_called; | 169 | bool sc_finished_called; |
--- src/sys/dev/virtio/virtio_mmio.c 2021/01/20 19:46:48 1.4
+++ src/sys/dev/virtio/virtio_mmio.c 2021/01/28 15:43:13 1.5
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: virtio_mmio.c,v 1.4 2021/01/20 19:46:48 reinoud Exp $ */ | 1 | /* $NetBSD: virtio_mmio.c,v 1.5 2021/01/28 15:43:13 reinoud Exp $ */ | |
2 | /* $OpenBSD: virtio_mmio.c,v 1.2 2017/02/24 17:12:31 patrick Exp $ */ | 2 | /* $OpenBSD: virtio_mmio.c,v 1.2 2017/02/24 17:12:31 patrick Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se> | 5 | * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se> | |
6 | * Copyright (c) 2012 Stefan Fritsch. | 6 | * Copyright (c) 2012 Stefan Fritsch. | |
7 | * Copyright (c) 2010 Minoura Makoto. | 7 | * Copyright (c) 2010 Minoura Makoto. | |
8 | * All rights reserved. | 8 | * All rights reserved. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -19,27 +19,27 @@ | @@ -19,27 +19,27 @@ | |||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #include <sys/cdefs.h> | 31 | #include <sys/cdefs.h> | |
32 | __KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.4 2021/01/20 19:46:48 reinoud Exp $"); | 32 | __KERNEL_RCSID(0, "$NetBSD: virtio_mmio.c,v 1.5 2021/01/28 15:43:13 reinoud Exp $"); | |
33 | 33 | |||
34 | #include <sys/param.h> | 34 | #include <sys/param.h> | |
35 | #include <sys/systm.h> | 35 | #include <sys/systm.h> | |
36 | #include <sys/kernel.h> | 36 | #include <sys/kernel.h> | |
37 | #include <sys/device.h> | 37 | #include <sys/device.h> | |
38 | #include <sys/mutex.h> | 38 | #include <sys/mutex.h> | |
39 | 39 | |||
40 | #define VIRTIO_PRIVATE | 40 | #define VIRTIO_PRIVATE | |
41 | #include <dev/virtio/virtio_mmiovar.h> | 41 | #include <dev/virtio/virtio_mmiovar.h> | |
42 | 42 | |||
43 | #define VIRTIO_MMIO_MAGIC ('v' | 'i' << 8 | 'r' << 16 | 't' << 24) | 43 | #define VIRTIO_MMIO_MAGIC ('v' | 'i' << 8 | 'r' << 16 | 't' << 24) | |
44 | 44 | |||
45 | #define VIRTIO_MMIO_MAGIC_VALUE 0x000 | 45 | #define VIRTIO_MMIO_MAGIC_VALUE 0x000 | |
@@ -58,82 +58,53 @@ __KERNEL_RCSID(0, "$NetBSD: virtio_mmio. | @@ -58,82 +58,53 @@ __KERNEL_RCSID(0, "$NetBSD: virtio_mmio. | |||
58 | #define VIRTIO_MMIO_QUEUE_PFN 0x040 | 58 | #define VIRTIO_MMIO_QUEUE_PFN 0x040 | |
59 | #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 | 59 | #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 | |
60 | #define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 | 60 | #define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 | |
61 | #define VIRTIO_MMIO_INTERRUPT_ACK 0x064 | 61 | #define VIRTIO_MMIO_INTERRUPT_ACK 0x064 | |
62 | #define VIRTIO_MMIO_STATUS 0x070 | 62 | #define VIRTIO_MMIO_STATUS 0x070 | |
63 | #define VIRTIO_MMIO_CONFIG 0x100 | 63 | #define VIRTIO_MMIO_CONFIG 0x100 | |
64 | 64 | |||
65 | #define VIRTIO_MMIO_INT_VRING (1 << 0) | 65 | #define VIRTIO_MMIO_INT_VRING (1 << 0) | |
66 | #define VIRTIO_MMIO_INT_CONFIG (1 << 1) | 66 | #define VIRTIO_MMIO_INT_CONFIG (1 << 1) | |
67 | 67 | |||
68 | /* | 68 | /* | |
69 | * MMIO configuration space for virtio-mmio v1 is in guest byte order. | 69 | * MMIO configuration space for virtio-mmio v1 is in guest byte order. | |
70 | * | 70 | * | |
71 | * AArch64 BE is special in that its bus space functions always read little | 71 | * XXX Note that aarch64eb pretends to be little endian. the MMIO registers | |
72 | * endian like on the PCI bus and thus need swapping to read host endian | 72 | * are in little endian but the device config registers and data structures | |
73 | * registers. | 73 | * are in big endian; this is due to a bug in current Qemu. | |
74 | * | |||
75 | * XXX this might also be true for other big endian machines. | |||
76 | * XXX: TODO test virtio MMIO on non AArch64 big endian machines. | |||
77 | */ | 74 | */ | |
78 | 75 | |||
79 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | 76 | #if defined(__aarch64__) && BYTE_ORDER == BIG_ENDIAN | |
80 | #define VIO16TOH(x) le16toh(x) | 77 | # define READ_ENDIAN LITTLE_ENDIAN | |
81 | #define VIO32TOH(x) le32toh(x) | 78 | # define STRUCT_ENDIAN BIG_ENDIAN | |
82 | #define VIO64TOH(x) le64toh(x) | 79 | #elif BYTE_ORDER == BIG_ENDIAN | |
83 | #define HTOVIO16(x) htole16(x) | 80 | # define READ_ENDIAN BIG_ENDIAN | |
84 | #define HTOVIO32(x) htole32(x) | 81 | # define STRUCT_ENDIAN BIG_ENDIAN | |
85 | #define HTOVIO64(x) htole64(x) | |||
86 | #define VIODEVRW_SWAP false /* can only be native endian now */ | |||
87 | #else | 82 | #else | |
88 | #define VIO16TOH(x) (x) | 83 | # define READ_ENDIAN LITTLE_ENDIAN | |
89 | #define VIO32TOH(x) (x) | 84 | # define STRUCT_ENDIAN LITTLE_ENDIAN | |
90 | #define VIO64TOH(x) (x) | |||
91 | #define HTOVIO16(x) (x) | |||
92 | #define HTOVIO32(x) (x) | |||
93 | #define HTOVIO64(x) (x) | |||
94 | #define VIODEVRW_SWAP false /* will only be native endian now */ | |||
95 | #endif | 85 | #endif | |
96 | 86 | |||
97 | 87 | |||
98 | static void virtio_mmio_kick(struct virtio_softc *, uint16_t); | 88 | static void virtio_mmio_kick(struct virtio_softc *, uint16_t); | |
99 | static uint8_t virtio_mmio_read_device_config_1(struct virtio_softc *, int); | |||
100 | static uint16_t virtio_mmio_read_device_config_2(struct virtio_softc *, int); | |||
101 | static uint32_t virtio_mmio_read_device_config_4(struct virtio_softc *, int); | |||
102 | static uint64_t virtio_mmio_read_device_config_8(struct virtio_softc *, int); | |||
103 | static void virtio_mmio_write_device_config_1(struct virtio_softc *, int, uint8_t); | |||
104 | static void virtio_mmio_write_device_config_2(struct virtio_softc *, int, uint16_t); | |||
105 | static void virtio_mmio_write_device_config_4(struct virtio_softc *, int, uint32_t); | |||
106 | static void virtio_mmio_write_device_config_8(struct virtio_softc *, int, uint64_t); | |||
107 | ||||
108 | static uint16_t virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t); | 89 | static uint16_t virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t); | |
109 | static void virtio_mmio_setup_queue(struct virtio_softc *, uint16_t, uint64_t); | 90 | static void virtio_mmio_setup_queue(struct virtio_softc *, uint16_t, uint64_t); | |
110 | static void virtio_mmio_set_status(struct virtio_softc *, int); | 91 | static void virtio_mmio_set_status(struct virtio_softc *, int); | |
111 | static void virtio_mmio_negotiate_features(struct virtio_softc *, uint64_t); | 92 | static void virtio_mmio_negotiate_features(struct virtio_softc *, uint64_t); | |
112 | static int virtio_mmio_setup_interrupts(struct virtio_softc *); | 93 | static int virtio_mmio_setup_interrupts(struct virtio_softc *); | |
113 | static void virtio_mmio_free_interrupts(struct virtio_softc *); | 94 | static void virtio_mmio_free_interrupts(struct virtio_softc *); | |
114 | 95 | |||
115 | static const struct virtio_ops virtio_mmio_ops = { | 96 | static const struct virtio_ops virtio_mmio_ops = { | |
116 | .kick = virtio_mmio_kick, | 97 | .kick = virtio_mmio_kick, | |
117 | ||||
118 | .read_dev_cfg_1 = virtio_mmio_read_device_config_1, | |||
119 | .read_dev_cfg_2 = virtio_mmio_read_device_config_2, | |||
120 | .read_dev_cfg_4 = virtio_mmio_read_device_config_4, | |||
121 | .read_dev_cfg_8 = virtio_mmio_read_device_config_8, | |||
122 | .write_dev_cfg_1 = virtio_mmio_write_device_config_1, | |||
123 | .write_dev_cfg_2 = virtio_mmio_write_device_config_2, | |||
124 | .write_dev_cfg_4 = virtio_mmio_write_device_config_4, | |||
125 | .write_dev_cfg_8 = virtio_mmio_write_device_config_8, | |||
126 | ||||
127 | .read_queue_size = virtio_mmio_read_queue_size, | 98 | .read_queue_size = virtio_mmio_read_queue_size, | |
128 | .setup_queue = virtio_mmio_setup_queue, | 99 | .setup_queue = virtio_mmio_setup_queue, | |
129 | .set_status = virtio_mmio_set_status, | 100 | .set_status = virtio_mmio_set_status, | |
130 | .neg_features = virtio_mmio_negotiate_features, | 101 | .neg_features = virtio_mmio_negotiate_features, | |
131 | .setup_interrupts = virtio_mmio_setup_interrupts, | 102 | .setup_interrupts = virtio_mmio_setup_interrupts, | |
132 | .free_interrupts = virtio_mmio_free_interrupts, | 103 | .free_interrupts = virtio_mmio_free_interrupts, | |
133 | }; | 104 | }; | |
134 | 105 | |||
135 | static uint16_t | 106 | static uint16_t | |
136 | virtio_mmio_read_queue_size(struct virtio_softc *vsc, uint16_t idx) | 107 | virtio_mmio_read_queue_size(struct virtio_softc *vsc, uint16_t idx) | |
137 | { | 108 | { | |
138 | struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; | 109 | struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; | |
139 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx); | 110 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_QUEUE_SEL, idx); | |
@@ -192,27 +163,28 @@ virtio_mmio_common_attach(struct virtio_ | @@ -192,27 +163,28 @@ virtio_mmio_common_attach(struct virtio_ | |||
192 | 163 | |||
193 | id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_DEVICE_ID); | 164 | id = bus_space_read_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_DEVICE_ID); | |
194 | 165 | |||
195 | /* we could use PAGE_SIZE, but virtio(4) assumes 4KiB for now */ | 166 | /* we could use PAGE_SIZE, but virtio(4) assumes 4KiB for now */ | |
196 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_GUEST_PAGE_SIZE, | 167 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_MMIO_GUEST_PAGE_SIZE, | |
197 | VIRTIO_PAGE_SIZE); | 168 | VIRTIO_PAGE_SIZE); | |
198 | 169 | |||
199 | /* no device connected. */ | 170 | /* no device connected. */ | |
200 | if (id == 0) | 171 | if (id == 0) | |
201 | return; | 172 | return; | |
202 | 173 | |||
203 | virtio_print_device_type(self, id, ver); | 174 | virtio_print_device_type(self, id, ver); | |
204 | vsc->sc_ops = &virtio_mmio_ops; | 175 | vsc->sc_ops = &virtio_mmio_ops; | |
205 | vsc->sc_devcfg_swap = VIODEVRW_SWAP; | 176 | vsc->sc_bus_endian = READ_ENDIAN; | |
177 | vsc->sc_struct_endian = STRUCT_ENDIAN; | |||
206 | 178 | |||
207 | /* set up our device config tag */ | 179 | /* set up our device config tag */ | |
208 | vsc->sc_devcfg_iosize = sc->sc_iosize - VIRTIO_MMIO_CONFIG; | 180 | vsc->sc_devcfg_iosize = sc->sc_iosize - VIRTIO_MMIO_CONFIG; | |
209 | vsc->sc_devcfg_iot = sc->sc_iot; | 181 | vsc->sc_devcfg_iot = sc->sc_iot; | |
210 | if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, | 182 | if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, | |
211 | VIRTIO_MMIO_CONFIG, vsc->sc_devcfg_iosize, | 183 | VIRTIO_MMIO_CONFIG, vsc->sc_devcfg_iosize, | |
212 | &vsc->sc_devcfg_ioh)) { | 184 | &vsc->sc_devcfg_ioh)) { | |
213 | aprint_error_dev(self, "can't map config i/o space\n"); | 185 | aprint_error_dev(self, "can't map config i/o space\n"); | |
214 | return; | 186 | return; | |
215 | } | 187 | } | |
216 | 188 | |||
217 | virtio_device_reset(vsc); | 189 | virtio_device_reset(vsc); | |
218 | virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); | 190 | virtio_mmio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); | |
@@ -259,120 +231,26 @@ virtio_mmio_negotiate_features(struct vi | @@ -259,120 +231,26 @@ virtio_mmio_negotiate_features(struct vi | |||
259 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, | 231 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, | |
260 | VIRTIO_MMIO_HOST_FEATURES_SEL, 0); | 232 | VIRTIO_MMIO_HOST_FEATURES_SEL, 0); | |
261 | r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, | 233 | r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, | |
262 | VIRTIO_MMIO_HOST_FEATURES); | 234 | VIRTIO_MMIO_HOST_FEATURES); | |
263 | r &= guest_features; | 235 | r &= guest_features; | |
264 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, | 236 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, | |
265 | VIRTIO_MMIO_GUEST_FEATURES_SEL, 0); | 237 | VIRTIO_MMIO_GUEST_FEATURES_SEL, 0); | |
266 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, | 238 | bus_space_write_4(sc->sc_iot, sc->sc_ioh, | |
267 | VIRTIO_MMIO_GUEST_FEATURES, r); | 239 | VIRTIO_MMIO_GUEST_FEATURES, r); | |
268 | 240 | |||
269 | vsc->sc_active_features = r; | 241 | vsc->sc_active_features = r; | |
270 | } | 242 | } | |
271 | 243 | |||
272 | # | |||
273 | /* | |||
274 | * Device configuration registers. | |||
275 | */ | |||
276 | ||||
277 | /* ---------------------------------------------------- | |||
278 | * Read/write device config code | |||
279 | * ----------------------------------------------------*/ | |||
280 | ||||
281 | static uint8_t | |||
282 | virtio_mmio_read_device_config_1(struct virtio_softc *vsc, int index) | |||
283 | { | |||
284 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
285 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
286 | ||||
287 | return bus_space_read_1(iot, ioh, index); | |||
288 | } | |||
289 | ||||
290 | static uint16_t | |||
291 | virtio_mmio_read_device_config_2(struct virtio_softc *vsc, int index) | |||
292 | { | |||
293 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
294 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
295 | ||||
296 | return VIO16TOH(bus_space_read_2(iot, ioh, index)); | |||
297 | } | |||
298 | ||||
299 | static uint32_t | |||
300 | virtio_mmio_read_device_config_4(struct virtio_softc *vsc, int index) | |||
301 | { | |||
302 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
303 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
304 | ||||
305 | return VIO32TOH(bus_space_read_4(iot, ioh, index)); | |||
306 | } | |||
307 | ||||
308 | static uint64_t | |||
309 | virtio_mmio_read_device_config_8(struct virtio_softc *vsc, int index) | |||
310 | { | |||
311 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
312 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
313 | uint64_t r; | |||
314 | ||||
315 | r = bus_space_read_4(iot, ioh, index + sizeof(uint32_t)); | |||
316 | r <<= 32; | |||
317 | r += bus_space_read_4(iot, ioh, index); | |||
318 | return VIO64TOH(r); | |||
319 | } | |||
320 | ||||
321 | static void | |||
322 | virtio_mmio_write_device_config_1(struct virtio_softc *vsc, | |||
323 | int index, uint8_t value) | |||
324 | { | |||
325 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
326 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
327 | ||||
328 | bus_space_write_1(iot, ioh, index, value); | |||
329 | } | |||
330 | ||||
331 | static void | |||
332 | virtio_mmio_write_device_config_2(struct virtio_softc *vsc, | |||
333 | int index, uint16_t value) | |||
334 | { | |||
335 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
336 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
337 | ||||
338 | value = HTOVIO16(value); | |||
339 | bus_space_write_2(iot, ioh, index, value); | |||
340 | } | |||
341 | ||||
342 | static void | |||
343 | virtio_mmio_write_device_config_4(struct virtio_softc *vsc, | |||
344 | int index, uint32_t value) | |||
345 | { | |||
346 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
347 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
348 | ||||
349 | value = HTOVIO32(value); | |||
350 | bus_space_write_4(iot, ioh, index, value); | |||
351 | } | |||
352 | ||||
353 | static void | |||
354 | virtio_mmio_write_device_config_8(struct virtio_softc *vsc, | |||
355 | int index, uint64_t value) | |||
356 | { | |||
357 | bus_space_tag_t iot = vsc->sc_devcfg_iot; | |||
358 | bus_space_handle_t ioh = vsc->sc_devcfg_ioh; | |||
359 | ||||
360 | value = HTOVIO64(value); | |||
361 | bus_space_write_4(iot, ioh, index, value & 0xffffffff); | |||
362 | bus_space_write_4(iot, ioh, index + sizeof(uint32_t), value >> 32); | |||
363 | } | |||
364 | ||||
365 | ||||
366 | /* | 244 | /* | |
367 | * Interrupt handler. | 245 | * Interrupt handler. | |
368 | */ | 246 | */ | |
369 | int | 247 | int | |
370 | virtio_mmio_intr(void *arg) | 248 | virtio_mmio_intr(void *arg) | |
371 | { | 249 | { | |
372 | struct virtio_mmio_softc *sc = arg; | 250 | struct virtio_mmio_softc *sc = arg; | |
373 | struct virtio_softc *vsc = &sc->sc_sc; | 251 | struct virtio_softc *vsc = &sc->sc_sc; | |
374 | int isr, r = 0; | 252 | int isr, r = 0; | |
375 | 253 | |||
376 | /* check and ack the interrupt */ | 254 | /* check and ack the interrupt */ | |
377 | isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, | 255 | isr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, | |
378 | VIRTIO_MMIO_INTERRUPT_STATUS); | 256 | VIRTIO_MMIO_INTERRUPT_STATUS); |