1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/cmn_err.h> 29 #include <mcamd_dimmcfg_impl.h> 30 31 /* 32 * We have built a list of the active csbase/csmask pairs, and now we want 33 * to associate those active chip-selects with actual dimms. To achieve this 34 * we must map the csbase/csmask pair to an associated logical DIMM and 35 * chip-select line. 36 * 37 * A logical DIMM comprises up to 2 physical dimms as follows: 38 * 39 * - in 64-bit mode without mismatched dimm support logical DIMMs are 40 * made up of just one physical dimm situated in a "lodimm" slot 41 * on channel A; the corresponding slot on channel B (if there is 42 * a channel B) must be empty or will be disabled if populated. 43 * 44 * - in 64-bit mode with mismatched dimm support a logical DIMM may 45 * be made up of 1 or 2 physical dimms - one on channel A and another 46 * in the corresponding slot on channel B. They are accessed 47 * independently. 48 * 49 * - in 128 bit mode a logical DIMM is made up of two physical dimms - 50 * a pair of one slot on channel A and its partner on channel B. 51 * The lodimm on channel A provides data [63:0] while the updimm 52 * on channel B provides data [127:64]. The two dimms must be 53 * identical in size and organisation (number of ranks etc). 54 * 55 * The following tables are derived from the corresponding 56 * "DRAM CS Base and DRAM CS Mask Registers" with and without mismatched 57 * dimm support tables of the BKDG (tables 5 and 6 of BKDG 3.31 for rev E 58 * and earlier; tables 8 and 9 of BKDG 3.01 for rev F and G). They could 59 * be implemented programatically, but are more readily reviewed for correctness 60 * presented as tables. 61 * 62 * When we observe a given chip-select base/mask pair to be enabled in a 63 * system configuration we lookup in the following tables to match on 64 * all of base register pair number, processor revision, socket type 65 * and dram configuration (e.g., quadrank registered or not); the remainder 66 * of the matched line provides the corresponding logical dimm (ldimm) 67 * number that the chip-select is to be associated with and details of 68 * which chip-select line is used to operate that chip-select (specified 69 * as a (channel, slot-number, rank-number) triple. With this 70 * information we determine the topology instance number of each physical 71 * DIMM. There are three distinct cases to consider: 72 * 73 * 128-bit MC mode: 74 * 75 * The lodimm (channel A) and updimm (channel B) dimm in a pair 76 * have instance numbers 2 * ldimm and 2 * ldimm + 1, i.e. 77 * 0/1, 2/3, 4/5, 5/6 for ldimm = 0, 1, 2, 3 (ldimms 2 and 3 78 * are only supported for socket 940 and socket F(1207). 79 * 80 * 64-bit MC mode, no mismatched dimm support: 81 * 82 * All dimms reside on channel A. If there is a channel B 83 * (anything other than socket 754) then any DIMMs on it will 84 * not be configured into the system. We number as for 85 * 128-bit mode but omiting the channel B DIMMs, i.e. 86 * 0, 2, 4, 6 for ldimm = 0, 1, 2, 3. 87 * 88 * 64-bit MC mode, mismatched dimm support enabled: 89 * 90 * Each rank of every DIMM is treated as a separate logical 91 * dimm, so while the package (939 or AM2) only supports two 92 * DIMMS per channel and normally logical dimms 2 and 3 93 * would not be supported they do spring into existence in this 94 * special mode. 95 * 96 * Because of the mismatched DIMM support case we cannot derive 97 * instance number from logical dimm number alone. For that case we use the 98 * slot number on the channel - that tracks the ldimm except in the 99 * mismatched case. This provides consistent instance numbering 100 * even for a system cycled through each of the above configurations - 101 * the instance dimm remains the same for a given channel and slot 102 * number. 103 * 104 * When quadrank DIMMs - quadrank registered or quadrank SODIMM - are in 105 * use we must always base the instance number off of the ldimm regardless 106 * of mismatched DIMM support. 107 */ 108 109 #define MCAMD_TOPONUM(ldimm, cslp, quadrank, mod64mux) \ 110 (((quadrank) || !(mod64mux)) ? \ 111 2 * (ldimm) + ((cslp)->csl_chan == CH_B) : \ 112 2 * (cslp)->csl_slot + ((cslp)->csl_chan == CH_B)) 113 114 /* BEGIN CSTYLED */ 115 116 /* 117 * Revision E and earlier mapping with mismatched dimm support disabled. 118 */ 119 static const struct mcdcfg_csmapline csmap_nomod64mux_preF[] = { 120 /* 121 * Pkgs base dramconfig ldimm cs A cs B 122 * 123 * Base reg 0 (mask 0) 124 */ 125 { SKT_ALL, 0, DCFG_ALL, 0, { { CH_A, 0, 0 }, { CH_B, 0, 0 } } }, 126 /* 127 * Base reg 1 (mask 1) 128 */ 129 { SKT_ALL, 1, DCFG_ALL, 0, { { CH_A, 0, 1 }, { CH_B, 0, 1 } } }, 130 /* 131 * Base reg 2 (mask 2) 132 */ 133 { SKT_ALL, 2, DCFG_ALL, 1, { { CH_A, 1, 0 }, { CH_B, 1, 0 } } }, 134 /* 135 * Base reg 3 (mask 3) 136 */ 137 { SKT_ALL, 3, DCFG_ALL, 1, { { CH_A, 1, 1 }, { CH_B, 1, 1 } } }, 138 /* 139 * Base reg 4 (mask 4) 140 */ 141 { SKT_754, 4, DCFG_N, 2, { { CH_A, 2, 0 } } }, 142 { SKT_940, 4, DCFG_N, 2, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, 143 { SKT_940, 4, DCFG_R4, 0, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, 144 /* 145 * Base reg 5 (mask 5) 146 */ 147 { SKT_754, 5, DCFG_N, 2, { { CH_A, 2, 1 } } }, 148 { SKT_940, 5, DCFG_N, 2, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, 149 { SKT_940, 5, DCFG_R4, 0, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, 150 /* 151 * Base reg 6 (mask 6) 152 */ 153 { SKT_754, 6, DCFG_N, 3, { { CH_A, 3, 0 } } }, 154 { SKT_940, 6, DCFG_N, 3, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, 155 { SKT_940, 6, DCFG_R4, 1, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, 156 /* 157 * Base reg 7 (mask 7) 158 */ 159 { SKT_754, 7, DCFG_N, 3, { { CH_A, 3, 1 } } }, 160 { SKT_940, 7, DCFG_N, 3, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } }, 161 { SKT_940, 7, DCFG_R4, 1, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } } 162 }; 163 164 /* 165 * Revision E and earlier mapping with mismatched dimm support. 166 * Mismatched dimm support applies only to the socket 939 package. 167 * Socket 939 does not support registered dimms, so quadrank RDIMMs are 168 * not an issue here. 169 */ 170 static const struct mcdcfg_csmapline csmap_mod64mux_preF[] = { 171 /* 172 * Pkgs base dramconfig ldimm cs A cs B 173 * 174 * Base reg 0 (mask 0) 175 */ 176 { SKT_939, 0, DCFG_N, 0, { { CH_A, 0, 0 } } }, 177 /* 178 * Base reg 1 (mask 1) 179 */ 180 { SKT_939, 1, DCFG_N, 0, { { CH_A, 0, 1 } } }, 181 /* 182 * Base reg 2 (mask 2) 183 */ 184 { SKT_939, 2, DCFG_N, 1, { { CH_A, 1, 0 } } }, 185 /* 186 * Base reg 3 (mask 3) 187 */ 188 { SKT_939, 3, DCFG_N, 1, { { CH_A, 1, 1 } } }, 189 /* 190 * Base reg 4 (mask 4) 191 */ 192 { SKT_939, 4, DCFG_N, 2, { { CH_B, 0, 0 } } }, 193 /* 194 * Base reg 5 (mask 5) 195 */ 196 { SKT_939, 5, DCFG_N, 2, { { CH_B, 0, 1 } } }, 197 /* 198 * Base reg 6 (mask 6) 199 */ 200 { SKT_939, 6, DCFG_N, 3, { { CH_B, 1, 0 } } }, 201 /* 202 * Base reg 7 (mask 7) 203 */ 204 { SKT_939, 7, DCFG_N, 3, { { CH_B, 1, 1 } } } 205 }; 206 207 /* 208 * Rev F and G csbase/csmask to logical DIMM and cs line mappings. 209 * 210 * We can reduce the tables by a few lines by taking into account which 211 * DIMM types are supported by the different package types: 212 * 213 * Number of dimms of given type supported per dram channel 214 * Package Reg'd DIMM 4-rank reg'd Unbuffered SO-DIMMs 215 * F(1207) 4 2 0 0 216 * AM2 0 0 2 1 217 * S1g1 0 0 0 1 218 */ 219 220 /* 221 * NPT (rev F & G) mapping with mismatched dimm support disabled. 222 */ 223 static const struct mcdcfg_csmapline csmap_nomod64mux_fg[] = { 224 /* 225 * Pkgs base dramconfig ldimm cs A cs B 226 * 227 * Base reg 0 (mask 0) 228 */ 229 { SKT_NPT, 0, DCFG_ALLNPT, 0, { { CH_A, 0, 0 }, { CH_B, 0, 0 } } }, 230 /* 231 * Base reg 1 (mask 0) 232 */ 233 { SKT_NPT, 1, DCFG_ALLNPT, 0, { { CH_A, 0, 1 }, { CH_B, 0, 1 } } }, 234 /* 235 * Base reg 2 (mask 1) 236 */ 237 { AM2F1207, 2, DCFG_N | DCFG_R4, 1, { { CH_A, 1, 0 }, { CH_B, 1, 0 } } }, 238 { AM2, 2, DCFG_S4, 0, { { CH_A, 1, 0 }, { CH_B, 1, 0 } } }, 239 { S1g1, 2, DCFG_N, 1, { { CH_A, 0, 2 }, { CH_B, 0, 2 } } }, 240 { S1g1, 2, DCFG_S4, 0, { { CH_A, 0, 2 }, { CH_B, 0, 2 } } }, 241 /* 242 * Base reg 3 (mask 1) 243 */ 244 { AM2F1207, 3, DCFG_N | DCFG_R4, 1, { { CH_A, 1, 1 }, { CH_B, 1, 1 } } }, 245 { AM2, 3, DCFG_S4, 0, { { CH_A, 1, 1 }, { CH_B, 1, 1 } } }, 246 { S1g1, 3, DCFG_N, 1, { { CH_A, 0, 3 }, { CH_B, 0, 3 } } }, 247 { S1g1, 3, DCFG_S4, 0, { { CH_A, 0, 3 }, { CH_B, 0, 3 } } }, 248 /* 249 * Base reg 4 (mask 2) 250 */ 251 { F1207, 4, DCFG_N, 2, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, 252 { F1207, 4, DCFG_R4, 0, { { CH_A, 2, 0 }, { CH_B, 2, 0 } } }, 253 /* 254 * Base reg 5 (mask 2) 255 */ 256 { F1207, 5, DCFG_N, 2, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, 257 { F1207, 5, DCFG_R4, 0, { { CH_A, 2, 1 }, { CH_B, 2, 1 } } }, 258 /* 259 * Base reg 6 (mask 3) 260 */ 261 { F1207, 6, DCFG_N, 3, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, 262 { F1207, 6, DCFG_R4, 1, { { CH_A, 3, 0 }, { CH_B, 3, 0 } } }, 263 /* 264 * Base reg 7 (mask 3) 265 */ 266 { F1207, 7, DCFG_N, 3, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } }, 267 { F1207, 7, DCFG_R4, 1, { { CH_A, 3, 1 }, { CH_B, 3, 1 } } } 268 }; 269 270 /* 271 * NPT (rev F & G) mapping with mismatched dimm support. 272 * Mismatched dimm support applies only to the AM2 and S1g1 packages. 273 * AM2 and S1g1 do not support registered dimms. 274 */ 275 static const struct mcdcfg_csmapline csmap_mod64mux_fg[] = { 276 /* 277 * Pkgs base dramconfig ldimm cs A cs B 278 * 279 * Base reg 0 (mask 0) 280 */ 281 { AM2S1g1, 0, DCFG_N | DCFG_S4, 0, { { CH_A, 0, 0 } } }, 282 /* 283 * Base reg 1 (mask 0) 284 */ 285 { AM2S1g1, 1, DCFG_N | DCFG_S4, 0, { { CH_A, 0, 1 } } }, 286 /* 287 * Base reg 2 (mask 1) 288 */ 289 { AM2, 2, DCFG_N, 1, { { CH_A, 1, 0 } } }, 290 { AM2, 2, DCFG_S4, 0, { { CH_A, 1, 0 } } }, 291 { S1g1, 2, DCFG_N, 1, { { CH_A, 0, 2 } } }, 292 { S1g1, 2, DCFG_S4, 0, { { CH_A, 0, 2 } } }, 293 /* 294 * Base reg 3 (mask 1) 295 */ 296 { AM2, 3, DCFG_N, 1, { { CH_A, 1, 1 } } }, 297 { AM2, 3, DCFG_S4, 0, { { CH_A, 1, 1 } } }, 298 { S1g1, 3, DCFG_N, 1, { { CH_A, 0, 3 } } }, 299 { S1g1, 3, DCFG_S4, 0, { { CH_A, 0, 3 } } }, 300 /* 301 * Base reg 4 (mask 2) 302 */ 303 { AM2S1g1, 4, DCFG_N, 2, { { CH_B, 0, 0 } } }, 304 { AM2S1g1, 4, DCFG_S4, 1, { { CH_B, 0, 0 } } }, 305 /* 306 * Base reg 5 (mask 2) 307 */ 308 { AM2S1g1, 5, DCFG_N, 2, { { CH_B, 0, 1 } } }, 309 { AM2S1g1, 5, DCFG_S4, 1, { { CH_B, 0, 1 } } }, 310 /* 311 * Base reg 6 (mask 3) 312 */ 313 { AM2, 6, DCFG_N, 3, { { CH_B, 1, 0 } } }, 314 { AM2, 6, DCFG_S4, 1, { { CH_B, 1, 0 } } }, 315 { S1g1, 6, DCFG_N, 3, { { CH_B, 0, 2 } } }, 316 { S1g1, 6, DCFG_S4, 1, { { CH_B, 0, 2 } } }, 317 /* 318 * Base reg 7 (mask 3) 319 */ 320 { AM2, 7, DCFG_N, 3, { { CH_B, 1, 1 } } }, 321 { AM2, 7, DCFG_S4, 1, { { CH_B, 1, 1 } } }, 322 { S1g1, 7, DCFG_N, 3, { { CH_B, 0, 3 } } }, 323 { S1g1, 7, DCFG_S4, 1, { { CH_B, 0, 3 } } } 324 }; 325 326 /* END CSTYLED */ 327 328 #define DCFG_NTBL 4 329 330 static const struct { 331 uint32_t revmask; /* applicable chip revs */ 332 int mod64mux; /* mismatched support or not */ 333 const struct mcdcfg_csmapline *map; 334 int nmapents; 335 } csmap_tbls[DCFG_NTBL] = { 336 { MC_F_REVS_BCDE, 0, &csmap_nomod64mux_preF[0], 337 sizeof (csmap_nomod64mux_preF) / sizeof (struct mcdcfg_csmapline) }, 338 { MC_F_REVS_BCDE, 1, &csmap_mod64mux_preF[0], 339 sizeof (csmap_mod64mux_preF) / sizeof (struct mcdcfg_csmapline) }, 340 { MC_F_REVS_FG, 0, &csmap_nomod64mux_fg[0], 341 sizeof (csmap_nomod64mux_fg) / sizeof (struct mcdcfg_csmapline) }, 342 { MC_F_REVS_FG, 1, &csmap_mod64mux_fg[0], 343 sizeof (csmap_mod64mux_fg) / sizeof (struct mcdcfg_csmapline) } 344 }; 345 346 int 347 mcdcfg_lookup(uint32_t rev, int mod64mux, int accwidth, int basenum, 348 uint32_t pkg, int r4, int s4, mcdcfg_rslt_t *rsltp) 349 { 350 const struct mcdcfg_csmapline *csm = NULL; 351 int ismux = (mod64mux != 0); 352 int nmapents; 353 int ndimm = (accwidth == 128) ? 2 : 1; 354 int dcfg; 355 int i; 356 357 /* 358 * Validate aspects that the table lookup won't. 359 */ 360 if ((accwidth != 64 && accwidth != 128) || (r4 != 0 && s4 != 0)) 361 return (-1); 362 363 for (i = 0; i < DCFG_NTBL; i++) { 364 if (MC_REV_MATCH(rev, csmap_tbls[i].revmask) && 365 ismux == csmap_tbls[i].mod64mux) { 366 csm = csmap_tbls[i].map; 367 nmapents = csmap_tbls[i].nmapents; 368 break; 369 } 370 } 371 if (csm == NULL) 372 return (-1); 373 374 if (r4) 375 dcfg = DCFG_R4; 376 else if (s4) 377 dcfg = DCFG_S4; 378 else 379 dcfg = DCFG_N; 380 381 for (i = 0; i < nmapents; i++, csm++) { 382 if (X86_SOCKET_MATCH(pkg, csm->csm_pkg) && 383 basenum == csm->csm_basereg && 384 (dcfg & csm->csm_dimmcfg) != 0) 385 break; 386 } 387 if (i == nmapents) 388 return (-1); 389 390 /* 391 * We return the dimm instance number here for the topology, based 392 * on the AMD Motherboard Design Guide. 393 */ 394 rsltp->ldimm = csm->csm_ldimm; 395 rsltp->ndimm = ndimm; 396 for (i = 0; i < ndimm; i++) { 397 const struct mcdcfg_csl *cslp = &csm->csm_cs[i]; 398 399 rsltp->dimm[i].toponum = 400 MCAMD_TOPONUM(rsltp->ldimm, cslp, r4 || s4, ismux); 401 rsltp->dimm[i].cslp = cslp; 402 } 403 404 return (0); 405 } 406 407 /* 408 * Given a chip-select line and package type return the chip-select line 409 * pin label for that package type. 410 */ 411 void 412 mcdcfg_csname(uint32_t pkg, const mcdcfg_csl_t *cslp, char *buf, int buflen) 413 { 414 int csnum; 415 416 switch (pkg) { 417 case X86_SOCKET_754: 418 /* 419 * Format is: MEMCS_L[{0..7}]. There is only channel A. 420 */ 421 csnum = 2 * cslp->csl_slot + cslp->csl_rank; 422 (void) snprintf(buf, buflen, "MEMCS_L%d", csnum); 423 break; 424 425 case X86_SOCKET_940: 426 /* 427 * Format is: MEMCS_L[{0..7}]. That does not identify 428 * a single dimm (since a single chip-select is shared 429 * by both members of a dimm pair in socket 940) so 430 * we tack on some channel identification. 431 */ 432 csnum = 2 * cslp->csl_slot + cslp->csl_rank; 433 (void) snprintf(buf, buflen, "MEMCS_L%d (channel %s)", csnum, 434 cslp->csl_chan == CH_A ? "A" : "B"); 435 436 break; 437 438 case X86_SOCKET_939: 439 /* 440 * Format is: MEMCS_{1,2}{L,H}_L[{1,0}] 441 * {1,2} - dimm pair 442 * {L,H} - lodimm or updimm 443 * {1,0} - rank 444 */ 445 (void) snprintf(buf, buflen, "MEMCS_%d%s_L[%d]", 446 cslp->csl_slot + 1, 447 cslp->csl_chan == CH_A ? "A" : "B", 448 cslp->csl_rank); 449 break; 450 451 case X86_SOCKET_F1207: 452 case X86_SOCKET_AM2: 453 case X86_SOCKET_S1g1: 454 /* 455 * Format is: M{B,A}{0,1,2,3}_CS_L[{0,1,2,3}] 456 * {B,A} - channel 457 * {0,1,2,3} - slot on channel 458 * {0,1,2,3} - rank 459 */ 460 (void) snprintf(buf, buflen, "M%s%d_CS_L[%d]", 461 cslp->csl_chan == CH_A ? "A" : "B", 462 cslp->csl_slot, 463 cslp->csl_rank); 464 break; 465 466 default: 467 (void) snprintf(buf, buflen, "Unknown"); 468 break; 469 } 470 } 471