Support VFIO cdev API in DPDK
Subsystems (5)
PATCH v9 3/19 vfio: split get device info from setup
In reply to Anatoly BurakovCurrently, setup gets device info as part of setup, while the separate get device info API also calls setup if the fd is zero. Untangle these two APIs and make each do one thing, and adjust all existing callers.
--- drivers/bus/cdx/cdx_vfio.c | 12 ++++++++-- drivers/bus/pci/linux/pci_vfio.c | 18 ++++++++++---- drivers/bus/platform/platform.c | 9 ++++++- drivers/crypto/bcmfs/bcmfs_vfio.c | 8 ++++++- lib/eal/freebsd/eal.c | 3 +-- lib/eal/include/rte_vfio.h | 23 +++++++----------- lib/eal/linux/eal_vfio.c | 40 +++++++++---------------------- 7 files changed, 59 insertions(+), 54 deletions(-)
drivers/bus/cdx/cdx_vfio.c +10 -2
@@ -401,10 +401,14 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev)return -1 ; ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* allocate vfio_res and get region info */ vfio_res =rte_zmalloc ("VFIO_RES" ,sizeof (*vfio_res),0 );if (vfio_res ==NULL ) {
@@ -510,10 +514,14 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev) } ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* map MMIO regions */ maps = vfio_res->maps;
drivers/bus/pci/linux/pci_vfio.c +14 -4
@@ -753,10 +753,14 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev) loc->domain, loc->bus, loc->devid, loc->function); ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd)) goto err_vfio_dev_fd;
@@ -962,10 +966,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) } ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; + ret =pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info);if (ret) goto err_vfio_dev;
@@ -1195,12 +1203,14 @@ pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,if (vfio_dev_fd <0 ) {return -1 ; }else if (vfio_dev_fd ==0 ) { -if (rte_vfio_get_device_info (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info) !=0 ) +if (rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, + &vfio_dev_fd) !=0 )return -1 ;/* save vfio_dev_fd so it can be used during release */ if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd) !=0 )return -1 ; +if (rte_vfio_get_device_info (vfio_dev_fd, &device_info) !=0 ) +return -1 ;if (pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info) !=0 )return -1 ;
drivers/bus/platform/platform.c +8 -1
@@ -292,12 +292,19 @@ device_setup(struct rte_platform_device *pdev)const char *name = pdev->name;int ret; - ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd, &dev_info); + ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd);if (ret) {PLATFORM_LOG_LINE (ERR ,"failed to setup %s" , name);return -ENODEV ; } + ret =rte_vfio_get_device_info (pdev->dev_fd, &dev_info); +if (ret) { +PLATFORM_LOG_LINE (ERR ,"failed to get device info for %s" , name); + ret = -ENODEV ; + goto out; + } +/* This is an extra check to confirm that platform device was initialized * by a kernel vfio-platform driver. On kernels that predate vfio-platform * driver this flag obviously does not exist. In such scenarios this
drivers/crypto/bcmfs/bcmfs_vfio.c +7 -1
@@ -25,12 +25,18 @@ vfio_map_dev_obj(const char *path, const char *dev_obj,struct vfio_device_info d_info = { .argsz =sizeof (d_info) };struct vfio_region_info reg_info = { .argsz =sizeof (reg_info) }; - ret =rte_vfio_setup_device (path, dev_obj, dev_fd, &d_info); + ret =rte_vfio_setup_device (path, dev_obj, dev_fd);if (ret) {BCMFS_LOG (ERR ,"VFIO Setting for device failed" );return ret; } + ret =rte_vfio_get_device_info (*dev_fd, &d_info); +if (ret) { +BCMFS_LOG (ERR ,"VFIO Getting device info failed" ); + goto map_failed; + } +/* getting device region info*/ ret =ioctl (*dev_fd,VFIO_DEVICE_GET_REGION_INFO , ®_info);if (ret <0 ) {
lib/eal/freebsd/eal.c +1 -2
@@ -822,8 +822,7 @@ rte_eal_vfio_get_vf_token(__rte_unused rte_uuid_t vf_token)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, - __rte_unused int *vfio_dev_fd, - __rte_unused struct vfio_device_info *device_info) + __rte_unused int *vfio_dev_fd) { rte_errno =ENOTSUP ;return -1 ;
lib/eal/include/rte_vfio.h +8 -15
@@ -55,10 +55,7 @@ struct vfio_device_info;* device location. * * @param vfio_dev_fd -* VFIO fd. -* -* @param device_info -* Device information. +* Pointer to VFIO fd, will be set to the opened device fd on success. * * @return * 0 on success.
@@ -67,7 +64,7 @@ struct vfio_device_info;*/ __rte_internal int rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +int *vfio_dev_fd);/** * @internal
@@ -187,19 +184,16 @@ rte_vfio_get_group_num(const char *sysfs_base,* @internal * Get device information. * +* This function retrieves VFIO device information from an already opened +* device. The device must be opened with rte_vfio_setup_device() first. +* * This function is only relevant to Linux and will return an error on BSD. * -* @param sysfs_base -* sysfs path prefix. -* -* @param dev_addr -* device location. -* * @param vfio_dev_fd -* VFIO fd. +* VFIO device fd (must be a valid, already opened fd). * * @param device_info -* Device information. +* Pointer to device information structure to be filled. * * @return * 0 on success.
@@ -207,8 +201,7 @@ rte_vfio_get_group_num(const char *sysfs_base,*/ __rte_internal int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info);/** * @internal
lib/eal/linux/eal_vfio.c +11 -29
@@ -758,7 +758,7 @@ rte_vfio_clear_group(int vfio_group_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) intrte_vfio_setup_device (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +int *vfio_dev_fd) {struct vfio_group_status group_status = { .argsz =sizeof (group_status)
@@ -975,7 +975,7 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, *vfio_dev_fd =ioctl (vfio_group_fd,VFIO_GROUP_GET_DEVICE_FD , dev);if (*vfio_dev_fd >=0 ) - goto dev_get_info; + goto out; }/* get a file descriptor for the device */
@@ -992,18 +992,8 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,return -1 ; } -/* test and setup the device */ -dev_get_info: - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, " -"error %i (%s)" , dev_addr, errno, -strerror (errno)); -close (*vfio_dev_fd); -close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); -return -1 ; - } +/* device is now set up */ +out:vfio_group_device_get (vfio_group_fd);return 0 ;
@@ -1217,26 +1207,18 @@ vfio_set_iommu_type(int vfio_container_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info) {int ret; -if (device_info ==NULL || *vfio_dev_fd <0 ) +if (device_info ==NULL || vfio_dev_fd <0 )return -1 ; -if (*vfio_dev_fd ==0 ) { - ret =rte_vfio_setup_device (sysfs_base, dev_addr, - vfio_dev_fd, device_info); -if (ret) -return -1 ; - }else { - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, error %i (%s)" , - dev_addr, errno,strerror (errno)); -return -1 ; - } + ret =ioctl (vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); +if (ret) { +EAL_LOG (ERR ,"Cannot get device info, error %i (%s)" , + errno,strerror (errno)); +return -1 ; }return 0 ;
Signature · 1 line
2.52.0
PATCH v9 4/19 vfio: add container device assignment API
In reply to Anatoly BurakovCurrently, VFIO has explicit group bind API's, but the way they're used is such that no one actually cares about VFIO groups, and the real goal of everyone using VFIO group bind API is to bind devices to particular VFIO container, such that when rte_vfio_setup_device call eventually comes, VFIO will pick up the correct container.
To remove dependency on group API's, add a new "container assign device" API call that will do the same thing, but will not depend on managing VFIO group fd's.
--- lib/eal/freebsd/eal.c | 10 ++++++++++ lib/eal/include/rte_vfio.h | 26 ++++++++++++++++++++++++++ lib/eal/linux/eal_vfio.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+)
lib/eal/freebsd/eal.c +10 -0
@@ -944,3 +944,13 @@ rte_vfio_container_dma_unmap(__rte_unused int container_fd, rte_errno =ENOTSUP ;return -1 ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device(__rte_unused int vfio_container_fd, + __rte_unused const char *sysfs_base, + __rte_unused const char *dev_addr) +{ + rte_errno =ENOTSUP ; +return -1 ; +}
lib/eal/include/rte_vfio.h +26 -0
@@ -271,6 +271,32 @@ __rte_internalint rte_vfio_container_destroy (int container_fd); +/** +* @internal +* +* Assign a device to a VFIO container. +* +* Doing so will cause `rte_vfio_setup_device()` to set up the device with the VFIO container +* specified in this assign operation. +* +* This function is only relevant on Linux. +* +* @param vfio_container_fd +* VFIO container file descriptor. +* @param sysfs_base +* Sysfs path prefix. +* @param dev_addr +* Device identifier. +* +* @return +* 0 on success. +* <0 on failure. +*/ +__rte_internal +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr); +/** * @internal * Bind a IOMMU group to a container.
lib/eal/linux/eal_vfio.c +32 -0
@@ -2102,6 +2102,38 @@ rte_vfio_container_destroy(int container_fd)return 0 ; } +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr) +{ +int iommu_group_num; +int ret; + + ret =rte_vfio_get_group_num (sysfs_base, dev_addr, &iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR ,"Cannot get IOMMU group number for device %s" , + dev_addr); +return -1 ; + }else if (ret ==0 ) { +EAL_LOG (ERR , +"Device %s is not assigned to any IOMMU group" , + dev_addr); +return -1 ; + } + + ret =rte_vfio_container_group_bind (vfio_container_fd, + iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR , +"Cannot bind IOMMU group %d for device %s" , + iommu_group_num, dev_addr); +return -1 ; + } + +return 0 ; +} +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) intrte_vfio_container_group_bind (int container_fd,int iommu_group_num)
Signature · 1 line
2.52.0
PATCH v9 5/19 net/nbl: do not use VFIO group bind API
In reply to Anatoly BurakovThe NBL driver currently uses group bind API, but it is using it only to get group fd and nothing else. In context of NBL driver, this is the only usage of VFIO API's in the driver, and it is not necessary to use it for what NBL driver is trying to accomplish.
Use a direct open() call instead, and store the group fd in common structure.
--- drivers/net/nbl/nbl_common/nbl_userdev.c | 19 ++++++++++++------- drivers/net/nbl/nbl_include/nbl_include.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-)
drivers/net/nbl/nbl_common/nbl_userdev.c +12 -7
@@ -387,6 +387,14 @@ nbl_userdev_mem_event_callback(enum rte_mem_event type, const void *addr, size_t } } +static int +nbl_open_group_fd (int iommu_group_num) +{ +char path[PATH_MAX ]; +snprintf (path,sizeof (path),RTE_VFIO_GROUP_FMT , iommu_group_num); +return open (path,O_RDWR ); +} +static int nbl_mdev_map_device (struct nbl_adapter *adapter) {const struct rte_pci_device *pci_dev = adapter->pci_dev;
@@ -424,11 +432,12 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) }NBL_LOG (DEBUG ,"nbl vfio container %d" , container); - vfio_group_fd =rte_vfio_container_group_bind (container, common->iommu_group_num); + vfio_group_fd =nbl_open_group_fd (common->iommu_group_num);if (vfio_group_fd <0 ) {NBL_LOG (ERR ,"nbl vfio group bind failed, %d" , vfio_group_fd); goto free_container; } + common->groupfd = vfio_group_fd;/* check if the group is viable */ ret =ioctl (vfio_group_fd,VFIO_GROUP_GET_STATUS , &group_status);
@@ -535,7 +544,6 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) } free_group:close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); free_container:if (container_create)rte_vfio_container_destroy (container);
@@ -549,17 +557,14 @@ static int nbl_mdev_unmap_device(struct nbl_adapter *adapter)close (common->devfd);rte_mcfg_mem_read_lock (); - vfio_group_fd =rte_vfio_container_group_bind (nbl_default_container, - common->iommu_group_num); + vfio_group_fd = common->groupfd;NBL_LOG (DEBUG ,"close vfio_group_fd %d" , vfio_group_fd); ret =ioctl (vfio_group_fd,VFIO_GROUP_UNSET_CONTAINER , &nbl_default_container);if (ret)NBL_LOG (ERR ,"unset container, error %i (%s) %d" , errno,strerror (errno), ret); nbl_group_count--; - ret =rte_vfio_container_group_unbind (nbl_default_container, common->iommu_group_num); -if (ret) -NBL_LOG (ERR ,"vfio container group unbind failed %d" , ret); +close (vfio_group_fd);if (!nbl_group_count) {rte_mem_event_callback_unregister (NBL_USERDEV_EVENT_CLB_NAME ,NULL );nbl_userdev_dma_free ();
drivers/net/nbl/nbl_include/nbl_include.h +1 -0
@@ -132,6 +132,7 @@ struct nbl_common_info {u16 vsi_id;u16 instance_id;int devfd; +int groupfd;int eventfd;int ifindex;int iommu_group_num;
Signature · 1 line
2.52.0
PATCH v9 6/19 net/ntnic: use container device assignment API
In reply to Anatoly BurakovThe NTNIC driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/net/ntnic/ntnic_vfio.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-)
drivers/net/ntnic/ntnic_vfio.c +9 -21
@@ -28,7 +28,6 @@ nt_vfio_vf_num(const struct rte_pci_device *pdev)/* Internal API */ struct vfio_dev {int container_fd; -int group_fd;int dev_fd;uint64_t iova_addr; };
@@ -50,7 +49,6 @@ nthw_vfio_setup(struct rte_pci_device *dev) {int ret;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num;int vf_num;struct vfio_dev *vfio;
@@ -66,14 +64,9 @@ nthw_vfio_setup(struct rte_pci_device *dev) } vfio->dev_fd =-1 ; - vfio->group_fd =-1 ; vfio->iova_addr =START_VF_IOVA ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, &iommu_group_num); -if (ret <=0 ) -return -1 ; -if (vf_num ==0 ) {/* use default container for pf0 */ vfio->container_fd =RTE_VFIO_DEFAULT_CONTAINER_FD ;
@@ -86,17 +79,14 @@ nthw_vfio_setup(struct rte_pci_device *dev) "VFIO device setup failed. VFIO container creation failed.");return -1 ; } - } + ret =rte_vfio_container_assign_device (vfio->container_fd, +rte_pci_get_sysfs_path (), devname); +if (ret <0 ) { +NT_LOG (ERR ,NTNIC , +"VFIO device setup failed. Assign device to container failed." ); + goto err; + } - vfio->group_fd =rte_vfio_container_group_bind (vfio->container_fd, iommu_group_num); - -if (vfio->group_fd <0 ) { -NT_LOG (ERR ,NTNIC , -"VFIO device setup failed. VFIO container group bind failed." ); - goto err; - } - -if (vf_num >0 ) {if (rte_pci_map_device (dev)) {NT_LOG (ERR ,NTNIC ,"Map VFIO device failed. is the vfio-pci driver loaded?" );
@@ -106,10 +96,8 @@ nthw_vfio_setup(struct rte_pci_device *dev) vfio->dev_fd =rte_intr_dev_fd_get (dev->intr_handle); -NT_LOG (DBG ,NTNIC , -"%s: VFIO id=%d, dev_fd=%d, container_fd=%d, group_fd=%d, iommu_group_num=%d" , - dev->name, vf_num, vfio->dev_fd, vfio->container_fd, vfio->group_fd, - iommu_group_num); +NT_LOG (DBG ,NTNIC ,"%s: VFIO id=%d, dev_fd=%d, container_fd=%d" , + dev->name, vf_num, vfio->dev_fd, vfio->container_fd);return vf_num;
Signature · 1 line
2.52.0
PATCH v9 7/19 vdpa/ifc: use container device assignment API
In reply to Anatoly BurakovThe IFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-)
drivers/vdpa/ifc/ifcvf_vdpa.c +3 -31
@@ -58,7 +58,6 @@ struct ifcvf_internal {struct ifcvf_hw hw;int configured;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd;rte_thread_t tid;/* thread for notify relay */ rte_thread_t intr_tid;/* thread for config space change interrupt relay */
@@ -174,28 +173,19 @@ ifcvf_vfio_setup(struct ifcvf_internal *internal) {struct rte_pci_device *dev = internal->pdev;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num; -int i, ret; +int i; internal->vfio_dev_fd =-1 ; - internal->vfio_group_fd =-1 ; internal->vfio_container_fd =-1 ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, - &iommu_group_num); -if (ret <=0 ) { -DRV_LOG (ERR ,"%s failed to get IOMMU group" , devname); -return -1 ; - } internal->vfio_container_fd =rte_vfio_container_create ();if (internal->vfio_container_fd <0 )return -1 ; - internal->vfio_group_fd =rte_vfio_container_group_bind ( - internal->vfio_container_fd, iommu_group_num); -if (internal->vfio_group_fd <0 ) +if (rte_vfio_container_assign_device (internal->vfio_container_fd, +rte_pci_get_sysfs_path (), devname) <0 ) goto err;if (rte_pci_map_device (dev))
@@ -1213,22 +1203,6 @@ ifcvf_set_features(int vid)return 0 ; } -static int -ifcvf_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct internal_list *list; - - vdev =rte_vhost_get_vdpa_device (vid); - list =find_internal_resource_by_vdev (vdev); -if (list ==NULL ) { -DRV_LOG (ERR ,"Invalid vDPA device: %p" , vdev); -return -1 ; - } - -return list->internal->vfio_group_fd; -} -static int ifcvf_get_vfio_device_fd (int vid) {
@@ -1474,7 +1448,6 @@ static struct rte_vdpa_dev_ops ifcvf_net_ops = { .set_vring_state = ifcvf_set_vring_state, .set_features = ifcvf_set_features, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_dev_type = ifcvf_get_device_type,
@@ -1605,7 +1578,6 @@ static struct rte_vdpa_dev_ops ifcvf_blk_ops = { .dev_close = ifcvf_dev_close, .set_vring_state = ifcvf_set_vring_state, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_config = ifcvf_blk_get_config,
Signature · 1 line
2.52.0
PATCH v9 8/19 vdpa/nfp: use container device assignment API
In reply to Anatoly BurakovThe NFP vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/nfp/nfp_vdpa.c | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-)
drivers/vdpa/nfp/nfp_vdpa.c +5 -32
@@ -36,9 +36,7 @@ struct nfp_vdpa_dev {struct nfp_vdpa_hw hw;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd; -int iommu_group;rte_thread_t tid;/**< Thread for notify relay */ int epoll_fd;
@@ -122,33 +120,26 @@ nfp_vdpa_vfio_setup(struct nfp_vdpa_dev *device)rte_pci_unmap_device (pci_dev);rte_pci_device_name (&pci_dev->addr, dev_name,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &device->iommu_group); -if (ret <=0 ) -return -1 ; device->vfio_container_fd =rte_vfio_container_create ();if (device->vfio_container_fd <0 )return -1 ; - device->vfio_group_fd =rte_vfio_container_group_bind ( - device->vfio_container_fd, device->iommu_group); -if (device->vfio_group_fd <0 ) + ret =rte_vfio_container_assign_device (device->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (ret <0 ) goto container_destroy; -DRV_VDPA_LOG (DEBUG ,"The container_fd=%d, group_fd=%d." , - device->vfio_container_fd, device->vfio_group_fd); +DRV_VDPA_LOG (DEBUG ,"container_fd=%d" , device->vfio_container_fd); ret =rte_pci_map_device (pci_dev);if (ret !=0 ) - goto group_unbind; + goto container_destroy; device->vfio_dev_fd =rte_intr_dev_fd_get (pci_dev->intr_handle);return 0 ; -group_unbind: -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group); container_destroy:rte_vfio_container_destroy (device->vfio_container_fd);
@@ -159,7 +150,6 @@ static void nfp_vdpa_vfio_teardown(struct nfp_vdpa_dev *device) {rte_pci_unmap_device (device->pci_dev); -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group);rte_vfio_container_destroy (device->vfio_container_fd); }
@@ -1025,22 +1015,6 @@ nfp_vdpa_dev_close(int vid)return 0 ; } -static int -nfp_vdpa_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct nfp_vdpa_dev_node *node; - - vdev =rte_vhost_get_vdpa_device (vid); - node =nfp_vdpa_find_node_by_vdev (vdev); -if (node ==NULL ) { -DRV_VDPA_LOG (ERR ,"Invalid vDPA device: %p." , vdev); -return -ENODEV ; - } - -return node->device->vfio_group_fd; -} -static int nfp_vdpa_get_vfio_device_fd (int vid) {
@@ -1192,7 +1166,6 @@ struct rte_vdpa_dev_ops nfp_vdpa_ops = { .dev_close = nfp_vdpa_dev_close, .set_vring_state = nfp_vdpa_set_vring_state, .set_features = nfp_vdpa_set_features, - .get_vfio_group_fd = nfp_vdpa_get_vfio_group_fd, .get_vfio_device_fd = nfp_vdpa_get_vfio_device_fd, .get_notify_area = nfp_vdpa_get_notify_area, };
Signature · 1 line
2.52.0
PATCH v9 9/19 vdpa/sfc: use container device assignment API
In reply to Anatoly BurakovThe SFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/vdpa/sfc/sfc_vdpa.c | 39 +++++++------------------------------ drivers/vdpa/sfc/sfc_vdpa.h | 2 -- 2 files changed, 7 insertions(+), 34 deletions(-)
drivers/vdpa/sfc/sfc_vdpa.c +7 -32
@@ -80,22 +80,12 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva) goto fail_container_create; } - rc =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &sva->iommu_group_num); -if (rc <=0 ) { -sfc_vdpa_err (sva,"failed to get IOMMU group for %s : %s" , - dev_name,rte_strerror (-rc)); - goto fail_get_group_num; - } - - sva->vfio_group_fd = -rte_vfio_container_group_bind (sva->vfio_container_fd, - sva->iommu_group_num); -if (sva->vfio_group_fd <0 ) { -sfc_vdpa_err (sva, -"failed to bind IOMMU group %d to container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - goto fail_group_bind; + rc =rte_vfio_container_assign_device (sva->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (rc <0 ) { +sfc_vdpa_err (sva,"failed to assign device %s to container %d" , + dev_name, sva->vfio_container_fd); + goto fail_device_assign; }if (rte_pci_map_device (dev) !=0 ) {
@@ -109,15 +99,7 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva)return 0 ; fail_pci_map_device: -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } - -fail_group_bind: -fail_get_group_num: +fail_device_assign:if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) {sfc_vdpa_err (sva,"failed to destroy container %d" , sva->vfio_container_fd);
@@ -132,13 +114,6 @@ sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter *sva) {rte_pci_unmap_device (sva->pdev); -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } -if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) { sfc_vdpa_err(sva, "failed to destroy container %d",
drivers/vdpa/sfc/sfc_vdpa.h +0 -2
@@ -70,10 +70,8 @@ struct sfc_vdpa_adapter {sfc_vdpa_filter_t filters; -int vfio_group_fd;int vfio_dev_fd;int vfio_container_fd; -int iommu_group_num;struct sfc_vdpa_ops_data *ops_data; };
Signature · 1 line
2.52.0
PATCH v9 10/19 vdpa/mlx5: remove group-related API
In reply to Anatoly BurakovThe mlx5 driver does not use the get_group_fd API provided by vDPA. This API is about to be removed, so remove its mention from mlx5.
--- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - 1 file changed, 1 deletion(-)
drivers/vdpa/mlx5/mlx5_vdpa.c +0 -1
@@ -523,7 +523,6 @@ static struct rte_vdpa_dev_ops mlx5_vdpa_ops = { .set_vring_state = mlx5_vdpa_set_vring_state, .set_features = mlx5_vdpa_features_set, .migration_done = NULL, - .get_vfio_group_fd = NULL, .get_vfio_device_fd = mlx5_vdpa_get_device_fd, .get_notify_area = mlx5_vdpa_get_notify_area, .get_stats_names = mlx5_vdpa_get_stats_names,
Signature · 1 line
2.52.0
PATCH v9 11/19 vhost: remove group-related API from driver
In reply to Anatoly BurakovThe vDPA driver API has "get_vfio_group_fd" in its ops structure, but no driver is using it any more, as better API's were added and implemented. Remove this API from vDPA ops structure.
--- doc/guides/prog_guide/vhost_lib.rst | 4 ---- doc/guides/rel_notes/deprecation.rst | 4 ---- lib/vhost/vdpa_driver.h | 3 --- 3 files changed, 11 deletions(-)
doc/guides/prog_guide/vhost_lib.rst +0 -4
@@ -471,10 +471,6 @@ Finally, a set of device ops is defined for device specific operations: Called to allow the device to response to RARP sending. -* ``get_vfio_group_fd`` - - Called to get the VFIO group fd of the device. - * ``get_vfio_device_fd`` Called to get the VFIO device fd of the device.
doc/guides/rel_notes/deprecation.rst +0 -4
@@ -30,10 +30,6 @@ Deprecation Notices Use the ``-S <service-corelist>`` parameter instead to specify the cores to be used for background services in DPDK. -* vdpa: The vDPA driver API will no longer offer ``get_vfio_group_fd`` - as part of its internal API. All drivers will be adjusted - to use the new unified VFIO container device assignment API. - * rte_atomicNN_xxx: These APIs do not take memory order parameter. This does not allow for writing optimized code for all the CPU architectures supported in DPDK. DPDK has adopted the atomic operations from
lib/vhost/vdpa_driver.h +0 -3
@@ -50,9 +50,6 @@ struct rte_vdpa_dev_ops {/** Destination operations when migration done */ int (*migration_done)(int vid); -/** Get the vfio group fd */ -int (*get_vfio_group_fd)(int vid); -/** Get the vfio device fd */ int (*get_vfio_device_fd)(int vid);
Signature · 1 line
2.52.0
PATCH v9 12/19 vfio: remove group-based API
In reply to Anatoly BurakovAll drivers have been adjusted to not use the VFIO group API directly and instead rely on container device assignment model, so the group API is no longer useful and can be removed.
--- lib/eal/freebsd/eal.c | 33 --------------- lib/eal/include/rte_vfio.h | 72 -------------------------------- lib/eal/linux/eal_vfio.c | 47 ++++++++++----------- lib/eal/linux/eal_vfio.h | 2 + lib/eal/linux/eal_vfio_mp_sync.c | 2 +- 5 files changed, 26 insertions(+), 130 deletions(-)
lib/eal/freebsd/eal.c +0 -33
@@ -856,13 +856,6 @@ int rte_vfio_noiommu_is_enabled(void)return 0 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) -int rte_vfio_clear_group(__rte_unused int vfio_group_fd) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base,
@@ -881,14 +874,6 @@ rte_vfio_get_container_fd(void)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) -int -rte_vfio_get_group_fd(__rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void )
@@ -905,24 +890,6 @@ rte_vfio_container_destroy(__rte_unused int container_fd)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) -int -rte_vfio_container_group_bind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) -int -rte_vfio_container_group_unbind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd,
lib/eal/include/rte_vfio.h +0 -72
90 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +23 -24
151 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +2 -0
@@ -51,6 +51,8 @@ vfio_set_iommu_type(int vfio_container_fd);int vfio_get_iommu_type (void ); +int vfio_get_group_fd_by_num (int iommu_group_num); +/* check if we have any supported extensions */ int vfio_has_supported_extensions (int vfio_container_fd);
lib/eal/linux/eal_vfio_mp_sync.c +1 -1
@@ -34,7 +34,7 @@ vfio_mp_primary(const struct rte_mp_msg *msg, const void *peer)case SOCKET_REQ_GROUP : r->req =SOCKET_REQ_GROUP ; r->group_num = m->group_num; - fd =rte_vfio_get_group_fd (m->group_num); + fd =vfio_get_group_fd_by_num (m->group_num);if (fd <0 && fd != -ENOENT ) r->result =SOCKET_ERR ;else if (fd == -ENOENT )
Signature · 1 line
2.52.0
PATCH v9 13/19 vfio: cleanup and refactor
In reply to Anatoly BurakovCurrently, VFIO code is a bit of an incoherent mess internally, with API's bleeding into each other, inconsistent returns, and a certain amount of spaghetti stemming from organic growth.
Refactor VFIO code to achieve the following goals:
- Make all error handling consistent, and provide/document rte_errno values returned from API's to indicate various conditions.
- Introduce new "VFIO mode" concept. This new API will tell caller if VFIO is enabled, and whether it is using group API, and whether it is running in no-IOMMU mode.
- Decouple rte_vfio_setup_device semantics from PCI bus return convention. Currently, when device is not managed by VFIO, rte_vfio_setup_device will return 1, which is bus speak for "skip this device", however VFIO has nothing to do with PCI bus and should not follow its API conventions.
- Perform device setup in device assign, and make device setup use shared code path with device assign and explicitly assuming default container. This is technically not necessary for group mode as device set up is a two-step process in that mode, but coming cdev mode will have a single-step device setup, and it would be easier if the worked the same way under the hood.
- Make VFIO internals more readable. Introduce a lot of infrastructure and more explicit validation, rather than over-reliance on sentinel values and implicit assumptions. This will also make it easier to integrate cdev mode down the line, as it will rely on most of this infrastructure.
This will change behavior of the following functions:
- rte_vfio_setup_device - when the device is not managed by VFIO, the function will now return -1 with rte_errno set to ENODEV
- rte_vfio_get_group_num - when the device is not managed by VFIO, the function will now return -1 with rte_errno set to ENODEV
- rte_vfio_container_destroy - the function will now release and close all group and device resources associated with the container being destroyed by this call
All users of rte_vfio_setup_device and rte_vfio_get_group_num have been adjusted to account for API change.
--- config/arm/meson.build | 1 + config/meson.build | 1 + drivers/bus/cdx/cdx_vfio.c | 17 +- drivers/bus/fslmc/fslmc_vfio.c | 4 +- drivers/bus/pci/linux/pci_vfio.c | 19 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 6 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 2 +- lib/eal/freebsd/eal.c | 16 + lib/eal/include/rte_vfio.h | 252 ++- lib/eal/linux/eal_vfio.c | 2264 +++++++--------------- lib/eal/linux/eal_vfio.h | 142 +- lib/eal/linux/eal_vfio_group.c | 984 ++++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 38 +- lib/eal/linux/meson.build | 1 + 14 files changed, 2104 insertions(+), 1643 deletions(-) create mode 100644 lib/eal/linux/eal_vfio_group.c
config/arm/meson.build +1 -0
@@ -147,6 +147,7 @@ implementer_cavium = { 'description': 'Cavium', 'flags': [ ['RTE_MAX_VFIO_GROUPS', 128], + ['RTE_MAX_VFIO_DEVICES', 256], ['RTE_MAX_LCORE', 96], ['RTE_MAX_NUMA_NODES', 2] ],
config/meson.build +1 -0
@@ -387,6 +387,7 @@ dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp')) dpdk_conf.set('RTE_PKTMBUF_HEADROOM', get_option('pkt_mbuf_headroom')) # values which have defaults which may be overridden dpdk_conf.set('RTE_MAX_VFIO_GROUPS', 64) +dpdk_conf.set('RTE_MAX_VFIO_DEVICES', 256) dpdk_conf.set('RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB', 64) dpdk_conf.set('RTE_LIBRTE_DPAA2_USE_PHYS_IOVA', true) if get_option('mbuf_refcnt_atomic')
drivers/bus/cdx/cdx_vfio.c +12 -5
@@ -22,6 +22,7 @@#include <eal_export.h> #include <rte_eal_paging.h> +#include <rte_errno.h> #include <rte_malloc.h> #include <rte_vfio.h>
@@ -402,8 +403,12 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev) ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, &vfio_dev_fd); -if (ret) +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
@@ -513,11 +518,13 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev)return -1 ; } - ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; - + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret) goto err_vfio_dev_fd;
drivers/bus/fslmc/fslmc_vfio.c +2 -2
@@ -364,9 +364,9 @@ fslmc_get_group_id(const char *group_name,/* get group number */ ret =rte_vfio_get_group_num (SYSFS_FSL_MC_DEVICES , group_name, groupid); -if (ret <=0 ) { +if (ret <0 ) {DPAA2_BUS_ERR ("Find %s IOMMU group" , group_name); -if (ret <0 ) +if (rte_errno !=ENODEV )return ret;return -EIO ;
drivers/bus/pci/linux/pci_vfio.c +13 -6
@@ -20,6 +20,7 @@#include <rte_malloc.h> #include <rte_vfio.h> #include <rte_eal.h> +#include <rte_errno.h> #include <bus_driver.h> #include <rte_spinlock.h> #include <rte_tailq.h>
@@ -752,10 +753,13 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev)snprintf (pci_addr,sizeof (pci_addr),PCI_PRI_FMT , loc->domain, loc->bus, loc->devid, loc->function); - ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
@@ -965,10 +969,13 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)return -1 ; } - ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
drivers/crypto/bcmfs/bcmfs_vfio.c +5 -1
@@ -9,6 +9,7 @@#include <sys/mman.h> #include <sys/ioctl.h> +#include <rte_errno.h> #include <rte_vfio.h> #include "bcmfs_device.h"
@@ -26,7 +27,10 @@ vfio_map_dev_obj(const char *path, const char *dev_obj,struct vfio_region_info reg_info = { .argsz =sizeof (reg_info) }; ret =rte_vfio_setup_device (path, dev_obj, dev_fd); -if (ret) { +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;BCMFS_LOG (ERR ,"VFIO Setting for device failed" );return ret; }
drivers/net/nbl/nbl_common/nbl_userdev.c +1 -1
@@ -414,7 +414,7 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) "%s/%s/", rte_pci_get_sysfs_path(), dev_name); ret =rte_vfio_get_group_num (pathname, dev_name, &common->iommu_group_num); -if (ret <=0 ) { +if (ret <0 ) {NBL_LOG (ERR ,"nbl vfio group number failed" );return -1 ; }
lib/eal/freebsd/eal.c +16 -0
@@ -921,3 +921,19 @@ rte_vfio_container_assign_device(__rte_unused int vfio_container_fd, rte_errno =ENOTSUP ;return -1 ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) +int +rte_vfio_get_device_info(__rte_unused int vfio_dev_fd, + __rte_unused struct vfio_device_info *device_info) +{ + rte_errno =ENOTSUP ; +return -1 ; +} + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_mode) +enum rte_vfio_mode +rte_vfio_get_mode (void ) +{ +return RTE_VFIO_MODE_NONE ; +}
lib/eal/include/rte_vfio.h +171 -81
417 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +745 -1519
2,437 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +122 -20
142 lines not on this page · raw message
lib/eal/linux/eal_vfio_group.c new file +984 -0
984 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v9 14/19 bus/pci: use the new VFIO mode API
In reply to Anatoly BurakovUse the new VFIO mode API to query no-IOMMU status.
--- drivers/bus/pci/linux/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bus/pci/linux/pci.c +1 -1
@@ -596,7 +596,7 @@ pci_device_iova_mode(const struct rte_pci_driver *pdrv,static int is_vfio_noiommu_enabled =-1 ;if (is_vfio_noiommu_enabled ==-1 ) { -if (rte_vfio_noiommu_is_enabled () ==1 ) +if (rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ) is_vfio_noiommu_enabled =1 ;else is_vfio_noiommu_enabled =0 ;
Signature · 1 line
2.52.0
PATCH v9 15/19 bus/fslmc: use the new VFIO mode API
In reply to Anatoly BurakovFSLMC bus only supports operating in group mode, and relies on no-IOMMU mode checks. Use the new VFIO API's to query no-IOMMU status, as well as protect the bus from initializing in non-group mode.
--- drivers/bus/fslmc/fslmc_bus.c | 10 +++++++++- drivers/bus/fslmc/fslmc_vfio.c | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-)
drivers/bus/fslmc/fslmc_bus.c +9 -1
@@ -332,6 +332,13 @@ rte_fslmc_scan(void) goto scan_fail; } +/* for container groups to work, VFIO must be in group mode */ +if (rte_vfio_get_mode () !=RTE_VFIO_MODE_GROUP && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU ) { + ret = -EINVAL ; + goto scan_fail; + } + ret =fslmc_get_container_group (group_name, &groupid);if (ret !=0 ) goto scan_fail;
@@ -500,7 +507,8 @@ rte_dpaa2_get_iommu_class(void)return RTE_IOVA_DC ;/* check if all devices on the bus support Virtual addressing or not */ -if (fslmc_all_device_support_iova () !=0 &&rte_vfio_noiommu_is_enabled () ==0 ) +if (fslmc_all_device_support_iova () !=0 && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU )return RTE_IOVA_VA ;return RTE_IOVA_PA ;
drivers/bus/fslmc/fslmc_vfio.c +1 -1
@@ -192,7 +192,7 @@ fslmc_vfio_add_group(int vfio_group_fd, group->fd = vfio_group_fd; group->groupid = iommu_group_num;rte_strscpy (group->group_name, group_name,sizeof (group->group_name)); -if (rte_vfio_noiommu_is_enabled () >0 ) +if (rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ) group->iommu_type =VFIO_NOIOMMU_IOMMU ;else group->iommu_type =VFIO_TYPE1_IOMMU ;
Signature · 1 line
2.52.0
PATCH v9 16/19 net/hinic3: use the new VFIO mode API
In reply to Anatoly BurakovUse new VFIO mode API to query no-IOMMU status.
--- drivers/net/hinic3/base/hinic3_hwdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/hinic3/base/hinic3_hwdev.c +2 -1
@@ -78,7 +78,8 @@ hinic3_is_vfio_iommu_enable(const struct rte_eth_dev *eth_dev) {struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (eth_dev, *pci_dev); -return pci_dev->kdrv ==RTE_PCI_KDRV_VFIO &&rte_vfio_noiommu_is_enabled () !=1 ; +return pci_dev->kdrv ==RTE_PCI_KDRV_VFIO && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU ; }int
Signature · 1 line
2.52.0
PATCH v9 17/19 net/ntnic: use the new VFIO mode API
In reply to Anatoly BurakovUse new VFIO mode API to query no-IOMMU status.
--- drivers/net/ntnic/ntnic_ethdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ntnic/ntnic_ethdev.c +1 -1
@@ -2690,7 +2690,7 @@ nthw_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) (pci_dev->device.devargs->data ? pci_dev->device.devargs->data : "NULL")); } -const int n_rte_vfio_no_io_mmu_enabled =rte_vfio_noiommu_is_enabled (); +const int n_rte_vfio_no_io_mmu_enabled =rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ;NT_LOG (DBG ,NTNIC ,"vfio_no_iommu_enabled=%d" , n_rte_vfio_no_io_mmu_enabled);if (n_rte_vfio_no_io_mmu_enabled) {
Signature · 1 line
2.52.0
PATCH v9 18/19 vfio: remove no-IOMMU check API
In reply to Anatoly BurakovThe rte_vfio_noiommu_is_enabled() check has now been replaced by the new mode API, so remove it.
--- lib/eal/freebsd/eal.c | 6 ------ lib/eal/include/rte_vfio.h | 14 -------------- lib/eal/linux/eal_vfio.c | 7 ------- 3 files changed, 27 deletions(-)
lib/eal/freebsd/eal.c +0 -6
@@ -850,12 +850,6 @@ int rte_vfio_is_enabled(__rte_unused const char *modname)return 0 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) -int rte_vfio_noiommu_is_enabled(void) -{ -return 0 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base,
lib/eal/include/rte_vfio.h +0 -14
@@ -170,20 +170,6 @@ __rte_internalenum rte_vfio_mode rte_vfio_get_mode (void ); -/** -* @internal -* Check if VFIO NOIOMMU mode is enabled. -* -* This function is only relevant on Linux in group mode. -* -* @return -* 1 if enabled. -* 0 if not enabled or not supported. -*/ -__rte_internal -int -rte_vfio_noiommu_is_enabled (void ); -/** * @internal * Parse IOMMU group number for a device.
lib/eal/linux/eal_vfio.c +0 -7
@@ -1277,13 +1277,6 @@ container_dma_unmap(struct container *cfg, uint64_t vaddr, uint64_t iova,return ret; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) -int -rte_vfio_noiommu_is_enabled (void ) -{ -return vfio_cfg.mode ==RTE_VFIO_MODE_NOIOMMU ; -} -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void )
Signature · 1 line
2.52.0
PATCH v9 19/19 vfio: introduce cdev mode
In reply to Anatoly BurakovAdd support for VFIO cdev (also known as IOMMUFD) API. The group API is now considered legacy in the kernel, and all further development is expected to happen in IOMMUFD infrastructure.
To assist any future use of VFIO cdev mode for custom behavior, also introduce "get device number" API, which is kind-of-but-not-really similar to the concept of IOMMU group.
--- lib/eal/freebsd/eal.c | 10 + lib/eal/include/rte_vfio.h | 31 +++ lib/eal/linux/eal_vfio.c | 222 +++++++++++++++++- lib/eal/linux/eal_vfio.h | 29 ++- lib/eal/linux/eal_vfio_cdev.c | 390 +++++++++++++++++++++++++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 42 ++++ lib/eal/linux/meson.build | 1 + 7 files changed, 721 insertions(+), 4 deletions(-) create mode 100644 lib/eal/linux/eal_vfio_cdev.c
lib/eal/freebsd/eal.c +10 -0
@@ -931,3 +931,13 @@ rte_vfio_get_mode(void) {return RTE_VFIO_MODE_NONE ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_num) +int +rte_vfio_get_device_num(__rte_unused const char *sysfs_base, + __rte_unused const char *dev_addr, + __rte_unused int *vfio_device_num) +{ + rte_errno =ENOTSUP ; +return -1 ; +}
lib/eal/include/rte_vfio.h +31 -0
@@ -28,6 +28,8 @@ extern "C" {#define RTE_VFIO_DIR "/dev/vfio"#define RTE_VFIO_CONTAINER_PATH "/dev/vfio/vfio" +#define RTE_VFIO_IOMMUFD_PATH "/dev/iommu" +#define RTE_VFIO_CDEV_DEVICES_PATH "/dev/vfio/devices"#define RTE_VFIO_GROUP_FMT "/dev/vfio/%u"#define RTE_VFIO_NOIOMMU_GROUP_FMT "/dev/vfio/noiommu-%u"#define RTE_VFIO_NOIOMMU_MODE "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode"
@@ -48,11 +50,13 @@ struct vfio_device_info;* - RTE_VFIO_MODE_NONE: VFIO is not enabled. * - RTE_VFIO_MODE_GROUP: Legacy group mode. * - RTE_VFIO_MODE_NOIOMMU: Unsafe no-IOMMU mode. +* - RTE_VFIO_MODE_CDEV: Character device mode. */ enum rte_vfio_mode {RTE_VFIO_MODE_NONE =0 ,/**< VFIO not enabled */ RTE_VFIO_MODE_GROUP ,/**< Group mode */ RTE_VFIO_MODE_NOIOMMU ,/**< Group mode with no IOMMU protection */ +RTE_VFIO_MODE_CDEV ,/**< Device mode */ };/**
@@ -197,6 +201,33 @@ __rte_internalint rte_vfio_get_group_num (const char *sysfs_base,const char *dev_addr,int *iommu_group_num); +/** +* @internal +* Parse VFIO cdev device number for a device. +* +* This function is only relevant on Linux in cdev mode. +* +* @param sysfs_base +* Sysfs path prefix. +* @param dev_addr +* Device identifier. +* @param vfio_device_num +* Pointer to where VFIO cdev device number will be stored. +* +* @return +* 0 on success. +* <0 on failure, rte_errno is set. +* +* Possible rte_errno values include: +* - ENODEV - Device not managed by VFIO. +* - EINVAL - Invalid parameters. +* - ENOXIO - VFIO support not initialized. +* - ENOTSUP - Unsupported VFIO mode. +*/ +__rte_internal +int +rte_vfio_get_device_num (const char *sysfs_base,const char *dev_addr,int *vfio_device_num); +/** * @internal * Get device information.
lib/eal/linux/eal_vfio.c +220 -2
294 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +27 -2
@@ -48,7 +48,10 @@ struct vfio_group {/* device tracking (common for group and cdev modes) */ struct vfio_device {bool active; -int group;/**< back-reference to group list (group mode) */ +union { +int group;/**< back-reference to group list (group mode) */ +int dev_num;/**< device number, e.g., X in /dev/vfio/devices/vfioX (cdev mode) */ + };int fd; };
@@ -61,12 +64,20 @@ struct vfio_group_config {struct vfio_group groups[RTE_MAX_VFIO_GROUPS ]; }; +/* cdev mode specific configuration */ +struct vfio_cdev_config { +uint32_t ioas_id; +}; +/* per-container configuration */ struct container {bool active;int container_fd;struct user_mem_maps mem_maps; -struct vfio_group_config group_cfg; +union { +struct vfio_group_config group_cfg; +struct vfio_cdev_config cdev_cfg; + };int n_devices;struct vfio_device devices[RTE_MAX_VFIO_DEVICES ]; };
@@ -160,12 +171,24 @@ int vfio_group_setup_iommu(struct container *cfg);int vfio_group_setup_device_fd (const char *dev_addr,struct vfio_group *grp,struct vfio_device *dev); +/* cdev mode functions */ +int vfio_cdev_enable (struct container *cfg); +int vfio_cdev_setup_ioas (struct container *cfg); +int vfio_cdev_sync_ioas (struct container *cfg); +int vfio_cdev_get_iommufd (void ); +int vfio_cdev_get_device_num (const char *sysfs_base,const char *dev_addr, +int *cdev_dev_num); +struct vfio_device *vfio_cdev_get_dev_by_num (struct container *cfg,int cdev_dev_num); +int vfio_cdev_setup_device (struct container *cfg,struct vfio_device *dev); +#define VFIO_MEM_EVENT_CLB_NAME "vfio_mem_event_clb"#define EAL_VFIO_MP "eal_vfio_mp_sync"#define SOCKET_REQ_CONTAINER 0x100#define SOCKET_REQ_GROUP 0x200#define SOCKET_REQ_IOMMU_TYPE 0x400 +#define SOCKET_REQ_CDEV 0x800 +#define SOCKET_REQ_IOAS_ID 0x1000#define SOCKET_OK 0x0#define SOCKET_NO_FD 0x1#define SOCKET_ERR 0xFF
@@ -176,6 +199,8 @@ struct vfio_mp_param {union {int group_num;int iommu_type_id; +int cdev_dev_num; +int ioas_id;enum rte_vfio_mode mode; }; };
lib/eal/linux/eal_vfio_cdev.c new file +390 -0
390 lines not on this page · raw message
lib/eal/linux/eal_vfio_mp_sync.c +42 -0
48 lines not on this page · raw message
lib/eal/linux/meson.build +1 -0
@@ -16,6 +16,7 @@ sources += files( 'eal_thread.c', 'eal_timer.c', 'eal_vfio.c', + 'eal_vfio_cdev.c', 'eal_vfio_group.c', 'eal_vfio_mp_sync.c', )
Signature · 1 line
2.52.0
Quoted 34 lines · On Wed, 5 Aug 2026 14:45:29 +0100 Anatoly Burakov <[email protected]>…
Therefore, what we do instead is introduce a new API for container device assignment which, semantically, will assign a device to specified container, so that when it is mapped using
rte_pci_map_device, the appropriate container is selected. Under the hood though, we essentially transition to getting device fd straight away at assign stage, so that by the time the PCI bus attempts to map the device, it is already mapped and we just return an fd. There is no "unassign" API becauserelease_devicealready performs that function.Additionally, a new
rte_vfio_get_modeAPI is added for those cases that need some introspection into VFIO's internals, with three new modes: group (old-style), no-iommu (old-style but without IOMMU), and cdev (the new mode). Although no-IOMMU is technically a variant of group mode, the distinction is largely irrelevant to the user, as all usages of noiommu checks in our codebase are for deciding whether to use IOVA or PA, not anything to do with managing groups. The current plan for kernel community is to *not* introduce no-IOMMU cdev implementation, and IOMMUFD's own group API compatibility layer also does not implement no-IOMMU mode, which is why this will be kept for compatibility for these use cases.There were other users of VFIO which relied on group API but only for convenience purposes; no actual VFIO functionality depended on those API's. Therefore, group API's are removed and, where appropriate, replaced with the new API's.
List of removed API's:
*
rte_vfio_get_group_fd
*rte_vfio_clear_group
*rte_vfio_container_group_bind(replaced by container assign API)
*rte_vfio_container_group_unbind
*rte_vfio_noiommu_is_enabled(replaced by new mode API)2. The API responsibilities aren't clear and bleed into each other
==================================================================
Quoted 6 lines
Some API's do multiple things at once. In particular:
*
rte_vfio_get_device_infowill setup the device
*rte_vfio_setup_devicewill get device infoThese API's have been adjusted to do one thing only.
AI diagnosed apply failure.
This does not apply to main. Patches 8 and 11 have stale context:
patch 8 still has the rte_pci_unmap_device() call in nfp_vdpa_vfio_setup() that 7185c65c95c6 ("vdpa/nfp: fix double PCI unmap on unplug") removed in June, and patch 11 has the pre-1c726e28fd wording of the RARP line in vhost_lib.rst. The series applies cleanly at 481aeec3d7, so v9 looks to be based on a tree from before 2026-06-24. Both are context-only; please rebase for v10.
Much of the stuff in cover letter needs to be release notes.
More AI (Claude Opus) comments:
Patch 13 (vfio: cleanup and refactor)
Error: container fd 0 is closed on the error path. CONTAINER_INITIALIZER only initializes the mem_maps lock, so container_fd is 0, not -1. The pre-refactor code initialized every vfio_cfgs[i].vfio_container_fd to -1. vfio_container_erase() tests
if (cfg->container_fd >= 0 && close(cfg->container_fd))
so any path that allocates a container and fails before assigning the fd closes stdin. rte_vfio_container_create() has three such paths (group open failure, iommufd open failure, and the default: arm), as does vfio_select_mode()'s err label. Add .container_fd = -1 to CONTAINER_INITIALIZER, and use the same initializer in vfio_container_erase() instead of (struct container){0}.
Error: double close in vfio_has_supported_extensions(). The VFIO_CHECK_ EXTENSION error path closes vfio_container_fd and returns -1, and the caller vfio_group_open_container_fd() then closes it again:
ret = vfio_has_supported_extensions(vfio_container_fd);
if (ret) {
EAL_LOG(DEBUG, "No supported IOMMU extensions found!");
close(vfio_container_fd);
return -1;
}Upstream had the close in the callee on both error paths and none in the caller; the refactor added the caller close and removed only one of the two callee closes. The fd may already have been handed out to another thread by then. Drop the close() inside vfio_has_supported_extensions().
Warning: no release notes. The series makes the entire rte_vfio API internal, removes the group-based API and rte_vfio_noiommu_is_enabled(), and adds cdev mode. Only deprecation.rst is touched; doc/guides/rel_notes/release_26_11.rst needs "Removed Items" and "New Features" entries.
Patch 14 (bus/pci: use the new VFIO mode API)
Error: noiommu is no longer detected. pci_device_iova_mode() runs from rte_pci_get_iommu_class() during rte_bus_get_iommu_class(), which rte_eal_init() calls at line 689, well before rte_vfio_enable() at line
775. rte_vfio_get_mode() returns RTE_VFIO_MODE_NONE at that point, so is_vfio_noiommu_enabled latches to 0 and IOVA VA is selected on a noiommu system. The old rte_vfio_noiommu_is_enabled() read /sys/module/vfio/parameters/enable_unsafe_noiommu_mode directly and was therefore valid before VFIO init. The noiommu probe needs to stay sysfs-based, or IOVA mode selection has to move after rte_vfio_enable().
Patch 15 (bus/fslmc: use the new VFIO mode API)
Error: fslmc bus scan now fails on every system. rte_fslmc_scan() is called from rte_bus_scan() at eal.c:680, again before rte_vfio_enable(). The new check
if (rte_vfio_get_mode() != RTE_VFIO_MODE_GROUP &&
rte_vfio_get_mode() != RTE_VFIO_MODE_NOIOMMU) {
ret = -EINVAL;
goto scan_fail;
}always sees RTE_VFIO_MODE_NONE, so no DPAA2 device is ever scanned. The same ordering problem applies to rte_dpaa2_get_iommu_class() and to fslmc_vfio_add_group(), which will now always pick VFIO_TYPE1_IOMMU.
Warning: the new scan_fail branch has no log message, unlike every other failure in that function, so the failure is silent.
Patch 19 (vfio: introduce cdev mode)
Error: vfio_cfg.ops is never set in a cdev-mode secondary. The only assignment is in vfio_cdev_enable(), reached solely from the primary arm of vfio_select_mode(). The secondary path calls vfio_sync_mode() and vfio_cdev_sync_ioas(), neither of which touches ops. A cdev secondary therefore has ops == NULL and every rte_vfio_container_dma_map()/ dma_unmap() fails in vfio_dma_mem_map() with "VFIO support not initialized". The same applies to a container made with rte_vfio_container_create() in a secondary: it opens an iommufd and allocates an IOAS but leaves ops NULL. Set vfio_cfg.ops to the iommufd ops in the secondary cdev path as well.
Note also that container_dma_map()/container_dma_unmap() dereference vfio_cfg.ops->partial_unmap without a NULL check; only vfio_dma_mem_map() guards it.
Patch 5 (net/nbl: do not use VFIO group bind API)
Info: nbl_open_group_fd() needs a blank line between the declaration and the statements:
static int
nbl_open_group_fd(int iommu_group_num)
{
char path[PATH_MAX];
snprintf(path, sizeof(path), RTE_VFIO_GROUP_FMT, iommu_group_num);
return open(path, O_RDWR);
}v10 cover Support VFIO cdev API in DPDK
In reply to a message not in the archiveThis patchset introduces a major refactor of the VFIO subsystem in DPDK to support character device (cdev) interface introduced in Linux kernel, as well as make the API more streamlined and useful. The goal is to simplify device management, improve compatibility, and clarify API responsibilities.
The following sections outline the key issues addressed by this patchset and the corresponding changes introduced.
1. Only group mode is supported
===============================
Since kernel version 4.14.327 (LTS), VFIO supports the new character device (cdev)-based way of working with VFIO devices (otherwise known as IOMMUFD). This is a device-centric mode and does away with all the complexity regarding groups and IOMMU types, delegating it all to the kernel, and exposes a much simpler interface to userspace.
The old group interface is still around, and will need to be kept in DPDK both for compatibility reasons, as well as supporting special cases (FSLMC bus, NBL driver, no-IOMMU mode etc.), but it is now internal-only and not exposed through the API the way it was before.
To enable this, VFIO is heavily refactored, so that the code can support both modes while relying on (mostly) common infrastructure.
Note that the existing rte_vfio_device_setup/release model is fundamentally incompatible with cdev mode, because for custom container cases, the expected flow is that the user binds the IOMMU group (and thus, implicitly, the device itself) to a specific container using rte_vfio_container_group_bind, whereas this step is not needed for cdev as the device fd is assigned to the container straight away.
Therefore, what we do instead is introduce a new API for container device assignment which, semantically, will assign a device to specified container, so that when it is mapped using rte_pci_map_device, the appropriate container is selected. Under the hood though, we essentially transition to getting device fd straight away at assign stage, so that by the time the PCI bus attempts to map the device, it is already mapped and we just return an fd. There is no "unassign" API because release_device already performs that function.
Additionally, a new rte_vfio_get_mode API is added for those cases that need some introspection into VFIO's internals, with three new modes: group (old-style), no-iommu (old-style but without IOMMU), and cdev (the new mode). Although no-IOMMU is technically a variant of group mode, the distinction is largely irrelevant to the user, as all usages of noiommu checks in our codebase are for deciding whether to use IOVA or PA, not anything to do with managing groups. The current plan for kernel community is to *not* introduce no-IOMMU cdev implementation, and IOMMUFD's own group API compatibility layer also does not implement no-IOMMU mode, which is why this will be kept for compatibility for these use cases.
There were other users of VFIO which relied on group API but only for convenience purposes; no actual VFIO functionality depended on those API's. Therefore, group API's are removed and, where appropriate, replaced with the new API's.
List of removed API's:
* rte_vfio_get_group_fd
* rte_vfio_clear_group
* rte_vfio_container_group_bind (replaced by container assign API)
* rte_vfio_container_group_unbind
* rte_vfio_noiommu_is_enabled (replaced by new mode API)
2. The API responsibilities aren't clear and bleed into each other
==================================================================
Some API's do multiple things at once. In particular:
* rte_vfio_get_device_info will setup the device
* rte_vfio_setup_device will get device info
These API's have been adjusted to do one thing only.
v10:
- Added a patch that renames confusing error labels
- Fixed compiler warning about unused variable
v9:
- Moved erroneous rte_errno-related comments to later in the patchset
- Moved removal of vDPA group fd API's to their respective patches
- Fixed typo in errno comments (ENXIO vs ENOXIO)
- Fixed corruption of group config in secondary process (v8 AI review)
v8:
- Rebase
- Fixed build errors due to variable shadowing
- Removed duplicate fd check as kernel does not provide a way to distinguish between device fd's
v7:
- Rebase
- Added removal of deprecation notices
- Fixed implicit numeric comparison in patch 12
v6:
- Fixed missing header include in vfio cdev file
v5:
- Added back missing uapi patch
v4:
- Fixed issues with documenting rte_vfio_mode enum
- Separated deprecation notices into a separate patchset
v3:
- Make API removal cleaner
- Fix get_group_num usages to align with new API
- Fix issues with function exports
- Fix issues with setup_device returning old-style values in some cases
v2:
- Make the entire API internal
- More aggressive API pruning, complete removal of group API
- Fixed a bug in group mode where device could not be used
- Better documentation and deprecation notice patches
- Moved doc patches to beginning of patchset
Anatoly Burakov (20):
uapi: update to v6.17 and add iommufd.h
vfio: make all functions internal
bus/pci: rename mismatching error labels
vfio: split get device info from setup
vfio: add container device assignment API
net/nbl: do not use VFIO group bind API
net/ntnic: use container device assignment API
vdpa/ifc: use container device assignment API
vdpa/nfp: use container device assignment API
vdpa/sfc: use container device assignment API
vdpa/mlx5: remove group-related API
vhost: remove group-related API from driver
vfio: remove group-based API
vfio: cleanup and refactor
bus/pci: use the new VFIO mode API
bus/fslmc: use the new VFIO mode API
net/hinic3: use the new VFIO mode API
net/ntnic: use the new VFIO mode API
vfio: remove no-IOMMU check API
vfio: introduce cdev mode
config/arm/meson.build | 1 + config/meson.build | 1 + doc/guides/prog_guide/vhost_lib.rst | 4 - doc/guides/rel_notes/deprecation.rst | 10 - drivers/bus/cdx/cdx_vfio.c | 25 +- drivers/bus/fslmc/fslmc_bus.c | 10 +- drivers/bus/fslmc/fslmc_vfio.c | 6 +- drivers/bus/pci/linux/pci.c | 2 +- drivers/bus/pci/linux/pci_vfio.c | 47 +- drivers/bus/platform/platform.c | 9 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 14 +- drivers/net/hinic3/base/hinic3_hwdev.c | 3 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 21 +- drivers/net/nbl/nbl_include/nbl_include.h | 1 + drivers/net/ntnic/ntnic_ethdev.c | 2 +- drivers/net/ntnic/ntnic_vfio.c | 30 +- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - drivers/vdpa/nfp/nfp_vdpa.c | 37 +- drivers/vdpa/sfc/sfc_vdpa.c | 39 +- drivers/vdpa/sfc/sfc_vdpa.h | 2 - kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- lib/eal/freebsd/eal.c | 98 +- lib/eal/include/rte_vfio.h | 387 ++-- lib/eal/linux/eal_vfio.c | 2444 ++++++++------------- lib/eal/linux/eal_vfio.h | 167 +- lib/eal/linux/eal_vfio_cdev.c | 390 ++++ lib/eal/linux/eal_vfio_group.c | 984 +++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 80 +- lib/eal/linux/meson.build | 2 + lib/eal/windows/eal.c | 4 +- lib/vhost/vdpa_driver.h | 3 - 35 files changed, 4263 insertions(+), 1903 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h create mode 100644 lib/eal/linux/eal_vfio_cdev.c create mode 100644 lib/eal/linux/eal_vfio_group.c
Signature · 1 line
2.52.0
PATCH v10 1/20 uapi: update to v6.17 and add iommufd.h
In order to support VF tokens for cdev-based VFIO mode, kernel v6.17 is required. Update internal headers to version v6.17 and include iommufd.h.
--- kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++++++++++++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- 4 files changed, 1305 insertions(+), 3 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h
kernel/linux/uapi/linux/iommufd.h new file +1292 -0
@@ -0,0 +1,1292 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. +*/ +#ifndef _IOMMUFD_H +#define _IOMMUFD_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +#define IOMMUFD_TYPE (';') + +/** +* DOC: General ioctl format +* +* The ioctl interface follows a general format to allow for extensibility. Each +* ioctl is passed in a structure pointer as the argument providing the size of +* the structure in the first u32. The kernel checks that any structure space +* beyond what it understands is 0. This allows userspace to use the backward +* compatible portion while consistently using the newer, larger, structures. +* +* ioctls use a standard meaning for common errnos: +* +* - ENOTTY: The IOCTL number itself is not supported at all +* - E2BIG: The IOCTL number is supported, but the provided structure has +* non-zero in a part the kernel does not understand. +* - EOPNOTSUPP: The IOCTL number is supported, and the structure is +* understood, however a known field has a value the kernel does not +* understand or support. +* - EINVAL: Everything about the IOCTL was understood, but a field is not +* correct. +* - ENOENT: An ID or IOVA provided does not exist. +* - ENOMEM: Out of memory. +* - EOVERFLOW: Mathematics overflowed. +* +* As well as additional errnos, within specific ioctls. +*/ +enum { +IOMMUFD_CMD_BASE =0x80 , +IOMMUFD_CMD_DESTROY =IOMMUFD_CMD_BASE , +IOMMUFD_CMD_IOAS_ALLOC =0x81 , +IOMMUFD_CMD_IOAS_ALLOW_IOVAS =0x82 , +IOMMUFD_CMD_IOAS_COPY =0x83 , +IOMMUFD_CMD_IOAS_IOVA_RANGES =0x84 , +IOMMUFD_CMD_IOAS_MAP =0x85 , +IOMMUFD_CMD_IOAS_UNMAP =0x86 , +IOMMUFD_CMD_OPTION =0x87 , +IOMMUFD_CMD_VFIO_IOAS =0x88 , +IOMMUFD_CMD_HWPT_ALLOC =0x89 , +IOMMUFD_CMD_GET_HW_INFO =0x8a , +IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING =0x8b , +IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP =0x8c , +IOMMUFD_CMD_HWPT_INVALIDATE =0x8d , +IOMMUFD_CMD_FAULT_QUEUE_ALLOC =0x8e , +IOMMUFD_CMD_IOAS_MAP_FILE =0x8f , +IOMMUFD_CMD_VIOMMU_ALLOC =0x90 , +IOMMUFD_CMD_VDEVICE_ALLOC =0x91 , +IOMMUFD_CMD_IOAS_CHANGE_PROCESS =0x92 , +IOMMUFD_CMD_VEVENTQ_ALLOC =0x93 , +IOMMUFD_CMD_HW_QUEUE_ALLOC =0x94 , +}; + +/** +* struct iommu_destroy - ioctl(IOMMU_DESTROY) +* @size: sizeof(struct iommu_destroy) +* @id: iommufd object ID to destroy. Can be any destroyable object type. +* +* Destroy any object held within iommufd. +*/ +struct iommu_destroy { +__u32 size; +__u32 id; +}; +#define IOMMU_DESTROY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DESTROY) + +/** +* struct iommu_ioas_alloc - ioctl(IOMMU_IOAS_ALLOC) +* @size: sizeof(struct iommu_ioas_alloc) +* @flags: Must be 0 +* @out_ioas_id: Output IOAS ID for the allocated object +* +* Allocate an IO Address Space (IOAS) which holds an IO Virtual Address (IOVA) +* to memory mapping. +*/ +struct iommu_ioas_alloc { +__u32 size; +__u32 flags; +__u32 out_ioas_id; +}; +#define IOMMU_IOAS_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOC) + +/** +* struct iommu_iova_range - ioctl(IOMMU_IOVA_RANGE) +* @start: First IOVA +* @last: Inclusive last IOVA +* +* An interval in IOVA space. +*/ +struct iommu_iova_range { +__aligned_u64 start; +__aligned_u64 last; +}; + +/** +* struct iommu_ioas_iova_ranges - ioctl(IOMMU_IOAS_IOVA_RANGES) +* @size: sizeof(struct iommu_ioas_iova_ranges) +* @ioas_id: IOAS ID to read ranges from +* @num_iovas: Input/Output total number of ranges in the IOAS +* @__reserved: Must be 0 +* @allowed_iovas: Pointer to the output array of struct iommu_iova_range +* @out_iova_alignment: Minimum alignment required for mapping IOVA +* +* Query an IOAS for ranges of allowed IOVAs. Mapping IOVA outside these ranges +* is not allowed. num_iovas will be set to the total number of iovas and +* the allowed_iovas[] will be filled in as space permits. +* +* The allowed ranges are dependent on the HW path the DMA operation takes, and +* can change during the lifetime of the IOAS. A fresh empty IOAS will have a +* full range, and each attached device will narrow the ranges based on that +* device's HW restrictions. Detaching a device can widen the ranges. Userspace +* should query ranges after every attach/detach to know what IOVAs are valid +* for mapping. +* +* On input num_iovas is the length of the allowed_iovas array. On output it is +* the total number of iovas filled in. The ioctl will return -EMSGSIZE and set +* num_iovas to the required value if num_iovas is too small. In this case the +* caller should allocate a larger output array and re-issue the ioctl. +* +* out_iova_alignment returns the minimum IOVA alignment that can be given +* to IOMMU_IOAS_MAP/COPY. IOVA's must satisfy:: +* +* starting_iova % out_iova_alignment == 0 +* (starting_iova + length) % out_iova_alignment == 0 +* +* out_iova_alignment can be 1 indicating any IOVA is allowed. It cannot +* be higher than the system PAGE_SIZE. +*/ +struct iommu_ioas_iova_ranges { +__u32 size; +__u32 ioas_id; +__u32 num_iovas; +__u32 __reserved; +__aligned_u64 allowed_iovas; +__aligned_u64 out_iova_alignment; +}; +#define IOMMU_IOAS_IOVA_RANGES _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_IOVA_RANGES) + +/** +* struct iommu_ioas_allow_iovas - ioctl(IOMMU_IOAS_ALLOW_IOVAS) +* @size: sizeof(struct iommu_ioas_allow_iovas) +* @ioas_id: IOAS ID to allow IOVAs from +* @num_iovas: Input/Output total number of ranges in the IOAS +* @__reserved: Must be 0 +* @allowed_iovas: Pointer to array of struct iommu_iova_range +* +* Ensure a range of IOVAs are always available for allocation. If this call +* succeeds then IOMMU_IOAS_IOVA_RANGES will never return a list of IOVA ranges +* that are narrower than the ranges provided here. This call will fail if +* IOMMU_IOAS_IOVA_RANGES is currently narrower than the given ranges. +* +* When an IOAS is first created the IOVA_RANGES will be maximally sized, and as +* devices are attached the IOVA will narrow based on the device restrictions. +* When an allowed range is specified any narrowing will be refused, ie device +* attachment can fail if the device requires limiting within the allowed range. +* +* Automatic IOVA allocation is also impacted by this call. MAP will only +* allocate within the allowed IOVAs if they are present. +* +* This call replaces the entire allowed list with the given list. +*/ +struct iommu_ioas_allow_iovas { +__u32 size; +__u32 ioas_id; +__u32 num_iovas; +__u32 __reserved; +__aligned_u64 allowed_iovas; +}; +#define IOMMU_IOAS_ALLOW_IOVAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOW_IOVAS) + +/** +* enum iommufd_ioas_map_flags - Flags for map and copy +* @IOMMU_IOAS_MAP_FIXED_IOVA: If clear the kernel will compute an appropriate +* IOVA to place the mapping at +* @IOMMU_IOAS_MAP_WRITEABLE: DMA is allowed to write to this mapping +* @IOMMU_IOAS_MAP_READABLE: DMA is allowed to read from this mapping +*/ +enum iommufd_ioas_map_flags { +IOMMU_IOAS_MAP_FIXED_IOVA =1 <<0 , +IOMMU_IOAS_MAP_WRITEABLE =1 <<1 , +IOMMU_IOAS_MAP_READABLE =1 <<2 , +}; + +/** +* struct iommu_ioas_map - ioctl(IOMMU_IOAS_MAP) +* @size: sizeof(struct iommu_ioas_map) +* @flags: Combination of enum iommufd_ioas_map_flags +* @ioas_id: IOAS ID to change the mapping of +* @__reserved: Must be 0 +* @user_va: Userspace pointer to start mapping from +* @length: Number of bytes to map +* @iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is set +* then this must be provided as input. +* +* Set an IOVA mapping from a user pointer. If FIXED_IOVA is specified then the +* mapping will be established at iova, otherwise a suitable location based on +* the reserved and allowed lists will be automatically selected and returned in +* iova. +* +* If IOMMU_IOAS_MAP_FIXED_IOVA is specified then the iova range must currently +* be unused, existing IOVA cannot be replaced. +*/ +struct iommu_ioas_map { +__u32 size; +__u32 flags; +__u32 ioas_id; +__u32 __reserved; +__aligned_u64 user_va; +__aligned_u64 length; +__aligned_u64 iova; +}; +#define IOMMU_IOAS_MAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_MAP) + +/** +* struct iommu_ioas_map_file - ioctl(IOMMU_IOAS_MAP_FILE) +* @size: sizeof(struct iommu_ioas_map_file) +* @flags: same as for iommu_ioas_map +* @ioas_id: same as for iommu_ioas_map +* @fd: the memfd to map +* @start: byte offset from start of file to map from +* @length: same as for iommu_ioas_map +* @iova: same as for iommu_ioas_map +* +* Set an IOVA mapping from a memfd file. All other arguments and semantics +* match those of IOMMU_IOAS_MAP. +*/ +struct iommu_ioas_map_file { +__u32 size; +__u32 flags; +__u32 ioas_id; +__s32 fd; +__aligned_u64 start; +__aligned_u64 length; +__aligned_u64 iova; +}; +#define IOMMU_IOAS_MAP_FILE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_MAP_FILE) + +/** +* struct iommu_ioas_copy - ioctl(IOMMU_IOAS_COPY) +* @size: sizeof(struct iommu_ioas_copy) +* @flags: Combination of enum iommufd_ioas_map_flags +* @dst_ioas_id: IOAS ID to change the mapping of +* @src_ioas_id: IOAS ID to copy from +* @length: Number of bytes to copy and map +* @dst_iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is +* set then this must be provided as input. +* @src_iova: IOVA to start the copy +* +* Copy an already existing mapping from src_ioas_id and establish it in +* dst_ioas_id. The src iova/length must exactly match a range used with +* IOMMU_IOAS_MAP. +* +* This may be used to efficiently clone a subset of an IOAS to another, or as a +* kind of 'cache' to speed up mapping. Copy has an efficiency advantage over +* establishing equivalent new mappings, as internal resources are shared, and +* the kernel will pin the user memory only once. +*/ +struct iommu_ioas_copy { +__u32 size; +__u32 flags; +__u32 dst_ioas_id; +__u32 src_ioas_id; +__aligned_u64 length; +__aligned_u64 dst_iova; +__aligned_u64 src_iova; +}; +#define IOMMU_IOAS_COPY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_COPY) + +/** +* struct iommu_ioas_unmap - ioctl(IOMMU_IOAS_UNMAP) +* @size: sizeof(struct iommu_ioas_unmap) +* @ioas_id: IOAS ID to change the mapping of +* @iova: IOVA to start the unmapping at +* @length: Number of bytes to unmap, and return back the bytes unmapped +* +* Unmap an IOVA range. The iova/length must be a superset of a previously +* mapped range used with IOMMU_IOAS_MAP or IOMMU_IOAS_COPY. Splitting or +* truncating ranges is not allowed. The values 0 to U64_MAX will unmap +* everything. +*/ +struct iommu_ioas_unmap { +__u32 size; +__u32 ioas_id; +__aligned_u64 iova; +__aligned_u64 length; +}; +#define IOMMU_IOAS_UNMAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_UNMAP) + +/** +* enum iommufd_option - ioctl(IOMMU_OPTION_RLIMIT_MODE) and +* ioctl(IOMMU_OPTION_HUGE_PAGES) +* @IOMMU_OPTION_RLIMIT_MODE: +* Change how RLIMIT_MEMLOCK accounting works. The caller must have privilege +* to invoke this. Value 0 (default) is user based accounting, 1 uses process +* based accounting. Global option, object_id must be 0 +* @IOMMU_OPTION_HUGE_PAGES: +* Value 1 (default) allows contiguous pages to be combined when generating +* iommu mappings. Value 0 disables combining, everything is mapped to +* PAGE_SIZE. This can be useful for benchmarking. This is a per-IOAS +* option, the object_id must be the IOAS ID. +*/ +enum iommufd_option { +IOMMU_OPTION_RLIMIT_MODE =0 , +IOMMU_OPTION_HUGE_PAGES =1 , +}; + +/** +* enum iommufd_option_ops - ioctl(IOMMU_OPTION_OP_SET) and +* ioctl(IOMMU_OPTION_OP_GET) +* @IOMMU_OPTION_OP_SET: Set the option's value +* @IOMMU_OPTION_OP_GET: Get the option's value +*/ +enum iommufd_option_ops { +IOMMU_OPTION_OP_SET =0 , +IOMMU_OPTION_OP_GET =1 , +}; + +/** +* struct iommu_option - iommu option multiplexer +* @size: sizeof(struct iommu_option) +* @option_id: One of enum iommufd_option +* @op: One of enum iommufd_option_ops +* @__reserved: Must be 0 +* @object_id: ID of the object if required +* @val64: Option value to set or value returned on get +* +* Change a simple option value. This multiplexor allows controlling options +* on objects. IOMMU_OPTION_OP_SET will load an option and IOMMU_OPTION_OP_GET +* will return the current value. +*/ +struct iommu_option { +__u32 size; +__u32 option_id; +__u16 op; +__u16 __reserved; +__u32 object_id; +__aligned_u64 val64; +}; +#define IOMMU_OPTION _IO(IOMMUFD_TYPE, IOMMUFD_CMD_OPTION) + +/** +* enum iommufd_vfio_ioas_op - IOMMU_VFIO_IOAS_* ioctls +* @IOMMU_VFIO_IOAS_GET: Get the current compatibility IOAS +* @IOMMU_VFIO_IOAS_SET: Change the current compatibility IOAS +* @IOMMU_VFIO_IOAS_CLEAR: Disable VFIO compatibility +*/ +enum iommufd_vfio_ioas_op { +IOMMU_VFIO_IOAS_GET =0 , +IOMMU_VFIO_IOAS_SET =1 , +IOMMU_VFIO_IOAS_CLEAR =2 , +}; + +/** +* struct iommu_vfio_ioas - ioctl(IOMMU_VFIO_IOAS) +* @size: sizeof(struct iommu_vfio_ioas) +* @ioas_id: For IOMMU_VFIO_IOAS_SET the input IOAS ID to set +* For IOMMU_VFIO_IOAS_GET will output the IOAS ID +* @op: One of enum iommufd_vfio_ioas_op +* @__reserved: Must be 0 +* +* The VFIO compatibility support uses a single ioas because VFIO APIs do not +* support the ID field. Set or Get the IOAS that VFIO compatibility will use. +* When VFIO_GROUP_SET_CONTAINER is used on an iommufd it will get the +* compatibility ioas, either by taking what is already set, or auto creating +* one. From then on VFIO will continue to use that ioas and is not effected by +* this ioctl. SET or CLEAR does not destroy any auto-created IOAS. +*/ +struct iommu_vfio_ioas { +__u32 size; +__u32 ioas_id; +__u16 op; +__u16 __reserved; +}; +#define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS) + +/** +* enum iommufd_hwpt_alloc_flags - Flags for HWPT allocation +* @IOMMU_HWPT_ALLOC_NEST_PARENT: If set, allocate a HWPT that can serve as +* the parent HWPT in a nesting configuration. +* @IOMMU_HWPT_ALLOC_DIRTY_TRACKING: Dirty tracking support for device IOMMU is +* enforced on device attachment +* @IOMMU_HWPT_FAULT_ID_VALID: The fault_id field of hwpt allocation data is +* valid. +* @IOMMU_HWPT_ALLOC_PASID: Requests a domain that can be used with PASID. The +* domain can be attached to any PASID on the device. +* Any domain attached to the non-PASID part of the +* device must also be flagged, otherwise attaching a +* PASID will blocked. +* For the user that wants to attach PASID, ioas is +* not recommended for both the non-PASID part +* and PASID part of the device. +* If IOMMU does not support PASID it will return +* error (-EOPNOTSUPP). +*/ +enum iommufd_hwpt_alloc_flags { +IOMMU_HWPT_ALLOC_NEST_PARENT =1 <<0 , +IOMMU_HWPT_ALLOC_DIRTY_TRACKING =1 <<1 , +IOMMU_HWPT_FAULT_ID_VALID =1 <<2 , +IOMMU_HWPT_ALLOC_PASID =1 <<3 , +}; + +/** +* enum iommu_hwpt_vtd_s1_flags - Intel VT-d stage-1 page table +* entry attributes +* @IOMMU_VTD_S1_SRE: Supervisor request +* @IOMMU_VTD_S1_EAFE: Extended access enable +* @IOMMU_VTD_S1_WPE: Write protect enable +*/ +enum iommu_hwpt_vtd_s1_flags { +IOMMU_VTD_S1_SRE =1 <<0 , +IOMMU_VTD_S1_EAFE =1 <<1 , +IOMMU_VTD_S1_WPE =1 <<2 , +}; + +/** +* struct iommu_hwpt_vtd_s1 - Intel VT-d stage-1 page table +* info (IOMMU_HWPT_DATA_VTD_S1) +* @flags: Combination of enum iommu_hwpt_vtd_s1_flags +* @pgtbl_addr: The base address of the stage-1 page table. +* @addr_width: The address width of the stage-1 page table +* @__reserved: Must be 0 +*/ +struct iommu_hwpt_vtd_s1 { +__aligned_u64 flags; +__aligned_u64 pgtbl_addr; +__u32 addr_width; +__u32 __reserved; +}; + +/** +* struct iommu_hwpt_arm_smmuv3 - ARM SMMUv3 nested STE +* (IOMMU_HWPT_DATA_ARM_SMMUV3) +* +* @ste: The first two double words of the user space Stream Table Entry for +* the translation. Must be little-endian. +* Allowed fields: (Refer to "5.2 Stream Table Entry" in SMMUv3 HW Spec) +* - word-0: V, Cfg, S1Fmt, S1ContextPtr, S1CDMax +* - word-1: EATS, S1DSS, S1CIR, S1COR, S1CSH, S1STALLD +* +* -EIO will be returned if @ste is not legal or contains any non-allowed field. +* Cfg can be used to select a S1, Bypass or Abort configuration. A Bypass +* nested domain will translate the same as the nesting parent. The S1 will +* install a Context Descriptor Table pointing at userspace memory translated +* by the nesting parent. +*/ +struct iommu_hwpt_arm_smmuv3 { +__aligned_le64 ste[2 ]; +}; + +/** +* enum iommu_hwpt_data_type - IOMMU HWPT Data Type +* @IOMMU_HWPT_DATA_NONE: no data +* @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table +* @IOMMU_HWPT_DATA_ARM_SMMUV3: ARM SMMUv3 Context Descriptor Table +*/ +enum iommu_hwpt_data_type { +IOMMU_HWPT_DATA_NONE =0 , +IOMMU_HWPT_DATA_VTD_S1 =1 , +IOMMU_HWPT_DATA_ARM_SMMUV3 =2 , +}; + +/** +* struct iommu_hwpt_alloc - ioctl(IOMMU_HWPT_ALLOC) +* @size: sizeof(struct iommu_hwpt_alloc) +* @flags: Combination of enum iommufd_hwpt_alloc_flags +* @dev_id: The device to allocate this HWPT for +* @pt_id: The IOAS or HWPT or vIOMMU to connect this HWPT to +* @out_hwpt_id: The ID of the new HWPT +* @__reserved: Must be 0 +* @data_type: One of enum iommu_hwpt_data_type +* @data_len: Length of the type specific data +* @data_uptr: User pointer to the type specific data +* @fault_id: The ID of IOMMUFD_FAULT object. Valid only if flags field of +* IOMMU_HWPT_FAULT_ID_VALID is set. +* @__reserved2: Padding to 64-bit alignment. Must be 0. +* +* Explicitly allocate a hardware page table object. This is the same object +* type that is returned by iommufd_device_attach() and represents the +* underlying iommu driver's iommu_domain kernel object. +* +* A kernel-managed HWPT will be created with the mappings from the given +* IOAS via the @pt_id. The @data_type for this allocation must be set to +* IOMMU_HWPT_DATA_NONE. The HWPT can be allocated as a parent HWPT for a +* nesting configuration by passing IOMMU_HWPT_ALLOC_NEST_PARENT via @flags. +* +* A user-managed nested HWPT will be created from a given vIOMMU (wrapping a +* parent HWPT) or a parent HWPT via @pt_id, in which the parent HWPT must be +* allocated previously via the same ioctl from a given IOAS (@pt_id). In this +* case, the @data_type must be set to a pre-defined type corresponding to an +* I/O page table type supported by the underlying IOMMU hardware. The device +* via @dev_id and the vIOMMU via @pt_id must be associated to the same IOMMU +* instance. +* +* If the @data_type is set to IOMMU_HWPT_DATA_NONE, @data_len and +* @data_uptr should be zero. Otherwise, both @data_len and @data_uptr +* must be given. +*/ +struct iommu_hwpt_alloc { +__u32 size; +__u32 flags; +__u32 dev_id; +__u32 pt_id; +__u32 out_hwpt_id; +__u32 __reserved; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr; +__u32 fault_id; +__u32 __reserved2; +}; +#define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) + +/** +* enum iommu_hw_info_vtd_flags - Flags for VT-d hw_info +* @IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17: If set, disallow read-only mappings +* on a nested_parent domain. +* https://www.intel.com/content/www/us/en/content-details/772415/content-details.html +*/ +enum iommu_hw_info_vtd_flags { +IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17 =1 <<0 , +}; + +/** +* struct iommu_hw_info_vtd - Intel VT-d hardware information +* +* @flags: Combination of enum iommu_hw_info_vtd_flags +* @__reserved: Must be 0 +* +* @cap_reg: Value of Intel VT-d capability register defined in VT-d spec +* section 11.4.2 Capability Register. +* @ecap_reg: Value of Intel VT-d capability register defined in VT-d spec +* section 11.4.3 Extended Capability Register. +* +* User needs to understand the Intel VT-d specification to decode the +* register value. +*/ +struct iommu_hw_info_vtd { +__u32 flags; +__u32 __reserved; +__aligned_u64 cap_reg; +__aligned_u64 ecap_reg; +}; + +/** +* struct iommu_hw_info_arm_smmuv3 - ARM SMMUv3 hardware information +* (IOMMU_HW_INFO_TYPE_ARM_SMMUV3) +* +* @flags: Must be set to 0 +* @__reserved: Must be 0 +* @idr: Implemented features for ARM SMMU Non-secure programming interface +* @iidr: Information about the implementation and implementer of ARM SMMU, +* and architecture version supported +* @aidr: ARM SMMU architecture version +* +* For the details of @idr, @iidr and @aidr, please refer to the chapters +* from 6.3.1 to 6.3.6 in the SMMUv3 Spec. +* +* This reports the raw HW capability, and not all bits are meaningful to be +* read by userspace. Only the following fields should be used: +* +* idr[0]: ST_LEVEL, TERM_MODEL, STALL_MODEL, TTENDIAN , CD2L, ASID16, TTF +* idr[1]: SIDSIZE, SSIDSIZE +* idr[3]: BBML, RIL +* idr[5]: VAX, GRAN64K, GRAN16K, GRAN4K +* +* - S1P should be assumed to be true if a NESTED HWPT can be created +* - VFIO/iommufd only support platforms with COHACC, it should be assumed to be +* true. +* - ATS is a per-device property. If the VMM describes any devices as ATS +* capable in ACPI/DT it should set the corresponding idr. +* +* This list may expand in future (eg E0PD, AIE, PBHA, D128, DS etc). It is +* important that VMMs do not read bits outside the list to allow for +* compatibility with future kernels. Several features in the SMMUv3 +* architecture are not currently supported by the kernel for nesting: HTTU, +* BTM, MPAM and others. +*/ +struct iommu_hw_info_arm_smmuv3 { +__u32 flags; +__u32 __reserved; +__u32 idr[6 ]; +__u32 iidr; +__u32 aidr; +}; + +/** +* struct iommu_hw_info_tegra241_cmdqv - NVIDIA Tegra241 CMDQV Hardware +* Information (IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV) +* +* @flags: Must be 0 +* @version: Version number for the CMDQ-V HW for PARAM bits[03:00] +* @log2vcmdqs: Log2 of the total number of VCMDQs for PARAM bits[07:04] +* @log2vsids: Log2 of the total number of SID replacements for PARAM bits[15:12] +* @__reserved: Must be 0 +* +* VMM can use these fields directly in its emulated global PARAM register. Note +* that only one Virtual Interface (VINTF) should be exposed to a VM, i.e. PARAM +* bits[11:08] should be set to 0 for log2 of the total number of VINTFs. +*/ +struct iommu_hw_info_tegra241_cmdqv { +__u32 flags; +__u8 version; +__u8 log2vcmdqs; +__u8 log2vsids; +__u8 __reserved; +}; + +/** +* enum iommu_hw_info_type - IOMMU Hardware Info Types +* @IOMMU_HW_INFO_TYPE_NONE: Output by the drivers that do not report hardware +* info +* @IOMMU_HW_INFO_TYPE_DEFAULT: Input to request for a default type +* @IOMMU_HW_INFO_TYPE_INTEL_VTD: Intel VT-d iommu info type +* @IOMMU_HW_INFO_TYPE_ARM_SMMUV3: ARM SMMUv3 iommu info type +* @IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) info type +*/ +enum iommu_hw_info_type { +IOMMU_HW_INFO_TYPE_NONE =0 , +IOMMU_HW_INFO_TYPE_DEFAULT =0 , +IOMMU_HW_INFO_TYPE_INTEL_VTD =1 , +IOMMU_HW_INFO_TYPE_ARM_SMMUV3 =2 , +IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV =3 , +}; + +/** +* enum iommufd_hw_capabilities +* @IOMMU_HW_CAP_DIRTY_TRACKING: IOMMU hardware support for dirty tracking +* If available, it means the following APIs +* are supported: +* +* IOMMU_HWPT_GET_DIRTY_BITMAP +* IOMMU_HWPT_SET_DIRTY_TRACKING +* +* @IOMMU_HW_CAP_PCI_PASID_EXEC: Execute Permission Supported, user ignores it +* when the struct +* iommu_hw_info::out_max_pasid_log2 is zero. +* @IOMMU_HW_CAP_PCI_PASID_PRIV: Privileged Mode Supported, user ignores it +* when the struct +* iommu_hw_info::out_max_pasid_log2 is zero. +*/ +enum iommufd_hw_capabilities { +IOMMU_HW_CAP_DIRTY_TRACKING =1 <<0 , +IOMMU_HW_CAP_PCI_PASID_EXEC =1 <<1 , +IOMMU_HW_CAP_PCI_PASID_PRIV =1 <<2 , +}; + +/** +* enum iommufd_hw_info_flags - Flags for iommu_hw_info +* @IOMMU_HW_INFO_FLAG_INPUT_TYPE: If set, @in_data_type carries an input type +* for user space to request for a specific info +*/ +enum iommufd_hw_info_flags { +IOMMU_HW_INFO_FLAG_INPUT_TYPE =1 <<0 , +}; + +/** +* struct iommu_hw_info - ioctl(IOMMU_GET_HW_INFO) +* @size: sizeof(struct iommu_hw_info) +* @flags: Must be 0 +* @dev_id: The device bound to the iommufd +* @data_len: Input the length of a user buffer in bytes. Output the length of +* data that kernel supports +* @data_uptr: User pointer to a user-space buffer used by the kernel to fill +* the iommu type specific hardware information data +* @in_data_type: This shares the same field with @out_data_type, making it be +* a bidirectional field. When IOMMU_HW_INFO_FLAG_INPUT_TYPE is +* set, an input type carried via this @in_data_type field will +* be valid, requesting for the info data to the given type. If +* IOMMU_HW_INFO_FLAG_INPUT_TYPE is unset, any input value will +* be seen as IOMMU_HW_INFO_TYPE_DEFAULT +* @out_data_type: Output the iommu hardware info type as defined in the enum +* iommu_hw_info_type. +* @out_capabilities: Output the generic iommu capability info type as defined +* in the enum iommu_hw_capabilities. +* @out_max_pasid_log2: Output the width of PASIDs. 0 means no PASID support. +* PCI devices turn to out_capabilities to check if the +* specific capabilities is supported or not. +* @__reserved: Must be 0 +* +* Query an iommu type specific hardware information data from an iommu behind +* a given device that has been bound to iommufd. This hardware info data will +* be used to sync capabilities between the virtual iommu and the physical +* iommu, e.g. a nested translation setup needs to check the hardware info, so +* a guest stage-1 page table can be compatible with the physical iommu. +* +* To capture an iommu type specific hardware information data, @data_uptr and +* its length @data_len must be provided. Trailing bytes will be zeroed if the +* user buffer is larger than the data that kernel has. Otherwise, kernel only +* fills the buffer using the given length in @data_len. If the ioctl succeeds, +* @data_len will be updated to the length that kernel actually supports, +* @out_data_type will be filled to decode the data filled in the buffer +* pointed by @data_uptr. Input @data_len == zero is allowed. +*/ +struct iommu_hw_info { +__u32 size; +__u32 flags; +__u32 dev_id; +__u32 data_len; +__aligned_u64 data_uptr; +union { +__u32 in_data_type; +__u32 out_data_type; + }; +__u8 out_max_pasid_log2; +__u8 __reserved[3 ]; +__aligned_u64 out_capabilities; +}; +#define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO) + +/* +* enum iommufd_hwpt_set_dirty_tracking_flags - Flags for steering dirty +* tracking +* @IOMMU_HWPT_DIRTY_TRACKING_ENABLE: Enable dirty tracking +*/ +enum iommufd_hwpt_set_dirty_tracking_flags { +IOMMU_HWPT_DIRTY_TRACKING_ENABLE =1 , +}; + +/** +* struct iommu_hwpt_set_dirty_tracking - ioctl(IOMMU_HWPT_SET_DIRTY_TRACKING) +* @size: sizeof(struct iommu_hwpt_set_dirty_tracking) +* @flags: Combination of enum iommufd_hwpt_set_dirty_tracking_flags +* @hwpt_id: HW pagetable ID that represents the IOMMU domain +* @__reserved: Must be 0 +* +* Toggle dirty tracking on an HW pagetable. +*/ +struct iommu_hwpt_set_dirty_tracking { +__u32 size; +__u32 flags; +__u32 hwpt_id; +__u32 __reserved; +}; +#define IOMMU_HWPT_SET_DIRTY_TRACKING _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING) + +/** +* enum iommufd_hwpt_get_dirty_bitmap_flags - Flags for getting dirty bits +* @IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR: Just read the PTEs without clearing +* any dirty bits metadata. This flag +* can be passed in the expectation +* where the next operation is an unmap +* of the same IOVA range. +* +*/ +enum iommufd_hwpt_get_dirty_bitmap_flags { +IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR =1 , +}; + +/** +* struct iommu_hwpt_get_dirty_bitmap - ioctl(IOMMU_HWPT_GET_DIRTY_BITMAP) +* @size: sizeof(struct iommu_hwpt_get_dirty_bitmap) +* @hwpt_id: HW pagetable ID that represents the IOMMU domain +* @flags: Combination of enum iommufd_hwpt_get_dirty_bitmap_flags +* @__reserved: Must be 0 +* @iova: base IOVA of the bitmap first bit +* @length: IOVA range size +* @page_size: page size granularity of each bit in the bitmap +* @data: bitmap where to set the dirty bits. The bitmap bits each +* represent a page_size which you deviate from an arbitrary iova. +* +* Checking a given IOVA is dirty: +* +* data[(iova / page_size) / 64] & (1ULL << ((iova / page_size) % 64)) +* +* Walk the IOMMU pagetables for a given IOVA range to return a bitmap +* with the dirty IOVAs. In doing so it will also by default clear any +* dirty bit metadata set in the IOPTE. +*/ +struct iommu_hwpt_get_dirty_bitmap { +__u32 size; +__u32 hwpt_id; +__u32 flags; +__u32 __reserved; +__aligned_u64 iova; +__aligned_u64 length; +__aligned_u64 page_size; +__aligned_u64 data; +}; +#define IOMMU_HWPT_GET_DIRTY_BITMAP _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP) + +/** +* enum iommu_hwpt_invalidate_data_type - IOMMU HWPT Cache Invalidation +* Data Type +* @IOMMU_HWPT_INVALIDATE_DATA_VTD_S1: Invalidation data for VTD_S1 +* @IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3: Invalidation data for ARM SMMUv3 +*/ +enum iommu_hwpt_invalidate_data_type { +IOMMU_HWPT_INVALIDATE_DATA_VTD_S1 =0 , +IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3 =1 , +}; + +/** +* enum iommu_hwpt_vtd_s1_invalidate_flags - Flags for Intel VT-d +* stage-1 cache invalidation +* @IOMMU_VTD_INV_FLAGS_LEAF: Indicates whether the invalidation applies +* to all-levels page structure cache or just +* the leaf PTE cache. +*/ +enum iommu_hwpt_vtd_s1_invalidate_flags { +IOMMU_VTD_INV_FLAGS_LEAF =1 <<0 , +}; + +/** +* struct iommu_hwpt_vtd_s1_invalidate - Intel VT-d cache invalidation +* (IOMMU_HWPT_INVALIDATE_DATA_VTD_S1) +* @addr: The start address of the range to be invalidated. It needs to +* be 4KB aligned. +* @npages: Number of contiguous 4K pages to be invalidated. +* @flags: Combination of enum iommu_hwpt_vtd_s1_invalidate_flags +* @__reserved: Must be 0 +* +* The Intel VT-d specific invalidation data for user-managed stage-1 cache +* invalidation in nested translation. Userspace uses this structure to +* tell the impacted cache scope after modifying the stage-1 page table. +* +* Invalidating all the caches related to the page table by setting @addr +* to be 0 and @npages to be U64_MAX. +* +* The device TLB will be invalidated automatically if ATS is enabled. +*/ +struct iommu_hwpt_vtd_s1_invalidate { +__aligned_u64 addr; +__aligned_u64 npages; +__u32 flags; +__u32 __reserved; +}; + +/** +* struct iommu_viommu_arm_smmuv3_invalidate - ARM SMMUv3 cache invalidation +* (IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3) +* @cmd: 128-bit cache invalidation command that runs in SMMU CMDQ. +* Must be little-endian. +* +* Supported command list only when passing in a vIOMMU via @hwpt_id: +* CMDQ_OP_TLBI_NSNH_ALL +* CMDQ_OP_TLBI_NH_VA +* CMDQ_OP_TLBI_NH_VAA +* CMDQ_OP_TLBI_NH_ALL +* CMDQ_OP_TLBI_NH_ASID +* CMDQ_OP_ATC_INV +* CMDQ_OP_CFGI_CD +* CMDQ_OP_CFGI_CD_ALL +* +* -EIO will be returned if the command is not supported. +*/ +struct iommu_viommu_arm_smmuv3_invalidate { +__aligned_le64 cmd[2 ]; +}; + +/** +* struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE) +* @size: sizeof(struct iommu_hwpt_invalidate) +* @hwpt_id: ID of a nested HWPT or a vIOMMU, for cache invalidation +* @data_uptr: User pointer to an array of driver-specific cache invalidation +* data. +* @data_type: One of enum iommu_hwpt_invalidate_data_type, defining the data +* type of all the entries in the invalidation request array. It +* should be a type supported by the hwpt pointed by @hwpt_id. +* @entry_len: Length (in bytes) of a request entry in the request array +* @entry_num: Input the number of cache invalidation requests in the array. +* Output the number of requests successfully handled by kernel. +* @__reserved: Must be 0. +* +* Invalidate iommu cache for user-managed page table or vIOMMU. Modifications +* on a user-managed page table should be followed by this operation, if a HWPT +* is passed in via @hwpt_id. Other caches, such as device cache or descriptor +* cache can be flushed if a vIOMMU is passed in via the @hwpt_id field. +* +* Each ioctl can support one or more cache invalidation requests in the array +* that has a total size of @entry_len * @entry_num. +* +* An empty invalidation request array by setting @entry_num==0 is allowed, and +* @entry_len and @data_uptr would be ignored in this case. This can be used to +* check if the given @data_type is supported or not by kernel. +*/ +struct iommu_hwpt_invalidate { +__u32 size; +__u32 hwpt_id; +__aligned_u64 data_uptr; +__u32 data_type; +__u32 entry_len; +__u32 entry_num; +__u32 __reserved; +}; +#define IOMMU_HWPT_INVALIDATE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_INVALIDATE) + +/** +* enum iommu_hwpt_pgfault_flags - flags for struct iommu_hwpt_pgfault +* @IOMMU_PGFAULT_FLAGS_PASID_VALID: The pasid field of the fault data is +* valid. +* @IOMMU_PGFAULT_FLAGS_LAST_PAGE: It's the last fault of a fault group. +*/ +enum iommu_hwpt_pgfault_flags { +IOMMU_PGFAULT_FLAGS_PASID_VALID = (1 <<0 ), +IOMMU_PGFAULT_FLAGS_LAST_PAGE = (1 <<1 ), +}; + +/** +* enum iommu_hwpt_pgfault_perm - perm bits for struct iommu_hwpt_pgfault +* @IOMMU_PGFAULT_PERM_READ: request for read permission +* @IOMMU_PGFAULT_PERM_WRITE: request for write permission +* @IOMMU_PGFAULT_PERM_EXEC: (PCIE 10.4.1) request with a PASID that has the +* Execute Requested bit set in PASID TLP Prefix. +* @IOMMU_PGFAULT_PERM_PRIV: (PCIE 10.4.1) request with a PASID that has the +* Privileged Mode Requested bit set in PASID TLP +* Prefix. +*/ +enum iommu_hwpt_pgfault_perm { +IOMMU_PGFAULT_PERM_READ = (1 <<0 ), +IOMMU_PGFAULT_PERM_WRITE = (1 <<1 ), +IOMMU_PGFAULT_PERM_EXEC = (1 <<2 ), +IOMMU_PGFAULT_PERM_PRIV = (1 <<3 ), +}; + +/** +* struct iommu_hwpt_pgfault - iommu page fault data +* @flags: Combination of enum iommu_hwpt_pgfault_flags +* @dev_id: id of the originated device +* @pasid: Process Address Space ID +* @grpid: Page Request Group Index +* @perm: Combination of enum iommu_hwpt_pgfault_perm +* @__reserved: Must be 0. +* @addr: Fault address +* @length: a hint of how much data the requestor is expecting to fetch. For +* example, if the PRI initiator knows it is going to do a 10MB +* transfer, it could fill in 10MB and the OS could pre-fault in +* 10MB of IOVA. It's default to 0 if there's no such hint. +* @cookie: kernel-managed cookie identifying a group of fault messages. The +* cookie number encoded in the last page fault of the group should +* be echoed back in the response message. +*/ +struct iommu_hwpt_pgfault { +__u32 flags; +__u32 dev_id; +__u32 pasid; +__u32 grpid; +__u32 perm; +__u32 __reserved; +__aligned_u64 addr; +__u32 length; +__u32 cookie; +}; + +/** +* enum iommufd_page_response_code - Return status of fault handlers +* @IOMMUFD_PAGE_RESP_SUCCESS: Fault has been handled and the page tables +* populated, retry the access. This is the +* "Success" defined in PCI 10.4.2.1. +* @IOMMUFD_PAGE_RESP_INVALID: Could not handle this fault, don't retry the +* access. This is the "Invalid Request" in PCI +* 10.4.2.1. +*/ +enum iommufd_page_response_code { +IOMMUFD_PAGE_RESP_SUCCESS =0 , +IOMMUFD_PAGE_RESP_INVALID =1 , +}; + +/** +* struct iommu_hwpt_page_response - IOMMU page fault response +* @cookie: The kernel-managed cookie reported in the fault message. +* @code: One of response code in enum iommufd_page_response_code. +*/ +struct iommu_hwpt_page_response { +__u32 cookie; +__u32 code; +}; + +/** +* struct iommu_fault_alloc - ioctl(IOMMU_FAULT_QUEUE_ALLOC) +* @size: sizeof(struct iommu_fault_alloc) +* @flags: Must be 0 +* @out_fault_id: The ID of the new FAULT +* @out_fault_fd: The fd of the new FAULT +* +* Explicitly allocate a fault handling object. +*/ +struct iommu_fault_alloc { +__u32 size; +__u32 flags; +__u32 out_fault_id; +__u32 out_fault_fd; +}; +#define IOMMU_FAULT_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_FAULT_QUEUE_ALLOC) + +/** +* enum iommu_viommu_type - Virtual IOMMU Type +* @IOMMU_VIOMMU_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VIOMMU_TYPE_ARM_SMMUV3: ARM SMMUv3 driver specific type +* @IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) enabled ARM SMMUv3 type +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_DEFAULT =0 , +IOMMU_VIOMMU_TYPE_ARM_SMMUV3 =1 , +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV =2 , +}; + +/** +* struct iommu_viommu_tegra241_cmdqv - NVIDIA Tegra241 CMDQV Virtual Interface +* (IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV) +* @out_vintf_mmap_offset: mmap offset argument for VINTF's page0 +* @out_vintf_mmap_length: mmap length argument for VINTF's page0 +* +* Both @out_vintf_mmap_offset and @out_vintf_mmap_length are reported by kernel +* for user space to mmap the VINTF page0 from the host physical address space +* to the guest physical address space so that a guest kernel can directly R/W +* access to the VINTF page0 in order to control its virtual command queues. +*/ +struct iommu_viommu_tegra241_cmdqv { +__aligned_u64 out_vintf_mmap_offset; +__aligned_u64 out_vintf_mmap_length; +}; + +/** +* struct iommu_viommu_alloc - ioctl(IOMMU_VIOMMU_ALLOC) +* @size: sizeof(struct iommu_viommu_alloc) +* @flags: Must be 0 +* @type: Type of the virtual IOMMU. Must be defined in enum iommu_viommu_type +* @dev_id: The device's physical IOMMU will be used to back the virtual IOMMU +* @hwpt_id: ID of a nesting parent HWPT to associate to +* @out_viommu_id: Output virtual IOMMU ID for the allocated object +* @data_len: Length of the type specific data +* @__reserved: Must be 0 +* @data_uptr: User pointer to a driver-specific virtual IOMMU data +* +* Allocate a virtual IOMMU object, representing the underlying physical IOMMU's +* virtualization support that is a security-isolated slice of the real IOMMU HW +* that is unique to a specific VM. Operations global to the IOMMU are connected +* to the vIOMMU, such as: +* - Security namespace for guest owned ID, e.g. guest-controlled cache tags +* - Non-device-affiliated event reporting, e.g. invalidation queue errors +* - Access to a sharable nesting parent pagetable across physical IOMMUs +* - Virtualization of various platforms IDs, e.g. RIDs and others +* - Delivery of paravirtualized invalidation +* - Direct assigned invalidation queues +* - Direct assigned interrupts +*/ +struct iommu_viommu_alloc { +__u32 size; +__u32 flags; +__u32 type; +__u32 dev_id; +__u32 hwpt_id; +__u32 out_viommu_id; +__u32 data_len; +__u32 __reserved; +__aligned_u64 data_uptr; +}; +#define IOMMU_VIOMMU_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_ALLOC) + +/** +* struct iommu_vdevice_alloc - ioctl(IOMMU_VDEVICE_ALLOC) +* @size: sizeof(struct iommu_vdevice_alloc) +* @viommu_id: vIOMMU ID to associate with the virtual device +* @dev_id: The physical device to allocate a virtual instance on the vIOMMU +* @out_vdevice_id: Object handle for the vDevice. Pass to IOMMU_DESTORY +* @virt_id: Virtual device ID per vIOMMU, e.g. vSID of ARM SMMUv3, vDeviceID +* of AMD IOMMU, and vRID of Intel VT-d +* +* Allocate a virtual device instance (for a physical device) against a vIOMMU. +* This instance holds the device's information (related to its vIOMMU) in a VM. +* User should use IOMMU_DESTROY to destroy the virtual device before +* destroying the physical device (by closing vfio_cdev fd). Otherwise the +* virtual device would be forcibly destroyed on physical device destruction, +* its vdevice_id would be permanently leaked (unremovable & unreusable) until +* iommu fd closed. +*/ +struct iommu_vdevice_alloc { +__u32 size; +__u32 viommu_id; +__u32 dev_id; +__u32 out_vdevice_id; +__aligned_u64 virt_id; +}; +#define IOMMU_VDEVICE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VDEVICE_ALLOC) + +/** +* struct iommu_ioas_change_process - ioctl(VFIO_IOAS_CHANGE_PROCESS) +* @size: sizeof(struct iommu_ioas_change_process) +* @__reserved: Must be 0 +* +* This transfers pinned memory counts for every memory map in every IOAS +* in the context to the current process. This only supports maps created +* with IOMMU_IOAS_MAP_FILE, and returns EINVAL if other maps are present. +* If the ioctl returns a failure status, then nothing is changed. +* +* This API is useful for transferring operation of a device from one process +* to another, such as during userland live update. +*/ +struct iommu_ioas_change_process { +__u32 size; +__u32 __reserved; +}; + +#define IOMMU_IOAS_CHANGE_PROCESS \ + _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_CHANGE_PROCESS) + +/** +* enum iommu_veventq_flag - flag for struct iommufd_vevent_header +* @IOMMU_VEVENTQ_FLAG_LOST_EVENTS: vEVENTQ has lost vEVENTs +*/ +enum iommu_veventq_flag { +IOMMU_VEVENTQ_FLAG_LOST_EVENTS = (1U <<0 ), +}; + +/** +* struct iommufd_vevent_header - Virtual Event Header for a vEVENTQ Status +* @flags: Combination of enum iommu_veventq_flag +* @sequence: The sequence index of a vEVENT in the vEVENTQ, with a range of +* [0, INT_MAX] where the following index of INT_MAX is 0 +* +* Each iommufd_vevent_header reports a sequence index of the following vEVENT: +* +* +----------------------+-------+----------------------+-------+---+-------+ +* | header0 {sequence=0} | data0 | header1 {sequence=1} | data1 |...| dataN | +* +----------------------+-------+----------------------+-------+---+-------+ +* +* And this sequence index is expected to be monotonic to the sequence index of +* the previous vEVENT. If two adjacent sequence indexes has a delta larger than +* 1, it means that delta - 1 number of vEVENTs has lost, e.g. two lost vEVENTs: +* +* +-----+----------------------+-------+----------------------+-------+-----+ +* | ... | header3 {sequence=3} | data3 | header6 {sequence=6} | data6 | ... | +* +-----+----------------------+-------+----------------------+-------+-----+ +* +* If a vEVENT lost at the tail of the vEVENTQ and there is no following vEVENT +* providing the next sequence index, an IOMMU_VEVENTQ_FLAG_LOST_EVENTS header +* would be added to the tail, and no data would follow this header: +* +* +--+----------------------+-------+-----------------------------------------+ +* |..| header3 {sequence=3} | data3 | header4 {flags=LOST_EVENTS, sequence=4} | +* +--+----------------------+-------+-----------------------------------------+ +*/ +struct iommufd_vevent_header { +__u32 flags; +__u32 sequence; +}; + +/** +* enum iommu_veventq_type - Virtual Event Queue Type +* @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue +* @IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension IRQ +*/ +enum iommu_veventq_type { +IOMMU_VEVENTQ_TYPE_DEFAULT =0 , +IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 =1 , +IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV =2 , +}; + +/** +* struct iommu_vevent_arm_smmuv3 - ARM SMMUv3 Virtual Event +* (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) +* @evt: 256-bit ARM SMMUv3 Event record, little-endian. +* Reported event records: (Refer to "7.3 Event records" in SMMUv3 HW Spec) +* - 0x04 C_BAD_STE +* - 0x06 F_STREAM_DISABLED +* - 0x08 C_BAD_SUBSTREAMID +* - 0x0a C_BAD_CD +* - 0x10 F_TRANSLATION +* - 0x11 F_ADDR_SIZE +* - 0x12 F_ACCESS +* - 0x13 F_PERMISSION +* +* StreamID field reports a virtual device ID. To receive a virtual event for a +* device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC. +*/ +struct iommu_vevent_arm_smmuv3 { +__aligned_le64 evt[4 ]; +}; + +/** +* struct iommu_vevent_tegra241_cmdqv - Tegra241 CMDQV IRQ +* (IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV) +* @lvcmdq_err_map: 128-bit logical vcmdq error map, little-endian. +* (Refer to register LVCMDQ_ERR_MAPs per VINTF ) +* +* The 128-bit register value from HW exclusively reflect the error bits for a +* Virtual Interface represented by a vIOMMU object. Read and report directly. +*/ +struct iommu_vevent_tegra241_cmdqv { +__aligned_le64 lvcmdq_err_map[2 ]; +}; + +/** +* struct iommu_veventq_alloc - ioctl(IOMMU_VEVENTQ_ALLOC) +* @size: sizeof(struct iommu_veventq_alloc) +* @flags: Must be 0 +* @viommu_id: virtual IOMMU ID to associate the vEVENTQ with +* @type: Type of the vEVENTQ. Must be defined in enum iommu_veventq_type +* @veventq_depth: Maximum number of events in the vEVENTQ +* @out_veventq_id: The ID of the new vEVENTQ +* @out_veventq_fd: The fd of the new vEVENTQ. User space must close the +* successfully returned fd after using it +* @__reserved: Must be 0 +* +* Explicitly allocate a virtual event queue interface for a vIOMMU. A vIOMMU +* can have multiple FDs for different types, but is confined to one per @type. +* User space should open the @out_veventq_fd to read vEVENTs out of a vEVENTQ, +* if there are vEVENTs available. A vEVENTQ will lose events due to overflow, +* if the number of the vEVENTs hits @veventq_depth. +* +* Each vEVENT in a vEVENTQ encloses a struct iommufd_vevent_header followed by +* a type-specific data structure, in a normal case: +* +* +-+---------+-------+---------+-------+-----+---------+-------+-+ +* | | header0 | data0 | header1 | data1 | ... | headerN | dataN | | +* +-+---------+-------+---------+-------+-----+---------+-------+-+ +* +* unless a tailing IOMMU_VEVENTQ_FLAG_LOST_EVENTS header is logged (refer to +* struct iommufd_vevent_header). +*/ +struct iommu_veventq_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 type; +__u32 veventq_depth; +__u32 out_veventq_id; +__u32 out_veventq_fd; +__u32 __reserved; +}; +#define IOMMU_VEVENTQ_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VEVENTQ_ALLOC) + +/** +* enum iommu_hw_queue_type - HW Queue Type +* @IOMMU_HW_QUEUE_TYPE_DEFAULT: Reserved for future use +* @IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) Virtual Command Queue (VCMDQ) +*/ +enum iommu_hw_queue_type { +IOMMU_HW_QUEUE_TYPE_DEFAULT =0 , +/* +* TEGRA241_CMDQV requirements (otherwise, allocation will fail) +* - alloc starts from the lowest @index=0 in ascending order +* - destroy starts from the last allocated @index in descending order +* - @base_addr must be aligned to @length in bytes and mapped in IOAS +* - @length must be a power of 2, with a minimum 32 bytes and a maximum +* 2 ^ idr[1].CMDQS * 16 bytes (use GET_HW_INFO call to read idr[1] +* from struct iommu_hw_info_arm_smmuv3) +* - suggest to back the queue memory with contiguous physical pages or +* a single huge page with alignment of the queue size, and limit the +* emulated vSMMU's IDR1.CMDQS to log2(huge page size / 16 bytes) +*/ +IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV =1 , +}; + +/** +* struct iommu_hw_queue_alloc - ioctl(IOMMU_HW_QUEUE_ALLOC) +* @size: sizeof(struct iommu_hw_queue_alloc) +* @flags: Must be 0 +* @viommu_id: Virtual IOMMU ID to associate the HW queue with +* @type: One of enum iommu_hw_queue_type +* @index: The logical index to the HW queue per virtual IOMMU for a multi-queue +* model +* @out_hw_queue_id: The ID of the new HW queue +* @nesting_parent_iova: Base address of the queue memory in the guest physical +* address space +* @length: Length of the queue memory +* +* Allocate a HW queue object for a vIOMMU-specific HW-accelerated queue, which +* allows HW to access a guest queue memory described using @nesting_parent_iova +* and @length. +* +* A vIOMMU can allocate multiple queues, but it must use a different @index per +* type to separate each allocation, e.g:: +* +* Type1 HW queue0, Type1 HW queue1, Type2 HW queue0, ... +*/ +struct iommu_hw_queue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 type; +__u32 index; +__u32 out_hw_queue_id; +__aligned_u64 nesting_parent_iova; +__aligned_u64 length; +}; +#define IOMMU_HW_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HW_QUEUE_ALLOC) +#endif
kernel/linux/uapi/linux/vduse.h +1 -1
@@ -237,7 +237,7 @@ struct vduse_iova_umem {* struct vduse_iova_info - information of one IOVA region * @start: start of the IOVA region * @last: last of the IOVA region -* @capability: capability of the IOVA regsion +* @capability: capability of the IOVA region * @reserved: for future use, needs to be initialized to zero * * Structure used by VDUSE_IOTLB_GET_INFO ioctl to get information of
kernel/linux/uapi/linux/vfio.h +11 -1
@@ -905,10 +905,12 @@ struct vfio_device_feature {* VFIO_DEVICE_BIND_IOMMUFD - _IOR(VFIO_TYPE, VFIO_BASE + 18, * struct vfio_device_bind_iommufd) * @argsz: User filled size of this data. -* @flags: Must be 0. +* @flags: Must be 0 or a bit flags of VFIO_DEVICE_BIND_* * @iommufd: iommufd to bind. * @out_devid: The device id generated by this bind. devid is a handle for * this device/iommufd bond and can be used in IOMMUFD commands. +* @token_uuid_ptr: Valid if VFIO_DEVICE_BIND_FLAG_TOKEN. Points to a 16 byte +* UUID in the same format as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN. * * Bind a vfio_device to the specified iommufd. *
@@ -917,13 +919,21 @@ struct vfio_device_feature {* * Unbind is automatically conducted when device fd is closed. * +* A token is sometimes required to open the device, unless this is known to be +* needed VFIO_DEVICE_BIND_FLAG_TOKEN should not be set and token_uuid_ptr is +* ignored. The only case today is a PF/VF relationship where the VF bind must +* be provided the same token as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN provided to +* the PF. +* * Return: 0 on success, -errno on failure. */ struct vfio_device_bind_iommufd {__u32 argsz;__u32 flags; +#define VFIO_DEVICE_BIND_FLAG_TOKEN (1 << 0)__s32 iommufd;__u32 out_devid; +__aligned_u64 token_uuid_ptr; };#define VFIO_DEVICE_BIND_IOMMUFD _IO(VFIO_TYPE, VFIO_BASE + 18)
kernel/linux/uapi/version +1 -1
@@ -1 +1 @@ -v6.16 +v6.17
Signature · 1 line
2.52.0
PATCH v10 2/20 vfio: make all functions internal
In reply to Anatoly BurakovThe VFIO API is an externally exported API because the original intent was to offer DMA mapping facilities to applications. However, practical usage of this API seems to be centered around drivers, so keeping this API exported to applications only creates needless API/ABI stability surface that has no added value.
Make the entire VFIO API internal-only and visible only to drivers.
--- doc/guides/rel_notes/deprecation.rst | 6 ---- lib/eal/freebsd/eal.c | 30 +++++++++--------- lib/eal/include/rte_vfio.h | 47 ++++++++++++++++++++++++---- lib/eal/linux/eal_vfio.c | 32 +++++++++---------- lib/eal/windows/eal.c | 4 +-- 5 files changed, 74 insertions(+), 45 deletions(-)
doc/guides/rel_notes/deprecation.rst +0 -6
@@ -29,12 +29,6 @@ Deprecation Notices Use the ``-S <service-corelist>`` parameter instead to specify the cores to be used for background services in DPDK. -* eal: The entire VFIO API (``rte_vfio_*``) will be made internal only, - and will only be available to EAL and drivers. - Group-based API (``rte_vfio_*_group_*``) will be removed - and replaced with unified container device assignment API. - This change will be made in 26.11 release. - * vdpa: The vDPA driver API will no longer offer ``get_vfio_group_fd`` as part of its internal API. All drivers will be adjusted to use the new unified VFIO container device assignment API.
lib/eal/freebsd/eal.c +15 -15
@@ -819,7 +819,7 @@ rte_eal_vfio_get_vf_token(__rte_unused rte_uuid_t vf_token) { } -RTE_EXPORT_SYMBOL(rte_vfio_setup_device) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_setup_device) int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, __rte_unused int *vfio_dev_fd,
@@ -829,7 +829,7 @@ int rte_vfio_setup_device(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_release_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_release_device) int rte_vfio_release_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, __rte_unused int fd)
@@ -838,33 +838,33 @@ int rte_vfio_release_device(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_enable) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_enable) int rte_vfio_enable(__rte_unused const char *modname) { rte_errno =ENOTSUP ;return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_is_enabled) int rte_vfio_is_enabled(__rte_unused const char *modname) {return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_noiommu_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) int rte_vfio_noiommu_is_enabled(void) {return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_clear_group) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) int rte_vfio_clear_group(__rte_unused int vfio_group_fd) { rte_errno =ENOTSUP ;return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_get_group_num) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr,
@@ -874,7 +874,7 @@ rte_vfio_get_group_num(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_container_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_container_fd) intrte_vfio_get_container_fd (void ) {
@@ -882,7 +882,7 @@ rte_vfio_get_container_fd(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) int rte_vfio_get_group_fd(__rte_unused int iommu_group_num) {
@@ -890,7 +890,7 @@ rte_vfio_get_group_fd(__rte_unused int iommu_group_num)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_create) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void ) {
@@ -898,7 +898,7 @@ rte_vfio_container_create(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_destroy) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_destroy) int rte_vfio_container_destroy(__rte_unused int container_fd) {
@@ -906,7 +906,7 @@ rte_vfio_container_destroy(__rte_unused int container_fd)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_bind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) int rte_vfio_container_group_bind(__rte_unused int container_fd, __rte_unused int iommu_group_num)
@@ -915,7 +915,7 @@ rte_vfio_container_group_bind(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_unbind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) int rte_vfio_container_group_unbind(__rte_unused int container_fd, __rte_unused int iommu_group_num)
@@ -924,7 +924,7 @@ rte_vfio_container_group_unbind(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
@@ -935,7 +935,7 @@ rte_vfio_container_dma_map(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_unmap) int rte_vfio_container_dma_unmap(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
lib/eal/include/rte_vfio.h +41 -6
214 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +16 -16
@@ -532,7 +532,7 @@ get_vfio_cfg_by_container_fd(int container_fd)return NULL ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) intrte_vfio_get_group_fd (int iommu_group_num) {
@@ -731,7 +731,7 @@ vfio_sync_default_container(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_clear_group) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) intrte_vfio_clear_group (int vfio_group_fd) {
@@ -755,7 +755,7 @@ rte_vfio_clear_group(int vfio_group_fd)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_setup_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) intrte_vfio_setup_device (const char *sysfs_base,const char *dev_addr,int *vfio_dev_fd,struct vfio_device_info *device_info)
@@ -1009,7 +1009,7 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_release_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_release_device) intrte_vfio_release_device (const char *sysfs_base,const char *dev_addr,int vfio_dev_fd)
@@ -1098,7 +1098,7 @@ rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,return ret; } -RTE_EXPORT_SYMBOL (rte_vfio_enable) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_enable) intrte_vfio_enable (const char *modname) {
@@ -1175,7 +1175,7 @@ rte_vfio_enable(const char *modname)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_is_enabled) intrte_vfio_is_enabled (const char *modname) {
@@ -1215,7 +1215,7 @@ vfio_set_iommu_type(int vfio_container_fd)return NULL ; } -RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vfio_get_device_info, 24.03) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) intrte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr,int *vfio_dev_fd,struct vfio_device_info *device_info)
@@ -1349,7 +1349,7 @@ vfio_open_container_fd(bool mp_request)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_container_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_container_fd) intrte_vfio_get_container_fd (void ) {
@@ -1363,7 +1363,7 @@ rte_vfio_get_container_fd(void)return default_vfio_cfg->vfio_container_fd; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_num) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_num) intrte_vfio_get_group_num (const char *sysfs_base,const char *dev_addr,int *iommu_group_num)
@@ -2034,7 +2034,7 @@ container_dma_unmap(struct vfio_config *vfio_cfg, uint64_t vaddr, uint64_t iova,return ret; } -RTE_EXPORT_SYMBOL (rte_vfio_noiommu_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) intrte_vfio_noiommu_is_enabled (void ) {
@@ -2067,7 +2067,7 @@ rte_vfio_noiommu_is_enabled(void)return c =='Y' ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_create) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void ) {
@@ -2094,7 +2094,7 @@ rte_vfio_container_create(void)return vfio_cfgs[i].vfio_container_fd; } -RTE_EXPORT_SYMBOL (rte_vfio_container_destroy) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_destroy) intrte_vfio_container_destroy (int container_fd) {
@@ -2120,7 +2120,7 @@ rte_vfio_container_destroy(int container_fd)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_bind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) intrte_vfio_container_group_bind (int container_fd,int iommu_group_num) {
@@ -2135,7 +2135,7 @@ rte_vfio_container_group_bind(int container_fd, int iommu_group_num)return vfio_get_group_fd (vfio_cfg, iommu_group_num); } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_unbind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) intrte_vfio_container_group_unbind (int container_fd,int iommu_group_num) {
@@ -2176,7 +2176,7 @@ rte_vfio_container_group_unbind(int container_fd, int iommu_group_num)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_dma_map) intrte_vfio_container_dma_map (int container_fd,uint64_t vaddr,uint64_t iova,uint64_t len)
@@ -2197,7 +2197,7 @@ rte_vfio_container_dma_map(int container_fd, uint64_t vaddr, uint64_t iova,return container_dma_map (vfio_cfg, vaddr, iova, len); } -RTE_EXPORT_SYMBOL (rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_dma_unmap) intrte_vfio_container_dma_unmap (int container_fd,uint64_t vaddr,uint64_t iova,uint64_t len)
lib/eal/windows/eal.c +2 -2
@@ -453,7 +453,7 @@ eal_asprintf(char **buffer, const char *format, ...)return ret; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
@@ -464,7 +464,7 @@ rte_vfio_container_dma_map(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_unmap) int rte_vfio_container_dma_unmap(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
Signature · 1 line
2.52.0
PATCH v10 3/20 bus/pci: rename mismatching error labels
In reply to Anatoly BurakovCurrently, there are two VFIO map functions - primary and secondary - that use a very similar goto error pattern. However, the label names are confusing.
Specifcally, for primary, we have three error labels: vfio_res (release VFIO resource), vfio_dev_fd (close the fd), and map (unmap all the mapped regions). For secondary, there is vfio_dev (close the fd), and vfio_dev_fd (unmap all mapped regions).
For consistency, align secondary process function's error labels to match semantics of how they work in primary process function.
--- drivers/bus/pci/linux/pci_vfio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/bus/pci/linux/pci_vfio.c +7 -7
@@ -968,7 +968,7 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) ret =pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info);if (ret) - goto err_vfio_dev; + goto err_vfio_dev_fd;/* map BARs */ maps = vfio_res->maps;
@@ -979,14 +979,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)if (ret <0 ) {PCI_LOG (ERR ,"%s sparse mapping BAR%i failed: %s" , pci_addr, i,strerror (errno)); - goto err_vfio_dev_fd; + goto err_map; } }else { ret =pci_vfio_mmap_bar (vfio_dev_fd, vfio_res, i,MAP_FIXED );if (ret <0 ) {PCI_LOG (ERR ,"%s mapping BAR%i failed: %s" , pci_addr, i,strerror (errno)); - goto err_vfio_dev_fd; + goto err_map; } }
@@ -995,17 +995,17 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)/* we need save vfio_dev_fd, so it can be used during release */ if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd)) - goto err_vfio_dev_fd; + goto err_map;if (rte_intr_dev_fd_set (dev->vfio_req_intr_handle, vfio_dev_fd)) - goto err_vfio_dev_fd; + goto err_map;return 0 ; -err_vfio_dev_fd: +err_map:for (j =0 ; j < i; j++) {if (maps[j].addr)pci_unmap_resource (maps[j].addr, maps[j].size); } -err_vfio_dev: +err_vfio_dev_fd:rte_vfio_release_device (rte_pci_get_sysfs_path (), pci_addr, vfio_dev_fd);return -1 ;
Signature · 1 line
2.52.0
PATCH v10 4/20 vfio: split get device info from setup
In reply to Anatoly BurakovCurrently, setup gets device info as part of setup, while the separate get device info API also calls setup if the fd is zero. Untangle these two APIs and make each do one thing, and adjust all existing callers.
--- drivers/bus/cdx/cdx_vfio.c | 12 ++++++++-- drivers/bus/pci/linux/pci_vfio.c | 18 ++++++++++---- drivers/bus/platform/platform.c | 9 ++++++- drivers/crypto/bcmfs/bcmfs_vfio.c | 8 ++++++- lib/eal/freebsd/eal.c | 3 +-- lib/eal/include/rte_vfio.h | 23 +++++++----------- lib/eal/linux/eal_vfio.c | 40 +++++++++---------------------- 7 files changed, 59 insertions(+), 54 deletions(-)
drivers/bus/cdx/cdx_vfio.c +10 -2
@@ -401,10 +401,14 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev)return -1 ; ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* allocate vfio_res and get region info */ vfio_res =rte_zmalloc ("VFIO_RES" ,sizeof (*vfio_res),0 );if (vfio_res ==NULL ) {
@@ -510,10 +514,14 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev) } ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* map MMIO regions */ maps = vfio_res->maps;
drivers/bus/pci/linux/pci_vfio.c +14 -4
@@ -753,10 +753,14 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev) loc->domain, loc->bus, loc->devid, loc->function); ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd)) goto err_vfio_dev_fd;
@@ -962,10 +966,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) } ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; + ret =pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info);if (ret) goto err_vfio_dev_fd;
@@ -1195,12 +1203,14 @@ pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,if (vfio_dev_fd <0 ) {return -1 ; }else if (vfio_dev_fd ==0 ) { -if (rte_vfio_get_device_info (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info) !=0 ) +if (rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, + &vfio_dev_fd) !=0 )return -1 ;/* save vfio_dev_fd so it can be used during release */ if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd) !=0 )return -1 ; +if (rte_vfio_get_device_info (vfio_dev_fd, &device_info) !=0 ) +return -1 ;if (pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info) !=0 )return -1 ;
drivers/bus/platform/platform.c +8 -1
@@ -292,12 +292,19 @@ device_setup(struct rte_platform_device *pdev)const char *name = pdev->name;int ret; - ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd, &dev_info); + ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd);if (ret) {PLATFORM_LOG_LINE (ERR ,"failed to setup %s" , name);return -ENODEV ; } + ret =rte_vfio_get_device_info (pdev->dev_fd, &dev_info); +if (ret) { +PLATFORM_LOG_LINE (ERR ,"failed to get device info for %s" , name); + ret = -ENODEV ; + goto out; + } +/* This is an extra check to confirm that platform device was initialized * by a kernel vfio-platform driver. On kernels that predate vfio-platform * driver this flag obviously does not exist. In such scenarios this
drivers/crypto/bcmfs/bcmfs_vfio.c +7 -1
@@ -25,12 +25,18 @@ vfio_map_dev_obj(const char *path, const char *dev_obj,struct vfio_device_info d_info = { .argsz =sizeof (d_info) };struct vfio_region_info reg_info = { .argsz =sizeof (reg_info) }; - ret =rte_vfio_setup_device (path, dev_obj, dev_fd, &d_info); + ret =rte_vfio_setup_device (path, dev_obj, dev_fd);if (ret) {BCMFS_LOG (ERR ,"VFIO Setting for device failed" );return ret; } + ret =rte_vfio_get_device_info (*dev_fd, &d_info); +if (ret) { +BCMFS_LOG (ERR ,"VFIO Getting device info failed" ); + goto map_failed; + } +/* getting device region info*/ ret =ioctl (*dev_fd,VFIO_DEVICE_GET_REGION_INFO , ®_info);if (ret <0 ) {
lib/eal/freebsd/eal.c +1 -2
@@ -822,8 +822,7 @@ rte_eal_vfio_get_vf_token(__rte_unused rte_uuid_t vf_token)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, - __rte_unused int *vfio_dev_fd, - __rte_unused struct vfio_device_info *device_info) + __rte_unused int *vfio_dev_fd) { rte_errno =ENOTSUP ;return -1 ;
lib/eal/include/rte_vfio.h +8 -15
@@ -55,10 +55,7 @@ struct vfio_device_info;* device location. * * @param vfio_dev_fd -* VFIO fd. -* -* @param device_info -* Device information. +* Pointer to VFIO fd, will be set to the opened device fd on success. * * @return * 0 on success.
@@ -67,7 +64,7 @@ struct vfio_device_info;*/ __rte_internal int rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +int *vfio_dev_fd);/** * @internal
@@ -187,19 +184,16 @@ rte_vfio_get_group_num(const char *sysfs_base,* @internal * Get device information. * +* This function retrieves VFIO device information from an already opened +* device. The device must be opened with rte_vfio_setup_device() first. +* * This function is only relevant to Linux and will return an error on BSD. * -* @param sysfs_base -* sysfs path prefix. -* -* @param dev_addr -* device location. -* * @param vfio_dev_fd -* VFIO fd. +* VFIO device fd (must be a valid, already opened fd). * * @param device_info -* Device information. +* Pointer to device information structure to be filled. * * @return * 0 on success.
@@ -207,8 +201,7 @@ rte_vfio_get_group_num(const char *sysfs_base,*/ __rte_internal int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info);/** * @internal
lib/eal/linux/eal_vfio.c +11 -29
@@ -758,7 +758,7 @@ rte_vfio_clear_group(int vfio_group_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) intrte_vfio_setup_device (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +int *vfio_dev_fd) {struct vfio_group_status group_status = { .argsz =sizeof (group_status)
@@ -975,7 +975,7 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, *vfio_dev_fd =ioctl (vfio_group_fd,VFIO_GROUP_GET_DEVICE_FD , dev);if (*vfio_dev_fd >=0 ) - goto dev_get_info; + goto out; }/* get a file descriptor for the device */
@@ -992,18 +992,8 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,return -1 ; } -/* test and setup the device */ -dev_get_info: - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, " -"error %i (%s)" , dev_addr, errno, -strerror (errno)); -close (*vfio_dev_fd); -close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); -return -1 ; - } +/* device is now set up */ +out:vfio_group_device_get (vfio_group_fd);return 0 ;
@@ -1217,26 +1207,18 @@ vfio_set_iommu_type(int vfio_container_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info) {int ret; -if (device_info ==NULL || *vfio_dev_fd <0 ) +if (device_info ==NULL || vfio_dev_fd <0 )return -1 ; -if (*vfio_dev_fd ==0 ) { - ret =rte_vfio_setup_device (sysfs_base, dev_addr, - vfio_dev_fd, device_info); -if (ret) -return -1 ; - }else { - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, error %i (%s)" , - dev_addr, errno,strerror (errno)); -return -1 ; - } + ret =ioctl (vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); +if (ret) { +EAL_LOG (ERR ,"Cannot get device info, error %i (%s)" , + errno,strerror (errno)); +return -1 ; }return 0 ;
Signature · 1 line
2.52.0
PATCH v10 5/20 vfio: add container device assignment API
In reply to Anatoly BurakovCurrently, VFIO has explicit group bind API's, but the way they're used is such that no one actually cares about VFIO groups, and the real goal of everyone using VFIO group bind API is to bind devices to particular VFIO container, such that when rte_vfio_setup_device call eventually comes, VFIO will pick up the correct container.
To remove dependency on group API's, add a new "container assign device" API call that will do the same thing, but will not depend on managing VFIO group fd's.
--- lib/eal/freebsd/eal.c | 10 ++++++++++ lib/eal/include/rte_vfio.h | 26 ++++++++++++++++++++++++++ lib/eal/linux/eal_vfio.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+)
lib/eal/freebsd/eal.c +10 -0
@@ -944,3 +944,13 @@ rte_vfio_container_dma_unmap(__rte_unused int container_fd, rte_errno =ENOTSUP ;return -1 ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device(__rte_unused int vfio_container_fd, + __rte_unused const char *sysfs_base, + __rte_unused const char *dev_addr) +{ + rte_errno =ENOTSUP ; +return -1 ; +}
lib/eal/include/rte_vfio.h +26 -0
@@ -271,6 +271,32 @@ __rte_internalint rte_vfio_container_destroy (int container_fd); +/** +* @internal +* +* Assign a device to a VFIO container. +* +* Doing so will cause `rte_vfio_setup_device()` to set up the device with the VFIO container +* specified in this assign operation. +* +* This function is only relevant on Linux. +* +* @param vfio_container_fd +* VFIO container file descriptor. +* @param sysfs_base +* Sysfs path prefix. +* @param dev_addr +* Device identifier. +* +* @return +* 0 on success. +* <0 on failure. +*/ +__rte_internal +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr); +/** * @internal * Bind a IOMMU group to a container.
lib/eal/linux/eal_vfio.c +32 -0
@@ -2102,6 +2102,38 @@ rte_vfio_container_destroy(int container_fd)return 0 ; } +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr) +{ +int iommu_group_num; +int ret; + + ret =rte_vfio_get_group_num (sysfs_base, dev_addr, &iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR ,"Cannot get IOMMU group number for device %s" , + dev_addr); +return -1 ; + }else if (ret ==0 ) { +EAL_LOG (ERR , +"Device %s is not assigned to any IOMMU group" , + dev_addr); +return -1 ; + } + + ret =rte_vfio_container_group_bind (vfio_container_fd, + iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR , +"Cannot bind IOMMU group %d for device %s" , + iommu_group_num, dev_addr); +return -1 ; + } + +return 0 ; +} +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) intrte_vfio_container_group_bind (int container_fd,int iommu_group_num)
Signature · 1 line
2.52.0
PATCH v10 6/20 net/nbl: do not use VFIO group bind API
In reply to Anatoly BurakovThe NBL driver currently uses group bind API, but it is using it only to get group fd and nothing else. In context of NBL driver, this is the only usage of VFIO API's in the driver, and it is not necessary to use it for what NBL driver is trying to accomplish.
Use a direct open() call instead, and store the group fd in common structure.
--- drivers/net/nbl/nbl_common/nbl_userdev.c | 19 ++++++++++++------- drivers/net/nbl/nbl_include/nbl_include.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-)
drivers/net/nbl/nbl_common/nbl_userdev.c +12 -7
@@ -387,6 +387,14 @@ nbl_userdev_mem_event_callback(enum rte_mem_event type, const void *addr, size_t } } +static int +nbl_open_group_fd (int iommu_group_num) +{ +char path[PATH_MAX ]; +snprintf (path,sizeof (path),RTE_VFIO_GROUP_FMT , iommu_group_num); +return open (path,O_RDWR ); +} +static int nbl_mdev_map_device (struct nbl_adapter *adapter) {const struct rte_pci_device *pci_dev = adapter->pci_dev;
@@ -424,11 +432,12 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) }NBL_LOG (DEBUG ,"nbl vfio container %d" , container); - vfio_group_fd =rte_vfio_container_group_bind (container, common->iommu_group_num); + vfio_group_fd =nbl_open_group_fd (common->iommu_group_num);if (vfio_group_fd <0 ) {NBL_LOG (ERR ,"nbl vfio group bind failed, %d" , vfio_group_fd); goto free_container; } + common->groupfd = vfio_group_fd;/* check if the group is viable */ ret =ioctl (vfio_group_fd,VFIO_GROUP_GET_STATUS , &group_status);
@@ -535,7 +544,6 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) } free_group:close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); free_container:if (container_create)rte_vfio_container_destroy (container);
@@ -549,17 +557,14 @@ static int nbl_mdev_unmap_device(struct nbl_adapter *adapter)close (common->devfd);rte_mcfg_mem_read_lock (); - vfio_group_fd =rte_vfio_container_group_bind (nbl_default_container, - common->iommu_group_num); + vfio_group_fd = common->groupfd;NBL_LOG (DEBUG ,"close vfio_group_fd %d" , vfio_group_fd); ret =ioctl (vfio_group_fd,VFIO_GROUP_UNSET_CONTAINER , &nbl_default_container);if (ret)NBL_LOG (ERR ,"unset container, error %i (%s) %d" , errno,strerror (errno), ret); nbl_group_count--; - ret =rte_vfio_container_group_unbind (nbl_default_container, common->iommu_group_num); -if (ret) -NBL_LOG (ERR ,"vfio container group unbind failed %d" , ret); +close (vfio_group_fd);if (!nbl_group_count) {rte_mem_event_callback_unregister (NBL_USERDEV_EVENT_CLB_NAME ,NULL );nbl_userdev_dma_free ();
drivers/net/nbl/nbl_include/nbl_include.h +1 -0
@@ -132,6 +132,7 @@ struct nbl_common_info {u16 vsi_id;u16 instance_id;int devfd; +int groupfd;int eventfd;int ifindex;int iommu_group_num;
Signature · 1 line
2.52.0
PATCH v10 7/20 net/ntnic: use container device assignment API
In reply to Anatoly BurakovThe NTNIC driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/net/ntnic/ntnic_vfio.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-)
drivers/net/ntnic/ntnic_vfio.c +9 -21
@@ -28,7 +28,6 @@ nt_vfio_vf_num(const struct rte_pci_device *pdev)/* Internal API */ struct vfio_dev {int container_fd; -int group_fd;int dev_fd;uint64_t iova_addr; };
@@ -50,7 +49,6 @@ nthw_vfio_setup(struct rte_pci_device *dev) {int ret;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num;int vf_num;struct vfio_dev *vfio;
@@ -66,14 +64,9 @@ nthw_vfio_setup(struct rte_pci_device *dev) } vfio->dev_fd =-1 ; - vfio->group_fd =-1 ; vfio->iova_addr =START_VF_IOVA ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, &iommu_group_num); -if (ret <=0 ) -return -1 ; -if (vf_num ==0 ) {/* use default container for pf0 */ vfio->container_fd =RTE_VFIO_DEFAULT_CONTAINER_FD ;
@@ -86,17 +79,14 @@ nthw_vfio_setup(struct rte_pci_device *dev) "VFIO device setup failed. VFIO container creation failed.");return -1 ; } - } + ret =rte_vfio_container_assign_device (vfio->container_fd, +rte_pci_get_sysfs_path (), devname); +if (ret <0 ) { +NT_LOG (ERR ,NTNIC , +"VFIO device setup failed. Assign device to container failed." ); + goto err; + } - vfio->group_fd =rte_vfio_container_group_bind (vfio->container_fd, iommu_group_num); - -if (vfio->group_fd <0 ) { -NT_LOG (ERR ,NTNIC , -"VFIO device setup failed. VFIO container group bind failed." ); - goto err; - } - -if (vf_num >0 ) {if (rte_pci_map_device (dev)) {NT_LOG (ERR ,NTNIC ,"Map VFIO device failed. is the vfio-pci driver loaded?" );
@@ -106,10 +96,8 @@ nthw_vfio_setup(struct rte_pci_device *dev) vfio->dev_fd =rte_intr_dev_fd_get (dev->intr_handle); -NT_LOG (DBG ,NTNIC , -"%s: VFIO id=%d, dev_fd=%d, container_fd=%d, group_fd=%d, iommu_group_num=%d" , - dev->name, vf_num, vfio->dev_fd, vfio->container_fd, vfio->group_fd, - iommu_group_num); +NT_LOG (DBG ,NTNIC ,"%s: VFIO id=%d, dev_fd=%d, container_fd=%d" , + dev->name, vf_num, vfio->dev_fd, vfio->container_fd);return vf_num;
Signature · 1 line
2.52.0
PATCH v10 8/20 vdpa/ifc: use container device assignment API
In reply to Anatoly BurakovThe IFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-)
drivers/vdpa/ifc/ifcvf_vdpa.c +3 -31
@@ -58,7 +58,6 @@ struct ifcvf_internal {struct ifcvf_hw hw;int configured;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd;rte_thread_t tid;/* thread for notify relay */ rte_thread_t intr_tid;/* thread for config space change interrupt relay */
@@ -174,28 +173,19 @@ ifcvf_vfio_setup(struct ifcvf_internal *internal) {struct rte_pci_device *dev = internal->pdev;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num; -int i, ret; +int i; internal->vfio_dev_fd =-1 ; - internal->vfio_group_fd =-1 ; internal->vfio_container_fd =-1 ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, - &iommu_group_num); -if (ret <=0 ) { -DRV_LOG (ERR ,"%s failed to get IOMMU group" , devname); -return -1 ; - } internal->vfio_container_fd =rte_vfio_container_create ();if (internal->vfio_container_fd <0 )return -1 ; - internal->vfio_group_fd =rte_vfio_container_group_bind ( - internal->vfio_container_fd, iommu_group_num); -if (internal->vfio_group_fd <0 ) +if (rte_vfio_container_assign_device (internal->vfio_container_fd, +rte_pci_get_sysfs_path (), devname) <0 ) goto err;if (rte_pci_map_device (dev))
@@ -1213,22 +1203,6 @@ ifcvf_set_features(int vid)return 0 ; } -static int -ifcvf_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct internal_list *list; - - vdev =rte_vhost_get_vdpa_device (vid); - list =find_internal_resource_by_vdev (vdev); -if (list ==NULL ) { -DRV_LOG (ERR ,"Invalid vDPA device: %p" , vdev); -return -1 ; - } - -return list->internal->vfio_group_fd; -} -static int ifcvf_get_vfio_device_fd (int vid) {
@@ -1474,7 +1448,6 @@ static struct rte_vdpa_dev_ops ifcvf_net_ops = { .set_vring_state = ifcvf_set_vring_state, .set_features = ifcvf_set_features, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_dev_type = ifcvf_get_device_type,
@@ -1605,7 +1578,6 @@ static struct rte_vdpa_dev_ops ifcvf_blk_ops = { .dev_close = ifcvf_dev_close, .set_vring_state = ifcvf_set_vring_state, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_config = ifcvf_blk_get_config,
Signature · 1 line
2.52.0
PATCH v10 9/20 vdpa/nfp: use container device assignment API
In reply to Anatoly BurakovThe NFP vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/nfp/nfp_vdpa.c | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-)
drivers/vdpa/nfp/nfp_vdpa.c +5 -32
@@ -36,9 +36,7 @@ struct nfp_vdpa_dev {struct nfp_vdpa_hw hw;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd; -int iommu_group;rte_thread_t tid;/**< Thread for notify relay */ int epoll_fd;
@@ -120,33 +118,26 @@ nfp_vdpa_vfio_setup(struct nfp_vdpa_dev *device)struct rte_pci_device *pci_dev = device->pci_dev;rte_pci_device_name (&pci_dev->addr, dev_name,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &device->iommu_group); -if (ret <=0 ) -return -1 ; device->vfio_container_fd =rte_vfio_container_create ();if (device->vfio_container_fd <0 )return -1 ; - device->vfio_group_fd =rte_vfio_container_group_bind ( - device->vfio_container_fd, device->iommu_group); -if (device->vfio_group_fd <0 ) + ret =rte_vfio_container_assign_device (device->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (ret <0 ) goto container_destroy; -DRV_VDPA_LOG (DEBUG ,"The container_fd=%d, group_fd=%d." , - device->vfio_container_fd, device->vfio_group_fd); +DRV_VDPA_LOG (DEBUG ,"container_fd=%d" , device->vfio_container_fd); ret =rte_pci_map_device (pci_dev);if (ret !=0 ) - goto group_unbind; + goto container_destroy; device->vfio_dev_fd =rte_intr_dev_fd_get (pci_dev->intr_handle);return 0 ; -group_unbind: -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group); container_destroy:rte_vfio_container_destroy (device->vfio_container_fd);
@@ -157,7 +148,6 @@ static void nfp_vdpa_vfio_teardown(struct nfp_vdpa_dev *device) {rte_pci_unmap_device (device->pci_dev); -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group);rte_vfio_container_destroy (device->vfio_container_fd); }
@@ -1023,22 +1013,6 @@ nfp_vdpa_dev_close(int vid)return 0 ; } -static int -nfp_vdpa_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct nfp_vdpa_dev_node *node; - - vdev =rte_vhost_get_vdpa_device (vid); - node =nfp_vdpa_find_node_by_vdev (vdev); -if (node ==NULL ) { -DRV_VDPA_LOG (ERR ,"Invalid vDPA device: %p." , vdev); -return -ENODEV ; - } - -return node->device->vfio_group_fd; -} -static int nfp_vdpa_get_vfio_device_fd (int vid) {
@@ -1190,7 +1164,6 @@ struct rte_vdpa_dev_ops nfp_vdpa_ops = { .dev_close = nfp_vdpa_dev_close, .set_vring_state = nfp_vdpa_set_vring_state, .set_features = nfp_vdpa_set_features, - .get_vfio_group_fd = nfp_vdpa_get_vfio_group_fd, .get_vfio_device_fd = nfp_vdpa_get_vfio_device_fd, .get_notify_area = nfp_vdpa_get_notify_area, };
Signature · 1 line
2.52.0
PATCH v10 10/20 vdpa/sfc: use container device assignment API
In reply to Anatoly BurakovThe SFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/vdpa/sfc/sfc_vdpa.c | 39 +++++++------------------------------ drivers/vdpa/sfc/sfc_vdpa.h | 2 -- 2 files changed, 7 insertions(+), 34 deletions(-)
drivers/vdpa/sfc/sfc_vdpa.c +7 -32
@@ -80,22 +80,12 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva) goto fail_container_create; } - rc =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &sva->iommu_group_num); -if (rc <=0 ) { -sfc_vdpa_err (sva,"failed to get IOMMU group for %s : %s" , - dev_name,rte_strerror (-rc)); - goto fail_get_group_num; - } - - sva->vfio_group_fd = -rte_vfio_container_group_bind (sva->vfio_container_fd, - sva->iommu_group_num); -if (sva->vfio_group_fd <0 ) { -sfc_vdpa_err (sva, -"failed to bind IOMMU group %d to container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - goto fail_group_bind; + rc =rte_vfio_container_assign_device (sva->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (rc <0 ) { +sfc_vdpa_err (sva,"failed to assign device %s to container %d" , + dev_name, sva->vfio_container_fd); + goto fail_device_assign; }if (rte_pci_map_device (dev) !=0 ) {
@@ -109,15 +99,7 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva)return 0 ; fail_pci_map_device: -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } - -fail_group_bind: -fail_get_group_num: +fail_device_assign:if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) {sfc_vdpa_err (sva,"failed to destroy container %d" , sva->vfio_container_fd);
@@ -132,13 +114,6 @@ sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter *sva) {rte_pci_unmap_device (sva->pdev); -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } -if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) { sfc_vdpa_err(sva, "failed to destroy container %d",
drivers/vdpa/sfc/sfc_vdpa.h +0 -2
@@ -70,10 +70,8 @@ struct sfc_vdpa_adapter {sfc_vdpa_filter_t filters; -int vfio_group_fd;int vfio_dev_fd;int vfio_container_fd; -int iommu_group_num;struct sfc_vdpa_ops_data *ops_data; };
Signature · 1 line
2.52.0
PATCH v10 11/20 vdpa/mlx5: remove group-related API
In reply to Anatoly BurakovThe mlx5 driver does not use the get_group_fd API provided by vDPA. This API is about to be removed, so remove its mention from mlx5.
--- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - 1 file changed, 1 deletion(-)
drivers/vdpa/mlx5/mlx5_vdpa.c +0 -1
@@ -523,7 +523,6 @@ static struct rte_vdpa_dev_ops mlx5_vdpa_ops = { .set_vring_state = mlx5_vdpa_set_vring_state, .set_features = mlx5_vdpa_features_set, .migration_done = NULL, - .get_vfio_group_fd = NULL, .get_vfio_device_fd = mlx5_vdpa_get_device_fd, .get_notify_area = mlx5_vdpa_get_notify_area, .get_stats_names = mlx5_vdpa_get_stats_names,
Signature · 1 line
2.52.0
PATCH v10 12/20 vhost: remove group-related API from driver
In reply to Anatoly BurakovThe vDPA driver API has "get_vfio_group_fd" in its ops structure, but no driver is using it any more, as better API's were added and implemented. Remove this API from vDPA ops structure.
--- doc/guides/prog_guide/vhost_lib.rst | 4 ---- doc/guides/rel_notes/deprecation.rst | 4 ---- lib/vhost/vdpa_driver.h | 3 --- 3 files changed, 11 deletions(-)
doc/guides/prog_guide/vhost_lib.rst +0 -4
@@ -471,10 +471,6 @@ Finally, a set of device ops is defined for device specific operations: Called to allow the device to respond to RARP sending. -* ``get_vfio_group_fd`` - - Called to get the VFIO group fd of the device. - * ``get_vfio_device_fd`` Called to get the VFIO device fd of the device.
doc/guides/rel_notes/deprecation.rst +0 -4
@@ -29,10 +29,6 @@ Deprecation Notices Use the ``-S <service-corelist>`` parameter instead to specify the cores to be used for background services in DPDK. -* vdpa: The vDPA driver API will no longer offer ``get_vfio_group_fd`` - as part of its internal API. All drivers will be adjusted - to use the new unified VFIO container device assignment API. - * rte_atomicNN_xxx: These APIs do not take memory order parameter. This does not allow for writing optimized code for all the CPU architectures supported in DPDK. DPDK has adopted the atomic operations from
lib/vhost/vdpa_driver.h +0 -3
@@ -50,9 +50,6 @@ struct rte_vdpa_dev_ops {/** Destination operations when migration done */ int (*migration_done)(int vid); -/** Get the vfio group fd */ -int (*get_vfio_group_fd)(int vid); -/** Get the vfio device fd */ int (*get_vfio_device_fd)(int vid);
Signature · 1 line
2.52.0
PATCH v10 13/20 vfio: remove group-based API
In reply to Anatoly BurakovAll drivers have been adjusted to not use the VFIO group API directly and instead rely on container device assignment model, so the group API is no longer useful and can be removed.
--- lib/eal/freebsd/eal.c | 33 --------------- lib/eal/include/rte_vfio.h | 72 -------------------------------- lib/eal/linux/eal_vfio.c | 47 ++++++++++----------- lib/eal/linux/eal_vfio.h | 2 + lib/eal/linux/eal_vfio_mp_sync.c | 2 +- 5 files changed, 26 insertions(+), 130 deletions(-)
lib/eal/freebsd/eal.c +0 -33
@@ -856,13 +856,6 @@ int rte_vfio_noiommu_is_enabled(void)return 0 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) -int rte_vfio_clear_group(__rte_unused int vfio_group_fd) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base,
@@ -881,14 +874,6 @@ rte_vfio_get_container_fd(void)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) -int -rte_vfio_get_group_fd(__rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void )
@@ -905,24 +890,6 @@ rte_vfio_container_destroy(__rte_unused int container_fd)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) -int -rte_vfio_container_group_bind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) -int -rte_vfio_container_group_unbind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd,
lib/eal/include/rte_vfio.h +0 -72
90 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +23 -24
151 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +2 -0
@@ -51,6 +51,8 @@ vfio_set_iommu_type(int vfio_container_fd);int vfio_get_iommu_type (void ); +int vfio_get_group_fd_by_num (int iommu_group_num); +/* check if we have any supported extensions */ int vfio_has_supported_extensions (int vfio_container_fd);
lib/eal/linux/eal_vfio_mp_sync.c +1 -1
@@ -34,7 +34,7 @@ vfio_mp_primary(const struct rte_mp_msg *msg, const void *peer)case SOCKET_REQ_GROUP : r->req =SOCKET_REQ_GROUP ; r->group_num = m->group_num; - fd =rte_vfio_get_group_fd (m->group_num); + fd =vfio_get_group_fd_by_num (m->group_num);if (fd <0 && fd != -ENOENT ) r->result =SOCKET_ERR ;else if (fd == -ENOENT )
Signature · 1 line
2.52.0
PATCH v10 14/20 vfio: cleanup and refactor
In reply to Anatoly BurakovCurrently, VFIO code is a bit of an incoherent mess internally, with API's bleeding into each other, inconsistent returns, and a certain amount of spaghetti stemming from organic growth.
Refactor VFIO code to achieve the following goals:
- Make all error handling consistent, and provide/document rte_errno values returned from API's to indicate various conditions.
- Introduce new "VFIO mode" concept. This new API will tell caller if VFIO is enabled, and whether it is using group API, and whether it is running in no-IOMMU mode.
- Decouple rte_vfio_setup_device semantics from PCI bus return convention. Currently, when device is not managed by VFIO, rte_vfio_setup_device will return 1, which is bus speak for "skip this device", however VFIO has nothing to do with PCI bus and should not follow its API conventions.
- Perform device setup in device assign, and make device setup use shared code path with device assign and explicitly assuming default container. This is technically not necessary for group mode as device set up is a two-step process in that mode, but coming cdev mode will have a single-step device setup, and it would be easier if the worked the same way under the hood.
- Make VFIO internals more readable. Introduce a lot of infrastructure and more explicit validation, rather than over-reliance on sentinel values and implicit assumptions. This will also make it easier to integrate cdev mode down the line, as it will rely on most of this infrastructure.
This will change behavior of the following functions:
- rte_vfio_setup_device - when the device is not managed by VFIO, the function will now return -1 with rte_errno set to ENODEV
- rte_vfio_get_group_num - when the device is not managed by VFIO, the function will now return -1 with rte_errno set to ENODEV
- rte_vfio_container_destroy - the function will now release and close all group and device resources associated with the container being destroyed by this call
All users of rte_vfio_setup_device and rte_vfio_get_group_num have been adjusted to account for API change.
--- config/arm/meson.build | 1 + config/meson.build | 1 + drivers/bus/cdx/cdx_vfio.c | 17 +- drivers/bus/fslmc/fslmc_vfio.c | 4 +- drivers/bus/pci/linux/pci_vfio.c | 19 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 6 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 2 +- lib/eal/freebsd/eal.c | 16 + lib/eal/include/rte_vfio.h | 252 ++- lib/eal/linux/eal_vfio.c | 2264 +++++++--------------- lib/eal/linux/eal_vfio.h | 142 +- lib/eal/linux/eal_vfio_group.c | 984 ++++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 38 +- lib/eal/linux/meson.build | 1 + 14 files changed, 2104 insertions(+), 1643 deletions(-) create mode 100644 lib/eal/linux/eal_vfio_group.c
config/arm/meson.build +1 -0
@@ -147,6 +147,7 @@ implementer_cavium = { 'description': 'Cavium', 'flags': [ ['RTE_MAX_VFIO_GROUPS', 128], + ['RTE_MAX_VFIO_DEVICES', 256], ['RTE_MAX_LCORE', 96], ['RTE_MAX_NUMA_NODES', 2] ],
config/meson.build +1 -0
@@ -387,6 +387,7 @@ dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp')) dpdk_conf.set('RTE_PKTMBUF_HEADROOM', get_option('pkt_mbuf_headroom')) # values which have defaults which may be overridden dpdk_conf.set('RTE_MAX_VFIO_GROUPS', 64) +dpdk_conf.set('RTE_MAX_VFIO_DEVICES', 256) dpdk_conf.set('RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB', 64) dpdk_conf.set('RTE_LIBRTE_DPAA2_USE_PHYS_IOVA', true) if get_option('mbuf_refcnt_atomic')
drivers/bus/cdx/cdx_vfio.c +12 -5
@@ -22,6 +22,7 @@#include <eal_export.h> #include <rte_eal_paging.h> +#include <rte_errno.h> #include <rte_malloc.h> #include <rte_vfio.h>
@@ -402,8 +403,12 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev) ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, &vfio_dev_fd); -if (ret) +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
@@ -513,11 +518,13 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev)return -1 ; } - ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; - + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret) goto err_vfio_dev_fd;
drivers/bus/fslmc/fslmc_vfio.c +2 -2
@@ -364,9 +364,9 @@ fslmc_get_group_id(const char *group_name,/* get group number */ ret =rte_vfio_get_group_num (SYSFS_FSL_MC_DEVICES , group_name, groupid); -if (ret <=0 ) { +if (ret <0 ) {DPAA2_BUS_ERR ("Find %s IOMMU group" , group_name); -if (ret <0 ) +if (rte_errno !=ENODEV )return ret;return -EIO ;
drivers/bus/pci/linux/pci_vfio.c +13 -6
@@ -20,6 +20,7 @@#include <rte_malloc.h> #include <rte_vfio.h> #include <rte_eal.h> +#include <rte_errno.h> #include <bus_driver.h> #include <rte_spinlock.h> #include <rte_tailq.h>
@@ -752,10 +753,13 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev)snprintf (pci_addr,sizeof (pci_addr),PCI_PRI_FMT , loc->domain, loc->bus, loc->devid, loc->function); - ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
@@ -965,10 +969,13 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)return -1 ; } - ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
drivers/crypto/bcmfs/bcmfs_vfio.c +5 -1
@@ -9,6 +9,7 @@#include <sys/mman.h> #include <sys/ioctl.h> +#include <rte_errno.h> #include <rte_vfio.h> #include "bcmfs_device.h"
@@ -26,7 +27,10 @@ vfio_map_dev_obj(const char *path, const char *dev_obj,struct vfio_region_info reg_info = { .argsz =sizeof (reg_info) }; ret =rte_vfio_setup_device (path, dev_obj, dev_fd); -if (ret) { +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;BCMFS_LOG (ERR ,"VFIO Setting for device failed" );return ret; }
drivers/net/nbl/nbl_common/nbl_userdev.c +1 -1
@@ -414,7 +414,7 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) "%s/%s/", rte_pci_get_sysfs_path(), dev_name); ret =rte_vfio_get_group_num (pathname, dev_name, &common->iommu_group_num); -if (ret <=0 ) { +if (ret <0 ) {NBL_LOG (ERR ,"nbl vfio group number failed" );return -1 ; }
lib/eal/freebsd/eal.c +16 -0
@@ -921,3 +921,19 @@ rte_vfio_container_assign_device(__rte_unused int vfio_container_fd, rte_errno =ENOTSUP ;return -1 ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) +int +rte_vfio_get_device_info(__rte_unused int vfio_dev_fd, + __rte_unused struct vfio_device_info *device_info) +{ + rte_errno =ENOTSUP ; +return -1 ; +} + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_mode) +enum rte_vfio_mode +rte_vfio_get_mode (void ) +{ +return RTE_VFIO_MODE_NONE ; +}
lib/eal/include/rte_vfio.h +171 -81
417 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +745 -1519
2,437 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +122 -20
142 lines not on this page · raw message
lib/eal/linux/eal_vfio_group.c new file +984 -0
984 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v10 15/20 bus/pci: use the new VFIO mode API
In reply to Anatoly BurakovUse the new VFIO mode API to query no-IOMMU status.
--- drivers/bus/pci/linux/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bus/pci/linux/pci.c +1 -1
@@ -596,7 +596,7 @@ pci_device_iova_mode(const struct rte_pci_driver *pdrv,static int is_vfio_noiommu_enabled =-1 ;if (is_vfio_noiommu_enabled ==-1 ) { -if (rte_vfio_noiommu_is_enabled () ==1 ) +if (rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ) is_vfio_noiommu_enabled =1 ;else is_vfio_noiommu_enabled =0 ;
Signature · 1 line
2.52.0
PATCH v10 16/20 bus/fslmc: use the new VFIO mode API
In reply to Anatoly BurakovFSLMC bus only supports operating in group mode, and relies on no-IOMMU mode checks. Use the new VFIO API's to query no-IOMMU status, as well as protect the bus from initializing in non-group mode.
--- drivers/bus/fslmc/fslmc_bus.c | 10 +++++++++- drivers/bus/fslmc/fslmc_vfio.c | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-)
drivers/bus/fslmc/fslmc_bus.c +9 -1
@@ -332,6 +332,13 @@ rte_fslmc_scan(void) goto scan_fail; } +/* for container groups to work, VFIO must be in group mode */ +if (rte_vfio_get_mode () !=RTE_VFIO_MODE_GROUP && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU ) { + ret = -EINVAL ; + goto scan_fail; + } + ret =fslmc_get_container_group (group_name, &groupid);if (ret !=0 ) goto scan_fail;
@@ -500,7 +507,8 @@ rte_dpaa2_get_iommu_class(void)return RTE_IOVA_DC ;/* check if all devices on the bus support Virtual addressing or not */ -if (fslmc_all_device_support_iova () !=0 &&rte_vfio_noiommu_is_enabled () ==0 ) +if (fslmc_all_device_support_iova () !=0 && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU )return RTE_IOVA_VA ;return RTE_IOVA_PA ;
drivers/bus/fslmc/fslmc_vfio.c +1 -1
@@ -192,7 +192,7 @@ fslmc_vfio_add_group(int vfio_group_fd, group->fd = vfio_group_fd; group->groupid = iommu_group_num;rte_strscpy (group->group_name, group_name,sizeof (group->group_name)); -if (rte_vfio_noiommu_is_enabled () >0 ) +if (rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ) group->iommu_type =VFIO_NOIOMMU_IOMMU ;else group->iommu_type =VFIO_TYPE1_IOMMU ;
Signature · 1 line
2.52.0
PATCH v10 17/20 net/hinic3: use the new VFIO mode API
In reply to Anatoly BurakovUse new VFIO mode API to query no-IOMMU status.
--- drivers/net/hinic3/base/hinic3_hwdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/hinic3/base/hinic3_hwdev.c +2 -1
@@ -78,7 +78,8 @@ hinic3_is_vfio_iommu_enable(const struct rte_eth_dev *eth_dev) {struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (eth_dev, *pci_dev); -return pci_dev->kdrv ==RTE_PCI_KDRV_VFIO &&rte_vfio_noiommu_is_enabled () !=1 ; +return pci_dev->kdrv ==RTE_PCI_KDRV_VFIO && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU ; }int
Signature · 1 line
2.52.0
PATCH v10 18/20 net/ntnic: use the new VFIO mode API
In reply to Anatoly BurakovUse new VFIO mode API to query no-IOMMU status.
--- drivers/net/ntnic/ntnic_ethdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ntnic/ntnic_ethdev.c +1 -1
@@ -2690,7 +2690,7 @@ nthw_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) (pci_dev->device.devargs->data ? pci_dev->device.devargs->data : "NULL")); } -const int n_rte_vfio_no_io_mmu_enabled =rte_vfio_noiommu_is_enabled (); +const int n_rte_vfio_no_io_mmu_enabled =rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ;NT_LOG (DBG ,NTNIC ,"vfio_no_iommu_enabled=%d" , n_rte_vfio_no_io_mmu_enabled);if (n_rte_vfio_no_io_mmu_enabled) {
Signature · 1 line
2.52.0
PATCH v10 19/20 vfio: remove no-IOMMU check API
In reply to Anatoly BurakovThe rte_vfio_noiommu_is_enabled() check has now been replaced by the new mode API, so remove it.
--- lib/eal/freebsd/eal.c | 6 ------ lib/eal/include/rte_vfio.h | 14 -------------- lib/eal/linux/eal_vfio.c | 7 ------- 3 files changed, 27 deletions(-)
lib/eal/freebsd/eal.c +0 -6
@@ -850,12 +850,6 @@ int rte_vfio_is_enabled(__rte_unused const char *modname)return 0 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) -int rte_vfio_noiommu_is_enabled(void) -{ -return 0 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base,
lib/eal/include/rte_vfio.h +0 -14
@@ -170,20 +170,6 @@ __rte_internalenum rte_vfio_mode rte_vfio_get_mode (void ); -/** -* @internal -* Check if VFIO NOIOMMU mode is enabled. -* -* This function is only relevant on Linux in group mode. -* -* @return -* 1 if enabled. -* 0 if not enabled or not supported. -*/ -__rte_internal -int -rte_vfio_noiommu_is_enabled (void ); -/** * @internal * Parse IOMMU group number for a device.
lib/eal/linux/eal_vfio.c +0 -7
@@ -1277,13 +1277,6 @@ container_dma_unmap(struct container *cfg, uint64_t vaddr, uint64_t iova,return ret; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) -int -rte_vfio_noiommu_is_enabled (void ) -{ -return vfio_cfg.mode ==RTE_VFIO_MODE_NOIOMMU ; -} -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void )
Signature · 1 line
2.52.0
PATCH v10 20/20 vfio: introduce cdev mode
In reply to Anatoly BurakovAdd support for VFIO cdev (also known as IOMMUFD) API. The group API is now considered legacy in the kernel, and all further development is expected to happen in IOMMUFD infrastructure.
To assist any future use of VFIO cdev mode for custom behavior, also introduce "get device number" API, which is kind-of-but-not-really similar to the concept of IOMMU group.
--- lib/eal/freebsd/eal.c | 10 + lib/eal/include/rte_vfio.h | 31 +++ lib/eal/linux/eal_vfio.c | 222 +++++++++++++++++- lib/eal/linux/eal_vfio.h | 29 ++- lib/eal/linux/eal_vfio_cdev.c | 390 +++++++++++++++++++++++++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 42 ++++ lib/eal/linux/meson.build | 1 + 7 files changed, 721 insertions(+), 4 deletions(-) create mode 100644 lib/eal/linux/eal_vfio_cdev.c
lib/eal/freebsd/eal.c +10 -0
@@ -931,3 +931,13 @@ rte_vfio_get_mode(void) {return RTE_VFIO_MODE_NONE ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_num) +int +rte_vfio_get_device_num(__rte_unused const char *sysfs_base, + __rte_unused const char *dev_addr, + __rte_unused int *vfio_device_num) +{ + rte_errno =ENOTSUP ; +return -1 ; +}
lib/eal/include/rte_vfio.h +31 -0
@@ -28,6 +28,8 @@ extern "C" {#define RTE_VFIO_DIR "/dev/vfio"#define RTE_VFIO_CONTAINER_PATH "/dev/vfio/vfio" +#define RTE_VFIO_IOMMUFD_PATH "/dev/iommu" +#define RTE_VFIO_CDEV_DEVICES_PATH "/dev/vfio/devices"#define RTE_VFIO_GROUP_FMT "/dev/vfio/%u"#define RTE_VFIO_NOIOMMU_GROUP_FMT "/dev/vfio/noiommu-%u"#define RTE_VFIO_NOIOMMU_MODE "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode"
@@ -48,11 +50,13 @@ struct vfio_device_info;* - RTE_VFIO_MODE_NONE: VFIO is not enabled. * - RTE_VFIO_MODE_GROUP: Legacy group mode. * - RTE_VFIO_MODE_NOIOMMU: Unsafe no-IOMMU mode. +* - RTE_VFIO_MODE_CDEV: Character device mode. */ enum rte_vfio_mode {RTE_VFIO_MODE_NONE =0 ,/**< VFIO not enabled */ RTE_VFIO_MODE_GROUP ,/**< Group mode */ RTE_VFIO_MODE_NOIOMMU ,/**< Group mode with no IOMMU protection */ +RTE_VFIO_MODE_CDEV ,/**< Device mode */ };/**
@@ -197,6 +201,33 @@ __rte_internalint rte_vfio_get_group_num (const char *sysfs_base,const char *dev_addr,int *iommu_group_num); +/** +* @internal +* Parse VFIO cdev device number for a device. +* +* This function is only relevant on Linux in cdev mode. +* +* @param sysfs_base +* Sysfs path prefix. +* @param dev_addr +* Device identifier. +* @param vfio_device_num +* Pointer to where VFIO cdev device number will be stored. +* +* @return +* 0 on success. +* <0 on failure, rte_errno is set. +* +* Possible rte_errno values include: +* - ENODEV - Device not managed by VFIO. +* - EINVAL - Invalid parameters. +* - ENOXIO - VFIO support not initialized. +* - ENOTSUP - Unsupported VFIO mode. +*/ +__rte_internal +int +rte_vfio_get_device_num (const char *sysfs_base,const char *dev_addr,int *vfio_device_num); +/** * @internal * Get device information.
lib/eal/linux/eal_vfio.c +220 -2
294 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +27 -2
@@ -48,7 +48,10 @@ struct vfio_group {/* device tracking (common for group and cdev modes) */ struct vfio_device {bool active; -int group;/**< back-reference to group list (group mode) */ +union { +int group;/**< back-reference to group list (group mode) */ +int dev_num;/**< device number, e.g., X in /dev/vfio/devices/vfioX (cdev mode) */ + };int fd; };
@@ -61,12 +64,20 @@ struct vfio_group_config {struct vfio_group groups[RTE_MAX_VFIO_GROUPS ]; }; +/* cdev mode specific configuration */ +struct vfio_cdev_config { +uint32_t ioas_id; +}; +/* per-container configuration */ struct container {bool active;int container_fd;struct user_mem_maps mem_maps; -struct vfio_group_config group_cfg; +union { +struct vfio_group_config group_cfg; +struct vfio_cdev_config cdev_cfg; + };int n_devices;struct vfio_device devices[RTE_MAX_VFIO_DEVICES ]; };
@@ -160,12 +171,24 @@ int vfio_group_setup_iommu(struct container *cfg);int vfio_group_setup_device_fd (const char *dev_addr,struct vfio_group *grp,struct vfio_device *dev); +/* cdev mode functions */ +int vfio_cdev_enable (struct container *cfg); +int vfio_cdev_setup_ioas (struct container *cfg); +int vfio_cdev_sync_ioas (struct container *cfg); +int vfio_cdev_get_iommufd (void ); +int vfio_cdev_get_device_num (const char *sysfs_base,const char *dev_addr, +int *cdev_dev_num); +struct vfio_device *vfio_cdev_get_dev_by_num (struct container *cfg,int cdev_dev_num); +int vfio_cdev_setup_device (struct container *cfg,struct vfio_device *dev); +#define VFIO_MEM_EVENT_CLB_NAME "vfio_mem_event_clb"#define EAL_VFIO_MP "eal_vfio_mp_sync"#define SOCKET_REQ_CONTAINER 0x100#define SOCKET_REQ_GROUP 0x200#define SOCKET_REQ_IOMMU_TYPE 0x400 +#define SOCKET_REQ_CDEV 0x800 +#define SOCKET_REQ_IOAS_ID 0x1000#define SOCKET_OK 0x0#define SOCKET_NO_FD 0x1#define SOCKET_ERR 0xFF
@@ -176,6 +199,8 @@ struct vfio_mp_param {union {int group_num;int iommu_type_id; +int cdev_dev_num; +int ioas_id;enum rte_vfio_mode mode; }; };
lib/eal/linux/eal_vfio_cdev.c new file +390 -0
390 lines not on this page · raw message
lib/eal/linux/eal_vfio_mp_sync.c +42 -0
48 lines not on this page · raw message
lib/eal/linux/meson.build +1 -0
@@ -16,6 +16,7 @@ sources += files( 'eal_thread.c', 'eal_timer.c', 'eal_vfio.c', + 'eal_vfio_cdev.c', 'eal_vfio_group.c', 'eal_vfio_mp_sync.c', )
Signature · 1 line
2.52.0
Quoted 170 lines · On Thu, 6 Aug 2026 15:11:00 +0100 Anatoly Burakov <[email protected]>…
This patchset introduces a major refactor of the VFIO subsystem in DPDK to support character device (cdev) interface introduced in Linux kernel, as well as make the API more streamlined and useful. The goal is to simplify device management, improve compatibility, and clarify API responsibilities.
The following sections outline the key issues addressed by this patchset and the corresponding changes introduced.
1. Only group mode is supported
===============================Since kernel version 4.14.327 (LTS), VFIO supports the new character device (cdev)-based way of working with VFIO devices (otherwise known as IOMMUFD). This is a device-centric mode and does away with all the complexity regarding groups and IOMMU types, delegating it all to the kernel, and exposes a much simpler interface to userspace.
The old group interface is still around, and will need to be kept in DPDK both for compatibility reasons, as well as supporting special cases (FSLMC bus, NBL driver, no-IOMMU mode etc.), but it is now internal-only and not exposed through the API the way it was before.
To enable this, VFIO is heavily refactored, so that the code can support both modes while relying on (mostly) common infrastructure.
Note that the existing
rte_vfio_device_setup/releasemodel is fundamentally incompatible with cdev mode, because for custom container cases, the expected flow is that the user binds the IOMMU group (and thus, implicitly, the device itself) to a specific container usingrte_vfio_container_group_bind, whereas this step is not needed for cdev as the device fd is assigned to the container straight away.Therefore, what we do instead is introduce a new API for container device assignment which, semantically, will assign a device to specified container, so that when it is mapped using
rte_pci_map_device, the appropriate container is selected. Under the hood though, we essentially transition to getting device fd straight away at assign stage, so that by the time the PCI bus attempts to map the device, it is already mapped and we just return an fd. There is no "unassign" API becauserelease_devicealready performs that function.Additionally, a new
rte_vfio_get_modeAPI is added for those cases that need some introspection into VFIO's internals, with three new modes: group (old-style), no-iommu (old-style but without IOMMU), and cdev (the new mode). Although no-IOMMU is technically a variant of group mode, the distinction is largely irrelevant to the user, as all usages of noiommu checks in our codebase are for deciding whether to use IOVA or PA, not anything to do with managing groups. The current plan for kernel community is to *not* introduce no-IOMMU cdev implementation, and IOMMUFD's own group API compatibility layer also does not implement no-IOMMU mode, which is why this will be kept for compatibility for these use cases.There were other users of VFIO which relied on group API but only for convenience purposes; no actual VFIO functionality depended on those API's. Therefore, group API's are removed and, where appropriate, replaced with the new API's.
List of removed API's:
*
rte_vfio_get_group_fd
*rte_vfio_clear_group
*rte_vfio_container_group_bind(replaced by container assign API)
*rte_vfio_container_group_unbind
*rte_vfio_noiommu_is_enabled(replaced by new mode API)2. The API responsibilities aren't clear and bleed into each other
==================================================================Some API's do multiple things at once. In particular:
*
rte_vfio_get_device_infowill setup the device
*rte_vfio_setup_devicewill get device infoThese API's have been adjusted to do one thing only.
v10:
- Added a patch that renames confusing error labels
- Fixed compiler warning about unused variablev9:
- Moved erroneous rte_errno-related comments to later in the patchset
- Moved removal of vDPA group fd API's to their respective patches
- Fixed typo in errno comments (ENXIO vs ENOXIO)
- Fixed corruption of group config in secondary process (v8 AI review)v8:
- Rebase
- Fixed build errors due to variable shadowing
- Removed duplicate fd check as kernel does not provide a way to distinguish between device fd'sv7:
- Rebase
- Added removal of deprecation notices
- Fixed implicit numeric comparison in patch 12v6:
- Fixed missing header include in vfio cdev filev5:
- Added back missing uapi patchv4:
- Fixed issues with documentingrte_vfio_modeenum
- Separated deprecation notices into a separate patchsetv3:
- Make API removal cleaner
- Fixget_group_numusages to align with new API
- Fix issues with function exports
- Fix issues withsetup_devicereturning old-style values in some casesv2:
- Make the entire API internal
- More aggressive API pruning, complete removal of group API
- Fixed a bug in group mode where device could not be used
- Better documentation and deprecation notice patches
- Moved doc patches to beginning of patchsetAnatoly Burakov (20):
uapi: update to v6.17 and addiommufd.h
vfio: make all functions internal
bus/pci: rename mismatching error labels
vfio: split get device info from setup
vfio: add container device assignment API
net/nbl: do not use VFIO group bind API
net/ntnic: use container device assignment API
vdpa/ifc: use container device assignment API
vdpa/nfp: use container device assignment API
vdpa/sfc: use container device assignment API
vdpa/mlx5: remove group-related API
vhost: remove group-related API from driver
vfio: remove group-based API
vfio: cleanup and refactor
bus/pci: use the new VFIO mode API
bus/fslmc: use the new VFIO mode API
net/hinic3: use the new VFIO mode API
net/ntnic: use the new VFIO mode API
vfio: remove no-IOMMU check API
vfio: introduce cdev modeconfig/arm/meson.build | 1 + config/meson.build | 1 + doc/guides/prog_guide/vhost_lib.rst | 4 - doc/guides/rel_notes/deprecation.rst | 10 - drivers/bus/cdx/cdx_vfio.c | 25 +- drivers/bus/fslmc/fslmc_bus.c | 10 +- drivers/bus/fslmc/fslmc_vfio.c | 6 +- drivers/bus/pci/linux/pci.c | 2 +- drivers/bus/pci/linux/pci_vfio.c | 47 +- drivers/bus/platform/platform.c | 9 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 14 +- drivers/net/hinic3/base/hinic3_hwdev.c | 3 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 21 +- drivers/net/nbl/nbl_include/nbl_include.h | 1 + drivers/net/ntnic/ntnic_ethdev.c | 2 +- drivers/net/ntnic/ntnic_vfio.c | 30 +- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - drivers/vdpa/nfp/nfp_vdpa.c | 37 +- drivers/vdpa/sfc/sfc_vdpa.c | 39 +- drivers/vdpa/sfc/sfc_vdpa.h | 2 - kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- lib/eal/freebsd/eal.c | 98 +- lib/eal/include/rte_vfio.h | 387 ++-- lib/eal/linux/eal_vfio.c | 2444 ++++++++------------- lib/eal/linux/eal_vfio.h | 167 +- lib/eal/linux/eal_vfio_cdev.c | 390 ++++ lib/eal/linux/eal_vfio_group.c | 984 +++++++++
Quoted 9 lines
lib/eal/linux/eal_vfio_mp_sync.c | 80 +- lib/eal/linux/meson.build | 2 + lib/eal/windows/eal.c | 4 +- lib/vhost/vdpa_driver.h | 3 - 35 files changed, 4263 insertions(+), 1903 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h create mode 100644 lib/eal/linux/eal_vfio_cdev.c create mode 100644 lib/eal/linux/eal_vfio_group.c
Still lots of open AI review feedback:
Patch 14/20 (vfio: cleanup and refactor)
Error: close(fd 0) on the container error path. CONTAINER_INITIALIZER in eal_vfio.h sets only the mem_maps lock, so container_fd is 0:
#define CONTAINER_INITIALIZER \
((struct container){ \
.mem_maps = {.lock = RTE_SPINLOCK_RECURSIVE_INITIALIZER,}, \
})vfio_container_erase() then does
if (cfg->container_fd >= 0 && close(cfg->container_fd))
so any container allocated but not yet given an fd closes stdin on teardown. rte_vfio_container_create() reaches this from three arms (group open failure, iommufd open failure, default:), and vfio_select_mode()'s err label reaches it too. The pre-refactor code initialized every vfio_cfgs[i].vfio_container_fd to -1. Add .container_fd = -1 to CONTAINER_INITIALIZER, and use that initializer in vfio_container_erase() rather than (struct container){0}.
Error: double close in vfio_has_supported_extensions(). The VFIO_CHECK_EXTENSION failure path closes vfio_container_fd and returns -1, and vfio_group_open_container_fd() closes it again:
ret = vfio_has_supported_extensions(vfio_container_fd);
if (ret) {
EAL_LOG(DEBUG, "No supported IOMMU extensions found!");
close(vfio_container_fd);
return -1;
}Upstream had the close in the callee on both of its error paths and none in the caller. The refactor added the caller close but removed only the n_extensions == 0 close, leaving the ioctl path closing twice. Drop the close() inside vfio_has_supported_extensions().
Warning: no release notes. The series makes the whole rte_vfio API internal, removes five public functions, and adds cdev mode. Only deprecation.rst is touched; release_26_11.rst needs "Removed Items" and "New Features" entries.
Patch 15/20 (bus/pci: use the new VFIO mode API)
Error: noiommu is never detected. pci_device_iova_mode() runs under rte_bus_get_iommu_class() at eal.c:689; rte_vfio_enable() does not run until :775. rte_vfio_get_mode() returns RTE_VFIO_MODE_NONE at that point, so is_vfio_noiommu_enabled latches to 0 and IOVA VA is chosen on a noiommu system. rte_vfio_noiommu_is_enabled() read the sysfs knob and did not depend on VFIO init.
Patch 16/20 (bus/fslmc: use the new VFIO mode API)
Error: fslmc bus scan fails on every system. rte_fslmc_scan() runs from rte_bus_scan() at eal.c:680, also before rte_vfio_enable(), so
if (rte_vfio_get_mode() != RTE_VFIO_MODE_GROUP &&
rte_vfio_get_mode() != RTE_VFIO_MODE_NOIOMMU) {
ret = -EINVAL;
goto scan_fail;
}always takes the failure branch and no DPAA2 device is ever scanned. The same ordering issue applies to rte_dpaa2_get_iommu_class() and to fslmc_vfio_add_group(), which will now always select VFIO_TYPE1_IOMMU.
Warning: the new scan_fail branch logs nothing, unlike every other failure in that function, so the failure is silent.
Patch 20/20 (vfio: introduce cdev mode)
Error: vfio_cfg.ops is never set in a cdev-mode secondary. The only assignment is in vfio_cdev_enable(), reached solely from the primary arm of vfio_select_mode(); the secondary arm calls vfio_sync_mode() and vfio_cdev_sync_ioas(), neither of which touches ops. Every rte_vfio_container_dma_map()/dma_unmap() in a cdev secondary therefore fails in vfio_dma_mem_map() with "VFIO support not initialized". A container made by rte_vfio_container_create() in a secondary has the same problem: iommufd opened, IOAS allocated, ops NULL. Set ops in the secondary cdev path.
Note also that container_dma_map()/container_dma_unmap() dereference vfio_cfg.ops->partial_unmap with no NULL check; only vfio_dma_mem_map() guards it.
Patch 3/20 (bus/pci: rename mismatching error labels)
Info: "Specifcally" in the commit body.
Patch 6/20 (net/nbl: do not use VFIO group bind API)
Info: blank line needed between the declaration and the statements in nbl_open_group_fd().
v11 cover Support VFIO cdev API in DPDK
In reply to a message not in the archiveThis patchset introduces a major refactor of the VFIO subsystem in DPDK to support character device (cdev) interface introduced in Linux kernel, as well as make the API more streamlined and useful. The goal is to simplify device management, improve compatibility, and clarify API responsibilities.
The following sections outline the key issues addressed by this patchset and the corresponding changes introduced.
1. Only group mode is supported
===============================
Since kernel version 4.14.327 (LTS), VFIO supports the new character device (cdev)-based way of working with VFIO devices (otherwise known as IOMMUFD). This is a device-centric mode and does away with all the complexity regarding groups and IOMMU types, delegating it all to the kernel, and exposes a much simpler interface to userspace.
The old group interface is still around, and will need to be kept in DPDK both for compatibility reasons, as well as supporting special cases (FSLMC bus, NBL driver, no-IOMMU mode etc.), but it is now internal-only and not exposed through the API the way it was before.
To enable this, VFIO is heavily refactored, so that the code can support both modes while relying on (mostly) common infrastructure.
Note that the existing rte_vfio_device_setup/release model is fundamentally incompatible with cdev mode, because for custom container cases, the expected flow is that the user binds the IOMMU group (and thus, implicitly, the device itself) to a specific container using rte_vfio_container_group_bind, whereas this step is not needed for cdev as the device fd is assigned to the container straight away.
Therefore, what we do instead is introduce a new API for container device assignment which, semantically, will assign a device to specified container, so that when it is mapped using rte_pci_map_device, the appropriate container is selected. Under the hood though, we essentially transition to getting device fd straight away at assign stage, so that by the time the PCI bus attempts to map the device, it is already mapped and we just return an fd. There is no "unassign" API because release_device already performs that function.
Additionally, a new rte_vfio_get_mode API is added for those cases that need some introspection into VFIO's internals, with three new modes: group (old-style), no-iommu (old-style but without IOMMU), and cdev (the new mode). Although no-IOMMU is technically a variant of group mode, the distinction is largely irrelevant to the user, as all usages of noiommu checks in our codebase are for deciding whether to use IOVA or PA, not anything to do with managing groups. The current plan for kernel community is to *not* introduce no-IOMMU cdev implementation, and IOMMUFD's own group API compatibility layer also does not implement no-IOMMU mode, which is why this will be kept for compatibility for these use cases.
There were other users of VFIO which relied on group API but only for convenience purposes; no actual VFIO functionality depended on those API's. Therefore, group API's are removed and, where appropriate, replaced with the new API's.
List of removed API's:
* rte_vfio_get_group_fd
* rte_vfio_clear_group
* rte_vfio_container_group_bind (replaced by container assign API)
* rte_vfio_container_group_unbind
* rte_vfio_noiommu_is_enabled (replaced by new mode API)
2. The API responsibilities aren't clear and bleed into each other
==================================================================
Some API's do multiple things at once. In particular:
* rte_vfio_get_device_info will setup the device
* rte_vfio_setup_device will get device info
These API's have been adjusted to do one thing only.
v11:
- Addressed feedback from Stephen's AI review:
- Use CONTAINER_INITIALIZER for reset
- Set container fd to -1 in CONTAINER_INITIALIZER
- Fixed double close()
- Moved VFIO init to earlier in init sequence to account for bus drivers needing no-IOMMU mode status
- Fixed missing ops set for cdev mode, and missing ops reset
- Fixed fd leak on failed attach in cdev
v10:
- Added a patch that renames confusing error labels
- Fixed compiler warning about unused variable
v9:
- Moved erroneous rte_errno-related comments to later in the patchset
- Moved removal of vDPA group fd API's to their respective patches
- Fixed typo in errno comments (ENXIO vs ENOXIO)
- Fixed corruption of group config in secondary process (v8 AI review)
v8:
- Rebase
- Fixed build errors due to variable shadowing
- Removed duplicate fd check as kernel does not provide a way to distinguish between device fd's
v7:
- Rebase
- Added removal of deprecation notices
- Fixed implicit numeric comparison in patch 12
v6:
- Fixed missing header include in vfio cdev file
v5:
- Added back missing uapi patch
v4:
- Fixed issues with documenting rte_vfio_mode enum
- Separated deprecation notices into a separate patchset
v3:
- Make API removal cleaner
- Fix get_group_num usages to align with new API
- Fix issues with function exports
- Fix issues with setup_device returning old-style values in some cases
v2:
- Make the entire API internal
- More aggressive API pruning, complete removal of group API
- Fixed a bug in group mode where device could not be used
- Better documentation and deprecation notice patches
- Moved doc patches to beginning of patchset
Anatoly Burakov (20):
uapi: update to v6.17 and add iommufd.h
vfio: make all functions internal
bus/pci: rename mismatching error labels
vfio: split get device info from setup
vfio: add container device assignment API
net/nbl: do not use VFIO group bind API
net/ntnic: use container device assignment API
vdpa/ifc: use container device assignment API
vdpa/nfp: use container device assignment API
vdpa/sfc: use container device assignment API
vdpa/mlx5: remove group-related API
vhost: remove group-related API from driver
vfio: remove group-based API
vfio: cleanup and refactor
bus/pci: use the new VFIO mode API
bus/fslmc: use the new VFIO mode API
net/hinic3: use the new VFIO mode API
net/ntnic: use the new VFIO mode API
vfio: remove no-IOMMU check API
vfio: introduce cdev mode
config/arm/meson.build | 1 + config/meson.build | 1 + doc/guides/prog_guide/vhost_lib.rst | 4 - doc/guides/rel_notes/deprecation.rst | 10 - drivers/bus/cdx/cdx_vfio.c | 25 +- drivers/bus/fslmc/fslmc_bus.c | 11 +- drivers/bus/fslmc/fslmc_vfio.c | 6 +- drivers/bus/pci/linux/pci.c | 2 +- drivers/bus/pci/linux/pci_vfio.c | 47 +- drivers/bus/platform/platform.c | 9 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 14 +- drivers/net/hinic3/base/hinic3_hwdev.c | 3 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 22 +- drivers/net/nbl/nbl_include/nbl_include.h | 1 + drivers/net/ntnic/ntnic_ethdev.c | 2 +- drivers/net/ntnic/ntnic_vfio.c | 30 +- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - drivers/vdpa/nfp/nfp_vdpa.c | 37 +- drivers/vdpa/sfc/sfc_vdpa.c | 39 +- drivers/vdpa/sfc/sfc_vdpa.h | 2 - kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- lib/eal/freebsd/eal.c | 98 +- lib/eal/include/rte_vfio.h | 387 ++-- lib/eal/linux/eal.c | 15 +- lib/eal/linux/eal_vfio.c | 2448 ++++++++------------- lib/eal/linux/eal_vfio.h | 169 +- lib/eal/linux/eal_vfio_cdev.c | 396 ++++ lib/eal/linux/eal_vfio_group.c | 983 +++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 80 +- lib/eal/linux/meson.build | 2 + lib/eal/windows/eal.c | 4 +- lib/vhost/vdpa_driver.h | 3 - 36 files changed, 4286 insertions(+), 1908 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h create mode 100644 lib/eal/linux/eal_vfio_cdev.c create mode 100644 lib/eal/linux/eal_vfio_group.c
Signature · 1 line
2.52.0
PATCH v11 1/20 uapi: update to v6.17 and add iommufd.h
In order to support VF tokens for cdev-based VFIO mode, kernel v6.17 is required. Update internal headers to version v6.17 and include iommufd.h.
--- kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++++++++++++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- 4 files changed, 1305 insertions(+), 3 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h
kernel/linux/uapi/linux/iommufd.h new file +1292 -0
@@ -0,0 +1,1292 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. +*/ +#ifndef _IOMMUFD_H +#define _IOMMUFD_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +#define IOMMUFD_TYPE (';') + +/** +* DOC: General ioctl format +* +* The ioctl interface follows a general format to allow for extensibility. Each +* ioctl is passed in a structure pointer as the argument providing the size of +* the structure in the first u32. The kernel checks that any structure space +* beyond what it understands is 0. This allows userspace to use the backward +* compatible portion while consistently using the newer, larger, structures. +* +* ioctls use a standard meaning for common errnos: +* +* - ENOTTY: The IOCTL number itself is not supported at all +* - E2BIG: The IOCTL number is supported, but the provided structure has +* non-zero in a part the kernel does not understand. +* - EOPNOTSUPP: The IOCTL number is supported, and the structure is +* understood, however a known field has a value the kernel does not +* understand or support. +* - EINVAL: Everything about the IOCTL was understood, but a field is not +* correct. +* - ENOENT: An ID or IOVA provided does not exist. +* - ENOMEM: Out of memory. +* - EOVERFLOW: Mathematics overflowed. +* +* As well as additional errnos, within specific ioctls. +*/ +enum { +IOMMUFD_CMD_BASE =0x80 , +IOMMUFD_CMD_DESTROY =IOMMUFD_CMD_BASE , +IOMMUFD_CMD_IOAS_ALLOC =0x81 , +IOMMUFD_CMD_IOAS_ALLOW_IOVAS =0x82 , +IOMMUFD_CMD_IOAS_COPY =0x83 , +IOMMUFD_CMD_IOAS_IOVA_RANGES =0x84 , +IOMMUFD_CMD_IOAS_MAP =0x85 , +IOMMUFD_CMD_IOAS_UNMAP =0x86 , +IOMMUFD_CMD_OPTION =0x87 , +IOMMUFD_CMD_VFIO_IOAS =0x88 , +IOMMUFD_CMD_HWPT_ALLOC =0x89 , +IOMMUFD_CMD_GET_HW_INFO =0x8a , +IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING =0x8b , +IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP =0x8c , +IOMMUFD_CMD_HWPT_INVALIDATE =0x8d , +IOMMUFD_CMD_FAULT_QUEUE_ALLOC =0x8e , +IOMMUFD_CMD_IOAS_MAP_FILE =0x8f , +IOMMUFD_CMD_VIOMMU_ALLOC =0x90 , +IOMMUFD_CMD_VDEVICE_ALLOC =0x91 , +IOMMUFD_CMD_IOAS_CHANGE_PROCESS =0x92 , +IOMMUFD_CMD_VEVENTQ_ALLOC =0x93 , +IOMMUFD_CMD_HW_QUEUE_ALLOC =0x94 , +}; + +/** +* struct iommu_destroy - ioctl(IOMMU_DESTROY) +* @size: sizeof(struct iommu_destroy) +* @id: iommufd object ID to destroy. Can be any destroyable object type. +* +* Destroy any object held within iommufd. +*/ +struct iommu_destroy { +__u32 size; +__u32 id; +}; +#define IOMMU_DESTROY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DESTROY) + +/** +* struct iommu_ioas_alloc - ioctl(IOMMU_IOAS_ALLOC) +* @size: sizeof(struct iommu_ioas_alloc) +* @flags: Must be 0 +* @out_ioas_id: Output IOAS ID for the allocated object +* +* Allocate an IO Address Space (IOAS) which holds an IO Virtual Address (IOVA) +* to memory mapping. +*/ +struct iommu_ioas_alloc { +__u32 size; +__u32 flags; +__u32 out_ioas_id; +}; +#define IOMMU_IOAS_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOC) + +/** +* struct iommu_iova_range - ioctl(IOMMU_IOVA_RANGE) +* @start: First IOVA +* @last: Inclusive last IOVA +* +* An interval in IOVA space. +*/ +struct iommu_iova_range { +__aligned_u64 start; +__aligned_u64 last; +}; + +/** +* struct iommu_ioas_iova_ranges - ioctl(IOMMU_IOAS_IOVA_RANGES) +* @size: sizeof(struct iommu_ioas_iova_ranges) +* @ioas_id: IOAS ID to read ranges from +* @num_iovas: Input/Output total number of ranges in the IOAS +* @__reserved: Must be 0 +* @allowed_iovas: Pointer to the output array of struct iommu_iova_range +* @out_iova_alignment: Minimum alignment required for mapping IOVA +* +* Query an IOAS for ranges of allowed IOVAs. Mapping IOVA outside these ranges +* is not allowed. num_iovas will be set to the total number of iovas and +* the allowed_iovas[] will be filled in as space permits. +* +* The allowed ranges are dependent on the HW path the DMA operation takes, and +* can change during the lifetime of the IOAS. A fresh empty IOAS will have a +* full range, and each attached device will narrow the ranges based on that +* device's HW restrictions. Detaching a device can widen the ranges. Userspace +* should query ranges after every attach/detach to know what IOVAs are valid +* for mapping. +* +* On input num_iovas is the length of the allowed_iovas array. On output it is +* the total number of iovas filled in. The ioctl will return -EMSGSIZE and set +* num_iovas to the required value if num_iovas is too small. In this case the +* caller should allocate a larger output array and re-issue the ioctl. +* +* out_iova_alignment returns the minimum IOVA alignment that can be given +* to IOMMU_IOAS_MAP/COPY. IOVA's must satisfy:: +* +* starting_iova % out_iova_alignment == 0 +* (starting_iova + length) % out_iova_alignment == 0 +* +* out_iova_alignment can be 1 indicating any IOVA is allowed. It cannot +* be higher than the system PAGE_SIZE. +*/ +struct iommu_ioas_iova_ranges { +__u32 size; +__u32 ioas_id; +__u32 num_iovas; +__u32 __reserved; +__aligned_u64 allowed_iovas; +__aligned_u64 out_iova_alignment; +}; +#define IOMMU_IOAS_IOVA_RANGES _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_IOVA_RANGES) + +/** +* struct iommu_ioas_allow_iovas - ioctl(IOMMU_IOAS_ALLOW_IOVAS) +* @size: sizeof(struct iommu_ioas_allow_iovas) +* @ioas_id: IOAS ID to allow IOVAs from +* @num_iovas: Input/Output total number of ranges in the IOAS +* @__reserved: Must be 0 +* @allowed_iovas: Pointer to array of struct iommu_iova_range +* +* Ensure a range of IOVAs are always available for allocation. If this call +* succeeds then IOMMU_IOAS_IOVA_RANGES will never return a list of IOVA ranges +* that are narrower than the ranges provided here. This call will fail if +* IOMMU_IOAS_IOVA_RANGES is currently narrower than the given ranges. +* +* When an IOAS is first created the IOVA_RANGES will be maximally sized, and as +* devices are attached the IOVA will narrow based on the device restrictions. +* When an allowed range is specified any narrowing will be refused, ie device +* attachment can fail if the device requires limiting within the allowed range. +* +* Automatic IOVA allocation is also impacted by this call. MAP will only +* allocate within the allowed IOVAs if they are present. +* +* This call replaces the entire allowed list with the given list. +*/ +struct iommu_ioas_allow_iovas { +__u32 size; +__u32 ioas_id; +__u32 num_iovas; +__u32 __reserved; +__aligned_u64 allowed_iovas; +}; +#define IOMMU_IOAS_ALLOW_IOVAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOW_IOVAS) + +/** +* enum iommufd_ioas_map_flags - Flags for map and copy +* @IOMMU_IOAS_MAP_FIXED_IOVA: If clear the kernel will compute an appropriate +* IOVA to place the mapping at +* @IOMMU_IOAS_MAP_WRITEABLE: DMA is allowed to write to this mapping +* @IOMMU_IOAS_MAP_READABLE: DMA is allowed to read from this mapping +*/ +enum iommufd_ioas_map_flags { +IOMMU_IOAS_MAP_FIXED_IOVA =1 <<0 , +IOMMU_IOAS_MAP_WRITEABLE =1 <<1 , +IOMMU_IOAS_MAP_READABLE =1 <<2 , +}; + +/** +* struct iommu_ioas_map - ioctl(IOMMU_IOAS_MAP) +* @size: sizeof(struct iommu_ioas_map) +* @flags: Combination of enum iommufd_ioas_map_flags +* @ioas_id: IOAS ID to change the mapping of +* @__reserved: Must be 0 +* @user_va: Userspace pointer to start mapping from +* @length: Number of bytes to map +* @iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is set +* then this must be provided as input. +* +* Set an IOVA mapping from a user pointer. If FIXED_IOVA is specified then the +* mapping will be established at iova, otherwise a suitable location based on +* the reserved and allowed lists will be automatically selected and returned in +* iova. +* +* If IOMMU_IOAS_MAP_FIXED_IOVA is specified then the iova range must currently +* be unused, existing IOVA cannot be replaced. +*/ +struct iommu_ioas_map { +__u32 size; +__u32 flags; +__u32 ioas_id; +__u32 __reserved; +__aligned_u64 user_va; +__aligned_u64 length; +__aligned_u64 iova; +}; +#define IOMMU_IOAS_MAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_MAP) + +/** +* struct iommu_ioas_map_file - ioctl(IOMMU_IOAS_MAP_FILE) +* @size: sizeof(struct iommu_ioas_map_file) +* @flags: same as for iommu_ioas_map +* @ioas_id: same as for iommu_ioas_map +* @fd: the memfd to map +* @start: byte offset from start of file to map from +* @length: same as for iommu_ioas_map +* @iova: same as for iommu_ioas_map +* +* Set an IOVA mapping from a memfd file. All other arguments and semantics +* match those of IOMMU_IOAS_MAP. +*/ +struct iommu_ioas_map_file { +__u32 size; +__u32 flags; +__u32 ioas_id; +__s32 fd; +__aligned_u64 start; +__aligned_u64 length; +__aligned_u64 iova; +}; +#define IOMMU_IOAS_MAP_FILE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_MAP_FILE) + +/** +* struct iommu_ioas_copy - ioctl(IOMMU_IOAS_COPY) +* @size: sizeof(struct iommu_ioas_copy) +* @flags: Combination of enum iommufd_ioas_map_flags +* @dst_ioas_id: IOAS ID to change the mapping of +* @src_ioas_id: IOAS ID to copy from +* @length: Number of bytes to copy and map +* @dst_iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is +* set then this must be provided as input. +* @src_iova: IOVA to start the copy +* +* Copy an already existing mapping from src_ioas_id and establish it in +* dst_ioas_id. The src iova/length must exactly match a range used with +* IOMMU_IOAS_MAP. +* +* This may be used to efficiently clone a subset of an IOAS to another, or as a +* kind of 'cache' to speed up mapping. Copy has an efficiency advantage over +* establishing equivalent new mappings, as internal resources are shared, and +* the kernel will pin the user memory only once. +*/ +struct iommu_ioas_copy { +__u32 size; +__u32 flags; +__u32 dst_ioas_id; +__u32 src_ioas_id; +__aligned_u64 length; +__aligned_u64 dst_iova; +__aligned_u64 src_iova; +}; +#define IOMMU_IOAS_COPY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_COPY) + +/** +* struct iommu_ioas_unmap - ioctl(IOMMU_IOAS_UNMAP) +* @size: sizeof(struct iommu_ioas_unmap) +* @ioas_id: IOAS ID to change the mapping of +* @iova: IOVA to start the unmapping at +* @length: Number of bytes to unmap, and return back the bytes unmapped +* +* Unmap an IOVA range. The iova/length must be a superset of a previously +* mapped range used with IOMMU_IOAS_MAP or IOMMU_IOAS_COPY. Splitting or +* truncating ranges is not allowed. The values 0 to U64_MAX will unmap +* everything. +*/ +struct iommu_ioas_unmap { +__u32 size; +__u32 ioas_id; +__aligned_u64 iova; +__aligned_u64 length; +}; +#define IOMMU_IOAS_UNMAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_UNMAP) + +/** +* enum iommufd_option - ioctl(IOMMU_OPTION_RLIMIT_MODE) and +* ioctl(IOMMU_OPTION_HUGE_PAGES) +* @IOMMU_OPTION_RLIMIT_MODE: +* Change how RLIMIT_MEMLOCK accounting works. The caller must have privilege +* to invoke this. Value 0 (default) is user based accounting, 1 uses process +* based accounting. Global option, object_id must be 0 +* @IOMMU_OPTION_HUGE_PAGES: +* Value 1 (default) allows contiguous pages to be combined when generating +* iommu mappings. Value 0 disables combining, everything is mapped to +* PAGE_SIZE. This can be useful for benchmarking. This is a per-IOAS +* option, the object_id must be the IOAS ID. +*/ +enum iommufd_option { +IOMMU_OPTION_RLIMIT_MODE =0 , +IOMMU_OPTION_HUGE_PAGES =1 , +}; + +/** +* enum iommufd_option_ops - ioctl(IOMMU_OPTION_OP_SET) and +* ioctl(IOMMU_OPTION_OP_GET) +* @IOMMU_OPTION_OP_SET: Set the option's value +* @IOMMU_OPTION_OP_GET: Get the option's value +*/ +enum iommufd_option_ops { +IOMMU_OPTION_OP_SET =0 , +IOMMU_OPTION_OP_GET =1 , +}; + +/** +* struct iommu_option - iommu option multiplexer +* @size: sizeof(struct iommu_option) +* @option_id: One of enum iommufd_option +* @op: One of enum iommufd_option_ops +* @__reserved: Must be 0 +* @object_id: ID of the object if required +* @val64: Option value to set or value returned on get +* +* Change a simple option value. This multiplexor allows controlling options +* on objects. IOMMU_OPTION_OP_SET will load an option and IOMMU_OPTION_OP_GET +* will return the current value. +*/ +struct iommu_option { +__u32 size; +__u32 option_id; +__u16 op; +__u16 __reserved; +__u32 object_id; +__aligned_u64 val64; +}; +#define IOMMU_OPTION _IO(IOMMUFD_TYPE, IOMMUFD_CMD_OPTION) + +/** +* enum iommufd_vfio_ioas_op - IOMMU_VFIO_IOAS_* ioctls +* @IOMMU_VFIO_IOAS_GET: Get the current compatibility IOAS +* @IOMMU_VFIO_IOAS_SET: Change the current compatibility IOAS +* @IOMMU_VFIO_IOAS_CLEAR: Disable VFIO compatibility +*/ +enum iommufd_vfio_ioas_op { +IOMMU_VFIO_IOAS_GET =0 , +IOMMU_VFIO_IOAS_SET =1 , +IOMMU_VFIO_IOAS_CLEAR =2 , +}; + +/** +* struct iommu_vfio_ioas - ioctl(IOMMU_VFIO_IOAS) +* @size: sizeof(struct iommu_vfio_ioas) +* @ioas_id: For IOMMU_VFIO_IOAS_SET the input IOAS ID to set +* For IOMMU_VFIO_IOAS_GET will output the IOAS ID +* @op: One of enum iommufd_vfio_ioas_op +* @__reserved: Must be 0 +* +* The VFIO compatibility support uses a single ioas because VFIO APIs do not +* support the ID field. Set or Get the IOAS that VFIO compatibility will use. +* When VFIO_GROUP_SET_CONTAINER is used on an iommufd it will get the +* compatibility ioas, either by taking what is already set, or auto creating +* one. From then on VFIO will continue to use that ioas and is not effected by +* this ioctl. SET or CLEAR does not destroy any auto-created IOAS. +*/ +struct iommu_vfio_ioas { +__u32 size; +__u32 ioas_id; +__u16 op; +__u16 __reserved; +}; +#define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS) + +/** +* enum iommufd_hwpt_alloc_flags - Flags for HWPT allocation +* @IOMMU_HWPT_ALLOC_NEST_PARENT: If set, allocate a HWPT that can serve as +* the parent HWPT in a nesting configuration. +* @IOMMU_HWPT_ALLOC_DIRTY_TRACKING: Dirty tracking support for device IOMMU is +* enforced on device attachment +* @IOMMU_HWPT_FAULT_ID_VALID: The fault_id field of hwpt allocation data is +* valid. +* @IOMMU_HWPT_ALLOC_PASID: Requests a domain that can be used with PASID. The +* domain can be attached to any PASID on the device. +* Any domain attached to the non-PASID part of the +* device must also be flagged, otherwise attaching a +* PASID will blocked. +* For the user that wants to attach PASID, ioas is +* not recommended for both the non-PASID part +* and PASID part of the device. +* If IOMMU does not support PASID it will return +* error (-EOPNOTSUPP). +*/ +enum iommufd_hwpt_alloc_flags { +IOMMU_HWPT_ALLOC_NEST_PARENT =1 <<0 , +IOMMU_HWPT_ALLOC_DIRTY_TRACKING =1 <<1 , +IOMMU_HWPT_FAULT_ID_VALID =1 <<2 , +IOMMU_HWPT_ALLOC_PASID =1 <<3 , +}; + +/** +* enum iommu_hwpt_vtd_s1_flags - Intel VT-d stage-1 page table +* entry attributes +* @IOMMU_VTD_S1_SRE: Supervisor request +* @IOMMU_VTD_S1_EAFE: Extended access enable +* @IOMMU_VTD_S1_WPE: Write protect enable +*/ +enum iommu_hwpt_vtd_s1_flags { +IOMMU_VTD_S1_SRE =1 <<0 , +IOMMU_VTD_S1_EAFE =1 <<1 , +IOMMU_VTD_S1_WPE =1 <<2 , +}; + +/** +* struct iommu_hwpt_vtd_s1 - Intel VT-d stage-1 page table +* info (IOMMU_HWPT_DATA_VTD_S1) +* @flags: Combination of enum iommu_hwpt_vtd_s1_flags +* @pgtbl_addr: The base address of the stage-1 page table. +* @addr_width: The address width of the stage-1 page table +* @__reserved: Must be 0 +*/ +struct iommu_hwpt_vtd_s1 { +__aligned_u64 flags; +__aligned_u64 pgtbl_addr; +__u32 addr_width; +__u32 __reserved; +}; + +/** +* struct iommu_hwpt_arm_smmuv3 - ARM SMMUv3 nested STE +* (IOMMU_HWPT_DATA_ARM_SMMUV3) +* +* @ste: The first two double words of the user space Stream Table Entry for +* the translation. Must be little-endian. +* Allowed fields: (Refer to "5.2 Stream Table Entry" in SMMUv3 HW Spec) +* - word-0: V, Cfg, S1Fmt, S1ContextPtr, S1CDMax +* - word-1: EATS, S1DSS, S1CIR, S1COR, S1CSH, S1STALLD +* +* -EIO will be returned if @ste is not legal or contains any non-allowed field. +* Cfg can be used to select a S1, Bypass or Abort configuration. A Bypass +* nested domain will translate the same as the nesting parent. The S1 will +* install a Context Descriptor Table pointing at userspace memory translated +* by the nesting parent. +*/ +struct iommu_hwpt_arm_smmuv3 { +__aligned_le64 ste[2 ]; +}; + +/** +* enum iommu_hwpt_data_type - IOMMU HWPT Data Type +* @IOMMU_HWPT_DATA_NONE: no data +* @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table +* @IOMMU_HWPT_DATA_ARM_SMMUV3: ARM SMMUv3 Context Descriptor Table +*/ +enum iommu_hwpt_data_type { +IOMMU_HWPT_DATA_NONE =0 , +IOMMU_HWPT_DATA_VTD_S1 =1 , +IOMMU_HWPT_DATA_ARM_SMMUV3 =2 , +}; + +/** +* struct iommu_hwpt_alloc - ioctl(IOMMU_HWPT_ALLOC) +* @size: sizeof(struct iommu_hwpt_alloc) +* @flags: Combination of enum iommufd_hwpt_alloc_flags +* @dev_id: The device to allocate this HWPT for +* @pt_id: The IOAS or HWPT or vIOMMU to connect this HWPT to +* @out_hwpt_id: The ID of the new HWPT +* @__reserved: Must be 0 +* @data_type: One of enum iommu_hwpt_data_type +* @data_len: Length of the type specific data +* @data_uptr: User pointer to the type specific data +* @fault_id: The ID of IOMMUFD_FAULT object. Valid only if flags field of +* IOMMU_HWPT_FAULT_ID_VALID is set. +* @__reserved2: Padding to 64-bit alignment. Must be 0. +* +* Explicitly allocate a hardware page table object. This is the same object +* type that is returned by iommufd_device_attach() and represents the +* underlying iommu driver's iommu_domain kernel object. +* +* A kernel-managed HWPT will be created with the mappings from the given +* IOAS via the @pt_id. The @data_type for this allocation must be set to +* IOMMU_HWPT_DATA_NONE. The HWPT can be allocated as a parent HWPT for a +* nesting configuration by passing IOMMU_HWPT_ALLOC_NEST_PARENT via @flags. +* +* A user-managed nested HWPT will be created from a given vIOMMU (wrapping a +* parent HWPT) or a parent HWPT via @pt_id, in which the parent HWPT must be +* allocated previously via the same ioctl from a given IOAS (@pt_id). In this +* case, the @data_type must be set to a pre-defined type corresponding to an +* I/O page table type supported by the underlying IOMMU hardware. The device +* via @dev_id and the vIOMMU via @pt_id must be associated to the same IOMMU +* instance. +* +* If the @data_type is set to IOMMU_HWPT_DATA_NONE, @data_len and +* @data_uptr should be zero. Otherwise, both @data_len and @data_uptr +* must be given. +*/ +struct iommu_hwpt_alloc { +__u32 size; +__u32 flags; +__u32 dev_id; +__u32 pt_id; +__u32 out_hwpt_id; +__u32 __reserved; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr; +__u32 fault_id; +__u32 __reserved2; +}; +#define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) + +/** +* enum iommu_hw_info_vtd_flags - Flags for VT-d hw_info +* @IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17: If set, disallow read-only mappings +* on a nested_parent domain. +* https://www.intel.com/content/www/us/en/content-details/772415/content-details.html +*/ +enum iommu_hw_info_vtd_flags { +IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17 =1 <<0 , +}; + +/** +* struct iommu_hw_info_vtd - Intel VT-d hardware information +* +* @flags: Combination of enum iommu_hw_info_vtd_flags +* @__reserved: Must be 0 +* +* @cap_reg: Value of Intel VT-d capability register defined in VT-d spec +* section 11.4.2 Capability Register. +* @ecap_reg: Value of Intel VT-d capability register defined in VT-d spec +* section 11.4.3 Extended Capability Register. +* +* User needs to understand the Intel VT-d specification to decode the +* register value. +*/ +struct iommu_hw_info_vtd { +__u32 flags; +__u32 __reserved; +__aligned_u64 cap_reg; +__aligned_u64 ecap_reg; +}; + +/** +* struct iommu_hw_info_arm_smmuv3 - ARM SMMUv3 hardware information +* (IOMMU_HW_INFO_TYPE_ARM_SMMUV3) +* +* @flags: Must be set to 0 +* @__reserved: Must be 0 +* @idr: Implemented features for ARM SMMU Non-secure programming interface +* @iidr: Information about the implementation and implementer of ARM SMMU, +* and architecture version supported +* @aidr: ARM SMMU architecture version +* +* For the details of @idr, @iidr and @aidr, please refer to the chapters +* from 6.3.1 to 6.3.6 in the SMMUv3 Spec. +* +* This reports the raw HW capability, and not all bits are meaningful to be +* read by userspace. Only the following fields should be used: +* +* idr[0]: ST_LEVEL, TERM_MODEL, STALL_MODEL, TTENDIAN , CD2L, ASID16, TTF +* idr[1]: SIDSIZE, SSIDSIZE +* idr[3]: BBML, RIL +* idr[5]: VAX, GRAN64K, GRAN16K, GRAN4K +* +* - S1P should be assumed to be true if a NESTED HWPT can be created +* - VFIO/iommufd only support platforms with COHACC, it should be assumed to be +* true. +* - ATS is a per-device property. If the VMM describes any devices as ATS +* capable in ACPI/DT it should set the corresponding idr. +* +* This list may expand in future (eg E0PD, AIE, PBHA, D128, DS etc). It is +* important that VMMs do not read bits outside the list to allow for +* compatibility with future kernels. Several features in the SMMUv3 +* architecture are not currently supported by the kernel for nesting: HTTU, +* BTM, MPAM and others. +*/ +struct iommu_hw_info_arm_smmuv3 { +__u32 flags; +__u32 __reserved; +__u32 idr[6 ]; +__u32 iidr; +__u32 aidr; +}; + +/** +* struct iommu_hw_info_tegra241_cmdqv - NVIDIA Tegra241 CMDQV Hardware +* Information (IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV) +* +* @flags: Must be 0 +* @version: Version number for the CMDQ-V HW for PARAM bits[03:00] +* @log2vcmdqs: Log2 of the total number of VCMDQs for PARAM bits[07:04] +* @log2vsids: Log2 of the total number of SID replacements for PARAM bits[15:12] +* @__reserved: Must be 0 +* +* VMM can use these fields directly in its emulated global PARAM register. Note +* that only one Virtual Interface (VINTF) should be exposed to a VM, i.e. PARAM +* bits[11:08] should be set to 0 for log2 of the total number of VINTFs. +*/ +struct iommu_hw_info_tegra241_cmdqv { +__u32 flags; +__u8 version; +__u8 log2vcmdqs; +__u8 log2vsids; +__u8 __reserved; +}; + +/** +* enum iommu_hw_info_type - IOMMU Hardware Info Types +* @IOMMU_HW_INFO_TYPE_NONE: Output by the drivers that do not report hardware +* info +* @IOMMU_HW_INFO_TYPE_DEFAULT: Input to request for a default type +* @IOMMU_HW_INFO_TYPE_INTEL_VTD: Intel VT-d iommu info type +* @IOMMU_HW_INFO_TYPE_ARM_SMMUV3: ARM SMMUv3 iommu info type +* @IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) info type +*/ +enum iommu_hw_info_type { +IOMMU_HW_INFO_TYPE_NONE =0 , +IOMMU_HW_INFO_TYPE_DEFAULT =0 , +IOMMU_HW_INFO_TYPE_INTEL_VTD =1 , +IOMMU_HW_INFO_TYPE_ARM_SMMUV3 =2 , +IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV =3 , +}; + +/** +* enum iommufd_hw_capabilities +* @IOMMU_HW_CAP_DIRTY_TRACKING: IOMMU hardware support for dirty tracking +* If available, it means the following APIs +* are supported: +* +* IOMMU_HWPT_GET_DIRTY_BITMAP +* IOMMU_HWPT_SET_DIRTY_TRACKING +* +* @IOMMU_HW_CAP_PCI_PASID_EXEC: Execute Permission Supported, user ignores it +* when the struct +* iommu_hw_info::out_max_pasid_log2 is zero. +* @IOMMU_HW_CAP_PCI_PASID_PRIV: Privileged Mode Supported, user ignores it +* when the struct +* iommu_hw_info::out_max_pasid_log2 is zero. +*/ +enum iommufd_hw_capabilities { +IOMMU_HW_CAP_DIRTY_TRACKING =1 <<0 , +IOMMU_HW_CAP_PCI_PASID_EXEC =1 <<1 , +IOMMU_HW_CAP_PCI_PASID_PRIV =1 <<2 , +}; + +/** +* enum iommufd_hw_info_flags - Flags for iommu_hw_info +* @IOMMU_HW_INFO_FLAG_INPUT_TYPE: If set, @in_data_type carries an input type +* for user space to request for a specific info +*/ +enum iommufd_hw_info_flags { +IOMMU_HW_INFO_FLAG_INPUT_TYPE =1 <<0 , +}; + +/** +* struct iommu_hw_info - ioctl(IOMMU_GET_HW_INFO) +* @size: sizeof(struct iommu_hw_info) +* @flags: Must be 0 +* @dev_id: The device bound to the iommufd +* @data_len: Input the length of a user buffer in bytes. Output the length of +* data that kernel supports +* @data_uptr: User pointer to a user-space buffer used by the kernel to fill +* the iommu type specific hardware information data +* @in_data_type: This shares the same field with @out_data_type, making it be +* a bidirectional field. When IOMMU_HW_INFO_FLAG_INPUT_TYPE is +* set, an input type carried via this @in_data_type field will +* be valid, requesting for the info data to the given type. If +* IOMMU_HW_INFO_FLAG_INPUT_TYPE is unset, any input value will +* be seen as IOMMU_HW_INFO_TYPE_DEFAULT +* @out_data_type: Output the iommu hardware info type as defined in the enum +* iommu_hw_info_type. +* @out_capabilities: Output the generic iommu capability info type as defined +* in the enum iommu_hw_capabilities. +* @out_max_pasid_log2: Output the width of PASIDs. 0 means no PASID support. +* PCI devices turn to out_capabilities to check if the +* specific capabilities is supported or not. +* @__reserved: Must be 0 +* +* Query an iommu type specific hardware information data from an iommu behind +* a given device that has been bound to iommufd. This hardware info data will +* be used to sync capabilities between the virtual iommu and the physical +* iommu, e.g. a nested translation setup needs to check the hardware info, so +* a guest stage-1 page table can be compatible with the physical iommu. +* +* To capture an iommu type specific hardware information data, @data_uptr and +* its length @data_len must be provided. Trailing bytes will be zeroed if the +* user buffer is larger than the data that kernel has. Otherwise, kernel only +* fills the buffer using the given length in @data_len. If the ioctl succeeds, +* @data_len will be updated to the length that kernel actually supports, +* @out_data_type will be filled to decode the data filled in the buffer +* pointed by @data_uptr. Input @data_len == zero is allowed. +*/ +struct iommu_hw_info { +__u32 size; +__u32 flags; +__u32 dev_id; +__u32 data_len; +__aligned_u64 data_uptr; +union { +__u32 in_data_type; +__u32 out_data_type; + }; +__u8 out_max_pasid_log2; +__u8 __reserved[3 ]; +__aligned_u64 out_capabilities; +}; +#define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO) + +/* +* enum iommufd_hwpt_set_dirty_tracking_flags - Flags for steering dirty +* tracking +* @IOMMU_HWPT_DIRTY_TRACKING_ENABLE: Enable dirty tracking +*/ +enum iommufd_hwpt_set_dirty_tracking_flags { +IOMMU_HWPT_DIRTY_TRACKING_ENABLE =1 , +}; + +/** +* struct iommu_hwpt_set_dirty_tracking - ioctl(IOMMU_HWPT_SET_DIRTY_TRACKING) +* @size: sizeof(struct iommu_hwpt_set_dirty_tracking) +* @flags: Combination of enum iommufd_hwpt_set_dirty_tracking_flags +* @hwpt_id: HW pagetable ID that represents the IOMMU domain +* @__reserved: Must be 0 +* +* Toggle dirty tracking on an HW pagetable. +*/ +struct iommu_hwpt_set_dirty_tracking { +__u32 size; +__u32 flags; +__u32 hwpt_id; +__u32 __reserved; +}; +#define IOMMU_HWPT_SET_DIRTY_TRACKING _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING) + +/** +* enum iommufd_hwpt_get_dirty_bitmap_flags - Flags for getting dirty bits +* @IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR: Just read the PTEs without clearing +* any dirty bits metadata. This flag +* can be passed in the expectation +* where the next operation is an unmap +* of the same IOVA range. +* +*/ +enum iommufd_hwpt_get_dirty_bitmap_flags { +IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR =1 , +}; + +/** +* struct iommu_hwpt_get_dirty_bitmap - ioctl(IOMMU_HWPT_GET_DIRTY_BITMAP) +* @size: sizeof(struct iommu_hwpt_get_dirty_bitmap) +* @hwpt_id: HW pagetable ID that represents the IOMMU domain +* @flags: Combination of enum iommufd_hwpt_get_dirty_bitmap_flags +* @__reserved: Must be 0 +* @iova: base IOVA of the bitmap first bit +* @length: IOVA range size +* @page_size: page size granularity of each bit in the bitmap +* @data: bitmap where to set the dirty bits. The bitmap bits each +* represent a page_size which you deviate from an arbitrary iova. +* +* Checking a given IOVA is dirty: +* +* data[(iova / page_size) / 64] & (1ULL << ((iova / page_size) % 64)) +* +* Walk the IOMMU pagetables for a given IOVA range to return a bitmap +* with the dirty IOVAs. In doing so it will also by default clear any +* dirty bit metadata set in the IOPTE. +*/ +struct iommu_hwpt_get_dirty_bitmap { +__u32 size; +__u32 hwpt_id; +__u32 flags; +__u32 __reserved; +__aligned_u64 iova; +__aligned_u64 length; +__aligned_u64 page_size; +__aligned_u64 data; +}; +#define IOMMU_HWPT_GET_DIRTY_BITMAP _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP) + +/** +* enum iommu_hwpt_invalidate_data_type - IOMMU HWPT Cache Invalidation +* Data Type +* @IOMMU_HWPT_INVALIDATE_DATA_VTD_S1: Invalidation data for VTD_S1 +* @IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3: Invalidation data for ARM SMMUv3 +*/ +enum iommu_hwpt_invalidate_data_type { +IOMMU_HWPT_INVALIDATE_DATA_VTD_S1 =0 , +IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3 =1 , +}; + +/** +* enum iommu_hwpt_vtd_s1_invalidate_flags - Flags for Intel VT-d +* stage-1 cache invalidation +* @IOMMU_VTD_INV_FLAGS_LEAF: Indicates whether the invalidation applies +* to all-levels page structure cache or just +* the leaf PTE cache. +*/ +enum iommu_hwpt_vtd_s1_invalidate_flags { +IOMMU_VTD_INV_FLAGS_LEAF =1 <<0 , +}; + +/** +* struct iommu_hwpt_vtd_s1_invalidate - Intel VT-d cache invalidation +* (IOMMU_HWPT_INVALIDATE_DATA_VTD_S1) +* @addr: The start address of the range to be invalidated. It needs to +* be 4KB aligned. +* @npages: Number of contiguous 4K pages to be invalidated. +* @flags: Combination of enum iommu_hwpt_vtd_s1_invalidate_flags +* @__reserved: Must be 0 +* +* The Intel VT-d specific invalidation data for user-managed stage-1 cache +* invalidation in nested translation. Userspace uses this structure to +* tell the impacted cache scope after modifying the stage-1 page table. +* +* Invalidating all the caches related to the page table by setting @addr +* to be 0 and @npages to be U64_MAX. +* +* The device TLB will be invalidated automatically if ATS is enabled. +*/ +struct iommu_hwpt_vtd_s1_invalidate { +__aligned_u64 addr; +__aligned_u64 npages; +__u32 flags; +__u32 __reserved; +}; + +/** +* struct iommu_viommu_arm_smmuv3_invalidate - ARM SMMUv3 cache invalidation +* (IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3) +* @cmd: 128-bit cache invalidation command that runs in SMMU CMDQ. +* Must be little-endian. +* +* Supported command list only when passing in a vIOMMU via @hwpt_id: +* CMDQ_OP_TLBI_NSNH_ALL +* CMDQ_OP_TLBI_NH_VA +* CMDQ_OP_TLBI_NH_VAA +* CMDQ_OP_TLBI_NH_ALL +* CMDQ_OP_TLBI_NH_ASID +* CMDQ_OP_ATC_INV +* CMDQ_OP_CFGI_CD +* CMDQ_OP_CFGI_CD_ALL +* +* -EIO will be returned if the command is not supported. +*/ +struct iommu_viommu_arm_smmuv3_invalidate { +__aligned_le64 cmd[2 ]; +}; + +/** +* struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE) +* @size: sizeof(struct iommu_hwpt_invalidate) +* @hwpt_id: ID of a nested HWPT or a vIOMMU, for cache invalidation +* @data_uptr: User pointer to an array of driver-specific cache invalidation +* data. +* @data_type: One of enum iommu_hwpt_invalidate_data_type, defining the data +* type of all the entries in the invalidation request array. It +* should be a type supported by the hwpt pointed by @hwpt_id. +* @entry_len: Length (in bytes) of a request entry in the request array +* @entry_num: Input the number of cache invalidation requests in the array. +* Output the number of requests successfully handled by kernel. +* @__reserved: Must be 0. +* +* Invalidate iommu cache for user-managed page table or vIOMMU. Modifications +* on a user-managed page table should be followed by this operation, if a HWPT +* is passed in via @hwpt_id. Other caches, such as device cache or descriptor +* cache can be flushed if a vIOMMU is passed in via the @hwpt_id field. +* +* Each ioctl can support one or more cache invalidation requests in the array +* that has a total size of @entry_len * @entry_num. +* +* An empty invalidation request array by setting @entry_num==0 is allowed, and +* @entry_len and @data_uptr would be ignored in this case. This can be used to +* check if the given @data_type is supported or not by kernel. +*/ +struct iommu_hwpt_invalidate { +__u32 size; +__u32 hwpt_id; +__aligned_u64 data_uptr; +__u32 data_type; +__u32 entry_len; +__u32 entry_num; +__u32 __reserved; +}; +#define IOMMU_HWPT_INVALIDATE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_INVALIDATE) + +/** +* enum iommu_hwpt_pgfault_flags - flags for struct iommu_hwpt_pgfault +* @IOMMU_PGFAULT_FLAGS_PASID_VALID: The pasid field of the fault data is +* valid. +* @IOMMU_PGFAULT_FLAGS_LAST_PAGE: It's the last fault of a fault group. +*/ +enum iommu_hwpt_pgfault_flags { +IOMMU_PGFAULT_FLAGS_PASID_VALID = (1 <<0 ), +IOMMU_PGFAULT_FLAGS_LAST_PAGE = (1 <<1 ), +}; + +/** +* enum iommu_hwpt_pgfault_perm - perm bits for struct iommu_hwpt_pgfault +* @IOMMU_PGFAULT_PERM_READ: request for read permission +* @IOMMU_PGFAULT_PERM_WRITE: request for write permission +* @IOMMU_PGFAULT_PERM_EXEC: (PCIE 10.4.1) request with a PASID that has the +* Execute Requested bit set in PASID TLP Prefix. +* @IOMMU_PGFAULT_PERM_PRIV: (PCIE 10.4.1) request with a PASID that has the +* Privileged Mode Requested bit set in PASID TLP +* Prefix. +*/ +enum iommu_hwpt_pgfault_perm { +IOMMU_PGFAULT_PERM_READ = (1 <<0 ), +IOMMU_PGFAULT_PERM_WRITE = (1 <<1 ), +IOMMU_PGFAULT_PERM_EXEC = (1 <<2 ), +IOMMU_PGFAULT_PERM_PRIV = (1 <<3 ), +}; + +/** +* struct iommu_hwpt_pgfault - iommu page fault data +* @flags: Combination of enum iommu_hwpt_pgfault_flags +* @dev_id: id of the originated device +* @pasid: Process Address Space ID +* @grpid: Page Request Group Index +* @perm: Combination of enum iommu_hwpt_pgfault_perm +* @__reserved: Must be 0. +* @addr: Fault address +* @length: a hint of how much data the requestor is expecting to fetch. For +* example, if the PRI initiator knows it is going to do a 10MB +* transfer, it could fill in 10MB and the OS could pre-fault in +* 10MB of IOVA. It's default to 0 if there's no such hint. +* @cookie: kernel-managed cookie identifying a group of fault messages. The +* cookie number encoded in the last page fault of the group should +* be echoed back in the response message. +*/ +struct iommu_hwpt_pgfault { +__u32 flags; +__u32 dev_id; +__u32 pasid; +__u32 grpid; +__u32 perm; +__u32 __reserved; +__aligned_u64 addr; +__u32 length; +__u32 cookie; +}; + +/** +* enum iommufd_page_response_code - Return status of fault handlers +* @IOMMUFD_PAGE_RESP_SUCCESS: Fault has been handled and the page tables +* populated, retry the access. This is the +* "Success" defined in PCI 10.4.2.1. +* @IOMMUFD_PAGE_RESP_INVALID: Could not handle this fault, don't retry the +* access. This is the "Invalid Request" in PCI +* 10.4.2.1. +*/ +enum iommufd_page_response_code { +IOMMUFD_PAGE_RESP_SUCCESS =0 , +IOMMUFD_PAGE_RESP_INVALID =1 , +}; + +/** +* struct iommu_hwpt_page_response - IOMMU page fault response +* @cookie: The kernel-managed cookie reported in the fault message. +* @code: One of response code in enum iommufd_page_response_code. +*/ +struct iommu_hwpt_page_response { +__u32 cookie; +__u32 code; +}; + +/** +* struct iommu_fault_alloc - ioctl(IOMMU_FAULT_QUEUE_ALLOC) +* @size: sizeof(struct iommu_fault_alloc) +* @flags: Must be 0 +* @out_fault_id: The ID of the new FAULT +* @out_fault_fd: The fd of the new FAULT +* +* Explicitly allocate a fault handling object. +*/ +struct iommu_fault_alloc { +__u32 size; +__u32 flags; +__u32 out_fault_id; +__u32 out_fault_fd; +}; +#define IOMMU_FAULT_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_FAULT_QUEUE_ALLOC) + +/** +* enum iommu_viommu_type - Virtual IOMMU Type +* @IOMMU_VIOMMU_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VIOMMU_TYPE_ARM_SMMUV3: ARM SMMUv3 driver specific type +* @IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) enabled ARM SMMUv3 type +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_DEFAULT =0 , +IOMMU_VIOMMU_TYPE_ARM_SMMUV3 =1 , +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV =2 , +}; + +/** +* struct iommu_viommu_tegra241_cmdqv - NVIDIA Tegra241 CMDQV Virtual Interface +* (IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV) +* @out_vintf_mmap_offset: mmap offset argument for VINTF's page0 +* @out_vintf_mmap_length: mmap length argument for VINTF's page0 +* +* Both @out_vintf_mmap_offset and @out_vintf_mmap_length are reported by kernel +* for user space to mmap the VINTF page0 from the host physical address space +* to the guest physical address space so that a guest kernel can directly R/W +* access to the VINTF page0 in order to control its virtual command queues. +*/ +struct iommu_viommu_tegra241_cmdqv { +__aligned_u64 out_vintf_mmap_offset; +__aligned_u64 out_vintf_mmap_length; +}; + +/** +* struct iommu_viommu_alloc - ioctl(IOMMU_VIOMMU_ALLOC) +* @size: sizeof(struct iommu_viommu_alloc) +* @flags: Must be 0 +* @type: Type of the virtual IOMMU. Must be defined in enum iommu_viommu_type +* @dev_id: The device's physical IOMMU will be used to back the virtual IOMMU +* @hwpt_id: ID of a nesting parent HWPT to associate to +* @out_viommu_id: Output virtual IOMMU ID for the allocated object +* @data_len: Length of the type specific data +* @__reserved: Must be 0 +* @data_uptr: User pointer to a driver-specific virtual IOMMU data +* +* Allocate a virtual IOMMU object, representing the underlying physical IOMMU's +* virtualization support that is a security-isolated slice of the real IOMMU HW +* that is unique to a specific VM. Operations global to the IOMMU are connected +* to the vIOMMU, such as: +* - Security namespace for guest owned ID, e.g. guest-controlled cache tags +* - Non-device-affiliated event reporting, e.g. invalidation queue errors +* - Access to a sharable nesting parent pagetable across physical IOMMUs +* - Virtualization of various platforms IDs, e.g. RIDs and others +* - Delivery of paravirtualized invalidation +* - Direct assigned invalidation queues +* - Direct assigned interrupts +*/ +struct iommu_viommu_alloc { +__u32 size; +__u32 flags; +__u32 type; +__u32 dev_id; +__u32 hwpt_id; +__u32 out_viommu_id; +__u32 data_len; +__u32 __reserved; +__aligned_u64 data_uptr; +}; +#define IOMMU_VIOMMU_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_ALLOC) + +/** +* struct iommu_vdevice_alloc - ioctl(IOMMU_VDEVICE_ALLOC) +* @size: sizeof(struct iommu_vdevice_alloc) +* @viommu_id: vIOMMU ID to associate with the virtual device +* @dev_id: The physical device to allocate a virtual instance on the vIOMMU +* @out_vdevice_id: Object handle for the vDevice. Pass to IOMMU_DESTORY +* @virt_id: Virtual device ID per vIOMMU, e.g. vSID of ARM SMMUv3, vDeviceID +* of AMD IOMMU, and vRID of Intel VT-d +* +* Allocate a virtual device instance (for a physical device) against a vIOMMU. +* This instance holds the device's information (related to its vIOMMU) in a VM. +* User should use IOMMU_DESTROY to destroy the virtual device before +* destroying the physical device (by closing vfio_cdev fd). Otherwise the +* virtual device would be forcibly destroyed on physical device destruction, +* its vdevice_id would be permanently leaked (unremovable & unreusable) until +* iommu fd closed. +*/ +struct iommu_vdevice_alloc { +__u32 size; +__u32 viommu_id; +__u32 dev_id; +__u32 out_vdevice_id; +__aligned_u64 virt_id; +}; +#define IOMMU_VDEVICE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VDEVICE_ALLOC) + +/** +* struct iommu_ioas_change_process - ioctl(VFIO_IOAS_CHANGE_PROCESS) +* @size: sizeof(struct iommu_ioas_change_process) +* @__reserved: Must be 0 +* +* This transfers pinned memory counts for every memory map in every IOAS +* in the context to the current process. This only supports maps created +* with IOMMU_IOAS_MAP_FILE, and returns EINVAL if other maps are present. +* If the ioctl returns a failure status, then nothing is changed. +* +* This API is useful for transferring operation of a device from one process +* to another, such as during userland live update. +*/ +struct iommu_ioas_change_process { +__u32 size; +__u32 __reserved; +}; + +#define IOMMU_IOAS_CHANGE_PROCESS \ + _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_CHANGE_PROCESS) + +/** +* enum iommu_veventq_flag - flag for struct iommufd_vevent_header +* @IOMMU_VEVENTQ_FLAG_LOST_EVENTS: vEVENTQ has lost vEVENTs +*/ +enum iommu_veventq_flag { +IOMMU_VEVENTQ_FLAG_LOST_EVENTS = (1U <<0 ), +}; + +/** +* struct iommufd_vevent_header - Virtual Event Header for a vEVENTQ Status +* @flags: Combination of enum iommu_veventq_flag +* @sequence: The sequence index of a vEVENT in the vEVENTQ, with a range of +* [0, INT_MAX] where the following index of INT_MAX is 0 +* +* Each iommufd_vevent_header reports a sequence index of the following vEVENT: +* +* +----------------------+-------+----------------------+-------+---+-------+ +* | header0 {sequence=0} | data0 | header1 {sequence=1} | data1 |...| dataN | +* +----------------------+-------+----------------------+-------+---+-------+ +* +* And this sequence index is expected to be monotonic to the sequence index of +* the previous vEVENT. If two adjacent sequence indexes has a delta larger than +* 1, it means that delta - 1 number of vEVENTs has lost, e.g. two lost vEVENTs: +* +* +-----+----------------------+-------+----------------------+-------+-----+ +* | ... | header3 {sequence=3} | data3 | header6 {sequence=6} | data6 | ... | +* +-----+----------------------+-------+----------------------+-------+-----+ +* +* If a vEVENT lost at the tail of the vEVENTQ and there is no following vEVENT +* providing the next sequence index, an IOMMU_VEVENTQ_FLAG_LOST_EVENTS header +* would be added to the tail, and no data would follow this header: +* +* +--+----------------------+-------+-----------------------------------------+ +* |..| header3 {sequence=3} | data3 | header4 {flags=LOST_EVENTS, sequence=4} | +* +--+----------------------+-------+-----------------------------------------+ +*/ +struct iommufd_vevent_header { +__u32 flags; +__u32 sequence; +}; + +/** +* enum iommu_veventq_type - Virtual Event Queue Type +* @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue +* @IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension IRQ +*/ +enum iommu_veventq_type { +IOMMU_VEVENTQ_TYPE_DEFAULT =0 , +IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 =1 , +IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV =2 , +}; + +/** +* struct iommu_vevent_arm_smmuv3 - ARM SMMUv3 Virtual Event +* (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) +* @evt: 256-bit ARM SMMUv3 Event record, little-endian. +* Reported event records: (Refer to "7.3 Event records" in SMMUv3 HW Spec) +* - 0x04 C_BAD_STE +* - 0x06 F_STREAM_DISABLED +* - 0x08 C_BAD_SUBSTREAMID +* - 0x0a C_BAD_CD +* - 0x10 F_TRANSLATION +* - 0x11 F_ADDR_SIZE +* - 0x12 F_ACCESS +* - 0x13 F_PERMISSION +* +* StreamID field reports a virtual device ID. To receive a virtual event for a +* device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC. +*/ +struct iommu_vevent_arm_smmuv3 { +__aligned_le64 evt[4 ]; +}; + +/** +* struct iommu_vevent_tegra241_cmdqv - Tegra241 CMDQV IRQ +* (IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV) +* @lvcmdq_err_map: 128-bit logical vcmdq error map, little-endian. +* (Refer to register LVCMDQ_ERR_MAPs per VINTF ) +* +* The 128-bit register value from HW exclusively reflect the error bits for a +* Virtual Interface represented by a vIOMMU object. Read and report directly. +*/ +struct iommu_vevent_tegra241_cmdqv { +__aligned_le64 lvcmdq_err_map[2 ]; +}; + +/** +* struct iommu_veventq_alloc - ioctl(IOMMU_VEVENTQ_ALLOC) +* @size: sizeof(struct iommu_veventq_alloc) +* @flags: Must be 0 +* @viommu_id: virtual IOMMU ID to associate the vEVENTQ with +* @type: Type of the vEVENTQ. Must be defined in enum iommu_veventq_type +* @veventq_depth: Maximum number of events in the vEVENTQ +* @out_veventq_id: The ID of the new vEVENTQ +* @out_veventq_fd: The fd of the new vEVENTQ. User space must close the +* successfully returned fd after using it +* @__reserved: Must be 0 +* +* Explicitly allocate a virtual event queue interface for a vIOMMU. A vIOMMU +* can have multiple FDs for different types, but is confined to one per @type. +* User space should open the @out_veventq_fd to read vEVENTs out of a vEVENTQ, +* if there are vEVENTs available. A vEVENTQ will lose events due to overflow, +* if the number of the vEVENTs hits @veventq_depth. +* +* Each vEVENT in a vEVENTQ encloses a struct iommufd_vevent_header followed by +* a type-specific data structure, in a normal case: +* +* +-+---------+-------+---------+-------+-----+---------+-------+-+ +* | | header0 | data0 | header1 | data1 | ... | headerN | dataN | | +* +-+---------+-------+---------+-------+-----+---------+-------+-+ +* +* unless a tailing IOMMU_VEVENTQ_FLAG_LOST_EVENTS header is logged (refer to +* struct iommufd_vevent_header). +*/ +struct iommu_veventq_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 type; +__u32 veventq_depth; +__u32 out_veventq_id; +__u32 out_veventq_fd; +__u32 __reserved; +}; +#define IOMMU_VEVENTQ_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VEVENTQ_ALLOC) + +/** +* enum iommu_hw_queue_type - HW Queue Type +* @IOMMU_HW_QUEUE_TYPE_DEFAULT: Reserved for future use +* @IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) Virtual Command Queue (VCMDQ) +*/ +enum iommu_hw_queue_type { +IOMMU_HW_QUEUE_TYPE_DEFAULT =0 , +/* +* TEGRA241_CMDQV requirements (otherwise, allocation will fail) +* - alloc starts from the lowest @index=0 in ascending order +* - destroy starts from the last allocated @index in descending order +* - @base_addr must be aligned to @length in bytes and mapped in IOAS +* - @length must be a power of 2, with a minimum 32 bytes and a maximum +* 2 ^ idr[1].CMDQS * 16 bytes (use GET_HW_INFO call to read idr[1] +* from struct iommu_hw_info_arm_smmuv3) +* - suggest to back the queue memory with contiguous physical pages or +* a single huge page with alignment of the queue size, and limit the +* emulated vSMMU's IDR1.CMDQS to log2(huge page size / 16 bytes) +*/ +IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV =1 , +}; + +/** +* struct iommu_hw_queue_alloc - ioctl(IOMMU_HW_QUEUE_ALLOC) +* @size: sizeof(struct iommu_hw_queue_alloc) +* @flags: Must be 0 +* @viommu_id: Virtual IOMMU ID to associate the HW queue with +* @type: One of enum iommu_hw_queue_type +* @index: The logical index to the HW queue per virtual IOMMU for a multi-queue +* model +* @out_hw_queue_id: The ID of the new HW queue +* @nesting_parent_iova: Base address of the queue memory in the guest physical +* address space +* @length: Length of the queue memory +* +* Allocate a HW queue object for a vIOMMU-specific HW-accelerated queue, which +* allows HW to access a guest queue memory described using @nesting_parent_iova +* and @length. +* +* A vIOMMU can allocate multiple queues, but it must use a different @index per +* type to separate each allocation, e.g:: +* +* Type1 HW queue0, Type1 HW queue1, Type2 HW queue0, ... +*/ +struct iommu_hw_queue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 type; +__u32 index; +__u32 out_hw_queue_id; +__aligned_u64 nesting_parent_iova; +__aligned_u64 length; +}; +#define IOMMU_HW_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HW_QUEUE_ALLOC) +#endif
kernel/linux/uapi/linux/vduse.h +1 -1
@@ -237,7 +237,7 @@ struct vduse_iova_umem {* struct vduse_iova_info - information of one IOVA region * @start: start of the IOVA region * @last: last of the IOVA region -* @capability: capability of the IOVA regsion +* @capability: capability of the IOVA region * @reserved: for future use, needs to be initialized to zero * * Structure used by VDUSE_IOTLB_GET_INFO ioctl to get information of
kernel/linux/uapi/linux/vfio.h +11 -1
@@ -905,10 +905,12 @@ struct vfio_device_feature {* VFIO_DEVICE_BIND_IOMMUFD - _IOR(VFIO_TYPE, VFIO_BASE + 18, * struct vfio_device_bind_iommufd) * @argsz: User filled size of this data. -* @flags: Must be 0. +* @flags: Must be 0 or a bit flags of VFIO_DEVICE_BIND_* * @iommufd: iommufd to bind. * @out_devid: The device id generated by this bind. devid is a handle for * this device/iommufd bond and can be used in IOMMUFD commands. +* @token_uuid_ptr: Valid if VFIO_DEVICE_BIND_FLAG_TOKEN. Points to a 16 byte +* UUID in the same format as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN. * * Bind a vfio_device to the specified iommufd. *
@@ -917,13 +919,21 @@ struct vfio_device_feature {* * Unbind is automatically conducted when device fd is closed. * +* A token is sometimes required to open the device, unless this is known to be +* needed VFIO_DEVICE_BIND_FLAG_TOKEN should not be set and token_uuid_ptr is +* ignored. The only case today is a PF/VF relationship where the VF bind must +* be provided the same token as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN provided to +* the PF. +* * Return: 0 on success, -errno on failure. */ struct vfio_device_bind_iommufd {__u32 argsz;__u32 flags; +#define VFIO_DEVICE_BIND_FLAG_TOKEN (1 << 0)__s32 iommufd;__u32 out_devid; +__aligned_u64 token_uuid_ptr; };#define VFIO_DEVICE_BIND_IOMMUFD _IO(VFIO_TYPE, VFIO_BASE + 18)
kernel/linux/uapi/version +1 -1
@@ -1 +1 @@ -v6.16 +v6.17
Signature · 1 line
2.52.0
PATCH v11 2/20 vfio: make all functions internal
In reply to Anatoly BurakovThe VFIO API is an externally exported API because the original intent was to offer DMA mapping facilities to applications. However, practical usage of this API seems to be centered around drivers, so keeping this API exported to applications only creates needless API/ABI stability surface that has no added value.
Make the entire VFIO API internal-only and visible only to drivers.
--- doc/guides/rel_notes/deprecation.rst | 6 ---- lib/eal/freebsd/eal.c | 30 +++++++++--------- lib/eal/include/rte_vfio.h | 47 ++++++++++++++++++++++++---- lib/eal/linux/eal_vfio.c | 32 +++++++++---------- lib/eal/windows/eal.c | 4 +-- 5 files changed, 74 insertions(+), 45 deletions(-)
doc/guides/rel_notes/deprecation.rst +0 -6
@@ -29,12 +29,6 @@ Deprecation Notices Use the ``-S <service-corelist>`` parameter instead to specify the cores to be used for background services in DPDK. -* eal: The entire VFIO API (``rte_vfio_*``) will be made internal only, - and will only be available to EAL and drivers. - Group-based API (``rte_vfio_*_group_*``) will be removed - and replaced with unified container device assignment API. - This change will be made in 26.11 release. - * vdpa: The vDPA driver API will no longer offer ``get_vfio_group_fd`` as part of its internal API. All drivers will be adjusted to use the new unified VFIO container device assignment API.
lib/eal/freebsd/eal.c +15 -15
@@ -819,7 +819,7 @@ rte_eal_vfio_get_vf_token(__rte_unused rte_uuid_t vf_token) { } -RTE_EXPORT_SYMBOL(rte_vfio_setup_device) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_setup_device) int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, __rte_unused int *vfio_dev_fd,
@@ -829,7 +829,7 @@ int rte_vfio_setup_device(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_release_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_release_device) int rte_vfio_release_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, __rte_unused int fd)
@@ -838,33 +838,33 @@ int rte_vfio_release_device(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_enable) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_enable) int rte_vfio_enable(__rte_unused const char *modname) { rte_errno =ENOTSUP ;return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_is_enabled) int rte_vfio_is_enabled(__rte_unused const char *modname) {return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_noiommu_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) int rte_vfio_noiommu_is_enabled(void) {return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_clear_group) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) int rte_vfio_clear_group(__rte_unused int vfio_group_fd) { rte_errno =ENOTSUP ;return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_get_group_num) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr,
@@ -874,7 +874,7 @@ rte_vfio_get_group_num(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_container_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_container_fd) intrte_vfio_get_container_fd (void ) {
@@ -882,7 +882,7 @@ rte_vfio_get_container_fd(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) int rte_vfio_get_group_fd(__rte_unused int iommu_group_num) {
@@ -890,7 +890,7 @@ rte_vfio_get_group_fd(__rte_unused int iommu_group_num)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_create) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void ) {
@@ -898,7 +898,7 @@ rte_vfio_container_create(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_destroy) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_destroy) int rte_vfio_container_destroy(__rte_unused int container_fd) {
@@ -906,7 +906,7 @@ rte_vfio_container_destroy(__rte_unused int container_fd)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_bind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) int rte_vfio_container_group_bind(__rte_unused int container_fd, __rte_unused int iommu_group_num)
@@ -915,7 +915,7 @@ rte_vfio_container_group_bind(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_unbind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) int rte_vfio_container_group_unbind(__rte_unused int container_fd, __rte_unused int iommu_group_num)
@@ -924,7 +924,7 @@ rte_vfio_container_group_unbind(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
@@ -935,7 +935,7 @@ rte_vfio_container_dma_map(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_unmap) int rte_vfio_container_dma_unmap(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
lib/eal/include/rte_vfio.h +41 -6
214 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +16 -16
@@ -532,7 +532,7 @@ get_vfio_cfg_by_container_fd(int container_fd)return NULL ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) intrte_vfio_get_group_fd (int iommu_group_num) {
@@ -731,7 +731,7 @@ vfio_sync_default_container(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_clear_group) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) intrte_vfio_clear_group (int vfio_group_fd) {
@@ -755,7 +755,7 @@ rte_vfio_clear_group(int vfio_group_fd)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_setup_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) intrte_vfio_setup_device (const char *sysfs_base,const char *dev_addr,int *vfio_dev_fd,struct vfio_device_info *device_info)
@@ -1009,7 +1009,7 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_release_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_release_device) intrte_vfio_release_device (const char *sysfs_base,const char *dev_addr,int vfio_dev_fd)
@@ -1098,7 +1098,7 @@ rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,return ret; } -RTE_EXPORT_SYMBOL (rte_vfio_enable) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_enable) intrte_vfio_enable (const char *modname) {
@@ -1175,7 +1175,7 @@ rte_vfio_enable(const char *modname)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_is_enabled) intrte_vfio_is_enabled (const char *modname) {
@@ -1215,7 +1215,7 @@ vfio_set_iommu_type(int vfio_container_fd)return NULL ; } -RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vfio_get_device_info, 24.03) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) intrte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr,int *vfio_dev_fd,struct vfio_device_info *device_info)
@@ -1349,7 +1349,7 @@ vfio_open_container_fd(bool mp_request)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_container_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_container_fd) intrte_vfio_get_container_fd (void ) {
@@ -1363,7 +1363,7 @@ rte_vfio_get_container_fd(void)return default_vfio_cfg->vfio_container_fd; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_num) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_num) intrte_vfio_get_group_num (const char *sysfs_base,const char *dev_addr,int *iommu_group_num)
@@ -2034,7 +2034,7 @@ container_dma_unmap(struct vfio_config *vfio_cfg, uint64_t vaddr, uint64_t iova,return ret; } -RTE_EXPORT_SYMBOL (rte_vfio_noiommu_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) intrte_vfio_noiommu_is_enabled (void ) {
@@ -2067,7 +2067,7 @@ rte_vfio_noiommu_is_enabled(void)return c =='Y' ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_create) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void ) {
@@ -2094,7 +2094,7 @@ rte_vfio_container_create(void)return vfio_cfgs[i].vfio_container_fd; } -RTE_EXPORT_SYMBOL (rte_vfio_container_destroy) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_destroy) intrte_vfio_container_destroy (int container_fd) {
@@ -2120,7 +2120,7 @@ rte_vfio_container_destroy(int container_fd)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_bind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) intrte_vfio_container_group_bind (int container_fd,int iommu_group_num) {
@@ -2135,7 +2135,7 @@ rte_vfio_container_group_bind(int container_fd, int iommu_group_num)return vfio_get_group_fd (vfio_cfg, iommu_group_num); } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_unbind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) intrte_vfio_container_group_unbind (int container_fd,int iommu_group_num) {
@@ -2176,7 +2176,7 @@ rte_vfio_container_group_unbind(int container_fd, int iommu_group_num)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_dma_map) intrte_vfio_container_dma_map (int container_fd,uint64_t vaddr,uint64_t iova,uint64_t len)
@@ -2197,7 +2197,7 @@ rte_vfio_container_dma_map(int container_fd, uint64_t vaddr, uint64_t iova,return container_dma_map (vfio_cfg, vaddr, iova, len); } -RTE_EXPORT_SYMBOL (rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_dma_unmap) intrte_vfio_container_dma_unmap (int container_fd,uint64_t vaddr,uint64_t iova,uint64_t len)
lib/eal/windows/eal.c +2 -2
@@ -453,7 +453,7 @@ eal_asprintf(char **buffer, const char *format, ...)return ret; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
@@ -464,7 +464,7 @@ rte_vfio_container_dma_map(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_unmap) int rte_vfio_container_dma_unmap(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
Signature · 1 line
2.52.0
PATCH v11 3/20 bus/pci: rename mismatching error labels
In reply to Anatoly BurakovCurrently, there are two VFIO map functions - primary and secondary - that use a very similar goto error pattern. However, the label names are confusing.
Specifically, for primary, we have three error labels: vfio_res (release VFIO resource), vfio_dev_fd (close the fd), and map (unmap all the mapped regions). For secondary, there is vfio_dev (close the fd), and vfio_dev_fd (unmap all mapped regions).
For consistency, align secondary process function's error labels to match semantics of how they work in primary process function.
--- drivers/bus/pci/linux/pci_vfio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/bus/pci/linux/pci_vfio.c +7 -7
@@ -968,7 +968,7 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) ret =pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info);if (ret) - goto err_vfio_dev; + goto err_vfio_dev_fd;/* map BARs */ maps = vfio_res->maps;
@@ -979,14 +979,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)if (ret <0 ) {PCI_LOG (ERR ,"%s sparse mapping BAR%i failed: %s" , pci_addr, i,strerror (errno)); - goto err_vfio_dev_fd; + goto err_map; } }else { ret =pci_vfio_mmap_bar (vfio_dev_fd, vfio_res, i,MAP_FIXED );if (ret <0 ) {PCI_LOG (ERR ,"%s mapping BAR%i failed: %s" , pci_addr, i,strerror (errno)); - goto err_vfio_dev_fd; + goto err_map; } }
@@ -995,17 +995,17 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)/* we need save vfio_dev_fd, so it can be used during release */ if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd)) - goto err_vfio_dev_fd; + goto err_map;if (rte_intr_dev_fd_set (dev->vfio_req_intr_handle, vfio_dev_fd)) - goto err_vfio_dev_fd; + goto err_map;return 0 ; -err_vfio_dev_fd: +err_map:for (j =0 ; j < i; j++) {if (maps[j].addr)pci_unmap_resource (maps[j].addr, maps[j].size); } -err_vfio_dev: +err_vfio_dev_fd:rte_vfio_release_device (rte_pci_get_sysfs_path (), pci_addr, vfio_dev_fd);return -1 ;
Signature · 1 line
2.52.0
PATCH v11 4/20 vfio: split get device info from setup
In reply to Anatoly BurakovCurrently, setup gets device info as part of setup, while the separate get device info API also calls setup if the fd is zero. Untangle these two APIs and make each do one thing, and adjust all existing callers.
--- drivers/bus/cdx/cdx_vfio.c | 12 ++++++++-- drivers/bus/pci/linux/pci_vfio.c | 18 ++++++++++---- drivers/bus/platform/platform.c | 9 ++++++- drivers/crypto/bcmfs/bcmfs_vfio.c | 8 ++++++- lib/eal/freebsd/eal.c | 3 +-- lib/eal/include/rte_vfio.h | 23 +++++++----------- lib/eal/linux/eal_vfio.c | 40 +++++++++---------------------- 7 files changed, 59 insertions(+), 54 deletions(-)
drivers/bus/cdx/cdx_vfio.c +10 -2
@@ -401,10 +401,14 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev)return -1 ; ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* allocate vfio_res and get region info */ vfio_res =rte_zmalloc ("VFIO_RES" ,sizeof (*vfio_res),0 );if (vfio_res ==NULL ) {
@@ -510,10 +514,14 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev) } ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* map MMIO regions */ maps = vfio_res->maps;
drivers/bus/pci/linux/pci_vfio.c +14 -4
@@ -753,10 +753,14 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev) loc->domain, loc->bus, loc->devid, loc->function); ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd)) goto err_vfio_dev_fd;
@@ -962,10 +966,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) } ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; + ret =pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info);if (ret) goto err_vfio_dev_fd;
@@ -1195,12 +1203,14 @@ pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,if (vfio_dev_fd <0 ) {return -1 ; }else if (vfio_dev_fd ==0 ) { -if (rte_vfio_get_device_info (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info) !=0 ) +if (rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, + &vfio_dev_fd) !=0 )return -1 ;/* save vfio_dev_fd so it can be used during release */ if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd) !=0 )return -1 ; +if (rte_vfio_get_device_info (vfio_dev_fd, &device_info) !=0 ) +return -1 ;if (pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info) !=0 )return -1 ;
drivers/bus/platform/platform.c +8 -1
@@ -292,12 +292,19 @@ device_setup(struct rte_platform_device *pdev)const char *name = pdev->name;int ret; - ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd, &dev_info); + ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd);if (ret) {PLATFORM_LOG_LINE (ERR ,"failed to setup %s" , name);return -ENODEV ; } + ret =rte_vfio_get_device_info (pdev->dev_fd, &dev_info); +if (ret) { +PLATFORM_LOG_LINE (ERR ,"failed to get device info for %s" , name); + ret = -ENODEV ; + goto out; + } +/* This is an extra check to confirm that platform device was initialized * by a kernel vfio-platform driver. On kernels that predate vfio-platform * driver this flag obviously does not exist. In such scenarios this
drivers/crypto/bcmfs/bcmfs_vfio.c +7 -1
@@ -25,12 +25,18 @@ vfio_map_dev_obj(const char *path, const char *dev_obj,struct vfio_device_info d_info = { .argsz =sizeof (d_info) };struct vfio_region_info reg_info = { .argsz =sizeof (reg_info) }; - ret =rte_vfio_setup_device (path, dev_obj, dev_fd, &d_info); + ret =rte_vfio_setup_device (path, dev_obj, dev_fd);if (ret) {BCMFS_LOG (ERR ,"VFIO Setting for device failed" );return ret; } + ret =rte_vfio_get_device_info (*dev_fd, &d_info); +if (ret) { +BCMFS_LOG (ERR ,"VFIO Getting device info failed" ); + goto map_failed; + } +/* getting device region info*/ ret =ioctl (*dev_fd,VFIO_DEVICE_GET_REGION_INFO , ®_info);if (ret <0 ) {
lib/eal/freebsd/eal.c +1 -2
@@ -822,8 +822,7 @@ rte_eal_vfio_get_vf_token(__rte_unused rte_uuid_t vf_token)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, - __rte_unused int *vfio_dev_fd, - __rte_unused struct vfio_device_info *device_info) + __rte_unused int *vfio_dev_fd) { rte_errno =ENOTSUP ;return -1 ;
lib/eal/include/rte_vfio.h +8 -15
@@ -55,10 +55,7 @@ struct vfio_device_info;* device location. * * @param vfio_dev_fd -* VFIO fd. -* -* @param device_info -* Device information. +* Pointer to VFIO fd, will be set to the opened device fd on success. * * @return * 0 on success.
@@ -67,7 +64,7 @@ struct vfio_device_info;*/ __rte_internal int rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +int *vfio_dev_fd);/** * @internal
@@ -187,19 +184,16 @@ rte_vfio_get_group_num(const char *sysfs_base,* @internal * Get device information. * +* This function retrieves VFIO device information from an already opened +* device. The device must be opened with rte_vfio_setup_device() first. +* * This function is only relevant to Linux and will return an error on BSD. * -* @param sysfs_base -* sysfs path prefix. -* -* @param dev_addr -* device location. -* * @param vfio_dev_fd -* VFIO fd. +* VFIO device fd (must be a valid, already opened fd). * * @param device_info -* Device information. +* Pointer to device information structure to be filled. * * @return * 0 on success.
@@ -207,8 +201,7 @@ rte_vfio_get_group_num(const char *sysfs_base,*/ __rte_internal int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info);/** * @internal
lib/eal/linux/eal_vfio.c +11 -29
@@ -758,7 +758,7 @@ rte_vfio_clear_group(int vfio_group_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) intrte_vfio_setup_device (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +int *vfio_dev_fd) {struct vfio_group_status group_status = { .argsz =sizeof (group_status)
@@ -975,7 +975,7 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, *vfio_dev_fd =ioctl (vfio_group_fd,VFIO_GROUP_GET_DEVICE_FD , dev);if (*vfio_dev_fd >=0 ) - goto dev_get_info; + goto out; }/* get a file descriptor for the device */
@@ -992,18 +992,8 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,return -1 ; } -/* test and setup the device */ -dev_get_info: - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, " -"error %i (%s)" , dev_addr, errno, -strerror (errno)); -close (*vfio_dev_fd); -close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); -return -1 ; - } +/* device is now set up */ +out:vfio_group_device_get (vfio_group_fd);return 0 ;
@@ -1217,26 +1207,18 @@ vfio_set_iommu_type(int vfio_container_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info) {int ret; -if (device_info ==NULL || *vfio_dev_fd <0 ) +if (device_info ==NULL || vfio_dev_fd <0 )return -1 ; -if (*vfio_dev_fd ==0 ) { - ret =rte_vfio_setup_device (sysfs_base, dev_addr, - vfio_dev_fd, device_info); -if (ret) -return -1 ; - }else { - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, error %i (%s)" , - dev_addr, errno,strerror (errno)); -return -1 ; - } + ret =ioctl (vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); +if (ret) { +EAL_LOG (ERR ,"Cannot get device info, error %i (%s)" , + errno,strerror (errno)); +return -1 ; }return 0 ;
Signature · 1 line
2.52.0
PATCH v11 5/20 vfio: add container device assignment API
In reply to Anatoly BurakovCurrently, VFIO has explicit group bind API's, but the way they're used is such that no one actually cares about VFIO groups, and the real goal of everyone using VFIO group bind API is to bind devices to particular VFIO container, such that when rte_vfio_setup_device call eventually comes, VFIO will pick up the correct container.
To remove dependency on group API's, add a new "container assign device" API call that will do the same thing, but will not depend on managing VFIO group fd's.
--- lib/eal/freebsd/eal.c | 10 ++++++++++ lib/eal/include/rte_vfio.h | 26 ++++++++++++++++++++++++++ lib/eal/linux/eal_vfio.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+)
lib/eal/freebsd/eal.c +10 -0
@@ -944,3 +944,13 @@ rte_vfio_container_dma_unmap(__rte_unused int container_fd, rte_errno =ENOTSUP ;return -1 ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device(__rte_unused int vfio_container_fd, + __rte_unused const char *sysfs_base, + __rte_unused const char *dev_addr) +{ + rte_errno =ENOTSUP ; +return -1 ; +}
lib/eal/include/rte_vfio.h +26 -0
@@ -271,6 +271,32 @@ __rte_internalint rte_vfio_container_destroy (int container_fd); +/** +* @internal +* +* Assign a device to a VFIO container. +* +* Doing so will cause `rte_vfio_setup_device()` to set up the device with the VFIO container +* specified in this assign operation. +* +* This function is only relevant on Linux. +* +* @param vfio_container_fd +* VFIO container file descriptor. +* @param sysfs_base +* Sysfs path prefix. +* @param dev_addr +* Device identifier. +* +* @return +* 0 on success. +* <0 on failure. +*/ +__rte_internal +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr); +/** * @internal * Bind a IOMMU group to a container.
lib/eal/linux/eal_vfio.c +32 -0
@@ -2102,6 +2102,38 @@ rte_vfio_container_destroy(int container_fd)return 0 ; } +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr) +{ +int iommu_group_num; +int ret; + + ret =rte_vfio_get_group_num (sysfs_base, dev_addr, &iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR ,"Cannot get IOMMU group number for device %s" , + dev_addr); +return -1 ; + }else if (ret ==0 ) { +EAL_LOG (ERR , +"Device %s is not assigned to any IOMMU group" , + dev_addr); +return -1 ; + } + + ret =rte_vfio_container_group_bind (vfio_container_fd, + iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR , +"Cannot bind IOMMU group %d for device %s" , + iommu_group_num, dev_addr); +return -1 ; + } + +return 0 ; +} +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) intrte_vfio_container_group_bind (int container_fd,int iommu_group_num)
Signature · 1 line
2.52.0
PATCH v11 6/20 net/nbl: do not use VFIO group bind API
In reply to Anatoly BurakovThe NBL driver currently uses group bind API, but it is using it only to get group fd and nothing else. In context of NBL driver, this is the only usage of VFIO API's in the driver, and it is not necessary to use it for what NBL driver is trying to accomplish.
Use a direct open() call instead, and store the group fd in common structure.
--- drivers/net/nbl/nbl_common/nbl_userdev.c | 20 +++++++++++++------- drivers/net/nbl/nbl_include/nbl_include.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-)
drivers/net/nbl/nbl_common/nbl_userdev.c +13 -7
@@ -387,6 +387,15 @@ nbl_userdev_mem_event_callback(enum rte_mem_event type, const void *addr, size_t } } +static int +nbl_open_group_fd (int iommu_group_num) +{ +char path[PATH_MAX ]; + +snprintf (path,sizeof (path),RTE_VFIO_GROUP_FMT , iommu_group_num); +return open (path,O_RDWR ); +} +static int nbl_mdev_map_device (struct nbl_adapter *adapter) {const struct rte_pci_device *pci_dev = adapter->pci_dev;
@@ -424,11 +433,12 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) }NBL_LOG (DEBUG ,"nbl vfio container %d" , container); - vfio_group_fd =rte_vfio_container_group_bind (container, common->iommu_group_num); + vfio_group_fd =nbl_open_group_fd (common->iommu_group_num);if (vfio_group_fd <0 ) {NBL_LOG (ERR ,"nbl vfio group bind failed, %d" , vfio_group_fd); goto free_container; } + common->groupfd = vfio_group_fd;/* check if the group is viable */ ret =ioctl (vfio_group_fd,VFIO_GROUP_GET_STATUS , &group_status);
@@ -535,7 +545,6 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) } free_group:close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); free_container:if (container_create)rte_vfio_container_destroy (container);
@@ -549,17 +558,14 @@ static int nbl_mdev_unmap_device(struct nbl_adapter *adapter)close (common->devfd);rte_mcfg_mem_read_lock (); - vfio_group_fd =rte_vfio_container_group_bind (nbl_default_container, - common->iommu_group_num); + vfio_group_fd = common->groupfd;NBL_LOG (DEBUG ,"close vfio_group_fd %d" , vfio_group_fd); ret =ioctl (vfio_group_fd,VFIO_GROUP_UNSET_CONTAINER , &nbl_default_container);if (ret)NBL_LOG (ERR ,"unset container, error %i (%s) %d" , errno,strerror (errno), ret); nbl_group_count--; - ret =rte_vfio_container_group_unbind (nbl_default_container, common->iommu_group_num); -if (ret) -NBL_LOG (ERR ,"vfio container group unbind failed %d" , ret); +close (vfio_group_fd);if (!nbl_group_count) {rte_mem_event_callback_unregister (NBL_USERDEV_EVENT_CLB_NAME ,NULL );nbl_userdev_dma_free ();
drivers/net/nbl/nbl_include/nbl_include.h +1 -0
@@ -132,6 +132,7 @@ struct nbl_common_info {u16 vsi_id;u16 instance_id;int devfd; +int groupfd;int eventfd;int ifindex;int iommu_group_num;
Signature · 1 line
2.52.0
PATCH v11 7/20 net/ntnic: use container device assignment API
In reply to Anatoly BurakovThe NTNIC driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/net/ntnic/ntnic_vfio.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-)
drivers/net/ntnic/ntnic_vfio.c +9 -21
@@ -28,7 +28,6 @@ nt_vfio_vf_num(const struct rte_pci_device *pdev)/* Internal API */ struct vfio_dev {int container_fd; -int group_fd;int dev_fd;uint64_t iova_addr; };
@@ -50,7 +49,6 @@ nthw_vfio_setup(struct rte_pci_device *dev) {int ret;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num;int vf_num;struct vfio_dev *vfio;
@@ -66,14 +64,9 @@ nthw_vfio_setup(struct rte_pci_device *dev) } vfio->dev_fd =-1 ; - vfio->group_fd =-1 ; vfio->iova_addr =START_VF_IOVA ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, &iommu_group_num); -if (ret <=0 ) -return -1 ; -if (vf_num ==0 ) {/* use default container for pf0 */ vfio->container_fd =RTE_VFIO_DEFAULT_CONTAINER_FD ;
@@ -86,17 +79,14 @@ nthw_vfio_setup(struct rte_pci_device *dev) "VFIO device setup failed. VFIO container creation failed.");return -1 ; } - } + ret =rte_vfio_container_assign_device (vfio->container_fd, +rte_pci_get_sysfs_path (), devname); +if (ret <0 ) { +NT_LOG (ERR ,NTNIC , +"VFIO device setup failed. Assign device to container failed." ); + goto err; + } - vfio->group_fd =rte_vfio_container_group_bind (vfio->container_fd, iommu_group_num); - -if (vfio->group_fd <0 ) { -NT_LOG (ERR ,NTNIC , -"VFIO device setup failed. VFIO container group bind failed." ); - goto err; - } - -if (vf_num >0 ) {if (rte_pci_map_device (dev)) {NT_LOG (ERR ,NTNIC ,"Map VFIO device failed. is the vfio-pci driver loaded?" );
@@ -106,10 +96,8 @@ nthw_vfio_setup(struct rte_pci_device *dev) vfio->dev_fd =rte_intr_dev_fd_get (dev->intr_handle); -NT_LOG (DBG ,NTNIC , -"%s: VFIO id=%d, dev_fd=%d, container_fd=%d, group_fd=%d, iommu_group_num=%d" , - dev->name, vf_num, vfio->dev_fd, vfio->container_fd, vfio->group_fd, - iommu_group_num); +NT_LOG (DBG ,NTNIC ,"%s: VFIO id=%d, dev_fd=%d, container_fd=%d" , + dev->name, vf_num, vfio->dev_fd, vfio->container_fd);return vf_num;
Signature · 1 line
2.52.0
PATCH v11 8/20 vdpa/ifc: use container device assignment API
In reply to Anatoly BurakovThe IFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-)
drivers/vdpa/ifc/ifcvf_vdpa.c +3 -31
@@ -58,7 +58,6 @@ struct ifcvf_internal {struct ifcvf_hw hw;int configured;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd;rte_thread_t tid;/* thread for notify relay */ rte_thread_t intr_tid;/* thread for config space change interrupt relay */
@@ -174,28 +173,19 @@ ifcvf_vfio_setup(struct ifcvf_internal *internal) {struct rte_pci_device *dev = internal->pdev;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num; -int i, ret; +int i; internal->vfio_dev_fd =-1 ; - internal->vfio_group_fd =-1 ; internal->vfio_container_fd =-1 ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, - &iommu_group_num); -if (ret <=0 ) { -DRV_LOG (ERR ,"%s failed to get IOMMU group" , devname); -return -1 ; - } internal->vfio_container_fd =rte_vfio_container_create ();if (internal->vfio_container_fd <0 )return -1 ; - internal->vfio_group_fd =rte_vfio_container_group_bind ( - internal->vfio_container_fd, iommu_group_num); -if (internal->vfio_group_fd <0 ) +if (rte_vfio_container_assign_device (internal->vfio_container_fd, +rte_pci_get_sysfs_path (), devname) <0 ) goto err;if (rte_pci_map_device (dev))
@@ -1213,22 +1203,6 @@ ifcvf_set_features(int vid)return 0 ; } -static int -ifcvf_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct internal_list *list; - - vdev =rte_vhost_get_vdpa_device (vid); - list =find_internal_resource_by_vdev (vdev); -if (list ==NULL ) { -DRV_LOG (ERR ,"Invalid vDPA device: %p" , vdev); -return -1 ; - } - -return list->internal->vfio_group_fd; -} -static int ifcvf_get_vfio_device_fd (int vid) {
@@ -1474,7 +1448,6 @@ static struct rte_vdpa_dev_ops ifcvf_net_ops = { .set_vring_state = ifcvf_set_vring_state, .set_features = ifcvf_set_features, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_dev_type = ifcvf_get_device_type,
@@ -1605,7 +1578,6 @@ static struct rte_vdpa_dev_ops ifcvf_blk_ops = { .dev_close = ifcvf_dev_close, .set_vring_state = ifcvf_set_vring_state, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_config = ifcvf_blk_get_config,
Signature · 1 line
2.52.0
PATCH v11 9/20 vdpa/nfp: use container device assignment API
In reply to Anatoly BurakovThe NFP vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/nfp/nfp_vdpa.c | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-)
drivers/vdpa/nfp/nfp_vdpa.c +5 -32
@@ -36,9 +36,7 @@ struct nfp_vdpa_dev {struct nfp_vdpa_hw hw;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd; -int iommu_group;rte_thread_t tid;/**< Thread for notify relay */ int epoll_fd;
@@ -120,33 +118,26 @@ nfp_vdpa_vfio_setup(struct nfp_vdpa_dev *device)struct rte_pci_device *pci_dev = device->pci_dev;rte_pci_device_name (&pci_dev->addr, dev_name,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &device->iommu_group); -if (ret <=0 ) -return -1 ; device->vfio_container_fd =rte_vfio_container_create ();if (device->vfio_container_fd <0 )return -1 ; - device->vfio_group_fd =rte_vfio_container_group_bind ( - device->vfio_container_fd, device->iommu_group); -if (device->vfio_group_fd <0 ) + ret =rte_vfio_container_assign_device (device->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (ret <0 ) goto container_destroy; -DRV_VDPA_LOG (DEBUG ,"The container_fd=%d, group_fd=%d." , - device->vfio_container_fd, device->vfio_group_fd); +DRV_VDPA_LOG (DEBUG ,"container_fd=%d" , device->vfio_container_fd); ret =rte_pci_map_device (pci_dev);if (ret !=0 ) - goto group_unbind; + goto container_destroy; device->vfio_dev_fd =rte_intr_dev_fd_get (pci_dev->intr_handle);return 0 ; -group_unbind: -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group); container_destroy:rte_vfio_container_destroy (device->vfio_container_fd);
@@ -157,7 +148,6 @@ static void nfp_vdpa_vfio_teardown(struct nfp_vdpa_dev *device) {rte_pci_unmap_device (device->pci_dev); -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group);rte_vfio_container_destroy (device->vfio_container_fd); }
@@ -1023,22 +1013,6 @@ nfp_vdpa_dev_close(int vid)return 0 ; } -static int -nfp_vdpa_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct nfp_vdpa_dev_node *node; - - vdev =rte_vhost_get_vdpa_device (vid); - node =nfp_vdpa_find_node_by_vdev (vdev); -if (node ==NULL ) { -DRV_VDPA_LOG (ERR ,"Invalid vDPA device: %p." , vdev); -return -ENODEV ; - } - -return node->device->vfio_group_fd; -} -static int nfp_vdpa_get_vfio_device_fd (int vid) {
@@ -1190,7 +1164,6 @@ struct rte_vdpa_dev_ops nfp_vdpa_ops = { .dev_close = nfp_vdpa_dev_close, .set_vring_state = nfp_vdpa_set_vring_state, .set_features = nfp_vdpa_set_features, - .get_vfio_group_fd = nfp_vdpa_get_vfio_group_fd, .get_vfio_device_fd = nfp_vdpa_get_vfio_device_fd, .get_notify_area = nfp_vdpa_get_notify_area, };
Signature · 1 line
2.52.0
PATCH v11 10/20 vdpa/sfc: use container device assignment API
In reply to Anatoly BurakovThe SFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/vdpa/sfc/sfc_vdpa.c | 39 +++++++------------------------------ drivers/vdpa/sfc/sfc_vdpa.h | 2 -- 2 files changed, 7 insertions(+), 34 deletions(-)
drivers/vdpa/sfc/sfc_vdpa.c +7 -32
@@ -80,22 +80,12 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva) goto fail_container_create; } - rc =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &sva->iommu_group_num); -if (rc <=0 ) { -sfc_vdpa_err (sva,"failed to get IOMMU group for %s : %s" , - dev_name,rte_strerror (-rc)); - goto fail_get_group_num; - } - - sva->vfio_group_fd = -rte_vfio_container_group_bind (sva->vfio_container_fd, - sva->iommu_group_num); -if (sva->vfio_group_fd <0 ) { -sfc_vdpa_err (sva, -"failed to bind IOMMU group %d to container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - goto fail_group_bind; + rc =rte_vfio_container_assign_device (sva->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (rc <0 ) { +sfc_vdpa_err (sva,"failed to assign device %s to container %d" , + dev_name, sva->vfio_container_fd); + goto fail_device_assign; }if (rte_pci_map_device (dev) !=0 ) {
@@ -109,15 +99,7 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva)return 0 ; fail_pci_map_device: -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } - -fail_group_bind: -fail_get_group_num: +fail_device_assign:if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) {sfc_vdpa_err (sva,"failed to destroy container %d" , sva->vfio_container_fd);
@@ -132,13 +114,6 @@ sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter *sva) {rte_pci_unmap_device (sva->pdev); -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } -if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) { sfc_vdpa_err(sva, "failed to destroy container %d",
drivers/vdpa/sfc/sfc_vdpa.h +0 -2
@@ -70,10 +70,8 @@ struct sfc_vdpa_adapter {sfc_vdpa_filter_t filters; -int vfio_group_fd;int vfio_dev_fd;int vfio_container_fd; -int iommu_group_num;struct sfc_vdpa_ops_data *ops_data; };
Signature · 1 line
2.52.0
PATCH v11 11/20 vdpa/mlx5: remove group-related API
In reply to Anatoly BurakovThe mlx5 driver does not use the get_group_fd API provided by vDPA. This API is about to be removed, so remove its mention from mlx5.
--- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - 1 file changed, 1 deletion(-)
drivers/vdpa/mlx5/mlx5_vdpa.c +0 -1
@@ -523,7 +523,6 @@ static struct rte_vdpa_dev_ops mlx5_vdpa_ops = { .set_vring_state = mlx5_vdpa_set_vring_state, .set_features = mlx5_vdpa_features_set, .migration_done = NULL, - .get_vfio_group_fd = NULL, .get_vfio_device_fd = mlx5_vdpa_get_device_fd, .get_notify_area = mlx5_vdpa_get_notify_area, .get_stats_names = mlx5_vdpa_get_stats_names,
Signature · 1 line
2.52.0
PATCH v11 12/20 vhost: remove group-related API from driver
In reply to Anatoly BurakovThe vDPA driver API has "get_vfio_group_fd" in its ops structure, but no driver is using it any more, as better API's were added and implemented. Remove this API from vDPA ops structure.
--- doc/guides/prog_guide/vhost_lib.rst | 4 ---- doc/guides/rel_notes/deprecation.rst | 4 ---- lib/vhost/vdpa_driver.h | 3 --- 3 files changed, 11 deletions(-)
doc/guides/prog_guide/vhost_lib.rst +0 -4
@@ -471,10 +471,6 @@ Finally, a set of device ops is defined for device specific operations: Called to allow the device to respond to RARP sending. -* ``get_vfio_group_fd`` - - Called to get the VFIO group fd of the device. - * ``get_vfio_device_fd`` Called to get the VFIO device fd of the device.
doc/guides/rel_notes/deprecation.rst +0 -4
@@ -29,10 +29,6 @@ Deprecation Notices Use the ``-S <service-corelist>`` parameter instead to specify the cores to be used for background services in DPDK. -* vdpa: The vDPA driver API will no longer offer ``get_vfio_group_fd`` - as part of its internal API. All drivers will be adjusted - to use the new unified VFIO container device assignment API. - * rte_atomicNN_xxx: These APIs do not take memory order parameter. This does not allow for writing optimized code for all the CPU architectures supported in DPDK. DPDK has adopted the atomic operations from
lib/vhost/vdpa_driver.h +0 -3
@@ -50,9 +50,6 @@ struct rte_vdpa_dev_ops {/** Destination operations when migration done */ int (*migration_done)(int vid); -/** Get the vfio group fd */ -int (*get_vfio_group_fd)(int vid); -/** Get the vfio device fd */ int (*get_vfio_device_fd)(int vid);
Signature · 1 line
2.52.0
PATCH v11 13/20 vfio: remove group-based API
In reply to Anatoly BurakovAll drivers have been adjusted to not use the VFIO group API directly and instead rely on container device assignment model, so the group API is no longer useful and can be removed.
--- lib/eal/freebsd/eal.c | 33 --------------- lib/eal/include/rte_vfio.h | 72 -------------------------------- lib/eal/linux/eal_vfio.c | 47 ++++++++++----------- lib/eal/linux/eal_vfio.h | 2 + lib/eal/linux/eal_vfio_mp_sync.c | 2 +- 5 files changed, 26 insertions(+), 130 deletions(-)
lib/eal/freebsd/eal.c +0 -33
@@ -856,13 +856,6 @@ int rte_vfio_noiommu_is_enabled(void)return 0 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) -int rte_vfio_clear_group(__rte_unused int vfio_group_fd) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base,
@@ -881,14 +874,6 @@ rte_vfio_get_container_fd(void)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) -int -rte_vfio_get_group_fd(__rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void )
@@ -905,24 +890,6 @@ rte_vfio_container_destroy(__rte_unused int container_fd)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) -int -rte_vfio_container_group_bind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) -int -rte_vfio_container_group_unbind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd,
lib/eal/include/rte_vfio.h +0 -72
90 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +23 -24
151 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +2 -0
@@ -51,6 +51,8 @@ vfio_set_iommu_type(int vfio_container_fd);int vfio_get_iommu_type (void ); +int vfio_get_group_fd_by_num (int iommu_group_num); +/* check if we have any supported extensions */ int vfio_has_supported_extensions (int vfio_container_fd);
lib/eal/linux/eal_vfio_mp_sync.c +1 -1
@@ -34,7 +34,7 @@ vfio_mp_primary(const struct rte_mp_msg *msg, const void *peer)case SOCKET_REQ_GROUP : r->req =SOCKET_REQ_GROUP ; r->group_num = m->group_num; - fd =rte_vfio_get_group_fd (m->group_num); + fd =vfio_get_group_fd_by_num (m->group_num);if (fd <0 && fd != -ENOENT ) r->result =SOCKET_ERR ;else if (fd == -ENOENT )
Signature · 1 line
2.52.0
PATCH v11 14/20 vfio: cleanup and refactor
In reply to Anatoly BurakovCurrently, VFIO code is a bit of an incoherent mess internally, with API's bleeding into each other, inconsistent returns, and a certain amount of spaghetti stemming from organic growth.
Refactor VFIO code to achieve the following goals:
- Make all error handling consistent, and provide/document rte_errno values returned from API's to indicate various conditions.
- Introduce new "VFIO mode" concept. This new API will tell caller if VFIO is enabled, and whether it is using group API, and whether it is running in no-IOMMU mode.
- Decouple rte_vfio_setup_device semantics from PCI bus return convention. Currently, when device is not managed by VFIO, rte_vfio_setup_device will return 1, which is bus speak for "skip this device", however VFIO has nothing to do with PCI bus and should not follow its API conventions.
- Perform device setup in device assign, and make device setup use shared code path with device assign and explicitly assuming default container. This is technically not necessary for group mode as device set up is a two-step process in that mode, but coming cdev mode will have a single-step device setup, and it would be easier if the worked the same way under the hood.
- Make VFIO internals more readable. Introduce a lot of infrastructure and more explicit validation, rather than over-reliance on sentinel values and implicit assumptions. This will also make it easier to integrate cdev mode down the line, as it will rely on most of this infrastructure.
This will change behavior of the following functions:
- rte_vfio_setup_device - when the device is not managed by VFIO, the function will now return -1 with rte_errno set to ENODEV
- rte_vfio_get_group_num - when the device is not managed by VFIO, the function will now return -1 with rte_errno set to ENODEV
- rte_vfio_container_destroy - the function will now release and close all group and device resources associated with the container being destroyed by this call
All users of rte_vfio_setup_device and rte_vfio_get_group_num have been adjusted to account for API change.
--- config/arm/meson.build | 1 + config/meson.build | 1 + drivers/bus/cdx/cdx_vfio.c | 17 +- drivers/bus/fslmc/fslmc_vfio.c | 4 +- drivers/bus/pci/linux/pci_vfio.c | 19 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 6 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 2 +- lib/eal/freebsd/eal.c | 16 + lib/eal/include/rte_vfio.h | 252 ++- lib/eal/linux/eal_vfio.c | 2264 +++++++--------------- lib/eal/linux/eal_vfio.h | 143 +- lib/eal/linux/eal_vfio_group.c | 983 ++++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 38 +- lib/eal/linux/meson.build | 1 + 14 files changed, 2104 insertions(+), 1643 deletions(-) create mode 100644 lib/eal/linux/eal_vfio_group.c
config/arm/meson.build +1 -0
@@ -147,6 +147,7 @@ implementer_cavium = { 'description': 'Cavium', 'flags': [ ['RTE_MAX_VFIO_GROUPS', 128], + ['RTE_MAX_VFIO_DEVICES', 256], ['RTE_MAX_LCORE', 96], ['RTE_MAX_NUMA_NODES', 2] ],
config/meson.build +1 -0
@@ -387,6 +387,7 @@ dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp')) dpdk_conf.set('RTE_PKTMBUF_HEADROOM', get_option('pkt_mbuf_headroom')) # values which have defaults which may be overridden dpdk_conf.set('RTE_MAX_VFIO_GROUPS', 64) +dpdk_conf.set('RTE_MAX_VFIO_DEVICES', 256) dpdk_conf.set('RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB', 64) dpdk_conf.set('RTE_LIBRTE_DPAA2_USE_PHYS_IOVA', true) if get_option('mbuf_refcnt_atomic')
drivers/bus/cdx/cdx_vfio.c +12 -5
@@ -22,6 +22,7 @@#include <eal_export.h> #include <rte_eal_paging.h> +#include <rte_errno.h> #include <rte_malloc.h> #include <rte_vfio.h>
@@ -402,8 +403,12 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev) ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, &vfio_dev_fd); -if (ret) +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
@@ -513,11 +518,13 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev)return -1 ; } - ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; - + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret) goto err_vfio_dev_fd;
drivers/bus/fslmc/fslmc_vfio.c +2 -2
@@ -364,9 +364,9 @@ fslmc_get_group_id(const char *group_name,/* get group number */ ret =rte_vfio_get_group_num (SYSFS_FSL_MC_DEVICES , group_name, groupid); -if (ret <=0 ) { +if (ret <0 ) {DPAA2_BUS_ERR ("Find %s IOMMU group" , group_name); -if (ret <0 ) +if (rte_errno !=ENODEV )return ret;return -EIO ;
drivers/bus/pci/linux/pci_vfio.c +13 -6
@@ -20,6 +20,7 @@#include <rte_malloc.h> #include <rte_vfio.h> #include <rte_eal.h> +#include <rte_errno.h> #include <bus_driver.h> #include <rte_spinlock.h> #include <rte_tailq.h>
@@ -752,10 +753,13 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev)snprintf (pci_addr,sizeof (pci_addr),PCI_PRI_FMT , loc->domain, loc->bus, loc->devid, loc->function); - ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
@@ -965,10 +969,13 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)return -1 ; } - ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd); -if (ret) + ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, &vfio_dev_fd); +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;return ret; + } ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info);if (ret)
drivers/crypto/bcmfs/bcmfs_vfio.c +5 -1
@@ -9,6 +9,7 @@#include <sys/mman.h> #include <sys/ioctl.h> +#include <rte_errno.h> #include <rte_vfio.h> #include "bcmfs_device.h"
@@ -26,7 +27,10 @@ vfio_map_dev_obj(const char *path, const char *dev_obj,struct vfio_region_info reg_info = { .argsz =sizeof (reg_info) }; ret =rte_vfio_setup_device (path, dev_obj, dev_fd); -if (ret) { +if (ret <0 ) { +/* Device not managed by VFIO - skip */ +if (rte_errno ==ENODEV ) + ret =1 ;BCMFS_LOG (ERR ,"VFIO Setting for device failed" );return ret; }
drivers/net/nbl/nbl_common/nbl_userdev.c +1 -1
@@ -415,7 +415,7 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) "%s/%s/", rte_pci_get_sysfs_path(), dev_name); ret =rte_vfio_get_group_num (pathname, dev_name, &common->iommu_group_num); -if (ret <=0 ) { +if (ret <0 ) {NBL_LOG (ERR ,"nbl vfio group number failed" );return -1 ; }
lib/eal/freebsd/eal.c +16 -0
@@ -921,3 +921,19 @@ rte_vfio_container_assign_device(__rte_unused int vfio_container_fd, rte_errno =ENOTSUP ;return -1 ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) +int +rte_vfio_get_device_info(__rte_unused int vfio_dev_fd, + __rte_unused struct vfio_device_info *device_info) +{ + rte_errno =ENOTSUP ; +return -1 ; +} + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_mode) +enum rte_vfio_mode +rte_vfio_get_mode (void ) +{ +return RTE_VFIO_MODE_NONE ; +}
lib/eal/include/rte_vfio.h +171 -81
417 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +745 -1519
2,437 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +123 -20
143 lines not on this page · raw message
lib/eal/linux/eal_vfio_group.c new file +983 -0
983 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.52.0
Part of the diff is not shown here. View the raw message.
PATCH v11 15/20 bus/pci: use the new VFIO mode API
In reply to Anatoly BurakovUse the new VFIO mode API to query no-IOMMU status. This requires moving the VFIO init earlier in the init sequence, as now checking no-IOMMU mode is not a sysfs check but instead relies on full VFIO subsystem to be initialized and available.
--- drivers/bus/pci/linux/pci.c | 2 +- lib/eal/linux/eal.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-)
drivers/bus/pci/linux/pci.c +1 -1
@@ -596,7 +596,7 @@ pci_device_iova_mode(const struct rte_pci_driver *pdrv,static int is_vfio_noiommu_enabled =-1 ;if (is_vfio_noiommu_enabled ==-1 ) { -if (rte_vfio_noiommu_is_enabled () ==1 ) +if (rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ) is_vfio_noiommu_enabled =1 ;else is_vfio_noiommu_enabled =0 ;
lib/eal/linux/eal.c +10 -5
@@ -677,6 +677,16 @@ rte_eal_init(int argc, char **argv) } } +/* +* VFIO must be initialized before bus scan because buses need to know +* about no-IOMMU mode status. +*/ +if (rte_vfio_enable ("vfio" )) { +rte_eal_init_alert ("Cannot init VFIO" ); + rte_errno =EAGAIN ; + goto err_out; + } +if (rte_bus_scan ()) {rte_eal_init_alert ("Cannot scan the buses for devices" ); rte_errno =ENODEV ;
@@ -772,11 +782,6 @@ rte_eal_init(int argc, char **argv)#endif } -if (rte_vfio_enable ("vfio" )) { -rte_eal_init_alert ("Cannot init VFIO" ); - rte_errno =EAGAIN ; - goto err_out; - }/* in secondary processes, memory init may allocate additional fbarrays * not present in primary processes, so to avoid any potential issues, * initialize memzones first.
Signature · 1 line
2.52.0
PATCH v11 16/20 bus/fslmc: use the new VFIO mode API
In reply to Anatoly BurakovFSLMC bus only supports operating in group mode, and relies on no-IOMMU mode checks. Use the new VFIO API's to query no-IOMMU status, as well as protect the bus from initializing in non-group mode.
--- drivers/bus/fslmc/fslmc_bus.c | 11 ++++++++++- drivers/bus/fslmc/fslmc_vfio.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-)
drivers/bus/fslmc/fslmc_bus.c +10 -1
@@ -332,6 +332,14 @@ rte_fslmc_scan(void) goto scan_fail; } +/* for container groups to work, VFIO must be in group mode */ +if (rte_vfio_get_mode () !=RTE_VFIO_MODE_GROUP && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU ) { +DPAA2_BUS_DEBUG ("DPAA2: VFIO not in group mode" ); + ret = -EINVAL ; + goto scan_fail; + } + ret =fslmc_get_container_group (group_name, &groupid);if (ret !=0 ) goto scan_fail;
@@ -500,7 +508,8 @@ rte_dpaa2_get_iommu_class(void)return RTE_IOVA_DC ;/* check if all devices on the bus support Virtual addressing or not */ -if (fslmc_all_device_support_iova () !=0 &&rte_vfio_noiommu_is_enabled () ==0 ) +if (fslmc_all_device_support_iova () !=0 && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU )return RTE_IOVA_VA ;return RTE_IOVA_PA ;
drivers/bus/fslmc/fslmc_vfio.c +1 -1
@@ -192,7 +192,7 @@ fslmc_vfio_add_group(int vfio_group_fd, group->fd = vfio_group_fd; group->groupid = iommu_group_num;rte_strscpy (group->group_name, group_name,sizeof (group->group_name)); -if (rte_vfio_noiommu_is_enabled () >0 ) +if (rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ) group->iommu_type =VFIO_NOIOMMU_IOMMU ;else group->iommu_type =VFIO_TYPE1_IOMMU ;
Signature · 1 line
2.52.0
PATCH v11 17/20 net/hinic3: use the new VFIO mode API
In reply to Anatoly BurakovUse new VFIO mode API to query no-IOMMU status.
--- drivers/net/hinic3/base/hinic3_hwdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/hinic3/base/hinic3_hwdev.c +2 -1
@@ -78,7 +78,8 @@ hinic3_is_vfio_iommu_enable(const struct rte_eth_dev *eth_dev) {struct rte_pci_device *pci_dev =RTE_CLASS_TO_BUS_DEVICE (eth_dev, *pci_dev); -return pci_dev->kdrv ==RTE_PCI_KDRV_VFIO &&rte_vfio_noiommu_is_enabled () !=1 ; +return pci_dev->kdrv ==RTE_PCI_KDRV_VFIO && +rte_vfio_get_mode () !=RTE_VFIO_MODE_NOIOMMU ; }int
Signature · 1 line
2.52.0
PATCH v11 18/20 net/ntnic: use the new VFIO mode API
In reply to Anatoly BurakovUse new VFIO mode API to query no-IOMMU status.
--- drivers/net/ntnic/ntnic_ethdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ntnic/ntnic_ethdev.c +1 -1
@@ -2690,7 +2690,7 @@ nthw_pci_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) (pci_dev->device.devargs->data ? pci_dev->device.devargs->data : "NULL")); } -const int n_rte_vfio_no_io_mmu_enabled =rte_vfio_noiommu_is_enabled (); +const int n_rte_vfio_no_io_mmu_enabled =rte_vfio_get_mode () ==RTE_VFIO_MODE_NOIOMMU ;NT_LOG (DBG ,NTNIC ,"vfio_no_iommu_enabled=%d" , n_rte_vfio_no_io_mmu_enabled);if (n_rte_vfio_no_io_mmu_enabled) {
Signature · 1 line
2.52.0
PATCH v11 19/20 vfio: remove no-IOMMU check API
In reply to Anatoly BurakovThe rte_vfio_noiommu_is_enabled() check has now been replaced by the new mode API, so remove it.
--- lib/eal/freebsd/eal.c | 6 ------ lib/eal/include/rte_vfio.h | 14 -------------- lib/eal/linux/eal_vfio.c | 7 ------- 3 files changed, 27 deletions(-)
lib/eal/freebsd/eal.c +0 -6
@@ -850,12 +850,6 @@ int rte_vfio_is_enabled(__rte_unused const char *modname)return 0 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) -int rte_vfio_noiommu_is_enabled(void) -{ -return 0 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base,
lib/eal/include/rte_vfio.h +0 -14
@@ -170,20 +170,6 @@ __rte_internalenum rte_vfio_mode rte_vfio_get_mode (void ); -/** -* @internal -* Check if VFIO NOIOMMU mode is enabled. -* -* This function is only relevant on Linux in group mode. -* -* @return -* 1 if enabled. -* 0 if not enabled or not supported. -*/ -__rte_internal -int -rte_vfio_noiommu_is_enabled (void ); -/** * @internal * Parse IOMMU group number for a device.
lib/eal/linux/eal_vfio.c +0 -7
@@ -1277,13 +1277,6 @@ container_dma_unmap(struct container *cfg, uint64_t vaddr, uint64_t iova,return ret; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) -int -rte_vfio_noiommu_is_enabled (void ) -{ -return vfio_cfg.mode ==RTE_VFIO_MODE_NOIOMMU ; -} -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void )
Signature · 1 line
2.52.0
PATCH v11 20/20 vfio: introduce cdev mode
In reply to Anatoly BurakovAdd support for VFIO cdev (also known as IOMMUFD) API. The group API is now considered legacy in the kernel, and all further development is expected to happen in IOMMUFD infrastructure.
The implementation largely follows the kernel reference, with most differences concentrated in how the container and the devices are set up. The VFIO container allocates an "IOAS" (IO address space), maps the memory into that space, and attaches devices to IOAS - there is no IOMMU type discovery at device attach time.
To assist any future use of VFIO cdev mode for custom behavior, also introduce "get device number" API, which is kind-of-but-not-really similar to the concept of IOMMU group.
--- lib/eal/freebsd/eal.c | 10 + lib/eal/include/rte_vfio.h | 31 +++ lib/eal/linux/eal_vfio.c | 226 +++++++++++++++++- lib/eal/linux/eal_vfio.h | 30 ++- lib/eal/linux/eal_vfio_cdev.c | 396 +++++++++++++++++++++++++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 42 ++++ lib/eal/linux/meson.build | 1 + 7 files changed, 732 insertions(+), 4 deletions(-) create mode 100644 lib/eal/linux/eal_vfio_cdev.c
lib/eal/freebsd/eal.c +10 -0
@@ -931,3 +931,13 @@ rte_vfio_get_mode(void) {return RTE_VFIO_MODE_NONE ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_num) +int +rte_vfio_get_device_num(__rte_unused const char *sysfs_base, + __rte_unused const char *dev_addr, + __rte_unused int *vfio_device_num) +{ + rte_errno =ENOTSUP ; +return -1 ; +}
lib/eal/include/rte_vfio.h +31 -0
@@ -28,6 +28,8 @@ extern "C" {#define RTE_VFIO_DIR "/dev/vfio"#define RTE_VFIO_CONTAINER_PATH "/dev/vfio/vfio" +#define RTE_VFIO_IOMMUFD_PATH "/dev/iommu" +#define RTE_VFIO_CDEV_DEVICES_PATH "/dev/vfio/devices"#define RTE_VFIO_GROUP_FMT "/dev/vfio/%u"#define RTE_VFIO_NOIOMMU_GROUP_FMT "/dev/vfio/noiommu-%u"#define RTE_VFIO_NOIOMMU_MODE "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode"
@@ -48,11 +50,13 @@ struct vfio_device_info;* - RTE_VFIO_MODE_NONE: VFIO is not enabled. * - RTE_VFIO_MODE_GROUP: Legacy group mode. * - RTE_VFIO_MODE_NOIOMMU: Unsafe no-IOMMU mode. +* - RTE_VFIO_MODE_CDEV: Character device mode. */ enum rte_vfio_mode {RTE_VFIO_MODE_NONE =0 ,/**< VFIO not enabled */ RTE_VFIO_MODE_GROUP ,/**< Group mode */ RTE_VFIO_MODE_NOIOMMU ,/**< Group mode with no IOMMU protection */ +RTE_VFIO_MODE_CDEV ,/**< Device mode */ };/**
@@ -197,6 +201,33 @@ __rte_internalint rte_vfio_get_group_num (const char *sysfs_base,const char *dev_addr,int *iommu_group_num); +/** +* @internal +* Parse VFIO cdev device number for a device. +* +* This function is only relevant on Linux in cdev mode. +* +* @param sysfs_base +* Sysfs path prefix. +* @param dev_addr +* Device identifier. +* @param vfio_device_num +* Pointer to where VFIO cdev device number will be stored. +* +* @return +* 0 on success. +* <0 on failure, rte_errno is set. +* +* Possible rte_errno values include: +* - ENODEV - Device not managed by VFIO. +* - EINVAL - Invalid parameters. +* - ENOXIO - VFIO support not initialized. +* - ENOTSUP - Unsupported VFIO mode. +*/ +__rte_internal +int +rte_vfio_get_device_num (const char *sysfs_base,const char *dev_addr,int *vfio_device_num); +/** * @internal * Get device information.
lib/eal/linux/eal_vfio.c +224 -2
302 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +28 -2
@@ -48,7 +48,10 @@ struct vfio_group {/* device tracking (common for group and cdev modes) */ struct vfio_device {bool active; -int group;/**< back-reference to group list (group mode) */ +union { +int group;/**< back-reference to group list (group mode) */ +int dev_num;/**< device number, e.g., X in /dev/vfio/devices/vfioX (cdev mode) */ + };int fd; };
@@ -61,12 +64,20 @@ struct vfio_group_config {struct vfio_group groups[RTE_MAX_VFIO_GROUPS ]; }; +/* cdev mode specific configuration */ +struct vfio_cdev_config { +uint32_t ioas_id; +}; +/* per-container configuration */ struct container {bool active;int container_fd;struct user_mem_maps mem_maps; -struct vfio_group_config group_cfg; +union { +struct vfio_group_config group_cfg; +struct vfio_cdev_config cdev_cfg; + };int n_devices;struct vfio_device devices[RTE_MAX_VFIO_DEVICES ]; };
@@ -161,12 +172,25 @@ int vfio_group_setup_iommu(struct container *cfg);int vfio_group_setup_device_fd (const char *dev_addr,struct vfio_group *grp,struct vfio_device *dev); +/* cdev mode functions */ +int vfio_cdev_enable (struct container *cfg); +void vfio_cdev_setup_ops (void ); +int vfio_cdev_setup_ioas (struct container *cfg); +int vfio_cdev_sync_ioas (struct container *cfg); +int vfio_cdev_get_iommufd (void ); +int vfio_cdev_get_device_num (const char *sysfs_base,const char *dev_addr, +int *cdev_dev_num); +struct vfio_device *vfio_cdev_get_dev_by_num (struct container *cfg,int cdev_dev_num); +int vfio_cdev_setup_device (struct container *cfg,struct vfio_device *dev); +#define VFIO_MEM_EVENT_CLB_NAME "vfio_mem_event_clb"#define EAL_VFIO_MP "eal_vfio_mp_sync"#define SOCKET_REQ_CONTAINER 0x100#define SOCKET_REQ_GROUP 0x200#define SOCKET_REQ_IOMMU_TYPE 0x400 +#define SOCKET_REQ_CDEV 0x800 +#define SOCKET_REQ_IOAS_ID 0x1000#define SOCKET_OK 0x0#define SOCKET_NO_FD 0x1#define SOCKET_ERR 0xFF
@@ -177,6 +201,8 @@ struct vfio_mp_param {union {int group_num;int iommu_type_id; +int cdev_dev_num; +int ioas_id;enum rte_vfio_mode mode; }; };
lib/eal/linux/eal_vfio_cdev.c new file +396 -0
396 lines not on this page · raw message
lib/eal/linux/eal_vfio_mp_sync.c +42 -0
48 lines not on this page · raw message
lib/eal/linux/meson.build +1 -0
@@ -16,6 +16,7 @@ sources += files( 'eal_thread.c', 'eal_timer.c', 'eal_vfio.c', + 'eal_vfio_cdev.c', 'eal_vfio_group.c', 'eal_vfio_mp_sync.c', )
Signature · 1 line
2.52.0
Quoted 181 lines · On Fri, 7 Aug 2026 15:46:09 +0100 Anatoly Burakov <[email protected]>…
This patchset introduces a major refactor of the VFIO subsystem in DPDK to support character device (cdev) interface introduced in Linux kernel, as well as make the API more streamlined and useful. The goal is to simplify device management, improve compatibility, and clarify API responsibilities.
The following sections outline the key issues addressed by this patchset and the corresponding changes introduced.
1. Only group mode is supported
===============================Since kernel version 4.14.327 (LTS), VFIO supports the new character device (cdev)-based way of working with VFIO devices (otherwise known as IOMMUFD). This is a device-centric mode and does away with all the complexity regarding groups and IOMMU types, delegating it all to the kernel, and exposes a much simpler interface to userspace.
The old group interface is still around, and will need to be kept in DPDK both for compatibility reasons, as well as supporting special cases (FSLMC bus, NBL driver, no-IOMMU mode etc.), but it is now internal-only and not exposed through the API the way it was before.
To enable this, VFIO is heavily refactored, so that the code can support both modes while relying on (mostly) common infrastructure.
Note that the existing
rte_vfio_device_setup/releasemodel is fundamentally incompatible with cdev mode, because for custom container cases, the expected flow is that the user binds the IOMMU group (and thus, implicitly, the device itself) to a specific container usingrte_vfio_container_group_bind, whereas this step is not needed for cdev as the device fd is assigned to the container straight away.Therefore, what we do instead is introduce a new API for container device assignment which, semantically, will assign a device to specified container, so that when it is mapped using
rte_pci_map_device, the appropriate container is selected. Under the hood though, we essentially transition to getting device fd straight away at assign stage, so that by the time the PCI bus attempts to map the device, it is already mapped and we just return an fd. There is no "unassign" API becauserelease_devicealready performs that function.Additionally, a new
rte_vfio_get_modeAPI is added for those cases that need some introspection into VFIO's internals, with three new modes: group (old-style), no-iommu (old-style but without IOMMU), and cdev (the new mode). Although no-IOMMU is technically a variant of group mode, the distinction is largely irrelevant to the user, as all usages of noiommu checks in our codebase are for deciding whether to use IOVA or PA, not anything to do with managing groups. The current plan for kernel community is to *not* introduce no-IOMMU cdev implementation, and IOMMUFD's own group API compatibility layer also does not implement no-IOMMU mode, which is why this will be kept for compatibility for these use cases.There were other users of VFIO which relied on group API but only for convenience purposes; no actual VFIO functionality depended on those API's. Therefore, group API's are removed and, where appropriate, replaced with the new API's.
List of removed API's:
*
rte_vfio_get_group_fd
*rte_vfio_clear_group
*rte_vfio_container_group_bind(replaced by container assign API)
*rte_vfio_container_group_unbind
*rte_vfio_noiommu_is_enabled(replaced by new mode API)2. The API responsibilities aren't clear and bleed into each other
==================================================================Some API's do multiple things at once. In particular:
*
rte_vfio_get_device_infowill setup the device
*rte_vfio_setup_devicewill get device infoThese API's have been adjusted to do one thing only.
v11:
- Addressed feedback from Stephen's AI review:
- UseCONTAINER_INITIALIZERfor reset
- Set container fd to -1 inCONTAINER_INITIALIZER
- Fixed doubleclose()
- Moved VFIO init to earlier in init sequence to account for bus drivers needing no-IOMMU mode status
- Fixed missing ops set for cdev mode, and missing ops reset
- Fixed fd leak on failed attach in cdevv10:
- Added a patch that renames confusing error labels
- Fixed compiler warning about unused variablev9:
- Moved erroneous rte_errno-related comments to later in the patchset
- Moved removal of vDPA group fd API's to their respective patches
- Fixed typo in errno comments (ENXIO vs ENOXIO)
- Fixed corruption of group config in secondary process (v8 AI review)v8:
- Rebase
- Fixed build errors due to variable shadowing
- Removed duplicate fd check as kernel does not provide a way to distinguish between device fd'sv7:
- Rebase
- Added removal of deprecation notices
- Fixed implicit numeric comparison in patch 12v6:
- Fixed missing header include in vfio cdev filev5:
- Added back missing uapi patchv4:
- Fixed issues with documentingrte_vfio_modeenum
- Separated deprecation notices into a separate patchsetv3:
- Make API removal cleaner
- Fixget_group_numusages to align with new API
- Fix issues with function exports
- Fix issues withsetup_devicereturning old-style values in some casesv2:
- Make the entire API internal
- More aggressive API pruning, complete removal of group API
- Fixed a bug in group mode where device could not be used
- Better documentation and deprecation notice patches
- Moved doc patches to beginning of patchsetAnatoly Burakov (20):
uapi: update to v6.17 and addiommufd.h
vfio: make all functions internal
bus/pci: rename mismatching error labels
vfio: split get device info from setup
vfio: add container device assignment API
net/nbl: do not use VFIO group bind API
net/ntnic: use container device assignment API
vdpa/ifc: use container device assignment API
vdpa/nfp: use container device assignment API
vdpa/sfc: use container device assignment API
vdpa/mlx5: remove group-related API
vhost: remove group-related API from driver
vfio: remove group-based API
vfio: cleanup and refactor
bus/pci: use the new VFIO mode API
bus/fslmc: use the new VFIO mode API
net/hinic3: use the new VFIO mode API
net/ntnic: use the new VFIO mode API
vfio: remove no-IOMMU check API
vfio: introduce cdev modeconfig/arm/meson.build | 1 + config/meson.build | 1 + doc/guides/prog_guide/vhost_lib.rst | 4 - doc/guides/rel_notes/deprecation.rst | 10 - drivers/bus/cdx/cdx_vfio.c | 25 +- drivers/bus/fslmc/fslmc_bus.c | 11 +- drivers/bus/fslmc/fslmc_vfio.c | 6 +- drivers/bus/pci/linux/pci.c | 2 +- drivers/bus/pci/linux/pci_vfio.c | 47 +- drivers/bus/platform/platform.c | 9 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 14 +- drivers/net/hinic3/base/hinic3_hwdev.c | 3 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 22 +- drivers/net/nbl/nbl_include/nbl_include.h | 1 + drivers/net/ntnic/ntnic_ethdev.c | 2 +- drivers/net/ntnic/ntnic_vfio.c | 30 +- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - drivers/vdpa/nfp/nfp_vdpa.c | 37 +- drivers/vdpa/sfc/sfc_vdpa.c | 39 +- drivers/vdpa/sfc/sfc_vdpa.h | 2 - kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- lib/eal/freebsd/eal.c | 98 +- lib/eal/include/rte_vfio.h | 387 ++-- lib/eal/linux/eal.c | 15 +- lib/eal/linux/eal_vfio.c | 2448 ++++++++------------- lib/eal/linux/eal_vfio.h | 169 +- lib/eal/linux/eal_vfio_cdev.c | 396 ++++ lib/eal/linux/eal_vfio_group.c | 983 +++++++++
Quoted 9 lines
lib/eal/linux/eal_vfio_mp_sync.c | 80 +- lib/eal/linux/meson.build | 2 + lib/eal/windows/eal.c | 4 +- lib/vhost/vdpa_driver.h | 3 - 36 files changed, 4286 insertions(+), 1908 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h create mode 100644 lib/eal/linux/eal_vfio_cdev.c create mode 100644 lib/eal/linux/eal_vfio_group.c
Still lots of AI feedback from Claude Opus 5
Patch 20/20 (vfio: introduce cdev mode)
Error: in cdev mode, DPDK memory is never DMA mapped under --legacy-mem. vfio_select_mode()'s cdev arm calls vfio_setup_dma_mem(cfg), which walks memsegs via rte_memseg_walk(). rte_vfio_enable() now runs at eal.c:684, but rte_eal_memory_init() is not until :797, so every memseg list still has memseg_arr.count == 0 and the walk maps nothing. The mem event callback registered on the next line covers dynamic mode, but legacy memory is populated by malloc_add_seg(), which does not call eal_memalloc_mem_event_notify(). vfio_cdev_setup_device() does no DMA setup either, so nothing ever maps the initial hugepages.
Group mode is unaffected because vfio_group_assign_device() calls vfio_setup_dma_mem() lazily at first device assign, which happens after memory init. The cdev path needs the same deferral, or an explicit re-walk once memory is up.
Warning: ENOXIO is not an errno. The doc comments introduced in patches 14 and 20 list
* - ENOXIO - VFIO support not initialized.
in twelve places in lib/eal/include/rte_vfio.h. The code sets ENXIO.
Warning: no release notes. The series makes the whole rte_vfio API internal, removes the group-based API and rte_vfio_noiommu_is_enabled(), and adds cdev mode. Only deprecation.rst is touched; doc/guides/rel_notes/release_26_11.rst needs "Removed Items" and "New Features" entries.
v12 cover Support VFIO cdev API in DPDK
In reply to a message not in the archiveThis patchset introduces a major refactor of the VFIO subsystem in DPDK to support character device (cdev) interface introduced in Linux kernel, as well as make the API more streamlined and useful. The goal is to simplify device management, improve compatibility, and clarify API responsibilities.
The following sections outline the key issues addressed by this patchset and the corresponding changes introduced.
1. Only group mode is supported
===============================
Since kernel version 4.14.327 (LTS), VFIO supports the new character device (cdev)-based way of working with VFIO devices (otherwise known as IOMMUFD). This is a device-centric mode and does away with all the complexity regarding groups and IOMMU types, delegating it all to the kernel, and exposes a much simpler interface to userspace.
The old group interface is still around, and will need to be kept in DPDK both for compatibility reasons, as well as supporting special cases (FSLMC bus, NBL driver, no-IOMMU mode etc.), but it is now internal-only and not exposed through the API the way it was before.
To enable this, VFIO is heavily refactored, so that the code can support both modes while relying on (mostly) common infrastructure.
Note that the existing rte_vfio_device_setup/release model is fundamentally incompatible with cdev mode, because for custom container cases, the expected flow is that the user binds the IOMMU group (and thus, implicitly, the device itself) to a specific container using rte_vfio_container_group_bind, whereas this step is not needed for cdev as the device fd is assigned to the container straight away.
Therefore, what we do instead is introduce a new API for container device assignment which, semantically, will assign a device to specified container, so that when it is mapped using rte_pci_map_device, the appropriate container is selected. Under the hood though, we essentially transition to getting device fd straight away at assign stage, so that by the time the PCI bus attempts to map the device, it is already mapped and we just return an fd. There is no "unassign" API because release_device already performs that function.
Additionally, a new rte_vfio_get_mode API is added for those cases that need some introspection into VFIO's internals, with three new modes: group (old-style), no-iommu (old-style but without IOMMU), and cdev (the new mode). Although no-IOMMU is technically a variant of group mode, the distinction is largely irrelevant to the user, as all usages of noiommu checks in our codebase are for deciding whether to use IOVA or PA, not anything to do with managing groups. The current plan for kernel community is to *not* introduce no-IOMMU cdev implementation, and IOMMUFD's own group API compatibility layer also does not implement no-IOMMU mode, which is why this will be kept for compatibility for these use cases.
There were other users of VFIO which relied on group API but only for convenience purposes; no actual VFIO functionality depended on those API's. Therefore, group API's are removed and, where appropriate, replaced with the new API's.
List of removed API's:
* rte_vfio_get_group_fd
* rte_vfio_clear_group
* rte_vfio_container_group_bind (replaced by container assign API)
* rte_vfio_container_group_unbind
* rte_vfio_noiommu_is_enabled (replaced by new mode API)
2. The API responsibilities aren't clear and bleed into each other
==================================================================
Some API's do multiple things at once. In particular:
* rte_vfio_get_device_info will setup the device
* rte_vfio_setup_device will get device info
These API's have been adjusted to do one thing only.
v12:
- Addressed feedback from Stephen's AI review:
- Add release notes updates to patch 2 and 20
- Fix ENXIO typos
- Added a new init step after memory init to enable DMA mapping for cdev
v11:
- Addressed feedback from Stephen's AI review:
- Use CONTAINER_INITIALIZER for reset
- Set container fd to -1 in CONTAINER_INITIALIZER
- Fixed double close()
- Moved VFIO init to earlier in init sequence to account for bus drivers needing no-IOMMU mode status
- Fixed missing ops set for cdev mode, and missing ops reset
- Fixed fd leak on failed attach in cdev
v10:
- Added a patch that renames confusing error labels
- Fixed compiler warning about unused variable
v9:
- Moved erroneous rte_errno-related comments to later in the patchset
- Moved removal of vDPA group fd API's to their respective patches
- Fixed typo in errno comments (ENXIO vs ENOXIO)
- Fixed corruption of group config in secondary process (v8 AI review)
v8:
- Rebase
- Fixed build errors due to variable shadowing
- Removed duplicate fd check as kernel does not provide a way to distinguish between device fd's
v7:
- Rebase
- Added removal of deprecation notices
- Fixed implicit numeric comparison in patch 12
v6:
- Fixed missing header include in vfio cdev file
v5:
- Added back missing uapi patch
v4:
- Fixed issues with documenting rte_vfio_mode enum
- Separated deprecation notices into a separate patchset
v3:
- Make API removal cleaner
- Fix get_group_num usages to align with new API
- Fix issues with function exports
- Fix issues with setup_device returning old-style values in some cases
v2:
- Make the entire API internal
- More aggressive API pruning, complete removal of group API
- Fixed a bug in group mode where device could not be used
- Better documentation and deprecation notice patches
- Moved doc patches to beginning of patchset
Anatoly Burakov (20):
uapi: update to v6.17 and add iommufd.h
vfio: make all functions internal
bus/pci: rename mismatching error labels
vfio: split get device info from setup
vfio: add container device assignment API
net/nbl: do not use VFIO group bind API
net/ntnic: use container device assignment API
vdpa/ifc: use container device assignment API
vdpa/nfp: use container device assignment API
vdpa/sfc: use container device assignment API
vdpa/mlx5: remove group-related API
vhost: remove group-related API from driver
vfio: remove group-based API
vfio: cleanup and refactor
bus/pci: use the new VFIO mode API
bus/fslmc: use the new VFIO mode API
net/hinic3: use the new VFIO mode API
net/ntnic: use the new VFIO mode API
vfio: remove no-IOMMU check API
vfio: introduce cdev mode
config/arm/meson.build | 1 + config/meson.build | 1 + doc/guides/prog_guide/vhost_lib.rst | 4 - doc/guides/rel_notes/deprecation.rst | 10 - doc/guides/rel_notes/release_26_11.rst | 13 + drivers/bus/cdx/cdx_vfio.c | 25 +- drivers/bus/fslmc/fslmc_bus.c | 11 +- drivers/bus/fslmc/fslmc_vfio.c | 6 +- drivers/bus/pci/linux/pci.c | 2 +- drivers/bus/pci/linux/pci_vfio.c | 47 +- drivers/bus/platform/platform.c | 9 +- drivers/crypto/bcmfs/bcmfs_vfio.c | 14 +- drivers/net/hinic3/base/hinic3_hwdev.c | 3 +- drivers/net/nbl/nbl_common/nbl_userdev.c | 22 +- drivers/net/nbl/nbl_include/nbl_include.h | 1 + drivers/net/ntnic/ntnic_ethdev.c | 2 +- drivers/net/ntnic/ntnic_vfio.c | 30 +- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - drivers/vdpa/nfp/nfp_vdpa.c | 37 +- drivers/vdpa/sfc/sfc_vdpa.c | 39 +- drivers/vdpa/sfc/sfc_vdpa.h | 2 - kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- lib/eal/freebsd/eal.c | 104 +- lib/eal/include/rte_vfio.h | 401 ++-- lib/eal/linux/eal.c | 22 +- lib/eal/linux/eal_vfio.c | 2471 ++++++++------------- lib/eal/linux/eal_vfio.h | 169 +- lib/eal/linux/eal_vfio_cdev.c | 396 ++++ lib/eal/linux/eal_vfio_group.c | 983 ++++++++ lib/eal/linux/eal_vfio_mp_sync.c | 80 +- lib/eal/linux/meson.build | 2 + lib/eal/windows/eal.c | 4 +- lib/vhost/vdpa_driver.h | 3 - 37 files changed, 4350 insertions(+), 1907 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h create mode 100644 lib/eal/linux/eal_vfio_cdev.c create mode 100644 lib/eal/linux/eal_vfio_group.c
Signature · 1 line
2.52.0
PATCH v12 1/20 uapi: update to v6.17 and add iommufd.h
In order to support VF tokens for cdev-based VFIO mode, kernel v6.17 is required. Update internal headers to version v6.17 and include iommufd.h.
--- kernel/linux/uapi/linux/iommufd.h | 1292 +++++++++++++++++++++++++++++ kernel/linux/uapi/linux/vduse.h | 2 +- kernel/linux/uapi/linux/vfio.h | 12 +- kernel/linux/uapi/version | 2 +- 4 files changed, 1305 insertions(+), 3 deletions(-) create mode 100644 kernel/linux/uapi/linux/iommufd.h
kernel/linux/uapi/linux/iommufd.h new file +1292 -0
@@ -0,0 +1,1292 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. +*/ +#ifndef _IOMMUFD_H +#define _IOMMUFD_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +#define IOMMUFD_TYPE (';') + +/** +* DOC: General ioctl format +* +* The ioctl interface follows a general format to allow for extensibility. Each +* ioctl is passed in a structure pointer as the argument providing the size of +* the structure in the first u32. The kernel checks that any structure space +* beyond what it understands is 0. This allows userspace to use the backward +* compatible portion while consistently using the newer, larger, structures. +* +* ioctls use a standard meaning for common errnos: +* +* - ENOTTY: The IOCTL number itself is not supported at all +* - E2BIG: The IOCTL number is supported, but the provided structure has +* non-zero in a part the kernel does not understand. +* - EOPNOTSUPP: The IOCTL number is supported, and the structure is +* understood, however a known field has a value the kernel does not +* understand or support. +* - EINVAL: Everything about the IOCTL was understood, but a field is not +* correct. +* - ENOENT: An ID or IOVA provided does not exist. +* - ENOMEM: Out of memory. +* - EOVERFLOW: Mathematics overflowed. +* +* As well as additional errnos, within specific ioctls. +*/ +enum { +IOMMUFD_CMD_BASE =0x80 , +IOMMUFD_CMD_DESTROY =IOMMUFD_CMD_BASE , +IOMMUFD_CMD_IOAS_ALLOC =0x81 , +IOMMUFD_CMD_IOAS_ALLOW_IOVAS =0x82 , +IOMMUFD_CMD_IOAS_COPY =0x83 , +IOMMUFD_CMD_IOAS_IOVA_RANGES =0x84 , +IOMMUFD_CMD_IOAS_MAP =0x85 , +IOMMUFD_CMD_IOAS_UNMAP =0x86 , +IOMMUFD_CMD_OPTION =0x87 , +IOMMUFD_CMD_VFIO_IOAS =0x88 , +IOMMUFD_CMD_HWPT_ALLOC =0x89 , +IOMMUFD_CMD_GET_HW_INFO =0x8a , +IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING =0x8b , +IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP =0x8c , +IOMMUFD_CMD_HWPT_INVALIDATE =0x8d , +IOMMUFD_CMD_FAULT_QUEUE_ALLOC =0x8e , +IOMMUFD_CMD_IOAS_MAP_FILE =0x8f , +IOMMUFD_CMD_VIOMMU_ALLOC =0x90 , +IOMMUFD_CMD_VDEVICE_ALLOC =0x91 , +IOMMUFD_CMD_IOAS_CHANGE_PROCESS =0x92 , +IOMMUFD_CMD_VEVENTQ_ALLOC =0x93 , +IOMMUFD_CMD_HW_QUEUE_ALLOC =0x94 , +}; + +/** +* struct iommu_destroy - ioctl(IOMMU_DESTROY) +* @size: sizeof(struct iommu_destroy) +* @id: iommufd object ID to destroy. Can be any destroyable object type. +* +* Destroy any object held within iommufd. +*/ +struct iommu_destroy { +__u32 size; +__u32 id; +}; +#define IOMMU_DESTROY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DESTROY) + +/** +* struct iommu_ioas_alloc - ioctl(IOMMU_IOAS_ALLOC) +* @size: sizeof(struct iommu_ioas_alloc) +* @flags: Must be 0 +* @out_ioas_id: Output IOAS ID for the allocated object +* +* Allocate an IO Address Space (IOAS) which holds an IO Virtual Address (IOVA) +* to memory mapping. +*/ +struct iommu_ioas_alloc { +__u32 size; +__u32 flags; +__u32 out_ioas_id; +}; +#define IOMMU_IOAS_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOC) + +/** +* struct iommu_iova_range - ioctl(IOMMU_IOVA_RANGE) +* @start: First IOVA +* @last: Inclusive last IOVA +* +* An interval in IOVA space. +*/ +struct iommu_iova_range { +__aligned_u64 start; +__aligned_u64 last; +}; + +/** +* struct iommu_ioas_iova_ranges - ioctl(IOMMU_IOAS_IOVA_RANGES) +* @size: sizeof(struct iommu_ioas_iova_ranges) +* @ioas_id: IOAS ID to read ranges from +* @num_iovas: Input/Output total number of ranges in the IOAS +* @__reserved: Must be 0 +* @allowed_iovas: Pointer to the output array of struct iommu_iova_range +* @out_iova_alignment: Minimum alignment required for mapping IOVA +* +* Query an IOAS for ranges of allowed IOVAs. Mapping IOVA outside these ranges +* is not allowed. num_iovas will be set to the total number of iovas and +* the allowed_iovas[] will be filled in as space permits. +* +* The allowed ranges are dependent on the HW path the DMA operation takes, and +* can change during the lifetime of the IOAS. A fresh empty IOAS will have a +* full range, and each attached device will narrow the ranges based on that +* device's HW restrictions. Detaching a device can widen the ranges. Userspace +* should query ranges after every attach/detach to know what IOVAs are valid +* for mapping. +* +* On input num_iovas is the length of the allowed_iovas array. On output it is +* the total number of iovas filled in. The ioctl will return -EMSGSIZE and set +* num_iovas to the required value if num_iovas is too small. In this case the +* caller should allocate a larger output array and re-issue the ioctl. +* +* out_iova_alignment returns the minimum IOVA alignment that can be given +* to IOMMU_IOAS_MAP/COPY. IOVA's must satisfy:: +* +* starting_iova % out_iova_alignment == 0 +* (starting_iova + length) % out_iova_alignment == 0 +* +* out_iova_alignment can be 1 indicating any IOVA is allowed. It cannot +* be higher than the system PAGE_SIZE. +*/ +struct iommu_ioas_iova_ranges { +__u32 size; +__u32 ioas_id; +__u32 num_iovas; +__u32 __reserved; +__aligned_u64 allowed_iovas; +__aligned_u64 out_iova_alignment; +}; +#define IOMMU_IOAS_IOVA_RANGES _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_IOVA_RANGES) + +/** +* struct iommu_ioas_allow_iovas - ioctl(IOMMU_IOAS_ALLOW_IOVAS) +* @size: sizeof(struct iommu_ioas_allow_iovas) +* @ioas_id: IOAS ID to allow IOVAs from +* @num_iovas: Input/Output total number of ranges in the IOAS +* @__reserved: Must be 0 +* @allowed_iovas: Pointer to array of struct iommu_iova_range +* +* Ensure a range of IOVAs are always available for allocation. If this call +* succeeds then IOMMU_IOAS_IOVA_RANGES will never return a list of IOVA ranges +* that are narrower than the ranges provided here. This call will fail if +* IOMMU_IOAS_IOVA_RANGES is currently narrower than the given ranges. +* +* When an IOAS is first created the IOVA_RANGES will be maximally sized, and as +* devices are attached the IOVA will narrow based on the device restrictions. +* When an allowed range is specified any narrowing will be refused, ie device +* attachment can fail if the device requires limiting within the allowed range. +* +* Automatic IOVA allocation is also impacted by this call. MAP will only +* allocate within the allowed IOVAs if they are present. +* +* This call replaces the entire allowed list with the given list. +*/ +struct iommu_ioas_allow_iovas { +__u32 size; +__u32 ioas_id; +__u32 num_iovas; +__u32 __reserved; +__aligned_u64 allowed_iovas; +}; +#define IOMMU_IOAS_ALLOW_IOVAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_ALLOW_IOVAS) + +/** +* enum iommufd_ioas_map_flags - Flags for map and copy +* @IOMMU_IOAS_MAP_FIXED_IOVA: If clear the kernel will compute an appropriate +* IOVA to place the mapping at +* @IOMMU_IOAS_MAP_WRITEABLE: DMA is allowed to write to this mapping +* @IOMMU_IOAS_MAP_READABLE: DMA is allowed to read from this mapping +*/ +enum iommufd_ioas_map_flags { +IOMMU_IOAS_MAP_FIXED_IOVA =1 <<0 , +IOMMU_IOAS_MAP_WRITEABLE =1 <<1 , +IOMMU_IOAS_MAP_READABLE =1 <<2 , +}; + +/** +* struct iommu_ioas_map - ioctl(IOMMU_IOAS_MAP) +* @size: sizeof(struct iommu_ioas_map) +* @flags: Combination of enum iommufd_ioas_map_flags +* @ioas_id: IOAS ID to change the mapping of +* @__reserved: Must be 0 +* @user_va: Userspace pointer to start mapping from +* @length: Number of bytes to map +* @iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is set +* then this must be provided as input. +* +* Set an IOVA mapping from a user pointer. If FIXED_IOVA is specified then the +* mapping will be established at iova, otherwise a suitable location based on +* the reserved and allowed lists will be automatically selected and returned in +* iova. +* +* If IOMMU_IOAS_MAP_FIXED_IOVA is specified then the iova range must currently +* be unused, existing IOVA cannot be replaced. +*/ +struct iommu_ioas_map { +__u32 size; +__u32 flags; +__u32 ioas_id; +__u32 __reserved; +__aligned_u64 user_va; +__aligned_u64 length; +__aligned_u64 iova; +}; +#define IOMMU_IOAS_MAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_MAP) + +/** +* struct iommu_ioas_map_file - ioctl(IOMMU_IOAS_MAP_FILE) +* @size: sizeof(struct iommu_ioas_map_file) +* @flags: same as for iommu_ioas_map +* @ioas_id: same as for iommu_ioas_map +* @fd: the memfd to map +* @start: byte offset from start of file to map from +* @length: same as for iommu_ioas_map +* @iova: same as for iommu_ioas_map +* +* Set an IOVA mapping from a memfd file. All other arguments and semantics +* match those of IOMMU_IOAS_MAP. +*/ +struct iommu_ioas_map_file { +__u32 size; +__u32 flags; +__u32 ioas_id; +__s32 fd; +__aligned_u64 start; +__aligned_u64 length; +__aligned_u64 iova; +}; +#define IOMMU_IOAS_MAP_FILE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_MAP_FILE) + +/** +* struct iommu_ioas_copy - ioctl(IOMMU_IOAS_COPY) +* @size: sizeof(struct iommu_ioas_copy) +* @flags: Combination of enum iommufd_ioas_map_flags +* @dst_ioas_id: IOAS ID to change the mapping of +* @src_ioas_id: IOAS ID to copy from +* @length: Number of bytes to copy and map +* @dst_iova: IOVA the mapping was placed at. If IOMMU_IOAS_MAP_FIXED_IOVA is +* set then this must be provided as input. +* @src_iova: IOVA to start the copy +* +* Copy an already existing mapping from src_ioas_id and establish it in +* dst_ioas_id. The src iova/length must exactly match a range used with +* IOMMU_IOAS_MAP. +* +* This may be used to efficiently clone a subset of an IOAS to another, or as a +* kind of 'cache' to speed up mapping. Copy has an efficiency advantage over +* establishing equivalent new mappings, as internal resources are shared, and +* the kernel will pin the user memory only once. +*/ +struct iommu_ioas_copy { +__u32 size; +__u32 flags; +__u32 dst_ioas_id; +__u32 src_ioas_id; +__aligned_u64 length; +__aligned_u64 dst_iova; +__aligned_u64 src_iova; +}; +#define IOMMU_IOAS_COPY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_COPY) + +/** +* struct iommu_ioas_unmap - ioctl(IOMMU_IOAS_UNMAP) +* @size: sizeof(struct iommu_ioas_unmap) +* @ioas_id: IOAS ID to change the mapping of +* @iova: IOVA to start the unmapping at +* @length: Number of bytes to unmap, and return back the bytes unmapped +* +* Unmap an IOVA range. The iova/length must be a superset of a previously +* mapped range used with IOMMU_IOAS_MAP or IOMMU_IOAS_COPY. Splitting or +* truncating ranges is not allowed. The values 0 to U64_MAX will unmap +* everything. +*/ +struct iommu_ioas_unmap { +__u32 size; +__u32 ioas_id; +__aligned_u64 iova; +__aligned_u64 length; +}; +#define IOMMU_IOAS_UNMAP _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_UNMAP) + +/** +* enum iommufd_option - ioctl(IOMMU_OPTION_RLIMIT_MODE) and +* ioctl(IOMMU_OPTION_HUGE_PAGES) +* @IOMMU_OPTION_RLIMIT_MODE: +* Change how RLIMIT_MEMLOCK accounting works. The caller must have privilege +* to invoke this. Value 0 (default) is user based accounting, 1 uses process +* based accounting. Global option, object_id must be 0 +* @IOMMU_OPTION_HUGE_PAGES: +* Value 1 (default) allows contiguous pages to be combined when generating +* iommu mappings. Value 0 disables combining, everything is mapped to +* PAGE_SIZE. This can be useful for benchmarking. This is a per-IOAS +* option, the object_id must be the IOAS ID. +*/ +enum iommufd_option { +IOMMU_OPTION_RLIMIT_MODE =0 , +IOMMU_OPTION_HUGE_PAGES =1 , +}; + +/** +* enum iommufd_option_ops - ioctl(IOMMU_OPTION_OP_SET) and +* ioctl(IOMMU_OPTION_OP_GET) +* @IOMMU_OPTION_OP_SET: Set the option's value +* @IOMMU_OPTION_OP_GET: Get the option's value +*/ +enum iommufd_option_ops { +IOMMU_OPTION_OP_SET =0 , +IOMMU_OPTION_OP_GET =1 , +}; + +/** +* struct iommu_option - iommu option multiplexer +* @size: sizeof(struct iommu_option) +* @option_id: One of enum iommufd_option +* @op: One of enum iommufd_option_ops +* @__reserved: Must be 0 +* @object_id: ID of the object if required +* @val64: Option value to set or value returned on get +* +* Change a simple option value. This multiplexor allows controlling options +* on objects. IOMMU_OPTION_OP_SET will load an option and IOMMU_OPTION_OP_GET +* will return the current value. +*/ +struct iommu_option { +__u32 size; +__u32 option_id; +__u16 op; +__u16 __reserved; +__u32 object_id; +__aligned_u64 val64; +}; +#define IOMMU_OPTION _IO(IOMMUFD_TYPE, IOMMUFD_CMD_OPTION) + +/** +* enum iommufd_vfio_ioas_op - IOMMU_VFIO_IOAS_* ioctls +* @IOMMU_VFIO_IOAS_GET: Get the current compatibility IOAS +* @IOMMU_VFIO_IOAS_SET: Change the current compatibility IOAS +* @IOMMU_VFIO_IOAS_CLEAR: Disable VFIO compatibility +*/ +enum iommufd_vfio_ioas_op { +IOMMU_VFIO_IOAS_GET =0 , +IOMMU_VFIO_IOAS_SET =1 , +IOMMU_VFIO_IOAS_CLEAR =2 , +}; + +/** +* struct iommu_vfio_ioas - ioctl(IOMMU_VFIO_IOAS) +* @size: sizeof(struct iommu_vfio_ioas) +* @ioas_id: For IOMMU_VFIO_IOAS_SET the input IOAS ID to set +* For IOMMU_VFIO_IOAS_GET will output the IOAS ID +* @op: One of enum iommufd_vfio_ioas_op +* @__reserved: Must be 0 +* +* The VFIO compatibility support uses a single ioas because VFIO APIs do not +* support the ID field. Set or Get the IOAS that VFIO compatibility will use. +* When VFIO_GROUP_SET_CONTAINER is used on an iommufd it will get the +* compatibility ioas, either by taking what is already set, or auto creating +* one. From then on VFIO will continue to use that ioas and is not effected by +* this ioctl. SET or CLEAR does not destroy any auto-created IOAS. +*/ +struct iommu_vfio_ioas { +__u32 size; +__u32 ioas_id; +__u16 op; +__u16 __reserved; +}; +#define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS) + +/** +* enum iommufd_hwpt_alloc_flags - Flags for HWPT allocation +* @IOMMU_HWPT_ALLOC_NEST_PARENT: If set, allocate a HWPT that can serve as +* the parent HWPT in a nesting configuration. +* @IOMMU_HWPT_ALLOC_DIRTY_TRACKING: Dirty tracking support for device IOMMU is +* enforced on device attachment +* @IOMMU_HWPT_FAULT_ID_VALID: The fault_id field of hwpt allocation data is +* valid. +* @IOMMU_HWPT_ALLOC_PASID: Requests a domain that can be used with PASID. The +* domain can be attached to any PASID on the device. +* Any domain attached to the non-PASID part of the +* device must also be flagged, otherwise attaching a +* PASID will blocked. +* For the user that wants to attach PASID, ioas is +* not recommended for both the non-PASID part +* and PASID part of the device. +* If IOMMU does not support PASID it will return +* error (-EOPNOTSUPP). +*/ +enum iommufd_hwpt_alloc_flags { +IOMMU_HWPT_ALLOC_NEST_PARENT =1 <<0 , +IOMMU_HWPT_ALLOC_DIRTY_TRACKING =1 <<1 , +IOMMU_HWPT_FAULT_ID_VALID =1 <<2 , +IOMMU_HWPT_ALLOC_PASID =1 <<3 , +}; + +/** +* enum iommu_hwpt_vtd_s1_flags - Intel VT-d stage-1 page table +* entry attributes +* @IOMMU_VTD_S1_SRE: Supervisor request +* @IOMMU_VTD_S1_EAFE: Extended access enable +* @IOMMU_VTD_S1_WPE: Write protect enable +*/ +enum iommu_hwpt_vtd_s1_flags { +IOMMU_VTD_S1_SRE =1 <<0 , +IOMMU_VTD_S1_EAFE =1 <<1 , +IOMMU_VTD_S1_WPE =1 <<2 , +}; + +/** +* struct iommu_hwpt_vtd_s1 - Intel VT-d stage-1 page table +* info (IOMMU_HWPT_DATA_VTD_S1) +* @flags: Combination of enum iommu_hwpt_vtd_s1_flags +* @pgtbl_addr: The base address of the stage-1 page table. +* @addr_width: The address width of the stage-1 page table +* @__reserved: Must be 0 +*/ +struct iommu_hwpt_vtd_s1 { +__aligned_u64 flags; +__aligned_u64 pgtbl_addr; +__u32 addr_width; +__u32 __reserved; +}; + +/** +* struct iommu_hwpt_arm_smmuv3 - ARM SMMUv3 nested STE +* (IOMMU_HWPT_DATA_ARM_SMMUV3) +* +* @ste: The first two double words of the user space Stream Table Entry for +* the translation. Must be little-endian. +* Allowed fields: (Refer to "5.2 Stream Table Entry" in SMMUv3 HW Spec) +* - word-0: V, Cfg, S1Fmt, S1ContextPtr, S1CDMax +* - word-1: EATS, S1DSS, S1CIR, S1COR, S1CSH, S1STALLD +* +* -EIO will be returned if @ste is not legal or contains any non-allowed field. +* Cfg can be used to select a S1, Bypass or Abort configuration. A Bypass +* nested domain will translate the same as the nesting parent. The S1 will +* install a Context Descriptor Table pointing at userspace memory translated +* by the nesting parent. +*/ +struct iommu_hwpt_arm_smmuv3 { +__aligned_le64 ste[2 ]; +}; + +/** +* enum iommu_hwpt_data_type - IOMMU HWPT Data Type +* @IOMMU_HWPT_DATA_NONE: no data +* @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table +* @IOMMU_HWPT_DATA_ARM_SMMUV3: ARM SMMUv3 Context Descriptor Table +*/ +enum iommu_hwpt_data_type { +IOMMU_HWPT_DATA_NONE =0 , +IOMMU_HWPT_DATA_VTD_S1 =1 , +IOMMU_HWPT_DATA_ARM_SMMUV3 =2 , +}; + +/** +* struct iommu_hwpt_alloc - ioctl(IOMMU_HWPT_ALLOC) +* @size: sizeof(struct iommu_hwpt_alloc) +* @flags: Combination of enum iommufd_hwpt_alloc_flags +* @dev_id: The device to allocate this HWPT for +* @pt_id: The IOAS or HWPT or vIOMMU to connect this HWPT to +* @out_hwpt_id: The ID of the new HWPT +* @__reserved: Must be 0 +* @data_type: One of enum iommu_hwpt_data_type +* @data_len: Length of the type specific data +* @data_uptr: User pointer to the type specific data +* @fault_id: The ID of IOMMUFD_FAULT object. Valid only if flags field of +* IOMMU_HWPT_FAULT_ID_VALID is set. +* @__reserved2: Padding to 64-bit alignment. Must be 0. +* +* Explicitly allocate a hardware page table object. This is the same object +* type that is returned by iommufd_device_attach() and represents the +* underlying iommu driver's iommu_domain kernel object. +* +* A kernel-managed HWPT will be created with the mappings from the given +* IOAS via the @pt_id. The @data_type for this allocation must be set to +* IOMMU_HWPT_DATA_NONE. The HWPT can be allocated as a parent HWPT for a +* nesting configuration by passing IOMMU_HWPT_ALLOC_NEST_PARENT via @flags. +* +* A user-managed nested HWPT will be created from a given vIOMMU (wrapping a +* parent HWPT) or a parent HWPT via @pt_id, in which the parent HWPT must be +* allocated previously via the same ioctl from a given IOAS (@pt_id). In this +* case, the @data_type must be set to a pre-defined type corresponding to an +* I/O page table type supported by the underlying IOMMU hardware. The device +* via @dev_id and the vIOMMU via @pt_id must be associated to the same IOMMU +* instance. +* +* If the @data_type is set to IOMMU_HWPT_DATA_NONE, @data_len and +* @data_uptr should be zero. Otherwise, both @data_len and @data_uptr +* must be given. +*/ +struct iommu_hwpt_alloc { +__u32 size; +__u32 flags; +__u32 dev_id; +__u32 pt_id; +__u32 out_hwpt_id; +__u32 __reserved; +__u32 data_type; +__u32 data_len; +__aligned_u64 data_uptr; +__u32 fault_id; +__u32 __reserved2; +}; +#define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) + +/** +* enum iommu_hw_info_vtd_flags - Flags for VT-d hw_info +* @IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17: If set, disallow read-only mappings +* on a nested_parent domain. +* https://www.intel.com/content/www/us/en/content-details/772415/content-details.html +*/ +enum iommu_hw_info_vtd_flags { +IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17 =1 <<0 , +}; + +/** +* struct iommu_hw_info_vtd - Intel VT-d hardware information +* +* @flags: Combination of enum iommu_hw_info_vtd_flags +* @__reserved: Must be 0 +* +* @cap_reg: Value of Intel VT-d capability register defined in VT-d spec +* section 11.4.2 Capability Register. +* @ecap_reg: Value of Intel VT-d capability register defined in VT-d spec +* section 11.4.3 Extended Capability Register. +* +* User needs to understand the Intel VT-d specification to decode the +* register value. +*/ +struct iommu_hw_info_vtd { +__u32 flags; +__u32 __reserved; +__aligned_u64 cap_reg; +__aligned_u64 ecap_reg; +}; + +/** +* struct iommu_hw_info_arm_smmuv3 - ARM SMMUv3 hardware information +* (IOMMU_HW_INFO_TYPE_ARM_SMMUV3) +* +* @flags: Must be set to 0 +* @__reserved: Must be 0 +* @idr: Implemented features for ARM SMMU Non-secure programming interface +* @iidr: Information about the implementation and implementer of ARM SMMU, +* and architecture version supported +* @aidr: ARM SMMU architecture version +* +* For the details of @idr, @iidr and @aidr, please refer to the chapters +* from 6.3.1 to 6.3.6 in the SMMUv3 Spec. +* +* This reports the raw HW capability, and not all bits are meaningful to be +* read by userspace. Only the following fields should be used: +* +* idr[0]: ST_LEVEL, TERM_MODEL, STALL_MODEL, TTENDIAN , CD2L, ASID16, TTF +* idr[1]: SIDSIZE, SSIDSIZE +* idr[3]: BBML, RIL +* idr[5]: VAX, GRAN64K, GRAN16K, GRAN4K +* +* - S1P should be assumed to be true if a NESTED HWPT can be created +* - VFIO/iommufd only support platforms with COHACC, it should be assumed to be +* true. +* - ATS is a per-device property. If the VMM describes any devices as ATS +* capable in ACPI/DT it should set the corresponding idr. +* +* This list may expand in future (eg E0PD, AIE, PBHA, D128, DS etc). It is +* important that VMMs do not read bits outside the list to allow for +* compatibility with future kernels. Several features in the SMMUv3 +* architecture are not currently supported by the kernel for nesting: HTTU, +* BTM, MPAM and others. +*/ +struct iommu_hw_info_arm_smmuv3 { +__u32 flags; +__u32 __reserved; +__u32 idr[6 ]; +__u32 iidr; +__u32 aidr; +}; + +/** +* struct iommu_hw_info_tegra241_cmdqv - NVIDIA Tegra241 CMDQV Hardware +* Information (IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV) +* +* @flags: Must be 0 +* @version: Version number for the CMDQ-V HW for PARAM bits[03:00] +* @log2vcmdqs: Log2 of the total number of VCMDQs for PARAM bits[07:04] +* @log2vsids: Log2 of the total number of SID replacements for PARAM bits[15:12] +* @__reserved: Must be 0 +* +* VMM can use these fields directly in its emulated global PARAM register. Note +* that only one Virtual Interface (VINTF) should be exposed to a VM, i.e. PARAM +* bits[11:08] should be set to 0 for log2 of the total number of VINTFs. +*/ +struct iommu_hw_info_tegra241_cmdqv { +__u32 flags; +__u8 version; +__u8 log2vcmdqs; +__u8 log2vsids; +__u8 __reserved; +}; + +/** +* enum iommu_hw_info_type - IOMMU Hardware Info Types +* @IOMMU_HW_INFO_TYPE_NONE: Output by the drivers that do not report hardware +* info +* @IOMMU_HW_INFO_TYPE_DEFAULT: Input to request for a default type +* @IOMMU_HW_INFO_TYPE_INTEL_VTD: Intel VT-d iommu info type +* @IOMMU_HW_INFO_TYPE_ARM_SMMUV3: ARM SMMUv3 iommu info type +* @IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) info type +*/ +enum iommu_hw_info_type { +IOMMU_HW_INFO_TYPE_NONE =0 , +IOMMU_HW_INFO_TYPE_DEFAULT =0 , +IOMMU_HW_INFO_TYPE_INTEL_VTD =1 , +IOMMU_HW_INFO_TYPE_ARM_SMMUV3 =2 , +IOMMU_HW_INFO_TYPE_TEGRA241_CMDQV =3 , +}; + +/** +* enum iommufd_hw_capabilities +* @IOMMU_HW_CAP_DIRTY_TRACKING: IOMMU hardware support for dirty tracking +* If available, it means the following APIs +* are supported: +* +* IOMMU_HWPT_GET_DIRTY_BITMAP +* IOMMU_HWPT_SET_DIRTY_TRACKING +* +* @IOMMU_HW_CAP_PCI_PASID_EXEC: Execute Permission Supported, user ignores it +* when the struct +* iommu_hw_info::out_max_pasid_log2 is zero. +* @IOMMU_HW_CAP_PCI_PASID_PRIV: Privileged Mode Supported, user ignores it +* when the struct +* iommu_hw_info::out_max_pasid_log2 is zero. +*/ +enum iommufd_hw_capabilities { +IOMMU_HW_CAP_DIRTY_TRACKING =1 <<0 , +IOMMU_HW_CAP_PCI_PASID_EXEC =1 <<1 , +IOMMU_HW_CAP_PCI_PASID_PRIV =1 <<2 , +}; + +/** +* enum iommufd_hw_info_flags - Flags for iommu_hw_info +* @IOMMU_HW_INFO_FLAG_INPUT_TYPE: If set, @in_data_type carries an input type +* for user space to request for a specific info +*/ +enum iommufd_hw_info_flags { +IOMMU_HW_INFO_FLAG_INPUT_TYPE =1 <<0 , +}; + +/** +* struct iommu_hw_info - ioctl(IOMMU_GET_HW_INFO) +* @size: sizeof(struct iommu_hw_info) +* @flags: Must be 0 +* @dev_id: The device bound to the iommufd +* @data_len: Input the length of a user buffer in bytes. Output the length of +* data that kernel supports +* @data_uptr: User pointer to a user-space buffer used by the kernel to fill +* the iommu type specific hardware information data +* @in_data_type: This shares the same field with @out_data_type, making it be +* a bidirectional field. When IOMMU_HW_INFO_FLAG_INPUT_TYPE is +* set, an input type carried via this @in_data_type field will +* be valid, requesting for the info data to the given type. If +* IOMMU_HW_INFO_FLAG_INPUT_TYPE is unset, any input value will +* be seen as IOMMU_HW_INFO_TYPE_DEFAULT +* @out_data_type: Output the iommu hardware info type as defined in the enum +* iommu_hw_info_type. +* @out_capabilities: Output the generic iommu capability info type as defined +* in the enum iommu_hw_capabilities. +* @out_max_pasid_log2: Output the width of PASIDs. 0 means no PASID support. +* PCI devices turn to out_capabilities to check if the +* specific capabilities is supported or not. +* @__reserved: Must be 0 +* +* Query an iommu type specific hardware information data from an iommu behind +* a given device that has been bound to iommufd. This hardware info data will +* be used to sync capabilities between the virtual iommu and the physical +* iommu, e.g. a nested translation setup needs to check the hardware info, so +* a guest stage-1 page table can be compatible with the physical iommu. +* +* To capture an iommu type specific hardware information data, @data_uptr and +* its length @data_len must be provided. Trailing bytes will be zeroed if the +* user buffer is larger than the data that kernel has. Otherwise, kernel only +* fills the buffer using the given length in @data_len. If the ioctl succeeds, +* @data_len will be updated to the length that kernel actually supports, +* @out_data_type will be filled to decode the data filled in the buffer +* pointed by @data_uptr. Input @data_len == zero is allowed. +*/ +struct iommu_hw_info { +__u32 size; +__u32 flags; +__u32 dev_id; +__u32 data_len; +__aligned_u64 data_uptr; +union { +__u32 in_data_type; +__u32 out_data_type; + }; +__u8 out_max_pasid_log2; +__u8 __reserved[3 ]; +__aligned_u64 out_capabilities; +}; +#define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO) + +/* +* enum iommufd_hwpt_set_dirty_tracking_flags - Flags for steering dirty +* tracking +* @IOMMU_HWPT_DIRTY_TRACKING_ENABLE: Enable dirty tracking +*/ +enum iommufd_hwpt_set_dirty_tracking_flags { +IOMMU_HWPT_DIRTY_TRACKING_ENABLE =1 , +}; + +/** +* struct iommu_hwpt_set_dirty_tracking - ioctl(IOMMU_HWPT_SET_DIRTY_TRACKING) +* @size: sizeof(struct iommu_hwpt_set_dirty_tracking) +* @flags: Combination of enum iommufd_hwpt_set_dirty_tracking_flags +* @hwpt_id: HW pagetable ID that represents the IOMMU domain +* @__reserved: Must be 0 +* +* Toggle dirty tracking on an HW pagetable. +*/ +struct iommu_hwpt_set_dirty_tracking { +__u32 size; +__u32 flags; +__u32 hwpt_id; +__u32 __reserved; +}; +#define IOMMU_HWPT_SET_DIRTY_TRACKING _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING) + +/** +* enum iommufd_hwpt_get_dirty_bitmap_flags - Flags for getting dirty bits +* @IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR: Just read the PTEs without clearing +* any dirty bits metadata. This flag +* can be passed in the expectation +* where the next operation is an unmap +* of the same IOVA range. +* +*/ +enum iommufd_hwpt_get_dirty_bitmap_flags { +IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR =1 , +}; + +/** +* struct iommu_hwpt_get_dirty_bitmap - ioctl(IOMMU_HWPT_GET_DIRTY_BITMAP) +* @size: sizeof(struct iommu_hwpt_get_dirty_bitmap) +* @hwpt_id: HW pagetable ID that represents the IOMMU domain +* @flags: Combination of enum iommufd_hwpt_get_dirty_bitmap_flags +* @__reserved: Must be 0 +* @iova: base IOVA of the bitmap first bit +* @length: IOVA range size +* @page_size: page size granularity of each bit in the bitmap +* @data: bitmap where to set the dirty bits. The bitmap bits each +* represent a page_size which you deviate from an arbitrary iova. +* +* Checking a given IOVA is dirty: +* +* data[(iova / page_size) / 64] & (1ULL << ((iova / page_size) % 64)) +* +* Walk the IOMMU pagetables for a given IOVA range to return a bitmap +* with the dirty IOVAs. In doing so it will also by default clear any +* dirty bit metadata set in the IOPTE. +*/ +struct iommu_hwpt_get_dirty_bitmap { +__u32 size; +__u32 hwpt_id; +__u32 flags; +__u32 __reserved; +__aligned_u64 iova; +__aligned_u64 length; +__aligned_u64 page_size; +__aligned_u64 data; +}; +#define IOMMU_HWPT_GET_DIRTY_BITMAP _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP) + +/** +* enum iommu_hwpt_invalidate_data_type - IOMMU HWPT Cache Invalidation +* Data Type +* @IOMMU_HWPT_INVALIDATE_DATA_VTD_S1: Invalidation data for VTD_S1 +* @IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3: Invalidation data for ARM SMMUv3 +*/ +enum iommu_hwpt_invalidate_data_type { +IOMMU_HWPT_INVALIDATE_DATA_VTD_S1 =0 , +IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3 =1 , +}; + +/** +* enum iommu_hwpt_vtd_s1_invalidate_flags - Flags for Intel VT-d +* stage-1 cache invalidation +* @IOMMU_VTD_INV_FLAGS_LEAF: Indicates whether the invalidation applies +* to all-levels page structure cache or just +* the leaf PTE cache. +*/ +enum iommu_hwpt_vtd_s1_invalidate_flags { +IOMMU_VTD_INV_FLAGS_LEAF =1 <<0 , +}; + +/** +* struct iommu_hwpt_vtd_s1_invalidate - Intel VT-d cache invalidation +* (IOMMU_HWPT_INVALIDATE_DATA_VTD_S1) +* @addr: The start address of the range to be invalidated. It needs to +* be 4KB aligned. +* @npages: Number of contiguous 4K pages to be invalidated. +* @flags: Combination of enum iommu_hwpt_vtd_s1_invalidate_flags +* @__reserved: Must be 0 +* +* The Intel VT-d specific invalidation data for user-managed stage-1 cache +* invalidation in nested translation. Userspace uses this structure to +* tell the impacted cache scope after modifying the stage-1 page table. +* +* Invalidating all the caches related to the page table by setting @addr +* to be 0 and @npages to be U64_MAX. +* +* The device TLB will be invalidated automatically if ATS is enabled. +*/ +struct iommu_hwpt_vtd_s1_invalidate { +__aligned_u64 addr; +__aligned_u64 npages; +__u32 flags; +__u32 __reserved; +}; + +/** +* struct iommu_viommu_arm_smmuv3_invalidate - ARM SMMUv3 cache invalidation +* (IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3) +* @cmd: 128-bit cache invalidation command that runs in SMMU CMDQ. +* Must be little-endian. +* +* Supported command list only when passing in a vIOMMU via @hwpt_id: +* CMDQ_OP_TLBI_NSNH_ALL +* CMDQ_OP_TLBI_NH_VA +* CMDQ_OP_TLBI_NH_VAA +* CMDQ_OP_TLBI_NH_ALL +* CMDQ_OP_TLBI_NH_ASID +* CMDQ_OP_ATC_INV +* CMDQ_OP_CFGI_CD +* CMDQ_OP_CFGI_CD_ALL +* +* -EIO will be returned if the command is not supported. +*/ +struct iommu_viommu_arm_smmuv3_invalidate { +__aligned_le64 cmd[2 ]; +}; + +/** +* struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE) +* @size: sizeof(struct iommu_hwpt_invalidate) +* @hwpt_id: ID of a nested HWPT or a vIOMMU, for cache invalidation +* @data_uptr: User pointer to an array of driver-specific cache invalidation +* data. +* @data_type: One of enum iommu_hwpt_invalidate_data_type, defining the data +* type of all the entries in the invalidation request array. It +* should be a type supported by the hwpt pointed by @hwpt_id. +* @entry_len: Length (in bytes) of a request entry in the request array +* @entry_num: Input the number of cache invalidation requests in the array. +* Output the number of requests successfully handled by kernel. +* @__reserved: Must be 0. +* +* Invalidate iommu cache for user-managed page table or vIOMMU. Modifications +* on a user-managed page table should be followed by this operation, if a HWPT +* is passed in via @hwpt_id. Other caches, such as device cache or descriptor +* cache can be flushed if a vIOMMU is passed in via the @hwpt_id field. +* +* Each ioctl can support one or more cache invalidation requests in the array +* that has a total size of @entry_len * @entry_num. +* +* An empty invalidation request array by setting @entry_num==0 is allowed, and +* @entry_len and @data_uptr would be ignored in this case. This can be used to +* check if the given @data_type is supported or not by kernel. +*/ +struct iommu_hwpt_invalidate { +__u32 size; +__u32 hwpt_id; +__aligned_u64 data_uptr; +__u32 data_type; +__u32 entry_len; +__u32 entry_num; +__u32 __reserved; +}; +#define IOMMU_HWPT_INVALIDATE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_INVALIDATE) + +/** +* enum iommu_hwpt_pgfault_flags - flags for struct iommu_hwpt_pgfault +* @IOMMU_PGFAULT_FLAGS_PASID_VALID: The pasid field of the fault data is +* valid. +* @IOMMU_PGFAULT_FLAGS_LAST_PAGE: It's the last fault of a fault group. +*/ +enum iommu_hwpt_pgfault_flags { +IOMMU_PGFAULT_FLAGS_PASID_VALID = (1 <<0 ), +IOMMU_PGFAULT_FLAGS_LAST_PAGE = (1 <<1 ), +}; + +/** +* enum iommu_hwpt_pgfault_perm - perm bits for struct iommu_hwpt_pgfault +* @IOMMU_PGFAULT_PERM_READ: request for read permission +* @IOMMU_PGFAULT_PERM_WRITE: request for write permission +* @IOMMU_PGFAULT_PERM_EXEC: (PCIE 10.4.1) request with a PASID that has the +* Execute Requested bit set in PASID TLP Prefix. +* @IOMMU_PGFAULT_PERM_PRIV: (PCIE 10.4.1) request with a PASID that has the +* Privileged Mode Requested bit set in PASID TLP +* Prefix. +*/ +enum iommu_hwpt_pgfault_perm { +IOMMU_PGFAULT_PERM_READ = (1 <<0 ), +IOMMU_PGFAULT_PERM_WRITE = (1 <<1 ), +IOMMU_PGFAULT_PERM_EXEC = (1 <<2 ), +IOMMU_PGFAULT_PERM_PRIV = (1 <<3 ), +}; + +/** +* struct iommu_hwpt_pgfault - iommu page fault data +* @flags: Combination of enum iommu_hwpt_pgfault_flags +* @dev_id: id of the originated device +* @pasid: Process Address Space ID +* @grpid: Page Request Group Index +* @perm: Combination of enum iommu_hwpt_pgfault_perm +* @__reserved: Must be 0. +* @addr: Fault address +* @length: a hint of how much data the requestor is expecting to fetch. For +* example, if the PRI initiator knows it is going to do a 10MB +* transfer, it could fill in 10MB and the OS could pre-fault in +* 10MB of IOVA. It's default to 0 if there's no such hint. +* @cookie: kernel-managed cookie identifying a group of fault messages. The +* cookie number encoded in the last page fault of the group should +* be echoed back in the response message. +*/ +struct iommu_hwpt_pgfault { +__u32 flags; +__u32 dev_id; +__u32 pasid; +__u32 grpid; +__u32 perm; +__u32 __reserved; +__aligned_u64 addr; +__u32 length; +__u32 cookie; +}; + +/** +* enum iommufd_page_response_code - Return status of fault handlers +* @IOMMUFD_PAGE_RESP_SUCCESS: Fault has been handled and the page tables +* populated, retry the access. This is the +* "Success" defined in PCI 10.4.2.1. +* @IOMMUFD_PAGE_RESP_INVALID: Could not handle this fault, don't retry the +* access. This is the "Invalid Request" in PCI +* 10.4.2.1. +*/ +enum iommufd_page_response_code { +IOMMUFD_PAGE_RESP_SUCCESS =0 , +IOMMUFD_PAGE_RESP_INVALID =1 , +}; + +/** +* struct iommu_hwpt_page_response - IOMMU page fault response +* @cookie: The kernel-managed cookie reported in the fault message. +* @code: One of response code in enum iommufd_page_response_code. +*/ +struct iommu_hwpt_page_response { +__u32 cookie; +__u32 code; +}; + +/** +* struct iommu_fault_alloc - ioctl(IOMMU_FAULT_QUEUE_ALLOC) +* @size: sizeof(struct iommu_fault_alloc) +* @flags: Must be 0 +* @out_fault_id: The ID of the new FAULT +* @out_fault_fd: The fd of the new FAULT +* +* Explicitly allocate a fault handling object. +*/ +struct iommu_fault_alloc { +__u32 size; +__u32 flags; +__u32 out_fault_id; +__u32 out_fault_fd; +}; +#define IOMMU_FAULT_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_FAULT_QUEUE_ALLOC) + +/** +* enum iommu_viommu_type - Virtual IOMMU Type +* @IOMMU_VIOMMU_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VIOMMU_TYPE_ARM_SMMUV3: ARM SMMUv3 driver specific type +* @IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) enabled ARM SMMUv3 type +*/ +enum iommu_viommu_type { +IOMMU_VIOMMU_TYPE_DEFAULT =0 , +IOMMU_VIOMMU_TYPE_ARM_SMMUV3 =1 , +IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV =2 , +}; + +/** +* struct iommu_viommu_tegra241_cmdqv - NVIDIA Tegra241 CMDQV Virtual Interface +* (IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV) +* @out_vintf_mmap_offset: mmap offset argument for VINTF's page0 +* @out_vintf_mmap_length: mmap length argument for VINTF's page0 +* +* Both @out_vintf_mmap_offset and @out_vintf_mmap_length are reported by kernel +* for user space to mmap the VINTF page0 from the host physical address space +* to the guest physical address space so that a guest kernel can directly R/W +* access to the VINTF page0 in order to control its virtual command queues. +*/ +struct iommu_viommu_tegra241_cmdqv { +__aligned_u64 out_vintf_mmap_offset; +__aligned_u64 out_vintf_mmap_length; +}; + +/** +* struct iommu_viommu_alloc - ioctl(IOMMU_VIOMMU_ALLOC) +* @size: sizeof(struct iommu_viommu_alloc) +* @flags: Must be 0 +* @type: Type of the virtual IOMMU. Must be defined in enum iommu_viommu_type +* @dev_id: The device's physical IOMMU will be used to back the virtual IOMMU +* @hwpt_id: ID of a nesting parent HWPT to associate to +* @out_viommu_id: Output virtual IOMMU ID for the allocated object +* @data_len: Length of the type specific data +* @__reserved: Must be 0 +* @data_uptr: User pointer to a driver-specific virtual IOMMU data +* +* Allocate a virtual IOMMU object, representing the underlying physical IOMMU's +* virtualization support that is a security-isolated slice of the real IOMMU HW +* that is unique to a specific VM. Operations global to the IOMMU are connected +* to the vIOMMU, such as: +* - Security namespace for guest owned ID, e.g. guest-controlled cache tags +* - Non-device-affiliated event reporting, e.g. invalidation queue errors +* - Access to a sharable nesting parent pagetable across physical IOMMUs +* - Virtualization of various platforms IDs, e.g. RIDs and others +* - Delivery of paravirtualized invalidation +* - Direct assigned invalidation queues +* - Direct assigned interrupts +*/ +struct iommu_viommu_alloc { +__u32 size; +__u32 flags; +__u32 type; +__u32 dev_id; +__u32 hwpt_id; +__u32 out_viommu_id; +__u32 data_len; +__u32 __reserved; +__aligned_u64 data_uptr; +}; +#define IOMMU_VIOMMU_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_ALLOC) + +/** +* struct iommu_vdevice_alloc - ioctl(IOMMU_VDEVICE_ALLOC) +* @size: sizeof(struct iommu_vdevice_alloc) +* @viommu_id: vIOMMU ID to associate with the virtual device +* @dev_id: The physical device to allocate a virtual instance on the vIOMMU +* @out_vdevice_id: Object handle for the vDevice. Pass to IOMMU_DESTORY +* @virt_id: Virtual device ID per vIOMMU, e.g. vSID of ARM SMMUv3, vDeviceID +* of AMD IOMMU, and vRID of Intel VT-d +* +* Allocate a virtual device instance (for a physical device) against a vIOMMU. +* This instance holds the device's information (related to its vIOMMU) in a VM. +* User should use IOMMU_DESTROY to destroy the virtual device before +* destroying the physical device (by closing vfio_cdev fd). Otherwise the +* virtual device would be forcibly destroyed on physical device destruction, +* its vdevice_id would be permanently leaked (unremovable & unreusable) until +* iommu fd closed. +*/ +struct iommu_vdevice_alloc { +__u32 size; +__u32 viommu_id; +__u32 dev_id; +__u32 out_vdevice_id; +__aligned_u64 virt_id; +}; +#define IOMMU_VDEVICE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VDEVICE_ALLOC) + +/** +* struct iommu_ioas_change_process - ioctl(VFIO_IOAS_CHANGE_PROCESS) +* @size: sizeof(struct iommu_ioas_change_process) +* @__reserved: Must be 0 +* +* This transfers pinned memory counts for every memory map in every IOAS +* in the context to the current process. This only supports maps created +* with IOMMU_IOAS_MAP_FILE, and returns EINVAL if other maps are present. +* If the ioctl returns a failure status, then nothing is changed. +* +* This API is useful for transferring operation of a device from one process +* to another, such as during userland live update. +*/ +struct iommu_ioas_change_process { +__u32 size; +__u32 __reserved; +}; + +#define IOMMU_IOAS_CHANGE_PROCESS \ + _IO(IOMMUFD_TYPE, IOMMUFD_CMD_IOAS_CHANGE_PROCESS) + +/** +* enum iommu_veventq_flag - flag for struct iommufd_vevent_header +* @IOMMU_VEVENTQ_FLAG_LOST_EVENTS: vEVENTQ has lost vEVENTs +*/ +enum iommu_veventq_flag { +IOMMU_VEVENTQ_FLAG_LOST_EVENTS = (1U <<0 ), +}; + +/** +* struct iommufd_vevent_header - Virtual Event Header for a vEVENTQ Status +* @flags: Combination of enum iommu_veventq_flag +* @sequence: The sequence index of a vEVENT in the vEVENTQ, with a range of +* [0, INT_MAX] where the following index of INT_MAX is 0 +* +* Each iommufd_vevent_header reports a sequence index of the following vEVENT: +* +* +----------------------+-------+----------------------+-------+---+-------+ +* | header0 {sequence=0} | data0 | header1 {sequence=1} | data1 |...| dataN | +* +----------------------+-------+----------------------+-------+---+-------+ +* +* And this sequence index is expected to be monotonic to the sequence index of +* the previous vEVENT. If two adjacent sequence indexes has a delta larger than +* 1, it means that delta - 1 number of vEVENTs has lost, e.g. two lost vEVENTs: +* +* +-----+----------------------+-------+----------------------+-------+-----+ +* | ... | header3 {sequence=3} | data3 | header6 {sequence=6} | data6 | ... | +* +-----+----------------------+-------+----------------------+-------+-----+ +* +* If a vEVENT lost at the tail of the vEVENTQ and there is no following vEVENT +* providing the next sequence index, an IOMMU_VEVENTQ_FLAG_LOST_EVENTS header +* would be added to the tail, and no data would follow this header: +* +* +--+----------------------+-------+-----------------------------------------+ +* |..| header3 {sequence=3} | data3 | header4 {flags=LOST_EVENTS, sequence=4} | +* +--+----------------------+-------+-----------------------------------------+ +*/ +struct iommufd_vevent_header { +__u32 flags; +__u32 sequence; +}; + +/** +* enum iommu_veventq_type - Virtual Event Queue Type +* @IOMMU_VEVENTQ_TYPE_DEFAULT: Reserved for future use +* @IOMMU_VEVENTQ_TYPE_ARM_SMMUV3: ARM SMMUv3 Virtual Event Queue +* @IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV Extension IRQ +*/ +enum iommu_veventq_type { +IOMMU_VEVENTQ_TYPE_DEFAULT =0 , +IOMMU_VEVENTQ_TYPE_ARM_SMMUV3 =1 , +IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV =2 , +}; + +/** +* struct iommu_vevent_arm_smmuv3 - ARM SMMUv3 Virtual Event +* (IOMMU_VEVENTQ_TYPE_ARM_SMMUV3) +* @evt: 256-bit ARM SMMUv3 Event record, little-endian. +* Reported event records: (Refer to "7.3 Event records" in SMMUv3 HW Spec) +* - 0x04 C_BAD_STE +* - 0x06 F_STREAM_DISABLED +* - 0x08 C_BAD_SUBSTREAMID +* - 0x0a C_BAD_CD +* - 0x10 F_TRANSLATION +* - 0x11 F_ADDR_SIZE +* - 0x12 F_ACCESS +* - 0x13 F_PERMISSION +* +* StreamID field reports a virtual device ID. To receive a virtual event for a +* device, a vDEVICE must be allocated via IOMMU_VDEVICE_ALLOC. +*/ +struct iommu_vevent_arm_smmuv3 { +__aligned_le64 evt[4 ]; +}; + +/** +* struct iommu_vevent_tegra241_cmdqv - Tegra241 CMDQV IRQ +* (IOMMU_VEVENTQ_TYPE_TEGRA241_CMDQV) +* @lvcmdq_err_map: 128-bit logical vcmdq error map, little-endian. +* (Refer to register LVCMDQ_ERR_MAPs per VINTF ) +* +* The 128-bit register value from HW exclusively reflect the error bits for a +* Virtual Interface represented by a vIOMMU object. Read and report directly. +*/ +struct iommu_vevent_tegra241_cmdqv { +__aligned_le64 lvcmdq_err_map[2 ]; +}; + +/** +* struct iommu_veventq_alloc - ioctl(IOMMU_VEVENTQ_ALLOC) +* @size: sizeof(struct iommu_veventq_alloc) +* @flags: Must be 0 +* @viommu_id: virtual IOMMU ID to associate the vEVENTQ with +* @type: Type of the vEVENTQ. Must be defined in enum iommu_veventq_type +* @veventq_depth: Maximum number of events in the vEVENTQ +* @out_veventq_id: The ID of the new vEVENTQ +* @out_veventq_fd: The fd of the new vEVENTQ. User space must close the +* successfully returned fd after using it +* @__reserved: Must be 0 +* +* Explicitly allocate a virtual event queue interface for a vIOMMU. A vIOMMU +* can have multiple FDs for different types, but is confined to one per @type. +* User space should open the @out_veventq_fd to read vEVENTs out of a vEVENTQ, +* if there are vEVENTs available. A vEVENTQ will lose events due to overflow, +* if the number of the vEVENTs hits @veventq_depth. +* +* Each vEVENT in a vEVENTQ encloses a struct iommufd_vevent_header followed by +* a type-specific data structure, in a normal case: +* +* +-+---------+-------+---------+-------+-----+---------+-------+-+ +* | | header0 | data0 | header1 | data1 | ... | headerN | dataN | | +* +-+---------+-------+---------+-------+-----+---------+-------+-+ +* +* unless a tailing IOMMU_VEVENTQ_FLAG_LOST_EVENTS header is logged (refer to +* struct iommufd_vevent_header). +*/ +struct iommu_veventq_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 type; +__u32 veventq_depth; +__u32 out_veventq_id; +__u32 out_veventq_fd; +__u32 __reserved; +}; +#define IOMMU_VEVENTQ_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VEVENTQ_ALLOC) + +/** +* enum iommu_hw_queue_type - HW Queue Type +* @IOMMU_HW_QUEUE_TYPE_DEFAULT: Reserved for future use +* @IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV: NVIDIA Tegra241 CMDQV (extension for ARM +* SMMUv3) Virtual Command Queue (VCMDQ) +*/ +enum iommu_hw_queue_type { +IOMMU_HW_QUEUE_TYPE_DEFAULT =0 , +/* +* TEGRA241_CMDQV requirements (otherwise, allocation will fail) +* - alloc starts from the lowest @index=0 in ascending order +* - destroy starts from the last allocated @index in descending order +* - @base_addr must be aligned to @length in bytes and mapped in IOAS +* - @length must be a power of 2, with a minimum 32 bytes and a maximum +* 2 ^ idr[1].CMDQS * 16 bytes (use GET_HW_INFO call to read idr[1] +* from struct iommu_hw_info_arm_smmuv3) +* - suggest to back the queue memory with contiguous physical pages or +* a single huge page with alignment of the queue size, and limit the +* emulated vSMMU's IDR1.CMDQS to log2(huge page size / 16 bytes) +*/ +IOMMU_HW_QUEUE_TYPE_TEGRA241_CMDQV =1 , +}; + +/** +* struct iommu_hw_queue_alloc - ioctl(IOMMU_HW_QUEUE_ALLOC) +* @size: sizeof(struct iommu_hw_queue_alloc) +* @flags: Must be 0 +* @viommu_id: Virtual IOMMU ID to associate the HW queue with +* @type: One of enum iommu_hw_queue_type +* @index: The logical index to the HW queue per virtual IOMMU for a multi-queue +* model +* @out_hw_queue_id: The ID of the new HW queue +* @nesting_parent_iova: Base address of the queue memory in the guest physical +* address space +* @length: Length of the queue memory +* +* Allocate a HW queue object for a vIOMMU-specific HW-accelerated queue, which +* allows HW to access a guest queue memory described using @nesting_parent_iova +* and @length. +* +* A vIOMMU can allocate multiple queues, but it must use a different @index per +* type to separate each allocation, e.g:: +* +* Type1 HW queue0, Type1 HW queue1, Type2 HW queue0, ... +*/ +struct iommu_hw_queue_alloc { +__u32 size; +__u32 flags; +__u32 viommu_id; +__u32 type; +__u32 index; +__u32 out_hw_queue_id; +__aligned_u64 nesting_parent_iova; +__aligned_u64 length; +}; +#define IOMMU_HW_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HW_QUEUE_ALLOC) +#endif
kernel/linux/uapi/linux/vduse.h +1 -1
@@ -237,7 +237,7 @@ struct vduse_iova_umem {* struct vduse_iova_info - information of one IOVA region * @start: start of the IOVA region * @last: last of the IOVA region -* @capability: capability of the IOVA regsion +* @capability: capability of the IOVA region * @reserved: for future use, needs to be initialized to zero * * Structure used by VDUSE_IOTLB_GET_INFO ioctl to get information of
kernel/linux/uapi/linux/vfio.h +11 -1
@@ -905,10 +905,12 @@ struct vfio_device_feature {* VFIO_DEVICE_BIND_IOMMUFD - _IOR(VFIO_TYPE, VFIO_BASE + 18, * struct vfio_device_bind_iommufd) * @argsz: User filled size of this data. -* @flags: Must be 0. +* @flags: Must be 0 or a bit flags of VFIO_DEVICE_BIND_* * @iommufd: iommufd to bind. * @out_devid: The device id generated by this bind. devid is a handle for * this device/iommufd bond and can be used in IOMMUFD commands. +* @token_uuid_ptr: Valid if VFIO_DEVICE_BIND_FLAG_TOKEN. Points to a 16 byte +* UUID in the same format as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN. * * Bind a vfio_device to the specified iommufd. *
@@ -917,13 +919,21 @@ struct vfio_device_feature {* * Unbind is automatically conducted when device fd is closed. * +* A token is sometimes required to open the device, unless this is known to be +* needed VFIO_DEVICE_BIND_FLAG_TOKEN should not be set and token_uuid_ptr is +* ignored. The only case today is a PF/VF relationship where the VF bind must +* be provided the same token as VFIO_DEVICE_FEATURE_PCI_VF_TOKEN provided to +* the PF. +* * Return: 0 on success, -errno on failure. */ struct vfio_device_bind_iommufd {__u32 argsz;__u32 flags; +#define VFIO_DEVICE_BIND_FLAG_TOKEN (1 << 0)__s32 iommufd;__u32 out_devid; +__aligned_u64 token_uuid_ptr; };#define VFIO_DEVICE_BIND_IOMMUFD _IO(VFIO_TYPE, VFIO_BASE + 18)
kernel/linux/uapi/version +1 -1
@@ -1 +1 @@ -v6.16 +v6.17
Signature · 1 line
2.52.0
Re: [PATCH v12 01/20] uapi: update to v6.17 and add iommufd.h
Quoted 6 lines · On Tue, 25 Aug 2026 14:20:58 +0100 Anatoly Burakov <[email protected]>…
In order to support VF tokens for cdev-based VFIO mode, kernel v6.17 is required. Update internal headers to version v6.17 and include
iommufd.h.Signed-off-by Anatoly Burakov <[email protected]>---
You should probably go to 7.2 kernel version if patch series gets updated. Since kernel / userspace is stable this would help.
PATCH v12 2/20 vfio: make all functions internal
In reply to Anatoly BurakovThe VFIO API is an externally exported API because the original intent was to offer DMA mapping facilities to applications. However, practical usage of this API seems to be centered around drivers, so keeping this API exported to applications only creates needless API/ABI stability surface that has no added value.
Make the entire VFIO API internal-only and visible only to drivers.
--- doc/guides/rel_notes/deprecation.rst | 6 ---- doc/guides/rel_notes/release_26_11.rst | 8 +++++ lib/eal/freebsd/eal.c | 30 ++++++++-------- lib/eal/include/rte_vfio.h | 47 ++++++++++++++++++++++---- lib/eal/linux/eal_vfio.c | 32 +++++++++--------- lib/eal/windows/eal.c | 4 +-- 6 files changed, 82 insertions(+), 45 deletions(-)
doc/guides/rel_notes/deprecation.rst +0 -6
@@ -29,12 +29,6 @@ Deprecation Notices Use the ``-S <service-corelist>`` parameter instead to specify the cores to be used for background services in DPDK. -* eal: The entire VFIO API (``rte_vfio_*``) will be made internal only, - and will only be available to EAL and drivers. - Group-based API (``rte_vfio_*_group_*``) will be removed - and replaced with unified container device assignment API. - This change will be made in 26.11 release. - * vdpa: The vDPA driver API will no longer offer ``get_vfio_group_fd`` as part of its internal API. All drivers will be adjusted to use the new unified VFIO container device assignment API.
doc/guides/rel_notes/release_26_11.rst +8 -0
@@ -93,6 +93,10 @@ API Changes Also, make sure to start the actual text at the margin. ======================================================= +* vfio: The entire VFIO API (``rte_vfio_*``) was made internal. + These functions are now available only to EAL and drivers, + and are no longer part of the public API. + ABI Changes -----------
@@ -109,6 +113,10 @@ ABI Changes Also, make sure to start the actual text at the margin. ======================================================= +* vfio: The entire VFIO API (``rte_vfio_*``) was made internal. + These functions are now available only to EAL and drivers, + and are no longer part of the public ABI. + Known Issues ------------
lib/eal/freebsd/eal.c +15 -15
@@ -819,7 +819,7 @@ rte_eal_vfio_get_vf_token(__rte_unused rte_uuid_t vf_token) { } -RTE_EXPORT_SYMBOL(rte_vfio_setup_device) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_setup_device) int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, __rte_unused int *vfio_dev_fd,
@@ -829,7 +829,7 @@ int rte_vfio_setup_device(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_release_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_release_device) int rte_vfio_release_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, __rte_unused int fd)
@@ -838,33 +838,33 @@ int rte_vfio_release_device(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_enable) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_enable) int rte_vfio_enable(__rte_unused const char *modname) { rte_errno =ENOTSUP ;return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_is_enabled) int rte_vfio_is_enabled(__rte_unused const char *modname) {return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_noiommu_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) int rte_vfio_noiommu_is_enabled(void) {return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_clear_group) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) int rte_vfio_clear_group(__rte_unused int vfio_group_fd) { rte_errno =ENOTSUP ;return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_get_group_num) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr,
@@ -874,7 +874,7 @@ rte_vfio_get_group_num(__rte_unused const char *sysfs_base,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_container_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_container_fd) intrte_vfio_get_container_fd (void ) {
@@ -882,7 +882,7 @@ rte_vfio_get_container_fd(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) int rte_vfio_get_group_fd(__rte_unused int iommu_group_num) {
@@ -890,7 +890,7 @@ rte_vfio_get_group_fd(__rte_unused int iommu_group_num)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_create) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void ) {
@@ -898,7 +898,7 @@ rte_vfio_container_create(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_destroy) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_destroy) int rte_vfio_container_destroy(__rte_unused int container_fd) {
@@ -906,7 +906,7 @@ rte_vfio_container_destroy(__rte_unused int container_fd)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_bind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) int rte_vfio_container_group_bind(__rte_unused int container_fd, __rte_unused int iommu_group_num)
@@ -915,7 +915,7 @@ rte_vfio_container_group_bind(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_unbind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) int rte_vfio_container_group_unbind(__rte_unused int container_fd, __rte_unused int iommu_group_num)
@@ -924,7 +924,7 @@ rte_vfio_container_group_unbind(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
@@ -935,7 +935,7 @@ rte_vfio_container_dma_map(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_unmap) int rte_vfio_container_dma_unmap(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
lib/eal/include/rte_vfio.h +41 -6
214 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +16 -16
@@ -532,7 +532,7 @@ get_vfio_cfg_by_container_fd(int container_fd)return NULL ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) intrte_vfio_get_group_fd (int iommu_group_num) {
@@ -731,7 +731,7 @@ vfio_sync_default_container(void)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_clear_group) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) intrte_vfio_clear_group (int vfio_group_fd) {
@@ -755,7 +755,7 @@ rte_vfio_clear_group(int vfio_group_fd)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_setup_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) intrte_vfio_setup_device (const char *sysfs_base,const char *dev_addr,int *vfio_dev_fd,struct vfio_device_info *device_info)
@@ -1009,7 +1009,7 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_release_device) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_release_device) intrte_vfio_release_device (const char *sysfs_base,const char *dev_addr,int vfio_dev_fd)
@@ -1098,7 +1098,7 @@ rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,return ret; } -RTE_EXPORT_SYMBOL (rte_vfio_enable) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_enable) intrte_vfio_enable (const char *modname) {
@@ -1175,7 +1175,7 @@ rte_vfio_enable(const char *modname)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_is_enabled) intrte_vfio_is_enabled (const char *modname) {
@@ -1215,7 +1215,7 @@ vfio_set_iommu_type(int vfio_container_fd)return NULL ; } -RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_vfio_get_device_info, 24.03) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) intrte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr,int *vfio_dev_fd,struct vfio_device_info *device_info)
@@ -1349,7 +1349,7 @@ vfio_open_container_fd(bool mp_request)return -1 ; } -RTE_EXPORT_SYMBOL (rte_vfio_get_container_fd) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_container_fd) intrte_vfio_get_container_fd (void ) {
@@ -1363,7 +1363,7 @@ rte_vfio_get_container_fd(void)return default_vfio_cfg->vfio_container_fd; } -RTE_EXPORT_SYMBOL (rte_vfio_get_group_num) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_num) intrte_vfio_get_group_num (const char *sysfs_base,const char *dev_addr,int *iommu_group_num)
@@ -2034,7 +2034,7 @@ container_dma_unmap(struct vfio_config *vfio_cfg, uint64_t vaddr, uint64_t iova,return ret; } -RTE_EXPORT_SYMBOL (rte_vfio_noiommu_is_enabled) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_noiommu_is_enabled) intrte_vfio_noiommu_is_enabled (void ) {
@@ -2067,7 +2067,7 @@ rte_vfio_noiommu_is_enabled(void)return c =='Y' ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_create) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void ) {
@@ -2094,7 +2094,7 @@ rte_vfio_container_create(void)return vfio_cfgs[i].vfio_container_fd; } -RTE_EXPORT_SYMBOL (rte_vfio_container_destroy) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_destroy) intrte_vfio_container_destroy (int container_fd) {
@@ -2120,7 +2120,7 @@ rte_vfio_container_destroy(int container_fd)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_bind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) intrte_vfio_container_group_bind (int container_fd,int iommu_group_num) {
@@ -2135,7 +2135,7 @@ rte_vfio_container_group_bind(int container_fd, int iommu_group_num)return vfio_get_group_fd (vfio_cfg, iommu_group_num); } -RTE_EXPORT_SYMBOL (rte_vfio_container_group_unbind) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) intrte_vfio_container_group_unbind (int container_fd,int iommu_group_num) {
@@ -2176,7 +2176,7 @@ rte_vfio_container_group_unbind(int container_fd, int iommu_group_num)return 0 ; } -RTE_EXPORT_SYMBOL (rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_dma_map) intrte_vfio_container_dma_map (int container_fd,uint64_t vaddr,uint64_t iova,uint64_t len)
@@ -2197,7 +2197,7 @@ rte_vfio_container_dma_map(int container_fd, uint64_t vaddr, uint64_t iova,return container_dma_map (vfio_cfg, vaddr, iova, len); } -RTE_EXPORT_SYMBOL (rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_dma_unmap) intrte_vfio_container_dma_unmap (int container_fd,uint64_t vaddr,uint64_t iova,uint64_t len)
lib/eal/windows/eal.c +2 -2
@@ -453,7 +453,7 @@ eal_asprintf(char **buffer, const char *format, ...)return ret; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_map) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
@@ -464,7 +464,7 @@ rte_vfio_container_dma_map(__rte_unused int container_fd,return -1 ; } -RTE_EXPORT_SYMBOL(rte_vfio_container_dma_unmap) +RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_unmap) int rte_vfio_container_dma_unmap(__rte_unused int container_fd, __rte_unused uint64_t vaddr,
Signature · 1 line
2.52.0
PATCH v12 3/20 bus/pci: rename mismatching error labels
In reply to Anatoly BurakovCurrently, there are two VFIO map functions - primary and secondary - that use a very similar goto error pattern. However, the label names are confusing.
Specifically, for primary, we have three error labels: vfio_res (release VFIO resource), vfio_dev_fd (close the fd), and map (unmap all the mapped regions). For secondary, there is vfio_dev (close the fd), and vfio_dev_fd (unmap all mapped regions).
For consistency, align secondary process function's error labels to match semantics of how they work in primary process function.
--- drivers/bus/pci/linux/pci_vfio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/bus/pci/linux/pci_vfio.c +7 -7
@@ -968,7 +968,7 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) ret =pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info);if (ret) - goto err_vfio_dev; + goto err_vfio_dev_fd;/* map BARs */ maps = vfio_res->maps;
@@ -979,14 +979,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)if (ret <0 ) {PCI_LOG (ERR ,"%s sparse mapping BAR%i failed: %s" , pci_addr, i,strerror (errno)); - goto err_vfio_dev_fd; + goto err_map; } }else { ret =pci_vfio_mmap_bar (vfio_dev_fd, vfio_res, i,MAP_FIXED );if (ret <0 ) {PCI_LOG (ERR ,"%s mapping BAR%i failed: %s" , pci_addr, i,strerror (errno)); - goto err_vfio_dev_fd; + goto err_map; } }
@@ -995,17 +995,17 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev)/* we need save vfio_dev_fd, so it can be used during release */ if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd)) - goto err_vfio_dev_fd; + goto err_map;if (rte_intr_dev_fd_set (dev->vfio_req_intr_handle, vfio_dev_fd)) - goto err_vfio_dev_fd; + goto err_map;return 0 ; -err_vfio_dev_fd: +err_map:for (j =0 ; j < i; j++) {if (maps[j].addr)pci_unmap_resource (maps[j].addr, maps[j].size); } -err_vfio_dev: +err_vfio_dev_fd:rte_vfio_release_device (rte_pci_get_sysfs_path (), pci_addr, vfio_dev_fd);return -1 ;
Signature · 1 line
2.52.0
PATCH v12 4/20 vfio: split get device info from setup
In reply to Anatoly BurakovCurrently, setup gets device info as part of setup, while the separate get device info API also calls setup if the fd is zero. Untangle these two APIs and make each do one thing, and adjust all existing callers.
--- drivers/bus/cdx/cdx_vfio.c | 12 ++++++++-- drivers/bus/pci/linux/pci_vfio.c | 18 ++++++++++---- drivers/bus/platform/platform.c | 9 ++++++- drivers/crypto/bcmfs/bcmfs_vfio.c | 8 ++++++- lib/eal/freebsd/eal.c | 3 +-- lib/eal/include/rte_vfio.h | 23 +++++++----------- lib/eal/linux/eal_vfio.c | 40 +++++++++---------------------- 7 files changed, 59 insertions(+), 54 deletions(-)
drivers/bus/cdx/cdx_vfio.c +10 -2
@@ -401,10 +401,14 @@ cdx_vfio_map_resource_primary(struct rte_cdx_device *dev)return -1 ; ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* allocate vfio_res and get region info */ vfio_res =rte_zmalloc ("VFIO_RES" ,sizeof (*vfio_res),0 );if (vfio_res ==NULL ) {
@@ -510,10 +514,14 @@ cdx_vfio_map_resource_secondary(struct rte_cdx_device *dev) } ret =rte_vfio_setup_device (RTE_CDX_BUS_DEVICES_PATH , dev_name, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +/* map MMIO regions */ maps = vfio_res->maps;
drivers/bus/pci/linux/pci_vfio.c +14 -4
@@ -753,10 +753,14 @@ pci_vfio_map_resource_primary(struct rte_pci_device *dev) loc->domain, loc->bus, loc->devid, loc->function); ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; +if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd)) goto err_vfio_dev_fd;
@@ -962,10 +966,14 @@ pci_vfio_map_resource_secondary(struct rte_pci_device *dev) } ret =rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info); + &vfio_dev_fd);if (ret)return ret; + ret =rte_vfio_get_device_info (vfio_dev_fd, &device_info); +if (ret) + goto err_vfio_dev_fd; + ret =pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info);if (ret) goto err_vfio_dev_fd;
@@ -1195,12 +1203,14 @@ pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,if (vfio_dev_fd <0 ) {return -1 ; }else if (vfio_dev_fd ==0 ) { -if (rte_vfio_get_device_info (rte_pci_get_sysfs_path (), pci_addr, - &vfio_dev_fd, &device_info) !=0 ) +if (rte_vfio_setup_device (rte_pci_get_sysfs_path (), pci_addr, + &vfio_dev_fd) !=0 )return -1 ;/* save vfio_dev_fd so it can be used during release */ if (rte_intr_dev_fd_set (dev->intr_handle, vfio_dev_fd) !=0 )return -1 ; +if (rte_vfio_get_device_info (vfio_dev_fd, &device_info) !=0 ) +return -1 ;if (pci_vfio_fill_regions (dev, vfio_dev_fd, &device_info) !=0 )return -1 ;
drivers/bus/platform/platform.c +8 -1
@@ -292,12 +292,19 @@ device_setup(struct rte_platform_device *pdev)const char *name = pdev->name;int ret; - ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd, &dev_info); + ret =rte_vfio_setup_device (PLATFORM_BUS_DEVICES_PATH , name, &pdev->dev_fd);if (ret) {PLATFORM_LOG_LINE (ERR ,"failed to setup %s" , name);return -ENODEV ; } + ret =rte_vfio_get_device_info (pdev->dev_fd, &dev_info); +if (ret) { +PLATFORM_LOG_LINE (ERR ,"failed to get device info for %s" , name); + ret = -ENODEV ; + goto out; + } +/* This is an extra check to confirm that platform device was initialized * by a kernel vfio-platform driver. On kernels that predate vfio-platform * driver this flag obviously does not exist. In such scenarios this
drivers/crypto/bcmfs/bcmfs_vfio.c +7 -1
@@ -25,12 +25,18 @@ vfio_map_dev_obj(const char *path, const char *dev_obj,struct vfio_device_info d_info = { .argsz =sizeof (d_info) };struct vfio_region_info reg_info = { .argsz =sizeof (reg_info) }; - ret =rte_vfio_setup_device (path, dev_obj, dev_fd, &d_info); + ret =rte_vfio_setup_device (path, dev_obj, dev_fd);if (ret) {BCMFS_LOG (ERR ,"VFIO Setting for device failed" );return ret; } + ret =rte_vfio_get_device_info (*dev_fd, &d_info); +if (ret) { +BCMFS_LOG (ERR ,"VFIO Getting device info failed" ); + goto map_failed; + } +/* getting device region info*/ ret =ioctl (*dev_fd,VFIO_DEVICE_GET_REGION_INFO , ®_info);if (ret <0 ) {
lib/eal/freebsd/eal.c +1 -2
@@ -822,8 +822,7 @@ rte_eal_vfio_get_vf_token(__rte_unused rte_uuid_t vf_token)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr, - __rte_unused int *vfio_dev_fd, - __rte_unused struct vfio_device_info *device_info) + __rte_unused int *vfio_dev_fd) { rte_errno =ENOTSUP ;return -1 ;
lib/eal/include/rte_vfio.h +8 -15
@@ -55,10 +55,7 @@ struct vfio_device_info;* device location. * * @param vfio_dev_fd -* VFIO fd. -* -* @param device_info -* Device information. +* Pointer to VFIO fd, will be set to the opened device fd on success. * * @return * 0 on success.
@@ -67,7 +64,7 @@ struct vfio_device_info;*/ __rte_internal int rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +int *vfio_dev_fd);/** * @internal
@@ -187,19 +184,16 @@ rte_vfio_get_group_num(const char *sysfs_base,* @internal * Get device information. * +* This function retrieves VFIO device information from an already opened +* device. The device must be opened with rte_vfio_setup_device() first. +* * This function is only relevant to Linux and will return an error on BSD. * -* @param sysfs_base -* sysfs path prefix. -* -* @param dev_addr -* device location. -* * @param vfio_dev_fd -* VFIO fd. +* VFIO device fd (must be a valid, already opened fd). * * @param device_info -* Device information. +* Pointer to device information structure to be filled. * * @return * 0 on success.
@@ -207,8 +201,7 @@ rte_vfio_get_group_num(const char *sysfs_base,*/ __rte_internal int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info); +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info);/** * @internal
lib/eal/linux/eal_vfio.c +11 -29
@@ -758,7 +758,7 @@ rte_vfio_clear_group(int vfio_group_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_setup_device) intrte_vfio_setup_device (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +int *vfio_dev_fd) {struct vfio_group_status group_status = { .argsz =sizeof (group_status)
@@ -975,7 +975,7 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, *vfio_dev_fd =ioctl (vfio_group_fd,VFIO_GROUP_GET_DEVICE_FD , dev);if (*vfio_dev_fd >=0 ) - goto dev_get_info; + goto out; }/* get a file descriptor for the device */
@@ -992,18 +992,8 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,return -1 ; } -/* test and setup the device */ -dev_get_info: - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, " -"error %i (%s)" , dev_addr, errno, -strerror (errno)); -close (*vfio_dev_fd); -close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); -return -1 ; - } +/* device is now set up */ +out:vfio_group_device_get (vfio_group_fd);return 0 ;
@@ -1217,26 +1207,18 @@ vfio_set_iommu_type(int vfio_container_fd)RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_device_info) int -rte_vfio_get_device_info (const char *sysfs_base,const char *dev_addr, -int *vfio_dev_fd,struct vfio_device_info *device_info) +rte_vfio_get_device_info (int vfio_dev_fd,struct vfio_device_info *device_info) {int ret; -if (device_info ==NULL || *vfio_dev_fd <0 ) +if (device_info ==NULL || vfio_dev_fd <0 )return -1 ; -if (*vfio_dev_fd ==0 ) { - ret =rte_vfio_setup_device (sysfs_base, dev_addr, - vfio_dev_fd, device_info); -if (ret) -return -1 ; - }else { - ret =ioctl (*vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); -if (ret) { -EAL_LOG (ERR ,"%s cannot get device info, error %i (%s)" , - dev_addr, errno,strerror (errno)); -return -1 ; - } + ret =ioctl (vfio_dev_fd,VFIO_DEVICE_GET_INFO , device_info); +if (ret) { +EAL_LOG (ERR ,"Cannot get device info, error %i (%s)" , + errno,strerror (errno)); +return -1 ; }return 0 ;
Signature · 1 line
2.52.0
PATCH v12 5/20 vfio: add container device assignment API
In reply to Anatoly BurakovCurrently, VFIO has explicit group bind API's, but the way they're used is such that no one actually cares about VFIO groups, and the real goal of everyone using VFIO group bind API is to bind devices to particular VFIO container, such that when rte_vfio_setup_device call eventually comes, VFIO will pick up the correct container.
To remove dependency on group API's, add a new "container assign device" API call that will do the same thing, but will not depend on managing VFIO group fd's.
--- lib/eal/freebsd/eal.c | 10 ++++++++++ lib/eal/include/rte_vfio.h | 26 ++++++++++++++++++++++++++ lib/eal/linux/eal_vfio.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+)
lib/eal/freebsd/eal.c +10 -0
@@ -944,3 +944,13 @@ rte_vfio_container_dma_unmap(__rte_unused int container_fd, rte_errno =ENOTSUP ;return -1 ; } + +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device(__rte_unused int vfio_container_fd, + __rte_unused const char *sysfs_base, + __rte_unused const char *dev_addr) +{ + rte_errno =ENOTSUP ; +return -1 ; +}
lib/eal/include/rte_vfio.h +26 -0
@@ -271,6 +271,32 @@ __rte_internalint rte_vfio_container_destroy (int container_fd); +/** +* @internal +* +* Assign a device to a VFIO container. +* +* Doing so will cause `rte_vfio_setup_device()` to set up the device with the VFIO container +* specified in this assign operation. +* +* This function is only relevant on Linux. +* +* @param vfio_container_fd +* VFIO container file descriptor. +* @param sysfs_base +* Sysfs path prefix. +* @param dev_addr +* Device identifier. +* +* @return +* 0 on success. +* <0 on failure. +*/ +__rte_internal +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr); +/** * @internal * Bind a IOMMU group to a container.
lib/eal/linux/eal_vfio.c +32 -0
@@ -2102,6 +2102,38 @@ rte_vfio_container_destroy(int container_fd)return 0 ; } +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_assign_device) +int +rte_vfio_container_assign_device (int vfio_container_fd,const char *sysfs_base, +const char *dev_addr) +{ +int iommu_group_num; +int ret; + + ret =rte_vfio_get_group_num (sysfs_base, dev_addr, &iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR ,"Cannot get IOMMU group number for device %s" , + dev_addr); +return -1 ; + }else if (ret ==0 ) { +EAL_LOG (ERR , +"Device %s is not assigned to any IOMMU group" , + dev_addr); +return -1 ; + } + + ret =rte_vfio_container_group_bind (vfio_container_fd, + iommu_group_num); +if (ret <0 ) { +EAL_LOG (ERR , +"Cannot bind IOMMU group %d for device %s" , + iommu_group_num, dev_addr); +return -1 ; + } + +return 0 ; +} +RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) intrte_vfio_container_group_bind (int container_fd,int iommu_group_num)
Signature · 1 line
2.52.0
PATCH v12 6/20 net/nbl: do not use VFIO group bind API
In reply to Anatoly BurakovThe NBL driver currently uses group bind API, but it is using it only to get group fd and nothing else. In context of NBL driver, this is the only usage of VFIO API's in the driver, and it is not necessary to use it for what NBL driver is trying to accomplish.
Use a direct open() call instead, and store the group fd in common structure.
--- drivers/net/nbl/nbl_common/nbl_userdev.c | 20 +++++++++++++------- drivers/net/nbl/nbl_include/nbl_include.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-)
drivers/net/nbl/nbl_common/nbl_userdev.c +13 -7
@@ -387,6 +387,15 @@ nbl_userdev_mem_event_callback(enum rte_mem_event type, const void *addr, size_t } } +static int +nbl_open_group_fd (int iommu_group_num) +{ +char path[PATH_MAX ]; + +snprintf (path,sizeof (path),RTE_VFIO_GROUP_FMT , iommu_group_num); +return open (path,O_RDWR ); +} +static int nbl_mdev_map_device (struct nbl_adapter *adapter) {const struct rte_pci_device *pci_dev = adapter->pci_dev;
@@ -424,11 +433,12 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) }NBL_LOG (DEBUG ,"nbl vfio container %d" , container); - vfio_group_fd =rte_vfio_container_group_bind (container, common->iommu_group_num); + vfio_group_fd =nbl_open_group_fd (common->iommu_group_num);if (vfio_group_fd <0 ) {NBL_LOG (ERR ,"nbl vfio group bind failed, %d" , vfio_group_fd); goto free_container; } + common->groupfd = vfio_group_fd;/* check if the group is viable */ ret =ioctl (vfio_group_fd,VFIO_GROUP_GET_STATUS , &group_status);
@@ -535,7 +545,6 @@ static int nbl_mdev_map_device(struct nbl_adapter *adapter) } free_group:close (vfio_group_fd); -rte_vfio_clear_group (vfio_group_fd); free_container:if (container_create)rte_vfio_container_destroy (container);
@@ -549,17 +558,14 @@ static int nbl_mdev_unmap_device(struct nbl_adapter *adapter)close (common->devfd);rte_mcfg_mem_read_lock (); - vfio_group_fd =rte_vfio_container_group_bind (nbl_default_container, - common->iommu_group_num); + vfio_group_fd = common->groupfd;NBL_LOG (DEBUG ,"close vfio_group_fd %d" , vfio_group_fd); ret =ioctl (vfio_group_fd,VFIO_GROUP_UNSET_CONTAINER , &nbl_default_container);if (ret)NBL_LOG (ERR ,"unset container, error %i (%s) %d" , errno,strerror (errno), ret); nbl_group_count--; - ret =rte_vfio_container_group_unbind (nbl_default_container, common->iommu_group_num); -if (ret) -NBL_LOG (ERR ,"vfio container group unbind failed %d" , ret); +close (vfio_group_fd);if (!nbl_group_count) {rte_mem_event_callback_unregister (NBL_USERDEV_EVENT_CLB_NAME ,NULL );nbl_userdev_dma_free ();
drivers/net/nbl/nbl_include/nbl_include.h +1 -0
@@ -132,6 +132,7 @@ struct nbl_common_info {u16 vsi_id;u16 instance_id;int devfd; +int groupfd;int eventfd;int ifindex;int iommu_group_num;
Signature · 1 line
2.52.0
PATCH v12 7/20 net/ntnic: use container device assignment API
In reply to Anatoly BurakovThe NTNIC driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/net/ntnic/ntnic_vfio.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-)
drivers/net/ntnic/ntnic_vfio.c +9 -21
@@ -28,7 +28,6 @@ nt_vfio_vf_num(const struct rte_pci_device *pdev)/* Internal API */ struct vfio_dev {int container_fd; -int group_fd;int dev_fd;uint64_t iova_addr; };
@@ -50,7 +49,6 @@ nthw_vfio_setup(struct rte_pci_device *dev) {int ret;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num;int vf_num;struct vfio_dev *vfio;
@@ -66,14 +64,9 @@ nthw_vfio_setup(struct rte_pci_device *dev) } vfio->dev_fd =-1 ; - vfio->group_fd =-1 ; vfio->iova_addr =START_VF_IOVA ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, &iommu_group_num); -if (ret <=0 ) -return -1 ; -if (vf_num ==0 ) {/* use default container for pf0 */ vfio->container_fd =RTE_VFIO_DEFAULT_CONTAINER_FD ;
@@ -86,17 +79,14 @@ nthw_vfio_setup(struct rte_pci_device *dev) "VFIO device setup failed. VFIO container creation failed.");return -1 ; } - } + ret =rte_vfio_container_assign_device (vfio->container_fd, +rte_pci_get_sysfs_path (), devname); +if (ret <0 ) { +NT_LOG (ERR ,NTNIC , +"VFIO device setup failed. Assign device to container failed." ); + goto err; + } - vfio->group_fd =rte_vfio_container_group_bind (vfio->container_fd, iommu_group_num); - -if (vfio->group_fd <0 ) { -NT_LOG (ERR ,NTNIC , -"VFIO device setup failed. VFIO container group bind failed." ); - goto err; - } - -if (vf_num >0 ) {if (rte_pci_map_device (dev)) {NT_LOG (ERR ,NTNIC ,"Map VFIO device failed. is the vfio-pci driver loaded?" );
@@ -106,10 +96,8 @@ nthw_vfio_setup(struct rte_pci_device *dev) vfio->dev_fd =rte_intr_dev_fd_get (dev->intr_handle); -NT_LOG (DBG ,NTNIC , -"%s: VFIO id=%d, dev_fd=%d, container_fd=%d, group_fd=%d, iommu_group_num=%d" , - dev->name, vf_num, vfio->dev_fd, vfio->container_fd, vfio->group_fd, - iommu_group_num); +NT_LOG (DBG ,NTNIC ,"%s: VFIO id=%d, dev_fd=%d, container_fd=%d" , + dev->name, vf_num, vfio->dev_fd, vfio->container_fd);return vf_num;
Signature · 1 line
2.52.0
PATCH v12 8/20 vdpa/ifc: use container device assignment API
In reply to Anatoly BurakovThe IFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/ifc/ifcvf_vdpa.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-)
drivers/vdpa/ifc/ifcvf_vdpa.c +3 -31
@@ -58,7 +58,6 @@ struct ifcvf_internal {struct ifcvf_hw hw;int configured;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd;rte_thread_t tid;/* thread for notify relay */ rte_thread_t intr_tid;/* thread for config space change interrupt relay */
@@ -174,28 +173,19 @@ ifcvf_vfio_setup(struct ifcvf_internal *internal) {struct rte_pci_device *dev = internal->pdev;char devname[RTE_DEV_NAME_MAX_LEN ] = {0 }; -int iommu_group_num; -int i, ret; +int i; internal->vfio_dev_fd =-1 ; - internal->vfio_group_fd =-1 ; internal->vfio_container_fd =-1 ;rte_pci_device_name (&dev->addr, devname,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), devname, - &iommu_group_num); -if (ret <=0 ) { -DRV_LOG (ERR ,"%s failed to get IOMMU group" , devname); -return -1 ; - } internal->vfio_container_fd =rte_vfio_container_create ();if (internal->vfio_container_fd <0 )return -1 ; - internal->vfio_group_fd =rte_vfio_container_group_bind ( - internal->vfio_container_fd, iommu_group_num); -if (internal->vfio_group_fd <0 ) +if (rte_vfio_container_assign_device (internal->vfio_container_fd, +rte_pci_get_sysfs_path (), devname) <0 ) goto err;if (rte_pci_map_device (dev))
@@ -1213,22 +1203,6 @@ ifcvf_set_features(int vid)return 0 ; } -static int -ifcvf_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct internal_list *list; - - vdev =rte_vhost_get_vdpa_device (vid); - list =find_internal_resource_by_vdev (vdev); -if (list ==NULL ) { -DRV_LOG (ERR ,"Invalid vDPA device: %p" , vdev); -return -1 ; - } - -return list->internal->vfio_group_fd; -} -static int ifcvf_get_vfio_device_fd (int vid) {
@@ -1474,7 +1448,6 @@ static struct rte_vdpa_dev_ops ifcvf_net_ops = { .set_vring_state = ifcvf_set_vring_state, .set_features = ifcvf_set_features, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_dev_type = ifcvf_get_device_type,
@@ -1605,7 +1578,6 @@ static struct rte_vdpa_dev_ops ifcvf_blk_ops = { .dev_close = ifcvf_dev_close, .set_vring_state = ifcvf_set_vring_state, .migration_done = NULL, - .get_vfio_group_fd = ifcvf_get_vfio_group_fd, .get_vfio_device_fd = ifcvf_get_vfio_device_fd, .get_notify_area = ifcvf_get_notify_area, .get_config = ifcvf_blk_get_config,
Signature · 1 line
2.52.0
PATCH v12 9/20 vdpa/nfp: use container device assignment API
In reply to Anatoly BurakovThe NFP vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics. Since group API is no longer used after these changes, remove its implementation.
--- drivers/vdpa/nfp/nfp_vdpa.c | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-)
drivers/vdpa/nfp/nfp_vdpa.c +5 -32
@@ -36,9 +36,7 @@ struct nfp_vdpa_dev {struct nfp_vdpa_hw hw;int vfio_container_fd; -int vfio_group_fd;int vfio_dev_fd; -int iommu_group;rte_thread_t tid;/**< Thread for notify relay */ int epoll_fd;
@@ -120,33 +118,26 @@ nfp_vdpa_vfio_setup(struct nfp_vdpa_dev *device)struct rte_pci_device *pci_dev = device->pci_dev;rte_pci_device_name (&pci_dev->addr, dev_name,RTE_DEV_NAME_MAX_LEN ); - ret =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &device->iommu_group); -if (ret <=0 ) -return -1 ; device->vfio_container_fd =rte_vfio_container_create ();if (device->vfio_container_fd <0 )return -1 ; - device->vfio_group_fd =rte_vfio_container_group_bind ( - device->vfio_container_fd, device->iommu_group); -if (device->vfio_group_fd <0 ) + ret =rte_vfio_container_assign_device (device->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (ret <0 ) goto container_destroy; -DRV_VDPA_LOG (DEBUG ,"The container_fd=%d, group_fd=%d." , - device->vfio_container_fd, device->vfio_group_fd); +DRV_VDPA_LOG (DEBUG ,"container_fd=%d" , device->vfio_container_fd); ret =rte_pci_map_device (pci_dev);if (ret !=0 ) - goto group_unbind; + goto container_destroy; device->vfio_dev_fd =rte_intr_dev_fd_get (pci_dev->intr_handle);return 0 ; -group_unbind: -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group); container_destroy:rte_vfio_container_destroy (device->vfio_container_fd);
@@ -157,7 +148,6 @@ static void nfp_vdpa_vfio_teardown(struct nfp_vdpa_dev *device) {rte_pci_unmap_device (device->pci_dev); -rte_vfio_container_group_unbind (device->vfio_container_fd, device->iommu_group);rte_vfio_container_destroy (device->vfio_container_fd); }
@@ -1023,22 +1013,6 @@ nfp_vdpa_dev_close(int vid)return 0 ; } -static int -nfp_vdpa_get_vfio_group_fd (int vid) -{ -struct rte_vdpa_device *vdev; -struct nfp_vdpa_dev_node *node; - - vdev =rte_vhost_get_vdpa_device (vid); - node =nfp_vdpa_find_node_by_vdev (vdev); -if (node ==NULL ) { -DRV_VDPA_LOG (ERR ,"Invalid vDPA device: %p." , vdev); -return -ENODEV ; - } - -return node->device->vfio_group_fd; -} -static int nfp_vdpa_get_vfio_device_fd (int vid) {
@@ -1190,7 +1164,6 @@ struct rte_vdpa_dev_ops nfp_vdpa_ops = { .dev_close = nfp_vdpa_dev_close, .set_vring_state = nfp_vdpa_set_vring_state, .set_features = nfp_vdpa_set_features, - .get_vfio_group_fd = nfp_vdpa_get_vfio_group_fd, .get_vfio_device_fd = nfp_vdpa_get_vfio_device_fd, .get_notify_area = nfp_vdpa_get_notify_area, };
Signature · 1 line
2.52.0
PATCH v12 10/20 vdpa/sfc: use container device assignment API
In reply to Anatoly BurakovThe SFC vDPA driver uses VFIO group bind/unbind functionality for container device assignment purposes. Use the new container device assignment API instead to provide clearer semantics.
--- drivers/vdpa/sfc/sfc_vdpa.c | 39 +++++++------------------------------ drivers/vdpa/sfc/sfc_vdpa.h | 2 -- 2 files changed, 7 insertions(+), 34 deletions(-)
drivers/vdpa/sfc/sfc_vdpa.c +7 -32
@@ -80,22 +80,12 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva) goto fail_container_create; } - rc =rte_vfio_get_group_num (rte_pci_get_sysfs_path (), dev_name, - &sva->iommu_group_num); -if (rc <=0 ) { -sfc_vdpa_err (sva,"failed to get IOMMU group for %s : %s" , - dev_name,rte_strerror (-rc)); - goto fail_get_group_num; - } - - sva->vfio_group_fd = -rte_vfio_container_group_bind (sva->vfio_container_fd, - sva->iommu_group_num); -if (sva->vfio_group_fd <0 ) { -sfc_vdpa_err (sva, -"failed to bind IOMMU group %d to container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - goto fail_group_bind; + rc =rte_vfio_container_assign_device (sva->vfio_container_fd, +rte_pci_get_sysfs_path (), dev_name); +if (rc <0 ) { +sfc_vdpa_err (sva,"failed to assign device %s to container %d" , + dev_name, sva->vfio_container_fd); + goto fail_device_assign; }if (rte_pci_map_device (dev) !=0 ) {
@@ -109,15 +99,7 @@ sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva)return 0 ; fail_pci_map_device: -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } - -fail_group_bind: -fail_get_group_num: +fail_device_assign:if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) {sfc_vdpa_err (sva,"failed to destroy container %d" , sva->vfio_container_fd);
@@ -132,13 +114,6 @@ sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter *sva) {rte_pci_unmap_device (sva->pdev); -if (rte_vfio_container_group_unbind (sva->vfio_container_fd, - sva->iommu_group_num) !=0 ) { -sfc_vdpa_err (sva, -"failed to unbind IOMMU group %d from container %d" , - sva->iommu_group_num, sva->vfio_container_fd); - } -if (rte_vfio_container_destroy (sva->vfio_container_fd) !=0 ) { sfc_vdpa_err(sva, "failed to destroy container %d",
drivers/vdpa/sfc/sfc_vdpa.h +0 -2
@@ -70,10 +70,8 @@ struct sfc_vdpa_adapter {sfc_vdpa_filter_t filters; -int vfio_group_fd;int vfio_dev_fd;int vfio_container_fd; -int iommu_group_num;struct sfc_vdpa_ops_data *ops_data; };
Signature · 1 line
2.52.0
PATCH v12 11/20 vdpa/mlx5: remove group-related API
In reply to Anatoly BurakovThe mlx5 driver does not use the get_group_fd API provided by vDPA. This API is about to be removed, so remove its mention from mlx5.
--- drivers/vdpa/mlx5/mlx5_vdpa.c | 1 - 1 file changed, 1 deletion(-)
drivers/vdpa/mlx5/mlx5_vdpa.c +0 -1
@@ -523,7 +523,6 @@ static struct rte_vdpa_dev_ops mlx5_vdpa_ops = { .set_vring_state = mlx5_vdpa_set_vring_state, .set_features = mlx5_vdpa_features_set, .migration_done = NULL, - .get_vfio_group_fd = NULL, .get_vfio_device_fd = mlx5_vdpa_get_device_fd, .get_notify_area = mlx5_vdpa_get_notify_area, .get_stats_names = mlx5_vdpa_get_stats_names,
Signature · 1 line
2.52.0
PATCH v12 12/20 vhost: remove group-related API from driver
In reply to Anatoly BurakovThe vDPA driver API has "get_vfio_group_fd" in its ops structure, but no driver is using it any more, as better API's were added and implemented. Remove this API from vDPA ops structure.
--- doc/guides/prog_guide/vhost_lib.rst | 4 ---- doc/guides/rel_notes/deprecation.rst | 4 ---- lib/vhost/vdpa_driver.h | 3 --- 3 files changed, 11 deletions(-)
doc/guides/prog_guide/vhost_lib.rst +0 -4
@@ -471,10 +471,6 @@ Finally, a set of device ops is defined for device specific operations: Called to allow the device to respond to RARP sending. -* ``get_vfio_group_fd`` - - Called to get the VFIO group fd of the device. - * ``get_vfio_device_fd`` Called to get the VFIO device fd of the device.
doc/guides/rel_notes/deprecation.rst +0 -4
@@ -29,10 +29,6 @@ Deprecation Notices Use the ``-S <service-corelist>`` parameter instead to specify the cores to be used for background services in DPDK. -* vdpa: The vDPA driver API will no longer offer ``get_vfio_group_fd`` - as part of its internal API. All drivers will be adjusted - to use the new unified VFIO container device assignment API. - * rte_atomicNN_xxx: These APIs do not take memory order parameter. This does not allow for writing optimized code for all the CPU architectures supported in DPDK. DPDK has adopted the atomic operations from
lib/vhost/vdpa_driver.h +0 -3
@@ -50,9 +50,6 @@ struct rte_vdpa_dev_ops {/** Destination operations when migration done */ int (*migration_done)(int vid); -/** Get the vfio group fd */ -int (*get_vfio_group_fd)(int vid); -/** Get the vfio device fd */ int (*get_vfio_device_fd)(int vid);
Signature · 1 line
2.52.0
PATCH v12 13/20 vfio: remove group-based API
In reply to Anatoly BurakovAll drivers have been adjusted to not use the VFIO group API directly and instead rely on container device assignment model, so the group API is no longer useful and can be removed.
--- lib/eal/freebsd/eal.c | 33 --------------- lib/eal/include/rte_vfio.h | 72 -------------------------------- lib/eal/linux/eal_vfio.c | 47 ++++++++++----------- lib/eal/linux/eal_vfio.h | 2 + lib/eal/linux/eal_vfio_mp_sync.c | 2 +- 5 files changed, 26 insertions(+), 130 deletions(-)
lib/eal/freebsd/eal.c +0 -33
@@ -856,13 +856,6 @@ int rte_vfio_noiommu_is_enabled(void)return 0 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_clear_group) -int rte_vfio_clear_group(__rte_unused int vfio_group_fd) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_get_group_num) int rte_vfio_get_group_num(__rte_unused const char *sysfs_base,
@@ -881,14 +874,6 @@ rte_vfio_get_container_fd(void)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_get_group_fd) -int -rte_vfio_get_group_fd(__rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_create) intrte_vfio_container_create (void )
@@ -905,24 +890,6 @@ rte_vfio_container_destroy(__rte_unused int container_fd)return -1 ; } -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_bind) -int -rte_vfio_container_group_bind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - -RTE_EXPORT_INTERNAL_SYMBOL (rte_vfio_container_group_unbind) -int -rte_vfio_container_group_unbind(__rte_unused int container_fd, - __rte_unused int iommu_group_num) -{ - rte_errno =ENOTSUP ; -return -1 ; -} - RTE_EXPORT_INTERNAL_SYMBOL(rte_vfio_container_dma_map) int rte_vfio_container_dma_map(__rte_unused int container_fd,
lib/eal/include/rte_vfio.h +0 -72
90 lines not on this page · raw message
lib/eal/linux/eal_vfio.c +23 -24
151 lines not on this page · raw message
lib/eal/linux/eal_vfio.h +2 -0
@@ -51,6 +51,8 @@ vfio_set_iommu_type(int vfio_container_fd);int vfio_get_iommu_type (void ); +int vfio_get_group_fd_by_num (int iommu_group_num); +/* check if we have any supported extensions */ int vfio_has_supported_extensions (int vfio_container_fd);
lib/eal/linux/eal_vfio_mp_sync.c +1 -1
@@ -34,7 +34,7 @@ vfio_mp_primary(const struct rte_mp_msg *msg, const void *peer)case SOCKET_REQ_GROUP : r->req =SOCKET_REQ_GROUP ; r->group_num = m->group_num; - fd =rte_vfio_get_group_fd (m->group_num); + fd =vfio_get_group_fd_by_num (m->group_num);if (fd <0 && fd != -ENOENT ) r->result =SOCKET_ERR ;else if (fd == -ENOENT )
Signature · 1 line
2.52.0