qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

virtio-bus.c (10680B)


      1 /*
      2  * VirtioBus
      3  *
      4  *  Copyright (C) 2012 : GreenSocs Ltd
      5  *      http://www.greensocs.com/ , email: info@greensocs.com
      6  *
      7  *  Developed by :
      8  *  Frederic Konrad   <fred.konrad@greensocs.com>
      9  *
     10  * This program is free software; you can redistribute it and/or modify
     11  * it under the terms of the GNU General Public License as published by
     12  * the Free Software Foundation, either version 2 of the License, or
     13  * (at your option) any later version.
     14  *
     15  * This program is distributed in the hope that it will be useful,
     16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  * GNU General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU General Public License along
     21  * with this program; if not, see <http://www.gnu.org/licenses/>.
     22  *
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "qemu/error-report.h"
     27 #include "qemu/module.h"
     28 #include "qapi/error.h"
     29 #include "hw/virtio/virtio-bus.h"
     30 #include "hw/virtio/virtio.h"
     31 #include "exec/address-spaces.h"
     32 
     33 /* #define DEBUG_VIRTIO_BUS */
     34 
     35 #ifdef DEBUG_VIRTIO_BUS
     36 #define DPRINTF(fmt, ...) \
     37 do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
     38 #else
     39 #define DPRINTF(fmt, ...) do { } while (0)
     40 #endif
     41 
     42 /* A VirtIODevice is being plugged */
     43 void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
     44 {
     45     DeviceState *qdev = DEVICE(vdev);
     46     BusState *qbus = BUS(qdev_get_parent_bus(qdev));
     47     VirtioBusState *bus = VIRTIO_BUS(qbus);
     48     VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
     49     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
     50     bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
     51     bool vdev_has_iommu;
     52     Error *local_err = NULL;
     53 
     54     DPRINTF("%s: plug device.\n", qbus->name);
     55 
     56     if (klass->pre_plugged != NULL) {
     57         klass->pre_plugged(qbus->parent, &local_err);
     58         if (local_err) {
     59             error_propagate(errp, local_err);
     60             return;
     61         }
     62     }
     63 
     64     /* Get the features of the plugged device. */
     65     assert(vdc->get_features != NULL);
     66     vdev->host_features = vdc->get_features(vdev, vdev->host_features,
     67                                             &local_err);
     68     if (local_err) {
     69         error_propagate(errp, local_err);
     70         return;
     71     }
     72 
     73     if (klass->device_plugged != NULL) {
     74         klass->device_plugged(qbus->parent, &local_err);
     75     }
     76     if (local_err) {
     77         error_propagate(errp, local_err);
     78         return;
     79     }
     80 
     81     vdev->dma_as = &address_space_memory;
     82     if (has_iommu) {
     83         vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
     84         /*
     85          * Present IOMMU_PLATFORM to the driver iff iommu_plattform=on and
     86          * device operational. If the driver does not accept IOMMU_PLATFORM
     87          * we fail the device.
     88          */
     89         virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM);
     90         if (klass->get_dma_as) {
     91             vdev->dma_as = klass->get_dma_as(qbus->parent);
     92             if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) {
     93                 error_setg(errp,
     94                        "iommu_platform=true is not supported by the device");
     95                 return;
     96             }
     97         }
     98     }
     99 }
    100 
    101 /* Reset the virtio_bus */
    102 void virtio_bus_reset(VirtioBusState *bus)
    103 {
    104     VirtIODevice *vdev = virtio_bus_get_device(bus);
    105 
    106     DPRINTF("%s: reset device.\n", BUS(bus)->name);
    107     virtio_bus_stop_ioeventfd(bus);
    108     if (vdev != NULL) {
    109         virtio_reset(vdev);
    110     }
    111 }
    112 
    113 /* A VirtIODevice is being unplugged */
    114 void virtio_bus_device_unplugged(VirtIODevice *vdev)
    115 {
    116     DeviceState *qdev = DEVICE(vdev);
    117     BusState *qbus = BUS(qdev_get_parent_bus(qdev));
    118     VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus);
    119 
    120     DPRINTF("%s: remove device.\n", qbus->name);
    121 
    122     if (vdev != NULL) {
    123         if (klass->device_unplugged != NULL) {
    124             klass->device_unplugged(qbus->parent);
    125         }
    126     }
    127 }
    128 
    129 /* Get the device id of the plugged device. */
    130 uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
    131 {
    132     VirtIODevice *vdev = virtio_bus_get_device(bus);
    133     assert(vdev != NULL);
    134     return vdev->device_id;
    135 }
    136 
    137 /* Get the config_len field of the plugged device. */
    138 size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
    139 {
    140     VirtIODevice *vdev = virtio_bus_get_device(bus);
    141     assert(vdev != NULL);
    142     return vdev->config_len;
    143 }
    144 
    145 /* Get bad features of the plugged device. */
    146 uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
    147 {
    148     VirtIODevice *vdev = virtio_bus_get_device(bus);
    149     VirtioDeviceClass *k;
    150 
    151     assert(vdev != NULL);
    152     k = VIRTIO_DEVICE_GET_CLASS(vdev);
    153     if (k->bad_features != NULL) {
    154         return k->bad_features(vdev);
    155     } else {
    156         return 0;
    157     }
    158 }
    159 
    160 /* Get config of the plugged device. */
    161 void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
    162 {
    163     VirtIODevice *vdev = virtio_bus_get_device(bus);
    164     VirtioDeviceClass *k;
    165 
    166     assert(vdev != NULL);
    167     k = VIRTIO_DEVICE_GET_CLASS(vdev);
    168     if (k->get_config != NULL) {
    169         k->get_config(vdev, config);
    170     }
    171 }
    172 
    173 /* Set config of the plugged device. */
    174 void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
    175 {
    176     VirtIODevice *vdev = virtio_bus_get_device(bus);
    177     VirtioDeviceClass *k;
    178 
    179     assert(vdev != NULL);
    180     k = VIRTIO_DEVICE_GET_CLASS(vdev);
    181     if (k->set_config != NULL) {
    182         k->set_config(vdev, config);
    183     }
    184 }
    185 
    186 /* On success, ioeventfd ownership belongs to the caller.  */
    187 int virtio_bus_grab_ioeventfd(VirtioBusState *bus)
    188 {
    189     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    190 
    191     /* vhost can be used even if ioeventfd=off in the proxy device,
    192      * so do not check k->ioeventfd_enabled.
    193      */
    194     if (!k->ioeventfd_assign) {
    195         return -ENOSYS;
    196     }
    197 
    198     if (bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
    199         virtio_bus_stop_ioeventfd(bus);
    200         /* Remember that we need to restart ioeventfd
    201          * when ioeventfd_grabbed becomes zero.
    202          */
    203         bus->ioeventfd_started = true;
    204     }
    205     bus->ioeventfd_grabbed++;
    206     return 0;
    207 }
    208 
    209 void virtio_bus_release_ioeventfd(VirtioBusState *bus)
    210 {
    211     assert(bus->ioeventfd_grabbed != 0);
    212     if (--bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
    213         /* Force virtio_bus_start_ioeventfd to act.  */
    214         bus->ioeventfd_started = false;
    215         virtio_bus_start_ioeventfd(bus);
    216     }
    217 }
    218 
    219 int virtio_bus_start_ioeventfd(VirtioBusState *bus)
    220 {
    221     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    222     DeviceState *proxy = DEVICE(BUS(bus)->parent);
    223     VirtIODevice *vdev = virtio_bus_get_device(bus);
    224     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
    225     int r;
    226 
    227     if (!k->ioeventfd_assign || !k->ioeventfd_enabled(proxy)) {
    228         return -ENOSYS;
    229     }
    230     if (bus->ioeventfd_started) {
    231         return 0;
    232     }
    233 
    234     /* Only set our notifier if we have ownership.  */
    235     if (!bus->ioeventfd_grabbed) {
    236         r = vdc->start_ioeventfd(vdev);
    237         if (r < 0) {
    238             error_report("%s: failed. Fallback to userspace (slower).", __func__);
    239             return r;
    240         }
    241     }
    242     bus->ioeventfd_started = true;
    243     return 0;
    244 }
    245 
    246 void virtio_bus_stop_ioeventfd(VirtioBusState *bus)
    247 {
    248     VirtIODevice *vdev;
    249     VirtioDeviceClass *vdc;
    250 
    251     if (!bus->ioeventfd_started) {
    252         return;
    253     }
    254 
    255     /* Only remove our notifier if we have ownership.  */
    256     if (!bus->ioeventfd_grabbed) {
    257         vdev = virtio_bus_get_device(bus);
    258         vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
    259         vdc->stop_ioeventfd(vdev);
    260     }
    261     bus->ioeventfd_started = false;
    262 }
    263 
    264 bool virtio_bus_ioeventfd_enabled(VirtioBusState *bus)
    265 {
    266     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    267     DeviceState *proxy = DEVICE(BUS(bus)->parent);
    268 
    269     return k->ioeventfd_assign && k->ioeventfd_enabled(proxy);
    270 }
    271 
    272 /*
    273  * This function switches ioeventfd on/off in the device.
    274  * The caller must set or clear the handlers for the EventNotifier.
    275  */
    276 int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign)
    277 {
    278     VirtIODevice *vdev = virtio_bus_get_device(bus);
    279     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
    280     DeviceState *proxy = DEVICE(BUS(bus)->parent);
    281     VirtQueue *vq = virtio_get_queue(vdev, n);
    282     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
    283     int r = 0;
    284 
    285     if (!k->ioeventfd_assign) {
    286         return -ENOSYS;
    287     }
    288 
    289     if (assign) {
    290         r = event_notifier_init(notifier, 1);
    291         if (r < 0) {
    292             error_report("%s: unable to init event notifier: %s (%d)",
    293                          __func__, strerror(-r), r);
    294             return r;
    295         }
    296         r = k->ioeventfd_assign(proxy, notifier, n, true);
    297         if (r < 0) {
    298             error_report("%s: unable to assign ioeventfd: %d", __func__, r);
    299             virtio_bus_cleanup_host_notifier(bus, n);
    300         }
    301     } else {
    302         k->ioeventfd_assign(proxy, notifier, n, false);
    303     }
    304 
    305     if (r == 0) {
    306         virtio_queue_set_host_notifier_enabled(vq, assign);
    307     }
    308 
    309     return r;
    310 }
    311 
    312 void virtio_bus_cleanup_host_notifier(VirtioBusState *bus, int n)
    313 {
    314     VirtIODevice *vdev = virtio_bus_get_device(bus);
    315     VirtQueue *vq = virtio_get_queue(vdev, n);
    316     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
    317 
    318     /* Test and clear notifier after disabling event,
    319      * in case poll callback didn't have time to run.
    320      */
    321     virtio_queue_host_notifier_read(notifier);
    322     event_notifier_cleanup(notifier);
    323 }
    324 
    325 static char *virtio_bus_get_dev_path(DeviceState *dev)
    326 {
    327     BusState *bus = qdev_get_parent_bus(dev);
    328     DeviceState *proxy = DEVICE(bus->parent);
    329     return qdev_get_dev_path(proxy);
    330 }
    331 
    332 static char *virtio_bus_get_fw_dev_path(DeviceState *dev)
    333 {
    334     return NULL;
    335 }
    336 
    337 bool virtio_bus_device_iommu_enabled(VirtIODevice *vdev)
    338 {
    339     DeviceState *qdev = DEVICE(vdev);
    340     BusState *qbus = BUS(qdev_get_parent_bus(qdev));
    341     VirtioBusState *bus = VIRTIO_BUS(qbus);
    342     VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
    343 
    344     if (!klass->iommu_enabled) {
    345         return false;
    346     }
    347 
    348     return klass->iommu_enabled(qbus->parent);
    349 }
    350 
    351 static void virtio_bus_class_init(ObjectClass *klass, void *data)
    352 {
    353     BusClass *bus_class = BUS_CLASS(klass);
    354     bus_class->get_dev_path = virtio_bus_get_dev_path;
    355     bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
    356 }
    357 
    358 static const TypeInfo virtio_bus_info = {
    359     .name = TYPE_VIRTIO_BUS,
    360     .parent = TYPE_BUS,
    361     .instance_size = sizeof(VirtioBusState),
    362     .abstract = true,
    363     .class_size = sizeof(VirtioBusClass),
    364     .class_init = virtio_bus_class_init
    365 };
    366 
    367 static void virtio_register_types(void)
    368 {
    369     type_register_static(&virtio_bus_info);
    370 }
    371 
    372 type_init(virtio_register_types)