xref: /illumos-gate/usr/src/common/mc/mc-amd/mcamd_synd.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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  */
35 static 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 
67 static 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 
174 int
175 mcamd_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 
201 int
202 mcamd_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 
226 int
227 mcamd_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*/
262 int
263 mcamd_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