MIPS HIGHMEM fixes for cache aliasing and non-DMA I/O.
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Tue, 18 Nov 2014 01:05:09 +0000 (17:05 -0800)
committerLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Tue, 18 Nov 2014 01:05:09 +0000 (17:05 -0800)
This patch fixes MIPS HIGHMEM for cache aliasing and non-DMA device
I/O. It does the following:

1.  Uses only colored page addresses while allocating by kmap*(),
    page address in HIGHMEM zone matches a kernel address by color.
    It allows easy re-allocation before flushing cache.
    It does it for kmap() and kmap_atomic().

2.  Fixes instruction cache flush by right color address via
    kmap_coherent() in case of I-cache aliasing.

3.  Flushes D-cache before page is provided for process as I-page.
    It is required for swapped-in pages in case of non-DMA I/O.

4.  Some optimization is done... more comes.

Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
12 files changed:
arch/mips/Kconfig
arch/mips/include/asm/cacheflush.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/fixmap.h
arch/mips/include/asm/highmem.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/page.h
arch/mips/mm/c-r4k.c
arch/mips/mm/cache.c
arch/mips/mm/highmem.c
arch/mips/mm/init.c
arch/mips/mm/sc-mips.c

index 7a58ab933b206a397c56b65f6a608fc4f9a1d8eb..8e566a1905ebd3a609af2c1df56d557c78b442d0 100644 (file)
@@ -324,6 +324,7 @@ config MIPS_MALTA
        select SYS_SUPPORTS_MULTITHREADING
        select SYS_SUPPORTS_SMARTMIPS
        select SYS_SUPPORTS_ZBOOT
+       select SYS_SUPPORTS_HIGHMEM
        help
          This enables support for the MIPS Technologies Malta evaluation
          board.
@@ -2115,6 +2116,7 @@ config CPU_R4400_WORKAROUNDS
 config HIGHMEM
        bool "High Memory Support"
        depends on 32BIT && CPU_SUPPORTS_HIGHMEM && SYS_SUPPORTS_HIGHMEM
+       depends on ( !SMP || NR_CPUS = 1 || NR_CPUS = 2 || NR_CPUS = 3 || NR_CPUS = 4 || NR_CPUS = 5 || NR_CPUS = 6 || NR_CPUS = 7 || NR_CPUS = 8 )
 
 config CPU_SUPPORTS_HIGHMEM
        bool
index 69468ded282820efd9547f7aa3837562e56db016..0cf73ff8849daaedb89cd9976dd6de1822fa20a8 100644 (file)
@@ -117,7 +117,8 @@ extern void kunmap_coherent(void);
 #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
 static inline void flush_kernel_dcache_page(struct page *page)
 {
-       BUG_ON(cpu_has_dc_aliases && PageHighMem(page));
+       if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
+               __flush_dcache_page(page);
 }
 
 /*
index e5ec8fcd8afaf9d822167605a8f4aaed22e9486f..fdcb80b731f849c94d133a15588d314138faa73b 100644 (file)
 #ifndef cpu_has_vtag_icache
 #define cpu_has_vtag_icache    (cpu_data[0].icache.flags & MIPS_CACHE_VTAG)
 #endif
+#ifndef cpu_has_vtag_dcache
+#define cpu_has_vtag_dcache     (cpu_data[0].dcache.flags & MIPS_CACHE_VTAG)
+#endif
+#ifndef cpu_has_ic_aliases
+#define cpu_has_ic_aliases      (cpu_data[0].icache.flags & MIPS_CACHE_ALIASES)
+#endif
 #ifndef cpu_has_dc_aliases
 #define cpu_has_dc_aliases     (cpu_data[0].dcache.flags & MIPS_CACHE_ALIASES)
 #endif
index dfaaf493e9d4a552238372506b1a662a8e6c260e..a690f05f2e73a173773827d521d63c0958284039 100644 (file)
  * fix-mapped?
  */
 enum fixed_addresses {
+
+/* must be <= 8, last_pkmap_nr_arr[] is initialized to 8 elements,
+   keep the total L1 size <= 512KB with 4 ways */
+#ifdef  CONFIG_PAGE_SIZE_64KB
+#define FIX_N_COLOURS 2
+#endif
+#ifdef  CONFIG_PAGE_SIZE_32KB
+#define FIX_N_COLOURS 4
+#endif
+#ifndef FIX_N_COLOURS
 #define FIX_N_COLOURS 8
+#endif
+
        FIX_CMAP_BEGIN,
 #ifdef CONFIG_MIPS_MT_SMTC
        FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS * 2),
