xref: /freebsd/stand/powerpc/ofw/cas.c (revision 42249ef2)
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 	/* Perform CAS only for POWER8 and later cores */
195 	switch (mfpvr() & PVR_VER_MASK) {
196 		case PVR_VER_P8:
197 		case PVR_VER_P8E:
198 		case PVR_VER_P8NVL:
199 		case PVR_VER_P9:
200 			break;
201 		default:
202 			return (0);
203 	}
204 
205 	/* Skip CAS when running on PowerNV */
206 	if (!ppc64_hv())
207 		return (0);
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