Skip to content

Commit b261e74

Browse files
ssqrewenlingz
authored andcommitted
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>
1 parent 7cc8566 commit b261e74

File tree

15 files changed

+220
-38
lines changed

15 files changed

+220
-38
lines changed

devicemodel/core/main.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#include "vmcfg_config.h"
6666
#include "vmcfg.h"
6767
#include "tpm.h"
68+
#include "virtio.h"
6869

6970
#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */
7071

@@ -703,6 +704,7 @@ enum {
703704
CMD_OPT_VSBL = 1000,
704705
CMD_OPT_PART_INFO,
705706
CMD_OPT_TRUSTY_ENABLE,
707+
CMD_OPT_VIRTIO_POLL_ENABLE,
706708
CMD_OPT_PTDEV_NO_RESET,
707709
CMD_OPT_DEBUGEXIT,
708710
CMD_OPT_VMCFG,
@@ -739,6 +741,7 @@ static struct option long_options[] = {
739741
{"part_info", required_argument, 0, CMD_OPT_PART_INFO},
740742
{"enable_trusty", no_argument, 0,
741743
CMD_OPT_TRUSTY_ENABLE},
744+
{"virtio_poll", required_argument, 0, CMD_OPT_VIRTIO_POLL_ENABLE},
742745
{"ptdev_no_reset", no_argument, 0,
743746
CMD_OPT_PTDEV_NO_RESET},
744747
{"debugexit", no_argument, 0, CMD_OPT_DEBUGEXIT},
@@ -862,6 +865,14 @@ dm_run(int argc, char *argv[])
862865
case CMD_OPT_TRUSTY_ENABLE:
863866
trusty_enabled = 1;
864867
break;
868+
case CMD_OPT_VIRTIO_POLL_ENABLE:
869+
if (acrn_parse_virtio_poll_interval(optarg) != 0) {
870+
errx(EX_USAGE,
871+
"invalid virtio poll interval %s",
872+
optarg);
873+
exit(1);
874+
}
875+
break;
865876
case CMD_OPT_PTDEV_NO_RESET:
866877
ptdev_no_reset(true);
867878
break;

devicemodel/hw/pci/virtio/virtio.c

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@
2828
#include <stdio.h>
2929
#include <stddef.h>
3030
#include <pthread.h>
31+
#include <string.h>
32+
#include <stdlib.h>
3133

3234
#include "dm.h"
3335
#include "pci_core.h"
3436
#include "virtio.h"
37+
#include "timer.h"
3538

3639
/*
3740
* Functions for dealing with generalized "virtual devices" as
@@ -45,6 +48,61 @@
4548
*/
4649
#define DEV_STRUCT(vs) ((void *)(vs))
4750

51+
static uint8_t virtio_poll_enabled;
52+
static size_t virtio_poll_interval;
53+
54+
static void
55+
virtio_start_timer(struct acrn_timer *timer, time_t sec, time_t nsec)
56+
{
57+
struct itimerspec ts;
58+
59+
/* setting the interval time */
60+
ts.it_interval.tv_sec = 0;
61+
ts.it_interval.tv_nsec = 0;
62+
/* set the delay time it will be started when timer_setting */
63+
ts.it_value.tv_sec = sec;
64+
ts.it_value.tv_nsec = nsec;
65+
assert(acrn_timer_settime(timer, &ts) == 0);
66+
}
67+
68+
static void
69+
virtio_poll_timer(void *arg)
70+
{
71+
struct virtio_base *base;
72+
struct virtio_ops *vops;
73+
struct virtio_vq_info *vq;
74+
const char *name;
75+
int i;
76+
77+
base = arg;
78+
vops = base->vops;
79+
name = vops->name;
80+
81+
if (base->mtx)
82+
pthread_mutex_lock(base->mtx);
83+
84+
base->polling_in_progress = 1;
85+
86+
for (i = 0; i < base->vops->nvq; i++) {
87+
vq = &base->queues[i];
88+
vq->used->flags |= ACRN_VRING_USED_F_NO_NOTIFY;
89+
/* TODO: call notify when necessary */
90+
if (vq->notify)
91+
(*vq->notify)(DEV_STRUCT(base), vq);
92+
else if (vops->qnotify)
93+
(*vops->qnotify)(DEV_STRUCT(base), vq);
94+
else
95+
fprintf(stderr,
96+
"%s: qnotify queue %d: missing vq/vops notify\r\n",
97+
name, i);
98+
}
99+
100+
if (base->mtx)
101+
pthread_mutex_unlock(base->mtx);
102+
103+
virtio_start_timer(&base->polling_timer, 0, virtio_poll_interval);
104+
}
105+
48106
/**
49107
* @brief Link a virtio_base to its constants, the virtio device,
50108
* and the PCI emulation.
@@ -60,7 +118,8 @@
60118
void
61119
virtio_linkup(struct virtio_base *base, struct virtio_ops *vops,
62120
void *pci_virtio_dev, struct pci_vdev *dev,
63-
struct virtio_vq_info *queues)
121+
struct virtio_vq_info *queues,
122+
int backend_type)
64123
{
65124
int i;
66125

@@ -69,6 +128,7 @@ virtio_linkup(struct virtio_base *base, struct virtio_ops *vops,
69128
base->vops = vops;
70129
base->dev = dev;
71130
dev->arg = base;
131+
base->backend_type = backend_type;
72132

73133
base->queues = queues;
74134
for (i = 0; i < vops->nvq; i++) {
@@ -100,6 +160,9 @@ virtio_reset_dev(struct virtio_base *base)
100160
/* if (base->mtx) */
101161
/* assert(pthread_mutex_isowned_np(base->mtx)); */
102162

163+
acrn_timer_deinit(&base->polling_timer);
164+
base->polling_in_progress = 0;
165+
103166
nvq = base->vops->nvq;
104167
for (vq = base->queues, i = 0; i < nvq; vq++, i++) {
105168
vq->flags = 0;
@@ -570,6 +633,30 @@ vq_endchains(struct virtio_vq_info *vq, int used_all_avail)
570633
vq_interrupt(base, vq);
571634
}
572635

636+
/**
637+
* @brief Helper function for clearing used ring flags.
638+
*
639+
* Driver should always use this helper function to clear used ring flags.
640+
* For virtio poll mode, in order to avoid trap, we should never really
641+
* clear used ring flags.
642+
*
643+
* @param base Pointer to struct virtio_base.
644+
* @param vq Pointer to struct virtio_vq_info.
645+
*
646+
* @return None
647+
*/
648+
void vq_clear_used_ring_flags(struct virtio_base *base, struct virtio_vq_info *vq)
649+
{
650+
int backend_type = base->backend_type;
651+
int polling_in_progress = base->polling_in_progress;
652+
653+
/* we should never unmask notification in polling mode */
654+
if (virtio_poll_enabled && backend_type == BACKEND_VBSU && polling_in_progress == 1)
655+
return;
656+
657+
vq->used->flags &= ~ACRN_VRING_USED_F_NO_NOTIFY;
658+
}
659+
573660
struct config_reg {
574661
uint16_t offset; /* register offset */
575662
uint8_t size; /* size (bytes) */
@@ -877,6 +964,17 @@ virtio_pci_legacy_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
877964
(*vops->set_status)(DEV_STRUCT(base), value);
878965
if (value == 0)
879966
(*vops->reset)(DEV_STRUCT(base));
967+
if ((value & VIRTIO_CR_STATUS_DRIVER_OK) &&
968+
base->backend_type == BACKEND_VBSU &&
969+
virtio_poll_enabled) {
970+
base->polling_timer.clockid = CLOCK_MONOTONIC;
971+
acrn_timer_init(&base->polling_timer, virtio_poll_timer, base);
972+
/* wait 5s to start virtio poll mode
973+
* skip vsbl and make sure device initialization completed
974+
* FIXME: Need optimization in the future
975+
*/
976+
virtio_start_timer(&base->polling_timer, 5, 0);
977+
}
880978
break;
881979
case VIRTIO_CR_CFGVEC:
882980
base->msix_cfg_idx = value;
@@ -1302,6 +1400,7 @@ virtio_common_cfg_write(struct pci_vdev *dev, uint64_t offset, int size,
13021400
(*vops->set_status)(DEV_STRUCT(base), value);
13031401
if (base->status == 0)
13041402
(*vops->reset)(DEV_STRUCT(base));
1403+
/* TODO: virtio poll mode for modern devices */
13051404
break;
13061405
case VIRTIO_COMMON_Q_SELECT:
13071406
/*
@@ -1878,3 +1977,26 @@ virtio_pci_modern_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
18781977

18791978
return -1;
18801979
}
1980+
1981+
/**
1982+
* @brief Get the virtio poll parameters
1983+
*
1984+
* @param optarg Pointer to parameters string.
1985+
*
1986+
* @return fail -1 success 0
1987+
*/
1988+
int
1989+
acrn_parse_virtio_poll_interval(const char *optarg)
1990+
{
1991+
char *ptr;
1992+
1993+
virtio_poll_interval = strtoul(optarg, &ptr, 0);
1994+
1995+
/* poll interval is limited from 1us to 10ms */
1996+
if (virtio_poll_interval < 1 || virtio_poll_interval > 10000000)
1997+
return -1;
1998+
1999+
virtio_poll_enabled = 1;
2000+
2001+
return 0;
2002+
}

devicemodel/hw/pci/virtio/virtio_audio.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ virtio_audio_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
316316
&virtio_audio_ops_k,
317317
virt_audio,
318318
dev,
319-
virt_audio->vq);
319+
virt_audio->vq,
320+
BACKEND_VBSK);
320321

321322
rc = virtio_audio_kernel_init(virt_audio);
322323
if (rc < 0) {

devicemodel/hw/pci/virtio/virtio_block.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ virtio_blk_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
384384
"error %d!\n", rc));
385385

386386
/* init virtio struct and virtqueues */
387-
virtio_linkup(&blk->base, &virtio_blk_ops, blk, dev, &blk->vq);
387+
virtio_linkup(&blk->base, &virtio_blk_ops, blk, dev, &blk->vq, BACKEND_VBSU);
388388
blk->base.mtx = &blk->mtx;
389389

390390
blk->vq.qsize = VIRTIO_BLK_RINGSZ;

devicemodel/hw/pci/virtio/virtio_console.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,7 @@ virtio_console_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
828828
"error %d!\n", rc));
829829

