[PATCH] ARM: Fix delayed dcache flush for ARMv6 non-aliasing caches
flush_dcache_page() did nothing for these caches, but since they suffer from I/D cache coherency issues, we need to ensure that data is written back to RAM. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
d411b845dc
commit
8830f04a09
|
@ -77,9 +77,8 @@ no_pmd:
|
|||
}
|
||||
|
||||
static void
|
||||
make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty)
|
||||
make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
|
||||
{
|
||||
struct address_space *mapping = page_mapping(page);
|
||||
struct mm_struct *mm = vma->vm_mm;
|
||||
struct vm_area_struct *mpnt;
|
||||
struct prio_tree_iter iter;
|
||||
|
@ -87,9 +86,6 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page,
|
|||
pgoff_t pgoff;
|
||||
int aliases = 0;
|
||||
|
||||
if (!mapping)
|
||||
return;
|
||||
|
||||
pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
|
||||
|
||||
/*
|
||||
|
@ -115,9 +111,11 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page,
|
|||
if (aliases)
|
||||
adjust_pte(vma, addr);
|
||||
else
|
||||
flush_cache_page(vma, addr, page_to_pfn(page));
|
||||
flush_cache_page(vma, addr, pfn);
|
||||
}
|
||||
|
||||
void __flush_dcache_page(struct address_space *mapping, struct page *page);
|
||||
|
||||
/*
|
||||
* Take care of architecture specific things when placing a new PTE into
|
||||
* a page table, or changing an existing PTE. Basically, there are two
|
||||
|
@ -134,29 +132,22 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page,
|
|||
void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
|
||||
{
|
||||
unsigned long pfn = pte_pfn(pte);
|
||||
struct address_space *mapping;
|
||||
struct page *page;
|
||||
|
||||
if (!pfn_valid(pfn))
|
||||
return;
|
||||
|
||||
page = pfn_to_page(pfn);
|
||||
if (page_mapping(page)) {
|
||||
mapping = page_mapping(page);
|
||||
if (mapping) {
|
||||
int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
|
||||
|
||||
if (dirty) {
|
||||
/*
|
||||
* This is our first userspace mapping of this page.
|
||||
* Ensure that the physical page is coherent with
|
||||
* the kernel mapping.
|
||||
*
|
||||
* FIXME: only need to do this on VIVT and aliasing
|
||||
* VIPT cache architectures. We can do that
|
||||
* by choosing whether to set this bit...
|
||||
*/
|
||||
__cpuc_flush_dcache_page(page_address(page));
|
||||
}
|
||||
if (dirty)
|
||||
__flush_dcache_page(mapping, page);
|
||||
|
||||
if (cache_is_vivt())
|
||||
make_coherent(vma, addr, page, dirty);
|
||||
make_coherent(mapping, vma, addr, pfn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,13 +37,8 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
|
|||
#define flush_pfn_alias(pfn,vaddr) do { } while (0)
|
||||
#endif
|
||||
|
||||
static void __flush_dcache_page(struct address_space *mapping, struct page *page)
|
||||
void __flush_dcache_page(struct address_space *mapping, struct page *page)
|
||||
{
|
||||
struct mm_struct *mm = current->active_mm;
|
||||
struct vm_area_struct *mpnt;
|
||||
struct prio_tree_iter iter;
|
||||
pgoff_t pgoff;
|
||||
|
||||
/*
|
||||
* Writeback any data associated with the kernel mapping of this
|
||||
* page. This ensures that data in the physical page is mutually
|
||||
|
@ -52,25 +47,22 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
|
|||
__cpuc_flush_dcache_page(page_address(page));
|
||||
|
||||
/*
|
||||
* If there's no mapping pointer here, then this page isn't
|
||||
* visible to userspace yet, so there are no cache lines
|
||||
* associated with any other aliases.
|
||||
*/
|
||||
if (!mapping)
|
||||
return;
|
||||
|
||||
/*
|
||||
* This is a page cache page. If we have a VIPT cache, we
|
||||
* only need to do one flush - which would be at the relevant
|
||||
* If this is a page cache page, and we have an aliasing VIPT cache,
|
||||
* we only need to do one flush - which would be at the relevant
|
||||
* userspace colour, which is congruent with page->index.
|
||||
*/
|
||||
if (cache_is_vipt()) {
|
||||
if (cache_is_vipt_aliasing())
|
||||
if (mapping && cache_is_vipt_aliasing())
|
||||
flush_pfn_alias(page_to_pfn(page),
|
||||
page->index << PAGE_CACHE_SHIFT);
|
||||
return;
|
||||
}
|
||||
|
||||
static void __flush_dcache_aliases(struct address_space *mapping, struct page *page)
|
||||
{
|
||||
struct mm_struct *mm = current->active_mm;
|
||||
struct vm_area_struct *mpnt;
|
||||
struct prio_tree_iter iter;
|
||||
pgoff_t pgoff;
|
||||
|
||||
/*
|
||||
* There are possible user space mappings of this page:
|
||||
* - VIVT cache: we need to also write back and invalidate all user
|
||||
|
@ -116,12 +108,12 @@ void flush_dcache_page(struct page *page)
|
|||
{
|
||||
struct address_space *mapping = page_mapping(page);
|
||||
|
||||
if (cache_is_vipt_nonaliasing())
|
||||
return;
|
||||
|
||||
if (mapping && !mapping_mapped(mapping))
|
||||
set_bit(PG_dcache_dirty, &page->flags);
|
||||
else
|
||||
else {
|
||||
__flush_dcache_page(mapping, page);
|
||||
if (mapping && cache_is_vivt())
|
||||
__flush_dcache_aliases(mapping, page);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(flush_dcache_page);
|
||||
|
|
Loading…
Reference in New Issue