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