xref: /illumos-gate/usr/src/common/mc/mc-amd/mcamd_synd.c (revision 7c8de9202c10c8c49a901bff2e373864b545bd57)
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