]> Pileus Git - ~andy/linux/blobdiff - arch/arc/mm/tlb.c
ARC: [mm] Lazy D-cache flush (non aliasing VIPT)
[~andy/linux] / arch / arc / mm / tlb.c
index 232a0ff80a5e2b7676592d3e7cf8b1ec832e157c..003d69ac6ffa63935a7bedf1089b61e238ff7a12 100644 (file)
@@ -418,23 +418,37 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
        local_irq_restore(flags);
 }
 
-/* arch hook called by core VM at the end of handle_mm_fault( ),
- * when a new PTE is entered in Page Tables or an existing one
- * is modified. We aggresively pre-install a TLB entry
+/*
+ * Called at the end of pagefault, for a userspace mapped page
+ *  -pre-install the corresponding TLB entry into MMU
+ *  -Finalize the delayed D-cache flush (wback+inv kernel mapping)
  */
-
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddress,
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
                      pte_t *ptep)
 {
+       unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
+
+       create_tlb(vma, vaddr, ptep);
 
-       create_tlb(vma, vaddress, ptep);
+       /* icache doesn't snoop dcache, thus needs to be made coherent here */
+       if (vma->vm_flags & VM_EXEC) {
+               struct page *page = pfn_to_page(pte_pfn(*ptep));
+
+               /* if page was dcache dirty, flush now */
+               int dirty = test_and_clear_bit(PG_arch_1, &page->flags);
+               if (dirty) {
+                       unsigned long paddr =  pte_val(*ptep) & PAGE_MASK;
+                       __flush_dcache_page(paddr);
+                       __inv_icache_page(paddr, vaddr);
+               }
+       }
 }
 
 /* Read the Cache Build Confuration Registers, Decode them and save into
  * the cpuinfo structure for later use.
  * No Validation is done here, simply read/convert the BCRs
  */
-void __init read_decode_mmu_bcr(void)
+void __cpuinit read_decode_mmu_bcr(void)
 {
        unsigned int tmp;
        struct bcr_mmu_1_2 *mmu2;       /* encoded MMU2 attr */
@@ -463,8 +477,46 @@ void __init read_decode_mmu_bcr(void)
        mmu->num_tlb = mmu->sets * mmu->ways;
 }
 
-void __init arc_mmu_init(void)
+char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len)
 {
+       int n = 0;
+       struct cpuinfo_arc_mmu *p_mmu = &cpuinfo_arc700[cpu_id].mmu;
+
+       n += scnprintf(buf + n, len - n, "ARC700 MMU [v%x]\t: %dk PAGE, ",
+                      p_mmu->ver, TO_KB(p_mmu->pg_sz));
+
+       n += scnprintf(buf + n, len - n,
+                      "J-TLB %d (%dx%d), uDTLB %d, uITLB %d, %s\n",
+                      p_mmu->num_tlb, p_mmu->sets, p_mmu->ways,
+                      p_mmu->u_dtlb, p_mmu->u_itlb,
+                      __CONFIG_ARC_MMU_SASID_VAL ? "SASID" : "");
+
+       return buf;
+}
+
+void __cpuinit arc_mmu_init(void)
+{
+       char str[256];
+       struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
+
+       printk(arc_mmu_mumbojumbo(0, str, sizeof(str)));
+
+       /* For efficiency sake, kernel is compile time built for a MMU ver
+        * This must match the hardware it is running on.
+        * Linux built for MMU V2, if run on MMU V1 will break down because V1
+        *  hardware doesn't understand cmds such as WriteNI, or IVUTLB
+        * On the other hand, Linux built for V1 if run on MMU V2 will do
+        *   un-needed workarounds to prevent memcpy thrashing.
+        * Similarly MMU V3 has new features which won't work on older MMU
+        */
+       if (mmu->ver != CONFIG_ARC_MMU_VER) {
+               panic("MMU ver %d doesn't match kernel built for %d...\n",
+                     mmu->ver, CONFIG_ARC_MMU_VER);
+       }
+
+       if (mmu->pg_sz != PAGE_SIZE)
+               panic("MMU pg size != PAGE_SIZE (%luk)\n", TO_KB(PAGE_SIZE));
+
        /*
         * ASID mgmt data structures are compile time init
         *  asid_cache = FIRST_ASID and asid_mm_map[] all zeroes
@@ -474,6 +526,12 @@ void __init arc_mmu_init(void)
 
        /* Enable the MMU */
        write_aux_reg(ARC_REG_PID, MMU_ENABLE);
+
+       /* In smp we use this reg for interrupt 1 scratch */
+#ifndef CONFIG_SMP
+       /* swapper_pg_dir is the pgd for the kernel, used by vmalloc */
+       write_aux_reg(ARC_REG_SCRATCH_DATA0, swapper_pg_dir);
+#endif
 }
 
 /*