xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4v/pri/mem_prop_update.c (revision 7382:9f654ba609eb)
13941Svenki /*
23941Svenki  * CDDL HEADER START
33941Svenki  *
43941Svenki  * The contents of this file are subject to the terms of the
53941Svenki  * Common Development and Distribution License (the "License").
63941Svenki  * You may not use this file except in compliance with the License.
73941Svenki  *
83941Svenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93941Svenki  * or http://www.opensolaris.org/os/licensing.
103941Svenki  * See the License for the specific language governing permissions
113941Svenki  * and limitations under the License.
123941Svenki  *
133941Svenki  * When distributing Covered Code, include this CDDL HEADER in each
143941Svenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153941Svenki  * If applicable, add the following below this CDDL HEADER, with the
163941Svenki  * fields enclosed by brackets "[]" replaced with your own identifying
173941Svenki  * information: Portions Copyright [yyyy] [name of copyright owner]
183941Svenki  *
193941Svenki  * CDDL HEADER END
203941Svenki  */
213941Svenki /*
22*7382SMichael.Bergknoff@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233941Svenki  * Use is subject to license terms.
243941Svenki  */
253941Svenki 
263941Svenki /*
273941Svenki  * The PRI plug-in picks up memory configuration data from the PRI
283941Svenki  * and injects this into PICL's /platform tree.  It only populates
293941Svenki  * the logical view of memory: memory, memory-segment, memory-bank.
303941Svenki  * It does not populate the /device tree since there are no memory
313941Svenki  * controller devices on sun4v.
323941Svenki  */
333941Svenki 
343941Svenki #include "priplugin.h"
353941Svenki #include "../../common/memcfg/piclmemcfg.h"
363941Svenki 
373941Svenki static void
384669Sfw157321 add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, md_t *mdp,
394669Sfw157321 	uint64_t size);
403941Svenki 
413941Svenki static void
423941Svenki add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp,
434669Sfw157321 	md_t *mdp, uint64_t *size, uint64_t *mask, unsigned int id);
443941Svenki static uint64_t countbits(uint64_t v);
453941Svenki 
463941Svenki static void
473941Svenki add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
484669Sfw157321 	md_t *mdp, uint64_t interleave, uint64_t *size, uint64_t base);
493941Svenki 
503941Svenki /*
513941Svenki  * Callback function for picl_walk_tree_by_class().
523941Svenki  * NOTE: picl_walk_tree_by_class() maps the return codes PICL_WALK_CONTINUE
533941Svenki  * and PICL_WALK_TERMINATE to PICL_SUCCESS.
543941Svenki  */
553941Svenki int
add_mem_prop(picl_nodehdl_t node,void * args)563941Svenki add_mem_prop(picl_nodehdl_t node, void *args)
573941Svenki {
583941Svenki 	mde_cookie_t *memorylistp, *segmentlistp, *banklistp;
593941Svenki 	picl_prophdl_t memh, segmenth, bankh;
605029Sfw157321 	mde_cookie_t *buf, md_rootnode;
613941Svenki 	int j, k, num_nodes, interleave, err;
623941Svenki 	int nsegments, nbanks, nmemory;
633941Svenki 	uint64_t memsize, segsize, segbase;
643941Svenki 	uint64_t size, mask;
654669Sfw157321 	md_t *mdp = (md_t *)args;
664669Sfw157321 
674669Sfw157321 	if (mdp == NULL)
684669Sfw157321 		return (PICL_WALK_CONTINUE);
693941Svenki 
705029Sfw157321 	md_rootnode = md_root_node(mdp);
715029Sfw157321 
723941Svenki 	/*
733941Svenki 	 * An absence of nodes or failure to obtain memory for searches
743941Svenki 	 * or absence of the /memory node will cause this to fail.
753941Svenki 	 * Return PICL_WALK_SUCCESS to allow the plug-in to continue.
763941Svenki 	 */
773941Svenki 	num_nodes = md_node_count(mdp);
783941Svenki 	if (num_nodes == 0) {
793941Svenki 		pri_debug(LOG_NOTICE, "add_mem_prop: no nodes to walk\n");
803941Svenki 		return (PICL_SUCCESS);
813941Svenki 	}
823941Svenki 	buf = (mde_cookie_t *)malloc(sizeof (mde_cookie_t) * num_nodes * 3);
833941Svenki 	if (buf == NULL) {
843941Svenki 		pri_debug(LOG_NOTICE, "add_mem_prop: can't allocate memory\n");
853941Svenki 		return (PICL_SUCCESS);
863941Svenki 	}
873941Svenki 
883941Svenki 	memorylistp = &buf[0];
893941Svenki 	segmentlistp = &buf[num_nodes];
903941Svenki 	banklistp = &buf[num_nodes * 2];
913941Svenki 
923941Svenki 	if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) {
933941Svenki 		pri_debug(LOG_NOTICE,
943941Svenki 		    "add_mem_prop: can't find /memory node in platform tree\n");
953941Svenki 		free(buf);
963941Svenki 		return (PICL_SUCCESS);
973941Svenki 	}
983941Svenki 
993941Svenki 	/*
1003941Svenki 	 * There should be only one memory node.
1013941Svenki 	 * If we can't find what we're looking for in the DAG then
1023941Svenki 	 * return PICL_PROPNOTFOUND to get the caller to re-try with
1033941Svenki 	 * a different property name.
1043941Svenki 	 */
1055029Sfw157321 	nmemory = md_scan_dag(mdp, md_rootnode, md_find_name(mdp,
1064669Sfw157321 	    "memory-segments"), md_find_name(mdp, "fwd"), memorylistp);
1073941Svenki 	if (nmemory != 1) {
1083941Svenki 		pri_debug(LOG_NOTICE,
1093941Svenki 		    "add_mem_prop: wrong number of memory dags: expected "
1103941Svenki 		    "1, got %d\n", nmemory);
1113941Svenki 		free(buf);
1123941Svenki 		return (PICL_PROPNOTFOUND);
1133941Svenki 	}
1143941Svenki 
1153941Svenki 	nsegments = md_scan_dag(mdp, memorylistp[0],
1163941Svenki 	    md_find_name(mdp, "memory-segment"),
1173941Svenki 	    md_find_name(mdp, "fwd"),
1183941Svenki 	    segmentlistp);
1193941Svenki 
1203941Svenki 	if (nsegments == 0) {
1213941Svenki 		pri_debug(LOG_NOTICE, "add_mem_prop: wrong number of memory "
1223941Svenki 		    "segments: expected >0, got %d\n", nsegments);
1233941Svenki 		free(buf);
1243941Svenki 		return (PICL_PROPNOTFOUND);
1253941Svenki 	}
1263941Svenki 
1273941Svenki 	/*
1283941Svenki 	 * Add memory segments, keep running total of system memory.
1293941Svenki 	 */
1303941Svenki 	for (memsize = 0, segsize = 0, j = 0; j < nsegments;
1313941Svenki 	    ++j, memsize += segsize) {
1323941Svenki 		nbanks = 0;
1333941Svenki 		err = ptree_create_and_add_node(memh,
1343941Svenki 		    PICL_NAME_MEMORY_SEGMENT,
1353941Svenki 		    PICL_CLASS_MEMORY_SEGMENT, &segmenth);
1363941Svenki 		if (err == PICL_SUCCESS) {
1373941Svenki 			size = 0;
1383941Svenki 			mask = 0;
1393941Svenki 
1403941Svenki 			/*
1413941Svenki 			 * Need to pull this out here since it's used for
1423941Svenki 			 * the ID.
1433941Svenki 			 */
1443941Svenki 			if (md_get_prop_val(mdp, segmentlistp[j], "base",
1453941Svenki 			    &segbase))
1463941Svenki 				segbase = 0ULL;
1473941Svenki 
1483941Svenki 			/*
1493941Svenki 			 * Add banks under each segment.
1503941Svenki 			 */
1513941Svenki 			nbanks = md_scan_dag(mdp, segmentlistp[j],
1523941Svenki 			    md_find_name(mdp, "memory-bank"),
1533941Svenki 			    md_find_name(mdp, "fwd"),
1543941Svenki 			    banklistp);
1553941Svenki 
1563941Svenki 			if (nbanks <= 0) {
1573941Svenki 				pri_debug(LOG_NOTICE, "add_mem_prop: no banks "
1583941Svenki 				    "found for segment %d\n", j);
1593941Svenki 			} else {
1603941Svenki 				for (k = 0; k < nbanks; ++k) {
1613941Svenki 					err =
1623941Svenki 					    ptree_create_and_add_node(segmenth,
1633941Svenki 					    PICL_NAME_MEMORY_BANK,
1643941Svenki 					    PICL_CLASS_MEMORY_BANK, &bankh);
1653941Svenki 					if (err == PICL_SUCCESS) {
1663941Svenki 						/*
1673941Svenki 						 * Add AddressMatch,
1683941Svenki 						 * AddressMask, Size, and
1693941Svenki 						 * ID to each bank.
1703941Svenki 						 */
1713941Svenki 						add_bank_props(bankh,
1723941Svenki 						    banklistp[k],
1734669Sfw157321 						    mdp,
1743941Svenki 						    &size, &mask,
1753941Svenki 						    (segbase >> 32) * j + k);
1763941Svenki 					}
1773941Svenki 				}
1783941Svenki 			}
1793941Svenki 		}
1803941Svenki 
1813941Svenki 		/*
1823941Svenki 		 * Add Interleave, BaseAddress, and Size to each segment.
1833941Svenki 		 */
1843941Svenki 		interleave = 2 << (countbits(mask & (size - 1)) - 1);
1853941Svenki 		add_segment_props(segmenth, segmentlistp[j],
1864669Sfw157321 		    mdp, interleave, &segsize, segbase);
1873941Svenki 	}
1883941Svenki 
1893941Svenki 	/*
1903941Svenki 	 * Add TransferSize and Size (total memory) to this node.
1913941Svenki 	 */
1924669Sfw157321 	add_memory_props(memh, memorylistp[0], mdp, memsize);
1933941Svenki 
1943941Svenki 	free(buf);
1953941Svenki 	return (PICL_WALK_CONTINUE);
1963941Svenki }
1973941Svenki 
1983941Svenki 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)1994669Sfw157321 add_bank_props(picl_nodehdl_t bankh, mde_cookie_t banklistp,
2004669Sfw157321 	md_t *mdp, uint64_t *size, uint64_t *mask, unsigned int id)
2013941Svenki {
2023941Svenki 	uint64_t int_value;
2033941Svenki 	mde_cookie_t *dimmlistp;
2043941Svenki 	int node_count, i, type_size, nac_size, status;
2053941Svenki 	uint8_t *type;
2063941Svenki 	char *pc, *nac;
2074669Sfw157321 	picl_prophdl_t dimmh;
2083941Svenki 
2093941Svenki 	*size = 0ULL;
2103941Svenki 	*mask = 0ULL;
2113941Svenki 
2123941Svenki 	node_count = md_node_count(mdp);
2133941Svenki 	dimmlistp = (mde_cookie_t *)malloc(node_count * sizeof (mde_cookie_t));
214*7382SMichael.Bergknoff@Sun.COM 	if (dimmlistp == NULL) {
215*7382SMichael.Bergknoff@Sun.COM 		pri_debug(LOG_NOTICE,
216*7382SMichael.Bergknoff@Sun.COM 		    "add_bank_props: can't allocate memory\n");
217*7382SMichael.Bergknoff@Sun.COM 		return;
218*7382SMichael.Bergknoff@Sun.COM 	}
2193941Svenki 
2203941Svenki 	if (!md_get_prop_val(mdp, banklistp, "size", &int_value)) {
2214669Sfw157321 		add_md_prop(bankh, sizeof (int_value), PICL_PROP_SIZE,
2223941Svenki 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
2233941Svenki 		*size = int_value;
2243941Svenki 	}
2253941Svenki 	if (!md_get_prop_val(mdp, banklistp, "mask",
2263941Svenki 	    &int_value)) {
2274669Sfw157321 		add_md_prop(bankh, sizeof (int_value),
2283941Svenki 		    PICL_PROP_ADDRESSMASK,
2293941Svenki 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
2303941Svenki 		*mask = int_value;
2313941Svenki 	}
2323941Svenki 	if (!md_get_prop_val(mdp, banklistp, "match",
2333941Svenki 	    &int_value)) {
2344669Sfw157321 		add_md_prop(bankh, sizeof (int_value),
2353941Svenki 		    PICL_PROP_ADDRESSMATCH,
2363941Svenki 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
2373941Svenki 	}
2383941Svenki 
2394669Sfw157321 	add_md_prop(bankh, sizeof (id), PICL_PROP_ID, &id,
2403941Svenki 	    PICL_PTYPE_INT);
2413941Svenki 
2423941Svenki 	node_count = md_scan_dag(mdp, banklistp, md_find_name(mdp, "component"),
2433941Svenki 	    md_find_name(mdp, "fwd"), dimmlistp);
2443941Svenki 
2453941Svenki 	for (i = 0; i < node_count; ++i) {
2464669Sfw157321 		status = md_get_prop_str(mdp, dimmlistp[i], "type",
2474669Sfw157321 		    (char **)&type);
2484669Sfw157321 		if (status == -1) {
2493941Svenki 			status = md_get_prop_data(mdp, dimmlistp[i],
2503941Svenki 			    "type", &type, &type_size);
2513941Svenki 		}
2524669Sfw157321 		if (status == -1) /* can't get node type - just skip */
2534669Sfw157321 			continue;
2544669Sfw157321 		if (strcmp((const char *)type, "dimm") == 0) {
2554669Sfw157321 			if (md_get_prop_str(mdp, dimmlistp[i], "nac",
2564669Sfw157321 			    (char **)&nac) == 0) {
2574669Sfw157321 				nac_size = strlen(nac) + 1;
2584669Sfw157321 				if (ptree_create_and_add_node(bankh,
2594669Sfw157321 				    PICL_NAME_MEMORY_MODULE,
2604669Sfw157321 				    PICL_CLASS_MEMORY_MODULE, &dimmh) ==
2614669Sfw157321 				    PICL_SUCCESS) {
2624669Sfw157321 					add_md_prop(dimmh, nac_size,
2633941Svenki 					    "nac", nac,
2643941Svenki 					    PICL_PTYPE_CHARSTRING);
2653941Svenki 					if ((pc = strrchr(nac, '/')) != NULL)
2663941Svenki 						nac = ++pc;
2673941Svenki 					nac_size = strlen(nac) + 1;
2684669Sfw157321 					add_md_prop(dimmh, nac_size,
2693941Svenki 					    PICL_PROP_LABEL, nac,
2703941Svenki 					    PICL_PTYPE_CHARSTRING);
2713941Svenki 				}
2723941Svenki 			}
2733941Svenki 		}
2743941Svenki 	}
275*7382SMichael.Bergknoff@Sun.COM 	free(dimmlistp);
2763941Svenki }
2773941Svenki 
2783941Svenki static uint64_t
countbits(uint64_t v)2793941Svenki countbits(uint64_t v)
2803941Svenki {
2813941Svenki 	uint64_t c;	/* c accumulates the total bits set in v */
2823941Svenki 
2833941Svenki 	for (c = 0; v; c++)
2843941Svenki 		v &= v - 1;	/* clear the least significant bit set */
2853941Svenki 	return (c);
2863941Svenki }
2873941Svenki 
2883941Svenki 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)2893941Svenki add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
2904669Sfw157321     md_t *mdp, uint64_t interleave, uint64_t *size, uint64_t base)
2913941Svenki {
2923941Svenki 	uint64_t int_value;
2933941Svenki 
2943941Svenki 	*size = 0;
2953941Svenki 	if (!md_get_prop_val(mdp, segmentlistp, "size", &int_value)) {
2963941Svenki 		add_md_prop(node, sizeof (int_value),
2973941Svenki 		    PICL_PROP_SIZE, &int_value,
2983941Svenki 		    PICL_PTYPE_UNSIGNED_INT);
2993941Svenki 		*size = int_value;
3003941Svenki 	}
3013941Svenki 	add_md_prop(node, sizeof (base), PICL_PROP_BASEADDRESS,
3024669Sfw157321 	    &base, PICL_PTYPE_UNSIGNED_INT);
3033941Svenki 
3043941Svenki 	add_md_prop(node, sizeof (interleave), PICL_PROP_INTERLEAVE_FACTOR,
3054669Sfw157321 	    &interleave, PICL_PTYPE_UNSIGNED_INT);
3063941Svenki }
3073941Svenki 
3083941Svenki static void
add_memory_props(picl_nodehdl_t node,mde_cookie_t memorylistp,md_t * mdp,uint64_t size)3094669Sfw157321 add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, md_t *mdp,
3104669Sfw157321 	uint64_t size)
3113941Svenki {
3123941Svenki 	uint64_t int_value;
3133941Svenki 
3143941Svenki 	/*
3153941Svenki 	 * If the top-level node has a size property then use that,
3163941Svenki 	 * otherwise use the size that was calculated by the caller
3173941Svenki 	 * and passed in.
3183941Svenki 	 */
3193941Svenki 	if (md_get_prop_val(mdp, memorylistp, "size", &int_value))
3203941Svenki 		int_value = size;
3213941Svenki 	add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, &int_value,
3224669Sfw157321 	    PICL_PTYPE_UNSIGNED_INT);
3233941Svenki 	if (!md_get_prop_val(mdp, memorylistp, "transfer_size",
3243941Svenki 	    &int_value)) {
3253941Svenki 		add_md_prop(node, sizeof (int_value),
3263941Svenki 		    PICL_PROP_TRANSFER_SIZE,
3273941Svenki 		    &int_value, PICL_PTYPE_UNSIGNED_INT);
3283941Svenki 	}
3293941Svenki }
330