mcamd_rowcol.c revision 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* 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"
#include <mcamd_api.h>
#include <mcamd_err.h>
#include <mcamd_rowcol_impl.h>
/*
* Convenience structures to stash MC and CS properties in. Some of these
* are read directly, while others are then calculated.
*/
struct rcp_mc {
int bnkswzl; /* bank-swizzle mode - derived */
};
struct rcp_cs {
};
static int
{
&pp->csintlvfctr)) {
}
return (0);
}
static int
{
}
return (0);
}
static int
{
"table for MC rev %d csmode %d\n", caller,
}
"table for MC rev %d csmode %d\n", caller,
}
if (csid) {
if (mcpp->csintlvfctr != 0) {
if (csid->csi_factor == 0) {
"could not work out cs interleave "
"paramters for MC rev %d, width %d, "
"csmode %d, factor %d\n", caller,
(int)mcpp->csintlvfctr);
}
} else {
csid->csi_factor = 0;
}
}
return (0);
}
static uint64_t
{
return (add);
}
/*
* earlier only) we will assign the "floating" bit to row address. If
* we adopt the same convention in address reconstruction then all should work.
*/
static uint32_t
{
int swapped = 0;
swapped++;
}
}
return (addr);
}
/*ARGSUSED*/
static uint64_t
{
continue;
}
}
return (iaddr);
}
static uint32_t
{
/*
* Knock off a column bit if the numbers are ambiguous
*/
nbits--;
if (abitno == MC_PC_COLADDRBIT)
bias = 1;
}
return (addr);
}
/*ARGSUSED*/
static uint64_t
{
/*
* Knock off a column bit if the numbers are ambiguous
*/
nbits--;
continue;
if (abitno == MC_PC_COLADDRBIT)
bias = 1;
}
return (iaddr);
}
/*
* Extract bank bit arguments and xor them together. Tables for
* non bank-swizzling should have all but the first argument zero.
*/
static uint32_t
{
for (i = 0; i < bnkargs; i++) {
}
}
return (addr);
}
/*
* bank_to_iaddr requires the iaddr reconstructed thus far with at least the
* row bits repopulated. That's because in bank swizzle mode
* the bank bits are the result of xor'ing three original iaddr bits
* together - two of which come from the row address and the third we
* can reconstruct here. Note that a zero bankaddr bit *can* result
* in a nonzero iaddr bit (unlike in row and col reconstruction).
*/
/*ARGSUSED*/
static uint64_t
{
if (bnkswzl) {
for (i = 1; i < MC_RC_BANKARGS; i++) {
}
}
if (val)
}
return (iaddr);
}
static int
{
const struct bankaddr_mode *bamp;
struct csintlv_desc csi;
return (-1); /* errno already set */
return (0);
}
/*
* Take a reconstructed InputAddr and undo the normalization described in
* BKDG 3.29 3.4.4 to include the base address of the MC if no node
* interleave or to insert the node interleave selection bits.
*/
static int
{
int intlvbits;
case 0x0:
intlvbits = 0;
break;
case 0x1:
intlvbits = 1;
break;
case 0x3:
intlvbits = 2;
break;
case 0x7:
intlvbits = 3;
break;
default:
"illegal IntlvEn of %d for MC 0x%p\n",
}
if (intlvbits != 0) {
/*
* For a 2/4/8 way interleave iaddr was formed by excising
* 1, 2, or 3 bits 12:12, 13:12, or 14:12 from dramaddr,
* the removed bits having done their job by selecting the
* responding node. So we must move bits 35:12 of the
* reconstructed iaddr up to make a 1, 2 or 3 bit hole and
* then fill those bits with the current IntlvSel value for
* this node. The node base address must be zero if nodes
* are interleaved.
*/
} else {
}
"intlven 0x%x intlvsel 0x%x MC base 0x%llx --> 0x%llx\n",
dramaddr);
return (0);
}
int
{
int rank;
return (-1); /* errno already set */
/*
* Convert chip-select number 0 .. 7 to a DIMM rank 0 .. 3. The
* rank is the index of the member of the dimm mcd_cs array which
* matches cs.
*/
return (-1); /* errno already set */
break;
}
if (rank == MC_CHIP_DIMMRANKMAX) {
"iteration over chip-selects of dimm 0x%p failed "
}
return (-1); /* errno already set */
return (0);
}
/*
* Given a MC and DIMM and offset (dimm rank, row, col, internal bank) we
* find the corresponding chip-select for the rank and then reconstruct
* a system address. In the absence of serial number support it is possible
* that we may be asked to perform this operation on a dimm which has been
* swapped, perhaps even for a dimm of different size and number of ranks.
* This may happen if fmadm repair has not been used. There are some
* unused bits in the offset and we could guard against this a little
* by recording in those bit some of the physical characteristic of the
* original DIMM such as size, number of ranks etc.
*/
int
{
int i;
const struct bankaddr_mode *bamp;
struct csintlv_desc csi;
int maskhi_hi = MC_DC_CSM_MASKHI_HIBIT;
int maskhi_lo = MC_DC_CSM_MASKHI_LOBIT;
int masklo_hi = MC_DC_CSM_MASKLO_HIBIT;
int masklo_lo = MC_DC_CSM_MASKLO_LOBIT;
return (-1); /* errno already set */
/*
* Find the rank'th chip-select on this dimm.
*/
i = 0;
i++;
}
"dimm in this slot does not have an %d'th cs\n",
rank);
}
return (-1); /* errno already set */
"mc_offset_to_pa") < 0)
return (-1); /* errno already set */
/*CONSTANTCONDITION*/
if (MC_DC_CSM_UNMASKED_BITS != 0) {
}
"cs basehi bits not being masked");
if (mcp.csintlvfctr != 0) {
"cs baselo bits not being masked");
}
"add iaddr bits from row");
"add iaddr bits from col");
"add iaddr bits from bank");
return (-1); /* errno already set */
return (0);
}
int
{
const struct bankaddr_mode *bamp;
return (-1); /* errno already set */
return (-1); /* errno already set */
return (0);
}