summaryrefslogtreecommitdiff
path: root/board/ge/bx50v3
diff options
context:
space:
mode:
authorMartyn Welch <martyn.welch@collabora.co.uk>2017-11-08 15:35:15 +0000
committerStefano Babic <sbabic@denx.de>2017-11-20 09:58:31 +0100
commitb418dfe16e62ffb6062e2acc5471821c011bc9cd (patch)
tree720e0579341bfc63a31843f46b2143e713f2288d /board/ge/bx50v3
parentda5337a61cd41f3bfbaee5b78ba58676bd288073 (diff)
downloadu-boot-b418dfe16e62ffb6062e2acc5471821c011bc9cd.tar.gz
board: ge: make VPD code common
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@collabora.co.uk> Acked-by: Stefano Babic <sbabic@denx.de>
Diffstat (limited to 'board/ge/bx50v3')
-rw-r--r--board/ge/bx50v3/Makefile2
-rw-r--r--board/ge/bx50v3/bx50v3.c2
-rw-r--r--board/ge/bx50v3/vpd_reader.c228
-rw-r--r--board/ge/bx50v3/vpd_reader.h25
4 files changed, 2 insertions, 255 deletions
diff --git a/board/ge/bx50v3/Makefile b/board/ge/bx50v3/Makefile
index 2fff27bc77..bcd149f5b0 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 2e8f394eaf..37de990176 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 98da893d2c..0000000000
--- 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 efa172a915..0000000000
--- 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));