summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2003-01-14 16:19:13 +1100
committerAnton Blanchard <anton@samba.org>2003-01-14 16:19:13 +1100
commit45d3cf3ef7ef0e681942018513358b1fe74a27e9 (patch)
tree903b3a85988d399c471e5da4b87190db28355e2f
parentbcd998aad6496759d239eaba760a6ca6d1a73e2c (diff)
parent75b368dc7acc3a5ce664d57c3da4b531af3c6563 (diff)
Merge samba.org:/scratch/anton/linux-2.5
into samba.org:/scratch/anton/sfr
-rw-r--r--arch/ppc64/mm/init.c64
-rw-r--r--include/asm-ppc64/cacheflush.h2
2 files changed, 35 insertions, 31 deletions
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
index 988b1f9f55dc..7c2bf5117d64 100644
--- a/arch/ppc64/mm/init.c
+++ b/arch/ppc64/mm/init.c
@@ -592,36 +592,24 @@ void __init mem_init(void)
*/
void flush_dcache_page(struct page *page)
{
+ /* avoid an atomic op if possible */
if (test_bit(PG_arch_1, &page->flags))
clear_bit(PG_arch_1, &page->flags);
}
-void flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
- if (cpu_has_noexecute())
- return;
-
- if ((vma->vm_flags & VM_EXEC) == 0)
- return;
-
- if (page->mapping && !PageReserved(page)
- && !test_bit(PG_arch_1, &page->flags)) {
- __flush_dcache_icache(page_address(page));
- set_bit(PG_arch_1, &page->flags);
- }
-}
-
void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
{
clear_page(page);
- /* XXX we shouldnt have to do this, but glibc requires it */
- if (cpu_has_noexecute()) {
- if (test_bit(PG_arch_1, &pg->flags))
- clear_bit(PG_arch_1, &pg->flags);
- } else {
- __flush_dcache_icache(page);
- }
+ /*
+ * We shouldnt have to do this, but some versions of glibc
+ * require it (ld.so assumes zero filled pages are icache clean)
+ * - Anton
+ */
+
+ /* avoid an atomic op if possible */
+ if (test_bit(PG_arch_1, &pg->flags))
+ clear_bit(PG_arch_1, &pg->flags);
}
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
@@ -630,20 +618,23 @@ void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
copy_page(vto, vfrom);
/*
- * Unfortunately we havent always marked our GOT and PLT sections
- * as executable, so we need to flush all file regions - Anton
+ * We should be able to use the following optimisation, however
+ * there are two problems.
+ * Firstly a bug in some versions of binutils meant PLT sections
+ * were not marked executable.
+ * Secondly the first word in the GOT section is blrl, used
+ * to establish the GOT address. Until recently the GOT was
+ * not marked executable.
+ * - Anton
*/
#if 0
if (!vma->vm_file && ((vma->vm_flags & VM_EXEC) == 0))
return;
#endif
- if (cpu_has_noexecute()) {
- if (test_bit(PG_arch_1, &pg->flags))
- clear_bit(PG_arch_1, &pg->flags);
- } else {
- __flush_dcache_icache(vto);
- }
+ /* avoid an atomic op if possible */
+ if (test_bit(PG_arch_1, &pg->flags))
+ clear_bit(PG_arch_1, &pg->flags);
}
void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
@@ -675,6 +666,19 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea,
pte_t *ptep;
int local = 0;
+ /* handle i-cache coherency */
+ if (!cpu_has_noexecute()) {
+ unsigned long pfn = pte_pfn(pte);
+ if (pfn_valid(pfn)) {
+ struct page *page = pfn_to_page(pfn);
+ if (!PageReserved(page)
+ && !test_bit(PG_arch_1, &page->flags)) {
+ __flush_dcache_icache(page_address(page));
+ set_bit(PG_arch_1, &page->flags);
+ }
+ }
+ }
+
/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
if (!pte_young(pte))
return;
diff --git a/include/asm-ppc64/cacheflush.h b/include/asm-ppc64/cacheflush.h
index 75d939cd219c..9a54101c4546 100644
--- a/include/asm-ppc64/cacheflush.h
+++ b/include/asm-ppc64/cacheflush.h
@@ -14,10 +14,10 @@
#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);
extern void flush_icache_range(unsigned long, unsigned long);
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr,
int len);