On 08/11/2017 16:35, Martyn Welch wrote:
> 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.we...@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));
> 

Acked-by: Stefano Babic <sba...@denx.de>

Best regards,
Stefano Babic

-- 
=====================================================================
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sba...@denx.de
=====================================================================
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to