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 #pragma ident "%Z%%M% %I% %E% SMI" 267aec1d6eScindi 277aec1d6eScindi /* 287aec1d6eScindi * Given a unum including an offset calculate the associated system 297aec1d6eScindi * address. This may be different to when the original PA to unum 307aec1d6eScindi * calculation took place if interleave etc has changed. 317aec1d6eScindi */ 327aec1d6eScindi 337aec1d6eScindi #include <sys/errno.h> 347aec1d6eScindi #include <sys/types.h> 357aec1d6eScindi #include <sys/mc.h> 367aec1d6eScindi 377aec1d6eScindi #include <mcamd_api.h> 387aec1d6eScindi #include <mcamd_err.h> 397aec1d6eScindi 407aec1d6eScindi /* 417aec1d6eScindi * The submitted unum must have the MC and DIMM numbers and an offset. 427aec1d6eScindi * Any cs info it has will not be used - we will reconstruct cs info. 437aec1d6eScindi * This is because cs is not in the topology used for diagnosis. 447aec1d6eScindi */ 457aec1d6eScindi int 46*8a40a695Sgavinm mcamd_unumtopa(struct mcamd_hdl *hdl, mcamd_node_t *root, mc_unum_t *unump, 477aec1d6eScindi uint64_t *pa) 487aec1d6eScindi { 497aec1d6eScindi mcamd_node_t *mc, *dimm; 50*8a40a695Sgavinm uint64_t num, holesz; 517aec1d6eScindi 527aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: chip %d " 537aec1d6eScindi "mc %d dimm %d offset 0x%llx\n", unump->unum_chip, unump->unum_mc, 547aec1d6eScindi unump->unum_dimms[0], unump->unum_offset); 557aec1d6eScindi 567aec1d6eScindi if (!MCAMD_RC_OFFSET_VALID(unump->unum_offset)) { 57*8a40a695Sgavinm mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: offset " 58*8a40a695Sgavinm "invalid\n"); 597aec1d6eScindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 607aec1d6eScindi } 617aec1d6eScindi 627aec1d6eScindi /* 637aec1d6eScindi * Search current config for a MC number matching the chip in the 64*8a40a695Sgavinm * unum. 657aec1d6eScindi */ 667aec1d6eScindi for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; 677aec1d6eScindi mc = mcamd_mc_next(hdl, root, mc)) { 68*8a40a695Sgavinm if (!mcamd_get_numprops(hdl, 69*8a40a695Sgavinm mc, MCAMD_PROP_NUM, &num, 70*8a40a695Sgavinm mc, MCAMD_PROP_DRAMHOLE_SIZE, &holesz, 71*8a40a695Sgavinm NULL)) { 727aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " 737aec1d6eScindi "failed to lookup num, dramhole for MC 0x%p\n", mc); 747aec1d6eScindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 757aec1d6eScindi } 767aec1d6eScindi if (num == unump->unum_chip) 777aec1d6eScindi break; 787aec1d6eScindi } 797aec1d6eScindi if (mc == NULL) { 807aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " 817aec1d6eScindi "no match for MC %d\n", unump->unum_chip); 827aec1d6eScindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 837aec1d6eScindi } 847aec1d6eScindi 857aec1d6eScindi /* 867aec1d6eScindi * Search DIMMs of this MC. We can match against the 877aec1d6eScindi * first dimm in the unum - if there is more than one they all 887aec1d6eScindi * share the same chip-selects anyway and the pa we will resolve 897aec1d6eScindi * to is not finer grained than the 128-bits of a dimm pair. 907aec1d6eScindi */ 917aec1d6eScindi for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL; 927aec1d6eScindi dimm = mcamd_dimm_next(hdl, mc, dimm)) { 937aec1d6eScindi if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &num)) { 947aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " 957aec1d6eScindi "failed to lookup num for dimm 0xx%p\n", 967aec1d6eScindi dimm); 977aec1d6eScindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 987aec1d6eScindi } 997aec1d6eScindi if (num == unump->unum_dimms[0]) 1007aec1d6eScindi break; 1017aec1d6eScindi } 1027aec1d6eScindi if (dimm == NULL) { 1037aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " 1047aec1d6eScindi "no match for dimm %d cs %d on MC %d\n", 1057aec1d6eScindi unump->unum_dimms[0], unump->unum_cs, unump->unum_chip); 1067aec1d6eScindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 1077aec1d6eScindi } 1087aec1d6eScindi 1097aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: matched " 1107aec1d6eScindi "mc 0x%p dimm 0x%p; resolving offset 0x%llx\n", 1117aec1d6eScindi mc, dimm, unump->unum_offset); 1127aec1d6eScindi 1137aec1d6eScindi if (mc_offset_to_pa(hdl, mc, dimm, unump->unum_offset, pa) < 0) { 1147aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " 1157aec1d6eScindi "mc_offset_to_pa failed: %s\n", mcamd_errmsg(hdl)); 1167aec1d6eScindi return (-1); /* errno already set */ 1177aec1d6eScindi } 1187aec1d6eScindi 1197aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " 1207aec1d6eScindi "mc_offset_to_pa succeeded and returned pa=0x%llx: %\n", 1217aec1d6eScindi *pa); 1227aec1d6eScindi 1237aec1d6eScindi /* 1247aec1d6eScindi * If this MC has a dram address hole just below 4GB then we must 1257aec1d6eScindi * hoist all address from the hole start upwards by the hole size 1267aec1d6eScindi */ 127*8a40a695Sgavinm if (holesz != 0) { 128*8a40a695Sgavinm if (*pa >= 0x100000000 - holesz) 129*8a40a695Sgavinm *pa += holesz; 1307aec1d6eScindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_untopa: hoist " 1317aec1d6eScindi "above dram hole of size 0x%llx to get pa=0x%llx", 132*8a40a695Sgavinm holesz, *pa); 1337aec1d6eScindi } 1347aec1d6eScindi 1357aec1d6eScindi return (0); 1367aec1d6eScindi } 137