| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * |
| * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| * or http://www.opensolaris.org/os/licensing. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * |
| * When distributing Covered Code, include this CDDL HEADER in each |
| * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| * If applicable, add the following below this CDDL HEADER, with the |
| * fields enclosed by brackets "[]" replaced with your own identifying |
| * information: Portions Copyright [yyyy] [name of copyright owner] |
| * |
| * CDDL HEADER END |
| * |
| * Copyright 2006 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| /* |
| * Given a unum including an offset calculate the associated system |
| * address. This may be different to when the original PA to unum |
| * calculation took place if interleave etc has changed. |
| */ |
| |
| #include <sys/errno.h> |
| #include <sys/types.h> |
| #include <sys/mc.h> |
| |
| #include <mcamd_api.h> |
| #include <mcamd_err.h> |
| |
| /* |
| * The submitted unum must have the MC and DIMM numbers and an offset. |
| * Any cs info it has will not be used - we will reconstruct cs info. |
| * This is because cs is not in the topology used for diagnosis. |
| */ |
| int |
| mcamd_unumtopa(struct mcamd_hdl *hdl, mcamd_node_t *root, mc_unum_t *unump, |
| uint64_t *pa) |
| { |
| mcamd_node_t *mc, *dimm; |
| uint64_t num, holesz; |
| |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: chip %d " |
| "mc %d dimm %d offset 0x%llx\n", unump->unum_chip, unump->unum_mc, |
| unump->unum_dimms[0], unump->unum_offset); |
| |
| if (!MCAMD_RC_OFFSET_VALID(unump->unum_offset)) { |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: offset " |
| "invalid\n"); |
| return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); |
| } |
| |
| /* |
| * Search current config for a MC number matching the chip in the |
| * unum. |
| */ |
| for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL; |
| mc = mcamd_mc_next(hdl, root, mc)) { |
| if (!mcamd_get_numprops(hdl, |
| mc, MCAMD_PROP_NUM, &num, |
| mc, MCAMD_PROP_DRAMHOLE_SIZE, &holesz, |
| NULL)) { |
| mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " |
| "failed to lookup num, dramhole for MC 0x%p\n", mc); |
| return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); |
| } |
| if (num == unump->unum_chip) |
| break; |
| } |
| if (mc == NULL) { |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " |
| "no match for MC %d\n", unump->unum_chip); |
| return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); |
| } |
| |
| /* |
| * Search DIMMs of this MC. We can match against the |
| * first dimm in the unum - if there is more than one they all |
| * share the same chip-selects anyway and the pa we will resolve |
| * to is not finer grained than the 128-bits of a dimm pair. |
| */ |
| for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL; |
| dimm = mcamd_dimm_next(hdl, mc, dimm)) { |
| if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &num)) { |
| mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_unumtopa: " |
| "failed to lookup num for dimm 0xx%p\n", |
| dimm); |
| return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID)); |
| } |
| if (num == unump->unum_dimms[0]) |
| break; |
| } |
| if (dimm == NULL) { |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa; " |
| "no match for dimm %d cs %d on MC %d\n", |
| unump->unum_dimms[0], unump->unum_cs, unump->unum_chip); |
| return (mcamd_set_errno(hdl, EMCAMD_NOADDR)); |
| } |
| |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: matched " |
| "mc 0x%p dimm 0x%p; resolving offset 0x%llx\n", |
| mc, dimm, unump->unum_offset); |
| |
| if (mc_offset_to_pa(hdl, mc, dimm, unump->unum_offset, pa) < 0) { |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " |
| "mc_offset_to_pa failed: %s\n", mcamd_errmsg(hdl)); |
| return (-1); /* errno already set */ |
| } |
| |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_unumtopa: " |
| "mc_offset_to_pa succeeded and returned pa=0x%llx: %\n", |
| *pa); |
| |
| /* |
| * If this MC has a dram address hole just below 4GB then we must |
| * hoist all address from the hole start upwards by the hole size |
| */ |
| if (holesz != 0) { |
| if (*pa >= 0x100000000 - holesz) |
| *pa += holesz; |
| mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_untopa: hoist " |
| "above dram hole of size 0x%llx to get pa=0x%llx", |
| holesz, *pa); |
| } |
| |
| return (0); |
| } |