Platform developers note that generic code will always
invoke this interface with mm->page_table_lock held.
-4) void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+4) void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
This time we need to remove the PAGE_SIZE sized translation
from the TLB. The 'vma' is the backing structure used by
After running, this interface must make sure that any previous
page table modification for address space 'vma->vm_mm' for
- user virtual address 'page' will be visible to the cpu. That
+ user virtual address 'addr' will be visible to the cpu. That
is, after running, there will be no entries in the TLB for
- 'vma->vm_mm' for virtual address 'page'.
+ 'vma->vm_mm' for virtual address 'addr'.
This is used primarily during fault processing.
change_range_of_page_tables(mm, start, end);
flush_tlb_range(vma, start, end);
- 3) flush_cache_page(vma, page);
+ 3) flush_cache_page(vma, addr);
set_pte(pte_pointer, new_pte_val);
- flush_tlb_page(vma, page);
+ flush_tlb_page(vma, addr);
The cache level flush will always be first, because this allows
us to properly handle systems whose caches are strict and require
call flush_cache_page (see below) for each entry which may be
modified.
-4) void flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+4) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr)
This time we need to remove a PAGE_SIZE sized range
from the cache. The 'vma' is the backing structure used by
"Harvard" type cache layouts).
After running, there will be no entries in the cache for
- 'vma->vm_mm' for virtual address 'page'.
+ 'vma->vm_mm' for virtual address 'addr'.
This is used primarily during fault processing.
NOTE: This does not fix shared mmaps, check out the sparc64 port for
one way to solve this (in particular SPARC_FLAG_MMAPSHARED).
-Next, you have two methods to solve the D-cache aliasing issue for all
+Next, you have to solve the D-cache aliasing issue for all
other cases. Please keep in mind that fact that, for a given page
mapped into some user address space, there is always at least one more
mapping, that of the kernel in it's linear mapping starting at
aliasing problem has the potential to exist since the kernel already
maps this page at its virtual address.
-First, I describe the old method to deal with this problem. I am
-describing it for documentation purposes, but it is deprecated and the
-latter method I describe next should be used by all new ports and all
-existing ports should move over to the new mechanism as well.
-
- flush_page_to_ram(struct page *page)
-
- The physical page 'page' is about to be place into the
- user address space of a process. If it is possible for
- stores done recently by the kernel into this physical
- page, to not be visible to an arbitrary mapping in userspace,
- you must flush this page from the D-cache.
-
- If the D-cache is writeback in nature, the dirty data (if
- any) for this physical page must be written back to main
- memory before the cache lines are invalidated.
-
-Admittedly, the author did not think very much when designing this
-interface. It does not give the architecture enough information about
-what exactly is going on, and there is no context to base a judgment
-on about whether an alias is possible at all. The new interfaces to
-deal with D-cache aliasing are meant to address this by telling the
-architecture specific code exactly which is going on at the proper points
-in time.
-
-Here is the new interface:
-
- void copy_user_page(void *to, void *from, unsigned long address)
- void clear_user_page(void *to, unsigned long address)
+ void copy_user_page(void *to, void *from, unsigned long addr, struct page *page)
+ void clear_user_page(void *to, unsigned long addr, struct page *page)
These two routines store data in user anonymous or COW
pages. It allows a port to efficiently avoid D-cache alias
of the same "color" as the user mapping of the page. Sparc64
for example, uses this technique.
- The "address" parameter tells the virtual address where the
- user will ultimately have this page mapped.
+ The 'addr' parameter tells the virtual address where the
+ user will ultimately have this page mapped, and the 'page'
+ parameter gives a pointer to the struct page of the target.
If D-cache aliasing is not an issue, these two routines may
simply call memcpy/memset directly and do nothing more.
void flush_icache_page(struct vm_area_struct *vma, struct page *page)
All the functionality of flush_icache_page can be implemented in
- flush_dcache_page and update_mmu_cache. In 2.5 the hope is to
+ flush_dcache_page and update_mmu_cache. In 2.7 the hope is to
remove this interface completely.
pte_unmap(pte);
goto out;
}
- flush_page_to_ram(page);
set_pte(pte, mk_pte(page, PAGE_GATE));
pte_unmap(pte);
}
}
err = copy_from_user(kaddr + offset, (char *)A(str),
bytes_to_copy);
- flush_page_to_ram(page);
+ flush_dcache_page(page);
kunmap(page);
if (err)
}
err = copy_from_user(kaddr + offset, (char *)A(str), bytes_to_copy);
flush_dcache_page(page);
- flush_page_to_ram(page);
kunmap(page);
if (err)
err = copy_from_user(kaddr + offset, (char *)A(str),
bytes_to_copy);
- flush_page_to_ram(page);
kunmap((unsigned long)kaddr);
if (err)
err = copy_from_user(kaddr + offset, (char *)A(str),
bytes_to_copy);
- flush_page_to_ram(page);
kunmap(page);
if (err)
flush_cache_page(vma, addr);
kaddr = kmap(page);
DUMP_WRITE(kaddr, PAGE_SIZE);
- flush_page_to_ram(page);
kunmap(page);
}
page_cache_release(page);
}
lru_cache_add_active(page);
flush_dcache_page(page);
- flush_page_to_ram(page);
set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
pte_chain = page_add_rmap(page, pte, pte_chain);
pte_unmap(pte);
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
/* Note that the following two definitions are _highly_ dependent
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma,start,end) do { } while (0)
#define flush_cache_page(vma,vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define invalidate_dcache_range(start,end) do { } while (0)
#define clean_dcache_range(start,end) do { } while (0)
cpu_cache_clean_invalidate_range((unsigned long)start, \
((unsigned long)start) + size, 0);
-/*
- * This is an obsolete interface; the functionality that was provided by this
- * function is now merged into our flush_dcache_page, flush_icache_page,
- * copy_user_page and clear_user_page functions.
- */
-#define flush_page_to_ram(page) do { } while (0)
-
/*
* flush_dcache_page is used when the kernel has written to the page
* cache page at virtual address page->virtual.
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_icache_page(vma,page) do { } while (0)
#define flush_dcache_page(page) \
/* Push the page at kernel virtual address and clear the icache */
/* RZ: use cpush %bc instead of cpush %dc, cinv %ic */
-#define flush_page_to_ram(page) __flush_page_to_ram(page_address(page))
extern inline void __flush_page_to_ram(void *vaddr)
{
if (CPU_IS_040_OR_060) {
}
}
-#define flush_dcache_page(page) do { } while (0)
+#define flush_dcache_page(page) __flush_page_to_ram(page_address(page))
#define flush_icache_page(vma,pg) do { } while (0)
#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE)
#endif
-#define clear_user_page(page, vaddr, pg) clear_page(page)
-#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
+#define clear_user_page(addr, vaddr, page) \
+ do { clear_page(addr); \
+ flush_dcache_page(page); \
+ } while (0)
+#define copy_user_page(to, from, vaddr, page) \
+ do { copy_page(to, from); \
+ flush_dcache_page(page); \
+ } while (0)
/*
* These are used to make use of C type-checking..
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_range(start,len) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
#define flush_icache_range(start,len) __flush_cache_all()
#define clear_page(page) _clear_page(page)
#define copy_page(to, from) _copy_page(to, from)
-#define clear_user_page(page, vaddr) clear_page(page)
-#define copy_user_page(to, from, vaddr) copy_page(to, from)
+
+#define clear_user_page(addr, vaddr, page) \
+ do { clear_page(addr); \
+ flush_dcache_page(page); \
+ } while (0)
+#define copy_user_page(to, from, vaddr, page) \
+ do { copy_page(to, from); \
+ flush_dcache_page(page); \
+ } while (0)
/*
* These are used to make use of C type-checking..
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
* - flush_cache_page(mm, vmaddr) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
- * - flush_page_to_ram(page) write back kernel page to ram
* - flush_icache_range(start, end) flush a range of instructions
*/
extern void (*_flush_cache_all)(void);
extern void (*_flush_icache_page)(struct vm_area_struct *vma,
struct page *page);
-#define flush_dcache_page(page) do { } while (0)
-
#define flush_cache_all() _flush_cache_all()
#define __flush_cache_all() ___flush_cache_all()
#define flush_cache_mm(mm) _flush_cache_mm(mm)
#define flush_cache_range(vma,start,end) _flush_cache_range(vma,start,end)
#define flush_cache_page(vma,page) _flush_cache_page(vma, page)
#define flush_cache_sigtramp(addr) _flush_cache_sigtramp(addr)
-#define flush_page_to_ram(page) _flush_page_to_ram(page)
+#define flush_dcache_page(page) _flush_page_to_ram(page)
#define flush_icache_range(start, end) _flush_icache_range(start,end)
#define flush_icache_page(vma, page) _flush_icache_page(vma, page)
#define clear_page(page) _clear_page(page)
#define copy_page(to, from) _copy_page(to, from)
-#define clear_user_page(page, vaddr) clear_page(page)
-#define copy_user_page(to, from, vaddr) copy_page(to, from)
+
+#define clear_user_page(addr, vaddr, page) \
+ do { clear_page(addr); \
+ flush_dcache_page(page); \
+ } while (0)
+#define copy_user_page(to, from, vaddr, page) \
+ do { copy_page(to, from); \
+ flush_dcache_page(page); \
+ } while (0)
/*
* These are used to make use of C type-checking..
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
* - flush_cache_page(mm, vmaddr) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
- * - flush_page_to_ram(page) write back kernel page to ram
*/
extern void (*_flush_cache_mm)(struct mm_struct *mm);
extern void (*_flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
extern void (*_flush_page_to_ram)(struct page * page);
#define flush_cache_all() do { } while(0)
-#define flush_dcache_page(page) do { } while (0)
#ifndef CONFIG_CPU_R10000
#define flush_cache_mm(mm) _flush_cache_mm(mm)
#define flush_cache_range(vma,start,end) _flush_cache_range(vma,start,end)
#define flush_cache_page(vma,page) _flush_cache_page(vma, page)
-#define flush_page_to_ram(page) _flush_page_to_ram(page)
-
+#define flush_dcache_page(page) _flush_page_to_ram(page)
#define flush_icache_range(start, end) _flush_cache_l1()
#define flush_icache_user_range(vma, page, addr, len) \
flush_icache_page((vma), (page))
#define flush_cache_mm(mm) do { } while(0)
#define flush_cache_range(vma,start,end) do { } while(0)
#define flush_cache_page(vma,page) do { } while(0)
-#define flush_page_to_ram(page) do { } while(0)
+#define flush_dcache_page(page) do { } while(0)
#define flush_icache_range(start, end) _flush_cache_l1()
#define flush_icache_user_range(vma, page, addr, len) \
flush_icache_page((vma), (page))
#define flush_kernel_dcache_range(start,size) \
flush_kernel_dcache_range_asm((start), (start)+(size));
-static inline void
-flush_page_to_ram(struct page *page)
-{
-}
-
extern void flush_cache_all_local(void);
static inline void cacheflush_h_tmp_function(void *dummy)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, a, b) do { } while (0)
#define flush_cache_page(vma, p) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_icache_page(vma, page) do { } while (0)
extern void flush_dcache_page(struct page *page);
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_icache_page(vma, page) do { } while (0)
extern void flush_dcache_page(struct page *page);
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
* - flush_cache_range(vma, start, end) flushes a range of pages
*
* - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
- * - flush_page_to_ram(page) write back kernel page to ram
* - flush_icache_range(start, end) flushes(invalidates) a range for icache
* - flush_icache_page(vma, pg) flushes(invalidates) a page for icache
*
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
extern void flush_icache_range(unsigned long start, unsigned long end);
extern void flush_cache_sigtramp(unsigned long addr);
-#define flush_page_to_ram(page) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
extern void sparc_flush_page_to_ram(struct page *page);
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) sparc_flush_page_to_ram(page)
#endif /* _SPARC_CACHEFLUSH_H */
extern void flush_dcache_page(struct page *page);
-/* This is unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_page_to_ram(page) do { } while (0)
-
#endif /* _SPARC64_CACHEFLUSH_H */
#define flush_cache_mm(mm) ((void)0)
#define flush_cache_range(vma, start, end) ((void)0)
#define flush_cache_page(vma, vmaddr) ((void)0)
-#define flush_page_to_ram(page) ((void)0)
#define flush_dcache_page(page) ((void)0)
#define flush_icache() ((void)0)
#define flush_icache_range(start, end) ((void)0)
unsigned long adr, int len);
extern void nb85e_cache_flush_sigtramp (unsigned long addr);
-#define flush_page_to_ram(x) ((void)0)
#define flush_cache_all nb85e_cache_flush_all
#define flush_cache_mm nb85e_cache_flush_mm
#define flush_cache_range nb85e_cache_flush_range
#define clear_page(page) memset ((void *)(page), 0, PAGE_SIZE)
#define copy_page(to, from) memcpy ((void *)(to), (void *)from, PAGE_SIZE)
-#define clear_user_page(page, vaddr, pg) clear_page (page)
-#define copy_user_page(to, from, vaddr,pg) copy_page (to, from)
+#define clear_user_page(addr, vaddr, page) \
+ do { clear_page(addr); \
+ flush_dcache_page(page); \
+ } while (0)
+#define copy_user_page(to, from, vaddr, page) \
+ do { copy_page(to, from); \
+ flush_dcache_page(page); \
+ } while (0)
#ifdef STRICT_MM_TYPECHECKS
/*
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
kaddr = kmap_atomic(page, KM_USER0);
memset((char *)kaddr + offset, 0, size);
flush_dcache_page(page);
- flush_page_to_ram(page);
kunmap_atomic(kaddr, KM_USER0);
}
flush_cache_page(vma, addr);
+ /*
+ * FIXME! We used to have flush_page_to_ram() in here, but
+ * that was wrong. davem says we need a new per-arch primitive
+ * to handle this correctly.
+ */
+
maddr = kmap(page);
if (write) {
memcpy(maddr + offset, buf, bytes);
- flush_page_to_ram(page);
flush_icache_user_range(vma, page, addr, bytes);
} else {
memcpy(buf, maddr + offset, bytes);
- flush_page_to_ram(page);
}
kunmap(page);
page_cache_release(page);
success:
/*
- * Found the page and have a reference on it, need to check sharing
- * and possibly copy it over to another page..
+ * Found the page and have a reference on it.
*/
mark_page_accessed(page);
- flush_page_to_ram(page);
return page;
no_cached_page:
success:
/*
- * Found the page and have a reference on it, need to check sharing
- * and possibly copy it over to another page..
+ * Found the page and have a reference on it.
*/
mark_page_accessed(page);
- flush_page_to_ram(page);
-
return page;
no_cached_page:
flush = zap_pte(mm, vma, addr, pte);
mm->rss++;
- flush_page_to_ram(page);
flush_icache_page(vma, page);
set_pte(pte, mk_pte(page, prot));
pte_chain = page_add_rmap(page, pte, pte_chain);
pte_t *page_table)
{
invalidate_vcache(address, vma->vm_mm, new_page);
- flush_page_to_ram(new_page);
flush_cache_page(vma, address);
establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
}
pte = pte_mkdirty(pte_mkwrite(pte));
unlock_page(page);
- flush_page_to_ram(page);
flush_icache_page(vma, page);
set_pte(page_table, pte);
pte_chain = page_add_rmap(page, page_table, pte_chain);
goto out;
}
mm->rss++;
- flush_page_to_ram(page);
entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
lru_cache_add_active(page);
mark_page_accessed(page);
/* Only go through if we didn't race with anybody else... */
if (pte_none(*page_table)) {
++mm->rss;
- flush_page_to_ram(new_page);
flush_icache_page(vma, new_page);
entry = mk_pte(new_page, vma->vm_page_prot);
if (write_access)
shmem_swp_unmap(entry);
delete_from_swap_cache(swappage);
spin_unlock(&info->lock);
- flush_page_to_ram(swappage);
copy_highpage(filepage, swappage);
unlock_page(swappage);
page_cache_release(swappage);
return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS;
mark_page_accessed(page);
- flush_page_to_ram(page);
return page;
}
return err;
if (page) {
mark_page_accessed(page);
- flush_page_to_ram(page);
err = install_page(mm, vma, addr, page, prot);
if (err) {
page_cache_release(page);
shmem = 0;
swcount = *swap_map;
if (swcount > 1) {
- flush_page_to_ram(page);
if (start_mm == &init_mm)
shmem = shmem_unuse(entry, page);
else