Parse storage keys related device tree entry in early_init_devtree and enable MMU feature MMU_FTR_PKEY if pkeys are supported.
MMU feature is used instead of CPU feature because this enables us to group MMU_FTR_KUAP and MMU_FTR_PKEY in asm feature fixup code. Signed-off-by: Aneesh Kumar K.V <aneesh.ku...@linux.ibm.com> --- arch/powerpc/include/asm/book3s/64/pkeys.h | 9 ++++ arch/powerpc/include/asm/mmu.h | 4 ++ arch/powerpc/kernel/prom.c | 6 +++ arch/powerpc/mm/book3s64/pkeys.c | 54 +++++++++++++--------- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/pkeys.h b/arch/powerpc/include/asm/book3s/64/pkeys.h index 8174662a9173..c2c7d744e3bb 100644 --- a/arch/powerpc/include/asm/book3s/64/pkeys.h +++ b/arch/powerpc/include/asm/book3s/64/pkeys.h @@ -22,4 +22,13 @@ static inline u16 pte_to_pkey_bits(u64 pteflags) return hash__pte_to_pkey_bits(pteflags); } +#ifdef CONFIG_PPC_MEM_KEYS +extern void pkey_early_init_devtree(void); +#else +static inline void pkey_early_init_devtree(void) +{ + +} +#endif + #endif /*_ASM_POWERPC_KEYS_H */ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 0699cfeeb8c9..3816e9901f7d 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -23,6 +23,7 @@ /* Radix page table supported and enabled */ #define MMU_FTR_TYPE_RADIX ASM_CONST(0x00000040) +#define MMU_FTR_PKEY ASM_CONST(0x00000080) /* * Individual features below. @@ -176,6 +177,9 @@ enum { MMU_FTR_RADIX_KUAP | #endif /* CONFIG_PPC_KUAP */ #endif /* CONFIG_PPC_RADIX_MMU */ +#ifdef CONFIG_PPC_MEM_KEYS + MMU_FTR_PKEY | +#endif 0, }; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 6620f37abe73..d027d1155a65 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -56,6 +56,7 @@ #include <asm/dt_cpu_ftrs.h> #include <asm/drmem.h> #include <asm/ultravisor.h> +#include <asm/pkeys.h> #include <mm/mmu_decl.h> @@ -791,6 +792,11 @@ void __init early_init_devtree(void *params) /* Now try to figure out if we are running on LPAR and so on */ pseries_probe_fw_features(); + /* + * Initialize pkey features and default AMR/IAMR values + */ + pkey_early_init_devtree(); + #ifdef CONFIG_PPC_PS3 /* Identify PS3 firmware */ if (of_flat_dt_is_compatible(of_get_flat_dt_root(), "sony,ps3")) diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c index 0303df9368e1..36cc4ff8ea5b 100644 --- a/arch/powerpc/mm/book3s64/pkeys.c +++ b/arch/powerpc/mm/book3s64/pkeys.c @@ -10,7 +10,8 @@ #include <asm/mmu.h> #include <asm/setup.h> #include <linux/pkeys.h> -#include <linux/of_device.h> +#include <linux/of_fdt.h> + DEFINE_STATIC_KEY_FALSE(pkey_disabled); DEFINE_STATIC_KEY_FALSE(execute_pkey_disabled); @@ -38,38 +39,45 @@ static int execute_only_key = 2; #define PKEY_REG_BITS (sizeof(u64) * 8) #define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey+1) * AMR_BITS_PER_PKEY)) +static int __init dt_scan_storage_keys(unsigned long node, + const char *uname, int depth, + void *data) +{ + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *prop; + int pkeys_total; + + /* We are scanning "cpu" nodes only */ + if (type == NULL || strcmp(type, "cpu") != 0) + return 0; + + prop = of_get_flat_dt_prop(node, "ibm,processor-storage-keys", NULL); + if (!prop) + return 0; + pkeys_total = be32_to_cpu(prop[0]); + return pkeys_total; +} + static int scan_pkey_feature(void) { - u32 vals[2]; - int pkeys_total = 0; - struct device_node *cpu; + int pkeys_total; /* * Pkey is not supported with Radix translation. */ - if (radix_enabled()) + if (early_radix_enabled()) return 0; - cpu = of_find_node_by_type(NULL, "cpu"); - if (!cpu) - return 0; + pkeys_total = of_scan_flat_dt(dt_scan_storage_keys, NULL); + if (pkeys_total == 0) { - if (of_property_read_u32_array(cpu, - "ibm,processor-storage-keys", vals, 2) == 0) { - /* - * Since any pkey can be used for data or execute, we will - * just treat all keys as equal and track them as one entity. - */ - pkeys_total = vals[0]; - /* Should we check for IAMR support FIXME!! */ - } else { /* * Let's assume 32 pkeys on P8 bare metal, if its not defined by device * tree. We make this exception since skiboot forgot to expose this * property on power8. */ if (!firmware_has_feature(FW_FEATURE_LPAR) && - cpu_has_feature(CPU_FTRS_POWER8)) + early_cpu_has_feature(CPU_FTRS_POWER8)) pkeys_total = 32; } @@ -82,7 +90,7 @@ static int scan_pkey_feature(void) return pkeys_total; } -static int pkey_initialize(void) +void __init pkey_early_init_devtree(void) { int pkeys_total, i; @@ -107,9 +115,11 @@ static int pkey_initialize(void) if (!pkeys_total) { /* No support for pkey. Mark it disabled */ static_branch_enable(&pkey_disabled); - return 0; + return; } + cur_cpu_spec->mmu_features |= MMU_FTR_PKEY; + /* * The device tree cannot be relied to indicate support for * execute_disable support. Instead we use a PVR check. @@ -187,11 +197,9 @@ static int pkey_initialize(void) */ initial_allocation_mask |= reserved_allocation_mask; - return 0; + return; } -arch_initcall(pkey_initialize); - void pkey_mm_init(struct mm_struct *mm) { if (static_branch_likely(&pkey_disabled)) -- 2.25.3