xref: /titanic_41/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem_mdesc.c (revision b69a86957bad202e0d4cd49e4ceb7fea54a83270)
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 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <string.h>
28 #include <umem.h>
29 #include <sys/mdesc.h>
30 #include <sys/fm/ldom.h>
31 
32 #include <mem_mdesc.h>
33 
34 void *
mem_alloc(size_t size)35 mem_alloc(size_t size)
36 {
37 	return (umem_alloc(size, UMEM_DEFAULT));
38 }
39 
40 void
mem_free(void * data,size_t size)41 mem_free(void *data, size_t size)
42 {
43 	umem_free(data, size);
44 }
45 
46 #define	MEM_BYTES_PER_CACHELINE	64
47 
48 static void
mdesc_init_n1(topo_mod_t * mod,md_t * mdp,mde_cookie_t * listp,md_mem_info_t * mem)49 mdesc_init_n1(topo_mod_t *mod, md_t *mdp, mde_cookie_t *listp,
50     md_mem_info_t *mem)
51 {
52 	int idx, mdesc_dimm_count;
53 	mem_dimm_map_t *dm, *d;
54 	uint64_t sysmem_size, i;
55 	int dimms, min_chan, max_chan, min_rank, max_rank;
56 	int chan, rank, dimm, chans, chan_step;
57 	uint64_t mask, chan_mask, chan_value;
58 	uint64_t rank_mask, rank_value;
59 	char *unum, *serial, *part;
60 	mem_seg_map_t *seg;
61 	mem_bank_map_t *bm;
62 	mem_dimm_list_t *dlp;
63 	mem_grp_t *mg;
64 	char s[20];
65 
66 	mdesc_dimm_count = md_scan_dag(mdp,
67 	    MDE_INVAL_ELEM_COOKIE, md_find_name(mdp, "dimm_data"),
68 	    md_find_name(mdp, "fwd"), listp);
69 
70 	for (idx = 0; idx < mdesc_dimm_count; idx++) {
71 
72 		if (md_get_prop_str(mdp, listp[idx], "nac", &unum) < 0)
73 			unum = "";
74 		if (md_get_prop_str(mdp, listp[idx], "serial#",
75 		    &serial) < 0)
76 			serial = "";
77 		if (md_get_prop_str(mdp, listp[idx], "part#",
78 		    &part) < 0)
79 			part = "";
80 
81 		dm = topo_mod_alloc(mod, sizeof (mem_dimm_map_t));
82 		dm->dm_label = topo_mod_strdup(mod, unum);
83 		dm->dm_serid = topo_mod_strdup(mod, serial);
84 		dm->dm_part = topo_mod_strdup(mod, part);
85 
86 		dm->dm_next = mem->mem_dm;
87 		mem->mem_dm = dm;
88 	}
89 
90 	/* N1 (MD) specific segment initialization */
91 
92 	dimms = 0;
93 	min_chan = 99;
94 	max_chan = -1;
95 	min_rank = 99;
96 	max_rank = -1;
97 
98 	for (d = mem->mem_dm; d != NULL; d = d->dm_next) {
99 		if (sscanf(d->dm_label, "MB/CMP0/CH%d/R%d/D%d",
100 		    &chan, &rank, &dimm) != 3) /* didn't scan all 3 values */
101 			return;
102 		min_chan = MIN(min_chan, chan);
103 		max_chan = MAX(max_chan, chan);
104 		min_rank = MIN(min_rank, rank);
105 		max_rank = MAX(max_rank, rank);
106 		dimms++;
107 	}
108 
109 	mdesc_dimm_count = md_scan_dag(mdp,
110 	    MDE_INVAL_ELEM_COOKIE,
111 	    md_find_name(mdp, "mblock"),
112 	    md_find_name(mdp, "fwd"),
113 	    listp);
114 	sysmem_size = 0;
115 	for (idx = 0; idx < mdesc_dimm_count; idx++) {
116 		uint64_t size = 0;
117 		if (md_get_prop_val(mdp, listp[idx], "size", &size) == 0)
118 			sysmem_size += size;
119 	}
120 
121 	for (i = 1 << 30; i < sysmem_size; i = i << 1)
122 		;
123 	if (max_rank > min_rank) {
124 		chans = dimms/4;
125 		rank_mask = i >> 1;
126 	} else {
127 		chans = dimms/2;
128 		rank_mask = 0;
129 	}
130 
131 	chan_mask = (uint64_t)((chans - 1) * MEM_BYTES_PER_CACHELINE);
132 	mask = rank_mask | chan_mask;
133 
134 	if (chans > 2)
135 		chan_step = 1;
136 	else
137 		chan_step = max_chan - min_chan;
138 
139 	seg = topo_mod_zalloc(mod, sizeof (mem_seg_map_t));
140 	seg->sm_next = mem->mem_seg;
141 	mem->mem_seg = seg;
142 	seg->sm_base = 0;
143 	seg->sm_size = sysmem_size;
144 
145 	mg = topo_mod_zalloc(mod, sizeof (mem_grp_t));
146 	seg->sm_grp = mg;
147 	mem->mem_group = mg;
148 
149 	for (rank = min_rank, rank_value = 0;
150 	    rank <= max_rank;
151 	    rank++, rank_value += rank_mask) {
152 		for (chan = min_chan, chan_value = 0;
153 		    chan <= max_chan;
154 		    chan += chan_step,
155 		    chan_value += MEM_BYTES_PER_CACHELINE) {
156 			bm = topo_mod_zalloc(mod, sizeof (mem_bank_map_t));
157 			bm->bm_mask = mask;
158 			bm->bm_match = chan_value | rank_value;
159 			bm->bm_shift = 1;
160 			bm->bm_grp = mg->mg_bank;
161 			mg->mg_bank = bm;
162 			bm->bm_next = mem->mem_bank;
163 			mem->mem_bank = bm;
164 			(void) sprintf(s, "MB/CMP0/CH%1d/R%1d", chan, rank);
165 			idx = 0;
166 			for (d = mem->mem_dm; d != NULL; d = d->dm_next) {
167 				if (strncmp(s, d->dm_label, strlen(s)) == 0) {
168 					dlp = topo_mod_zalloc(mod,
169 					    sizeof (mem_dimm_list_t));
170 					dlp->dl_next = bm->bm_dlist;
171 					bm->bm_dlist = dlp;
172 					dlp->dl_dimm = d;
173 				}
174 			}
175 		}
176 	}
177 }
178 
179 uint16_t
mem_log2(uint64_t v)180 mem_log2(uint64_t v)
181 {
182 	uint16_t i;
183 	for (i = 0; v > 1; i++) {
184 		v = v >> 1;
185 	}
186 	return (i);
187 }
188 
189 mem_dimm_map_t *
mem_get_dimm_by_sn(char * sn,md_mem_info_t * mem)190 mem_get_dimm_by_sn(char *sn, md_mem_info_t *mem)
191 {
192 	mem_dimm_map_t *dp;
193 
194 	for (dp = mem->mem_dm; dp != NULL; dp = dp->dm_next) {
195 		if (strcmp(sn, dp->dm_serid) == 0)
196 			return (dp);
197 	}
198 	return (NULL);
199 }
200 
201 mem_grp_t *
find_grp(mde_cookie_t * listp,size_t n,mde_cookie_t * bclist,mem_bank_map_t ** banklist,size_t mem_bank_count,md_mem_info_t * mem)202 find_grp(mde_cookie_t *listp, size_t n, mde_cookie_t *bclist,
203     mem_bank_map_t **banklist, size_t mem_bank_count, md_mem_info_t *mem) {
204 
205 	mem_grp_t *mg;
206 	mem_bank_map_t *bp;
207 	size_t i, j;
208 	int err;
209 
210 	for (mg = mem->mem_group; mg != NULL; mg = mg->mg_next) {
211 		if (mg->mg_size == n) {
212 			err = 0;
213 			for (i = 0, bp = mg->mg_bank;
214 			    i < n && bp != NULL;
215 			    i++, bp = bp->bm_grp) {
216 				for (j = 0; j < mem_bank_count; j++) {
217 					if (listp[i] == *(bclist+j) &&
218 					    bp == *(banklist+j))
219 						break;
220 				}
221 				if (bp == NULL) err++;
222 			}
223 		}
224 		else
225 			err++;
226 		if (err == 0)
227 			return (mg);
228 	}
229 	return (NULL);
230 }
231 
232 mem_grp_t *
create_grp(topo_mod_t * mod,mde_cookie_t * listp,size_t n,mde_cookie_t * bclist,mem_bank_map_t ** banklist,size_t mem_bank_count,md_mem_info_t * mem)233 create_grp(topo_mod_t *mod, mde_cookie_t *listp, size_t n, mde_cookie_t *bclist,
234     mem_bank_map_t **banklist, size_t mem_bank_count, md_mem_info_t *mem) {
235 
236 	mem_grp_t *mg;
237 	size_t i, j;
238 
239 	mg = topo_mod_zalloc(mod, sizeof (mem_grp_t));
240 	mg->mg_size = n;
241 	mg->mg_next = mem->mem_group;
242 	mem->mem_group = mg;
243 
244 	for (i = 0; i < n; i++) {
245 		for (j = 0; j < mem_bank_count; j++) {
246 			if (listp[i] == *(bclist+j)) {
247 				(*(banklist+j))->bm_grp = mg->mg_bank;
248 				mg->mg_bank = *(banklist+j);
249 			}
250 		}
251 	}
252 	return (mg);
253 }
254 
255 static void
mdesc_init_n2(topo_mod_t * mod,md_t * mdp,mde_cookie_t * listp,md_mem_info_t * mem,int num_comps)256 mdesc_init_n2(topo_mod_t *mod, md_t *mdp, mde_cookie_t *listp,
257     md_mem_info_t *mem, int num_comps)
258 {
259 	mde_cookie_t *dl, *bl, *bclist;
260 	int bc, idx, mdesc_dimm_count, mdesc_bank_count;
261 	mem_dimm_map_t *dm, **dp;
262 	uint64_t i;
263 	int n;
264 	uint64_t mask, match, base, size;
265 	char *unum, *serial, *part, *dash;
266 	mem_seg_map_t *smp;
267 	mem_bank_map_t *bmp, **banklist;
268 	mem_dimm_list_t *dlp;
269 	mem_grp_t *gmp;
270 	char *type, *sp, *jnum, *nac;
271 	size_t ss;
272 
273 	mdesc_dimm_count = 0;
274 	for (idx = 0; idx < num_comps; idx++) {
275 		if (md_get_prop_str(mdp, listp[idx], "type", &type) < 0)
276 			continue;
277 		if ((strcmp(type, "dimm") == 0) ||
278 		    (strcmp(type, "mem-board") == 0) ||
279 		    (strcmp(type, "memboard") == 0)) {
280 			mdesc_dimm_count++;
281 			if (md_get_prop_str(mdp, listp[idx], "nac",
282 			    &nac) < 0)
283 				nac = "";
284 			if (md_get_prop_str(mdp, listp[idx], "label",
285 			    &jnum) < 0)
286 				jnum = "";
287 			if (md_get_prop_str(mdp, listp[idx],
288 			    "serial_number", &serial) < 0)
289 				serial = "";
290 			if (md_get_prop_str(mdp, listp[idx],
291 			    "part_number", &part) < 0)
292 				part = "";
293 			if (md_get_prop_str(mdp, listp[idx],
294 			    "dash_number", &dash) < 0)
295 				dash = "";
296 
297 			ss = strlen(part) + strlen(dash) + 1;
298 			sp = topo_mod_alloc(mod, ss);
299 			sp = strcpy(sp, part);
300 			sp = strncat(sp, dash, strlen(dash) + 1);
301 
302 			dm = topo_mod_alloc(mod, sizeof (mem_dimm_map_t));
303 
304 			if ((strcmp(nac, "") != 0) &&
305 			    (strcmp(jnum, "") != 0)) {
306 				ss = strlen(nac) + strlen(jnum) + 2;
307 				unum = topo_mod_alloc(mod, ss);
308 				(void) snprintf(unum, ss, "%s/%s", nac,
309 				    jnum);
310 				dm->dm_label = unum;
311 			} else {
312 				unum = nac;
313 				dm->dm_label = topo_mod_strdup(mod, unum);
314 			}
315 
316 			dm->dm_serid = topo_mod_strdup(mod, serial);
317 			dm->dm_part = sp;
318 
319 			/* The following is an insertion sort. */
320 
321 			for (dp = &(mem->mem_dm); ; dp = &((*dp)->dm_next)) {
322 				if ((*dp == NULL) ||
323 				    (strcmp((*dp)->dm_label,
324 				    dm->dm_label) > 0)) {
325 					dm->dm_next = *dp;
326 					*dp = dm;
327 					break;
328 				}
329 			}
330 		}
331 	}
332 
333 	/* N2 (PRI) specific segment initialization occurs here */
334 
335 	mdesc_bank_count = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
336 	    md_find_name(mdp, "memory-bank"),
337 	    md_find_name(mdp, "fwd"),
338 	    listp);
339 
340 	/*
341 	 * banklist and bclist will be parallel arrays.  For a given bank,
342 	 * bclist[i] will be the PRI node id, and *banklist+i will point to the
343 	 * mem_bank_map_t for that bank.
344 	 */
345 
346 	banklist = topo_mod_zalloc(mod, mdesc_bank_count *
347 	    sizeof (mem_bank_map_t *));
348 	bclist = topo_mod_zalloc(mod, mdesc_bank_count *
349 	    sizeof (mde_cookie_t));
350 
351 	dl = topo_mod_zalloc(mod, mdesc_dimm_count * sizeof (mde_cookie_t));
352 
353 	for (idx = 0; idx < mdesc_bank_count; idx++) {
354 		if (md_get_prop_val(mdp, listp[idx], "mask", &mask) < 0)
355 			mask = 0;
356 		if (md_get_prop_val(mdp, listp[idx], "match", &match) < 0)
357 			match = 0;
358 
359 		bmp = topo_mod_zalloc(mod, sizeof (mem_bank_map_t));
360 		bmp->bm_next = mem->mem_bank;
361 		mem->mem_bank = bmp;
362 		bmp->bm_mask = mask;
363 		bmp->bm_match = match;
364 		/* link this bank to its dimms */
365 		n = md_scan_dag(mdp, listp[idx],
366 		    md_find_name(mdp, "component"),
367 		    md_find_name(mdp, "fwd"),
368 		    dl);
369 		bmp->bm_shift = mem_log2(n);
370 
371 		bclist[idx] = listp[idx];
372 		*(banklist+idx) = bmp;
373 
374 		for (i = 0; i < n; i++) {
375 			if (md_get_prop_str(mdp, dl[i],
376 			    "serial_number", &serial) < 0)
377 				continue;
378 			if ((dm = mem_get_dimm_by_sn(serial, mem)) == NULL)
379 				continue;
380 			dlp = topo_mod_zalloc(mod, sizeof (mem_dimm_list_t));
381 			dlp->dl_next = bmp->bm_dlist;
382 			bmp->bm_dlist = dlp;
383 			dlp->dl_dimm = dm;
384 		}
385 	}
386 	topo_mod_free(mod, dl, mdesc_dimm_count * sizeof (mde_cookie_t));
387 
388 	bl = topo_mod_zalloc(mod, mdesc_bank_count * sizeof (mde_cookie_t));
389 	n = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
390 	    md_find_name(mdp, "memory-segment"),
391 	    md_find_name(mdp, "fwd"),
392 	    listp);
393 	for (idx = 0; idx < n; idx++) {
394 		if (md_get_prop_val(mdp, listp[idx], "base", &base) < 0)
395 			base = 0;
396 		if (md_get_prop_val(mdp, listp[idx], "size", &size) < 0)
397 			size = 0;
398 		bc = md_scan_dag(mdp, listp[idx],
399 		    md_find_name(mdp, "memory-bank"),
400 		    md_find_name(mdp, "fwd"),
401 		    bl);
402 		smp = topo_mod_zalloc(mod, sizeof (mem_seg_map_t));
403 		smp->sm_next = mem->mem_seg;
404 		mem->mem_seg = smp;
405 		smp->sm_base = base;
406 		smp->sm_size = size;
407 		gmp = find_grp(bl, bc, bclist, banklist, mdesc_bank_count, mem);
408 		if (gmp == NULL)
409 			smp->sm_grp = create_grp(mod, bl, bc,
410 			    bclist, banklist, mdesc_bank_count, mem);
411 		else
412 			smp->sm_grp = gmp;
413 	}
414 	topo_mod_free(mod, bl, mdesc_bank_count * sizeof (mde_cookie_t));
415 	topo_mod_free(mod, bclist, mdesc_bank_count * sizeof (mde_cookie_t));
416 	topo_mod_free(mod, banklist,
417 	    mdesc_bank_count * sizeof (mem_bank_map_t *));
418 }
419 
420 int
mem_mdesc_init(topo_mod_t * mod,md_mem_info_t * mem)421 mem_mdesc_init(topo_mod_t *mod, md_mem_info_t *mem)
422 {
423 	int rc = 0;
424 	md_t *mdp;
425 	ssize_t bufsiz = 0;
426 	uint64_t *bufp;
427 	ldom_hdl_t *lhp;
428 	mde_cookie_t *listp;
429 	int num_nodes;
430 	int num_comps = 0;
431 	uint32_t type = 0;
432 
433 	/* get the PRI/MD */
434 	if ((lhp = ldom_init(mem_alloc, mem_free)) == NULL) {
435 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
436 	}
437 	(void) ldom_get_type(lhp, &type);
438 	if ((type & LDOM_TYPE_CONTROL) != 0) {
439 		bufsiz = ldom_get_core_md(lhp, &bufp);
440 	} else {
441 		bufsiz = ldom_get_local_md(lhp, &bufp);
442 	}
443 	if (bufsiz <= 0) {
444 		topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
445 		ldom_fini(lhp);
446 		return (-1);
447 	}
448 
449 	if ((mdp = md_init_intern(bufp, mem_alloc, mem_free)) == NULL ||
450 	    md_node_count(mdp) <= 0) {
451 		mem_free(bufp, (size_t)bufsiz);
452 		ldom_fini(lhp);
453 		return (-1);
454 	}
455 
456 	num_nodes = md_node_count(mdp);
457 	listp = mem_alloc(sizeof (mde_cookie_t) * num_nodes);
458 
459 	num_comps = md_scan_dag(mdp,
460 	    MDE_INVAL_ELEM_COOKIE,
461 	    md_find_name(mdp, "component"),
462 	    md_find_name(mdp, "fwd"),
463 	    listp);
464 	if (num_comps == 0)
465 		mdesc_init_n1(mod, mdp, listp, mem);
466 	else
467 		mdesc_init_n2(mod, mdp, listp, mem, num_comps);
468 
469 	mem_free(listp, sizeof (mde_cookie_t) * num_nodes);
470 
471 	mem_free(bufp, (size_t)bufsiz);
472 	(void) md_fini(mdp);
473 	ldom_fini(lhp);
474 
475 	return (rc);
476 }
477 
478 void
mem_mdesc_fini(topo_mod_t * mod,md_mem_info_t * mem)479 mem_mdesc_fini(topo_mod_t *mod, md_mem_info_t *mem)
480 {
481 	mem_dimm_map_t *dm, *next;
482 	mem_dimm_list_t *dl, *nl;
483 	mem_bank_map_t *bm, *cm;
484 	mem_grp_t *gm, *hm;
485 	mem_seg_map_t *sm, *snext;
486 
487 	for (dm = mem->mem_dm; dm != NULL; dm = next) {
488 		next = dm->dm_next;
489 		topo_mod_strfree(mod, dm->dm_label);
490 		topo_mod_strfree(mod, dm->dm_serid);
491 		topo_mod_strfree(mod, dm->dm_part);
492 		topo_mod_free(mod, dm, sizeof (mem_dimm_map_t));
493 	}
494 	for (bm = mem->mem_bank; bm != NULL; bm = cm) {
495 		for (dl = bm->bm_dlist; dl != NULL; dl = nl) {
496 			nl = dl->dl_next;
497 			topo_mod_free(mod, dl, sizeof (mem_dimm_list_t));
498 		}
499 		cm = bm->bm_next;
500 		topo_mod_free(mod, bm, sizeof (mem_bank_map_t));
501 	}
502 	for (gm = mem->mem_group; gm != NULL; gm = hm) {
503 		hm = gm->mg_next;
504 		topo_mod_free(mod, gm, sizeof (mem_grp_t));
505 	}
506 	for (sm = mem->mem_seg; sm != NULL; sm = snext) {
507 		snext = sm->sm_next;
508 		topo_mod_free(mod, sm, sizeof (mem_seg_map_t));
509 	}
510 }
511