summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig4
-rw-r--r--common/globalvar.c12
-rw-r--r--common/imx-bbu-nand-fcb.c145
-rw-r--r--common/state/backend_bucket_circular.c6
-rw-r--r--common/state/backend_format_dtb.c2
-rw-r--r--common/state/backend_format_raw.c10
-rw-r--r--common/state/backend_storage.c6
-rw-r--r--common/state/state.c1
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;
}