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 <lmark@codeaurora.org>
This commit is contained in:
Liam Mark 2016-08-11 16:17:17 -07:00
parent e94b446eac
commit 05f15e3f74
4 changed files with 45 additions and 2 deletions

View file

@ -28,6 +28,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/cma.h> #include <linux/cma.h>
#include <linux/msm_dma_iommu_mapping.h>
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/highmem.h> #include <asm/highmem.h>
@ -2190,6 +2191,9 @@ static void __arm_iommu_detach_device(struct device *dev)
return; return;
} }
if (msm_dma_unmap_all_for_dev(dev))
dev_warn(dev, "IOMMU detach with outstanding mappings\n");
iommu_detach_device(mapping->domain, dev); iommu_detach_device(mapping->domain, dev);
kref_put(&mapping->kref, release_iommu_mapping); kref_put(&mapping->kref, release_iommu_mapping);
to_dma_iommu_mapping(dev) = NULL; to_dma_iommu_mapping(dev) = NULL;

View file

@ -34,6 +34,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <asm/dma-iommu.h> #include <asm/dma-iommu.h>
#include <linux/dma-mapping-fast.h> #include <linux/dma-mapping-fast.h>
#include <linux/msm_dma_iommu_mapping.h>
#include "mm.h" #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, iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS,
&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); iommu_detach_device(mapping->domain, dev);
kref_put(&mapping->kref, release_iommu_mapping); kref_put(&mapping->kref, release_iommu_mapping);
dev->archdata.mapping = NULL; dev->archdata.mapping = NULL;

View file

@ -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 * 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 * it under the terms of the GNU General Public License version 2 and
@ -344,6 +344,35 @@ out:
return; 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 * Only to be called by ION code when a buffer is freed
*/ */

View file

@ -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 * 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 * 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, void msm_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int nents,
enum dma_data_direction dir, struct dma_buf *dma_buf); 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 * 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) {} static inline void msm_dma_buf_freed(void *buffer) {}
#endif /*CONFIG_IOMMU_API*/ #endif /*CONFIG_IOMMU_API*/