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