All of lore.kernel.org
 help / color / mirror / Atom feed
From: Robin Murphy <robin.murphy@arm.com>
To: Jordan Crouse <jcrouse@codeaurora.org>, linux-arm-msm@vger.kernel.org
Cc: David Airlie <airlied@linux.ie>, Sean Paul <sean@poorly.run>,
	dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	iommu@lists.linux-foundation.org,
	John Stultz <john.stultz@linaro.org>,
	Daniel Vetter <daniel@ffwll.ch>,
	freedreno@lists.freedesktop.org
Subject: Re: [PATCH v2 4/6] drm/msm: Add support to create a local pagetable
Date: Tue, 7 Jul 2020 12:36:42 +0100	[thread overview]
Message-ID: <3feed674-5eb9-ca2f-76a7-f888f431c409@arm.com> (raw)
In-Reply-To: <20200626200414.14382-5-jcrouse@codeaurora.org>

On 2020-06-26 21:04, Jordan Crouse wrote:
> Add support to create a io-pgtable for use by targets that support
> per-instance pagetables.  In order to support per-instance pagetables the
> GPU SMMU device needs to have the qcom,adreno-smmu compatible string and
> split pagetables and auxiliary domains need to be supported and enabled.
> 
> Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
> ---
> 
>   drivers/gpu/drm/msm/msm_gpummu.c |   2 +-
>   drivers/gpu/drm/msm/msm_iommu.c  | 180 ++++++++++++++++++++++++++++++-
>   drivers/gpu/drm/msm/msm_mmu.h    |  16 ++-
>   3 files changed, 195 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
> index 310a31b05faa..aab121f4beb7 100644
> --- a/drivers/gpu/drm/msm/msm_gpummu.c
> +++ b/drivers/gpu/drm/msm/msm_gpummu.c
> @@ -102,7 +102,7 @@ struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu)
>   	}
>   
>   	gpummu->gpu = gpu;
> -	msm_mmu_init(&gpummu->base, dev, &funcs);
> +	msm_mmu_init(&gpummu->base, dev, &funcs, MSM_MMU_GPUMMU);
>   
>   	return &gpummu->base;
>   }
> diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
> index 1b6635504069..f455c597f76d 100644
> --- a/drivers/gpu/drm/msm/msm_iommu.c
> +++ b/drivers/gpu/drm/msm/msm_iommu.c
> @@ -4,15 +4,192 @@
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
>   
> +#include <linux/io-pgtable.h>
>   #include "msm_drv.h"
>   #include "msm_mmu.h"
>   
>   struct msm_iommu {
>   	struct msm_mmu base;
>   	struct iommu_domain *domain;
> +	struct iommu_domain *aux_domain;
>   };
> +
>   #define to_msm_iommu(x) container_of(x, struct msm_iommu, base)
>   
> +struct msm_iommu_pagetable {
> +	struct msm_mmu base;
> +	struct msm_mmu *parent;
> +	struct io_pgtable_ops *pgtbl_ops;
> +	phys_addr_t ttbr;
> +	u32 asid;
> +};
> +
> +static struct msm_iommu_pagetable *to_pagetable(struct msm_mmu *mmu)
> +{
> +	return container_of(mmu, struct msm_iommu_pagetable, base);
> +}
> +
> +static int msm_iommu_pagetable_unmap(struct msm_mmu *mmu, u64 iova,
> +		size_t size)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +	struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
> +	size_t unmapped = 0;
> +
> +	/* Unmap the block one page at a time */
> +	while (size) {
> +		unmapped += ops->unmap(ops, iova, 4096, NULL);
> +		iova += 4096;
> +		size -= 4096;
> +	}
> +
> +	iommu_flush_tlb_all(to_msm_iommu(pagetable->parent)->domain);
> +
> +	return (unmapped == size) ? 0 : -EINVAL;
> +}

Remember in patch #1 when you said "Then 'domain' can be used like any 
other iommu domain to map and unmap iova addresses in the pagetable."?

This appears to be very much not that :/

Robin.

