/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * The PRI plug-in picks up memory configuration data from the PRI * and injects this into PICL's /platform tree. It only populates * the logical view of memory: memory, memory-segment, memory-bank. * It does not populate the /device tree since there are no memory * controller devices on sun4v. */ #include "priplugin.h" #include "../../common/memcfg/piclmemcfg.h" static void add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, md_t *mdp, uint64_t size); static void add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp, md_t *mdp, uint64_t *size, uint64_t *mask, unsigned int id); static uint64_t countbits(uint64_t v); static void add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp, md_t *mdp, uint64_t interleave, uint64_t *size, uint64_t base); /* * Callback function for picl_walk_tree_by_class(). * NOTE: picl_walk_tree_by_class() maps the return codes PICL_WALK_CONTINUE * and PICL_WALK_TERMINATE to PICL_SUCCESS. */ int add_mem_prop(picl_nodehdl_t node, void *args) { mde_cookie_t *memorylistp, *segmentlistp, *banklistp; picl_prophdl_t memh, segmenth, bankh; mde_cookie_t *buf, md_rootnode; int j, k, num_nodes, interleave, err; int nsegments, nbanks, nmemory; uint64_t memsize, segsize, segbase; uint64_t size, mask; md_t *mdp = (md_t *)args; if (mdp == NULL) return (PICL_WALK_CONTINUE); md_rootnode = md_root_node(mdp); /* * An absence of nodes or failure to obtain memory for searches * or absence of the /memory node will cause this to fail. * Return PICL_WALK_SUCCESS to allow the plug-in to continue. */ num_nodes = md_node_count(mdp); if (num_nodes == 0) { pri_debug(LOG_NOTICE, "add_mem_prop: no nodes to walk\n"); return (PICL_SUCCESS); } buf = (mde_cookie_t *)malloc(sizeof (mde_cookie_t) * num_nodes * 3); if (buf == NULL) { pri_debug(LOG_NOTICE, "add_mem_prop: can't allocate memory\n"); return (PICL_SUCCESS); } memorylistp = &buf[0]; segmentlistp = &buf[num_nodes]; banklistp = &buf[num_nodes * 2]; if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) { pri_debug(LOG_NOTICE, "add_mem_prop: can't find /memory node in platform tree\n"); free(buf); return (PICL_SUCCESS); } /* * There should be only one memory node. * If we can't find what we're looking for in the DAG then * return PICL_PROPNOTFOUND to get the caller to re-try with * a different property name. */ nmemory = md_scan_dag(mdp, md_rootnode, md_find_name(mdp, "memory-segments"), md_find_name(mdp, "fwd"), memorylistp); if (nmemory != 1) { pri_debug(LOG_NOTICE, "add_mem_prop: wrong number of memory dags: expected " "1, got %d\n", nmemory); free(buf); return (PICL_PROPNOTFOUND); } nsegments = md_scan_dag(mdp, memorylistp[0], md_find_name(mdp, "memory-segment"), md_find_name(mdp, "fwd"), segmentlistp); if (nsegments == 0) { pri_debug(LOG_NOTICE, "add_mem_prop: wrong number of memory " "segments: expected >0, got %d\n", nsegments); free(buf); return (PICL_PROPNOTFOUND); } /* * Add memory segments, keep running total of system memory. */ for (memsize = 0, segsize = 0, j = 0; j < nsegments; ++j, memsize += segsize) { nbanks = 0; err = ptree_create_and_add_node(memh, PICL_NAME_MEMORY_SEGMENT, PICL_CLASS_MEMORY_SEGMENT, &segmenth); if (err == PICL_SUCCESS) { size = 0; mask = 0; /* * Need to pull this out here since it's used for * the ID. */ if (md_get_prop_val(mdp, segmentlistp[j], "base", &segbase)) segbase = 0ULL; /* * Add banks under each segment. */ nbanks = md_scan_dag(mdp, segmentlistp[j], md_find_name(mdp, "memory-bank"), md_find_name(mdp, "fwd"), banklistp); if (nbanks <= 0) { pri_debug(LOG_NOTICE, "add_mem_prop: no banks " "found for segment %d\n", j); } else { for (k = 0; k < nbanks; ++k) { err = ptree_create_and_add_node(segmenth, PICL_NAME_MEMORY_BANK, PICL_CLASS_MEMORY_BANK, &bankh); if (err == PICL_SUCCESS) { /* * Add AddressMatch, * AddressMask, Size, and * ID to each bank. */ add_bank_props(bankh, banklistp[k], mdp, &size, &mask, (segbase >> 32) * j + k); } } } } /* * Add Interleave, BaseAddress, and Size to each segment. */ interleave = 2 << (countbits(mask & (size - 1)) - 1); add_segment_props(segmenth, segmentlistp[j], mdp, interleave, &segsize, segbase); } /* * Add TransferSize and Size (total memory) to this node. */ add_memory_props(memh, memorylistp[0], mdp, memsize); free(buf); return (PICL_WALK_CONTINUE); } static void add_bank_props(picl_nodehdl_t bankh, mde_cookie_t banklistp, md_t *mdp, uint64_t *size, uint64_t *mask, unsigned int id) { uint64_t int_value; mde_cookie_t *dimmlistp; int node_count, i, type_size, nac_size, status; uint8_t *type; char *pc, *nac; picl_prophdl_t dimmh; *size = 0ULL; *mask = 0ULL; node_count = md_node_count(mdp); dimmlistp = (mde_cookie_t *)malloc(node_count * sizeof (mde_cookie_t)); if (dimmlistp == NULL) { pri_debug(LOG_NOTICE, "add_bank_props: can't allocate memory\n"); return; } if (!md_get_prop_val(mdp, banklistp, "size", &int_value)) { add_md_prop(bankh, sizeof (int_value), PICL_PROP_SIZE, &int_value, PICL_PTYPE_UNSIGNED_INT); *size = int_value; } if (!md_get_prop_val(mdp, banklistp, "mask", &int_value)) { add_md_prop(bankh, sizeof (int_value), PICL_PROP_ADDRESSMASK, &int_value, PICL_PTYPE_UNSIGNED_INT); *mask = int_value; } if (!md_get_prop_val(mdp, banklistp, "match", &int_value)) { add_md_prop(bankh, sizeof (int_value), PICL_PROP_ADDRESSMATCH, &int_value, PICL_PTYPE_UNSIGNED_INT); } add_md_prop(bankh, sizeof (id), PICL_PROP_ID, &id, PICL_PTYPE_INT); node_count = md_scan_dag(mdp, banklistp, md_find_name(mdp, "component"), md_find_name(mdp, "fwd"), dimmlistp); for (i = 0; i < node_count; ++i) { status = md_get_prop_str(mdp, dimmlistp[i], "type", (char **)&type); if (status == -1) { status = md_get_prop_data(mdp, dimmlistp[i], "type", &type, &type_size); } if (status == -1) /* can't get node type - just skip */ continue; if (strcmp((const char *)type, "dimm") == 0) { if (md_get_prop_str(mdp, dimmlistp[i], "nac", (char **)&nac) == 0) { nac_size = strlen(nac) + 1; if (ptree_create_and_add_node(bankh, PICL_NAME_MEMORY_MODULE, PICL_CLASS_MEMORY_MODULE, &dimmh) == PICL_SUCCESS) { add_md_prop(dimmh, nac_size, "nac", nac, PICL_PTYPE_CHARSTRING); if ((pc = strrchr(nac, '/')) != NULL) nac = ++pc; nac_size = strlen(nac) + 1; add_md_prop(dimmh, nac_size, PICL_PROP_LABEL, nac, PICL_PTYPE_CHARSTRING); } } } } free(dimmlistp); } static uint64_t countbits(uint64_t v) { uint64_t c; /* c accumulates the total bits set in v */ for (c = 0; v; c++) v &= v - 1; /* clear the least significant bit set */ return (c); } static void add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp, md_t *mdp, uint64_t interleave, uint64_t *size, uint64_t base) { uint64_t int_value; *size = 0; if (!md_get_prop_val(mdp, segmentlistp, "size", &int_value)) { add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, &int_value, PICL_PTYPE_UNSIGNED_INT); *size = int_value; } add_md_prop(node, sizeof (base), PICL_PROP_BASEADDRESS, &base, PICL_PTYPE_UNSIGNED_INT); add_md_prop(node, sizeof (interleave), PICL_PROP_INTERLEAVE_FACTOR, &interleave, PICL_PTYPE_UNSIGNED_INT); } static void add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, md_t *mdp, uint64_t size) { uint64_t int_value; /* * If the top-level node has a size property then use that, * otherwise use the size that was calculated by the caller * and passed in. */ if (md_get_prop_val(mdp, memorylistp, "size", &int_value)) int_value = size; add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, &int_value, PICL_PTYPE_UNSIGNED_INT); if (!md_get_prop_val(mdp, memorylistp, "transfer_size", &int_value)) { add_md_prop(node, sizeof (int_value), PICL_PROP_TRANSFER_SIZE, &int_value, PICL_PTYPE_UNSIGNED_INT); } }