xref: /netbsd-src/sys/dev/nand/hamming.c (revision f273a7a174ebed441f3363e0c944bd42390ca256)
1*f273a7a1Sandvar /*	$NetBSD: hamming.c,v 1.2 2021/12/07 21:37:37 andvar Exp $	*/
22b6ee221Sahoka 
32b6ee221Sahoka /*
42b6ee221Sahoka  * Copyright (c) 2008, Atmel Corporation
52b6ee221Sahoka  *
62b6ee221Sahoka  * All rights reserved.
72b6ee221Sahoka  *
82b6ee221Sahoka  * Redistribution and use in source and binary forms, with or without
92b6ee221Sahoka  * modification, are permitted provided that the following conditions are met:
102b6ee221Sahoka  *
112b6ee221Sahoka  * - Redistributions of source code must retain the above copyright notice,
122b6ee221Sahoka  * this list of conditions and the disclaimer below.
132b6ee221Sahoka  *
142b6ee221Sahoka  * Atmel's name may not be used to endorse or promote products derived from
152b6ee221Sahoka  * this software without specific prior written permission.
162b6ee221Sahoka  *
172b6ee221Sahoka  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
182b6ee221Sahoka  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
192b6ee221Sahoka  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
202b6ee221Sahoka  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
212b6ee221Sahoka  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222b6ee221Sahoka  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
232b6ee221Sahoka  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
242b6ee221Sahoka  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
252b6ee221Sahoka  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
262b6ee221Sahoka  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272b6ee221Sahoka  */
282b6ee221Sahoka 
292b6ee221Sahoka #include <sys/cdefs.h>
30*f273a7a1Sandvar __KERNEL_RCSID(0, "$NetBSD: hamming.c,v 1.2 2021/12/07 21:37:37 andvar Exp $");
312b6ee221Sahoka 
322b6ee221Sahoka #include <sys/param.h>
332b6ee221Sahoka #include <lib/libkern/libkern.h>
342b6ee221Sahoka #include "hamming.h"
352b6ee221Sahoka 
362b6ee221Sahoka /**
372b6ee221Sahoka  * Calculates the 22-bit hamming code for a 256-bytes block of data.
382b6ee221Sahoka  * \param data  Data buffer to calculate code for.
392b6ee221Sahoka  * \param code  Pointer to a buffer where the code should be stored.
402b6ee221Sahoka  */
412b6ee221Sahoka void
hamming_compute_256(const uint8_t * data,uint8_t * code)422b6ee221Sahoka hamming_compute_256(const uint8_t *data, uint8_t *code)
432b6ee221Sahoka {
442b6ee221Sahoka 	unsigned int i;
452b6ee221Sahoka 	uint8_t column_sum = 0;
462b6ee221Sahoka 	uint8_t even_line_code = 0;
472b6ee221Sahoka 	uint8_t odd_line_code = 0;
482b6ee221Sahoka 	uint8_t even_column_code = 0;
492b6ee221Sahoka 	uint8_t odd_column_code = 0;
502b6ee221Sahoka 
512b6ee221Sahoka 	/*-
522b6ee221Sahoka 	 * Xor all bytes together to get the column sum;
532b6ee221Sahoka 	 * At the same time, calculate the even and odd line codes
542b6ee221Sahoka 	 */
552b6ee221Sahoka 	for (i = 0; i < 256; i++) {
562b6ee221Sahoka 		column_sum ^= data[i];
572b6ee221Sahoka 
582b6ee221Sahoka 		/*-
592b6ee221Sahoka 		 * If the xor sum of the byte is 0, then this byte has no
602b6ee221Sahoka 		 * incidence on the computed code; so check if the sum is 1.
612b6ee221Sahoka 		 */
622b6ee221Sahoka 		if ((popcount(data[i]) & 1) == 1) {
632b6ee221Sahoka 			/*-
642b6ee221Sahoka 			 * Parity groups are formed by forcing a particular
652b6ee221Sahoka 			 * index bit to 0 (even) or 1 (odd).
662b6ee221Sahoka 			 * Example on one byte:
672b6ee221Sahoka 			 *
682b6ee221Sahoka 			 * bits (dec)  7   6   5   4   3   2   1   0
692b6ee221Sahoka 			 *      (bin) 111 110 101 100 011 010 001 000
702b6ee221Sahoka 			 *                            '---'---'---'----------.
712b6ee221Sahoka 			 *                                                   |
722b6ee221Sahoka 			 * groups P4' ooooooooooooooo eeeeeeeeeeeeeee P4     |
732b6ee221Sahoka 			 *        P2' ooooooo eeeeeee ooooooo eeeeeee P2     |
742b6ee221Sahoka 			 *        P1' ooo eee ooo eee ooo eee ooo eee P1     |
752b6ee221Sahoka 			 *                                                   |
762b6ee221Sahoka 			 * We can see that:                                  |
772b6ee221Sahoka 			 *  - P4  -> bit 2 of index is 0 --------------------'
782b6ee221Sahoka 			 *  - P4' -> bit 2 of index is 1.
792b6ee221Sahoka 			 *  - P2  -> bit 1 of index if 0.
802b6ee221Sahoka 			 *  - etc...
812b6ee221Sahoka 			 * We deduce that a bit position has an impact on all
822b6ee221Sahoka 			 * even Px if the log2(x)nth bit of its index is 0
832b6ee221Sahoka 			 *     ex: log2(4) = 2,
842b6ee221Sahoka 			 * bit2 of the index must be 0 (-> 0 1 2 3)
852b6ee221Sahoka 			 * and on all odd Px' if the log2(x)nth bit
862b6ee221Sahoka 			 * of its index is 1
872b6ee221Sahoka 			 *     ex: log2(2) = 1,
882b6ee221Sahoka 			 * bit1 of the index must be 1 (-> 0 1 4 5)
892b6ee221Sahoka 			 *
902b6ee221Sahoka 			 * As such, we calculate all the possible Px and Px'
912b6ee221Sahoka 			 * values at the same time in two variables,
922b6ee221Sahoka 			 * even_line_code and odd_line_code, such as
932b6ee221Sahoka 			 *     even_line_code bits: P128  P64  P32
942b6ee221Sahoka 			 *                        P16  P8  P4  P2  P1
952b6ee221Sahoka 			 *     odd_line_code  bits: P128' P64' P32' P16'
962b6ee221Sahoka 			 *                        P8' P4' P2' P1'
972b6ee221Sahoka 			 */
982b6ee221Sahoka 			even_line_code ^= (255 - i);
992b6ee221Sahoka 			odd_line_code ^= i;
1002b6ee221Sahoka 		}
1012b6ee221Sahoka 	}
1022b6ee221Sahoka 
1032b6ee221Sahoka 	/*-
1042b6ee221Sahoka 	 * At this point, we have the line parities, and the column sum.
105*f273a7a1Sandvar 	 * First, We must calculate the parity group values on the column sum.
1062b6ee221Sahoka 	 */
1072b6ee221Sahoka 	for (i = 0; i < 8; i++) {
1082b6ee221Sahoka 		if (column_sum & 1) {
1092b6ee221Sahoka 			even_column_code ^= (7 - i);
1102b6ee221Sahoka 			odd_column_code ^= i;
1112b6ee221Sahoka 		}
1122b6ee221Sahoka 		column_sum >>= 1;
1132b6ee221Sahoka 	}
1142b6ee221Sahoka 
1152b6ee221Sahoka 	/*-
1162b6ee221Sahoka 	 * Now, we must interleave the parity values,
1172b6ee221Sahoka 	 * to obtain the following layout:
1182b6ee221Sahoka 	 * Code[0] = Line1
1192b6ee221Sahoka 	 * Code[1] = Line2
1202b6ee221Sahoka 	 * Code[2] = Column
1212b6ee221Sahoka 	 * Line = Px' Px P(x-1)- P(x-1) ...
1222b6ee221Sahoka 	 * Column = P4' P4 P2' P2 P1' P1 PadBit PadBit
1232b6ee221Sahoka 	 */
1242b6ee221Sahoka 	code[0] = 0;
1252b6ee221Sahoka 	code[1] = 0;
1262b6ee221Sahoka 	code[2] = 0;
1272b6ee221Sahoka 
1282b6ee221Sahoka 	for (i = 0; i < 4; i++) {
1292b6ee221Sahoka 		code[0] <<= 2;
1302b6ee221Sahoka 		code[1] <<= 2;
1312b6ee221Sahoka 		code[2] <<= 2;
1322b6ee221Sahoka 
1332b6ee221Sahoka 		/* Line 1 */
1342b6ee221Sahoka 		if ((odd_line_code & 0x80) != 0) {
1352b6ee221Sahoka 
1362b6ee221Sahoka 			code[0] |= 2;
1372b6ee221Sahoka 		}
1382b6ee221Sahoka 		if ((even_line_code & 0x80) != 0) {
1392b6ee221Sahoka 
1402b6ee221Sahoka 			code[0] |= 1;
1412b6ee221Sahoka 		}
1422b6ee221Sahoka 
1432b6ee221Sahoka 		/* Line 2 */
1442b6ee221Sahoka 		if ((odd_line_code & 0x08) != 0) {
1452b6ee221Sahoka 
1462b6ee221Sahoka 			code[1] |= 2;
1472b6ee221Sahoka 		}
1482b6ee221Sahoka 		if ((even_line_code & 0x08) != 0) {
1492b6ee221Sahoka 
1502b6ee221Sahoka 			code[1] |= 1;
1512b6ee221Sahoka 		}
1522b6ee221Sahoka 
1532b6ee221Sahoka 		/* Column */
1542b6ee221Sahoka 		if ((odd_column_code & 0x04) != 0) {
1552b6ee221Sahoka 
1562b6ee221Sahoka 			code[2] |= 2;
1572b6ee221Sahoka 		}
1582b6ee221Sahoka 		if ((even_column_code & 0x04) != 0) {
1592b6ee221Sahoka 
1602b6ee221Sahoka 			code[2] |= 1;
1612b6ee221Sahoka 		}
1622b6ee221Sahoka 
1632b6ee221Sahoka 		odd_line_code <<= 1;
1642b6ee221Sahoka 		even_line_code <<= 1;
1652b6ee221Sahoka 		odd_column_code <<= 1;
1662b6ee221Sahoka 		even_column_code <<= 1;
1672b6ee221Sahoka 	}
1682b6ee221Sahoka 
1692b6ee221Sahoka 	/* Invert codes (linux compatibility) */
1702b6ee221Sahoka 	code[0] = ~code[0];
1712b6ee221Sahoka 	code[1] = ~code[1];
1722b6ee221Sahoka 	code[2] = ~code[2];
1732b6ee221Sahoka }
1742b6ee221Sahoka 
1752b6ee221Sahoka /**
1762b6ee221Sahoka  * Verifies and corrects a 256-bytes block of data using the given 22-bits
1772b6ee221Sahoka  * hamming code.
1782b6ee221Sahoka  * Returns 0 if there is no error, otherwise returns a HAMMING_ERROR code.
1792b6ee221Sahoka  * param data  Data buffer to check.
1802b6ee221Sahoka  * \param original_code  Hamming code to use for verifying the data.
1812b6ee221Sahoka  */
1822b6ee221Sahoka uint8_t
hamming_correct_256(uint8_t * data,const uint8_t * original_code,const uint8_t * computed_code)1832b6ee221Sahoka hamming_correct_256(uint8_t *data, const uint8_t *original_code,
1842b6ee221Sahoka     const uint8_t *computed_code)
1852b6ee221Sahoka {
1862b6ee221Sahoka 	/* Calculate new code */
1872b6ee221Sahoka 	/* we allocate 4 bytes so we can use popcount32 in one step */
1882b6ee221Sahoka 	uint8_t correction_code[4];
1892b6ee221Sahoka 
1902b6ee221Sahoka 	/* this byte should remain zero all the time */
1912b6ee221Sahoka 	correction_code[3] = 0;
1922b6ee221Sahoka 
1932b6ee221Sahoka 	/* Xor both codes together */
1942b6ee221Sahoka 	correction_code[0] = computed_code[0] ^ original_code[0];
1952b6ee221Sahoka 	correction_code[1] = computed_code[1] ^ original_code[1];
1962b6ee221Sahoka 	correction_code[2] = computed_code[2] ^ original_code[2];
1972b6ee221Sahoka 
1982b6ee221Sahoka 	/* If all bytes are 0, there is no error */
1992b6ee221Sahoka 	if (*(uint32_t *)correction_code == 0) {
2002b6ee221Sahoka 		return 0;
2012b6ee221Sahoka 	}
2022b6ee221Sahoka 	/* If there is a single bit error, there are 11 bits set to 1 */
2032b6ee221Sahoka 	if (popcount32(*(uint32_t *)correction_code) == 11) {
2042b6ee221Sahoka 		/* Get byte and bit indexes */
2052b6ee221Sahoka 		uint8_t byte = correction_code[0] & 0x80;
2062b6ee221Sahoka 		byte |= (correction_code[0] << 1) & 0x40;
2072b6ee221Sahoka 		byte |= (correction_code[0] << 2) & 0x20;
2082b6ee221Sahoka 		byte |= (correction_code[0] << 3) & 0x10;
2092b6ee221Sahoka 
2102b6ee221Sahoka 		byte |= (correction_code[1] >> 4) & 0x08;
2112b6ee221Sahoka 		byte |= (correction_code[1] >> 3) & 0x04;
2122b6ee221Sahoka 		byte |= (correction_code[1] >> 2) & 0x02;
2132b6ee221Sahoka 		byte |= (correction_code[1] >> 1) & 0x01;
2142b6ee221Sahoka 
2152b6ee221Sahoka 		uint8_t bit = (correction_code[2] >> 5) & 0x04;
2162b6ee221Sahoka 		bit |= (correction_code[2] >> 4) & 0x02;
2172b6ee221Sahoka 		bit |= (correction_code[2] >> 3) & 0x01;
2182b6ee221Sahoka 
2192b6ee221Sahoka 		/* Correct bit */
2202b6ee221Sahoka 		data[byte] ^= (1 << bit);
2212b6ee221Sahoka 
2222b6ee221Sahoka 		return HAMMING_ERROR_SINGLEBIT;
2232b6ee221Sahoka 	}
2242b6ee221Sahoka 	/* Check if ECC has been corrupted */
2252b6ee221Sahoka 	if (popcount32(*(uint32_t *)correction_code) == 1) {
2262b6ee221Sahoka 		return HAMMING_ERROR_ECC;
2272b6ee221Sahoka 	} else {
2282b6ee221Sahoka 		/* Otherwise, this is a multi-bit error */
2292b6ee221Sahoka 		return HAMMING_ERROR_MULTIPLEBITS;
2302b6ee221Sahoka 	}
2312b6ee221Sahoka }
2322b6ee221Sahoka 
233