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 * 35 mem_alloc(size_t size) 36 { 37 return (umem_alloc(size, UMEM_DEFAULT)); 38 } 39 40 void 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 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 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 * 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 * 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 * 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 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 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 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