Home | History | Annotate | Download | only in pri
      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