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