@@ -56,7 +68,7 @@ enum fixed_addresses {
 #ifdef CONFIG_HIGHMEM
        /* reserved pte's for temporary kernel mappings */
        FIX_KMAP_BEGIN = FIX_CMAP_END + 1,
-       FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+       FIX_KMAP_END = FIX_KMAP_BEGIN+(8*NR_CPUS*FIX_N_COLOURS)-1,
 #endif
        __end_of_fixed_addresses
 };
index b0dd0c84df7040dadb1f8d82f5f8b849d2c5a5a4..d0310dc032d61897625febe667af4777b5b9a6af 100644 (file)
@@ -37,11 +37,38 @@ extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
+
+/*  8 colors pages are here */
+#ifdef  CONFIG_PAGE_SIZE_4KB
+#define LAST_PKMAP 4096
+#endif
+#ifdef  CONFIG_PAGE_SIZE_8KB
+#define LAST_PKMAP 2048
+#endif
+#ifdef  CONFIG_PAGE_SIZE_16KB
+#define LAST_PKMAP 1024
+#endif
+
+/* 32KB and 64KB pages should have 4 and 2 colors to keep space under control */
+#ifndef LAST_PKMAP
 #define LAST_PKMAP 1024
+#endif
+
 #define LAST_PKMAP_MASK (LAST_PKMAP-1)
 #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
+#define ARCH_PKMAP_COLORING             1
+#define     set_pkmap_color(pg,cl)      { cl = ((unsigned long)lowmem_page_address(pg) \
+                                          >> PAGE_SHIFT) & (FIX_N_COLOURS-1); }
+#define     get_last_pkmap_nr(p,cl)     (last_pkmap_nr_arr[cl])
+#define     get_next_pkmap_nr(p,cl)     (last_pkmap_nr_arr[cl] = \
+                                           ((p + FIX_N_COLOURS) & LAST_PKMAP_MASK))
+#define     is_no_more_pkmaps(p,cl)     (p < FIX_N_COLOURS)
+#define     get_next_pkmap_counter(c,cl)    (c - FIX_N_COLOURS)
+extern unsigned int     last_pkmap_nr_arr[];
+
+
 extern void * kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
 
index 87e6207b05e4334f242cadf80b01305811edd3fd..8342d16b2066c89472b7832fb4e45ac0420b00d5 100644 (file)
 #define MIPS_CONF6_SYND                (_ULCAST_(1) << 13)
 
 #define MIPS_CONF7_WII         (_ULCAST_(1) << 31)
-
+#define MIPS_CONF7_AR          (_ULCAST_(1) << 16)
+#define MIPS_CONF7_IAR         (_ULCAST_(1) << 10)
 #define MIPS_CONF7_RPS         (_ULCAST_(1) << 2)
 
 
index f59552fae9173264ab58ffd3fbe95e080ec5db93..023f3da9f5e395142b6c3568539a2216ab9547c5 100644 (file)
@@ -70,13 +70,16 @@ static inline unsigned long pages_do_alias(unsigned long addr1,
 
 struct page;
 
+#include <asm/cpu-features.h>
+
 static inline void clear_user_page(void *addr, unsigned long vaddr,
        struct page *page)
 {
        extern void (*flush_data_cache_page)(unsigned long addr);
 
        clear_page(addr);
-       if (pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK))
+       if (cpu_has_vtag_dcache || (cpu_has_dc_aliases &&
+            pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK)))
                flush_data_cache_page((unsigned long)addr);
 }
 
index 21813beec7a56f8c17ff493ca6000324168850fe..940f938cf082a0cc1cf11f10106c827058fdf752 100644 (file)
@@ -402,8 +402,11 @@ static inline void local_r4k_flush_cache_range(void * args)
                return;
 
        r4k_blast_dcache();
