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
mcdcfg_lookup(uint32_t rev,int mod64mux,int accwidth,int basenum,uint32_t pkg,int r4,int s4,mcdcfg_rslt_t * rsltp)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
mcdcfg_csname(uint32_t pkg,const mcdcfg_csl_t * cslp,char * buf,int buflen)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