[SPARC64]: Create a seperate kernel TSB for 4MB/256MB mappings.
[pandora-kernel.git] / arch / sparc64 / mm / init.c
index 0137d3d..2a12313 100644 (file)
 
 extern void device_scan(void);
 
+#define MAX_PHYS_ADDRESS       (1UL << 42UL)
+#define KPTE_BITMAP_CHUNK_SZ   (256UL * 1024UL * 1024UL)
+#define KPTE_BITMAP_BYTES      \
+       ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+
+unsigned long kern_linear_pte_xor[2] __read_mostly;
+
+/* A bitmap, one bit for every 256MB of physical memory.  If the bit
+ * is clear, we should use a 4MB page (via kern_linear_pte_xor[0]) else
+ * if set we should use a 256MB page (via kern_linear_pte_xor[1]).
+ */
+unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+
+/* A special kernel TSB for 4MB and 256MB linear mappings.  */
+struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
+
 #define MAX_BANKS      32
 
 static struct linux_prom64_registers pavail[MAX_BANKS] __initdata;
@@ -119,7 +135,6 @@ unsigned long phys_base __read_mostly;
 unsigned long kern_base __read_mostly;
 unsigned long kern_size __read_mostly;
 unsigned long pfn_base __read_mostly;
-unsigned long kern_linear_pte_xor __read_mostly;
 
 /* get_new_mmu_context() uses "cache + 1".  */
 DEFINE_SPINLOCK(ctx_alloc_lock);
@@ -296,7 +311,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t p
 
                tsb = &mm->context.tsb[(address >> PAGE_SHIFT) &
                                       (mm->context.tsb_nentries - 1UL)];
-               tag = (address >> 22UL) | CTX_HWBITS(mm->context) << 48UL;
+               tag = (address >> 22UL);
                tsb_insert(tsb, tag, pte_val(pte));
        }
 }
@@ -510,6 +525,11 @@ static void __init hypervisor_tlb_lock(unsigned long vaddr,
                               "=&r" (arg3)
                             : "0" (func), "1" (arg0), "2" (arg1),
                               "3" (arg2), "4" (arg3));
+       if (arg0 != 0) {
+               prom_printf("hypervisor_tlb_lock[%lx:%lx:%lx:%lx]: "
+                           "errors with %lx\n", vaddr, 0, pte, mmu, arg0);
+               prom_halt();
+       }
 }
 
 static unsigned long kern_large_tte(unsigned long paddr);
@@ -873,6 +893,9 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
        return end_pfn;
 }
 
+static struct linux_prom64_registers pall[MAX_BANKS] __initdata;
+static int pall_ents __initdata;
+
 #ifdef CONFIG_DEBUG_PAGEALLOC
 static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, pgprot_t prot)
 {
@@ -928,14 +951,41 @@ static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend,
        return alloc_bytes;
 }
 
-static struct linux_prom64_registers pall[MAX_BANKS] __initdata;
-static int pall_ents __initdata;
-
 extern unsigned int kvmap_linear_patch[1];
+#endif /* CONFIG_DEBUG_PAGEALLOC */
+
+static void __init mark_kpte_bitmap(unsigned long start, unsigned long end)
+{
+       const unsigned long shift_256MB = 28;
+       const unsigned long mask_256MB = ((1UL << shift_256MB) - 1UL);
+       const unsigned long size_256MB = (1UL << shift_256MB);
+
+       while (start < end) {
+               long remains;
+
+               if (start & mask_256MB) {
+                       start = (start + size_256MB) & ~mask_256MB;
+                       continue;
+               }
+
+               remains = end - start;
+               while (remains >= size_256MB) {
+                       unsigned long index = start >> shift_256MB;
+
+                       __set_bit(index, kpte_linear_bitmap);
+
+                       start += size_256MB;
+                       remains -= size_256MB;
+               }
+       }
+}
 
 static void __init kernel_physical_mapping_init(void)
 {
-       unsigned long i, mem_alloced = 0UL;
+       unsigned long i;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       unsigned long mem_alloced = 0UL;
+#endif
 
        read_obp_memory("reg", &pall[0], &pall_ents);
 
@@ -944,10 +994,16 @@ static void __init kernel_physical_mapping_init(void)
 
                phys_start = pall[i].phys_addr;
                phys_end = phys_start + pall[i].reg_size;
+
+               mark_kpte_bitmap(phys_start, phys_end);
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
                mem_alloced += kernel_map_range(phys_start, phys_end,
                                                PAGE_KERNEL);
+#endif
        }
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
        printk("Allocated %ld bytes for kernel page tables.\n",
               mem_alloced);
 
@@ -955,8 +1011,10 @@ static void __init kernel_physical_mapping_init(void)
        flushi(&kvmap_linear_patch[0]);
 
        __flush_tlb_all();