830830
virtio_linkup(&console->base, &virtio_console_ops, console, dev,
831-
console->queues);
831+
console->queues, BACKEND_VBSU);
832832
console->base.mtx = &console->mtx;
833833
console->base.device_caps = VIRTIO_CONSOLE_S_HOSTCAPS;
834834

devicemodel/hw/pci/virtio/virtio_coreu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ virtio_coreu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
281281

282282
DPRINTF(("vcoreu init: using VBS-U...\n"));
283283
virtio_linkup(&vcoreu->base, &virtio_coreu_ops,
284-
vcoreu, dev, vcoreu->queues);
284+
vcoreu, dev, vcoreu->queues, BACKEND_VBSU);
285285
vcoreu->base.mtx = &vcoreu->mtx;
286286

287287
vcoreu->queues[0].qsize = VIRTIO_COREU_RINGSZ;

devicemodel/hw/pci/virtio/virtio_hdcp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ virtio_hdcp_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
413413

414414
DPRINTF(("vhdcp init: using VBS-U...\n"));
415415
virtio_linkup(&vhdcp->base, &virtio_hdcp_ops,
416-
vhdcp, dev, vhdcp->queues);
416+
vhdcp, dev, vhdcp->queues, BACKEND_VBSU);
417417
vhdcp->base.mtx = &vhdcp->mtx;
418418

