[U-Boot] [PATCHv3 3/4] spl: Lightweight UBI and UBI fastmap support
Heiko Schocher
hs at denx.de
Mon Jan 11 07:14:14 CET 2016
Hello Ladislav,
Am 11.01.2016 um 00:17 schrieb Ladislav Michl:
> From: Thomas Gleixner <tglx at linutronix.de>
>
> Booting a payload out of NAND FLASH from the SPL is a crux today, as
> it requires hard partioned FLASH. Not a brilliant idea with the
> reliability of todays NAND FLASH chips.
>
> The upstream UBI + UBI fastmap implementation which is about to
> brought to u-boot is too heavy weight for SPLs as it provides way more
> functionality than needed for a SPL and does not even fit into the
> restricted SPL areas which are loaded from the SoC boot ROM.
>
> So this provides a fast and lightweight implementation of UBI scanning
> and UBI fastmap attach. The scan and logical to physical block mapping
> code is developed from scratch, while the fastmap implementation is
> lifted from the linux kernel source and stripped down to fit the SPL
> needs.
>
> The text foot print on the board which I used for development is:
>
> 6854 0 0 6854 1abd
> drivers/mtd/ubispl/built-in.o
>
> Attaching a NAND chip with 4096 physical eraseblocks (4 blocks are
> reserved for the SPL) takes:
>
> In full scan mode: 1172ms
> In fastmap mode: 95ms
>
> The code requires quite some storage. The largest and unknown part of
> it is the number of fastmap blocks to read. Therefor the data
> structure is not put into the BSS. The code requires a pointer to free
> memory handed in which is initialized by the UBI attach code itself.
>
> See doc/README.ubispl for further information on how to use it.
>
> This shares the ubi-media.h and crc32 implementation of drivers/mtd/ubi
> There is no way to share the fastmap code, as UBISPL only utilizes the
> slightly modified functions ubi_attach_fastmap() and ubi_scan_fastmap()
> from the original kernel ubi fastmap implementation.
>
> Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
> Signed-off-by: Ladislav Michl <ladis at linux-mips.org>
> ---
>
> Changes in v2:
> - fixes ubi_calc_fm_size to include also sizeof(struct ubi_fm_sb)
> - dropped private copy of ubi-media.h
> - ubi-wrapper.h now contains only needed definitions from ubi.h
> and ubi-user.h
> - used return values from errno.h
>
> Changes in v3:
> - move vol_id check to ubi_scan_vid_hdr to verify it has meaningfull value
> before testing ubi->toload
> - fixed checkpatch errors except those present also in linux code
Thanks! Patch applies now ;-)
>
> README | 4 +
> doc/README.ubispl | 143 ++++++
> drivers/Makefile | 1 +
> drivers/mtd/ubispl/Makefile | 1 +
> drivers/mtd/ubispl/ubi-wrapper.h | 106 +++++
> drivers/mtd/ubispl/ubispl.c | 926 +++++++++++++++++++++++++++++++++++++++
> drivers/mtd/ubispl/ubispl.h | 136 ++++++
> include/ubispl.h | 92 ++++
> 8 files changed, 1409 insertions(+)
> create mode 100644 doc/README.ubispl
> create mode 100644 drivers/mtd/ubispl/Makefile
> create mode 100644 drivers/mtd/ubispl/ubi-wrapper.h
> create mode 100644 drivers/mtd/ubispl/ubispl.c
> create mode 100644 drivers/mtd/ubispl/ubispl.h
> create mode 100644 include/ubispl.h
Only 2 nitpicks
[...]
> diff --git a/drivers/mtd/ubispl/ubispl.c b/drivers/mtd/ubispl/ubispl.c
> new file mode 100644
> index 0000000..e2d5aff
> --- /dev/null
> +++ b/drivers/mtd/ubispl/ubispl.c
> @@ -0,0 +1,926 @@
[...]
> +static int ubi_attach_fastmap(struct ubi_scan_info *ubi,
> + struct ubi_attach_info *ai,
> + struct ubi_fastmap_layout *fm)
> +{
> + struct ubi_fm_hdr *fmhdr;
> + struct ubi_fm_scan_pool *fmpl1, *fmpl2;
> + struct ubi_fm_ec *fmec;
> + struct ubi_fm_volhdr *fmvhdr;
> + struct ubi_fm_eba *fm_eba;
> + int ret, i, j, pool_size, wl_pool_size;
> + size_t fm_pos = 0, fm_size = ubi->fm_size;
> + void *fm_raw = ubi->fm_buf;
> +
> + memset(ubi->fm_used, 0, sizeof(ubi->fm_used));
> +
> + fm_pos += sizeof(struct ubi_fm_sb);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> +
> + fmhdr = (struct ubi_fm_hdr *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmhdr);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> +
> + if (be32_to_cpu(fmhdr->magic) != UBI_FM_HDR_MAGIC) {
> + ubi_err("bad fastmap header magic: 0x%x, expected: 0x%x",
> + be32_to_cpu(fmhdr->magic), UBI_FM_HDR_MAGIC);
> + goto fail_bad;
> + }
> +
> + fmpl1 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmpl1);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> + if (be32_to_cpu(fmpl1->magic) != UBI_FM_POOL_MAGIC) {
> + ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x",
> + be32_to_cpu(fmpl1->magic), UBI_FM_POOL_MAGIC);
> + goto fail_bad;
> + }
> +
> + fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmpl2);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> + if (be32_to_cpu(fmpl2->magic) != UBI_FM_POOL_MAGIC) {
> + ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x",
> + be32_to_cpu(fmpl2->magic), UBI_FM_POOL_MAGIC);
> + goto fail_bad;
> + }
> +
> + pool_size = be16_to_cpu(fmpl1->size);
> + wl_pool_size = be16_to_cpu(fmpl2->size);
> + fm->max_pool_size = be16_to_cpu(fmpl1->max_size);
> + fm->max_wl_pool_size = be16_to_cpu(fmpl2->max_size);
> +
> + if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) {
> + ubi_err("bad pool size: %i", pool_size);
> + goto fail_bad;
> + }
> +
> + if (wl_pool_size > UBI_FM_MAX_POOL_SIZE || wl_pool_size < 0) {
> + ubi_err("bad WL pool size: %i", wl_pool_size);
> + goto fail_bad;
> + }
> +
> + if (fm->max_pool_size > UBI_FM_MAX_POOL_SIZE ||
> + fm->max_pool_size < 0) {
> + ubi_err("bad maximal pool size: %i", fm->max_pool_size);
> + goto fail_bad;
> + }
> +
> + if (fm->max_wl_pool_size > UBI_FM_MAX_POOL_SIZE ||
> + fm->max_wl_pool_size < 0) {
> + ubi_err("bad maximal WL pool size: %i", fm->max_wl_pool_size);
> + goto fail_bad;
> + }
> +
> + /* read EC values from free list */
> + for (i = 0; i < be32_to_cpu(fmhdr->free_peb_count); i++) {
> + fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmec);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> + }
> +
> + /* read EC values from used list */
> + for (i = 0; i < be32_to_cpu(fmhdr->used_peb_count); i++) {
> + fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmec);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> +
> + generic_set_bit(be32_to_cpu(fmec->pnum), ubi->fm_used);
> + }
> +
> + /* read EC values from scrub list */
> + for (i = 0; i < be32_to_cpu(fmhdr->scrub_peb_count); i++) {
> + fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmec);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> + }
> +
> + /* read EC values from erase list */
> + for (i = 0; i < be32_to_cpu(fmhdr->erase_peb_count); i++) {
> + fmec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmec);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> + }
> +
> + /* Iterate over all volumes and read their EBA table */
> + for (i = 0; i < be32_to_cpu(fmhdr->vol_count); i++) {
> + u32 vol_id, vol_type, used, reserved;
> +
> + fmvhdr = (struct ubi_fm_volhdr *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fmvhdr);
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> +
> + if (be32_to_cpu(fmvhdr->magic) != UBI_FM_VHDR_MAGIC) {
> + ubi_err("bad fastmap vol header magic: 0x%x, " \
> + "expected: 0x%x",
> + be32_to_cpu(fmvhdr->magic), UBI_FM_VHDR_MAGIC);
> + goto fail_bad;
> + }
> +
> + vol_id = be32_to_cpu(fmvhdr->vol_id);
> + vol_type = fmvhdr->vol_type;
> + used = be32_to_cpu(fmvhdr->used_ebs);
> +
> + fm_eba = (struct ubi_fm_eba *)(fm_raw + fm_pos);
> + fm_pos += sizeof(*fm_eba);
> + fm_pos += (sizeof(__be32) * be32_to_cpu(fm_eba->reserved_pebs));
> + if (fm_pos >= fm_size)
> + goto fail_bad;
> +
> + if (be32_to_cpu(fm_eba->magic) != UBI_FM_EBA_MAGIC) {
> + ubi_err("bad fastmap EBA header magic: 0x%x, " \
> + "expected: 0x%x",
> + be32_to_cpu(fm_eba->magic), UBI_FM_EBA_MAGIC);
> + goto fail_bad;
> + }
> +
> + reserved = be32_to_cpu(fm_eba->reserved_pebs);
> + ubi_dbg("FA: vol %u used %u res: %u", vol_id, used, reserved);
> + for (j = 0; j < reserved; j++) {
> + int pnum = be32_to_cpu(fm_eba->pnum[j]);
> +
> + if ((int)be32_to_cpu(fm_eba->pnum[j]) < 0)
> + continue;
> +
> + if (!__test_and_clear_bit(pnum, ubi->fm_used))
> + continue;
> +
> + /*
> + * We only handle static volumes so used_ebs
> + * needs to be handed in. And we do not assign
> + * the reserved blocks
> + */
> + if (j >= used)
> + continue;
> +
> + ret = assign_aeb_to_av(ubi, pnum, j, vol_id,
> + vol_type, used);
> + if (!ret)
> + continue;
> +
> + /*
> + * Nasty: The fastmap claims that the volume
> + * has one block more than it, but that block
> + * is always empty and the other blocks have
> + * the correct number of total LEBs in the
> + * headers. Deal with it.
> + */
> + if (ret != UBI_IO_FF && j != used - 1)
> + goto fail_bad;
> + ubi_dbg("FA: Vol: %u Ignoring empty LEB %d of %d",
> + vol_id, j, used);
> + }
> + }
> +
> + ret = scan_pool(ubi, fmpl1->pebs, pool_size);
> + if (ret)
> + goto fail;
> +
> + ret = scan_pool(ubi, fmpl2->pebs, wl_pool_size);
> + if (ret)
> + goto fail;
> +
> +#ifdef CHECKME
What means this?
> + /*
> + * If fastmap is leaking PEBs (must not happen), raise a
> + * fat warning and fall back to scanning mode.
> + * We do this here because in ubi_wl_init() it's too late
> + * and we cannot fall back to scanning.
> + */
> + if (WARN_ON(count_fastmap_pebs(ai) != ubi->peb_count -
> + ai->bad_peb_count - fm->used_blocks))
> + goto fail_bad;
> +#endif
> +
> + return 0;
> +
> +fail_bad:
> + ret = UBI_BAD_FASTMAP;
> +fail:
> + return ret;
> +}
> +
> +static int ubi_scan_fastmap(struct ubi_scan_info *ubi,
> + struct ubi_attach_info *ai,
> + int fm_anchor)
> +{
> + struct ubi_fm_sb *fmsb, *fmsb2;
> + struct ubi_vid_hdr *vh;
> + struct ubi_fastmap_layout *fm;
> + int i, used_blocks, pnum, ret = 0;
> + size_t fm_size;
> + __be32 crc, tmp_crc;
> + unsigned long long sqnum = 0;
> +
> + fmsb = &ubi->fm_sb;
> + fm = &ubi->fm_layout;
> +
> + ret = ubi_io_read(ubi, fmsb, fm_anchor, ubi->leb_start, sizeof(*fmsb));
> + if (ret && ret != UBI_IO_BITFLIPS)
> + goto free_fm_sb;
> + else if (ret == UBI_IO_BITFLIPS)
> + fm->to_be_tortured[0] = 1;
> +
> + if (be32_to_cpu(fmsb->magic) != UBI_FM_SB_MAGIC) {
> + ubi_err("bad super block magic: 0x%x, expected: 0x%x",
> + be32_to_cpu(fmsb->magic), UBI_FM_SB_MAGIC);
> + ret = UBI_BAD_FASTMAP;
> + goto free_fm_sb;
> + }
> +
> + if (fmsb->version != UBI_FM_FMT_VERSION) {
> + ubi_err("bad fastmap version: %i, expected: %i",
> + fmsb->version, UBI_FM_FMT_VERSION);
> + ret = UBI_BAD_FASTMAP;
> + goto free_fm_sb;
> + }
> +
> + used_blocks = be32_to_cpu(fmsb->used_blocks);
> + if (used_blocks > UBI_FM_MAX_BLOCKS || used_blocks < 1) {
> + ubi_err("number of fastmap blocks is invalid: %i", used_blocks);
> + ret = UBI_BAD_FASTMAP;
> + goto free_fm_sb;
> + }
> +
> + fm_size = ubi->leb_size * used_blocks;
> + if (fm_size != ubi->fm_size) {
> + ubi_err("bad fastmap size: %zi, expected: %zi", fm_size,
> + ubi->fm_size);
> + ret = UBI_BAD_FASTMAP;
> + goto free_fm_sb;
> + }
> +
> + vh = &ubi->fm_vh;
> +
> + for (i = 0; i < used_blocks; i++) {
> + pnum = be32_to_cpu(fmsb->block_loc[i]);
> +
> + if (ubi_io_is_bad(ubi, pnum)) {
> + ret = UBI_BAD_FASTMAP;
> + goto free_hdr;
> + }
> +
> +#ifdef LATER
Here to ... what means this?
> + int image_seq;
> + ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
> + if (ret && ret != UBI_IO_BITFLIPS) {
> + ubi_err("unable to read fastmap block# %i EC (PEB: %i)",
> + i, pnum);
> + if (ret > 0)
> + ret = UBI_BAD_FASTMAP;
> + goto free_hdr;
> + } else if (ret == UBI_IO_BITFLIPS)
> + fm->to_be_tortured[i] = 1;
> +
> + image_seq = be32_to_cpu(ech->image_seq);
> + if (!ubi->image_seq)
> + ubi->image_seq = image_seq;
> + /*
> + * Older UBI implementations have image_seq set to zero, so
> + * we shouldn't fail if image_seq == 0.
> + */
> + if (image_seq && (image_seq != ubi->image_seq)) {
> + ubi_err("wrong image seq:%d instead of %d",
> + be32_to_cpu(ech->image_seq), ubi->image_seq);
> + ret = UBI_BAD_FASTMAP;
> + goto free_hdr;
> + }
> +#endif
Beside of this:
Acked-by: Heiko Schocher <hs at denx.de>
bye,
Heiko
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
More information about the U-Boot
mailing list