10d63ce2bSvenki /*
20d63ce2bSvenki * CDDL HEADER START
30d63ce2bSvenki *
40d63ce2bSvenki * The contents of this file are subject to the terms of the
50d63ce2bSvenki * Common Development and Distribution License (the "License").
60d63ce2bSvenki * You may not use this file except in compliance with the License.
70d63ce2bSvenki *
80d63ce2bSvenki * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90d63ce2bSvenki * or http://www.opensolaris.org/os/licensing.
100d63ce2bSvenki * See the License for the specific language governing permissions
110d63ce2bSvenki * and limitations under the License.
120d63ce2bSvenki *
130d63ce2bSvenki * When distributing Covered Code, include this CDDL HEADER in each
140d63ce2bSvenki * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150d63ce2bSvenki * If applicable, add the following below this CDDL HEADER, with the
160d63ce2bSvenki * fields enclosed by brackets "[]" replaced with your own identifying
170d63ce2bSvenki * information: Portions Copyright [yyyy] [name of copyright owner]
180d63ce2bSvenki *
190d63ce2bSvenki * CDDL HEADER END
200d63ce2bSvenki */
210d63ce2bSvenki /*
22*2ea390f3SMichael Bergknoff * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230d63ce2bSvenki * Use is subject to license terms.
240d63ce2bSvenki */
250d63ce2bSvenki
260d63ce2bSvenki /*
270d63ce2bSvenki * The PRI plug-in picks up memory configuration data from the PRI
280d63ce2bSvenki * and injects this into PICL's /platform tree. It only populates
290d63ce2bSvenki * the logical view of memory: memory, memory-segment, memory-bank.
300d63ce2bSvenki * It does not populate the /device tree since there are no memory
310d63ce2bSvenki * controller devices on sun4v.
320d63ce2bSvenki */
330d63ce2bSvenki
340d63ce2bSvenki #include "priplugin.h"
350d63ce2bSvenki #include "../../common/memcfg/piclmemcfg.h"
360d63ce2bSvenki
370d63ce2bSvenki static void
38a90d965dSfw add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, md_t *mdp,
39a90d965dSfw uint64_t size);
400d63ce2bSvenki
410d63ce2bSvenki static void
420d63ce2bSvenki add_bank_props(picl_nodehdl_t node, mde_cookie_t banklistp,
43a90d965dSfw md_t *mdp, uint64_t *size, uint64_t *mask, unsigned int id);
440d63ce2bSvenki static uint64_t countbits(uint64_t v);
450d63ce2bSvenki
460d63ce2bSvenki static void
470d63ce2bSvenki add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
48a90d965dSfw md_t *mdp, uint64_t interleave, uint64_t *size, uint64_t base);
490d63ce2bSvenki
500d63ce2bSvenki /*
510d63ce2bSvenki * Callback function for picl_walk_tree_by_class().
520d63ce2bSvenki * NOTE: picl_walk_tree_by_class() maps the return codes PICL_WALK_CONTINUE
530d63ce2bSvenki * and PICL_WALK_TERMINATE to PICL_SUCCESS.
540d63ce2bSvenki */
550d63ce2bSvenki int
add_mem_prop(picl_nodehdl_t node,void * args)560d63ce2bSvenki add_mem_prop(picl_nodehdl_t node, void *args)
570d63ce2bSvenki {
580d63ce2bSvenki mde_cookie_t *memorylistp, *segmentlistp, *banklistp;
590d63ce2bSvenki picl_prophdl_t memh, segmenth, bankh;
60d2b9c676Sfw mde_cookie_t *buf, md_rootnode;
610d63ce2bSvenki int j, k, num_nodes, interleave, err;
620d63ce2bSvenki int nsegments, nbanks, nmemory;
630d63ce2bSvenki uint64_t memsize, segsize, segbase;
640d63ce2bSvenki uint64_t size, mask;
65a90d965dSfw md_t *mdp = (md_t *)args;
66a90d965dSfw
67a90d965dSfw if (mdp == NULL)
68a90d965dSfw return (PICL_WALK_CONTINUE);
690d63ce2bSvenki
70d2b9c676Sfw md_rootnode = md_root_node(mdp);
71d2b9c676Sfw
720d63ce2bSvenki /*
730d63ce2bSvenki * An absence of nodes or failure to obtain memory for searches
740d63ce2bSvenki * or absence of the /memory node will cause this to fail.
750d63ce2bSvenki * Return PICL_WALK_SUCCESS to allow the plug-in to continue.
760d63ce2bSvenki */
770d63ce2bSvenki num_nodes = md_node_count(mdp);
780d63ce2bSvenki if (num_nodes == 0) {
790d63ce2bSvenki pri_debug(LOG_NOTICE, "add_mem_prop: no nodes to walk\n");
800d63ce2bSvenki return (PICL_SUCCESS);
810d63ce2bSvenki }
820d63ce2bSvenki buf = (mde_cookie_t *)malloc(sizeof (mde_cookie_t) * num_nodes * 3);
830d63ce2bSvenki if (buf == NULL) {
840d63ce2bSvenki pri_debug(LOG_NOTICE, "add_mem_prop: can't allocate memory\n");
850d63ce2bSvenki return (PICL_SUCCESS);
860d63ce2bSvenki }
870d63ce2bSvenki
880d63ce2bSvenki memorylistp = &buf[0];
890d63ce2bSvenki segmentlistp = &buf[num_nodes];
900d63ce2bSvenki banklistp = &buf[num_nodes * 2];
910d63ce2bSvenki
920d63ce2bSvenki if ((ptree_get_node_by_path(MEMORY_PATH, &memh)) != PICL_SUCCESS) {
930d63ce2bSvenki pri_debug(LOG_NOTICE,
940d63ce2bSvenki "add_mem_prop: can't find /memory node in platform tree\n");
950d63ce2bSvenki free(buf);
960d63ce2bSvenki return (PICL_SUCCESS);
970d63ce2bSvenki }
980d63ce2bSvenki
990d63ce2bSvenki /*
1000d63ce2bSvenki * There should be only one memory node.
1010d63ce2bSvenki * If we can't find what we're looking for in the DAG then
1020d63ce2bSvenki * return PICL_PROPNOTFOUND to get the caller to re-try with
1030d63ce2bSvenki * a different property name.
1040d63ce2bSvenki */
105d2b9c676Sfw nmemory = md_scan_dag(mdp, md_rootnode, md_find_name(mdp,
106a90d965dSfw "memory-segments"), md_find_name(mdp, "fwd"), memorylistp);
1070d63ce2bSvenki if (nmemory != 1) {
1080d63ce2bSvenki pri_debug(LOG_NOTICE,
1090d63ce2bSvenki "add_mem_prop: wrong number of memory dags: expected "
1100d63ce2bSvenki "1, got %d\n", nmemory);
1110d63ce2bSvenki free(buf);
1120d63ce2bSvenki return (PICL_PROPNOTFOUND);
1130d63ce2bSvenki }
1140d63ce2bSvenki
1150d63ce2bSvenki nsegments = md_scan_dag(mdp, memorylistp[0],
1160d63ce2bSvenki md_find_name(mdp, "memory-segment"),
1170d63ce2bSvenki md_find_name(mdp, "fwd"),
1180d63ce2bSvenki segmentlistp);
1190d63ce2bSvenki
1200d63ce2bSvenki if (nsegments == 0) {
1210d63ce2bSvenki pri_debug(LOG_NOTICE, "add_mem_prop: wrong number of memory "
1220d63ce2bSvenki "segments: expected >0, got %d\n", nsegments);
1230d63ce2bSvenki free(buf);
1240d63ce2bSvenki return (PICL_PROPNOTFOUND);
1250d63ce2bSvenki }
1260d63ce2bSvenki
1270d63ce2bSvenki /*
1280d63ce2bSvenki * Add memory segments, keep running total of system memory.
1290d63ce2bSvenki */
1300d63ce2bSvenki for (memsize = 0, segsize = 0, j = 0; j < nsegments;
1310d63ce2bSvenki ++j, memsize += segsize) {
1320d63ce2bSvenki nbanks = 0;
1330d63ce2bSvenki err = ptree_create_and_add_node(memh,
1340d63ce2bSvenki PICL_NAME_MEMORY_SEGMENT,
1350d63ce2bSvenki PICL_CLASS_MEMORY_SEGMENT, &segmenth);
1360d63ce2bSvenki if (err == PICL_SUCCESS) {
1370d63ce2bSvenki size = 0;
1380d63ce2bSvenki mask = 0;
1390d63ce2bSvenki
1400d63ce2bSvenki /*
1410d63ce2bSvenki * Need to pull this out here since it's used for
1420d63ce2bSvenki * the ID.
1430d63ce2bSvenki */
1440d63ce2bSvenki if (md_get_prop_val(mdp, segmentlistp[j], "base",
1450d63ce2bSvenki &segbase))
1460d63ce2bSvenki segbase = 0ULL;
1470d63ce2bSvenki
1480d63ce2bSvenki /*
1490d63ce2bSvenki * Add banks under each segment.
1500d63ce2bSvenki */
1510d63ce2bSvenki nbanks = md_scan_dag(mdp, segmentlistp[j],
1520d63ce2bSvenki md_find_name(mdp, "memory-bank"),
1530d63ce2bSvenki md_find_name(mdp, "fwd"),
1540d63ce2bSvenki banklistp);
1550d63ce2bSvenki
1560d63ce2bSvenki if (nbanks <= 0) {
1570d63ce2bSvenki pri_debug(LOG_NOTICE, "add_mem_prop: no banks "
1580d63ce2bSvenki "found for segment %d\n", j);
1590d63ce2bSvenki } else {
1600d63ce2bSvenki for (k = 0; k < nbanks; ++k) {
1610d63ce2bSvenki err =
1620d63ce2bSvenki ptree_create_and_add_node(segmenth,
1630d63ce2bSvenki PICL_NAME_MEMORY_BANK,
1640d63ce2bSvenki PICL_CLASS_MEMORY_BANK, &bankh);
1650d63ce2bSvenki if (err == PICL_SUCCESS) {
1660d63ce2bSvenki /*
1670d63ce2bSvenki * Add AddressMatch,
1680d63ce2bSvenki * AddressMask, Size, and
1690d63ce2bSvenki * ID to each bank.
1700d63ce2bSvenki */
1710d63ce2bSvenki add_bank_props(bankh,
1720d63ce2bSvenki banklistp[k],
173a90d965dSfw mdp,
1740d63ce2bSvenki &size, &mask,
1750d63ce2bSvenki (segbase >> 32) * j + k);
1760d63ce2bSvenki }
1770d63ce2bSvenki }
1780d63ce2bSvenki }
1790d63ce2bSvenki }
1800d63ce2bSvenki
1810d63ce2bSvenki /*
1820d63ce2bSvenki * Add Interleave, BaseAddress, and Size to each segment.
1830d63ce2bSvenki */
1840d63ce2bSvenki interleave = 2 << (countbits(mask & (size - 1)) - 1);
1850d63ce2bSvenki add_segment_props(segmenth, segmentlistp[j],
186a90d965dSfw mdp, interleave, &segsize, segbase);
1870d63ce2bSvenki }
1880d63ce2bSvenki
1890d63ce2bSvenki /*
1900d63ce2bSvenki * Add TransferSize and Size (total memory) to this node.
1910d63ce2bSvenki */
192a90d965dSfw add_memory_props(memh, memorylistp[0], mdp, memsize);
1930d63ce2bSvenki
1940d63ce2bSvenki free(buf);
1950d63ce2bSvenki return (PICL_WALK_CONTINUE);
1960d63ce2bSvenki }
1970d63ce2bSvenki
1980d63ce2bSvenki 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)199a90d965dSfw add_bank_props(picl_nodehdl_t bankh, mde_cookie_t banklistp,
200a90d965dSfw md_t *mdp, uint64_t *size, uint64_t *mask, unsigned int id)
2010d63ce2bSvenki {
2020d63ce2bSvenki uint64_t int_value;
2030d63ce2bSvenki mde_cookie_t *dimmlistp;
2040d63ce2bSvenki int node_count, i, type_size, nac_size, status;
2050d63ce2bSvenki uint8_t *type;
2060d63ce2bSvenki char *pc, *nac;
207a90d965dSfw picl_prophdl_t dimmh;
2080d63ce2bSvenki
2090d63ce2bSvenki *size = 0ULL;
2100d63ce2bSvenki *mask = 0ULL;
2110d63ce2bSvenki
2120d63ce2bSvenki node_count = md_node_count(mdp);
2130d63ce2bSvenki dimmlistp = (mde_cookie_t *)malloc(node_count * sizeof (mde_cookie_t));
214*2ea390f3SMichael Bergknoff if (dimmlistp == NULL) {
215*2ea390f3SMichael Bergknoff pri_debug(LOG_NOTICE,
216*2ea390f3SMichael Bergknoff "add_bank_props: can't allocate memory\n");
217*2ea390f3SMichael Bergknoff return;
218*2ea390f3SMichael Bergknoff }
2190d63ce2bSvenki
2200d63ce2bSvenki if (!md_get_prop_val(mdp, banklistp, "size", &int_value)) {
221a90d965dSfw add_md_prop(bankh, sizeof (int_value), PICL_PROP_SIZE,
2220d63ce2bSvenki &int_value, PICL_PTYPE_UNSIGNED_INT);
2230d63ce2bSvenki *size = int_value;
2240d63ce2bSvenki }
2250d63ce2bSvenki if (!md_get_prop_val(mdp, banklistp, "mask",
2260d63ce2bSvenki &int_value)) {
227a90d965dSfw add_md_prop(bankh, sizeof (int_value),
2280d63ce2bSvenki PICL_PROP_ADDRESSMASK,
2290d63ce2bSvenki &int_value, PICL_PTYPE_UNSIGNED_INT);
2300d63ce2bSvenki *mask = int_value;
2310d63ce2bSvenki }
2320d63ce2bSvenki if (!md_get_prop_val(mdp, banklistp, "match",
2330d63ce2bSvenki &int_value)) {
234a90d965dSfw add_md_prop(bankh, sizeof (int_value),
2350d63ce2bSvenki PICL_PROP_ADDRESSMATCH,
2360d63ce2bSvenki &int_value, PICL_PTYPE_UNSIGNED_INT);
2370d63ce2bSvenki }
2380d63ce2bSvenki
239a90d965dSfw add_md_prop(bankh, sizeof (id), PICL_PROP_ID, &id,
2400d63ce2bSvenki PICL_PTYPE_INT);
2410d63ce2bSvenki
2420d63ce2bSvenki node_count = md_scan_dag(mdp, banklistp, md_find_name(mdp, "component"),
2430d63ce2bSvenki md_find_name(mdp, "fwd"), dimmlistp);
2440d63ce2bSvenki
2450d63ce2bSvenki for (i = 0; i < node_count; ++i) {
246a90d965dSfw status = md_get_prop_str(mdp, dimmlistp[i], "type",
247a90d965dSfw (char **)&type);
248a90d965dSfw if (status == -1) {
2490d63ce2bSvenki status = md_get_prop_data(mdp, dimmlistp[i],
2500d63ce2bSvenki "type", &type, &type_size);
2510d63ce2bSvenki }
252a90d965dSfw if (status == -1) /* can't get node type - just skip */
253a90d965dSfw continue;
254a90d965dSfw if (strcmp((const char *)type, "dimm") == 0) {
255a90d965dSfw if (md_get_prop_str(mdp, dimmlistp[i], "nac",
256a90d965dSfw (char **)&nac) == 0) {
257a90d965dSfw nac_size = strlen(nac) + 1;
258a90d965dSfw if (ptree_create_and_add_node(bankh,
259a90d965dSfw PICL_NAME_MEMORY_MODULE,
260a90d965dSfw PICL_CLASS_MEMORY_MODULE, &dimmh) ==
261a90d965dSfw PICL_SUCCESS) {
262a90d965dSfw add_md_prop(dimmh, nac_size,
2630d63ce2bSvenki "nac", nac,
2640d63ce2bSvenki PICL_PTYPE_CHARSTRING);
2650d63ce2bSvenki if ((pc = strrchr(nac, '/')) != NULL)
2660d63ce2bSvenki nac = ++pc;
2670d63ce2bSvenki nac_size = strlen(nac) + 1;
268a90d965dSfw add_md_prop(dimmh, nac_size,
2690d63ce2bSvenki PICL_PROP_LABEL, nac,
2700d63ce2bSvenki PICL_PTYPE_CHARSTRING);
2710d63ce2bSvenki }
2720d63ce2bSvenki }
2730d63ce2bSvenki }
2740d63ce2bSvenki }
275*2ea390f3SMichael Bergknoff free(dimmlistp);
2760d63ce2bSvenki }
2770d63ce2bSvenki
2780d63ce2bSvenki static uint64_t
countbits(uint64_t v)2790d63ce2bSvenki countbits(uint64_t v)
2800d63ce2bSvenki {
2810d63ce2bSvenki uint64_t c; /* c accumulates the total bits set in v */
2820d63ce2bSvenki
2830d63ce2bSvenki for (c = 0; v; c++)
2840d63ce2bSvenki v &= v - 1; /* clear the least significant bit set */
2850d63ce2bSvenki return (c);
2860d63ce2bSvenki }
2870d63ce2bSvenki
2880d63ce2bSvenki 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)2890d63ce2bSvenki add_segment_props(picl_nodehdl_t node, mde_cookie_t segmentlistp,
290a90d965dSfw md_t *mdp, uint64_t interleave, uint64_t *size, uint64_t base)
2910d63ce2bSvenki {
2920d63ce2bSvenki uint64_t int_value;
2930d63ce2bSvenki
2940d63ce2bSvenki *size = 0;
2950d63ce2bSvenki if (!md_get_prop_val(mdp, segmentlistp, "size", &int_value)) {
2960d63ce2bSvenki add_md_prop(node, sizeof (int_value),
2970d63ce2bSvenki PICL_PROP_SIZE, &int_value,
2980d63ce2bSvenki PICL_PTYPE_UNSIGNED_INT);
2990d63ce2bSvenki *size = int_value;
3000d63ce2bSvenki }
3010d63ce2bSvenki add_md_prop(node, sizeof (base), PICL_PROP_BASEADDRESS,
302a90d965dSfw &base, PICL_PTYPE_UNSIGNED_INT);
3030d63ce2bSvenki
3040d63ce2bSvenki add_md_prop(node, sizeof (interleave), PICL_PROP_INTERLEAVE_FACTOR,
305a90d965dSfw &interleave, PICL_PTYPE_UNSIGNED_INT);
3060d63ce2bSvenki }
3070d63ce2bSvenki
3080d63ce2bSvenki static void
add_memory_props(picl_nodehdl_t node,mde_cookie_t memorylistp,md_t * mdp,uint64_t size)309a90d965dSfw add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, md_t *mdp,
310a90d965dSfw uint64_t size)
3110d63ce2bSvenki {
3120d63ce2bSvenki uint64_t int_value;
3130d63ce2bSvenki
3140d63ce2bSvenki /*
3150d63ce2bSvenki * If the top-level node has a size property then use that,
3160d63ce2bSvenki * otherwise use the size that was calculated by the caller
3170d63ce2bSvenki * and passed in.
3180d63ce2bSvenki */
3190d63ce2bSvenki if (md_get_prop_val(mdp, memorylistp, "size", &int_value))
3200d63ce2bSvenki int_value = size;
3210d63ce2bSvenki add_md_prop(node, sizeof (int_value), PICL_PROP_SIZE, &int_value,
322a90d965dSfw PICL_PTYPE_UNSIGNED_INT);
3230d63ce2bSvenki if (!md_get_prop_val(mdp, memorylistp, "transfer_size",
3240d63ce2bSvenki &int_value)) {
3250d63ce2bSvenki add_md_prop(node, sizeof (int_value),
3260d63ce2bSvenki PICL_PROP_TRANSFER_SIZE,
3270d63ce2bSvenki &int_value, PICL_PTYPE_UNSIGNED_INT);
3280d63ce2bSvenki }
3290d63ce2bSvenki }
330