From e453eb66bcda9c6aff4ce2c97e96bcb19587b411 Mon Sep 17 00:00:00 2001 From: Guchun Chen Date: Fri, 9 Mar 2018 20:48:57 +0800 Subject: [PATCH] drm: smmu: fix smmu map failure In concurrency test, smmu map failure appears in a low possibility. This is caused by virtual address conflict. Display driver calls different smmu map APIs to do map with the same domain, while the virtual address allocation happens separately, one in dmp-mapping.c, and another one is in msm_gem_vam.c. This could not gurantee the virtual addresses by different callers are different in the same mmu domain, if they are the same, the virtual address will possibily be mapped twice, hence conflict happens. The change is to fix this: 1. Remove the map calling for early splash buffer from msm_smmu_map. 2. Introduce one new map API early_splash_map/unmap, dedicated for memory mapping for early splash usercase. CRs-Fixed: 2198827 Change-Id: I8e632f1971998a14c362b5bf0ae9a5522a5a1bff Signed-off-by: Guchun Chen --- drivers/gpu/drm/msm/msm_mmu.h | 4 ++ drivers/gpu/drm/msm/msm_smmu.c | 70 ++++++++++++++++++++-------- drivers/gpu/drm/msm/sde/sde_splash.c | 11 +++-- 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index cd3a710f8f27..74dea95d90de 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -46,6 +46,10 @@ struct msm_mmu_funcs { void (*destroy)(struct msm_mmu *mmu); void (*enable)(struct msm_mmu *mmu); void (*disable)(struct msm_mmu *mmu); + int (*early_splash_map)(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, u32 flags); + void (*early_splash_unmap)(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt); int (*set_property)(struct msm_mmu *mmu, enum iommu_attr attr, void *data); }; diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index 4247243055b6..aefbe0988fe5 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -120,30 +120,19 @@ 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; int ret; if (!client || !sgt) return -EINVAL; - if (iova != 0) { - if (!client->mmu_mapping || !client->mmu_mapping->domain) - return -EINVAL; + 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); - domain = client->mmu_mapping->domain; - - return iommu_map_sg(domain, iova, sgt->sgl, - sgt->nents, flags); - } else { - 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; - } + return (ret != sgt->nents) ? -ENOMEM : 0; } static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, @@ -160,6 +149,47 @@ static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, DMA_BIDIRECTIONAL); } +static int msm_smmu_early_splash_map(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, u32 flags) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + struct iommu_domain *domain; + + if (!client || !sgt) + return -EINVAL; + + if (!client->mmu_mapping || !client->mmu_mapping->domain) + return -EINVAL; + + domain = client->mmu_mapping->domain; + + return iommu_map_sg(domain, iova, sgt->sgl, sgt->nents, flags); +} + +static void msm_smmu_early_splash_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; + size_t len = 0; + int unmapped, i = 0; + + if (!client || !client->mmu_mapping || !client->mmu_mapping->domain) + return; + + domain = client->mmu_mapping->domain; + + for_each_sg(sgt->sgl, sg, sgt->nents, i) + len += sg->length; + + unmapped = iommu_unmap(domain, iova, len); + if (unmapped < len) + DRM_ERROR("could not unmap iova@%llx\n", iova); +} + static void msm_smmu_destroy(struct msm_mmu *mmu) { struct msm_smmu *smmu = to_msm_smmu(mmu); @@ -199,6 +229,8 @@ static const struct msm_mmu_funcs funcs = { .map = msm_smmu_map, .unmap = msm_smmu_unmap, .destroy = msm_smmu_destroy, + .early_splash_map = msm_smmu_early_splash_map, + .early_splash_unmap = msm_smmu_early_splash_unmap, .set_property = msm_smmu_set_property, }; diff --git a/drivers/gpu/drm/msm/sde/sde_splash.c b/drivers/gpu/drm/msm/sde/sde_splash.c index 19e6406600cd..2789ae053663 100644 --- a/drivers/gpu/drm/msm/sde/sde_splash.c +++ b/drivers/gpu/drm/msm/sde/sde_splash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -301,8 +301,8 @@ static int _sde_splash_free_resource(struct msm_mmu *mmu, return -EINVAL; if (mmu->funcs && mmu->funcs->unmap) - mmu->funcs->unmap(mmu, sinfo->splash_mem_paddr[conn], - msm_obj->sgt, NULL); + mmu->funcs->early_splash_unmap(mmu, + sinfo->splash_mem_paddr[conn], msm_obj->sgt); _sde_splash_free_bootup_memory_to_system(sinfo->splash_mem_paddr[conn], sinfo->splash_mem_size[conn]); @@ -489,8 +489,9 @@ int sde_splash_smmu_map(struct drm_device *dev, struct msm_mmu *mmu, msm_obj = to_msm_bo(sinfo->obj[i]); if (mmu->funcs && mmu->funcs->map) { - ret = mmu->funcs->map(mmu, sinfo->splash_mem_paddr[i], - msm_obj->sgt, IOMMU_READ | IOMMU_NOEXEC, NULL); + ret = mmu->funcs->early_splash_map(mmu, + sinfo->splash_mem_paddr[i], msm_obj->sgt, + IOMMU_READ | IOMMU_NOEXEC); if (!ret) { SDE_ERROR("Map blk %d @%pK failed.\n",