Andrey Ryabinin <a...@yandex-team.com> writes:

> Add vfio-group type and allow user to create such object via
> '-object' command line argument or 'object-add' qmp command.
> Parameters are:
>  - @fd - file descriptor
>  - @container - id of vfio-container object which will be used for
>         this VFIO group
>  - @groupid - number representing IOMMU group (no needed if @fd
>                                            and @container were provided)
> E.g.:
>      -object vfio-container,id=ct,fd=5 \
>      -object vfio-group,id=group,fd=6,container=ct
>
> Signed-off-by: Andrey Ryabinin <a...@yandex-team.com>
> ---
>  hw/vfio/common.c              | 267 +++++++++++++++++++++++-----------
>  hw/vfio/trace-events          |   2 +-
>  include/hw/vfio/vfio-common.h |   4 +
>  qapi/qom.json                 |  15 ++
>  4 files changed, 205 insertions(+), 83 deletions(-)
>
> diff --git a/hw/vfio/common.c b/hw/vfio/common.c
> index 392057d3025..95722ecf96a 100644
> --- a/hw/vfio/common.c
> +++ b/hw/vfio/common.c
> @@ -1911,31 +1911,40 @@ static int vfio_init_container(VFIOContainer 
> *container, int group_fd,
>                                 Error **errp)
>  {
>      int iommu_type, ret;
> +    struct vfio_group_status status = { .argsz = sizeof(status) };
>  
>      iommu_type = vfio_get_iommu_type(container, errp);
>      if (iommu_type < 0) {
>          return iommu_type;
>      }
>  
> -    ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER, &container->fd);
> +
> +    ret = ioctl(group_fd, VFIO_GROUP_GET_STATUS, &status);
>      if (ret) {
> -        error_setg_errno(errp, errno, "Failed to set group container");
> +        error_setg_errno(errp, errno, "Failed to get group status");
>          return -errno;
>      }
> -
> -    while (ioctl(container->fd, VFIO_SET_IOMMU, iommu_type)) {
> -        if (iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) {
> -            /*
> -             * On sPAPR, despite the IOMMU subdriver always advertises v1 and
> -             * v2, the running platform may not support v2 and there is no
> -             * way to guess it until an IOMMU group gets added to the 
> container.
> -             * So in case it fails with v2, try v1 as a fallback.
> -             */
> -            iommu_type = VFIO_SPAPR_TCE_IOMMU;
> -            continue;
> +    if (!(status.flags & VFIO_GROUP_FLAGS_CONTAINER_SET)) {
> +        ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER, &container->fd);
> +        if (ret) {
> +            error_setg_errno(errp, errno, "Failed to set group container");
> +            return -errno;
> +        }
> +
> +        while (ioctl(container->fd, VFIO_SET_IOMMU, iommu_type)) {
> +            if (iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) {
> +                /*
> +                 * On sPAPR, despite the IOMMU subdriver always advertises 
> v1 and
> +                 * v2, the running platform may not support v2 and there is 
> no
> +                 * way to guess it until an IOMMU group gets added to the 
> container.
> +                 * So in case it fails with v2, try v1 as a fallback.
> +                 */
> +                iommu_type = VFIO_SPAPR_TCE_IOMMU;
> +                continue;
> +            }
> +            error_setg_errno(errp, errno, "Failed to set iommu for 
> container");
> +            return -errno;
>          }
> -        error_setg_errno(errp, errno, "Failed to set iommu for container");
> -        return -errno;
>      }
>  
>      container->iommu_type = iommu_type;
> @@ -2050,34 +2059,44 @@ static int vfio_connect_container(VFIOGroup *group, 
> AddressSpace *as,
>       * with some IOMMU types. vfio_ram_block_discard_disable() handles the
>       * details once we know which type of IOMMU we are using.
>       */
> -
> -    QLIST_FOREACH(container, &space->containers, next) {
> -        if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
> -            ret = vfio_ram_block_discard_disable(container, true);
> -            if (ret) {
> -                error_setg_errno(errp, -ret,
> -                                 "Cannot set discarding of RAM broken");
> -                if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER,
> -                          &container->fd)) {
> -                    error_report("vfio: error disconnecting group %d from"
> -                                 " container", group->groupid);
> +    if (!group->container) {
> +        QLIST_FOREACH(container, &space->containers, next) {
> +            if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) 
> {
> +                ret = vfio_ram_block_discard_disable(container, true);
> +                if (ret) {
> +                    error_setg_errno(errp, -ret,
> +                                     "Cannot set discarding of RAM broken");
> +                    if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER,
> +                              &container->fd)) {
> +                        error_report("vfio: error disconnecting group %d 
> from"
> +                                     " container", group->groupid);
> +                    }
> +                    return ret;
>                  }
> -                return ret;
> +                group->container = container;
> +                QLIST_INSERT_HEAD(&container->group_list, group, 
> container_next);
> +                vfio_kvm_device_add_group(group);
> +                return 0;
>              }
> -            group->container = container;
> -            QLIST_INSERT_HEAD(&container->group_list, group, container_next);
> -            vfio_kvm_device_add_group(group);
> -            return 0;
>          }
> -    }
> +        container = VFIO_CONTAINER(object_new(TYPE_VFIO_CONTAINER));
> +        container->space = space;
>  
> -    container = VFIO_CONTAINER(object_new(TYPE_VFIO_CONTAINER));
> -    container->space = space;
> -
> -    user_creatable_complete(USER_CREATABLE(container), errp);
> -    if (*errp) {
> -        ret = -1;
> -        goto free_container_exit;
> +        user_creatable_complete(USER_CREATABLE(container), errp);
> +        if (*errp) {
> +            ret = -1;
> +            goto free_container_exit;
> +        }
> +        group->container = container;
> +    } else if (group->container->initialized) {
> +        object_ref(OBJECT(group->container));
> +        QLIST_INSERT_HEAD(&group->container->group_list, group, 
> container_next);
> +        vfio_kvm_device_add_group(group);
> +        return 0;
> +    } else {
> +        container = group->container;
> +        container->space = space;
> +        object_ref(OBJECT(container));
>      }
>  
>      ret = vfio_init_container(container, group->fd, errp);
> @@ -2228,6 +2247,10 @@ static void vfio_disconnect_container(VFIOGroup *group)
>  {
>      VFIOContainer *container = group->container;
>  
> +    if (!group->container) {
> +            return;
> +    }
> +
>      QLIST_REMOVE(group, container_next);
>      group->container = NULL;
>  
> @@ -2251,7 +2274,6 @@ static void vfio_disconnect_container(VFIOGroup *group)
>  VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp)
>  {
>      VFIOGroup *group;
> -    char path[32];
>      struct vfio_group_status status = { .argsz = sizeof(status) };
>  
>      QLIST_FOREACH(group, &vfio_group_list, next) {
> @@ -2267,31 +2289,14 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace 
> *as, Error **errp)
>          }
>      }
>  
> -    group = g_malloc0(sizeof(*group));
> -
> -    snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
> -    group->fd = qemu_open_old(path, O_RDWR);
> -    if (group->fd < 0) {
> -        error_setg_errno(errp, errno, "failed to open %s", path);
> -        goto free_group_exit;
> -    }
> -
> -    if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
> -        error_setg_errno(errp, errno, "failed to get group %d status", 
> groupid);
> -        goto close_fd_exit;
> -    }
> -
> -    if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
> -        error_setg(errp, "group %d is not viable", groupid);
> -        error_append_hint(errp,
> -                          "Please ensure all devices within the iommu_group "
> -                          "are bound to their vfio bus driver.\n");
> -        goto close_fd_exit;
> +    group = VFIO_GROUP(object_new(TYPE_VFIO_GROUP));
> +    object_property_set_int(OBJECT(group), "groupid", groupid, errp);
> +    user_creatable_complete(USER_CREATABLE(group), errp);
> +    if (*errp) {
> +        object_unref(OBJECT(group));
> +        return NULL;
>      }
>  
> -    group->groupid = groupid;
> -    QLIST_INIT(&group->device_list);
> -
>      if (vfio_connect_container(group, as, errp)) {
>          error_prepend(errp, "failed to setup container for group %d: ",
>                        groupid);
> @@ -2302,15 +2307,10 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace 
> *as, Error **errp)
>          qemu_register_reset(vfio_reset_handler, NULL);
>      }
>  
> -    QLIST_INSERT_HEAD(&vfio_group_list, group, next);
> -
>      return group;
>  
>  close_fd_exit:
> -    close(group->fd);
> -
> -free_group_exit:
> -    g_free(group);
> +    object_unref(OBJECT(group));
>  
>      return NULL;
>  }
> @@ -2321,19 +2321,7 @@ void vfio_put_group(VFIOGroup *group)
>          return;
>      }
>  
> -    if (!group->ram_block_discard_allowed) {
> -        vfio_ram_block_discard_disable(group->container, false);
> -    }
> -    vfio_kvm_device_del_group(group);
> -    vfio_disconnect_container(group);
> -    QLIST_REMOVE(group, next);
> -    trace_vfio_put_group(group->fd);
> -    close(group->fd);
> -    g_free(group);
> -
> -    if (QLIST_EMPTY(&vfio_group_list)) {
> -        qemu_unregister_reset(vfio_reset_handler, NULL);
> -    }
> +    object_unref(OBJECT(group));
>  }
>  
>  int vfio_get_device(VFIOGroup *group, const char *name,

Like in the previous patch, you do more than the commit message
says.  Could you split it off into a separate commit?

> @@ -2676,8 +2664,123 @@ static const TypeInfo vfio_container_info = {
>      },
>  };
>  
> +static void vfio_group_set_fd(Object *obj, const char *value,
> +                              Error **errp)
> +{
> +    VFIOGroup *group = VFIO_GROUP(obj);
> +
> +    group->fd = monitor_fd_param(monitor_cur(), value, errp);
> +}
> +
> +static void vfio_group_set_groupid(Object *obj, Visitor *v,
> +                                   const char *name, void *opaque,
> +                                   Error **errp)
> +{
> +    VFIOGroup *group = VFIO_GROUP(obj);
> +    Error *error = NULL;
> +    uint32_t groupid;
> +
> +    visit_type_uint32(v, name, &groupid, &error);
> +    if (error) {
> +        error_propagate(errp, error);
> +        return;
> +    }
> +
> +    group->groupid = groupid;
> +}
> +
> +static void vfio_group_complete(UserCreatable *uc, Error **errp)
> +{
> +    VFIOGroup *group = VFIO_GROUP(uc);
> +    struct vfio_group_status status = { .argsz = sizeof(status) };
> +
> +    if (group->fd < 0 && group->groupid >= 0) {
> +        char path[32];
> +
> +        snprintf(path, sizeof(path), "/dev/vfio/%d", group->groupid);
> +
> +        group->fd = qemu_open_old(path, O_RDWR);
> +        if (group->fd < 0) {
> +            error_setg_errno(errp, errno, "failed to open %s", path);
> +            return;
> +        }
> +    }
> +
> +    if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
> +        error_setg_errno(errp, errno, "failed to get group %d status", 
> group->groupid);
> +        return;
> +    }
> +
> +    if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
> +        error_setg(errp, "group %d is not viable", group->groupid);
> +        error_append_hint(errp,
> +                          "Please ensure all devices within the iommu_group "
> +                          "are bound to their vfio bus driver.\n");
> +    }
> +}
> +
> +static void vfio_group_class_init(ObjectClass *class, void *data)
> +{
> +    UserCreatableClass *ucc = USER_CREATABLE_CLASS(class);
> +    ucc->complete = vfio_group_complete;
> +
> +    object_class_property_add_link(class, "container", TYPE_VFIO_CONTAINER,
> +                                   offsetof(VFIOGroup, container),
> +                                   object_property_allow_set_link, 0);
> +    object_class_property_add_str(class, "fd", NULL, vfio_group_set_fd);
> +    object_class_property_add(class, "groupid", "int", NULL,
> +                              vfio_group_set_groupid,
> +                              NULL, NULL);
> +}
> +
> +static void vfio_group_instance_init(Object *obj)
> +{
> +    VFIOGroup *group = VFIO_GROUP(obj);
> +
> +    QLIST_INIT(&group->device_list);
> +    group->fd = -1;
> +    group->groupid = -1;
> +    QLIST_INSERT_HEAD(&vfio_group_list, group, next);
> +}
> +
> +static void
> +vfio_group_instance_finalize(Object *obj)
> +{
> +    VFIOGroup *group = VFIO_GROUP(obj);
> +
> +    if (!group->ram_block_discard_allowed) {
> +        vfio_ram_block_discard_disable(group->container, false);
> +    }
> +
> +    vfio_kvm_device_del_group(group);
> +    vfio_disconnect_container(group);
> +    QLIST_REMOVE(group, next);
> +    trace_vfio_group_instance_finalize(group->fd);
> +    if (group->fd >= 0) {
> +        close(group->fd);
> +    }
> +
> +    if (QLIST_EMPTY(&vfio_group_list)) {
> +        qemu_unregister_reset(vfio_reset_handler, NULL);
> +    }
> +}
> +
> +static const TypeInfo vfio_group_info = {
> +    .name = TYPE_VFIO_GROUP,
> +    .parent = TYPE_OBJECT,
> +    .class_init = vfio_group_class_init,
> +    .instance_size = sizeof(VFIOGroup),
> +    .instance_init = vfio_group_instance_init,
> +    .instance_finalize = vfio_group_instance_finalize,
> +    .interfaces = (InterfaceInfo[]) {
> +        {TYPE_USER_CREATABLE},
> +        {}
> +    },
> +};
> +
>  static void register_vfio_types(void)
>  {
>      type_register_static(&vfio_container_info);
> +    type_register_static(&vfio_group_info);
>  }
>  type_init(register_vfio_types)
> diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
> index 8b79cf33a33..6ae0ed09acd 100644
> --- a/hw/vfio/trace-events
> +++ b/hw/vfio/trace-events
> @@ -105,7 +105,7 @@ vfio_listener_region_add_no_dma_map(const char *name, 
> uint64_t iova, uint64_t si
>  vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING 
> region_del 0x%"PRIx64" - 0x%"PRIx64
>  vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 
> 0x%"PRIx64" - 0x%"PRIx64
>  vfio_container_instance_finalize(int fd) "close container->fd=%d"
> -vfio_put_group(int fd) "close group->fd=%d"
> +vfio_group_instance_finalize(int fd) "close group->fd=%d"
>  vfio_get_device(const char * name, unsigned int flags, unsigned int 
> num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: 
> %u"
>  vfio_put_base_device(int fd) "close vdev->fd=%d"
>  vfio_region_setup(const char *dev, int index, const char *name, unsigned 
> long flags, unsigned long offset, unsigned long size) "Device %s, region %d 
> \"%s\", flags: 0x%lx, offset: 0x%lx, size: 0x%lx"
> diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
> index 0ab99060e44..f2d67093f44 100644
> --- a/include/hw/vfio/vfio-common.h
> +++ b/include/hw/vfio/vfio-common.h
> @@ -156,6 +156,7 @@ struct VFIODeviceOps {
>  };
>  
>  typedef struct VFIOGroup {
> +    Object parent;
>      int fd;
>      int groupid;
>      VFIOContainer *container;
> @@ -194,6 +195,9 @@ typedef struct VFIODisplay {
>  #define TYPE_VFIO_CONTAINER "vfio-container"
>  OBJECT_DECLARE_SIMPLE_TYPE(VFIOContainer, VFIO_CONTAINER)
>  
> +#define TYPE_VFIO_GROUP "vfio-group"
> +OBJECT_DECLARE_SIMPLE_TYPE(VFIOGroup, VFIO_GROUP)
> +
>  void vfio_put_base_device(VFIODevice *vbasedev);
>  void vfio_disable_irqindex(VFIODevice *vbasedev, int index);
>  void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index);

This morphs struct VFIOGroup into a QOM object.

> diff --git a/qapi/qom.json b/qapi/qom.json
> index d1a88e10b52..f46dd6b8034 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -746,6 +746,19 @@
>  { 'struct': 'VFIOContainerProperties',
>    'data': { 'fd': 'str' } }
>  
> +##
> +# @VFIOGroupProperties:
> +#
> +# Properties for vfio-group objects.
> +#
> +# @fd: file descriptor of vfio group
> +# @container: container

Try again.

If you think this review comment is too terse to be useful, you're
right!  So is your doc comment ;)

> +#
> +# Since: 7.2
> +##
> +{ 'struct': 'VFIOGroupProperties',
> +  'data': { 'fd': 'str', 'container': 'str'} }
> +
>  ##
>  # @VfioUserServerProperties:
>  #
> @@ -901,6 +914,7 @@
>      'tls-creds-x509',
>      'tls-cipher-suites',
>      'vfio-container',
> +    'vfio-group',
>      { 'name': 'x-remote-object', 'features': [ 'unstable' ] },
>      { 'name': 'x-vfio-user-server', 'features': [ 'unstable' ] }
>    ] }
> @@ -967,6 +981,7 @@
>        'tls-creds-x509':             'TlsCredsX509Properties',
>        'tls-cipher-suites':          'TlsCredsProperties',
>        'vfio-container':             'VFIOContainerProperties',
> +      'vfio-group':                 'VFIOGroupProperties',
>        'x-remote-object':            'RemoteObjectProperties',
>        'x-vfio-user-server':         'VfioUserServerProperties'
>    } }


Reply via email to