]> err.no Git - linux-2.6/blobdiff - arch/powerpc/mm/hash_utils_64.c
[POWERPC] Add ability to 4K kernel to hash in 64K pages
[linux-2.6] / arch / powerpc / mm / hash_utils_64.c
index 5610ffb142110afda95b4b81fc2967aa633be04e..028ba4ed03d2c88f5c413b96c83fe60e00161f58 100644 (file)
@@ -420,7 +420,7 @@ static void __init htab_finish_init(void)
        extern unsigned int *htab_call_hpte_remove;
        extern unsigned int *htab_call_hpte_updatepp;
 
-#ifdef CONFIG_PPC_64K_PAGES
+#ifdef CONFIG_PPC_HAS_HASH_64K
        extern unsigned int *ht64_call_hpte_insert1;
        extern unsigned int *ht64_call_hpte_insert2;
        extern unsigned int *ht64_call_hpte_remove;
@@ -648,7 +648,11 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                        return 1;
                }
                vsid = get_vsid(mm->context.id, ea);
+#ifdef CONFIG_PPC_MM_SLICES
+               psize = get_slice_psize(mm, ea);
+#else
                psize = mm->context.user_psize;
+#endif
                break;
        case VMALLOC_REGION_ID:
                mm = &init_mm;
@@ -678,13 +682,21 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
 
 #ifdef CONFIG_HUGETLB_PAGE
        /* Handle hugepage regions */
-       if (HPAGE_SHIFT &&
-           unlikely(get_slice_psize(mm, ea) == mmu_huge_psize)) {
+       if (HPAGE_SHIFT && psize == mmu_huge_psize) {
                DBG_LOW(" -> huge page !\n");
                return hash_huge_page(mm, access, ea, vsid, local, trap);
        }
 #endif /* CONFIG_HUGETLB_PAGE */
 
+#ifndef CONFIG_PPC_64K_PAGES
+       /* If we use 4K pages and our psize is not 4K, then we are hitting
+        * a special driver mapping, we need to align the address before
+        * we fetch the PTE
+        */
+       if (psize != MMU_PAGE_4K)
+               ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
+#endif /* CONFIG_PPC_64K_PAGES */
+
        /* Get PTE and page size from page tables */
        ptep = find_linux_pte(pgdir, ea);
        if (ptep == NULL || !pte_present(*ptep)) {
@@ -707,9 +719,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        }
 
        /* Do actual hashing */
-#ifndef CONFIG_PPC_64K_PAGES
-       rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
+#ifdef CONFIG_PPC_64K_PAGES
        /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
        if (pte_val(*ptep) & _PAGE_4K_PFN) {
                demote_segment_4k(mm, ea);
@@ -751,12 +761,14 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                        mmu_psize_defs[mmu_vmalloc_psize].sllp;
                slb_flush_and_rebolt();
        }
+#endif /* CONFIG_PPC_64K_PAGES */
 
+#ifdef CONFIG_PPC_HAS_HASH_64K
        if (psize == MMU_PAGE_64K)
                rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
        else
+#endif /* CONFIG_PPC_HAS_HASH_64K */
                rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#endif /* CONFIG_PPC_64K_PAGES */
 
 #ifndef CONFIG_PPC_64K_PAGES
        DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
@@ -812,19 +824,22 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
        /* Get VSID */
        vsid = get_vsid(mm->context.id, ea);
 
-       /* Hash it in */
+       /* Hash doesn't like irqs */
        local_irq_save(flags);
+
+       /* Is that local to this CPU ? */
        mask = cpumask_of_cpu(smp_processor_id());
        if (cpus_equal(mm->cpu_vm_mask, mask))
                local = 1;
-#ifndef CONFIG_PPC_64K_PAGES
-       __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
+
+       /* Hash it in */
+#ifdef CONFIG_PPC_HAS_HASH_64K
        if (mm->context.user_psize == MMU_PAGE_64K)
                __hash_page_64K(ea, access, vsid, ptep, trap, local);
        else
-               __hash_page_4K(ea, access, vsid, ptep, trap, local);
 #endif /* CONFIG_PPC_64K_PAGES */
+               __hash_page_4K(ea, access, vsid, ptep, trap, local);
+
        local_irq_restore(flags);
 }