[U-Boot] [PATCH v5 7/8] board: ge: make VPD code common

Martyn Welch martyn.welch at collabora.co.uk
Wed Nov 8 15:35:15 UTC 2017


The VPD data is used on a number of GE products. Move the parsing code to
a common location so that we can share this code.

Signed-off-by: Martyn Welch <martyn.welch at collabora.co.uk>
---
Changes in v4:
   - New patch.

Changes in v5:
   - Fixed checkpatch issues.

board/ge/bx50v3/Makefile     |   2 +-
 board/ge/bx50v3/bx50v3.c     |   2 +-
 board/ge/bx50v3/vpd_reader.c | 228 -------------------------------------------
 board/ge/bx50v3/vpd_reader.h |  25 -----
 board/ge/common/Makefile     |   7 ++
 board/ge/common/vpd_reader.c | 197 +++++++++++++++++++++++++++++++++++++
 board/ge/common/vpd_reader.h |  17 ++++
 7 files changed, 223 insertions(+), 255 deletions(-)
 delete mode 100644 board/ge/bx50v3/vpd_reader.c
 delete mode 100644 board/ge/bx50v3/vpd_reader.h
 create mode 100644 board/ge/common/Makefile
 create mode 100644 board/ge/common/vpd_reader.c
 create mode 100644 board/ge/common/vpd_reader.h

diff --git a/board/ge/bx50v3/Makefile b/board/ge/bx50v3/Makefile
index 2fff27b..bcd149f 100644
--- a/board/ge/bx50v3/Makefile
+++ b/board/ge/bx50v3/Makefile
@@ -5,4 +5,4 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-y  := bx50v3.o vpd_reader.o
+obj-y  := bx50v3.o
diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c
index 2e8f394..37de990 100644
--- a/board/ge/bx50v3/bx50v3.c
+++ b/board/ge/bx50v3/bx50v3.c
@@ -28,7 +28,7 @@
 #include <input.h>
 #include <pwm.h>
 #include <stdlib.h>