> +
> +static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova,
> +		struct sg_table *sgt, size_t len, int prot)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +	struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
> +	struct scatterlist *sg;
> +	size_t mapped = 0;
> +	u64 addr = iova;
> +	unsigned int i;
> +
> +	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +		size_t size = sg->length;
> +		phys_addr_t phys = sg_phys(sg);
> +
> +		/* Map the block one page at a time */
> +		while (size) {
> +			if (ops->map(ops, addr, phys, 4096, prot)) {
> +				msm_iommu_pagetable_unmap(mmu, iova, mapped);
> +				return -EINVAL;
> +			}
> +
> +			phys += 4096;
> +			addr += 4096;
> +			size -= 4096;
> +			mapped += 4096;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static void msm_iommu_pagetable_destroy(struct msm_mmu *mmu)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +
> +	free_io_pgtable_ops(pagetable->pgtbl_ops);
> +	kfree(pagetable);
> +}
> +
> +/*
> + * Given a parent device, create and return an aux domain. This will enable the
> + * TTBR0 region
> + */
> +static struct iommu_domain *msm_iommu_get_aux_domain(struct msm_mmu *parent)
> +{
> +	struct msm_iommu *iommu = to_msm_iommu(parent);
> +	struct iommu_domain *domain;
> +	int ret;
> +
> +	if (iommu->aux_domain)
> +		return iommu->aux_domain;
> +
> +	if (!iommu_dev_has_feature(parent->dev, IOMMU_DEV_FEAT_AUX))
> +		return ERR_PTR(-ENODEV);
> +
> +	domain = iommu_domain_alloc(&platform_bus_type);
> +	if (!domain)
> +		return ERR_PTR(-ENODEV);
> +
> +	ret = iommu_aux_attach_device(domain, parent->dev);
> +	if (ret) {
> +		iommu_domain_free(domain);
> +		return ERR_PTR(ret);
> +	}
> +
> +	iommu->aux_domain = domain;
> +	return domain;
> +}
> +
> +int msm_iommu_pagetable_params(struct msm_mmu *mmu,
> +		phys_addr_t *ttbr, int *asid)
> +{
> +	struct msm_iommu_pagetable *pagetable;
> +
> +	if (mmu->type != MSM_MMU_IOMMU_PAGETABLE)
> +		return -EINVAL;
> +
> +	pagetable = to_pagetable(mmu);
> +
> +	if (ttbr)
> +		*ttbr = pagetable->ttbr;
> +
> +	if (asid)
> +		*asid = pagetable->asid;
> +
> +	return 0;
> +}
> +
> +static const struct msm_mmu_funcs pagetable_funcs = {
> +		.map = msm_iommu_pagetable_map,
> +		.unmap = msm_iommu_pagetable_unmap,
> +		.destroy = msm_iommu_pagetable_destroy,
> +};
> +
> +struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
> +{
> +	static int next_asid = 16;
> +	struct msm_iommu_pagetable *pagetable;
> +	struct iommu_domain *aux_domain;
> +	struct io_pgtable_cfg cfg;
> +	int ret;
> +
> +	/* Make sure that the parent has a aux domain attached */
> +	aux_domain = msm_iommu_get_aux_domain(parent);
> +	if (IS_ERR(aux_domain))
> +		return ERR_CAST(aux_domain);
> +
> +	/* Get the pagetable configuration from the aux domain */
> +	ret = iommu_domain_get_attr(aux_domain, DOMAIN_ATTR_PGTABLE_CFG, &cfg);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	pagetable = kzalloc(sizeof(*pagetable), GFP_KERNEL);
> +	if (!pagetable)
> +		return ERR_PTR(-ENOMEM);
> +
> +	msm_mmu_init(&pagetable->base, parent->dev, &pagetable_funcs,
> +		MSM_MMU_IOMMU_PAGETABLE);
> +
> +	cfg.tlb = NULL;
> +
> +	pagetable->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1,
> +		&cfg, aux_domain);
> +
> +	if (!pagetable->pgtbl_ops) {
> +		kfree(pagetable);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +
> +	/* Needed later for TLB flush */
> +	pagetable->parent = parent;
> +	pagetable->ttbr = cfg.arm_lpae_s1_cfg.ttbr;
> +
> +	pagetable->asid = next_asid;
> +	next_asid = (next_asid + 1)  % 255;
> +	if (next_asid < 16)
> +		next_asid = 16;
> +
> +	return &pagetable->base;
> +}
> +
>   static int msm_fault_handler(struct iommu_domain *domain, struct device *dev,
>   		unsigned long iova, int flags, void *arg)
>   {
> @@ -40,6 +217,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
>   	if (iova & BIT_ULL(48))
>   		iova |= GENMASK_ULL(63, 49);
>   
> +
>   	ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot);
>   	WARN_ON(!ret);
>   
> @@ -85,7 +263,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
>   		return ERR_PTR(-ENOMEM);
>   
>   	iommu->domain = domain;
> -	msm_mmu_init(&iommu->base, dev, &funcs);
> +	msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU);
>   	iommu_set_fault_handler(domain, msm_fault_handler, iommu);
>   
>   	ret = iommu_attach_device(iommu->domain, dev);
> diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
> index 3a534ee59bf6..61ade89d9e48 100644
> --- a/drivers/gpu/drm/msm/msm_mmu.h
> +++ b/drivers/gpu/drm/msm/msm_mmu.h
> @@ -17,18 +17,26 @@ struct msm_mmu_funcs {
>   	void (*destroy)(struct msm_mmu *mmu);
>   };
>   
> +enum msm_mmu_type {
> +	MSM_MMU_GPUMMU,
> +	MSM_MMU_IOMMU,
> +	MSM_MMU_IOMMU_PAGETABLE,
> +};
> +
>   struct msm_mmu {
>   	const struct msm_mmu_funcs *funcs;
>   	struct device *dev;
>   	int (*handler)(void *arg, unsigned long iova, int flags);
>   	void *arg;
> +	enum msm_mmu_type type;
>   };
>   
>   static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
> -		const struct msm_mmu_funcs *funcs)
> +		const struct msm_mmu_funcs *funcs, enum msm_mmu_type type)
>   {
>   	mmu->dev = dev;
>   	mmu->funcs = funcs;
> +	mmu->type = type;
>   }
>   
>   struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
> @@ -41,7 +49,13 @@ static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg,
>   	mmu->handler = handler;
>   }
>   
> +struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent);
> +
>   void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
>   		dma_addr_t *tran_error);
>   
> +
> +int msm_iommu_pagetable_params(struct msm_mmu *mmu, phys_addr_t *ttbr,
> +		int *asid);
> +
>   #endif /* __MSM_MMU_H__ */
> 

