[ARM] 5366/1: fix shared memory coherency with VIVT L1 + L2 caches

When there are multiple L1-aliasing userland mappings of the same physical
page, we currently remap each of them uncached, to prevent VIVT cache
aliasing issues. (E.g. writes to one of the mappings not being immediately
visible via another mapping.)  However, when we do this remapping, there
could still be stale data in the L2 cache, and an uncached mapping might
bypass L2 and go straight to RAM.  This would cause reads from such
mappings to see old data (until the dirty L2 line is eventually evicted.)

This issue is solved by forcing a L2 cache flush whenever the shared page
is made L1 uncacheable.

Ideally, we would make L1 uncacheable and L2 cacheable as L2 is PIPT. But
Feroceon does not support that combination, and the TEX=5 C=0 B=0 encoding
for XSc3 doesn't appear to work in practice.

Signed-off-by: Nicolas Pitre <nico@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Nicolas Pitre 2009-01-16 23:02:54 +01:00 committed by Russell King
parent ecbab71c52
commit 08e445bd6a

View File

@ -66,7 +66,10 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address)
* fault (ie, is old), we can safely ignore any issues. * fault (ie, is old), we can safely ignore any issues.
*/ */
if (ret && (pte_val(entry) & L_PTE_MT_MASK) != shared_pte_mask) { if (ret && (pte_val(entry) & L_PTE_MT_MASK) != shared_pte_mask) {
flush_cache_page(vma, address, pte_pfn(entry)); unsigned long pfn = pte_pfn(entry);
flush_cache_page(vma, address, pfn);
outer_flush_range((pfn << PAGE_SHIFT),
(pfn << PAGE_SHIFT) + PAGE_SIZE);
pte_val(entry) &= ~L_PTE_MT_MASK; pte_val(entry) &= ~L_PTE_MT_MASK;
pte_val(entry) |= shared_pte_mask; pte_val(entry) |= shared_pte_mask;
set_pte_at(vma->vm_mm, address, pte, entry); set_pte_at(vma->vm_mm, address, pte, entry);