1 /*- 2 * Copyright (c) 2019 Leandro Lupori 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <openfirm.h> 30 #include <stand.h> 31 32 /* PVR */ 33 #define PVR_VER_P8E 0x004b0000 34 #define PVR_VER_P8NVL 0x004c0000 35 #define PVR_VER_P8 0x004d0000 36 #define PVR_VER_P9 0x004e0000 37 #define PVR_VER_MASK 0xffff0000 38 39 /* loader version of kernel's CPU_MAXSIZE */ 40 #define MAX_CPUS ((uint32_t)256u) 41 42 /* Option Vectors' settings */ 43 44 /* length of ignored OV */ 45 #define OV_IGN_LEN 0 46 47 /* byte 1 (of any OV) */ 48 #define OV_IGN 0x80 49 50 /* Option Vector 5 */ 51 52 /* byte 2 */ 53 #define OV5_LPAR 0x80 54 #define OV5_SPLPAR 0x40 55 #define OV5_DRMEM 0x20 56 #define OV5_LP 0x10 57 #define OV5_ALPHA_PART 0x08 58 #define OV5_DMA_DELAY 0x04 59 #define OV5_DONATE_CPU 0x02 60 #define OV5_MSI 0x01 61 62 /* 9-12: max cpus */ 63 #define OV5_MAX_CPUS(n) ((MAX_CPUS >> (3*8 - (n)*8)) & 0xff) 64 65 /* 13-14: LoPAPR Level */ 66 #define LOPAPR_LEVEL 0x0101 /* 1.1 */ 67 #define OV5_LOPAPR_LEVEL(n) ((LOPAPR_LEVEL >> (8 - (n)*8)) & 0xff) 68 69 /* byte 17: Platform Facilities */ 70 #define OV5_RNG 0x80 71 #define OV5_COMP_ENG 0x40 72 #define OV5_ENC_ENG 0x20 73 74 /* byte 21: Sub-Processors */ 75 #define OV5_NO_SUBPROCS 0 76 #define OV5_SUBPROCS 1 77 78 /* byte 23: interrupt controller */ 79 #define OV5_INTC_XICS 0 80 81 /* byte 24: MMU */ 82 #define OV5_MMU_HPT 0 83 84 /* byte 25: HPT MMU Extensions */ 85 #define OV5_HPT_EXT_NONE 0 86 87 /* byte 26: Radix MMU Extensions */ 88 #define OV5_RPT_EXT_NONE 0 89 90 91 struct pvr { 92 uint32_t mask; 93 uint32_t val; 94 }; 95 96 struct opt_vec_ignore { 97 char data[2]; 98 } __packed; 99 100 struct opt_vec4 { 101 char data[3]; 102 } __packed; 103 104 struct opt_vec5 { 105 char data[27]; 106 } __packed; 107 108 static struct ibm_arch_vec { 109 struct pvr pvr_list[5]; 110 uint8_t num_opts; 111 struct opt_vec_ignore vec1; 112 struct opt_vec_ignore vec2; 113 struct opt_vec_ignore vec3; 114 struct opt_vec4 vec4; 115 struct opt_vec5 vec5; 116 } __packed ibm_arch_vec = { 117 /* pvr_list */ { 118 { PVR_VER_MASK, PVR_VER_P8 }, /* POWER8 */ 119 { PVR_VER_MASK, PVR_VER_P8E }, /* POWER8E */ 120 { PVR_VER_MASK, PVR_VER_P8NVL }, /* POWER8NVL */ 121 { PVR_VER_MASK, PVR_VER_P9 }, /* POWER9 */ 122 { 0, 0xffffffffu } /* terminator */ 123 }, 124 4, /* num_opts (4 actually means 5 option vectors) */ 125 { OV_IGN_LEN, OV_IGN }, /* OV1 */ 126 { OV_IGN_LEN, OV_IGN }, /* OV2 */ 127 { OV_IGN_LEN, OV_IGN }, /* OV3 */ 128 /* OV4 (can't be ignored) */ { 129 sizeof(struct opt_vec4) - 2, /* length (n-2) */ 130 0, 131 10 /* Minimum VP entitled capacity percentage * 100 132 * (if absent assume 10%) */ 133 }, 134 /* OV5 */ { 135 sizeof(struct opt_vec5) - 2, /* length (n-2) */ 136 0, /* don't ignore */ 137 OV5_LPAR | OV5_SPLPAR | OV5_LP | OV5_MSI, 138 0, 139 0, /* Cooperative Memory Over-commitment */ 140 0, /* Associativity Information Option */ 141 0, /* Binary Option Controls */ 142 0, /* Reserved */ 143 0, /* Reserved */ 144 OV5_MAX_CPUS(0), 145 OV5_MAX_CPUS(1), /* 10 */ 146 OV5_MAX_CPUS(2), 147 OV5_MAX_CPUS(3), 148 OV5_LOPAPR_LEVEL(0), 149 OV5_LOPAPR_LEVEL(1), 150 0, /* Reserved */ 151 0, /* Reserved */ 152 0, /* Platform Facilities */ 153 0, /* Reserved */ 154 0, /* Reserved */ 155 0, /* Reserved */ /* 20 */ 156 OV5_NO_SUBPROCS, 157 0, /* DRMEM_V2 */ 158 OV5_INTC_XICS, 159 OV5_MMU_HPT, 160 OV5_HPT_EXT_NONE, 161 OV5_RPT_EXT_NONE 162 } 163 }; 164 165 static __inline register_t 166 mfpvr(void) 167 { 168 register_t value; 169 170 __asm __volatile ("mfpvr %0" : "=r"(value)); 171 172 return (value); 173 } 174 175 static __inline int 176 ppc64_hv(void) 177 { 178 int hv; 179 180 /* PSL_HV is bit 3 of 64-bit MSR */ 181 __asm __volatile ("mfmsr %0\n\t" 182 "rldicl %0,%0,4,63" : "=r"(hv)); 183 184 return (hv); 185 } 186 187 int 188 ppc64_cas(void) 189 { 190 int rc; 191 ihandle_t ihandle; 192 cell_t err; 193 194 /* Skip CAS when running on PowerNV */ 195 if (!ppc64_hv()) 196 return (0); 197 198 /* Perform CAS only for POWER8 and later cores */ 199 switch (mfpvr() & PVR_VER_MASK) { 200 case PVR_VER_P8: 201 case PVR_VER_P8E: 202 case PVR_VER_P8NVL: 203 case PVR_VER_P9: 204 break; 205 default: 206 return (0); 207 } 208 209 ihandle = OF_open("/"); 210 if (ihandle == -1) { 211 printf("cas: failed to open / node\n"); 212 return (-1); 213 } 214 215 if (rc = OF_call_method("ibm,client-architecture-support", 216 ihandle, 1, 1, &ibm_arch_vec, &err)) 217 printf("cas: failed to call CAS method\n"); 218 else if (err) { 219 printf("cas: error: 0x%08lX\n", err); 220 rc = -1; 221 } 222 223 OF_close(ihandle); 224 return (rc); 225 } 226