mcamd_rowcol.c revision 8a40a695ee676a322b094e9afe5375567bfb51e3
/*
* 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
* 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.
*/
struct mcprops {
};
struct csprops {
};
static int
{
if (!mcamd_get_numprops(hdl,
NULL)) {
}
return (0);
}
static int
{
if (!mcamd_get_numprops(hdl,
NULL)) {
}
return (0);
}
static int
const char *caller)
{
}
"table for MC rev %d csmode %d\n", caller,
}
}
if (csid) {
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 swizzle if requested.
*/
static uint32_t
{
/*
* rcb_bankbit[abitno] tells us which iaddr bit number
* will form bit abitno of the bank address
*/
/*
* If bank swizzling is in operation then xor the bit value
* obtained above with other iaddr bits.
*/
if (swzlp) {
for (i = 0; i < MC_RC_SWZLBITS; i++) {
}
}
if (val)
}
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 (swzlp) {
for (i = 0; i < MC_RC_SWZLBITS; i++) {
}
}
if (val)
}
return (iaddr);
}
static int
{
const struct rct_bnkaddrmode *bamp;
const struct rct_rcbmap *rcbmp;
struct rct_csintlv csi;
"iaddr_to_rcb") < 0)
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.
*
* Note that the DRAM controller InputAddr is still 36 bits
* 35:0 on rev F.
*/
} else {
}
"intlven 0x%x intlvsel 0x%x MC base 0x%llx --> 0x%llx\n",
dramaddr);
return (0);
}
int
{
return (-1); /* errno already set */
return (-1); /* errno already set */
return (0);
}
/*
* Given an MC, 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
{
const struct rct_bnkaddrmode *bamp;
const struct rct_rcbmap *rcbmp;
struct rct_csintlv csi;
"-> rank %d bank %d row 0x%x col 0x%x\n", offset,
return (-1); /* errno already set */
/*
* Find the chip-select on this dimm using the given rank.
*/
return (-1); /* errno already set */
break;
}
"dimm in this slot does not have a cs using rank %d\n",
rank);
}
/*
* If the cs# has been substituted by the online spare then the
* given unum is not actually contributing to the system address
* map since all accesses to it are redirected.
*
* If the cs# failed BIOS test it is not in the address map.
*
* If the cs# is the online spare cs# then it is contributing to
* the system address map only if swapped in, and the csbase etc
* parameters to use must be those of the bad cs#.
*/
/*
* Iterate over all cs# of this memory controller to find
* the bad one - the bad cs# need not be on the same dimm
* as the spare.
*/
&csnum)) {
"mcamd_offset_to_pa: csnum lookup failed "
"while looking for bad cs#");
return (mcamd_set_errno(hdl,
}
break;
}
return (mcamd_set_errno(hdl,
}
/* found bad cs - reread properties from it instead of spare */
return (-1); /* errno already set */
}
"mc_offset_to_pa") < 0)
return (-1); /* errno already set */
/*
* If there are umaskable DRAM InputAddr bits the add those bits
* to iaddr from the cs base address.
*/
}
/*
* basehi bits not meing masked pass straight through to the
* iaddr.
*/
"cs basehi bits not being masked");
/*
* if cs interleaving is active then baselo address bit are being
* masked - pass the rest through.
*/
"cs baselo bits not being masked");
}
/*
* Reconstruct iaddr bits from known row address
*/
"add iaddr bits from row");
/*
* Reconstruct iaddr bits from known column address
*/
"add iaddr bits from col");
/*
* Reconstruct iaddr bits from known internal banksel address
*/
"add iaddr bits from bank");
/*
* Move iaddr up into the range for this MC and insert any
* node interleave selection bits.
*/
return (-1); /* errno already set */
return (0);
}
int
{
const struct rct_bnkaddrmode *bamp;
return (-1); /* errno already set */
"mcamd_cs_size") < 0)
return (-1); /* errno already set */
return (0);
}