WARNING: multiple messages have this Message-ID (diff)
From: Robin Murphy <robin.murphy@arm.com>
To: Jordan Crouse <jcrouse@codeaurora.org>, linux-arm-msm@vger.kernel.org
Cc: David Airlie <airlied@linux.ie>,
	freedreno@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	dri-devel@lists.freedesktop.org,
	iommu@lists.linux-foundation.org,
	John Stultz <john.stultz@linaro.org>,
	Daniel Vetter <daniel@ffwll.ch>, Sean Paul <sean@poorly.run>
Subject: Re: [PATCH v2 4/6] drm/msm: Add support to create a local pagetable
Date: Tue, 7 Jul 2020 12:36:42 +0100	[thread overview]
Message-ID: <3feed674-5eb9-ca2f-76a7-f888f431c409@arm.com> (raw)
In-Reply-To: <20200626200414.14382-5-jcrouse@codeaurora.org>

On 2020-06-26 21:04, Jordan Crouse wrote:
> Add support to create a io-pgtable for use by targets that support
> per-instance pagetables.  In order to support per-instance pagetables the
> GPU SMMU device needs to have the qcom,adreno-smmu compatible string and
> split pagetables and auxiliary domains need to be supported and enabled.
> 
> Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
> ---
> 
>   drivers/gpu/drm/msm/msm_gpummu.c |   2 +-
>   drivers/gpu/drm/msm/msm_iommu.c  | 180 ++++++++++++++++++++++++++++++-
>   drivers/gpu/drm/msm/msm_mmu.h    |  16 ++-
>   3 files changed, 195 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
> index 310a31b05faa..aab121f4beb7 100644
> --- a/drivers/gpu/drm/msm/msm_gpummu.c
> +++ b/drivers/gpu/drm/msm/msm_gpummu.c
> @@ -102,7 +102,7 @@ struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu)
>   	}
>   
>   	gpummu->gpu = gpu;
> -	msm_mmu_init(&gpummu->base, dev, &funcs);
> +	msm_mmu_init(&gpummu->base, dev, &funcs, MSM_MMU_GPUMMU);
>   
>   	return &gpummu->base;
>   }
> diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
> index 1b6635504069..f455c597f76d 100644
> --- a/drivers/gpu/drm/msm/msm_iommu.c
> +++ b/drivers/gpu/drm/msm/msm_iommu.c
> @@ -4,15 +4,192 @@
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
>   
> +#include <linux/io-pgtable.h>
>   #include "msm_drv.h"
>   #include "msm_mmu.h"
>   
>   struct msm_iommu {
>   	struct msm_mmu base;
>   	struct iommu_domain *domain;
> +	struct iommu_domain *aux_domain;
>   };
> +
>   #define to_msm_iommu(x) container_of(x, struct msm_iommu, base)
>   
> +struct msm_iommu_pagetable {
> +	struct msm_mmu base;
> +	struct msm_mmu *parent;
> +	struct io_pgtable_ops *pgtbl_ops;
> +	phys_addr_t ttbr;
> +	u32 asid;
> +};
> +
> +static struct msm_iommu_pagetable *to_pagetable(struct msm_mmu *mmu)
> +{
> +	return container_of(mmu, struct msm_iommu_pagetable, base);
> +}
> +
> +static int msm_iommu_pagetable_unmap(struct msm_mmu *mmu, u64 iova,
> +		size_t size)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +	struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
> +	size_t unmapped = 0;
> +
> +	/* Unmap the block one page at a time */
> +	while (size) {
> +		unmapped += ops->unmap(ops, iova, 4096, NULL);
> +		iova += 4096;
> +		size -= 4096;
> +	}
> +
> +	iommu_flush_tlb_all(to_msm_iommu(pagetable->parent)->domain);
> +
> +	return (unmapped == size) ? 0 : -EINVAL;
> +}