-       if (exec)
+       if (exec) {
+               if (!cpu_has_ic_fills_f_dc)
+                       wmb();
                r4k_blast_icache();
+       }
 }
 
 static void r4k_flush_cache_range(struct vm_area_struct *vma,
@@ -467,6 +470,7 @@ static inline void local_r4k_flush_cache_page(void *args)
        pmd_t *pmdp;
        pte_t *ptep;
        void *vaddr;
+       int dontflash = 0;
 
        /*
         * If ownes no valid ASID yet, cannot possibly have gotten
@@ -488,6 +492,10 @@ static inline void local_r4k_flush_cache_page(void *args)
        if (!(pte_present(*ptep)))
                return;
 
+       /*  accelerate it! See below, just skipping kmap_*()/kunmap_*() */
+       if ((!exec) && !cpu_has_dc_aliases)
+               return;
+
        if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID))
                vaddr = NULL;
        else {
@@ -506,6 +514,8 @@ static inline void local_r4k_flush_cache_page(void *args)
 
        if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
                r4k_blast_dcache_page(addr);
+               if (exec && !cpu_has_ic_fills_f_dc)
+                       wmb();
                if (exec && !cpu_icache_snoops_remote_store)
                        r4k_blast_scache_page(addr);
        }
@@ -515,8 +525,10 @@ static inline void local_r4k_flush_cache_page(void *args)
 
                        if (cpu_context(cpu, mm) != 0)
                                drop_mmu_context(mm, cpu);
+                       dontflash = 1;
                } else
-                       r4k_blast_icache_page(addr);
+                       if (map_coherent || !cpu_has_ic_aliases)
+                               r4k_blast_icache_page(addr);
        }
 
        if (vaddr) {
@@ -525,6 +537,13 @@ static inline void local_r4k_flush_cache_page(void *args)
                else
                        kunmap_atomic(vaddr);
        }
+
+       /*  in case of I-cache aliasing - blast it via coherent page */
+       if (exec && cpu_has_ic_aliases && (!dontflash) && !map_coherent) {
+               vaddr = kmap_coherent(page, addr);
+               r4k_blast_icache_page((unsigned long)vaddr);
+               kunmap_coherent();
+       }
 }
 
 static void r4k_flush_cache_page(struct vm_area_struct *vma,
@@ -537,6 +556,8 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
        args.pfn = pfn;
 
        r4k_on_each_cpu(local_r4k_flush_cache_page, &args);
+       if (cpu_has_dc_aliases)
+               ClearPageDcacheDirty(pfn_to_page(pfn));
 }
 
 static inline void local_r4k_flush_data_cache_page(void * addr)
@@ -568,6 +589,8 @@ static inline void local_r4k_flush_icache_range(unsigned long start, unsigned lo
                }
        }
 
+       wmb();
+
        if (end - start > icache_size)
                r4k_blast_icache();
        else
@@ -1067,7 +1090,11 @@ static void __cpuinit probe_pcache(void)
        case CPU_1004K:
                if (c->cputype == CPU_74K)
                        alias_74k_erratum(c);
