Loading drivers/iommu/Kconfig +19 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,25 @@ config MSM_IOMMU_TLBINVAL_ON_MAP If unsure, say Y here. config MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING bool "Don't align Virtual address at 1MB boundary" depends on MSM_IOMMU help Say Y here if the MMU500 revision has a bug in active prefetch which can cause TLB corruptions due to 1MB alignment of a buffer. Here is the sequence which will surface this BUG. 1) Create a 2-level mapping in v7S format for 1MB buffer. Start of the buffer should be at even MB boundary. 2) Create a section mapping for 1MB buffer adjacent to previous mapping in step 1. 3) Access last page from 2 level mapping followed by an access into section mapped area. 4) Step 3 will result into TLB corruption and this corruption can lead to any misbehavior (like Permission fault) for sub-sequent transactions. If unsure, say Y here if IOMMU mapping will not exhaust the VA space. # AMD IOMMU support config AMD_IOMMU bool "AMD IOMMU support" Loading drivers/iommu/msm_iommu_domains.c +20 −2 Original line number Diff line number Diff line /* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2015, 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 Loading Loading @@ -387,6 +387,21 @@ static struct msm_iova_data *msm_domain_to_iova_data(struct iommu_domain return iova_data; } #ifdef CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING static unsigned long get_alignment_order(unsigned long align) { if (align >= SZ_1M && align < SZ_2M) return ilog2(SZ_2M); else return ilog2(align); } #else static unsigned long get_alignment_order(unsigned long align) { return ilog2(align); } #endif int msm_allocate_iova_address(unsigned int iommu_domain, unsigned int partition_no, unsigned long size, Loading @@ -396,6 +411,7 @@ int msm_allocate_iova_address(unsigned int iommu_domain, struct msm_iova_data *data; struct mem_pool *pool; unsigned long va; unsigned long aligned_order; data = find_domain(iommu_domain); Loading @@ -410,8 +426,10 @@ int msm_allocate_iova_address(unsigned int iommu_domain, if (!pool->gpool) return -EINVAL; aligned_order = get_alignment_order(align); mutex_lock(&pool->pool_mutex); va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align)); va = gen_pool_alloc_aligned(pool->gpool, size, aligned_order); mutex_unlock(&pool->pool_mutex); if (va) { pool->free -= size; Loading Loading
drivers/iommu/Kconfig +19 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,25 @@ config MSM_IOMMU_TLBINVAL_ON_MAP If unsure, say Y here. config MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING bool "Don't align Virtual address at 1MB boundary" depends on MSM_IOMMU help Say Y here if the MMU500 revision has a bug in active prefetch which can cause TLB corruptions due to 1MB alignment of a buffer. Here is the sequence which will surface this BUG. 1) Create a 2-level mapping in v7S format for 1MB buffer. Start of the buffer should be at even MB boundary. 2) Create a section mapping for 1MB buffer adjacent to previous mapping in step 1. 3) Access last page from 2 level mapping followed by an access into section mapped area. 4) Step 3 will result into TLB corruption and this corruption can lead to any misbehavior (like Permission fault) for sub-sequent transactions. If unsure, say Y here if IOMMU mapping will not exhaust the VA space. # AMD IOMMU support config AMD_IOMMU bool "AMD IOMMU support" Loading
drivers/iommu/msm_iommu_domains.c +20 −2 Original line number Diff line number Diff line /* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. /* Copyright (c) 2010-2015, 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 Loading Loading @@ -387,6 +387,21 @@ static struct msm_iova_data *msm_domain_to_iova_data(struct iommu_domain return iova_data; } #ifdef CONFIG_MMU500_ACTIVE_PREFETCH_BUG_WITH_SECTION_MAPPING static unsigned long get_alignment_order(unsigned long align) { if (align >= SZ_1M && align < SZ_2M) return ilog2(SZ_2M); else return ilog2(align); } #else static unsigned long get_alignment_order(unsigned long align) { return ilog2(align); } #endif int msm_allocate_iova_address(unsigned int iommu_domain, unsigned int partition_no, unsigned long size, Loading @@ -396,6 +411,7 @@ int msm_allocate_iova_address(unsigned int iommu_domain, struct msm_iova_data *data; struct mem_pool *pool; unsigned long va; unsigned long aligned_order; data = find_domain(iommu_domain); Loading @@ -410,8 +426,10 @@ int msm_allocate_iova_address(unsigned int iommu_domain, if (!pool->gpool) return -EINVAL; aligned_order = get_alignment_order(align); mutex_lock(&pool->pool_mutex); va = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align)); va = gen_pool_alloc_aligned(pool->gpool, size, aligned_order); mutex_unlock(&pool->pool_mutex); if (va) { pool->free -= size; Loading