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",