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_CPU_P8E 0x004b0000 34 #define PVR_CPU_P8NVL 0x004c0000 35 #define PVR_CPU_P8 0x004d0000 36 #define PVR_CPU_P9 0x004e0000 37 #define PVR_CPU_MASK 0xffff0000 38 39 #define PVR_ISA_207 0x0f000004 40 #define PVR_ISA_300 0x0f000005 41 #define PVR_ISA_MASK 0xffffffff 42 43 /* loader version of kernel's CPU_MAXSIZE */ 44 #define MAX_CPUS ((uint32_t)256u) 45 46 /* Option Vectors' settings */ 47 48 /* length of ignored OV */ 49 #define OV_IGN_LEN 0 50 51 /* byte 1 (of any OV) */ 52 #define OV_IGN 0x80 53 54 /* Option Vector 5 */ 55 56 /* byte 2 */ 57 #define OV5_LPAR 0x80 58 #define OV5_SPLPAR 0x40 59 #define OV5_DRMEM 0x20 60 #define OV5_LP 0x10 61 #define OV5_ALPHA_PART 0x08 62 #define OV5_DMA_DELAY 0x04 63 #define OV5_DONATE_CPU 0x02 64 #define OV5_MSI 0x01 65 66 /* 9-12: max cpus */ 67 #define OV5_MAX_CPUS(n) ((MAX_CPUS >> (3*8 - (n)*8)) & 0xff) 68 69 /* 13-14: LoPAPR Level */ 70 #define LOPAPR_LEVEL 0x0101 /* 1.1 */ 71 #define OV5_LOPAPR_LEVEL(n) ((LOPAPR_LEVEL >> (8 - (n)*8)) & 0xff) 72 73 /* byte 17: Platform Facilities */ 74 #define OV5_RNG 0x80 75 #define OV5_COMP_ENG 0x40 76 #define OV5_ENC_ENG 0x20 77 78 /* byte 21: Sub-Processors */ 79 #define OV5_NO_SUBPROCS 0 80 #define OV5_SUBPROCS 1 81 82 /* byte 23: interrupt controller */ 83 #define OV5_INTC_XICS 0 84 85 /* byte 24: MMU */ 86 #define OV5_MMU_HPT 0 87 88 /* byte 25: HPT MMU Extensions */ 89 #define OV5_HPT_EXT_NONE 0 90 91 /* byte 26: Radix MMU Extensions */ 92 #define OV5_RPT_EXT_NONE 0 93 94 95 struct pvr { 96 uint32_t mask; 97 uint32_t val; 98 }; 99 100 struct opt_vec_ignore { 101 char data[2]; 102 } __packed; 103 104 struct opt_vec4 { 105 char data[3]; 106 } __packed; 107 108 struct opt_vec5 { 109 char data[27]; 110 } __packed; 111 112 static struct ibm_arch_vec { 113 struct pvr pvr_list[7]; 114 uint8_t num_opts; 115 struct opt_vec_ignore vec1; 116 struct opt_vec_ignore vec2; 117 struct opt_vec_ignore vec3; 118 struct opt_vec4 vec4; 119 struct opt_vec5 vec5; 120 } __packed ibm_arch_vec = { 121 /* pvr_list */ { 122 { PVR_CPU_MASK, PVR_CPU_P8 }, /* POWER8 */ 123 { PVR_CPU_MASK, PVR_CPU_P8E }, /* POWER8E */ 124 { PVR_CPU_MASK, PVR_CPU_P8NVL }, /* POWER8NVL */ 125 { PVR_CPU_MASK, PVR_CPU_P9 }, /* POWER9 */ 126 { PVR_ISA_MASK, PVR_ISA_207 }, /* All ISA 2.07 */ 127 { PVR_ISA_MASK, PVR_ISA_300 }, /* All ISA 3.00 */ 128 { 0, 0xffffffffu } /* terminator */ 129 }, 130 4, /* num_opts (4 actually means 5 option vectors) */ 131 { OV_IGN_LEN, OV_IGN }, /* OV1 */ 132 { OV_IGN_LEN, OV_IGN }, /* OV2 */ 133 { OV_IGN_LEN, OV_IGN }, /* OV3 */ 134 /* OV4 (can't be ignored) */ { 135 sizeof(struct opt_vec4) - 2, /* length (n-2) */ 136 0, 137 10 /* Minimum VP entitled capacity percentage * 100 138 * (if absent assume 10%) */ 139 }, 140 /* OV5 */ { 141 sizeof(struct opt_vec5) - 2, /* length (n-2) */ 142 0, /* don't ignore */ 143 OV5_LPAR | OV5_SPLPAR | OV5_LP | OV5_MSI, 144 0, 145 0, /* Cooperative Memory Over-commitment */ 146 0, /* Associativity Information Option */ 147 0, /* Binary Option Controls */ 148 0, /* Reserved */ 149 0, /* Reserved */ 150 OV5_MAX_CPUS(0), 151 OV5_MAX_CPUS(1), /* 10 */ 152 OV5_MAX_CPUS(2), 153 OV5_MAX_CPUS(3), 154 OV5_LOPAPR_LEVEL(0), 155 OV5_LOPAPR_LEVEL(1), 156 0, /* Reserved */ 157 0, /* Reserved */ 158 0, /* Platform Facilities */ 159 0, /* Reserved */ 160 0, /* Reserved */ 161 0, /* Reserved */ /* 20 */ 162 OV5_NO_SUBPROCS, 163 0, /* DRMEM_V2 */ 164 OV5_INTC_XICS, 165 OV5_MMU_HPT, 166 OV5_HPT_EXT_NONE, 167 OV5_RPT_EXT_NONE 168 } 169 }; 170 171 static __inline register_t 172 mfpvr(void) 173 { 174 register_t value; 175 176 __asm __volatile ("mfpvr %0" : "=r"(value)); 177 178 return (value); 179 } 180 181 static __inline int 182 ppc64_hv(void) 183 { 184 int hv; 185 186 /* PSL_HV is bit 3 of 64-bit MSR */ 187 __asm __volatile ("mfmsr %0\n\t" 188 "rldicl %0,%0,4,63" : "=r"(hv)); 189 190 return (hv); 191 } 192 193 int 194 ppc64_cas(void) 195 { 196 int rc; 197 ihandle_t ihandle; 198 cell_t err; 199 200 /* Perform CAS only for POWER8 and later cores */ 201 switch (mfpvr() & PVR_CPU_MASK) { 202 case PVR_CPU_P8: 203 case PVR_CPU_P8E: 204 case PVR_CPU_P8NVL: 205 case PVR_CPU_P9: 206 break; 207 default: 208 return (0); 209 } 210 211 /* Skip CAS when running on PowerNV */ 212 if (ppc64_hv()) 213 return (0); 214 215 ihandle = OF_open("/"); 216 if (ihandle == -1) { 217 printf("cas: failed to open / node\n"); 218 return (-1); 219 } 220 221 if (rc = OF_call_method("ibm,client-architecture-support", 222 ihandle, 1, 1, &ibm_arch_vec, &err)) 223 printf("cas: failed to call CAS method\n"); 224 else if (err) { 225 printf("cas: error: 0x%08lX\n", err); 226 rc = -1; 227 } 228 229 OF_close(ihandle); 230 return (rc); 231 } 232