mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-19 02:29:40 +00:00
bhyve: change vq_getchain to return iovecs in both directions
The old prototype requires callers to inspect flags of each descriptors
to get the starting position of host-writable iovecs.
vq_getchain() is changed to return a virtio request with the number of
host-readable iovecs and host-writable iovecs instead. Callers can avoid
boilerplate code of getting the start offset of host-writable iovecs.
Sponsored by: The FreeBSD Foundation
Reviewed by: afedorov
Approved by: philip (mentor)
Differential Revision: https://reviews.freebsd.org/D29433
(cherry picked from commit b013912772
)
This commit is contained in:
parent
ddf1b5ac76
commit
3fc8a816d9
@ -197,32 +197,24 @@ pci_vt9p_notify(void *vsc, struct vqueue_info *vq)
|
||||
struct iovec iov[VT9P_MAX_IOV];
|
||||
struct pci_vt9p_softc *sc;
|
||||
struct pci_vt9p_request *preq;
|
||||
uint16_t idx, n, i;
|
||||
uint16_t flags[VT9P_MAX_IOV];
|
||||
struct vi_req req;
|
||||
uint16_t n;
|
||||
|
||||
sc = vsc;
|
||||
|
||||
while (vq_has_descs(vq)) {
|
||||
n = vq_getchain(vq, &idx, iov, VT9P_MAX_IOV, flags);
|
||||
n = vq_getchain(vq, iov, VT9P_MAX_IOV, &req);
|
||||
preq = calloc(1, sizeof(struct pci_vt9p_request));
|
||||
preq->vsr_sc = sc;
|
||||
preq->vsr_idx = idx;
|
||||
preq->vsr_idx = req.idx;
|
||||
preq->vsr_iov = iov;
|
||||
preq->vsr_niov = n;
|
||||
preq->vsr_respidx = 0;
|
||||
|
||||
/* Count readable descriptors */
|
||||
for (i = 0; i < n; i++) {
|
||||
if (flags[i] & VRING_DESC_F_WRITE)
|
||||
break;
|
||||
|
||||
preq->vsr_respidx++;
|
||||
}
|
||||
preq->vsr_respidx = req.readable;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
DPRINTF(("vt9p: vt9p_notify(): desc%d base=%p, "
|
||||
"len=%zu, flags=0x%04x\r\n", i, iov[i].iov_base,
|
||||
iov[i].iov_len, flags[i]));
|
||||
"len=%zu\r\n", i, iov[i].iov_base,
|
||||
iov[i].iov_len));
|
||||
}
|
||||
|
||||
l9p_connection_recv(sc->vsc_conn, iov, preq->vsr_respidx, preq);
|
||||
|
@ -308,11 +308,11 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
|
||||
int err;
|
||||
ssize_t iolen;
|
||||
int writeop, type;
|
||||
struct vi_req req;
|
||||
struct iovec iov[BLOCKIF_IOV_MAX + 2];
|
||||
uint16_t idx, flags[BLOCKIF_IOV_MAX + 2];
|
||||
struct virtio_blk_discard_write_zeroes *discard;
|
||||
|
||||
n = vq_getchain(vq, &idx, iov, BLOCKIF_IOV_MAX + 2, flags);
|
||||
n = vq_getchain(vq, iov, BLOCKIF_IOV_MAX + 2, &req);
|
||||
|
||||
/*
|
||||
* The first descriptor will be the read-only fixed header,
|
||||
@ -324,16 +324,16 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
|
||||
*/
|
||||
assert(n >= 2 && n <= BLOCKIF_IOV_MAX + 2);
|
||||
|
||||
io = &sc->vbsc_ios[idx];
|
||||
assert((flags[0] & VRING_DESC_F_WRITE) == 0);
|
||||
io = &sc->vbsc_ios[req.idx];
|
||||
assert(req.readable != 0);
|
||||
assert(iov[0].iov_len == sizeof(struct virtio_blk_hdr));
|
||||
vbh = (struct virtio_blk_hdr *)iov[0].iov_base;
|
||||
memcpy(&io->io_req.br_iov, &iov[1], sizeof(struct iovec) * (n - 2));
|
||||
io->io_req.br_iovcnt = n - 2;
|
||||
io->io_req.br_offset = vbh->vbh_sector * VTBLK_BSIZE;
|
||||
io->io_status = (uint8_t *)iov[--n].iov_base;
|
||||
assert(req.writable != 0);
|
||||
assert(iov[n].iov_len == 1);
|
||||
assert(flags[n] & VRING_DESC_F_WRITE);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
@ -342,16 +342,17 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
|
||||
*/
|
||||
type = vbh->vbh_type & ~VBH_FLAG_BARRIER;
|
||||
writeop = (type == VBH_OP_WRITE || type == VBH_OP_DISCARD);
|
||||
/*
|
||||
* - Write op implies read-only descriptor
|
||||
* - Read/ident op implies write-only descriptor
|
||||
*
|
||||
* By taking away either the read-only fixed header or the write-only
|
||||
* status iovec, the following condition should hold true.
|
||||
*/
|
||||
assert(n == (writeop ? req.readable : req.writable));
|
||||
|
||||
iolen = 0;
|
||||
for (i = 1; i < n; i++) {
|
||||
/*
|
||||
* - write op implies read-only descriptor,
|
||||
* - read/ident op implies write-only descriptor,
|
||||
* therefore test the inverse of the descriptor bit
|
||||
* to the op.
|
||||
*/
|
||||
assert(((flags[i] & VRING_DESC_F_WRITE) == 0) == writeop);
|
||||
iolen += iov[i].iov_len;
|
||||
}
|
||||
io->io_req.br_resid = iolen;
|
||||
|
@ -415,10 +415,10 @@ pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg)
|
||||
struct pci_vtcon_port *port;
|
||||
struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg;
|
||||
struct vqueue_info *vq;
|
||||
struct vi_req req;
|
||||
struct iovec iov;
|
||||
static char dummybuf[2048];
|
||||
int len, n;
|
||||
uint16_t idx;
|
||||
|
||||
port = sock->vss_port;
|
||||
vq = pci_vtcon_port_to_vq(port, true);
|
||||
@ -441,7 +441,7 @@ pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg)
|
||||
}
|
||||
|
||||
do {
|
||||
n = vq_getchain(vq, &idx, &iov, 1, NULL);
|
||||
n = vq_getchain(vq, &iov, 1, &req);
|
||||
len = readv(sock->vss_conn_fd, &iov, n);
|
||||
|
||||
if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) {
|
||||
@ -453,7 +453,7 @@ pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
vq_relchain(vq, idx, len);
|
||||
vq_relchain(vq, req.idx, len);
|
||||
} while (vq_has_descs(vq));
|
||||
|
||||
vq_endchains(vq, 1);
|
||||
@ -572,8 +572,8 @@ pci_vtcon_control_send(struct pci_vtcon_softc *sc,
|
||||
struct pci_vtcon_control *ctrl, const void *payload, size_t len)
|
||||
{
|
||||
struct vqueue_info *vq;
|
||||
struct vi_req req;
|
||||
struct iovec iov;
|
||||
uint16_t idx;
|
||||
int n;
|
||||
|
||||
vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true);
|
||||
@ -581,7 +581,7 @@ pci_vtcon_control_send(struct pci_vtcon_softc *sc,
|
||||
if (!vq_has_descs(vq))
|
||||
return;
|
||||
|
||||
n = vq_getchain(vq, &idx, &iov, 1, NULL);
|
||||
n = vq_getchain(vq, &iov, 1, &req);
|
||||
|
||||
assert(n == 1);
|
||||
|
||||
@ -590,7 +590,7 @@ pci_vtcon_control_send(struct pci_vtcon_softc *sc,
|
||||
memcpy(iov.iov_base + sizeof(struct pci_vtcon_control),
|
||||
payload, len);
|
||||
|
||||
vq_relchain(vq, idx, sizeof(struct pci_vtcon_control) + len);
|
||||
vq_relchain(vq, req.idx, sizeof(struct pci_vtcon_control) + len);
|
||||
vq_endchains(vq, 1);
|
||||
}
|
||||
|
||||
@ -601,14 +601,14 @@ pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq)
|
||||
struct pci_vtcon_softc *sc;
|
||||
struct pci_vtcon_port *port;
|
||||
struct iovec iov[1];
|
||||
uint16_t idx, n;
|
||||
uint16_t flags[8];
|
||||
struct vi_req req;
|
||||
uint16_t n;
|
||||
|
||||
sc = vsc;
|
||||
port = pci_vtcon_vq_to_port(sc, vq);
|
||||
|
||||
while (vq_has_descs(vq)) {
|
||||
n = vq_getchain(vq, &idx, iov, 1, flags);
|
||||
n = vq_getchain(vq, iov, 1, &req);
|
||||
assert(n >= 1);
|
||||
if (port != NULL)
|
||||
port->vsp_cb(port, port->vsp_arg, iov, 1);
|
||||
@ -616,7 +616,7 @@ pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq)
|
||||
/*
|
||||
* Release this chain and handle more
|
||||
*/
|
||||
vq_relchain(vq, idx, 0);
|
||||
vq_relchain(vq, req.idx, 0);
|
||||
}
|
||||
vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
|
||||
}
|
||||
|
@ -248,6 +248,7 @@ pci_vtnet_rx(struct pci_vtnet_softc *sc)
|
||||
struct virtio_mrg_rxbuf_info info[VTNET_MAXSEGS];
|
||||
struct iovec iov[VTNET_MAXSEGS + 1];
|
||||
struct vqueue_info *vq;
|
||||
struct vi_req req;
|
||||
|
||||
vq = &sc->vsc_queues[VTNET_RXQ];
|
||||
|
||||
@ -288,8 +289,9 @@ pci_vtnet_rx(struct pci_vtnet_softc *sc)
|
||||
riov = iov;
|
||||
n_chains = 0;
|
||||
do {
|
||||
int n = vq_getchain(vq, &info[n_chains].idx, riov,
|
||||
VTNET_MAXSEGS - riov_len, NULL);
|
||||
int n = vq_getchain(vq, riov, VTNET_MAXSEGS - riov_len,
|
||||
&req);
|
||||
info[n_chains].idx = req.idx;
|
||||
|
||||
if (n == 0) {
|
||||
/*
|
||||
@ -435,7 +437,7 @@ pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vqueue_info *vq)
|
||||
{
|
||||
struct iovec iov[VTNET_MAXSEGS + 1];
|
||||
struct iovec *siov = iov;
|
||||
uint16_t idx;
|
||||
struct vi_req req;
|
||||
ssize_t len;
|
||||
int n;
|
||||
|
||||
@ -443,7 +445,7 @@ pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vqueue_info *vq)
|
||||
* Obtain chain of descriptors. The first descriptor also
|
||||
* contains the virtio-net header.
|
||||
*/
|
||||
n = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);
|
||||
n = vq_getchain(vq, iov, VTNET_MAXSEGS, &req);
|
||||
assert(n >= 1 && n <= VTNET_MAXSEGS);
|
||||
|
||||
if (sc->vhdrlen != sc->be_vhdrlen) {
|
||||
@ -473,7 +475,7 @@ pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vqueue_info *vq)
|
||||
* Return the processed chain to the guest, reporting
|
||||
* the number of bytes that we read.
|
||||
*/
|
||||
vq_relchain(vq, idx, len);
|
||||
vq_relchain(vq, req.idx, len);
|
||||
}
|
||||
|
||||
/* Called on TX kick. */
|
||||
|
@ -113,8 +113,8 @@ pci_vtrnd_notify(void *vsc, struct vqueue_info *vq)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct pci_vtrnd_softc *sc;
|
||||
struct vi_req req;
|
||||
int len;
|
||||
uint16_t idx;
|
||||
|
||||
sc = vsc;
|
||||
|
||||
@ -124,7 +124,7 @@ pci_vtrnd_notify(void *vsc, struct vqueue_info *vq)
|
||||
}
|
||||
|
||||
while (vq_has_descs(vq)) {
|
||||
vq_getchain(vq, &idx, &iov, 1, NULL);
|
||||
vq_getchain(vq, &iov, 1, &req);
|
||||
|
||||
len = read(sc->vrsc_fd, iov.iov_base, iov.iov_len);
|
||||
|
||||
@ -136,7 +136,7 @@ pci_vtrnd_notify(void *vsc, struct vqueue_info *vq)
|
||||
/*
|
||||
* Release this chain and handle more
|
||||
*/
|
||||
vq_relchain(vq, idx, len);
|
||||
vq_relchain(vq, req.idx, len);
|
||||
}
|
||||
vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
|
||||
}
|
||||
|
@ -558,7 +558,8 @@ pci_vtscsi_controlq_notify(void *vsc, struct vqueue_info *vq)
|
||||
{
|
||||
struct pci_vtscsi_softc *sc;
|
||||
struct iovec iov[VTSCSI_MAXSEG];
|
||||
uint16_t idx, n;
|
||||
struct vi_req req;
|
||||
uint16_t n;
|
||||
void *buf = NULL;
|
||||
size_t bufsize;
|
||||
int iolen;
|
||||
@ -566,7 +567,7 @@ pci_vtscsi_controlq_notify(void *vsc, struct vqueue_info *vq)
|
||||
sc = vsc;
|
||||
|
||||
while (vq_has_descs(vq)) {
|
||||
n = vq_getchain(vq, &idx, iov, VTSCSI_MAXSEG, NULL);
|
||||
n = vq_getchain(vq, iov, VTSCSI_MAXSEG, &req);
|
||||
bufsize = iov_to_buf(iov, n, &buf);
|
||||
iolen = pci_vtscsi_control_handle(sc, buf, bufsize);
|
||||
buf_to_iov(buf + bufsize - iolen, iolen, iov, n,
|
||||
@ -575,7 +576,7 @@ pci_vtscsi_controlq_notify(void *vsc, struct vqueue_info *vq)
|
||||
/*
|
||||
* Release this chain and handle more
|
||||
*/
|
||||
vq_relchain(vq, idx, iolen);
|
||||
vq_relchain(vq, req.idx, iolen);
|
||||
}
|
||||
vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
|
||||
free(buf);
|
||||
@ -595,33 +596,23 @@ pci_vtscsi_requestq_notify(void *vsc, struct vqueue_info *vq)
|
||||
struct pci_vtscsi_queue *q;
|
||||
struct pci_vtscsi_request *req;
|
||||
struct iovec iov[VTSCSI_MAXSEG];
|
||||
uint16_t flags[VTSCSI_MAXSEG];
|
||||
uint16_t idx, n, i;
|
||||
int readable;
|
||||
struct vi_req vireq;
|
||||
uint16_t n;
|
||||
|
||||
sc = vsc;
|
||||
q = &sc->vss_queues[vq->vq_num - 2];
|
||||
|
||||
while (vq_has_descs(vq)) {
|
||||
readable = 0;
|
||||
n = vq_getchain(vq, &idx, iov, VTSCSI_MAXSEG, flags);
|
||||
|
||||
/* Count readable descriptors */
|
||||
for (i = 0; i < n; i++) {
|
||||
if (flags[i] & VRING_DESC_F_WRITE)
|
||||
break;
|
||||
|
||||
readable++;
|
||||
}
|
||||
n = vq_getchain(vq, iov, VTSCSI_MAXSEG, &vireq);
|
||||
|
||||
req = calloc(1, sizeof(struct pci_vtscsi_request));
|
||||
req->vsr_idx = idx;
|
||||
req->vsr_idx = vireq.idx;
|
||||
req->vsr_queue = q;
|
||||
req->vsr_niov_in = readable;
|
||||
req->vsr_niov_out = n - readable;
|
||||
req->vsr_niov_in = vireq.readable;
|
||||
req->vsr_niov_out = vireq.writable;
|
||||
memcpy(req->vsr_iov_in, iov,
|
||||
req->vsr_niov_in * sizeof(struct iovec));
|
||||
memcpy(req->vsr_iov_out, iov + readable,
|
||||
memcpy(req->vsr_iov_out, iov + vireq.readable,
|
||||
req->vsr_niov_out * sizeof(struct iovec));
|
||||
|
||||
pthread_mutex_lock(&q->vsq_mtx);
|
||||
@ -629,7 +620,8 @@ pci_vtscsi_requestq_notify(void *vsc, struct vqueue_info *vq)
|
||||
pthread_cond_signal(&q->vsq_cv);
|
||||
pthread_mutex_unlock(&q->vsq_mtx);
|
||||
|
||||
DPRINTF(("virtio-scsi: request <idx=%d> enqueued", idx));
|
||||
DPRINTF(("virtio-scsi: request <idx=%d> enqueued",
|
||||
vireq.idx));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
|
||||
@ -213,15 +214,18 @@ vi_vq_init(struct virtio_softc *vs, uint32_t pfn)
|
||||
* descriptor.
|
||||
*/
|
||||
static inline void
|
||||
_vq_record(int i, volatile struct vring_desc *vd, struct vmctx *ctx,
|
||||
struct iovec *iov, int n_iov, uint16_t *flags) {
|
||||
_vq_record(int i, volatile struct vring_desc *vd,
|
||||
struct vmctx *ctx, struct iovec *iov, int n_iov,
|
||||
struct vi_req *reqp) {
|
||||
|
||||
if (i >= n_iov)
|
||||
return;
|
||||
iov[i].iov_base = paddr_guest2host(ctx, vd->addr, vd->len);
|
||||
iov[i].iov_len = vd->len;
|
||||
if (flags != NULL)
|
||||
flags[i] = vd->flags;
|
||||
if ((vd->flags & VRING_DESC_F_WRITE) == 0)
|
||||
reqp->readable++;
|
||||
else
|
||||
reqp->writable++;
|
||||
}
|
||||
#define VQ_MAX_DESCRIPTORS 512 /* see below */
|
||||
|
||||
@ -253,11 +257,6 @@ _vq_record(int i, volatile struct vring_desc *vd, struct vmctx *ctx,
|
||||
* a larger iov array if needed, or supply a zero length to find
|
||||
* out how much space is needed).
|
||||
*
|
||||
* If you want to verify the WRITE flag on each descriptor, pass a
|
||||
* non-NULL "flags" pointer to an array of "uint16_t" of the same size
|
||||
* as n_iov and we'll copy each "flags" field after unwinding any
|
||||
* indirects.
|
||||
*
|
||||
* If some descriptor(s) are invalid, this prints a diagnostic message
|
||||
* and returns -1. If no descriptors are ready now it simply returns 0.
|
||||
*
|
||||
@ -265,12 +264,13 @@ _vq_record(int i, volatile struct vring_desc *vd, struct vmctx *ctx,
|
||||
* that vq_has_descs() does one).
|
||||
*/
|
||||
int
|
||||
vq_getchain(struct vqueue_info *vq, uint16_t *pidx,
|
||||
struct iovec *iov, int n_iov, uint16_t *flags)
|
||||
vq_getchain(struct vqueue_info *vq, struct iovec *iov, int niov,
|
||||
struct vi_req *reqp)
|
||||
{
|
||||
int i;
|
||||
u_int ndesc, n_indir;
|
||||
u_int idx, next;
|
||||
struct vi_req req;
|
||||
volatile struct vring_desc *vdir, *vindir, *vp;
|
||||
struct vmctx *ctx;
|
||||
struct virtio_softc *vs;
|
||||
@ -278,6 +278,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx,
|
||||
|
||||
vs = vq->vq_vs;
|
||||
name = vs->vs_vc->vc_name;
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
||||
/*
|
||||
* Note: it's the responsibility of the guest not to
|
||||
@ -313,7 +314,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx,
|
||||
* index, but we just abort if the count gets excessive.
|
||||
*/
|
||||
ctx = vs->vs_pi->pi_vmctx;
|
||||
*pidx = next = vq->vq_avail->ring[idx & (vq->vq_qsize - 1)];
|
||||
req.idx = next = vq->vq_avail->ring[idx & (vq->vq_qsize - 1)];
|
||||
vq->vq_last_avail++;
|
||||
for (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->next) {
|
||||
if (next >= vq->vq_qsize) {
|
||||
@ -325,7 +326,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx,
|
||||
}
|
||||
vdir = &vq->vq_desc[next];
|
||||
if ((vdir->flags & VRING_DESC_F_INDIRECT) == 0) {
|
||||
_vq_record(i, vdir, ctx, iov, n_iov, flags);
|
||||
_vq_record(i, vdir, ctx, iov, niov, &req);
|
||||
i++;
|
||||
} else if ((vs->vs_vc->vc_hv_caps &
|
||||
VIRTIO_RING_F_INDIRECT_DESC) == 0) {
|
||||
@ -362,7 +363,7 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx,
|
||||
name);
|
||||
return (-1);
|
||||
}
|
||||
_vq_record(i, vp, ctx, iov, n_iov, flags);
|
||||
_vq_record(i, vp, ctx, iov, niov, &req);
|
||||
if (++i > VQ_MAX_DESCRIPTORS)
|
||||
goto loopy;
|
||||
if ((vp->flags & VRING_DESC_F_NEXT) == 0)
|
||||
@ -378,13 +379,18 @@ vq_getchain(struct vqueue_info *vq, uint16_t *pidx,
|
||||
}
|
||||
}
|
||||
if ((vdir->flags & VRING_DESC_F_NEXT) == 0)
|
||||
return (i);
|
||||
goto done;
|
||||
}
|
||||
|
||||
loopy:
|
||||
EPRINTLN(
|
||||
"%s: descriptor loop? count > %d - driver confused?",
|
||||
name, i);
|
||||
return (-1);
|
||||
|
||||
done:
|
||||
*reqp = req;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -371,6 +371,18 @@ vq_kick_disable(struct vqueue_info *vq)
|
||||
}
|
||||
|
||||
struct iovec;
|
||||
|
||||
/*
|
||||
* Request description returned by vq_getchain.
|
||||
*
|
||||
* Writable iovecs start at iov[req.readable].
|
||||
*/
|
||||
struct vi_req {
|
||||
int readable; /* num of readable iovecs */
|
||||
int writable; /* num of writable iovecs */
|
||||
unsigned int idx; /* ring index */
|
||||
};
|
||||
|
||||
void vi_softc_linkup(struct virtio_softc *vs, struct virtio_consts *vc,
|
||||
void *dev_softc, struct pci_devinst *pi,
|
||||
struct vqueue_info *queues);
|
||||
@ -378,8 +390,8 @@ int vi_intr_init(struct virtio_softc *vs, int barnum, int use_msix);
|
||||
void vi_reset_dev(struct virtio_softc *);
|
||||
void vi_set_io_bar(struct virtio_softc *, int);
|
||||
|
||||
int vq_getchain(struct vqueue_info *vq, uint16_t *pidx,
|
||||
struct iovec *iov, int n_iov, uint16_t *flags);
|
||||
int vq_getchain(struct vqueue_info *vq, struct iovec *iov, int niov,
|
||||
struct vi_req *reqp);
|
||||
void vq_retchains(struct vqueue_info *vq, uint16_t n_chains);
|
||||
void vq_relchain_prepare(struct vqueue_info *vq, uint16_t idx,
|
||||
uint32_t iolen);
|
||||
|
Loading…
Reference in New Issue
Block a user