qemu

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

ap.c (4863B)


      1 /*
      2  * VFIO based AP matrix device assignment
      3  *
      4  * Copyright 2018 IBM Corp.
      5  * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
      6  *            Halil Pasic <pasic@linux.ibm.com>
      7  *
      8  * This work is licensed under the terms of the GNU GPL, version 2 or (at
      9  * your option) any later version. See the COPYING file in the top-level
     10  * directory.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include <linux/vfio.h>
     15 #include <sys/ioctl.h>
     16 #include "qapi/error.h"
     17 #include "hw/vfio/vfio.h"
     18 #include "hw/vfio/vfio-common.h"
     19 #include "hw/s390x/ap-device.h"
     20 #include "qemu/error-report.h"
     21 #include "qemu/module.h"
     22 #include "qemu/option.h"
     23 #include "qemu/config-file.h"
     24 #include "kvm/kvm_s390x.h"
     25 #include "migration/vmstate.h"
     26 #include "hw/qdev-properties.h"
     27 #include "hw/s390x/ap-bridge.h"
     28 #include "exec/address-spaces.h"
     29 #include "qom/object.h"
     30 
     31 #define TYPE_VFIO_AP_DEVICE      "vfio-ap"
     32 
     33 struct VFIOAPDevice {
     34     APDevice apdev;
     35     VFIODevice vdev;
     36 };
     37 
     38 OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE)
     39 
     40 static void vfio_ap_compute_needs_reset(VFIODevice *vdev)
     41 {
     42     vdev->needs_reset = false;
     43 }
     44 
     45 /*
     46  * We don't need vfio_hot_reset_multi and vfio_eoi operations for
     47  * vfio-ap device now.
     48  */
     49 struct VFIODeviceOps vfio_ap_ops = {
     50     .vfio_compute_needs_reset = vfio_ap_compute_needs_reset,
     51 };
     52 
     53 static void vfio_ap_put_device(VFIOAPDevice *vapdev)
     54 {
     55     g_free(vapdev->vdev.name);
     56     vfio_put_base_device(&vapdev->vdev);
     57 }
     58 
     59 static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp)
     60 {
     61     GError *gerror = NULL;
     62     char *symlink, *group_path;
     63     int groupid;
     64 
     65     symlink = g_strdup_printf("%s/iommu_group", vapdev->vdev.sysfsdev);
     66     group_path = g_file_read_link(symlink, &gerror);
     67     g_free(symlink);
     68 
     69     if (!group_path) {
     70         error_setg(errp, "%s: no iommu_group found for %s: %s",
     71                    TYPE_VFIO_AP_DEVICE, vapdev->vdev.sysfsdev, gerror->message);
     72         g_error_free(gerror);
     73         return NULL;
     74     }
     75 
     76     if (sscanf(basename(group_path), "%d", &groupid) != 1) {
     77         error_setg(errp, "vfio: failed to read %s", group_path);
     78         g_free(group_path);
     79         return NULL;
     80     }
     81 
     82     g_free(group_path);
     83 
     84     return vfio_get_group(groupid, &address_space_memory, errp);
     85 }
     86 
     87 static void vfio_ap_realize(DeviceState *dev, Error **errp)
     88 {
     89     int ret;
     90     char *mdevid;
     91     VFIOGroup *vfio_group;
     92     APDevice *apdev = AP_DEVICE(dev);
     93     VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev);
     94 
     95     vfio_group = vfio_ap_get_group(vapdev, errp);
     96     if (!vfio_group) {
     97         return;
     98     }
     99 
    100     vapdev->vdev.ops = &vfio_ap_ops;
    101     vapdev->vdev.type = VFIO_DEVICE_TYPE_AP;
    102     mdevid = basename(vapdev->vdev.sysfsdev);
    103     vapdev->vdev.name = g_strdup_printf("%s", mdevid);
    104     vapdev->vdev.dev = dev;
    105 
    106     /*
    107      * vfio-ap devices operate in a way compatible with discarding of
    108      * memory in RAM blocks, as no pages are pinned in the host.
    109      * This needs to be set before vfio_get_device() for vfio common to
    110      * handle ram_block_discard_disable().
    111      */
    112     vapdev->vdev.ram_block_discard_allowed = true;
    113 
    114     ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, errp);
    115     if (ret) {
    116         goto out_get_dev_err;
    117     }
    118 
    119     return;
    120 
    121 out_get_dev_err:
    122     vfio_ap_put_device(vapdev);
    123     vfio_put_group(vfio_group);
    124 }
    125 
    126 static void vfio_ap_unrealize(DeviceState *dev)
    127 {
    128     APDevice *apdev = AP_DEVICE(dev);
    129     VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev);
    130     VFIOGroup *group = vapdev->vdev.group;
    131 
    132     vfio_ap_put_device(vapdev);
    133     vfio_put_group(group);
    134 }
    135 
    136 static Property vfio_ap_properties[] = {
    137     DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev),
    138     DEFINE_PROP_END_OF_LIST(),
    139 };
    140 
    141 static void vfio_ap_reset(DeviceState *dev)
    142 {
    143     int ret;
    144     APDevice *apdev = AP_DEVICE(dev);
    145     VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev);
    146 
    147     ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET);
    148     if (ret) {
    149         error_report("%s: failed to reset %s device: %s", __func__,
    150                      vapdev->vdev.name, strerror(errno));
    151     }
    152 }
    153 
    154 static const VMStateDescription vfio_ap_vmstate = {
    155     .name = "vfio-ap",
    156     .unmigratable = 1,
    157 };
    158 
    159 static void vfio_ap_class_init(ObjectClass *klass, void *data)
    160 {
    161     DeviceClass *dc = DEVICE_CLASS(klass);
    162 
    163     device_class_set_props(dc, vfio_ap_properties);
    164     dc->vmsd = &vfio_ap_vmstate;
    165     dc->desc = "VFIO-based AP device assignment";
    166     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    167     dc->realize = vfio_ap_realize;
    168     dc->unrealize = vfio_ap_unrealize;
    169     dc->hotpluggable = true;
    170     dc->reset = vfio_ap_reset;
    171     dc->bus_type = TYPE_AP_BUS;
    172 }
    173 
    174 static const TypeInfo vfio_ap_info = {
    175     .name = TYPE_VFIO_AP_DEVICE,
    176     .parent = TYPE_AP_DEVICE,
    177     .instance_size = sizeof(VFIOAPDevice),
    178     .class_init = vfio_ap_class_init,
    179 };
    180 
    181 static void vfio_ap_type_init(void)
    182 {
    183     type_register_static(&vfio_ap_info);
    184 }
    185 
    186 type_init(vfio_ap_type_init)