Remember in patch #1 when you said "Then 'domain' can be used like any 
other iommu domain to map and unmap iova addresses in the pagetable."?

This appears to be very much not that :/

Robin.

> +
> +static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova,
> +		struct sg_table *sgt, size_t len, int prot)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +	struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
> +	struct scatterlist *sg;
> +	size_t mapped = 0;
> +	u64 addr = iova;
> +	unsigned int i;
> +
> +	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +		size_t size = sg->length;
> +		phys_addr_t phys = sg_phys(sg);
> +
> +		/* Map the block one page at a time */
> +		while (size) {
> +			if (ops->map(ops, addr, phys, 4096, prot)) {
> +				msm_iommu_pagetable_unmap(mmu, iova, mapped);
> +				return -EINVAL;
> +			}
> +
> +			phys += 4096;
> +			addr += 4096;
> +			size -= 4096;
> +			mapped += 4096;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static void msm_iommu_pagetable_destroy(struct msm_mmu *mmu)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +
> +	free_io_pgtable_ops(pagetable->pgtbl_ops);
> +	kfree(pagetable);
> +}
> +
> +/*
> + * Given a parent device, create and return an aux domain. This will enable the
> + * TTBR0 region
> + */
> +static struct iommu_domain *msm_iommu_get_aux_domain(struct msm_mmu *parent)
> +{
> +	struct msm_iommu *iommu = to_msm_iommu(parent);
> +	struct iommu_domain *domain;
> +	int ret;
> +
> +	if (iommu->aux_domain)
> +		return iommu->aux_domain;
> +
> +	if (!iommu_dev_has_feature(parent->dev, IOMMU_DEV_FEAT_AUX))
> +		return ERR_PTR(-ENODEV);
> +
> +	domain = iommu_domain_alloc(&platform_bus_type);
> +	if (!domain)
> +		return ERR_PTR(-ENODEV);
> +
> +	ret = iommu_aux_attach_device(domain, parent->dev);
> +	if (ret) {
> +		iommu_domain_free(domain);
> +		return ERR_PTR(ret);
> +	}
> +
> +	iommu->aux_domain = domain;
> +	return domain;
> +}
> +
> +int msm_iommu_pagetable_params(struct msm_mmu *mmu,
> +		phys_addr_t *ttbr, int *asid)
> +{
> +	struct msm_iommu_pagetable *pagetable;
> +
> +	if (mmu->type != MSM_MMU_IOMMU_PAGETABLE)
> +		return -EINVAL;
> +
> +	pagetable = to_pagetable(mmu);
> +
> +	if (ttbr)
> +		*ttbr = pagetable->ttbr;
> +
> +	if (asid)
> +		*asid = pagetable->asid;
> +
> +	return 0;
> +}
> +
> +static const struct msm_mmu_funcs pagetable_funcs = {
> +		.map = msm_iommu_pagetable_map,
> +		.unmap = msm_iommu_pagetable_unmap,
> +		.destroy = msm_iommu_pagetable_destroy,
> +};
> +
> +struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
> +{
> +	static int next_asid = 16;
> +	struct msm_iommu_pagetable *pagetable;
> +	struct iommu_domain *aux_domain;
> +	struct io_pgtable_cfg cfg;
> +	int ret;
> +
> +	/* Make sure that the parent has a aux domain attached */
> +	aux_domain = msm_iommu_get_aux_domain(parent);
> +	if (IS_ERR(aux_domain))
> +		return ERR_CAST(aux_domain);
> +
> +	/* Get the pagetable configuration from the aux domain */
> +	ret = iommu_domain_get_attr(aux_domain, DOMAIN_ATTR_PGTABLE_CFG, &cfg);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	pagetable = kzalloc(sizeof(*pagetable), GFP_KERNEL);
> +	if (!pagetable)
> +		return ERR_PTR(-ENOMEM);
> +
> +	msm_mmu_init(&pagetable->base, parent->dev, &pagetable_funcs,
> +		MSM_MMU_IOMMU_PAGETABLE);
> +
> +	cfg.tlb = NULL;
> +
> +	pagetable->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1,
> +		&cfg, aux_domain);
> +
> +	if (!pagetable->pgtbl_ops) {
> +		kfree(pagetable);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +
> +	/* Needed later for TLB flush */
> +	pagetable->parent = parent;
> +	pagetable->ttbr = cfg.arm_lpae_s1_cfg.ttbr;
> +
> +	pagetable->asid = next_asid;
> +	next_asid = (next_asid + 1)  % 255;
> +	if (next_asid < 16)
> +		next_asid = 16;
> +
> +	return &pagetable->base;
> +}
> +
>   static int msm_fault_handler(struct iommu_domain *domain, struct device *dev,
>   		unsigned long iova, int flags, void *arg)
>   {
> @@ -40,6 +217,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
>   	if (iova & BIT_ULL(48))
>   		iova |= GENMASK_ULL(63, 49);
>   
> +
>   	ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot);
>   	WARN_ON(!ret);
>   
> @@ -85,7 +263,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
>   		return ERR_PTR(-ENOMEM);
>   
>   	iommu->domain = domain;
> -	msm_mmu_init(&iommu->base, dev, &funcs);
> +	msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU);
>   	iommu_set_fault_handler(domain, msm_fault_handler, iommu);
>   
>   	ret = iommu_attach_device(iommu->domain, dev);
> diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
> index 3a534ee59bf6..61ade89d9e48 100644
> --- a/drivers/gpu/drm/msm/msm_mmu.h
> +++ b/drivers/gpu/drm/msm/msm_mmu.h
> @@ -17,18 +17,26 @@ struct msm_mmu_funcs {
>   	void (*destroy)(struct msm_mmu *mmu);
>   };
>   
> +enum msm_mmu_type {
> +	MSM_MMU_GPUMMU,
> +	MSM_MMU_IOMMU,
> +	MSM_MMU_IOMMU_PAGETABLE,
> +};
> +
>   struct msm_mmu {
>   	const struct msm_mmu_funcs *funcs;
>   	struct device *dev;
>   	int (*handler)(void *arg, unsigned long iova, int flags);
>   	void *arg;
> +	enum msm_mmu_type type;
>   };
>   
>   static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
> -		const struct msm_mmu_funcs *funcs)
> +		const struct msm_mmu_funcs *funcs, enum msm_mmu_type type)
>   {
>   	mmu->dev = dev;
>   	mmu->funcs = funcs;
> +	mmu->type = type;
>   }
>   
>   struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
> @@ -41,7 +49,13 @@ static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg,
>   	mmu->handler = handler;
>   }
>   
> +struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent);
> +
>   void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
>   		dma_addr_t *tran_error);
>   
> +
> +int msm_iommu_pagetable_params(struct msm_mmu *mmu, phys_addr_t *ttbr,
> +		int *asid);
> +
>   #endif /* __MSM_MMU_H__ */
> 
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

