xref: /illumos-gate/usr/src/common/mc/mc-amd/mcamd_unumtopa.c (revision 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe)
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