+#endif
 }
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
 void kernel_map_pages(struct page *page, int numpages, int enable)
 {
        unsigned long phys_start = page_to_pfn(page) << PAGE_SHIFT;
@@ -1031,6 +1089,7 @@ static void __init sun4v_ktsb_init(void)
 {
        unsigned long ktsb_pa;
 
+       /* First KTSB for PAGE_SIZE mappings.  */
        ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE);
 
        switch (PAGE_SIZE) {
@@ -1056,15 +1115,24 @@ static void __init sun4v_ktsb_init(void)
                break;
        };
 
-       ktsb_descr[0].assoc = 0;
+       ktsb_descr[0].assoc = 1;
        ktsb_descr[0].num_ttes = KERNEL_TSB_NENTRIES;
        ktsb_descr[0].ctx_idx = 0;
        ktsb_descr[0].tsb_base = ktsb_pa;
        ktsb_descr[0].resv = 0;
 
-       /* XXX When we have a kernel large page size TSB, describe
-        * XXX it in ktsb_descr[1] here.
-        */
+       /* Second KTSB for 4MB/256MB mappings.  */
+       ktsb_pa = (kern_base +
+                  ((unsigned long)&swapper_4m_tsb[0] - KERNBASE));
+
+       ktsb_descr[1].pgsz_idx = HV_PGSZ_IDX_4MB;
+       ktsb_descr[1].pgsz_mask = (HV_PGSZ_MASK_4MB |
+                                  HV_PGSZ_MASK_256MB);
+       ktsb_descr[1].assoc = 1;
+       ktsb_descr[1].num_ttes = KERNEL_TSB4M_NENTRIES;
+       ktsb_descr[1].ctx_idx = 0;
+       ktsb_descr[1].tsb_base = ktsb_pa;
+       ktsb_descr[1].resv = 0;
 }
 
 void __cpuinit sun4v_ktsb_register(void)
@@ -1077,8 +1145,7 @@ void __cpuinit sun4v_ktsb_register(void)
        pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE);
 
        func = HV_FAST_MMU_TSB_CTX0;
-       /* XXX set arg0 to 2 when we use ktsb_descr[1], see above XXX */
-       arg0 = 1;
+       arg0 = 2;
        arg1 = pa;
        __asm__ __volatile__("ta        %6"
                             : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
@@ -1105,6 +1172,10 @@ void __init paging_init(void)
        kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
        kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
 
+       /* Invalidate both kernel TSBs.  */
+       memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
+       memset(swapper_4m_tsb, 0x40, sizeof(swapper_4m_tsb));
+
        if (tlb_type == hypervisor)
                sun4v_pgprot_init();
        else
@@ -1165,9 +1236,7 @@ void __init paging_init(void)
        pages_avail = 0;
        last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
        kernel_physical_mapping_init();
-#endif
 
        {
                unsigned long zones_size[MAX_NR_ZONES];
@@ -1346,6 +1415,10 @@ EXPORT_SYMBOL(PAGE_KERNEL);
 
 pgprot_t PAGE_KERNEL_LOCKED __read_mostly;
 pgprot_t PAGE_COPY __read_mostly;
+
+pgprot_t PAGE_SHARED __read_mostly;
+EXPORT_SYMBOL(PAGE_SHARED);
+
 pgprot_t PAGE_EXEC __read_mostly;
 unsigned long pg_iobits __read_mostly;
 
@@ -1360,6 +1433,7 @@ static void prot_init_common(unsigned long page_none,
                             unsigned long page_exec_bit)
 {
        PAGE_COPY = __pgprot(page_copy);
+       PAGE_SHARED = __pgprot(page_shared);
 
        protection_map[0x0] = __pgprot(page_none);
        protection_map[0x1] = __pgprot(page_readonly & ~page_exec_bit);
@@ -1401,10 +1475,13 @@ static void __init sun4u_pgprot_init(void)
        pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4U | __DIRTY_BITS_4U |
                     __ACCESS_BITS_4U | _PAGE_E_4U);
 
-       kern_linear_pte_xor = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
+       kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
                0xfffff80000000000;
-       kern_linear_pte_xor |= (_PAGE_CP_4U | _PAGE_CV_4U |
-                               _PAGE_P_4U | _PAGE_W_4U);
+       kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |
+                                  _PAGE_P_4U | _PAGE_W_4U);
+
+       /* XXX Should use 256MB on Panther. XXX */
+       kern_linear_pte_xor[1] = kern_linear_pte_xor[0];
 
        _PAGE_SZBITS = _PAGE_SZBITS_4U;
        _PAGE_ALL_SZ_BITS =  (_PAGE_SZ4MB_4U | _PAGE_SZ512K_4U |
@@ -1442,10 +1519,15 @@ static void __init sun4v_pgprot_init(void)
        _PAGE_E = _PAGE_E_4V;
        _PAGE_CACHE = _PAGE_CACHE_4V;
 
-       kern_linear_pte_xor = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
+       kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
+               0xfffff80000000000;
+       kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |
+                                  _PAGE_P_4V | _PAGE_W_4V);
+
+       kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
                0xfffff80000000000;
-       kern_linear_pte_xor |= (_PAGE_CP_4V | _PAGE_CV_4V |
-                               _PAGE_P_4V | _PAGE_W_4V);
+       kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
+                                  _PAGE_P_4V | _PAGE_W_4V);
 
        pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4V | __DIRTY_BITS_4V |
                     __ACCESS_BITS_4V | _PAGE_E_4V);