-#include "vpd_reader.h"
+#include "../common/vpd_reader.h"
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifndef CONFIG_SYS_I2C_EEPROM_ADDR
diff --git a/board/ge/bx50v3/vpd_reader.c b/board/ge/bx50v3/vpd_reader.c
deleted file mode 100644
index 98da893..0000000
--- a/board/ge/bx50v3/vpd_reader.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2016 General Electric Company
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include "vpd_reader.h"
-
-#include <linux/bch.h>
-#include <stdlib.h>
-
-
-/* BCH configuration */
-
-const struct {
-	int header_ecc_capability_bits;
-	int data_ecc_capability_bits;
-	unsigned int prim_poly;
-	struct {
-		int min;
-		int max;
-	} galois_field_order;
-} bch_configuration = {
-	.header_ecc_capability_bits = 4,
-	.data_ecc_capability_bits = 16,
-	.prim_poly = 0,
-	.galois_field_order = {
-		.min = 5,
-		.max = 15,
-	},
-};
-
-static int calculate_galois_field_order(size_t source_length)
-{
-	int gfo = bch_configuration.galois_field_order.min;
-
-	for (; gfo < bch_configuration.galois_field_order.max &&
-	     ((((1 << gfo) - 1) - ((int)source_length * 8)) < 0);
-	     gfo++) {
-	}
-
-	if (gfo == bch_configuration.galois_field_order.max) {
-		return -1;
-	}
-
-	return gfo + 1;
-}
-
-static int verify_bch(int ecc_bits, unsigned int prim_poly,
-	uint8_t * data, size_t data_length,
-	const uint8_t * ecc, size_t ecc_length)
-{
-	int gfo = calculate_galois_field_order(data_length);
-	if (gfo < 0) {
-		return -1;
-	}
-
-	struct bch_control * bch = init_bch(gfo, ecc_bits, prim_poly);
-	if (!bch) {
-		return -1;
-	}
-
-	if (bch->ecc_bytes != ecc_length) {
-		free_bch(bch);
-		return -1;
-	}
-
-	unsigned * errloc = (unsigned *)calloc(data_length, sizeof(unsigned));
-	int errors = decode_bch(
-			bch, data, data_length, ecc, NULL, NULL, errloc);
-	free_bch(bch);
-	if (errors < 0) {
-		free(errloc);
-		return -1;
-	}
-
-	if (errors > 0) {
-		for (int n = 0; n < errors; n++) {
-			if (errloc[n] >= 8 * data_length) {
-				/* n-th error located in ecc (no need for data correction) */
-			} else {
-				/* n-th error located in data */
-				data[errloc[n] / 8] ^= 1 << (errloc[n] % 8);
-			}
-		}
-	}
-
-	free(errloc);
-	return 0;
-}
-
-
-static const int ID = 0;
-static const int LEN = 1;
-static const int VER = 2;
-static const int TYP = 3;
-static const int BLOCK_SIZE = 4;
-
-static const uint8_t HEADER_BLOCK_ID = 0x00;
-static const uint8_t HEADER_BLOCK_LEN = 18;
-static const uint32_t HEADER_BLOCK_MAGIC = 0xca53ca53;
-static const size_t HEADER_BLOCK_VERIFY_LEN = 14;
-static const size_t HEADER_BLOCK_ECC_OFF = 14;
-static const size_t HEADER_BLOCK_ECC_LEN = 4;
-
-static const uint8_t ECC_BLOCK_ID = 0xFF;
-
-int vpd_reader(
-	size_t size,
-	uint8_t * data,
-	void * userdata,
-	int (*fn)(
-	    void * userdata,
-	    uint8_t id,
-	    uint8_t version,
-	    uint8_t type,
-	    size_t size,
-	    uint8_t const * data))
-{
-	if (   size < HEADER_BLOCK_LEN
-	    || data == NULL
-	    || fn == NULL) {
-		return -EINVAL;
-	}
-
-	/*
-	 * +--------------------+--------------------+--//--+--------------------+
-	 * | header block       | data block         | ...  | ecc block          |
-	 * +--------------------+--------------------+--//--+--------------------+
-	 * :                    :                           :
-	 * +------+-------+-----+                           +------+-------------+
-	 * | id   | magic | ecc |                           | ...  | ecc         |
-	 * | len  | off   |     |                           +------+-------------+
-	 * | ver  | size  |     |                           :
-	 * | type |       |     |                           :
-	 * +------+-------+-----+                           :
-	 * :              :     :                           :
-	 * <----- [1] ---->     <----------- [2] ----------->
-	 *
-	 * Repair (if necessary) the contents of header block [1] by using a
-	 * 4 byte ECC located at the end of the header block.  A successful
-	 * return value means that we can trust the header.
-	 */
-	int ret = verify_bch(
-		bch_configuration.header_ecc_capability_bits,
-		bch_configuration.prim_poly,
-		data,
-		HEADER_BLOCK_VERIFY_LEN,
-		&data[HEADER_BLOCK_ECC_OFF],
-		HEADER_BLOCK_ECC_LEN);
-	if (ret < 0) {
-		return ret;
-	}
-
-	/* Validate header block { id, length, version, type }. */
-	if (   data[ID] != HEADER_BLOCK_ID
-	    || data[LEN] != HEADER_BLOCK_LEN
-	    || data[VER] != 0
-	    || data[TYP] != 0
-	    || ntohl(*(uint32_t *)(&data[4])) != HEADER_BLOCK_MAGIC) {
-		return -EINVAL;
-	}
-
-	uint32_t offset = ntohl(*(uint32_t *)(&data[8]));
-	uint16_t size_bits = ntohs(*(uint16_t *)(&data[12]));
-
-	/* Check that ECC header fits. */
-	if (offset + 3 >= size) {
-		return -EINVAL;
-	}
-
-	/* Validate ECC block. */
-	uint8_t * ecc = &data[offset];
-	if (   ecc[ID] != ECC_BLOCK_ID
-	    || ecc[LEN] < BLOCK_SIZE
-	    || ecc[LEN] + offset > size
-	    || ecc[LEN] - BLOCK_SIZE != size_bits / 8
-	    || ecc[VER] != 1
-	    || ecc[TYP] != 1) {
-		return -EINVAL;
-	}
-
-	/*
-	 * Use the header block to locate the ECC block and verify the data
-	 * blocks [2] against the ecc block ECC.
-	 */
-	ret = verify_bch(
-		bch_configuration.data_ecc_capability_bits,
-		bch_configuration.prim_poly,
-		&data[data[LEN]],
-		offset - data[LEN],
-		&data[offset + BLOCK_SIZE],
-		ecc[LEN] - BLOCK_SIZE);
-	if (ret < 0) {
-		return ret;
-	}
-
-	/* Stop after ECC.  Ignore possible zero padding. */
-	size = offset;
-
-	for (;;) {
-		/* Move to next block. */
-		size -= data[LEN];
-		data += data[LEN];
-
-		if (size == 0) {
-			/* Finished iterating through blocks. */
-			return 0;
-		}
-
-		if (   size < BLOCK_SIZE
-		    || data[LEN] < BLOCK_SIZE) {
-			/* Not enough data for a header, or short header. */
-			return -EINVAL;
-		}
-
-		ret = fn(
-			userdata,
-			data[ID],
-			data[VER],
-			data[TYP],
-			data[LEN] - BLOCK_SIZE,
-			&data[BLOCK_SIZE]);
-		if (ret) {
-			return ret;
-		}
-	}
-}
diff --git a/board/ge/bx50v3/vpd_reader.h b/board/ge/bx50v3/vpd_reader.h
deleted file mode 100644
index efa172a..0000000
--- a/board/ge/bx50v3/vpd_reader.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2016 General Electric Company
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include "common.h"
-
-/*
- * Read VPD from given data, verify content, and call callback
- * for each vital product data block.
- *
- * Returns Non-zero on error.  Negative numbers encode errno.
- */
-int vpd_reader(
-	size_t size,
-	uint8_t * data,
-	void * userdata,
-	int (*fn)(
-	    void * userdata,
-	    uint8_t id,
-	    uint8_t version,
-	    uint8_t type,
-	    size_t size,
-	    uint8_t const * data));
diff --git a/board/ge/common/Makefile b/board/ge/common/Makefile
new file mode 100644
index 0000000..93e6c01
--- /dev/null
+++ b/board/ge/common/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright 2017 General Electric Company
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y  := vpd_reader.o
diff --git a/board/ge/common/vpd_reader.c b/board/ge/common/vpd_reader.c
new file mode 100644
index 0000000..7367427
--- /dev/null
+++ b/board/ge/common/vpd_reader.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2016 General Electric Company
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "vpd_reader.h"
+
+#include <linux/bch.h>
+#include <stdlib.h>
+
+/* BCH configuration */
+
+const struct {
+	int header_ecc_capability_bits;
+	int data_ecc_capability_bits;
+	unsigned int prim_poly;
+	struct {
+		int min;
+		int max;
+	} galois_field_order;
+} bch_configuration = {
+	.header_ecc_capability_bits = 4,
+	.data_ecc_capability_bits = 16,
+	.prim_poly = 0,
+	.galois_field_order = {
+		.min = 5,
+		.max = 15,
+	},
+};
+
+static int calculate_galois_field_order(size_t source_length)
+{
+	int gfo = bch_configuration.galois_field_order.min;
+
+	for (; gfo < bch_configuration.galois_field_order.max &&
+	     ((((1 << gfo) - 1) - ((int)source_length * 8)) < 0);
+	     gfo++) {
+	}
+
+	if (gfo == bch_configuration.galois_field_order.max)
+		return -1;
+
+	return gfo + 1;
+}
+
+static int verify_bch(int ecc_bits, unsigned int prim_poly, u8 *data,
+		      size_t data_length, const u8 *ecc, size_t ecc_length)
+{
+	int gfo = calculate_galois_field_order(data_length);
+
+	if (gfo < 0)
+		return -1;
+
+	struct bch_control *bch = init_bch(gfo, ecc_bits, prim_poly);
+
+	if (!bch)
+		return -1;
+
+	if (bch->ecc_bytes != ecc_length) {
+		free_bch(bch);
+		return -1;
+	}
+
+	unsigned int *errloc = (unsigned int *)calloc(data_length,
+						      sizeof(unsigned int));
+	int errors = decode_bch(bch, data, data_length, ecc, NULL, NULL,
+				errloc);
+
+	free_bch(bch);
+	if (errors < 0) {
+		free(errloc);
+		return -1;
+	}
+
+	if (errors > 0) {
+		for (int n = 0; n < errors; n++) {
+			if (errloc[n] >= 8 * data_length) {
+				/*
+				 * n-th error located in ecc (no need for data
+				 * correction)
+				 */
+			} else {
+				/* n-th error located in data */
+				data[errloc[n] / 8] ^= 1 << (errloc[n] % 8);
+			}
+		}
+	}
+
+	free(errloc);
+	return 0;
+}
+
+static const int ID;
+static const int LEN = 1;
+static const int VER = 2;
+static const int TYP = 3;
+static const int BLOCK_SIZE = 4;
+
+static const u8 HEADER_BLOCK_ID;
+static const u8 HEADER_BLOCK_LEN = 18;
+static const u32 HEADER_BLOCK_MAGIC = 0xca53ca53;
+static const size_t HEADER_BLOCK_VERIFY_LEN = 14;
+static const size_t HEADER_BLOCK_ECC_OFF = 14;
+static const size_t HEADER_BLOCK_ECC_LEN = 4;
+
+static const u8 ECC_BLOCK_ID = 0xFF;
+
+int vpd_reader(size_t size, u8 *data, void *userdata,
+	       int (*fn)(void *userdata, u8 id, u8 version, u8 type,
+			 size_t size, u8 const *data))
+{
+	if (size < HEADER_BLOCK_LEN || !data || !fn)
+		return -EINVAL;
+
+	/*
+	 * +--------------------+----------------+--//--+--------------------+
+	 * | header block       | data block     | ...  | ecc block          |
+	 * +--------------------+----------------+--//--+--------------------+
+	 * :                    :                       :
+	 * +------+-------+-----+                       +------+-------------+
+	 * | id   | magic | ecc |                       | ...  | ecc         |
+	 * | len  | off   |     |                       +------+-------------+
+	 * | ver  | size  |     |                       :
+	 * | type |       |     |                       :
+	 * +------+-------+-----+                       :
+	 * :              :     :                       :
+	 * <----- [1] ---->     <--------- [2] --------->
+	 *
+	 * Repair (if necessary) the contents of header block [1] by using a
+	 * 4 byte ECC located at the end of the header block.  A successful
+	 * return value means that we can trust the header.
+	 */
+	int ret = verify_bch(bch_configuration.header_ecc_capability_bits,
+			     bch_configuration.prim_poly, data,
+			     HEADER_BLOCK_VERIFY_LEN,
+			     &data[HEADER_BLOCK_ECC_OFF], HEADER_BLOCK_ECC_LEN);
+	if (ret < 0)
+		return ret;
+
+	/* Validate header block { id, length, version, type }. */
+	if (data[ID] != HEADER_BLOCK_ID || data[LEN] != HEADER_BLOCK_LEN ||
+	    data[VER] != 0 || data[TYP] != 0 ||
+	    ntohl(*(u32 *)(&data[4])) != HEADER_BLOCK_MAGIC)
+		return -EINVAL;
+
+	u32 offset = ntohl(*(u32 *)(&data[8]));
+	u16 size_bits = ntohs(*(u16 *)(&data[12]));
+
+	/* Check that ECC header fits. */
+	if (offset + 3 >= size)
+		return -EINVAL;
+
+	/* Validate ECC block. */
+	u8 *ecc = &data[offset];
+
+	if (ecc[ID] != ECC_BLOCK_ID || ecc[LEN] < BLOCK_SIZE ||
+	    ecc[LEN] + offset > size ||
+	    ecc[LEN] - BLOCK_SIZE != size_bits / 8 || ecc[VER] != 1 ||
+	    ecc[TYP] != 1)
+		return -EINVAL;
+
+	/*
+	 * Use the header block to locate the ECC block and verify the data
+	 * blocks [2] against the ecc block ECC.
+	 */
+	ret = verify_bch(bch_configuration.data_ecc_capability_bits,
+			 bch_configuration.prim_poly, &data[data[LEN]],
+			 offset - data[LEN], &data[offset + BLOCK_SIZE],
+			 ecc[LEN] - BLOCK_SIZE);
+	if (ret < 0)
+		return ret;
+
+	/* Stop after ECC.  Ignore possible zero padding. */
+	size = offset;
+
+	for (;;) {
+		/* Move to next block. */
+		size -= data[LEN];
+		data += data[LEN];
+
+		if (size == 0) {
+			/* Finished iterating through blocks. */
+			return 0;
+		}
+
+		if (size < BLOCK_SIZE || data[LEN] < BLOCK_SIZE) {
+			/* Not enough data for a header, or short header. */
+			return -EINVAL;
+		}
+
+		ret = fn(userdata, data[ID], data[VER], data[TYP],
+			 data[LEN] - BLOCK_SIZE, &data[BLOCK_SIZE]);
+		if (ret)
+			return ret;
+	}
+}
diff --git a/board/ge/common/vpd_reader.h b/board/ge/common/vpd_reader.h
new file mode 100644
index 0000000..4abba8f
--- /dev/null
+++ b/board/ge/common/vpd_reader.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2016 General Electric Company
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include "common.h"
+
+/*
+ * Read VPD from given data, verify content, and call callback
+ * for each vital product data block.
+ *
+ * Returns Non-zero on error.  Negative numbers encode errno.
+ */
+int vpd_reader(size_t size, u8 *data, void *userdata,
+	       int (*fn)(void *userdata, u8 id, u8 version, u8 type,
+			 size_t size, u8 const *data));
-- 
2.1.4



More information about the U-Boot mailing list