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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 * 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Given a unum including an offset calculate the associated system 30 * address. This may be different to when the original PA to unum 31 * calculation took place if interleave etc has changed. 32 */ 33 34 #include <sys/errno.h> 35 #include <sys/types.h> 36 #include <sys/mc.h> 37 38 #include <mcamd_api.h> 39 #include <mcamd_err.h> 40 41 extern int mc_offset_to_pa(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *, 42 uint64_t, uint64_t *); 43 44 /* 45 * The submitted unum must have the MC and DIMM numbers and an offset. 46 * Any cs info it has will not be used - we will reconstruct cs info. 47 * This is because cs is not in the topology used for diagnosis. 48 */ 49 int 50 mcamd_unumtopa(struct mcamd_hdl *hdl, mcamd_node_t *root, struct mc_unum *unump, 51 uint64_t *pa) 52 { 53 mcamd_node_t *mc, *dimm; 54 uint64_t num, hole; 55 56 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: chip %d " 57 "mc %d dimm %d offset 0x%llx\n", unump->unum_chip, unump->unum_mc, 58 unump->unum_dimms[0], unump->unum_offset); 59 60 if (!MCAMD_RC_OFFSET_VALID(unump->unum_offset)) { 61 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Offset invalid\n"); 62 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 63 } 64 65 /* 66 * Search current config for a MC number matching the chip in the 67 * unum. MC property num is by chip, not MC on chip. 68 */ 69 for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; 70 mc = mcamd_mc_next(hdl, root, mc)) { 71 if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &num) || 72 !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &hole)) { 73 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " 74 "failed to lookup num, dramhole for MC 0x%p\n", mc); 75 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 76 } 77 if (num == unump->unum_chip) 78 break; 79 } 80 if (mc == NULL) { 81 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " 82 "no match for MC %d\n", unump->unum_chip); 83 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 84 } 85 86 /* 87 * Search DIMMs of this MC. We can match against the 88 * first dimm in the unum - if there is more than one they all 89 * share the same chip-selects anyway and the pa we will resolve 90 * to is not finer grained than the 128-bits of a dimm pair. 91 */ 92 for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL; 93 dimm = mcamd_dimm_next(hdl, mc, dimm)) { 94 if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &num)) { 95 mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " 96 "failed to lookup num for dimm 0xx%p\n", 97 dimm); 98 return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); 99 } 100 if (num == unump->unum_dimms[0]) 101 break; 102 } 103 if (dimm == NULL) { 104 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " 105 "no match for dimm %d cs %d on MC %d\n", 106 unump->unum_dimms[0], unump->unum_cs, unump->unum_chip); 107 return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); 108 } 109 110 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: matched " 111 "mc 0x%p dimm 0x%p; resolving offset 0x%llx\n", 112 mc, dimm, unump->unum_offset); 113 114 if (mc_offset_to_pa(hdl, mc, dimm, unump->unum_offset, pa) < 0) { 115 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " 116 "mc_offset_to_pa failed: %s\n", mcamd_errmsg(hdl)); 117 return (-1); /* errno already set */ 118 } 119 120 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " 121 "mc_offset_to_pa succeeded and returned pa=0x%llx: %\n", 122 *pa); 123 124 /* 125 * If this MC has a dram address hole just below 4GB then we must 126 * hoist all address from the hole start upwards by the hole size 127 */ 128 if (hole & MC_DC_HOLE_VALID) { 129 uint64_t hsz = (hole & MC_DC_HOLE_OFFSET_MASK) << 130 MC_DC_HOLE_OFFSET_LSHIFT; 131 if (*pa >= 0x100000000 - hsz) 132 *pa += hsz; 133 mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_untopa: hoist " 134 "above dram hole of size 0x%llx to get pa=0x%llx", 135 hsz, *pa); 136 } 137 138 return (0); 139 } 140