qemu/hw/vfio/ap.c
<<
>>
Prefs
   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
  33struct VFIOAPDevice {
  34    APDevice apdev;
  35    VFIODevice vdev;
  36};
  37
  38OBJECT_DECLARE_SIMPLE_TYPE(VFIOAPDevice, VFIO_AP_DEVICE)
  39
  40static 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 */
  49struct VFIODeviceOps vfio_ap_ops = {
  50    .vfio_compute_needs_reset = vfio_ap_compute_needs_reset,
  51};
  52
  53static void vfio_ap_put_device(VFIOAPDevice *vapdev)
  54{
  55    g_free(vapdev->vdev.name);
  56    vfio_put_base_device(&vapdev->vdev);
  57}
  58
  59static 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
  87static 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
 121out_get_dev_err:
 122    vfio_ap_put_device(vapdev);
 123    vfio_put_group(vfio_group);
 124}
 125
 126static 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
 136static Property vfio_ap_properties[] = {
 137    DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev),
 138    DEFINE_PROP_END_OF_LIST(),
 139};
 140
 141static 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
 154static const VMStateDescription vfio_ap_vmstate = {
 155    .name = "vfio-ap",
 156    .unmigratable = 1,
 157};
 158
 159static 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
 174static 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
 181static void vfio_ap_type_init(void)
 182{
 183    type_register_static(&vfio_ap_info);
 184}
 185
 186type_init(vfio_ap_type_init)
 187