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 err = 0;
211 for (mg = mem->mem_group; mg != NULL; mg = mg->mg_next) {
212 if (mg->mg_size == n) {
213 err = 0;
214 for (i = 0, bp = mg->mg_bank;
215 i < n && bp != NULL;
216 i++, bp = bp->bm_grp) {
217 for (j = 0; j < mem_bank_count; j++) {
218 if (listp[i] == *(bclist+j) &&
219 bp == *(banklist+j))
220 break;
221 }
222 if (bp == NULL) err++;
223 }
224 } else {
225 err++;
226 }
227 if (err == 0)
228 return (mg);
229 }
230 return (NULL);
231 }
232
233 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)234 create_grp(topo_mod_t *mod, mde_cookie_t *listp, size_t n, mde_cookie_t *bclist,
235 mem_bank_map_t **banklist, size_t mem_bank_count, md_mem_info_t *mem)
236 {
237 mem_grp_t *mg;
238 size_t i, j;
239
240 mg = topo_mod_zalloc(mod, sizeof (mem_grp_t));
241 mg->mg_size = n;
242 mg->mg_next = mem->mem_group;
243 mem->mem_group = mg;
244
245 for (i = 0; i < n; i++) {
246 for (j = 0; j < mem_bank_count; j++) {
247 if (listp[i] == *(bclist+j)) {
248 (*(banklist+j))->bm_grp = mg->mg_bank;
249 mg->mg_bank = *(banklist+j);
250 }
251 }
252 }
253 return (mg);
254 }
255
256 static void
mdesc_init_n2(topo_mod_t * mod,md_t * mdp,mde_cookie_t * listp,md_mem_info_t * mem,int num_comps)257 mdesc_init_n2(topo_mod_t *mod, md_t *mdp, mde_cookie_t *listp,
258 md_mem_info_t *mem, int num_comps)
259 {
260 mde_cookie_t *dl, *bl, *bclist;
261 int bc, idx, mdesc_dimm_count, mdesc_bank_count;
262 mem_dimm_map_t *dm, **dp;
263 uint64_t i;
264 int n;
265 uint64_t mask, match, base, size;
266 char *unum, *serial, *part, *dash;
267 mem_seg_map_t *smp;
268 mem_bank_map_t *bmp, **banklist;
269 mem_dimm_list_t *dlp;
270 mem_grp_t *gmp;
271 char *type, *sp, *jnum, *nac;
272 size_t ss;
273
274 mdesc_dimm_count = 0;
275 for (idx = 0; idx < num_comps; idx++) {
276 if (md_get_prop_str(mdp, listp[idx], "type", &type) < 0)
277 continue;
278 if ((strcmp(type, "dimm") == 0) ||
279 (strcmp(type, "mem-board") == 0) ||
280 (strcmp(type, "memboard") == 0)) {
281 mdesc_dimm_count++;
282 if (md_get_prop_str(mdp, listp[idx], "nac",
283 &nac) < 0)
284 nac = "";
285 if (md_get_prop_str(mdp, listp[idx], "label",
286 &jnum) < 0)
287 jnum = "";
288 if (md_get_prop_str(mdp, listp[idx],
289 "serial_number", &serial) < 0)
290 serial = "";
291 if (md_get_prop_str(mdp, listp[idx],
292 "part_number", &part) < 0)
293 part = "";
294 if (md_get_prop_str(mdp, listp[idx],
295 "dash_number", &dash) < 0)
296 dash = "";
297
298 ss = strlen(part) + strlen(dash) + 1;
299 sp = topo_mod_alloc(mod, ss);
300 sp = strcpy(sp, part);
301 sp = strncat(sp, dash, strlen(dash) + 1);
302
303 dm = topo_mod_alloc(mod, sizeof (mem_dimm_map_t));
304
305 if ((strcmp(nac, "") != 0) &&
306 (strcmp(jnum, "") != 0)) {
307 ss = strlen(nac) + strlen(jnum) + 2;
308 unum = topo_mod_alloc(mod, ss);
309 (void) snprintf(unum, ss, "%s/%s", nac,
310 jnum);
311 dm->dm_label = unum;
312 } else {
313 unum = nac;
314 dm->dm_label = topo_mod_strdup(mod, unum);
315 }
316
317 dm->dm_serid = topo_mod_strdup(mod, serial);
318 dm->dm_part = sp;
319
320 /* The following is an insertion sort. */
321
322 for (dp = &(mem->mem_dm); ; dp = &((*dp)->dm_next)) {
323 if ((*dp == NULL) ||
324 (strcmp((*dp)->dm_label,
325 dm->dm_label) > 0)) {
326 dm->dm_next = *dp;
327 *dp = dm;
328 break;
329 }
330 }
331 }
332 }
333
334 /* N2 (PRI) specific segment initialization occurs here */
335
336 mdesc_bank_count = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
337 md_find_name(mdp, "memory-bank"),
338 md_find_name(mdp, "fwd"),
339 listp);
340
341 /*
342 * banklist and bclist will be parallel arrays. For a given bank,
343 * bclist[i] will be the PRI node id, and *banklist+i will point to the
344 * mem_bank_map_t for that bank.
345 */
346
347 banklist = topo_mod_zalloc(mod, mdesc_bank_count *
348 sizeof (mem_bank_map_t *));
349 bclist = topo_mod_zalloc(mod, mdesc_bank_count *
350 sizeof (mde_cookie_t));
351
352 dl = topo_mod_zalloc(mod, mdesc_dimm_count * sizeof (mde_cookie_t));
353
354 for (idx = 0; idx < mdesc_bank_count; idx++) {
355 if (md_get_prop_val(mdp, listp[idx], "mask", &mask) < 0)
356 mask = 0;
357 if (md_get_prop_val(mdp, listp[idx], "match", &match) < 0)
358 match = 0;
359
360 bmp = topo_mod_zalloc(mod, sizeof (mem_bank_map_t));
361 bmp->bm_next = mem->mem_bank;
362 mem->mem_bank = bmp;
363 bmp->bm_mask = mask;
364 bmp->bm_match = match;
365 /* link this bank to its dimms */
366 n = md_scan_dag(mdp, listp[idx],
367 md_find_name(mdp, "component"),
368 md_find_name(mdp, "fwd"),
369 dl);
370 bmp->bm_shift = mem_log2(n);
371
372 bclist[idx] = listp[idx];
373 *(banklist+idx) = bmp;
374
375 for (i = 0; i < n; i++) {
376 if (md_get_prop_str(mdp, dl[i],
377 "serial_number", &serial) < 0)
378 continue;
379 if ((dm = mem_get_dimm_by_sn(serial, mem)) == NULL)
380 continue;
381 dlp = topo_mod_zalloc(mod, sizeof (mem_dimm_list_t));
382 dlp->dl_next = bmp->bm_dlist;
383 bmp->bm_dlist = dlp;
384 dlp->dl_dimm = dm;
385 }
386 }
387 topo_mod_free(mod, dl, mdesc_dimm_count * sizeof (mde_cookie_t));
388
389 bl = topo_mod_zalloc(mod, mdesc_bank_count * sizeof (mde_cookie_t));
390 n = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
391 md_find_name(mdp, "memory-segment"),
392 md_find_name(mdp, "fwd"),
393 listp);
394 for (idx = 0; idx < n; idx++) {
395 if (md_get_prop_val(mdp, listp[idx], "base", &base) < 0)
396 base = 0;
397 if (md_get_prop_val(mdp, listp[idx], "size", &size) < 0)
398 size = 0;
399 bc = md_scan_dag(mdp, listp[idx],
400 md_find_name(mdp, "memory-bank"),
401 md_find_name(mdp, "fwd"),
402 bl);
403 smp = topo_mod_zalloc(mod, sizeof (mem_seg_map_t));
404 smp->sm_next = mem->mem_seg;
405 mem->mem_seg = smp;
406 smp->sm_base = base;
407 smp->sm_size = size;
408 gmp = find_grp(bl, bc, bclist, banklist, mdesc_bank_count, mem);
409 if (gmp == NULL)
410 smp->sm_grp = create_grp(mod, bl, bc,
411 bclist, banklist, mdesc_bank_count, mem);
412 else
413 smp->sm_grp = gmp;
414 }
415 topo_mod_free(mod, bl, mdesc_bank_count * sizeof (mde_cookie_t));
416 topo_mod_free(mod, bclist, mdesc_bank_count * sizeof (mde_cookie_t));
417 topo_mod_free(mod, banklist,
418 mdesc_bank_count * sizeof (mem_bank_map_t *));
419 }
420
421 int
mem_mdesc_init(topo_mod_t * mod,md_mem_info_t * mem)422 mem_mdesc_init(topo_mod_t *mod, md_mem_info_t *mem)
423 {
424 int rc = 0;
425 md_t *mdp;
426 ssize_t bufsiz = 0;
427 uint64_t *bufp;
428 ldom_hdl_t *lhp;
429 mde_cookie_t *listp;
430 int num_nodes;
431 int num_comps = 0;
432 uint32_t type = 0;
433
434 /* get the PRI/MD */
435 if ((lhp = ldom_init(mem_alloc, mem_free)) == NULL) {
436 return (topo_mod_seterrno(mod, EMOD_NOMEM));
437 }
438 (void) ldom_get_type(lhp, &type);
439 if ((type & LDOM_TYPE_CONTROL) != 0) {
440 bufsiz = ldom_get_core_md(lhp, &bufp);
441 } else {
442 bufsiz = ldom_get_local_md(lhp, &bufp);
443 }
444 if (bufsiz <= 0) {
445 topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
446 ldom_fini(lhp);
447 return (-1);
448 }
449
450 if ((mdp = md_init_intern(bufp, mem_alloc, mem_free)) == NULL ||
451 md_node_count(mdp) <= 0) {
452 mem_free(bufp, (size_t)bufsiz);
453 ldom_fini(lhp);
454 return (-1);
455 }
456
457 num_nodes = md_node_count(mdp);
458 listp = mem_alloc(sizeof (mde_cookie_t) * num_nodes);
459
460 num_comps = md_scan_dag(mdp,
461 MDE_INVAL_ELEM_COOKIE,
462 md_find_name(mdp, "component"),
463 md_find_name(mdp, "fwd"),
464 listp);
465 if (num_comps == 0)
466 mdesc_init_n1(mod, mdp, listp, mem);
467 else
468 mdesc_init_n2(mod, mdp, listp, mem, num_comps);
469
470 mem_free(listp, sizeof (mde_cookie_t) * num_nodes);
471
472 mem_free(bufp, (size_t)bufsiz);
473 (void) md_fini(mdp);
474 ldom_fini(lhp);
475
476 return (rc);
477 }
478
479 void
mem_mdesc_fini(topo_mod_t * mod,md_mem_info_t * mem)480 mem_mdesc_fini(topo_mod_t *mod, md_mem_info_t *mem)
481 {
482 mem_dimm_map_t *dm, *next;
483 mem_dimm_list_t *dl, *nl;
484 mem_bank_map_t *bm, *cm;
485 mem_grp_t *gm, *hm;
486 mem_seg_map_t *sm, *snext;
487
488 for (dm = mem->mem_dm; dm != NULL; dm = next) {
489 next = dm->dm_next;
490 topo_mod_strfree(mod, dm->dm_label);
491 topo_mod_strfree(mod, dm->dm_serid);
492 topo_mod_strfree(mod, dm->dm_part);
493 topo_mod_free(mod, dm, sizeof (mem_dimm_map_t));
494 }
495 for (bm = mem->mem_bank; bm != NULL; bm = cm) {
496 for (dl = bm->bm_dlist; dl != NULL; dl = nl) {
497 nl = dl->dl_next;
498 topo_mod_free(mod, dl, sizeof (mem_dimm_list_t));
499 }
500 cm = bm->bm_next;
501 topo_mod_free(mod, bm, sizeof (mem_bank_map_t));
502 }
503 for (gm = mem->mem_group; gm != NULL; gm = hm) {
504 hm = gm->mg_next;
505 topo_mod_free(mod, gm, sizeof (mem_grp_t));
506 }
507 for (sm = mem->mem_seg; sm != NULL; sm = snext) {
508 snext = sm->sm_next;
509 topo_mod_free(mod, sm, sizeof (mem_seg_map_t));
510 }
511 }
512