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