aboutsummaryrefslogtreecommitdiff
path: root/core/cpufeatures.c
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-02-16 13:40:42 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2018-02-21 11:58:19 +1100
commit7f4c8e8ce0b78ca046643d7f4f63d81f4fd11746 (patch)
tree1083ea2e11490069aa0bba324cc48bb73a0f627b /core/cpufeatures.c
parent08b1929052f8dfa1cc6b0ab3a9df77c9b5493914 (diff)
downloadskiboot-7f4c8e8ce0b78ca046643d7f4f63d81f4fd11746.zip
skiboot-7f4c8e8ce0b78ca046643d7f4f63d81f4fd11746.tar.gz
skiboot-7f4c8e8ce0b78ca046643d7f4f63d81f4fd11746.tar.bz2
dt: add /cpus/ibm, powerpc-cpu-features device tree bindings
This is a new CPU feature advertising interface that is fine-grained, extensible, aware of privilege levels, and gives control of features to all levels of the stack (firmware, hypervisor, and OS). The design and binding specification is described in detail in doc/. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> [stewart: fix maybe-uninitialized warning from older GCC, doc cleanup] Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'core/cpufeatures.c')
-rw-r--r--core/cpufeatures.c922
1 files changed, 922 insertions, 0 deletions
diff --git a/core/cpufeatures.c b/core/cpufeatures.c
new file mode 100644
index 0000000..fa946e4
--- /dev/null
+++ b/core/cpufeatures.c
@@ -0,0 +1,922 @@
+/* Copyright 2017-2018 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file deals with setup of /cpus/ibm,powerpc-cpu-features dt
+ */
+
+#include <skiboot.h>
+#include <cpu.h>
+#include <processor.h>
+#include <ccan/str/str.h>
+#include <device.h>
+
+#ifdef DEBUG
+#define DBG(fmt, a...) prlog(PR_DEBUG, "CPUFT: " fmt, ##a)
+#else
+#define DBG(fmt, a...)
+#endif
+
+/* Device-tree visible constants follow */
+#define ISA_V2_07B 2070
+#define ISA_V3_0B 3000
+
+#define USABLE_PR (1U << 0)
+#define USABLE_OS (1U << 1)
+#define USABLE_HV (1U << 2)
+
+#define HV_SUPPORT_HFSCR (1U << 0)
+#define OS_SUPPORT_FSCR (1U << 0)
+
+/* Following are definitions for the match tables, not the DT binding itself */
+#define ISA_BASE 0
+
+#define HV_NONE 0
+#define HV_CUSTOM 1
+#define HV_HFSCR 2
+
+#define OS_NONE 0
+#define OS_CUSTOM 1
+#define OS_FSCR 2
+
+/* CPU bitmasks for match table */
+#define CPU_P8_DD1 (1U << 0)
+#define CPU_P8_DD2 (1U << 1)
+#define CPU_P9_DD1 (1U << 2)
+#define CPU_P9_DD2 (1U << 3)
+
+#define CPU_P8 (CPU_P8_DD1|CPU_P8_DD2)
+#define CPU_P9 (CPU_P9_DD1|CPU_P9_DD2)
+#define CPU_ALL (CPU_P8|CPU_P9)
+
+struct cpu_feature {
+ const char *name;
+ uint32_t cpus_supported;
+ uint32_t isa;
+ uint32_t usable_privilege;
+ uint32_t hv_support;
+ uint32_t os_support;
+ uint32_t hfscr_bit_nr;
+ uint32_t fscr_bit_nr;
+ uint32_t hwcap_bit_nr;
+ const char *dependencies_names; /* space-delimited names */
+};
+
+/*
+ * The base (or NULL) cpu feature set is the CPU features available
+ * when no child nodes of the /cpus/ibm,powerpc-cpu-features node exist. The
+ * base feature set is POWER8 (ISAv2.07B), less features that are listed
+ * explicitly.
+ *
+ * XXX: currently, the feature dependencies are not necessarily captured
+ * exactly or completely. This is somewhat acceptable because all
+ * implementations must be aware of all these features.
+ */
+static const struct cpu_feature cpu_features_table[] = {
+ /*
+ * Big endian as in ISAv2.07B, MSR_LE=0
+ */
+ { "big-endian",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * Little endian as in ISAv2.07B, MSR_LE=1.
+ *
+ * When both big and little endian are defined, there is an LPCR ILE
+ * bit and implementation specific way to switch HILE mode, MSR_SLE,
+ * etc.
+ */
+ { "little-endian",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * MSR_HV=1 mode as in ISAv2.07B (i.e., hypervisor privileged
+ * instructions and registers).
+ */
+ { "hypervisor",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV,
+ HV_CUSTOM, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B interrupt vectors, registers, and control registers
+ * (e.g., AIL, ILE, HV, etc LPCR bits).
+ *
+ * This does not necessarily specify all possible interrupt types.
+ * floating-point, for example requires some ways to handle floating
+ * point exceptions, but the low level details of interrupt handler
+ * is not a dependency there. There will always be *some* interrupt
+ * handler, (and some way to provide memory magagement, etc.).
+ */
+ { "interrupt-facilities",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ { "smt",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, 14,
+ NULL, },
+
+ /*
+ * ISAv2.07B Program Priority Registers (PPR)
+ * PPR and associated control registers (e.g. RPR, PSPB),
+ * priority "or" instructions, etc.
+ */
+ { "program-priority-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 5.7.9.1. Virtual Page Class Key Protecion
+ * AMR, IAMR, AMOR, UAMOR, etc registers and MMU key bits.
+ */
+ { "virtual-page-class-key-protection",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B SAO storage control attribute
+ */
+ { "strong-access-ordering",
+ CPU_ALL & ~CPU_P9_DD1,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B no-execute storage control attribute
+ */
+ { "no-execute",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * Cache inhibited attribute supported on large pages.
+ */
+ { "cache-inhibited-large-page",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 8. Debug Facilities
+ * CIEA, CIABR, DEAW, MEte, trace interrupt, etc.
+ * Except CFAR, branch tracing.
+ */
+ { "debug-facilities",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B CFAR
+ */
+ { "come-from-address-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ "debug-facilities", },
+
+ /*
+ * ISAv2.07B Branch tracing (optional in ISA)
+ */
+ { "branch-tracing",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ "debug-facilities", },
+
+ /*
+ * ISAv2.07B Floating-point Facility
+ */
+ { "floating-point",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(63), -1, 27,
+ NULL, },
+
+ /*
+ * ISAv2.07B Vector Facility (VMX)
+ */
+ { "vector",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(62), -1, 28,
+ "floating-point", },
+
+ /*
+ * ISAv2.07B Vector-scalar Facility (VSX)
+ */
+ { "vector-scalar",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, 7,
+ "vector", },
+
+ { "vector-crypto",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, 57,
+ "vector", },
+
+ /*
+ * ISAv2.07B Quadword Load and Store instructions
+ * including lqarx/stdqcx. instructions.
+ */
+ { "quadword-load-store",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Binary Coded Decimal (BCD)
+ * BCD fixed point instructions
+ */
+ { "decimal-integer",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Decimal floating-point Facility (DFP)
+ */
+ { "decimal-floating-point",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, 10,
+ "floating-point", },
+
+ /*
+ * ISAv2.07B
+ * DSCR, default data prefetch LPCR, etc
+ */
+ { "data-stream-control-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(61), PPC_BITLSHIFT(61), 61,
+ NULL, },
+
+ /*
+ * ISAv2.07B Branch History Rolling Buffer (BHRB)
+ */
+ { "branch-history-rolling-buffer",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(59), -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Transactional Memory Facility (TM or HTM)
+ */
+ { "transactional-memory",
+ CPU_P8, /* P9 support is not enabled yet */
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(58), -1, 62,
+ NULL, },
+
+ /*
+ * ISAv3.0B TM additions
+ * TEXASR bit 17, self-induced vs external footprint overflow
+ */
+ { "transactional-memory-v3",
+ 0,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "transactional-memory", },
+
+ /*
+ * ISAv2.07B Event-Based Branch Facility (EBB)
+ */
+ { "event-based-branch",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(56), PPC_BITLSHIFT(56), 60,
+ NULL, },
+
+ /*
+ * ISAv2.07B Target Address Register (TAR)
+ */
+ { "target-address-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(55), PPC_BITLSHIFT(55), 58,
+ NULL, },
+
+ /*
+ * ISAv2.07B Control Register (CTRL)
+ */
+ { "control-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 11. Processor Control.
+ * msgsnd, msgsndp, doorbell, etc.
+ *
+ * ISAv3.0B is not compatible (different addressing, HFSCR required
+ * for msgsndp).
+ */
+ { "processor-control-facility",
+ CPU_P8_DD2, /* P8 DD1 has no dbell */
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B PURR, SPURR registers
+ */
+ { "processor-utilization-of-resources-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER8 initiate coprocessor store word indexed (icswx) instruction
+ */
+ { "coprocessor-icswx",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B hash based MMU and all instructions, registers,
+ * data structures, exceptions, etc.
+ */
+ { "mmu-hash",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER8 MCE / machine check exception.
+ */
+ { "machine-check-power8",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER8 PMU / performance monitor unit.
+ */
+ { "performance-monitor-power8",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B alignment interrupts set DSISR register
+ *
+ * POWER CPUs do not used this, and it's removed from ISAv3.0B.
+ */
+ { "alignment-interrupt-dsisr",
+ 0,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B / POWER8 doze, nap, sleep, winkle instructions
+ * XXX: is Linux we using some BookIV specific implementation details
+ * in nap handling? We have no POWER8 specific key here.
+ */
+ { "idle-nap",
+ CPU_P8,
+ ISA_BASE, USABLE_HV,
+ HV_CUSTOM, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B wait instruction
+ */
+ { "wait",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ { "subcore",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ "smt", },
+
+ /*
+ * ISAv3.0B radix based MMU
+ */
+ { "mmu-radix",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B hash based MMU, new hash pte format, PCTR, etc
+ */
+ { "mmu-hash-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B wait instruction
+ */
+ { "wait-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B stop idle instructions and registers
+ * XXX: Same question as for idle-nap
+ */
+ { "idle-stop",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Hypervisor Virtualization Interrupt
+ * Also associated system registers, LPCR EE, HEIC, HVICE,
+ * system reset SRR1 reason, etc.
+ */
+ { "hypervisor-virtualization-interrupt",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV,
+ HV_CUSTOM, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER9 MCE / machine check exception.
+ */
+ { "machine-check-power9",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER9 PMU / performance monitor unit.
+ */
+ { "performance-monitor-power9",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B scv/rfscv system call instructions and exceptions, fscr bit
+ * etc.
+ */
+ { "system-call-vectored",
+ CPU_P9,
+ ISA_V3_0B, USABLE_OS|USABLE_PR,
+ HV_NONE, OS_CUSTOM,
+ -1, PPC_BITLSHIFT(51), -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Book3S Chapter 10. Processor Control.
+ * global msgsnd, msgsndp, msgsync, doorbell, etc.
+ */
+ { "processor-control-facility-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_NONE,
+ PPC_BITLSHIFT(53), -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B addpcis instruction
+ */
+ { "pc-relative-addressing",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 7. Timer Facilities
+ * TB, VTB, DEC, HDEC, IC, etc registers and exceptions.
+ * Not including PURR or SPURR registers.
+ */
+ { "timer-facilities",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Book3S Chapter 7. Timer Facilities
+ * Large decrementer and hypervisor decrementer
+ */
+ { "timer-facilities-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "timer-facilities", },
+
+ /*
+ * ISAv3.0B deliver a random number instruction (darn)
+ */
+ { "random-number-generator",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B fixed point instructions and registers
+ * multiply-add, modulo, count trailing zeroes, cmprb, cmpeqb,
+ * extswsli, mfvsrld, mtvsrdd, mtvsrws, addex, CA32, OV32,
+ * mcrxrx, setb
+ */
+ { "fixed-point-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ { "decimal-integer-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "fixed-point-v3 decimal-integer", },
+
+ /*
+ * ISAv3.0B lightweight mffs
+ */
+ { "floating-point-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "floating-point", },
+
+ { "decimal-floating-point-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "floating-point-v3 decimal-floating-point", },
+
+ { "vector-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "vector", },
+
+ { "vector-scalar-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "vector-v3 vector-scalar" },
+
+ { "vector-binary128",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, 54,
+ "vector-scalar-v3", },
+
+ { "vector-binary16",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "vector-v3", },
+
+ /*
+ * ISAv3.0B external exception for EBB
+ */
+ { "event-based-branch-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "event-based-branch", },
+
+ /*
+ * ISAv3.0B Atomic Memory Operations (AMO)
+ */
+ { "atomic-memory-operations",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Copy-Paste Facility
+ */
+ { "copy-paste",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B GSR SPR register
+ * POWER9 does not implement it
+ */
+ { "group-start-register",
+ 0,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+};
+
+static void add_cpu_feature_nodeps(struct dt_node *features,
+ const struct cpu_feature *f)
+{
+ struct dt_node *feature;
+
+ feature = dt_new(features, f->name);
+ assert(feature);
+
+ dt_add_property_cells(feature, "isa", f->isa);
+ dt_add_property_cells(feature, "usable-privilege", f->usable_privilege);
+
+ if (f->usable_privilege & USABLE_HV) {
+ if (f->hv_support != HV_NONE) {
+ uint32_t s = 0;
+ if (f->hv_support == HV_HFSCR)
+ s |= HV_SUPPORT_HFSCR;
+
+ dt_add_property_cells(feature, "hv-support", s);
+ if (f->hfscr_bit_nr != -1)
+ dt_add_property_cells(feature, "hfscr-bit-nr", f->hfscr_bit_nr);
+ } else {
+ assert(f->hfscr_bit_nr == -1);
+ }
+ }
+
+ if (f->usable_privilege & USABLE_OS) {
+ if (f->os_support != OS_NONE) {
+ uint32_t s = 0;
+ if (f->os_support == OS_FSCR)
+ s |= OS_SUPPORT_FSCR;
+ dt_add_property_cells(feature, "os-support", s);
+ if (f->fscr_bit_nr != -1)
+ dt_add_property_cells(feature, "fscr-bit-nr", f->fscr_bit_nr);
+ } else {
+ assert(f->fscr_bit_nr == -1);
+ }
+ }
+
+ if (f->usable_privilege & USABLE_PR) {
+ if (f->hwcap_bit_nr != -1)
+ dt_add_property_cells(feature, "hwcap-bit-nr", f->hwcap_bit_nr);
+ }
+
+ if (f->dependencies_names)
+ dt_add_property(feature, "dependencies", NULL, 0);
+}
+
+static void add_cpufeatures_dependencies(struct dt_node *features)
+{
+ struct dt_node *feature;
+
+ dt_for_each_node(features, feature) {
+ const struct cpu_feature *f = NULL;
+ const char *deps_names;
+ struct dt_property *deps;
+ int nr_deps;
+ int i;
+
+ /* Find features with dependencies */
+
+ deps = __dt_find_property(feature, "dependencies");
+ if (!deps)
+ continue;
+
+ /* Find the matching cpu table */
+ for (i = 0; i < ARRAY_SIZE(cpu_features_table); i++) {
+ f = &cpu_features_table[i];
+ if (!strcmp(f->name, feature->name))
+ break;
+ }
+ assert(f);
+ assert(f->dependencies_names);
+
+ /*
+ * Count number of depended features and allocate space
+ * for phandles in the property.
+ */
+ deps_names = f->dependencies_names;
+ nr_deps = strcount(deps_names, " ") + 1;
+ dt_resize_property(&deps, nr_deps * sizeof(u32));
+ deps->len = nr_deps * sizeof(u32);
+
+ DBG("feature %s has %d dependencies (%s)\n", f->name, nr_deps, deps_names);
+ /*
+ * For each one, find the depended feature then advance to
+ * next name.
+ */
+ for (i = 0; i < nr_deps; i++) {
+ struct dt_node *dep;
+ int len;
+
+ if (nr_deps - i == 1)
+ len = strlen(deps_names);
+ else
+ len = strchr(deps_names, ' ') - deps_names;
+
+ dt_for_each_node(features, dep) {
+ if (!strncmp(deps_names, dep->name, len))
+ goto found_dep;
+ }
+
+ prlog(PR_ERR, "CPUFT: feature %s dependencies not found\n", f->name);
+ break;
+found_dep:
+ DBG(" %s found dep (%s)\n", f->name, dep->name);
+ dt_property_set_cell(deps, i, dep->phandle);
+
+ /* Advance over the name + delimiter */
+ deps_names += len + 1;
+ }
+ }
+}
+
+static void add_cpufeatures(struct dt_node *cpus,
+ uint32_t cpu_feature_isa, uint32_t cpu_feature_cpu,
+ const char *cpu_name)
+{
+ struct dt_node *features;
+ int i;
+
+ DBG("creating cpufeatures for cpu:%d isa:%d\n", cpu_feature_cpu, cpu_feature_isa);
+
+ features = dt_new(cpus, "ibm,powerpc-cpu-features");
+ assert(features);
+
+ dt_add_property_cells(features, "isa", cpu_feature_isa);
+
+ dt_add_property_string(features, "device_type", "cpu-features");
+ dt_add_property_string(features, "compatible", "ibm,powerpc-cpu-features");
+ dt_add_property_string(features, "display-name", cpu_name);
+
+ /* add without dependencies */
+ for (i = 0; i < ARRAY_SIZE(cpu_features_table); i++) {
+ const struct cpu_feature *f = &cpu_features_table[i];
+
+ if (f->cpus_supported & cpu_feature_cpu) {
+ DBG(" '%s'\n", f->name);
+ add_cpu_feature_nodeps(features, f);
+ }
+ }
+
+ /* dependency construction pass */
+ add_cpufeatures_dependencies(features);
+}
+
+void dt_add_cpufeatures(struct dt_node *root)
+{
+ int version;
+ uint32_t cpu_feature_isa = 0;
+ uint32_t cpu_feature_cpu = 0;
+ struct dt_node *cpus;
+ const char *cpu_name = NULL;
+
+ version = mfspr(SPR_PVR);
+ switch(PVR_TYPE(version)) {
+ case PVR_TYPE_P8:
+ if (!cpu_name)
+ cpu_name = "POWER8";
+ /* fallthrough */
+ case PVR_TYPE_P8E:
+ if (!cpu_name)
+ cpu_name = "POWER8E";
+ /* fallthrough */
+ case PVR_TYPE_P8NVL:
+ if (!cpu_name)
+ cpu_name = "POWER8NVL";
+
+ cpu_feature_isa = ISA_V2_07B;
+ if (PVR_VERS_MAJ(version) == 1)
+ cpu_feature_cpu = CPU_P8_DD1;
+ else
+ cpu_feature_cpu = CPU_P8_DD2;
+ break;
+ case PVR_TYPE_P9:
+ if (!cpu_name)
+ cpu_name = "POWER9";
+
+ cpu_feature_isa = ISA_V3_0B;
+ if (is_power9n(version) && (PVR_VERS_MAJ(version) == 1)) {
+ /* P9N DD1 */
+ cpu_feature_cpu = CPU_P9_DD1;
+ } else if (is_power9n(version) &&
+ (PVR_VERS_MAJ(version) == 2)) {
+ /* P9N DD2.x */
+ cpu_feature_cpu = CPU_P9_DD2;
+ } else {
+ assert(0);
+ }
+
+ break;
+ default:
+ return;
+ }
+
+ cpus = dt_new_check(root, "cpus");
+
+ add_cpufeatures(cpus, cpu_feature_isa, cpu_feature_cpu, cpu_name);
+}