From 05f15e3f74c903e874d227609821724e381f0aba Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Thu, 11 Aug 2016 16:17:17 -0700 Subject: [PATCH] iommu: msm: ensure lazy mappings are unmapped on detach Ensure that on detach any lazy mappings for that device are released. We don't want to leave any outstanding mappings after detach because the client expects all mappings to have been unmapped, also we don't want to leave references, in the lazy mapping framework, to devices which could cease to exists. CRs-Fixed: 1053605 Change-Id: I9894257c4783073fdba734a175bac486d6ee9347 Signed-off-by: Liam Mark --- arch/arm/mm/dma-mapping.c | 4 ++++ arch/arm64/mm/dma-mapping.c | 4 ++++ drivers/iommu/msm_dma_iommu_mapping.c | 31 ++++++++++++++++++++++++++- include/linux/msm_dma_iommu_mapping.h | 8 ++++++- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index d41957eae6ef..b663ad2182c3 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -2190,6 +2191,9 @@ static void __arm_iommu_detach_device(struct device *dev) return; } + if (msm_dma_unmap_all_for_dev(dev)) + dev_warn(dev, "IOMMU detach with outstanding mappings\n"); + iommu_detach_device(mapping->domain, dev); kref_put(&mapping->kref, release_iommu_mapping); to_dma_iommu_mapping(dev) = NULL; diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 06f9ffccd562..eb62c3d36faf 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "mm.h" @@ -2164,6 +2165,9 @@ void arm_iommu_detach_device(struct device *dev) iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, &s1_bypass); + if (msm_dma_unmap_all_for_dev(dev)) + dev_warn(dev, "IOMMU detach with outstanding mappings\n"); + iommu_detach_device(mapping->domain, dev); kref_put(&mapping->kref, release_iommu_mapping); dev->archdata.mapping = NULL; diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c index b91c7785df0b..0377f08e5007 100644 --- a/drivers/iommu/msm_dma_iommu_mapping.c +++ b/drivers/iommu/msm_dma_iommu_mapping.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -344,6 +344,35 @@ out: return; } +int msm_dma_unmap_all_for_dev(struct device *dev) +{ + int ret = 0; + struct msm_iommu_meta *meta; + struct rb_root *root; + struct rb_node *meta_node; + + mutex_lock(&msm_iommu_map_mutex); + root = &iommu_root; + meta_node = rb_first(root); + while (meta_node) { + struct msm_iommu_map *iommu_map; + + meta = rb_entry(meta_node, struct msm_iommu_meta, node); + mutex_lock(&meta->lock); + list_for_each_entry(iommu_map, &meta->iommu_maps, lnode) + if (iommu_map->dev == dev) + if (!kref_put(&iommu_map->ref, + msm_iommu_map_release)) + ret = -EINVAL; + + mutex_unlock(&meta->lock); + meta_node = rb_next(meta_node); + } + mutex_unlock(&msm_iommu_map_mutex); + + return ret; +} + /* * Only to be called by ION code when a buffer is freed */ diff --git a/include/linux/msm_dma_iommu_mapping.h b/include/linux/msm_dma_iommu_mapping.h index 370d6f5e1d65..76451faa2073 100644 --- a/include/linux/msm_dma_iommu_mapping.h +++ b/include/linux/msm_dma_iommu_mapping.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -50,6 +50,7 @@ static inline int msm_dma_map_sg(struct device *dev, struct scatterlist *sg, void msm_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int nents, enum dma_data_direction dir, struct dma_buf *dma_buf); +int msm_dma_unmap_all_for_dev(struct device *dev); /* * Below is private function only to be called by framework (ION) and not by @@ -89,6 +90,11 @@ static inline void msm_dma_unmap_sg(struct device *dev, { } +int msm_dma_unmap_all_for_dev(struct device *dev) +{ + return 0; +} + static inline void msm_dma_buf_freed(void *buffer) {} #endif /*CONFIG_IOMMU_API*/