Lines Matching +full:virtio +full:- +full:pci
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
35 #include <dev/virtio/pci/virtio_pci_legacy_var.h>
49 #include "virtio.h"
53 * defined by <https://www.google.com/#output=search&q=virtio+spec>
57 * In case we decide to relax the "virtio softc comes at the
58 * front of virtio-based device softc" constraint, let's use
65 * the PCI emulation.
76 vs->vs_vc = vc;
77 vs->vs_pi = pi;
78 pi->pi_arg = vs;
80 vs->vs_queues = queues;
81 for (i = 0; i < vc->vc_nvq; i++) {
88 * Reset device (device-wide). This erases all queues, i.e.,
94 * If MSI-X is enabled, this also resets all the vectors to NO_VECTOR.
102 if (vs->vs_mtx)
103 assert(pthread_mutex_isowned_np(vs->vs_mtx));
105 nvq = vs->vs_vc->vc_nvq;
106 for (vq = vs->vs_queues, i = 0; i < nvq; vq++, i++) {
107 vq->vq_flags = 0;
108 vq->vq_last_avail = 0;
109 vq->vq_next_used = 0;
110 vq->vq_save_used = 0;
111 vq->vq_pfn = 0;
112 vq->vq_msix_idx = VIRTIO_MSI_NO_VECTOR;
114 vs->vs_negotiated_caps = 0;
115 vs->vs_curq = 0;
116 /* vs->vs_status = 0; -- redundant */
117 if (vs->vs_isr)
118 pci_lintr_deassert(vs->vs_pi);
119 vs->vs_isr = 0;
120 vs->vs_msix_cfg_idx = VIRTIO_MSI_NO_VECTOR;
124 * Set I/O BAR (usually 0) to map PCI config registers.
132 * ??? should we use VIRTIO_PCI_CONFIG_OFF(0) if MSI-X is disabled?
135 size = VIRTIO_PCI_CONFIG_OFF(1) + vs->vs_vc->vc_cfgsize;
136 pci_emul_alloc_bar(vs->vs_pi, barnum, PCIBAR_IO, size);
140 * Initialize MSI-X vector capabilities if we're to use MSI-X,
143 * We assume we want one MSI-X vector per queue, here, plus one
152 vs->vs_flags |= VIRTIO_USE_MSIX;
156 nvec = vs->vs_vc->vc_nvq + 1;
157 if (pci_emul_add_msixcap(vs->vs_pi, nvec, barnum))
160 vs->vs_flags &= ~VIRTIO_USE_MSIX;
163 pci_emul_add_msicap(vs->vs_pi, 1);
165 /* Legacy interrupts are mandatory for virtio devices */
166 pci_lintr_request(vs->vs_pi);
172 * Initialize the currently-selected virtio queue (vs->vs_curq).
184 vq = &vs->vs_queues[vs->vs_curq];
185 vq->vq_pfn = pfn;
187 size = vring_size_aligned(vq->vq_qsize);
188 base = paddr_guest2host(vs->vs_pi->pi_vmctx, phys, size);
191 vq->vq_desc = (struct vring_desc *)base;
192 base += vq->vq_qsize * sizeof(struct vring_desc);
195 vq->vq_avail = (struct vring_avail *)base;
196 base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t);
202 vq->vq_used = (struct vring_used *)base;
205 vq->vq_flags = VQ_ALLOC;
206 vq->vq_last_avail = 0;
207 vq->vq_next_used = 0;
208 vq->vq_save_used = 0;
224 len = atomic_load_32(&vd->len);
225 addr = atomic_load_64(&vd->addr);
228 if ((vd->flags & VRING_DESC_F_WRITE) == 0)
229 reqp->readable++;
231 reqp->writable++;
251 * at vs->vs_pi) so that it can find indirect descriptors.
257 * up to VQ_MAX_DESCRIPTORS, before giving up and returning -1.
264 * and returns -1. If no descriptors are ready now it simply returns 0.
282 vs = vq->vq_vs;
283 name = vs->vs_vc->vc_name;
288 * update vq->vq_avail->idx until all of the descriptors
292 * Compute (vq_avail->idx - last_avail) in integers mod 2**16. This is
294 * since the last time we updated vq->vq_last_avail.
299 idx = vq->vq_last_avail;
300 ndesc = (uint16_t)((u_int)vq->vq_avail->idx - idx);
303 if (ndesc > vq->vq_qsize) {
308 return (-1);
316 * check whether we're re-visiting a previously visited
319 ctx = vs->vs_pi->pi_vmctx;
320 req.idx = next = vq->vq_avail->ring[idx & (vq->vq_qsize - 1)];
321 vq->vq_last_avail++;
322 for (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->next) {
323 if (next >= vq->vq_qsize) {
328 return (-1);
330 vdir = &vq->vq_desc[next];
331 if ((vdir->flags & VRING_DESC_F_INDIRECT) == 0) {
334 } else if ((vs->vs_vc->vc_hv_caps &
340 return (-1);
342 n_indir = vdir->len / 16;
343 if ((vdir->len & 0xf) || n_indir == 0) {
347 name, (u_int)vdir->len);
348 return (-1);
351 vdir->addr, vdir->len);
362 if (vp->flags & VRING_DESC_F_INDIRECT) {
367 return (-1);
372 if ((vp->flags & VRING_DESC_F_NEXT) == 0)
374 next = vp->next;
380 return (-1);
384 if ((vdir->flags & VRING_DESC_F_NEXT) == 0)
390 "%s: descriptor loop? count > %d - driver confused?",
392 return (-1);
409 vq->vq_last_avail -= n_chains;
421 * - mask is N-1 where N is a power of 2 so computes x % N
422 * - vuh points to the "used" data shared with guest
423 * - vue points to the "used" ring entry we want to update
425 mask = vq->vq_qsize - 1;
426 vuh = vq->vq_used;
428 vue = &vuh->ring[vq->vq_next_used++ & mask];
429 vue->id = idx;
430 vue->len = iolen;
442 vq->vq_used->idx = vq->vq_next_used;
471 * processing -- it's possible that descriptors became available after
490 vs = vq->vq_vs;
491 old_idx = vq->vq_save_used;
492 vq->vq_save_used = new_idx = vq->vq_used->idx;
501 (vs->vs_negotiated_caps & VIRTIO_F_NOTIFY_ON_EMPTY))
503 else if (vs->vs_negotiated_caps & VIRTIO_RING_F_EVENT_IDX) {
507 * (see src/sys/dev/virtio/virtio_ring.h).
509 intr = (uint16_t)(new_idx - event_idx - 1) <
510 (uint16_t)(new_idx - old_idx);
513 !(vq->vq_avail->flags & VRING_AVAIL_F_NO_INTERRUPT);
544 hi = sizeof(config_regs) / sizeof(*config_regs) - 1;
548 if (cr->cr_offset == offset)
550 if (cr->cr_offset < offset)
553 hi = mid - 1;
559 * Handle pci config space reads.
560 * If it's to the MSI-X info, do that.
561 * If it's part of the virtio standard stuff, do that.
567 struct virtio_softc *vs = pi->pi_arg;
576 if (vs->vs_flags & VIRTIO_USE_MSIX) {
586 if (vs->vs_mtx)
587 pthread_mutex_lock(vs->vs_mtx);
589 vc = vs->vs_vc;
590 name = vc->vc_name;
600 * Subtract off the standard size (including MSI-X
604 newoff = offset - virtio_config_size;
605 max = vc->vc_cfgsize ? vc->vc_cfgsize : 0x100000000;
608 if (vc->vc_cfgread != NULL)
609 error = (*vc->vc_cfgread)(DEV_SOFTC(vs), newoff, size, &value);
618 if (cr == NULL || cr->cr_size != size) {
623 name, cr->cr_name, size);
634 value = vc->vc_hv_caps;
637 value = vs->vs_negotiated_caps;
640 if (vs->vs_curq < vc->vc_nvq)
641 value = vs->vs_queues[vs->vs_curq].vq_pfn;
644 value = vs->vs_curq < vc->vc_nvq ?
645 vs->vs_queues[vs->vs_curq].vq_qsize : 0;
648 value = vs->vs_curq;
654 value = vs->vs_status;
657 value = vs->vs_isr;
658 vs->vs_isr = 0; /* a read clears this flag */
663 value = vs->vs_msix_cfg_idx;
666 value = vs->vs_curq < vc->vc_nvq ?
667 vs->vs_queues[vs->vs_curq].vq_msix_idx :
672 if (vs->vs_mtx)
673 pthread_mutex_unlock(vs->vs_mtx);
678 * Handle pci config space writes.
679 * If it's to the MSI-X info, do that.
680 * If it's part of the virtio standard stuff, do that.
687 struct virtio_softc *vs = pi->pi_arg;
696 if (vs->vs_flags & VIRTIO_USE_MSIX) {
707 if (vs->vs_mtx)
708 pthread_mutex_lock(vs->vs_mtx);
710 vc = vs->vs_vc;
711 name = vc->vc_name;
720 * Subtract off the standard size (including MSI-X
723 newoff = offset - virtio_config_size;
724 max = vc->vc_cfgsize ? vc->vc_cfgsize : 0x100000000;
727 if (vc->vc_cfgwrite != NULL)
728 error = (*vc->vc_cfgwrite)(DEV_SOFTC(vs), newoff, size, value);
737 if (cr == NULL || cr->cr_size != size || cr->cr_ro) {
740 if (cr->cr_size != size)
743 name, cr->cr_name, size);
744 if (cr->cr_ro)
746 "%s: write to read-only reg %s",
747 name, cr->cr_name);
758 vs->vs_negotiated_caps = value & vc->vc_hv_caps;
759 if (vc->vc_apply_features)
760 (*vc->vc_apply_features)(DEV_SOFTC(vs),
761 vs->vs_negotiated_caps);
764 if (vs->vs_curq >= vc->vc_nvq)
774 vs->vs_curq = value;
777 if (value >= (unsigned int)vc->vc_nvq) {
782 vq = &vs->vs_queues[value];
783 if (vq->vq_notify)
784 (*vq->vq_notify)(DEV_SOFTC(vs), vq);
785 else if (vc->vc_qnotify)
786 (*vc->vc_qnotify)(DEV_SOFTC(vs), vq);
793 vs->vs_status = value;
795 (*vc->vc_reset)(DEV_SOFTC(vs));
798 vs->vs_msix_cfg_idx = value;
801 if (vs->vs_curq >= vc->vc_nvq)
803 vq = &vs->vs_queues[vs->vs_curq];
804 vq->vq_msix_idx = value;
812 name, cr->cr_name, vs->vs_curq, vc->vc_nvq);
814 if (vs->vs_mtx)
815 pthread_mutex_unlock(vs->vs_mtx);
825 vs = pi->pi_arg;
826 vc = vs->vs_vc;
828 vc = vs->vs_vc;
829 assert(vc->vc_pause != NULL);
830 (*vc->vc_pause)(DEV_SOFTC(vs));
841 vs = pi->pi_arg;
842 vc = vs->vs_vc;
844 vc = vs->vs_vc;
845 assert(vc->vc_resume != NULL);
846 (*vc->vc_resume)(DEV_SOFTC(vs));
856 SNAPSHOT_VAR_OR_LEAVE(vs->vs_flags, meta, ret, done);
857 SNAPSHOT_VAR_OR_LEAVE(vs->vs_negotiated_caps, meta, ret, done);
858 SNAPSHOT_VAR_OR_LEAVE(vs->vs_curq, meta, ret, done);
859 SNAPSHOT_VAR_OR_LEAVE(vs->vs_status, meta, ret, done);
860 SNAPSHOT_VAR_OR_LEAVE(vs->vs_isr, meta, ret, done);
861 SNAPSHOT_VAR_OR_LEAVE(vs->vs_msix_cfg_idx, meta, ret, done);
872 SNAPSHOT_VAR_CMP_OR_LEAVE(vc->vc_nvq, meta, ret, done);
873 SNAPSHOT_VAR_CMP_OR_LEAVE(vc->vc_cfgsize, meta, ret, done);
874 SNAPSHOT_VAR_CMP_OR_LEAVE(vc->vc_hv_caps, meta, ret, done);
890 ctx = vs->vs_pi->pi_vmctx;
891 vc = vs->vs_vc;
893 /* Save virtio queue info */
894 for (i = 0; i < vc->vc_nvq; i++) {
895 vq = &vs->vs_queues[i];
897 SNAPSHOT_VAR_CMP_OR_LEAVE(vq->vq_qsize, meta, ret, done);
898 SNAPSHOT_VAR_CMP_OR_LEAVE(vq->vq_num, meta, ret, done);
900 SNAPSHOT_VAR_OR_LEAVE(vq->vq_flags, meta, ret, done);
901 SNAPSHOT_VAR_OR_LEAVE(vq->vq_last_avail, meta, ret, done);
902 SNAPSHOT_VAR_OR_LEAVE(vq->vq_next_used, meta, ret, done);
903 SNAPSHOT_VAR_OR_LEAVE(vq->vq_save_used, meta, ret, done);
904 SNAPSHOT_VAR_OR_LEAVE(vq->vq_msix_idx, meta, ret, done);
906 SNAPSHOT_VAR_OR_LEAVE(vq->vq_pfn, meta, ret, done);
911 addr_size = vq->vq_qsize * sizeof(struct vring_desc);
912 SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_desc, addr_size,
915 addr_size = (2 + vq->vq_qsize + 1) * sizeof(uint16_t);
916 SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_avail, addr_size,
919 addr_size = (2 + 2 * vq->vq_qsize + 1) * sizeof(uint16_t);
920 SNAPSHOT_GUEST2HOST_ADDR_OR_LEAVE(ctx, vq->vq_used, addr_size,
923 SNAPSHOT_BUF_OR_LEAVE(vq->vq_desc,
924 vring_size_aligned(vq->vq_qsize), meta, ret, done);
939 pi = meta->dev_data;
940 vs = pi->pi_arg;
941 vc = vs->vs_vc;
943 /* Save virtio softc */
948 /* Save virtio consts */
953 /* Save virtio queue info */
959 if (vc->vc_snapshot != NULL) {
960 ret = (*vc->vc_snapshot)(DEV_SOFTC(vs), meta);