17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
5*8a40a695Sgavinm  * Common Development and Distribution License (the "License").
6*8a40a695Sgavinm  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  *
217aec1d6eScindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
227aec1d6eScindi  * Use is subject to license terms.
237aec1d6eScindi  */
247aec1d6eScindi 
257aec1d6eScindi /*
267aec1d6eScindi  * Given a unum including an offset calculate the associated system
277aec1d6eScindi  * address.  This may be different to when the original PA to unum
287aec1d6eScindi  * calculation took place if interleave etc has changed.
297aec1d6eScindi  */
307aec1d6eScindi 
317aec1d6eScindi #include <sys/errno.h>
327aec1d6eScindi #include <sys/types.h>
337aec1d6eScindi #include <sys/mc.h>
347aec1d6eScindi 
357aec1d6eScindi #include <mcamd_api.h>
367aec1d6eScindi #include <mcamd_err.h>
377aec1d6eScindi 
387aec1d6eScindi /*
397aec1d6eScindi  * The submitted unum must have the MC and DIMM numbers and an offset.
407aec1d6eScindi  * Any cs info it has will not be used - we will reconstruct cs info.
417aec1d6eScindi  * This is because cs is not in the topology used for diagnosis.
427aec1d6eScindi  */
437aec1d6eScindi int
mcamd_unumtopa(struct mcamd_hdl * hdl,mcamd_node_t * root,mc_unum_t * unump,uint64_t * pa)44*8a40a695Sgavinm mcamd_unumtopa(struct mcamd_hdl *hdl, mcamd_node_t *root, mc_unum_t *unump,
457aec1d6eScindi     uint64_t *pa)
467aec1d6eScindi {
477aec1d6eScindi 	mcamd_node_t *mc, *dimm;
48*8a40a695Sgavinm 	uint64_t num, holesz;
497aec1d6eScindi 
507aec1d6eScindi 	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: chip %d "
517aec1d6eScindi 	    "mc %d dimm %d offset 0x%llx\n", unump->unum_chip, unump->unum_mc,
527aec1d6eScindi 	    unump->unum_dimms[0], unump->unum_offset);
537aec1d6eScindi 
547aec1d6eScindi 	if (!MCAMD_RC_OFFSET_VALID(unump->unum_offset)) {
55*8a40a695Sgavinm 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: offset "
56*8a40a695Sgavinm 		    "invalid\n");
577aec1d6eScindi 		return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
587aec1d6eScindi 	}
597aec1d6eScindi 
607aec1d6eScindi 	/*
617aec1d6eScindi 	 * Search current config for a MC number matching the chip in the
62*8a40a695Sgavinm 	 * unum.
637aec1d6eScindi 	 */
647aec1d6eScindi 	for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL;
657aec1d6eScindi 	    mc = mcamd_mc_next(hdl, root, mc)) {
66*8a40a695Sgavinm 		if (!mcamd_get_numprops(hdl,
67*8a40a695Sgavinm 		    mc, MCAMD_PROP_NUM, &num,
68*8a40a695Sgavinm 		    mc, MCAMD_PROP_DRAMHOLE_SIZE, &holesz,
69*8a40a695Sgavinm 		    NULL)) {
707aec1d6eScindi 			mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: "
717aec1d6eScindi 			    "failed to lookup num, dramhole for MC 0x%p\n", mc);
727aec1d6eScindi 			return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
737aec1d6eScindi 		}
747aec1d6eScindi 		if (num == unump->unum_chip)
757aec1d6eScindi 			break;
767aec1d6eScindi 	}
777aec1d6eScindi 	if (mc == NULL) {
787aec1d6eScindi 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; "
797aec1d6eScindi 		    "no match for MC %d\n", unump->unum_chip);
807aec1d6eScindi 		return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
817aec1d6eScindi 	}
827aec1d6eScindi 
837aec1d6eScindi 	/*
847aec1d6eScindi 	 * Search DIMMs of this MC.  We can match against the
857aec1d6eScindi 	 * first dimm in the unum - if there is more than one they all
867aec1d6eScindi 	 * share the same chip-selects anyway and the pa we will resolve
877aec1d6eScindi 	 * to is not finer grained than the 128-bits of a dimm pair.
887aec1d6eScindi 	 */
897aec1d6eScindi 	for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL;
907aec1d6eScindi 	    dimm = mcamd_dimm_next(hdl, mc, dimm)) {
917aec1d6eScindi 		if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &num)) {
927aec1d6eScindi 			mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: "
937aec1d6eScindi 			    "failed to lookup num for dimm 0xx%p\n",
947aec1d6eScindi 			    dimm);
957aec1d6eScindi 			return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
967aec1d6eScindi 		}
977aec1d6eScindi 		if (num == unump->unum_dimms[0])
987aec1d6eScindi 			break;
997aec1d6eScindi 	}
1007aec1d6eScindi 	if (dimm == NULL) {
1017aec1d6eScindi 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; "
1027aec1d6eScindi 		    "no match for dimm %d cs %d on MC %d\n",
1037aec1d6eScindi 		    unump->unum_dimms[0], unump->unum_cs, unump->unum_chip);
1047aec1d6eScindi 		return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
1057aec1d6eScindi 	}
1067aec1d6eScindi 
1077aec1d6eScindi 	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: matched "
1087aec1d6eScindi 	    "mc 0x%p dimm 0x%p; resolving offset 0x%llx\n",
1097aec1d6eScindi 	    mc, dimm, unump->unum_offset);
1107aec1d6eScindi 
1117aec1d6eScindi 	if (mc_offset_to_pa(hdl, mc, dimm, unump->unum_offset, pa) < 0) {
1127aec1d6eScindi 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: "
1137aec1d6eScindi 		    "mc_offset_to_pa failed: %s\n", mcamd_errmsg(hdl));
1147aec1d6eScindi 		return (-1);	/* errno already set */
1157aec1d6eScindi 	}
1167aec1d6eScindi 
1177aec1d6eScindi 	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: "
1187aec1d6eScindi 	    "mc_offset_to_pa succeeded and returned pa=0x%llx: %\n",
1197aec1d6eScindi 	    *pa);
1207aec1d6eScindi 
1217aec1d6eScindi 	/*
1227aec1d6eScindi 	 * If this MC has a dram address hole just below 4GB then we must
1237aec1d6eScindi 	 * hoist all address from the hole start upwards by the hole size
1247aec1d6eScindi 	 */
125*8a40a695Sgavinm 	if (holesz != 0) {
126*8a40a695Sgavinm 		if (*pa >= 0x100000000 - holesz)
127*8a40a695Sgavinm 			*pa += holesz;
1287aec1d6eScindi 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_untopa: hoist "
1297aec1d6eScindi 		    "above dram hole of size 0x%llx to get pa=0x%llx",
130*8a40a695Sgavinm 		    holesz, *pa);
1317aec1d6eScindi 	}
1327aec1d6eScindi 
1337aec1d6eScindi 	return (0);
1347aec1d6eScindi }
135