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/pci/virtio_pci_legacy.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 /* Driver for the legacy VirtIO PCI interface. */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/lock.h>
   38 #include <sys/kernel.h>
   39 #include <sys/module.h>
   40 #include <sys/endian.h>
   41 
   42 #include <machine/bus.h>
   43 #include <machine/resource.h>
   44 #include <sys/bus.h>
   45 #include <sys/rman.h>
   46 
   47 #include <dev/pci/pcivar.h>
   48 #include <dev/pci/pcireg.h>
   49 
   50 #include <dev/virtio/virtio.h>
   51 #include <dev/virtio/virtqueue.h>
   52 #include <dev/virtio/pci/virtio_pci.h>
   53 #include <dev/virtio/pci/virtio_pci_legacy_var.h>
   54 
   55 #include "virtio_bus_if.h"
   56 #include "virtio_pci_if.h"
   57 #include "virtio_if.h"
   58 
   59 struct vtpci_legacy_softc {
   60         device_t                         vtpci_dev;
   61         struct vtpci_common              vtpci_common;
   62         int                              vtpci_res_type;
   63         struct resource                 *vtpci_res;
   64         struct resource                 *vtpci_msix_table_res;
   65         struct resource                 *vtpci_msix_pba_res;
   66 };
   67 
   68 static int      vtpci_legacy_probe(device_t);
   69 static int      vtpci_legacy_attach(device_t);
   70 static int      vtpci_legacy_detach(device_t);
   71 static int      vtpci_legacy_suspend(device_t);
   72 static int      vtpci_legacy_resume(device_t);
   73 static int      vtpci_legacy_shutdown(device_t);
   74 
   75 static void     vtpci_legacy_driver_added(device_t, driver_t *);
   76 static void     vtpci_legacy_child_detached(device_t, device_t);
   77 static int      vtpci_legacy_read_ivar(device_t, device_t, int, uintptr_t *);
   78 static int      vtpci_legacy_write_ivar(device_t, device_t, int, uintptr_t);
   79 
   80 static uint8_t  vtpci_legacy_read_isr(device_t);
   81 static uint16_t vtpci_legacy_get_vq_size(device_t, int);
   82 static bus_size_t vtpci_legacy_get_vq_notify_off(device_t, int);
   83 static void     vtpci_legacy_set_vq(device_t, struct virtqueue *);
   84 static void     vtpci_legacy_disable_vq(device_t, int);
   85 static int      vtpci_legacy_register_cfg_msix(device_t,
   86                     struct vtpci_interrupt *);
   87 static int      vtpci_legacy_register_vq_msix(device_t, int idx,
   88                     struct vtpci_interrupt *);
   89 
   90 static uint64_t vtpci_legacy_negotiate_features(device_t, uint64_t);
   91 static int      vtpci_legacy_with_feature(device_t, uint64_t);
   92 static int      vtpci_legacy_alloc_virtqueues(device_t, int, int,
   93                     struct vq_alloc_info *);
   94 static int      vtpci_legacy_setup_interrupts(device_t, enum intr_type);
   95 static void     vtpci_legacy_stop(device_t);
   96 static int      vtpci_legacy_reinit(device_t, uint64_t);
   97 static void     vtpci_legacy_reinit_complete(device_t);
   98 static void     vtpci_legacy_notify_vq(device_t, uint16_t, bus_size_t);
   99 static void     vtpci_legacy_read_dev_config(device_t, bus_size_t, void *, int);
  100 static void     vtpci_legacy_write_dev_config(device_t, bus_size_t, const void *, int);
  101 
  102 static bool     vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc);
  103 static void     vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc);
  104 static int      vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *);
  105 static void     vtpci_legacy_free_resources(struct vtpci_legacy_softc *);
  106 
  107 static void     vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *);
  108 
  109 static uint8_t  vtpci_legacy_get_status(struct vtpci_legacy_softc *);
  110 static void     vtpci_legacy_set_status(struct vtpci_legacy_softc *, uint8_t);
  111 static void     vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *, int);
  112 static void     vtpci_legacy_reset(struct vtpci_legacy_softc *);
  113 
  114 #define VIRTIO_PCI_LEGACY_CONFIG(_sc) \
  115     VIRTIO_PCI_CONFIG_OFF(vtpci_is_msix_enabled(&(_sc)->vtpci_common))
  116 
  117 #define vtpci_legacy_read_config_1(sc, o) \
  118     bus_read_1((sc)->vtpci_res, (o))
  119 #define vtpci_legacy_write_config_1(sc, o, v) \
  120     bus_write_1((sc)->vtpci_res, (o), (v))
  121 /*
  122  * VirtIO specifies that PCI Configuration area is guest endian. However,
  123  * since PCI devices are inherently little-endian, on big-endian systems
  124  * the bus layer transparently converts it to BE. For virtio-legacy, this
  125  * conversion is undesired, so an extra byte swap is required to fix it.
  126  */
  127 #define vtpci_legacy_read_config_2(sc, o) \
  128     le16toh(bus_read_2((sc)->vtpci_res, (o)))
  129 #define vtpci_legacy_read_config_4(sc, o) \
  130     le32toh(bus_read_4((sc)->vtpci_res, (o)))
  131 #define vtpci_legacy_write_config_2(sc, o, v) \
  132     bus_write_2((sc)->vtpci_res, (o), (htole16(v)))
  133 #define vtpci_legacy_write_config_4(sc, o, v) \
  134     bus_write_4((sc)->vtpci_res, (o), (htole32(v)))
  135 /* PCI Header LE. On BE systems the bus layer takes care of byte swapping. */
  136 #define vtpci_legacy_read_header_2(sc, o) \
  137     bus_read_2((sc)->vtpci_res, (o))
  138 #define vtpci_legacy_read_header_4(sc, o) \
  139     bus_read_4((sc)->vtpci_res, (o))
  140 #define vtpci_legacy_write_header_2(sc, o, v) \
  141     bus_write_2((sc)->vtpci_res, (o), (v))
  142 #define vtpci_legacy_write_header_4(sc, o, v) \
  143     bus_write_4((sc)->vtpci_res, (o), (v))
  144 
  145 static device_method_t vtpci_legacy_methods[] = {
  146         /* Device interface. */
  147         DEVMETHOD(device_probe,                   vtpci_legacy_probe),
  148         DEVMETHOD(device_attach,                  vtpci_legacy_attach),
  149         DEVMETHOD(device_detach,                  vtpci_legacy_detach),
  150         DEVMETHOD(device_suspend,                 vtpci_legacy_suspend),
  151         DEVMETHOD(device_resume,                  vtpci_legacy_resume),
  152         DEVMETHOD(device_shutdown,                vtpci_legacy_shutdown),
  153 
  154         /* Bus interface. */
  155         DEVMETHOD(bus_driver_added,               vtpci_legacy_driver_added),
  156         DEVMETHOD(bus_child_detached,             vtpci_legacy_child_detached),
  157         DEVMETHOD(bus_child_pnpinfo,              virtio_child_pnpinfo),
  158         DEVMETHOD(bus_read_ivar,                  vtpci_legacy_read_ivar),
  159         DEVMETHOD(bus_write_ivar,                 vtpci_legacy_write_ivar),
  160 
  161         /* VirtIO PCI interface. */
  162         DEVMETHOD(virtio_pci_read_isr,           vtpci_legacy_read_isr),
  163         DEVMETHOD(virtio_pci_get_vq_size,        vtpci_legacy_get_vq_size),
  164         DEVMETHOD(virtio_pci_get_vq_notify_off,  vtpci_legacy_get_vq_notify_off),
  165         DEVMETHOD(virtio_pci_set_vq,             vtpci_legacy_set_vq),
  166         DEVMETHOD(virtio_pci_disable_vq,         vtpci_legacy_disable_vq),
  167         DEVMETHOD(virtio_pci_register_cfg_msix,  vtpci_legacy_register_cfg_msix),
  168         DEVMETHOD(virtio_pci_register_vq_msix,   vtpci_legacy_register_vq_msix),
  169 
  170         /* VirtIO bus interface. */
  171         DEVMETHOD(virtio_bus_negotiate_features,  vtpci_legacy_negotiate_features),
  172         DEVMETHOD(virtio_bus_with_feature,        vtpci_legacy_with_feature),
  173         DEVMETHOD(virtio_bus_alloc_virtqueues,    vtpci_legacy_alloc_virtqueues),
  174         DEVMETHOD(virtio_bus_setup_intr,          vtpci_legacy_setup_interrupts),
  175         DEVMETHOD(virtio_bus_stop,                vtpci_legacy_stop),
  176         DEVMETHOD(virtio_bus_reinit,              vtpci_legacy_reinit),
  177         DEVMETHOD(virtio_bus_reinit_complete,     vtpci_legacy_reinit_complete),
  178         DEVMETHOD(virtio_bus_notify_vq,           vtpci_legacy_notify_vq),
  179         DEVMETHOD(virtio_bus_read_device_config,  vtpci_legacy_read_dev_config),
  180         DEVMETHOD(virtio_bus_write_device_config, vtpci_legacy_write_dev_config),
  181 
  182         DEVMETHOD_END
  183 };
  184 
  185 static driver_t vtpci_legacy_driver = {
  186         .name = "virtio_pci",
  187         .methods = vtpci_legacy_methods,
  188         .size = sizeof(struct vtpci_legacy_softc)
  189 };
  190 
  191 DRIVER_MODULE(virtio_pci_legacy, pci, vtpci_legacy_driver, 0, 0);
  192 
  193 static int
  194 vtpci_legacy_probe(device_t dev)
  195 {
  196         char desc[64];
  197         const char *name;
  198 
  199         if (pci_get_vendor(dev) != VIRTIO_PCI_VENDORID)
  200                 return (ENXIO);
  201 
  202         if (pci_get_device(dev) < VIRTIO_PCI_DEVICEID_MIN ||
  203             pci_get_device(dev) > VIRTIO_PCI_DEVICEID_LEGACY_MAX)
  204                 return (ENXIO);
  205 
  206         if (pci_get_revid(dev) != VIRTIO_PCI_ABI_VERSION)
  207                 return (ENXIO);
  208 
  209         name = virtio_device_name(pci_get_subdevice(dev));
  210         if (name == NULL)
  211                 name = "Unknown";
  212 
  213         snprintf(desc, sizeof(desc), "VirtIO PCI (legacy) %s adapter", name);
  214         device_set_desc_copy(dev, desc);
  215 
  216         /* Prefer transitional modern VirtIO PCI. */
  217         return (BUS_PROBE_LOW_PRIORITY);
  218 }
  219 
  220 static int
  221 vtpci_legacy_attach(device_t dev)
  222 {
  223         struct vtpci_legacy_softc *sc;
  224         int error;
  225 
  226         sc = device_get_softc(dev);
  227         sc->vtpci_dev = dev;
  228         vtpci_init(&sc->vtpci_common, dev, false);
  229 
  230         error = vtpci_legacy_alloc_resources(sc);
  231         if (error) {
  232                 device_printf(dev, "cannot map I/O space nor memory space\n");
  233                 return (error);
  234         }
  235 
  236         if (vtpci_is_msix_available(&sc->vtpci_common) &&
  237             !vtpci_legacy_setup_msix(sc)) {
  238                 device_printf(dev, "cannot setup MSI-x resources\n");
  239                 error = ENXIO;
  240                 goto fail;
  241         }
  242 
  243         vtpci_legacy_reset(sc);
  244 
  245         /* Tell the host we've noticed this device. */
  246         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK);
  247 
  248         error = vtpci_add_child(&sc->vtpci_common);
  249         if (error)
  250                 goto fail;
  251 
  252         vtpci_legacy_probe_and_attach_child(sc);
  253 
  254         return (0);
  255 
  256 fail:
  257         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED);
  258         vtpci_legacy_detach(dev);
  259 
  260         return (error);
  261 }
  262 
  263 static int
  264 vtpci_legacy_detach(device_t dev)
  265 {
  266         struct vtpci_legacy_softc *sc;
  267         int error;
  268 
  269         sc = device_get_softc(dev);
  270 
  271         error = vtpci_delete_child(&sc->vtpci_common);
  272         if (error)
  273                 return (error);
  274 
  275         vtpci_legacy_reset(sc);
  276         vtpci_legacy_teardown_msix(sc);
  277         vtpci_legacy_free_resources(sc);
  278 
  279         return (0);
  280 }
  281 
  282 static int
  283 vtpci_legacy_suspend(device_t dev)
  284 {
  285         return (bus_generic_suspend(dev));
  286 }
  287 
  288 static int
  289 vtpci_legacy_resume(device_t dev)
  290 {
  291         return (bus_generic_resume(dev));
  292 }
  293 
  294 static int
  295 vtpci_legacy_shutdown(device_t dev)
  296 {
  297         (void) bus_generic_shutdown(dev);
  298         /* Forcibly stop the host device. */
  299         vtpci_legacy_stop(dev);
  300 
  301         return (0);
  302 }
  303 
  304 static void
  305 vtpci_legacy_driver_added(device_t dev, driver_t *driver)
  306 {
  307         vtpci_legacy_probe_and_attach_child(device_get_softc(dev));
  308 }
  309 
  310 static void
  311 vtpci_legacy_child_detached(device_t dev, device_t child)
  312 {
  313         struct vtpci_legacy_softc *sc;
  314 
  315         sc = device_get_softc(dev);
  316 
  317         vtpci_legacy_reset(sc);
  318         vtpci_child_detached(&sc->vtpci_common);
  319 
  320         /* After the reset, retell the host we've noticed this device. */
  321         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK);
  322 }
  323 
  324 static int
  325 vtpci_legacy_read_ivar(device_t dev, device_t child, int index,
  326     uintptr_t *result)
  327 {
  328         struct vtpci_legacy_softc *sc;
  329         struct vtpci_common *cn;
  330 
  331         sc = device_get_softc(dev);
  332         cn = &sc->vtpci_common;
  333 
  334         if (vtpci_child_device(cn) != child)
  335                 return (ENOENT);
  336 
  337         switch (index) {
  338         case VIRTIO_IVAR_DEVTYPE:
  339                 *result = pci_get_subdevice(dev);
  340                 break;
  341         default:
  342                 return (vtpci_read_ivar(cn, index, result));
  343         }
  344 
  345         return (0);
  346 }
  347 
  348 static int
  349 vtpci_legacy_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
  350 {
  351         struct vtpci_legacy_softc *sc;
  352         struct vtpci_common *cn;
  353 
  354         sc = device_get_softc(dev);
  355         cn = &sc->vtpci_common;
  356 
  357         if (vtpci_child_device(cn) != child)
  358                 return (ENOENT);
  359 
  360         switch (index) {
  361         default:
  362                 return (vtpci_write_ivar(cn, index, value));
  363         }
  364 
  365         return (0);
  366 }
  367 
  368 static uint64_t
  369 vtpci_legacy_negotiate_features(device_t dev, uint64_t child_features)
  370 {
  371         struct vtpci_legacy_softc *sc;
  372         uint64_t host_features, features;
  373 
  374         sc = device_get_softc(dev);
  375         host_features = vtpci_legacy_read_header_4(sc, VIRTIO_PCI_HOST_FEATURES);
  376 
  377         features = vtpci_negotiate_features(&sc->vtpci_common,
  378             child_features, host_features);
  379         vtpci_legacy_write_header_4(sc, VIRTIO_PCI_GUEST_FEATURES, features);
  380 
  381         return (features);
  382 }
  383 
  384 static int
  385 vtpci_legacy_with_feature(device_t dev, uint64_t feature)
  386 {
  387         struct vtpci_legacy_softc *sc;
  388 
  389         sc = device_get_softc(dev);
  390 
  391         return (vtpci_with_feature(&sc->vtpci_common, feature));
  392 }
  393 
  394 static int
  395 vtpci_legacy_alloc_virtqueues(device_t dev, int flags, int nvqs,
  396     struct vq_alloc_info *vq_info)
  397 {
  398         struct vtpci_legacy_softc *sc;
  399         struct vtpci_common *cn;
  400 
  401         sc = device_get_softc(dev);
  402         cn = &sc->vtpci_common;
  403 
  404         return (vtpci_alloc_virtqueues(cn, flags, nvqs, vq_info));
  405 }
  406 
  407 static int
  408 vtpci_legacy_setup_interrupts(device_t dev, enum intr_type type)
  409 {
  410         struct vtpci_legacy_softc *sc;
  411 
  412         sc = device_get_softc(dev);
  413 
  414         return (vtpci_setup_interrupts(&sc->vtpci_common, type));
  415 }
  416 
  417 static void
  418 vtpci_legacy_stop(device_t dev)
  419 {
  420         vtpci_legacy_reset(device_get_softc(dev));
  421 }
  422 
  423 static int
  424 vtpci_legacy_reinit(device_t dev, uint64_t features)
  425 {
  426         struct vtpci_legacy_softc *sc;
  427         struct vtpci_common *cn;
  428         int error;
  429 
  430         sc = device_get_softc(dev);
  431         cn = &sc->vtpci_common;
  432 
  433         /*
  434          * Redrive the device initialization. This is a bit of an abuse of
  435          * the specification, but VirtualBox, QEMU/KVM, and BHyVe seem to
  436          * play nice.
  437          *
  438          * We do not allow the host device to change from what was originally
  439          * negotiated beyond what the guest driver changed. MSIX state should
  440          * not change, number of virtqueues and their size remain the same, etc.
  441          * This will need to be rethought when we want to support migration.
  442          */
  443 
  444         if (vtpci_legacy_get_status(sc) != VIRTIO_CONFIG_STATUS_RESET)
  445                 vtpci_legacy_stop(dev);
  446 
  447         /*
  448          * Quickly drive the status through ACK and DRIVER. The device does
  449          * not become usable again until DRIVER_OK in reinit complete.
  450          */
  451         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_ACK);
  452         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER);
  453 
  454         vtpci_legacy_negotiate_features(dev, features);
  455 
  456         error = vtpci_reinit(cn);
  457         if (error)
  458                 return (error);
  459 
  460         return (0);
  461 }
  462 
  463 static void
  464 vtpci_legacy_reinit_complete(device_t dev)
  465 {
  466         struct vtpci_legacy_softc *sc;
  467 
  468         sc = device_get_softc(dev);
  469 
  470         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK);
  471 }
  472 
  473 static void
  474 vtpci_legacy_notify_vq(device_t dev, uint16_t queue, bus_size_t offset)
  475 {
  476         struct vtpci_legacy_softc *sc;
  477 
  478         sc = device_get_softc(dev);
  479         MPASS(offset == VIRTIO_PCI_QUEUE_NOTIFY);
  480 
  481         vtpci_legacy_write_header_2(sc, offset, queue);
  482 }
  483 
  484 static uint8_t
  485 vtpci_legacy_get_status(struct vtpci_legacy_softc *sc)
  486 {
  487         return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_STATUS));
  488 }
  489 
  490 static void
  491 vtpci_legacy_set_status(struct vtpci_legacy_softc *sc, uint8_t status)
  492 {
  493         if (status != VIRTIO_CONFIG_STATUS_RESET)
  494                 status |= vtpci_legacy_get_status(sc);
  495 
  496         vtpci_legacy_write_config_1(sc, VIRTIO_PCI_STATUS, status);
  497 }
  498 
  499 static void
  500 vtpci_legacy_read_dev_config(device_t dev, bus_size_t offset,
  501     void *dst, int length)
  502 {
  503         struct vtpci_legacy_softc *sc;
  504         bus_size_t off;
  505         uint8_t *d;
  506         int i;
  507 
  508         sc = device_get_softc(dev);
  509         off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset;
  510 
  511         d = dst;
  512         for (i = 0; i < length; i++) {
  513                 d[i] = vtpci_legacy_read_config_1(sc, off + i);
  514         }
  515 }
  516 
  517 static void
  518 vtpci_legacy_write_dev_config(device_t dev, bus_size_t offset,
  519     const void *src, int length)
  520 {
  521         struct vtpci_legacy_softc *sc;
  522         bus_size_t off;
  523         const uint8_t *s;
  524         int i;
  525 
  526         sc = device_get_softc(dev);
  527         off = VIRTIO_PCI_LEGACY_CONFIG(sc) + offset;
  528 
  529         s = src;
  530         for (i = 0; i < length; i++) {
  531                 vtpci_legacy_write_config_1(sc, off + i, s[i]);
  532         }
  533 }
  534 
  535 static bool
  536 vtpci_legacy_setup_msix(struct vtpci_legacy_softc *sc)
  537 {
  538         device_t dev;
  539         int rid, table_rid;
  540 
  541         dev = sc->vtpci_dev;
  542 
  543         rid = table_rid = pci_msix_table_bar(dev);
  544         if (rid != PCIR_BAR(0)) {
  545                 sc->vtpci_msix_table_res = bus_alloc_resource_any(
  546                     dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  547                 if (sc->vtpci_msix_table_res == NULL)
  548                         return (false);
  549         }
  550 
  551         rid = pci_msix_pba_bar(dev);
  552         if (rid != table_rid && rid != PCIR_BAR(0)) {
  553                 sc->vtpci_msix_pba_res = bus_alloc_resource_any(
  554                     dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  555                 if (sc->vtpci_msix_pba_res == NULL)
  556                         return (false);
  557         }
  558 
  559         return (true);
  560 }
  561 
  562 static void
  563 vtpci_legacy_teardown_msix(struct vtpci_legacy_softc *sc)
  564 {
  565         device_t dev;
  566 
  567         dev = sc->vtpci_dev;
  568 
  569         if (sc->vtpci_msix_pba_res != NULL) {
  570                 bus_release_resource(dev, SYS_RES_MEMORY,
  571                     rman_get_rid(sc->vtpci_msix_pba_res),
  572                     sc->vtpci_msix_pba_res);
  573                 sc->vtpci_msix_pba_res = NULL;
  574         }
  575         if (sc->vtpci_msix_table_res != NULL) {
  576                 bus_release_resource(dev, SYS_RES_MEMORY,
  577                     rman_get_rid(sc->vtpci_msix_table_res),
  578                     sc->vtpci_msix_table_res);
  579                 sc->vtpci_msix_table_res = NULL;
  580         }
  581 }
  582 
  583 static int
  584 vtpci_legacy_alloc_resources(struct vtpci_legacy_softc *sc)
  585 {
  586         const int res_types[] = { SYS_RES_IOPORT, SYS_RES_MEMORY };
  587         device_t dev;
  588         int rid, i;
  589 
  590         dev = sc->vtpci_dev;
  591         
  592         /*
  593          * Most hypervisors export the common configuration structure in IO
  594          * space, but some use memory space; try both.
  595          */
  596         for (i = 0; nitems(res_types); i++) {
  597                 rid = PCIR_BAR(0);
  598                 sc->vtpci_res_type = res_types[i];
  599                 sc->vtpci_res = bus_alloc_resource_any(dev, res_types[i], &rid,
  600                     RF_ACTIVE);
  601                 if (sc->vtpci_res != NULL)
  602                         break;
  603         }
  604         if (sc->vtpci_res == NULL)
  605                 return (ENXIO);
  606 
  607         return (0);
  608 }
  609 
  610 static void
  611 vtpci_legacy_free_resources(struct vtpci_legacy_softc *sc)
  612 {
  613         device_t dev;
  614 
  615         dev = sc->vtpci_dev;
  616 
  617         if (sc->vtpci_res != NULL) {
  618                 bus_release_resource(dev, sc->vtpci_res_type, PCIR_BAR(0),
  619                     sc->vtpci_res);
  620                 sc->vtpci_res = NULL;
  621         }
  622 }
  623 
  624 static void
  625 vtpci_legacy_probe_and_attach_child(struct vtpci_legacy_softc *sc)
  626 {
  627         device_t dev, child;
  628 
  629         dev = sc->vtpci_dev;
  630         child = vtpci_child_device(&sc->vtpci_common);
  631 
  632         if (child == NULL || device_get_state(child) != DS_NOTPRESENT)
  633                 return;
  634 
  635         if (device_probe(child) != 0)
  636                 return;
  637 
  638         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER);
  639 
  640         if (device_attach(child) != 0) {
  641                 vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_FAILED);
  642                 /* Reset status for future attempt. */
  643                 vtpci_legacy_child_detached(dev, child);
  644         } else {
  645                 vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_DRIVER_OK);
  646                 VIRTIO_ATTACH_COMPLETED(child);
  647         }
  648 }
  649 
  650 static int
  651 vtpci_legacy_register_msix(struct vtpci_legacy_softc *sc, int offset,
  652     struct vtpci_interrupt *intr)
  653 {
  654         uint16_t vector;
  655 
  656         if (intr != NULL) {
  657                 /* Map from guest rid to host vector. */
  658                 vector = intr->vti_rid - 1;
  659         } else
  660                 vector = VIRTIO_MSI_NO_VECTOR;
  661 
  662         vtpci_legacy_write_header_2(sc, offset, vector);
  663         return (vtpci_legacy_read_header_2(sc, offset) == vector ? 0 : ENODEV);
  664 }
  665 
  666 static int
  667 vtpci_legacy_register_cfg_msix(device_t dev, struct vtpci_interrupt *intr)
  668 {
  669         struct vtpci_legacy_softc *sc;
  670         int error;
  671 
  672         sc = device_get_softc(dev);
  673 
  674         error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_CONFIG_VECTOR, intr);
  675         if (error) {
  676                 device_printf(dev,
  677                     "unable to register config MSIX interrupt\n");
  678                 return (error);
  679         }
  680 
  681         return (0);
  682 }
  683 
  684 static int
  685 vtpci_legacy_register_vq_msix(device_t dev, int idx,
  686     struct vtpci_interrupt *intr)
  687 {
  688         struct vtpci_legacy_softc *sc;
  689         int error;
  690 
  691         sc = device_get_softc(dev);
  692 
  693         vtpci_legacy_select_virtqueue(sc, idx);
  694         error = vtpci_legacy_register_msix(sc, VIRTIO_MSI_QUEUE_VECTOR, intr);
  695         if (error) {
  696                 device_printf(dev,
  697                     "unable to register virtqueue MSIX interrupt\n");
  698                 return (error);
  699         }
  700 
  701         return (0);
  702 }
  703 
  704 static void
  705 vtpci_legacy_reset(struct vtpci_legacy_softc *sc)
  706 {
  707         /*
  708          * Setting the status to RESET sets the host device to the
  709          * original, uninitialized state.
  710          */
  711         vtpci_legacy_set_status(sc, VIRTIO_CONFIG_STATUS_RESET);
  712         (void) vtpci_legacy_get_status(sc);
  713 }
  714 
  715 static void
  716 vtpci_legacy_select_virtqueue(struct vtpci_legacy_softc *sc, int idx)
  717 {
  718         vtpci_legacy_write_header_2(sc, VIRTIO_PCI_QUEUE_SEL, idx);
  719 }
  720 
  721 static uint8_t
  722 vtpci_legacy_read_isr(device_t dev)
  723 {
  724         struct vtpci_legacy_softc *sc;
  725 
  726         sc = device_get_softc(dev);
  727 
  728         return (vtpci_legacy_read_config_1(sc, VIRTIO_PCI_ISR));
  729 }
  730 
  731 static uint16_t
  732 vtpci_legacy_get_vq_size(device_t dev, int idx)
  733 {
  734         struct vtpci_legacy_softc *sc;
  735 
  736         sc = device_get_softc(dev);
  737 
  738         vtpci_legacy_select_virtqueue(sc, idx);
  739         return (vtpci_legacy_read_header_2(sc, VIRTIO_PCI_QUEUE_NUM));
  740 }
  741 
  742 static bus_size_t
  743 vtpci_legacy_get_vq_notify_off(device_t dev, int idx)
  744 {
  745         return (VIRTIO_PCI_QUEUE_NOTIFY);
  746 }
  747 
  748 static void
  749 vtpci_legacy_set_vq(device_t dev, struct virtqueue *vq)
  750 {
  751         struct vtpci_legacy_softc *sc;
  752 
  753         sc = device_get_softc(dev);
  754 
  755         vtpci_legacy_select_virtqueue(sc, virtqueue_index(vq));
  756         vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN,
  757             virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
  758 }
  759 
  760 static void
  761 vtpci_legacy_disable_vq(device_t dev, int idx)
  762 {
  763         struct vtpci_legacy_softc *sc;
  764 
  765         sc = device_get_softc(dev);
  766 
  767         vtpci_legacy_select_virtqueue(sc, idx);
  768         vtpci_legacy_write_header_4(sc, VIRTIO_PCI_QUEUE_PFN, 0);
  769 }

Cache object: 91b5ab8f1cc91dff41b75f25087abd2b


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