xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4v/pri/mem_prop_update.c (revision 0d63ce2b32a9e1cc8ed71d4d92536c44d66a530a)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * The PRI plug-in picks up memory configuration data from the PRI
28  * and injects this into PICL's /platform tree.  It only populates
29  * the logical view of memory: memory, memory-segment, memory-bank.
30  * It does not populate the /device tree since there are no memory
31  * controller devices on sun4v.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include "priplugin.h"
37 #include "../../common/memcfg/piclmemcfg.h"
38 
39 /*
40  * These 3 variable are defined and set in mdescplugin.c
41  */
42 extern picl_nodehdl_t	root_node;
43 extern md_t		*mdp;
44 extern mde_cookie_t	rootnode;
45 
46 static void
47 add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, uint64_t size);
48 
49 static void
50 add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp,
51 	uint64_t *size, uint64_t *mask, unsigned int id);
52 static uint64_t countbits(uint64_t v);
53 
54 static void
55 add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
56 	uint64_t interleave, uint64_t *size, uint64_t base);
57 
58 /*
59  * Callback function for picl_walk_tree_by_class().
60  * NOTE: picl_walk_tree_by_class() maps the return codes PICL_WALK_CONTINUE
61  * and PICL_WALK_TERMINATE to PICL_SUCCESS.
62  */
63 int
64 add_mem_prop(picl_nodehdl_t node, void *args)
65 {
66 	mde_cookie_t *memorylistp, *segmentlistp, *banklistp;
67 	picl_prophdl_t memh, segmenth, bankh;
68 	mde_cookie_t *buf;
69 	int j, k, num_nodes, interleave, err;
70 	int nsegments, nbanks, nmemory;
71 	uint64_t memsize, segsize, segbase;
72 	uint64_t size, mask;
73 
74 	/*
75 	 * An absence of nodes or failure to obtain memory for searches
76 	 * or absence of the /memory node will cause this to fail.
77 	 * Return PICL_WALK_SUCCESS to allow the plug-in to continue.
78 	 */
79 	num_nodes = md_node_count(mdp);
80 	if (num_nodes == 0) {
81 		pri_debug(LOG_NOTICE, "add_mem_prop: no nodes to walk\n");
82 		return (PICL_SUCCESS);
83 	}
84 	buf = (mde_cookie_t *)malloc(sizeof (mde_cookie_t) * num_nodes * 3);
85 	if (buf == NULL) {
86 		pri_debug(LOG_NOTICE, "add_mem_prop: can't allocate memory\n");
87 		return (PICL_SUCCESS);
88 	}
89 
90 	memorylistp = &buf[0];
91 	segmentlistp = &buf[num_nodes];
92 	banklistp = &buf[num_nodes * 2];
93 
94 	if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) {
95 		pri_debug(LOG_NOTICE,
96 		    "add_mem_prop: can't find /memory node in platform tree\n");
97 		free(buf);
98 		return (PICL_SUCCESS);
99 	}
100 
101 	/*
102 	 * There should be only one memory node.
103 	 * If we can't find what we're looking for in the DAG then
104 	 * return PICL_PROPNOTFOUND to get the caller to re-try with
105 	 * a different property name.
106 	 */
107 	nmemory = md_scan_dag(mdp, rootnode, md_find_name(mdp, args),
108 	    md_find_name(mdp, "fwd"), memorylistp);
109 	if (nmemory != 1) {
110 		pri_debug(LOG_NOTICE,
111 		    "add_mem_prop: wrong number of memory dags: expected "
112 		    "1, got %d\n", nmemory);
113 		free(buf);
114 		return (PICL_PROPNOTFOUND);
115 	}
116 
117 	nsegments = md_scan_dag(mdp, memorylistp[0],
118 	    md_find_name(mdp, "memory-segment"),
119 	    md_find_name(mdp, "fwd"),
120 	    segmentlistp);
121 
122 	if (nsegments == 0) {
123 		pri_debug(LOG_NOTICE, "add_mem_prop: wrong number of memory "
124 		    "segments: expected >0, got %d\n", nsegments);
125 		free(buf);
126 		return (PICL_PROPNOTFOUND);
127 	}
128 
129 	/*
130 	 * Add memory segments, keep running total of system memory.
131 	 */
132 	for (memsize = 0, segsize = 0, j = 0; j < nsegments;
133 	    ++j, memsize += segsize) {
134 		nbanks = 0;
135 		err = ptree_create_and_add_node(memh,
136 		    PICL_NAME_MEMORY_SEGMENT,
137 		    PICL_CLASS_MEMORY_SEGMENT, &segmenth);
138 		if (err == PICL_SUCCESS) {
139 			size = 0;
140 			mask = 0;
141 
142 			/*
143 			 * Need to pull this out here since it's used for
144 			 * the ID.
145 			 */
146 			if (md_get_prop_val(mdp, segmentlistp[j], "base",
147 			    &segbase))
148 				segbase = 0ULL;
149 
150 			/*
151 			 * Add banks under each segment.
152 			 */
153 			nbanks = md_scan_dag(mdp, segmentlistp[j],
154 			    md_find_name(mdp, "memory-bank"),
155 			    md_find_name(mdp, "fwd"),
156 			    banklistp);
157 
158 			if (nbanks <= 0) {
159 				pri_debug(LOG_NOTICE, "add_mem_prop: no banks "
160 				    "found for segment %d\n", j);
161 			} else {
162 				for (k = 0; k < nbanks; ++k) {
163 					err =
164 					    ptree_create_and_add_node(segmenth,
165 					    PICL_NAME_MEMORY_BANK,
166 					    PICL_CLASS_MEMORY_BANK, &bankh);
167 					if (err == PICL_SUCCESS) {
168 						/*
169 						 * Add AddressMatch,
170 						 * AddressMask, Size, and
171 						 * ID to each bank.
172 						 */
173 						add_bank_props(bankh,
174 						    banklistp[k],
175 						    &size, &mask,
176 						    (segbase >> 32) * j + k);
177 					}
178 				}
179 			}
180 		}
181 
182 		/*
183 		 * Add Interleave, BaseAddress, and Size to each segment.
184 		 */
185 		interleave = 2 << (countbits(mask & (size - 1)) - 1);
186 		add_segment_props(segmenth, segmentlistp[j],
187 			interleave, &segsize, segbase);
188 	}
189 
190 	/*
191 	 * Add TransferSize and Size (total memory) to this node.
192 	 */
193 	add_memory_props(memh, memorylistp[0], memsize);
194 
195 	free(buf);
196 	return (PICL_WALK_CONTINUE);
197 }
198 
199 static void
200 add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp,
201 	uint64_t *size, uint64_t *mask, unsigned int id)
202 {
203 	uint64_t int_value;
204 	mde_cookie_t *dimmlistp;
205 	int node_count, i, type_size, nac_size, status;
206 	uint8_t *type;
207 	char *pc, *nac;
208 
209 	*size = 0ULL;
210 	*mask = 0ULL;
211 
212 	node_count = md_node_count(mdp);
213 	dimmlistp = (mde_cookie_t *)malloc(node_count * sizeof (mde_cookie_t));
214 
215 	if (!md_get_prop_val(mdp, banklistp, "size", &int_value)) {
216 		add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE,
217 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
218 		*size = int_value;
219 	}
220 	if (!md_get_prop_val(mdp, banklistp, "mask",
221 	    &int_value)) {
222 		add_md_prop(node, sizeof (int_value),
223 		    PICL_PROP_ADDRESSMASK,
224 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
225 		*mask = int_value;
226 	}
227 	if (!md_get_prop_val(mdp, banklistp, "match",
228 	    &int_value)) {
229 		add_md_prop(node, sizeof (int_value),
230 		    PICL_PROP_ADDRESSMATCH,
231 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
232 	}
233 
234 	add_md_prop(node, sizeof (id), PICL_PROP_ID, &id,
235 	    PICL_PTYPE_INT);
236 
237 	node_count = md_scan_dag(mdp, banklistp, md_find_name(mdp, "component"),
238 	    md_find_name(mdp, "fwd"), dimmlistp);
239 
240 	for (i = 0; i < node_count; ++i) {
241 		if ((status = md_get_prop_str(mdp, dimmlistp[i], "type",
242 		    (char **)&type)) == -1) {
243 			status = md_get_prop_data(mdp, dimmlistp[i],
244 			    "type", &type, &type_size);
245 		}
246 		if (status == 0) {
247 			if (strcmp((const char *)type, "dimm") == 0) {
248 				if (!md_get_prop_str(mdp, dimmlistp[i], "nac",
249 				    (char **)&nac)) {
250 					nac_size = strlen(nac) + 1;
251 					add_md_prop(node, nac_size,
252 					    "nac", nac,
253 					    PICL_PTYPE_CHARSTRING);
254 					if ((pc = strrchr(nac, '/')) != NULL)
255 						nac = ++pc;
256 					nac_size = strlen(nac) + 1;
257 					add_md_prop(node, nac_size,
258 					    PICL_PROP_LABEL, nac,
259 					    PICL_PTYPE_CHARSTRING);
260 				}
261 			}
262 		}
263 	}
264 }
265 
266 static uint64_t
267 countbits(uint64_t v)
268 {
269 	uint64_t c;	/* c accumulates the total bits set in v */
270 
271 	for (c = 0; v; c++)
272 		v &= v - 1;	/* clear the least significant bit set */
273 	return (c);
274 }
275 
276 static void
277 add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
278     uint64_t interleave, uint64_t *size, uint64_t base)
279 {
280 	uint64_t int_value;
281 
282 	*size = 0;
283 	if (!md_get_prop_val(mdp, segmentlistp, "size", &int_value)) {
284 		add_md_prop(node, sizeof (int_value),
285 		    PICL_PROP_SIZE, &int_value,
286 		    PICL_PTYPE_UNSIGNED_INT);
287 		*size = int_value;
288 	}
289 	add_md_prop(node, sizeof (base), PICL_PROP_BASEADDRESS,
290 		&base, PICL_PTYPE_UNSIGNED_INT);
291 
292 	add_md_prop(node, sizeof (interleave), PICL_PROP_INTERLEAVE_FACTOR,
293 		&interleave, PICL_PTYPE_UNSIGNED_INT);
294 }
295 
296 static void
297 add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, uint64_t size)
298 {
299 	uint64_t int_value;
300 
301 	/*
302 	 * If the top-level node has a size property then use that,
303 	 * otherwise use the size that was calculated by the caller
304 	 * and passed in.
305 	 */
306 	if (md_get_prop_val(mdp, memorylistp, "size", &int_value))
307 		int_value = size;
308 	add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, &int_value,
309 		PICL_PTYPE_UNSIGNED_INT);
310 	if (!md_get_prop_val(mdp, memorylistp, "transfer_size",
311 	    &int_value)) {
312 		add_md_prop(node, sizeof (int_value),
313 		    PICL_PROP_TRANSFER_SIZE,
314 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
315 	}
316 }
317