xref: /openbmc/linux/tools/virtio/virtio_test.c (revision 6b27cd84)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
24e53f78eSMichael S. Tsirkin #define _GNU_SOURCE
34e53f78eSMichael S. Tsirkin #include <getopt.h>
4633fae33SEugenio Pérez #include <limits.h>
54e53f78eSMichael S. Tsirkin #include <string.h>
64e53f78eSMichael S. Tsirkin #include <poll.h>
74e53f78eSMichael S. Tsirkin #include <sys/eventfd.h>
84e53f78eSMichael S. Tsirkin #include <stdlib.h>
94e53f78eSMichael S. Tsirkin #include <assert.h>
104e53f78eSMichael S. Tsirkin #include <unistd.h>
114e53f78eSMichael S. Tsirkin #include <sys/ioctl.h>
124e53f78eSMichael S. Tsirkin #include <sys/stat.h>
134e53f78eSMichael S. Tsirkin #include <sys/types.h>
144e53f78eSMichael S. Tsirkin #include <fcntl.h>
1561d0b5a4SRusty Russell #include <stdbool.h>
162d7ce0e8SMichael S. Tsirkin #include <linux/virtio_types.h>
174e53f78eSMichael S. Tsirkin #include <linux/vhost.h>
184e53f78eSMichael S. Tsirkin #include <linux/virtio.h>
194e53f78eSMichael S. Tsirkin #include <linux/virtio_ring.h>
204e53f78eSMichael S. Tsirkin #include "../../drivers/vhost/test.h"
214e53f78eSMichael S. Tsirkin 
227add78b2SEugenio Pérez #define RANDOM_BATCH -1
237add78b2SEugenio Pérez 
2461d0b5a4SRusty Russell /* Unused */
2561d0b5a4SRusty Russell void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
2661d0b5a4SRusty Russell 
274e53f78eSMichael S. Tsirkin struct vq_info {
284e53f78eSMichael S. Tsirkin 	int kick;
294e53f78eSMichael S. Tsirkin 	int call;
304e53f78eSMichael S. Tsirkin 	int num;
314e53f78eSMichael S. Tsirkin 	int idx;
324e53f78eSMichael S. Tsirkin 	void *ring;
334e53f78eSMichael S. Tsirkin 	/* copy used for control */
344e53f78eSMichael S. Tsirkin 	struct vring vring;
354e53f78eSMichael S. Tsirkin 	struct virtqueue *vq;
364e53f78eSMichael S. Tsirkin };
374e53f78eSMichael S. Tsirkin 
384e53f78eSMichael S. Tsirkin struct vdev_info {
394e53f78eSMichael S. Tsirkin 	struct virtio_device vdev;
404e53f78eSMichael S. Tsirkin 	int control;
414e53f78eSMichael S. Tsirkin 	struct pollfd fds[1];
424e53f78eSMichael S. Tsirkin 	struct vq_info vqs[1];
434e53f78eSMichael S. Tsirkin 	int nvqs;
444e53f78eSMichael S. Tsirkin 	void *buf;
454e53f78eSMichael S. Tsirkin 	size_t buf_size;
464e53f78eSMichael S. Tsirkin 	struct vhost_memory *mem;
474e53f78eSMichael S. Tsirkin };
484e53f78eSMichael S. Tsirkin 
49264ee5aaSEugenio Pérez static const struct vhost_vring_file no_backend = { .fd = -1 },
50264ee5aaSEugenio Pérez 				     backend = { .fd = 1 };
511d8bf5c3SEugenio Pérez static const struct vhost_vring_state null_state = {};
52264ee5aaSEugenio Pérez 
vq_notify(struct virtqueue * vq)5346f9c2b9SHeinz Graalfs bool vq_notify(struct virtqueue *vq)
544e53f78eSMichael S. Tsirkin {
554e53f78eSMichael S. Tsirkin 	struct vq_info *info = vq->priv;
564e53f78eSMichael S. Tsirkin 	unsigned long long v = 1;
574e53f78eSMichael S. Tsirkin 	int r;
584e53f78eSMichael S. Tsirkin 	r = write(info->kick, &v, sizeof v);
594e53f78eSMichael S. Tsirkin 	assert(r == sizeof v);
6046f9c2b9SHeinz Graalfs 	return true;
614e53f78eSMichael S. Tsirkin }
624e53f78eSMichael S. Tsirkin 
vq_callback(struct virtqueue * vq)634e53f78eSMichael S. Tsirkin void vq_callback(struct virtqueue *vq)
644e53f78eSMichael S. Tsirkin {
654e53f78eSMichael S. Tsirkin }
664e53f78eSMichael S. Tsirkin 
674e53f78eSMichael S. Tsirkin 
vhost_vq_setup(struct vdev_info * dev,struct vq_info * info)684e53f78eSMichael S. Tsirkin void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
694e53f78eSMichael S. Tsirkin {
704e53f78eSMichael S. Tsirkin 	struct vhost_vring_state state = { .index = info->idx };
714e53f78eSMichael S. Tsirkin 	struct vhost_vring_file file = { .index = info->idx };
72e16e12beSMichael S. Tsirkin 	unsigned long long features = dev->vdev.features;
734e53f78eSMichael S. Tsirkin 	struct vhost_vring_addr addr = {
744e53f78eSMichael S. Tsirkin 		.index = info->idx,
754e53f78eSMichael S. Tsirkin 		.desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
764e53f78eSMichael S. Tsirkin 		.avail_user_addr = (uint64_t)(unsigned long)info->vring.avail,
774e53f78eSMichael S. Tsirkin 		.used_user_addr = (uint64_t)(unsigned long)info->vring.used,
784e53f78eSMichael S. Tsirkin 	};
794e53f78eSMichael S. Tsirkin 	int r;
804e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
814e53f78eSMichael S. Tsirkin 	assert(r >= 0);
824e53f78eSMichael S. Tsirkin 	state.num = info->vring.num;
834e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
844e53f78eSMichael S. Tsirkin 	assert(r >= 0);
854e53f78eSMichael S. Tsirkin 	state.num = 0;
864e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
874e53f78eSMichael S. Tsirkin 	assert(r >= 0);
884e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
894e53f78eSMichael S. Tsirkin 	assert(r >= 0);
904e53f78eSMichael S. Tsirkin 	file.fd = info->kick;
914e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
924e53f78eSMichael S. Tsirkin 	assert(r >= 0);
934e53f78eSMichael S. Tsirkin 	file.fd = info->call;
944e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
954e53f78eSMichael S. Tsirkin 	assert(r >= 0);
964e53f78eSMichael S. Tsirkin }
974e53f78eSMichael S. Tsirkin 
vq_reset(struct vq_info * info,int num,struct virtio_device * vdev)9867412392SEugenio Pérez static void vq_reset(struct vq_info *info, int num, struct virtio_device *vdev)
9967412392SEugenio Pérez {
10067412392SEugenio Pérez 	if (info->vq)
10167412392SEugenio Pérez 		vring_del_virtqueue(info->vq);
10267412392SEugenio Pérez 
10367412392SEugenio Pérez 	memset(info->ring, 0, vring_size(num, 4096));
10467412392SEugenio Pérez 	vring_init(&info->vring, num, info->ring, 4096);
10507d9629dSXuan Zhuo 	info->vq = vring_new_virtqueue(info->idx, num, 4096, vdev, true, false,
10607d9629dSXuan Zhuo 				       info->ring, vq_notify, vq_callback, "test");
10767412392SEugenio Pérez 	assert(info->vq);
10867412392SEugenio Pérez 	info->vq->priv = info;
10967412392SEugenio Pérez }
11067412392SEugenio Pérez 
vq_info_add(struct vdev_info * dev,int num)1114e53f78eSMichael S. Tsirkin static void vq_info_add(struct vdev_info *dev, int num)
1124e53f78eSMichael S. Tsirkin {
1134e53f78eSMichael S. Tsirkin 	struct vq_info *info = &dev->vqs[dev->nvqs];
1144e53f78eSMichael S. Tsirkin 	int r;
1154e53f78eSMichael S. Tsirkin 	info->idx = dev->nvqs;
1164e53f78eSMichael S. Tsirkin 	info->kick = eventfd(0, EFD_NONBLOCK);
1174e53f78eSMichael S. Tsirkin 	info->call = eventfd(0, EFD_NONBLOCK);
1184e53f78eSMichael S. Tsirkin 	r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
1194e53f78eSMichael S. Tsirkin 	assert(r >= 0);
12067412392SEugenio Pérez 	vq_reset(info, num, &dev->vdev);
1214e53f78eSMichael S. Tsirkin 	vhost_vq_setup(dev, info);
1224e53f78eSMichael S. Tsirkin 	dev->fds[info->idx].fd = info->call;
1234e53f78eSMichael S. Tsirkin 	dev->fds[info->idx].events = POLLIN;
1244e53f78eSMichael S. Tsirkin 	dev->nvqs++;
1254e53f78eSMichael S. Tsirkin }
1264e53f78eSMichael S. Tsirkin 
vdev_info_init(struct vdev_info * dev,unsigned long long features)1274e53f78eSMichael S. Tsirkin static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
1284e53f78eSMichael S. Tsirkin {
1294e53f78eSMichael S. Tsirkin 	int r;
1304e53f78eSMichael S. Tsirkin 	memset(dev, 0, sizeof *dev);
131e16e12beSMichael S. Tsirkin 	dev->vdev.features = features;
132cb91909eSEugenio Pérez 	INIT_LIST_HEAD(&dev->vdev.vqs);
13332f1b53fSStefano Garzarella 	spin_lock_init(&dev->vdev.vqs_list_lock);
1344e53f78eSMichael S. Tsirkin 	dev->buf_size = 1024;
1354e53f78eSMichael S. Tsirkin 	dev->buf = malloc(dev->buf_size);
1364e53f78eSMichael S. Tsirkin 	assert(dev->buf);
1374e53f78eSMichael S. Tsirkin 	dev->control = open("/dev/vhost-test", O_RDWR);
1384e53f78eSMichael S. Tsirkin 	assert(dev->control >= 0);
1394e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
1404e53f78eSMichael S. Tsirkin 	assert(r >= 0);
1414e53f78eSMichael S. Tsirkin 	dev->mem = malloc(offsetof(struct vhost_memory, regions) +
1424e53f78eSMichael S. Tsirkin 			  sizeof dev->mem->regions[0]);
1434e53f78eSMichael S. Tsirkin 	assert(dev->mem);
1444e53f78eSMichael S. Tsirkin 	memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
1454e53f78eSMichael S. Tsirkin                           sizeof dev->mem->regions[0]);
1464e53f78eSMichael S. Tsirkin 	dev->mem->nregions = 1;
1474e53f78eSMichael S. Tsirkin 	dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
1484e53f78eSMichael S. Tsirkin 	dev->mem->regions[0].userspace_addr = (long)dev->buf;
1494e53f78eSMichael S. Tsirkin 	dev->mem->regions[0].memory_size = dev->buf_size;
1504e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
1514e53f78eSMichael S. Tsirkin 	assert(r >= 0);
1524e53f78eSMichael S. Tsirkin }
1534e53f78eSMichael S. Tsirkin 
1544e53f78eSMichael S. Tsirkin /* TODO: this is pretty bad: we get a cache line bounce
1554e53f78eSMichael S. Tsirkin  * for the wait queue on poll and another one on read,
1564e53f78eSMichael S. Tsirkin  * plus the read which is there just to clear the
1574e53f78eSMichael S. Tsirkin  * current state. */
wait_for_interrupt(struct vdev_info * dev)1584e53f78eSMichael S. Tsirkin static void wait_for_interrupt(struct vdev_info *dev)
1594e53f78eSMichael S. Tsirkin {
1604e53f78eSMichael S. Tsirkin 	int i;
1614e53f78eSMichael S. Tsirkin 	unsigned long long val;
1624e53f78eSMichael S. Tsirkin 	poll(dev->fds, dev->nvqs, -1);
1634e53f78eSMichael S. Tsirkin 	for (i = 0; i < dev->nvqs; ++i)
1644e53f78eSMichael S. Tsirkin 		if (dev->fds[i].revents & POLLIN) {
1654e53f78eSMichael S. Tsirkin 			read(dev->fds[i].fd, &val, sizeof val);
1664e53f78eSMichael S. Tsirkin 		}
1674e53f78eSMichael S. Tsirkin }
1684e53f78eSMichael S. Tsirkin 
run_test(struct vdev_info * dev,struct vq_info * vq,bool delayed,int batch,int reset_n,int bufs)16964d09888SMichael S. Tsirkin static void run_test(struct vdev_info *dev, struct vq_info *vq,
170264ee5aaSEugenio Pérez 		     bool delayed, int batch, int reset_n, int bufs)
1714e53f78eSMichael S. Tsirkin {
1724e53f78eSMichael S. Tsirkin 	struct scatterlist sl;
173264ee5aaSEugenio Pérez 	long started = 0, completed = 0, next_reset = reset_n;
174633fae33SEugenio Pérez 	long completed_before, started_before;
1754e53f78eSMichael S. Tsirkin 	int r, test = 1;
176a4722f64Swangjianli 	unsigned int len;
1774e53f78eSMichael S. Tsirkin 	long long spurious = 0;
1787add78b2SEugenio Pérez 	const bool random_batch = batch == RANDOM_BATCH;
1791d8bf5c3SEugenio Pérez 
1804e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_TEST_RUN, &test);
1814e53f78eSMichael S. Tsirkin 	assert(r >= 0);
1821d8bf5c3SEugenio Pérez 	if (!reset_n) {
1831d8bf5c3SEugenio Pérez 		next_reset = INT_MAX;
1841d8bf5c3SEugenio Pérez 	}
1851d8bf5c3SEugenio Pérez 
1864e53f78eSMichael S. Tsirkin 	for (;;) {
1874e53f78eSMichael S. Tsirkin 		virtqueue_disable_cb(vq->vq);
1884e53f78eSMichael S. Tsirkin 		completed_before = completed;
189633fae33SEugenio Pérez 		started_before = started;
1904e53f78eSMichael S. Tsirkin 		do {
1911d8bf5c3SEugenio Pérez 			const bool reset = completed > next_reset;
1927add78b2SEugenio Pérez 			if (random_batch)
1937add78b2SEugenio Pérez 				batch = (random() % vq->vring.num) + 1;
1947add78b2SEugenio Pérez 
195633fae33SEugenio Pérez 			while (started < bufs &&
196633fae33SEugenio Pérez 			       (started - completed) < batch) {
1974e53f78eSMichael S. Tsirkin 				sg_init_one(&sl, dev->buf, dev->buf_size);
198cf994e0aSRusty Russell 				r = virtqueue_add_outbuf(vq->vq, &sl, 1,
199f96fde41SRusty Russell 							 dev->buf + started,
200f96fde41SRusty Russell 							 GFP_ATOMIC);
201633fae33SEugenio Pérez 				if (unlikely(r != 0)) {
202633fae33SEugenio Pérez 					if (r == -ENOSPC &&
203633fae33SEugenio Pérez 					    started > started_before)
204633fae33SEugenio Pérez 						r = 0;
205633fae33SEugenio Pérez 					else
20653c18c99SHeinz Graalfs 						r = -1;
207633fae33SEugenio Pérez 					break;
2084e53f78eSMichael S. Tsirkin 				}
209633fae33SEugenio Pérez 
210633fae33SEugenio Pérez 				++started;
211633fae33SEugenio Pérez 
212633fae33SEugenio Pérez 				if (unlikely(!virtqueue_kick(vq->vq))) {
213633fae33SEugenio Pérez 					r = -1;
214633fae33SEugenio Pérez 					break;
215633fae33SEugenio Pérez 				}
216633fae33SEugenio Pérez 			}
217633fae33SEugenio Pérez 
218633fae33SEugenio Pérez 			if (started >= bufs)
2194e53f78eSMichael S. Tsirkin 				r = -1;
2204e53f78eSMichael S. Tsirkin 
221264ee5aaSEugenio Pérez 			if (reset) {
222264ee5aaSEugenio Pérez 				r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
223264ee5aaSEugenio Pérez 					  &no_backend);
224264ee5aaSEugenio Pérez 				assert(!r);
225264ee5aaSEugenio Pérez 			}
226264ee5aaSEugenio Pérez 
2274e53f78eSMichael S. Tsirkin 			/* Flush out completed bufs if any */
228633fae33SEugenio Pérez 			while (virtqueue_get_buf(vq->vq, &len)) {
2294e53f78eSMichael S. Tsirkin 				++completed;
2304e53f78eSMichael S. Tsirkin 				r = 0;
2314e53f78eSMichael S. Tsirkin 			}
2324e53f78eSMichael S. Tsirkin 
233264ee5aaSEugenio Pérez 			if (reset) {
2341d8bf5c3SEugenio Pérez 				struct vhost_vring_state s = { .index = 0 };
2351d8bf5c3SEugenio Pérez 
2361d8bf5c3SEugenio Pérez 				vq_reset(vq, vq->vring.num, &dev->vdev);
2371d8bf5c3SEugenio Pérez 
2381d8bf5c3SEugenio Pérez 				r = ioctl(dev->control, VHOST_GET_VRING_BASE,
2391d8bf5c3SEugenio Pérez 					  &s);
2401d8bf5c3SEugenio Pérez 				assert(!r);
2411d8bf5c3SEugenio Pérez 
2421d8bf5c3SEugenio Pérez 				s.num = 0;
2431d8bf5c3SEugenio Pérez 				r = ioctl(dev->control, VHOST_SET_VRING_BASE,
2441d8bf5c3SEugenio Pérez 					  &null_state);
2451d8bf5c3SEugenio Pérez 				assert(!r);
2461d8bf5c3SEugenio Pérez 
247264ee5aaSEugenio Pérez 				r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
248264ee5aaSEugenio Pérez 					  &backend);
249264ee5aaSEugenio Pérez 				assert(!r);
250264ee5aaSEugenio Pérez 
2511d8bf5c3SEugenio Pérez 				started = completed;
252264ee5aaSEugenio Pérez 				while (completed > next_reset)
253264ee5aaSEugenio Pérez 					next_reset += completed;
254264ee5aaSEugenio Pérez 			}
255de929b04SRusty Russell 		} while (r == 0);
256633fae33SEugenio Pérez 		if (completed == completed_before && started == started_before)
2574e53f78eSMichael S. Tsirkin 			++spurious;
2584e53f78eSMichael S. Tsirkin 		assert(completed <= bufs);
2594e53f78eSMichael S. Tsirkin 		assert(started <= bufs);
2604e53f78eSMichael S. Tsirkin 		if (completed == bufs)
2614e53f78eSMichael S. Tsirkin 			break;
26264d09888SMichael S. Tsirkin 		if (delayed) {
26364d09888SMichael S. Tsirkin 			if (virtqueue_enable_cb_delayed(vq->vq))
26464d09888SMichael S. Tsirkin 				wait_for_interrupt(dev);
26564d09888SMichael S. Tsirkin 		} else {
26664d09888SMichael S. Tsirkin 			if (virtqueue_enable_cb(vq->vq))
2674e53f78eSMichael S. Tsirkin 				wait_for_interrupt(dev);
2684e53f78eSMichael S. Tsirkin 		}
2694e53f78eSMichael S. Tsirkin 	}
2704e53f78eSMichael S. Tsirkin 	test = 0;
2714e53f78eSMichael S. Tsirkin 	r = ioctl(dev->control, VHOST_TEST_RUN, &test);
2724e53f78eSMichael S. Tsirkin 	assert(r >= 0);
2731d8bf5c3SEugenio Pérez 	fprintf(stderr,
2741d8bf5c3SEugenio Pérez 		"spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n",
2751d8bf5c3SEugenio Pérez 		spurious, started, completed);
2764e53f78eSMichael S. Tsirkin }
2774e53f78eSMichael S. Tsirkin 
2784e53f78eSMichael S. Tsirkin const char optstring[] = "h";
2794e53f78eSMichael S. Tsirkin const struct option longopts[] = {
2804e53f78eSMichael S. Tsirkin 	{
2814e53f78eSMichael S. Tsirkin 		.name = "help",
2824e53f78eSMichael S. Tsirkin 		.val = 'h',
2834e53f78eSMichael S. Tsirkin 	},
2844e53f78eSMichael S. Tsirkin 	{
2854423fe40SMichael S. Tsirkin 		.name = "event-idx",
2864423fe40SMichael S. Tsirkin 		.val = 'E',
2874423fe40SMichael S. Tsirkin 	},
2884423fe40SMichael S. Tsirkin 	{
2894423fe40SMichael S. Tsirkin 		.name = "no-event-idx",
2904423fe40SMichael S. Tsirkin 		.val = 'e',
2914423fe40SMichael S. Tsirkin 	},
2924423fe40SMichael S. Tsirkin 	{
2934e53f78eSMichael S. Tsirkin 		.name = "indirect",
2944e53f78eSMichael S. Tsirkin 		.val = 'I',
2954e53f78eSMichael S. Tsirkin 	},
2964e53f78eSMichael S. Tsirkin 	{
2974e53f78eSMichael S. Tsirkin 		.name = "no-indirect",
2984e53f78eSMichael S. Tsirkin 		.val = 'i',
2994e53f78eSMichael S. Tsirkin 	},
3004e53f78eSMichael S. Tsirkin 	{
30143b09122SMichael S. Tsirkin 		.name = "virtio-1",
30243b09122SMichael S. Tsirkin 		.val = '1',
30343b09122SMichael S. Tsirkin 	},
30443b09122SMichael S. Tsirkin 	{
30543b09122SMichael S. Tsirkin 		.name = "no-virtio-1",
30643b09122SMichael S. Tsirkin 		.val = '0',
30743b09122SMichael S. Tsirkin 	},
30843b09122SMichael S. Tsirkin 	{
30964d09888SMichael S. Tsirkin 		.name = "delayed-interrupt",
31064d09888SMichael S. Tsirkin 		.val = 'D',
31164d09888SMichael S. Tsirkin 	},
31264d09888SMichael S. Tsirkin 	{
31364d09888SMichael S. Tsirkin 		.name = "no-delayed-interrupt",
31464d09888SMichael S. Tsirkin 		.val = 'd',
31564d09888SMichael S. Tsirkin 	},
31664d09888SMichael S. Tsirkin 	{
317633fae33SEugenio Pérez 		.name = "batch",
318633fae33SEugenio Pérez 		.val = 'b',
319633fae33SEugenio Pérez 		.has_arg = required_argument,
320633fae33SEugenio Pérez 	},
321633fae33SEugenio Pérez 	{
322264ee5aaSEugenio Pérez 		.name = "reset",
323264ee5aaSEugenio Pérez 		.val = 'r',
324264ee5aaSEugenio Pérez 		.has_arg = optional_argument,
325264ee5aaSEugenio Pérez 	},
326264ee5aaSEugenio Pérez 	{
3274e53f78eSMichael S. Tsirkin 	}
3284e53f78eSMichael S. Tsirkin };
3294e53f78eSMichael S. Tsirkin 
help(int status)330*6b27cd84SRong Tao static void help(int status)
3314e53f78eSMichael S. Tsirkin {
3324423fe40SMichael S. Tsirkin 	fprintf(stderr, "Usage: virtio_test [--help]"
3334423fe40SMichael S. Tsirkin 		" [--no-indirect]"
3344423fe40SMichael S. Tsirkin 		" [--no-event-idx]"
33543b09122SMichael S. Tsirkin 		" [--no-virtio-1]"
33664d09888SMichael S. Tsirkin 		" [--delayed-interrupt]"
3377add78b2SEugenio Pérez 		" [--batch=random/N]"
338264ee5aaSEugenio Pérez 		" [--reset=N]"
3394423fe40SMichael S. Tsirkin 		"\n");
340*6b27cd84SRong Tao 
341*6b27cd84SRong Tao 	exit(status);
3424e53f78eSMichael S. Tsirkin }
3434e53f78eSMichael S. Tsirkin 
main(int argc,char ** argv)3444e53f78eSMichael S. Tsirkin int main(int argc, char **argv)
3454e53f78eSMichael S. Tsirkin {
3464e53f78eSMichael S. Tsirkin 	struct vdev_info dev;
3474423fe40SMichael S. Tsirkin 	unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
34843b09122SMichael S. Tsirkin 		(1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1);
349264ee5aaSEugenio Pérez 	long batch = 1, reset = 0;
3504e53f78eSMichael S. Tsirkin 	int o;
35164d09888SMichael S. Tsirkin 	bool delayed = false;
3524e53f78eSMichael S. Tsirkin 
3534e53f78eSMichael S. Tsirkin 	for (;;) {
3544e53f78eSMichael S. Tsirkin 		o = getopt_long(argc, argv, optstring, longopts, NULL);
3554e53f78eSMichael S. Tsirkin 		switch (o) {
3564e53f78eSMichael S. Tsirkin 		case -1:
3574e53f78eSMichael S. Tsirkin 			goto done;
3584e53f78eSMichael S. Tsirkin 		case '?':
359*6b27cd84SRong Tao 			help(2);
3604423fe40SMichael S. Tsirkin 		case 'e':
3614423fe40SMichael S. Tsirkin 			features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX);
3624423fe40SMichael S. Tsirkin 			break;
3634e53f78eSMichael S. Tsirkin 		case 'h':
364*6b27cd84SRong Tao 			help(0);
3654e53f78eSMichael S. Tsirkin 		case 'i':
3664e53f78eSMichael S. Tsirkin 			features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
3674e53f78eSMichael S. Tsirkin 			break;
36843b09122SMichael S. Tsirkin 		case '0':
36943b09122SMichael S. Tsirkin 			features &= ~(1ULL << VIRTIO_F_VERSION_1);
37043b09122SMichael S. Tsirkin 			break;
37164d09888SMichael S. Tsirkin 		case 'D':
37264d09888SMichael S. Tsirkin 			delayed = true;
37364d09888SMichael S. Tsirkin 			break;
374633fae33SEugenio Pérez 		case 'b':
3757add78b2SEugenio Pérez 			if (0 == strcmp(optarg, "random")) {
3767add78b2SEugenio Pérez 				batch = RANDOM_BATCH;
3777add78b2SEugenio Pérez 			} else {
378633fae33SEugenio Pérez 				batch = strtol(optarg, NULL, 10);
379633fae33SEugenio Pérez 				assert(batch > 0);
380633fae33SEugenio Pérez 				assert(batch < (long)INT_MAX + 1);
3817add78b2SEugenio Pérez 			}
382633fae33SEugenio Pérez 			break;
383264ee5aaSEugenio Pérez 		case 'r':
384264ee5aaSEugenio Pérez 			if (!optarg) {
385264ee5aaSEugenio Pérez 				reset = 1;
386264ee5aaSEugenio Pérez 			} else {
387264ee5aaSEugenio Pérez 				reset = strtol(optarg, NULL, 10);
388264ee5aaSEugenio Pérez 				assert(reset > 0);
389264ee5aaSEugenio Pérez 				assert(reset < (long)INT_MAX + 1);
390264ee5aaSEugenio Pérez 			}
391264ee5aaSEugenio Pérez 			break;
3924e53f78eSMichael S. Tsirkin 		default:
3934e53f78eSMichael S. Tsirkin 			assert(0);
3944e53f78eSMichael S. Tsirkin 			break;
3954e53f78eSMichael S. Tsirkin 		}
3964e53f78eSMichael S. Tsirkin 	}
3974e53f78eSMichael S. Tsirkin 
3984e53f78eSMichael S. Tsirkin done:
3994e53f78eSMichael S. Tsirkin 	vdev_info_init(&dev, features);
4004e53f78eSMichael S. Tsirkin 	vq_info_add(&dev, 256);
401264ee5aaSEugenio Pérez 	run_test(&dev, &dev.vqs[0], delayed, batch, reset, 0x100000);
4024e53f78eSMichael S. Tsirkin 	return 0;
4034e53f78eSMichael S. Tsirkin }
404