powerpc/mm/hash64: Factor out hash preload psize check
[pandora-kernel.git] / arch / powerpc / mm / hash_utils_64.c
index 58a022d..86ca75a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/sysctl.h>
+#include <linux/export.h>
 #include <linux/ctype.h>
 #include <linux/cache.h>
 #include <linux/init.h>
@@ -53,6 +54,7 @@
 #include <asm/sections.h>
 #include <asm/spu.h>
 #include <asm/udbg.h>
+#include <asm/code-patching.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -104,9 +106,6 @@ int mmu_kernel_ssize = MMU_SEGSIZE_256M;
 int mmu_highuser_ssize = MMU_SEGSIZE_256M;
 u16 mmu_slb_size = 64;
 EXPORT_SYMBOL_GPL(mmu_slb_size);
-#ifdef CONFIG_HUGETLB_PAGE
-unsigned int HPAGE_SHIFT;
-#endif
 #ifdef CONFIG_PPC_64K_PAGES
 int mmu_ci_restrictions;
 #endif
@@ -258,11 +257,11 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node,
        for (; size >= 4; size -= 4, ++prop) {
                if (prop[0] == 40) {
                        DBG("1T segment support detected\n");
-                       cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT;
+                       cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT;
                        return 1;
                }
        }
-       cur_cpu_spec->cpu_features &= ~CPU_FTR_NO_SLBIE_B;
+       cur_cpu_spec->mmu_features &= ~MMU_FTR_NO_SLBIE_B;
        return 0;
 }
 
@@ -288,7 +287,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
        if (prop != NULL) {
                DBG("Page sizes from device-tree:\n");
                size /= 4;
-               cur_cpu_spec->cpu_features &= ~(CPU_FTR_16M_PAGE);
+               cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE);
                while(size > 0) {
                        unsigned int shift = prop[0];
                        unsigned int slbenc = prop[1];
@@ -316,7 +315,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
                                break;
                        case 0x18:
                                idx = MMU_PAGE_16M;
-                               cur_cpu_spec->cpu_features |= CPU_FTR_16M_PAGE;
+                               cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE;
                                break;
                        case 0x22:
                                idx = MMU_PAGE_16G;
@@ -411,7 +410,7 @@ static void __init htab_init_page_sizes(void)
         * Not in the device-tree, let's fallback on known size
         * list for 16M capable GP & GR
         */
-       if (cpu_has_feature(CPU_FTR_16M_PAGE))
+       if (mmu_has_feature(MMU_FTR_16M_PAGE))
                memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
                       sizeof(mmu_psize_defaults_gp));
  found:
@@ -441,7 +440,7 @@ static void __init htab_init_page_sizes(void)
                mmu_vmalloc_psize = MMU_PAGE_64K;
                if (mmu_linear_psize == MMU_PAGE_4K)
                        mmu_linear_psize = MMU_PAGE_64K;
