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