xref: /illumos-gate/usr/src/common/mc/mc-amd/mcamd_unumtopa.c (revision dd72704bd9e794056c558153663c739e2012d721)
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 /*
26  * Given a unum including an offset calculate the associated system
27  * address.  This may be different to when the original PA to unum
28  * calculation took place if interleave etc has changed.
29  */
30 
31 #include <sys/errno.h>
32 #include <sys/types.h>
33 #include <sys/mc.h>
34 
35 #include <mcamd_api.h>
36 #include <mcamd_err.h>
37 
38 /*
39  * The submitted unum must have the MC and DIMM numbers and an offset.
40  * Any cs info it has will not be used - we will reconstruct cs info.
41  * This is because cs is not in the topology used for diagnosis.
42  */
43 int
44 mcamd_unumtopa(struct mcamd_hdl *hdl, mcamd_node_t *root, mc_unum_t *unump,
45     uint64_t *pa)
46 {
47 	mcamd_node_t *mc, *dimm;
48 	uint64_t num, holesz;
49 
50 	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: chip %d "
51 	    "mc %d dimm %d offset 0x%llx\n", unump->unum_chip, unump->unum_mc,
52 	    unump->unum_dimms[0], unump->unum_offset);
53 
54 	if (!MCAMD_RC_OFFSET_VALID(unump->unum_offset)) {
55 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: offset "
56 		    "invalid\n");
57 		return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
58 	}
59 
60 	/*
61 	 * Search current config for a MC number matching the chip in the
62 	 * unum.
63 	 */
64 	for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL;
65 	    mc = mcamd_mc_next(hdl, root, mc)) {
66 		if (!mcamd_get_numprops(hdl,
67 		    mc, MCAMD_PROP_NUM, &num,
68 		    mc, MCAMD_PROP_DRAMHOLE_SIZE, &holesz,
69 		    NULL)) {
70 			mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: "
71 			    "failed to lookup num, dramhole for MC 0x%p\n", mc);
72 			return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
73 		}
74 		if (num == unump->unum_chip)
75 			break;
76 	}
77 	if (mc == NULL) {
78 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; "
79 		    "no match for MC %d\n", unump->unum_chip);
80 		return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
81 	}
82 
83 	/*
84 	 * Search DIMMs of this MC.  We can match against the
85 	 * first dimm in the unum - if there is more than one they all
86 	 * share the same chip-selects anyway and the pa we will resolve
87 	 * to is not finer grained than the 128-bits of a dimm pair.
88 	 */
89 	for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL;
90 	    dimm = mcamd_dimm_next(hdl, mc, dimm)) {
91 		if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &num)) {
92 			mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: "
93 			    "failed to lookup num for dimm 0xx%p\n",
94 			    dimm);
95 			return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
96 		}
97 		if (num == unump->unum_dimms[0])
98 			break;
99 	}
100 	if (dimm == NULL) {
101 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; "
102 		    "no match for dimm %d cs %d on MC %d\n",
103 		    unump->unum_dimms[0], unump->unum_cs, unump->unum_chip);
104 		return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
105 	}
106 
107 	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: matched "
108 	    "mc 0x%p dimm 0x%p; resolving offset 0x%llx\n",
109 	    mc, dimm, unump->unum_offset);
110 
111 	if (mc_offset_to_pa(hdl, mc, dimm, unump->unum_offset, pa) < 0) {
112 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: "
113 		    "mc_offset_to_pa failed: %s\n", mcamd_errmsg(hdl));
114 		return (-1);	/* errno already set */
115 	}
116 
117 	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: "
118 	    "mc_offset_to_pa succeeded and returned pa=0x%llx: %\n",
119 	    *pa);
120 
121 	/*
122 	 * If this MC has a dram address hole just below 4GB then we must
123 	 * hoist all address from the hole start upwards by the hole size
124 	 */
125 	if (holesz != 0) {
126 		if (*pa >= 0x100000000 - holesz)
127 			*pa += holesz;
128 		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_untopa: hoist "
129 		    "above dram hole of size 0x%llx to get pa=0x%llx",
130 		    holesz, *pa);
131 	}
132 
133 	return (0);
134 }
135