WARNING: multiple messages have this Message-ID (diff)
From: Robin Murphy <robin.murphy@arm.com>
To: Jordan Crouse <jcrouse@codeaurora.org>, linux-arm-msm@vger.kernel.org
Cc: David Airlie <airlied@linux.ie>,
	freedreno@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	dri-devel@lists.freedesktop.org,
	iommu@lists.linux-foundation.org, Sean Paul <sean@poorly.run>
Subject: Re: [PATCH v2 4/6] drm/msm: Add support to create a local pagetable
Date: Tue, 7 Jul 2020 12:36:42 +0100	[thread overview]
Message-ID: <3feed674-5eb9-ca2f-76a7-f888f431c409@arm.com> (raw)
In-Reply-To: <20200626200414.14382-5-jcrouse@codeaurora.org>

On 2020-06-26 21:04, Jordan Crouse wrote:
> Add support to create a io-pgtable for use by targets that support
> per-instance pagetables.  In order to support per-instance pagetables the
> GPU SMMU device needs to have the qcom,adreno-smmu compatible string and
> split pagetables and auxiliary domains need to be supported and enabled.
> 
> Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
> ---
> 
>   drivers/gpu/drm/msm/msm_gpummu.c |   2 +-
>   drivers/gpu/drm/msm/msm_iommu.c  | 180 ++++++++++++++++++++++++++++++-
>   drivers/gpu/drm/msm/msm_mmu.h    |  16 ++-
>   3 files changed, 195 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/msm_gpummu.c b/drivers/gpu/drm/msm/msm_gpummu.c
> index 310a31b05faa..aab121f4beb7 100644
> --- a/drivers/gpu/drm/msm/msm_gpummu.c
> +++ b/drivers/gpu/drm/msm/msm_gpummu.c
> @@ -102,7 +102,7 @@ struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu)
>   	}
>   
>   	gpummu->gpu = gpu;
> -	msm_mmu_init(&gpummu->base, dev, &funcs);
> +	msm_mmu_init(&gpummu->base, dev, &funcs, MSM_MMU_GPUMMU);
>   
>   	return &gpummu->base;
>   }
> diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
> index 1b6635504069..f455c597f76d 100644
> --- a/drivers/gpu/drm/msm/msm_iommu.c
> +++ b/drivers/gpu/drm/msm/msm_iommu.c
> @@ -4,15 +4,192 @@
>    * Author: Rob Clark <robdclark@gmail.com>
>    */
>   
> +#include <linux/io-pgtable.h>
>   #include "msm_drv.h"
>   #include "msm_mmu.h"
>   
>   struct msm_iommu {
>   	struct msm_mmu base;
>   	struct iommu_domain *domain;
> +	struct iommu_domain *aux_domain;
>   };
> +
>   #define to_msm_iommu(x) container_of(x, struct msm_iommu, base)
>   
> +struct msm_iommu_pagetable {
> +	struct msm_mmu base;
> +	struct msm_mmu *parent;
> +	struct io_pgtable_ops *pgtbl_ops;
> +	phys_addr_t ttbr;
> +	u32 asid;
> +};
> +
> +static struct msm_iommu_pagetable *to_pagetable(struct msm_mmu *mmu)
> +{
> +	return container_of(mmu, struct msm_iommu_pagetable, base);
> +}
> +
> +static int msm_iommu_pagetable_unmap(struct msm_mmu *mmu, u64 iova,
> +		size_t size)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +	struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
> +	size_t unmapped = 0;
> +
> +	/* Unmap the block one page at a time */
> +	while (size) {
> +		unmapped += ops->unmap(ops, iova, 4096, NULL);
> +		iova += 4096;
> +		size -= 4096;
> +	}
> +
> +	iommu_flush_tlb_all(to_msm_iommu(pagetable->parent)->domain);
> +
> +	return (unmapped == size) ? 0 : -EINVAL;
> +}

