summaryrefslogtreecommitdiff
path: root/usr/src/common/mc
diff options
context:
space:
mode:
authorgavinm <none@none>2006-10-05 17:39:16 -0700
committergavinm <none@none>2006-10-05 17:39:16 -0700
commit8a40a695ee676a322b094e9afe5375567bfb51e3 (patch)
treeb59160470b2412ad6a4afc8cf53da85376e7a18a /usr/src/common/mc
parent6fec36253a9fa8abfdf231fb3ea9fc656a2ff872 (diff)
downloadillumos-joyent-8a40a695ee676a322b094e9afe5375567bfb51e3.tar.gz
PSARC 2006/564 FMA for Athlon 64 and Opteron Rev F/G Processors
PSARC 2006/566 eversholt language enhancements: confprop_defined 6362846 eversholt doesn't allow dashes in pathname components 6391591 AMD NB config should not set NbMcaToMstCpuEn 6391605 AMD DRAM scrubber should be disabled when errata #99 applies 6398506 memory controller driver should not bother to attach at all on rev F 6424822 FMA needs to support AMD family 0xf revs F and G 6443847 FMA x64 multibit ChipKill rules need to follow MQSC guidelines 6443849 Accrue inf_sys and s_ecc ECC errors against memory 6443858 mc-amd can free unitsrtr before usage in subsequent error path 6443891 mc-amd does not recognise mismatched dimm support 6455363 x86 error injector should allow addr option for most errors 6455370 Opteron erratum 101 only applies on revs D and earlier 6455373 Identify chip-select lines used on a dimm 6455377 improve x64 quadrank dimm support 6455382 add generic interfaces for amd chip revision and package/socket type 6468723 mem scheme fmri containment test for hc scheme is busted 6473807 eversholt could use some mdb support 6473811 eversholt needs a confprop_defined function 6473819 eversholt should show version of rules active in DE 6475302 ::nvlist broken by some runtime link ordering changes
Diffstat (limited to 'usr/src/common/mc')
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_api.h135
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_misc.c79
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_patounum.c446
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_rowcol.c404
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h68
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c750
-rw-r--r--usr/src/common/mc/mc-amd/mcamd_unumtopa.c33
7 files changed, 1251 insertions, 664 deletions
diff --git a/usr/src/common/mc/mc-amd/mcamd_api.h b/usr/src/common/mc/mc-amd/mcamd_api.h
index 646f457fdc..977b9dfe94 100644
--- a/usr/src/common/mc/mc-amd/mcamd_api.h
+++ b/usr/src/common/mc/mc-amd/mcamd_api.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -62,55 +61,79 @@ typedef struct mcamd_node mcamd_node_t;
struct mcamd_hdl;
/*
- * If changing the properties below be sure to propogate to mcamd_misc.c
- * in common code, mcamd_subr.c in the mc-amd driver, and mcamd_prop.c
- * from libmcamd.
+ * Properties and raw register values for an mcamd_node_t are retrieved via
+ * mcamd_get_numprop(s) and mcamd_get_cfgreg(s) specifying a property or
+ * register code below.
*/
-#define MCAMD_PROP_NUM 0
-#define MCAMD_PROP_BASE_ADDR 1
-#define MCAMD_PROP_LIM_ADDR 2
-#define MCAMD_PROP_MASK 3
-#define MCAMD_PROP_DRAM_ILEN 4
-#define MCAMD_PROP_DRAM_ILSEL 5
-#define MCAMD_PROP_DRAM_HOLE 6
-#define MCAMD_PROP_DRAM_CONFIG 7
-#define MCAMD_PROP_ACCESS_WIDTH 8
-#define MCAMD_PROP_LODIMM 9
-#define MCAMD_PROP_UPDIMM 10
-#define MCAMD_PROP_CSBANKMAP 11
-#define MCAMD_PROP_SIZE 12
-#define MCAMD_PROP_CSBANK_INTLV 13
-#define MCAMD_PROP_CS0 14 /* CS0 to CS3 must be contiguous */
-#define MCAMD_PROP_CS1 15
-#define MCAMD_PROP_CS2 16
-#define MCAMD_PROP_CS3 17
-#define MCAMD_PROP_REV 18
-#define MCAMD_PROP_DISABLED_CS 19
-
-#define MCAMD_NUMPROPS 20
+typedef uint64_t mcamd_prop_t;
+typedef uint32_t mcamd_cfgreg_t;
+typedef enum mcamd_propcode {
+ /*
+ * Common properties
+ */
+ MCAMD_PROP_NUM = 0x4000,
#define MCAMD_PROPSTR_NUM "num"
+ MCAMD_PROP_SIZE,
+#define MCAMD_PROPSTR_SIZE "size"
+ MCAMD_PROP_BASE_ADDR,
#define MCAMD_PROPSTR_BASE_ADDR "base-addr"
+ /*
+ * Memory controller properties
+ */
+ MCAMD_PROP_REV = 0x5000,
+#define MCAMD_PROPSTR_REV "revision"
+ MCAMD_PROP_LIM_ADDR,
#define MCAMD_PROPSTR_LIM_ADDR "lim-addr"
-#define MCAMD_PROPSTR_MASK "mask"
-#define MCAMD_PROPSTR_DRAM_ILEN "dram-ilen"
-#define MCAMD_PROPSTR_DRAM_ILSEL "dram-ilsel"
-#define MCAMD_PROPSTR_DRAM_HOLE "dram-hole"
-#define MCAMD_PROPSTR_DRAM_CONFIG "dram-config"
+ MCAMD_PROP_ILEN,
+#define MCAMD_PROPSTR_ILEN "node-ilen"
+ MCAMD_PROP_ILSEL,
+#define MCAMD_PROPSTR_ILSEL "node-ilsel"
+ MCAMD_PROP_CSINTLVFCTR,
+#define MCAMD_PROPSTR_CSINTLVFCTR "cs-intlv-factor"
+ MCAMD_PROP_DRAMHOLE_SIZE,
+#define MCAMD_PROPSTR_DRAMHOLE_SIZE "dram-hole-size"
+ MCAMD_PROP_ACCESS_WIDTH,
#define MCAMD_PROPSTR_ACCESS_WIDTH "access-width"
-#define MCAMD_PROPSTR_LODIMM "lodimm-num"
-#define MCAMD_PROPSTR_UPDIMM "updimm-num"
-#define MCAMD_PROPSTR_CSBANKMAP "bank-mapping"
-#define MCAMD_PROPSTR_SIZE "size"
-#define MCAMD_PROPSTR_CSBANK_INTLV "csbank-intlv"
-#define MCAMD_PROPSTR_CS0 "csnum0"
-#define MCAMD_PROPSTR_CS1 "csnum1"
-#define MCAMD_PROPSTR_CS2 "csnum2"
-#define MCAMD_PROPSTR_CS3 "csnum3"
-#define MCAMD_PROPSTR_REV "revision"
-#define MCAMD_PROPSTR_DISABLED_CS "disabled-cs"
-
+ MCAMD_PROP_CSBANKMAPREG,
+#define MCAMD_PROPSTR_CSBANKMAPREG "bank-mapping"
+ MCAMD_PROP_BANKSWZL,
+#define MCAMD_PROPSTR_BANKSWZL "bankswizzle"
+ MCAMD_PROP_MOD64MUX,
+#define MCAMD_PROPSTR_MOD64MUX "mismatched-dimm-support"
+ MCAMD_PROP_SPARECS,
+#define MCAMD_PROPSTR_SPARECS "spare-csnum"
+ MCAMD_PROP_BADCS,
+#define MCAMD_PROPSTR_BADCS "bad-csnum"
+ /*
+ * Chip-select properties
+ */
+ MCAMD_PROP_MASK = 0x6000,
+#define MCAMD_PROPSTR_MASK "mask"
+ MCAMD_PROP_CSBE,
+#define MCAMD_PROPSTR_CSBE "cs-bank-enable"
+ MCAMD_PROP_SPARE,
+#define MCAMD_PROPSTR_SPARE "online-spare"
+ MCAMD_PROP_TESTFAIL,
+#define MCAMD_PROPSTR_TESTFAIL "failed-test"
+ MCAMD_PROP_CSDIMM1,
+#define MCAMD_PROPSTR_CSDIMM1 "dimm1-num"
+ MCAMD_PROP_CSDIMM2,
+#define MCAMD_PROPSTR_CSDIMM2 "dimm2-num"
+ MCAMD_PROP_DIMMRANK
+#define MCAMD_PROPSTR_DIMMRANK "dimm-rank"
+} mcamd_propcode_t;
+
+typedef enum mcamd_regcode {
+ MCAMD_REG_DRAMBASE = 0x7000,
+ MCAMD_REG_DRAMLIMIT,
+ MCAMD_REG_DRAMHOLE,
+ MCAMD_REG_DRAMCFGLO,
+ MCAMD_REG_DRAMCFGHI,
+ MCAMD_REG_CSBASE,
+ MCAMD_REG_CSMASK
+} mcamd_regcode_t;
/*
* Flags for mcamd_dprintf
*/
@@ -123,7 +146,8 @@ typedef union mcamd_dimm_offset_un mcamd_dimm_offset_un_t;
* Offset definition. Encode everything in a single uint64_t, allowing some
* room for growth in numbers of rows/columns/banks in future MC revisions.
* Some consumers will handle this as an opaque uint64 to be passed around,
- * while others will want to look inside via the union defined below.
+ * while others will want to look inside via the union defined below. Since
+ * we must support a 32-bit kernel we structure this as two uint32_t.
*/
#define MCAMD_OFFSET_VERSION_0 0x0
@@ -170,13 +194,16 @@ union mcamd_dimm_offset_un {
/*
* Routines provided by the common mcamd code.
*/
-extern const char *mcamd_get_propname(uint_t);
+extern const char *mcamd_get_propname(mcamd_propcode_t);
extern int mcamd_patounum(struct mcamd_hdl *, mcamd_node_t *, uint64_t,
- uint32_t, int, struct mc_unum *);
-
-extern int mcamd_unumtopa(struct mcamd_hdl *, mcamd_node_t *, struct mc_unum *,
+ uint32_t, int, mc_unum_t *);
+extern int mcamd_unumtopa(struct mcamd_hdl *, mcamd_node_t *, mc_unum_t *,
uint64_t *);
+extern int mc_pa_to_offset(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *,
+ uint64_t, uint64_t *);
+extern int mc_offset_to_pa(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *,
+ uint64_t, uint64_t *);
extern int mcamd_cs_size(struct mcamd_hdl *, mcamd_node_t *, int, size_t *);
@@ -204,8 +231,12 @@ extern mcamd_node_t *mcamd_dimm_next(struct mcamd_hdl *, mcamd_node_t *,
extern mcamd_node_t *mcamd_cs_mc(struct mcamd_hdl *, mcamd_node_t *);
extern mcamd_node_t *mcamd_dimm_mc(struct mcamd_hdl *, mcamd_node_t *);
-extern int mcamd_get_numprop(struct mcamd_hdl *, mcamd_node_t *, uint_t,
- uint64_t *);
+extern int mcamd_get_numprop(struct mcamd_hdl *, mcamd_node_t *,
+ mcamd_propcode_t, mcamd_prop_t *);
+extern int mcamd_get_numprops(struct mcamd_hdl *, ...);
+extern int mcamd_get_cfgreg(struct mcamd_hdl *, mcamd_node_t *,
+ mcamd_regcode_t, mcamd_cfgreg_t *);
+extern int mcamd_get_cfgregs(struct mcamd_hdl *, ...);
extern int mcamd_errno(struct mcamd_hdl *);
extern int mcamd_set_errno(struct mcamd_hdl *, int);
diff --git a/usr/src/common/mc/mc-amd/mcamd_misc.c b/usr/src/common/mc/mc-amd/mcamd_misc.c
index 2bd4d508a3..ca82eeb320 100644
--- a/usr/src/common/mc/mc-amd/mcamd_misc.c
+++ b/usr/src/common/mc/mc-amd/mcamd_misc.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -29,37 +28,55 @@
#include <mcamd_api.h>
-static const char *const _mcamd_proplist[] = {
- MCAMD_PROPSTR_NUM,
- MCAMD_PROPSTR_BASE_ADDR,
- MCAMD_PROPSTR_LIM_ADDR,
- MCAMD_PROPSTR_MASK,
- MCAMD_PROPSTR_DRAM_ILEN,
- MCAMD_PROPSTR_DRAM_ILSEL,
- MCAMD_PROPSTR_DRAM_HOLE,
- MCAMD_PROPSTR_DRAM_CONFIG,
- MCAMD_PROPSTR_ACCESS_WIDTH,
- MCAMD_PROPSTR_LODIMM,
- MCAMD_PROPSTR_UPDIMM,
- MCAMD_PROPSTR_CSBANKMAP,
- MCAMD_PROPSTR_SIZE,
- MCAMD_PROPSTR_CSBANK_INTLV,
- MCAMD_PROPSTR_CS0,
- MCAMD_PROPSTR_CS1,
- MCAMD_PROPSTR_CS2,
- MCAMD_PROPSTR_CS3,
- MCAMD_PROPSTR_REV,
- MCAMD_PROPSTR_DISABLED_CS,
+static struct mcproptostr {
+ mcamd_propcode_t code;
+ const char *name;
+} _propstrings[] = {
+ /*
+ * Common codes
+ */
+ { MCAMD_PROP_NUM, MCAMD_PROPSTR_NUM },
+ { MCAMD_PROP_SIZE, MCAMD_PROPSTR_SIZE },
+ { MCAMD_PROP_BASE_ADDR, MCAMD_PROPSTR_BASE_ADDR },
+ /*
+ * Memory controller properties
+ */
+ { MCAMD_PROP_REV, MCAMD_PROPSTR_REV },
+ { MCAMD_PROP_LIM_ADDR, MCAMD_PROPSTR_LIM_ADDR },
+ { MCAMD_PROP_ILEN, MCAMD_PROPSTR_ILEN },
+ { MCAMD_PROP_ILSEL, MCAMD_PROPSTR_ILSEL },
+ { MCAMD_PROP_CSINTLVFCTR, MCAMD_PROPSTR_CSINTLVFCTR },
+ { MCAMD_PROP_ACCESS_WIDTH, MCAMD_PROPSTR_ACCESS_WIDTH },
+ { MCAMD_PROP_CSBANKMAPREG, MCAMD_PROPSTR_CSBANKMAPREG },
+ { MCAMD_PROP_BANKSWZL, MCAMD_PROPSTR_BANKSWZL },
+ { MCAMD_PROP_DRAMHOLE_SIZE, MCAMD_PROPSTR_DRAMHOLE_SIZE },
+ { MCAMD_PROP_MOD64MUX, MCAMD_PROPSTR_MOD64MUX },
+ { MCAMD_PROP_SPARECS, MCAMD_PROPSTR_SPARECS },
+ { MCAMD_PROP_BADCS, MCAMD_PROPSTR_BADCS },
+ /*
+ * Chip-select properties
+ */
+ { MCAMD_PROP_MASK, MCAMD_PROPSTR_MASK },
+ { MCAMD_PROP_CSBE, MCAMD_PROPSTR_CSBE },
+ { MCAMD_PROP_SPARE, MCAMD_PROPSTR_SPARE },
+ { MCAMD_PROP_TESTFAIL, MCAMD_PROPSTR_TESTFAIL },
+ { MCAMD_PROP_CSDIMM1, MCAMD_PROPSTR_CSDIMM1 },
+ { MCAMD_PROP_CSDIMM2, MCAMD_PROPSTR_CSDIMM2 },
+ { MCAMD_PROP_DIMMRANK, MCAMD_PROPSTR_DIMMRANK },
};
-static const int _mcamd_nprop = sizeof (_mcamd_proplist) /
- sizeof (_mcamd_proplist[0]);
+static const int _nprop = sizeof (_propstrings) /
+ sizeof (struct mcproptostr);
const char *
-mcamd_get_propname(uint_t code)
+mcamd_get_propname(mcamd_propcode_t code)
{
- if (code < _mcamd_nprop)
- return (_mcamd_proplist[code]);
- else
- return (NULL);
+ int i;
+
+ for (i = 0; i < _nprop; i++) {
+ if (_propstrings[i].code == code)
+ return (_propstrings[i].name);
+ }
+
+ return (NULL);
}
diff --git a/usr/src/common/mc/mc-amd/mcamd_patounum.c b/usr/src/common/mc/mc-amd/mcamd_patounum.c
index 9bad114f30..b58a751d60 100644
--- a/usr/src/common/mc/mc-amd/mcamd_patounum.c
+++ b/usr/src/common/mc/mc-amd/mcamd_patounum.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -37,33 +36,49 @@
#include <mcamd_api.h>
#include <mcamd_err.h>
-extern int mc_pa_to_offset(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *,
- mcamd_node_t *, uint64_t, uint64_t *);
-#define LO_DIMM 0x1
-#define UP_DIMM 0x2
+#define CSDIMM1 0x1
+#define CSDIMM2 0x2
#define BITS(val, high, low) \
((val) & (((2ULL << (high)) - 1) & ~((1ULL << (low)) - 1)))
+/*
+ * iaddr_gen generates a "normalized" DRAM controller input address
+ * from a system address (physical address) if it falls within the
+ * mapped range for this memory controller. Normalisation is
+ * performed by subtracting the node base address from the system address,
+ * allowing from hoisting, and excising any bits being used in node
+ * interleaving.
+ */
static int
iaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
uint64_t *iaddrp)
{
uint64_t orig = pa;
- uint64_t mcnum, base, lim, dramaddr, ilen, ilsel, top, dramhole;
-
- if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &base) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &lim) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &ilen) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, &ilsel) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &dramhole)) {
+ uint64_t mcnum, base, lim, dramaddr, ilen, ilsel, top, holesz;
+
+ if (!mcamd_get_numprops(hdl,
+ mc, MCAMD_PROP_NUM, &mcnum,
+ mc, MCAMD_PROP_BASE_ADDR, &base,
+ mc, MCAMD_PROP_LIM_ADDR, &lim,
+ mc, MCAMD_PROP_ILEN, &ilen,
+ mc, MCAMD_PROP_ILSEL, &ilsel,
+ mc, MCAMD_PROP_DRAMHOLE_SIZE, &holesz,
+ NULL)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "iaddr_gen: failed to "
"lookup required properties");
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
}
+ /*
+ * A node with no mapped memory (no active chip-selects is usually
+ * mapped with base and lim both zero. We'll cover that case and
+ * any other where the range is 0.
+ */
+ if (base == lim)
+ return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
+
if (pa < base || pa > lim) {
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: PA 0x%llx not "
"in range [0x%llx, 0x%llx] of MC %d\n", pa, base, lim,
@@ -80,13 +95,11 @@ iaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
* we need to reduce any address at or above 4GB by the size of
* the hole.
*/
- if (dramhole & MC_DC_HOLE_VALID && pa >= 0x100000000) {
- uint64_t holesize = (dramhole & MC_DC_HOLE_OFFSET_MASK) <<
- MC_DC_HOLE_OFFSET_LSHIFT;
- pa -= holesize;
+ if (holesz != 0 && pa >= 0x100000000) {
+ pa -= holesz;
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_gen: dram hole "
"valid; pa decremented from 0x%llx to 0x%llx for "
- "a dramhole size of 0x%llx\n", orig, pa, holesize);
+ "a dramhole size of 0x%llx\n", orig, pa, holesz);
}
dramaddr = BITS(pa, 39, 0) - BITS(base, 39, 24);
@@ -127,52 +140,123 @@ iaddr_gen(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
return (0);
}
+/*
+ * cs_match determines whether the given DRAM controller input address
+ * would be responded to by the given chip-select (which may or may not
+ * be interleaved with other chip-selects). Since we include nodes
+ * for spare chip-selects (if any) and those marked TestFail (if any)
+ * we must check chip-select-bank-enable.
+ */
static int
cs_match(struct mcamd_hdl *hdl, uint64_t iaddr, mcamd_node_t *cs)
{
- uint64_t csnum, csbase, csmask;
- int match;
-
- if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum) ||
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, &csbase) ||
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, &csmask)) {
+ uint64_t csnum, csbase, csmask, csbe;
+ int match = 0;
+
+ if (!mcamd_get_numprops(hdl,
+ cs, MCAMD_PROP_NUM, &csnum,
+ cs, MCAMD_PROP_BASE_ADDR, &csbase,
+ cs, MCAMD_PROP_MASK, &csmask,
+ cs, MCAMD_PROP_CSBE, &csbe,
+ NULL)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_match: failed to lookup "
"required properties\n");
return (0);
}
- match = ((iaddr & ~csmask) == (csbase & ~csmask));
+ if (csbe) {
+ match = ((iaddr & ~csmask) == (csbase & ~csmask));
- mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx does "
- "%smatch CS %d (base 0x%llx, mask 0x%llx)\n", iaddr,
- match ? "" : "not ", (int)csnum, csbase, csmask);
+ mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx "
+ "does %smatch CS %d (base 0x%llx, mask 0x%llx)\n", iaddr,
+ match ? "" : "not ", (int)csnum, csbase, csmask);
+ } else {
+ mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_match: iaddr 0x%llx "
+ "does not match disabled CS %d\n", iaddr, (int)csnum);
+ }
return (match);
}
+/*
+ * Given a chip-select node determine whether it has been substituted
+ * by the online spare chip-select.
+ */
+static mcamd_node_t *
+cs_sparedto(struct mcamd_hdl *hdl, mcamd_node_t *cs, mcamd_node_t *mc)
+{
+ uint64_t csnum, badcsnum, sparecsnum, tmpcsnum;
+
+ if (!mcamd_get_numprops(hdl,
+ cs, MCAMD_PROP_NUM, &csnum,
+ mc, MCAMD_PROP_BADCS, &badcsnum,
+ mc, MCAMD_PROP_SPARECS, &sparecsnum,
+ NULL)) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: failed to "
+ "lookup required properties\n");
+ return (NULL);
+ }
+
+ if ((badcsnum == MC_INVALNUM && sparecsnum == MC_INVALNUM) ||
+ csnum != badcsnum)
+ return (NULL);
+
+ for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
+ cs = mcamd_cs_next(hdl, mc, cs)) {
+ if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &tmpcsnum)) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: "
+ "fail to lookup csnum - cannot reroute to spare\n");
+ return (NULL);
+ }
+ if (tmpcsnum == sparecsnum)
+ break;
+ }
+
+ if (cs != NULL) {
+ mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "cs_sparedto: cs#%d is "
+ "redirected to active online spare of cs#%d\n", csnum,
+ sparecsnum);
+ } else {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR, "cs_sparedto: cs#%d is "
+ "redirected but cannot find spare cs# - cannout reroute to "
+ "cs#%d\n", csnum, sparecsnum);
+ }
+
+ return (cs);
+}
+
+/*
+ * Having determined which node and chip-select an address maps to,
+ * as well as whether it is a dimm1, dimm2 or dimm1/dimm2 pair
+ * involved, fill the unum structure including an optional dimm offset
+ * member.
+ */
static int
unum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which,
- uint64_t iaddr, struct mc_unum *unump, int incloff)
+ uint64_t iaddr, mc_unum_t *unump, int incloff)
{
+ uint64_t chipnum, csnum, dimm1, dimm2, ranknum;
mcamd_node_t *mc, *dimm;
- uint64_t chipnum, csnum, lonum, upnum;
- int i;
int offsetdimm;
+ int i;
if ((mc = mcamd_cs_mc(hdl, cs)) == NULL ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &chipnum) ||
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) {
+ !mcamd_get_numprops(hdl,
+ mc, MCAMD_PROP_NUM, &chipnum,
+ cs, MCAMD_PROP_NUM, &csnum,
+ cs, MCAMD_PROP_DIMMRANK, &ranknum,
+ NULL)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
"lookup required properties\n");
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
}
- if ((which & LO_DIMM) &&
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_LODIMM, &lonum) ||
- (which & UP_DIMM) &&
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_UPDIMM, &upnum)) {
+ if ((which & CSDIMM1) &&
+ !mcamd_get_numprop(hdl, cs, MCAMD_PROP_CSDIMM1, &dimm1) ||
+ (which & CSDIMM2) &&
+ !mcamd_get_numprop(hdl, cs, MCAMD_PROP_CSDIMM2, &dimm2)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "unum_fill: failed to "
- "lookup lodimm/hidimm properties\n");
+ "lookup dimm1/dimm2 properties\n");
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
}
@@ -180,23 +264,24 @@ unum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which,
unump->unum_chip = chipnum;
unump->unum_mc = 0;
unump->unum_cs = csnum;
+ unump->unum_rank = ranknum;
for (i = 0; i < MC_UNUM_NDIMM; i++) {
- unump->unum_dimms[i] = -1;
+ unump->unum_dimms[i] = MC_INVALNUM;
}
switch (which) {
- case LO_DIMM:
- unump->unum_dimms[0] = lonum;
- offsetdimm = lonum;
+ case CSDIMM1:
+ unump->unum_dimms[0] = dimm1;
+ offsetdimm = dimm1;
break;
- case UP_DIMM:
- unump->unum_dimms[0] = upnum;
- offsetdimm = upnum;
+ case CSDIMM2:
+ unump->unum_dimms[0] = dimm2;
+ offsetdimm = dimm2;
break;
- case LO_DIMM | UP_DIMM:
- unump->unum_dimms[0] = lonum;
- unump->unum_dimms[1] = upnum;
- offsetdimm = lonum;
+ case CSDIMM1 | CSDIMM2:
+ unump->unum_dimms[0] = dimm1;
+ unump->unum_dimms[1] = dimm2;
+ offsetdimm = dimm1;
break;
}
@@ -207,7 +292,7 @@ unum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which,
/*
* We wish to calculate a dimm offset. In the paired case we will
- * lookup the lodimm (see offsetdimm above).
+ * lookup dimm1 (see offsetdimm above).
*/
for (dimm = mcamd_dimm_next(hdl, mc, NULL); dimm != NULL;
dimm = mcamd_dimm_next(hdl, mc, dimm)) {
@@ -233,57 +318,79 @@ unum_fill(struct mcamd_hdl *hdl, mcamd_node_t *cs, int which,
* mc_pa_to_offset sets the offset to an invalid value if
* it hits an error.
*/
- (void) mc_pa_to_offset(hdl, mc, cs, dimm, iaddr, &unump->unum_offset);
+ (void) mc_pa_to_offset(hdl, mc, cs, iaddr, &unump->unum_offset);
return (0);
}
/*
- * We have translated a system address to a (node, chip-select). That
- * identifies one (in 64-bit MC mode) or two (in 128-bit MC mode DIMMs,
- * either a lodimm or a lodimm/updimm pair. For all cases except an
- * uncorrectable ChipKill error we can interpret the address alignment and
- * syndrome to deduce whether we are on the lodimm or updimm.
+ * We have translated a system address to a (node, chip-select), and wish
+ * to determine the associated dimm or dimms.
+ *
+ * A (node, chip-select) pair identifies one (in 64-bit MC mode) or two (in
+ * 128-bit MC mode) DIMMs. In the case of a single dimm it is usually in a
+ * lodimm (channel A) slot, but if mismatched dimm support is present it may
+ * be an updimm (channel B).
+ *
+ * Where just one dimm is associated with the chip-select we are done.
+ * Where there are two dimms associated with the chip-select we can
+ * use the ECC type and/or syndrome to determine which of the pair we
+ * resolve to, if the error is correctable. If the error is uncorrectable
+ * then in 64/8 ECC mode we can still resolve to a single dimm (since ECC
+ * is calculated and checked on each half of the data separately), but
+ * in ChipKill mode we cannot resolve down to a single dimm.
*/
static int
-mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
+mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *cs, uint64_t pa,
uint32_t synd, int syndtype)
{
- uint64_t accwidth;
- uint_t sym, pat;
int lobit, hibit, data, check;
+ uint64_t dimm1, dimm2;
+ uint_t sym, pat;
+ int ndimm;
- if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_ACCESS_WIDTH, &accwidth) ||
- (accwidth != 64 && accwidth != 128)) {
- mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: failed "
- "to lookup required properties\n");
+ /*
+ * Read the associated dimm instance numbers. The provider must
+ * assure that if there is just one dimm then it is in the first
+ * property, and if there are two then the first must be on
+ * channel A.
+ */
+ if (!mcamd_get_numprops(hdl,
+ cs, MCAMD_PROP_CSDIMM1, &dimm1,
+ cs, MCAMD_PROP_CSDIMM2, &dimm2,
+ NULL)) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: failed to "
+ "lookup required properties");
+ return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
+ }
+ ndimm = (dimm1 != MC_INVALNUM) + (dimm2 != MC_INVALNUM);
+ if (ndimm == 0) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_whichdimm: found no "
+ "dimms associated with chip-select");
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
}
- /*
- * In 64 bit mode only LO dimms are occupied.
- */
- if (accwidth == 64) {
- mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64-bit mode "
- "therefore LO_DIMM\n");
- return (LO_DIMM);
+ if (ndimm == 1) {
+ mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: just one "
+ "dimm associated with this chip-select");
+ return (CSDIMM1);
}
+ /*
+ * 64/8 ECC is checked separately for the upper and lower
+ * halves, so even an uncorrectable error is contained within
+ * one of the two halves. The error address is accurate to
+ * 8 bytes, so bit 4 distinguises upper from lower.
+ */
if (syndtype == AMD_SYNDTYPE_ECC) {
- /*
- * 64/8 ECC is checked separately for the upper and lower
- * halves, so even an uncorrectable error is contained within
- * one of the two halves. The error address is accurate to
- * 8 bytes, so bit 4 distinguises upper from lower.
- */
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: 64/8 ECC "
"and PA 0x%llx is in %s half\n", pa,
pa & 8 ? "lower" : "upper");
- return (pa & 8 ? UP_DIMM : LO_DIMM);
+ return (pa & 8 ? CSDIMM2 : CSDIMM1);
}
/*
- * ChipKill ECC (necessarily in 128-bit mode.
+ * ChipKill ECC
*/
if (mcamd_cksynd_decode(hdl, synd, &sym, &pat)) {
/*
@@ -298,12 +405,12 @@ mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: "
"ChipKill symbol %d (%s %d..%d), so LODIMM\n", sym,
data ? "data" : "check", lobit, hibit);
- return (LO_DIMM);
+ return (CSDIMM1);
} else {
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichdimm: "
"ChipKill symbol %d (%s %d..%d), so UPDIMM\n", sym,
data ? "data" : "check", lobit, hibit);
- return (UP_DIMM);
+ return (CSDIMM2);
}
} else {
/*
@@ -313,65 +420,60 @@ mc_whichdimm(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_whichhdimm: "
"uncorrectable ChipKill, could be either LODIMM "
"or UPDIMM\n");
- return (LO_DIMM | UP_DIMM);
+ return (CSDIMM1 | CSDIMM2);
}
}
/*
- * Brute-force BKDG pa to cs translation. The following is from BKDG 3.29
- * so is for revisions prior to F. It is coded to look as much like the
+ * Brute-force BKDG pa to cs translation, coded to look as much like the
* BKDG code as possible.
*/
static int
mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
- uint32_t synd, int syndtype, struct mc_unum *unump)
+ uint32_t synd, int syndtype, mc_unum_t *unump)
{
int which;
- uint64_t mcnum;
+ uint64_t mcnum, rev;
mcamd_node_t *cs;
/*
+ * Raw registers as per BKDG
+ */
+ uint32_t HoleEn;
+ uint32_t DramBase, DramLimit;
+ uint32_t CSBase, CSMask;
+ /*
* Variables as per BKDG
*/
int Ilog;
uint32_t SystemAddr = (uint32_t)(pa >> 8);
uint64_t IntlvEn, IntlvSel;
- uint32_t DramBase, DramLimit; /* assume DramEn */
- uint32_t HoleOffset, HoleEn;
- uint32_t CSBase, CSMask; /* assuume CSBE */
+ uint32_t HoleOffset;
uint32_t InputAddr, Temp;
- /*
- * Additional variables which we need since we will reading
- * MC properties instead of PCI config space, and the MC properties
- * are stored in a cooked state.
- */
- uint64_t prop_drambase, prop_dramlimit, prop_dramhole;
- uint64_t prop_intlven, prop_intlvsel;
- uint64_t prop_csbase, prop_csmask;
-
- if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &mcnum) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &prop_drambase) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &prop_dramlimit) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &prop_dramhole) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &prop_intlven) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL,
- &prop_intlvsel)) {
+ if (!mcamd_get_numprops(hdl,
+ mc, MCAMD_PROP_NUM, &mcnum,
+ mc, MCAMD_PROP_REV, &rev, NULL) || !mcamd_get_cfgregs(hdl,
+ mc, MCAMD_REG_DRAMBASE, &DramBase,
+ mc, MCAMD_REG_DRAMLIMIT, &DramLimit,
+ mc, MCAMD_REG_DRAMHOLE, &HoleEn, NULL)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: failed "
- "to lookup required properties\n");
+ "to lookup required properties and registers\n");
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
}
/*
- * Brute force deconstruction of the MC properties. If we decide to
- * keep this then we need some of the mcamd.g defines available to us.
+ * BKDG line to skip Why
+ *
+ * F1Offset = ... Register already read,
+ * DramBase = Get_PCI() and retrieved above.
+ * DramEn = ... Function only called for enabled nodes.
*/
- DramBase = ((prop_drambase >> 8) & 0xffff0000) | (prop_intlven << 8);
IntlvEn = (DramBase & 0x00000700) >> 8;
DramBase &= 0xffff0000;
- DramLimit = ((prop_dramlimit >> 8) & 0xffff0000) | (prop_intlvsel << 8);
+ /* DramLimit = Get_PCI() Retrieved above */
IntlvSel = (DramLimit & 0x00000700) >> 8;
DramLimit |= 0x0000ffff;
- HoleEn = prop_dramhole; /* uncooked */
+ /* HoleEn = ... Retrieved above */
HoleOffset = (HoleEn & 0x0000ff00) << 8;
HoleEn &= 0x00000001;
@@ -383,6 +485,11 @@ mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
}
+ if (HoleEn && SystemAddr > 0x00ffffff)
+ InputAddr = SystemAddr - HoleOffset;
+
+ InputAddr = SystemAddr - DramBase;
+
if (IntlvEn) {
if (IntlvSel == ((SystemAddr >> 4) & IntlvEn)) {
switch (IntlvEn) {
@@ -399,8 +506,8 @@ mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
return (mcamd_set_errno(hdl,
EMCAMD_TREEINVALID));
}
- Temp = (SystemAddr >> (4 + Ilog)) << 4;
- InputAddr = (Temp | (SystemAddr & 0x0000000f)) << 4;
+ Temp = (InputAddr >> (4 + Ilog)) << 4;
+ InputAddr = (Temp | (SystemAddr & 0x0000000f));
} else {
/* not this node */
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
@@ -408,41 +515,57 @@ mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
(int)mcnum);
return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
}
- } else {
- /* No interleave */
- InputAddr = (SystemAddr - DramBase) << 4;
}
- if (HoleEn && SystemAddr > 0x00ffffff)
- InputAddr -= HoleOffset;
+ if (!MC_REV_MATCH(rev, MC_REVS_FG))
+ InputAddr <<= 4;
for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
cs = mcamd_cs_next(hdl, mc, cs)) {
- uint64_t csnum;
-
- if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR,
- &prop_csbase) ||
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK,
- &prop_csmask) ||
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csnum)) {
+ uint64_t csnum, CSEn;
+
+ if (!mcamd_get_cfgregs(hdl,
+ cs, MCAMD_REG_CSBASE, &CSBase,
+ cs, MCAMD_REG_CSMASK, &CSMask,
+ NULL) ||
+ !mcamd_get_numprops(hdl,
+ cs, MCAMD_PROP_NUM, &csnum,
+ cs, MCAMD_PROP_CSBE, &CSEn,
+ NULL)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mc_bkdg_patounm: "
- "failed to read cs properties\n");
+ "failed to read cs registers\n");
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
}
- CSBase = ((prop_csbase >> 4) & 0xffe00000) |
- ((prop_csbase >> 4) & 0x0000fe00);
- CSBase &= 0xffe0fe00;
- CSMask = ((prop_csmask >> 4) & 0x3fe00000) |
- ((prop_csmask >> 4) & 0x0000fe00);
- CSMask = (CSMask | 0x001f01ff) & 0x3fffffff;
+ /*
+ * BKDG line to skip Why
+ *
+ * F2Offset = Register already read,
+ * F2MaskOffset (rev F) Register already read
+ * CSBase = Register already read
+ * CSEn = We only keep enabled cs.
+ */
+ if (MC_REV_MATCH(rev, MC_REVS_FG)) {
+ CSBase &= 0x1ff83fe0;
+ /* CSMask = Get_PCI() Retrieved above */
+ CSMask = (CSMask | 0x0007c01f) & 0x1fffffff;
+ } else {
+ CSBase &= 0xffe0fe00;
+ /* CSMask = Get_PCI() Retrieved above */
+ CSMask = (CSMask | 0x001f01ff) & 0x3fffffff;
+ }
+
+ if (CSEn && (InputAddr & ~CSMask) == (CSBase & ~CSMask)) {
+ mcamd_node_t *sparecs;
- if (((InputAddr & ~CSMask) == (CSBase & ~CSMask))) {
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_bkdg_patounum: "
"match for chip select %d of MC %d\n", (int)csnum,
(int)mcnum);
- if ((which = mc_whichdimm(hdl, mc, pa, synd,
+ if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL)
+ cs = sparecs;
+
+ if ((which = mc_whichdimm(hdl, cs, pa, synd,
syndtype)) < 0)
return (-1); /* errno is set for us */
@@ -465,24 +588,28 @@ mc_bkdg_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
}
+/*
+ * Called for each memory controller to see if the given address is
+ * mapped to this node (as determined in iaddr_gen) and, if so, which
+ * chip-select on this node responds.
+ */
+
/*ARGSUSED*/
static int
mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
- uint32_t synd, int syndtype, struct mc_unum *unump)
+ uint32_t synd, int syndtype, mc_unum_t *unump)
{
uint64_t iaddr;
- mcamd_node_t *cs;
+ mcamd_node_t *cs, *sparecs;
int which;
#ifdef DEBUG
- struct mc_unum bkdg_unum;
+ mc_unum_t bkdg_unum;
int bkdgres;
/*
* We perform the translation twice, once using the brute-force
* approach of the BKDG and again using a more elegant but more
- * difficult to review against the BKDG approach. Note that both
- * approaches need to change for rev F since it increases max CS
- * size and so iaddr calculation etc changes.
+ * difficult to review against the BKDG approach.
*/
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "BKDG brute-force method begins\n");
bkdgres = mc_bkdg_patounum(hdl, mc, pa, synd, syndtype, &bkdg_unum);
@@ -501,7 +628,18 @@ mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
if (cs == NULL)
return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
- if ((which = mc_whichdimm(hdl, mc, pa, synd, syndtype)) < 0)
+ /*
+ * If the spare chip-select has been swapped in for the one just
+ * matched then it is really the spare that we are after. Note that
+ * when the swap is done the csbase, csmask and CSBE of the spare
+ * rank do not change - accesses to the bad rank (as nominated in
+ * the Online Spare Control Register) are redirect to the spare.
+ */
+ if ((sparecs = cs_sparedto(hdl, cs, mc)) != NULL) {
+ cs = sparecs;
+ }
+
+ if ((which = mc_whichdimm(hdl, cs, pa, synd, syndtype)) < 0)
return (-1); /* errno is set for us */
if (unum_fill(hdl, cs, which, iaddr, unump, 1) < 0)
@@ -509,15 +647,24 @@ mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
#ifdef DEBUG
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "bkdgres=%d res=0\n", bkdgres);
-#ifndef _KERNEL
/* offset is not checked - see note in BKDG algorithm */
- assert(bkdgres == 0 && unump->unum_board == bkdg_unum.unum_board &&
+ if (bkdgres != 0) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR, "BKDG alg failed while "
+ "ours succeeded\n");
+ } else if (!(unump->unum_board == bkdg_unum.unum_board &&
unump->unum_chip == bkdg_unum.unum_chip &&
unump->unum_mc == bkdg_unum.unum_mc &&
unump->unum_cs == bkdg_unum.unum_cs &&
unump->unum_dimms[0] == bkdg_unum.unum_dimms[0] &&
- unump->unum_dimms[1] == bkdg_unum.unum_dimms[1]);
-#endif /* !_KERNEL */
+ unump->unum_dimms[1] == bkdg_unum.unum_dimms[1])) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR,
+ "BKDG: node %d mc %d cs %d dimm(s) %d/%d\n"
+ "Ours: node 5d mc %d cs %d dimm(s) %d/%d\n",
+ bkdg_unum.unum_chip, bkdg_unum.unum_mc, bkdg_unum.unum_cs,
+ bkdg_unum.unum_dimms[0], bkdg_unum.unum_dimms[1],
+ unump->unum_chip, unump->unum_mc, unump->unum_cs,
+ unump->unum_dimms[0], unump->unum_dimms[1]);
+ }
#endif /* DEBUG */
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "Result: chip %d mc %d cs %d "
@@ -529,13 +676,18 @@ mc_patounum(struct mcamd_hdl *hdl, mcamd_node_t *mc, uint64_t pa,
int
mcamd_patounum(struct mcamd_hdl *hdl, mcamd_node_t *root, uint64_t pa,
- uint32_t synd, int syndtype, struct mc_unum *unump)
+ uint32_t synd, int syndtype, mc_unum_t *unump)
{
mcamd_node_t *mc;
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_patounum: pa=0x%llx, "
"synd=0x%x, syndtype=%d\n", pa, synd, syndtype);
+ /*
+ * Consider allowing syndrome 0 to act as a generic multibit
+ * syndrome. For example icache inf_sys_ecc1 captures an address
+ * but no syndrome - we can still resolve this to a dimm or dimms.
+ */
if (!mcamd_synd_validate(hdl, synd, syndtype))
return (mcamd_set_errno(hdl, EMCAMD_SYNDINVALID));
diff --git a/usr/src/common/mc/mc-amd/mcamd_rowcol.c b/usr/src/common/mc/mc-amd/mcamd_rowcol.c
index 3309d69421..979a182937 100644
--- a/usr/src/common/mc/mc-amd/mcamd_rowcol.c
+++ b/usr/src/common/mc/mc-amd/mcamd_rowcol.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -30,59 +29,68 @@
#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.
+ * Convenience structures to stash MC and CS properties in.
*/
-struct rcp_mc {
- uint64_t num; /* corresponding chip number */
- uint64_t rev; /* revision */
- uint64_t width; /* access width */
- uint64_t base; /* MC base address */
- uint64_t lim; /* MC limit address */
- uint64_t csbnkmap; /* chip-select bank map */
- uint64_t intlven; /* Node-interleave mask */
- uint64_t intlvsel; /* Node-interleave selection for this node */
- uint64_t csintlvfctr; /* chip-select interleave factor on this node */
- int bnkswzl; /* bank-swizzle mode - derived */
+struct mcprops {
+ mcamd_prop_t num; /* corresponding chip number */
+ mcamd_prop_t rev; /* revision */
+ mcamd_prop_t width; /* access width */
+ mcamd_prop_t base; /* MC base address */
+ mcamd_prop_t lim; /* MC limit address */
+ mcamd_prop_t csbnkmap_reg; /* chip-select bank map */
+ mcamd_prop_t intlven; /* Node-intlv mask */
+ mcamd_prop_t intlvsel; /* Node-intlv selection for this node */
+ mcamd_prop_t csintlvfctr; /* cs intlv factor on this node */
+ mcamd_prop_t bnkswzl; /* bank-swizzle mode */
+ mcamd_prop_t sparecs; /* spare cs#, if any */
+ mcamd_prop_t badcs; /* substituted cs#, if any */
};
-struct rcp_cs {
- uint64_t num; /* chip-select number */
- uint64_t base; /* chip-select base address */
- uint64_t mask; /* chip-select mask */
+struct csprops {
+ mcamd_prop_t num; /* chip-select number */
+ mcamd_prop_t base; /* chip-select base address */
+ mcamd_prop_t mask; /* chip-select mask */
+ mcamd_prop_t testfail; /* marked testFail */
+ mcamd_prop_t dimmrank; /* rank number on dimm(s) */
};
static int
getmcprops(struct mcamd_hdl *hdl, mcamd_node_t *mc, const char *caller,
- struct rcp_mc *pp)
+ struct mcprops *pp)
{
- if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &pp->num) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_REV, &pp->rev) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_ACCESS_WIDTH, &pp->width) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_BASE_ADDR, &pp->base) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_LIM_ADDR, &pp->lim) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_CSBANKMAP, &pp->csbnkmap) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILEN, &pp->intlven) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_ILSEL, &pp->intlvsel) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_CSBANK_INTLV,
- &pp->csintlvfctr)) {
+ if (!mcamd_get_numprops(hdl,
+ mc, MCAMD_PROP_NUM, &pp->num,
+ mc, MCAMD_PROP_REV, &pp->rev,
+ mc, MCAMD_PROP_ACCESS_WIDTH, &pp->width,
+ mc, MCAMD_PROP_BASE_ADDR, &pp->base,
+ mc, MCAMD_PROP_LIM_ADDR, &pp->lim,
+ mc, MCAMD_PROP_CSBANKMAPREG, &pp->csbnkmap_reg,
+ mc, MCAMD_PROP_ILEN, &pp->intlven,
+ mc, MCAMD_PROP_ILSEL, &pp->intlvsel,
+ mc, MCAMD_PROP_CSINTLVFCTR, &pp->csintlvfctr,
+ mc, MCAMD_PROP_BANKSWZL, &pp->bnkswzl,
+ mc, MCAMD_PROP_SPARECS, &pp->sparecs,
+ mc, MCAMD_PROP_BADCS, &pp->badcs,
+ NULL)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "%s: failed to read mc "
"props for mc 0x%p\n", caller, mc);
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
}
- pp->bnkswzl = ((pp->csbnkmap & MC_DC_BAM_CSBANK_SWIZZLE) != 0);
-
return (0);
}
static int
getcsprops(struct mcamd_hdl *hdl, mcamd_node_t *cs, const char *caller,
- struct rcp_cs *csp)
+ struct csprops *csp)
{
- if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM, &csp->num) ||
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_BASE_ADDR, &csp->base) ||
- !mcamd_get_numprop(hdl, cs, MCAMD_PROP_MASK, &csp->mask)) {
+ if (!mcamd_get_numprops(hdl,
+ cs, MCAMD_PROP_NUM, &csp->num,
+ cs, MCAMD_PROP_BASE_ADDR, &csp->base,
+ cs, MCAMD_PROP_MASK, &csp->mask,
+ cs, MCAMD_PROP_TESTFAIL, &csp->testfail,
+ cs, MCAMD_PROP_DIMMRANK, &csp->dimmrank,
+ NULL)) {
mcamd_dprintf(hdl, MCAMD_DBG_ERR, "%s: failed to read cs "
"props for cs 0x%p\n", caller, cs);
return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
@@ -92,35 +100,43 @@ getcsprops(struct mcamd_hdl *hdl, mcamd_node_t *cs, const char *caller,
}
static int
-gettbls(struct mcamd_hdl *hdl, uint_t csmode, struct rcp_mc *mcpp,
- const struct bankaddr_mode **bamp, const struct csrcb_map **rcbmp,
- struct csintlv_desc *csid, const char *caller)
+gettbls(struct mcamd_hdl *hdl, uint_t csmode, struct mcprops *mcpp,
+ const struct rct_bnkaddrmode **bamp, const struct rct_rcbmap **rcbmp,
+ const struct rct_bnkswzlinfo **swzlp, struct rct_csintlv *csid,
+ const char *caller)
{
- if (bamp && (*bamp = rct_bankaddr_mode(mcpp->rev, csmode)) == NULL) {
+ uint_t rev = (uint_t)mcpp->rev;
+ int width = (int)mcpp->width;
+
+ if (bamp && (*bamp = rct_bnkaddrmode(rev, csmode)) == NULL) {
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: no bank address mode "
- "table for MC rev %d csmode %d\n", caller,
- (int)mcpp->rev, csmode);
+ "table for MC rev %d csmode %d\n", caller, rev, csmode);
return (mcamd_set_errno(hdl, EMCAMD_NOTSUP));
}
- if (rcbmp && (*rcbmp = rct_rcbmap(mcpp->rev, mcpp->width,
- csmode)) == NULL) {
+ if (rcbmp && (*rcbmp = rct_rcbmap(rev, width, csmode)) == NULL) {
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: no dram address map "
"table for MC rev %d csmode %d\n", caller,
- (int)mcpp->rev, csmode);
+ rev, csmode);
+ return (mcamd_set_errno(hdl, EMCAMD_NOTSUP));
+ }
+
+ if (swzlp && (*swzlp = rct_bnkswzlinfo(rev, width)) == NULL) {
+ mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: no bank swizzling "
+ "table for MC rev %d width %d\n", caller, rev, width);
return (mcamd_set_errno(hdl, EMCAMD_NOTSUP));
}
if (csid) {
- if (mcpp->csintlvfctr != 0) {
- rct_csintlv_bits(mcpp->rev, mcpp->width, csmode,
+ if (mcpp->csintlvfctr > 1) {
+ rct_csintlv_bits(rev, width, csmode,
mcpp->csintlvfctr, csid);
if (csid->csi_factor == 0) {
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "%s: "
"could not work out cs interleave "
"paramters for MC rev %d, width %d, "
"csmode %d, factor %d\n", caller,
- (int)mcpp->rev, (int)mcpp->width, csmode,
+ rev, width, csmode,
(int)mcpp->csintlvfctr);
return (mcamd_set_errno(hdl, EMCAMD_NOTSUP));
}
@@ -149,8 +165,8 @@ iaddr_add(struct mcamd_hdl *hdl, uint64_t in, uint64_t add, const char *what)
* we adopt the same convention in address reconstruction then all should work.
*/
static uint32_t
-iaddr_to_row(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
- const struct csrcb_map *rcbm, struct csintlv_desc *csid, uint64_t iaddr)
+iaddr_to_row(struct mcamd_hdl *hdl, const struct rct_bnkaddrmode *bamp,
+ const struct rct_rcbmap *rcbm, struct rct_csintlv *csid, uint64_t iaddr)
{
uint32_t addr = 0;
int abitno, ibitno;
@@ -158,13 +174,13 @@ iaddr_to_row(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
int swapped = 0;
for (abitno = 0; abitno < nbits; abitno++) {
- ibitno = rcbm->csrcb_rowbits[abitno];
+ ibitno = rcbm->rcb_rowbit[abitno];
if (MC_RC_CSI_SWAPPED_BIT(csid, ibitno)) {
ibitno = MC_RC_CSI_BITSWAP(csid, ibitno);
swapped++;
}
- if (iaddr & (1 << ibitno))
- addr |= (1 << abitno);
+ if (BITVAL(iaddr, ibitno) != 0)
+ SETBIT(addr, abitno);
}
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_to_row: iaddr 0x%llx --> "
@@ -175,8 +191,8 @@ iaddr_to_row(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
/*ARGSUSED*/
static uint64_t
-row_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
- const struct csrcb_map *rcbm, struct csintlv_desc *csid, uint32_t rowaddr)
+row_to_iaddr(struct mcamd_hdl *hdl, const struct rct_bnkaddrmode *bamp,
+ const struct rct_rcbmap *rcbm, struct rct_csintlv *csid, uint32_t rowaddr)
{
uint64_t iaddr = 0;
int abitno, ibitno;
@@ -185,7 +201,7 @@ row_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
for (abitno = 0; abitno < nbits; abitno++) {
if (BIT(rowaddr, abitno) == 0)
continue;
- ibitno = rcbm->csrcb_rowbits[abitno];
+ ibitno = rcbm->rcb_rowbit[abitno];
if (MC_RC_CSI_SWAPPED_BIT(csid, ibitno)) {
ibitno = MC_RC_CSI_BITSWAP(csid, ibitno);
}
@@ -197,8 +213,8 @@ row_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
static uint32_t
-iaddr_to_col(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
- const struct csrcb_map *rcbm, uint64_t iaddr)
+iaddr_to_col(struct mcamd_hdl *hdl, const struct rct_bnkaddrmode *bamp,
+ const struct rct_rcbmap *rcbm, uint64_t iaddr)
{
uint32_t addr = 0;
int abitno, ibitno, bias = 0;
@@ -214,9 +230,9 @@ iaddr_to_col(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
if (abitno == MC_PC_COLADDRBIT)
bias = 1;
- ibitno = rcbm->csrcb_colbits[abitno + bias];
+ ibitno = rcbm->rcb_colbit[abitno + bias];
- if (iaddr & (1 << ibitno))
+ if (BITVAL(iaddr, ibitno) != 0)
SETBIT(addr, abitno);
}
@@ -228,8 +244,8 @@ iaddr_to_col(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
/*ARGSUSED*/
static uint64_t
-col_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
- const struct csrcb_map *rcbm, uint32_t coladdr)
+col_to_iaddr(struct mcamd_hdl *hdl, const struct rct_bnkaddrmode *bamp,
+ const struct rct_rcbmap *rcbm, uint32_t coladdr)
{
uint64_t iaddr = 0;
int abitno, ibitno, bias = 0;
@@ -248,7 +264,7 @@ col_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
if (abitno == MC_PC_COLADDRBIT)
bias = 1;
- ibitno = rcbm->csrcb_colbits[abitno + bias];
+ ibitno = rcbm->rcb_colbit[abitno + bias];
SETBIT(iaddr, ibitno);
}
@@ -256,24 +272,38 @@ col_to_iaddr(struct mcamd_hdl *hdl, const struct bankaddr_mode *bamp,
}
/*
- * Extract bank bit arguments and xor them together. Tables for
- * non bank-swizzling should have all but the first argument zero.
+ * Extract bank bit arguments and swizzle if requested.
*/
static uint32_t
-iaddr_to_bank(struct mcamd_hdl *hdl, const struct csrcb_map *rcbm,
- int bnkswzl, uint64_t iaddr)
+iaddr_to_bank(struct mcamd_hdl *hdl, const struct rct_rcbmap *rcbm,
+ const struct rct_bnkswzlinfo *swzlp, uint64_t iaddr)
{
uint32_t addr = 0;
int abitno, ibitno, i;
- int bnkargs = bnkswzl ? MC_RC_BANKARGS : 1;
- for (abitno = 0; abitno < MC_RC_BANKBITS; abitno++) {
- uint32_t val = 0;
- for (i = 0; i < bnkargs; i++) {
- ibitno = rcbm->csrcb_bankargs[abitno][i];
- val ^= ((iaddr >> ibitno) & 0x1);
+ for (abitno = 0; abitno < rcbm->rcb_nbankbits; abitno++) {
+ uint32_t val;
+
+ /*
+ * rcb_bankbit[abitno] tells us which iaddr bit number
+ * will form bit abitno of the bank address
+ */
+ ibitno = rcbm->rcb_bankbit[abitno];
+ val = BITVAL(iaddr, ibitno);
+
+ /*
+ * 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++) {
+ ibitno = swzlp->bswz_rowbits[abitno][i];
+ val ^= BITVAL(iaddr, ibitno);
+ }
}
- addr |= (val << abitno);
+
+ if (val)
+ SETBIT(addr, abitno);
}
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "iaddr_to_bank: iaddr 0x%llx --> "
@@ -292,41 +322,44 @@ iaddr_to_bank(struct mcamd_hdl *hdl, const struct csrcb_map *rcbm,
*/
/*ARGSUSED*/
static uint64_t
-bank_to_iaddr(struct mcamd_hdl *hdl, const struct csrcb_map *rcbm,
- int bnkswzl, uint64_t partiaddr, uint32_t bankaddr)
+bank_to_iaddr(struct mcamd_hdl *hdl, const struct rct_rcbmap *rcbm,
+ const struct rct_bnkswzlinfo *swzlp, uint64_t partiaddr, uint32_t bankaddr)
{
uint64_t iaddr = 0;
int abitno, pibitno, i;
- for (abitno = 0; abitno < MC_RC_BANKBITS; abitno++) {
+ for (abitno = 0; abitno < rcbm->rcb_nbankbits; abitno++) {
uint32_t val = BITVAL(bankaddr, abitno);
- if (bnkswzl) {
- for (i = 1; i < MC_RC_BANKARGS; i++) {
- pibitno = rcbm->csrcb_bankargs[abitno][i];
+ if (swzlp) {
+ for (i = 0; i < MC_RC_SWZLBITS; i++) {
+ pibitno = swzlp->bswz_rowbits[abitno][i];
val ^= BITVAL(partiaddr, pibitno);
}
}
if (val)
- SETBIT(iaddr, rcbm->csrcb_bankargs[abitno][0]);
+ SETBIT(iaddr, rcbm->rcb_bankbit[abitno]);
}
return (iaddr);
}
static int
-iaddr_to_rcb(struct mcamd_hdl *hdl, uint_t csmode, struct rcp_mc *mcpp,
+iaddr_to_rcb(struct mcamd_hdl *hdl, uint_t csmode, struct mcprops *mcpp,
uint64_t iaddr, uint32_t *rowp, uint32_t *colp, uint32_t *bankp)
{
- const struct bankaddr_mode *bamp;
- const struct csrcb_map *rcbm;
- struct csintlv_desc csi;
-
- if (gettbls(hdl, csmode, mcpp, &bamp, &rcbm, &csi, "iaddr_to_rcb") < 0)
+ const struct rct_bnkaddrmode *bamp;
+ const struct rct_rcbmap *rcbmp;
+ const struct rct_bnkswzlinfo *swzlp = NULL;
+ struct rct_csintlv csi;
+
+ if (gettbls(hdl, csmode, mcpp, &bamp, &rcbmp,
+ mcpp->bnkswzl ? &swzlp : NULL, &csi,
+ "iaddr_to_rcb") < 0)
return (-1); /* errno already set */
- *rowp = iaddr_to_row(hdl, bamp, rcbm, &csi, iaddr);
- *colp = iaddr_to_col(hdl, bamp, rcbm, iaddr);
- *bankp = iaddr_to_bank(hdl, rcbm, mcpp->bnkswzl, iaddr);
+ *rowp = iaddr_to_row(hdl, bamp, rcbmp, &csi, iaddr);
+ *colp = iaddr_to_col(hdl, bamp, rcbmp, iaddr);
+ *bankp = iaddr_to_bank(hdl, rcbmp, swzlp, iaddr);
return (0);
}
@@ -337,7 +370,7 @@ iaddr_to_rcb(struct mcamd_hdl *hdl, uint_t csmode, struct rcp_mc *mcpp,
* interleave or to insert the node interleave selection bits.
*/
static int
-iaddr_unnormalize(struct mcamd_hdl *hdl, struct rcp_mc *mcpp, uint64_t iaddr,
+iaddr_unnormalize(struct mcamd_hdl *hdl, struct mcprops *mcpp, uint64_t iaddr,
uint64_t *rsltp)
{
uint64_t dramaddr;
@@ -373,6 +406,9 @@ iaddr_unnormalize(struct mcamd_hdl *hdl, struct rcp_mc *mcpp, uint64_t iaddr,
* 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.
*/
dramaddr = (BITS(iaddr, 35, 12) << intlvbits) |
(mcpp->intlvsel << 12) | BITS(iaddr, 11, 0);
@@ -392,15 +428,13 @@ iaddr_unnormalize(struct mcamd_hdl *hdl, struct rcp_mc *mcpp, uint64_t iaddr,
int
mc_pa_to_offset(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *cs,
- mcamd_node_t *dimm, uint64_t iaddr, uint64_t *offsetp)
+ uint64_t iaddr, uint64_t *offsetp)
{
mcamd_dimm_offset_un_t offset_un;
uint_t csmode;
uint32_t bankaddr, rowaddr, coladdr;
- int rank;
- mcamd_node_t *tcs;
- struct rcp_mc mcp;
- struct rcp_cs csp;
+ struct mcprops mcp;
+ struct csprops csp;
*offsetp = MCAMD_RC_INVALID_OFFSET;
@@ -408,29 +442,7 @@ mc_pa_to_offset(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *cs,
getcsprops(hdl, cs, "mc_dimm_offset", &csp) < 0)
return (-1); /* errno already set */
- csmode = MC_CS_MODE(mcp.csbnkmap, csp.num);
-
- /*
- * 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.
- */
- for (rank = 0, tcs = mcamd_cs_next(hdl, (mcamd_node_t *)dimm, NULL);
- tcs != NULL;
- rank++, tcs = mcamd_cs_next(hdl, (mcamd_node_t *)dimm, tcs)) {
- struct rcp_cs tcsp;
-
- if (getcsprops(hdl, tcs, "mc_dimm_offset", &tcsp) < 0)
- return (-1); /* errno already set */
- if (tcsp.num == csp.num)
- break;
- }
- if (rank == MC_CHIP_DIMMRANKMAX) {
- mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_dimm_offset: "
- "iteration over chip-selects of dimm 0x%p failed "
- "to match on expected csnum %d\n", dimm, (int)csp.num);
- return (mcamd_set_errno(hdl, EMCAMD_TREEINVALID));
- }
+ csmode = MC_CS_MODE(mcp.csbnkmap_reg, csp.num);
if (iaddr_to_rcb(hdl, csmode, &mcp, iaddr, &rowaddr,
&coladdr, &bankaddr) < 0)
@@ -440,7 +452,7 @@ mc_pa_to_offset(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *cs,
offset_un.do_valid = 1;
offset_un.do_version = MCAMD_OFFSET_VERSION;
- offset_un.do_rank = rank;
+ offset_un.do_rank = csp.dimmrank;
offset_un.do_row = rowaddr;
offset_un.do_bank = bankaddr;
offset_un.do_col = coladdr;
@@ -451,7 +463,7 @@ mc_pa_to_offset(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *cs,
}
/*
- * Given a MC and DIMM and offset (dimm rank, row, col, internal bank) we
+ * 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
@@ -468,18 +480,15 @@ mc_offset_to_pa(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *dimm,
mcamd_node_t *cs;
mcamd_dimm_offset_un_t off_un;
uint32_t rank, rowaddr, bankaddr, coladdr;
- int i;
uint64_t iaddr = 0;
- const struct bankaddr_mode *bamp;
- const struct csrcb_map *rcbm;
- struct csintlv_desc csi;
- struct rcp_mc mcp;
- struct rcp_cs csp;
+ const struct rct_bnkaddrmode *bamp;
+ const struct rct_rcbmap *rcbmp;
+ const struct rct_bnkswzlinfo *swzlp = NULL;
+ struct rct_csintlv csi;
+ struct mcprops mcp;
+ struct csprops csp;
uint64_t csmode;
- 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;
+ int maskhi_hi, maskhi_lo, masklo_hi, masklo_lo;
off_un.do_offset = offset;
rank = off_un.do_rank;
@@ -487,65 +496,149 @@ mc_offset_to_pa(struct mcamd_hdl *hdl, mcamd_node_t *mc, mcamd_node_t *dimm,
rowaddr = off_un.do_row;
coladdr = off_un.do_col;
+ mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_offset_to_pa: offset 0x%llx "
+ "-> rank %d bank %d row 0x%x col 0x%x\n", offset,
+ rank, bankaddr, rowaddr, coladdr);
+
if (getmcprops(hdl, mc, "mc_offset_to_pa", &mcp) < 0)
return (-1); /* errno already set */
+ maskhi_hi = MC_CSMASKHI_HIBIT(mcp.rev);
+ maskhi_lo = MC_CSMASKHI_LOBIT(mcp.rev);
+ masklo_hi = MC_CSMASKLO_HIBIT(mcp.rev);
+ masklo_lo = MC_CSMASKLO_LOBIT(mcp.rev);
+
/*
- * Find the rank'th chip-select on this dimm.
+ * Find the chip-select on this dimm using the given rank.
*/
- i = 0;
- cs = mcamd_cs_next(hdl, dimm, NULL);
- while (i != rank && cs != NULL) {
- cs = mcamd_cs_next(hdl, dimm, cs);
- i++;
+ for (cs = mcamd_cs_next(hdl, dimm, NULL); cs != NULL;
+ cs = mcamd_cs_next(hdl, dimm, cs)) {
+ if (getcsprops(hdl, cs, "mc_offset_to_pa", &csp) < 0)
+ return (-1); /* errno already set */
+
+ if (csp.dimmrank == rank)
+ break;
}
- if (i != rank || cs == NULL) {
+
+ if (cs == NULL) {
mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mc_offset_to_pa: Current "
- "dimm in this slot does not have an %d'th cs\n",
+ "dimm in this slot does not have a cs using rank %d\n",
rank);
return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
}
- if (getcsprops(hdl, cs, "mc_offset_to_pa", &csp) < 0)
- return (-1); /* errno already set */
+ /*
+ * 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#.
+ */
+ if (mcp.badcs != MC_INVALNUM && csp.num == mcp.badcs) {
+ return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
+ } else if (csp.testfail) {
+ return (mcamd_set_errno(hdl, EMCAMD_NOADDR));
+ } else if (mcp.sparecs != MC_INVALNUM && csp.num == mcp.sparecs &&
+ mcp.badcs != MC_INVALNUM) {
+ /*
+ * 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.
+ */
+ for (cs = mcamd_cs_next(hdl, mc, NULL); cs != NULL;
+ cs = mcamd_cs_next(hdl, mc, cs)) {
+ mcamd_prop_t csnum;
+
+ if (!mcamd_get_numprop(hdl, cs, MCAMD_PROP_NUM,
+ &csnum)) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR,
+ "mcamd_offset_to_pa: csnum lookup failed "
+ "while looking for bad cs#");
+ return (mcamd_set_errno(hdl,
+ EMCAMD_TREEINVALID));
+ }
+ if (csnum == mcp.badcs)
+ break;
+ }
+
+ if (cs == NULL) {
+ mcamd_dprintf(hdl, MCAMD_DBG_ERR, "mcamd_offset_to_pa: "
+ "failed to find cs for bad cs#%d\n", mcp.badcs);
+ return (mcamd_set_errno(hdl,
+ EMCAMD_TREEINVALID));
+ }
+
+ /* found bad cs - reread properties from it instead of spare */
+ if (getcsprops(hdl, cs, "mc_offset_to_pa", &csp) < 0)
+ return (-1); /* errno already set */
+ }
- csmode = MC_CS_MODE(mcp.csbnkmap, csp.num);
+ csmode = MC_CS_MODE(mcp.csbnkmap_reg, csp.num);
- if (gettbls(hdl, csmode, &mcp, &bamp, &rcbm, &csi,
+ if (gettbls(hdl, csmode, &mcp, &bamp, &rcbmp,
+ mcp.bnkswzl ? &swzlp : NULL, &csi,
"mc_offset_to_pa") < 0)
return (-1); /* errno already set */
- /*CONSTANTCONDITION*/
- if (MC_DC_CSM_UNMASKED_BITS != 0) {
+ /*
+ * If there are umaskable DRAM InputAddr bits the add those bits
+ * to iaddr from the cs base address.
+ */
+ if (MC_CSMASK_UNMASKABLE(mcp.rev) != 0) {
iaddr |= iaddr_add(hdl, iaddr,
- BITS(csp.base, maskhi_hi + MC_DC_CSM_UNMASKED_BITS,
+ BITS(csp.base, maskhi_hi + MC_CSMASK_UNMASKABLE(mcp.rev),
maskhi_hi + 1), "unmaskable cs basehi bits");
}
+ /*
+ * basehi bits not meing masked pass straight through to the
+ * iaddr.
+ */
iaddr |= iaddr_add(hdl, iaddr,
BITS(csp.base, maskhi_hi, maskhi_lo) &
~BITS(csp.mask, maskhi_hi, maskhi_lo),
"cs basehi bits not being masked");
- if (mcp.csintlvfctr != 0) {
+ /*
+ * if cs interleaving is active then baselo address bit are being
+ * masked - pass the rest through.
+ */
+ if (mcp.csintlvfctr > 1) {
iaddr |= iaddr_add(hdl, iaddr,
BITS(csp.base, masklo_hi, masklo_lo) &
~BITS(csp.mask, masklo_hi, masklo_lo),
"cs baselo bits not being masked");
}
+ /*
+ * Reconstruct iaddr bits from known row address
+ */
iaddr |= iaddr_add(hdl, iaddr,
- row_to_iaddr(hdl, bamp, rcbm, &csi, rowaddr),
+ row_to_iaddr(hdl, bamp, rcbmp, &csi, rowaddr),
"add iaddr bits from row");
+ /*
+ * Reconstruct iaddr bits from known column address
+ */
iaddr |= iaddr_add(hdl, iaddr,
- col_to_iaddr(hdl, bamp, rcbm, coladdr),
+ col_to_iaddr(hdl, bamp, rcbmp, coladdr),
"add iaddr bits from col");
+ /*
+ * Reconstruct iaddr bits from known internal banksel address
+ */
iaddr |= iaddr_add(hdl, iaddr,
- bank_to_iaddr(hdl, rcbm, mcp.bnkswzl, iaddr, bankaddr),
+ bank_to_iaddr(hdl, rcbmp, swzlp, iaddr, bankaddr),
"add iaddr bits from bank");
+ /*
+ * Move iaddr up into the range for this MC and insert any
+ * node interleave selection bits.
+ */
if (iaddr_unnormalize(hdl, &mcp, iaddr, pap) < 0)
return (-1); /* errno already set */
@@ -556,15 +649,16 @@ int
mcamd_cs_size(struct mcamd_hdl *hdl, mcamd_node_t *mc, int csnum, size_t *szp)
{
uint_t csmode;
- struct rcp_mc mcp;
- const struct bankaddr_mode *bamp;
+ struct mcprops mcp;
+ const struct rct_bnkaddrmode *bamp;
if (getmcprops(hdl, mc, "mcamd_cs_size", &mcp) < 0)
return (-1); /* errno already set */
- csmode = MC_CS_MODE(mcp.csbnkmap, csnum);
+ csmode = MC_CS_MODE(mcp.csbnkmap_reg, csnum);
- if (gettbls(hdl, csmode, &mcp, &bamp, NULL, NULL, "mcamd_cs_size") < 0)
+ if (gettbls(hdl, csmode, &mcp, &bamp, NULL, NULL, NULL,
+ "mcamd_cs_size") < 0)
return (-1); /* errno already set */
*szp = MC_CS_SIZE(bamp, mcp.width);
diff --git a/usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h b/usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h
index d7341e9b28..72064e2c21 100644
--- a/usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h
+++ b/usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -55,59 +54,31 @@ extern "C" {
#define BITVAL(var, num) ((BIT(var, num) >> (num)) & 1ULL)
-#define MC_RC_ROW_MAX 14 /* maximum number of row address bits */
-#define MC_RC_COL_MAX 12 /* maximum number of col address bits */
-#define MC_RC_BANKBITS 2 /* number of internal banksel bits */
-#define MC_RC_BANKARGS 3 /* bits used for 1 banksel bit */
-#define MC_RC_CSMODES 16 /* max number of cs bankaddr modes */
+#define MC_RC_ROW_MAX 16 /* maximum number of row address bits */
+#define MC_RC_COL_MAX 12 /* maximum number of col address bits */
+#define MC_RC_BANKBITS_MAX 3 /* number of internal banksel bits */
+#define MC_RC_CSMODES 16 /* max number of cs bankaddr modes */
+#define MC_RC_SWZLBITS 2 /* number of row bits in swizzle */
-/*
- * Row, column and bank mapping is derived after allowing for interleave
- * from the normalized dram address through the tables of BKDG 3.29
- * section 3.5.6.1. We have tables for:
- *
- * . rev CG and earlier, 64-bit MC mode
- * . rev CG and earlier, 128-bit MC mode
- * . rev D and later, 64-bit MC mode (no bank swizzling if rev E)
- * . rev D and later, 128-bit MC mode (no bank swizzling if rev E)
- * . rev E and later, 64-bit MC mode with bank swizzling
- * . rev E and later, 128-bit MC mode with bank swizzling
- *
- * Each table is indexed by CS Mode (equivalently, CS size) and tells us
- * which bits of the normalized dram address (i.e., the address modified for
- * the local MC base address and with node interleave selection bits removed)
- * to use in forming the column address, row address and internal bank
- * selection.
- *
- * Note that for rev CG and earlier there is some overloading of CS mode
- * encoding such that we do not know the number of row and column address
- * bits from the CS mode alone, e.g., for 128MB DIMM modules we may have
- * 13 row bits and 9 column, or 12 row and 10 column. In these case the
- * tables held in the structures defined below will have a duplicated bit
- * number in the row and column bits. In these ambiguous cases cm_rc_ambig
- * should be set in the table.
- */
-
-struct bankaddr_mode {
+struct rct_bnkaddrmode {
int bam_sizemb; /* DIMM size in MB */
int bam_nrows; /* number of row address bits */
int bam_ncols; /* number of column address bits */
int bam_ambig; /* numbers are maximums; keep last */
};
-struct csrcb_map {
- int csrcb_bankargs[MC_RC_BANKBITS][MC_RC_BANKARGS];
- int csrcb_rowbits[MC_RC_ROW_MAX];
- int csrcb_colbits[MC_RC_COL_MAX + 1]; /* one for MC_PC_ALL */
+struct rct_rcbmap {
+ int rcb_nbankbits; /* # of bank address bits */
+ int rcb_bankbit[MC_RC_BANKBITS_MAX]; /* bank address bits */
+ int rcb_rowbit[MC_RC_ROW_MAX];
+ int rcb_colbit[MC_RC_COL_MAX + 1]; /* one for MC_PC_ALL */
};
-struct csrcb_map_tbl {
- int mt_rev; /* revision to which this applies */
- int mt_width; /* MC mode (64 or 128) */
- struct csrcb_map mt_csmap[MC_RC_CSMODES];
+struct rct_bnkswzlinfo {
+ int bswz_rowbits[MC_RC_BANKBITS_MAX][MC_RC_SWZLBITS];
};
-struct csintlv_desc {
+struct rct_csintlv {
int csi_factor; /* cs interleave factor */
int csi_hibit; /* first non-offset bit in addr */
int csi_lobit; /* first row bit in addr */
@@ -121,9 +92,10 @@ struct csintlv_desc {
#define MC_RC_CSI_BITSWAP(csidp, n) \
(csidp->csi_hibit + n - csidp->csi_lobit)
-extern const struct bankaddr_mode *rct_bankaddr_mode(uint_t, uint_t);
-extern const struct csrcb_map *rct_rcbmap(uint_t, int, uint_t);
-extern void rct_csintlv_bits(uint_t, int, uint_t, int, struct csintlv_desc *);
+extern const struct rct_bnkaddrmode *rct_bnkaddrmode(uint_t, uint_t);
+extern const struct rct_rcbmap *rct_rcbmap(uint_t, int, uint_t);
+extern const struct rct_bnkswzlinfo *rct_bnkswzlinfo(uint_t, int);
+extern void rct_csintlv_bits(uint_t, int, uint_t, int, struct rct_csintlv *);
#ifdef __cplusplus
}
diff --git a/usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c b/usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c
index f6d8ab5e57..79e360590b 100644
--- a/usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c
+++ b/usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c
@@ -32,80 +32,89 @@
#include <mcamd_rowcol_impl.h>
/*
- * Chip-Select Bank Address Mode Encodings - BKDG 3.29 3.5.6
+ * =========== Chip-Select Bank Address Mode Encodings =======================
*/
-static const struct bankaddr_mode bankaddr_modes_pre_d[];
-static const struct bankaddr_mode bankaddr_modes_d_e[];
-static const struct bam_desc {
- int rev;
+/* Individual table declarations */
+static const struct rct_bnkaddrmode bnkaddr_tbls_pre_d[];
+static const struct rct_bnkaddrmode bnkaddr_tbls_d_e[];
+static const struct rct_bnkaddrmode bnkaddr_tbls_f[];
+
+/* Managing bank address mode tables */
+static const struct _bnkaddrmode_tbldesc {
+ uint_t revmask;
int nmodes;
- const struct bankaddr_mode *modetbl;
-} bankaddr_modes[] = {
- { MC_REV_PRE_D, 7, bankaddr_modes_pre_d },
- { MC_REV_D_E, 11, bankaddr_modes_d_e },
+ const struct rct_bnkaddrmode *modetbl;
+} bnkaddr_tbls[] = {
+ { MC_REVS_BC, 7, bnkaddr_tbls_pre_d },
+ { MC_REVS_DE, 11, bnkaddr_tbls_d_e },
+ { MC_REVS_FG, 12, bnkaddr_tbls_f },
};
/*
- * DRAM Address Mappings for bank/row/column - BKDG 3.29 3.5.6.1
+ * =========== DRAM Address Mappings for bank/row/column =====================
*/
-static const struct csrcb_map_tbl dram_addrmap_pre_d_128;
-static const struct csrcb_map_tbl dram_addrmap_pre_d_64;
-static const struct csrcb_map_tbl dram_addrmap_d_e_64;
-static const struct csrcb_map_tbl dram_addrmap_d_e_128;
-static const struct rcbmap_desc {
+
+/* Individual table declarations */
+struct _rcbmap_tbl {
+ uint_t mt_revmask; /* revision to which this applies */
+ int mt_width; /* MC mode (64 or 128) */
+ const struct rct_rcbmap mt_csmap[MC_RC_CSMODES];
+};
+
+static const struct _rcbmap_tbl dram_addrmap_pre_d_64;
+static const struct _rcbmap_tbl dram_addrmap_pre_d_128;
+static const struct _rcbmap_tbl dram_addrmap_d_e_64;
+static const struct _rcbmap_tbl dram_addrmap_d_e_128;
+static const struct _rcbmap_tbl dram_addrmap_f_64;
+static const struct _rcbmap_tbl dram_addrmap_f_128;
+
+/* Managing row/column/bank tables */
+static const struct _rcbmap_tbldesc {
int nmodes;
- const struct csrcb_map_tbl *rcbmap;
-} rcbmaps[] = {
+ const struct _rcbmap_tbl *rcbmap;
+} rcbmap_tbls[] = {
{ 7, &dram_addrmap_pre_d_64 },
{ 7, &dram_addrmap_pre_d_128 },
{ 11, &dram_addrmap_d_e_64 },
{ 11, &dram_addrmap_d_e_128 },
+ { 12, &dram_addrmap_f_64 },
+ { 12, &dram_addrmap_f_128 },
};
/*
- * Lookup the Chip-Select Bank Address Mode Encoding table for a given
- * chip revision and chip-select mode.
+ * =========== Bank swizzling information ====================================
*/
-const struct bankaddr_mode *
-rct_bankaddr_mode(uint_t mcrev, uint_t csmode)
-{
- int i;
- const struct bam_desc *bdp = bankaddr_modes;
-
- for (i = 0; i < sizeof (bankaddr_modes) / sizeof (struct bam_desc);
- i++, bdp++) {
- if (bdp->rev == mcrev && csmode < bdp->nmodes)
- return (&bdp->modetbl[csmode]);
- }
+/* Individual table declarations */
+struct _bnkswzl_tbl {
+ uint_t swzt_revmask; /* revision to which this applies */
+ int swzt_width; /* MC mode (64 or 128) */
+ const struct rct_bnkswzlinfo swzt_bits;
+};
- return (NULL);
-}
+static const struct _bnkswzl_tbl bnswzl_info_e_64;
+static const struct _bnkswzl_tbl bnswzl_info_e_128;
+static const struct _bnkswzl_tbl bnswzl_info_f_64;
+static const struct _bnkswzl_tbl bnswzl_info_f_128;
+
+/* Managing bank swizzle tables */
+static const struct _bnkswzl_tbl *bnkswzl_tbls[] = {
+ &bnswzl_info_e_64,
+ &bnswzl_info_e_128,
+ &bnswzl_info_f_64,
+ &bnswzl_info_f_128,
+};
/*
- * Lookup the DRAM Address Mapping table for a given chip revision, access
- * width, bank-swizzle and chip-select mode.
+ * ======================================================================
+ * | Tables reflecting those in the BKDG |
+ * ======================================================================
*/
-const struct csrcb_map *
-rct_rcbmap(uint_t mcrev, int width, uint_t csmode)
-{
- const struct csrcb_map_tbl *rcbm;
- int i;
-
- for (i = 0; i < sizeof (rcbmaps) / sizeof (struct rcbmap_desc); i++) {
- rcbm = rcbmaps[i].rcbmap;
- if (rcbm->mt_rev == mcrev && rcbm->mt_width == width &&
- csmode < rcbmaps[i].nmodes)
- return (&rcbm->mt_csmap[csmode]);
- }
-
- return (NULL);
-}
/*
- * DRAM Address Mapping in Interleaving Mode - BKDG 3.29 section 3.5.6.2.
+ * DRAM Address Mapping in Interleaving Mode
*
* Chip-select interleave is performed by addressing across the columns
* of the first row of internal bank-select 0 on a chip-select, then the
@@ -113,9 +122,8 @@ rct_rcbmap(uint_t mcrev, int width, uint_t csmode)
* moving on to the next row of this chip-select we then rotate across
* other chip-selects in the interleave. The row/column/bank mappings
* described elsewhere in this file show that a DRAM InputAddr breaks down
- * as follows (example is the first line of table 7 which is for a 32MB
- * chip-select requiring 25 bits to address all of it) for the non-interleaved
- * case:
+ * as follows, using an example for CS Mode 0000 revision CG and earlier 64-bit
+ * mode; the cs size is 32MB, requiring 25 bits to address all of it.
*
* chip-selection bits | offset within chip-select bits |
* | row bits | bank bits | column bits | - |
@@ -131,125 +139,19 @@ rct_rcbmap(uint_t mcrev, int width, uint_t csmode)
* bits 15, 14 and 13. We swap the chosen bits with the least significant
* high order chip-selection bits.
*
- * Tables 13-16 of BKDG 3.5.6.2 really just describe the above. Working
+ * The BKDG interleave tables really just describe the above. Working
* out the high-order bits to swap is easy since that is derived directly
* from the chip-select size. The low-order bits depend on the device
* parameters since we need to target the least significant row address bits -
- * but we have that information from the rcbmaps since the first row bit
+ * but we have that information from the rcbmap_tbls since the first row bit
* simply follows the last bank address bit.
- *
- * Short version: we will do tables 13 to 16 programatically rather than
- * replicating those tables.
*/
/*
- * Yet another highbit function. This really needs to go to common source.
- * Returns range 0 to 64 inclusive;
- */
-static int
-topbit(uint64_t i)
-{
- int h = 1;
-
- if (i == 0)
- return (0);
-
- if (i & 0xffffffff00000000ULL) {
- h += 32;
- i >>= 32;
- }
-
- if (i & 0xffff0000) {
- h += 16;
- i >>= 16;
- }
-
- if (i & 0xff00) {
- h += 8;
- i >>= 8;
- }
-
- if (i & 0xf0) {
- h += 4;
- i >>= 4;
- }
-
- if (i & 0xc) {
- h += 2;
- i >>= 2;
- }
-
- if (i & 0x2)
- h += 1;
-
- return (h);
-}
-
-void
-rct_csintlv_bits(uint_t mcrev, int width, uint_t csmode, int factor,
- struct csintlv_desc *csid)
-{
- int i, lstbnkbit;
- size_t csz;
- const struct bankaddr_mode *bam;
- const struct csrcb_map *rcm;
-
- /*
- * 8-way cs interleave for some large cs sizes in 128-bit mode is
- * not implemented.
- */
- if (factor == 8 && width == 128 &&
- ((mcrev == MC_REV_PRE_D && csmode == 0x6) ||
- (mcrev == MC_REV_D_E && (csmode == 0x9 || csmode == 0xa)))) {
- csid->csi_factor = 0;
- return;
- }
-
- if ((bam = rct_bankaddr_mode(mcrev, csmode)) == NULL ||
- (rcm = rct_rcbmap(mcrev, width, csmode)) == NULL) {
- csid->csi_factor = 0;
- return;
- }
-
- csz = MC_CS_SIZE(bam, width);
-
- switch (factor) {
- case 2:
- csid->csi_nbits = 1;
- break;
- case 4:
- csid->csi_nbits = 2;
- break;
- case 8:
- csid->csi_nbits = 3;
- break;
- default:
- csid->csi_factor = 0;
- return;
- }
-
- csid->csi_hibit = topbit(csz) - 1;
-
- lstbnkbit = 0;
- for (i = 0; i < MC_RC_BANKBITS; i++) {
- /* first bank arg for a bit is "real" bank bit */
- if (rcm->csrcb_bankargs[i][0] > lstbnkbit)
- lstbnkbit = rcm->csrcb_bankargs[i][0];
- }
-
- /* first row bit is immediately after last bank bit */
- csid->csi_lobit = lstbnkbit + 1;
-
- csid->csi_factor = factor;
-}
-
-
-/*
* General notes for CS Bank Address Mode Encoding tables.
*
- * These are the tables of BKDG 3.29 section 3.5.6. They are indexed
- * by chip-select mode. Where the numbers of rows and columns is
- * ambiguous (as it is for a number of rev CG and earlier cases)
+ * These are indexed by chip-select mode. Where the numbers of rows and
+ * columns is ambiguous (as it is for a number of rev CG and earlier cases)
* the bam_config should be initialized to 1 and the numbers of rows
* and columns should be the maximums.
*/
@@ -257,7 +159,7 @@ rct_csintlv_bits(uint_t mcrev, int width, uint_t csmode, int factor,
/*
* Chip Select Bank Address Mode Encoding for rev CG and earlier.
*/
-static const struct bankaddr_mode bankaddr_modes_pre_d[] = {
+static const struct rct_bnkaddrmode bnkaddr_tbls_pre_d[] = {
{ /* 000 */
32, 12, 8
},
@@ -265,16 +167,16 @@ static const struct bankaddr_mode bankaddr_modes_pre_d[] = {
64, 12, 9
},
{ /* 010 */
- 128, 13, 10, 1
+ 128, 13, 10, 1 /* AMBIG */
},
{ /* 011 */
- 256, 13, 11, 1
+ 256, 13, 11, 1 /* AMBIG */
},
{ /* 100 */
- 512, 14, 11, 1
+ 512, 14, 11, 1 /* AMBIG */
},
{ /* 101 */
- 1024, 14, 12, 1
+ 1024, 14, 12, 1 /* AMBIG */
},
{ /* 110 */
2048, 14, 12
@@ -284,7 +186,7 @@ static const struct bankaddr_mode bankaddr_modes_pre_d[] = {
/*
* Chip Select Bank Address Mode Encoding for revs D and E.
*/
-static const struct bankaddr_mode bankaddr_modes_d_e[] = {
+static const struct rct_bnkaddrmode bnkaddr_tbls_d_e[] = {
{ /* 0000 */
32, 12, 8
},
@@ -321,6 +223,49 @@ static const struct bankaddr_mode bankaddr_modes_d_e[] = {
};
/*
+ * Chip Select Bank Address Mode Encoding for rev F
+ */
+static const struct rct_bnkaddrmode bnkaddr_tbls_f[] = {
+ { /* 0000 */
+ 128, 13, 9
+ },
+ { /* 0001 */
+ 256, 13, 10
+ },
+ { /* 0010 */
+ 512, 14, 10
+ },
+ { /* 0011 */
+ 512, 13, 11
+ },
+ { /* 0100 */
+ 512, 13, 10
+ },
+ { /* 0101 */
+ 1024, 14, 10
+ },
+ { /* 0110 */
+ 1024, 14, 11
+ },
+ { /* 0111 */
+ 2048, 15, 10
+ },
+ { /* 1000 */
+ 2048, 14, 11
+ },
+ { /* 1001 */
+ 4096, 15, 11
+ },
+ { /* 1010 */
+ 4096, 16, 10
+ },
+ { /* 1011 */
+ 8192, 16, 11
+ }
+
+};
+
+/*
* General notes on Row/Column/Bank table initialisation.
*
* These are the tables 7, 8, 9, 10, 11 and 12 of BKDG 3.29 section 3.5.6.1.
@@ -360,42 +305,42 @@ static const struct bankaddr_mode bankaddr_modes_d_e[] = {
* Row/Column/Bank address mappings for rev CG in 64-bit mode, no interleave.
* See BKDG 3.29 3.5.6 Table 7.
*/
-static const struct csrcb_map_tbl dram_addrmap_pre_d_64 = {
- MC_REV_PRE_D,
+static const struct _rcbmap_tbl dram_addrmap_pre_d_64 = {
+ MC_REVS_BC,
64,
{
{ /* 000 */
- { { 11 }, { 12 } },
+ 2, { 11, 12 },
{ 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18 },
{ 3, 4, 5, 6, 7, 8, 9, 10 }
},
{ /* 001 */
- { { 13 }, { 12 } },
+ 2, { 13, 12 },
{ 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11 }
},
{ /* 010 */
- { { 13 }, { 12 } },
+ 2, { 13, 12 },
{ 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 26 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 26 }
},
{ /* 011 */
- { { 13 }, { 14 } },
+ 2, { 13, 14 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 27 }
},
{ /* 100 */
- { { 13 }, { 14 } },
+ 2, { 13, 14 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 28 }
},
{ /* 101 */
- { { 15 }, { 14 } },
+ 2, { 15, 14 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 29, 16, 17, 18, 27, 28 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 28 }
},
{ /* 110 */
- { { 15 }, { 14 } },
+ 2, { 15, 14 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 29, 16, 17, 18, 27, 28 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 30 }
},
@@ -410,42 +355,42 @@ static const struct csrcb_map_tbl dram_addrmap_pre_d_64 = {
* Row/Column/Bank address mappings for rev CG in 128-bit mode, no interleave.
* See BKDG 3.29 3.5.6 Table 8.
*/
-static const struct csrcb_map_tbl dram_addrmap_pre_d_128 = {
- MC_REV_PRE_D,
+static const struct _rcbmap_tbl dram_addrmap_pre_d_128 = {
+ MC_REVS_BC,
128,
{
{ /* 000 */
- { { 12 }, { 13 } },
+ 2, { 12, 13 },
{ 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 19 },
{ 4, 5, 6, 7, 8, 9, 10, 11 }
},
{ /* 001 */
- { { 14 }, { 13 } },
+ 2, { 14, 13 },
{ 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12 }
},
{ /* 010 */
- { { 14 }, { 13 } },
+ 2, { 14, 13 },
{ 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 27 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 27 }
},
{ /* 011 */
- { { 14 }, { 15 } },
+ 2, { 14, 15 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 28 }
},
{ /* 100 */
- { { 14 }, { 15 } },
+ 2, { 14, 15 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 29 }
},
{ /* 101 */
- { { 16 }, { 15 } },
+ 2, { 16, 15 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 30, 17, 18, 19, 28, 29 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 29 }
},
{ /* 110 */
- { { 16 }, { 15 } },
+ 2, { 16, 15 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 30, 17, 18, 19, 28, 29 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 31 }
},
@@ -459,62 +404,62 @@ static const struct csrcb_map_tbl dram_addrmap_pre_d_128 = {
* Row/Column/Bank address mappings for rev D/E in 64-bit mode, no interleave.
* See BKDG 3.29 3.5.6 Table 9.
*/
-static const struct csrcb_map_tbl dram_addrmap_d_e_64 = {
- MC_REV_D_E,
+static const struct _rcbmap_tbl dram_addrmap_d_e_64 = {
+ MC_REVS_DE,
64,
{
{ /* 0000 */
- { { 11, 17, 20 }, { 12, 18, 21 } },
+ 2, { 11, 12 },
{ 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18 },
{ 3, 4, 5, 6, 7, 8, 9, 10 }
},
{ /* 0001 */
- { { 12, 17, 20 }, { 13, 18, 21 } },
+ 2, { 12, 13 },
{ 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 26 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11 }
},
{ /* 0010 */
- { { 12, 17, 20 }, { 13, 18, 21 } },
+ 2, { 12, 13 },
{ 19, 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 26 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11 }
},
{ /* 0011 */
- { { 13, 17, 20 }, { 14, 18, 21 } },
+ 2, { 13, 14 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
},
{ /* 0100 */
- { { 13, 17, 20 }, { 14, 18, 21 } },
+ 2, { 13, 14 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
},
{ /* 0101 */
- { { 13, 17, 20 }, { 14, 18, 21 } },
+ 2, { 13, 14 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 27, 28 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
},
{ /* 0110 */
- { { 14, 17, 20 }, { 15, 18, 21 } },
+ 2, { 14, 15 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 28, 29 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 }
},
{ /* 0111 */
- { { 14, 17, 20 }, { 15, 18, 21 } },
+ 2, { 14, 15 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 28, 29 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 }
},
{ /* 1000 */
- { { 14, 17, 20 }, { 15, 18, 21 } },
+ 2, { 14, 15 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 28, 29 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 }
},
{ /* 1001 */
- { { 15, 17, 20 }, { 16, 18, 21 } },
+ 2, { 15, 16 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 29, 30 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 14 }
},
{ /* 1010 */
- { { 15, 17, 20 }, { 16, 18, 21 } },
+ 2, { 15, 16 },
{ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 29, 30 },
{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13, 14 }
},
@@ -528,62 +473,62 @@ static const struct csrcb_map_tbl dram_addrmap_d_e_64 = {
* Row/Column/Bank address mappings for rev D/E in 128-bit mode, no interleave.
* See BKDG 3.29 3.5.6 Table 9.
*/
-static const struct csrcb_map_tbl dram_addrmap_d_e_128 = {
- MC_REV_D_E,
+static const struct _rcbmap_tbl dram_addrmap_d_e_128 = {
+ MC_REVS_DE,
128,
{
{ /* 0000 */
- { { 12, 18, 21 }, { 13, 19, 22 } },
+ 2, { 12, 13 },
{ 20, 21, 22, 23, 24, 25, 14, 15, 16, 17, 18, 19 },
{ 4, 5, 6, 7, 8, 9, 10, 11 }
},
{ /* 0001 */
- { { 13, 18, 21 }, { 14, 19, 22 } },
+ 2, { 13, 14 },
{ 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 27 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12 }
},
{ /* 0010 */
- { { 13, 18, 21 }, { 14, 19, 22 } },
+ 2, { 13, 14 },
{ 20, 21, 22, 23, 24, 25, 26, 15, 16, 17, 18, 19, 27 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12 }
},
{ /* 0011 */
- { { 14, 18, 21 }, { 15, 19, 22 } },
+ 2, { 14, 15 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }
},
{ /* 0100 */
- { { 14, 18, 21 }, { 15, 19, 22 } },
+ 2, { 14, 15 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }
},
{ /* 0101 */
- { { 14, 18, 21 }, { 15, 19, 22 } },
+ 2, { 14, 15 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 16, 17, 18, 19, 28, 29 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }
},
{ /* 0110 */
- { { 15, 18, 21 }, { 16, 19, 22 } },
+ 2, { 15, 16 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 19, 29, 30 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 }
},
{ /* 0111 */
- { { 15, 18, 21 }, { 16, 19, 22 } },
+ 2, { 15, 16 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 19, 29, 30 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 }
},
{ /* 1000 */
- { { 15, 18, 21 }, { 16, 19, 22 } },
+ 2, { 15, 16 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 17, 18, 19, 29, 30 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 }
},
{ /* 1001 */
- { { 16, 18, 21 }, { 17, 19, 22 } },
+ 2, { 16, 17 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 18, 19, 30, 31 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 15 }
},
{ /* 1010 */
- { { 16, 18, 21 }, { 17, 19, 22 } },
+ 2, { 16, 17 },
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 18, 19, 30, 31 },
{ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14, 15 }
},
@@ -592,3 +537,382 @@ static const struct csrcb_map_tbl dram_addrmap_d_e_128 = {
*/
}
};
+
+/*
+ * Row/Column/Bank address mappings for revs F/G in 64-bit mode, no interleave.
+ */
+static const struct _rcbmap_tbl dram_addrmap_f_64 = {
+ MC_REVS_FG,
+ 64,
+ {
+ { /* 0000 */
+ 2, { 12, 13 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 14, 15, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11 },
+ },
+ { /* 0001 */
+ 2, { 13, 14 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 15, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },
+ },
+ { /* 0010 */
+ 2, { 13, 14 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 15, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 },
+ },
+ { /* 0011 */
+ 2, { 14, 15 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 },
+ },
+ { /* 0100 */
+ 3, { 13, 14, 15 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 },
+ },
+ { /* 0101 */
+ 3, { 13, 14, 15 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
+ },
+ { /* 0110 */
+ 2, { 14, 15 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 },
+ },
+ { /* 0111 */
+ 3, { 13, 14, 15 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
+ },
+ { /* 1000 */
+ 3, { 14, 15, 16 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 },
+ },
+ { /* 1001 */
+ 3, { 14, 15, 16 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 },
+ },
+ { /* 1010 */
+ 3, { 13, 14, 15 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 16, 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
+ },
+ { /* 1011 */
+ 3, { 14, 15, 16 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 17 },
+ { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, MC_PC_ALL, 13 },
+ },
+ /*
+ * remainder unused
+ */
+ }
+};
+
+/*
+ * Row/Column/Bank address mappings for revs F/G in 128-bit mode, no interleave.
+ */
+static const struct _rcbmap_tbl dram_addrmap_f_128 = {
+ MC_REVS_FG,
+ 128,
+ {
+ { /* 0000 */
+ 2, { 13, 14 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 15, 16, 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12 },
+ },
+ { /* 0001 */
+ 2, { 14, 15 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 16, 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
+ },
+ { /* 0010 */
+ 2, { 14, 15 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 16, 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
+ },
+ { /* 0011 */
+ 2, { 15, 16 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 },
+ },
+ { /* 0100 */
+ 3, { 14, 15, 16 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
+ },
+ { /* 0101 */
+ 3, { 14, 15, 16 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
+ },
+ { /* 0110 */
+ 2, { 15, 16 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 },
+ },
+ { /* 0111 */
+ 3, { 14, 15, 16 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
+ },
+ { /* 1000 */
+ 3, { 15, 16, 17 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 },
+ },
+ { /* 1001 */
+ 3, { 15, 16, 17 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 },
+ },
+ { /* 1010 */
+ 3, { 14, 15, 16 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 17, 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
+ },
+ { /* 1011 */
+ 3, { 15, 16, 17 },
+ { 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 18 },
+ { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, MC_PC_ALL, 14 },
+ },
+ /*
+ * remainder unused
+ */
+ }
+};
+
+/*
+ * Bank swizzling is an option in revisions E and later. Each internal-bank-
+ * select address bit is xor'd with two row address bits. Which row
+ * address bits to use is not dependent on bank address mode but on
+ * revision and dram controller width alone.
+ *
+ * While rev E only supports 2 bank address bits, rev F supports 3 but not
+ * all chip-select bank address modes use all 3. These tables will list
+ * the row bits to use in swizzling for the maximum number of supported
+ * bank address bits - the consumer musr determine how many should be
+ * applied (listed in the above row/col/bank tables).
+ */
+
+static const struct _bnkswzl_tbl bnswzl_info_e_64 = {
+ MC_REV_E,
+ 64,
+ {
+ {
+ { 17, 20 }, /* rows bits to swizzle with BA0 */
+ { 18, 21 }, /* rows bits to swizzle with BA1 */
+ /* only 2 bankaddr bits on rev E */
+ }
+ }
+};
+
+static const struct _bnkswzl_tbl bnswzl_info_e_128 = {
+ MC_REV_E,
+ 128,
+ {
+ {
+ { 18, 21 }, /* rows bits to swizzle with BA0 */
+ { 19, 22 }, /* rows bits to swizzle with BA1 */
+ /* only 2 bankaddr bits on rev E */
+ }
+ }
+};
+
+static const struct _bnkswzl_tbl bnswzl_info_f_64 = {
+ MC_REVS_FG,
+ 64,
+ {
+ {
+ { 17, 22 }, /* rows bits to swizzle with BA0 */
+ { 18, 23 }, /* rows bits to swizzle with BA1 */
+ { 19, 24 }, /* rows bits to swizzle with BA2 */
+ }
+ }
+};
+
+static const struct _bnkswzl_tbl bnswzl_info_f_128 = {
+ MC_REVS_FG,
+ 128,
+ {
+ {
+ { 18, 23 }, /* rows bits to swizzle with BA0 */
+ { 19, 24 }, /* rows bits to swizzle with BA1 */
+ { 20, 25 }, /* rows bits to swizzle with BA2 */
+ }
+ }
+};
+
+/*
+ * Yet another highbit function. This really needs to go to common source.
+ * Returns range 0 to 64 inclusive;
+ */
+static int
+topbit(uint64_t i)
+{
+ int h = 1;
+
+ if (i == 0)
+ return (0);
+
+ if (i & 0xffffffff00000000ULL) {
+ h += 32;
+ i >>= 32;
+ }
+
+ if (i & 0xffff0000) {
+ h += 16;
+ i >>= 16;
+ }
+
+ if (i & 0xff00) {
+ h += 8;
+ i >>= 8;
+ }
+
+ if (i & 0xf0) {
+ h += 4;
+ i >>= 4;
+ }
+
+ if (i & 0xc) {
+ h += 2;
+ i >>= 2;
+ }
+
+ if (i & 0x2)
+ h += 1;
+
+ return (h);
+}
+
+/*
+ * Lookup the Chip-Select Bank Address Mode Encoding table for a given
+ * chip revision and chip-select mode.
+ */
+const struct rct_bnkaddrmode *
+rct_bnkaddrmode(uint_t mcrev, uint_t csmode)
+{
+ int i;
+ const struct _bnkaddrmode_tbldesc *bdp = bnkaddr_tbls;
+
+ for (i = 0; i < sizeof (bnkaddr_tbls) /
+ sizeof (struct _bnkaddrmode_tbldesc);
+ i++, bdp++) {
+ if (MC_REV_MATCH(mcrev, bdp->revmask) && csmode < bdp->nmodes)
+ return (&bdp->modetbl[csmode]);
+
+ }
+
+ return (NULL);
+}
+
+/*
+ * Lookup the DRAM Address Mapping table for a given chip revision, access
+ * width, bank-swizzle and chip-select mode.
+ */
+const struct rct_rcbmap *
+rct_rcbmap(uint_t mcrev, int width, uint_t csmode)
+{
+ const struct _rcbmap_tbl *rcbm;
+ int i;
+
+ for (i = 0; i < sizeof (rcbmap_tbls) /
+ sizeof (struct _rcbmap_tbldesc); i++) {
+ rcbm = rcbmap_tbls[i].rcbmap;
+ if (MC_REV_MATCH(mcrev, rcbm->mt_revmask) &&
+ rcbm->mt_width == width && csmode < rcbmap_tbls[i].nmodes)
+ return (&rcbm->mt_csmap[csmode]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Lookup the bank swizzling information for a given chip revision and
+ * access width.
+ */
+const struct rct_bnkswzlinfo *
+rct_bnkswzlinfo(uint_t mcrev, int width)
+{
+ int i;
+ const struct _bnkswzl_tbl *swztp;
+
+ for (i = 0; i < sizeof (bnkswzl_tbls) /
+ sizeof (struct rcb_bnkswzl_tbl *); i++) {
+ swztp = bnkswzl_tbls[i];
+ if (MC_REV_MATCH(mcrev, swztp->swzt_revmask) &&
+ swztp->swzt_width == width)
+ return (&swztp->swzt_bits);
+ }
+
+ return (NULL);
+}
+
+void
+rct_csintlv_bits(uint_t mcrev, int width, uint_t csmode, int factor,
+ struct rct_csintlv *csid)
+{
+ int i, lstbnkbit;
+ size_t csz;
+ const struct rct_bnkaddrmode *bam;
+ const struct rct_rcbmap *rcm;
+
+ /*
+ * 8-way cs interleave for some large cs sizes in 128-bit mode is
+ * not implemented prior to rev F.
+ */
+ if (factor == 8 && width == 128 &&
+ ((MC_REV_MATCH(mcrev, MC_REVS_BC) && csmode == 0x6) ||
+ (MC_REV_MATCH(mcrev, MC_REVS_DE) &&
+ (csmode == 0x9 || csmode == 0xa)))) {
+ csid->csi_factor = 0;
+ return;
+ }
+
+ if ((bam = rct_bnkaddrmode(mcrev, csmode)) == NULL ||
+ (rcm = rct_rcbmap(mcrev, width, csmode)) == NULL) {
+ csid->csi_factor = 0;
+ return;
+ }
+
+ csz = MC_CS_SIZE(bam, width);
+
+ switch (factor) {
+ case 2:
+ csid->csi_nbits = 1;
+ break;
+ case 4:
+ csid->csi_nbits = 2;
+ break;
+ case 8:
+ csid->csi_nbits = 3;
+ break;
+ default:
+ csid->csi_factor = 0;
+ return;
+ }
+
+ csid->csi_hibit = topbit(csz) - 1;
+
+ /*
+ * The first row bit is immediately after the last bank bit.
+ */
+ lstbnkbit = 0;
+ for (i = 0; i < rcm->rcb_nbankbits; i++)
+ if (rcm->rcb_bankbit[i] > lstbnkbit)
+ lstbnkbit = rcm->rcb_bankbit[i];
+
+ csid->csi_lobit = lstbnkbit + 1;
+
+ csid->csi_factor = factor;
+}
diff --git a/usr/src/common/mc/mc-amd/mcamd_unumtopa.c b/usr/src/common/mc/mc-amd/mcamd_unumtopa.c
index 90c1dcd56f..1b859ef6b4 100644
--- a/usr/src/common/mc/mc-amd/mcamd_unumtopa.c
+++ b/usr/src/common/mc/mc-amd/mcamd_unumtopa.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -38,38 +37,38 @@
#include <mcamd_api.h>
#include <mcamd_err.h>
-extern int mc_offset_to_pa(struct mcamd_hdl *, mcamd_node_t *, mcamd_node_t *,
- uint64_t, uint64_t *);
-
/*
* 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, struct mc_unum *unump,
+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, hole;
+ 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, "Offset invalid\n");
+ 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. MC property num is by chip, not MC on chip.
+ * unum.
*/
for (mc = mcamd_mc_next(hdl, root, NULL); mc != NULL;
mc = mcamd_mc_next(hdl, root, mc)) {
- if (!mcamd_get_numprop(hdl, mc, MCAMD_PROP_NUM, &num) ||
- !mcamd_get_numprop(hdl, mc, MCAMD_PROP_DRAM_HOLE, &hole)) {
+ 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));
@@ -125,14 +124,12 @@ mcamd_unumtopa(struct mcamd_hdl *hdl, mcamd_node_t *root, struct mc_unum *unump,
* 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 (hole & MC_DC_HOLE_VALID) {
- uint64_t hsz = (hole & MC_DC_HOLE_OFFSET_MASK) <<
- MC_DC_HOLE_OFFSET_LSHIFT;
- if (*pa >= 0x100000000 - hsz)
- *pa += hsz;
+ 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",
- hsz, *pa);
+ holesz, *pa);
}
return (0);