1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*
26  * Copyright 2019 Peter Tribble.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/fcntl.h>
32 #include <sys/promif.h>
33 #include <sys/prom_plat.h>
34 #include <sys/salib.h>
35 
36 extern int is_sun4v;
37 
38 /*
39  * Check if the CPU should default to 64-bit or not.
40  * UltraSPARC-1's default to 32-bit mode.
41  * Everything else defaults to 64-bit mode.
42  */
43 
44 /*
45  * Manufacturer codes for the CPUs we're interested in
46  */
47 #define	TI_JEDEC	0x17
48 #define	SUNW_JEDEC	0x22
49 
50 /*
51  * Implementation codes for the CPUs we're interested in
52  */
53 #define	IMPL_US_I	0x10
54 
55 static pnode_t
56 visit(pnode_t node)
57 {
58 	int impl, manu;
59 	char name[32];
60 	static char ultrasparc[] = "SUNW,UltraSPARC";
61 	static char implementation[] = "implementation#";
62 	static char manufacturer[] = "manufacturer#";
63 
64 	/*
65 	 * if name isn't 'SUNW,UltraSPARC', continue.
66 	 */
67 	if (prom_getproplen(node, "name") != sizeof (ultrasparc))
68 		return ((pnode_t)0);
69 	(void) prom_getprop(node, "name", name);
70 	if (strncmp(name, ultrasparc, sizeof (ultrasparc)) != 0)
71 		return ((pnode_t)0);
72 
73 	if (prom_getproplen(node, manufacturer) != sizeof (int))
74 		return ((pnode_t)0);
75 	(void) prom_getprop(node, manufacturer, (caddr_t)&manu);
76 
77 	if ((manu != SUNW_JEDEC) && (manu != TI_JEDEC))
78 		return ((pnode_t)0);
79 
80 	if (prom_getproplen(node, implementation) != sizeof (int))
81 		return ((pnode_t)0);
82 	(void) prom_getprop(node, implementation, (caddr_t)&impl);
83 
84 	if (impl != IMPL_US_I)
85 		return ((pnode_t)0);
86 
87 	return (node);
88 }
89 
90 /*
91  * visit each node in the device tree, until we get a non-null answer
92  */
93 static pnode_t
94 walk(pnode_t node)
95 {
96 	pnode_t id;
97 
98 	if (visit(node))
99 		return (node);
100 
101 	for (node = prom_childnode(node); node; node = prom_nextnode(node))
102 		if ((id = walk(node)) != (pnode_t)0)
103 			return (id);
104 
105 	return ((pnode_t)0);
106 }
107 
108 /*
109  * Check if the CPU is an UltraSPARC-1 or not.
110  */
111 int
112 cpu_is_ultrasparc_1(void)
113 {
114 	static int cpu_checked;
115 	static int cpu_default;
116 
117 	/*
118 	 * If we already checked or the machine is
119 	 * a sun4v, we already know the answer.
120 	 */
121 	if (!is_sun4v || cpu_checked == 0) {
122 		if (walk(prom_rootnode()))
123 			cpu_default = 1;
124 		cpu_checked = 1;
125 	}
126 
127 	return (cpu_default);
128 }
129 
130 /*
131  * Retain a page or reclaim a previously retained page of physical
132  * memory for use by the prom upgrade. If successful, leave
133  * an indication that a page was retained by creating a boolean
134  * property in the root node.
135  *
136  * XXX: SUNW,retain doesn't work as expected on server systems,
137  * so we don't try to retain any memory on those systems.
138  *
139  * XXX: do a '0 to my-self' as a workaround for 4160914
140  */
141 
142 int dont_retain_memory;
143 
144 void
145 retain_nvram_page(void)
146 {
147 	unsigned long long phys = 0;
148 	int len;
149 	char name[32];
150 	static char create_prop[] =
151 	    "0 to my-self dev / 0 0 \" boot-retained-page\" property";
152 	static char ue[] = "SUNW,Ultra-Enterprise";
153 	extern int verbosemode;
154 
155 	if (dont_retain_memory)
156 		return;
157 
158 	if (!is_sun4v) {
159 		len = prom_getproplen(prom_rootnode(), "name");
160 		if ((len != -1) && (len <= sizeof (name))) {
161 			(void) prom_getprop(prom_rootnode(), "name", name);
162 			if (strcmp(name, ue) == 0)
163 				return;
164 		}
165 	}
166 
167 	if (prom_retain("OBPnvram", PAGESIZE, PAGESIZE, &phys) != 0) {
168 		printf("prom_retain failed\n");
169 		return;
170 	}
171 	if (verbosemode)
172 		printf("retained OBPnvram page at 0x%llx\n", phys);
173 
174 	prom_interpret(create_prop, 0, 0, 0, 0, 0);
175 }
176