summaryrefslogtreecommitdiff
path: root/arch/powerpc/mm/pkeys.c
diff options
context:
space:
mode:
authorRam Pai <linuxram@us.ibm.com>2018-01-18 17:50:44 -0800
committerMichael Ellerman <mpe@ellerman.id.au>2018-01-21 01:06:10 +1100
commitcf43d3b26452a332d7e1d64a00079c607613e944 (patch)
tree1ba0104d42603265673d677bd2206da7383edfa4 /arch/powerpc/mm/pkeys.c
parentc5cc1f4df6b16646f8fae7aab523c1820bf916e8 (diff)
powerpc: Enable pkey subsystem
PAPR defines 'ibm,processor-storage-keys' property. It exports two values. The first value holds the number of data-access keys and the second holds the number of instruction-access keys. Due to a bug in the firmware, instruction-access keys is always reported as zero. However any key can be configured to disable data-access and/or disable execution-access. The inavailablity of the second value is not a big handicap, though it could have been used to determine if the platform supported disable-execution-access. Non-PAPR platforms do not define this property in the device tree yet. Fortunately power8 is the only released Non-PAPR platform that is supported. Here, we hardcode the number of supported pkey to 32, by consulting the PowerISA3.0 This patch calculates the number of keys supported by the platform. Also it determines the platform support for read/write/execution access support for pkeys. Signed-off-by: Ram Pai <linuxram@us.ibm.com> [mpe: Use a PVR check instead of CPU_FTR for execute. Restrict to Power7/8/9 for now until older CPUs are tested.] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/mm/pkeys.c')
-rw-r--r--arch/powerpc/mm/pkeys.c64
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
/*