[U-Boot] [PATCH] SPL: Lightweight UBI and UBI fastmap support

Ladislav Michl ladis at linux-mips.org
Wed Dec 30 03:12:55 CET 2015


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/

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?

Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
Signed-off-by: Ladislav Michl <ladis at linux-mips.org>
---
 README                           |   4 +
 doc/README.ubispl                | 144 ++++++
 drivers/Makefile                 |   3 +-
 drivers/mtd/ubispl/Makefile      |   1 +
 drivers/mtd/ubispl/ubi-wrapper.h | 104 +++++
 drivers/mtd/ubispl/ubispl.c      | 921 +++++++++++++++++++++++++++++++++++++++
 drivers/mtd/ubispl/ubispl.h      | 136 ++++++
 include/ubispl.h                 |  90 ++++
 8 files changed, 1402 insertions(+), 1 deletion(-)
 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

diff --git a/README b/README
index 43f307f..b6d01a9 100644
--- a/README
+++ b/README
@@ -3654,6 +3654,10 @@ FIT uImage format:
 		Support for NAND boot using simple NAND drivers that
 		expose the cmd_ctrl() interface.
 
+		CONFIG_SPL_UBI
+		Support for a lightweight UBI (fastmap) scanner and
+		loader
+
 		CONFIG_SPL_MTD_SUPPORT
 		Support for the MTD subsystem within SPL.  Useful for
 		environment on NAND support within SPL.
diff --git a/doc/README.ubispl b/doc/README.ubispl
new file mode 100644
index 0000000..f90e0a1
--- /dev/null
+++ b/doc/README.ubispl
@@ -0,0 +1,144 @@
+Lightweight UBI and UBI fastmap support
+
+# Copyright (C) Thomas Gleixner <tglx at linutronix.de>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+
+Scans the UBI information and loads the requested static volumes into
+memory.
+
+Configuration Options:
+
+   CONFIG_SPL_UBI
+     Enables the SPL UBI support
+
+   CONFIG_SPL_UBI_MAX_VOL_LEBS
+     The maximum number of logical eraseblocks which a static volume
+     to load can contain. Used for sizing the scan data structure
+
+   CONFIG_SPL_UBI_MAX_PEB_SIZE
+     The maximum physical erase block size. Either a compile time
+     constant or runtime detection. Used for sizing the scan data
+     structure
+
+   CONFIG_SPL_UBI_MAX_PEBS
+     The maximum physical erase block count. Either a compile time
+     constant or runtime detection. Used for sizing the scan data
+     structure
+
+   CONFIG_SPL_UBI_VOL_IDS
+     The maximum volume ids which can be loaded. Used for sizing the
+     scan data structure.
+
+Usage notes:
+
+In the board config file define for example:
+
+#define CONFIG_SPL_UBI
+#define CONFIG_SPL_UBI_MAX_VOL_LEBS	256
+#define CONFIG_SPL_UBI_MAX_PEB_SIZE	(256*1024)
+#define CONFIG_SPL_UBI_MAX_PEBS		4096
+#define CONFIG_SPL_UBI_VOL_IDS		8
+
+The size requirement is roughly as follows:
+
+    2k for the basic data structure
+  + CONFIG_SPL_UBI_VOL_IDS * CONFIG_SPL_UBI_MAX_VOL_LEBS * 8
+  + CONFIG_SPL_UBI_MAX_PEBS * 64
+  + CONFIG_SPL_UBI_MAX_PEB_SIZE * UBI_FM_MAX_BLOCKS
+
+The last one is big, but I really don't care in that stage. Real world
+implementations only use the first couple of blocks, but the code
+handles up to UBI_FM_MAX_BLOCKS.
+
+Given the above configuration example the requirement is about 5M
+which is usually not a problem to reserve in the RAM along with the
+other areas like the kernel/dts load address.
+
+So something like this will do the trick:
+
+#define SPL_FINFO_ADDR			0x80800000
+#define SPL_DTB_LOAD_ADDR		0x81800000
+#define SPL_KERNEL_LOAD_ADDR		0x82000000
+
+In the board file, implement the following:
+
+static struct ubispl_load myvolumes[] = {
+	{
+		.name		= "Kernel",
+		.vol_id		= 0,
+		.load_addr	= (void *)SPL_KERNEL_LOAD_ADDR,
+	},
+	{
+		.name		= "DTB",
+		.vol_id		= 1,
+		.load_addr	= (void *)SPL_DTB_LOAD_ADDR,
+	}
+};
+
+int spl_start_uboot(void)
+{
+	struct ubispl_info info;
+
+	info.ubi = (struct ubi_scan_info *) SPL_FINFO_ADDR;
+	info.fastmap = 1;
+	info.read = nand_spl_read_flash;
+
+#if COMPILE_TIME_DEFINED
+	/*
+	 * MY_NAND_NR_SPL_PEBS is the number of physical erase blocks
+	 * in the FLASH which are reserved for the SPL. Think about
+	 * mtd partitions:
+	 *
+	 * part_spl { .start = 0, .end = 4 }
+	 * part_ubi { .start = 4, .end = NR_PEBS }
+	 */
+	info.peb_offset = MY_NAND_NR_SPL_PEBS;
+	info.peb_size = CONFIG_SYS_NAND_BLOCK_SIZE;
+	info.vid_offset = MY_NAND_UBI_VID_OFFS;
+	info.leb_start = MY_NAND_UBI_DATA_OFFS;
+	info.peb_count = MY_NAND_UBI_NUM_PEBS;
+#else
+	get_flash_info(&flash_info);
+	info.peb_offset = MY_NAND_NR_SPL_PEBS;
+	info.peb_size = flash_info.peb_size;
+
+	/*
+	 * The VID and Data offset depend on the capability of the
+	 * FLASH chip to do subpage writes.
+	 *
+	 * If the flash chip supports subpage writes, then the VID
+	 * header starts at the second subpage. So for 2k pages size
+	 * with 4 subpages the VID offset is 512. The DATA offset is 2k.
+	 *
+	 * If the flash chip does not support subpage writes then the
+	 * VID offset is FLASH_PAGE_SIZE and the DATA offset
+	 * 2 * FLASH_PAGE_SIZE
+	 */
+	info.vid_offset = flash_info.vid_offset;
+	info.leb_start = flash_info.data_offset;
+
+	/*
+	 * The flash reports the total number of erase blocks, so
+	 * we need to subtract the number of blocks which are reserved
+	 * for the SPL itself and not managed by UBI.
+	 */
+	info.peb_count = flash_info.peb_count - MY_NAND_NR_SPL_PEBS;
+#endif
+
+	ret = ubispl_load_volumes(&info, myvolumes, ARRAY_SIZE(myvolumes);
+
+	....
+
+}
+
+Note: you can load any payload that way. You can even load u-boot from
+UBI, so the only non UBI managed FLASH area is the one which is
+reserved for the SPL itself and read from the SoC ROM.
+
+And you can do fallback scenarios:
+
+    if (ubispl_load_volumes(&info, volumes0, ARRAY_SIZE(volumes0)))
+        if (ubispl_load_volumes(&info, volumes1, ARRAY_SIZE(volumes1)))
+	    ubispl_load_volumes(&info, vol_uboot, ARRAY_SIZE(vol_uboot));
+
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/
 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,
+};
+
+/*
+ * UBI volume type constants.
+ *
+ * @UBI_DYNAMIC_VOLUME: dynamic volume
+ * @UBI_STATIC_VOLUME:  static volume
+ */
+enum {
+	UBI_DYNAMIC_VOLUME = 3,
+	UBI_STATIC_VOLUME  = 4,
+};
+
+#define UBI_BAD_FASTMAP		(-1)
+
+/*
+ * 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
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;
+	/*
+	 * 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
+		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
diff --git a/include/ubispl.h b/include/ubispl.h
new file mode 100644
index 0000000..df4b0e1
--- /dev/null
+++ b/include/ubispl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) Thomas Gleixner <tglx at linutronix.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#ifndef __UBOOT_UBISPL_H
+#define __UBOOT_UBISPL_H
+
+/*
+ * The following CONFIG options are relevant for UBISPL
+ *
+ * #define CONFIG_SPL_UBI_MAX_VOL_LEBS		256
+ *
+ * Defines the maximum number of logical erase blocks per loadable
+ * (static) volume to size the ubispl internal arrays.
+ *
+ * #define CONFIG_SPL_UBI_MAX_PEB_SIZE		(256*1024)
+ *
+ * Defines the maximum physical erase block size to size the fastmap
+ * buffer for ubispl.
+ *
+ * #define CONFIG_SPL_UBI_MAX_PEBS		4096
+ *
+ * Define the maximum number of physical erase blocks to size the
+ * ubispl internal arrays.
+ *
+ * #define CONFIG_SPL_UBI_VOL_IDS		8
+ *
+ * Defines the maximum number of volumes in which UBISPL is
+ * interested. Limits the amount of memory for the scan data and
+ * speeds up the scan process as we simply ignore stuff which we dont
+ * want to load from the SPL anyway. So the volumes which can be
+ * loaded in the above example are ids 0 - 7
+ */
+
+/*
+ * The struct definition is in drivers/mtd/ubispl/ubispl.h. It does
+ * not fit into the BSS due to the large buffer requirement of the
+ * upstream fastmap code. So the caller of ubispl_load_volumes needs
+ * to hand in a pointer to a free memory area where ubispl will place
+ * its data. The area is not required to be initialized.
+ */
+struct ubi_scan_info;
+
+/**
+ * struct ubispl_info - description structure for fast ubi scan
+ * @ubi:		Pointer to memory space for ubi scan info structure
+ * @peb_size:		Physical erase block size
+ * @vid_offset:		Offset of the VID header
+ * @leb_start:		Start of the logical erase block, i.e. offset of data
+ * @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.
+ * @fastmap:		Enable fastmap attachment
+ * @read:		Read function to access the flash
+ */
+struct ubispl_info {
+	struct ubi_scan_info	*ubi;
+	u32			peb_size;
+	u32			vid_offset;
+	u32			leb_start;
+	u32			peb_count;
+	u32			peb_offset;
+	int			fastmap;
+	int			(*read)(u32 pnum, u32 offset, u32 len, void *dest);
+};
+
+/**
+ * struct ubispl_load - structure to describe a volume to load
+ * @name:	Name of the volume
+ * @vol_id:	Volume id
+ * @load_addr:	Load address of the volume
+ */
+struct ubispl_load {
+	char		*name;
+	int		vol_id;
+	void		*load_addr;
+};
+
+/**
+ * ubispl_load_volumes - Scan flash and load volumes
+ * @info:	Pointer to the ubi scan info structure
+ * @lovls:	Pointer to array of volumes to load
+ * @nrvols:	Array size of @lovls
+ */
+extern int ubispl_load_volumes(struct ubispl_info *info,
+			       struct ubispl_load *lvols, int nrvols);
+
+#endif
-- 
2.1.4




More information about the U-Boot mailing list