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