Re: [PATCH v5 12/19] iommufd: Add a HW pagetable object

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Jason,

On 11/16/22 22:00, Jason Gunthorpe wrote:
> The hw_pagetable object exposes the internal struct iommu_domain's to
> userspace. An iommu_domain is required when any DMA device attaches to an
> IOAS to control the io page table through the iommu driver.
>
> For compatibility with VFIO the hw_pagetable is automatically created when
> a DMA device is attached to the IOAS. If a compatible iommu_domain already
> exists then the hw_pagetable associated with it is used for the
> attachment.
>
> In the initial series there is no iommufd uAPI for the hw_pagetable
> object. The next patch provides driver facing APIs for IO page table
> attachment that allows drivers to accept either an IOAS or a hw_pagetable
> ID and for the driver to return the hw_pagetable ID that was auto-selected
> from an IOAS. The expectation is the driver will provide uAPI through its
> own FD for attaching its device to iommufd. This allows userspace to learn
> the mapping of devices to iommu_domains and to override the automatic
> attachment.
>
> The future HW specific interface will allow userspace to create
> hw_pagetable objects using iommu_domains with IOMMU driver specific
> parameters. This infrastructure will allow linking those domains to IOAS's
> and devices.
>
> Tested-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
> Tested-by: Yi Liu <yi.l.liu@xxxxxxxxx>
> Tested-by: Lixiao Yang <lixiao.yang@xxxxxxxxx>
> Tested-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx>
> Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>
> Signed-off-by: Jason Gunthorpe <jgg@xxxxxxxxxx>
> ---
>  drivers/iommu/iommufd/Makefile          |  1 +
>  drivers/iommu/iommufd/hw_pagetable.c    | 57 +++++++++++++++++++++++++
>  drivers/iommu/iommufd/ioas.c            |  3 ++
>  drivers/iommu/iommufd/iommufd_private.h | 33 ++++++++++++++
>  drivers/iommu/iommufd/main.c            |  3 ++
>  5 files changed, 97 insertions(+)
>  create mode 100644 drivers/iommu/iommufd/hw_pagetable.c
>
> diff --git a/drivers/iommu/iommufd/Makefile b/drivers/iommu/iommufd/Makefile
> index 2b4f36f1b72f9d..e13e971aa28c60 100644
> --- a/drivers/iommu/iommufd/Makefile
> +++ b/drivers/iommu/iommufd/Makefile
> @@ -1,5 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  iommufd-y := \
> +	hw_pagetable.o \
>  	io_pagetable.o \
>  	ioas.o \
>  	main.o \
> diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
> new file mode 100644
> index 00000000000000..43d473989a0667
> --- /dev/null
> +++ b/drivers/iommu/iommufd/hw_pagetable.c
> @@ -0,0 +1,57 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
> + */
> +#include <linux/iommu.h>
> +
> +#include "iommufd_private.h"
> +
> +void iommufd_hw_pagetable_destroy(struct iommufd_object *obj)
> +{
> +	struct iommufd_hw_pagetable *hwpt =
> +		container_of(obj, struct iommufd_hw_pagetable, obj);
> +
> +	WARN_ON(!list_empty(&hwpt->devices));
> +
> +	iommu_domain_free(hwpt->domain);
> +	refcount_dec(&hwpt->ioas->obj.users);
> +	mutex_destroy(&hwpt->devices_lock);
> +}
> +
> +/**
> + * iommufd_hw_pagetable_alloc() - Get an iommu_domain for a device
> + * @ictx: iommufd context
> + * @ioas: IOAS to associate the domain with
> + * @dev: Device to get an iommu_domain for
> + *
> + * Allocate a new iommu_domain and return it as a hw_pagetable.
> + */
> +struct iommufd_hw_pagetable *
> +iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
> +			   struct device *dev)
> +{
> +	struct iommufd_hw_pagetable *hwpt;
> +	int rc;
> +
> +	hwpt = iommufd_object_alloc(ictx, hwpt, IOMMUFD_OBJ_HW_PAGETABLE);
> +	if (IS_ERR(hwpt))
> +		return hwpt;
> +
> +	hwpt->domain = iommu_domain_alloc(dev->bus);
> +	if (!hwpt->domain) {
> +		rc = -ENOMEM;
> +		goto out_abort;
> +	}
> +
> +	INIT_LIST_HEAD(&hwpt->devices);
> +	INIT_LIST_HEAD(&hwpt->hwpt_item);
> +	mutex_init(&hwpt->devices_lock);
> +	/* Pairs with iommufd_hw_pagetable_destroy() */
> +	refcount_inc(&ioas->obj.users);
> +	hwpt->ioas = ioas;
> +	return hwpt;
> +
> +out_abort:
> +	iommufd_object_abort(ictx, &hwpt->obj);
> +	return ERR_PTR(rc);
> +}
> diff --git a/drivers/iommu/iommufd/ioas.c b/drivers/iommu/iommufd/ioas.c
> index 7671456e86413a..64e6d0f73e39aa 100644
> --- a/drivers/iommu/iommufd/ioas.c
> +++ b/drivers/iommu/iommufd/ioas.c
> @@ -17,6 +17,7 @@ void iommufd_ioas_destroy(struct iommufd_object *obj)
>  	rc = iopt_unmap_all(&ioas->iopt, NULL);
>  	WARN_ON(rc && rc != -ENOENT);
>  	iopt_destroy_table(&ioas->iopt);
> +	mutex_destroy(&ioas->mutex);
>  }
>  
>  struct iommufd_ioas *iommufd_ioas_alloc(struct iommufd_ctx *ictx)
> @@ -28,6 +29,8 @@ struct iommufd_ioas *iommufd_ioas_alloc(struct iommufd_ctx *ictx)
>  		return ioas;
>  
>  	iopt_init_table(&ioas->iopt);
> +	INIT_LIST_HEAD(&ioas->hwpt_list);
> +	mutex_init(&ioas->mutex);
>  	return ioas;
>  }
>  
> diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
> index 6721332dbbba03..bb5cbd8f4e5991 100644
> --- a/drivers/iommu/iommufd/iommufd_private.h
> +++ b/drivers/iommu/iommufd/iommufd_private.h
> @@ -103,6 +103,7 @@ static inline int iommufd_ucmd_respond(struct iommufd_ucmd *ucmd,
>  enum iommufd_object_type {
>  	IOMMUFD_OBJ_NONE,
>  	IOMMUFD_OBJ_ANY = IOMMUFD_OBJ_NONE,
> +	IOMMUFD_OBJ_HW_PAGETABLE,
>  	IOMMUFD_OBJ_IOAS,
>  };
>  
> @@ -181,10 +182,20 @@ struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
>   * io_pagetable object. It is a user controlled mapping of IOVA -> PFNs. The
>   * mapping is copied into all of the associated domains and made available to
>   * in-kernel users.
> + *
> + * Every iommu_domain that is created is wrapped in a iommufd_hw_pagetable
> + * object. When we go to attach a device to an IOAS we need to get an
> + * iommu_domain and wrapping iommufd_hw_pagetable for it.
> + *
> + * An iommu_domain & iommfd_hw_pagetable will be automatically selected
> + * for a device based on the hwpt_list. If no suitable iommu_domain
> + * is found a new iommu_domain will be created.
>   */
>  struct iommufd_ioas {
>  	struct iommufd_object obj;
>  	struct io_pagetable iopt;
> +	struct mutex mutex;+	struct list_head hwpt_list;
>  };
>  
>  static inline struct iommufd_ioas *iommufd_get_ioas(struct iommufd_ucmd *ucmd,
> @@ -207,6 +218,28 @@ int iommufd_ioas_option(struct iommufd_ucmd *ucmd);
>  int iommufd_option_rlimit_mode(struct iommu_option *cmd,
>  			       struct iommufd_ctx *ictx);
>  
> +/*
> + * A HW pagetable is called an iommu_domain inside the kernel. This user object
> + * allows directly creating and inspecting the domains. Domains that have kernel
> + * owned page tables will be associated with an iommufd_ioas that provides the
> + * IOVA to PFN map.
> + */
> +struct iommufd_hw_pagetable {
> +	struct iommufd_object obj;
> +	struct iommufd_ioas *ioas;
> +	struct iommu_domain *domain;
> +	bool auto_domain : 1;
> +	/* Head at iommufd_ioas::hwpt_list */
> +	struct list_head hwpt_item;
> +	struct mutex devices_lock;
> +	struct list_head devices;
> +};
> +
> +struct iommufd_hw_pagetable *
> +iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
> +			   struct device *dev);
> +void iommufd_hw_pagetable_destroy(struct iommufd_object *obj);
> +
>  struct iommufd_access {
>  	unsigned long iova_alignment;
>  	u32 iopt_access_list_id;
> diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
> index 266109045537ed..3eab714b8e12a3 100644
> --- a/drivers/iommu/iommufd/main.c
> +++ b/drivers/iommu/iommufd/main.c
> @@ -355,6 +355,9 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
>  	[IOMMUFD_OBJ_IOAS] = {
>  		.destroy = iommufd_ioas_destroy,
>  	},
> +	[IOMMUFD_OBJ_HW_PAGETABLE] = {
> +		.destroy = iommufd_hw_pagetable_destroy,
> +	},
>  };
>  
>  static struct miscdevice iommu_misc_dev = {


Reviewed-by: Eric Auger <eric.auger@xxxxxxxxxx>

Eric




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux