19fca2b7dSJohn Levon /* 29fca2b7dSJohn Levon * Container for vfio-user IOMMU type: rather than communicating with the kernel 39fca2b7dSJohn Levon * vfio driver, we communicate over a socket to a server using the vfio-user 49fca2b7dSJohn Levon * protocol. 59fca2b7dSJohn Levon * 69fca2b7dSJohn Levon * SPDX-License-Identifier: GPL-2.0-or-later 79fca2b7dSJohn Levon */ 89fca2b7dSJohn Levon 99fca2b7dSJohn Levon #include <sys/ioctl.h> 109fca2b7dSJohn Levon #include <linux/vfio.h> 119fca2b7dSJohn Levon #include "qemu/osdep.h" 129fca2b7dSJohn Levon 139fca2b7dSJohn Levon #include "hw/vfio-user/container.h" 143bdb738bSJohn Levon #include "hw/vfio-user/device.h" 159fca2b7dSJohn Levon #include "hw/vfio/vfio-cpr.h" 169fca2b7dSJohn Levon #include "hw/vfio/vfio-device.h" 179fca2b7dSJohn Levon #include "hw/vfio/vfio-listener.h" 189fca2b7dSJohn Levon #include "qapi/error.h" 199fca2b7dSJohn Levon 209fca2b7dSJohn Levon static int vfio_user_dma_unmap(const VFIOContainerBase *bcontainer, 219fca2b7dSJohn Levon hwaddr iova, ram_addr_t size, 229fca2b7dSJohn Levon IOMMUTLBEntry *iotlb, bool unmap_all) 239fca2b7dSJohn Levon { 249fca2b7dSJohn Levon return -ENOTSUP; 259fca2b7dSJohn Levon } 269fca2b7dSJohn Levon 279fca2b7dSJohn Levon static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova, 289fca2b7dSJohn Levon ram_addr_t size, void *vaddr, bool readonly, 299fca2b7dSJohn Levon MemoryRegion *mrp) 309fca2b7dSJohn Levon { 319fca2b7dSJohn Levon return -ENOTSUP; 329fca2b7dSJohn Levon } 339fca2b7dSJohn Levon 349fca2b7dSJohn Levon static int 359fca2b7dSJohn Levon vfio_user_set_dirty_page_tracking(const VFIOContainerBase *bcontainer, 369fca2b7dSJohn Levon bool start, Error **errp) 379fca2b7dSJohn Levon { 389fca2b7dSJohn Levon error_setg_errno(errp, ENOTSUP, "Not supported"); 399fca2b7dSJohn Levon return -ENOTSUP; 409fca2b7dSJohn Levon } 419fca2b7dSJohn Levon 429fca2b7dSJohn Levon static int vfio_user_query_dirty_bitmap(const VFIOContainerBase *bcontainer, 439fca2b7dSJohn Levon VFIOBitmap *vbmap, hwaddr iova, 449fca2b7dSJohn Levon hwaddr size, Error **errp) 459fca2b7dSJohn Levon { 469fca2b7dSJohn Levon error_setg_errno(errp, ENOTSUP, "Not supported"); 479fca2b7dSJohn Levon return -ENOTSUP; 489fca2b7dSJohn Levon } 499fca2b7dSJohn Levon 509fca2b7dSJohn Levon static bool vfio_user_setup(VFIOContainerBase *bcontainer, Error **errp) 519fca2b7dSJohn Levon { 52*52ce9c35SJohn Levon VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer, 53*52ce9c35SJohn Levon bcontainer); 54*52ce9c35SJohn Levon 55*52ce9c35SJohn Levon assert(container->proxy->dma_pgsizes != 0); 56*52ce9c35SJohn Levon bcontainer->pgsizes = container->proxy->dma_pgsizes; 57*52ce9c35SJohn Levon bcontainer->dma_max_mappings = container->proxy->max_dma; 58*52ce9c35SJohn Levon 59*52ce9c35SJohn Levon /* No live migration support yet. */ 60*52ce9c35SJohn Levon bcontainer->dirty_pages_supported = false; 61*52ce9c35SJohn Levon bcontainer->max_dirty_bitmap_size = container->proxy->max_bitmap; 62*52ce9c35SJohn Levon bcontainer->dirty_pgsizes = container->proxy->migr_pgsize; 63*52ce9c35SJohn Levon 64*52ce9c35SJohn Levon return true; 659fca2b7dSJohn Levon } 669fca2b7dSJohn Levon 67*52ce9c35SJohn Levon static VFIOUserContainer *vfio_user_create_container(VFIODevice *vbasedev, 68*52ce9c35SJohn Levon Error **errp) 699fca2b7dSJohn Levon { 709fca2b7dSJohn Levon VFIOUserContainer *container; 719fca2b7dSJohn Levon 729fca2b7dSJohn Levon container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER)); 73*52ce9c35SJohn Levon container->proxy = vbasedev->proxy; 749fca2b7dSJohn Levon return container; 759fca2b7dSJohn Levon } 769fca2b7dSJohn Levon 779fca2b7dSJohn Levon /* 789fca2b7dSJohn Levon * Try to mirror vfio_container_connect() as much as possible. 799fca2b7dSJohn Levon */ 809fca2b7dSJohn Levon static VFIOUserContainer * 81*52ce9c35SJohn Levon vfio_user_container_connect(AddressSpace *as, VFIODevice *vbasedev, 82*52ce9c35SJohn Levon Error **errp) 839fca2b7dSJohn Levon { 849fca2b7dSJohn Levon VFIOContainerBase *bcontainer; 859fca2b7dSJohn Levon VFIOUserContainer *container; 869fca2b7dSJohn Levon VFIOAddressSpace *space; 879fca2b7dSJohn Levon VFIOIOMMUClass *vioc; 88*52ce9c35SJohn Levon int ret; 899fca2b7dSJohn Levon 909fca2b7dSJohn Levon space = vfio_address_space_get(as); 919fca2b7dSJohn Levon 92*52ce9c35SJohn Levon container = vfio_user_create_container(vbasedev, errp); 939fca2b7dSJohn Levon if (!container) { 949fca2b7dSJohn Levon goto put_space_exit; 959fca2b7dSJohn Levon } 969fca2b7dSJohn Levon 979fca2b7dSJohn Levon bcontainer = &container->bcontainer; 989fca2b7dSJohn Levon 999fca2b7dSJohn Levon if (!vfio_cpr_register_container(bcontainer, errp)) { 1009fca2b7dSJohn Levon goto free_container_exit; 1019fca2b7dSJohn Levon } 1029fca2b7dSJohn Levon 103*52ce9c35SJohn Levon ret = ram_block_uncoordinated_discard_disable(true); 104*52ce9c35SJohn Levon if (ret) { 105*52ce9c35SJohn Levon error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken"); 106*52ce9c35SJohn Levon goto unregister_container_exit; 107*52ce9c35SJohn Levon } 108*52ce9c35SJohn Levon 1099fca2b7dSJohn Levon vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 1109fca2b7dSJohn Levon assert(vioc->setup); 1119fca2b7dSJohn Levon 1129fca2b7dSJohn Levon if (!vioc->setup(bcontainer, errp)) { 113*52ce9c35SJohn Levon goto enable_discards_exit; 1149fca2b7dSJohn Levon } 1159fca2b7dSJohn Levon 1169fca2b7dSJohn Levon vfio_address_space_insert(space, bcontainer); 1179fca2b7dSJohn Levon 1189fca2b7dSJohn Levon if (!vfio_listener_register(bcontainer, errp)) { 1199fca2b7dSJohn Levon goto listener_release_exit; 1209fca2b7dSJohn Levon } 1219fca2b7dSJohn Levon 1229fca2b7dSJohn Levon bcontainer->initialized = true; 1239fca2b7dSJohn Levon 1249fca2b7dSJohn Levon return container; 1259fca2b7dSJohn Levon 1269fca2b7dSJohn Levon listener_release_exit: 1279fca2b7dSJohn Levon vfio_listener_unregister(bcontainer); 1289fca2b7dSJohn Levon if (vioc->release) { 1299fca2b7dSJohn Levon vioc->release(bcontainer); 1309fca2b7dSJohn Levon } 1319fca2b7dSJohn Levon 132*52ce9c35SJohn Levon enable_discards_exit: 133*52ce9c35SJohn Levon ram_block_uncoordinated_discard_disable(false); 134*52ce9c35SJohn Levon 1359fca2b7dSJohn Levon unregister_container_exit: 1369fca2b7dSJohn Levon vfio_cpr_unregister_container(bcontainer); 1379fca2b7dSJohn Levon 1389fca2b7dSJohn Levon free_container_exit: 1399fca2b7dSJohn Levon object_unref(container); 1409fca2b7dSJohn Levon 1419fca2b7dSJohn Levon put_space_exit: 1429fca2b7dSJohn Levon vfio_address_space_put(space); 1439fca2b7dSJohn Levon 1449fca2b7dSJohn Levon return NULL; 1459fca2b7dSJohn Levon } 1469fca2b7dSJohn Levon 1479fca2b7dSJohn Levon static void vfio_user_container_disconnect(VFIOUserContainer *container) 1489fca2b7dSJohn Levon { 1499fca2b7dSJohn Levon VFIOContainerBase *bcontainer = &container->bcontainer; 1509fca2b7dSJohn Levon VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 151*52ce9c35SJohn Levon VFIOAddressSpace *space = bcontainer->space; 152*52ce9c35SJohn Levon 153*52ce9c35SJohn Levon ram_block_uncoordinated_discard_disable(false); 1549fca2b7dSJohn Levon 1559fca2b7dSJohn Levon vfio_listener_unregister(bcontainer); 1569fca2b7dSJohn Levon if (vioc->release) { 1579fca2b7dSJohn Levon vioc->release(bcontainer); 1589fca2b7dSJohn Levon } 1599fca2b7dSJohn Levon 1609fca2b7dSJohn Levon vfio_cpr_unregister_container(bcontainer); 1619fca2b7dSJohn Levon object_unref(container); 1629fca2b7dSJohn Levon 1639fca2b7dSJohn Levon vfio_address_space_put(space); 1649fca2b7dSJohn Levon } 1659fca2b7dSJohn Levon 1669fca2b7dSJohn Levon static bool vfio_user_device_get(VFIOUserContainer *container, 1679fca2b7dSJohn Levon VFIODevice *vbasedev, Error **errp) 1689fca2b7dSJohn Levon { 1693bdb738bSJohn Levon struct vfio_device_info info = { .argsz = sizeof(info) }; 1703bdb738bSJohn Levon 1713bdb738bSJohn Levon 1723bdb738bSJohn Levon if (!vfio_user_get_device_info(vbasedev->proxy, &info, errp)) { 1733bdb738bSJohn Levon return false; 1743bdb738bSJohn Levon } 1759fca2b7dSJohn Levon 1769fca2b7dSJohn Levon vbasedev->fd = -1; 1779fca2b7dSJohn Levon 1789fca2b7dSJohn Levon vfio_device_prepare(vbasedev, &container->bcontainer, &info); 1799fca2b7dSJohn Levon 1809fca2b7dSJohn Levon return true; 1819fca2b7dSJohn Levon } 1829fca2b7dSJohn Levon 1839fca2b7dSJohn Levon /* 1849fca2b7dSJohn Levon * vfio_user_device_attach: attach a device to a new container. 1859fca2b7dSJohn Levon */ 1869fca2b7dSJohn Levon static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev, 1879fca2b7dSJohn Levon AddressSpace *as, Error **errp) 1889fca2b7dSJohn Levon { 1899fca2b7dSJohn Levon VFIOUserContainer *container; 1909fca2b7dSJohn Levon 191*52ce9c35SJohn Levon container = vfio_user_container_connect(as, vbasedev, errp); 1929fca2b7dSJohn Levon if (container == NULL) { 1939fca2b7dSJohn Levon error_prepend(errp, "failed to connect proxy"); 1949fca2b7dSJohn Levon return false; 1959fca2b7dSJohn Levon } 1969fca2b7dSJohn Levon 1979fca2b7dSJohn Levon return vfio_user_device_get(container, vbasedev, errp); 1989fca2b7dSJohn Levon } 1999fca2b7dSJohn Levon 2009fca2b7dSJohn Levon static void vfio_user_device_detach(VFIODevice *vbasedev) 2019fca2b7dSJohn Levon { 2029fca2b7dSJohn Levon VFIOUserContainer *container = container_of(vbasedev->bcontainer, 2039fca2b7dSJohn Levon VFIOUserContainer, bcontainer); 2049fca2b7dSJohn Levon 2059fca2b7dSJohn Levon vfio_device_unprepare(vbasedev); 2069fca2b7dSJohn Levon 2079fca2b7dSJohn Levon vfio_user_container_disconnect(container); 2089fca2b7dSJohn Levon } 2099fca2b7dSJohn Levon 2109fca2b7dSJohn Levon static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single) 2119fca2b7dSJohn Levon { 2129fca2b7dSJohn Levon /* ->needs_reset is always false for vfio-user. */ 2139fca2b7dSJohn Levon return 0; 2149fca2b7dSJohn Levon } 2159fca2b7dSJohn Levon 2169fca2b7dSJohn Levon static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data) 2179fca2b7dSJohn Levon { 2189fca2b7dSJohn Levon VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); 2199fca2b7dSJohn Levon 2209fca2b7dSJohn Levon vioc->setup = vfio_user_setup; 2219fca2b7dSJohn Levon vioc->dma_map = vfio_user_dma_map; 2229fca2b7dSJohn Levon vioc->dma_unmap = vfio_user_dma_unmap; 2239fca2b7dSJohn Levon vioc->attach_device = vfio_user_device_attach; 2249fca2b7dSJohn Levon vioc->detach_device = vfio_user_device_detach; 2259fca2b7dSJohn Levon vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking; 2269fca2b7dSJohn Levon vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap; 2279fca2b7dSJohn Levon vioc->pci_hot_reset = vfio_user_pci_hot_reset; 2289fca2b7dSJohn Levon }; 2299fca2b7dSJohn Levon 2309fca2b7dSJohn Levon static const TypeInfo types[] = { 2319fca2b7dSJohn Levon { 2329fca2b7dSJohn Levon .name = TYPE_VFIO_IOMMU_USER, 2339fca2b7dSJohn Levon .parent = TYPE_VFIO_IOMMU, 2349fca2b7dSJohn Levon .instance_size = sizeof(VFIOUserContainer), 2359fca2b7dSJohn Levon .class_init = vfio_iommu_user_class_init, 2369fca2b7dSJohn Levon }, 2379fca2b7dSJohn Levon }; 2389fca2b7dSJohn Levon 2399fca2b7dSJohn Levon DEFINE_TYPES(types) 240