1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2016 General Electric Company
6 #include "vpd_reader.h"
12 /* BCH configuration */
15 int header_ecc_capability_bits;
16 int data_ecc_capability_bits;
17 unsigned int prim_poly;
22 } bch_configuration = {
23 .header_ecc_capability_bits = 4,
24 .data_ecc_capability_bits = 16,
26 .galois_field_order = {
32 static int calculate_galois_field_order(size_t source_length)
34 int gfo = bch_configuration.galois_field_order.min;
36 for (; gfo < bch_configuration.galois_field_order.max &&
37 ((((1 << gfo) - 1) - ((int)source_length * 8)) < 0);
41 if (gfo == bch_configuration.galois_field_order.max)
47 static int verify_bch(int ecc_bits, unsigned int prim_poly, u8 *data,
48 size_t data_length, const u8 *ecc, size_t ecc_length)
50 int gfo = calculate_galois_field_order(data_length);
55 struct bch_control *bch = init_bch(gfo, ecc_bits, prim_poly);
60 if (bch->ecc_bytes != ecc_length) {
65 unsigned int *errloc = (unsigned int *)calloc(data_length,
66 sizeof(unsigned int));
67 int errors = decode_bch(bch, data, data_length, ecc, NULL, NULL,
77 for (int n = 0; n < errors; n++) {
78 if (errloc[n] >= 8 * data_length) {
80 * n-th error located in ecc (no need for data
84 /* n-th error located in data */
85 data[errloc[n] / 8] ^= 1 << (errloc[n] % 8);
95 static const int LEN = 1;
96 static const int VER = 2;
97 static const int TYP = 3;
98 static const int BLOCK_SIZE = 4;
100 static const u8 HEADER_BLOCK_ID;
101 static const u8 HEADER_BLOCK_LEN = 18;
102 static const u32 HEADER_BLOCK_MAGIC = 0xca53ca53;
103 static const size_t HEADER_BLOCK_VERIFY_LEN = 14;
104 static const size_t HEADER_BLOCK_ECC_OFF = 14;
105 static const size_t HEADER_BLOCK_ECC_LEN = 4;
107 static const u8 ECC_BLOCK_ID = 0xFF;
109 static int vpd_reader(size_t size, u8 *data, struct vpd_cache *userdata,
110 int (*fn)(struct vpd_cache *, u8 id, u8 version, u8 type,
111 size_t size, u8 const *data))
113 if (size < HEADER_BLOCK_LEN || !data || !fn)
117 * +--------------------+----------------+--//--+--------------------+
118 * | header block | data block | ... | ecc block |
119 * +--------------------+----------------+--//--+--------------------+
121 * +------+-------+-----+ +------+-------------+
122 * | id | magic | ecc | | ... | ecc |
123 * | len | off | | +------+-------------+
126 * +------+-------+-----+ :
128 * <----- [1] ----> <--------- [2] --------->
130 * Repair (if necessary) the contents of header block [1] by using a
131 * 4 byte ECC located at the end of the header block. A successful
132 * return value means that we can trust the header.
134 int ret = verify_bch(bch_configuration.header_ecc_capability_bits,
135 bch_configuration.prim_poly, data,
136 HEADER_BLOCK_VERIFY_LEN,
137 &data[HEADER_BLOCK_ECC_OFF], HEADER_BLOCK_ECC_LEN);
141 /* Validate header block { id, length, version, type }. */
142 if (data[ID] != HEADER_BLOCK_ID || data[LEN] != HEADER_BLOCK_LEN ||
143 data[VER] != 0 || data[TYP] != 0 ||
144 ntohl(*(u32 *)(&data[4])) != HEADER_BLOCK_MAGIC)
147 u32 offset = ntohl(*(u32 *)(&data[8]));
148 u16 size_bits = ntohs(*(u16 *)(&data[12]));
150 /* Check that ECC header fits. */
151 if (offset + 3 >= size)
154 /* Validate ECC block. */
155 u8 *ecc = &data[offset];
157 if (ecc[ID] != ECC_BLOCK_ID || ecc[LEN] < BLOCK_SIZE ||
158 ecc[LEN] + offset > size ||
159 ecc[LEN] - BLOCK_SIZE != size_bits / 8 || ecc[VER] != 1 ||
164 * Use the header block to locate the ECC block and verify the data
165 * blocks [2] against the ecc block ECC.
167 ret = verify_bch(bch_configuration.data_ecc_capability_bits,
168 bch_configuration.prim_poly, &data[data[LEN]],
169 offset - data[LEN], &data[offset + BLOCK_SIZE],
170 ecc[LEN] - BLOCK_SIZE);
174 /* Stop after ECC. Ignore possible zero padding. */
178 /* Move to next block. */
183 /* Finished iterating through blocks. */
187 if (size < BLOCK_SIZE || data[LEN] < BLOCK_SIZE) {
188 /* Not enough data for a header, or short header. */
192 ret = fn(userdata, data[ID], data[VER], data[TYP],
193 data[LEN] - BLOCK_SIZE, &data[BLOCK_SIZE]);
199 int read_vpd(struct vpd_cache *cache,
200 int (*process_block)(struct vpd_cache *, u8 id, u8 version,
201 u8 type, size_t size, u8 const *data))
203 static const size_t size = CONFIG_SYS_VPD_EEPROM_SIZE;
207 unsigned int current_i2c_bus = i2c_get_bus_num();
209 res = i2c_set_bus_num(CONFIG_SYS_VPD_EEPROM_I2C_BUS);
217 res = i2c_read(CONFIG_SYS_VPD_EEPROM_I2C_ADDR, 0,
218 CONFIG_SYS_VPD_EEPROM_I2C_ADDR_LEN,
221 res = vpd_reader(size, data, cache, process_block);
225 i2c_set_bus_num(current_i2c_bus);