[U-Boot] [PATCH] SPL: Lightweight UBI and UBI fastmap support
Ladislav Michl
ladis at linux-mips.org
Mon Jan 4 16:12:49 CET 2016
On Mon, Jan 04, 2016 at 10:30:03AM +0100, Heiko Schocher wrote:
> Am 30.12.2015 um 03:12 schrieb Ladislav Michl:
> >From: Thomas Gleixner <tglx at linutronix.de>
> >
> >This is an update of Thomas's patch:
> >https://patchwork.ozlabs.org/patch/367306/
> >patch still depends on spl_nand_simple implementation:
> >https://patchwork.ozlabs.org/patch/367305/
>
> Huh, in patchwork, this patch is in "deferred" state ...
> Tom?
>
> Maybe you should add it to your patch and make a patchseries.
Will post entire serie.
> >Changes from original version:
> >- fixes ubi_calc_fm_size to include also sizeof(struct ubi_fm_sb)
> >- dropped private copy of ubi-media.h
> >- accomodate for actual Makefile
> >
> >As original patch is more that a year old, should we update to current
> >linux fastmap code?
>
> Yes, please! I did for U-Boot an UBI/UBIFS update to linux 4.2, as
> Richard Weinberger stated, that the old fastmap implementation is
> buggy!
I just checked that, there are two functions involved: ubi_scan_fastmap
and ubi_attach_fastmap where the newer version of the latter is quite
bloated for spl (uses lists), so I'll left it for later. Note that
ubi_calc_fm_size bug is already fixed.
[...]
> No real showstoppers, besides that the patch doubles a lot of
> defines, which are already defined in ubi headers. You should
> try (if it is possible, I didn;t looked deeper into it), if you
> could prevent this.
Removing ubi-wrapper.h and using defines from ubi.h and ubi-user.h
makes things even worse as ubispl.c uses lighter struct ubi_scan_info
instead of struct ubi_device as function parameter. However I synced
defines used where appropriate.
> [...]
> >diff --git a/drivers/Makefile b/drivers/Makefile
> >index c9031f2..e0bcb52 100644
> >--- a/drivers/Makefile
> >+++ b/drivers/Makefile
> >@@ -22,10 +22,11 @@ obj-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += mtd/spi/
> > obj-$(CONFIG_SPL_SPI_SUPPORT) += spi/
> > obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/
> > obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/
> >+obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/
> > obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd/
> > obj-$(CONFIG_SPL_NAND_SUPPORT) += mtd/nand/
> >-obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/
>
> Is this an ubi related change? And please sort alphabetical.
No, it is a result of alphabetical sorting :) What about something
like this applied first?
-- >8 --
Subject: mtd: Sort subsystem directories aplhabeticaly in Makefile
Signed-off-by: Ladislav Michl <ladis at linux-mips.org>
diff --git a/drivers/Makefile b/drivers/Makefile
index c9031f2..9c5c6c0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -18,14 +18,14 @@ obj-$(CONFIG_SYS_MVEBU_DDR_A38X) += ddr/marvell/a38x/
obj-$(CONFIG_SYS_MVEBU_DDR_AXP) += ddr/marvell/axp/
obj-$(CONFIG_ALTERA_SDRAM) += ddr/altera/
obj-$(CONFIG_SPL_SERIAL_SUPPORT) += serial/
-obj-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += mtd/spi/
obj-$(CONFIG_SPL_SPI_SUPPORT) += spi/
obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/
obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/
+obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/
obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd/
obj-$(CONFIG_SPL_NAND_SUPPORT) += mtd/nand/
-obj-$(CONFIG_SPL_DRIVERS_MISC_SUPPORT) += misc/
obj-$(CONFIG_SPL_ONENAND_SUPPORT) += mtd/onenand/
+obj-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += mtd/spi/
obj-$(CONFIG_SPL_DMA_SUPPORT) += dma/
obj-$(CONFIG_SPL_ETH_SUPPORT) += net/
obj-$(CONFIG_SPL_ETH_SUPPORT) += net/phy/
> > obj-$(CONFIG_SPL_ONENAND_SUPPORT) += mtd/onenand/
> >+obj-$(CONFIG_SPL_UBI) += mtd/ubispl/
> > obj-$(CONFIG_SPL_DMA_SUPPORT) += dma/
> > obj-$(CONFIG_SPL_ETH_SUPPORT) += net/
> > obj-$(CONFIG_SPL_ETH_SUPPORT) += net/phy/
> >diff --git a/drivers/mtd/ubispl/Makefile b/drivers/mtd/ubispl/Makefile
> >new file mode 100644
> >index 0000000..740dbed
> >--- /dev/null
> >+++ b/drivers/mtd/ubispl/Makefile
> >@@ -0,0 +1 @@
> >+obj-y += ubispl.o ../ubi/crc32.o
> >diff --git a/drivers/mtd/ubispl/ubi-wrapper.h b/drivers/mtd/ubispl/ubi-wrapper.h
> >new file mode 100644
> >index 0000000..dd76e6b
> >--- /dev/null
> >+++ b/drivers/mtd/ubispl/ubi-wrapper.h
> >@@ -0,0 +1,104 @@
> >+/*
> >+ * The parts taken from the kernel implementation are:
> >+ *
> >+ * Copyright (c) International Business Machines Corp., 2006
> >+ *
> >+ * UBISPL specific wrappers and defines:
> >+ *
> >+ * Copyright (c) Thomas Gleixner <tglx at linutronix.de>
> >+ *
> >+ * SPDX-License-Identifier: GPL-2.0+
> >+ */
> >+
> >+/*
> >+ * Contains various defines, wrappers to make the upstream fastboot
> >+ * code happy.
> >+ */
> >+#ifndef __UBOOT_UBI_WRAPPER_H
> >+#define __UBOOT_UBI_WRAPPER_H
> >+
> >+/*
> >+ * Error codes returned by the I/O sub-system.
> >+ *
> >+ * UBI_IO_FF: the read region of flash contains only 0xFFs
> >+ * UBI_IO_FF_BITFLIPS: the same as %UBI_IO_FF, but also also there was a data
> >+ * integrity error reported by the MTD driver
> >+ * (uncorrectable ECC error in case of NAND)
> >+ * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC)
> >+ * UBI_IO_BAD_HDR_EBADMSG: the same as %UBI_IO_BAD_HDR, but also there was a
> >+ * data integrity error reported by the MTD driver
> >+ * (uncorrectable ECC error in case of NAND)
> >+ * UBI_IO_BITFLIPS: bit-flips were detected and corrected
> >+ *
> >+ * UBI_FASTMAP_ANCHOR: u-boot SPL add on to tell the caller that the fastmap
> >+ * anchor block has been found
> >+ *
> >+ * Note, it is probably better to have bit-flip and ebadmsg as flags which can
> >+ * be or'ed with other error code. But this is a big change because there are
> >+ * may callers, so it does not worth the risk of introducing a bug
> >+ */
> >+enum {
> >+ UBI_IO_FF = 1,
> >+ UBI_IO_FF_BITFLIPS,
> >+ UBI_IO_BAD_HDR,
> >+ UBI_IO_BAD_HDR_EBADMSG,
> >+ UBI_IO_BITFLIPS,
> >+ UBI_FASTMAP_ANCHOR,
> >+};
>
> Couldn;t you use the definition from ./drivers/mtd/ubi/ubi.h ?
>
> >+/*
> >+ * UBI volume type constants.
> >+ *
> >+ * @UBI_DYNAMIC_VOLUME: dynamic volume
> >+ * @UBI_STATIC_VOLUME: static volume
> >+ */
> >+enum {
> >+ UBI_DYNAMIC_VOLUME = 3,
> >+ UBI_STATIC_VOLUME = 4,
> >+};
>
> Same here, this is already defined here:
> ./include/mtd/ubi-user.h
Those definitions could be used for a price of some ifdefs in common code.
I consider duplication a better option.
> >+#define UBI_BAD_FASTMAP (-1)
>
> ./drivers/mtd/ubi/ubi.h:
>
> /*
> * Return codes of the fastmap sub-system
> *
> * UBI_NO_FASTMAP: No fastmap super block was found
> * UBI_BAD_FASTMAP: A fastmap was found but it's unusable
> */
> enum {
> UBI_NO_FASTMAP = 1,
> UBI_BAD_FASTMAP,
> };
>
> differ to existing definition... maybe a bad idea?
fixed in next version.
> >+
> >+/*
> >+ * Stub structure so the fastmap code is happy.
> >+ */
> >+struct ubi_attach_info {
> >+ int i;
> >+};
> >+
> >+/**
> >+ * struct ubi_fastmap_layout - in-memory fastmap data structure.
> >+ * @e: PEBs used by the current fastmap
> >+ * @to_be_tortured: if non-zero tortured this PEB
> >+ * @used_blocks: number of used PEBs
> >+ * @max_pool_size: maximal size of the user pool
> >+ * @max_wl_pool_size: maximal size of the pool used by the WL sub-system
> >+ */
> >+struct ubi_fastmap_layout {
> >+ struct ubi_wl_entry *e[UBI_FM_MAX_BLOCKS];
> >+ int to_be_tortured[UBI_FM_MAX_BLOCKS];
> >+ int used_blocks;
> >+ int max_pool_size;
> >+ int max_wl_pool_size;
> >+};
> >+
> >+/**
> >+ * struct ubi_fm_pool - in-memory fastmap pool
> >+ * @pebs: PEBs in this pool
> >+ * @used: number of used PEBs
> >+ * @size: total number of PEBs in this pool
> >+ * @max_size: maximal size of the pool
> >+ *
> >+ * A pool gets filled with up to max_size.
> >+ * If all PEBs within the pool are used a new fastmap will be written
> >+ * to the flash and the pool gets refilled with empty PEBs.
> >+ *
> >+ */
> >+struct ubi_fm_pool {
> >+ int pebs[UBI_FM_MAX_POOL_SIZE];
> >+ int used;
> >+ int size;
> >+ int max_size;
> >+};
> >+
> >+#endif
>
> Do we really need this wrapper file ... At last we need some comments
> in the not spl ubi code, that we double the defines ...
It makes things actually simpler. File modified to contain only copy and
paste defines except UBI_FASTMAP_ANCHOR.
> Do you have some numbers how many bytes the current ubispl implementation
> needs?
text data bss dec hex filename
46989 1368 201084 249441 3ce61 spl
53041 1368 203132 257541 3ee05 spl.ubi
(compared to SPL which is loading kernel from fixed NAND offset)
> >diff --git a/drivers/mtd/ubispl/ubispl.c b/drivers/mtd/ubispl/ubispl.c
> >new file mode 100644
> >index 0000000..9b11bd4
> >--- /dev/null
> >+++ b/drivers/mtd/ubispl/ubispl.c
> >@@ -0,0 +1,921 @@
> >+/*
> >+ * Copyright (c) Thomas Gleixner <tglx at linutronix.de>
> >+ *
> >+ * The parts taken from the kernel implementation are:
> >+ *
> >+ * Copyright (c) International Business Machines Corp., 2006
> >+
> >+ * SPDX-License-Identifier: GPL-2.0+
> >+ */
> >+
> >+#include <common.h>
> >+#include <ubispl.h>
> >+
> >+#include <linux/crc32.h>
> >+
> >+#include "ubispl.h"
> >+
> >+/**
> >+ * ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device.
> >+ * @ubi: UBI device description object
> >+ */
> >+static size_t ubi_calc_fm_size(struct ubi_scan_info *ubi)
> >+{
> >+ size_t size;
> >+
> >+ size = sizeof(struct ubi_fm_sb) +
> >+ sizeof(struct ubi_fm_hdr) +
> >+ sizeof(struct ubi_fm_scan_pool) +
> >+ sizeof(struct ubi_fm_scan_pool) +
> >+ (ubi->peb_count * sizeof(struct ubi_fm_ec)) +
> >+ (sizeof(struct ubi_fm_eba) +
> >+ (ubi->peb_count * sizeof(__be32))) +
> >+ sizeof(struct ubi_fm_volhdr) * UBI_MAX_VOLUMES;
> >+ return roundup(size, ubi->leb_size);
> >+}
> >+
> >+static int ubi_io_read(struct ubi_scan_info *ubi, void *buf, int pnum,
> >+ unsigned long from, unsigned long len)
> >+{
> >+ return ubi->read(pnum + ubi->peb_offset, from, len, buf);
> >+}
> >+
> >+static int ubi_io_is_bad(struct ubi_scan_info *ubi, int peb)
> >+{
> >+ return peb >= ubi->peb_count || peb < 0;
> >+}
> >+
> >+static int ubi_io_read_vid_hdr(struct ubi_scan_info *ubi, int pnum,
> >+ struct ubi_vid_hdr *vh, int unused)
> >+{
> >+ u32 magic;
> >+ int res;
> >+
> >+ /* No point in rescanning a corrupt block */
> >+ if (test_bit(pnum, ubi->corrupt))
> >+ return -1;
>
> Please use defines from errno.h (fix this globally).
fixed.
> >+ /*
> >+ * If the block has been scanned already, no need to rescan
> >+ */
> >+ if (test_and_set_bit(pnum, ubi->scanned))
> >+ return 0;
> >+
> >+ res = ubi_io_read(ubi, vh, pnum, ubi->vid_offset, sizeof(*vh));
> >+
> >+ /*
> >+ * Bad block, unrecoverable ECC error, skip the block
> >+ */
> >+ if (res) {
> >+ ubi_dbg("Skipping bad or unreadable block %d", pnum);
> >+ vh->magic = 0;
> >+ generic_set_bit(pnum, ubi->corrupt);
> >+ return res;
> >+ }
> >+
> >+ /* Magic number available ? */
> >+ magic = be32_to_cpu(vh->magic);
> >+ if ((magic != UBI_VID_HDR_MAGIC)) {
> >+ generic_set_bit(pnum, ubi->corrupt);
> >+ if (magic == 0xffffffff)
> >+ return UBI_IO_FF;
> >+ ubi_msg("Bad magic in block 0%d %08x", pnum, magic);
> >+ return UBI_IO_BAD_HDR;
> >+ }
> >+
> >+ /* Header CRC correct ? */
> >+ if (crc32(UBI_CRC32_INIT, vh, UBI_VID_HDR_SIZE_CRC) !=
> >+ be32_to_cpu(vh->hdr_crc)) {
> >+ ubi_msg("Bad CRC in block 0%d", pnum);
> >+ generic_set_bit(pnum, ubi->corrupt);
> >+ return UBI_IO_BAD_HDR;
> >+ }
> >+
> >+ ubi_dbg("RV: pnum: %i sqnum %llu", pnum, be64_to_cpu(vh->sqnum));
> >+
> >+ return 0;
> >+}
> >+
> >+static int ubi_rescan_fm_vid_hdr(struct ubi_scan_info *ubi,
> >+ struct ubi_vid_hdr *vh,
> >+ u32 fm_pnum, u32 fm_vol_id, u32 fm_lnum)
> >+{
> >+ int res;
> >+
> >+ if (ubi_io_is_bad(ubi, fm_pnum))
> >+ return -1;
> >+
> >+ res = ubi_io_read_vid_hdr(ubi, fm_pnum, vh, 0);
> >+ if (!res) {
> >+ /* Check volume id, volume type and lnum */
> >+ if (be32_to_cpu(vh->vol_id) == fm_vol_id &&
> >+ vh->vol_type == UBI_VID_STATIC &&
> >+ be32_to_cpu(vh->lnum) == fm_lnum)
> >+ return 0;
> >+ ubi_dbg("RS: PEB %u vol: %u : %u typ %u lnum %u %u",
> >+ fm_pnum, fm_vol_id, vh->vol_type,
> >+ be32_to_cpu(vh->vol_id),
> >+ fm_lnum, be32_to_cpu(vh->lnum));
> >+ }
> >+ return -1;
> >+}
> >+
> >+/* Insert the logic block into the volume info */
> >+static int ubi_add_peb_to_vol(struct ubi_scan_info *ubi,
> >+ struct ubi_vid_hdr *vh, u32 vol_id,
> >+ u32 vol_type, u32 pnum, u32 lnum)
> >+{
> >+ struct ubi_vol_info *vi = ubi->volinfo + vol_id;
> >+ u32 *ltp;
> >+
> >+ /*
> >+ * We only care about static volumes with an id <
> >+ * UBI_SPL_VOL_IDS.
> >+ */
> >+ if (vol_id >= UBI_SPL_VOL_IDS || vol_type != UBI_VID_STATIC)
> >+ return 0;
> >+
> >+ /*
> >+ * If the volume is larger than expected, yell and give up :(
> >+ */
> >+ if (lnum >= UBI_MAX_VOL_LEBS) {
> >+ ubi_warn("Vol: %u LEB %d > %d", vol_id, lnum, UBI_MAX_VOL_LEBS);
> >+ return -1;
> >+ }
> >+
> >+ ubi_dbg("SC: Add PEB %u to Vol %u as LEB %u fnd %d sc %d",
> >+ pnum, vol_id, lnum, !!test_bit(lnum, vi->found),
> >+ !!test_bit(pnum, ubi->scanned));
> >+
> >+ /* Points to the translation entry */
> >+ ltp = vi->lebs_to_pebs + lnum;
> >+
> >+ /* If the block is already assigned, check sqnum */
> >+ if (__test_and_set_bit(lnum, vi->found)) {
> >+ u32 cur_pnum = *ltp;
> >+ struct ubi_vid_hdr *cur = ubi->blockinfo + cur_pnum;
> >+
> >+ /*
> >+ * If the current block hase not yet been scanned, we
> >+ * need to do that. The other block might be stale or
> >+ * the current block corrupted and the FM not yet
> >+ * updated.
> >+ */
> >+ if (!test_bit(cur_pnum, ubi->scanned)) {
> >+ /*
> >+ * If the scan fails, we use the valid block
> >+ */
> >+ if (ubi_rescan_fm_vid_hdr(ubi, cur, cur_pnum, vol_id,
> >+ lnum)) {
> >+ *ltp = pnum;
> >+ return 0;
> >+ }
> >+ }
> >+
> >+ /*
> >+ * Should not happen ....
> >+ */
> >+ if (test_bit(cur_pnum, ubi->corrupt)) {
> >+ *ltp = pnum;
> >+ return 0;
> >+ }
> >+
> >+ ubi_dbg("Vol %u LEB %u PEB %u->sqnum %llu NPEB %u->sqnum %llu",
> >+ vol_id, lnum, cur_pnum, be64_to_cpu(cur->sqnum), pnum,
> >+ be64_to_cpu(vh->sqnum));
> >+
> >+ /*
> >+ * Compare sqnum and take the newer one
> >+ */
> >+ if (be64_to_cpu(cur->sqnum) < be64_to_cpu(vh->sqnum))
> >+ *ltp = pnum;
> >+ } else {
> >+ *ltp = pnum;
> >+ if (lnum > vi->last_block)
> >+ vi->last_block = lnum;
> >+ }
> >+
> >+ return 0;
> >+}
> >+
> >+static int ubi_scan_vid_hdr(struct ubi_scan_info *ubi, struct ubi_vid_hdr *vh,
> >+ u32 pnum)
> >+{
> >+ u32 vol_id, lnum;
> >+ int res;
> >+
> >+ if (ubi_io_is_bad(ubi, pnum))
> >+ return -1;
> >+
> >+ res = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
> >+ if (res)
> >+ return res;
> >+
> >+ /* Get volume id */
> >+ vol_id = be32_to_cpu(vh->vol_id);
> >+
> >+ /* If this is the fastmap anchor, return right away */
> >+ if (vol_id == UBI_FM_SB_VOLUME_ID)
> >+ return ubi->fm_enabled ? UBI_FASTMAP_ANCHOR : 0;
> >+
> >+ /* We are only interested in the volumes to load */
> >+ if (!test_bit(vol_id, ubi->toload))
> >+ return 0;
> >+
> >+ lnum = be32_to_cpu(vh->lnum);
> >+
> >+ return ubi_add_peb_to_vol(ubi, vh, vol_id, vh->vol_type, pnum, lnum);
> >+}
> >+
> >+static int assign_aeb_to_av(struct ubi_scan_info *ubi, u32 pnum, u32 lnum,
> >+ u32 vol_id, u32 vol_type, u32 used)
> >+{
> >+ struct ubi_vid_hdr *vh;
> >+
> >+ if (ubi_io_is_bad(ubi, pnum))
> >+ return -1;
> >+
> >+ ubi->fastmap_pebs++;
> >+
> >+ if (vol_id >= UBI_SPL_VOL_IDS || vol_type != UBI_STATIC_VOLUME)
> >+ return 0;
> >+
> >+ /* We are only interested in the volumes to load */
> >+ if (!test_bit(vol_id, ubi->toload))
> >+ return 0;
> >+
> >+ vh = ubi->blockinfo + pnum;
> >+
> >+ return ubi_scan_vid_hdr(ubi, vh, pnum);
> >+}
> >+
> >+static int scan_pool(struct ubi_scan_info *ubi, __be32 *pebs, int pool_size)
> >+{
> >+ struct ubi_vid_hdr *vh;
> >+ u32 pnum;
> >+ int i;
> >+
> >+ ubi_dbg("Scanning pool size: %d", pool_size);
> >+
> >+ for (i = 0; i < pool_size; i++) {
> >+ pnum = be32_to_cpu(pebs[i]);
> >+
> >+ if (ubi_io_is_bad(ubi, pnum)) {
> >+ ubi_err("FM: Bad PEB in fastmap pool! %u", pnum);
> >+ return UBI_BAD_FASTMAP;
> >+ }
> >+
> >+ vh = ubi->blockinfo + pnum;
> >+ /*
> >+ * We allow the scan to fail here. The loader will notice
> >+ * and look for a replacement.
> >+ */
> >+ ubi_scan_vid_hdr(ubi, vh, pnum);
> >+ }
> >+ return 0;
> >+}
> >+
> >+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
>
> ?
>
> >+ /*
> >+ * 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;
> >+ unsigned int fsize, nblocks;
> >+ 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
>
> What means this?
I do not know. Thomas probably decided not to handle UBI volumes created
by ancient UBI implementations.
> >+ 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
> >+ ret = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
> >+ if (ret && ret != UBI_IO_BITFLIPS) {
> >+ ubi_err("unable to read fastmap block# %i (PEB: %i)",
> >+ i, pnum);
> >+ goto free_hdr;
> >+ }
> >+
> >+ /*
> >+ * Mainline code rescans the anchor header. We've done
> >+ * that already so we merily copy it over.
> >+ */
> >+ if (pnum == fm_anchor)
> >+ memcpy(vh, ubi->blockinfo + pnum, sizeof(*fm));
> >+
> >+ if (i == 0) {
> >+ if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) {
> >+ ubi_err("bad fastmap anchor vol_id: 0x%x," \
> >+ " expected: 0x%x",
> >+ be32_to_cpu(vh->vol_id),
> >+ UBI_FM_SB_VOLUME_ID);
> >+ ret = UBI_BAD_FASTMAP;
> >+ goto free_hdr;
> >+ }
> >+ } else {
> >+ if (be32_to_cpu(vh->vol_id) != UBI_FM_DATA_VOLUME_ID) {
> >+ ubi_err("bad fastmap data vol_id: 0x%x," \
> >+ " expected: 0x%x",
> >+ be32_to_cpu(vh->vol_id),
> >+ UBI_FM_DATA_VOLUME_ID);
> >+ ret = UBI_BAD_FASTMAP;
> >+ goto free_hdr;
> >+ }
> >+ }
> >+
> >+ if (sqnum < be64_to_cpu(vh->sqnum))
> >+ sqnum = be64_to_cpu(vh->sqnum);
> >+
> >+ ret = ubi_io_read(ubi, ubi->fm_buf + (ubi->leb_size * i), pnum,
> >+ ubi->leb_start, ubi->leb_size);
> >+ if (ret && ret != UBI_IO_BITFLIPS) {
> >+ ubi_err("unable to read fastmap block# %i (PEB: %i, " \
> >+ "err: %i)", i, pnum, ret);
> >+ goto free_hdr;
> >+ }
> >+ }
> >+
> >+ fmsb2 = (struct ubi_fm_sb *)(ubi->fm_buf);
> >+ tmp_crc = be32_to_cpu(fmsb2->data_crc);
> >+ fmsb2->data_crc = 0;
> >+ crc = crc32(UBI_CRC32_INIT, ubi->fm_buf, fm_size);
> >+ if (crc != tmp_crc) {
> >+ ubi_err("fastmap data CRC is invalid");
> >+ ubi_err("CRC should be: 0x%x, calc: 0x%x", tmp_crc, crc);
> >+ ret = UBI_BAD_FASTMAP;
> >+ goto free_hdr;
> >+ }
> >+
> >+ fmsb2->sqnum = sqnum;
> >+
> >+ fm->used_blocks = used_blocks;
> >+
> >+ ret = ubi_attach_fastmap(ubi, ai, fm);
> >+ if (ret) {
> >+ if (ret > 0)
> >+ ret = UBI_BAD_FASTMAP;
> >+ goto free_hdr;
> >+ }
> >+
> >+ ubi->fm = fm;
> >+ ubi->fm_pool.max_size = ubi->fm->max_pool_size;
> >+ ubi->fm_wl_pool.max_size = ubi->fm->max_wl_pool_size;
> >+ nblocks = ubi->peb_count;
> >+ fsize = ubi->fsize_mb;
> >+ ubi_msg("attached by fastmap %uMB %u blocks", fsize, nblocks);
> >+ ubi_dbg("fastmap pool size: %d", ubi->fm_pool.max_size);
> >+ ubi_dbg("fastmap WL pool size: %d", ubi->fm_wl_pool.max_size);
> >+
> >+out:
> >+ if (ret)
> >+ ubi_err("Attach by fastmap failed, doing a full scan!");
> >+ return ret;
> >+
> >+free_hdr:
> >+free_fm_sb:
> >+ goto out;
> >+}
> >+
> >+/*
> >+ * Scan the flash and attempt to attach via fastmap
> >+ */
> >+static void ipl_scan(struct ubi_scan_info *ubi)
> >+{
> >+ unsigned int pnum;
> >+ int res;
> >+
> >+ /*
> >+ * Scan first for the fastmap super block
> >+ */
> >+ for (pnum = 0; pnum < UBI_FM_MAX_START; pnum++) {
> >+ res = ubi_scan_vid_hdr(ubi, ubi->blockinfo + pnum, pnum);
> >+ /*
> >+ * We ignore errors here as we are meriliy scanning
> >+ * the headers.
> >+ */
> >+ if (res != UBI_FASTMAP_ANCHOR)
> >+ continue;
> >+
> >+ /*
> >+ * If fastmap is disabled, continue scanning. This
> >+ * might happen because the previous attempt failed or
> >+ * the caller disabled it right away.
> >+ */
> >+ if (!ubi->fm_enabled)
> >+ continue;
> >+
> >+ /*
> >+ * Try to attach the fastmap, if that fails continue
> >+ * scanning.
> >+ */
> >+ if (!ubi_scan_fastmap(ubi, NULL, pnum))
> >+ return;
> >+ /*
> >+ * Fastmap failed. Clear everything we have and start
> >+ * over. We are paranoid and do not trust anything.
> >+ */
> >+ memset(ubi->volinfo, 0, sizeof(ubi->volinfo));
> >+ pnum = 0;
> >+ break;
> >+ }
> >+
> >+ /*
> >+ * Continue scanning, ignore errors, we might find what we are
> >+ * looking for,
> >+ */
> >+ for (; pnum < ubi->peb_count; pnum++)
> >+ ubi_scan_vid_hdr(ubi, ubi->blockinfo + pnum, pnum);
> >+}
> >+
> >+/*
> >+ * Load a logical block of a volume into memory
> >+ */
> >+static int ubi_load_block(struct ubi_scan_info *ubi, uint8_t *laddr,
> >+ struct ubi_vol_info *vi, u32 vol_id, u32 lnum,
> >+ u32 last)
> >+{
> >+ struct ubi_vid_hdr *vh, *vrepl;
> >+ u32 pnum, crc, dlen;
> >+
> >+retry:
> >+ /*
> >+ * If this is a fastmap run, we try to rescan full, otherwise
> >+ * we simply give up.
> >+ */
> >+ if (!test_bit(lnum, vi->found)) {
> >+ ubi_warn("LEB %d of %d is missing", lnum, last);
> >+ return -1;
> >+ }
> >+
> >+ pnum = vi->lebs_to_pebs[lnum];
> >+
> >+ ubi_dbg("Load vol %u LEB %u PEB %u", vol_id, lnum, pnum);
> >+
> >+ if (ubi_io_is_bad(ubi, pnum)) {
> >+ ubi_warn("Corrupted mapping block %d PB %d\n", lnum, pnum);
> >+ return -1;
> >+ }
> >+
> >+ if (test_bit(pnum, ubi->corrupt))
> >+ goto find_other;
> >+
> >+ /*
> >+ * Lets try to read that block
> >+ */
> >+ vh = ubi->blockinfo + pnum;
> >+
> >+ if (!test_bit(pnum, ubi->scanned)) {
> >+ ubi_warn("Vol: %u LEB %u PEB %u not yet scanned", vol_id,
> >+ lnum, pnum);
> >+ if (ubi_rescan_fm_vid_hdr(ubi, vh, pnum, vol_id, lnum))
> >+ goto find_other;
> >+ }
> >+
> >+ /*
> >+ * Check, if the total number of blocks is correct
> >+ */
> >+ if (be32_to_cpu(vh->used_ebs) != last) {
> >+ ubi_dbg("Block count missmatch.");
> >+ ubi_dbg("vh->used_ebs: %d nrblocks: %d",
> >+ be32_to_cpu(vh->used_ebs), last);
> >+ generic_set_bit(pnum, ubi->corrupt);
> >+ goto find_other;
> >+ }
> >+
> >+ /*
> >+ * Get the data length of this block.
> >+ */
> >+ dlen = be32_to_cpu(vh->data_size);
> >+
> >+ /*
> >+ * Read the data into RAM. We ignore the return value
> >+ * here as the only thing which might go wrong are
> >+ * bitflips. Try nevertheless.
> >+ */
> >+ ubi_io_read(ubi, laddr, pnum, ubi->leb_start, dlen);
> >+
> >+ /* Calculate CRC over the data */
> >+ crc = crc32(UBI_CRC32_INIT, laddr, dlen);
> >+
> >+ if (crc != be32_to_cpu(vh->data_crc)) {
> >+ ubi_warn("Vol: %u LEB %u PEB %u data CRC failure", vol_id,
> >+ lnum, pnum);
> >+ generic_set_bit(pnum, ubi->corrupt);
> >+ goto find_other;
> >+ }
> >+
> >+ /* We are good. Return the data length we read */
> >+ return dlen;
> >+
> >+find_other:
> >+ ubi_dbg("Find replacement for LEB %u PEB %u", lnum, pnum);
> >+ generic_clear_bit(lnum, vi->found);
> >+ vrepl = NULL;
> >+
> >+ for (pnum = 0; pnum < ubi->peb_count; pnum++) {
> >+ struct ubi_vid_hdr *tmp = ubi->blockinfo + pnum;
> >+ u32 t_vol_id = be32_to_cpu(tmp->vol_id);
> >+ u32 t_lnum = be32_to_cpu(tmp->lnum);
> >+
> >+ if (test_bit(pnum, ubi->corrupt))
> >+ continue;
> >+
> >+ if (t_vol_id != vol_id || t_lnum != lnum)
> >+ continue;
> >+
> >+ if (!test_bit(pnum, ubi->scanned)) {
> >+ ubi_warn("Vol: %u LEB %u PEB %u not yet scanned", vol_id,
> >+ lnum, pnum);
> >+ if (ubi_rescan_fm_vid_hdr(ubi, tmp, pnum, vol_id, lnum))
> >+ continue;
> >+ }
> >+
> >+ /*
> >+ * We found one. If its the first, assign it otherwise
> >+ * compare the sqnum
> >+ */
> >+ generic_set_bit(lnum, vi->found);
> >+
> >+ if (!vrepl) {
> >+ vrepl = tmp;
> >+ continue;
> >+ }
> >+
> >+ if (be64_to_cpu(vrepl->sqnum) < be64_to_cpu(tmp->sqnum))
> >+ vrepl = tmp;
> >+ }
> >+
> >+ if (vrepl) {
> >+ /* Update the vi table */
> >+ pnum = vrepl - ubi->blockinfo;
> >+ vi->lebs_to_pebs[lnum] = pnum;
> >+ ubi_dbg("Trying PEB %u for LEB %u", pnum, lnum);
> >+ vh = vrepl;
> >+ }
> >+ goto retry;
> >+}
> >+
> >+/*
> >+ * Load a volume into RAM
> >+ */
> >+static int ipl_load(struct ubi_scan_info *ubi, const u32 vol_id, uint8_t *laddr)
> >+{
> >+ struct ubi_vol_info *vi;
> >+ u32 lnum, last;
> >+
> >+ if (vol_id >= UBI_SPL_VOL_IDS)
> >+ return -1;
> >+
> >+ vi = ubi->volinfo + vol_id;
> >+ last = vi->last_block + 1;
> >+
> >+ /* Read the blocks to RAM, check CRC */
> >+ for (lnum = 0 ; lnum < last; lnum++) {
> >+ int res = ubi_load_block(ubi, laddr, vi, vol_id, lnum, last);
> >+
> >+ if (res < 0) {
> >+ ubi_warn("Failed to load volume %u", vol_id);
> >+ return res;
> >+ }
> >+ /* res is the data length of the read block */
> >+ laddr += res;
> >+ }
> >+ return 0;
> >+}
> >+
> >+int ubispl_load_volumes(struct ubispl_info *info, struct ubispl_load *lvols,
> >+ int nrvols)
> >+{
> >+ struct ubi_scan_info *ubi = info->ubi;
> >+ int res, i, fastmap = info->fastmap;
> >+ u32 fsize;
> >+
> >+retry:
> >+ /*
> >+ * We do a partial initializiation of @ubi. Cleaning fm_buf is
> >+ * not necessary.
> >+ */
> >+ memset(ubi, 0, offsetof(struct ubi_scan_info, fm_buf));
> >+
> >+ ubi->read = info->read;
> >+
> >+ /* Precalculate the offsets */
> >+ ubi->vid_offset = info->vid_offset;
> >+ ubi->leb_start = info->leb_start;
> >+ ubi->leb_size = info->peb_size - ubi->leb_start;
> >+ ubi->peb_count = info->peb_count;
> >+ ubi->peb_offset = info->peb_offset;
> >+
> >+ fsize = info->peb_size * info->peb_count;
> >+ ubi->fsize_mb = fsize >> 20;
> >+
> >+ /* Fastmap init */
> >+ ubi->fm_size = ubi_calc_fm_size(ubi);
> >+ ubi->fm_enabled = fastmap;
> >+
> >+ for (i = 0; i < nrvols; i++) {
> >+ struct ubispl_load *lv = lvols + i;
> >+
> >+ generic_set_bit(lv->vol_id, ubi->toload);
> >+ }
> >+
> >+ ipl_scan(ubi);
> >+
> >+ for (i = 0; i < nrvols; i++) {
> >+ struct ubispl_load *lv = lvols + i;
> >+
> >+ ubi_msg("Load %s (#%d)", lv->name, lv->vol_id);
> >+ res = ipl_load(ubi, lv->vol_id, lv->load_addr);
> >+ if (res) {
> >+ if (fastmap) {
> >+ fastmap = 0;
> >+ goto retry;
> >+ }
> >+ ubi_warn("Failed \n");
> >+ return res;
> >+ }
> >+ }
> >+ return 0;
> >+}
> >diff --git a/drivers/mtd/ubispl/ubispl.h b/drivers/mtd/ubispl/ubispl.h
> >new file mode 100644
> >index 0000000..a64a394
> >--- /dev/null
> >+++ b/drivers/mtd/ubispl/ubispl.h
> >@@ -0,0 +1,136 @@
> >+/*
> >+ * Copyright (c) Thomas Gleixner <tglx at linutronix.de>
> >+ *
> >+ * SPDX-License-Identifier: GPL-2.0+
> >+ */
> >+
> >+#ifndef _UBOOT_MTD_UBISPL_H
> >+#define _UBOOT_MTD_UBISPL_H
> >+
> >+#include "../ubi/ubi-media.h"
> >+#include "ubi-wrapper.h"
> >+
> >+/*
> >+ * The maximum number of volume ids we scan. So you can load volume id
> >+ * 0 to (CONFIG_SPL_UBI_VOL_ID_MAX - 1)
> >+ */
> >+#define UBI_SPL_VOL_IDS CONFIG_SPL_UBI_VOL_IDS
> >+/*
> >+ * The size of the read buffer for the fastmap blocks. In theory up to
> >+ * UBI_FM_MAX_BLOCKS * CONFIG_SPL_MAX_PEB_SIZE. In practice today
> >+ * one or two blocks.
> >+ */
> >+#define UBI_FM_BUF_SIZE (UBI_FM_MAX_BLOCKS * CONFIG_SPL_UBI_MAX_PEB_SIZE)
> >+/*
> >+ * The size of the bitmaps for the attach/ scan
> >+ */
> >+#define UBI_FM_BM_SIZE ((CONFIG_SPL_UBI_MAX_PEBS / BITS_PER_LONG) + 1)
> >+/*
> >+ * The maximum number of logical erase blocks per loadable volume
> >+ */
> >+#define UBI_MAX_VOL_LEBS CONFIG_SPL_UBI_MAX_VOL_LEBS
> >+/*
> >+ * The bitmap size for the above to denote the found blocks inside the volume
> >+ */
> >+#define UBI_VOL_BM_SIZE ((UBI_MAX_VOL_LEBS / BITS_PER_LONG) + 1)
> >+
> >+/**
> >+ * struct ubi_vol_info - UBISPL internal volume represenation
> >+ * @last_block: The last block (highest LEB) found for this volume
> >+ * @found: Bitmap to mark found LEBS
> >+ * @lebs_to_pebs: LEB to PEB translation table
> >+ */
> >+struct ubi_vol_info {
> >+ u32 last_block;
> >+ unsigned long found[UBI_VOL_BM_SIZE];
> >+ u32 lebs_to_pebs[UBI_MAX_VOL_LEBS];
> >+};
> >+
> >+/**
> >+ * struct ubi_scan_info - UBISPL internal data for FM attach and full scan
> >+ *
> >+ * @read: Read function to access the flash provided by the caller
> >+ * @peb_count: Number of physical erase blocks in the UBI FLASH area
> >+ * aka MTD partition.
> >+ * @peb_offset: Offset of PEB0 in the UBI FLASH area (aka MTD partition)
> >+ * to the real start of the FLASH in erase blocks.
> >+ * @fsize_mb: Size of the scanned FLASH area in MB (stats only)
> >+ * @vid_offset: Offset from the start of a PEB to the VID header
> >+ * @leb_start: Offset from the start of a PEB to the data area
> >+ * @leb_size: Size of the data area
> >+ *
> >+ * @fastmap_pebs: Counter of PEBs "attached" by fastmap
> >+ * @fastmap_anchor: The anchor PEB of the fastmap
> >+ * @fm_sb: The fastmap super block data
> >+ * @fm_vh: The fastmap VID header
> >+ * @fm: Pointer to the fastmap layout
> >+ * @fm_layout: The fastmap layout itself
> >+ * @fm_pool: The pool of PEBs to scan at fastmap attach time
> >+ * @fm_wl_pool: The pool of PEBs scheduled for wearleveling
> >+ *
> >+ * @fm_enabled: Indicator whether fastmap attachment is enabled.
> >+ * @fm_used: Bitmap to indicate the PEBS covered by fastmap
> >+ * @scanned: Bitmap to indicate the PEBS of which the VID header
> >+ * hase been physically scanned.
> >+ * @corrupt: Bitmap to indicate corrupt blocks
> >+ * @toload: Bitmap to indicate the volumes which should be loaded
> >+ *
> >+ * @blockinfo: The vid headers of the scanned blocks
> >+ * @volinfo: The volume information of the interesting (toload)
> >+ * volumes
> >+ *
> >+ * @fm_buf: The large fastmap attach buffer
> >+ */
> >+struct ubi_scan_info {
> >+ int (*read)(u32 pnum, u32 offset, u32 len, void *dest);
> >+ unsigned int fsize_mb;
> >+ unsigned int peb_count;
> >+ unsigned int peb_offset;
> >+
> >+ unsigned long vid_offset;
> >+ unsigned long leb_start;
> >+ unsigned long leb_size;
> >+
> >+ /* Fastmap: The upstream required fields */
> >+ int fastmap_pebs;
> >+ int fastmap_anchor;
> >+ size_t fm_size;
> >+ struct ubi_fm_sb fm_sb;
> >+ struct ubi_vid_hdr fm_vh;
> >+ struct ubi_fastmap_layout *fm;
> >+ struct ubi_fastmap_layout fm_layout;
> >+ struct ubi_fm_pool fm_pool;
> >+ struct ubi_fm_pool fm_wl_pool;
> >+
> >+ /* Fastmap: UBISPL specific data */
> >+ int fm_enabled;
> >+ unsigned long fm_used[UBI_FM_BM_SIZE];
> >+ unsigned long scanned[UBI_FM_BM_SIZE];
> >+ unsigned long corrupt[UBI_FM_BM_SIZE];
> >+ unsigned long toload[UBI_FM_BM_SIZE];
> >+
> >+ /* Data for storing the VID and volume information */
> >+ struct ubi_vol_info volinfo[UBI_SPL_VOL_IDS];
> >+ struct ubi_vid_hdr blockinfo[CONFIG_SPL_UBI_MAX_PEBS];
> >+
> >+ /* The large buffer for the fastmap */
> >+ uint8_t fm_buf[UBI_FM_BUF_SIZE];
> >+};
> >+
> >+#ifdef CFG_DEBUG
> >+#define ubi_dbg(fmt, ...) printf("UBI: debug:" fmt "\n", ##__VA_ARGS__)
> >+#else
> >+#define ubi_dbg(fmt, ...)
> >+#endif
> >+
> >+#ifdef CONFIG_UBI_SILENCE_MSG
> >+#define ubi_msg(fmt, ...)
> >+#else
> >+#define ubi_msg(fmt, ...) printf("UBI: " fmt "\n", ##__VA_ARGS__)
> >+#endif
> >+/* UBI warning messages */
> >+#define ubi_warn(fmt, ...) printf("UBI warning: " fmt "\n", ##__VA_ARGS__)
> >+/* UBI error messages */
> >+#define ubi_err(fmt, ...) printf("UBI error: " fmt "\n", ##__VA_ARGS__)
> >+
> >+#endif
>
> Isn;t it possible to avoid this duplications ?
See above.
[...]
Best regards,
ladis
More information about the U-Boot
mailing list