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/dev/virtio/virtio.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice unmodified, this list of conditions, and the following
   12  *    disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/module.h>
   37 #include <sys/sbuf.h>
   38 
   39 #include <machine/bus.h>
   40 #include <machine/resource.h>
   41 #include <sys/bus.h>
   42 #include <sys/rman.h>
   43 
   44 #include <dev/virtio/virtio.h>
   45 #include <dev/virtio/virtio_config.h>
   46 #include <dev/virtio/virtqueue.h>
   47 
   48 #include "virtio_bus_if.h"
   49 
   50 static int virtio_modevent(module_t, int, void *);
   51 static const char *virtio_feature_name(uint64_t, struct virtio_feature_desc *);
   52 
   53 static struct virtio_ident {
   54         uint16_t        devid;
   55         const char      *name;
   56 } virtio_ident_table[] = {
   57         { VIRTIO_ID_NETWORK,            "Network"                       },
   58         { VIRTIO_ID_BLOCK,              "Block"                         },
   59         { VIRTIO_ID_CONSOLE,            "Console"                       },
   60         { VIRTIO_ID_ENTROPY,            "Entropy"                       },
   61         { VIRTIO_ID_BALLOON,            "Balloon"                       },
   62         { VIRTIO_ID_IOMEMORY,           "IOMemory"                      },
   63         { VIRTIO_ID_RPMSG,              "Remote Processor Messaging"    },
   64         { VIRTIO_ID_SCSI,               "SCSI"                          },
   65         { VIRTIO_ID_9P,                 "9P Transport"                  },
   66         { VIRTIO_ID_RPROC_SERIAL,       "Remote Processor Serial"       },
   67         { VIRTIO_ID_CAIF,               "CAIF"                          },
   68         { VIRTIO_ID_GPU,                "GPU"                           },
   69         { VIRTIO_ID_INPUT,              "Input"                         },
   70         { VIRTIO_ID_VSOCK,              "VSOCK Transport"               },
   71         { VIRTIO_ID_CRYPTO,             "Crypto"                        },
   72 
   73         { 0, NULL }
   74 };
   75 
   76 /* Device independent features. */
   77 static struct virtio_feature_desc virtio_common_feature_desc[] = {
   78         { VIRTIO_F_NOTIFY_ON_EMPTY,     "NotifyOnEmpty"         }, /* Legacy */
   79         { VIRTIO_F_ANY_LAYOUT,          "AnyLayout"             }, /* Legacy */
   80         { VIRTIO_RING_F_INDIRECT_DESC,  "RingIndirectDesc"      },
   81         { VIRTIO_RING_F_EVENT_IDX,      "RingEventIdx"          },
   82         { VIRTIO_F_BAD_FEATURE,         "BadFeature"            }, /* Legacy */
   83         { VIRTIO_F_VERSION_1,           "Version1"              },
   84         { VIRTIO_F_IOMMU_PLATFORM,      "IOMMUPlatform"         },
   85 
   86         { 0, NULL }
   87 };
   88 
   89 const char *
   90 virtio_device_name(uint16_t devid)
   91 {
   92         struct virtio_ident *ident;
   93 
   94         for (ident = virtio_ident_table; ident->name != NULL; ident++) {
   95                 if (ident->devid == devid)
   96                         return (ident->name);
   97         }
   98 
   99         return (NULL);
  100 }
  101 
  102 static const char *
  103 virtio_feature_name(uint64_t val, struct virtio_feature_desc *desc)
  104 {
  105         int i, j;
  106         struct virtio_feature_desc *descs[2] = { desc,
  107             virtio_common_feature_desc };
  108 
  109         for (i = 0; i < 2; i++) {
  110                 if (descs[i] == NULL)
  111                         continue;
  112 
  113                 for (j = 0; descs[i][j].vfd_val != 0; j++) {
  114                         if (val == descs[i][j].vfd_val)
  115                                 return (descs[i][j].vfd_str);
  116                 }
  117         }
  118 
  119         return (NULL);
  120 }
  121 
  122 int
  123 virtio_describe_sbuf(struct sbuf *sb, uint64_t features,
  124     struct virtio_feature_desc *desc)
  125 {
  126         const char *name;
  127         uint64_t val;
  128         int n;
  129 
  130         sbuf_printf(sb, "%#jx", (uintmax_t) features);
  131 
  132         for (n = 0, val = 1ULL << 63; val != 0; val >>= 1) {
  133                 /*
  134                  * BAD_FEATURE is used to detect broken Linux clients
  135                  * and therefore is not applicable to FreeBSD.
  136                  */
  137                 if (((features & val) == 0) || val == VIRTIO_F_BAD_FEATURE)
  138                         continue;
  139 
  140                 if (n++ == 0)
  141                         sbuf_cat(sb, " <");
  142                 else
  143                         sbuf_cat(sb, ",");
  144 
  145                 name = virtio_feature_name(val, desc);
  146                 if (name == NULL)
  147                         sbuf_printf(sb, "%#jx", (uintmax_t) val);
  148                 else
  149                         sbuf_cat(sb, name);
  150         }
  151 
  152         if (n > 0)
  153                 sbuf_cat(sb, ">");
  154 
  155         return (sbuf_finish(sb));
  156 }
  157 
  158 void
  159 virtio_describe(device_t dev, const char *msg, uint64_t features,
  160     struct virtio_feature_desc *desc)
  161 {
  162         struct sbuf sb;
  163         char *buf;
  164         int error;
  165 
  166         if ((buf = malloc(1024, M_TEMP, M_NOWAIT)) == NULL) {
  167                 error = ENOMEM;
  168                 goto out;
  169         }
  170 
  171         sbuf_new(&sb, buf, 1024, SBUF_FIXEDLEN);
  172         sbuf_printf(&sb, "%s features: ", msg);
  173 
  174         error = virtio_describe_sbuf(&sb, features, desc);
  175         if (error == 0)
  176                 device_printf(dev, "%s\n", sbuf_data(&sb));
  177 
  178         sbuf_delete(&sb);
  179         free(buf, M_TEMP);
  180 
  181 out:
  182         if (error != 0) {
  183                 device_printf(dev, "%s features: %#jx\n", msg,
  184                     (uintmax_t) features);
  185         }
  186 }
  187 
  188 uint64_t
  189 virtio_filter_transport_features(uint64_t features)
  190 {
  191         uint64_t transport, mask;
  192 
  193         transport = (1ULL <<
  194             (VIRTIO_TRANSPORT_F_END - VIRTIO_TRANSPORT_F_START)) - 1;
  195         transport <<= VIRTIO_TRANSPORT_F_START;
  196 
  197         mask = -1ULL & ~transport;
  198         mask |= VIRTIO_RING_F_INDIRECT_DESC;
  199         mask |= VIRTIO_RING_F_EVENT_IDX;
  200         mask |= VIRTIO_F_VERSION_1;
  201 
  202         return (features & mask);
  203 }
  204 
  205 int
  206 virtio_bus_is_modern(device_t dev)
  207 {
  208         uintptr_t modern;
  209 
  210         virtio_read_ivar(dev, VIRTIO_IVAR_MODERN, &modern);
  211         return (modern != 0);
  212 }
  213 
  214 void
  215 virtio_read_device_config_array(device_t dev, bus_size_t offset, void *dst,
  216     int size, int count)
  217 {
  218         int i, gen;
  219 
  220         do {
  221                 gen = virtio_config_generation(dev);
  222 
  223                 for (i = 0; i < count; i++) {
  224                         virtio_read_device_config(dev, offset + i * size,
  225                             (uint8_t *) dst + i * size, size);
  226                 }
  227         } while (gen != virtio_config_generation(dev));
  228 }
  229 
  230 /*
  231  * VirtIO bus method wrappers.
  232  */
  233 
  234 void
  235 virtio_read_ivar(device_t dev, int ivar, uintptr_t *val)
  236 {
  237 
  238         *val = -1;
  239         BUS_READ_IVAR(device_get_parent(dev), dev, ivar, val);
  240 }
  241 
  242 void
  243 virtio_write_ivar(device_t dev, int ivar, uintptr_t val)
  244 {
  245 
  246         BUS_WRITE_IVAR(device_get_parent(dev), dev, ivar, val);
  247 }
  248 
  249 uint64_t
  250 virtio_negotiate_features(device_t dev, uint64_t child_features)
  251 {
  252 
  253         return (VIRTIO_BUS_NEGOTIATE_FEATURES(device_get_parent(dev),
  254             child_features));
  255 }
  256 
  257 int
  258 virtio_finalize_features(device_t dev)
  259 {
  260 
  261         return (VIRTIO_BUS_FINALIZE_FEATURES(device_get_parent(dev)));
  262 }
  263 
  264 int
  265 virtio_alloc_virtqueues(device_t dev, int flags, int nvqs,
  266     struct vq_alloc_info *info)
  267 {
  268 
  269         return (VIRTIO_BUS_ALLOC_VIRTQUEUES(device_get_parent(dev), flags,
  270             nvqs, info));
  271 }
  272 
  273 int
  274 virtio_setup_intr(device_t dev, enum intr_type type)
  275 {
  276 
  277         return (VIRTIO_BUS_SETUP_INTR(device_get_parent(dev), type));
  278 }
  279 
  280 int
  281 virtio_with_feature(device_t dev, uint64_t feature)
  282 {
  283 
  284         return (VIRTIO_BUS_WITH_FEATURE(device_get_parent(dev), feature));
  285 }
  286 
  287 void
  288 virtio_stop(device_t dev)
  289 {
  290 
  291         VIRTIO_BUS_STOP(device_get_parent(dev));
  292 }
  293 
  294 int
  295 virtio_reinit(device_t dev, uint64_t features)
  296 {
  297 
  298         return (VIRTIO_BUS_REINIT(device_get_parent(dev), features));
  299 }
  300 
  301 void
  302 virtio_reinit_complete(device_t dev)
  303 {
  304 
  305         VIRTIO_BUS_REINIT_COMPLETE(device_get_parent(dev));
  306 }
  307 
  308 int
  309 virtio_config_generation(device_t dev)
  310 {
  311 
  312         return (VIRTIO_BUS_CONFIG_GENERATION(device_get_parent(dev)));
  313 }
  314 
  315 void
  316 virtio_read_device_config(device_t dev, bus_size_t offset, void *dst, int len)
  317 {
  318 
  319         VIRTIO_BUS_READ_DEVICE_CONFIG(device_get_parent(dev),
  320             offset, dst, len);
  321 }
  322 
  323 void
  324 virtio_write_device_config(device_t dev, bus_size_t offset, const void *dst, int len)
  325 {
  326 
  327         VIRTIO_BUS_WRITE_DEVICE_CONFIG(device_get_parent(dev),
  328             offset, dst, len);
  329 }
  330 
  331 int
  332 virtio_child_pnpinfo(device_t busdev __unused, device_t child, struct sbuf *sb)
  333 {
  334 
  335         /*
  336          * All of these PCI fields will be only 16 bits, but on the vtmmio bus
  337          * the corresponding fields (only "vendor" and "device_type") are 32
  338          * bits.  Many virtio drivers can attach below either bus.
  339          * Gratuitously expand these two fields to 32-bits to allow sharing PNP
  340          * match table data between the mostly-similar buses.
  341          *
  342          * Subdevice and device_type are redundant in both buses, so I don't
  343          * see a lot of PNP utility in exposing the same value under a
  344          * different name.
  345          */
  346         sbuf_printf(sb, "vendor=0x%08x device=0x%04x subvendor=0x%04x "
  347             "device_type=0x%08x", (unsigned)virtio_get_vendor(child),
  348             (unsigned)virtio_get_device(child),
  349             (unsigned)virtio_get_subvendor(child),
  350             (unsigned)virtio_get_device_type(child));
  351         return (0);
  352 }
  353 
  354 static int
  355 virtio_modevent(module_t mod, int type, void *unused)
  356 {
  357         int error;
  358 
  359         switch (type) {
  360         case MOD_LOAD:
  361         case MOD_QUIESCE:
  362         case MOD_UNLOAD:
  363         case MOD_SHUTDOWN:
  364                 error = 0;
  365                 break;
  366         default:
  367                 error = EOPNOTSUPP;
  368                 break;
  369         }
  370 
  371         return (error);
  372 }
  373 
  374 static moduledata_t virtio_mod = {
  375         "virtio",
  376         virtio_modevent,
  377         0
  378 };
  379 
  380 DECLARE_MODULE(virtio, virtio_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
  381 MODULE_VERSION(virtio, 1);

Cache object: db114de9fac5bfbcf272198fd72f0c4d


[ 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.