mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
msm: iommu: re-use existing buffers for `extra' mappings
There is a bug on some hardware that requires us to overmap Iommu mappings by 2x. Currently, we set aside a dummy buffer onto which we map all of these dummy mappings. In general, for large mappings it's nice to use the more efficient iommu_map_range instead of calling iommu_map repeatedly. However, with our current approach in msm_iommu_map_extra we can't use iommu_map_range for page_sizes larger than the dummy buffer. To avoid wasting memory by increasing the size of the dummy buffer, we can simply remap on top of the the buffer being mapped in the first place. Since the second mapping should never be used (besides by the buggy hardware) this should not be a problem. Re-use existing buffers for all `extra' mappings. Essentially, map the same physical address range twice. To be extra safe, make the second mapping read-only. Change-Id: I35462ad50de8da1f2befa3e3f0895925535cdc98 Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
This commit is contained in:
parent
32c723c2da
commit
0423b88e29
8 changed files with 45 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2011-2013, 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
|
||||
|
@ -90,6 +90,7 @@ extern int msm_use_iommu(void);
|
|||
|
||||
extern int msm_iommu_map_extra(struct iommu_domain *domain,
|
||||
unsigned long start_iova,
|
||||
unsigned long phys_addr,
|
||||
unsigned long size,
|
||||
unsigned long page_size,
|
||||
int cached);
|
||||
|
@ -140,6 +141,7 @@ static inline int msm_use_iommu(void)
|
|||
|
||||
static inline int msm_iommu_map_extra(struct iommu_domain *domain,
|
||||
unsigned long start_iova,
|
||||
unsigned long phys_addr,
|
||||
unsigned long size,
|
||||
unsigned long page_size,
|
||||
int cached)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2013, 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
|
||||
|
@ -26,9 +26,6 @@
|
|||
#include <mach/socinfo.h>
|
||||
#include <mach/msm_subsystem_map.h>
|
||||
|
||||
/* dummy 64K for overmapping */
|
||||
char iommu_dummy[2*SZ_64K-4];
|
||||
|
||||
struct msm_iova_data {
|
||||
struct rb_node node;
|
||||
struct mem_pool *pools;
|
||||
|
@ -51,17 +48,29 @@ int msm_use_iommu()
|
|||
return iommu_present(&platform_bus_type);
|
||||
}
|
||||
|
||||
bool msm_iommu_page_size_is_supported(unsigned long page_size)
|
||||
{
|
||||
return page_size == SZ_4K
|
||||
|| page_size == SZ_64K
|
||||
|| page_size == SZ_1M
|
||||
|| page_size == SZ_16M;
|
||||
}
|
||||
|
||||
int msm_iommu_map_extra(struct iommu_domain *domain,
|
||||
unsigned long start_iova,
|
||||
unsigned long phy_addr,
|
||||
unsigned long size,
|
||||
unsigned long page_size,
|
||||
int cached)
|
||||
int prot)
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
unsigned long phy_addr = ALIGN(virt_to_phys(iommu_dummy), page_size);
|
||||
unsigned long temp_iova = start_iova;
|
||||
if (page_size == SZ_4K) {
|
||||
/* the extra "padding" should never be written to. map it
|
||||
* read-only. */
|
||||
prot &= ~IOMMU_WRITE;
|
||||
|
||||
if (msm_iommu_page_size_is_supported(page_size)) {
|
||||
struct scatterlist *sglist;
|
||||
unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
|
||||
struct page *dummy_page = phys_to_page(phy_addr);
|
||||
|
@ -77,7 +86,7 @@ int msm_iommu_map_extra(struct iommu_domain *domain,
|
|||
for (i = 0; i < nrpages; i++)
|
||||
sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
|
||||
|
||||
ret = iommu_map_range(domain, temp_iova, sglist, size, cached);
|
||||
ret = iommu_map_range(domain, temp_iova, sglist, size, prot);
|
||||
if (ret) {
|
||||
pr_err("%s: could not map extra %lx in domain %p\n",
|
||||
__func__, start_iova, domain);
|
||||
|
@ -91,7 +100,7 @@ int msm_iommu_map_extra(struct iommu_domain *domain,
|
|||
|
||||
for (i = 0; i < nrpages; i++) {
|
||||
ret = iommu_map(domain, temp_iova, phy_addr, page_size,
|
||||
cached);
|
||||
prot);
|
||||
if (ret) {
|
||||
pr_err("%s: could not map %lx in domain %p, error: %d\n",
|
||||
__func__, start_iova, domain, ret);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2011-2013, 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
|
||||
|
@ -412,8 +412,8 @@ struct msm_mapped_buffer *msm_subsystem_map_buffer(unsigned long phys,
|
|||
|
||||
if (flags & MSM_SUBSYSTEM_MAP_IOMMU_2X)
|
||||
msm_iommu_map_extra
|
||||
(d, temp_va, length, SZ_4K,
|
||||
(IOMMU_READ | IOMMU_WRITE));
|
||||
(d, temp_va, phys, length, SZ_4K,
|
||||
IOMMU_READ);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* drivers/gpu/ion/ion_carveout_heap.c
|
||||
*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -430,8 +430,9 @@ int ion_carveout_heap_map_iommu(struct ion_buffer *buffer,
|
|||
|
||||
if (extra) {
|
||||
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, extra,
|
||||
SZ_4K, prot);
|
||||
unsigned long phys_addr = sg_phys(sglist);
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
|
||||
extra, SZ_4K, prot);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
|
|
@ -228,8 +228,9 @@ int ion_cma_map_iommu(struct ion_buffer *buffer,
|
|||
|
||||
extra_iova_addr = data->iova_addr + buffer->size;
|
||||
if (extra) {
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
|
||||
prot);
|
||||
unsigned long phys_addr = sg_phys(table->sgl);
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
|
||||
extra, SZ_4K, prot);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
|
|
@ -926,6 +926,7 @@ static int iommu_map_all(unsigned long domain_num, struct ion_cp_heap *cp_heap,
|
|||
}
|
||||
if (domain_num == cp_heap->iommu_2x_map_domain)
|
||||
ret_value = msm_iommu_map_extra(domain, temp_iova,
|
||||
cp_heap->base,
|
||||
cp_heap->total_size,
|
||||
SZ_64K, prot);
|
||||
if (ret_value)
|
||||
|
@ -1018,8 +1019,9 @@ static int ion_cp_heap_map_iommu(struct ion_buffer *buffer,
|
|||
|
||||
if (extra) {
|
||||
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, extra,
|
||||
SZ_4K, prot);
|
||||
unsigned long phys_addr = sg_phys(buffer->sg_table->sgl);
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
|
||||
extra, SZ_4K, prot);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
|
|
@ -354,8 +354,9 @@ int ion_iommu_heap_map_iommu(struct ion_buffer *buffer,
|
|||
|
||||
if (extra) {
|
||||
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
|
||||
prot);
|
||||
unsigned long phys_addr = sg_phys(buffer->sg_table->sgl);
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
|
||||
extra, SZ_4K, prot);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* drivers/gpu/ion/ion_system_heap.c
|
||||
*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -304,8 +304,9 @@ int ion_system_heap_map_iommu(struct ion_buffer *buffer,
|
|||
|
||||
extra_iova_addr = data->iova_addr + buffer->size;
|
||||
if (extra) {
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
|
||||
prot);
|
||||
unsigned long phys_addr = sg_phys(table->sgl);
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
|
||||
extra, SZ_4K, prot);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
@ -524,8 +525,9 @@ int ion_system_contig_heap_map_iommu(struct ion_buffer *buffer,
|
|||
|
||||
if (extra) {
|
||||
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
|
||||
prot);
|
||||
unsigned long phys_addr = sg_phys(sglist);
|
||||
ret = msm_iommu_map_extra(domain, extra_iova_addr, phys_addr,
|
||||
extra, SZ_4K, prot);
|
||||
if (ret)
|
||||
goto out2;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue