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 <openfirm.h> 27 #include <stand.h> 28 29 #include <sys/endian.h> 30 31 /* #define CAS_DEBUG */ 32 #ifdef CAS_DEBUG 33 #define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) 34 #else 35 #define DPRINTF(fmt, ...) do { ; } while (0) 36 #endif 37 38 /* PVR */ 39 #define PVR_CPU_P6 0x003e0000 40 #define PVR_CPU_P7 0x003f0000 41 #define PVR_CPU_P7PLUS 0x004a0000 42 #define PVR_CPU_P8E 0x004b0000 43 #define PVR_CPU_P8NVL 0x004c0000 44 #define PVR_CPU_P8 0x004d0000 45 #define PVR_CPU_P9 0x004e0000 46 #define PVR_CPU_P10 0x00800000 47 #define PVR_CPU_P11 0x00820000 48 #define PVR_CPU_MASK 0xffff0000 49 50 #define PVR_ISA_207 0x0f000004 51 #define PVR_ISA_300 0x0f000005 52 #define PVR_ISA_31 0x0f000006 53 #define PVR_ISA_MASK 0xffffffff 54 55 /* loader version of kernel's CPU_MAXSIZE */ 56 #define MAX_CPUS ((uint32_t)256u) 57 58 /* Option Vectors' settings */ 59 60 /* length of ignored OV */ 61 #define OV_IGN_LEN 0 62 63 /* byte 1 (of any OV) */ 64 #define OV_IGN 0x80 65 66 /* Option Vector 5 */ 67 68 /* byte 2 */ 69 #define OV5_LPAR 0x80 70 #define OV5_SPLPAR 0x40 71 #define OV5_DRMEM 0x20 72 #define OV5_LP 0x10 73 #define OV5_ALPHA_PART 0x08 74 #define OV5_DMA_DELAY 0x04 75 #define OV5_DONATE_CPU 0x02 76 #define OV5_MSI 0x01 77 78 /* 9-12: max cpus */ 79 #define OV5_MAX_CPUS(n) ((MAX_CPUS >> (3*8 - (n)*8)) & 0xff) 80 81 /* 13-14: LoPAPR Level */ 82 #define LOPAPR_LEVEL 0x0101 /* 1.1 */ 83 #define OV5_LOPAPR_LEVEL(n) ((LOPAPR_LEVEL >> (8 - (n)*8)) & 0xff) 84 85 /* byte 17: Platform Facilities */ 86 #define OV5_RNG 0x80 87 #define OV5_COMP_ENG 0x40 88 #define OV5_ENC_ENG 0x20 89 90 /* byte 21: Sub-Processors */ 91 #define OV5_NO_SUBPROCS 0 92 #define OV5_SUBPROCS 1 93 94 /* byte 23: interrupt controller */ 95 #define OV5_INTC_XICS 0 96 97 /* byte 24: MMU */ 98 #define OV5_MMU_INDEX 24 99 #define OV5_MMU_HPT 0 100 #define OV5_MMU_RADIX 0x40 101 #define OV5_MMU_EITHER 0x80 102 #define OV5_MMU_DYNAMIC 0xc0 103 104 /* byte 25: HPT MMU Extensions */ 105 #define OV5_HPT_EXT_INDEX 25 106 #define OV5_HPT_GTSE 0x40 107 108 /* byte 26: Radix MMU Extensions */ 109 #define OV5_RADIX_EXT_INDEX 26 110 #define OV5_RADIX_GTSE 0x40 111 112 113 struct pvr { 114 uint32_t mask; 115 uint32_t val; 116 }; 117 118 struct opt_vec_ignore { 119 char data[2]; 120 } __packed; 121 122 struct opt_vec4 { 123 char data[3]; 124 } __packed; 125 126 struct opt_vec5 { 127 char data[27]; 128 } __packed; 129 130 static struct ibm_arch_vec { 131 struct pvr pvr_list[13]; 132 uint8_t num_opts; 133 struct opt_vec_ignore vec1; 134 struct opt_vec_ignore vec2; 135 struct opt_vec_ignore vec3; 136 struct opt_vec4 vec4; 137 struct opt_vec5 vec5; 138 } __packed ibm_arch_vec = { 139 /* pvr_list */ { 140 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P6) }, 141 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P7) }, 142 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P7PLUS) }, 143 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P8) }, 144 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P8E) }, 145 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P8NVL) }, 146 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P9) }, 147 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P10) }, 148 { htobe32(PVR_CPU_MASK), htobe32(PVR_CPU_P11) }, 149 { htobe32(PVR_ISA_MASK), htobe32(PVR_ISA_207) }, 150 { htobe32(PVR_ISA_MASK), htobe32(PVR_ISA_300) }, 151 { htobe32(PVR_ISA_MASK), htobe32(PVR_ISA_31) }, 152 { 0, 0xffffffffu } /* terminator */ 153 }, 154 4, /* num_opts (4 actually means 5 option vectors) */ 155 { OV_IGN_LEN, OV_IGN }, /* OV1 */ 156 { OV_IGN_LEN, OV_IGN }, /* OV2 */ 157 { OV_IGN_LEN, OV_IGN }, /* OV3 */ 158 /* OV4 (can't be ignored) */ { 159 sizeof(struct opt_vec4) - 2, /* length (n-2) */ 160 0, 161 10 /* Minimum VP entitled capacity percentage * 100 162 * (if absent assume 10%) */ 163 }, 164 /* OV5 */ { 165 sizeof(struct opt_vec5) - 2, /* length (n-2) */ 166 0, /* don't ignore */ 167 OV5_LPAR | OV5_SPLPAR | OV5_LP | OV5_MSI, 168 0, 169 0, /* Cooperative Memory Over-commitment */ 170 0, /* Associativity Information Option */ 171 0, /* Binary Option Controls */ 172 0, /* Reserved */ 173 0, /* Reserved */ 174 OV5_MAX_CPUS(0), 175 OV5_MAX_CPUS(1), /* 10 */ 176 OV5_MAX_CPUS(2), 177 OV5_MAX_CPUS(3), 178 OV5_LOPAPR_LEVEL(0), 179 OV5_LOPAPR_LEVEL(1), 180 0, /* Reserved */ 181 0, /* Reserved */ 182 0, /* Platform Facilities */ 183 0, /* Reserved */ 184 0, /* Reserved */ 185 0, /* Reserved */ /* 20 */ 186 OV5_NO_SUBPROCS, 187 0, /* DRMEM_V2 */ 188 OV5_INTC_XICS, 189 OV5_MMU_HPT, 190 0, 191 0 192 } 193 }; 194 195 int 196 ppc64_cas(void) 197 { 198 phandle_t pkg; 199 ihandle_t inst; 200 cell_t err = 0; 201 uint8_t buf[16], idx, val; 202 int i, len, rc, radix_mmu; 203 const char *var; 204 char *ov5; 205 206 pkg = OF_finddevice("/chosen"); 207 if (pkg == -1) { 208 printf("cas: couldn't find /chosen\n"); 209 return (-1); 210 } 211 212 len = OF_getprop(pkg, "ibm,arch-vec-5-platform-support", buf, 213 sizeof(buf)); 214 if (len == -1) 215 /* CAS not supported */ 216 return (0); 217 218 radix_mmu = 0; 219 ov5 = ibm_arch_vec.vec5.data; 220 for (i = 0; i < len; i += 2) { 221 idx = buf[i]; 222 val = buf[i + 1]; 223 DPRINTF("idx 0x%02x val 0x%02x\n", idx, val); 224 225 switch (idx) { 226 case OV5_MMU_INDEX: 227 /* 228 * Note that testing for OV5_MMU_RADIX/OV5_MMU_EITHER 229 * also covers OV5_MMU_DYNAMIC. 230 */ 231 if ((val & OV5_MMU_RADIX) || (val & OV5_MMU_EITHER)) 232 radix_mmu = 1; 233 break; 234 235 case OV5_RADIX_EXT_INDEX: 236 if (val & OV5_RADIX_GTSE) 237 ov5[idx] = OV5_RADIX_GTSE; 238 break; 239 240 case OV5_HPT_EXT_INDEX: 241 default: 242 break; 243 } 244 } 245 246 if (!radix_mmu) 247 /* 248 * If radix is not supported, set radix_mmu to 0 to avoid 249 * the kernel trying to use it and panic. 250 */ 251 setenv("radix_mmu", "0", 1); 252 else if ((var = getenv("radix_mmu")) != NULL && var[0] == '0') 253 radix_mmu = 0; 254 else 255 ov5[OV5_MMU_INDEX] = OV5_MMU_RADIX; 256 257 inst = OF_open("/"); 258 if (inst == -1) { 259 printf("cas: failed to open / node\n"); 260 return (-1); 261 } 262 263 DPRINTF("MMU 0x%02x RADIX_EXT 0x%02x\n", 264 ov5[OV5_MMU_INDEX], ov5[OV5_RADIX_EXT_INDEX]); 265 rc = OF_call_method("ibm,client-architecture-support", 266 inst, 1, 1, &ibm_arch_vec, &err); 267 if (rc != 0 || err) { 268 printf("cas: CAS method returned an error: rc %d err %jd\n", 269 rc, (intmax_t)err); 270 rc = -1; 271 } 272 273 OF_close(inst); 274 printf("cas: selected %s MMU\n", radix_mmu ? "radix" : "hash"); 275 return (rc); 276 } 277