Remember in patch #1 when you said "Then 'domain' can be used like any 
other iommu domain to map and unmap iova addresses in the pagetable."?

This appears to be very much not that :/

Robin.

> +
> +static int msm_iommu_pagetable_map(struct msm_mmu *mmu, u64 iova,
> +		struct sg_table *sgt, size_t len, int prot)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +	struct io_pgtable_ops *ops = pagetable->pgtbl_ops;
> +	struct scatterlist *sg;
> +	size_t mapped = 0;
> +	u64 addr = iova;
> +	unsigned int i;
> +
> +	for_each_sg(sgt->sgl, sg, sgt->nents, i) {
> +		size_t size = sg->length;
> +		phys_addr_t phys = sg_phys(sg);
> +
> +		/* Map the block one page at a time */
> +		while (size) {
> +			if (ops->map(ops, addr, phys, 4096, prot)) {
> +				msm_iommu_pagetable_unmap(mmu, iova, mapped);
> +				return -EINVAL;
> +			}
> +
> +			phys += 4096;
> +			addr += 4096;
> +			size -= 4096;
> +			mapped += 4096;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static void msm_iommu_pagetable_destroy(struct msm_mmu *mmu)
> +{
> +	struct msm_iommu_pagetable *pagetable = to_pagetable(mmu);
> +
> +	free_io_pgtable_ops(pagetable->pgtbl_ops);
> +	kfree(pagetable);
> +}
> +
> +/*
> + * Given a parent device, create and return an aux domain. This will enable the
> + * TTBR0 region
> + */
> +static struct iommu_domain *msm_iommu_get_aux_domain(struct msm_mmu *parent)
> +{
> +	struct msm_iommu *iommu = to_msm_iommu(parent);
> +	struct iommu_domain *domain;
> +	int ret;
> +
> +	if (iommu->aux_domain)
> +		return iommu->aux_domain;
> +
> +	if (!iommu_dev_has_feature(parent->dev, IOMMU_DEV_FEAT_AUX))
> +		return ERR_PTR(-ENODEV);
> +
> +	domain = iommu_domain_alloc(&platform_bus_type);
> +	if (!domain)
> +		return ERR_PTR(-ENODEV);
> +
> +	ret = iommu_aux_attach_device(domain, parent->dev);
> +	if (ret) {
> +		iommu_domain_free(domain);
> +		return ERR_PTR(ret);
> +	}
> +
> +	iommu->aux_domain = domain;
> +	return domain;
> +}
> +
> +int msm_iommu_pagetable_params(struct msm_mmu *mmu,
> +		phys_addr_t *ttbr, int *asid)
> +{
> +	struct msm_iommu_pagetable *pagetable;
> +
> +	if (mmu->type != MSM_MMU_IOMMU_PAGETABLE)
> +		return -EINVAL;
> +
> +	pagetable = to_pagetable(mmu);
> +
> +	if (ttbr)
> +		*ttbr = pagetable->ttbr;
> +
> +	if (asid)
> +		*asid = pagetable->asid;
> +
> +	return 0;
> +}
> +
> +static const struct msm_mmu_funcs pagetable_funcs = {
> +		.map = msm_iommu_pagetable_map,
> +		.unmap = msm_iommu_pagetable_unmap,
> +		.destroy = msm_iommu_pagetable_destroy,
> +};
> +
> +struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent)
> +{
> +	static int next_asid = 16;
> +	struct msm_iommu_pagetable *pagetable;
> +	struct iommu_domain *aux_domain;
> +	struct io_pgtable_cfg cfg;
> +	int ret;
> +
> +	/* Make sure that the parent has a aux domain attached */
> +	aux_domain = msm_iommu_get_aux_domain(parent);
> +	if (IS_ERR(aux_domain))
> +		return ERR_CAST(aux_domain);
> +
> +	/* Get the pagetable configuration from the aux domain */
> +	ret = iommu_domain_get_attr(aux_domain, DOMAIN_ATTR_PGTABLE_CFG, &cfg);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	pagetable = kzalloc(sizeof(*pagetable), GFP_KERNEL);
> +	if (!pagetable)
> +		return ERR_PTR(-ENOMEM);
> +
> +	msm_mmu_init(&pagetable->base, parent->dev, &pagetable_funcs,
> +		MSM_MMU_IOMMU_PAGETABLE);
> +
> +	cfg.tlb = NULL;
> +
> +	pagetable->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1,
> +		&cfg, aux_domain);
> +
> +	if (!pagetable->pgtbl_ops) {
> +		kfree(pagetable);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +
> +	/* Needed later for TLB flush */
> +	pagetable->parent = parent;
> +	pagetable->ttbr = cfg.arm_lpae_s1_cfg.ttbr;
> +
> +	pagetable->asid = next_asid;
> +	next_asid = (next_asid + 1)  % 255;
> +	if (next_asid < 16)
> +		next_asid = 16;
> +
> +	return &pagetable->base;
> +}
> +
>   static int msm_fault_handler(struct iommu_domain *domain, struct device *dev,
>   		unsigned long iova, int flags, void *arg)
>   {
> @@ -40,6 +217,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
>   	if (iova & BIT_ULL(48))
>   		iova |= GENMASK_ULL(63, 49);
>   
> +
>   	ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot);
>   	WARN_ON(!ret);
>   
> @@ -85,7 +263,7 @@ struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
>   		return ERR_PTR(-ENOMEM);
>   
>   	iommu->domain = domain;
> -	msm_mmu_init(&iommu->base, dev, &funcs);
> +	msm_mmu_init(&iommu->base, dev, &funcs, MSM_MMU_IOMMU);
>   	iommu_set_fault_handler(domain, msm_fault_handler, iommu);
>   
>   	ret = iommu_attach_device(iommu->domain, dev);
> diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
> index 3a534ee59bf6..61ade89d9e48 100644
> --- a/drivers/gpu/drm/msm/msm_mmu.h
> +++ b/drivers/gpu/drm/msm/msm_mmu.h
> @@ -17,18 +17,26 @@ struct msm_mmu_funcs {
>   	void (*destroy)(struct msm_mmu *mmu);
>   };
>   
> +enum msm_mmu_type {
> +	MSM_MMU_GPUMMU,
> +	MSM_MMU_IOMMU,
> +	MSM_MMU_IOMMU_PAGETABLE,
> +};
> +
>   struct msm_mmu {
>   	const struct msm_mmu_funcs *funcs;
>   	struct device *dev;
>   	int (*handler)(void *arg, unsigned long iova, int flags);
>   	void *arg;
> +	enum msm_mmu_type type;
>   };
>   
>   static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
> -		const struct msm_mmu_funcs *funcs)
> +		const struct msm_mmu_funcs *funcs, enum msm_mmu_type type)
>   {
>   	mmu->dev = dev;
>   	mmu->funcs = funcs;
> +	mmu->type = type;
>   }
>   
>   struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
> @@ -41,7 +49,13 @@ static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg,
>   	mmu->handler = handler;
>   }
>   
> +struct msm_mmu *msm_iommu_pagetable_create(struct msm_mmu *parent);
> +
>   void msm_gpummu_params(struct msm_mmu *mmu, dma_addr_t *pt_base,
>   		dma_addr_t *tran_error);
>   
> +
> +int msm_iommu_pagetable_params(struct msm_mmu *mmu, phys_addr_t *ttbr,
> +		int *asid);
> +
>   #endif /* __MSM_MMU_H__ */
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2020-07-07 11:36 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-26 20:04 [PATCH v2 0/6] iommu-arm-smmu: Add auxiliary domains and per-instance pagetables Jordan Crouse
2020-06-26 20:04 ` Jordan Crouse
2020-06-26 20:04 ` Jordan Crouse
2020-06-26 20:04 ` Jordan Crouse
2020-06-26 20:04 ` [PATCH v2 1/6] iommu/arm-smmu: Add auxiliary domain support for arm-smmuv2 Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-07-07 10:48   ` Jean-Philippe Brucker
2020-07-07 10:48     ` Jean-Philippe Brucker
2020-07-07 10:48     ` Jean-Philippe Brucker
2020-07-07 12:34   ` Robin Murphy
2020-07-07 12:34     ` Robin Murphy
2020-07-07 12:34     ` Robin Murphy
2020-07-07 15:09     ` [Freedreno] " Rob Clark
2020-07-07 15:09       ` Rob Clark
2020-07-07 15:09       ` Rob Clark
2020-07-13 17:35       ` Jordan Crouse
2020-07-13 17:35         ` Jordan Crouse
2020-07-13 17:35         ` Jordan Crouse
2020-06-26 20:04 ` [PATCH v2 2/6] iommu/io-pgtable: Allow a pgtable implementation to skip TLB operations Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-07-07 11:34   ` Robin Murphy
2020-07-07 11:34     ` Robin Murphy
2020-07-07 14:25     ` [Freedreno] " Rob Clark
2020-07-07 14:25       ` Rob Clark
2020-07-07 14:58       ` Rob Clark
2020-07-07 14:58         ` Rob Clark
2020-07-08 19:19         ` Jordan Crouse
2020-07-08 19:19           ` Jordan Crouse
2020-06-26 20:04 ` [PATCH v2 3/6] iommu/arm-smmu: Add a domain attribute to pass the pagetable config Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-26 20:04 ` [PATCH v2 4/6] drm/msm: Add support to create a local pagetable Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-07-07 11:36   ` Robin Murphy [this message]
2020-07-07 11:36     ` Robin Murphy
2020-07-07 11:36     ` Robin Murphy
2020-07-07 14:41     ` [Freedreno] " Rob Clark
2020-07-07 14:41       ` Rob Clark
2020-07-07 14:41       ` Rob Clark
2020-07-08 19:35     ` Jordan Crouse
2020-07-08 19:35       ` Jordan Crouse
2020-07-08 19:35       ` Jordan Crouse
2020-06-26 20:04 ` [PATCH v2 5/6] drm/msm: Add support for address space instances Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-26 20:04 ` [PATCH v2 6/6] drm/msm/a6xx: Add support for per-instance pagetables Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-26 20:04   ` Jordan Crouse
2020-06-27 19:56   ` Rob Clark
2020-06-27 19:56     ` Rob Clark
2020-06-27 19:56     ` Rob Clark
2020-06-27 20:11     ` Rob Clark
2020-06-27 20:11       ` Rob Clark
2020-06-27 20:11       ` Rob Clark
2020-06-29 14:56       ` [Freedreno] " Jordan Crouse
2020-06-29 14:56         ` Jordan Crouse
2020-06-29 14:56         ` Jordan Crouse

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3feed674-5eb9-ca2f-76a7-f888f431c409@arm.com \
    --to=robin.murphy@arm.com \
    --cc=airlied@linux.ie \
    --cc=daniel@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=freedreno@lists.freedesktop.org \
    --cc=iommu@lists.linux-foundation.org \
    --cc=jcrouse@codeaurora.org \
    --cc=john.stultz@linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sean@poorly.run \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.