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 95struct pvr { 96 uint32_t mask; 97 uint32_t val; 98}; 99 100struct opt_vec_ignore { 101 char data[2]; 102} __packed; 103 104struct opt_vec4 { 105 char data[3]; 106} __packed; 107 108struct opt_vec5 { 109 char data[27]; 110} __packed; 111 112static 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 171static __inline register_t 172mfpvr(void) 173{ 174 register_t value; 175 176 __asm __volatile ("mfpvr %0" : "=r"(value)); 177 178 return (value); 179} 180 181static __inline int 182ppc64_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 193int 194ppc64_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