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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2000-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 /* 28 * This plugin creates memory configuration nodes and properties in the 29 * PICL tree for Grover/Grover+ platform. 30 * 31 * Subtree of memory-controller in the physical aspect. 32 * memory-controller --- memory-module 33 * However, there is no memory controller node on Grover. Thus we need to 34 * create it under platform. 35 * 36 * Subtree of memory in the logical aspect. 37 * memory --- memory-segment 38 * Add property _memory-module_ at memory-segment referring to the 39 * memory-module since memory-segment equals to memory-module on Grover. 40 * 41 * Undo strategy: 42 * Create all nodes and properties, or none if it fails in physical and 43 * logical memory tree respectively. It keeps on creating logical 44 * memory tree although it falis on physical logical tree, but no link to 45 * memory module. 46 * 47 * NOTE: 48 * It depends on PICL devtree plugin. 49 */ 50 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <unistd.h> 54 #include <alloca.h> 55 #include <syslog.h> 56 #include <string.h> 57 #include <libintl.h> 58 #include <picl.h> 59 #include <picltree.h> 60 #include <sys/types.h> 61 #include <sys/obpdefs.h> 62 #include "piclmemcfg.h" 63 #include "memcfg_impl.h" 64 65 static void piclmemcfg_register(void); 66 static void piclmemcfg_init(void); 67 static void piclmemcfg_fini(void); 68 69 #pragma init(piclmemcfg_register) 70 71 static picld_plugin_reg_t my_reg_info = { 72 PICLD_PLUGIN_VERSION_1, 73 PICLD_PLUGIN_NON_CRITICAL, 74 "SUNW_piclmemcfg", 75 piclmemcfg_init, 76 piclmemcfg_fini 77 }; 78 79 /* 80 * Create logical memory tree 81 * memory --- memory-segment 82 */ 83 static int 84 create_logical_tree(picl_nodehdl_t memh, mmodinfo_t *mmodinfo) 85 { 86 picl_nodehdl_t msegh; 87 picl_nodehdl_t *memsegh; 88 ptree_propinfo_t propinfo; 89 uint32_t ifactor = INTERLEAVEFACTOR; 90 int i; 91 int err = PICL_SUCCESS; 92 93 if ((memsegh = alloca(sizeof (picl_nodehdl_t) * TOTAL_MEM_SLOTS)) == 94 NULL) 95 return (PICL_FAILURE); 96 97 for (i = 0; i < TOTAL_MEM_SLOTS; i++) { 98 /* 99 * It means no segment for the slot if size is zero 100 */ 101 if (mmodinfo[i].size == 0) { 102 memsegh[i] = 0; 103 continue; 104 } 105 106 /* 107 * Create memory-segment node under memory 108 */ 109 err = ptree_create_and_add_node(memh, PICL_NAME_MEMORY_SEGMENT, 110 PICL_CLASS_MEMORY_SEGMENT, &msegh); 111 if (err != PICL_SUCCESS) 112 break; 113 114 /* 115 * For undo easily later 116 */ 117 memsegh[i] = msegh; 118 119 /* 120 * Add property, Size to memory-segment node 121 */ 122 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 123 PICL_PTYPE_UNSIGNED_INT, PICL_READ, 124 sizeof (mmodinfo[i].size), PICL_PROP_SIZE, NULL, NULL); 125 if (err != PICL_SUCCESS) 126 break; 127 128 err = ptree_create_and_add_prop(msegh, &propinfo, 129 &mmodinfo[i].size, NULL); 130 if (err != PICL_SUCCESS) 131 break; 132 133 /* 134 * Add property, BaseAddress to memory-segment node 135 */ 136 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 137 PICL_PTYPE_UNSIGNED_INT, PICL_READ, 138 sizeof (mmodinfo[i].base), PICL_PROP_BASEADDRESS, NULL, 139 NULL); 140 if (err != PICL_SUCCESS) 141 break; 142 143 err = ptree_create_and_add_prop(msegh, &propinfo, 144 &mmodinfo[i].base, NULL); 145 if (err != PICL_SUCCESS) 146 break; 147 148 /* 149 * Add property, InterleaveFactor to memory-segment node 150 */ 151 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 152 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (ifactor), 153 PICL_PROP_INTERLEAVE_FACTOR, NULL, NULL); 154 if (err != PICL_SUCCESS) 155 break; 156 157 err = ptree_create_and_add_prop(msegh, &propinfo, &ifactor, 158 NULL); 159 if (err != PICL_SUCCESS) 160 break; 161 162 /* 163 * Add reference property to the memory module if memory 164 * module node handle is not NULL. 165 */ 166 if (mmodinfo[i].memmodh == 0) 167 continue; 168 169 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 170 PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), 171 PICL_REFPROP_MEMORY_MODULE, NULL, NULL); 172 if (err != PICL_SUCCESS) 173 break; 174 175 err = ptree_create_and_add_prop(msegh, &propinfo, 176 &mmodinfo[i].memmodh, NULL); 177 if (err != PICL_SUCCESS) 178 break; 179 } 180 181 if (err != PICL_SUCCESS) { 182 /* 183 * Undo in the logical memory tree 184 */ 185 for (i = 0; i < TOTAL_MEM_SLOTS; i++) { 186 if (memsegh[i] == 0) 187 continue; 188 189 (void) ptree_delete_node(memsegh[i]); 190 (void) ptree_destroy_node(memsegh[i]); 191 } 192 } 193 194 return (err); 195 } 196 197 /* 198 * Create physical memory tree 199 * memory-controller --- memory-module 200 */ 201 static int 202 create_physical_tree(picl_nodehdl_t plfh, mmodinfo_t *mmodinfo) 203 { 204 picl_nodehdl_t mch, memmodh; 205 ptree_propinfo_t propinfo; 206 int i; 207 int err = PICL_SUCCESS; 208 uint32_t id; 209 210 /* 211 * Create memory-controller node under platform 212 */ 213 err = ptree_create_and_add_node(plfh, PICL_NAME_MEMORY_CONTROLLER, 214 PICL_CLASS_MEMORY_CONTROLLER, &mch); 215 if (err != PICL_SUCCESS) 216 return (err); 217 218 /* 219 * Create memory-module nodes and properties 220 * Get all memory modules with dimm 221 */ 222 for (i = 0; i < TOTAL_MEM_SLOTS; i++) { 223 /* 224 * It means no dimm on the slot if size is zero 225 */ 226 if (mmodinfo[i].size == 0) 227 continue; 228 229 /* Create memory-module node under memory-controller */ 230 err = ptree_create_and_add_node(mch, PICL_NAME_MEMORY_MODULE, 231 PICL_CLASS_MEMORY_MODULE, &memmodh); 232 if (err != PICL_SUCCESS) 233 break; 234 235 /* 236 * Update memory module node handle at mmodinfo 237 */ 238 mmodinfo[i].memmodh = memmodh; 239 240 /* 241 * Add property, Size to memory-module node 242 */ 243 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 244 PICL_PTYPE_UNSIGNED_INT, PICL_READ, 245 sizeof (mmodinfo[i].size), PICL_PROP_SIZE, NULL, NULL); 246 if (err != PICL_SUCCESS) 247 break; 248 249 err = ptree_create_and_add_prop(memmodh, &propinfo, 250 &mmodinfo[i].size, NULL); 251 if (err != PICL_SUCCESS) 252 break; 253 254 /* 255 * Add property, ID to memory-module node 256 */ 257 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 258 PICL_PTYPE_INT, PICL_READ, sizeof (id), PICL_PROP_ID, 259 NULL, NULL); 260 if (err != PICL_SUCCESS) 261 break; 262 263 id = i; 264 err = ptree_create_and_add_prop(memmodh, &propinfo, &id, NULL); 265 if (err != PICL_SUCCESS) 266 break; 267 } 268 269 if (err != PICL_SUCCESS) { 270 /* 271 * Clear out the saved memory module node handle so that 272 * logical memory tree won't link to memory module. 273 */ 274 for (i = 0; i < TOTAL_MEM_SLOTS; i++) 275 mmodinfo[i].memmodh = 0; 276 277 /* 278 * Undo in the physical memory tree 279 */ 280 (void) ptree_delete_node(mch); 281 (void) ptree_destroy_node(mch); 282 } 283 284 return (err); 285 } 286 287 /* 288 * Get the memory module and memory segment information from 289 * property reg of memory node. 290 * 291 * mmodinfo will be updated. Also, the pointers to mseginfo and 292 * the number of segments will be passed to the caller. 293 */ 294 static int 295 get_reg_info(picl_nodehdl_t plfh, picl_nodehdl_t memh, 296 mmodinfo_t *mmodinfo) 297 { 298 picl_prophdl_t proph; 299 ptree_propinfo_t pinfo; 300 regspec_t *memspec; 301 int i, err; 302 int pval; 303 int nregspec; 304 305 306 /* 307 * Check if the #size-cells of the platform node is 2 308 */ 309 err = ptree_get_propval_by_name(plfh, OBP_PROP_SIZE_CELLS, &pval, 310 sizeof (pval)); 311 312 if (err == PICL_PROPNOTFOUND) 313 pval = SUPPORTED_NUM_CELL_SIZE; 314 else if (err != PICL_SUCCESS) 315 return (err); 316 317 /* 318 * don't know to handle other vals 319 */ 320 if (pval != SUPPORTED_NUM_CELL_SIZE) 321 return (PICL_FAILURE); 322 323 /* 324 * Get property reg of memory node 325 */ 326 err = ptree_get_prop_by_name(memh, OBP_REG, &proph); 327 if (err != PICL_SUCCESS) 328 return (err); 329 330 err = ptree_get_propinfo(proph, &pinfo); 331 if (err != PICL_SUCCESS) 332 return (err); 333 334 if ((memspec = alloca(pinfo.piclinfo.size)) == NULL) 335 return (PICL_FAILURE); 336 337 nregspec = pinfo.piclinfo.size / sizeof (*memspec); 338 339 if ((nregspec == 0) || (nregspec > TOTAL_MEM_SLOTS)) 340 return (PICL_FAILURE); 341 342 err = ptree_get_propval(proph, memspec, pinfo.piclinfo.size); 343 if (err != PICL_SUCCESS) 344 return (err); 345 346 347 for (i = 0; i < nregspec; i++) { 348 349 mmodinfo[i].base = memspec[i].physaddr; 350 mmodinfo[i].size = memspec[i].size; 351 352 } 353 354 return (PICL_SUCCESS); 355 } 356 357 /* 358 * executed as part of .init when the plugin is dlopen()ed 359 */ 360 static void 361 piclmemcfg_register(void) 362 { 363 (void) picld_plugin_register(&my_reg_info); 364 } 365 366 /* 367 * Init entry point of the plugin 368 * Creates the PICL nodes and properties in the physical and logical aspects. 369 */ 370 static void 371 piclmemcfg_init(void) 372 { 373 picl_nodehdl_t plfh, memh; 374 mmodinfo_t mmodinfo[TOTAL_MEM_SLOTS]; 375 376 /* 377 * Get platform node 378 */ 379 if ((ptree_get_node_by_path(PLATFORM_PATH, &plfh)) != PICL_SUCCESS) { 380 syslog(LOG_ERR, EM_INIT_FAILED); 381 return; 382 } 383 384 /* 385 * Find the memory node 386 */ 387 if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) { 388 syslog(LOG_ERR, EM_INIT_FAILED); 389 return; 390 } 391 392 /* 393 * Initialize the mmodinfo and get segment information from reg 394 */ 395 (void) memset(mmodinfo, 0, sizeof (mmodinfo)); 396 397 if ((get_reg_info(plfh, memh, mmodinfo)) != PICL_SUCCESS) { 398 syslog(LOG_ERR, EM_INIT_FAILED); 399 return; 400 } 401 402 /* 403 * Create subtree of memory-controller in the physical aspect. 404 * memory-controller --- memory-module 405 */ 406 if ((create_physical_tree(plfh, mmodinfo)) != PICL_SUCCESS) 407 syslog(LOG_ERR, EM_PHYSIC_MEM_TREE_FAILED); 408 409 /* 410 * Create subtree of memory in the logical aspect. 411 * memory --- memory-segment 412 */ 413 if ((create_logical_tree(memh, mmodinfo)) != PICL_SUCCESS) 414 syslog(LOG_ERR, EM_LOGIC_MEM_TREE_FAILED); 415 } 416 417 /* 418 * fini entry point of the plugin 419 */ 420 static void 421 piclmemcfg_fini(void) 422 { 423 } 424