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