Line data Source code
1 : /* $OpenBSD: virtio_pci.c,v 1.18 2017/05/31 08:57:48 sf Exp $ */
2 : /* $NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $ */
3 :
4 : /*
5 : * Copyright (c) 2012 Stefan Fritsch.
6 : * Copyright (c) 2010 Minoura Makoto.
7 : * All rights reserved.
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions
11 : * are met:
12 : * 1. Redistributions of source code must retain the above copyright
13 : * notice, this list of conditions and the following disclaimer.
14 : * 2. Redistributions in binary form must reproduce the above copyright
15 : * notice, this list of conditions and the following disclaimer in the
16 : * documentation and/or other materials provided with the distribution.
17 : *
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
20 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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
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
27 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : */
29 :
30 : #include <sys/param.h>
31 : #include <sys/systm.h>
32 : #include <sys/device.h>
33 : #include <sys/mutex.h>
34 :
35 : #include <dev/pci/pcidevs.h>
36 : #include <dev/pci/pcireg.h>
37 : #include <dev/pci/pcivar.h>
38 :
39 : #include <dev/pv/virtioreg.h>
40 : #include <dev/pv/virtiovar.h>
41 :
42 : /*
43 : * XXX: Before being used on big endian arches, the access to config registers
44 : * XXX: needs to be reviewed/fixed. The non-device specific registers are
45 : * XXX: PCI-endian while the device specific registers are native endian.
46 : */
47 :
48 : #define MAX_MSIX_VECS 8
49 : #define virtio_set_status(sc, s) virtio_pci_set_status(sc, s)
50 : #define virtio_device_reset(sc) virtio_set_status((sc), 0)
51 :
52 : struct virtio_pci_softc;
53 :
54 : int virtio_pci_match(struct device *, void *, void *);
55 : void virtio_pci_attach(struct device *, struct device *, void *);
56 : int virtio_pci_detach(struct device *, int);
57 :
58 : void virtio_pci_kick(struct virtio_softc *, uint16_t);
59 : uint8_t virtio_pci_read_device_config_1(struct virtio_softc *, int);
60 : uint16_t virtio_pci_read_device_config_2(struct virtio_softc *, int);
61 : uint32_t virtio_pci_read_device_config_4(struct virtio_softc *, int);
62 : uint64_t virtio_pci_read_device_config_8(struct virtio_softc *, int);
63 : void virtio_pci_write_device_config_1(struct virtio_softc *, int, uint8_t);
64 : void virtio_pci_write_device_config_2(struct virtio_softc *, int, uint16_t);
65 : void virtio_pci_write_device_config_4(struct virtio_softc *, int, uint32_t);
66 : void virtio_pci_write_device_config_8(struct virtio_softc *, int, uint64_t);
67 : uint16_t virtio_pci_read_queue_size(struct virtio_softc *, uint16_t);
68 : void virtio_pci_setup_queue(struct virtio_softc *, uint16_t, uint32_t);
69 : void virtio_pci_set_status(struct virtio_softc *, int);
70 : uint32_t virtio_pci_negotiate_features(struct virtio_softc *, uint32_t,
71 : const struct virtio_feature_name *);
72 : int virtio_pci_msix_establish(struct virtio_pci_softc *, struct pci_attach_args *, int, int (*)(void *), void *);
73 : int virtio_pci_setup_msix(struct virtio_pci_softc *, struct pci_attach_args *, int);
74 : void virtio_pci_free_irqs(struct virtio_pci_softc *);
75 : int virtio_pci_poll_intr(void *);
76 : int virtio_pci_legacy_intr(void *);
77 : int virtio_pci_legacy_intr_mpsafe(void *);
78 : int virtio_pci_config_intr(void *);
79 : int virtio_pci_queue_intr(void *);
80 : int virtio_pci_shared_queue_intr(void *);
81 :
82 : enum irq_type {
83 : IRQ_NO_MSIX,
84 : IRQ_MSIX_SHARED, /* vec 0: config irq, vec 1 shared by all vqs */
85 : IRQ_MSIX_PER_VQ, /* vec 0: config irq, vec n: irq of vq[n-1] */
86 : };
87 :
88 : struct virtio_pci_softc {
89 : struct virtio_softc sc_sc;
90 : pci_chipset_tag_t sc_pc;
91 :
92 : bus_space_tag_t sc_iot;
93 : bus_space_handle_t sc_ioh;
94 : bus_size_t sc_iosize;
95 :
96 : void *sc_ih[MAX_MSIX_VECS];
97 :
98 : int sc_config_offset;
99 : enum irq_type sc_irq_type;
100 : };
101 :
102 : struct cfattach virtio_pci_ca = {
103 : sizeof(struct virtio_pci_softc),
104 : virtio_pci_match,
105 : virtio_pci_attach,
106 : virtio_pci_detach,
107 : NULL
108 : };
109 :
110 : struct virtio_ops virtio_pci_ops = {
111 : virtio_pci_kick,
112 : virtio_pci_read_device_config_1,
113 : virtio_pci_read_device_config_2,
114 : virtio_pci_read_device_config_4,
115 : virtio_pci_read_device_config_8,
116 : virtio_pci_write_device_config_1,
117 : virtio_pci_write_device_config_2,
118 : virtio_pci_write_device_config_4,
119 : virtio_pci_write_device_config_8,
120 : virtio_pci_read_queue_size,
121 : virtio_pci_setup_queue,
122 : virtio_pci_set_status,
123 : virtio_pci_negotiate_features,
124 : virtio_pci_poll_intr,
125 : };
126 :
127 : uint16_t
128 0 : virtio_pci_read_queue_size(struct virtio_softc *vsc, uint16_t idx)
129 : {
130 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
131 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_SELECT,
132 : idx);
133 0 : return bus_space_read_2(sc->sc_iot, sc->sc_ioh,
134 : VIRTIO_CONFIG_QUEUE_SIZE);
135 : }
136 :
137 : void
138 0 : virtio_pci_setup_queue(struct virtio_softc *vsc, uint16_t idx, uint32_t addr)
139 : {
140 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
141 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_SELECT,
142 : idx);
143 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_ADDRESS,
144 : addr);
145 :
146 : /*
147 : * This path is only executed if this function is called after
148 : * the child's attach function has finished. In other cases,
149 : * it's done in virtio_pci_setup_msix().
150 : */
151 0 : if (sc->sc_irq_type != IRQ_NO_MSIX) {
152 : int vec = 1;
153 0 : if (sc->sc_irq_type == IRQ_MSIX_PER_VQ)
154 0 : vec += idx;
155 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
156 : VIRTIO_MSI_QUEUE_VECTOR, vec);
157 0 : }
158 0 : }
159 :
160 : void
161 0 : virtio_pci_set_status(struct virtio_softc *vsc, int status)
162 : {
163 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
164 : int old = 0;
165 :
166 0 : if (status != 0)
167 0 : old = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
168 : VIRTIO_CONFIG_DEVICE_STATUS);
169 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_DEVICE_STATUS,
170 : status|old);
171 0 : }
172 :
173 : int
174 0 : virtio_pci_match(struct device *parent, void *match, void *aux)
175 : {
176 : struct pci_attach_args *pa;
177 :
178 0 : pa = (struct pci_attach_args *)aux;
179 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_QUMRANET &&
180 0 : PCI_PRODUCT(pa->pa_id) >= 0x1000 &&
181 0 : PCI_PRODUCT(pa->pa_id) <= 0x103f &&
182 0 : PCI_REVISION(pa->pa_class) == 0)
183 0 : return 1;
184 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_OPENBSD &&
185 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_OPENBSD_CONTROL)
186 0 : return 1;
187 0 : return 0;
188 0 : }
189 :
190 : void
191 0 : virtio_pci_attach(struct device *parent, struct device *self, void *aux)
192 : {
193 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)self;
194 0 : struct virtio_softc *vsc = &sc->sc_sc;
195 0 : struct pci_attach_args *pa = (struct pci_attach_args *)aux;
196 0 : pci_chipset_tag_t pc = pa->pa_pc;
197 0 : pcitag_t tag = pa->pa_tag;
198 : int revision;
199 : pcireg_t id;
200 : char const *intrstr;
201 0 : pci_intr_handle_t ih;
202 :
203 0 : revision = PCI_REVISION(pa->pa_class);
204 0 : if (revision != 0) {
205 0 : printf("unknown revision 0x%02x; giving up\n", revision);
206 0 : return;
207 : }
208 :
209 : /* subsystem ID shows what I am */
210 0 : id = PCI_PRODUCT(pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG));
211 :
212 0 : printf("\n");
213 :
214 0 : vsc->sc_ops = &virtio_pci_ops;
215 0 : sc->sc_pc = pc;
216 0 : vsc->sc_dmat = pa->pa_dmat;
217 0 : sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI;
218 0 : sc->sc_irq_type = IRQ_NO_MSIX;
219 :
220 : /*
221 : * For virtio, ignore normal MSI black/white-listing depending on the
222 : * PCI bridge but enable it unconditionally.
223 : */
224 0 : pa->pa_flags |= PCI_FLAGS_MSI_ENABLED;
225 :
226 0 : if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
227 0 : &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize, 0)) {
228 0 : printf("%s: can't map i/o space\n", vsc->sc_dev.dv_xname);
229 0 : return;
230 : }
231 :
232 0 : virtio_device_reset(vsc);
233 0 : virtio_pci_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK);
234 0 : virtio_pci_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER);
235 :
236 : /* XXX: use softc as aux... */
237 0 : vsc->sc_childdevid = id;
238 0 : vsc->sc_child = NULL;
239 0 : config_found(self, sc, NULL);
240 0 : if (vsc->sc_child == NULL) {
241 0 : printf("%s: no matching child driver; not configured\n",
242 0 : vsc->sc_dev.dv_xname);
243 0 : goto fail_1;
244 : }
245 0 : if (vsc->sc_child == VIRTIO_CHILD_ERROR) {
246 0 : printf("%s: virtio configuration failed\n",
247 0 : vsc->sc_dev.dv_xname);
248 0 : goto fail_1;
249 : }
250 :
251 0 : if (virtio_pci_setup_msix(sc, pa, 0) == 0) {
252 0 : sc->sc_irq_type = IRQ_MSIX_PER_VQ;
253 : intrstr = "msix per-VQ";
254 0 : } else if (virtio_pci_setup_msix(sc, pa, 1) == 0) {
255 0 : sc->sc_irq_type = IRQ_MSIX_SHARED;
256 : intrstr = "msix shared";
257 0 : } else {
258 : int (*ih_func)(void *) = virtio_pci_legacy_intr;
259 0 : if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
260 0 : printf("%s: couldn't map interrupt\n", vsc->sc_dev.dv_xname);
261 0 : goto fail_2;
262 : }
263 0 : intrstr = pci_intr_string(pc, ih);
264 : /*
265 : * We always set the IPL_MPSAFE flag in order to do the relatively
266 : * expensive ISR read without lock, and then grab the kernel lock in
267 : * the interrupt handler.
268 : */
269 0 : if (vsc->sc_ipl & IPL_MPSAFE)
270 0 : ih_func = virtio_pci_legacy_intr_mpsafe;
271 0 : sc->sc_ih[0] = pci_intr_establish(pc, ih, vsc->sc_ipl | IPL_MPSAFE,
272 0 : ih_func, sc, vsc->sc_dev.dv_xname);
273 0 : if (sc->sc_ih[0] == NULL) {
274 0 : printf("%s: couldn't establish interrupt", vsc->sc_dev.dv_xname);
275 0 : if (intrstr != NULL)
276 0 : printf(" at %s", intrstr);
277 0 : printf("\n");
278 0 : goto fail_2;
279 : }
280 0 : }
281 0 : printf("%s: %s\n", vsc->sc_dev.dv_xname, intrstr);
282 :
283 0 : virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK);
284 0 : return;
285 :
286 : fail_2:
287 0 : config_detach(vsc->sc_child, 0);
288 : fail_1:
289 : /* no pci_mapreg_unmap() or pci_intr_unmap() */
290 0 : virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
291 0 : }
292 :
293 : int
294 0 : virtio_pci_detach(struct device *self, int flags)
295 : {
296 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)self;
297 0 : struct virtio_softc *vsc = &sc->sc_sc;
298 : int r;
299 :
300 0 : if (vsc->sc_child != 0 && vsc->sc_child != VIRTIO_CHILD_ERROR) {
301 0 : r = config_detach(vsc->sc_child, flags);
302 0 : if (r)
303 0 : return r;
304 : }
305 0 : KASSERT(vsc->sc_child == 0 || vsc->sc_child == VIRTIO_CHILD_ERROR);
306 0 : KASSERT(vsc->sc_vqs == 0);
307 0 : virtio_pci_free_irqs(sc);
308 0 : if (sc->sc_iosize)
309 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
310 0 : sc->sc_iosize = 0;
311 :
312 0 : return 0;
313 0 : }
314 :
315 : /*
316 : * Feature negotiation.
317 : * Prints available / negotiated features if guest_feature_names != NULL and
318 : * VIRTIO_DEBUG is 1
319 : */
320 : uint32_t
321 0 : virtio_pci_negotiate_features(struct virtio_softc *vsc, uint32_t guest_features,
322 : const struct virtio_feature_name *guest_feature_names)
323 : {
324 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
325 : uint32_t host, neg;
326 :
327 : /*
328 : * indirect descriptors can be switched off by setting bit 1 in the
329 : * driver flags, see config(8)
330 : */
331 0 : if (!(vsc->sc_dev.dv_cfdata->cf_flags & 1) &&
332 0 : !(vsc->sc_child->dv_cfdata->cf_flags & 1)) {
333 0 : guest_features |= VIRTIO_F_RING_INDIRECT_DESC;
334 0 : } else {
335 0 : printf("RingIndirectDesc disabled by UKC\n");
336 : }
337 0 : host = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
338 : VIRTIO_CONFIG_DEVICE_FEATURES);
339 0 : neg = host & guest_features;
340 : #if VIRTIO_DEBUG
341 : if (guest_feature_names)
342 : virtio_log_features(host, neg, guest_feature_names);
343 : #endif
344 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh,
345 : VIRTIO_CONFIG_GUEST_FEATURES, neg);
346 0 : vsc->sc_features = neg;
347 0 : if (neg & VIRTIO_F_RING_INDIRECT_DESC)
348 0 : vsc->sc_indirect = 1;
349 : else
350 0 : vsc->sc_indirect = 0;
351 :
352 0 : return neg;
353 : }
354 :
355 : /*
356 : * Device configuration registers.
357 : */
358 : uint8_t
359 0 : virtio_pci_read_device_config_1(struct virtio_softc *vsc, int index)
360 : {
361 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
362 0 : return bus_space_read_1(sc->sc_iot, sc->sc_ioh,
363 : sc->sc_config_offset + index);
364 : }
365 :
366 : uint16_t
367 0 : virtio_pci_read_device_config_2(struct virtio_softc *vsc, int index)
368 : {
369 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
370 0 : return bus_space_read_2(sc->sc_iot, sc->sc_ioh,
371 : sc->sc_config_offset + index);
372 : }
373 :
374 : uint32_t
375 0 : virtio_pci_read_device_config_4(struct virtio_softc *vsc, int index)
376 : {
377 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
378 0 : return bus_space_read_4(sc->sc_iot, sc->sc_ioh,
379 : sc->sc_config_offset + index);
380 : }
381 :
382 : uint64_t
383 0 : virtio_pci_read_device_config_8(struct virtio_softc *vsc, int index)
384 : {
385 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
386 : uint64_t r;
387 :
388 0 : r = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
389 : sc->sc_config_offset + index + sizeof(uint32_t));
390 0 : r <<= 32;
391 0 : r += bus_space_read_4(sc->sc_iot, sc->sc_ioh,
392 : sc->sc_config_offset + index);
393 0 : return r;
394 : }
395 :
396 : void
397 0 : virtio_pci_write_device_config_1(struct virtio_softc *vsc, int index,
398 : uint8_t value)
399 : {
400 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
401 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh,
402 : sc->sc_config_offset + index, value);
403 0 : }
404 :
405 : void
406 0 : virtio_pci_write_device_config_2(struct virtio_softc *vsc, int index,
407 : uint16_t value)
408 : {
409 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
410 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
411 : sc->sc_config_offset + index, value);
412 0 : }
413 :
414 : void
415 0 : virtio_pci_write_device_config_4(struct virtio_softc *vsc,
416 : int index, uint32_t value)
417 : {
418 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
419 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh,
420 : sc->sc_config_offset + index, value);
421 0 : }
422 :
423 : void
424 0 : virtio_pci_write_device_config_8(struct virtio_softc *vsc,
425 : int index, uint64_t value)
426 : {
427 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
428 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh,
429 : sc->sc_config_offset + index, value & 0xffffffff);
430 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh,
431 : sc->sc_config_offset + index + sizeof(uint32_t), value >> 32);
432 0 : }
433 :
434 : int
435 0 : virtio_pci_msix_establish(struct virtio_pci_softc *sc,
436 : struct pci_attach_args *pa, int idx, int (*handler)(void *), void *ih_arg)
437 : {
438 0 : struct virtio_softc *vsc = &sc->sc_sc;
439 0 : pci_intr_handle_t ih;
440 :
441 0 : if (pci_intr_map_msix(pa, idx, &ih) != 0) {
442 : #if VIRTIO_DEBUG
443 : printf("%s[%d]: pci_intr_map_msix failed\n",
444 : vsc->sc_dev.dv_xname, idx);
445 : #endif
446 0 : return 1;
447 : }
448 0 : sc->sc_ih[idx] = pci_intr_establish(sc->sc_pc, ih, vsc->sc_ipl,
449 0 : handler, ih_arg, vsc->sc_dev.dv_xname);
450 0 : if (sc->sc_ih[idx] == NULL) {
451 0 : printf("%s[%d]: couldn't establish msix interrupt\n",
452 : vsc->sc_dev.dv_xname, idx);
453 0 : return 1;
454 : }
455 0 : return 0;
456 0 : }
457 :
458 : void
459 0 : virtio_pci_free_irqs(struct virtio_pci_softc *sc)
460 : {
461 0 : struct virtio_softc *vsc = &sc->sc_sc;
462 : int i;
463 :
464 0 : if (sc->sc_config_offset == VIRTIO_CONFIG_DEVICE_CONFIG_MSI) {
465 0 : for (i = 0; i < vsc->sc_nvqs; i++) {
466 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
467 : VIRTIO_CONFIG_QUEUE_SELECT, i);
468 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
469 : VIRTIO_MSI_QUEUE_VECTOR, VIRTIO_MSI_NO_VECTOR);
470 : }
471 : }
472 :
473 0 : for (i = 0; i < MAX_MSIX_VECS; i++) {
474 0 : if (sc->sc_ih[i]) {
475 0 : pci_intr_disestablish(sc->sc_pc, sc->sc_ih[i]);
476 0 : sc->sc_ih[i] = NULL;
477 0 : }
478 : }
479 :
480 0 : sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI;
481 0 : }
482 :
483 : int
484 0 : virtio_pci_setup_msix(struct virtio_pci_softc *sc, struct pci_attach_args *pa,
485 : int shared)
486 : {
487 0 : struct virtio_softc *vsc = &sc->sc_sc;
488 : int i;
489 :
490 0 : if (virtio_pci_msix_establish(sc, pa, 0, virtio_pci_config_intr, vsc))
491 0 : return 1;
492 0 : sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_MSI;
493 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh, VIRTIO_MSI_CONFIG_VECTOR, 0);
494 :
495 0 : if (shared) {
496 0 : if (virtio_pci_msix_establish(sc, pa, 1,
497 : virtio_pci_shared_queue_intr, vsc)) {
498 : goto fail;
499 : }
500 :
501 0 : for (i = 0; i < vsc->sc_nvqs; i++) {
502 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
503 : VIRTIO_CONFIG_QUEUE_SELECT, i);
504 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
505 : VIRTIO_MSI_QUEUE_VECTOR, 1);
506 : }
507 : } else {
508 0 : for (i = 0; i <= vsc->sc_nvqs; i++) {
509 0 : if (virtio_pci_msix_establish(sc, pa, i + 1,
510 0 : virtio_pci_queue_intr, &vsc->sc_vqs[i])) {
511 : goto fail;
512 : }
513 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
514 : VIRTIO_CONFIG_QUEUE_SELECT, i);
515 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh,
516 : VIRTIO_MSI_QUEUE_VECTOR, i + 1);
517 : }
518 : }
519 :
520 0 : return 0;
521 : fail:
522 0 : virtio_pci_free_irqs(sc);
523 0 : return 1;
524 0 : }
525 :
526 : /*
527 : * Interrupt handler.
528 : */
529 :
530 : /*
531 : * Only used without MSI-X
532 : */
533 : int
534 0 : virtio_pci_legacy_intr(void *arg)
535 : {
536 0 : struct virtio_pci_softc *sc = arg;
537 0 : struct virtio_softc *vsc = &sc->sc_sc;
538 : int isr, r = 0;
539 :
540 : /* check and ack the interrupt */
541 0 : isr = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
542 : VIRTIO_CONFIG_ISR_STATUS);
543 0 : if (isr == 0)
544 0 : return 0;
545 0 : KERNEL_LOCK();
546 0 : if ((isr & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) &&
547 0 : (vsc->sc_config_change != NULL)) {
548 0 : r = (vsc->sc_config_change)(vsc);
549 0 : }
550 0 : r |= virtio_check_vqs(vsc);
551 0 : KERNEL_UNLOCK();
552 :
553 0 : return r;
554 0 : }
555 :
556 : int
557 0 : virtio_pci_legacy_intr_mpsafe(void *arg)
558 : {
559 0 : struct virtio_pci_softc *sc = arg;
560 0 : struct virtio_softc *vsc = &sc->sc_sc;
561 : int isr, r = 0;
562 :
563 : /* check and ack the interrupt */
564 0 : isr = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
565 : VIRTIO_CONFIG_ISR_STATUS);
566 0 : if (isr == 0)
567 0 : return 0;
568 0 : if ((isr & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) &&
569 0 : (vsc->sc_config_change != NULL)) {
570 0 : r = (vsc->sc_config_change)(vsc);
571 0 : }
572 0 : r |= virtio_check_vqs(vsc);
573 0 : return r;
574 0 : }
575 :
576 : /*
577 : * Only used with MSI-X
578 : */
579 : int
580 0 : virtio_pci_config_intr(void *arg)
581 : {
582 0 : struct virtio_softc *vsc = arg;
583 :
584 0 : if (vsc->sc_config_change != NULL)
585 0 : return vsc->sc_config_change(vsc);
586 0 : return 0;
587 0 : }
588 :
589 : /*
590 : * Only used with MSI-X
591 : */
592 : int
593 0 : virtio_pci_queue_intr(void *arg)
594 : {
595 0 : struct virtqueue *vq = arg;
596 :
597 0 : if (vq->vq_done)
598 0 : return (vq->vq_done)(vq);
599 0 : return 0;
600 0 : }
601 :
602 : int
603 0 : virtio_pci_shared_queue_intr(void *arg)
604 : {
605 0 : struct virtio_softc *vsc = arg;
606 :
607 0 : return virtio_check_vqs(vsc);
608 : }
609 :
610 : /*
611 : * Interrupt handler to be used when polling.
612 : * We cannot use isr here because it is not defined in MSI-X mode.
613 : */
614 : int
615 0 : virtio_pci_poll_intr(void *arg)
616 : {
617 0 : struct virtio_pci_softc *sc = arg;
618 0 : struct virtio_softc *vsc = &sc->sc_sc;
619 : int r = 0;
620 :
621 0 : if (vsc->sc_config_change != NULL)
622 0 : r = (vsc->sc_config_change)(vsc);
623 :
624 0 : r |= virtio_check_vqs(vsc);
625 :
626 0 : return r;
627 : }
628 :
629 : void
630 0 : virtio_pci_kick(struct virtio_softc *vsc, uint16_t idx)
631 : {
632 0 : struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
633 0 : bus_space_write_2(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_NOTIFY,
634 : idx);
635 0 : }
|