xref: /freebsd/stand/powerpc/ofw/cas.c (revision e17f5b1d)
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