[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