Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/virtio.c
Show All 35 Lines | |||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include <pthread_np.h> | #include <pthread_np.h> | ||||
#include "bhyverun.h" | #include "bhyverun.h" | ||||
#include "iov.h" | |||||
#include "pci_emul.h" | #include "pci_emul.h" | ||||
#include "virtio.h" | #include "virtio.h" | ||||
/* | /* | ||||
* Functions for dealing with generalized "virtual devices" as | * Functions for dealing with generalized "virtual devices" as | ||||
* defined by <https://www.google.com/#output=search&q=virtio+spec> | * defined by <https://www.google.com/#output=search&q=virtio+spec> | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 324 Lines • ▼ Show 20 Lines | vq_getchain(struct vqueue_info *vq, uint16_t *pidx, | ||||
} | } | ||||
loopy: | loopy: | ||||
fprintf(stderr, | fprintf(stderr, | ||||
"%s: descriptor loop? count > %d - driver confused?\r\n", | "%s: descriptor loop? count > %d - driver confused?\r\n", | ||||
name, i); | name, i); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
int vq_getbufs_mrgrx(struct vqueue_info *vq, struct iovec *iov, | |||||
int n_iov, int len, struct virtio_used *used, int *u_cnt) | |||||
{ | |||||
uint16_t idx; | |||||
int i, iov_len; | |||||
int bufs, last_avail_saved, n; | |||||
int total_len; | |||||
i = 0; | |||||
bufs = 0; | |||||
total_len = 0; | |||||
/* | /* | ||||
* vq_getchain() increment the last avail index. | |||||
* Save it to restore if there are no enough buffers to store packet. | |||||
*/ | |||||
last_avail_saved = vq->vq_last_avail; | |||||
while (1) { | |||||
n = vq_getchain(vq, &idx, &iov[i], n_iov - i, NULL); | |||||
if (n <= 0) { | |||||
/* Restore the last avail index. */ | |||||
vq->vq_last_avail = last_avail_saved; | |||||
*u_cnt = 0; | |||||
return (n); | |||||
} | |||||
iov_len = count_iov(&iov[i], n); | |||||
vmaffione: The name of 'iov_len' variable is really confusing, as struct iovec.iov_len refers to the… | |||||
i += n; | |||||
total_len += iov_len; | |||||
used[bufs].vu_idx = idx; | |||||
if (total_len < len) { | |||||
used[bufs].vu_tlen = iov_len; | |||||
bufs++; | |||||
} else { | |||||
used[bufs].vu_tlen = iov_len - (total_len - len); | |||||
bufs++; | |||||
break; | |||||
} | |||||
}; | |||||
*u_cnt = bufs; | |||||
return i; | |||||
} | |||||
/* | |||||
* Return the currently-first request chain back to the available queue. | * Return the currently-first request chain back to the available queue. | ||||
* | * | ||||
* (This chain is the one you handled when you called vq_getchain() | * (This chain is the one you handled when you called vq_getchain() | ||||
* and used its positive return value.) | * and used its positive return value.) | ||||
*/ | */ | ||||
void | void | ||||
vq_retchain(struct vqueue_info *vq) | vq_retchain(struct vqueue_info *vq) | ||||
{ | { | ||||
Show All 32 Lines | vq_relchain(struct vqueue_info *vq, uint16_t idx, uint32_t iolen) | ||||
vue = &vuh->vu_ring[uidx++ & mask]; | vue = &vuh->vu_ring[uidx++ & mask]; | ||||
vue->vu_idx = idx; | vue->vu_idx = idx; | ||||
vue->vu_tlen = iolen; | vue->vu_tlen = iolen; | ||||
/* | /* | ||||
* Ensure the used descriptor is visible before updating the index. | * Ensure the used descriptor is visible before updating the index. | ||||
* This is necessary on ISAs with memory ordering less strict than x86. | * This is necessary on ISAs with memory ordering less strict than x86. | ||||
*/ | */ | ||||
atomic_thread_fence_rel(); | |||||
vuh->vu_idx = uidx; | |||||
} | |||||
/* | |||||
* Return specified merged rx buffers to the guest, setting its I/O length. | |||||
*/ | |||||
void | |||||
vq_relbufs_mrgrx(struct vqueue_info *vq, int nbufs, struct virtio_used *used) | |||||
{ | |||||
int i; | |||||
uint16_t uidx, mask; | |||||
volatile struct vring_used *vuh; | |||||
volatile struct virtio_used *vue; | |||||
mask = vq->vq_qsize - 1; | |||||
vuh = vq->vq_used; | |||||
uidx = vuh->vu_idx; | |||||
if (nbufs == 1) { | |||||
vue = &vuh->vu_ring[uidx++ & mask]; | |||||
vue->vu_idx = used[0].vu_idx; | |||||
vue->vu_tlen = used[0].vu_tlen; | |||||
} else { | |||||
for (i = 0; i < nbufs; i++) { | |||||
vue = &vuh->vu_ring[(uidx + i) & mask]; | |||||
vue->vu_idx = used[i].vu_idx; | |||||
vue->vu_tlen = used[i].vu_tlen; | |||||
} | |||||
uidx += nbufs; | |||||
} | |||||
atomic_thread_fence_rel(); | atomic_thread_fence_rel(); | ||||
vuh->vu_idx = uidx; | vuh->vu_idx = uidx; | ||||
} | } | ||||
/* | /* | ||||
* Driver has finished processing "available" chains and calling | * Driver has finished processing "available" chains and calling | ||||
* vq_relchain on each one. If driver used all the available | * vq_relchain on each one. If driver used all the available | ||||
* chains, used_all should be set. | * chains, used_all should be set. | ||||
▲ Show 20 Lines • Show All 355 Lines • Show Last 20 Lines |
The name of 'iov_len' variable is really confusing, as struct iovec.iov_len refers to the length of a single slot, while your variable refers to the sum of the lengths of possibly many slots...
It's better to use something like 'chain_len'