Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) #define _GNU_SOURCE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) #include <getopt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) #include <limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) #include <poll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #include <sys/eventfd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <assert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <sys/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <stdbool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/virtio_types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/vhost.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/virtio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/virtio_ring.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include "../../drivers/vhost/test.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #define RANDOM_BATCH -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) /* Unused */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) struct vq_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	int kick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	int call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	int num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	void *ring;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	/* copy used for control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	struct vring vring;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	struct virtqueue *vq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) struct vdev_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct virtio_device vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	int control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	struct pollfd fds[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	struct vq_info vqs[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	int nvqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	void *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	size_t buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	struct vhost_memory *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) static const struct vhost_vring_file no_backend = { .fd = -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 				     backend = { .fd = 1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) static const struct vhost_vring_state null_state = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) bool vq_notify(struct virtqueue *vq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	struct vq_info *info = vq->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	unsigned long long v = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	r = write(info->kick, &v, sizeof v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	assert(r == sizeof v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) void vq_callback(struct virtqueue *vq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	struct vhost_vring_state state = { .index = info->idx };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	struct vhost_vring_file file = { .index = info->idx };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	unsigned long long features = dev->vdev.features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	struct vhost_vring_addr addr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		.index = info->idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 		.desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		.avail_user_addr = (uint64_t)(unsigned long)info->vring.avail,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		.used_user_addr = (uint64_t)(unsigned long)info->vring.used,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	state.num = info->vring.num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	state.num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	file.fd = info->kick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	file.fd = info->call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) static void vq_reset(struct vq_info *info, int num, struct virtio_device *vdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	if (info->vq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		vring_del_virtqueue(info->vq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	memset(info->ring, 0, vring_size(num, 4096));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	vring_init(&info->vring, num, info->ring, 4096);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	info->vq = __vring_new_virtqueue(info->idx, info->vring, vdev, true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 					 false, vq_notify, vq_callback, "test");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	assert(info->vq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	info->vq->priv = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static void vq_info_add(struct vdev_info *dev, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	struct vq_info *info = &dev->vqs[dev->nvqs];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	info->idx = dev->nvqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	info->kick = eventfd(0, EFD_NONBLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	info->call = eventfd(0, EFD_NONBLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	vq_reset(info, num, &dev->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	vhost_vq_setup(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	dev->fds[info->idx].fd = info->call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	dev->fds[info->idx].events = POLLIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	dev->nvqs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	memset(dev, 0, sizeof *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	dev->vdev.features = features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	INIT_LIST_HEAD(&dev->vdev.vqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	spin_lock_init(&dev->vdev.vqs_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	dev->buf_size = 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	dev->buf = malloc(dev->buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	assert(dev->buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)         dev->control = open("/dev/vhost-test", O_RDWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	assert(dev->control >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	dev->mem = malloc(offsetof(struct vhost_memory, regions) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 			  sizeof dev->mem->regions[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	assert(dev->mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)                           sizeof dev->mem->regions[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	dev->mem->nregions = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	dev->mem->regions[0].userspace_addr = (long)dev->buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	dev->mem->regions[0].memory_size = dev->buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* TODO: this is pretty bad: we get a cache line bounce
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)  * for the wait queue on poll and another one on read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)  * plus the read which is there just to clear the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)  * current state. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static void wait_for_interrupt(struct vdev_info *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	unsigned long long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	poll(dev->fds, dev->nvqs, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	for (i = 0; i < dev->nvqs; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		if (dev->fds[i].revents & POLLIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 			read(dev->fds[i].fd, &val, sizeof val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static void run_test(struct vdev_info *dev, struct vq_info *vq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		     bool delayed, int batch, int reset_n, int bufs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	struct scatterlist sl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	long started = 0, completed = 0, next_reset = reset_n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	long completed_before, started_before;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	int r, test = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	unsigned len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	long long spurious = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	const bool random_batch = batch == RANDOM_BATCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	r = ioctl(dev->control, VHOST_TEST_RUN, &test);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	if (!reset_n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		next_reset = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		virtqueue_disable_cb(vq->vq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		completed_before = completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		started_before = started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 			const bool reset = completed > next_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 			if (random_batch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 				batch = (random() % vq->vring.num) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 			while (started < bufs &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 			       (started - completed) < batch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 				sg_init_one(&sl, dev->buf, dev->buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 				r = virtqueue_add_outbuf(vq->vq, &sl, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 							 dev->buf + started,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 							 GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 				if (unlikely(r != 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 					if (r == -ENOSPC &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 					    started > started_before)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 						r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 					else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 						r = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 					break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 				++started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 				if (unlikely(!virtqueue_kick(vq->vq))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 					r = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 					break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 			if (started >= bufs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 				r = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 			if (reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 				r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 					  &no_backend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 				assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 			/* Flush out completed bufs if any */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 			while (virtqueue_get_buf(vq->vq, &len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 				++completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 				r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 			if (reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 				struct vhost_vring_state s = { .index = 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 				vq_reset(vq, vq->vring.num, &dev->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 				r = ioctl(dev->control, VHOST_GET_VRING_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 					  &s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 				assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 				s.num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 				r = ioctl(dev->control, VHOST_SET_VRING_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 					  &null_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 				assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 				r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 					  &backend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 				assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 				started = completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 				while (completed > next_reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 					next_reset += completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		} while (r == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		if (completed == completed_before && started == started_before)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 			++spurious;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 		assert(completed <= bufs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		assert(started <= bufs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 		if (completed == bufs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 		if (delayed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 			if (virtqueue_enable_cb_delayed(vq->vq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 				wait_for_interrupt(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 			if (virtqueue_enable_cb(vq->vq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 				wait_for_interrupt(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	test = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	r = ioctl(dev->control, VHOST_TEST_RUN, &test);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	fprintf(stderr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		"spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 		spurious, started, completed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) const char optstring[] = "h";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) const struct option longopts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		.name = "help",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		.val = 'h',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		.name = "event-idx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		.val = 'E',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 		.name = "no-event-idx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		.val = 'e',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 		.name = "indirect",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		.val = 'I',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		.name = "no-indirect",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		.val = 'i',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 		.name = "virtio-1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 		.val = '1',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 		.name = "no-virtio-1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 		.val = '0',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		.name = "delayed-interrupt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		.val = 'D',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 		.name = "no-delayed-interrupt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		.val = 'd',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		.name = "batch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		.val = 'b',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 		.has_arg = required_argument,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		.name = "reset",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		.val = 'r',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		.has_arg = optional_argument,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static void help(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	fprintf(stderr, "Usage: virtio_test [--help]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 		" [--no-indirect]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 		" [--no-event-idx]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		" [--no-virtio-1]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 		" [--delayed-interrupt]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		" [--batch=random/N]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 		" [--reset=N]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 		"\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) int main(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	struct vdev_info dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 		(1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	long batch = 1, reset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	int o;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	bool delayed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		o = getopt_long(argc, argv, optstring, longopts, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		switch (o) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 			goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 		case '?':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 			help();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 			exit(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		case 'e':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 			features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 			help();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 			goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		case 'i':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 			features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		case '0':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 			features &= ~(1ULL << VIRTIO_F_VERSION_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		case 'D':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 			delayed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		case 'b':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 			if (0 == strcmp(optarg, "random")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 				batch = RANDOM_BATCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 			} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 				batch = strtol(optarg, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 				assert(batch > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 				assert(batch < (long)INT_MAX + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		case 'r':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 			if (!optarg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 				reset = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 			} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 				reset = strtol(optarg, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 				assert(reset > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 				assert(reset < (long)INT_MAX + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 			assert(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	vdev_info_init(&dev, features);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	vq_info_add(&dev, 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	run_test(&dev, &dev.vqs[0], delayed, batch, reset, 0x100000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }