diff options
author | gavinm <none@none> | 2006-10-05 17:39:16 -0700 |
---|---|---|
committer | gavinm <none@none> | 2006-10-05 17:39:16 -0700 |
commit | 8a40a695ee676a322b094e9afe5375567bfb51e3 (patch) | |
tree | b59160470b2412ad6a4afc8cf53da85376e7a18a /usr/src/common/mc | |
parent | 6fec36253a9fa8abfdf231fb3ea9fc656a2ff872 (diff) | |
download | illumos-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.h | 135 | ||||
-rw-r--r-- | usr/src/common/mc/mc-amd/mcamd_misc.c | 79 | ||||
-rw-r--r-- | usr/src/common/mc/mc-amd/mcamd_patounum.c | 446 | ||||
-rw-r--r-- | usr/src/common/mc/mc-amd/mcamd_rowcol.c | 404 | ||||
-rw-r--r-- | usr/src/common/mc/mc-amd/mcamd_rowcol_impl.h | 68 | ||||
-rw-r--r-- | usr/src/common/mc/mc-amd/mcamd_rowcol_tbl.c | 750 | ||||
-rw-r--r-- | usr/src/common/mc/mc-amd/mcamd_unumtopa.c | 33 |
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); |