mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-20 16:42:04 -06:00

Add support for getting basic device information. Originally-by: John Johnson <john.g.johnson@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John Levon <john.levon@nutanix.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250625193012.2316242-6-john.levon@nutanix.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
214 lines
5.5 KiB
C
214 lines
5.5 KiB
C
/*
|
|
* Container for vfio-user IOMMU type: rather than communicating with the kernel
|
|
* vfio driver, we communicate over a socket to a server using the vfio-user
|
|
* protocol.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <linux/vfio.h>
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "hw/vfio-user/container.h"
|
|
#include "hw/vfio-user/device.h"
|
|
#include "hw/vfio/vfio-cpr.h"
|
|
#include "hw/vfio/vfio-device.h"
|
|
#include "hw/vfio/vfio-listener.h"
|
|
#include "qapi/error.h"
|
|
|
|
static int vfio_user_dma_unmap(const VFIOContainerBase *bcontainer,
|
|
hwaddr iova, ram_addr_t size,
|
|
IOMMUTLBEntry *iotlb, bool unmap_all)
|
|
{
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
|
|
ram_addr_t size, void *vaddr, bool readonly,
|
|
MemoryRegion *mrp)
|
|
{
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
static int
|
|
vfio_user_set_dirty_page_tracking(const VFIOContainerBase *bcontainer,
|
|
bool start, Error **errp)
|
|
{
|
|
error_setg_errno(errp, ENOTSUP, "Not supported");
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
static int vfio_user_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
|
VFIOBitmap *vbmap, hwaddr iova,
|
|
hwaddr size, Error **errp)
|
|
{
|
|
error_setg_errno(errp, ENOTSUP, "Not supported");
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
static bool vfio_user_setup(VFIOContainerBase *bcontainer, Error **errp)
|
|
{
|
|
error_setg_errno(errp, ENOTSUP, "Not supported");
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
static VFIOUserContainer *vfio_user_create_container(Error **errp)
|
|
{
|
|
VFIOUserContainer *container;
|
|
|
|
container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER));
|
|
return container;
|
|
}
|
|
|
|
/*
|
|
* Try to mirror vfio_container_connect() as much as possible.
|
|
*/
|
|
static VFIOUserContainer *
|
|
vfio_user_container_connect(AddressSpace *as, Error **errp)
|
|
{
|
|
VFIOContainerBase *bcontainer;
|
|
VFIOUserContainer *container;
|
|
VFIOAddressSpace *space;
|
|
VFIOIOMMUClass *vioc;
|
|
|
|
space = vfio_address_space_get(as);
|
|
|
|
container = vfio_user_create_container(errp);
|
|
if (!container) {
|
|
goto put_space_exit;
|
|
}
|
|
|
|
bcontainer = &container->bcontainer;
|
|
|
|
if (!vfio_cpr_register_container(bcontainer, errp)) {
|
|
goto free_container_exit;
|
|
}
|
|
|
|
vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
|
|
assert(vioc->setup);
|
|
|
|
if (!vioc->setup(bcontainer, errp)) {
|
|
goto unregister_container_exit;
|
|
}
|
|
|
|
vfio_address_space_insert(space, bcontainer);
|
|
|
|
if (!vfio_listener_register(bcontainer, errp)) {
|
|
goto listener_release_exit;
|
|
}
|
|
|
|
bcontainer->initialized = true;
|
|
|
|
return container;
|
|
|
|
listener_release_exit:
|
|
vfio_listener_unregister(bcontainer);
|
|
if (vioc->release) {
|
|
vioc->release(bcontainer);
|
|
}
|
|
|
|
unregister_container_exit:
|
|
vfio_cpr_unregister_container(bcontainer);
|
|
|
|
free_container_exit:
|
|
object_unref(container);
|
|
|
|
put_space_exit:
|
|
vfio_address_space_put(space);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void vfio_user_container_disconnect(VFIOUserContainer *container)
|
|
{
|
|
VFIOContainerBase *bcontainer = &container->bcontainer;
|
|
VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
|
|
|
|
vfio_listener_unregister(bcontainer);
|
|
if (vioc->release) {
|
|
vioc->release(bcontainer);
|
|
}
|
|
|
|
VFIOAddressSpace *space = bcontainer->space;
|
|
|
|
vfio_cpr_unregister_container(bcontainer);
|
|
object_unref(container);
|
|
|
|
vfio_address_space_put(space);
|
|
}
|
|
|
|
static bool vfio_user_device_get(VFIOUserContainer *container,
|
|
VFIODevice *vbasedev, Error **errp)
|
|
{
|
|
struct vfio_device_info info = { .argsz = sizeof(info) };
|
|
|
|
|
|
if (!vfio_user_get_device_info(vbasedev->proxy, &info, errp)) {
|
|
return false;
|
|
}
|
|
|
|
vbasedev->fd = -1;
|
|
|
|
vfio_device_prepare(vbasedev, &container->bcontainer, &info);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* vfio_user_device_attach: attach a device to a new container.
|
|
*/
|
|
static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev,
|
|
AddressSpace *as, Error **errp)
|
|
{
|
|
VFIOUserContainer *container;
|
|
|
|
container = vfio_user_container_connect(as, errp);
|
|
if (container == NULL) {
|
|
error_prepend(errp, "failed to connect proxy");
|
|
return false;
|
|
}
|
|
|
|
return vfio_user_device_get(container, vbasedev, errp);
|
|
}
|
|
|
|
static void vfio_user_device_detach(VFIODevice *vbasedev)
|
|
{
|
|
VFIOUserContainer *container = container_of(vbasedev->bcontainer,
|
|
VFIOUserContainer, bcontainer);
|
|
|
|
vfio_device_unprepare(vbasedev);
|
|
|
|
vfio_user_container_disconnect(container);
|
|
}
|
|
|
|
static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single)
|
|
{
|
|
/* ->needs_reset is always false for vfio-user. */
|
|
return 0;
|
|
}
|
|
|
|
static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data)
|
|
{
|
|
VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
|
|
|
|
vioc->setup = vfio_user_setup;
|
|
vioc->dma_map = vfio_user_dma_map;
|
|
vioc->dma_unmap = vfio_user_dma_unmap;
|
|
vioc->attach_device = vfio_user_device_attach;
|
|
vioc->detach_device = vfio_user_device_detach;
|
|
vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking;
|
|
vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap;
|
|
vioc->pci_hot_reset = vfio_user_pci_hot_reset;
|
|
};
|
|
|
|
static const TypeInfo types[] = {
|
|
{
|
|
.name = TYPE_VFIO_IOMMU_USER,
|
|
.parent = TYPE_VFIO_IOMMU,
|
|
.instance_size = sizeof(VFIOUserContainer),
|
|
.class_init = vfio_iommu_user_class_init,
|
|
},
|
|
};
|
|
|
|
DEFINE_TYPES(types)
|