Deleted Added
sdiff udiff text old ( 245678 ) new ( 246214 )
full compact
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 246214 2013-02-01 16:58:59Z neel $
27 */
28
29#include <sys/cdefs.h>
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
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
76static int use_msix = 1;
77
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;
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
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 */
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 }
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;
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);
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
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
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
479 assert(baridx == 0);
480
481 if (offset + size > pci_vtblk_iosize(pi)) {
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
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;
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
547 assert(baridx == 0);
548
549 if (offset + size > pci_vtblk_iosize(pi)) {
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
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;
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 ---