| /* |
| * 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. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| #include <mcamd_api.h> |
| |
| /* |
| * 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); |
| } |