-               if ((read_c0_config7() & (1 << 16))) {
+               if (!(read_c0_config7() & MIPS_CONF7_IAR)) {
+                       if (c->icache.waysize > PAGE_SIZE)
+                               c->icache.flags |= MIPS_CACHE_ALIASES;
+               }
+               if (read_c0_config7() & MIPS_CONF7_AR) {
                        /* effectively physically indexed dcache,
                           thus no virtual aliases. */
                        c->dcache.flags |= MIPS_CACHE_PINDEX;
@@ -1078,6 +1105,14 @@ static void __cpuinit probe_pcache(void)
                        c->dcache.flags |= MIPS_CACHE_ALIASES;
        }
 
+#ifdef  CONFIG_HIGHMEM
+       if (((c->dcache.flags & MIPS_CACHE_ALIASES) &&
+            ((c->dcache.waysize / PAGE_SIZE) > FIX_N_COLOURS)) ||
+            ((c->icache.flags & MIPS_CACHE_ALIASES) &&
+            ((c->icache.waysize / PAGE_SIZE) > FIX_N_COLOURS)))
+               panic("PAGE_SIZE*WAYS too small for L1 size, too many colors");
+#endif
+
        switch (c->cputype) {
        case CPU_20KC:
                /*
@@ -1100,10 +1135,12 @@ static void __cpuinit probe_pcache(void)
        c->icache.ways = 1;
 #endif
 
-       printk("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n",
-              icache_size >> 10,
+       printk("Primary instruction cache %ldkB, %s, %s, %slinesize %d bytes.\n",
+              icache_size >> 10, way_string[c->icache.ways],
               c->icache.flags & MIPS_CACHE_VTAG ? "VIVT" : "VIPT",
-              way_string[c->icache.ways], c->icache.linesz);
+              (c->icache.flags & MIPS_CACHE_ALIASES) ?
+                       "I-cache aliases, " : "",
+              c->icache.linesz);
 
        printk("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n",
               dcache_size >> 10, way_string[c->dcache.ways],
index 5aeb3eb0b72f87b5f108a6d287517e53d038be2a..e4b1ae169c22724cef1da5e87a427ff30e43f326 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/processor.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
+#include <linux/highmem.h>
 
 /* Cache operations. */
 void (*flush_cache_all)(void);
@@ -80,12 +81,9 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
 
 void __flush_dcache_page(struct page *page)
 {
-       struct address_space *mapping = page_mapping(page);
-       unsigned long addr;
+       void *addr;
 
-       if (PageHighMem(page))
-               return;
-       if (mapping && !mapping_mapped(mapping)) {
+       if (page_mapping(page) && !page_mapped(page)) {
                SetPageDcacheDirty(page);
                return;
        }
@@ -95,25 +93,55 @@ void __flush_dcache_page(struct page *page)
         * case is for exec env/arg pages and those are %99 certainly going to
         * get faulted into the tlb (and thus flushed) anyways.
         */
-       addr = (unsigned long) page_address(page);
-       flush_data_cache_page(addr);
+       if (PageHighMem(page)) {
+               addr = kmap_atomic(page);
+               flush_data_cache_page((unsigned long)addr);
+               kunmap_atomic(addr);
+       } else {
+               addr = (void *) page_address(page);
+               flush_data_cache_page((unsigned long)addr);
+       }
+       ClearPageDcacheDirty(page);
 }
 
 EXPORT_SYMBOL(__flush_dcache_page);
 
 void __flush_anon_page(struct page *page, unsigned long vmaddr)
 {
-       unsigned long addr = (unsigned long) page_address(page);
-
-       if (pages_do_alias(addr, vmaddr)) {
-               if (page_mapped(page) && !Page_dcache_dirty(page)) {
-                       void *kaddr;
-
-                       kaddr = kmap_coherent(page, vmaddr);
-                       flush_data_cache_page((unsigned long)kaddr);
-                       kunmap_coherent();
-               } else
-                       flush_data_cache_page(addr);
+       if (!PageHighMem(page)) {
+               unsigned long addr = (unsigned long) page_address(page);
+
+               if (pages_do_alias(addr, vmaddr & PAGE_MASK)) {
+                       if (page_mapped(page) && !Page_dcache_dirty(page)) {
+                               void *kaddr;
+
+                               kaddr = kmap_coherent(page, vmaddr);
+                               flush_data_cache_page((unsigned long)kaddr);
+                               kunmap_coherent();
+                       } else {
+                               flush_data_cache_page(addr);
+                               ClearPageDcacheDirty(page);
+                       }
+               }
+       } else {
+               void *laddr = lowmem_page_address(page);
+
+               if (pages_do_alias((unsigned long)laddr, vmaddr & PAGE_MASK)) {
+                       if (page_mapped(page) && !Page_dcache_dirty(page)) {
+                               void *kaddr;
+
+                               kaddr = kmap_coherent(page, vmaddr);
+                               flush_data_cache_page((unsigned long)kaddr);
+                               kunmap_coherent();
+                       } else {
+                               void *kaddr;
+
+                               kaddr = kmap_atomic(page);
+                               flush_data_cache_page((unsigned long)kaddr);
+                               kunmap_atomic(kaddr);
+                               ClearPageDcacheDirty(page);
+                       }
+               }
        }
 }
 
@@ -127,15 +155,28 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address,
        int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
 
        pfn = pte_pfn(pte);
-       if (unlikely(!pfn_valid(pfn)))
+       if (unlikely(!pfn_valid(pfn))) {
+               wmb();
                return;
+       }
        page = pfn_to_page(pfn);
-       if (page_mapping(page) && Page_dcache_dirty(page)) {
-               addr = (unsigned long) page_address(page);
-               if (exec || pages_do_alias(addr, address & PAGE_MASK))
+       if (page_mapped(page) && Page_dcache_dirty(page)) {
+               void *kaddr = NULL;
+               if (PageHighMem(page)) {
+                       addr = (unsigned long)kmap_atomic(page);
+                       kaddr = (void *)addr;
+               } else
+                       addr = (unsigned long) page_address(page);
+               if (exec || (cpu_has_dc_aliases &&
+                   pages_do_alias(addr, address & PAGE_MASK))) {
                        flush_data_cache_page(addr);
-               ClearPageDcacheDirty(page);
+                       ClearPageDcacheDirty(page);
+               }
+
+               if (kaddr)
+                       kunmap_atomic((void *)kaddr);
        }
+       wmb();  /* finish any outstanding arch cache flushes before ret to user */
 }
 
 unsigned long _page_cachable_default;
index da815d295239baaaf6e1d1069e2255baa8d75358..10fc041454944dd0e543fe501f4f0e01434b63f1 100644 (file)
@@ -9,6 +9,7 @@
 static pte_t *kmap_pte;
 
 unsigned long highstart_pfn, highend_pfn;
+unsigned int  last_pkmap_nr_arr[FIX_N_COLOURS] = { 0, 1, 2, 3, 4, 5, 6, 7 };
 
 void *kmap(struct page *page)
 {
@@ -53,8 +54,12 @@ void *kmap_atomic(struct page *page)
                return page_address(page);
 
        type = kmap_atomic_idx_push();
-       idx = type + KM_TYPE_NR*smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+
+       idx = (((unsigned long)lowmem_page_address(page)) >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
+       idx = (FIX_N_COLOURS - idx);
+       idx = idx + FIX_N_COLOURS * (smp_processor_id() + NR_CPUS * type);
+       vaddr = __fix_to_virt(FIX_KMAP_BEGIN - 1 + idx);    /* actually - FIX_CMAP_END */
+
 #ifdef CONFIG_DEBUG_HIGHMEM
        BUG_ON(!pte_none(*(kmap_pte - idx)));
 #endif
@@ -75,12 +80,16 @@ void __kunmap_atomic(void *kvaddr)
                return;
        }
 
-       type = kmap_atomic_idx();
 #ifdef CONFIG_DEBUG_HIGHMEM
        {
-               int idx = type + KM_TYPE_NR * smp_processor_id();
+               int idx;
+               type = kmap_atomic_idx();
 
-               BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+               idx = ((unsigned long)kvaddr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
+               idx = (FIX_N_COLOURS - idx);
+               idx = idx + FIX_N_COLOURS * (smp_processor_id() + NR_CPUS * type);
+
+               BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN -1 + idx));
 
                /*
                 * force other mappings to Oops if they'll try to access
@@ -95,26 +104,6 @@ void __kunmap_atomic(void *kvaddr)
 }
 EXPORT_SYMBOL(__kunmap_atomic);
 
-/*
- * This is the same as kmap_atomic() but can map memory that doesn't
- * have a struct page associated with it.
- */
-void *kmap_atomic_pfn(unsigned long pfn)
-{
-       unsigned long vaddr;
-       int idx, type;
-
-       pagefault_disable();
-
-       type = kmap_atomic_idx_push();
-       idx = type + KM_TYPE_NR*smp_processor_id();
-       vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-       set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
-       flush_tlb_one(vaddr);
-
-       return (void*) vaddr;
-}
-
 struct page *kmap_atomic_to_page(void *ptr)
 {
        unsigned long idx, vaddr = (unsigned long)ptr;
@@ -124,7 +113,7 @@ struct page *kmap_atomic_to_page(void *ptr)
                return virt_to_page(ptr);
 
        idx = virt_to_fix(vaddr);
-       pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+       pte = kmap_pte - (idx - FIX_KMAP_BEGIN + 1);
        return pte_page(*pte);
 }
 
@@ -133,6 +122,6 @@ void __init kmap_init(void)
        unsigned long kmap_vstart;
 
        /* cache the first kmap pte */
-       kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+       kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN - 1); /* actually - FIX_CMAP_END */
        kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
 }
index 9b973e0af9cbbd2ba7c164fcfea8d9ac93265d36..b57022bde9ae79be32e8e4d5733bf5f21d31bacc 100644 (file)
@@ -122,7 +122,7 @@ void *kmap_coherent(struct page *page, unsigned long addr)
        pte_t pte;
        int tlbidx;
 
-       BUG_ON(Page_dcache_dirty(page));
+       /* BUG_ON(Page_dcache_dirty(page)); - removed for I-cache flush */
 
        inc_preempt_count();
        idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
@@ -213,9 +213,15 @@ void copy_user_highpage(struct page *to, struct page *from,
                copy_page(vto, vfrom);
                kunmap_atomic(vfrom);
        }
-       if ((!cpu_has_ic_fills_f_dc) ||
-           pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
+       if (cpu_has_dc_aliases)
+               SetPageDcacheDirty(to);
+       if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+           cpu_has_vtag_dcache || (cpu_has_dc_aliases &&
+            pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))) {
                flush_data_cache_page((unsigned long)vto);
+               if (cpu_has_dc_aliases)
+                       ClearPageDcacheDirty(to);
+       }
        kunmap_atomic(vto);
        /* Make sure this page is cleared on other CPU's too before using it */
        smp_wmb();
@@ -235,8 +241,14 @@ void copy_to_user_page(struct vm_area_struct *vma,
                if (cpu_has_dc_aliases)
                        SetPageDcacheDirty(page);
        }
-       if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc)
+       if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+           (Page_dcache_dirty(page) &&
+            pages_do_alias((unsigned long)dst & PAGE_MASK,
+                           vaddr & PAGE_MASK))) {
                flush_cache_page(vma, vaddr, page_to_pfn(page));
+               if (cpu_has_dc_aliases)
+                       ClearPageDcacheDirty(page);
+       }
 }
 
 void copy_from_user_page(struct vm_area_struct *vma,
@@ -248,11 +260,8 @@ void copy_from_user_page(struct vm_area_struct *vma,
                void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
                memcpy(dst, vfrom, len);
                kunmap_coherent();
-       } else {
+       } else
                memcpy(dst, src, len);
-               if (cpu_has_dc_aliases)
-                       SetPageDcacheDirty(page);
-       }
 }
 
 void __init fixrange_init(unsigned long start, unsigned long end,
@@ -322,7 +331,7 @@ int page_is_ram(unsigned long pagenr)
 void __init paging_init(void)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES];
-       unsigned long lastpfn __maybe_unused;
+       unsigned long lastpfn;
 
        pagetable_init();
 
@@ -342,14 +351,6 @@ void __init paging_init(void)
 #ifdef CONFIG_HIGHMEM
        max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
        lastpfn = highend_pfn;
-
-       if (cpu_has_dc_aliases && max_low_pfn != highend_pfn) {
-               printk(KERN_WARNING "This processor doesn't support highmem."
-                      " %ldk highmem ignored\n",
-                      (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
-               max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
-               lastpfn = max_low_pfn;
-       }
 #endif
 
        free_area_init_nodes(max_zone_pfns);
index df96da7e939b540f9b1b9c73dae3f73162845d8e..3ede85fac088c747bdbd9a89c0907b22f3413e03 100644 (file)
@@ -23,6 +23,7 @@
  */
 static void mips_sc_wback_inv(unsigned long addr, unsigned long size)
 {
+       __sync();
        blast_scache_range(addr, addr + size);
 }