diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Kconfig | 4 | ||||
-rw-r--r-- | common/globalvar.c | 12 | ||||
-rw-r--r-- | common/imx-bbu-nand-fcb.c | 145 | ||||
-rw-r--r-- | common/state/backend_bucket_circular.c | 6 | ||||
-rw-r--r-- | common/state/backend_format_dtb.c | 2 | ||||
-rw-r--r-- | common/state/backend_format_raw.c | 10 | ||||
-rw-r--r-- | common/state/backend_storage.c | 6 | ||||
-rw-r--r-- | common/state/state.c | 1 |
8 files changed, 172 insertions, 14 deletions
diff --git a/common/Kconfig b/common/Kconfig index 8e40e8435c..62733e1dc4 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -101,6 +101,7 @@ config BAREBOX_UPDATE_IMX_NAND_FCB depends on BAREBOX_UPDATE depends on MTD_WRITE depends on NAND_MXS + select BCH if ARCH_IMX6 default y config UBIFORMAT @@ -643,6 +644,9 @@ config BOOTM_FORCE_SIGNED_IMAGES config BLSPEC depends on BLOCK depends on FLEXIBLE_BOOTARGS + depends on !SHELL_NONE + select BOOT + select BOOTM select OFTREE bool prompt "Support bootloader spec" diff --git a/common/globalvar.c b/common/globalvar.c index 32ca6a24db..1ecf5134af 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -99,6 +99,9 @@ void dev_param_init_from_nv(struct device_d *dev, const char *name) const char *val; int ret = 0; + if (!IS_ENABLED(CONFIG_NVVAR)) + return; + if (dev == &nv_device) return; if (dev == &global_device) @@ -395,6 +398,9 @@ static void globalvar_nv_sync(const char *name) { const char *val; + if (!IS_ENABLED(CONFIG_NVVAR)) + return; + val = dev_get_param(&nv_device, name); if (val) dev_set_param(&global_device, name, val); @@ -542,6 +548,8 @@ int nvvar_save(void) const char *env = default_environment_path_get(); int ret; #define TMPDIR "/.env.tmp" + if (!IS_ENABLED(CONFIG_NVVAR)) + return -ENOSYS; if (!nv_dirty || !env) return 0; @@ -602,7 +610,9 @@ static int nv_global_param_complete(struct device_d *dev, struct string_list *sl int nv_global_complete(struct string_list *sl, char *instr) { nv_global_param_complete(&global_device, sl, instr, 0); - nv_global_param_complete(&nv_device, sl, instr, 0); + + if (IS_ENABLED(CONFIG_NVVAR)) + nv_global_param_complete(&nv_device, sl, instr, 0); return 0; } diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c index 34a5f83230..5d3d3f7e93 100644 --- a/common/imx-bbu-nand-fcb.c +++ b/common/imx-bbu-nand-fcb.c @@ -33,9 +33,12 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/stat.h> +#include <linux/bch.h> +#include <linux/bitops.h> #include <io.h> #include <crc.h> #include <mach/generic.h> +#include <mach/imx6.h> #include <mtd/mtd-peb.h> struct dbbt_block { @@ -129,6 +132,132 @@ static uint8_t calculate_parity_13_8(uint8_t d) return p; } +static uint8_t reverse_bit(uint8_t b) +{ + b = (b & 0xf0) >> 4 | (b & 0x0f) << 4; + b = (b & 0xcc) >> 2 | (b & 0x33) << 2; + b = (b & 0xaa) >> 1 | (b & 0x55) << 1; + + return b; +} + +static void encode_bch_ecc(void *buf, struct fcb_block *fcb, int eccbits) +{ + int i, j, m = 13; + int blocksize = 128; + int numblocks = 8; + int ecc_buf_size = (m * eccbits + 7) / 8; + struct bch_control *bch = init_bch(m, eccbits, 0); + uint8_t *ecc_buf = xmalloc(ecc_buf_size); + uint8_t *tmp_buf = xzalloc(blocksize * numblocks); + uint8_t *psrc, *pdst; + + /* + * The blocks here are bit aligned. If eccbits is a multiple of 8, + * we just can copy bytes. Otherwiese we must move the blocks to + * the next free bit position. + */ + BUG_ON(eccbits % 8); + + memcpy(tmp_buf, fcb, sizeof(*fcb)); + + for (i = 0; i < numblocks; i++) { + memset(ecc_buf, 0, ecc_buf_size); + psrc = tmp_buf + i * blocksize; + pdst = buf + i * (blocksize + ecc_buf_size); + + /* copy data byte aligned to destination buf */ + memcpy(pdst, psrc, blocksize); + + /* + * imx-kobs use a modified encode_bch which reverse the + * bit order of the data before calculating bch. + * Do this in the buffer and use the bch lib here. + */ + for (j = 0; j < blocksize; j++) + psrc[j] = reverse_bit(psrc[j]); + + encode_bch(bch, psrc, blocksize, ecc_buf); + + /* reverse ecc bit */ + for (j = 0; j < ecc_buf_size; j++) + ecc_buf[j] = reverse_bit(ecc_buf[j]); + + /* Here eccbuf is byte aligned and we can just copy it */ + memcpy(pdst + blocksize, ecc_buf, ecc_buf_size); + } + + free(ecc_buf); + free(tmp_buf); + free_bch(bch); +} + +struct fcb_block *read_fcb_bch(void *rawpage, int eccbits) +{ + int i, j, ret, errbit, m = 13; + int blocksize = 128; + int numblocks = 8; + int ecc_buf_size = (m * eccbits + 7) / 8; + struct bch_control *bch = init_bch(m, eccbits, 0); + uint8_t *fcb = xmalloc(numblocks * blocksize); + uint8_t *ecc_buf = xmalloc(ecc_buf_size); + uint8_t *data_buf = xmalloc(blocksize); + unsigned int *errloc = xmalloc(eccbits * sizeof(*errloc)); + uint8_t *psrc, *pdst; + + /* see encode_bch_ecc */ + BUG_ON(eccbits % 8); + + for (i = 0; i < numblocks; i++) { + psrc = rawpage + 32 + i * (blocksize + ecc_buf_size); + pdst = fcb + i * blocksize; + + /* reverse data bit */ + for (j = 0; j < blocksize; j++) + data_buf[j] = reverse_bit(psrc[j]); + + /* reverse ecc bit */ + for (j = 0; j < ecc_buf_size; j++) + ecc_buf[j] = reverse_bit(psrc[j + blocksize]); + + ret = decode_bch(bch, data_buf, blocksize, ecc_buf, + NULL, NULL, errloc); + + if (ret < 0) { + pr_err("Uncorrectable error at block %d\n", i); + free(fcb); + fcb = ERR_PTR(ret); + goto out; + } + if (ret > 0) + pr_info("Found %d correctable errors in block %d\n", + ret, i); + + for (j = 0; j < ret; j++) { + /* + * calculate the reverse position + * pos - (pos % 8) -> byte offset + * 7 - (pos % 8) -> reverse bit position + */ + errbit = errloc[j] - 2 * (errloc[j] % 8) + 7; + pr_debug("Found error: bit %d in block %d\n", + errbit, i); + if (errbit < blocksize * 8) + change_bit(errbit, psrc); + /* else error in ecc, ignore it */ + } + memcpy(pdst, psrc, blocksize); + } + +out: + free(data_buf); + free(ecc_buf); + free(errloc); + free_bch(bch); + + return (struct fcb_block *)fcb; +} + static void encode_hamming_13_8(void *_src, void *_ecc, size_t size) { int i; @@ -312,7 +441,11 @@ static int read_fcb(struct mtd_info *mtd, int num, struct fcb_block **retfcb) goto err; } - fcb = read_fcb_hamming_13_8(rawpage); + if (cpu_is_mx6ul()) + fcb = read_fcb_bch(rawpage, 40); + else + fcb = read_fcb_hamming_13_8(rawpage); + if (IS_ERR(fcb)) { pr_err("Cannot read fcb\n"); ret = PTR_ERR(fcb); @@ -766,8 +899,14 @@ static int imx_bbu_write_fcbs_dbbts(struct mtd_info *mtd, struct fcb_block *fcb) fcb_raw_page = xzalloc(mtd->writesize + mtd->oobsize); - memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block)); - encode_hamming_13_8(fcb_raw_page + 12, fcb_raw_page + 12 + 512, 512); + if (cpu_is_mx6ul()) { + /* 40 bit BCH, for i.MX6UL */ + encode_bch_ecc(fcb_raw_page + 32, fcb, 40); + } else { + memcpy(fcb_raw_page + 12, fcb, sizeof(struct fcb_block)); + encode_hamming_13_8(fcb_raw_page + 12, + fcb_raw_page + 12 + 512, 512); + } dbbt = dbbt_data_create(mtd); diff --git a/common/state/backend_bucket_circular.c b/common/state/backend_bucket_circular.c index 5279ec9ce2..832f44e599 100644 --- a/common/state/backend_bucket_circular.c +++ b/common/state/backend_bucket_circular.c @@ -385,7 +385,7 @@ static int state_backend_bucket_circular_init( ret = state_mtd_peb_read(circ, buf, 0, circ->max_size); if (ret && ret != -EUCLEAN) - return ret; + goto out; for (sub_offset = circ->max_size - circ->writesize; sub_offset >= 0; sub_offset -= circ->writesize) { @@ -408,9 +408,11 @@ static int state_backend_bucket_circular_init( circ->write_area = sub_offset + circ->writesize; circ->last_written_length = written_length; + ret = 0; +out: free(buf); - return 0; + return ret; } static void state_backend_bucket_circular_free(struct diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c index 55fa1fc597..e88cda499b 100644 --- a/common/state/backend_format_dtb.c +++ b/common/state/backend_format_dtb.c @@ -120,8 +120,6 @@ static int state_backend_format_dtb_pack(struct state_backend_format *format, of_delete_node(fdtb->root); fdtb->root = root; - free(fdt); - return 0; } diff --git a/common/state/backend_format_raw.c b/common/state/backend_format_raw.c index 232856a209..d76718cf82 100644 --- a/common/state/backend_format_raw.c +++ b/common/state/backend_format_raw.c @@ -211,6 +211,12 @@ static int backend_format_raw_pack(struct state_backend_format *format, unsigned int size_data; int ret; + if (backend_raw->algo) { + ret = backend_raw_digest_init(backend_raw); + if (ret) + return ret; + } + sv = list_last_entry(&state->variables, struct state_variable, list); size_data = sv->start + sv->size; size_full = size_data + sizeof(*header) + backend_raw->digest_length; @@ -233,10 +239,6 @@ static int backend_format_raw_pack(struct state_backend_format *format, sizeof(*header) - sizeof(uint32_t)); if (backend_raw->algo) { - ret = backend_raw_digest_init(backend_raw); - if (ret) - return ret; - /* hmac over header and data */ ret = digest_update(backend_raw->digest, buf, sizeof(*header) + size_data); if (ret) { diff --git a/common/state/backend_storage.c b/common/state/backend_storage.c index 9ed6ad79ac..8d24f7053d 100644 --- a/common/state/backend_storage.c +++ b/common/state/backend_storage.c @@ -110,12 +110,14 @@ static int bucket_refresh(struct state_backend_storage *storage, refresh: ret = bucket->write(bucket, buf, len); - if (ret) + if (ret) { dev_warn(storage->dev, "Failed to restore bucket %d@0x%08lx\n", bucket->num, bucket->offset); - else + } else { dev_info(storage->dev, "restored bucket %d@0x%08lx\n", bucket->num, bucket->offset); + bucket->needs_refresh = 0; + } return ret; } diff --git a/common/state/state.c b/common/state/state.c index 8369aedac6..6db77f2c18 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -577,6 +577,7 @@ struct state *state_new_from_node(struct device_node *node, char *path, partition_node = of_parse_phandle(node, "backend", 0); if (!partition_node) { dev_err(&state->dev, "Cannot resolve \"backend\" phandle\n"); + ret = -EINVAL; goto out_release_state; } |