Home | History | Annotate | Download | only in mc-amd
      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	"@(#)mcamd_unumtopa.c	1.2	06/10/06 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