-               if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) {
+               if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) {
                        /*
                         * Don't use 64k pages for ioremap on pSeries, since
                         * that would stop us accessing the HEA ethernet.
@@ -533,11 +532,11 @@ static unsigned long __init htab_get_table_size(void)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-void create_section_mapping(unsigned long start, unsigned long end)
+int create_section_mapping(unsigned long start, unsigned long end)
 {
-       BUG_ON(htab_bolt_mapping(start, end, __pa(start),
+       return htab_bolt_mapping(start, end, __pa(start),
                                 pgprot_val(PAGE_KERNEL), mmu_linear_psize,
-                                mmu_kernel_ssize));
+                                mmu_kernel_ssize);
 }
 
 int remove_section_mapping(unsigned long start, unsigned long end)
@@ -547,15 +546,7 @@ int remove_section_mapping(unsigned long start, unsigned long end)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
-static inline void make_bl(unsigned int *insn_addr, void *func)
-{
-       unsigned long funcp = *((unsigned long *)func);
-       int offset = funcp - (unsigned long)insn_addr;
-
-       *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc));
-       flush_icache_range((unsigned long)insn_addr, 4+
-                          (unsigned long)insn_addr);
-}
+#define FUNCTION_TEXT(A)       ((*(unsigned long *)(A)))
 
 static void __init htab_finish_init(void)
 {
@@ -570,16 +561,33 @@ static void __init htab_finish_init(void)
        extern unsigned int *ht64_call_hpte_remove;
        extern unsigned int *ht64_call_hpte_updatepp;
 
-       make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert);
-       make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert);
-       make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove);
-       make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp);
+       patch_branch(ht64_call_hpte_insert1,
+               FUNCTION_TEXT(ppc_md.hpte_insert),
+               BRANCH_SET_LINK);
+       patch_branch(ht64_call_hpte_insert2,
+               FUNCTION_TEXT(ppc_md.hpte_insert),
+               BRANCH_SET_LINK);
+       patch_branch(ht64_call_hpte_remove,
+               FUNCTION_TEXT(ppc_md.hpte_remove),
+               BRANCH_SET_LINK);
+       patch_branch(ht64_call_hpte_updatepp,
+               FUNCTION_TEXT(ppc_md.hpte_updatepp),
+               BRANCH_SET_LINK);
+
 #endif /* CONFIG_PPC_HAS_HASH_64K */
 
-       make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert);
-       make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert);
-       make_bl(htab_call_hpte_remove, ppc_md.hpte_remove);
-       make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp);
+       patch_branch(htab_call_hpte_insert1,
+               FUNCTION_TEXT(ppc_md.hpte_insert),
+               BRANCH_SET_LINK);
+       patch_branch(htab_call_hpte_insert2,
+               FUNCTION_TEXT(ppc_md.hpte_insert),
+               BRANCH_SET_LINK);
+       patch_branch(htab_call_hpte_remove,
+               FUNCTION_TEXT(ppc_md.hpte_remove),
+               BRANCH_SET_LINK);
+       patch_branch(htab_call_hpte_updatepp,
+               FUNCTION_TEXT(ppc_md.hpte_updatepp),
+               BRANCH_SET_LINK);
 }
 
 static void __init htab_initialize(void)
@@ -598,7 +606,7 @@ static void __init htab_initialize(void)
        /* Initialize page sizes */
        htab_init_page_sizes();
 
-       if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) {
+       if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) {
                mmu_kernel_ssize = MMU_SEGSIZE_1T;
                mmu_highuser_ssize = MMU_SEGSIZE_1T;
                printk(KERN_INFO "Using 1TB segments\n");
@@ -739,7 +747,7 @@ void __init early_init_mmu(void)
 
        /* Initialize stab / SLB management except on iSeries
         */
-       if (cpu_has_feature(CPU_FTR_SLB))
+       if (mmu_has_feature(MMU_FTR_SLB))
                slb_initialize();
        else if (!firmware_has_feature(FW_FEATURE_ISERIES))
                stab_initialize(get_paca()->stab_real);
@@ -756,7 +764,7 @@ void __cpuinit early_init_mmu_secondary(void)
         * in real mode on pSeries and we want a virtual address on
         * iSeries anyway
         */
-       if (cpu_has_feature(CPU_FTR_SLB))
+       if (mmu_has_feature(MMU_FTR_SLB))
                slb_initialize();
        else
                stab_initialize(get_paca()->stab_addr);
@@ -1066,6 +1074,22 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
 }
 EXPORT_SYMBOL_GPL(hash_page);
 
+#ifdef CONFIG_PPC_MM_SLICES
+static bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
+{
+       /* We only prefault standard pages for now */
+       if (unlikely(get_slice_psize(mm, ea) != mm->context.user_psize))
+               return false;
+
+       return true;
+}
+#else
+static bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
+{
+       return true;
+}
+#endif
+
 void hash_preload(struct mm_struct *mm, unsigned long ea,
                  unsigned long access, unsigned long trap)
 {
@@ -1077,11 +1101,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
 
        BUG_ON(REGION_ID(ea) != USER_REGION_ID);
 
-#ifdef CONFIG_PPC_MM_SLICES
-       /* We only prefault standard pages for now */
-       if (unlikely(get_slice_psize(mm, ea) != mm->context.user_psize))
+       if (!should_hash_preload(mm, ea))
                return;
-#endif
 
        DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
                " trap=%lx\n", mm, mm->pgd, ea, access, trap);