1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2012 Nexenta Systems, Inc. 24 * Copyright 2012 Alexey Zaytsev <alexey.zaytsev@gmail.com> 25 */ 26 27 /* Based on the NetBSD virtio driver by Minoura Makoto. */ 28 /* 29 * Copyright (c) 2010 Minoura Makoto. 30 * All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 42 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 44 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 50 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 * 52 */ 53 54 #include <sys/conf.h> 55 #include <sys/kmem.h> 56 #include <sys/debug.h> 57 #include <sys/modctl.h> 58 #include <sys/autoconf.h> 59 #include <sys/ddi_impldefs.h> 60 #include <sys/ddi.h> 61 #include <sys/sunddi.h> 62 #include <sys/sunndi.h> 63 #include <sys/avintr.h> 64 #include <sys/spl.h> 65 #include <sys/promif.h> 66 #include <sys/list.h> 67 #include <sys/bootconf.h> 68 #include <sys/bootsvcs.h> 69 #include <sys/sysmacros.h> 70 #include <sys/pci.h> 71 72 #include "virtiovar.h" 73 #include "virtioreg.h" 74 #define NDEVNAMES (sizeof (virtio_device_name) / sizeof (char *)) 75 #define MINSEG_INDIRECT 2 /* use indirect if nsegs >= this value */ 76 #define VIRTQUEUE_ALIGN(n) (((n)+(VIRTIO_PAGE_SIZE-1)) & \ 77 ~(VIRTIO_PAGE_SIZE-1)) 78 79 void 80 virtio_set_status(struct virtio_softc *sc, unsigned int status) 81 { 82 int old = 0; 83 84 if (status != 0) 85 old = ddi_get8(sc->sc_ioh, 86 (uint8_t *)(sc->sc_io_addr + 87 VIRTIO_CONFIG_DEVICE_STATUS)); 88 89 ddi_put8(sc->sc_ioh, 90 (uint8_t *)(sc->sc_io_addr + VIRTIO_CONFIG_DEVICE_STATUS), 91 status | old); 92 } 93 94 /* 95 * Negotiate features, save the result in sc->sc_features 96 */ 97 uint32_t 98 virtio_negotiate_features(struct virtio_softc *sc, uint32_t guest_features) 99 { 100 uint32_t host_features; 101 uint32_t features; 102 103 host_features = ddi_get32(sc->sc_ioh, 104 /* LINTED E_BAD_PTR_CAST_ALIGN */ 105 (uint32_t *)(sc->sc_io_addr + VIRTIO_CONFIG_DEVICE_FEATURES)); 106 107 dev_debug(sc->sc_dev, CE_NOTE, 108 "host features: %x, guest features: %x", 109 host_features, guest_features); 110 111 features = host_features & guest_features; 112 ddi_put32(sc->sc_ioh, 113 /* LINTED E_BAD_PTR_CAST_ALIGN */ 114 (uint32_t *)(sc->sc_io_addr + VIRTIO_CONFIG_GUEST_FEATURES), 115 features); 116 117 sc->sc_features = features; 118 119 return (host_features); 120 } 121 122 size_t 123 virtio_show_features(uint32_t features, 124 char *buf, size_t len) 125 { 126 char *orig_buf = buf; 127 char *bufend = buf + len; 128 129 /* LINTED E_PTRDIFF_OVERFLOW */ 130 buf += snprintf(buf, bufend - buf, "Generic ( "); 131 if (features & VIRTIO_F_RING_INDIRECT_DESC) 132 /* LINTED E_PTRDIFF_OVERFLOW */ 133 buf += snprintf(buf, bufend - buf, "INDIRECT_DESC "); 134 135 /* LINTED E_PTRDIFF_OVERFLOW */ 136 buf += snprintf(buf, bufend - buf, ") "); 137 138 /* LINTED E_PTRDIFF_OVERFLOW */ 139 return (buf - orig_buf); 140 } 141 142 boolean_t 143 virtio_has_feature(struct virtio_softc *sc, uint32_t feature) 144 { 145 return (sc->sc_features & feature); 146 } 147 148 /* 149 * Device configuration registers. 150 */ 151 uint8_t 152 virtio_read_device_config_1(struct virtio_softc *sc, unsigned int index) 153 { 154 ASSERT(sc->sc_config_offset); 155 return ddi_get8(sc->sc_ioh, 156 (uint8_t *)(sc->sc_io_addr + sc->sc_config_offset + index)); 157 } 158 159 uint16_t 160 virtio_read_device_config_2(struct virtio_softc *sc, unsigned int index) 161 { 162 ASSERT(sc->sc_config_offset); 163 return ddi_get16(sc->sc_ioh, 164 /* LINTED E_BAD_PTR_CAST_ALIGN */ 165 (uint16_t *)(sc->sc_io_addr + sc->sc_config_offset + index)); 166 } 167 168 uint32_t 169 virtio_read_device_config_4(struct virtio_softc *sc, unsigned int index) 170 { 171 ASSERT(sc->sc_config_offset); 172 return ddi_get32(sc->sc_ioh, 173 /* LINTED E_BAD_PTR_CAST_ALIGN */ 174 (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index)); 175 } 176 177 uint64_t 178 virtio_read_device_config_8(struct virtio_softc *sc, unsigned int index) 179 { 180 uint64_t r; 181 182 ASSERT(sc->sc_config_offset); 183 r = ddi_get32(sc->sc_ioh, 184 /* LINTED E_BAD_PTR_CAST_ALIGN */ 185 (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + 186 index + sizeof (uint32_t))); 187 188 r <<= 32; 189 190 r += ddi_get32(sc->sc_ioh, 191 /* LINTED E_BAD_PTR_CAST_ALIGN */ 192 (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index)); 193 return (r); 194 } 195 196 void 197 virtio_write_device_config_1(struct virtio_softc *sc, 198 unsigned int index, uint8_t value) 199 { 200 ASSERT(sc->sc_config_offset); 201 ddi_put8(sc->sc_ioh, 202 (uint8_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value); 203 } 204 205 void 206 virtio_write_device_config_2(struct virtio_softc *sc, 207 unsigned int index, uint16_t value) 208 { 209 ASSERT(sc->sc_config_offset); 210 ddi_put16(sc->sc_ioh, 211 /* LINTED E_BAD_PTR_CAST_ALIGN */ 212 (uint16_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value); 213 } 214 215 void 216 virtio_write_device_config_4(struct virtio_softc *sc, 217 unsigned int index, uint32_t value) 218 { 219 ASSERT(sc->sc_config_offset); 220 ddi_put32(sc->sc_ioh, 221 /* LINTED E_BAD_PTR_CAST_ALIGN */ 222 (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value); 223 } 224 225 void 226 virtio_write_device_config_8(struct virtio_softc *sc, 227 unsigned int index, uint64_t value) 228 { 229 ASSERT(sc->sc_config_offset); 230 ddi_put32(sc->sc_ioh, 231 /* LINTED E_BAD_PTR_CAST_ALIGN */ 232 (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index), 233 value & 0xFFFFFFFF); 234 ddi_put32(sc->sc_ioh, 235 /* LINTED E_BAD_PTR_CAST_ALIGN */ 236 (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + 237 index + sizeof (uint32_t)), value >> 32); 238 } 239 240 /* 241 * Start/stop vq interrupt. No guarantee. 242 */ 243 void 244 virtio_stop_vq_intr(struct virtqueue *vq) 245 { 246 vq->vq_avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; 247 } 248 249 void 250 virtio_start_vq_intr(struct virtqueue *vq) 251 { 252 vq->vq_avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; 253 } 254 255 static ddi_dma_attr_t virtio_vq_dma_attr = { 256 DMA_ATTR_V0, /* Version number */ 257 0, /* low address */ 258 /* 259 * high address. Has to fit into 32 bits 260 * after page-shifting 261 */ 262 0x00000FFFFFFFFFFF, 263 0xFFFFFFFF, /* counter register max */ 264 VIRTIO_PAGE_SIZE, /* page alignment required */ 265 0x3F, /* burst sizes: 1 - 32 */ 266 0x1, /* minimum transfer size */ 267 0xFFFFFFFF, /* max transfer size */ 268 0xFFFFFFFF, /* address register max */ 269 1, /* no scatter-gather */ 270 1, /* device operates on bytes */ 271 0, /* attr flag: set to 0 */ 272 }; 273 274 static ddi_dma_attr_t virtio_vq_indirect_dma_attr = { 275 DMA_ATTR_V0, /* Version number */ 276 0, /* low address */ 277 0xFFFFFFFFFFFFFFFF, /* high address */ 278 0xFFFFFFFF, /* counter register max */ 279 1, /* No specific alignment */ 280 0x3F, /* burst sizes: 1 - 32 */ 281 0x1, /* minimum transfer size */ 282 0xFFFFFFFF, /* max transfer size */ 283 0xFFFFFFFF, /* address register max */ 284 1, /* no scatter-gather */ 285 1, /* device operates on bytes */ 286 0, /* attr flag: set to 0 */ 287 }; 288 289 /* Same for direct and indirect descriptors. */ 290 static ddi_device_acc_attr_t virtio_vq_devattr = { 291 DDI_DEVICE_ATTR_V0, 292 DDI_NEVERSWAP_ACC, 293 DDI_STORECACHING_OK_ACC, 294 DDI_DEFAULT_ACC 295 }; 296 297 static void 298 virtio_free_indirect(struct vq_entry *entry) 299 { 300 301 (void) ddi_dma_unbind_handle(entry->qe_indirect_dma_handle); 302 ddi_dma_mem_free(&entry->qe_indirect_dma_acch); 303 ddi_dma_free_handle(&entry->qe_indirect_dma_handle); 304 305 entry->qe_indirect_descs = NULL; 306 } 307 308 309 static int 310 virtio_alloc_indirect(struct virtio_softc *sc, struct vq_entry *entry) 311 { 312 int allocsize, num; 313 size_t len; 314 unsigned int ncookies; 315 int ret; 316 317 num = entry->qe_queue->vq_indirect_num; 318 ASSERT(num > 1); 319 320 allocsize = sizeof (struct vring_desc) * num; 321 322 ret = ddi_dma_alloc_handle(sc->sc_dev, &virtio_vq_indirect_dma_attr, 323 DDI_DMA_SLEEP, NULL, &entry->qe_indirect_dma_handle); 324 if (ret != DDI_SUCCESS) { 325 dev_err(sc->sc_dev, CE_WARN, 326 "Failed to allocate dma handle for indirect descriptors," 327 " entry %d, vq %d", entry->qe_index, 328 entry->qe_queue->vq_index); 329 goto out_alloc_handle; 330 } 331 332 ret = ddi_dma_mem_alloc(entry->qe_indirect_dma_handle, 333 allocsize, &virtio_vq_devattr, 334 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 335 (caddr_t *)&entry->qe_indirect_descs, &len, 336 &entry->qe_indirect_dma_acch); 337 if (ret != DDI_SUCCESS) { 338 dev_err(sc->sc_dev, CE_WARN, 339 "Failed to alocate dma memory for indirect descriptors," 340 " entry %d, vq %d,", entry->qe_index, 341 entry->qe_queue->vq_index); 342 goto out_alloc; 343 } 344 345 (void) memset(entry->qe_indirect_descs, 0xff, allocsize); 346 347 ret = ddi_dma_addr_bind_handle(entry->qe_indirect_dma_handle, NULL, 348 (caddr_t)entry->qe_indirect_descs, len, 349 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 350 DDI_DMA_SLEEP, NULL, &entry->qe_indirect_dma_cookie, &ncookies); 351 if (ret != DDI_DMA_MAPPED) { 352 dev_err(sc->sc_dev, CE_WARN, 353 "Failed to bind dma memory for indirect descriptors," 354 "entry %d, vq %d", entry->qe_index, 355 entry->qe_queue->vq_index); 356 goto out_bind; 357 } 358 359 /* We asked for a single segment */ 360 ASSERT(ncookies == 1); 361 362 return (0); 363 364 out_bind: 365 ddi_dma_mem_free(&entry->qe_indirect_dma_acch); 366 out_alloc: 367 ddi_dma_free_handle(&entry->qe_indirect_dma_handle); 368 out_alloc_handle: 369 370 return (ret); 371 } 372 373 /* 374 * Initialize the vq structure. 375 */ 376 static int 377 virtio_init_vq(struct virtio_softc *sc, struct virtqueue *vq) 378 { 379 int ret; 380 uint16_t i; 381 int vq_size = vq->vq_num; 382 int indirect_num = vq->vq_indirect_num; 383 384 /* free slot management */ 385 list_create(&vq->vq_freelist, sizeof (struct vq_entry), 386 offsetof(struct vq_entry, qe_list)); 387 388 for (i = 0; i < vq_size; i++) { 389 struct vq_entry *entry = &vq->vq_entries[i]; 390 list_insert_tail(&vq->vq_freelist, entry); 391 entry->qe_index = i; 392 entry->qe_desc = &vq->vq_descs[i]; 393 entry->qe_queue = vq; 394 395 if (indirect_num) { 396 ret = virtio_alloc_indirect(sc, entry); 397 if (ret) 398 goto out_indirect; 399 } 400 } 401 402 mutex_init(&vq->vq_freelist_lock, "virtio-freelist", 403 MUTEX_DRIVER, DDI_INTR_PRI(sc->sc_intr_prio)); 404 mutex_init(&vq->vq_avail_lock, "virtio-avail", 405 MUTEX_DRIVER, DDI_INTR_PRI(sc->sc_intr_prio)); 406 mutex_init(&vq->vq_used_lock, "virtio-used", 407 MUTEX_DRIVER, DDI_INTR_PRI(sc->sc_intr_prio)); 408 409 return (0); 410 411 out_indirect: 412 for (i = 0; i < vq_size; i++) { 413 struct vq_entry *entry = &vq->vq_entries[i]; 414 if (entry->qe_indirect_descs) 415 virtio_free_indirect(entry); 416 } 417 418 return (ret); 419 } 420 421 422 423 /* 424 * Allocate/free a vq. 425 */ 426 struct virtqueue * 427 virtio_alloc_vq(struct virtio_softc *sc, 428 unsigned int index, 429 unsigned int size, 430 unsigned int indirect_num, 431 const char *name) 432 { 433 int vq_size, allocsize1, allocsize2, allocsize = 0; 434 int ret; 435 unsigned int ncookies; 436 size_t len; 437 struct virtqueue *vq; 438 439 440 ddi_put16(sc->sc_ioh, 441 /* LINTED E_BAD_PTR_CAST_ALIGN */ 442 (uint16_t *)(sc->sc_io_addr + VIRTIO_CONFIG_QUEUE_SELECT), index); 443 vq_size = ddi_get16(sc->sc_ioh, 444 /* LINTED E_BAD_PTR_CAST_ALIGN */ 445 (uint16_t *)(sc->sc_io_addr + VIRTIO_CONFIG_QUEUE_SIZE)); 446 if (vq_size == 0) { 447 dev_err(sc->sc_dev, CE_WARN, 448 "virtqueue dest not exist, index %d for %s\n", index, name); 449 goto out; 450 } 451 452 vq = kmem_zalloc(sizeof (struct virtqueue), KM_SLEEP); 453 454 /* size 0 => use native vq size, good for receive queues. */ 455 if (size) 456 vq_size = MIN(vq_size, size); 457 458 /* allocsize1: descriptor table + avail ring + pad */ 459 allocsize1 = VIRTQUEUE_ALIGN(sizeof (struct vring_desc) * vq_size + 460 sizeof (struct vring_avail) + 461 sizeof (uint16_t) * vq_size); 462 /* allocsize2: used ring + pad */ 463 allocsize2 = VIRTQUEUE_ALIGN(sizeof (struct vring_used) 464 + sizeof (struct vring_used_elem) * vq_size); 465 466 allocsize = allocsize1 + allocsize2; 467 468 ret = ddi_dma_alloc_handle(sc->sc_dev, &virtio_vq_dma_attr, 469 DDI_DMA_SLEEP, NULL, &vq->vq_dma_handle); 470 if (ret != DDI_SUCCESS) { 471 dev_err(sc->sc_dev, CE_WARN, 472 "Failed to allocate dma handle for vq %d", index); 473 goto out_alloc_handle; 474 } 475 476 ret = ddi_dma_mem_alloc(vq->vq_dma_handle, allocsize, 477 &virtio_vq_devattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 478 (caddr_t *)&vq->vq_vaddr, &len, &vq->vq_dma_acch); 479 if (ret != DDI_SUCCESS) { 480 dev_err(sc->sc_dev, CE_WARN, 481 "Failed to alocate dma memory for vq %d", index); 482 goto out_alloc; 483 } 484 485 486 ret = ddi_dma_addr_bind_handle(vq->vq_dma_handle, NULL, 487 (caddr_t)vq->vq_vaddr, len, 488 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 489 DDI_DMA_SLEEP, NULL, &vq->vq_dma_cookie, &ncookies); 490 if (ret != DDI_DMA_MAPPED) { 491 dev_err(sc->sc_dev, CE_WARN, 492 "Failed to bind dma memory for vq %d", index); 493 goto out_bind; 494 } 495 496 /* We asked for a single segment */ 497 ASSERT(ncookies == 1); 498 /* and page-ligned buffers. */ 499 ASSERT(vq->vq_dma_cookie.dmac_laddress % VIRTIO_PAGE_SIZE == 0); 500 501 (void) memset(vq->vq_vaddr, 0, allocsize); 502 503 /* Make sure all zeros hit the buffer before we point the host to it */ 504 membar_producer(); 505 506 /* set the vq address */ 507 ddi_put32(sc->sc_ioh, 508 /* LINTED E_BAD_PTR_CAST_ALIGN */ 509 (uint32_t *)(sc->sc_io_addr + VIRTIO_CONFIG_QUEUE_ADDRESS), 510 (vq->vq_dma_cookie.dmac_laddress / VIRTIO_PAGE_SIZE)); 511 512 /* remember addresses and offsets for later use */ 513 vq->vq_owner = sc; 514 vq->vq_num = vq_size; 515 vq->vq_index = index; 516 vq->vq_descs = vq->vq_vaddr; 517 vq->vq_availoffset = sizeof (struct vring_desc)*vq_size; 518 vq->vq_avail = (void *)(((char *)vq->vq_descs) + vq->vq_availoffset); 519 vq->vq_usedoffset = allocsize1; 520 vq->vq_used = (void *)(((char *)vq->vq_descs) + vq->vq_usedoffset); 521 522 ASSERT(indirect_num == 0 || 523 virtio_has_feature(sc, VIRTIO_F_RING_INDIRECT_DESC)); 524 vq->vq_indirect_num = indirect_num; 525 526 /* free slot management */ 527 vq->vq_entries = kmem_zalloc(sizeof (struct vq_entry) * vq_size, 528 KM_SLEEP); 529 530 ret = virtio_init_vq(sc, vq); 531 if (ret) 532 goto out_init; 533 534 dev_debug(sc->sc_dev, CE_NOTE, 535 "Allocated %d entries for vq %d:%s (%d incdirect descs)", 536 vq_size, index, name, indirect_num * vq_size); 537 538 return (vq); 539 540 out_init: 541 kmem_free(vq->vq_entries, sizeof (struct vq_entry) * vq_size); 542 (void) ddi_dma_unbind_handle(vq->vq_dma_handle); 543 out_bind: 544 ddi_dma_mem_free(&vq->vq_dma_acch); 545 out_alloc: 546 ddi_dma_free_handle(&vq->vq_dma_handle); 547 out_alloc_handle: 548 kmem_free(vq, sizeof (struct virtqueue)); 549 out: 550 return (NULL); 551 } 552 553 554 void 555 virtio_free_vq(struct virtqueue *vq) 556 { 557 struct virtio_softc *sc = vq->vq_owner; 558 int i; 559 560 /* tell device that there's no virtqueue any longer */ 561 ddi_put16(sc->sc_ioh, 562 /* LINTED E_BAD_PTR_CAST_ALIGN */ 563 (uint16_t *)(sc->sc_io_addr + VIRTIO_CONFIG_QUEUE_SELECT), 564 vq->vq_index); 565 ddi_put32(sc->sc_ioh, 566 /* LINTED E_BAD_PTR_CAST_ALIGN */ 567 (uint32_t *)(sc->sc_io_addr + VIRTIO_CONFIG_QUEUE_ADDRESS), 0); 568 569 /* Free the indirect descriptors, if any. */ 570 for (i = 0; i < vq->vq_num; i++) { 571 struct vq_entry *entry = &vq->vq_entries[i]; 572 if (entry->qe_indirect_descs) 573 virtio_free_indirect(entry); 574 } 575 576 kmem_free(vq->vq_entries, sizeof (struct vq_entry) * vq->vq_num); 577 578 (void) ddi_dma_unbind_handle(vq->vq_dma_handle); 579 ddi_dma_mem_free(&vq->vq_dma_acch); 580 ddi_dma_free_handle(&vq->vq_dma_handle); 581 582 mutex_destroy(&vq->vq_used_lock); 583 mutex_destroy(&vq->vq_avail_lock); 584 mutex_destroy(&vq->vq_freelist_lock); 585 586 kmem_free(vq, sizeof (struct virtqueue)); 587 } 588 589 /* 590 * Free descriptor management. 591 */ 592 struct vq_entry * 593 vq_alloc_entry(struct virtqueue *vq) 594 { 595 struct vq_entry *qe; 596 597 mutex_enter(&vq->vq_freelist_lock); 598 if (list_is_empty(&vq->vq_freelist)) { 599 mutex_exit(&vq->vq_freelist_lock); 600 return (NULL); 601 } 602 qe = list_remove_head(&vq->vq_freelist); 603 604 ASSERT(vq->vq_used_entries >= 0); 605 vq->vq_used_entries++; 606 607 mutex_exit(&vq->vq_freelist_lock); 608 609 qe->qe_next = NULL; 610 qe->qe_indirect_next = 0; 611 (void) memset(qe->qe_desc, 0, sizeof (struct vring_desc)); 612 613 return (qe); 614 } 615 616 void 617 vq_free_entry(struct virtqueue *vq, struct vq_entry *qe) 618 { 619 mutex_enter(&vq->vq_freelist_lock); 620 621 list_insert_head(&vq->vq_freelist, qe); 622 vq->vq_used_entries--; 623 ASSERT(vq->vq_used_entries >= 0); 624 mutex_exit(&vq->vq_freelist_lock); 625 } 626 627 /* 628 * We (intentionally) don't have a global vq mutex, so you are 629 * responsible for external locking to avoid allocting/freeing any 630 * entries before using the returned value. Have fun. 631 */ 632 uint_t 633 vq_num_used(struct virtqueue *vq) 634 { 635 /* vq->vq_freelist_lock would not help here. */ 636 return (vq->vq_used_entries); 637 } 638 639 static inline void 640 virtio_ve_set_desc(struct vring_desc *desc, uint64_t paddr, uint32_t len, 641 boolean_t write) 642 { 643 desc->addr = paddr; 644 desc->len = len; 645 desc->next = 0; 646 desc->flags = 0; 647 648 /* 'write' - from the driver's point of view */ 649 if (!write) 650 desc->flags = VRING_DESC_F_WRITE; 651 652 653 } 654 655 void 656 virtio_ve_set(struct vq_entry *qe, uint64_t paddr, uint32_t len, 657 boolean_t write) 658 { 659 virtio_ve_set_desc(qe->qe_desc, paddr, len, write); 660 } 661 662 void 663 virtio_ve_add_indirect_buf(struct vq_entry *qe, uint64_t paddr, uint32_t len, 664 boolean_t write) 665 { 666 struct vring_desc *indirect_desc; 667 668 ASSERT(qe->qe_queue->vq_indirect_num); 669 ASSERT(qe->qe_indirect_next < qe->qe_queue->vq_indirect_num); 670 671 indirect_desc = &qe->qe_indirect_descs[qe->qe_indirect_next]; 672 virtio_ve_set_desc(indirect_desc, paddr, len, write); 673 qe->qe_indirect_next++; 674 } 675 676 void 677 virtio_ve_add_cookie(struct vq_entry *qe, ddi_dma_handle_t dma_handle, 678 ddi_dma_cookie_t dma_cookie, unsigned int ncookies, boolean_t write) 679 { 680 int i; 681 682 for (i = 0; i < ncookies; i++) { 683 virtio_ve_add_indirect_buf(qe, dma_cookie.dmac_laddress, 684 dma_cookie.dmac_size, write); 685 ddi_dma_nextcookie(dma_handle, &dma_cookie); 686 } 687 } 688 689 void 690 virtio_sync_vq(struct virtqueue *vq) 691 { 692 struct virtio_softc *vsc = vq->vq_owner; 693 694 /* Make sure the avail ring update hit the buffer */ 695 membar_producer(); 696 697 vq->vq_avail->idx = vq->vq_avail_idx; 698 699 /* Make sure the avail idx update hits the buffer */ 700 membar_producer(); 701 702 /* Make sure we see the flags update */ 703 membar_consumer(); 704 705 if (!(vq->vq_used->flags & VRING_USED_F_NO_NOTIFY)) 706 ddi_put16(vsc->sc_ioh, 707 /* LINTED E_BAD_PTR_CAST_ALIGN */ 708 (uint16_t *)(vsc->sc_io_addr + 709 VIRTIO_CONFIG_QUEUE_NOTIFY), 710 vq->vq_index); 711 } 712 713 void 714 virtio_push_chain(struct vq_entry *qe, boolean_t sync) 715 { 716 struct virtqueue *vq = qe->qe_queue; 717 struct vq_entry *head = qe; 718 struct vring_desc *desc; 719 int idx; 720 721 ASSERT(qe); 722 723 /* 724 * Bind the descs together, paddr and len should be already 725 * set with virtio_ve_set 726 */ 727 do { 728 /* Bind the indirect descriptors */ 729 if (qe->qe_indirect_next > 1) { 730 uint16_t i = 0; 731 732 /* 733 * Set the pointer/flags to the 734 * first indirect descriptor 735 */ 736 virtio_ve_set_desc(qe->qe_desc, 737 qe->qe_indirect_dma_cookie.dmac_laddress, 738 sizeof (struct vring_desc) * qe->qe_indirect_next, 739 B_FALSE); 740 qe->qe_desc->flags |= VRING_DESC_F_INDIRECT; 741 742 /* For all but the last one, add the next index/flag */ 743 do { 744 desc = &qe->qe_indirect_descs[i]; 745 i++; 746 747 desc->flags |= VRING_DESC_F_NEXT; 748 desc->next = i; 749 } while (i < qe->qe_indirect_next - 1); 750 751 } 752 753 if (qe->qe_next) { 754 qe->qe_desc->flags |= VRING_DESC_F_NEXT; 755 qe->qe_desc->next = qe->qe_next->qe_index; 756 } 757 758 qe = qe->qe_next; 759 } while (qe); 760 761 mutex_enter(&vq->vq_avail_lock); 762 idx = vq->vq_avail_idx; 763 vq->vq_avail_idx++; 764 765 /* Make sure the bits hit the descriptor(s) */ 766 membar_producer(); 767 vq->vq_avail->ring[idx % vq->vq_num] = head->qe_index; 768 769 /* Notify the device, if needed. */ 770 if (sync) 771 virtio_sync_vq(vq); 772 773 mutex_exit(&vq->vq_avail_lock); 774 } 775 776 /* Get a chain of descriptors from the used ring, if one is available. */ 777 struct vq_entry * 778 virtio_pull_chain(struct virtqueue *vq, uint32_t *len) 779 { 780 struct vq_entry *head; 781 int slot; 782 int usedidx; 783 784 mutex_enter(&vq->vq_used_lock); 785 786 /* No used entries? Bye. */ 787 if (vq->vq_used_idx == vq->vq_used->idx) { 788 mutex_exit(&vq->vq_used_lock); 789 return (NULL); 790 } 791 792 usedidx = vq->vq_used_idx; 793 vq->vq_used_idx++; 794 mutex_exit(&vq->vq_used_lock); 795 796 usedidx %= vq->vq_num; 797 798 /* Make sure we do the next step _after_ checking the idx. */ 799 membar_consumer(); 800 801 slot = vq->vq_used->ring[usedidx].id; 802 *len = vq->vq_used->ring[usedidx].len; 803 804 head = &vq->vq_entries[slot]; 805 806 return (head); 807 } 808 809 void 810 virtio_free_chain(struct vq_entry *qe) 811 { 812 struct vq_entry *tmp; 813 struct virtqueue *vq = qe->qe_queue; 814 815 ASSERT(qe); 816 817 do { 818 ASSERT(qe->qe_queue == vq); 819 tmp = qe->qe_next; 820 vq_free_entry(vq, qe); 821 qe = tmp; 822 } while (tmp); 823 } 824 825 void 826 virtio_ventry_stick(struct vq_entry *first, struct vq_entry *second) 827 { 828 first->qe_next = second; 829 } 830 831 static int 832 virtio_register_msi(struct virtio_softc *sc, 833 struct virtio_int_handler *config_handler, 834 struct virtio_int_handler vq_handlers[], 835 int intr_types) 836 { 837 int count, actual; 838 int int_type; 839 int i; 840 int handler_count; 841 int ret; 842 843 /* If both MSI and MSI-x are reported, prefer MSI-x. */ 844 int_type = DDI_INTR_TYPE_MSI; 845 if (intr_types & DDI_INTR_TYPE_MSIX) 846 int_type = DDI_INTR_TYPE_MSIX; 847 848 /* Walk the handler table to get the number of handlers. */ 849 for (handler_count = 0; 850 vq_handlers && vq_handlers[handler_count].vh_func; 851 handler_count++) 852 ; 853 854 /* +1 if there is a config change handler. */ 855 if (config_handler) 856 handler_count++; 857 858 /* Number of MSIs supported by the device. */ 859 ret = ddi_intr_get_nintrs(sc->sc_dev, int_type, &count); 860 if (ret != DDI_SUCCESS) { 861 dev_err(sc->sc_dev, CE_WARN, "ddi_intr_get_nintrs failed"); 862 return (ret); 863 } 864 865 /* 866 * Those who try to register more handlers then the device 867 * supports shall suffer. 868 */ 869 ASSERT(handler_count <= count); 870 871 sc->sc_intr_htable = kmem_zalloc( 872 sizeof (ddi_intr_handle_t) * handler_count, KM_SLEEP); 873 874 ret = ddi_intr_alloc(sc->sc_dev, sc->sc_intr_htable, int_type, 0, 875 handler_count, &actual, DDI_INTR_ALLOC_NORMAL); 876 if (ret != DDI_SUCCESS) { 877 dev_err(sc->sc_dev, CE_WARN, "Failed to allocate MSI: %d", ret); 878 goto out_msi_alloc; 879 } 880 881 if (actual != handler_count) { 882 dev_err(sc->sc_dev, CE_WARN, 883 "Not enough MSI available: need %d, available %d", 884 handler_count, actual); 885 goto out_msi_available; 886 } 887 888 sc->sc_intr_num = handler_count; 889 sc->sc_intr_config = B_FALSE; 890 if (config_handler) { 891 sc->sc_intr_config = B_TRUE; 892 } 893 894 /* Assume they are all same priority */ 895 ret = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_prio); 896 if (ret != DDI_SUCCESS) { 897 dev_err(sc->sc_dev, CE_WARN, "ddi_intr_get_pri failed"); 898 goto out_msi_prio; 899 } 900 901 /* Add the vq handlers */ 902 for (i = 0; vq_handlers[i].vh_func; i++) { 903 ret = ddi_intr_add_handler(sc->sc_intr_htable[i], 904 vq_handlers[i].vh_func, 905 sc, vq_handlers[i].vh_priv); 906 if (ret != DDI_SUCCESS) { 907 dev_err(sc->sc_dev, CE_WARN, 908 "ddi_intr_add_handler failed"); 909 /* Remove the handlers that succeeded. */ 910 while (--i >= 0) { 911 (void) ddi_intr_remove_handler( 912 sc->sc_intr_htable[i]); 913 } 914 goto out_add_handlers; 915 } 916 } 917 918 /* Don't forget the config handler */ 919 if (config_handler) { 920 ret = ddi_intr_add_handler(sc->sc_intr_htable[i], 921 config_handler->vh_func, 922 sc, config_handler->vh_priv); 923 if (ret != DDI_SUCCESS) { 924 dev_err(sc->sc_dev, CE_WARN, 925 "ddi_intr_add_handler failed"); 926 /* Remove the handlers that succeeded. */ 927 while (--i >= 0) { 928 (void) ddi_intr_remove_handler( 929 sc->sc_intr_htable[i]); 930 } 931 goto out_add_handlers; 932 } 933 } 934 935 /* We know we are using MSI, so set the config offset. */ 936 sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_MSI; 937 938 ret = ddi_intr_get_cap(sc->sc_intr_htable[0], 939 &sc->sc_intr_cap); 940 /* Just in case. */ 941 if (ret != DDI_SUCCESS) 942 sc->sc_intr_cap = 0; 943 944 out_add_handlers: 945 out_msi_prio: 946 out_msi_available: 947 for (i = 0; i < actual; i++) 948 (void) ddi_intr_free(sc->sc_intr_htable[i]); 949 out_msi_alloc: 950 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t) * count); 951 952 return (ret); 953 } 954 955 struct virtio_handler_container { 956 int nhandlers; 957 struct virtio_int_handler config_handler; 958 struct virtio_int_handler vq_handlers[]; 959 }; 960 961 uint_t 962 virtio_intx_dispatch(caddr_t arg1, caddr_t arg2) 963 { 964 struct virtio_softc *sc = (void *)arg1; 965 struct virtio_handler_container *vhc = (void *)arg2; 966 uint8_t isr_status; 967 int i; 968 969 isr_status = ddi_get8(sc->sc_ioh, (uint8_t *)(sc->sc_io_addr + 970 VIRTIO_CONFIG_ISR_STATUS)); 971 972 if (!isr_status) 973 return (DDI_INTR_UNCLAIMED); 974 975 if ((isr_status & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) && 976 vhc->config_handler.vh_func) { 977 vhc->config_handler.vh_func((void *)sc, 978 vhc->config_handler.vh_priv); 979 } 980 981 /* Notify all handlers */ 982 for (i = 0; i < vhc->nhandlers; i++) { 983 vhc->vq_handlers[i].vh_func((void *)sc, 984 vhc->vq_handlers[i].vh_priv); 985 } 986 987 return (DDI_INTR_CLAIMED); 988 } 989 990 /* 991 * config_handler and vq_handlers may be allocated on stack. 992 * Take precautions not to loose them. 993 */ 994 static int 995 virtio_register_intx(struct virtio_softc *sc, 996 struct virtio_int_handler *config_handler, 997 struct virtio_int_handler vq_handlers[]) 998 { 999 int vq_handler_count; 1000 int config_handler_count = 0; 1001 int actual; 1002 struct virtio_handler_container *vhc; 1003 int ret = DDI_FAILURE; 1004 1005 /* Walk the handler table to get the number of handlers. */ 1006 for (vq_handler_count = 0; 1007 vq_handlers && vq_handlers[vq_handler_count].vh_func; 1008 vq_handler_count++) 1009 ; 1010 1011 if (config_handler) 1012 config_handler_count = 1; 1013 1014 vhc = kmem_zalloc(sizeof (struct virtio_handler_container) + 1015 sizeof (struct virtio_int_handler) * vq_handler_count, 1016 KM_SLEEP); 1017 1018 vhc->nhandlers = vq_handler_count; 1019 (void) memcpy(vhc->vq_handlers, vq_handlers, 1020 sizeof (struct virtio_int_handler) * vq_handler_count); 1021 1022 if (config_handler) { 1023 (void) memcpy(&vhc->config_handler, config_handler, 1024 sizeof (struct virtio_int_handler)); 1025 } 1026 1027 /* Just a single entry for a single interrupt. */ 1028 sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); 1029 1030 ret = ddi_intr_alloc(sc->sc_dev, sc->sc_intr_htable, 1031 DDI_INTR_TYPE_FIXED, 0, 1, &actual, 1032 DDI_INTR_ALLOC_NORMAL); 1033 if (ret != DDI_SUCCESS) { 1034 dev_err(sc->sc_dev, CE_WARN, 1035 "Failed to allocate a fixed interrupt: %d", ret); 1036 goto out_int_alloc; 1037 } 1038 1039 ASSERT(actual == 1); 1040 sc->sc_intr_num = 1; 1041 1042 ret = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_prio); 1043 if (ret != DDI_SUCCESS) { 1044 dev_err(sc->sc_dev, CE_WARN, "ddi_intr_get_pri failed"); 1045 goto out_prio; 1046 } 1047 1048 ret = ddi_intr_add_handler(sc->sc_intr_htable[0], 1049 virtio_intx_dispatch, sc, vhc); 1050 if (ret != DDI_SUCCESS) { 1051 dev_err(sc->sc_dev, CE_WARN, "ddi_intr_add_handler failed"); 1052 goto out_add_handlers; 1053 } 1054 1055 /* We know we are not using MSI, so set the config offset. */ 1056 sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI; 1057 1058 return (DDI_SUCCESS); 1059 1060 out_add_handlers: 1061 out_prio: 1062 (void) ddi_intr_free(sc->sc_intr_htable[0]); 1063 out_int_alloc: 1064 kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t)); 1065 kmem_free(vhc, sizeof (struct virtio_int_handler) * 1066 (vq_handler_count + config_handler_count)); 1067 return (ret); 1068 } 1069 1070 /* 1071 * We find out if we support MSI during this, and the register layout 1072 * depends on the MSI (doh). Don't acces the device specific bits in 1073 * BAR 0 before calling it! 1074 */ 1075 int 1076 virtio_register_ints(struct virtio_softc *sc, 1077 struct virtio_int_handler *config_handler, 1078 struct virtio_int_handler vq_handlers[]) 1079 { 1080 int ret; 1081 int intr_types; 1082 1083 /* Determine which types of interrupts are supported */ 1084 ret = ddi_intr_get_supported_types(sc->sc_dev, &intr_types); 1085 if (ret != DDI_SUCCESS) { 1086 dev_err(sc->sc_dev, CE_WARN, "Can't get supported int types"); 1087 goto out_inttype; 1088 } 1089 1090 /* If we have msi, let's use them. */ 1091 if (intr_types & (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { 1092 ret = virtio_register_msi(sc, config_handler, 1093 vq_handlers, intr_types); 1094 if (!ret) 1095 return (0); 1096 } 1097 1098 /* Fall back to old-fashioned interrupts. */ 1099 if (intr_types & DDI_INTR_TYPE_FIXED) { 1100 dev_debug(sc->sc_dev, CE_WARN, 1101 "Using legacy interrupts"); 1102 1103 return (virtio_register_intx(sc, config_handler, vq_handlers)); 1104 } 1105 1106 dev_err(sc->sc_dev, CE_WARN, 1107 "MSI failed and fixed interrupts not supported. Giving up."); 1108 ret = DDI_FAILURE; 1109 1110 out_inttype: 1111 return (ret); 1112 } 1113 1114 1115 static int 1116 virtio_enable_msi(struct virtio_softc *sc) 1117 { 1118 int ret, i; 1119 int vq_handler_count = sc->sc_intr_num; 1120 1121 /* Number of handlers, not counting the counfig. */ 1122 if (sc->sc_intr_config) 1123 vq_handler_count--; 1124 1125 /* Enable the iterrupts. Either the whole block, or one by one. */ 1126 if (sc->sc_intr_cap & DDI_INTR_FLAG_BLOCK) { 1127 ret = ddi_intr_block_enable(sc->sc_intr_htable, 1128 sc->sc_intr_num); 1129 if (ret != DDI_SUCCESS) { 1130 dev_err(sc->sc_dev, CE_WARN, 1131 "Failed to enable MSI, falling back to INTx"); 1132 goto out_enable; 1133 } 1134 } else { 1135 for (i = 0; i < sc->sc_intr_num; i++) { 1136 ret = ddi_intr_enable(sc->sc_intr_htable[i]); 1137 if (ret != DDI_SUCCESS) { 1138 dev_err(sc->sc_dev, CE_WARN, 1139 "Failed to enable MSI %d, " 1140 "falling back to INTx", i); 1141 1142 while (--i >= 0) { 1143 (void) ddi_intr_disable( 1144 sc->sc_intr_htable[i]); 1145 } 1146 goto out_enable; 1147 } 1148 } 1149 } 1150 1151 /* Bind the allocated MSI to the queues and config */ 1152 for (i = 0; i < vq_handler_count; i++) { 1153 int check; 1154 ddi_put16(sc->sc_ioh, 1155 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1156 (uint16_t *)(sc->sc_io_addr + 1157 VIRTIO_CONFIG_QUEUE_SELECT), i); 1158 1159 ddi_put16(sc->sc_ioh, 1160 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1161 (uint16_t *)(sc->sc_io_addr + 1162 VIRTIO_CONFIG_QUEUE_VECTOR), i); 1163 1164 check = ddi_get16(sc->sc_ioh, 1165 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1166 (uint16_t *)(sc->sc_io_addr + 1167 VIRTIO_CONFIG_QUEUE_VECTOR)); 1168 if (check != i) { 1169 dev_err(sc->sc_dev, CE_WARN, "Failed to bind handler" 1170 "for VQ %d, MSI %d. Check = %x", i, i, check); 1171 ret = ENODEV; 1172 goto out_bind; 1173 } 1174 } 1175 1176 if (sc->sc_intr_config) { 1177 int check; 1178 ddi_put16(sc->sc_ioh, 1179 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1180 (uint16_t *)(sc->sc_io_addr + 1181 VIRTIO_CONFIG_CONFIG_VECTOR), i); 1182 1183 check = ddi_get16(sc->sc_ioh, 1184 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1185 (uint16_t *)(sc->sc_io_addr + 1186 VIRTIO_CONFIG_CONFIG_VECTOR)); 1187 if (check != i) { 1188 dev_err(sc->sc_dev, CE_WARN, "Failed to bind handler " 1189 "for Config updates, MSI %d", i); 1190 ret = ENODEV; 1191 goto out_bind; 1192 } 1193 } 1194 1195 return (DDI_SUCCESS); 1196 1197 out_bind: 1198 /* Unbind the vqs */ 1199 for (i = 0; i < vq_handler_count - 1; i++) { 1200 ddi_put16(sc->sc_ioh, 1201 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1202 (uint16_t *)(sc->sc_io_addr + 1203 VIRTIO_CONFIG_QUEUE_SELECT), i); 1204 1205 ddi_put16(sc->sc_ioh, 1206 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1207 (uint16_t *)(sc->sc_io_addr + 1208 VIRTIO_CONFIG_QUEUE_VECTOR), 1209 VIRTIO_MSI_NO_VECTOR); 1210 } 1211 /* And the config */ 1212 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1213 ddi_put16(sc->sc_ioh, (uint16_t *)(sc->sc_io_addr + 1214 VIRTIO_CONFIG_CONFIG_VECTOR), VIRTIO_MSI_NO_VECTOR); 1215 1216 ret = DDI_FAILURE; 1217 1218 out_enable: 1219 return (ret); 1220 } 1221 1222 static int virtio_enable_intx(struct virtio_softc *sc) 1223 { 1224 int ret; 1225 1226 ret = ddi_intr_enable(sc->sc_intr_htable[0]); 1227 if (ret != DDI_SUCCESS) 1228 dev_err(sc->sc_dev, CE_WARN, 1229 "Failed to enable interrupt: %d", ret); 1230 return (ret); 1231 } 1232 1233 /* 1234 * We can't enable/disable individual handlers in the INTx case so do 1235 * the whole bunch even in the msi case. 1236 */ 1237 int 1238 virtio_enable_ints(struct virtio_softc *sc) 1239 { 1240 1241 /* See if we are using MSI. */ 1242 if (sc->sc_config_offset == VIRTIO_CONFIG_DEVICE_CONFIG_MSI) 1243 return (virtio_enable_msi(sc)); 1244 1245 ASSERT(sc->sc_config_offset == VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI); 1246 1247 return (virtio_enable_intx(sc)); 1248 } 1249 1250 void 1251 virtio_release_ints(struct virtio_softc *sc) 1252 { 1253 int i; 1254 int ret; 1255 1256 /* We were running with MSI, unbind them. */ 1257 if (sc->sc_config_offset == VIRTIO_CONFIG_DEVICE_CONFIG_MSI) { 1258 /* Unbind all vqs */ 1259 for (i = 0; i < sc->sc_nvqs; i++) { 1260 ddi_put16(sc->sc_ioh, 1261 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1262 (uint16_t *)(sc->sc_io_addr + 1263 VIRTIO_CONFIG_QUEUE_SELECT), i); 1264 1265 ddi_put16(sc->sc_ioh, 1266 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1267 (uint16_t *)(sc->sc_io_addr + 1268 VIRTIO_CONFIG_QUEUE_VECTOR), 1269 VIRTIO_MSI_NO_VECTOR); 1270 } 1271 /* And the config */ 1272 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1273 ddi_put16(sc->sc_ioh, (uint16_t *)(sc->sc_io_addr + 1274 VIRTIO_CONFIG_CONFIG_VECTOR), 1275 VIRTIO_MSI_NO_VECTOR); 1276 1277 } 1278 1279 /* Disable the iterrupts. Either the whole block, or one by one. */ 1280 if (sc->sc_intr_cap & DDI_INTR_FLAG_BLOCK) { 1281 ret = ddi_intr_block_disable(sc->sc_intr_htable, 1282 sc->sc_intr_num); 1283 if (ret != DDI_SUCCESS) { 1284 dev_err(sc->sc_dev, CE_WARN, 1285 "Failed to disable MSIs, won't be able to" 1286 "reuse next time"); 1287 } 1288 } else { 1289 for (i = 0; i < sc->sc_intr_num; i++) { 1290 ret = ddi_intr_disable(sc->sc_intr_htable[i]); 1291 if (ret != DDI_SUCCESS) { 1292 dev_err(sc->sc_dev, CE_WARN, 1293 "Failed to disable interrupt %d, " 1294 "won't be able to reuse", i); 1295 1296 } 1297 } 1298 } 1299 1300 1301 for (i = 0; i < sc->sc_intr_num; i++) { 1302 (void) ddi_intr_remove_handler(sc->sc_intr_htable[i]); 1303 } 1304 1305 for (i = 0; i < sc->sc_intr_num; i++) 1306 (void) ddi_intr_free(sc->sc_intr_htable[i]); 1307 1308 kmem_free(sc->sc_intr_htable, 1309 sizeof (ddi_intr_handle_t) * sc->sc_intr_num); 1310 1311 1312 /* After disabling interrupts, the config offset is non-MSI. */ 1313 sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI; 1314 } 1315 1316 /* 1317 * Module linkage information for the kernel. 1318 */ 1319 static struct modlmisc modlmisc = { 1320 &mod_miscops, /* Type of module */ 1321 "VirtIO common library module", 1322 }; 1323 1324 static struct modlinkage modlinkage = { 1325 MODREV_1, 1326 { 1327 (void *)&modlmisc, 1328 NULL 1329 } 1330 }; 1331 1332 int 1333 _init(void) 1334 { 1335 return (mod_install(&modlinkage)); 1336 } 1337 1338 int 1339 _fini(void) 1340 { 1341 return (mod_remove(&modlinkage)); 1342 } 1343 1344 int 1345 _info(struct modinfo *modinfop) 1346 { 1347 return (mod_info(&modlinkage, modinfop)); 1348 } 1349