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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 /*
28  * This plugin creates memory configuration nodes and properties in the
29  * PICL tree for Grover/Grover+ platform.
30  *
31  * Subtree of memory-controller in the physical aspect.
32  * memory-controller --- memory-module
33  * However, there is no memory controller node on Grover. Thus we need to
34  * create it under platform.
35  *
36  * Subtree of memory in the logical aspect.
37  * memory --- memory-segment
38  * Add property _memory-module_ at memory-segment referring to the
39  * memory-module since memory-segment equals to memory-module on Grover.
40  *
41  * Undo strategy:
42  * Create all nodes and properties, or none if it fails in physical and
43  * logical memory tree respectively. It keeps on creating logical
44  * memory tree although it falis on physical logical tree, but no link to
45  * memory module.
46  *
47  * NOTE:
48  * It depends on PICL devtree plugin.
49  */
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <alloca.h>
55 #include <syslog.h>
56 #include <string.h>
57 #include <libintl.h>
58 #include <picl.h>
59 #include <picltree.h>
60 #include <sys/types.h>
61 #include <sys/obpdefs.h>
62 #include "piclmemcfg.h"
63 #include "memcfg_impl.h"
64 
65 static	void	piclmemcfg_register(void);
66 static	void	piclmemcfg_init(void);
67 static	void	piclmemcfg_fini(void);
68 
69 #pragma	init(piclmemcfg_register)
70 
71 static picld_plugin_reg_t  my_reg_info = {
72 	PICLD_PLUGIN_VERSION_1,
73 	PICLD_PLUGIN_NON_CRITICAL,
74 	"SUNW_piclmemcfg",
75 	piclmemcfg_init,
76 	piclmemcfg_fini
77 };
78 
79 /*
80  * Create logical memory tree
81  * memory --- memory-segment
82  */
83 static int
create_logical_tree(picl_nodehdl_t memh,mmodinfo_t * mmodinfo)84 create_logical_tree(picl_nodehdl_t memh, mmodinfo_t *mmodinfo)
85 {
86 	picl_nodehdl_t		msegh;
87 	picl_nodehdl_t		*memsegh;
88 	ptree_propinfo_t	propinfo;
89 	uint32_t		ifactor = INTERLEAVEFACTOR;
90 	int			i;
91 	int			err = PICL_SUCCESS;
92 
93 	if ((memsegh = alloca(sizeof (picl_nodehdl_t) * TOTAL_MEM_SLOTS)) ==
94 	    NULL)
95 		return (PICL_FAILURE);
96 
97 	for (i = 0; i < TOTAL_MEM_SLOTS; i++) {
98 		/*
99 		 * It means no segment for the slot if size is zero
100 		 */
101 		if (mmodinfo[i].size == 0) {
102 			memsegh[i] = 0;
103 			continue;
104 		}
105 
106 		/*
107 		 * Create memory-segment node under memory
108 		 */
109 		err = ptree_create_and_add_node(memh, PICL_NAME_MEMORY_SEGMENT,
110 		    PICL_CLASS_MEMORY_SEGMENT, &msegh);
111 		if (err != PICL_SUCCESS)
112 			break;
113 
114 		/*
115 		 * For undo easily later
116 		 */
117 		memsegh[i] = msegh;
118 
119 		/*
120 		 * Add property, Size to memory-segment node
121 		 */
122 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
123 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ,
124 		    sizeof (mmodinfo[i].size), PICL_PROP_SIZE, NULL, NULL);
125 		if (err != PICL_SUCCESS)
126 			break;
127 
128 		err = ptree_create_and_add_prop(msegh, &propinfo,
129 		    &mmodinfo[i].size, NULL);
130 		if (err != PICL_SUCCESS)
131 			break;
132 
133 		/*
134 		 * Add property, BaseAddress to memory-segment node
135 		 */
136 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
137 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ,
138 		    sizeof (mmodinfo[i].base), PICL_PROP_BASEADDRESS, NULL,
139 		    NULL);
140 		if (err != PICL_SUCCESS)
141 			break;
142 
143 		err = ptree_create_and_add_prop(msegh, &propinfo,
144 		    &mmodinfo[i].base, NULL);
145 		if (err != PICL_SUCCESS)
146 			break;
147 
148 		/*
149 		 * Add property, InterleaveFactor to memory-segment node
150 		 */
151 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
152 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (ifactor),
153 		    PICL_PROP_INTERLEAVE_FACTOR, NULL, NULL);
154 		if (err != PICL_SUCCESS)
155 			break;
156 
157 		err = ptree_create_and_add_prop(msegh, &propinfo, &ifactor,
158 		    NULL);
159 		if (err != PICL_SUCCESS)
160 			break;
161 
162 		/*
163 		 * Add reference property to the memory module if memory
164 		 * module node handle is not NULL.
165 		 */
166 		if (mmodinfo[i].memmodh == 0)
167 			continue;
168 
169 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
170 		    PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t),
171 		    PICL_REFPROP_MEMORY_MODULE, NULL, NULL);
172 		if (err != PICL_SUCCESS)
173 			break;
174 
175 		err = ptree_create_and_add_prop(msegh, &propinfo,
176 		    &mmodinfo[i].memmodh, NULL);
177 		if (err != PICL_SUCCESS)
178 			break;
179 	}
180 
181 	if (err != PICL_SUCCESS) {
182 		/*
183 		 * Undo in the logical memory tree
184 		 */
185 		for (i = 0; i < TOTAL_MEM_SLOTS; i++) {
186 			if (memsegh[i] == 0)
187 				continue;
188 
189 			(void) ptree_delete_node(memsegh[i]);
190 			(void) ptree_destroy_node(memsegh[i]);
191 		}
192 	}
193 
194 	return (err);
195 }
196 
197 /*
198  * Create physical memory tree
199  * memory-controller --- memory-module
200  */
201 static int
create_physical_tree(picl_nodehdl_t plfh,mmodinfo_t * mmodinfo)202 create_physical_tree(picl_nodehdl_t plfh, mmodinfo_t *mmodinfo)
203 {
204 	picl_nodehdl_t		mch, memmodh;
205 	ptree_propinfo_t	propinfo;
206 	int			i;
207 	int			err = PICL_SUCCESS;
208 	uint32_t		id;
209 
210 	/*
211 	 * Create memory-controller node under platform
212 	 */
213 	err = ptree_create_and_add_node(plfh, PICL_NAME_MEMORY_CONTROLLER,
214 	    PICL_CLASS_MEMORY_CONTROLLER, &mch);
215 	if (err != PICL_SUCCESS)
216 		return (err);
217 
218 	/*
219 	 * Create memory-module nodes and properties
220 	 * Get all memory modules with dimm
221 	 */
222 	for (i = 0; i < TOTAL_MEM_SLOTS; i++) {
223 		/*
224 		 * It means no dimm on the slot if size is zero
225 		 */
226 		if (mmodinfo[i].size == 0)
227 			continue;
228 
229 		/* Create memory-module node under memory-controller */
230 		err = ptree_create_and_add_node(mch, PICL_NAME_MEMORY_MODULE,
231 		    PICL_CLASS_MEMORY_MODULE, &memmodh);
232 		if (err != PICL_SUCCESS)
233 			break;
234 
235 		/*
236 		 * Update memory module node handle at mmodinfo
237 		 */
238 		mmodinfo[i].memmodh = memmodh;
239 
240 		/*
241 		 * Add property, Size to memory-module node
242 		 */
243 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
244 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ,
245 		    sizeof (mmodinfo[i].size), PICL_PROP_SIZE, NULL, NULL);
246 		if (err != PICL_SUCCESS)
247 			break;
248 
249 		err = ptree_create_and_add_prop(memmodh, &propinfo,
250 		    &mmodinfo[i].size, NULL);
251 		if (err != PICL_SUCCESS)
252 			break;
253 
254 		/*
255 		 * Add property, ID to memory-module node
256 		 */
257 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
258 		    PICL_PTYPE_INT, PICL_READ, sizeof (id), PICL_PROP_ID,
259 		    NULL, NULL);
260 		if (err != PICL_SUCCESS)
261 			break;
262 
263 		id = i;
264 		err = ptree_create_and_add_prop(memmodh, &propinfo, &id, NULL);
265 		if (err != PICL_SUCCESS)
266 			break;
267 	}
268 
269 	if (err != PICL_SUCCESS) {
270 		/*
271 		 * Clear out the saved memory module node handle so that
272 		 * logical memory tree won't link to memory module.
273 		 */
274 		for (i = 0; i < TOTAL_MEM_SLOTS; i++)
275 			mmodinfo[i].memmodh = 0;
276 
277 		/*
278 		 * Undo in the physical memory tree
279 		 */
280 		(void) ptree_delete_node(mch);
281 		(void) ptree_destroy_node(mch);
282 	}
283 
284 	return (err);
285 }
286 
287 /*
288  * Get the memory module and memory segment information from
289  * property reg of memory node.
290  *
291  * mmodinfo will be updated. Also, the pointers to mseginfo and
292  * the number of segments will be passed to the caller.
293  */
294 static int
get_reg_info(picl_nodehdl_t plfh,picl_nodehdl_t memh,mmodinfo_t * mmodinfo)295 get_reg_info(picl_nodehdl_t plfh, picl_nodehdl_t memh,
296     mmodinfo_t *mmodinfo)
297 {
298 	picl_prophdl_t		proph;
299 	ptree_propinfo_t	pinfo;
300 	regspec_t		*memspec;
301 	int			i, err;
302 	int			pval;
303 	int			nregspec;
304 
305 
306 	/*
307 	 * Check if the #size-cells of the platform node is 2
308 	 */
309 	err = ptree_get_propval_by_name(plfh, OBP_PROP_SIZE_CELLS, &pval,
310 	    sizeof (pval));
311 
312 	if (err == PICL_PROPNOTFOUND)
313 		pval = SUPPORTED_NUM_CELL_SIZE;
314 	else if (err != PICL_SUCCESS)
315 		return (err);
316 
317 	/*
318 	 * don't know to handle other vals
319 	 */
320 	if (pval != SUPPORTED_NUM_CELL_SIZE)
321 		return (PICL_FAILURE);
322 
323 	/*
324 	 * Get property reg of memory node
325 	 */
326 	err = ptree_get_prop_by_name(memh, OBP_REG, &proph);
327 	if (err != PICL_SUCCESS)
328 		return (err);
329 
330 	err = ptree_get_propinfo(proph, &pinfo);
331 	if (err != PICL_SUCCESS)
332 		return (err);
333 
334 	if ((memspec = alloca(pinfo.piclinfo.size)) == NULL)
335 		return (PICL_FAILURE);
336 
337 	nregspec = pinfo.piclinfo.size / sizeof (*memspec);
338 
339 	if ((nregspec == 0) || (nregspec > TOTAL_MEM_SLOTS))
340 		return (PICL_FAILURE);
341 
342 	err = ptree_get_propval(proph, memspec, pinfo.piclinfo.size);
343 	if (err != PICL_SUCCESS)
344 		return (err);
345 
346 
347 	for (i = 0; i < nregspec; i++) {
348 
349 		mmodinfo[i].base = memspec[i].physaddr;
350 		mmodinfo[i].size = memspec[i].size;
351 
352 	}
353 
354 	return (PICL_SUCCESS);
355 }
356 
357 /*
358  * executed as part of .init when the plugin is dlopen()ed
359  */
360 static void
piclmemcfg_register(void)361 piclmemcfg_register(void)
362 {
363 	(void) picld_plugin_register(&my_reg_info);
364 }
365 
366 /*
367  * Init entry point of the plugin
368  * Creates the PICL nodes and properties in the physical and logical aspects.
369  */
370 static void
piclmemcfg_init(void)371 piclmemcfg_init(void)
372 {
373 	picl_nodehdl_t		plfh, memh;
374 	mmodinfo_t		mmodinfo[TOTAL_MEM_SLOTS];
375 
376 	/*
377 	 * Get platform node
378 	 */
379 	if ((ptree_get_node_by_path(PLATFORM_PATH, &plfh)) != PICL_SUCCESS) {
380 		syslog(LOG_ERR, EM_INIT_FAILED);
381 		return;
382 	}
383 
384 	/*
385 	 * Find the memory node
386 	 */
387 	if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) {
388 		syslog(LOG_ERR, EM_INIT_FAILED);
389 		return;
390 	}
391 
392 	/*
393 	 * Initialize the mmodinfo and get segment information from reg
394 	 */
395 	(void) memset(mmodinfo, 0, sizeof (mmodinfo));
396 
397 	if ((get_reg_info(plfh, memh, mmodinfo)) != PICL_SUCCESS) {
398 		syslog(LOG_ERR, EM_INIT_FAILED);
399 		return;
400 	}
401 
402 	/*
403 	 * Create subtree of memory-controller in the physical aspect.
404 	 * memory-controller --- memory-module
405 	 */
406 	if ((create_physical_tree(plfh, mmodinfo)) != PICL_SUCCESS)
407 		syslog(LOG_ERR, EM_PHYSIC_MEM_TREE_FAILED);
408 
409 	/*
410 	 * Create subtree of memory in the logical aspect.
411 	 * memory --- memory-segment
412 	 */
413 	if ((create_logical_tree(memh, mmodinfo)) != PICL_SUCCESS)
414 		syslog(LOG_ERR, EM_LOGIC_MEM_TREE_FAILED);
415 }
416 
417 /*
418  * fini entry point of the plugin
419  */
420 static void
piclmemcfg_fini(void)421 piclmemcfg_fini(void)
422 {
423 }
424