419419
vhdcp->queues[0].qsize = VIRTIO_HDCP_RINGSZ;

devicemodel/hw/pci/virtio/virtio_hyper_dmabuf.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ virtio_hyper_dmabuf_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
299299
&virtio_hyper_dmabuf_ops_k,
300300
hyper_dmabuf,
301301
dev,
302-
hyper_dmabuf->vq);
302+
hyper_dmabuf->vq,
303+
BACKEND_VBSK);
303304

304305
rc = virtio_hyper_dmabuf_k_init();
305306
if (rc < 0) {

devicemodel/hw/pci/virtio/virtio_input.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ virtio_input_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
640640
goto fail;
641641
}
642642

643-
virtio_linkup(&vi->base, &virtio_input_ops, vi, dev, vi->queues);
643+
virtio_linkup(&vi->base, &virtio_input_ops, vi, dev, vi->queues, BACKEND_VBSU);
644644
vi->base.mtx = &vi->mtx;
645645
vi->base.device_caps = VIRTIO_INPUT_S_HOSTCAPS;
646646

devicemodel/hw/pci/virtio/virtio_ipu.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,8 @@ virtio_ipu_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
320320
&virtio_ipu_ops_k,
321321
ipu,
322322
dev,
323-
ipu->vq);
323+
ipu->vq,
324+
BACKEND_VBSK);
324325

325326
rc = virtio_ipu_k_init(ipu);
326327
if (rc < 0) {

0 commit comments

Comments
 (0)