diff options
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r-- | arch/powerpc/mm/pkeys.c | 64 |
1 files changed, 55 insertions, 9 deletions
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c index 4a885cc165e5..ba71c5481f42 100644 --- a/arch/powerpc/mm/pkeys.c +++ b/arch/powerpc/mm/pkeys.c @@ -6,11 +6,14 @@ */ #include <asm/mman.h> +#include <asm/setup.h> #include <linux/pkeys.h> +#include <linux/of_device.h> DEFINE_STATIC_KEY_TRUE(pkey_disabled); bool pkey_execute_disable_supported; int pkeys_total; /* Total pkeys as per device tree */ +bool pkeys_devtree_defined; /* pkey property exported by device tree */ u32 initial_allocation_mask; /* Bits set for reserved keys */ u64 pkey_amr_uamor_mask; /* Bits in AMR/UMOR not to be touched */ u64 pkey_iamr_mask; /* Bits in AMR not to be touched */ @@ -22,6 +25,35 @@ u64 pkey_iamr_mask; /* Bits in AMR not to be touched */ #define PKEY_REG_BITS (sizeof(u64)*8) #define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey+1) * AMR_BITS_PER_PKEY)) +static void scan_pkey_feature(void) +{ + u32 vals[2]; + struct device_node *cpu; + + cpu = of_find_node_by_type(NULL, "cpu"); + if (!cpu) + return; + + if (of_property_read_u32_array(cpu, + "ibm,processor-storage-keys", vals, 2)) + return; + + /* + * 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 = be32_to_cpu(vals[0]); + pkeys_devtree_defined = true; +} + +static inline bool pkey_mmu_enabled(void) +{ + if (firmware_has_feature(FW_FEATURE_LPAR)) + return pkeys_total; + else + return cpu_has_feature(CPU_FTR_PKEY); +} + int pkey_initialize(void) { int os_reserved, i; @@ -42,14 +74,17 @@ int pkey_initialize(void) __builtin_popcountl(ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT) != (sizeof(u64) * BITS_PER_BYTE)); + /* scan the device tree for pkey feature */ + scan_pkey_feature(); + /* - * Disable the pkey system till everything is in place. A subsequent - * patch will enable it. + * 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. */ - static_branch_enable(&pkey_disabled); - - /* Lets assume 32 keys */ - pkeys_total = 32; + if (!pkeys_devtree_defined && !firmware_has_feature(FW_FEATURE_LPAR) && + cpu_has_feature(CPU_FTRS_POWER8)) + pkeys_total = 32; /* * Adjust the upper limit, based on the number of bits supported by @@ -58,11 +93,22 @@ int pkey_initialize(void) pkeys_total = min_t(int, pkeys_total, (ARCH_VM_PKEY_FLAGS >> VM_PKEY_SHIFT)); + if (!pkey_mmu_enabled() || radix_enabled() || !pkeys_total) + static_branch_enable(&pkey_disabled); + else + static_branch_disable(&pkey_disabled); + + if (static_branch_likely(&pkey_disabled)) + return 0; + /* - * Disable execute_disable support for now. A subsequent patch will - * enable it. + * The device tree cannot be relied to indicate support for + * execute_disable support. Instead we use a PVR check. */ - pkey_execute_disable_supported = false; + if (pvr_version_is(PVR_POWER7) || pvr_version_is(PVR_POWER7p)) + pkey_execute_disable_supported = false; + else + pkey_execute_disable_supported = true; #ifdef CONFIG_PPC_4K_PAGES /* |