Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54a8c3cf authored by Chintan Pandya's avatar Chintan Pandya Committed by Gerrit - the friendly Code Review server
Browse files

iommu: msm: Workaround MMU500 active pre-fetch BUG



MMU500 has a bug in active pre-fetch when page table
format is v7S. Details of the BUG are as follows.

If the 2-level mapping is followed by 1MB section mapping at
odd-MB boundary, then any consecutive access across that odd
boundary can cause TLB corruption if these entries are being
active pre-fetched.

                              .
                              .
Even MB boundary     ----------------------------------
                     | Pointer to 2nd level page table |
Odd MB boundary      ----------------------------------
                     | PTE pointing to 1 MB region     |
Even MB boundary     ----------------------------------
                              .
                              .

To workaround this bug, don't allow virtual address at 1MB
alignment. Instead align the buffer at 2MB boundary which
will not reproduce the BUG condition.

If we disable active pre-fetch, BUG would not appear but
that would be huge performance cost that we don't want to
live with.

Change-Id: Ia29299e3d53790a786deee86ee07862277fc4968
Signed-off-by: default avatarChintan Pandya <cpandya@codeaurora.org>
parent 82dae81f
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -148,6 +148,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"
+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
@@ -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,
@@ -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);

@@ -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;