mcamd_patounum.c revision 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * CDDL HEADER START
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * The contents of this file are subject to the terms of the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Common Development and Distribution License, Version 1.0 only
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * (the "License"). You may not use this file except in compliance
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * with the License.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * or http://www.opensolaris.org/os/licensing.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * See the License for the specific language governing permissions
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * and limitations under the License.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * When distributing Covered Code, include this CDDL HEADER in each
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If applicable, add the following below this CDDL HEADER, with the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * fields enclosed by brackets "[]" replaced with your own identifying
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * information: Portions Copyright [yyyy] [name of copyright owner]
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * CDDL HEADER END
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Use is subject to license terms.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#pragma ident "%Z%%M% %I% %E% SMI"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Given a physical address and an optional syndrome, determine the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * name of the memory module that contains it.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/errno.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/types.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <sys/mc.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <mcamd_api.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <mcamd_err.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiextern int mc_pa_to_offset(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_node_t *, uint64_t, uint64_t *);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#define LO_DIMM 0x1
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#define UP_DIMM 0x2
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#define BITS(val, high, low) \
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi ((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1)))
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiiaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t *iaddrp)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t orig = pa;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t mcnum, base, lim, dramaddr, ilen, ilsel, top, dramhole;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &base) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &lim) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &ilen) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, &ilsel) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &dramhole)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "iaddr_gen: failed to "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "lookup required properties");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (pa < base || pa > lim) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx not "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "in range [0x%llx, 0x%llx] of MC %d\n", pa, base, lim,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (int)mcnum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Rev E and later added the DRAM Hole Address Register for
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * memory hoisting. In earlier revisions memory hoisting is
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * achieved by following some algorithm to modify the CS bases etc,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * and this pa to unum algorithm will simply see those modified
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * values. But if the Hole Address Register is being used then
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * we need to reduce any address at or above 4GB by the size of
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * the hole.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (dramhole & MC_DC_HOLE_VALID && pa >= 0x100000000) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t holesize = (dramhole & MC_DC_HOLE_OFFSET_MASK) <<
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi MC_DC_HOLE_OFFSET_LSHIFT;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi pa -= holesize;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: dram hole "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "valid; pa decremented from 0x%llx to 0x%llx for "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "a dramhole size of 0x%llx\n", orig, pa, holesize);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi dramaddr = BITS(pa, 39, 0) - BITS(base, 39, 24);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (ilen != 0) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int pailsel;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (ilen != 1 && ilen != 3 && ilen != 7) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "Invalid intlven "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "of %d for MC %d\n", (int)ilen, (int)mcnum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if ((pailsel = BITS(pa, 14, 12) >> 12 & ilen) != ilsel) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "PA 0x%llx in a %d-way node interleave indicates "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "selection %d, MC %d has ilsel of %d\n",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi pa, (int)ilen + 1, pailsel, (int)mcnum, (int)ilsel);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (ilen == 1)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi top = BITS(dramaddr, 36, 13) >> 1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi else if (ilen == 3)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi top = BITS(dramaddr, 37, 14) >> 2;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi else if (ilen == 7)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi top = BITS(dramaddr, 38, 15) >> 3;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } else {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi top = BITS(dramaddr, 35, 12);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *iaddrp = top | BITS(dramaddr, 11, 0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx in range "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "[0x%llx, 0x%llx] of MC %d; normalized address for cs compare "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "is 0x%llx\n", pa, base, lim, (int)mcnum, *iaddrp);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindics_match(struct mcamd_hdl *hdl, uint64_t iaddr, mcamd_node_t *cs)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t csnum, csbase, csmask;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int match;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, &csbase) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, &csmask)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_match: failed to lookup "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "required properties\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi match = ((iaddr & ~csmask) == (csbase & ~csmask));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx does "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "%smatch CS %d (base 0x%llx, mask 0x%llx)\n", iaddr,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi match ? "" : "not ", (int)csnum, csbase, csmask);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (match);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiunum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t iaddr, struct mc_unum *unump, int incloff)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_node_t *mc, *dimm;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t chipnum, csnum, lonum, upnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int i;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int offsetdimm;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if ((mc = mcamd_cs_mc(hdl, cs)) == NULL ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &chipnum) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "lookup required properties\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if ((which & LO_DIMM) &&
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, cs, MCAMD_PROP_LODIMM, &lonum) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (which & UP_DIMM) &&
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, cs, MCAMD_PROP_UPDIMM, &upnum)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "lookup lodimm/hidimm properties\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_board = 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_chip = chipnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_mc = 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_cs = csnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi for (i = 0; i < MC_UNUM_NDIMM; i++) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_dimms[i] = -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi switch (which) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case LO_DIMM:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_dimms[0] = lonum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi offsetdimm = lonum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case UP_DIMM:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_dimms[0] = upnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi offsetdimm = upnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case LO_DIMM | UP_DIMM:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_dimms[0] = lonum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_dimms[1] = upnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi offsetdimm = lonum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!incloff) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_offset = MCAMD_RC_INVALID_OFFSET;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * We wish to calculate a dimm offset. In the paired case we will
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * lookup the lodimm (see offsetdimm above).
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi dimm = mcamd_dimm_next(hdl, mc, dimm)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t dnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!mcamd_get_numprop(hdl, dimm, MCAMD_PROP_NUM, &dnum)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "to lookup dimm number property\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi continue;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (dnum == offsetdimm)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (dimm == NULL) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "find dimm with number %d for offset calculation\n",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi offsetdimm);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_offset = MCAMD_RC_INVALID_OFFSET;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * mc_pa_to_offset sets the offset to an invalid value if
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * it hits an error.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) mc_pa_to_offset(hdl, mc, cs, dimm, iaddr, &unump->unum_offset);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * We have translated a system address to a (node, chip-select). That
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * identifies one (in 64-bit MC mode) or two (in 128-bit MC mode DIMMs,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * either a lodimm or a lodimm/updimm pair. For all cases except an
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * uncorrectable ChipKill error we can interpret the address alignment and
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * syndrome to deduce whether we are on the lodimm or updimm.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindimc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t synd, int syndtype)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t accwidth;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint_t sym, pat;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int lobit, hibit, data, check;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_ACCESS_WIDTH, &accwidth) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (accwidth != 64 && accwidth != 128)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: failed "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "to lookup required properties\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * In 64 bit mode only LO dimms are occupied.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (accwidth == 64) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64-bit mode "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "therefore LO_DIMM\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (LO_DIMM);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (syndtype == AMD_SYNDTYPE_ECC) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * 64/8 ECC is checked separately for the upper and lower
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * halves, so even an uncorrectable error is contained within
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * one of the two halves. The error address is accurate to
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * 8 bytes, so bit 4 distinguises upper from lower.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64/8 ECC "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "and PA 0x%llx is in %s half\n", pa,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi pa & 8 ? "lower" : "upper");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (pa & 8 ? UP_DIMM : LO_DIMM);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * ChipKill ECC (necessarily in 128-bit mode.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * A correctable ChipKill syndrome and we can tell
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * which half the error was in from the symbol number.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (mcamd_cksym_decode(hdl, sym, &lobit, &hibit, &data,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi &check) == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (data && hibit <= 63 || check && hibit <= 7) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "ChipKill symbol %d (%s %d..%d), so LODIMM\n", sym,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi data ? "data" : "check", lobit, hibit);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (LO_DIMM);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } else {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "ChipKill symbol %d (%s %d..%d), so UPDIMM\n", sym,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi data ? "data" : "check", lobit, hibit);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (UP_DIMM);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } else {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * An uncorrectable error while in ChipKill ECC mode - can't
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * tell which dimm or dimms the errors lie within.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichhdimm: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "uncorrectable ChipKill, could be either LODIMM "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "or UPDIMM\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (LO_DIMM | UP_DIMM);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Brute-force BKDG pa to cs translation. The following is from BKDG 3.29
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * so is for revisions prior to F. It is coded to look as much like the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * BKDG code as possible.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindimc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t synd, int syndtype, struct mc_unum *unump)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int which;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t mcnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_node_t *cs;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Variables as per BKDG
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int Ilog;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t SystemAddr = (uint32_t)(pa >> 8);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t IntlvEn, IntlvSel;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t DramBase, DramLimit; /* assume DramEn */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t HoleOffset, HoleEn;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t CSBase, CSMask; /* assuume CSBE */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t InputAddr, Temp;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Additional variables which we need since we will reading
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * MC properties instead of PCI config space, and the MC properties
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * are stored in a cooked state.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t prop_drambase, prop_dramlimit, prop_dramhole;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t prop_intlven, prop_intlvsel;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t prop_csbase, prop_csmask;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &prop_drambase) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &prop_dramlimit) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &prop_dramhole) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &prop_intlven) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi &prop_intlvsel)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: failed "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "to lookup required properties\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Brute force deconstruction of the MC properties. If we decide to
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * keep this then we need some of the mcamd.g defines available to us.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi DramBase = ((prop_drambase >> 8) & 0xffff0000) | (prop_intlven << 8);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi IntlvEn = (DramBase & 0x00000700) >> 8;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi DramBase &= 0xffff0000;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi DramLimit = ((prop_dramlimit >> 8) & 0xffff0000) | (prop_intlvsel << 8);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi IntlvSel = (DramLimit & 0x00000700) >> 8;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi DramLimit |= 0x0000ffff;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi HoleEn = prop_dramhole; /* uncooked */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi HoleOffset = (HoleEn & 0x0000ff00) << 8;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi HoleEn &= 0x00000001;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!(DramBase <= SystemAddr && SystemAddr <= DramLimit)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "SystemAddr 0x%x derived from PA 0x%llx is not in the "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "address range [0x%x, 0x%x] of MC %d\n",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi SystemAddr, pa, DramBase, DramLimit, (int)mcnum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (IntlvEn) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (IntlvSel == ((SystemAddr >> 4) & IntlvEn)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi switch (IntlvEn) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case 1:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi Ilog = 1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case 3:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi Ilog = 2;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case 7:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi Ilog = 3;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi default:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi Temp = (SystemAddr >> (4 + Ilog)) << 4;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi InputAddr = (Temp | (SystemAddr & 0x0000000f)) << 4;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } else {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* not this node */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "Node interleaving, MC node %d not selected\n",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (int)mcnum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } else {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* No interleave */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi InputAddr = (SystemAddr - DramBase) << 4;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (HoleEn && SystemAddr > 0x00ffffff)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi InputAddr -= HoleOffset;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi cs = mcamd_cs_next(hdl, mc, cs)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t csnum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi &prop_csbase) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi &prop_csmask) ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "failed to read cs properties\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi CSBase = ((prop_csbase >> 4) & 0xffe00000) |
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi ((prop_csbase >> 4) & 0x0000fe00);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi CSBase &= 0xffe0fe00;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi CSMask = ((prop_csmask >> 4) & 0x3fe00000) |
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi ((prop_csmask >> 4) & 0x0000fe00);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi CSMask = (CSMask | 0x001f01ff) & 0x3fffffff;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (((InputAddr & ~CSMask) == (CSBase & ~CSMask))) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "match for chip select %d of MC %d\n", (int)csnum,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (int)mcnum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if ((which = mc_whichdimm(hdl, mc, pa, synd,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi syndtype)) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1); /* errno is set for us */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * The BKDG algorithm drops low-order bits that
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * are unimportant in deriving chip-select but are
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * included in row/col/bank mapping, so do not
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * perform offset calculation in this case.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (unum_fill(hdl, cs, which, InputAddr, unump, 0) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1); /* errno is set for us */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounum: in range "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "for MC %d but no cs responds\n", (int)mcnum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/*ARGSUSED*/
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindimc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t synd, int syndtype, struct mc_unum *unump)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint64_t iaddr;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_node_t *cs;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int which;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#ifdef DEBUG
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct mc_unum bkdg_unum;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int bkdgres;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /*
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * We perform the translation twice, once using the brute-force
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * approach of the BKDG and again using a more elegant but more
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * difficult to review against the BKDG approach. Note that both
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * approaches need to change for rev F since it increases max CS
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * size and so iaddr calculation etc changes.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi bkdgres = mc_bkdg_patounum(hdl, mc, pa, synd, syndtype, &bkdg_unum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method ends\n");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#endif
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (iaddr_gen(hdl, mc, pa, &iaddr) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1); /* errno is set for us */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi cs = mcamd_cs_next(hdl, mc, cs)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (cs_match(hdl, iaddr, cs))
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (cs == NULL)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if ((which = mc_whichdimm(hdl, mc, pa, synd, syndtype)) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1); /* errno is set for us */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (unum_fill(hdl, cs, which, iaddr, unump, 1) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1); /* errno is set for us */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#ifdef DEBUG
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "bkdgres=%d res=0\n", bkdgres);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#ifndef _KERNEL
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* offset is not checked - see note in BKDG algorithm */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi assert(bkdgres == 0 && unump->unum_board == bkdg_unum.unum_board &&
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_chip == bkdg_unum.unum_chip &&
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_mc == bkdg_unum.unum_mc &&
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_cs == bkdg_unum.unum_cs &&
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_dimms[0] == bkdg_unum.unum_dimms[0] &&
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_dimms[1] == bkdg_unum.unum_dimms[1]);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#endif /* !_KERNEL */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#endif /* DEBUG */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Result: chip %d mc %d cs %d "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "offset 0x%llx\n", unump->unum_chip, unump->unum_mc,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unump->unum_cs, unump->unum_offset);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiint
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindimcamd_patounum(struct mcamd_hdl *hdl, mcamd_node_t *root, uint64_t pa,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint32_t synd, int syndtype, struct mc_unum *unump)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_node_t *mc;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: pa=0x%llx, "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "synd=0x%x, syndtype=%d\n", pa, synd, syndtype);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!mcamd_synd_validate(hdl, synd, syndtype))
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mc = mcamd_mc_next(hdl, root, mc)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (mc_patounum(hdl, mc, pa, synd, syndtype, unump) == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (mcamd_errno(hdl) != EMCAMD_NOADDR)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1); /* errno is set for us */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}