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 md_t *mdp; 44 extern mde_cookie_t rootnode; 45 46 static void 47 add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, uint64_t size); 48 49 static void 50 add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp, 51 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 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 74 /* 75 * An absence of nodes or failure to obtain memory for searches 76 * or absence of the /memory node will cause this to fail. 77 * Return PICL_WALK_SUCCESS to allow the plug-in to continue. 78 */ 79 num_nodes = md_node_count(mdp); 80 if (num_nodes == 0) { 81 pri_debug(LOG_NOTICE, "add_mem_prop: no nodes to walk\n"); 82 return (PICL_SUCCESS); 83 } 84 buf = (mde_cookie_t *)malloc(sizeof (mde_cookie_t) * num_nodes * 3); 85 if (buf == NULL) { 86 pri_debug(LOG_NOTICE, "add_mem_prop: can't allocate memory\n"); 87 return (PICL_SUCCESS); 88 } 89 90 memorylistp = &buf[0]; 91 segmentlistp = &buf[num_nodes]; 92 banklistp = &buf[num_nodes * 2]; 93 94 if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) { 95 pri_debug(LOG_NOTICE, 96 "add_mem_prop: can't find /memory node in platform tree\n"); 97 free(buf); 98 return (PICL_SUCCESS); 99 } 100 101 /* 102 * There should be only one memory node. 103 * If we can't find what we're looking for in the DAG then 104 * return PICL_PROPNOTFOUND to get the caller to re-try with 105 * a different property name. 106 */ 107 nmemory = md_scan_dag(mdp, rootnode, md_find_name(mdp, args), 108 md_find_name(mdp, "fwd"), memorylistp); 109 if (nmemory != 1) { 110 pri_debug(LOG_NOTICE, 111 "add_mem_prop: wrong number of memory dags: expected " 112 "1, got %d\n", nmemory); 113 free(buf); 114 return (PICL_PROPNOTFOUND); 115 } 116 117 nsegments = md_scan_dag(mdp, memorylistp[0], 118 md_find_name(mdp, "memory-segment"), 119 md_find_name(mdp, "fwd"), 120 segmentlistp); 121 122 if (nsegments == 0) { 123 pri_debug(LOG_NOTICE, "add_mem_prop: wrong number of memory " 124 "segments: expected >0, got %d\n", nsegments); 125 free(buf); 126 return (PICL_PROPNOTFOUND); 127 } 128 129 /* 130 * Add memory segments, keep running total of system memory. 131 */ 132 for (memsize = 0, segsize = 0, j = 0; j < nsegments; 133 ++j, memsize += segsize) { 134 nbanks = 0; 135 err = ptree_create_and_add_node(memh, 136 PICL_NAME_MEMORY_SEGMENT, 137 PICL_CLASS_MEMORY_SEGMENT, &segmenth); 138 if (err == PICL_SUCCESS) { 139 size = 0; 140 mask = 0; 141 142 /* 143 * Need to pull this out here since it's used for 144 * the ID. 145 */ 146 if (md_get_prop_val(mdp, segmentlistp[j], "base", 147 &segbase)) 148 segbase = 0ULL; 149 150 /* 151 * Add banks under each segment. 152 */ 153 nbanks = md_scan_dag(mdp, segmentlistp[j], 154 md_find_name(mdp, "memory-bank"), 155 md_find_name(mdp, "fwd"), 156 banklistp); 157 158 if (nbanks <= 0) { 159 pri_debug(LOG_NOTICE, "add_mem_prop: no banks " 160 "found for segment %d\n", j); 161 } else { 162 for (k = 0; k < nbanks; ++k) { 163 err = 164 ptree_create_and_add_node(segmenth, 165 PICL_NAME_MEMORY_BANK, 166 PICL_CLASS_MEMORY_BANK, &bankh); 167 if (err == PICL_SUCCESS) { 168 /* 169 * Add AddressMatch, 170 * AddressMask, Size, and 171 * ID to each bank. 172 */ 173 add_bank_props(bankh, 174 banklistp[k], 175 &size, &mask, 176 (segbase >> 32) * j + k); 177 } 178 } 179 } 180 } 181 182 /* 183 * Add Interleave, BaseAddress, and Size to each segment. 184 */ 185 interleave = 2 << (countbits(mask & (size - 1)) - 1); 186 add_segment_props(segmenth, segmentlistp[j], 187 interleave, &segsize, segbase); 188 } 189 190 /* 191 * Add TransferSize and Size (total memory) to this node. 192 */ 193 add_memory_props(memh, memorylistp[0], memsize); 194 195 free(buf); 196 return (PICL_WALK_CONTINUE); 197 } 198 199 static void 200 add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp, 201 uint64_t *size, uint64_t *mask, unsigned int id) 202 { 203 uint64_t int_value; 204 mde_cookie_t *dimmlistp; 205 int node_count, i, type_size, nac_size, status; 206 uint8_t *type; 207 char *pc, *nac; 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 215 if (!md_get_prop_val(mdp, banklistp, "size", &int_value)) { 216 add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, 217 &int_value, PICL_PTYPE_UNSIGNED_INT); 218 *size = int_value; 219 } 220 if (!md_get_prop_val(mdp, banklistp, "mask", 221 &int_value)) { 222 add_md_prop(node, sizeof (int_value), 223 PICL_PROP_ADDRESSMASK, 224 &int_value, PICL_PTYPE_UNSIGNED_INT); 225 *mask = int_value; 226 } 227 if (!md_get_prop_val(mdp, banklistp, "match", 228 &int_value)) { 229 add_md_prop(node, sizeof (int_value), 230 PICL_PROP_ADDRESSMATCH, 231 &int_value, PICL_PTYPE_UNSIGNED_INT); 232 } 233 234 add_md_prop(node, sizeof (id), PICL_PROP_ID, &id, 235 PICL_PTYPE_INT); 236 237 node_count = md_scan_dag(mdp, banklistp, md_find_name(mdp, "component"), 238 md_find_name(mdp, "fwd"), dimmlistp); 239 240 for (i = 0; i < node_count; ++i) { 241 if ((status = md_get_prop_str(mdp, dimmlistp[i], "type", 242 (char **)&type)) == -1) { 243 status = md_get_prop_data(mdp, dimmlistp[i], 244 "type", &type, &type_size); 245 } 246 if (status == 0) { 247 if (strcmp((const char *)type, "dimm") == 0) { 248 if (!md_get_prop_str(mdp, dimmlistp[i], "nac", 249 (char **)&nac)) { 250 nac_size = strlen(nac) + 1; 251 add_md_prop(node, nac_size, 252 "nac", nac, 253 PICL_PTYPE_CHARSTRING); 254 if ((pc = strrchr(nac, '/')) != NULL) 255 nac = ++pc; 256 nac_size = strlen(nac) + 1; 257 add_md_prop(node, nac_size, 258 PICL_PROP_LABEL, nac, 259 PICL_PTYPE_CHARSTRING); 260 } 261 } 262 } 263 } 264 } 265 266 static uint64_t 267 countbits(uint64_t v) 268 { 269 uint64_t c; /* c accumulates the total bits set in v */ 270 271 for (c = 0; v; c++) 272 v &= v - 1; /* clear the least significant bit set */ 273 return (c); 274 } 275 276 static void 277 add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp, 278 uint64_t interleave, uint64_t *size, uint64_t base) 279 { 280 uint64_t int_value; 281 282 *size = 0; 283 if (!md_get_prop_val(mdp, segmentlistp, "size", &int_value)) { 284 add_md_prop(node, sizeof (int_value), 285 PICL_PROP_SIZE, &int_value, 286 PICL_PTYPE_UNSIGNED_INT); 287 *size = int_value; 288 } 289 add_md_prop(node, sizeof (base), PICL_PROP_BASEADDRESS, 290 &base, PICL_PTYPE_UNSIGNED_INT); 291 292 add_md_prop(node, sizeof (interleave), PICL_PROP_INTERLEAVE_FACTOR, 293 &interleave, PICL_PTYPE_UNSIGNED_INT); 294 } 295 296 static void 297 add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, uint64_t size) 298 { 299 uint64_t int_value; 300 301 /* 302 * If the top-level node has a size property then use that, 303 * otherwise use the size that was calculated by the caller 304 * and passed in. 305 */ 306 if (md_get_prop_val(mdp, memorylistp, "size", &int_value)) 307 int_value = size; 308 add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, &int_value, 309 PICL_PTYPE_UNSIGNED_INT); 310 if (!md_get_prop_val(mdp, memorylistp, "transfer_size", 311 &int_value)) { 312 add_md_prop(node, sizeof (int_value), 313 PICL_PROP_TRANSFER_SIZE, 314 &int_value, PICL_PTYPE_UNSIGNED_INT); 315 } 316 } 317