/* Copyright 2017-2019 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 #include #include #include #include #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_0_1 (1U << 3) // 2.01 or 2.1 #define CPU_P9P (1U << 4) #define CPU_P9_DD2_2 (1U << 5) #define CPU_P9_DD2_3 (1U << 6) #define CPU_P9_DD2 (CPU_P9_DD2_0_1|CPU_P9_DD2_2|CPU_P9_DD2_3|CPU_P9P) #define CPU_P8 (CPU_P8_DD1|CPU_P8_DD2) #define CPU_P9 (CPU_P9_DD1|CPU_P9_DD2|CPU_P9P) #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), 52, 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, 53, 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, }, /* * Due to hardware bugs in POWER9, the hypervisor needs to assist * guests. * * Presence of this feature indicates presence of the bug. * * See linux kernel commit 4bb3c7a0208f * and linux Documentation/powerpc/transactional_memory.txt */ { "tm-suspend-hypervisor-assist", CPU_P9_DD2_2|CPU_P9_DD2_3|CPU_P9P, ISA_V3_0B, USABLE_HV, HV_CUSTOM, OS_NONE, -1, -1, -1, NULL, }, /* * Due to hardware bugs in POWER9, the hypervisor can hit * CPU bugs in the operations it needs to do for * tm-suspend-hypervisor-assist. * * Presence of this "feature" means processor is affected by the bug. * * See linux kernel commit 4bb3c7a0208f * and linux Documentation/powerpc/transactional_memory.txt */ { "tm-suspend-xer-so-bug", CPU_P9_DD2_2, ISA_V3_0B, USABLE_HV, HV_CUSTOM, 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 */ 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_P8NVL: cpu_name = "POWER8NVL"; cpu_feature_isa = ISA_V2_07B; 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) == 2)) { /* P9N DD2.x */ switch (PVR_VERS_MIN(version)) { case 0: case 1: cpu_feature_cpu = CPU_P9_DD2_0_1; break; case 2: cpu_feature_cpu = CPU_P9_DD2_2; break; case 3: cpu_feature_cpu = CPU_P9_DD2_3; break; default: assert(0); } } else { assert(0); } break; case PVR_TYPE_P9P: if (!cpu_name) cpu_name = "POWER9P"; cpu_feature_isa = ISA_V3_0B; cpu_feature_cpu = CPU_P9P; break; default: return; } cpus = dt_new_check(root, "cpus"); add_cpufeatures(cpus, cpu_feature_isa, cpu_feature_cpu, cpu_name); }