The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/tools/virtio/virtio_test.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #define _GNU_SOURCE
    2 #include <getopt.h>
    3 #include <string.h>
    4 #include <poll.h>
    5 #include <sys/eventfd.h>
    6 #include <stdlib.h>
    7 #include <assert.h>
    8 #include <unistd.h>
    9 #include <sys/ioctl.h>
   10 #include <sys/stat.h>
   11 #include <sys/types.h>
   12 #include <fcntl.h>
   13 #include <linux/vhost.h>
   14 #include <linux/virtio.h>
   15 #include <linux/virtio_ring.h>
   16 #include "../../drivers/vhost/test.h"
   17 
   18 struct vq_info {
   19         int kick;
   20         int call;
   21         int num;
   22         int idx;
   23         void *ring;
   24         /* copy used for control */
   25         struct vring vring;
   26         struct virtqueue *vq;
   27 };
   28 
   29 struct vdev_info {
   30         struct virtio_device vdev;
   31         int control;
   32         struct pollfd fds[1];
   33         struct vq_info vqs[1];
   34         int nvqs;
   35         void *buf;
   36         size_t buf_size;
   37         struct vhost_memory *mem;
   38 };
   39 
   40 void vq_notify(struct virtqueue *vq)
   41 {
   42         struct vq_info *info = vq->priv;
   43         unsigned long long v = 1;
   44         int r;
   45         r = write(info->kick, &v, sizeof v);
   46         assert(r == sizeof v);
   47 }
   48 
   49 void vq_callback(struct virtqueue *vq)
   50 {
   51 }
   52 
   53 
   54 void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
   55 {
   56         struct vhost_vring_state state = { .index = info->idx };
   57         struct vhost_vring_file file = { .index = info->idx };
   58         unsigned long long features = dev->vdev.features[0];
   59         struct vhost_vring_addr addr = {
   60                 .index = info->idx,
   61                 .desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
   62                 .avail_user_addr = (uint64_t)(unsigned long)info->vring.avail,
   63                 .used_user_addr = (uint64_t)(unsigned long)info->vring.used,
   64         };
   65         int r;
   66         r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
   67         assert(r >= 0);
   68         state.num = info->vring.num;
   69         r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
   70         assert(r >= 0);
   71         state.num = 0;
   72         r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
   73         assert(r >= 0);
   74         r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
   75         assert(r >= 0);
   76         file.fd = info->kick;
   77         r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
   78         assert(r >= 0);
   79         file.fd = info->call;
   80         r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
   81         assert(r >= 0);
   82 }
   83 
   84 static void vq_info_add(struct vdev_info *dev, int num)
   85 {
   86         struct vq_info *info = &dev->vqs[dev->nvqs];
   87         int r;
   88         info->idx = dev->nvqs;
   89         info->kick = eventfd(0, EFD_NONBLOCK);
   90         info->call = eventfd(0, EFD_NONBLOCK);
   91         r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
   92         assert(r >= 0);
   93         memset(info->ring, 0, vring_size(num, 4096));
   94         vring_init(&info->vring, num, info->ring, 4096);
   95         info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev,
   96                                        true, info->ring,
   97                                        vq_notify, vq_callback, "test");
   98         assert(info->vq);
   99         info->vq->priv = info;
  100         vhost_vq_setup(dev, info);
  101         dev->fds[info->idx].fd = info->call;
  102         dev->fds[info->idx].events = POLLIN;
  103         dev->nvqs++;
  104 }
  105 
  106 static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
  107 {
  108         int r;
  109         memset(dev, 0, sizeof *dev);
  110         dev->vdev.features[0] = features;
  111         dev->vdev.features[1] = features >> 32;
  112         dev->buf_size = 1024;
  113         dev->buf = malloc(dev->buf_size);
  114         assert(dev->buf);
  115         dev->control = open("/dev/vhost-test", O_RDWR);
  116         assert(dev->control >= 0);
  117         r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
  118         assert(r >= 0);
  119         dev->mem = malloc(offsetof(struct vhost_memory, regions) +
  120                           sizeof dev->mem->regions[0]);
  121         assert(dev->mem);
  122         memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
  123                           sizeof dev->mem->regions[0]);
  124         dev->mem->nregions = 1;
  125         dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
  126         dev->mem->regions[0].userspace_addr = (long)dev->buf;
  127         dev->mem->regions[0].memory_size = dev->buf_size;
  128         r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
  129         assert(r >= 0);
  130 }
  131 
  132 /* TODO: this is pretty bad: we get a cache line bounce
  133  * for the wait queue on poll and another one on read,
  134  * plus the read which is there just to clear the
  135  * current state. */
  136 static void wait_for_interrupt(struct vdev_info *dev)
  137 {
  138         int i;
  139         unsigned long long val;
  140         poll(dev->fds, dev->nvqs, -1);
  141         for (i = 0; i < dev->nvqs; ++i)
  142                 if (dev->fds[i].revents & POLLIN) {
  143                         read(dev->fds[i].fd, &val, sizeof val);
  144                 }
  145 }
  146 
  147 static void run_test(struct vdev_info *dev, struct vq_info *vq,
  148                      bool delayed, int bufs)
  149 {
  150         struct scatterlist sl;
  151         long started = 0, completed = 0;
  152         long completed_before;
  153         int r, test = 1;
  154         unsigned len;
  155         long long spurious = 0;
  156         r = ioctl(dev->control, VHOST_TEST_RUN, &test);
  157         assert(r >= 0);
  158         for (;;) {
  159                 virtqueue_disable_cb(vq->vq);
  160                 completed_before = completed;
  161                 do {
  162                         if (started < bufs) {
  163                                 sg_init_one(&sl, dev->buf, dev->buf_size);
  164                                 r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
  165                                                       dev->buf + started,
  166                                                       GFP_ATOMIC);
  167                                 if (likely(r == 0)) {
  168                                         ++started;
  169                                         virtqueue_kick(vq->vq);
  170                                 }
  171                         } else
  172                                 r = -1;
  173 
  174                         /* Flush out completed bufs if any */
  175                         if (virtqueue_get_buf(vq->vq, &len)) {
  176                                 ++completed;
  177                                 r = 0;
  178                         }
  179 
  180                 } while (r == 0);
  181                 if (completed == completed_before)
  182                         ++spurious;
  183                 assert(completed <= bufs);
  184                 assert(started <= bufs);
  185                 if (completed == bufs)
  186                         break;
  187                 if (delayed) {
  188                         if (virtqueue_enable_cb_delayed(vq->vq))
  189                                 wait_for_interrupt(dev);
  190                 } else {
  191                         if (virtqueue_enable_cb(vq->vq))
  192                                 wait_for_interrupt(dev);
  193                 }
  194         }
  195         test = 0;
  196         r = ioctl(dev->control, VHOST_TEST_RUN, &test);
  197         assert(r >= 0);
  198         fprintf(stderr, "spurious wakeus: 0x%llx\n", spurious);
  199 }
  200 
  201 const char optstring[] = "h";
  202 const struct option longopts[] = {
  203         {
  204                 .name = "help",
  205                 .val = 'h',
  206         },
  207         {
  208                 .name = "event-idx",
  209                 .val = 'E',
  210         },
  211         {
  212                 .name = "no-event-idx",
  213                 .val = 'e',
  214         },
  215         {
  216                 .name = "indirect",
  217                 .val = 'I',
  218         },
  219         {
  220                 .name = "no-indirect",
  221                 .val = 'i',
  222         },
  223         {
  224                 .name = "delayed-interrupt",
  225                 .val = 'D',
  226         },
  227         {
  228                 .name = "no-delayed-interrupt",
  229                 .val = 'd',
  230         },
  231         {
  232         }
  233 };
  234 
  235 static void help(void)
  236 {
  237         fprintf(stderr, "Usage: virtio_test [--help]"
  238                 " [--no-indirect]"
  239                 " [--no-event-idx]"
  240                 " [--delayed-interrupt]"
  241                 "\n");
  242 }
  243 
  244 int main(int argc, char **argv)
  245 {
  246         struct vdev_info dev;
  247         unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
  248                 (1ULL << VIRTIO_RING_F_EVENT_IDX);
  249         int o;
  250         bool delayed = false;
  251 
  252         for (;;) {
  253                 o = getopt_long(argc, argv, optstring, longopts, NULL);
  254                 switch (o) {
  255                 case -1:
  256                         goto done;
  257                 case '?':
  258                         help();
  259                         exit(2);
  260                 case 'e':
  261                         features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX);
  262                         break;
  263                 case 'h':
  264                         help();
  265                         goto done;
  266                 case 'i':
  267                         features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
  268                         break;
  269                 case 'D':
  270                         delayed = true;
  271                         break;
  272                 default:
  273                         assert(0);
  274                         break;
  275                 }
  276         }
  277 
  278 done:
  279         vdev_info_init(&dev, features);
  280         vq_info_add(&dev, 256);
  281         run_test(&dev, &dev.vqs[0], delayed, 0x100000);
  282         return 0;
  283 }

Cache object: f0079b16de8cd4dda1eb7300eb751daa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.