| // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| /* |
| * This file deals with setup of /cpus/ibm,powerpc-cpu-features dt |
| * |
| * Copyright 2017-2019 IBM Corp. |
| */ |
| |
| #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 ISA_V3_1 3100 |
| |
| #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_P10 (1U << 7) |
| |
| #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|CPU_P10) |
| |
| 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, }, |
| |
| /* |
| * DAWR1, DAWRX1 etc. |
| */ |
| { "debug-facilities-v31", |
| CPU_P10, |
| ISA_V3_1, 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|CPU_P10, |
| 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|CPU_P10, |
| ISA_V3_0B, USABLE_HV|USABLE_OS, |
| HV_CUSTOM, OS_CUSTOM, |
| -1, -1, -1, |
| NULL, }, |
| |
| /* |
| * ISAv3.0B wait instruction |
| */ |
| { "wait-v3", |
| CPU_P9|CPU_P10, |
| 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|CPU_P10, |
| 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|CPU_P10, |
| 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, }, |
| |
| /* |
| * POWER10 MCE / machine check exception. |
| */ |
| { "machine-check-power10", |
| CPU_P10, |
| 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, }, |
| |
| /* |
| * POWER10 PMU / performance monitor unit. |
| */ |
| { "performance-monitor-power10", |
| CPU_P10, |
| ISA_V3_1, 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|CPU_P10, |
| 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|CPU_P10, |
| 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|CPU_P10, |
| 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|CPU_P10, |
| 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|CPU_P10, |
| 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|CPU_P10, |
| ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR, |
| HV_NONE, OS_NONE, |
| -1, -1, -1, |
| NULL, }, |
| |
| { "decimal-integer-v3", |
| CPU_P9|CPU_P10, |
| 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|CPU_P10, |
| ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR, |
| HV_NONE, OS_NONE, |
| -1, -1, -1, |
| "floating-point", }, |
| |
| { "decimal-floating-point-v3", |
| CPU_P9|CPU_P10, |
| 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|CPU_P10, |
| ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR, |
| HV_NONE, OS_NONE, |
| -1, -1, -1, |
| "vector", }, |
| |
| { "vector-scalar-v3", |
| CPU_P9|CPU_P10, |
| ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR, |
| HV_NONE, OS_NONE, |
| -1, -1, -1, |
| "vector-v3 vector-scalar" }, |
| |
| { "vector-binary128", |
| CPU_P9|CPU_P10, |
| ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR, |
| HV_NONE, OS_NONE, |
| -1, -1, 54, |
| "vector-scalar-v3", }, |
| |
| { "vector-binary16", |
| CPU_P9|CPU_P10, |
| 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|CPU_P10, |
| 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|CPU_P10, |
| 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|CPU_P10, |
| 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, }, |
| |
| /* |
| * Enable matrix multiply accumulate. |
| */ |
| { "matrix-multiply-accumulate", |
| CPU_P10, |
| ISA_V3_1, USABLE_PR, |
| HV_CUSTOM, OS_CUSTOM, |
| -1, -1, 49, |
| NULL, }, |
| |
| /* |
| * Enable prefix instructions. Toolchains assume this is |
| * enabled for when compiling for ISA 3.1. |
| */ |
| { "prefix-instructions", |
| CPU_P10, |
| ISA_V3_1, USABLE_HV|USABLE_OS|USABLE_PR, |
| HV_HFSCR, OS_FSCR, |
| 13, 13, -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)); |
| |
| 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 if (is_power9c(version) && |
| (PVR_VERS_MAJ(version) == 1)) { |
| /* P9C DD1.x */ |
| switch (PVR_VERS_MIN(version)) { |
| case 1: |
| /* Cumulus DD1.1 => Nimbus DD2.1 */ |
| cpu_feature_cpu = CPU_P9_DD2_0_1; |
| break; |
| case 2: |
| /* Cumulus DD1.2 */ |
| cpu_feature_cpu = CPU_P9_DD2_2; |
| break; |
| case 3: |
| /* Cumulus DD1.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; |
| case PVR_TYPE_P10: |
| if (!cpu_name) |
| cpu_name = "POWER10"; |
| |
| cpu_feature_isa = ISA_V3_1; |
| cpu_feature_cpu = CPU_P10; |
| break; |
| default: |
| return; |
| } |
| |
| cpus = dt_new_check(root, "cpus"); |
| |
| add_cpufeatures(cpus, cpu_feature_isa, cpu_feature_cpu, cpu_name); |
| } |