/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include /* * Indexed by syndrome, value is bit number. If value is -1, a multi-bit * error has been detected. A special case is the zero'th entry - a * syndrome of 0x0 indicates no bits in error. */ static char eccsynd[] = { -1, 64, 65, -1, 66, -1, -1, -1, 67, -1, -1, 17, -1, -1, 16, -1, 68, -1, -1, 18, -1, 19, 20, -1, -1, 21, 22, -1, 23, -1, -1, -1, 69, -1, -1, 8, -1, 9, 10, -1, -1, 11, 12, -1, 13, -1, -1, -1, -1, 14, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, 32, -1, -1, 34, -1, 35, -1, -1, 36, 37, -1, -1, 38, -1, 39, -1, -1, -1, -1, 56, -1, 57, -1, -1, 58, 59, -1, -1, 60, -1, 61, -1, -1, 62, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, 48, -1, -1, 50, -1, 51, -1, -1, 52, 53, -1, -1, 54, -1, 55, -1, -1, -1, -1, 40, -1, 41, -1, -1, 42, 43, -1, -1, 44, -1, 45, -1, -1, 46, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, -1, -1, -1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 7, -1, -1, -1, -1, -1, -1, 24, -1, 25, 26, -1, -1, 27, 28, -1, 29, -1, -1, -1, -1, 30, -1, -1, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; /* * The first dimension of this table is the errored bit pattern, which is the * column dimension of the table in the BKDG. Conveniently, the bit pattern * is also the lowest-order nibble in the syndrome, thus allowing the first * dimension value to be calculated. The second dimension is the symbol * number, which can be found by searching for a matching syndrome. * * Note that the first dimension is actually (errored_bit_pattern - 1) since * 0 is not a valid errored bit pattern. */ #define MCAMD_CKSYND_NPATS 15 #define MCAMD_CKSYND_NSYMS 36 static uint16_t cksynd[MCAMD_CKSYND_NPATS][MCAMD_CKSYND_NSYMS] = { /* table column 0x1 */ { 0xe821, 0x5d31, 0x0001, 0x2021, 0x5041, 0xbe21, 0x4951, 0x74e1, 0x15c1, 0x3d01, 0x9801, 0xd131, 0xe1d1, 0x6051, 0xa4c1, 0x11c1, 0x45d1, 0x63e1, 0xb741, 0xdd41, 0x2bd1, 0x83c1, 0x8fd1, 0x4791, 0x5781, 0xbf41, 0x9391, 0xcce1, 0xa761, 0xff61, 0x5451, 0x6fc1, 0xbe01, 0x4101, 0xc441, 0x7621 }, /* table column 0x2 */ { 0x7c32, 0xa612, 0x0002, 0x3032, 0xa082, 0xd732, 0x8ea2, 0x9872, 0x2a42, 0x1602, 0xec02, 0x6212, 0x7262, 0xb0a2, 0xf842, 0x2242, 0x8a62, 0xb172, 0xd982, 0x6682, 0x3d62, 0xc142, 0xc562, 0x89e2, 0xa9c2, 0xd582, 0xe1e2, 0x4472, 0xf9b2, 0x55b2, 0xa8a2, 0xb542, 0xd702, 0x8202, 0x4882, 0x9b32 }, /* table column 0x3 */ { 0x9413, 0xfb23, 0x0003, 0x1013, 0xf0c3, 0x6913, 0xc7f3, 0xec93, 0x3f83, 0x2b03, 0x7403, 0xb323, 0x93b3, 0xd0f3, 0x5c83, 0x3383, 0xcfb3, 0xd293, 0x6ec3, 0xbbc3, 0x16b3, 0x4283, 0x4ab3, 0xce73, 0xfe43, 0x6ac3, 0x7273, 0x8893, 0x5ed3, 0xaad3, 0xfcf3, 0xda83, 0x6903, 0xc303, 0x8cc3, 0xed13 }, /* table column 0x4 */ { 0xbb44, 0x9584, 0x0004, 0x4044, 0x9054, 0x2144, 0x5394, 0xd6b4, 0xcef4, 0x8504, 0x6b04, 0x3884, 0xb834, 0x1094, 0xe6f4, 0xc8f4, 0x5e34, 0x14b4, 0x2254, 0x3554, 0x4f34, 0xa4f4, 0xa934, 0x5264, 0x92a4, 0x2954, 0x6464, 0xfdb4, 0xe214, 0x7914, 0x9694, 0x19f4, 0x2104, 0x5804, 0xf654, 0xda44 }, /* table column 0x5 */ { 0x5365, 0xc8b5, 0x0005, 0x6065, 0xc015, 0x9f65, 0x1ac5, 0xa255, 0xdb35, 0xb805, 0xf305, 0xe9b5, 0x59e5, 0x70c5, 0x4235, 0xd935, 0x1be5, 0x7755, 0x9515, 0xe815, 0x64e5, 0x2735, 0x26e5, 0x15f5, 0xc525, 0x9615, 0xf7f5, 0x3155, 0x4575, 0x8675, 0xc2c5, 0x7635, 0x9f05, 0x1905, 0x3215, 0xac65 }, /* table column 0x6 */ { 0xc776, 0x3396, 0x0006, 0x7076, 0x30d6, 0xf676, 0xdd36, 0x4ec6, 0xe4b6, 0x9306, 0x8706, 0x5a96, 0xca56, 0xa036, 0x1eb6, 0xeab6, 0xd456, 0xa5c6, 0xfbd6, 0x53d6, 0x7256, 0x65b6, 0x6c56, 0xdb86, 0x3b66, 0xfcd6, 0x8586, 0xb9c6, 0x1ba6, 0x2ca6, 0x3e36, 0xacb6, 0xf606, 0xda06, 0xbed6, 0x4176 }, /* table column 0x7 */ { 0x2f57, 0x6ea7, 0x0007, 0x5057, 0x6097, 0x4857, 0x9467, 0x3a27, 0xf177, 0xae07, 0x1f07, 0x8ba7, 0x2b87, 0xc067, 0xba77, 0xfb77, 0x9187, 0xc627, 0x4c97, 0x8e97, 0x5987, 0xe677, 0xe387, 0x9c17, 0x6ce7, 0x4397, 0x1617, 0x7527, 0xbcc7, 0xd3c7, 0x6a67, 0xc377, 0x4807, 0x9b07, 0x7a97, 0x3757 }, /* table column 0x8 */ { 0xdd88, 0xeac8, 0x0008, 0x8088, 0xe0a8, 0x3288, 0xa1e8, 0x6bd8, 0x4758, 0xca08, 0xbd08, 0x1cc8, 0xdc18, 0x20e8, 0x7b58, 0x4c58, 0xa718, 0x28d8, 0x33a8, 0x1aa8, 0x8518, 0xf858, 0xfe18, 0xa3b8, 0xe3f8, 0x3ea8, 0xb8b8, 0x56d8, 0x7328, 0x9e28, 0xebe8, 0x2e58, 0x3208, 0xac08, 0x5ba8, 0x6f88 }, /* table column 0x9 */ { 0x35a9, 0xb7f9, 0x0009, 0xa0a9, 0xb0e9, 0x8ca9, 0xe8b9, 0x1f39, 0x5299, 0xf709, 0x2509, 0xcdf9, 0x3dc9, 0x40b9, 0xdf99, 0x5d99, 0xe2c9, 0x4b39, 0x84e9, 0xc7e9, 0xaec9, 0x7b99, 0x71c9, 0xe429, 0xb479, 0x81e9, 0x2b29, 0x9a39, 0xd449, 0x6149, 0xbfb9, 0x4199, 0x8c09, 0xed09, 0x9fe9, 0x19a9 }, /* table column 0xa */ { 0xa1ba, 0x4cda, 0x000a, 0xb0ba, 0x402a, 0xe5ba, 0x2f4a, 0xf3aa, 0x6d1a, 0xdc0a, 0x510a, 0x7eda, 0xae7a, 0x904a, 0x831a, 0x6e1a, 0x2d7a, 0x99aa, 0xea2a, 0x7c2a, 0xb87a, 0x391a, 0x3b7a, 0x2a5a, 0x4a3a, 0xeb2a, 0x595a, 0x12aa, 0x8a9a, 0xcb9a, 0x434a, 0x9b1a, 0xe50a, 0x2e0a, 0x132a, 0xf4ba }, /* table column 0xb */ { 0x499b, 0x11eb, 0x000b, 0x909b, 0x106b, 0x5b9b, 0x661b, 0x874b, 0x78db, 0xe10b, 0xc90b, 0xafeb, 0x4fab, 0xf01b, 0x27db, 0x7fdb, 0x68ab, 0xfa4b, 0x5d6b, 0xa16b, 0x93ab, 0xbadb, 0xb4ab, 0x6dcb, 0x1dbb, 0x546b, 0xcacb, 0xde4b, 0x2dfb, 0x34fb, 0x171b, 0xf4db, 0x5b0b, 0x6f0b, 0xd76b, 0x829b }, /* table column 0xc */ { 0x66cc, 0x7f4c, 0x000c, 0xc0cc, 0x70fc, 0x13cc, 0xf27c, 0xbd6c, 0x89ac, 0x4f0c, 0xd60c, 0x244c, 0x642c, 0x307c, 0x9dac, 0x84ac, 0xf92c, 0x3c6c, 0x11fc, 0x2ffc, 0xca2c, 0x5cac, 0x572c, 0xf1dc, 0x715c, 0x17fc, 0xdcdc, 0xab6c, 0x913c, 0xe73c, 0x7d7c, 0x37ac, 0x130c, 0xf40c, 0xadfc, 0xb5cc }, /* table column 0xd */ { 0x8eed, 0x227d, 0x000d, 0xe0ed, 0x20bd, 0xaded, 0xbb2d, 0xc98d, 0x9c6d, 0x720d, 0x4e0d, 0xf57d, 0x85fd, 0x502d, 0x396d, 0x956d, 0xbcfd, 0x5f8d, 0xa6bd, 0xf2bd, 0xe1fd, 0xdf6d, 0xd8fd, 0xb64d, 0x26dd, 0xa8bd, 0x4f4d, 0x678d, 0x365d, 0x185d, 0x292d, 0x586d, 0xad0d, 0xb50d, 0x69bd, 0xc3ed }, /* table column 0xe */ { 0x1afe, 0xd95e, 0x000e, 0xf0fe, 0xd07e, 0xc4fe, 0x7cde, 0x251e, 0xa3ee, 0x590e, 0x3a0e, 0x465e, 0x164e, 0x80de, 0x65ee, 0xa6ee, 0x734e, 0x8d1e, 0xc87e, 0x497e, 0xf74e, 0x9dee, 0x924e, 0x783e, 0xd89e, 0xc27e, 0x3d3e, 0xef1e, 0x688e, 0xb28e, 0xd5de, 0x82ee, 0xc40e, 0x760e, 0xe57e, 0x2efe }, /* table column 0xf */ { 0xf2df, 0x846f, 0x000f, 0xd0df, 0x803f, 0x7adf, 0x358f, 0x51ff, 0xb62f, 0x640f, 0xa20f, 0x976f, 0xf79f, 0xe08f, 0xc12f, 0xb72f, 0x369f, 0xeeff, 0x7f3f, 0x943f, 0xdc9f, 0x1e2f, 0x1d9f, 0x3faf, 0x8f1f, 0x7d3f, 0xaeaf, 0x23ff, 0xcfef, 0x4def, 0x818f, 0xed2f, 0x7a0f, 0x370f, 0x213f, 0x58df } }; int mcamd_synd_validate(struct mcamd_hdl *hdl, uint32_t synd, int syndtype) { int result; switch (syndtype) { case AMD_SYNDTYPE_ECC: result = (synd > 0 && synd <= 0xff); break; case AMD_SYNDTYPE_CHIPKILL: result = (synd > 0 && synd <= 0xffff); break; default: mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_synd_validate: invalid syndtype %d\n", syndtype); return (0); } if (result == 0) mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_synd_validate: " "invalid %s syndrome 0x%x\n", syndtype == AMD_SYNDTYPE_ECC ? "64/8" : "ChipKill", synd); return (result); } int mcamd_eccsynd_decode(struct mcamd_hdl *hdl, uint32_t synd, uint_t *bitp) { char bit; if (synd > 0xff) { mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: " "invalid synd 0x%x\n", synd); return (0); } if ((bit = eccsynd[synd]) == -1) { mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: " "synd 0x%x is a multi-bit syndrome\n", synd); return (0); } mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_eccsynd_decode: " "synd 0x%x is single-bit and indicates %s bit %d\n", synd, bit >= 64 ? "check" : "data", bit >= 64 ? bit - 64 : bit); *bitp = bit; return (1); } int mcamd_cksynd_decode(struct mcamd_hdl *hdl, uint32_t synd, uint_t *symp, uint_t *patp) { int pat = synd & 0xf; int i; if (pat == 0) { mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_cksynd_decode: " "synd 0x%x is not a correctable syndrome\n", synd); return (0); } for (i = 0; i < MCAMD_CKSYND_NSYMS; i++) { if (cksynd[pat - 1][i] == synd) { *symp = i; *patp = pat; mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_cksynd_decode: synd 0x%x is correctable " "and indicates symbol %d\n", synd, i); return (1); } } mcamd_dprintf(hdl, MCAMD_DBG_FLOW, "mcamd_cksynd_decode: " "synd 0x%x is not a correctable syndrome\n", synd); return (0); } /* * symbols 0 to 0xf: data[63:0] * symbols 0x10 to 0x1f: data[127:64] * symbols 0x20, 0x21: checkbits for [63:0] * symbols 0x22, 0x23: checkbits for [127:64] */ /*ARGSUSED*/ int mcamd_cksym_decode(struct mcamd_hdl *hdl, uint_t sym, int *lowbitp, int *hibitp, int *data, int *check) { if (sym <= 0xf || sym >= 0x10 && sym <= 0x1f) { *data = 1; *check = 0; *lowbitp = sym * 4; *hibitp = (sym + 1) * 4 - 1; } else if (sym >= 0x20 && sym <= 0x23) { *data = 0; *check = 1; *lowbitp = (sym - 0x20) * 4; *hibitp = (sym + 1 - 0x20) * 4 - 1; } else { return (0); } return (1); }