mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-01 09:42:10 +00:00
dm: virtio poll mode support for RT
Device trap has great impact on latency of real time (RT) tasks. This patch provide a virtio poll mode to avoid trap. According to the virtio spec, backend devices can declare the notification is not needed so that frontend will never trap. This means the backends make commitment to the frontends they have a poll mechanism which don’t need any frontends notification. This patch uses a periodic timer to give backends pseudo notifications so that drive them processing data in their virtqueues. People should choose a appropriate notification peroid interval to use this poll mode. Too big interval may cause virtqueue processing latency while too small interval may cause high SOS CPU usage. The suggested interval is between 100us to 1ms. The poll mode is not enabled by default and traditional trap notification mode will be used. To use poll mode for RT with interval 1ms. You can add following acrn-dm parameter. --virtio_poll 1000000 Tracked-On: #1956 Signed-off-by: Jie Deng <jie.deng@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
parent
7cc8566d37
commit
b261e74dd5
@ -65,6 +65,7 @@
|
||||
#include "vmcfg_config.h"
|
||||
#include "vmcfg.h"
|
||||
#include "tpm.h"
|
||||
#include "virtio.h"
|
||||
|
||||
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
|
||||
|
||||
@ -703,6 +704,7 @@ enum {
|
||||
CMD_OPT_VSBL = 1000,
|
||||
CMD_OPT_PART_INFO,
|
||||
CMD_OPT_TRUSTY_ENABLE,
|
||||
CMD_OPT_VIRTIO_POLL_ENABLE,
|
||||
CMD_OPT_PTDEV_NO_RESET,
|
||||
CMD_OPT_DEBUGEXIT,
|
||||
CMD_OPT_VMCFG,
|
||||
@ -739,6 +741,7 @@ static struct option long_options[] = {
|
||||
{"part_info", required_argument, 0, CMD_OPT_PART_INFO},
|
||||
{"enable_trusty", no_argument, 0,
|
||||
CMD_OPT_TRUSTY_ENABLE},
|
||||
{"virtio_poll", required_argument, 0, CMD_OPT_VIRTIO_POLL_ENABLE},
|
||||
{"ptdev_no_reset", no_argument, 0,
|
||||
CMD_OPT_PTDEV_NO_RESET},
|
||||
{"debugexit", no_argument, 0, CMD_OPT_DEBUGEXIT},
|
||||
@ -862,6 +865,14 @@ dm_run(int argc, char *argv[])
|
||||
case CMD_OPT_TRUSTY_ENABLE:
|
||||
trusty_enabled = 1;
|
||||
break;
|
||||
case CMD_OPT_VIRTIO_POLL_ENABLE:
|
||||
if (acrn_parse_virtio_poll_interval(optarg) != 0) {
|
||||
errx(EX_USAGE,
|
||||
"invalid virtio poll interval %s",
|
||||
optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case CMD_OPT_PTDEV_NO_RESET:
|
||||
ptdev_no_reset(true);
|
||||
break;
|
||||
|
@ -28,10 +28,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "pci_core.h"
|
||||
#include "virtio.h"
|
||||
#include "timer.h"
|
||||
|
||||
/*
|
||||
* Functions for dealing with generalized "virtual devices" as
|
||||
@ -45,6 +48,61 @@
|
||||
*/
|
||||
#define DEV_STRUCT(vs) ((void *)(vs))
|
||||
|
||||
static uint8_t virtio_poll_enabled;
|
||||
static size_t virtio_poll_interval;
|
||||
|
||||
static void
|
||||
virtio_start_timer(struct acrn_timer *timer, time_t sec, time_t nsec)
|
||||
{
|
||||
struct itimerspec ts;
|
||||
|
||||
/* setting the interval time */
|
||||
ts.it_interval.tv_sec = 0;
|
||||
ts.it_interval.tv_nsec = 0;
|
||||
/* set the delay time it will be started when timer_setting */
|
||||
ts.it_value.tv_sec = sec;
|
||||
ts.it_value.tv_nsec = nsec;
|
||||
assert(acrn_timer_settime(timer, &ts) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
virtio_poll_timer(void *arg)
|
||||
{
|
||||
struct virtio_base *base;
|
||||
struct virtio_ops *vops;
|
||||
struct virtio_vq_info *vq;
|
||||
const char *name;
|
||||
int i;
|
||||
|
||||
base = arg;
|
||||
vops = base->vops;
|
||||
name = vops->name;
|
||||
|
||||
if (base->mtx)
|
||||
pthread_mutex_lock(base->mtx);
|
||||
|
||||
base->polling_in_progress = 1;
|
||||
|
||||
for (i = 0; i < base->vops->nvq; i++) {
|
||||
vq = &base->queues[i];
|
||||
vq->used->flags |= ACRN_VRING_USED_F_NO_NOTIFY;
|
||||
/* TODO: call notify when necessary */
|
||||
if (vq->notify)
|
||||
(*vq->notify)(DEV_STRUCT(base), vq);
|
||||
else if (vops->qnotify)
|
||||
(*vops->qnotify)(DEV_STRUCT(base), vq);
|
||||
else
|
||||
fprintf(stderr,
|
||||
"%s: qnotify queue %d: missing vq/vops notify\r\n",
|
||||
name, i);
|
||||
}
|
||||
|
||||
if (base->mtx)
|
||||
pthread_mutex_unlock(base->mtx);
|
||||
|
||||
virtio_start_timer(&base->polling_timer, 0, virtio_poll_interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Link a virtio_base to its constants, the virtio device,
|
||||
* and the PCI emulation.
|
||||
@ -60,7 +118,8 @@
|
||||
void
|
||||
virtio_linkup(struct virtio_base *base, struct virtio_ops *vops,
|
||||
void *pci_virtio_dev, struct pci_vdev *dev,
|
||||
struct virtio_vq_info *queues)
|
||||
struct virtio_vq_info *queues,
|
||||
int backend_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -69,6 +128,7 @@ virtio_linkup(struct virtio_base *base, struct virtio_ops *vops,
|
||||
base->vops = vops;
|
||||
base->dev = dev;
|
||||
dev->arg = base;
|
||||
base->backend_type = backend_type;
|
||||
|
||||
base->queues = queues;
|
||||
for (i = 0; i < vops->nvq; i++) {
|
||||
@ -100,6 +160,9 @@ virtio_reset_dev(struct virtio_base *base)
|
||||
/* if (base->mtx) */
|
||||
/* assert(pthread_mutex_isowned_np(base->mtx)); */
|
||||
|
||||
acrn_timer_deinit(&base->polling_timer);
|
||||
base->polling_in_progress = 0;
|
||||
|
||||
nvq = base->vops->nvq;
|
||||
for (vq = base->queues, i = 0; i < nvq; vq++, i++) {
|
||||
vq->flags = 0;
|
||||
@ -570,6 +633,30 @@ vq_endchains(struct virtio_vq_info *vq, int used_all_avail)
|
||||
vq_interrupt(base, vq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function for clearing used ring flags.
|
||||
*
|
||||
* Driver should always use this helper function to clear used ring flags.
|
||||
* For virtio poll mode, in order to avoid trap, we should never really
|
||||
* clear used ring flags.
|
||||
*
|
||||
* @param base Pointer to struct virtio_base.
|
||||
* @param vq Pointer to struct virtio_vq_info.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void vq_clear_used_ring_flags(struct virtio_base *base, struct virtio_vq_info *vq)
|
||||
{
|
||||
int backend_type = base->backend_type;
|
||||
int polling_in_progress = base->polling_in_progress;
|
||||
|
||||
/* we should never unmask notification in polling mode */
|
||||
if (virtio_poll_enabled && backend_type == BACKEND_VBSU && polling_in_progress == 1)
|
||||
return;
|
||||
|
||||
vq->used->flags &= ~ACRN_VRING_USED_F_NO_NOTIFY;
|
||||
}
|
||||
|
||||
struct config_reg {
|
||||
uint16_t offset; /* register offset */
|
||||
uint8_t size; /* size (bytes) */
|
||||
@ -877,6 +964,17 @@ bad:
|
||||
(*vops->set_status)(DEV_STRUCT(base), value);
|
||||
if (value == 0)
|
||||
(*vops->reset)(DEV_STRUCT(base));
|
||||
if ((value & VIRTIO_CR_STATUS_DRIVER_OK) &&
|
||||
base->backend_type == BACKEND_VBSU &&
|
||||
virtio_poll_enabled) {
|
||||
base->polling_timer.clockid = CLOCK_MONOTONIC;
|
||||
acrn_timer_init(&base->polling_timer, virtio_poll_timer, base);
|
||||
/* wait 5s to start virtio poll mode
|
||||
* skip vsbl and make sure device initialization completed
|
||||
* FIXME: Need optimization in the future
|
||||
*/
|
||||
virtio_start_timer(&base->polling_timer, 5, 0);
|
||||
}
|
||||
break;
|
||||
case VIRTIO_CR_CFGVEC:
|
||||
base->msix_cfg_idx = value;
|
||||
@ -1302,6 +1400,7 @@ virtio_common_cfg_write(struct pci_vdev *dev, uint64_t offset, int size,
|
||||
(*vops->set_status)(DEV_STRUCT(base), value);
|
||||
if (base->status == 0)
|
||||
(*vops->reset)(DEV_STRUCT(base));
|
||||
/* TODO: virtio poll mode for modern devices */
|
||||
break;
|
||||
case VIRTIO_COMMON_Q_SELECT:
|
||||
/*
|
||||
@ -1878,3 +1977,26 @@ virtio_pci_modern_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the virtio poll parameters
|
||||
*
|
||||
* @param optarg Pointer to parameters string.
|
||||
*
|
||||
* @return fail -1 success 0
|
||||
*/
|
||||
int
|
||||
acrn_parse_virtio_poll_interval(const char *optarg)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
virtio_poll_interval = strtoul(optarg, &ptr, 0);
|
||||
|
||||
/* poll interval is limited from 1us to 10ms */
|
||||
if (virtio_poll_interval < 1 || virtio_poll_interval > 10000000)
|
||||
return -1;
|
||||
|
||||
virtio_poll_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
@ -316,7 +316,8 @@ virtio_audio_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
&virtio_audio_ops_k,
|
||||
virt_audio,
|
||||
dev,
|
||||
virt_audio->vq);
|
||||
virt_audio->vq,
|
||||
BACKEND_VBSK);
|
||||
|
||||
rc = virtio_audio_kernel_init(virt_audio);
|
||||
if (rc < 0) {
|
||||
|
@ -384,7 +384,7 @@ virtio_blk_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
"error %d!\n", rc));
|
||||
|
||||
/* init virtio struct and virtqueues */
|
||||
virtio_linkup(&blk->base, &virtio_blk_ops, blk, dev, &blk->vq);
|
||||
virtio_linkup(&blk->base, &virtio_blk_ops, blk, dev, &blk->vq, BACKEND_VBSU);
|
||||
blk->base.mtx = &blk->mtx;
|
||||
|
||||
blk->vq.qsize = VIRTIO_BLK_RINGSZ;
|
||||
|
@ -828,7 +828,7 @@ virtio_console_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
"error %d!\n", rc));
|
||||
|
||||
virtio_linkup(&console->base, &virtio_console_ops, console, dev,
|
||||
console->queues);
|
||||
console->queues, BACKEND_VBSU);
|
||||
console->base.mtx = &console->mtx;
|
||||
console->base.device_caps = VIRTIO_CONSOLE_S_HOSTCAPS;
|
||||
|
||||
|
@ -281,7 +281,7 @@ virtio_coreu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
|
||||
DPRINTF(("vcoreu init: using VBS-U...\n"));
|
||||
virtio_linkup(&vcoreu->base, &virtio_coreu_ops,
|
||||
vcoreu, dev, vcoreu->queues);
|
||||
vcoreu, dev, vcoreu->queues, BACKEND_VBSU);
|
||||
vcoreu->base.mtx = &vcoreu->mtx;
|
||||
|
||||
vcoreu->queues[0].qsize = VIRTIO_COREU_RINGSZ;
|
||||
|
@ -413,7 +413,7 @@ virtio_hdcp_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
|
||||
DPRINTF(("vhdcp init: using VBS-U...\n"));
|
||||
virtio_linkup(&vhdcp->base, &virtio_hdcp_ops,
|
||||
vhdcp, dev, vhdcp->queues);
|
||||
vhdcp, dev, vhdcp->queues, BACKEND_VBSU);
|
||||
vhdcp->base.mtx = &vhdcp->mtx;
|
||||
|
||||
vhdcp->queues[0].qsize = VIRTIO_HDCP_RINGSZ;
|
||||
|
@ -299,7 +299,8 @@ virtio_hyper_dmabuf_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
&virtio_hyper_dmabuf_ops_k,
|
||||
hyper_dmabuf,
|
||||
dev,
|
||||
hyper_dmabuf->vq);
|
||||
hyper_dmabuf->vq,
|
||||
BACKEND_VBSK);
|
||||
|
||||
rc = virtio_hyper_dmabuf_k_init();
|
||||
if (rc < 0) {
|
||||
|
@ -640,7 +640,7 @@ virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
virtio_linkup(&vi->base, &virtio_input_ops, vi, dev, vi->queues);
|
||||
virtio_linkup(&vi->base, &virtio_input_ops, vi, dev, vi->queues, BACKEND_VBSU);
|
||||
vi->base.mtx = &vi->mtx;
|
||||
vi->base.device_caps = VIRTIO_INPUT_S_HOSTCAPS;
|
||||
|
||||
|
@ -320,7 +320,8 @@ virtio_ipu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
&virtio_ipu_ops_k,
|
||||
ipu,
|
||||
dev,
|
||||
ipu->vq);
|
||||
ipu->vq,
|
||||
BACKEND_VBSK);
|
||||
|
||||
rc = virtio_ipu_k_init(ipu);
|
||||
if (rc < 0) {
|
||||
|
@ -1577,7 +1577,7 @@ vmei_notify_tx(void *data, struct virtio_vq_info *vq)
|
||||
|
||||
pthread_mutex_lock(&vmei->tx_mutex);
|
||||
DPRINTF("TX: New OUT buffer available!\n");
|
||||
vq->used->flags &= ~ACRN_VRING_USED_F_NO_NOTIFY;
|
||||
vq_clear_used_ring_flags(&vmei->base, vq);
|
||||
pthread_mutex_unlock(&vmei->tx_mutex);
|
||||
}
|
||||
|
||||
@ -1870,7 +1870,7 @@ static void *vmei_rx_thread(void *param)
|
||||
while (vmei->status != VMEI_STST_DEINIT) {
|
||||
/* note - rx mutex is locked here */
|
||||
while (vq_ring_ready(vq)) {
|
||||
vq->used->flags &= ~ACRN_VRING_USED_F_NO_NOTIFY;
|
||||
vq_clear_used_ring_flags(&vmei->base, vq);
|
||||
mb();
|
||||
if (vq_has_descs(vq) &&
|
||||
vmei->rx_need_sched &&
|
||||
@ -2255,7 +2255,7 @@ init:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
virtio_linkup(&vmei->base, &virtio_mei_ops, vmei, dev, vmei->vqs);
|
||||
virtio_linkup(&vmei->base, &virtio_mei_ops, vmei, dev, vmei->vqs, BACKEND_VBSU);
|
||||
vmei->base.mtx = &vmei->mutex;
|
||||
|
||||
for (i = 0; i < VMEI_VQ_NUM; i++)
|
||||
|
@ -555,7 +555,7 @@ virtio_net_tx_thread(void *param)
|
||||
for (;;) {
|
||||
/* note - tx mutex is locked here */
|
||||
while (net->resetting || !vq_has_descs(vq)) {
|
||||
vq->used->flags &= ~ACRN_VRING_USED_F_NO_NOTIFY;
|
||||
vq_clear_used_ring_flags(&net->base, vq);
|
||||
/* memory barrier */
|
||||
mb();
|
||||
if (!net->resetting && vq_has_descs(vq))
|
||||
@ -724,7 +724,7 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
char nstr[80];
|
||||
char tname[MAXCOMLEN + 1];
|
||||
struct virtio_net *net;
|
||||
char *devname;
|
||||
char *devname = NULL;
|
||||
char *vtopts;
|
||||
char *opt;
|
||||
int mac_provided;
|
||||
@ -751,25 +751,10 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
DPRINTF(("virtio_net: pthread_mutex_init failed with "
|
||||
"error %d!\n", rc));
|
||||
|
||||
virtio_linkup(&net->base, &virtio_net_ops, net, dev, net->queues);
|
||||
net->base.mtx = &net->mtx;
|
||||
net->base.device_caps = VIRTIO_NET_S_HOSTCAPS;
|
||||
|
||||
net->queues[VIRTIO_NET_RXQ].qsize = VIRTIO_NET_RINGSZ;
|
||||
net->queues[VIRTIO_NET_RXQ].notify = virtio_net_ping_rxq;
|
||||
net->queues[VIRTIO_NET_TXQ].qsize = VIRTIO_NET_RINGSZ;
|
||||
net->queues[VIRTIO_NET_TXQ].notify = virtio_net_ping_txq;
|
||||
#ifdef notyet
|
||||
net->queues[VIRTIO_NET_CTLQ].qsize = VIRTIO_NET_RINGSZ;
|
||||
net->queues[VIRTIO_NET_CTLQ].notify = virtio_net_ping_ctlq;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attempt to open the tap device and read the MAC address
|
||||
* if specified
|
||||
* Read the MAC address if specified
|
||||
*/
|
||||
mac_provided = 0;
|
||||
net->tapfd = -1;
|
||||
net->vhost_net = NULL;
|
||||
if (opts != NULL) {
|
||||
int err;
|
||||
@ -795,13 +780,37 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
mac_provided = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtio_linkup(&net->base, &virtio_net_ops, net, dev, net->queues,
|
||||
net->use_vhost ? BACKEND_VHOST : BACKEND_VBSU);
|
||||
net->base.mtx = &net->mtx;
|
||||
net->base.device_caps = VIRTIO_NET_S_HOSTCAPS;
|
||||
|
||||
net->queues[VIRTIO_NET_RXQ].qsize = VIRTIO_NET_RINGSZ;
|
||||
net->queues[VIRTIO_NET_RXQ].notify = virtio_net_ping_rxq;
|
||||
net->queues[VIRTIO_NET_TXQ].qsize = VIRTIO_NET_RINGSZ;
|
||||
net->queues[VIRTIO_NET_TXQ].notify = virtio_net_ping_txq;
|
||||
#ifdef notyet
|
||||
net->queues[VIRTIO_NET_CTLQ].qsize = VIRTIO_NET_RINGSZ;
|
||||
net->queues[VIRTIO_NET_CTLQ].notify = virtio_net_ping_ctlq;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Attempt to open the tap device
|
||||
*/
|
||||
net->tapfd = -1;
|
||||
|
||||
if (!devname) {
|
||||
WPRINTF(("virtio_net: devname NULL\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp(devname, "tap", 3) == 0 ||
|
||||
strncmp(devname, "vmnet", 5) == 0)
|
||||
virtio_net_tap_setup(net, devname);
|
||||
|
||||
free(devname);
|
||||
}
|
||||
|
||||
/*
|
||||
* The default MAC address is the standard NetApp OUI of 00-a0-98,
|
||||
|
@ -404,7 +404,7 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
if (rnd->vbs_k.status == VIRTIO_DEV_PRE_INIT) {
|
||||
DPRINTF(("%s: VBS-K option detected!\n", __func__));
|
||||
virtio_linkup(&rnd->base, &virtio_rnd_ops_k,
|
||||
rnd, dev, &rnd->vq);
|
||||
rnd, dev, &rnd->vq, BACKEND_VBSK);
|
||||
rc = virtio_rnd_kernel_init(rnd);
|
||||
if (rc < 0) {
|
||||
WPRINTF(("virtio_rnd: VBS-K init failed,error %d!\n",
|
||||
@ -417,7 +417,7 @@ virtio_rnd_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
if (rnd->vbs_k.status == VIRTIO_DEV_INITIAL ||
|
||||
rnd->vbs_k.status != VIRTIO_DEV_INIT_SUCCESS) {
|
||||
DPRINTF(("%s: fallback to VBS-U...\n", __func__));
|
||||
virtio_linkup(&rnd->base, &virtio_rnd_ops, rnd, dev, &rnd->vq);
|
||||
virtio_linkup(&rnd->base, &virtio_rnd_ops, rnd, dev, &rnd->vq, BACKEND_VBSU);
|
||||
}
|
||||
|
||||
rnd->base.mtx = &rnd->mtx;
|
||||
|
@ -512,7 +512,7 @@ virtio_rpmb_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
|
||||
goto out;
|
||||
}
|
||||
|
||||
virtio_linkup(&rpmb->base, &virtio_rpmb_ops, rpmb, dev, &rpmb->vq);
|
||||
virtio_linkup(&rpmb->base, &virtio_rpmb_ops, rpmb, dev, &rpmb->vq, BACKEND_VBSU);
|
||||
|
||||
rpmb->base.mtx = &rpmb->mtx;
|
||||
rpmb->vq.qsize = VIRTIO_RPMB_RINGSZ;
|
||||
|
@ -127,6 +127,7 @@
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "timer.h"
|
||||
|
||||
/**
|
||||
* @brief virtio API
|
||||
@ -171,6 +172,14 @@ struct virtio_vring_used {
|
||||
/* uint16_t avail_event; -- after N ring entries */
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
BACKEND_UNKNOWN = 0,
|
||||
BACKEND_VBSU,
|
||||
BACKEND_VBSK,
|
||||
BACKEND_VHOST,
|
||||
BACKEND_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* The address of any given virtual queue is determined by a single
|
||||
* Page Frame Number register. The guest writes the PFN into the
|
||||
@ -520,6 +529,9 @@ struct virtio_base {
|
||||
uint32_t device_feature_select; /**< current selected device feature */
|
||||
uint32_t driver_feature_select; /**< current selected guest feature */
|
||||
int cfg_coff; /**< PCI cfg access capability offset */
|
||||
int backend_type; /**< VBSU, VBSK or VHOST */
|
||||
struct acrn_timer polling_timer; /**< timer for polling mode */
|
||||
int polling_in_progress; /**< The polling status */
|
||||
};
|
||||
|
||||
#define VIRTIO_BASE_LOCK(vb) \
|
||||
@ -703,12 +715,23 @@ struct iovec;
|
||||
* @param pci_virtio_dev Pointer to instance of certain virtio device.
|
||||
* @param dev Pointer to struct pci_vdev which emulates a PCI device.
|
||||
* @param queues Pointer to struct virtio_vq_info, normally an array.
|
||||
* @param backend_type can be VBSU, VBSK or VHOST
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void virtio_linkup(struct virtio_base *base, struct virtio_ops *vops,
|
||||
void *pci_virtio_dev, struct pci_vdev *dev,
|
||||
struct virtio_vq_info *queues);
|
||||
struct virtio_vq_info *queues,
|
||||
int backend_type);
|
||||
|
||||
/**
|
||||
* @brief Get the virtio poll parameters
|
||||
*
|
||||
* @param optarg Pointer to parameters string.
|
||||
*
|
||||
* @return fail -1 success 0
|
||||
*/
|
||||
int acrn_parse_virtio_poll_interval(const char *optarg);
|
||||
|
||||
/**
|
||||
* @brief Initialize MSI-X vector capabilities if we're to use MSI-X,
|
||||
@ -816,6 +839,20 @@ void vq_relchain(struct virtio_vq_info *vq, uint16_t idx, uint32_t iolen);
|
||||
*/
|
||||
void vq_endchains(struct virtio_vq_info *vq, int used_all_avail);
|
||||
|
||||
/**
|
||||
* @brief Helper function for clearing used ring flags.
|
||||
*
|
||||
* Driver should always use this helper function to clear used ring flags.
|
||||
* For virtio poll mode, in order to avoid trap, we should never really
|
||||
* clear used ring flags.
|
||||
*
|
||||
* @param base Pointer to struct virtio_base.
|
||||
* @param vq Pointer to struct virtio_vq_info.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void vq_clear_used_ring_flags(struct virtio_base *base, struct virtio_vq_info *vq);
|
||||
|
||||
/**
|
||||
* @brief Handle PCI configuration space reads.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user