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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <mcamd_api.h>
29
30/*
31 * Indexed by syndrome, value is bit number.  If value is -1, a multi-bit
32 * error has been detected.  A special case is the zero'th entry - a
33 * syndrome of 0x0 indicates no bits in error.
34 */
35static char eccsynd[] = {
36	-1, 64, 65, -1, 66, -1, -1, -1, 67, -1, -1, 17, -1, -1, 16, -1,
37	68, -1, -1, 18, -1, 19, 20, -1, -1, 21, 22, -1, 23, -1, -1, -1,
38	69, -1, -1,  8, -1,  9, 10, -1, -1, 11, 12, -1, 13, -1, -1, -1,
39	-1, 14, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
40	70, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, 32,
41	-1, -1, 34, -1, 35, -1, -1, 36, 37, -1, -1, 38, -1, 39, -1, -1,
42	-1, -1, 56, -1, 57, -1, -1, 58, 59, -1, -1, 60, -1, 61, -1, -1,
43	62, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44	71, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 48,
45	-1, -1, 50, -1, 51, -1, -1, 52, 53, -1, -1, 54, -1, 55, -1, -1,
46	-1, -1, 40, -1, 41, -1, -1, 42, 43, -1, -1, 44, -1, 45, -1, -1,
47	46, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  1, -1, -1,  0, -1,
49	-1, -1, -1,  2, -1,  3,  4, -1, -1,  5,  6, -1,  7, -1, -1, -1,
50	-1, -1, -1, 24, -1, 25, 26, -1, -1, 27, 28, -1, 29, -1, -1, -1,
51	-1, 30, -1, -1, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
52};
53
54/*
55 * The first dimension of this table is the errored bit pattern, which is the
56 * column dimension of the table in the BKDG.  Conveniently, the bit pattern
57 * is also the lowest-order nibble in the syndrome, thus allowing the first
58 * dimension value to be calculated.  The second dimension is the symbol
59 * number, which can be found by searching for a matching syndrome.
60 *
61 * Note that the first dimension is actually (errored_bit_pattern - 1) since
62 * 0 is not a valid errored bit pattern.
63 */
64#define	MCAMD_CKSYND_NPATS	15
65#define	MCAMD_CKSYND_NSYMS	36
66
67static uint16_t cksynd[MCAMD_CKSYND_NPATS][MCAMD_CKSYND_NSYMS] = {
68	/* table column 0x1 */
69	{ 0xe821, 0x5d31, 0x0001, 0x2021, 0x5041, 0xbe21, 0x4951, 0x74e1,
70	0x15c1, 0x3d01, 0x9801, 0xd131, 0xe1d1, 0x6051, 0xa4c1, 0x11c1,
71	0x45d1, 0x63e1, 0xb741, 0xdd41, 0x2bd1, 0x83c1, 0x8fd1, 0x4791,
72	0x5781, 0xbf41, 0x9391, 0xcce1, 0xa761, 0xff61, 0x5451, 0x6fc1,
73	0xbe01, 0x4101, 0xc441, 0x7621 },
74
75	/* table column 0x2 */
76	{ 0x7c32, 0xa612, 0x0002, 0x3032, 0xa082, 0xd732, 0x8ea2, 0x9872,
77	0x2a42, 0x1602, 0xec02, 0x6212, 0x7262, 0xb0a2, 0xf842, 0x2242,
78	0x8a62, 0xb172, 0xd982, 0x6682, 0x3d62, 0xc142, 0xc562, 0x89e2,
79	0xa9c2, 0xd582, 0xe1e2, 0x4472, 0xf9b2, 0x55b2, 0xa8a2, 0xb542,
80	0xd702, 0x8202, 0x4882, 0x9b32 },
81
82	/* table column 0x3 */
83	{ 0x9413, 0xfb23, 0x0003, 0x1013, 0xf0c3, 0x6913, 0xc7f3, 0xec93,
84	0x3f83, 0x2b03, 0x7403, 0xb323, 0x93b3, 0xd0f3, 0x5c83, 0x3383,
85	0xcfb3, 0xd293, 0x6ec3, 0xbbc3, 0x16b3, 0x4283, 0x4ab3, 0xce73,
86	0xfe43, 0x6ac3, 0x7273, 0x8893, 0x5ed3, 0xaad3, 0xfcf3, 0xda83,
87	0x6903, 0xc303, 0x8cc3, 0xed13 },
88
89	/* table column 0x4 */
90	{ 0xbb44, 0x9584, 0x0004, 0x4044, 0x9054, 0x2144, 0x5394, 0xd6b4,
91	0xcef4, 0x8504, 0x6b04, 0x3884, 0xb834, 0x1094, 0xe6f4, 0xc8f4,
92	0x5e34, 0x14b4, 0x2254, 0x3554, 0x4f34, 0xa4f4, 0xa934, 0x5264,
93	0x92a4, 0x2954, 0x6464, 0xfdb4, 0xe214, 0x7914, 0x9694, 0x19f4,
94	0x2104, 0x5804, 0xf654, 0xda44 },
95
96	/* table column 0x5 */
97	{ 0x5365, 0xc8b5, 0x0005, 0x6065, 0xc015, 0x9f65, 0x1ac5, 0xa255,
98	0xdb35, 0xb805, 0xf305, 0xe9b5, 0x59e5, 0x70c5, 0x4235, 0xd935,
99	0x1be5, 0x7755, 0x9515, 0xe815, 0x64e5, 0x2735, 0x26e5, 0x15f5,
100	0xc525, 0x9615, 0xf7f5, 0x3155, 0x4575, 0x8675, 0xc2c5, 0x7635,
101	0x9f05, 0x1905, 0x3215, 0xac65 },
102
103	/* table column 0x6 */
104	{ 0xc776, 0x3396, 0x0006, 0x7076, 0x30d6, 0xf676, 0xdd36, 0x4ec6,
105	0xe4b6, 0x9306, 0x8706, 0x5a96, 0xca56, 0xa036, 0x1eb6, 0xeab6,
106	0xd456, 0xa5c6, 0xfbd6, 0x53d6, 0x7256, 0x65b6, 0x6c56, 0xdb86,
107	0x3b66, 0xfcd6, 0x8586, 0xb9c6, 0x1ba6, 0x2ca6, 0x3e36, 0xacb6,
108	0xf606, 0xda06, 0xbed6, 0x4176 },
109
110	/* table column 0x7 */
111	{ 0x2f57, 0x6ea7, 0x0007, 0x5057, 0x6097, 0x4857, 0x9467, 0x3a27,
112	0xf177, 0xae07, 0x1f07, 0x8ba7, 0x2b87, 0xc067, 0xba77, 0xfb77,
113	0x9187, 0xc627, 0x4c97, 0x8e97, 0x5987, 0xe677, 0xe387, 0x9c17,
114	0x6ce7, 0x4397, 0x1617, 0x7527, 0xbcc7, 0xd3c7, 0x6a67, 0xc377,
115	0x4807, 0x9b07, 0x7a97, 0x3757 },
116
117	/* table column 0x8 */
118	{ 0xdd88, 0xeac8, 0x0008, 0x8088, 0xe0a8, 0x3288, 0xa1e8, 0x6bd8,
119	0x4758, 0xca08, 0xbd08, 0x1cc8, 0xdc18, 0x20e8, 0x7b58, 0x4c58,
120	0xa718, 0x28d8, 0x33a8, 0x1aa8, 0x8518, 0xf858, 0xfe18, 0xa3b8,
121	0xe3f8, 0x3ea8, 0xb8b8, 0x56d8, 0x7328, 0x9e28, 0xebe8, 0x2e58,
122	0x3208, 0xac08, 0x5ba8, 0x6f88 },
123
124	/* table column 0x9 */
125	{ 0x35a9, 0xb7f9, 0x0009, 0xa0a9, 0xb0e9, 0x8ca9, 0xe8b9, 0x1f39,
126	0x5299, 0xf709, 0x2509, 0xcdf9, 0x3dc9, 0x40b9, 0xdf99, 0x5d99,
127	0xe2c9, 0x4b39, 0x84e9, 0xc7e9, 0xaec9, 0x7b99, 0x71c9, 0xe429,
128	0xb479, 0x81e9, 0x2b29, 0x9a39, 0xd449, 0x6149, 0xbfb9, 0x4199,
129	0x8c09, 0xed09, 0x9fe9, 0x19a9 },
130
131	/* table column 0xa */
132	{ 0xa1ba, 0x4cda, 0x000a, 0xb0ba, 0x402a, 0xe5ba, 0x2f4a, 0xf3aa,
133	0x6d1a, 0xdc0a, 0x510a, 0x7eda, 0xae7a, 0x904a, 0x831a, 0x6e1a,
134	0x2d7a, 0x99aa, 0xea2a, 0x7c2a, 0xb87a, 0x391a, 0x3b7a, 0x2a5a,
135	0x4a3a, 0xeb2a, 0x595a, 0x12aa, 0x8a9a, 0xcb9a, 0x434a, 0x9b1a,
136	0xe50a, 0x2e0a, 0x132a, 0xf4ba },
137
138	/* table column 0xb */
139	{ 0x499b, 0x11eb, 0x000b, 0x909b, 0x106b, 0x5b9b, 0x661b, 0x874b,
140	0x78db, 0xe10b, 0xc90b, 0xafeb, 0x4fab, 0xf01b, 0x27db, 0x7fdb,
141	0x68ab, 0xfa4b, 0x5d6b, 0xa16b, 0x93ab, 0xbadb, 0xb4ab, 0x6dcb,
142	0x1dbb, 0x546b, 0xcacb, 0xde4b, 0x2dfb, 0x34fb, 0x171b, 0xf4db,
143	0x5b0b, 0x6f0b, 0xd76b, 0x829b },
144
145	/* table column 0xc */
146	{ 0x66cc, 0x7f4c, 0x000c, 0xc0cc, 0x70fc, 0x13cc, 0xf27c, 0xbd6c,
147	0x89ac, 0x4f0c, 0xd60c, 0x244c, 0x642c, 0x307c, 0x9dac, 0x84ac,
148	0xf92c, 0x3c6c, 0x11fc, 0x2ffc, 0xca2c, 0x5cac, 0x572c, 0xf1dc,
149	0x715c, 0x17fc, 0xdcdc, 0xab6c, 0x913c, 0xe73c, 0x7d7c, 0x37ac,
150	0x130c, 0xf40c, 0xadfc, 0xb5cc },
151
152	/* table column 0xd */
153	{ 0x8eed, 0x227d, 0x000d, 0xe0ed, 0x20bd, 0xaded, 0xbb2d, 0xc98d,
154	0x9c6d, 0x720d, 0x4e0d, 0xf57d, 0x85fd, 0x502d, 0x396d, 0x956d,
155	0xbcfd, 0x5f8d, 0xa6bd, 0xf2bd, 0xe1fd, 0xdf6d, 0xd8fd, 0xb64d,
156	0x26dd, 0xa8bd, 0x4f4d, 0x678d, 0x365d, 0x185d, 0x292d, 0x586d,
157	0xad0d, 0xb50d, 0x69bd, 0xc3ed },
158
159	/* table column 0xe */
160	{ 0x1afe, 0xd95e, 0x000e, 0xf0fe, 0xd07e, 0xc4fe, 0x7cde, 0x251e,
161	0xa3ee, 0x590e, 0x3a0e, 0x465e, 0x164e, 0x80de, 0x65ee, 0xa6ee,
162	0x734e, 0x8d1e, 0xc87e, 0x497e, 0xf74e, 0x9dee, 0x924e, 0x783e,
163	0xd89e, 0xc27e, 0x3d3e, 0xef1e, 0x688e, 0xb28e, 0xd5de, 0x82ee,
164	0xc40e, 0x760e, 0xe57e, 0x2efe },
165
166	/* table column 0xf */
167	{ 0xf2df, 0x846f, 0x000f, 0xd0df, 0x803f, 0x7adf, 0x358f, 0x51ff,
168	0xb62f, 0x640f, 0xa20f, 0x976f, 0xf79f, 0xe08f, 0xc12f, 0xb72f,
169	0x369f, 0xeeff, 0x7f3f, 0x943f, 0xdc9f, 0x1e2f, 0x1d9f, 0x3faf,
170	0x8f1f, 0x7d3f, 0xaeaf, 0x23ff, 0xcfef, 0x4def, 0x818f, 0xed2f,
171	0x7a0f, 0x370f, 0x213f, 0x58df }
172};
173
174int
175mcamd_synd_validate(struct mcamd_hdl *hdl, uint32_t synd, int syndtype)
176{
177	int result;
178
179	switch (syndtype) {
180	case AMD_SYNDTYPE_ECC:
181		result = (synd > 0 && synd <= 0xff);
182		break;
183	case AMD_SYNDTYPE_CHIPKILL:
184		result = (synd > 0 && synd <= 0xffff);
185		break;
186	default:
187		mcamd_dprintf(hdl, MCAMD_DBG_FLOW,
188		    "mcamd_synd_validate: invalid syndtype %d\n", syndtype);
189		return (0);
190	}
191
192	if (result == 0)
193		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_synd_validate: "
194		    "invalid %s syndrome 0x%x\n",
195		    syndtype == AMD_SYNDTYPE_ECC ? "64/8" : "ChipKill",
196		    synd);
197
198	return (result);
199}
200
201int
202mcamd_eccsynd_decode(struct mcamd_hdl *hdl, uint32_t synd, uint_t *bitp)
203{
204	char bit;
205
206	if (synd > 0xff) {
207		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: "
208		    "invalid synd 0x%x\n", synd);
209		return (0);
210	}
211	if ((bit = eccsynd[synd]) == -1) {
212		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: "
213		    "synd 0x%x is a multi-bit syndrome\n", synd);
214		return (0);
215	}
216
217	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: "
218	    "synd 0x%x is single-bit and indicates %s bit %d\n", synd,
219	    bit >= 64 ? "check" : "data",
220	    bit >= 64 ? bit - 64 : bit);
221
222	*bitp = bit;
223	return (1);
224}
225
226int
227mcamd_cksynd_decode(struct mcamd_hdl *hdl, uint32_t synd, uint_t *symp,
228    uint_t *patp)
229{
230	int pat = synd & 0xf;
231	int i;
232
233	if (pat == 0) {
234		mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_cksynd_decode: "
235		    "synd 0x%x is not a correctable syndrome\n", synd);
236		return (0);
237	}
238
239	for (i = 0; i < MCAMD_CKSYND_NSYMS; i++) {
240		if (cksynd[pat - 1][i] == synd) {
241			*symp = i;
242			*patp = pat;
243			mcamd_dprintf(hdl, MCAMD_DBG_FLOW,
244			    "mcamd_cksynd_decode: synd 0x%x is correctable "
245			    "and indicates symbol %d\n", synd, i);
246			return (1);
247		}
248	}
249
250	mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_cksynd_decode: "
251	    "synd 0x%x is not a correctable syndrome\n", synd);
252	return (0);
253}
254
255/*
256 * symbols 0 to 0xf:		data[63:0]
257 * symbols 0x10 to 0x1f:	data[127:64]
258 * symbols 0x20, 0x21:		checkbits for [63:0]
259 * symbols 0x22, 0x23:		checkbits for [127:64]
260 */
261/*ARGSUSED*/
262int
263mcamd_cksym_decode(struct mcamd_hdl *hdl, uint_t sym, int *lowbitp,
264    int *hibitp, int *data, int *check)
265{
266	if (sym <= 0xf || sym >= 0x10 && sym <= 0x1f) {
267		*data = 1;
268		*check = 0;
269		*lowbitp = sym * 4;
270		*hibitp = (sym + 1) * 4 - 1;
271	} else if (sym >= 0x20 && sym <= 0x23) {
272		*data = 0;
273		*check = 1;
274		*lowbitp = (sym - 0x20) * 4;
275		*hibitp = (sym + 1 - 0x20) * 4 - 1;
276	} else {
277		return (0);
278	}
279
280	return (1);
281}
282