This add generic mmu_feature_enabled() function that get patched to take right code path based on the feature bit enabled. The main difference between the existing mmu_has_feature() function is the hot patching using jump label framework.
The implementation wraps around mmu_has_feature so that we can use this in early bootup code before we do the hotpatching. Signed-off-by: Aneesh Kumar K.V <aneesh.ku...@linux.vnet.ibm.com> --- arch/powerpc/include/asm/book3s/64/mmu.h | 2 +- arch/powerpc/include/asm/mmu.h | 28 ++++++++++++++++++++++++ arch/powerpc/include/asm/synch.h | 1 + arch/powerpc/kernel/module.c | 5 +++++ arch/powerpc/kernel/setup_64.c | 3 +++ arch/powerpc/kernel/vmlinux.lds.S | 7 ++++++ arch/powerpc/lib/feature-fixups.c | 37 ++++++++++++++++++++++++++++++++ 7 files changed, 82 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h index 0835a8f9904b..696b7c5cc31f 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu.h +++ b/arch/powerpc/include/asm/book3s/64/mmu.h @@ -23,7 +23,7 @@ struct mmu_psize_def { }; extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; -#define radix_enabled() mmu_has_feature(MMU_FTR_RADIX) +#define radix_enabled() mmu_feature_enabled(MMU_FTR_RADIX) #endif /* __ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 9e8c05f9c562..fdb70dc218e5 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -3,6 +3,7 @@ #ifdef __KERNEL__ #include <linux/types.h> +#include <linux/jump_label.h> #include <asm/asm-compat.h> #include <asm/feature-fixups.h> @@ -125,6 +126,7 @@ static inline void mmu_clear_feature(unsigned long feature) } extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup; +extern unsigned int __start___mmu_ftr_fixup_c, __stop___mmu_ftr_fixup_c; #ifdef CONFIG_PPC64 /* This is our real memory area size on ppc64 server, on embedded, we @@ -142,6 +144,32 @@ static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr) } #endif /* !CONFIG_DEBUG_VM */ +#ifdef HAVE_JUMP_LABEL +static __always_inline bool mmu_feature_enabled(unsigned long feature) +{ + asm_volatile_goto("1:\n\t" + ".pushsection __mmu_ftr_fixup_c, \"a\"\n\t" + JUMP_ENTRY_TYPE "%0\n\t" /* feature bit */ + JUMP_ENTRY_TYPE "1b\n\t" + JUMP_ENTRY_TYPE "%l[l_true]\n\t" + JUMP_ENTRY_TYPE "%l[l_false]\n\t" + ".popsection\n\t" + : : "i"(feature) : : l_true, l_false); + if (mmu_has_feature(feature)) +l_true: + return true; +l_false: + return false; +} +#else +static __always_inline bool mmu_feature_enabled(unsigned long feature) +{ + if (mmu_has_feature(feature)) + return true; + return false; +} +#endif + #endif /* !__ASSEMBLY__ */ /* The kernel use the constants below to index in the page sizes array. diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index c50868681f9e..c34dd7ae176f 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -14,6 +14,7 @@ extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; extern void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end); extern void do_final_fixups(void); +extern void do_feature_fixups_in_c(unsigned long value, void *fixup_start, void *fixup_end); static inline void eieio(void) { diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c index d1f1b35bf0c7..ea109d0b9494 100644 --- a/arch/powerpc/kernel/module.c +++ b/arch/powerpc/kernel/module.c @@ -80,5 +80,10 @@ int module_finalize(const Elf_Ehdr *hdr, (void *)sect->sh_addr, (void *)sect->sh_addr + sect->sh_size); + sect = find_section(hdr, sechdrs, "__mmu_ftr_fixup_c"); + if (sect != NULL) + do_feature_fixups_in_c(cur_cpu_spec->mmu_features, + (void *)sect->sh_addr, + (void *)sect->sh_addr + sect->sh_size); return 0; } diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 5c03a6a9b054..79ab96ea7a6e 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -479,6 +479,9 @@ void __init setup_system(void) &__start___mmu_ftr_fixup, &__stop___mmu_ftr_fixup); do_feature_fixups(powerpc_firmware_features, &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); + do_feature_fixups_in_c(cur_cpu_spec->mmu_features, + &__start___mmu_ftr_fixup_c, + &__stop___mmu_ftr_fixup_c); do_lwsync_fixups(cur_cpu_spec->cpu_features, &__start___lwsync_fixup, &__stop___lwsync_fixup); do_final_fixups(); diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index d41fd0af8980..ffeed71987f6 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -147,6 +147,13 @@ SECTIONS *(__fw_ftr_fixup) __stop___fw_ftr_fixup = .; } + + . = ALIGN(8); + __mmu_ftr_fixup_c : AT(ADDR(__mmu_ftr_fixup_c) - LOAD_OFFSET) { + __start___mmu_ftr_fixup_c = .; + *(__mmu_ftr_fixup_c) + __stop___mmu_ftr_fixup_c = .; + } #endif .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { INIT_RAM_FS diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index 7ce3870d7ddd..8e5fd8c71b0c 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -31,6 +31,13 @@ struct fixup_entry { long alt_end_off; }; +struct ftr_fixup_entry { + unsigned long feature_bit; + int *code; + unsigned long true_target; + unsigned long false_target; +}; + static unsigned int *calc_addr(struct fixup_entry *fcur, long offset) { /* @@ -151,6 +158,36 @@ void do_final_fixups(void) #endif } +void do_feature_fixups_in_c(unsigned long value, void *fixup_start, + void *fixup_end) +{ + unsigned long target; + struct ftr_fixup_entry *fcur, *fend; + + fcur = fixup_start; + fend = fixup_end; + + for (; fcur < fend; fcur++) { + if (fcur->code && + kernel_text_address((unsigned long)fcur->code)) { + if (value & fcur->feature_bit) + target = fcur->true_target; + else + target = fcur->false_target; + + /* Are we looping ? */ + if ((unsigned long)fcur->code == target) + continue; + + if (patch_branch(fcur->code, target, 0)) { + WARN_ON(1); + pr_err("Unable to patch radix section at %p\n", + fcur->code); + } + } + } +} + #ifdef CONFIG_FTR_FIXUP_SELFTEST #define check(x) \ -- 2.7.4 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev