From 095e8c48851426fcd472096ce7f392647133ce8b Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 20 Apr 2017 09:05:40 -0600 Subject: [PATCH 01/11] drm/msm: Safely skip holes in the counter group lists For backwards compatibility the counter group list has some built in gaps that return NULL when queried. Make sure that all the functions that query the list are able to handle a NULL pointer. Change-Id: Ic0dedbadd10ccf3a3b9b1f1b035a46a4f7ee8493 Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 969ed810ce9d..116825fc78f9 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -721,7 +721,7 @@ static struct adreno_counter_group *get_counter_group(struct msm_gpu *gpu, return ERR_PTR(-ENODEV); if (groupid >= adreno_gpu->nr_counter_groups) - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENODEV); return (struct adreno_counter_group *) adreno_gpu->counter_groups[groupid]; @@ -744,7 +744,7 @@ u64 adreno_read_counter(struct msm_gpu *gpu, u32 groupid, int counterid) struct adreno_counter_group *group = get_counter_group(gpu, groupid); - if (!IS_ERR(group) && group->funcs.read) + if (!IS_ERR_OR_NULL(group) && group->funcs.read) return group->funcs.read(gpu, group, counterid); return 0; @@ -755,6 +755,6 @@ void adreno_put_counter(struct msm_gpu *gpu, u32 groupid, int counterid) struct adreno_counter_group *group = get_counter_group(gpu, groupid); - if (!IS_ERR(group) && group->funcs.put) + if (!IS_ERR_OR_NULL(group) && group->funcs.put) group->funcs.put(gpu, group, counterid); } From b54b359084bedc367979143ce24d13135139a60d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Apr 2017 15:01:38 -0600 Subject: [PATCH 02/11] drm/msm: return -EFAULT if copy_from_user() fails copy_from_user_inatomic() is actually a local function that returns -EFAULT or positive values on error. Otherwise copy_from_user() returns the number of bytes remaining to be copied. We want to return -EFAULT here. I removed an unlikely() because we just did a copy_from_user() so I don't think it can possibly make a difference. Change-Id: Ic0dedbad3437020c12053b6d93276a4dd24a577a Signed-off-by: Dan Carpenter Signed-off-by: Rob Clark Git-commit: 21c42da18ef128ca8fb4cc4ead888f5c61e3916a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [jcrouse@codeaurora.org: fix minor merge conflict and checkpatch errors] Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_gem_submit.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 0566cefaae81..ef8cad11605c 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -79,13 +79,16 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, void __user *userptr = to_user_ptr(args->bos + (i * sizeof(submit_bo))); - ret = copy_from_user_inatomic(&submit_bo, userptr, sizeof(submit_bo)); - if (unlikely(ret)) { + if (copy_from_user_inatomic(&submit_bo, userptr, + sizeof(submit_bo))) { pagefault_enable(); spin_unlock(&file->table_lock); - ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo)); - if (ret) + if (copy_from_user(&submit_bo, userptr, + sizeof(submit_bo))) { + ret = -EFAULT; goto out; + } + spin_lock(&file->table_lock); pagefault_disable(); } @@ -280,8 +283,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob uint32_t off; bool valid; - ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc)); - if (ret) + if (copy_from_user(&submit_reloc, userptr, + sizeof(submit_reloc))) return -EFAULT; if (submit_reloc.submit_offset % 4) { From 7af30a44e9a00eaa8af47f684896d241b2b992d6 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:39 -0600 Subject: [PATCH 03/11] drm/msm: Set IOMMU flags in the IOMMU specific code Pass the bo flags all the way down to the iommu map code and translate into the IOMMU flags right before mapping. This crosses the streams a bit by moving BO level knowledge all the way down into the MMU driver but it removes IOMMU specific knowledge from the address space level which will be important when the address space code for the GPU and the display are merged into one. Change-Id: Ic0dedbad256f8986658bbe50fc2e2bd4051b7a7c Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_gem_vma.c | 12 +----------- drivers/gpu/drm/msm/msm_iommu.c | 12 +++++++++++- drivers/gpu/drm/msm/msm_mmu.h | 2 +- drivers/gpu/drm/msm/msm_smmu.c | 5 +++-- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index a227f1ba0573..2a4906752b70 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -141,16 +141,6 @@ static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace, size_t size = 0; struct scatterlist *sg; int ret, i; - int iommu_flags = IOMMU_READ; - - if (!(flags & MSM_BO_GPU_READONLY)) - iommu_flags |= IOMMU_WRITE; - - if (flags & MSM_BO_PRIVILEGED) - iommu_flags |= IOMMU_PRIV; - - if ((flags & MSM_BO_CACHED) && msm_iommu_coherent(aspace->mmu)) - iommu_flags |= IOMMU_CACHE; if (WARN_ON(drm_mm_node_allocated(&vma->node))) return 0; @@ -167,7 +157,7 @@ static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace, if (aspace->mmu) ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, - iommu_flags); + flags); /* Get a reference to the aspace to keep it around */ kref_get(&aspace->kref); diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 3af24646f4f1..99579bfaadef 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -196,7 +196,7 @@ static void msm_iommu_detach_dynamic(struct msm_mmu *mmu) } static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, - struct sg_table *sgt, int prot) + struct sg_table *sgt, u32 flags) { struct msm_iommu *iommu = to_msm_iommu(mmu); struct iommu_domain *domain = iommu->domain; @@ -204,10 +204,20 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, uint64_t da = iova; unsigned int i, j; int ret; + u32 prot = IOMMU_READ; if (!domain || !sgt) return -EINVAL; + if (!(flags & MSM_BO_GPU_READONLY)) + prot |= IOMMU_WRITE; + + if (flags & MSM_BO_PRIVILEGED) + prot |= IOMMU_PRIV; + + if ((flags & MSM_BO_CACHED) && msm_iommu_coherent(mmu)) + prot |= IOMMU_CACHE; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { phys_addr_t pa = sg_phys(sg) - sg->offset; size_t bytes = sg->length + sg->offset; diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 501f12bef00d..4d8f55c1d7d5 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -34,7 +34,7 @@ struct msm_mmu_funcs { int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); void (*detach)(struct msm_mmu *mmu); int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, - int prot); + u32 flags); int (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt); int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt, enum dma_data_direction dir); diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index c99f51e09700..5cdcde12ee52 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -105,7 +105,7 @@ static void msm_smmu_detach(struct msm_mmu *mmu) } static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, - struct sg_table *sgt, int prot) + struct sg_table *sgt, u32 flags) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); @@ -128,7 +128,8 @@ static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, VERB("map[%d]: %16llx %08x(%zx)", i, iova, pa, bytes); - ret = iommu_map(domain, da, pa, bytes, prot); + ret = iommu_map(domain, da, pa, bytes, + IOMMU_READ | IOMMU_WRITE); if (ret) goto fail; From 82fbc52e90dbd445e633239d1af444b048b7a00c Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:39 -0600 Subject: [PATCH 04/11] drm/msm: Consoldate mmu ->map and mmu ->map_sg For all intents and purposes the mmu ->map function has used a scatter gather list for some time. Drop the pretense and just make both the SMMU and IOMMU flavors use the sg flavor of their respective iommu API functions. As a result we can drop the map_sg hooks in the SMMU driver and get rid of a considerable amount of re-invented wheels in the IOMMU driver. Change-Id: Ic0dedbadc4724c8ae389892fb85610435c5c08cf Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_gem_vma.c | 6 +- drivers/gpu/drm/msm/msm_iommu.c | 57 +++++-------------- drivers/gpu/drm/msm/msm_mmu.h | 6 +- drivers/gpu/drm/msm/msm_smmu.c | 94 ++----------------------------- 4 files changed, 22 insertions(+), 141 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 2a4906752b70..d549874b95fc 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -48,8 +48,7 @@ static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace, aspace->mmu->funcs->unmap_dma_buf(aspace->mmu, sgt, buf, DMA_BIDIRECTIONAL); else - aspace->mmu->funcs->unmap_sg(aspace->mmu, sgt, - DMA_BIDIRECTIONAL); + aspace->mmu->funcs->unmap(aspace->mmu, 0, sgt); vma->iova = 0; @@ -68,8 +67,7 @@ static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf, DMA_BIDIRECTIONAL); else - ret = aspace->mmu->funcs->map_sg(aspace->mmu, sgt, - DMA_BIDIRECTIONAL); + ret = aspace->mmu->funcs->map(aspace->mmu, 0, sgt, flags); if (!ret) vma->iova = sg_dma_address(sgt->sgl); diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 99579bfaadef..a4ece31aa25a 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -200,9 +200,6 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, { struct msm_iommu *iommu = to_msm_iommu(mmu); struct iommu_domain *domain = iommu->domain; - struct scatterlist *sg; - uint64_t da = iova; - unsigned int i, j; int ret; u32 prot = IOMMU_READ; @@ -218,57 +215,31 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, if ((flags & MSM_BO_CACHED) && msm_iommu_coherent(mmu)) prot |= IOMMU_CACHE; - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - phys_addr_t pa = sg_phys(sg) - sg->offset; - size_t bytes = sg->length + sg->offset; + /* iommu_map_sg returns the number of bytes mapped */ + ret = iommu_map_sg(domain, iova, sgt->sgl, sgt->nents, prot); + if (ret) + sgt->sgl->dma_address = iova; - VERB("map[%d]: %016llx %pa(%zx)", i, iova, &pa, bytes); - - ret = iommu_map(domain, da, pa, bytes, prot); - if (ret) - goto fail; - - da += bytes; - } - - return 0; - -fail: - da = iova; - - for_each_sg(sgt->sgl, sg, i, j) { - size_t bytes = sg->length + sg->offset; - iommu_unmap(domain, da, bytes); - da += bytes; - } - return ret; + return ret ? 0 : -ENOMEM; } -static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, +static void msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt) { struct msm_iommu *iommu = to_msm_iommu(mmu); struct iommu_domain *domain = iommu->domain; struct scatterlist *sg; - uint64_t da = iova; - int i; + size_t len = 0; + int ret, i; - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - size_t bytes = sg->length + sg->offset; - size_t unmapped; + for_each_sg(sgt->sgl, sg, sgt->nents, i) + len += sg->length; - unmapped = iommu_unmap(domain, da, bytes); - if (unmapped < bytes) - return unmapped; + ret = iommu_unmap(domain, iova, len); + if (ret != len) + dev_warn(mmu->dev, "could not unmap iova %llx\n", iova); - VERB("unmap[%d]: %016llx(%zx)", i, iova, bytes); - - BUG_ON(!PAGE_ALIGNED(bytes)); - - da += bytes; - } - - return 0; + sgt->sgl->dma_address = 0; } static void msm_iommu_destroy(struct msm_mmu *mmu) diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 4d8f55c1d7d5..35c8be71a88b 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -35,11 +35,7 @@ struct msm_mmu_funcs { void (*detach)(struct msm_mmu *mmu); int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, u32 flags); - int (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt); - int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir); - void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir); + void (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt); int (*map_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, struct dma_buf *dma_buf, int dir); void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index 5cdcde12ee52..f794fee41c0c 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -109,103 +109,21 @@ static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; - struct scatterlist *sg; - uint64_t da = iova; - unsigned int i, j; int ret; - if (!client) - return -ENODEV; + ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, + DMA_BIDIRECTIONAL); - domain = client->mmu_mapping->domain; - if (!domain || !sgt) - return -EINVAL; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - u32 pa = sg_phys(sg) - sg->offset; - size_t bytes = sg->length + sg->offset; - - VERB("map[%d]: %16llx %08x(%zx)", i, iova, pa, bytes); - - ret = iommu_map(domain, da, pa, bytes, - IOMMU_READ | IOMMU_WRITE); - if (ret) - goto fail; - - da += bytes; - } - - return 0; - -fail: - da = iova; - - for_each_sg(sgt->sgl, sg, i, j) { - size_t bytes = sg->length + sg->offset; - - iommu_unmap(domain, da, bytes); - da += bytes; - } - return ret; + return (ret != sgt->nents) ? -ENOMEM : 0; } -static int msm_smmu_map_sg(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int ret; - - ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, dir); - if (ret != sgt->nents) - return -ENOMEM; - - return 0; -} - -static void msm_smmu_unmap_sg(struct msm_mmu *mmu, struct sg_table *sgt, - enum dma_data_direction dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - - dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir); -} - -static int msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, +static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); - struct iommu_domain *domain; - struct scatterlist *sg; - uint64_t da = iova; - int i; - if (!client) - return -ENODEV; - - domain = client->mmu_mapping->domain; - if (!domain || !sgt) - return -EINVAL; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - size_t bytes = sg->length + sg->offset; - size_t unmapped; - - unmapped = iommu_unmap(domain, da, bytes); - if (unmapped < bytes) - return unmapped; - - VERB("unmap[%d]: %16llx(%zx)", i, iova, bytes); - - WARN_ON(!PAGE_ALIGNED(bytes)); - - da += bytes; - } - - return 0; + dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL); } static void msm_smmu_destroy(struct msm_mmu *mmu) @@ -249,8 +167,6 @@ static const struct msm_mmu_funcs funcs = { .attach = msm_smmu_attach, .detach = msm_smmu_detach, .map = msm_smmu_map, - .map_sg = msm_smmu_map_sg, - .unmap_sg = msm_smmu_unmap_sg, .unmap = msm_smmu_unmap, .map_dma_buf = msm_smmu_map_dma_buf, .unmap_dma_buf = msm_smmu_unmap_dma_buf, From 438cdcdae0a59bcf176a36b99abd35ff41a23a72 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:40 -0600 Subject: [PATCH 05/11] drm/msm: Get rid of the MMU ->map_dma_buf and ->unmap_dma_buf funcs Finish consolidating the MMU map and unmap operations into a single function. By passing in the meta token to map/unmap the specific SMMU operations can make a local decision as to which function to call. Change-Id: Ic0dedbad52aac6ed1317411b2667755794d1818f Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_gem_vma.c | 26 ++++++----------- drivers/gpu/drm/msm/msm_iommu.c | 4 +-- drivers/gpu/drm/msm/msm_mmu.h | 9 ++---- drivers/gpu/drm/msm/msm_smmu.c | 46 +++++++++---------------------- 4 files changed, 26 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index d549874b95fc..487812d91ab7 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -42,13 +42,8 @@ static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, void *priv) { - struct dma_buf *buf = priv; - if (buf) - aspace->mmu->funcs->unmap_dma_buf(aspace->mmu, - sgt, buf, DMA_BIDIRECTIONAL); - else - aspace->mmu->funcs->unmap(aspace->mmu, 0, sgt); + aspace->mmu->funcs->unmap(aspace->mmu, 0, sgt, priv); vma->iova = 0; @@ -60,20 +55,15 @@ static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, void *priv, unsigned int flags) { - struct dma_buf *buf = priv; int ret; - if (buf) - ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf, - DMA_BIDIRECTIONAL); - else - ret = aspace->mmu->funcs->map(aspace->mmu, 0, sgt, flags); - - if (!ret) + ret = aspace->mmu->funcs->map(aspace->mmu, 0, sgt, flags, priv); + if (!ret) { vma->iova = sg_dma_address(sgt->sgl); - /* Get a reference to the aspace to keep it around */ - kref_get(&aspace->kref); + /* Get a reference to the aspace to keep it around */ + kref_get(&aspace->kref); + } return ret; } @@ -122,7 +112,7 @@ static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace, return; if (aspace->mmu) - aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt); + aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, NULL); drm_mm_remove_node(&vma->node); @@ -155,7 +145,7 @@ static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace, if (aspace->mmu) ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, - flags); + flags, NULL); /* Get a reference to the aspace to keep it around */ kref_get(&aspace->kref); diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index a4ece31aa25a..e465c737aab5 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -196,7 +196,7 @@ static void msm_iommu_detach_dynamic(struct msm_mmu *mmu) } static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, - struct sg_table *sgt, u32 flags) + struct sg_table *sgt, u32 flags, void *priv) { struct msm_iommu *iommu = to_msm_iommu(mmu); struct iommu_domain *domain = iommu->domain; @@ -224,7 +224,7 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, } static void msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, - struct sg_table *sgt) + struct sg_table *sgt, void *priv) { struct msm_iommu *iommu = to_msm_iommu(mmu); struct iommu_domain *domain = iommu->domain; diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 35c8be71a88b..2cbe5c7c7bf9 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -34,12 +34,9 @@ struct msm_mmu_funcs { int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); void (*detach)(struct msm_mmu *mmu); int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, - u32 flags); - void (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt); - int (*map_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir); - void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir); + u32 flags, void *priv); + void (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, + void *priv); void (*destroy)(struct msm_mmu *mmu); }; diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index f794fee41c0c..f5c6e0cd8048 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -105,25 +105,34 @@ static void msm_smmu_detach(struct msm_mmu *mmu) } static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, - struct sg_table *sgt, u32 flags) + struct sg_table *sgt, u32 flags, void *priv) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); int ret; - ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, + if (priv) + ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents, + DMA_BIDIRECTIONAL, priv); + else + ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL); return (ret != sgt->nents) ? -ENOMEM : 0; } static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, - struct sg_table *sgt) + struct sg_table *sgt, void *priv) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); - dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL); + if (priv) + msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, + DMA_BIDIRECTIONAL, priv); + else + dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, + DMA_BIDIRECTIONAL); } static void msm_smmu_destroy(struct msm_mmu *mmu) @@ -136,40 +145,11 @@ static void msm_smmu_destroy(struct msm_mmu *mmu) kfree(smmu); } -static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - int ret; - - ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents, dir, - dma_buf); - if (ret != sgt->nents) { - DRM_ERROR("dma map sg failed\n"); - return -ENOMEM; - } - - return 0; -} - - -static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, - struct dma_buf *dma_buf, int dir) -{ - struct msm_smmu *smmu = to_msm_smmu(mmu); - struct msm_smmu_client *client = msm_smmu_to_client(smmu); - - msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf); -} - static const struct msm_mmu_funcs funcs = { .attach = msm_smmu_attach, .detach = msm_smmu_detach, .map = msm_smmu_map, .unmap = msm_smmu_unmap, - .map_dma_buf = msm_smmu_map_dma_buf, - .unmap_dma_buf = msm_smmu_unmap_dma_buf, .destroy = msm_smmu_destroy, }; From 1576b22ae914d60cd762fd6ef6e47012cb544820 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:40 -0600 Subject: [PATCH 06/11] drm/msm: Finish consolidating the address space code Now that the SMMU/IOMMU differences have been resolved the only delta between the SMMU and the IOMMU address space implementations is the actual address space allocation which we can work around by assuming the caller doesn't want address generation if they specify the same start and end address (i.e. 0). With that optimization we can get rid of the address space sub functions and a bunch of otherwise duplicated code. Change-Id: Ic0dedbaddef0fcd3a8f39e30f95c71245d84f111 Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_gem.h | 13 +- drivers/gpu/drm/msm/msm_gem_vma.c | 192 ++++++++++-------------------- 2 files changed, 66 insertions(+), 139 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index ac46c473791f..f7df8f6c0eb6 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -25,21 +25,12 @@ /* Additional internal-use only BO flags: */ #define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ -struct msm_gem_aspace_ops { - int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *, - struct sg_table *sgt, void *priv, unsigned int flags); - - void (*unmap)(struct msm_gem_address_space *, struct msm_gem_vma *, - struct sg_table *sgt, void *priv); - - void (*destroy)(struct msm_gem_address_space *); -}; - struct msm_gem_address_space { const char *name; struct msm_mmu *mmu; - const struct msm_gem_aspace_ops *ops; struct kref kref; + struct drm_mm mm; + u64 va_len; }; struct msm_gem_vma { diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 487812d91ab7..1f912ebff683 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -25,8 +25,10 @@ msm_gem_address_space_destroy(struct kref *kref) struct msm_gem_address_space *aspace = container_of(kref, struct msm_gem_address_space, kref); - if (aspace->ops->destroy) - aspace->ops->destroy(aspace); + if (aspace->va_len) + drm_mm_takedown(&aspace->mm); + + aspace->mmu->funcs->destroy(aspace->mmu); kfree(aspace); } @@ -37,45 +39,9 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace) kref_put(&aspace->kref, msm_gem_address_space_destroy); } -/* SDE address space operations */ -static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace, - struct msm_gem_vma *vma, struct sg_table *sgt, - void *priv) -{ - - aspace->mmu->funcs->unmap(aspace->mmu, 0, sgt, priv); - - vma->iova = 0; - - msm_gem_address_space_put(aspace); -} - - -static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, - struct msm_gem_vma *vma, struct sg_table *sgt, - void *priv, unsigned int flags) -{ - int ret; - - ret = aspace->mmu->funcs->map(aspace->mmu, 0, sgt, flags, priv); - if (!ret) { - vma->iova = sg_dma_address(sgt->sgl); - - /* Get a reference to the aspace to keep it around */ - kref_get(&aspace->kref); - } - - return ret; -} - -static const struct msm_gem_aspace_ops smmu_aspace_ops = { - .map = smmu_aspace_map_vma, - .unmap = smmu_aspace_unmap_vma, -}; - -struct msm_gem_address_space * -msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, - const char *name) +static struct msm_gem_address_space * +msm_gem_address_space_new(struct msm_mmu *mmu, const char *name, + uint64_t start, uint64_t end) { struct msm_gem_address_space *aspace; @@ -88,125 +54,95 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, aspace->name = name; aspace->mmu = mmu; - aspace->ops = &smmu_aspace_ops; + + aspace->va_len = end - start; + + if (aspace->va_len) + drm_mm_init(&aspace->mm, (start >> PAGE_SHIFT), + (end >> PAGE_SHIFT) - 1); kref_init(&aspace->kref); return aspace; } -/* GPU address space operations */ -struct msm_iommu_aspace { - struct msm_gem_address_space base; - struct drm_mm mm; -}; - -#define to_iommu_aspace(aspace) \ - ((struct msm_iommu_aspace *) \ - container_of(aspace, struct msm_iommu_aspace, base)) - -static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace, - struct msm_gem_vma *vma, struct sg_table *sgt, void *priv) +static int allocate_iova(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, + u64 *iova) { - if (!vma->iova) - return; - - if (aspace->mmu) - aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, NULL); - - drm_mm_remove_node(&vma->node); - - vma->iova = 0; - - msm_gem_address_space_put(aspace); -} - -static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace, - struct msm_gem_vma *vma, struct sg_table *sgt, void *priv, - unsigned int flags) -{ - struct msm_iommu_aspace *local = to_iommu_aspace(aspace); - size_t size = 0; struct scatterlist *sg; + size_t size = 0; int ret, i; + if (!aspace->va_len) + return 0; + if (WARN_ON(drm_mm_node_allocated(&vma->node))) return 0; for_each_sg(sgt->sgl, sg, sgt->nents, i) size += sg->length + sg->offset; - ret = drm_mm_insert_node(&local->mm, &vma->node, size >> PAGE_SHIFT, + ret = drm_mm_insert_node(&aspace->mm, &vma->node, size >> PAGE_SHIFT, 0, DRM_MM_SEARCH_DEFAULT); - if (ret) - return ret; - vma->iova = vma->node.start << PAGE_SHIFT; - - if (aspace->mmu) - ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, - flags, NULL); - - /* Get a reference to the aspace to keep it around */ - kref_get(&aspace->kref); + if (!ret && iova) + *iova = vma->node.start << PAGE_SHIFT; return ret; } -static void iommu_aspace_destroy(struct msm_gem_address_space *aspace) -{ - struct msm_iommu_aspace *local = to_iommu_aspace(aspace); - - drm_mm_takedown(&local->mm); - aspace->mmu->funcs->destroy(aspace->mmu); -} - -static const struct msm_gem_aspace_ops msm_iommu_aspace_ops = { - .map = iommu_aspace_map_vma, - .unmap = iommu_aspace_unmap_vma, - .destroy = iommu_aspace_destroy, -}; - -static struct msm_gem_address_space * -msm_gem_address_space_new(struct msm_mmu *mmu, const char *name, - uint64_t start, uint64_t end) -{ - struct msm_iommu_aspace *local; - - if (!mmu) - return ERR_PTR(-EINVAL); - - local = kzalloc(sizeof(*local), GFP_KERNEL); - if (!local) - return ERR_PTR(-ENOMEM); - - drm_mm_init(&local->mm, (start >> PAGE_SHIFT), - (end >> PAGE_SHIFT) - 1); - - local->base.name = name; - local->base.mmu = mmu; - local->base.ops = &msm_iommu_aspace_ops; - - kref_init(&local->base.kref); - - return &local->base; -} - int msm_gem_map_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, void *priv, unsigned int flags) { - if (aspace && aspace->ops->map) - return aspace->ops->map(aspace, vma, sgt, priv, flags); + u64 iova = 0; + int ret; - return -EINVAL; + if (!aspace) + return -EINVAL; + + ret = allocate_iova(aspace, vma, sgt, &iova); + if (ret) + return ret; + + ret = aspace->mmu->funcs->map(aspace->mmu, iova, sgt, + flags, priv); + + if (ret) { + if (drm_mm_node_allocated(&vma->node)) + drm_mm_remove_node(&vma->node); + + return ret; + } + + vma->iova = sg_dma_address(sgt->sgl); + kref_get(&aspace->kref); + + return 0; } void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, void *priv) { - if (aspace && aspace->ops->unmap) - aspace->ops->unmap(aspace, vma, sgt, priv); + if (!aspace || !vma->iova) + return; + + aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, priv); + + if (drm_mm_node_allocated(&vma->node)) + drm_mm_remove_node(&vma->node); + + vma->iova = 0; + + msm_gem_address_space_put(aspace); +} + +struct msm_gem_address_space * +msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, + const char *name) +{ + return msm_gem_address_space_new(mmu, name, 0, 0); } struct msm_gem_address_space * From 4e061d8b6002fbb9c124a89f4952cebda0f0450d Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:41 -0600 Subject: [PATCH 07/11] drm/msm: Refactor GPU IOMMU Very soon we will be adding support for secure domains and so a bit of refactoring is needed the GPU IOMMU code: * Add support for directly probing the context bank device at create instead of at attach. This makes it a little bit easier to directly associate a mmu device with a specific context bank. * Specify the domain type at create time. Add a new domain type MSM_DOMAIN_USER to associate the user domain with the gfx3d_user context bank. Also add MSM_DOMAIN_DEFAULT with no context bank for legacy devices (read MDP4) with only one context bank to attach to the parent device. Adding a domain type saves us from having to create N entry points for each domain type. Note that dynamic domains stay with their own initalization function. This is because dynamic domains are cloned from the parent domain so the semantics are too different to try to smash into the generic functions. Change-Id: Ic0dedbad41692e776cddc72cda653ae637f9ec77 Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 10 +- drivers/gpu/drm/msm/msm_drv.h | 2 +- drivers/gpu/drm/msm/msm_gem_vma.c | 4 +- drivers/gpu/drm/msm/msm_gpu.c | 2 +- drivers/gpu/drm/msm/msm_iommu.c | 186 ++++++++++++++---------- drivers/gpu/drm/msm/msm_mmu.h | 13 +- 6 files changed, 129 insertions(+), 88 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index b6cddee0cf34..d089ba600de8 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -515,15 +515,11 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) mdelay(16); if (config->iommu) { - struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, config->iommu); - - if (IS_ERR(mmu)) { - ret = PTR_ERR(mmu); - goto fail; - } + config->iommu->geometry.aperture_start = 0x1000; + config->iommu->geometry.aperture_end = 0xffffffff; aspace = msm_gem_address_space_create(&pdev->dev, - mmu, "mdp4", 0x1000, 0xffffffff); + config->iommu, MSM_IOMMU_DOMAIN_DEFAULT, "mdp4"); if (IS_ERR(aspace)) { ret = PTR_ERR(aspace); goto fail; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 943d73fa544d..d934819d1f1c 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -412,7 +412,7 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace); /* For GPU and legacy display */ struct msm_gem_address_space * msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, - const char *name); + int type, const char *name); struct msm_gem_address_space * msm_gem_address_space_create_instance(struct msm_mmu *parent, const char *name, uint64_t start, uint64_t end); diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 1f912ebff683..47f7436854fb 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -147,9 +147,9 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, struct msm_gem_address_space * msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, - const char *name) + int type, const char *name) { - struct msm_mmu *mmu = msm_iommu_new(dev, domain); + struct msm_mmu *mmu = msm_iommu_new(dev, type, domain); if (IS_ERR(mmu)) return (struct msm_gem_address_space *) mmu; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 5a505a8bf328..cbc37dcce1d0 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -837,7 +837,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, dev_info(drm->dev, "%s: using IOMMU\n", name); gpu->aspace = msm_gem_address_space_create(&pdev->dev, - iommu, "gpu"); + iommu, MSM_IOMMU_DOMAIN_USER, "gpu"); if (IS_ERR(gpu->aspace)) { ret = PTR_ERR(gpu->aspace); dev_err(drm->dev, "failed to init iommu: %d\n", ret); diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index e465c737aab5..38b5cd6d45df 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -27,23 +27,41 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev, return 0; } +static void enable_iommu_clocks(struct msm_iommu *iommu) +{ + int i; + + for (i = 0; i < iommu->nr_clocks; i++) { + if (iommu->clocks[i]) + clk_prepare_enable(iommu->clocks[i]); + } +} + +static void disable_iommu_clocks(struct msm_iommu *iommu) +{ + int i; + + for (i = 0; i < iommu->nr_clocks; i++) { + if (iommu->clocks[i]) + clk_disable_unprepare(iommu->clocks[i]); + } +} + /* * Get and enable the IOMMU clocks so that we can make * sure they stay on the entire duration so that we can * safely change the pagetable from the GPU */ -static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev) +static void get_iommu_clocks(struct msm_iommu *iommu, struct device *dev) { - struct msm_iommu *iommu = to_msm_iommu(mmu); - struct device *dev; struct property *prop; const char *name; int i = 0; - if (WARN_ON(!pdev)) + if (iommu->nr_clocks) { + enable_iommu_clocks(iommu); return; - - dev = &pdev->dev; + } iommu->nr_clocks = of_property_count_strings(dev->of_node, "clock-names"); @@ -61,79 +79,40 @@ static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev) break; iommu->clocks[i] = clk_get(dev, name); - if (iommu->clocks[i]) - clk_prepare_enable(iommu->clocks[i]); - i++; } + + enable_iommu_clocks(iommu); } -static int _attach_iommu_device(struct msm_mmu *mmu, - struct iommu_domain *domain, const char **names, int cnt) -{ - int i; - - /* See if there is a iommus member in the current device. If not, look - * for the names and see if there is one in there. - */ - - if (of_find_property(mmu->dev->of_node, "iommus", NULL)) - return iommu_attach_device(domain, mmu->dev); - - /* Look through the list of names for a target */ - for (i = 0; i < cnt; i++) { - struct device_node *node = - of_find_node_by_name(mmu->dev->of_node, names[i]); - - if (!node) - continue; - - if (of_find_property(node, "iommus", NULL)) { - struct platform_device *pdev; - - /* Get the platform device for the node */ - of_platform_populate(node->parent, NULL, NULL, - mmu->dev); - - pdev = of_find_device_by_node(node); - - if (!pdev) - continue; - - _get_iommu_clocks(mmu, - of_find_device_by_node(node->parent)); - - mmu->dev = &pdev->dev; - - return iommu_attach_device(domain, mmu->dev); - } - } - - dev_err(mmu->dev, "Couldn't find a IOMMU device\n"); - return -ENODEV; -} - -static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt) +static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, + int cnt) { struct msm_iommu *iommu = to_msm_iommu(mmu); - int val = 1, ret; + + return iommu_attach_device(iommu->domain, mmu->dev); +} + +static int msm_iommu_attach_user(struct msm_mmu *mmu, const char **names, + int cnt) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + int ret, val = 1; /* Hope springs eternal */ - iommu->allow_dynamic = true; + iommu->allow_dynamic = !iommu_domain_set_attr(iommu->domain, + DOMAIN_ATTR_ENABLE_TTBR1, &val) ? true : false; - /* per-instance pagetables need TTBR1 support in the IOMMU driver */ - ret = iommu_domain_set_attr(iommu->domain, - DOMAIN_ATTR_ENABLE_TTBR1, &val); - if (ret) - iommu->allow_dynamic = false; + get_iommu_clocks(iommu, mmu->dev->parent); /* Mark the GPU as I/O coherent if it is supported */ iommu->is_coherent = of_dma_is_coherent(mmu->dev->of_node); - /* Attach the device to the domain */ - ret = _attach_iommu_device(mmu, iommu->domain, names, cnt); - if (ret) + ret = iommu_attach_device(iommu->domain, mmu->dev); + if (ret) { + disable_iommu_clocks(iommu); return ret; + } /* * Get the context bank for the base domain; this will be shared with @@ -179,14 +158,10 @@ static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names, static void msm_iommu_detach(struct msm_mmu *mmu) { struct msm_iommu *iommu = to_msm_iommu(mmu); - int i; iommu_detach_device(iommu->domain, mmu->dev); - for (i = 0; i < iommu->nr_clocks; i++) { - if (iommu->clocks[i]) - clk_disable(iommu->clocks[i]); - } + disable_iommu_clocks(iommu); } static void msm_iommu_detach_dynamic(struct msm_mmu *mmu) @@ -249,7 +224,30 @@ static void msm_iommu_destroy(struct msm_mmu *mmu) kfree(iommu); } -static const struct msm_mmu_funcs funcs = { +static struct device *find_context_bank(const char *name) +{ + struct device_node *node = of_find_node_by_name(NULL, name); + struct platform_device *pdev, *parent; + + if (!node) + return ERR_PTR(-ENODEV); + + if (!of_find_property(node, "iommus", NULL)) + return ERR_PTR(-ENODEV); + + /* Get the parent device */ + parent = of_find_device_by_node(node->parent); + + /* Populate the sub nodes */ + of_platform_populate(parent->dev.of_node, NULL, NULL, &parent->dev); + + /* Get the context bank device */ + pdev = of_find_device_by_node(node); + + return pdev ? &pdev->dev : ERR_PTR(-ENODEV); +} + +static const struct msm_mmu_funcs default_funcs = { .attach = msm_iommu_attach, .detach = msm_iommu_detach, .map = msm_iommu_map, @@ -257,6 +255,14 @@ static const struct msm_mmu_funcs funcs = { .destroy = msm_iommu_destroy, }; +static const struct msm_mmu_funcs user_funcs = { + .attach = msm_iommu_attach_user, + .detach = msm_iommu_detach, + .map = msm_iommu_map, + .unmap = msm_iommu_unmap, + .destroy = msm_iommu_destroy, +}; + static const struct msm_mmu_funcs dynamic_funcs = { .attach = msm_iommu_attach_dynamic, .detach = msm_iommu_detach_dynamic, @@ -265,8 +271,22 @@ static const struct msm_mmu_funcs dynamic_funcs = { .destroy = msm_iommu_destroy, }; -struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain, - const struct msm_mmu_funcs *funcs) +static const struct { + const char *cbname; + const struct msm_mmu_funcs *funcs; +} msm_iommu_domains[] = { + [MSM_IOMMU_DOMAIN_DEFAULT] = { + .cbname = NULL, + .funcs = &default_funcs, + }, + [MSM_IOMMU_DOMAIN_USER] = { + .cbname = "gfx3d_user", + .funcs = &user_funcs, + }, +}; + +static struct msm_mmu *iommu_create(struct device *dev, + struct iommu_domain *domain, const struct msm_mmu_funcs *funcs) { struct msm_iommu *iommu; @@ -280,9 +300,23 @@ struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain, return &iommu->base; } -struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) + +struct msm_mmu *msm_iommu_new(struct device *parent, + enum msm_iommu_domain_type type, struct iommu_domain *domain) { - return _msm_iommu_new(dev, domain, &funcs); + struct device *dev = parent; + + if (type >= ARRAY_SIZE(msm_iommu_domains) || + !msm_iommu_domains[type].funcs) + return ERR_PTR(-ENODEV); + + if (msm_iommu_domains[type].cbname) { + dev = find_context_bank(msm_iommu_domains[type].cbname); + if (IS_ERR(dev)) + return ERR_CAST(dev); + } + + return iommu_create(dev, domain, msm_iommu_domains[type].funcs); } /* @@ -307,7 +341,7 @@ struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *base) if (!domain) return ERR_PTR(-ENODEV); - mmu = _msm_iommu_new(base->dev, domain, &dynamic_funcs); + mmu = iommu_create(base->dev, domain, &dynamic_funcs); if (IS_ERR(mmu)) { if (domain) diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 2cbe5c7c7bf9..0292a9ae1d33 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -30,6 +30,11 @@ enum msm_mmu_domain_type { MSM_SMMU_DOMAIN_MAX, }; +enum msm_iommu_domain_type { + MSM_IOMMU_DOMAIN_DEFAULT, + MSM_IOMMU_DOMAIN_USER, +}; + struct msm_mmu_funcs { int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); void (*detach)(struct msm_mmu *mmu); @@ -52,9 +57,15 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, mmu->funcs = funcs; } -struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); +/* Create a new SDE mmu device */ struct msm_mmu *msm_smmu_new(struct device *dev, enum msm_mmu_domain_type domain); + +/* Create a new legacy MDP4 or GPU mmu device */ +struct msm_mmu *msm_iommu_new(struct device *parent, + enum msm_iommu_domain_type type, struct iommu_domain *domain); + +/* Create a new dynamic domain for GPU */ struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig); #endif /* __MSM_MMU_H__ */ From f0eb0ed585c15c7a011d7d6b3f1d0cd58751f7dd Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:42 -0600 Subject: [PATCH 08/11] drm/msm: Add enable/disable hooks for mmu 5XX targets that are using per-process pagetables will need to keep the IOMMU clocks on the entire time because we don't know exactly when the GPU might touch it. That said there are occassional depencency issues if the clocks are enabled out of order. To be certain we should enable the MMU clocks last and disable them first. Add enable/disable hooks to the MMU struct to do this cleanly from the GPU pm_resume / pm_suspend paths. Change-Id: Ic0dedbad8e2298e55c90b29eed657baa0933ddcf Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_gpu.c | 6 +++ drivers/gpu/drm/msm/msm_iommu.c | 75 ++++++++++++++------------------- drivers/gpu/drm/msm/msm_mmu.h | 14 ++++++ 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index cbc37dcce1d0..2f01db8b08c3 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -183,6 +183,9 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) if (ret) return ret; + if (gpu->aspace && gpu->aspace->mmu) + msm_mmu_enable(gpu->aspace->mmu); + return 0; } @@ -203,6 +206,9 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) if (WARN_ON(gpu->active_cnt < 0)) return -EINVAL; + if (gpu->aspace && gpu->aspace->mmu) + msm_mmu_disable(gpu->aspace->mmu); + ret = disable_axi(gpu); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index 38b5cd6d45df..f5d89f76dda8 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -27,49 +27,17 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev, return 0; } -static void enable_iommu_clocks(struct msm_iommu *iommu) -{ - int i; - - for (i = 0; i < iommu->nr_clocks; i++) { - if (iommu->clocks[i]) - clk_prepare_enable(iommu->clocks[i]); - } -} - -static void disable_iommu_clocks(struct msm_iommu *iommu) -{ - int i; - - for (i = 0; i < iommu->nr_clocks; i++) { - if (iommu->clocks[i]) - clk_disable_unprepare(iommu->clocks[i]); - } -} - -/* - * Get and enable the IOMMU clocks so that we can make - * sure they stay on the entire duration so that we can - * safely change the pagetable from the GPU - */ -static void get_iommu_clocks(struct msm_iommu *iommu, struct device *dev) +static void iommu_get_clocks(struct msm_iommu *iommu, struct device *dev) { struct property *prop; const char *name; int i = 0; - if (iommu->nr_clocks) { - enable_iommu_clocks(iommu); - return; - } - iommu->nr_clocks = of_property_count_strings(dev->of_node, "clock-names"); - if (iommu->nr_clocks < 0) { - iommu->nr_clocks = 0; + if (iommu->nr_clocks < 0) return; - } if (WARN_ON(iommu->nr_clocks > ARRAY_SIZE(iommu->clocks))) iommu->nr_clocks = ARRAY_SIZE(iommu->clocks); @@ -78,11 +46,34 @@ static void get_iommu_clocks(struct msm_iommu *iommu, struct device *dev) if (i == iommu->nr_clocks) break; - iommu->clocks[i] = clk_get(dev, name); - i++; + iommu->clocks[i++] = clk_get(dev, name); } +} - enable_iommu_clocks(iommu); + +static void msm_iommu_clocks_enable(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + int i; + + if (!iommu->nr_clocks) + iommu_get_clocks(iommu, mmu->dev->parent); + + for (i = 0; i < iommu->nr_clocks; i++) { + if (iommu->clocks[i]) + clk_prepare_enable(iommu->clocks[i]); + } +} + +static void msm_iommu_clocks_disable(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + int i; + + for (i = 0; i < iommu->nr_clocks; i++) { + if (iommu->clocks[i]) + clk_disable_unprepare(iommu->clocks[i]); + } } static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, @@ -103,16 +94,12 @@ static int msm_iommu_attach_user(struct msm_mmu *mmu, const char **names, iommu->allow_dynamic = !iommu_domain_set_attr(iommu->domain, DOMAIN_ATTR_ENABLE_TTBR1, &val) ? true : false; - get_iommu_clocks(iommu, mmu->dev->parent); - /* Mark the GPU as I/O coherent if it is supported */ iommu->is_coherent = of_dma_is_coherent(mmu->dev->of_node); ret = iommu_attach_device(iommu->domain, mmu->dev); - if (ret) { - disable_iommu_clocks(iommu); + if (ret) return ret; - } /* * Get the context bank for the base domain; this will be shared with @@ -160,8 +147,6 @@ static void msm_iommu_detach(struct msm_mmu *mmu) struct msm_iommu *iommu = to_msm_iommu(mmu); iommu_detach_device(iommu->domain, mmu->dev); - - disable_iommu_clocks(iommu); } static void msm_iommu_detach_dynamic(struct msm_mmu *mmu) @@ -261,6 +246,8 @@ static const struct msm_mmu_funcs user_funcs = { .map = msm_iommu_map, .unmap = msm_iommu_unmap, .destroy = msm_iommu_destroy, + .enable = msm_iommu_clocks_enable, + .disable = msm_iommu_clocks_disable, }; static const struct msm_mmu_funcs dynamic_funcs = { diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 0292a9ae1d33..8be3cefd686d 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -43,6 +43,8 @@ struct msm_mmu_funcs { void (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, void *priv); void (*destroy)(struct msm_mmu *mmu); + void (*enable)(struct msm_mmu *mmu); + void (*disable)(struct msm_mmu *mmu); }; struct msm_mmu { @@ -68,4 +70,16 @@ struct msm_mmu *msm_iommu_new(struct device *parent, /* Create a new dynamic domain for GPU */ struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig); +static inline void msm_mmu_enable(struct msm_mmu *mmu) +{ + if (mmu->funcs->enable) + mmu->funcs->enable(mmu); +} + +static inline void msm_mmu_disable(struct msm_mmu *mmu) +{ + if (mmu->funcs->disable) + mmu->funcs->disable(mmu); +} + #endif /* __MSM_MMU_H__ */ From 0bea8c919aeeeeab129b2e3fcbc35410dfb75872 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:42 -0600 Subject: [PATCH 09/11] drm/msm: Remove iommu names during attach None of the existing iommu implementations use the names passed in at attach time by the API. Save a bit of .data room by removing the static string definitions and passing NULL to the attach function. Change-Id: Ic0dedbada9561768b8d9716ea101619e6b549ea4 Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 7 +------ drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 13 +++---------- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c | 7 +------ drivers/gpu/drm/msm/sde/sde_kms.c | 7 +------ 4 files changed, 6 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 116825fc78f9..aea275161c62 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -404,10 +404,6 @@ void adreno_wait_ring(struct msm_ringbuffer *ring, uint32_t ndwords) ring->gpu->name, ring->id); } -static const char *iommu_ports[] = { - "gfx3d_user", -}; - /* Read the set of powerlevels */ static int _adreno_get_pwrlevels(struct msm_gpu *gpu, struct device_node *node) { @@ -579,8 +575,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, mmu = gpu->aspace->mmu; if (mmu) { - ret = mmu->funcs->attach(mmu, iommu_ports, - ARRAY_SIZE(iommu_ports)); + ret = mmu->funcs->attach(mmu, NULL, 0); if (ret) return ret; } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index d089ba600de8..119221eacb43 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -184,8 +184,7 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) mdp4_crtc_cancel_pending_flip(priv->crtcs[i], file); if (aspace) { - aspace->mmu->funcs->detach(aspace->mmu, - iommu_ports, ARRAY_SIZE(iommu_ports)); + aspace->mmu->funcs->detach(aspace->mmu); msm_gem_address_space_destroy(aspace); } } @@ -202,8 +201,7 @@ static void mdp4_destroy(struct msm_kms *kms) drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo); if (aspace) { - aspace->mmu->funcs->detach(aspace->mmu, - iommu_ports, ARRAY_SIZE(iommu_ports)); + aspace->mmu->funcs->detach(aspace->mmu); msm_gem_address_space_put(aspace); } @@ -416,10 +414,6 @@ fail: return ret; } -static const char *iommu_ports[] = { - "mdp_port0_cb0", "mdp_port1_cb0", -}; - struct msm_kms *mdp4_kms_init(struct drm_device *dev) { struct platform_device *pdev = dev->platformdev; @@ -527,8 +521,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) mdp4_kms->aspace = aspace; - ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports, - ARRAY_SIZE(iommu_ports)); + ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0); if (ret) goto fail; } else { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index e4e69ebd116e..4dbf456504b7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -22,10 +22,6 @@ #include "msm_mmu.h" #include "mdp5_kms.h" -static const char *iommu_ports[] = { - "mdp_0", -}; - static int mdp5_hw_init(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); @@ -613,8 +609,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) mdp5_kms->aspace = aspace; - ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports, - ARRAY_SIZE(iommu_ports)); + ret = aspace->mmu->funcs->attach(aspace->mmu, NULL, 0); if (ret) { dev_err(&pdev->dev, "failed to attach iommu: %d\n", ret); diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 581918da183f..c448874a1f8a 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -41,10 +41,6 @@ #define CREATE_TRACE_POINTS #include "sde_trace.h" -static const char * const iommu_ports[] = { - "mdp_0", -}; - /** * Controls size of event log buffer. Specified as a power of 2. */ @@ -1076,8 +1072,7 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) sde_kms->aspace[i] = aspace; - ret = mmu->funcs->attach(mmu, (const char **)iommu_ports, - ARRAY_SIZE(iommu_ports)); + ret = mmu->funcs->attach(mmu, NULL, 0); if (ret) { SDE_ERROR("failed to attach iommu %d: %d\n", i, ret); msm_gem_address_space_put(aspace); From 8e00aa10d2c7675231af568c5cf7e3b7a3e69bdc Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:43 -0600 Subject: [PATCH 10/11] msm/drm: Add secure support to GPU IOMMU Add support for creating a secure domain in the GPU IOMMU. By default the secure domain is bound to context bank name "gfx3d_secure". Change-Id: Ic0dedbad19f69ec4175624dc80f2114bfda2e195 Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/msm_iommu.c | 27 +++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_mmu.h | 1 + 2 files changed, 28 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index f5d89f76dda8..b52c4752c5fe 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -17,6 +17,7 @@ #include #include +#include #include "msm_drv.h" #include "msm_iommu.h" @@ -142,6 +143,20 @@ static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names, return 0; } +static int msm_iommu_attach_secure(struct msm_mmu *mmu, const char **names, + int cnt) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + int ret, vmid = VMID_CP_PIXEL; + + ret = iommu_domain_set_attr(iommu->domain, DOMAIN_ATTR_SECURE_VMID, + &vmid); + if (ret) + return ret; + + return iommu_attach_device(iommu->domain, mmu->dev); +} + static void msm_iommu_detach(struct msm_mmu *mmu) { struct msm_iommu *iommu = to_msm_iommu(mmu); @@ -250,6 +265,14 @@ static const struct msm_mmu_funcs user_funcs = { .disable = msm_iommu_clocks_disable, }; +static const struct msm_mmu_funcs secure_funcs = { + .attach = msm_iommu_attach_secure, + .detach = msm_iommu_detach, + .map = msm_iommu_map, + .unmap = msm_iommu_unmap, + .destroy = msm_iommu_destroy, +}; + static const struct msm_mmu_funcs dynamic_funcs = { .attach = msm_iommu_attach_dynamic, .detach = msm_iommu_detach_dynamic, @@ -270,6 +293,10 @@ static const struct { .cbname = "gfx3d_user", .funcs = &user_funcs, }, + [MSM_IOMMU_DOMAIN_SECURE] = { + .cbname = "gfx3d_secure", + .funcs = &secure_funcs + }, }; static struct msm_mmu *iommu_create(struct device *dev, diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index 8be3cefd686d..033370ccbe24 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -33,6 +33,7 @@ enum msm_mmu_domain_type { enum msm_iommu_domain_type { MSM_IOMMU_DOMAIN_DEFAULT, MSM_IOMMU_DOMAIN_USER, + MSM_IOMMU_DOMAIN_SECURE, }; struct msm_mmu_funcs { From d84fd15df03db850f81d7057f8082478a994e5e1 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 7 Apr 2017 15:01:43 -0600 Subject: [PATCH 11/11] msm/drm: Move msm_drm_config configuration into the GPUs With the upcoming secure code the decision tree for configuration (deciding where virtual addresses start/stop, etc) is going to get a bit more complex. Head issues off at the pass by moving the configuration into the GPU specific code. This does result in a bit more code duplication but it is a lot cleaner. Change-Id: Ic0dedbad57c11a4bba01825214d0a7853ab537ba Signed-off-by: Jordan Crouse --- drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 9 ++++++++- drivers/gpu/drm/msm/adreno/a4xx_gpu.c | 9 ++++++++- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 16 +++++++++++++++- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 24 +++--------------------- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +- drivers/gpu/drm/msm/msm_gpu.h | 3 +++ 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index c4f886fd6037..a417e42944fc 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -466,6 +466,7 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) struct msm_gpu *gpu; struct msm_drm_private *priv = dev->dev_private; struct platform_device *pdev = priv->gpu_pdev; + struct msm_gpu_config a3xx_config = { 0 }; int ret; if (!pdev) { @@ -491,7 +492,13 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) adreno_gpu->registers = a3xx_registers; adreno_gpu->reg_offsets = a3xx_register_offsets; - ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); + a3xx_config.ioname = MSM_GPU_DEFAULT_IONAME; + a3xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME; + a3xx_config.nr_rings = 1; + a3xx_config.va_start = 0x300000; + a3xx_config.va_end = 0xffffffff; + + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a3xx_config); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 534a7c3fbdca..069823f054f7 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -543,6 +543,7 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) struct msm_gpu *gpu; struct msm_drm_private *priv = dev->dev_private; struct platform_device *pdev = priv->gpu_pdev; + struct msm_gpu_config a4xx_config = { 0 }; int ret; if (!pdev) { @@ -568,7 +569,13 @@ struct msm_gpu *a4xx_gpu_init(struct drm_device *dev) adreno_gpu->registers = a4xx_registers; adreno_gpu->reg_offsets = a4xx_register_offsets; - ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 1); + a4xx_config.ioname = MSM_GPU_DEFAULT_IONAME; + a4xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME; + a4xx_config.nr_rings = 1; + a4xx_config.va_start = 0x300000; + a4xx_config.va_end = 0xffffffff; + + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a4xx_config); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 32b2c7fab839..ec75d1792af5 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1306,6 +1306,7 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) struct a5xx_gpu *a5xx_gpu = NULL; struct adreno_gpu *adreno_gpu; struct msm_gpu *gpu; + struct msm_gpu_config a5xx_config = { 0 }; int ret; if (!pdev) { @@ -1329,7 +1330,20 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) /* Check the efuses for some configuration */ a5xx_efuses_read(pdev, adreno_gpu); - ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, 4); + a5xx_config.ioname = MSM_GPU_DEFAULT_IONAME; + a5xx_config.irqname = MSM_GPU_DEFAULT_IRQNAME; + + /* Set the number of rings to 4 - yay preemption */ + a5xx_config.nr_rings = 4; + + /* + * Set the user domain range to fall into the TTBR1 region for global + * objects + */ + a5xx_config.va_start = 0x800000000; + a5xx_config.va_end = 0x8ffffffff; + + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, &a5xx_config); if (ret) { a5xx_destroy(&(a5xx_gpu->base.base)); return ERR_PTR(ret); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index aea275161c62..19ce41edc175 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -519,10 +519,10 @@ static int adreno_of_parse(struct platform_device *pdev, struct msm_gpu *gpu) int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct adreno_gpu *adreno_gpu, - const struct adreno_gpu_funcs *funcs, int nr_rings) + const struct adreno_gpu_funcs *funcs, + struct msm_gpu_config *gpu_config) { struct adreno_platform_config *config = pdev->dev.platform_data; - struct msm_gpu_config adreno_gpu_config = { 0 }; struct msm_gpu *gpu = &adreno_gpu->base; struct msm_mmu *mmu; int ret; @@ -536,26 +536,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, /* Get the rest of the target configuration from the device tree */ adreno_of_parse(pdev, gpu); - adreno_gpu_config.ioname = "kgsl_3d0_reg_memory"; - adreno_gpu_config.irqname = "kgsl_3d0_irq"; - adreno_gpu_config.nr_rings = nr_rings; - - adreno_gpu_config.va_start = SZ_16M; - adreno_gpu_config.va_end = 0xffffffff; - - if (adreno_gpu->revn >= 500) { - /* 5XX targets use a 64 bit region */ - adreno_gpu_config.va_start = 0x800000000; - adreno_gpu_config.va_end = 0x8ffffffff; - } else { - adreno_gpu_config.va_start = 0x300000; - adreno_gpu_config.va_end = 0xffffffff; - } - - adreno_gpu_config.nr_rings = nr_rings; - ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base, - adreno_gpu->info->name, &adreno_gpu_config); + adreno_gpu->info->name, gpu_config); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 8e8f3e5182d6..3f9bc655c383 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -257,7 +257,7 @@ struct msm_ringbuffer *adreno_active_ring(struct msm_gpu *gpu); int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs, - int nr_rings); + struct msm_gpu_config *config); void adreno_gpu_cleanup(struct adreno_gpu *gpu); void adreno_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 3fac423929c5..29e2e59b580b 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -29,6 +29,9 @@ struct msm_gem_submit; struct msm_gpu_perfcntr; +#define MSM_GPU_DEFAULT_IONAME "kgsl_3d0_reg_memory" +#define MSM_GPU_DEFAULT_IRQNAME "kgsl_3d0_irq" + struct msm_gpu_config { const char *ioname; const char *irqname;