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