pci_virtio_block.c (245678) | pci_virtio_block.c (246214) |
---|---|
1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * | 1/*- 2 * Copyright (c) 2011 NetApp, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * |
26 * $FreeBSD: head/usr.sbin/bhyve/pci_virtio_block.c 245678 2013-01-20 03:42:49Z neel $ | 26 * $FreeBSD: head/usr.sbin/bhyve/pci_virtio_block.c 246214 2013-02-01 16:58:59Z neel $ |
27 */ 28 29#include <sys/cdefs.h> | 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_virtio_block.c 245678 2013-01-20 03:42:49Z neel $"); | 30__FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_virtio_block.c 246214 2013-02-01 16:58:59Z neel $"); |
31 32#include <sys/param.h> 33#include <sys/linker_set.h> 34#include <sys/stat.h> 35#include <sys/uio.h> 36#include <sys/ioctl.h> 37#include <sys/disk.h> 38 --- 11 unchanged lines hidden (view full) --- 50#include "bhyverun.h" 51#include "pci_emul.h" 52#include "virtio.h" 53 54#define VTBLK_RINGSZ 64 55 56#define VTBLK_CFGSZ 28 57 | 31 32#include <sys/param.h> 33#include <sys/linker_set.h> 34#include <sys/stat.h> 35#include <sys/uio.h> 36#include <sys/ioctl.h> 37#include <sys/disk.h> 38 --- 11 unchanged lines hidden (view full) --- 50#include "bhyverun.h" 51#include "pci_emul.h" 52#include "virtio.h" 53 54#define VTBLK_RINGSZ 64 55 56#define VTBLK_CFGSZ 28 57 |
58#define VTBLK_R_CFG VTCFG_R_CFG0 | 58#define VTBLK_R_CFG VTCFG_R_CFG1 |
59#define VTBLK_R_CFG_END VTBLK_R_CFG + VTBLK_CFGSZ -1 60#define VTBLK_R_MAX VTBLK_R_CFG_END 61 62#define VTBLK_REGSZ VTBLK_R_MAX+1 63 64#define VTBLK_MAXSEGS 32 65 66#define VTBLK_S_OK 0 67#define VTBLK_S_IOERR 1 68 69/* 70 * Host capabilities 71 */ 72#define VTBLK_S_HOSTCAPS \ 73 ( 0x00000004 | /* host maximum request segments */ \ 74 0x10000000 ) /* supports indirect descriptors */ 75 | 59#define VTBLK_R_CFG_END VTBLK_R_CFG + VTBLK_CFGSZ -1 60#define VTBLK_R_MAX VTBLK_R_CFG_END 61 62#define VTBLK_REGSZ VTBLK_R_MAX+1 63 64#define VTBLK_MAXSEGS 32 65 66#define VTBLK_S_OK 0 67#define VTBLK_S_IOERR 1 68 69/* 70 * Host capabilities 71 */ 72#define VTBLK_S_HOSTCAPS \ 73 ( 0x00000004 | /* host maximum request segments */ \ 74 0x10000000 ) /* supports indirect descriptors */ 75 |
76static int use_msix = 1; 77 |
|
76struct vring_hqueue { 77 /* Internal state */ 78 uint16_t hq_size; 79 uint16_t hq_cur_aidx; /* trails behind 'avail_idx' */ 80 81 /* Host-context pointers to the queue */ 82 struct virtio_desc *hq_dtable; 83 uint16_t *hq_avail_flags; --- 46 unchanged lines hidden (view full) --- 130 int vbsc_fd; 131 int vbsc_status; 132 int vbsc_isr; 133 int vbsc_lastq; 134 uint32_t vbsc_features; 135 uint64_t vbsc_pfn; 136 struct vring_hqueue vbsc_q; 137 struct vtblk_config vbsc_cfg; | 78struct vring_hqueue { 79 /* Internal state */ 80 uint16_t hq_size; 81 uint16_t hq_cur_aidx; /* trails behind 'avail_idx' */ 82 83 /* Host-context pointers to the queue */ 84 struct virtio_desc *hq_dtable; 85 uint16_t *hq_avail_flags; --- 46 unchanged lines hidden (view full) --- 132 int vbsc_fd; 133 int vbsc_status; 134 int vbsc_isr; 135 int vbsc_lastq; 136 uint32_t vbsc_features; 137 uint64_t vbsc_pfn; 138 struct vring_hqueue vbsc_q; 139 struct vtblk_config vbsc_cfg; |
140 uint16_t msix_table_idx_req; 141 uint16_t msix_table_idx_cfg; |
|
138}; 139 | 142}; 143 |
144/* 145 * Return the size of IO BAR that maps virtio header and device specific 146 * region. The size would vary depending on whether MSI-X is enabled or 147 * not 148 */ 149static uint64_t 150pci_vtblk_iosize(struct pci_devinst *pi) 151{ 152 153 if (pci_msix_enabled(pi)) 154 return (VTBLK_REGSZ); 155 else 156 return (VTBLK_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX)); 157} 158 |
|
140/* 141 * Return the number of available descriptors in the vring taking care 142 * of the 16-bit index wraparound. 143 */ 144static int 145hq_num_avail(struct vring_hqueue *hq) 146{ 147 int ndesc; --- 137 unchanged lines hidden (view full) --- 285 * sending when an end-of-packet is found 286 */ 287 for (i = 0; i < ndescs; i++) 288 pci_vtblk_proc(sc, hq); 289 290 /* 291 * Generate an interrupt if able 292 */ | 159/* 160 * Return the number of available descriptors in the vring taking care 161 * of the 16-bit index wraparound. 162 */ 163static int 164hq_num_avail(struct vring_hqueue *hq) 165{ 166 int ndesc; --- 137 unchanged lines hidden (view full) --- 304 * sending when an end-of-packet is found 305 */ 306 for (i = 0; i < ndescs; i++) 307 pci_vtblk_proc(sc, hq); 308 309 /* 310 * Generate an interrupt if able 311 */ |
293 if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0 && 294 sc->vbsc_isr == 0) { 295 sc->vbsc_isr = 1; 296 pci_generate_msi(sc->vbsc_pi, 0); | 312 if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) { 313 if (use_msix) { 314 pci_generate_msix(sc->vbsc_pi, sc->msix_table_idx_req); 315 } else if (sc->vbsc_isr == 0) { 316 sc->vbsc_isr = 1; 317 pci_generate_msi(sc->vbsc_pi, 0); 318 } |
297 } 298 299} 300 301static void 302pci_vtblk_ring_init(struct pci_vtblk_softc *sc, uint64_t pfn) 303{ 304 struct vring_hqueue *hq; --- 25 unchanged lines hidden (view full) --- 330static int 331pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 332{ 333 struct stat sbuf; 334 struct pci_vtblk_softc *sc; 335 off_t size; 336 int fd; 337 int sectsz; | 319 } 320 321} 322 323static void 324pci_vtblk_ring_init(struct pci_vtblk_softc *sc, uint64_t pfn) 325{ 326 struct vring_hqueue *hq; --- 25 unchanged lines hidden (view full) --- 352static int 353pci_vtblk_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 354{ 355 struct stat sbuf; 356 struct pci_vtblk_softc *sc; 357 off_t size; 358 int fd; 359 int sectsz; |
360 const char *env_msi; |
|
338 339 if (opts == NULL) { 340 printf("virtio-block: backing device required\n"); 341 return (1); 342 } 343 344 /* 345 * Access to guest memory is required. Fail if --- 50 unchanged lines hidden (view full) --- 396 sc->vbsc_cfg.vbc_geom_s = 0; 397 sc->vbsc_cfg.vbc_sectors_max = 0; 398 399 /* initialize config space */ 400 pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_BLOCK); 401 pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 402 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE); 403 pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_BLOCK); | 361 362 if (opts == NULL) { 363 printf("virtio-block: backing device required\n"); 364 return (1); 365 } 366 367 /* 368 * Access to guest memory is required. Fail if --- 50 unchanged lines hidden (view full) --- 419 sc->vbsc_cfg.vbc_geom_s = 0; 420 sc->vbsc_cfg.vbc_sectors_max = 0; 421 422 /* initialize config space */ 423 pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_BLOCK); 424 pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 425 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE); 426 pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_BLOCK); |
404 pci_emul_add_msicap(pi, 1); | 427 428 if ((env_msi = getenv("BHYVE_USE_MSI"))) { 429 if (strcasecmp(env_msi, "yes") == 0) 430 use_msix = 0; 431 } 432 433 if (use_msix) { 434 /* MSI-X Support */ 435 sc->msix_table_idx_req = VIRTIO_MSI_NO_VECTOR; 436 sc->msix_table_idx_cfg = VIRTIO_MSI_NO_VECTOR; 437 438 if (pci_emul_add_msixcap(pi, 2, 1)) 439 return (1); 440 } else { 441 /* MSI Support */ 442 pci_emul_add_msicap(pi, 1); 443 } 444 |
405 pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTBLK_REGSZ); 406 407 return (0); 408} 409 | 445 pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTBLK_REGSZ); 446 447 return (0); 448} 449 |
450static uint64_t 451vtblk_adjust_offset(struct pci_devinst *pi, uint64_t offset) 452{ 453 /* 454 * Device specific offsets used by guest would change 455 * based on whether MSI-X capability is enabled or not 456 */ 457 if (!pci_msix_enabled(pi)) { 458 if (offset >= VTCFG_R_MSIX) 459 return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX)); 460 } 461 462 return (offset); 463} 464 |
|
410static void 411pci_vtblk_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 412 int baridx, uint64_t offset, int size, uint64_t value) 413{ 414 struct pci_vtblk_softc *sc = pi->pi_arg; 415 | 465static void 466pci_vtblk_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 467 int baridx, uint64_t offset, int size, uint64_t value) 468{ 469 struct pci_vtblk_softc *sc = pi->pi_arg; 470 |
471 if (use_msix) { 472 if (baridx == pci_msix_table_bar(pi) || 473 baridx == pci_msix_pba_bar(pi)) { 474 pci_emul_msix_twrite(pi, offset, size, value); 475 return; 476 } 477 } 478 |
|
416 assert(baridx == 0); 417 | 479 assert(baridx == 0); 480 |
418 if (offset + size > VTBLK_REGSZ) { | 481 if (offset + size > pci_vtblk_iosize(pi)) { |
419 DPRINTF(("vtblk_write: 2big, offset %ld size %d\n", 420 offset, size)); 421 return; 422 } 423 | 482 DPRINTF(("vtblk_write: 2big, offset %ld size %d\n", 483 offset, size)); 484 return; 485 } 486 |
487 offset = vtblk_adjust_offset(pi, offset); 488 |
|
424 switch (offset) { 425 case VTCFG_R_GUESTCAP: 426 assert(size == 4); 427 sc->vbsc_features = value & VTBLK_S_HOSTCAPS; 428 break; 429 case VTCFG_R_PFN: 430 assert(size == 4); 431 pci_vtblk_ring_init(sc, value); --- 6 unchanged lines hidden (view full) --- 438 assert(size == 2); 439 assert(value == 0); 440 pci_vtblk_qnotify(sc); 441 break; 442 case VTCFG_R_STATUS: 443 assert(size == 1); 444 pci_vtblk_update_status(sc, value); 445 break; | 489 switch (offset) { 490 case VTCFG_R_GUESTCAP: 491 assert(size == 4); 492 sc->vbsc_features = value & VTBLK_S_HOSTCAPS; 493 break; 494 case VTCFG_R_PFN: 495 assert(size == 4); 496 pci_vtblk_ring_init(sc, value); --- 6 unchanged lines hidden (view full) --- 503 assert(size == 2); 504 assert(value == 0); 505 pci_vtblk_qnotify(sc); 506 break; 507 case VTCFG_R_STATUS: 508 assert(size == 1); 509 pci_vtblk_update_status(sc, value); 510 break; |
511 case VTCFG_R_CFGVEC: 512 assert(size == 2); 513 sc->msix_table_idx_cfg = value; 514 break; 515 case VTCFG_R_QVEC: 516 assert(size == 2); 517 sc->msix_table_idx_req = value; 518 break; |
|
446 case VTCFG_R_HOSTCAP: 447 case VTCFG_R_QNUM: 448 case VTCFG_R_ISR: 449 case VTBLK_R_CFG ... VTBLK_R_CFG_END: 450 DPRINTF(("vtblk: write to readonly reg %ld\n\r", offset)); 451 break; 452 default: 453 DPRINTF(("vtblk: unknown i/o write offset %ld\n\r", offset)); --- 5 unchanged lines hidden (view full) --- 459uint64_t 460pci_vtblk_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 461 int baridx, uint64_t offset, int size) 462{ 463 struct pci_vtblk_softc *sc = pi->pi_arg; 464 void *ptr; 465 uint32_t value; 466 | 519 case VTCFG_R_HOSTCAP: 520 case VTCFG_R_QNUM: 521 case VTCFG_R_ISR: 522 case VTBLK_R_CFG ... VTBLK_R_CFG_END: 523 DPRINTF(("vtblk: write to readonly reg %ld\n\r", offset)); 524 break; 525 default: 526 DPRINTF(("vtblk: unknown i/o write offset %ld\n\r", offset)); --- 5 unchanged lines hidden (view full) --- 532uint64_t 533pci_vtblk_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 534 int baridx, uint64_t offset, int size) 535{ 536 struct pci_vtblk_softc *sc = pi->pi_arg; 537 void *ptr; 538 uint32_t value; 539 |
540 if (use_msix) { 541 if (baridx == pci_msix_table_bar(pi) || 542 baridx == pci_msix_pba_bar(pi)) { 543 return (pci_emul_msix_tread(pi, offset, size)); 544 } 545 } 546 |
|
467 assert(baridx == 0); 468 | 547 assert(baridx == 0); 548 |
469 if (offset + size > VTBLK_REGSZ) { | 549 if (offset + size > pci_vtblk_iosize(pi)) { |
470 DPRINTF(("vtblk_read: 2big, offset %ld size %d\n", 471 offset, size)); 472 return (0); 473 } 474 | 550 DPRINTF(("vtblk_read: 2big, offset %ld size %d\n", 551 offset, size)); 552 return (0); 553 } 554 |
555 offset = vtblk_adjust_offset(pi, offset); 556 |
|
475 switch (offset) { 476 case VTCFG_R_HOSTCAP: 477 assert(size == 4); 478 value = VTBLK_S_HOSTCAPS; 479 break; 480 case VTCFG_R_GUESTCAP: 481 assert(size == 4); 482 value = sc->vbsc_features; /* XXX never read ? */ --- 17 unchanged lines hidden (view full) --- 500 assert(size == 1); 501 value = sc->vbsc_status; 502 break; 503 case VTCFG_R_ISR: 504 assert(size == 1); 505 value = sc->vbsc_isr; 506 sc->vbsc_isr = 0; /* a read clears this flag */ 507 break; | 557 switch (offset) { 558 case VTCFG_R_HOSTCAP: 559 assert(size == 4); 560 value = VTBLK_S_HOSTCAPS; 561 break; 562 case VTCFG_R_GUESTCAP: 563 assert(size == 4); 564 value = sc->vbsc_features; /* XXX never read ? */ --- 17 unchanged lines hidden (view full) --- 582 assert(size == 1); 583 value = sc->vbsc_status; 584 break; 585 case VTCFG_R_ISR: 586 assert(size == 1); 587 value = sc->vbsc_isr; 588 sc->vbsc_isr = 0; /* a read clears this flag */ 589 break; |
590 case VTCFG_R_CFGVEC: 591 assert(size == 2); 592 value = sc->msix_table_idx_cfg; 593 break; 594 case VTCFG_R_QVEC: 595 assert(size == 2); 596 value = sc->msix_table_idx_req; 597 break; |
|
508 case VTBLK_R_CFG ... VTBLK_R_CFG_END: 509 assert(size + offset <= (VTBLK_R_CFG_END + 1)); 510 ptr = (uint8_t *)&sc->vbsc_cfg + offset - VTBLK_R_CFG; 511 if (size == 1) { 512 value = *(uint8_t *) ptr; 513 } else if (size == 2) { 514 value = *(uint16_t *) ptr; 515 } else { --- 19 unchanged lines hidden --- | 598 case VTBLK_R_CFG ... VTBLK_R_CFG_END: 599 assert(size + offset <= (VTBLK_R_CFG_END + 1)); 600 ptr = (uint8_t *)&sc->vbsc_cfg + offset - VTBLK_R_CFG; 601 if (size == 1) { 602 value = *(uint8_t *) ptr; 603 } else if (size == 2) { 604 value = *(uint16_t *) ptr; 605 } else { --- 19 unchanged lines hidden --- |