/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include /* * We have built a list of the active csbase/csmask pairs, and now we want * to associate those active chip-selects with actual dimms. To achieve this * we must map the csbase/csmask pair to an associated logical DIMM and * chip-select line. * * A logical DIMM comprises up to 2 physical dimms as follows: * * - in 64-bit mode without mismatched dimm support logical DIMMs are * made up of just one physical dimm situated in a "lodimm" slot * on channel A; the corresponding slot on channel B (if there is * a channel B) must be empty or will be disabled if populated. * * - in 64-bit mode with mismatched dimm support a logical DIMM may * be made up of 1 or 2 physical dimms - one on channel A and another * in the corresponding slot on channel B. They are accessed * independently. * * - in 128 bit mode a logical DIMM is made up of two physical dimms - * a pair of one slot on channel A and its partner on channel B. * The lodimm on channel A provides data [63:0] while the updimm * on channel B provides data [127:64]. The two dimms must be * identical in size and organisation (number of ranks etc). * * The following tables are derived from the corresponding * "DRAM CS Base and DRAM CS Mask Registers" with and without mismatched * dimm support tables of the BKDG (tables 5 and 6 of BKDG 3.31 for rev E * and earlier; tables 8 and 9 of BKDG 3.01 for rev F and G). They could * be implemented programatically, but are more readily reviewed for correctness * presented as tables. * * When we observe a given chip-select base/mask pair to be enabled in a * system configuration we lookup in the following tables to match on * all of base register pair number, processor revision, socket type * and dram configuration (e.g., quadrank registered or not); the remainder * of the matched line provides the corresponding logical dimm (ldimm) * number that the chip-select is to be associated with and details of * which chip-select line is used to operate that chip-select (specified * as a (channel, slot-number, rank-number) triple. With this * information we determine the topology instance number of each physical * DIMM. There are three distinct cases to consider: * * 128-bit MC mode: * * The lodimm (channel A) and updimm (channel B) dimm in a pair * have instance numbers 2 * ldimm and 2 * ldimm + 1, i.e. * 0/1, 2/3, 4/5, 5/6 for ldimm = 0, 1, 2, 3 (ldimms 2 and 3 * are only supported for socket 940 and socket F(1207). * * 64-bit MC mode, no mismatched dimm support: * * All dimms reside on channel A. If there is a channel B * (anything other than socket 754) then any DIMMs on it will * not be configured into the system. We number as for * 128-bit mode but omiting the channel B DIMMs, i.e. * 0, 2, 4, 6 for ldimm = 0, 1, 2, 3. * * 64-bit MC mode, mismatched dimm support enabled: * * Each rank of every DIMM is treated as a separate logical * dimm, so while the package (939 or AM2) only supports two * DIMMS per channel and normally logical dimms 2 and 3 * would not be supported they do spring into existence in this * special mode. * * Because of the mismatched DIMM support case we cannot derive * instance number from logical dimm number alone. For that case we use the * slot number on the channel - that tracks the ldimm except in the * mismatched case. This provides consistent instance numbering * even for a system cycled through each of the above configurations - * the instance dimm remains the same for a given channel and slot * number. * * When quadrank DIMMs - quadrank registered or quadrank SODIMM - are in * use we must always base the instance number off of the ldimm regardless * of mismatched DIMM support. */ #define MCAMD_TOPONUM(ldimm, cslp, quadrank, mod64mux) \ (((quadrank) || !(mod64mux)) ? \ 2 * (ldimm) + ((cslp)->csl_chan == CH_B) : \ 2 * (cslp)->csl_slot + ((cslp)->csl_chan == CH_B)) /* BEGIN CSTYLED */ /* * Revision E and earlier mapping with mismatched dimm support disabled. */ static const struct mcdcfg_csmapline csmap_nomod64mux_preF[] = { /* * Pkgs base dramconfig ldimm cs A cs B * * Base reg 0 (mask 0) */ { SKT_ALL, 0, DCFG_ALL, 0, { { CH_A, 0, 0 }, { CH_B, 0, 0 } } }, /* * Base reg 1 (mask 1) */ { SKT_ALL, 1, DCFG_ALL, 0, { { CH_A, 0, 1 }, { CH_B, 0, 1 } } }, /* * Base reg 2 (mask 2) */ { SKT_ALL, 2, DCFG_ALL, 1, { { CH_A, 1, 0 }, { CH_B, 1, 0 } } }, /* * Base reg 3 (mask 3) */ { SKT_ALL, 3, DCFG_ALL, 1, { { CH_A, 1, 1 }, { CH_B, 1, 1 } } }, /* * Base reg 4 (mask 4) */ { SKT_754, 4, DCFG_N, 2, { { CH_A, 2, 0 } } }, { SKT_940, 4, DCFG_N, 2, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, { SKT_940, 4, DCFG_R4, 0, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, /* * Base reg 5 (mask 5) */ { SKT_754, 5, DCFG_N, 2, { { CH_A, 2, 1 } } }, { SKT_940, 5, DCFG_N, 2, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, { SKT_940, 5, DCFG_R4, 0, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, /* * Base reg 6 (mask 6) */ { SKT_754, 6, DCFG_N, 3, { { CH_A, 3, 0 } } }, { SKT_940, 6, DCFG_N, 3, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, { SKT_940, 6, DCFG_R4, 1, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, /* * Base reg 7 (mask 7) */ { SKT_754, 7, DCFG_N, 3, { { CH_A, 3, 1 } } }, { SKT_940, 7, DCFG_N, 3, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } }, { SKT_940, 7, DCFG_R4, 1, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } } }; /* * Revision E and earlier mapping with mismatched dimm support. * Mismatched dimm support applies only to the socket 939 package. * Socket 939 does not support registered dimms, so quadrank RDIMMs are * not an issue here. */ static const struct mcdcfg_csmapline csmap_mod64mux_preF[] = { /* * Pkgs base dramconfig ldimm cs A cs B * * Base reg 0 (mask 0) */ { SKT_939, 0, DCFG_N, 0, { { CH_A, 0, 0 } } }, /* * Base reg 1 (mask 1) */ { SKT_939, 1, DCFG_N, 0, { { CH_A, 0, 1 } } }, /* * Base reg 2 (mask 2) */ { SKT_939, 2, DCFG_N, 1, { { CH_A, 1, 0 } } }, /* * Base reg 3 (mask 3) */ { SKT_939, 3, DCFG_N, 1, { { CH_A, 1, 1 } } }, /* * Base reg 4 (mask 4) */ { SKT_939, 4, DCFG_N, 2, { { CH_B, 0, 0 } } }, /* * Base reg 5 (mask 5) */ { SKT_939, 5, DCFG_N, 2, { { CH_B, 0, 1 } } }, /* * Base reg 6 (mask 6) */ { SKT_939, 6, DCFG_N, 3, { { CH_B, 1, 0 } } }, /* * Base reg 7 (mask 7) */ { SKT_939, 7, DCFG_N, 3, { { CH_B, 1, 1 } } } }; /* * Rev F and G csbase/csmask to logical DIMM and cs line mappings. * * We can reduce the tables by a few lines by taking into account which * DIMM types are supported by the different package types: * * Number of dimms of given type supported per dram channel * Package Reg'd DIMM 4-rank reg'd Unbuffered SO-DIMMs * F(1207) 4 2 0 0 * AM2 0 0 2 1 * S1g1 0 0 0 1 */ /* * NPT (rev F & G) mapping with mismatched dimm support disabled. */ static const struct mcdcfg_csmapline csmap_nomod64mux_fg[] = { /* * Pkgs base dramconfig ldimm cs A cs B * * Base reg 0 (mask 0) */ { SKT_NPT, 0, DCFG_ALLNPT, 0, { { CH_A, 0, 0 }, { CH_B, 0, 0 } } }, /* * Base reg 1 (mask 0) */ { SKT_NPT, 1, DCFG_ALLNPT, 0, { { CH_A, 0, 1 }, { CH_B, 0, 1 } } }, /* * Base reg 2 (mask 1) */ { AM2F1207, 2, DCFG_N | DCFG_R4, 1, { { CH_A, 1, 0 }, { CH_B, 1, 0 } } }, { AM2, 2, DCFG_S4, 0, { { CH_A, 1, 0 }, { CH_B, 1, 0 } } }, { S1g1, 2, DCFG_N, 1, { { CH_A, 0, 2 }, { CH_B, 0, 2 } } }, { S1g1, 2, DCFG_S4, 0, { { CH_A, 0, 2 }, { CH_B, 0, 2 } } }, /* * Base reg 3 (mask 1) */ { AM2F1207, 3, DCFG_N | DCFG_R4, 1, { { CH_A, 1, 1 }, { CH_B, 1, 1 } } }, { AM2, 3, DCFG_S4, 0, { { CH_A, 1, 1 }, { CH_B, 1, 1 } } }, { S1g1, 3, DCFG_N, 1, { { CH_A, 0, 3 }, { CH_B, 0, 3 } } }, { S1g1, 3, DCFG_S4, 0, { { CH_A, 0, 3 }, { CH_B, 0, 3 } } }, /* * Base reg 4 (mask 2) */ { F1207, 4, DCFG_N, 2, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, { F1207, 4, DCFG_R4, 0, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, /* * Base reg 5 (mask 2) */ { F1207, 5, DCFG_N, 2, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, { F1207, 5, DCFG_R4, 0, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, /* * Base reg 6 (mask 3) */ { F1207, 6, DCFG_N, 3, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, { F1207, 6, DCFG_R4, 1, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, /* * Base reg 7 (mask 3) */ { F1207, 7, DCFG_N, 3, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } }, { F1207, 7, DCFG_R4, 1, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } } }; /* * NPT (rev F & G) mapping with mismatched dimm support. * Mismatched dimm support applies only to the AM2 and S1g1 packages. * AM2 and S1g1 do not support registered dimms. */ static const struct mcdcfg_csmapline csmap_mod64mux_fg[] = { /* * Pkgs base dramconfig ldimm cs A cs B * * Base reg 0 (mask 0) */ { AM2S1g1, 0, DCFG_N | DCFG_S4, 0, { { CH_A, 0, 0 } } }, /* * Base reg 1 (mask 0) */ { AM2S1g1, 1, DCFG_N | DCFG_S4, 0, { { CH_A, 0, 1 } } }, /* * Base reg 2 (mask 1) */ { AM2, 2, DCFG_N, 1, { { CH_A, 1, 0 } } }, { AM2, 2, DCFG_S4, 0, { { CH_A, 1, 0 } } }, { S1g1, 2, DCFG_N, 1, { { CH_A, 0, 2 } } }, { S1g1, 2, DCFG_S4, 0, { { CH_A, 0, 2 } } }, /* * Base reg 3 (mask 1) */ { AM2, 3, DCFG_N, 1, { { CH_A, 1, 1 } } }, { AM2, 3, DCFG_S4, 0, { { CH_A, 1, 1 } } }, { S1g1, 3, DCFG_N, 1, { { CH_A, 0, 3 } } }, { S1g1, 3, DCFG_S4, 0, { { CH_A, 0, 3 } } }, /* * Base reg 4 (mask 2) */ { AM2S1g1, 4, DCFG_N, 2, { { CH_B, 0, 0 } } }, { AM2S1g1, 4, DCFG_S4, 1, { { CH_B, 0, 0 } } }, /* * Base reg 5 (mask 2) */ { AM2S1g1, 5, DCFG_N, 2, { { CH_B, 0, 1 } } }, { AM2S1g1, 5, DCFG_S4, 1, { { CH_B, 0, 1 } } }, /* * Base reg 6 (mask 3) */ { AM2, 6, DCFG_N, 3, { { CH_B, 1, 0 } } }, { AM2, 6, DCFG_S4, 1, { { CH_B, 1, 0 } } }, { S1g1, 6, DCFG_N, 3, { { CH_B, 0, 2 } } }, { S1g1, 6, DCFG_S4, 1, { { CH_B, 0, 2 } } }, /* * Base reg 7 (mask 3) */ { AM2, 7, DCFG_N, 3, { { CH_B, 1, 1 } } }, { AM2, 7, DCFG_S4, 1, { { CH_B, 1, 1 } } }, { S1g1, 7, DCFG_N, 3, { { CH_B, 0, 3 } } }, { S1g1, 7, DCFG_S4, 1, { { CH_B, 0, 3 } } } }; /* END CSTYLED */ #define DCFG_NTBL 4 static const struct { uint32_t revmask; /* applicable chip revs */ int mod64mux; /* mismatched support or not */ const struct mcdcfg_csmapline *map; int nmapents; } csmap_tbls[DCFG_NTBL] = { { MC_F_REVS_BCDE, 0, &csmap_nomod64mux_preF[0], sizeof (csmap_nomod64mux_preF) / sizeof (struct mcdcfg_csmapline) }, { MC_F_REVS_BCDE, 1, &csmap_mod64mux_preF[0], sizeof (csmap_mod64mux_preF) / sizeof (struct mcdcfg_csmapline) }, { MC_F_REVS_FG, 0, &csmap_nomod64mux_fg[0], sizeof (csmap_nomod64mux_fg) / sizeof (struct mcdcfg_csmapline) }, { MC_F_REVS_FG, 1, &csmap_mod64mux_fg[0], sizeof (csmap_mod64mux_fg) / sizeof (struct mcdcfg_csmapline) } }; int mcdcfg_lookup(uint32_t rev, int mod64mux, int accwidth, int basenum, uint32_t pkg, int r4, int s4, mcdcfg_rslt_t *rsltp) { const struct mcdcfg_csmapline *csm = NULL; int ismux = (mod64mux != 0); int nmapents; int ndimm = (accwidth == 128) ? 2 : 1; int dcfg; int i; /* * Validate aspects that the table lookup won't. */ if ((accwidth != 64 && accwidth != 128) || (r4 != 0 && s4 != 0)) return (-1); for (i = 0; i < DCFG_NTBL; i++) { if (MC_REV_MATCH(rev, csmap_tbls[i].revmask) && ismux == csmap_tbls[i].mod64mux) { csm = csmap_tbls[i].map; nmapents = csmap_tbls[i].nmapents; break; } } if (csm == NULL) return (-1); if (r4) dcfg = DCFG_R4; else if (s4) dcfg = DCFG_S4; else dcfg = DCFG_N; for (i = 0; i < nmapents; i++, csm++) { if (X86_SOCKET_MATCH(pkg, csm->csm_pkg) && basenum == csm->csm_basereg && (dcfg & csm->csm_dimmcfg) != 0) break; } if (i == nmapents) return (-1); /* * We return the dimm instance number here for the topology, based * on the AMD Motherboard Design Guide. */ rsltp->ldimm = csm->csm_ldimm; rsltp->ndimm = ndimm; for (i = 0; i < ndimm; i++) { const struct mcdcfg_csl *cslp = &csm->csm_cs[i]; rsltp->dimm[i].toponum = MCAMD_TOPONUM(rsltp->ldimm, cslp, r4 || s4, ismux); rsltp->dimm[i].cslp = cslp; } return (0); } /* * Given a chip-select line and package type return the chip-select line * pin label for that package type. */ void mcdcfg_csname(uint32_t pkg, const mcdcfg_csl_t *cslp, char *buf, int buflen) { int csnum; switch (pkg) { case X86_SOCKET_754: /* * Format is: MEMCS_L[{0..7}]. There is only channel A. */ csnum = 2 * cslp->csl_slot + cslp->csl_rank; (void) snprintf(buf, buflen, "MEMCS_L%d", csnum); break; case X86_SOCKET_940: /* * Format is: MEMCS_L[{0..7}]. That does not identify * a single dimm (since a single chip-select is shared * by both members of a dimm pair in socket 940) so * we tack on some channel identification. */ csnum = 2 * cslp->csl_slot + cslp->csl_rank; (void) snprintf(buf, buflen, "MEMCS_L%d (channel %s)", csnum, cslp->csl_chan == CH_A ? "A" : "B"); break; case X86_SOCKET_939: /* * Format is: MEMCS_{1,2}{L,H}_L[{1,0}] * {1,2} - dimm pair * {L,H} - lodimm or updimm * {1,0} - rank */ (void) snprintf(buf, buflen, "MEMCS_%d%s_L[%d]", cslp->csl_slot + 1, cslp->csl_chan == CH_A ? "A" : "B", cslp->csl_rank); break; case X86_SOCKET_F1207: case X86_SOCKET_AM2: case X86_SOCKET_S1g1: /* * Format is: M{B,A}{0,1,2,3}_CS_L[{0,1,2,3}] * {B,A} - channel * {0,1,2,3} - slot on channel * {0,1,2,3} - rank */ (void) snprintf(buf, buflen, "M%s%d_CS_L[%d]", cslp->csl_chan == CH_A ? "A" : "B", cslp->csl_slot, cslp->csl_rank); break; default: (void) snprintf(buf, buflen, "Unknown"); break; } }