Merge git://git.denx.de/u-boot-dm
diff --git a/README b/README
index 63bdeb9..da74513 100644
--- a/README
+++ b/README
@@ -3494,6 +3494,10 @@
 		without a fastmap.
 		default: 0
 
+		CONFIG_MTD_UBI_FM_DEBUG
+		Enable UBI fastmap debug
+		default: 0
+
 - UBIFS support
 		CONFIG_CMD_UBIFS
 
diff --git a/arch/Kconfig b/arch/Kconfig
index 4f73819..25dcf4a 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -24,6 +24,7 @@
 	select CREATE_ARCH_SYMLINK
 	select HAVE_PRIVATE_LIBGCC if !ARM64
 	select HAVE_GENERIC_BOARD
+	select SYS_GENERIC_BOARD
 	select SUPPORT_OF_CONTROL
 
 config AVR32
@@ -63,6 +64,10 @@
 	bool "Nios II architecture"
 	select HAVE_GENERIC_BOARD
 	select SYS_GENERIC_BOARD
+	select SUPPORT_OF_CONTROL
+	select OF_CONTROL
+	select DM
+	select CPU
 
 config OPENRISC
 	bool "OpenRISC architecture"
@@ -71,6 +76,7 @@
 	bool "PowerPC architecture"
 	select HAVE_PRIVATE_LIBGCC
 	select HAVE_GENERIC_BOARD
+	select SYS_GENERIC_BOARD
 	select SUPPORT_OF_CONTROL
 
 config SANDBOX
diff --git a/arch/arm/include/asm/arch-lpc32xx/config.h b/arch/arm/include/asm/arch-lpc32xx/config.h
index 2d082ef..845ba4f 100644
--- a/arch/arm/include/asm/arch-lpc32xx/config.h
+++ b/arch/arm/include/asm/arch-lpc32xx/config.h
@@ -9,7 +9,6 @@
 #ifndef _LPC32XX_CONFIG_H
 #define _LPC32XX_CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Basic CPU architecture */
 #define CONFIG_ARCH_CPU_INIT
diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S
index 4c3a94a..80548eb 100644
--- a/arch/arm/lib/crt0.S
+++ b/arch/arm/lib/crt0.S
@@ -82,31 +82,11 @@
 #else
 	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
 #endif
-	mov	r2, sp
-	sub	sp, sp, #GD_SIZE	/* allocate one GD above SP */
-#if defined(CONFIG_CPU_V7M)	/* v7M forbids using SP as BIC destination */
-	mov	r3, sp
-	bic	r3, r3, #7
-	mov	sp, r3
-#else
-	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
-#endif
-	mov	r9, sp		/* GD is above SP */
-	mov	r1, sp
+	mov	r0, sp
+	bl	board_init_f_mem
+	mov	sp, r0
+
 	mov	r0, #0
-clr_gd:
-	cmp	r1, r2			/* while not at end of GD */
-#if defined(CONFIG_CPU_V7M)
-	itt	lo
-#endif
-	strlo	r0, [r1]		/* clear 32-bit GD word */
-	addlo	r1, r1, #4		/* move to next */
-	blo	clr_gd
-#if defined(CONFIG_SYS_MALLOC_F_LEN)
-	sub	sp, sp, #CONFIG_SYS_MALLOC_F_LEN
-	str	sp, [r9, #GD_MALLOC_BASE]
-#endif
-	/* mov r0, #0 not needed due to above code */
 	bl	board_init_f
 
 #if ! defined(CONFIG_SPL_BUILD)
diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S
index 8b34e04..cef1c71 100644
--- a/arch/arm/lib/crt0_64.S
+++ b/arch/arm/lib/crt0_64.S
@@ -74,19 +74,10 @@
 #else
 	ldr	x0, =(CONFIG_SYS_INIT_SP_ADDR)
 #endif
-	sub	x18, x0, #GD_SIZE	/* allocate one GD above SP */
-	bic	x18, x18, #0x7		/* 8-byte alignment for GD */
-zero_gd:
-	sub	x0, x0, #0x8
-	str	xzr, [x0]
-	cmp	x0, x18
-	b.gt	zero_gd
-#if defined(CONFIG_SYS_MALLOC_F_LEN)
-	ldr	x0, =CONFIG_SYS_MALLOC_F_LEN
-	sub	x0, x18, x0
-	str	x0, [x18, #GD_MALLOC_BASE]
-#endif
 	bic	sp, x0, #0xf	/* 16-byte alignment for ABI compliance */
+	bl	board_init_f_mem
+	mov	sp, x0
+
 	mov	x0, #0
 	bl	board_init_f
 
diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c
index e7df6d3..7bdac3b 100644
--- a/arch/arm/mach-zynq/spl.c
+++ b/arch/arm/mach-zynq/spl.c
@@ -20,7 +20,6 @@
 	/* Clear the BSS. */
 	memset(__bss_start, 0, __bss_end - __bss_start);
 
-	preloader_console_init();
 	arch_cpu_init();
 	board_init_r(NULL, 0);
 }
@@ -28,6 +27,7 @@
 #ifdef CONFIG_SPL_BOARD_INIT
 void spl_board_init(void)
 {
+	preloader_console_init();
 	board_init();
 }
 #endif
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S
index 953d3a1..14f46a8 100644
--- a/arch/microblaze/cpu/start.S
+++ b/arch/microblaze/cpu/start.S
@@ -25,6 +25,7 @@
 
 	addi	r8, r0, __end
 	mts	rslr, r8
+	/* TODO: Redo this code to call board_init_f_mem() */
 #if defined(CONFIG_SPL_BUILD)
 	addi	r1, r0, CONFIG_SPL_STACK_ADDR
 	mts	rshr, r1
@@ -141,6 +142,7 @@
 	ori	r12, r12, 0x1a0
 	mts	rmsr, r12
 
+	/* TODO: Redo this code to call board_init_f_mem() */
 clear_bss:
 	/* clear BSS segments */
 	addi	r5, r0, __bss_start
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
index 8ae7f6e..bb4fb2a 100644
--- a/arch/nios2/Kconfig
+++ b/arch/nios2/Kconfig
@@ -4,15 +4,11 @@
 config SYS_ARCH
 	default "nios2"
 
-choice
-	prompt "Target select"
-	optional
-
-config TARGET_NIOS2_GENERIC
-	bool "Support nios2-generic"
-
-endchoice
-
-source "board/altera/nios2-generic/Kconfig"
+config SYS_CONFIG_NAME
+	string "Board header file"
+	help
+	  This option should contain the base name of board header file.
+	  The header file include/configs/<CONFIG_SYS_CONFIG_NAME>.h
+	  should be included from include/config.h.
 
 endmenu
diff --git a/arch/nios2/cpu/Makefile b/arch/nios2/cpu/Makefile
index 3fe7847..185ca3c 100644
--- a/arch/nios2/cpu/Makefile
+++ b/arch/nios2/cpu/Makefile
@@ -7,5 +7,5 @@
 
 extra-y	= start.o
 obj-y	= exceptions.o
-obj-y	+= cpu.o interrupts.o sysid.o traps.o
+obj-y	+= cpu.o interrupts.o traps.o
 obj-y	+= fdt.o
diff --git a/arch/nios2/cpu/cpu.c b/arch/nios2/cpu/cpu.c
index 39ae972..ff0fa20 100644
--- a/arch/nios2/cpu/cpu.c
+++ b/arch/nios2/cpu/cpu.c
@@ -6,25 +6,18 @@
  */
 
 #include <common.h>
-#include <asm/nios2.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
 #include <asm/cache.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#if defined (CONFIG_SYS_NIOS_SYSID_BASE)
-extern void display_sysid (void);
-#endif /* CONFIG_SYS_NIOS_SYSID_BASE */
-
 #ifdef CONFIG_DISPLAY_CPUINFO
 int print_cpuinfo(void)
 {
-	printf ("CPU   : Nios-II\n");
-#if !defined(CONFIG_SYS_NIOS_SYSID_BASE)
-	printf ("SYSID : <unknown>\n");
-#else
-	display_sysid ();
-#endif
-	return (0);
+	printf("CPU:   Nios-II\n");
+	return 0;
 }
 #endif /* CONFIG_DISPLAY_CPUINFO */
 
@@ -32,29 +25,120 @@
 {
 	disable_interrupts();
 	/* indirect call to go beyond 256MB limitation of toolchain */
-	nios2_callr(CONFIG_SYS_RESET_ADDR);
+	nios2_callr(gd->arch.reset_addr);
 	return 0;
 }
 
-int dcache_status(void)
+/*
+ * COPY EXCEPTION TRAMPOLINE -- copy the tramp to the
+ * exception address. Define CONFIG_ROM_STUBS to prevent
+ * the copy (e.g. exception in flash or in other
+ * softare/firmware component).
+ */
+#ifndef CONFIG_ROM_STUBS
+static void copy_exception_trampoline(void)
+{
+	extern int _except_start, _except_end;
+	void *except_target = (void *)gd->arch.exception_addr;
+
+	if (&_except_start != except_target) {
+		memcpy(except_target, &_except_start,
+		       &_except_end - &_except_start);
+		flush_cache(gd->arch.exception_addr,
+			    &_except_end - &_except_start);
+	}
+}
+#endif
+
+int arch_cpu_init_dm(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_CPU, &dev);
+	if (ret)
+		return ret;
+	if (!dev)
+		return -ENODEV;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+#ifndef CONFIG_ROM_STUBS
+	copy_exception_trampoline();
+#endif
+
+	return 0;
+}
+
+static int altera_nios2_get_desc(struct udevice *dev, char *buf, int size)
+{
+	const char *cpu_name = "Nios-II";
+
+	if (size < strlen(cpu_name))
+		return -ENOSPC;
+	strcpy(buf, cpu_name);
+
+	return 0;
+}
+
+static int altera_nios2_get_info(struct udevice *dev, struct cpu_info *info)
+{
+	info->cpu_freq = gd->cpu_clk;
+	info->features = (1 << CPU_FEAT_L1_CACHE) |
+		(gd->arch.has_mmu ? (1 << CPU_FEAT_MMU) : 0);
+
+	return 0;
+}
+
+static int altera_nios2_get_count(struct udevice *dev)
 {
 	return 1;
 }
 
-void dcache_enable(void)
+static int altera_nios2_probe(struct udevice *dev)
 {
-	flush_dcache(CONFIG_SYS_DCACHE_SIZE, CONFIG_SYS_DCACHELINE_SIZE);
-}
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
 
-void dcache_disable(void)
-{
-	flush_dcache(CONFIG_SYS_DCACHE_SIZE, CONFIG_SYS_DCACHELINE_SIZE);
-}
-
-int arch_cpu_init(void)
-{
-	gd->cpu_clk = CONFIG_SYS_CLK_FREQ;
-	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	gd->cpu_clk = fdtdec_get_int(blob, node,
+		"clock-frequency", 0);
+	gd->arch.dcache_line_size = fdtdec_get_int(blob, node,
+		"dcache-line-size", 0);
+	gd->arch.icache_line_size = fdtdec_get_int(blob, node,
+		"icache-line-size", 0);
+	gd->arch.dcache_size = fdtdec_get_int(blob, node,
+		"dcache-size", 0);
+	gd->arch.icache_size = fdtdec_get_int(blob, node,
+		"icache-size", 0);
+	gd->arch.reset_addr = fdtdec_get_int(blob, node,
+		"altr,reset-addr", 0);
+	gd->arch.exception_addr = fdtdec_get_int(blob, node,
+		"altr,exception-addr", 0);
+	gd->arch.has_initda = fdtdec_get_int(blob, node,
+		"altr,has-initda", 0);
+	gd->arch.has_mmu = fdtdec_get_int(blob, node,
+		"altr,has-mmu", 0);
+	gd->arch.io_region_base = gd->arch.has_mmu ? 0xe0000000 : 0x8000000;
 
 	return 0;
 }
+
+static const struct cpu_ops altera_nios2_ops = {
+	.get_desc	= altera_nios2_get_desc,
+	.get_info	= altera_nios2_get_info,
+	.get_count	= altera_nios2_get_count,
+};
+
+static const struct udevice_id altera_nios2_ids[] = {
+	{ .compatible = "altr,nios2-1.0" },
+	{ .compatible = "altr,nios2-1.1" },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_nios2) = {
+	.name		= "altera_nios2",
+	.id		= UCLASS_CPU,
+	.of_match	= altera_nios2_ids,
+	.probe		= altera_nios2_probe,
+	.ops		= &altera_nios2_ops,
+	.flags		= DM_FLAG_PRE_RELOC,
+};
diff --git a/arch/nios2/cpu/interrupts.c b/arch/nios2/cpu/interrupts.c
index 9d7e193..1599674 100644
--- a/arch/nios2/cpu/interrupts.c
+++ b/arch/nios2/cpu/interrupts.c
@@ -8,43 +8,14 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
-
+#include <common.h>
+#include <command.h>
 #include <asm/nios2.h>
 #include <asm/types.h>
 #include <asm/io.h>
 #include <asm/ptrace.h>
-#include <common.h>
-#include <command.h>
-#include <watchdog.h>
-#ifdef CONFIG_STATUS_LED
-#include <status_led.h>
-#endif
 
-typedef volatile struct {
-	unsigned	status;			/* Timer status reg */
-	unsigned	control;		/* Timer control reg */
-	unsigned	periodl;		/* Timeout period low */
-	unsigned	periodh;		/* Timeout period high */
-	unsigned	snapl;			/* Snapshot low */
-	unsigned	snaph;			/* Snapshot high */
-} nios_timer_t;
-
-/* status register */
-#define NIOS_TIMER_TO		(1 << 0)	/* Timeout */
-#define NIOS_TIMER_RUN		(1 << 1)	/* Timer running */
-
-/* control register */
-#define NIOS_TIMER_ITO		(1 << 0)	/* Timeout int ena */
-#define NIOS_TIMER_CONT		(1 << 1)	/* Continuous mode */
-#define NIOS_TIMER_START	(1 << 2)	/* Start timer */
-#define NIOS_TIMER_STOP		(1 << 3)	/* Stop timer */
-
-#if defined(CONFIG_SYS_NIOS_TMRBASE) && !defined(CONFIG_SYS_NIOS_TMRIRQ)
-#error CONFIG_SYS_NIOS_TMRIRQ not defined (see documentation)
-#endif
-
-/****************************************************************************/
-
+/*************************************************************************/
 struct	irq_action {
 	interrupt_handler_t *handler;
 	void *arg;
@@ -53,111 +24,6 @@
 
 static struct irq_action vecs[32];
 
-/*************************************************************************/
-volatile ulong timestamp = 0;
-
-void reset_timer (void)
-{
-	nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
-
-	/* From Embedded Peripherals Handbook:
-	 *
-	 * "When the hardware is configured with Writeable period
-	 * disabled, writing to one of the period_n registers causes
-	 * the counter to reset to the fixed Timeout Period specified
-	 * at system generation time."
-	 *
-	 * Here we force a reload to prevent early timeouts from
-	 * get_timer() when the interrupt period is greater than
-	 * than 1 msec.
-	 *
-	 * Simply write to periodl with its own value to force an
-	 * internal counter reload, THEN reset the timestamp.
-	 */
-	writel (readl (&tmr->periodl), &tmr->periodl);
-	timestamp = 0;
-
-	/* From Embedded Peripherals Handbook:
-	 *
-	 * "Writing to one of the period_n registers stops the internal
-	 * counter, except when the hardware is configured with Start/Stop
-	 * control bits off. If Start/Stop control bits is off, writing
-	 * either register does not stop the counter."
-	 *
-	 * In order to accomodate either configuration, the control
-	 * register is re-written. If the counter is stopped, it will
-	 * be restarted. If it is running, the write is essentially
-	 * a nop.
-	 */
-	writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
-			&tmr->control);
-
-}
-
-ulong get_timer (ulong base)
-{
-	WATCHDOG_RESET ();
-	return (timestamp - base);
-}
-
-/*
- * This function is derived from Blackfin code (read timebase as long long).
- * On Nios2 it just returns the timer value.
- */
-unsigned long long get_ticks(void)
-{
-	return get_timer(0);
-}
-
-/*
- * This function is derived from Blackfin code.
- * On Nios2 it returns the number of timer ticks per second.
- */
-ulong get_tbclk(void)
-{
-	ulong tbclk;
-
-	tbclk = CONFIG_SYS_HZ;
-	return tbclk;
-}
-
-/* The board must handle this interrupt if a timer is not
- * provided.
- */
-#if defined(CONFIG_SYS_NIOS_TMRBASE)
-void tmr_isr (void *arg)
-{
-	nios_timer_t *tmr = (nios_timer_t *)arg;
-	/* Interrupt is cleared by writing anything to the
-	 * status register.
-	 */
-	writel (0, &tmr->status);
-	timestamp += CONFIG_SYS_NIOS_TMRMS;
-#ifdef CONFIG_STATUS_LED
-	status_led_tick(timestamp);
-#endif
-}
-
-static void tmr_init (void)
-{
-	nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
-
-	writel (0, &tmr->status);
-	writel (0, &tmr->control);
-	writel (NIOS_TIMER_STOP, &tmr->control);
-
-#if defined(CONFIG_SYS_NIOS_TMRCNT)
-	writel (CONFIG_SYS_NIOS_TMRCNT & 0xffff, &tmr->periodl);
-	writel ((CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff, &tmr->periodh);
-#endif
-	writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
-			&tmr->control);
-	irq_install_handler (CONFIG_SYS_NIOS_TMRIRQ, tmr_isr, (void *)tmr);
-}
-
-#endif /* CONFIG_SYS_NIOS_TMRBASE */
-
-/*************************************************************************/
 int disable_interrupts (void)
 {
 	int val = rdctl (CTL_STATUS);
@@ -245,10 +111,6 @@
 		vecs[i].count = 0;
 	}
 
-#if defined(CONFIG_SYS_NIOS_TMRBASE)
-	tmr_init ();
-#endif
-
 	enable_interrupts ();
 	return (0);
 }
diff --git a/arch/nios2/cpu/start.S b/arch/nios2/cpu/start.S
index 6af9b4e..8758e7e 100644
--- a/arch/nios2/cpu/start.S
+++ b/arch/nios2/cpu/start.S
@@ -9,30 +9,38 @@
 #include <config.h>
 #include <version.h>
 
-/*************************************************************************
- * RESTART
- ************************************************************************/
+/*
+ * icache and dcache configuration used only for start.S.
+ * the values are chosen so that it will work for all configuration.
+ */
+#define ICACHE_LINE_SIZE	32 /* fixed 32 */
+#define ICACHE_SIZE_MAX		0x10000 /* 64k max */
+#define DCACHE_LINE_SIZE_MIN	4 /* 4, 16, 32 */
+#define DCACHE_SIZE_MAX		0x10000 /* 64k max */
 
+	/* RESTART */
 	.text
-	.global _start
+	.global _start, _except_start, _except_end
 
 _start:
 	wrctl	status, r0		/* Disable interrupts */
-	/* ICACHE INIT -- only the icache line at the reset address
+	/*
+	 * ICACHE INIT -- only the icache line at the reset address
 	 * is invalidated at reset. So the init must stay within
 	 * the cache line size (8 words). If GERMS is used, we'll
 	 * just be invalidating the cache a second time. If cache
 	 * is not implemented initi behaves as nop.
 	 */
-	ori	r4, r0, %lo(CONFIG_SYS_ICACHELINE_SIZE)
-	movhi	r5, %hi(CONFIG_SYS_ICACHE_SIZE)
-	ori	r5, r5, %lo(CONFIG_SYS_ICACHE_SIZE)
+	ori	r4, r0, %lo(ICACHE_LINE_SIZE)
+	movhi	r5, %hi(ICACHE_SIZE_MAX)
+	ori	r5, r5, %lo(ICACHE_SIZE_MAX)
 0:	initi	r5
 	sub	r5, r5, r4
 	bgt	r5, r0, 0b
 	br	_except_end	/* Skip the tramp */
 
-	/* EXCEPTION TRAMPOLINE -- the following gets copied
+	/*
+	 * EXCEPTION TRAMPOLINE -- the following gets copied
 	 * to the exception address (below), but is otherwise at the
 	 * default exception vector offset (0x0020).
 	 */
@@ -42,24 +50,26 @@
 	jmp	et
 _except_end:
 
-	/* INTERRUPTS -- for now, all interrupts masked and globally
+	/*
+	 * INTERRUPTS -- for now, all interrupts masked and globally
 	 * disabled.
 	 */
 	wrctl	ienable, r0		/* All disabled	*/
 
-	/* DCACHE INIT -- if dcache not implemented, initd behaves as
+	/*
+	 * DCACHE INIT -- if dcache not implemented, initd behaves as
 	 * nop.
 	 */
-	movhi	r4, %hi(CONFIG_SYS_DCACHELINE_SIZE)
-	ori	r4, r4, %lo(CONFIG_SYS_DCACHELINE_SIZE)
-	movhi	r5, %hi(CONFIG_SYS_DCACHE_SIZE)
-	ori	r5, r5, %lo(CONFIG_SYS_DCACHE_SIZE)
+	ori	r4, r0, %lo(DCACHE_LINE_SIZE_MIN)
+	movhi	r5, %hi(DCACHE_SIZE_MAX)
+	ori	r5, r5, %lo(DCACHE_SIZE_MAX)
 	mov	r6, r0
 1:	initd	0(r6)
 	add	r6, r6, r4
 	bltu	r6, r5, 1b
 
-	/* RELOCATE CODE, DATA & COMMAND TABLE -- the following code
+	/*
+	 * RELOCATE CODE, DATA & COMMAND TABLE -- the following code
 	 * assumes code, data and the command table are all
 	 * contiguous. This lets us relocate everything as a single
 	 * block. Make sure the linker script matches this ;-)
@@ -73,8 +83,9 @@
 	ori	r5, r5, %lo(_start)	/* r5 <- linked _start */
 	beq	r4, r5, 3f
 
-	movhi	r6, %hi(_edata)
-	ori	r6, r6, %lo(_edata)
+	movhi	r6, %hi(CONFIG_SYS_MONITOR_LEN)
+	ori	r6, r6, %lo(CONFIG_SYS_MONITOR_LEN)
+	add	r6, r6, r5
 2:	ldwio	r7, 0(r4)
 	addi	r4, r4, 4
 	stwio	r7, 0(r5)
@@ -82,50 +93,13 @@
 	bne	r5, r6, 2b
 3:
 
-	/* ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent
-	 * and between __bss_start and __bss_end.
-	 */
-	 movhi	r5, %hi(__bss_start)
-	 ori	r5, r5, %lo(__bss_start)
-	 movhi	r6, %hi(__bss_end)
-	 ori	r6, r6, %lo(__bss_end)
-	 beq	r5, r6, 5f
-
-4:	stwio	r0, 0(r5)
-	 addi	r5, r5, 4
-	 bne	r5, r6, 4b
-5:
-
 	/* JUMP TO RELOC ADDR */
 	movhi	r4, %hi(_reloc)
 	ori	r4, r4, %lo(_reloc)
 	jmp	r4
 _reloc:
 
-	/* COPY EXCEPTION TRAMPOLINE -- copy the tramp to the
-	 * exception address. Define CONFIG_ROM_STUBS to prevent
-	 * the copy (e.g. exception in flash or in other
-	 * softare/firmware component).
-	 */
-#if !defined(CONFIG_ROM_STUBS)
-	movhi	r4, %hi(_except_start)
-	ori	r4, r4, %lo(_except_start)
-	movhi	r5, %hi(_except_end)
-	ori	r5, r5, %lo(_except_end)
-	movhi	r6, %hi(CONFIG_SYS_EXCEPTION_ADDR)
-	ori	r6, r6, %lo(CONFIG_SYS_EXCEPTION_ADDR)
-	beq	r4, r6, 7f	/* Skip if at proper addr */
-
-6:	ldwio	r7, 0(r4)
-	stwio	r7, 0(r6)
-	addi	r4, r4, 4
-	addi	r6, r6, 4
-	bne	r4, r5, 6b
-7:
-#endif
-
-	/* STACK INIT -- zero top two words for call back chain.
-	 */
+	/* STACK INIT -- zero top two words for call back chain. */
 	movhi	sp, %hi(CONFIG_SYS_INIT_SP)
 	ori	sp, sp, %lo(CONFIG_SYS_INIT_SP)
 	addi	sp, sp, -8
@@ -133,80 +107,64 @@
 	stw	r0, 4(sp)
 	mov	fp, sp
 
-	/*
-	 * Call board_init_f -- never returns
-	 */
+	/* Allocate and zero GD, update SP */
+	mov	r4, sp
+	movhi	r2, %hi(board_init_f_mem@h)
+	ori	r2, r2, %lo(board_init_f_mem@h)
+	callr	r2
+
+	/* Update stack- and frame-pointers */
+	mov	sp, r2
+	mov	fp, sp
+
+	/* Call board_init_f -- never returns */
 	mov	r4, r0
 	movhi	r2, %hi(board_init_f@h)
 	ori	r2, r2, %lo(board_init_f@h)
 	callr	r2
 
-	/* NEVER RETURNS -- but branch to the _start just
+	/*
+	 * NEVER RETURNS -- but branch to the _start just
 	 * in case ;-)
 	 */
 	br	_start
 
-
-
-/*
- * relocate_code -- Nios2 handles the relocation above. But
- * the generic board code monkeys with the heap, stack, etc.
- * (it makes some assumptions that may not be appropriate
- * for Nios). Nevertheless, we capitulate here.
- *
- * We'll call the board_init_r from here since this isn't
- * supposed to return.
- *
- * void relocate_code (ulong sp, gd_t *global_data,
- *			ulong reloc_addr)
- *			__attribute__ ((noreturn));
- */
+	/*
+	 * relocate_code -- Nios2 handles the relocation above. But
+	 * the generic board code monkeys with the heap, stack, etc.
+	 * (it makes some assumptions that may not be appropriate
+	 * for Nios). Nevertheless, we capitulate here.
+	 *
+	 * We'll call the board_init_r from here since this isn't
+	 * supposed to return.
+	 *
+	 * void relocate_code (ulong sp, gd_t *global_data,
+	 *			ulong reloc_addr)
+	 *			__attribute__ ((noreturn));
+	 */
 	.text
 	.global relocate_code
 
 relocate_code:
 	mov	sp, r4		/* Set the new sp */
 	mov	r4, r5
+
+	/*
+	 * ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent
+	 * and between __bss_start and __bss_end.
+	 */
+	movhi	r5, %hi(__bss_start)
+	ori	r5, r5, %lo(__bss_start)
+	movhi	r6, %hi(__bss_end)
+	ori	r6, r6, %lo(__bss_end)
+	beq	r5, r6, 5f
+
+4:	stwio	r0, 0(r5)
+	addi	r5, r5, 4
+	bne	r5, r6, 4b
+5:
+
 	movhi	r8, %hi(board_init_r@h)
 	ori	r8, r8, %lo(board_init_r@h)
 	callr	r8
 	ret
-
-/*
- * dly_clks -- Nios2 (like Nios1) doesn't have a timebase in
- * the core. For simple delay loops, we do our best by counting
- * instruction cycles.
- *
- * Instruction performance varies based on the core. For cores
- * with icache and static/dynamic branch prediction (II/f, II/s):
- *
- *	Normal ALU (e.g. add, cmp, etc):	1 cycle
- *	Branch (correctly predicted, taken):	2 cycles
- *	Negative offset is predicted (II/s).
- *
- * For cores without icache and no branch prediction (II/e):
- *
- *	Normal ALU (e.g. add, cmp, etc):	6 cycles
- *	Branch (no prediction):			6 cycles
- *
- * For simplicity, if an instruction cache is implemented we
- * assume II/f or II/s. Otherwise, we use the II/e.
- *
- */
-	.globl dly_clks
-
-dly_clks:
-
-#if (CONFIG_SYS_ICACHE_SIZE > 0)
-	subi	r4, r4, 3		/* 3 clocks/loop	*/
-#else
-	subi	r4, r4, 12		/* 12 clocks/loop	*/
-#endif
-	bge	r4, r0, dly_clks
-	ret
-
-	.data
-	.globl	version_string
-
-version_string:
-	.ascii U_BOOT_VERSION_STRING, "\0"
diff --git a/arch/nios2/cpu/sysid.c b/arch/nios2/cpu/sysid.c
deleted file mode 100644
index 50819b2..0000000
--- a/arch/nios2/cpu/sysid.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
- * Scott McNutt <smcnutt@psyent.com>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include <common.h>
-
-#if defined (CONFIG_SYS_NIOS_SYSID_BASE)
-
-#include <command.h>
-#include <asm/io.h>
-#include <linux/time.h>
-
-typedef volatile struct {
-	unsigned	id;			/* The system build id */
-	unsigned	timestamp;		/* Timestamp */
-} nios_sysid_t;
-
-void display_sysid (void)
-{
-	nios_sysid_t *sysid = (nios_sysid_t *)CONFIG_SYS_NIOS_SYSID_BASE;
-	struct tm t;
-	char asc[32];
-	time_t stamp;
-
-	stamp = readl (&sysid->timestamp);
-	localtime_r (&stamp, &t);
-	asctime_r (&t, asc);
-	printf ("SYSID : %08lx, %s", readl (&sysid->id), asc);
-
-}
-
-int do_sysid (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	display_sysid ();
-	return (0);
-}
-
-U_BOOT_CMD(
-	sysid,	1,	1,	do_sysid,
-	"display Nios-II system id",
-	""
-);
-#endif /* CONFIG_SYS_NIOS_SYSID_BASE */
diff --git a/arch/nios2/cpu/u-boot.lds b/arch/nios2/cpu/u-boot.lds
index 6e174be..3bd3f2c 100644
--- a/arch/nios2/cpu/u-boot.lds
+++ b/arch/nios2/cpu/u-boot.lds
@@ -50,9 +50,11 @@
 	  *(.gnu.linkonce.d*)
 	}
 
-	. = ALIGN(16);
-	_gp = .;			/* Global pointer addr */
-	PROVIDE (gp = .);
+	/*
+	 * gp - Since we don't use gp for small data with option "-G0",
+	 * we will use gp as global data pointer. The _gp location is
+	 * not needed.
+	 */
 
 	.sdata :
 	{
@@ -65,6 +67,12 @@
 	_edata = .;
 	PROVIDE (edata = .);
 
+	/*
+	 * _end - This is end of u-boot.bin image.
+	 * dtb will be appended here to make u-boot-dtb.bin
+	 */
+	_end = .;
+
 	/* UNINIT DATA - Small uninitialized data is first so it's
 	 * adjacent to sdata and can be referenced via gp. The normal
 	 * bss follows. We keep it adjacent to simplify init code.
diff --git a/arch/nios2/dts/.gitignore b/arch/nios2/dts/.gitignore
new file mode 100644
index 0000000..b60ed20
--- /dev/null
+++ b/arch/nios2/dts/.gitignore
@@ -0,0 +1 @@
+*.dtb
diff --git a/arch/nios2/dts/3c120_devboard.dts b/arch/nios2/dts/3c120_devboard.dts
new file mode 100644
index 0000000..a3cfacb
--- /dev/null
+++ b/arch/nios2/dts/3c120_devboard.dts
@@ -0,0 +1,201 @@
+/*
+ *  Copyright (C) 2013 Altera Corporation
+ *
+ * This file is generated by sopc2dts.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/dts-v1/;
+
+/ {
+	model = "altr,qsys_ghrd_3c120";
+	compatible = "altr,qsys_ghrd_3c120";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu: cpu@0x0 {
+			device_type = "cpu";
+			compatible = "altr,nios2-1.0";
+			reg = <0x00000000>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			clock-frequency = <125000000>;
+			dcache-line-size = <32>;
+			icache-line-size = <32>;
+			dcache-size = <32768>;
+			icache-size = <32768>;
+			altr,implementation = "fast";
+			altr,pid-num-bits = <8>;
+			altr,tlb-num-ways = <16>;
+			altr,tlb-num-entries = <128>;
+			altr,tlb-ptr-sz = <7>;
+			altr,has-div = <1>;
+			altr,has-mul = <1>;
+			altr,reset-addr = <0xc2800000>;
+			altr,fast-tlb-miss-addr = <0xc7fff400>;
+			altr,exception-addr = <0xd0000020>;
+			altr,has-initda = <1>;
+			altr,has-mmu = <1>;
+		};
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x10000000 0x08000000>,
+			<0x07fff400 0x00000400>;
+	};
+
+	sopc@0 {
+		device_type = "soc";
+		ranges;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "altr,avalon", "simple-bus";
+		bus-frequency = <125000000>;
+
+		pb_cpu_to_io: bridge@0x8000000 {
+			compatible = "simple-bus";
+			reg = <0x08000000 0x00800000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x00002000 0x08002000 0x00002000>,
+				<0x00004000 0x08004000 0x00000400>,
+				<0x00004400 0x08004400 0x00000040>,
+				<0x00004800 0x08004800 0x00000040>,
+				<0x00004c80 0x08004c80 0x00000020>,
+				<0x00004cc0 0x08004cc0 0x00000010>,
+				<0x00004ce0 0x08004ce0 0x00000010>,
+				<0x00004d00 0x08004d00 0x00000010>,
+				<0x00004d40 0x08004d40 0x00000008>,
+				<0x00004d50 0x08004d50 0x00000008>,
+				<0x00008000 0x08008000 0x00000020>,
+				<0x00400000 0x08400000 0x00000020>;
+
+			timer_1ms: timer@0x400000 {
+				compatible = "altr,timer-1.0";
+				reg = <0x00400000 0x00000020>;
+				interrupt-parent = <&cpu>;
+				interrupts = <11>;
+				clock-frequency = <125000000>;
+			};
+
+			timer_0: timer@0x8000 {
+				compatible = "altr,timer-1.0";
+				reg = < 0x00008000 0x00000020 >;
+				interrupt-parent = < &cpu >;
+				interrupts = < 5 >;
+				clock-frequency = < 125000000 >;
+			};
+
+			sysid: sysid@0x4d40 {
+				compatible = "altr,sysid-1.0";
+				reg = <0x00004d40 0x00000008>;
+			};
+
+			jtag_uart: serial@0x4d50 {
+				compatible = "altr,juart-1.0";
+				reg = <0x00004d50 0x00000008>;
+				interrupt-parent = <&cpu>;
+				interrupts = <1>;
+			};
+
+			tse_mac: ethernet@0x4000 {
+				compatible = "altr,tse-1.0";
+				reg = <0x00004000 0x00000400>,
+					<0x00004400 0x00000040>,
+					<0x00004800 0x00000040>,
+					<0x00002000 0x00002000>;
+				reg-names = "control_port", "rx_csr", "tx_csr", "s1";
+				interrupt-parent = <&cpu>;
+				interrupts = <2 3>;
+				interrupt-names = "rx_irq", "tx_irq";
+				rx-fifo-depth = <8192>;
+				tx-fifo-depth = <8192>;
+				max-frame-size = <1518>;
+				local-mac-address = [ 00 00 00 00 00 00 ];
+				phy-mode = "rgmii-id";
+				phy-handle = <&phy0>;
+				tse_mac_mdio: mdio {
+					compatible = "altr,tse-mdio";
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy0: ethernet-phy@18 {
+						reg = <18>;
+						device_type = "ethernet-phy";
+					};
+				};
+			};
+
+			uart: serial@0x4c80 {
+				compatible = "altr,uart-1.0";
+				reg = <0x00004c80 0x00000020>;
+				interrupt-parent = <&cpu>;
+				interrupts = <10>;
+				current-speed = <115200>;
+				clock-frequency = <62500000>;
+			};
+
+			user_led_pio_8out: gpio@0x4cc0 {
+				compatible = "altr,pio-1.0";
+				reg = <0x00004cc0 0x00000010>;
+				resetvalue = <255>;
+				altr,gpio-bank-width = <8>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				gpio-bank-name = "led";
+			};
+
+			user_dipsw_pio_8in: gpio@0x4ce0 {
+				compatible = "altr,pio-1.0";
+				reg = <0x00004ce0 0x00000010>;
+				interrupt-parent = <&cpu>;
+				interrupts = <8>;
+				edge_type = <2>;
+				level_trigger = <0>;
+				resetvalue = <0>;
+				altr,gpio-bank-width = <8>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				gpio-bank-name = "dipsw";
+			};
+
+			user_pb_pio_4in: gpio@0x4d00 {
+				compatible = "altr,pio-1.0";
+				reg = <0x00004d00 0x00000010>;
+				interrupt-parent = <&cpu>;
+				interrupts = <9>;
+				edge_type = <2>;
+				level_trigger = <0>;
+				resetvalue = <0>;
+				altr,gpio-bank-width = <4>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				gpio-bank-name = "pb";
+			};
+		};
+
+		cfi_flash_64m: flash@0x0 {
+			compatible = "cfi-flash";
+			reg = <0x00000000 0x04000000>;
+			bank-width = <2>;
+			device-width = <1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@800000 {
+				reg = <0x00800000 0x01e00000>;
+				label = "JFFS2 Filesystem";
+			};
+		};
+	};
+
+	chosen {
+		bootargs = "debug console=ttyJ0,115200";
+		stdout-path = &jtag_uart;
+	};
+};
diff --git a/arch/nios2/dts/Makefile b/arch/nios2/dts/Makefile
new file mode 100644
index 0000000..b40eca9
--- /dev/null
+++ b/arch/nios2/dts/Makefile
@@ -0,0 +1,11 @@
+dtb-y += $(CONFIG_DEFAULT_DEVICE_TREE:"%"=%).dtb
+
+targets += $(dtb-y)
+
+DTC_FLAGS += -R 4 -p 0x1000
+
+PHONY += dtbs
+dtbs: $(addprefix $(obj)/, $(dtb-y))
+	@:
+
+clean-files := *.dtb
diff --git a/arch/nios2/dts/include/dt-bindings b/arch/nios2/dts/include/dt-bindings
new file mode 120000
index 0000000..0cecb3d
--- /dev/null
+++ b/arch/nios2/dts/include/dt-bindings
@@ -0,0 +1 @@
+../../../../include/dt-bindings
\ No newline at end of file
diff --git a/arch/nios2/include/asm/cache.h b/arch/nios2/include/asm/cache.h
index 9b87c9f..dde43cd 100644
--- a/arch/nios2/include/asm/cache.h
+++ b/arch/nios2/include/asm/cache.h
@@ -8,18 +8,11 @@
 #ifndef __ASM_NIOS2_CACHE_H_
 #define __ASM_NIOS2_CACHE_H_
 
-extern void flush_dcache (unsigned long start, unsigned long size);
-extern void flush_icache (unsigned long start, unsigned long size);
-
 /*
- * Valid L1 data cache line sizes for the NIOS2 architecture are 4, 16, and 32
- * bytes.  If the board configuration has not specified one we default to the
- * largest of these values for alignment of DMA buffers.
+ * Valid L1 data cache line sizes for the NIOS2 architecture are 4,
+ * 16, and 32 bytes. We default to the largest of these values for
+ * alignment of DMA buffers.
  */
-#ifdef CONFIG_SYS_CACHELINE_SIZE
-#define ARCH_DMA_MINALIGN	CONFIG_SYS_CACHELINE_SIZE
-#else
 #define ARCH_DMA_MINALIGN	32
-#endif
 
 #endif /* __ASM_NIOS2_CACHE_H_ */
diff --git a/arch/nios2/include/asm/config.h b/arch/nios2/include/asm/config.h
index 9c13848..cd29734 100644
--- a/arch/nios2/include/asm/config.h
+++ b/arch/nios2/include/asm/config.h
@@ -7,6 +7,4 @@
 #ifndef _ASM_CONFIG_H_
 #define _ASM_CONFIG_H_
 
-#define CONFIG_SYS_GENERIC_GLOBAL_DATA
-
 #endif
diff --git a/arch/nios2/include/asm/dma-mapping.h b/arch/nios2/include/asm/dma-mapping.h
index 1350e3b..1562d35 100644
--- a/arch/nios2/include/asm/dma-mapping.h
+++ b/arch/nios2/include/asm/dma-mapping.h
@@ -1,23 +1,24 @@
 #ifndef __ASM_NIOS2_DMA_MAPPING_H
 #define __ASM_NIOS2_DMA_MAPPING_H
 
-/* dma_alloc_coherent() return cache-line aligned allocation which is mapped
- * to uncached io region.
- *
- * IO_REGION_BASE should be defined in board config header file
- *   0x80000000 for nommu, 0xe0000000 for mmu
- */
+#include <memalign.h>
+#include <asm/io.h>
 
+/*
+ * dma_alloc_coherent() return cache-line aligned allocation which is mapped
+ * to uncached io region.
+ */
 static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	void *addr = malloc(len + CONFIG_SYS_DCACHELINE_SIZE);
-	if (!addr)
-		return 0;
-	flush_dcache((unsigned long)addr, len + CONFIG_SYS_DCACHELINE_SIZE);
-	*handle = ((unsigned long)addr +
-		   (CONFIG_SYS_DCACHELINE_SIZE - 1)) &
-		~(CONFIG_SYS_DCACHELINE_SIZE - 1) & ~(IO_REGION_BASE);
-	return (void *)(*handle | IO_REGION_BASE);
-}
+	unsigned long addr = (unsigned long)malloc_cache_aligned(len);
 
+	if (!addr)
+		return NULL;
+
+	invalidate_dcache_range(addr, addr + len);
+	if (handle)
+		*handle = addr;
+
+	return ioremap(addr, len);
+}
 #endif /* __ASM_NIOS2_DMA_MAPPING_H */
diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h
index 580b019..d6a2cfa 100644
--- a/arch/nios2/include/asm/global_data.h
+++ b/arch/nios2/include/asm/global_data.h
@@ -9,6 +9,15 @@
 
 /* Architecture-specific global data */
 struct arch_global_data {
+	u32 dcache_line_size;
+	u32 icache_line_size;
+	u32 dcache_size;
+	u32 icache_size;
+	u32 reset_addr;
+	u32 exception_addr;
+	int has_initda;
+	int has_mmu;
+	u32 io_region_base;
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/nios2/include/asm/gpio.h b/arch/nios2/include/asm/gpio.h
index 908381f..306ab4c 100644
--- a/arch/nios2/include/asm/gpio.h
+++ b/arch/nios2/include/asm/gpio.h
@@ -1,79 +1 @@
-/*
- * nios2 gpio driver
- *
- * This gpio core is described in http://nioswiki.com/GPIO
- * bit[0] data
- * bit[1] output enable
- *
- * When CONFIG_SYS_GPIO_BASE is not defined, the board may either
- * provide its own driver or the altera_pio driver may be used.
- *
- * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _ASM_NIOS2_GPIO_H_
-#define _ASM_NIOS2_GPIO_H_
-
-#ifdef CONFIG_SYS_GPIO_BASE
-#include <asm/io.h>
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-	return 0;
-}
-
-static inline int gpio_free(unsigned gpio)
-{
-	return 0;
-}
-
-static inline int gpio_direction_input(unsigned gpio)
-{
-	writel(1, CONFIG_SYS_GPIO_BASE + (gpio << 2));
-	return 0;
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-	writel(value ? 3 : 2, CONFIG_SYS_GPIO_BASE + (gpio << 2));
-	return 0;
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-	return readl(CONFIG_SYS_GPIO_BASE + (gpio << 2));
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-	writel(value ? 3 : 2, CONFIG_SYS_GPIO_BASE + (gpio << 2));
-}
-
-static inline int gpio_is_valid(int number)
-{
-	return ((unsigned)number) < CONFIG_SYS_GPIO_WIDTH;
-}
-#else
-#ifdef CONFIG_ALTERA_PIO
-extern int altera_pio_init(u32 base, u8 width, char iot,
-			   u32 rstval, u32 negmask,
-			   const char *label);
-
-extern void altera_pio_info(void);
-#define gpio_status() altera_pio_info()
-#endif
-
-extern int gpio_request(unsigned gpio, const char *label);
-extern int gpio_free(unsigned gpio);
-extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio, int value);
-extern int gpio_get_value(unsigned gpio);
-extern void gpio_set_value(unsigned gpio, int value);
-extern int gpio_is_valid(int number);
-#endif /* CONFIG_SYS_GPIO_BASE */
-
-#endif /* _ASM_NIOS2_GPIO_H_ */
+#include <asm-generic/gpio.h>
diff --git a/arch/nios2/include/asm/io.h b/arch/nios2/include/asm/io.h
index 69ab23e..e7da35b 100644
--- a/arch/nios2/include/asm/io.h
+++ b/arch/nios2/include/asm/io.h
@@ -39,12 +39,18 @@
 
 static inline phys_addr_t virt_to_phys(void * vaddr)
 {
-	return (phys_addr_t)(vaddr);
+	DECLARE_GLOBAL_DATA_PTR;
+	if (gd->arch.has_mmu)
+		return (phys_addr_t)vaddr & 0x1fffffff;
+	else
+		return (phys_addr_t)vaddr & 0x7fffffff;
 }
 
-extern unsigned char inb (unsigned char *port);
-extern unsigned short inw (unsigned short *port);
-extern unsigned inl (unsigned port);
+static inline void *ioremap(unsigned long physaddr, unsigned long size)
+{
+	DECLARE_GLOBAL_DATA_PTR;
+	return (void *)(gd->arch.io_region_base | physaddr);
+}
 
 #define __raw_writeb(v,a)       (*(volatile unsigned char  *)(a) = (v))
 #define __raw_writew(v,a)       (*(volatile unsigned short *)(a) = (v))
@@ -111,4 +117,59 @@
 	while (count--) outl (*p++, port);
 }
 
+/*
+ * Clear and set bits in one shot. These macros can be used to clear and
+ * set multiple bits in a register using a single call. These macros can
+ * also be used to set a multiple-bit bit pattern using a mask, by
+ * specifying the mask in the 'clear' parameter and the new bit pattern
+ * in the 'set' parameter.
+ */
+
+#define out_arch(type,endian,a,v)	__raw_write##type(cpu_to_##endian(v),a)
+#define in_arch(type,endian,a)		endian##_to_cpu(__raw_read##type(a))
+
+#define out_le32(a,v)	out_arch(l,le32,a,v)
+#define out_le16(a,v)	out_arch(w,le16,a,v)
+
+#define in_le32(a)	in_arch(l,le32,a)
+#define in_le16(a)	in_arch(w,le16,a)
+
+#define out_be32(a,v)	out_arch(l,be32,a,v)
+#define out_be16(a,v)	out_arch(w,be16,a,v)
+
+#define in_be32(a)	in_arch(l,be32,a)
+#define in_be16(a)	in_arch(w,be16,a)
+
+#define out_8(a,v)	__raw_writeb(v,a)
+#define in_8(a)		__raw_readb(a)
+
+#define clrbits(type, addr, clear) \
+	out_##type((addr), in_##type(addr) & ~(clear))
+
+#define setbits(type, addr, set) \
+	out_##type((addr), in_##type(addr) | (set))
+
+#define clrsetbits(type, addr, clear, set) \
+	out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
+
+#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
+#define setbits_be32(addr, set) setbits(be32, addr, set)
+#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
+
+#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
+#define setbits_le32(addr, set) setbits(le32, addr, set)
+#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
+
+#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
+#define setbits_be16(addr, set) setbits(be16, addr, set)
+#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
+
+#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
+#define setbits_le16(addr, set) setbits(le16, addr, set)
+#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
+
+#define clrbits_8(addr, clear) clrbits(8, addr, clear)
+#define setbits_8(addr, set) setbits(8, addr, set)
+#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
+
 #endif /* __ASM_NIOS2_IO_H_ */
diff --git a/arch/nios2/include/asm/psr.h b/arch/nios2/include/asm/psr.h
deleted file mode 100644
index 3ebb2a0..0000000
--- a/arch/nios2/include/asm/psr.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
- * Scott McNutt <smcnutt@psyent.com>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#ifndef __ASM_NIOS2_PSR_H_
-#define __ASM_NIOS2_PSR_H_
-
-
-#endif /* __ASM_NIOS2_PSR_H_ */
diff --git a/arch/nios2/include/asm/sections.h b/arch/nios2/include/asm/sections.h
index f0da75d..2b8c516 100644
--- a/arch/nios2/include/asm/sections.h
+++ b/arch/nios2/include/asm/sections.h
@@ -1,11 +1 @@
-/*
- * Copyright (c) 2012 The Chromium OS Authors.
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#ifndef __ASM_NIOS2_SECTIONS_H
-#define __ASM_NIOS2_SECTIONS_H
-
 #include <asm-generic/sections.h>
-
-#endif
diff --git a/arch/nios2/include/asm/system.h b/arch/nios2/include/asm/system.h
index 6213a16..b158535 100644
--- a/arch/nios2/include/asm/system.h
+++ b/arch/nios2/include/asm/system.h
@@ -45,4 +45,6 @@
 	"callr	%0"					\
 	: : "r" (addr))
 
+void display_sysid(void);
+
 #endif /* __ASM_NIOS2_SYSTEM_H */
diff --git a/arch/nios2/include/asm/unaligned.h b/arch/nios2/include/asm/unaligned.h
index 779117c..6cecbbb 100644
--- a/arch/nios2/include/asm/unaligned.h
+++ b/arch/nios2/include/asm/unaligned.h
@@ -1,6 +1 @@
-#ifndef _ASM_NIOS2_UNALIGNED_H
-#define _ASM_NIOS2_UNALIGNED_H
-
 #include <asm-generic/unaligned.h>
-
-#endif /* _ASM_NIOS2_UNALIGNED_H */
diff --git a/arch/nios2/lib/Makefile b/arch/nios2/lib/Makefile
index 079378a..e35d2e9 100644
--- a/arch/nios2/lib/Makefile
+++ b/arch/nios2/lib/Makefile
@@ -8,4 +8,3 @@
 obj-y	+= cache.o
 obj-$(CONFIG_CMD_BOOTM) += bootm.o
 obj-y	+= libgcc.o
-obj-y	+= time.o
diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c
index c730a3f..4e5c269 100644
--- a/arch/nios2/lib/bootm.c
+++ b/arch/nios2/lib/bootm.c
@@ -6,9 +6,6 @@
  */
 
 #include <common.h>
-#include <command.h>
-#include <asm/byteorder.h>
-#include <asm/cache.h>
 
 #define NIOS_MAGIC 0x534f494e /* enable command line and initrd passing */
 
@@ -40,8 +37,7 @@
 
 	/* flushes data and instruction caches before calling the kernel */
 	disable_interrupts();
-	flush_dcache((ulong)kernel, CONFIG_SYS_DCACHE_SIZE);
-	flush_icache((ulong)kernel, CONFIG_SYS_ICACHE_SIZE);
+	flush_dcache_all();
 
 	debug("bootargs=%s @ 0x%lx\n", commandline, (ulong)&commandline);
 	debug("initrd=0x%lx-0x%lx\n", (ulong)initrd_start, (ulong)initrd_end);
diff --git a/arch/nios2/lib/cache.S b/arch/nios2/lib/cache.S
deleted file mode 100644
index 683f005..0000000
--- a/arch/nios2/lib/cache.S
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
- * Scott McNutt <smcnutt@psyent.com>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include <config.h>
-
-	.text
-
-	.global flush_dcache
-
-flush_dcache:
-	add	r5, r5, r4
-	movhi	r8, %hi(CONFIG_SYS_DCACHELINE_SIZE)
-	ori	r8, r8, %lo(CONFIG_SYS_DCACHELINE_SIZE)
-0:	flushd	0(r4)
-	add	r4, r4, r8
-	bltu	r4, r5, 0b
-	ret
-
-
-	.global flush_icache
-
-flush_icache:
-	add	r5, r5, r4
-	movhi	r8, %hi(CONFIG_SYS_ICACHELINE_SIZE)
-	ori	r8, r8, %lo(CONFIG_SYS_ICACHELINE_SIZE)
-1:	flushi	r4
-	add	r4, r4, r8
-	bltu	r4, r5, 1b
-	ret
-
-	.global flush_dcache_range
-
-flush_dcache_range:
-	movhi	r8, %hi(CONFIG_SYS_DCACHELINE_SIZE)
-	ori	r8, r8, %lo(CONFIG_SYS_DCACHELINE_SIZE)
-0:	flushd	0(r4)
-	add	r4, r4, r8
-	bltu	r4, r5, 0b
-	ret
-
-	.global flush_cache
-
-flush_cache:
-	add	r5, r5, r4
-	mov	r9, r4
-	mov	r10, r5
-
-	movhi	r8, %hi(CONFIG_SYS_DCACHELINE_SIZE)
-	ori	r8, r8, %lo(CONFIG_SYS_DCACHELINE_SIZE)
-0:	flushd	0(r4)
-	add	r4, r4, r8
-	bltu	r4, r5, 0b
-
-	mov	r4, r9
-	mov	r5, r10
-	movhi	r8, %hi(CONFIG_SYS_ICACHELINE_SIZE)
-	ori	r8, r8, %lo(CONFIG_SYS_ICACHELINE_SIZE)
-1:	flushi	r4
-	add	r4, r4, r8
-	bltu	r4, r5, 1b
-
-	sync
-	flushp
-	ret
diff --git a/arch/nios2/lib/cache.c b/arch/nios2/lib/cache.c
new file mode 100644
index 0000000..7c74e1a
--- /dev/null
+++ b/arch/nios2/lib/cache.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright (C) 2009, Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/cache.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void __flush_dcache(unsigned long start, unsigned long end)
+{
+	unsigned long addr;
+
+	start &= ~(gd->arch.dcache_line_size - 1);
+	end += (gd->arch.dcache_line_size - 1);
+	end &= ~(gd->arch.dcache_line_size - 1);
+
+	for (addr = start; addr < end; addr += gd->arch.dcache_line_size) {
+		__asm__ __volatile__ ("   flushda 0(%0)\n"
+					: /* Outputs */
+					: /* Inputs  */ "r"(addr)
+					/* : No clobber */);
+	}
+}
+
+static void __flush_dcache_all(unsigned long start, unsigned long end)
+{
+	unsigned long addr;
+
+	start &= ~(gd->arch.dcache_line_size - 1);
+	end += (gd->arch.dcache_line_size - 1);
+	end &= ~(gd->arch.dcache_line_size - 1);
+
+	if (end > start + gd->arch.dcache_size)
+		end = start + gd->arch.dcache_size;
+
+	for (addr = start; addr < end; addr += gd->arch.dcache_line_size) {
+		__asm__ __volatile__ ("   flushd 0(%0)\n"
+					: /* Outputs */
+					: /* Inputs  */ "r"(addr)
+					/* : No clobber */);
+	}
+}
+
+static void __invalidate_dcache(unsigned long start, unsigned long end)
+{
+	unsigned long addr;
+
+	start &= ~(gd->arch.dcache_line_size - 1);
+	end += (gd->arch.dcache_line_size - 1);
+	end &= ~(gd->arch.dcache_line_size - 1);
+
+	for (addr = start; addr < end; addr += gd->arch.dcache_line_size) {
+		__asm__ __volatile__ ("   initda 0(%0)\n"
+					: /* Outputs */
+					: /* Inputs  */ "r"(addr)
+					/* : No clobber */);
+	}
+}
+
+static void __flush_icache(unsigned long start, unsigned long end)
+{
+	unsigned long addr;
+
+	start &= ~(gd->arch.icache_line_size - 1);
+	end += (gd->arch.icache_line_size - 1);
+	end &= ~(gd->arch.icache_line_size - 1);
+
+	if (end > start + gd->arch.icache_size)
+		end = start + gd->arch.icache_size;
+
+	for (addr = start; addr < end; addr += gd->arch.icache_line_size) {
+		__asm__ __volatile__ ("   flushi %0\n"
+					: /* Outputs */
+					: /* Inputs  */ "r"(addr)
+					/* : No clobber */);
+	}
+	__asm__ __volatile(" flushp\n");
+}
+
+void flush_dcache_all(void)
+{
+	__flush_dcache_all(0, gd->arch.dcache_size);
+	__flush_icache(0, gd->arch.icache_size);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long end)
+{
+	if (gd->arch.has_initda)
+		__flush_dcache(start, end);
+	else
+		__flush_dcache_all(start, end);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	if (gd->arch.has_initda)
+		__flush_dcache(start, start + size);
+	else
+		__flush_dcache_all(start, start + size);
+	__flush_icache(start, start + size);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long end)
+{
+	if (gd->arch.has_initda)
+		__invalidate_dcache(start, end);
+	else
+		__flush_dcache_all(start, end);
+}
+
+int dcache_status(void)
+{
+	return 1;
+}
+
+void dcache_enable(void)
+{
+	flush_dcache_all();
+}
+
+void dcache_disable(void)
+{
+	flush_dcache_all();
+}
diff --git a/arch/nios2/lib/time.c b/arch/nios2/lib/time.c
deleted file mode 100644
index d396045..0000000
--- a/arch/nios2/lib/time.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * (C) Copyright 2003, Psyent Corporation <www.psyent.com>
- * Scott McNutt <smcnutt@psyent.com>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include <common.h>
-#include <watchdog.h>
-
-
-extern void dly_clks( unsigned long ticks );
-
-void __udelay(unsigned long usec)
-{
-	/* The Nios core doesn't have a timebase, so we do our
-	 * best for now and call a low-level loop that counts
-	 * cpu clocks.
-	 */
-	unsigned long cnt = (CONFIG_SYS_CLK_FREQ/1000000) * usec;
-	dly_clks (cnt);
-}
diff --git a/board/altera/common/cfide.c b/board/altera/common/cfide.c
deleted file mode 100644
index 40d6a12..0000000
--- a/board/altera/common/cfide.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Altera CF drvier
- *
- * (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <common.h>
-#include <asm/io.h>
-
-#if defined(CONFIG_IDE_RESET) && defined(CONFIG_SYS_CF_CTL_BASE)
-/* ide_set_reset for Altera CF interface */
-#define ALTERA_CF_CTL_STATUS			0
-#define ALTERA_CF_IDE_CTL			4
-#define ALTERA_CF_CTL_STATUS_PRESENT_MSK	(0x1)
-#define ALTERA_CF_CTL_STATUS_POWER_MSK		(0x2)
-#define ALTERA_CF_CTL_STATUS_RESET_MSK		(0x4)
-#define ALTERA_CF_CTL_STATUS_IRQ_EN_MSK	(0x8)
-#define ALTERA_CF_IDE_CTL_IRQ_EN_MSK		(0x1)
-
-void ide_set_reset(int idereset)
-{
-	int i;
-	writel(idereset ? ALTERA_CF_CTL_STATUS_RESET_MSK :
-	       ALTERA_CF_CTL_STATUS_POWER_MSK,
-	       CONFIG_SYS_CF_CTL_BASE + ALTERA_CF_CTL_STATUS);
-	/* wait 500 ms for power to stabilize */
-	for (i = 0; i < 500; i++)
-		udelay(1000);
-}
-#endif
diff --git a/board/altera/nios2-generic/Kconfig b/board/altera/nios2-generic/Kconfig
deleted file mode 100644
index cd3d098..0000000
--- a/board/altera/nios2-generic/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-if TARGET_NIOS2_GENERIC
-
-config SYS_BOARD
-	default "nios2-generic"
-
-config SYS_VENDOR
-	default "altera"
-
-config SYS_CONFIG_NAME
-	default "nios2-generic"
-
-endif
diff --git a/board/altera/nios2-generic/MAINTAINERS b/board/altera/nios2-generic/MAINTAINERS
deleted file mode 100644
index 9cbcba9..0000000
--- a/board/altera/nios2-generic/MAINTAINERS
+++ /dev/null
@@ -1,6 +0,0 @@
-NIOS2-GENERIC BOARD
-M:	Scott McNutt <smcnutt@psyent.com>
-S:	Maintained
-F:	board/altera/nios2-generic/
-F:	include/configs/nios2-generic.h
-F:	configs/nios2-generic_defconfig
diff --git a/board/altera/nios2-generic/Makefile b/board/altera/nios2-generic/Makefile
deleted file mode 100644
index 5e4192c..0000000
--- a/board/altera/nios2-generic/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# (C) Copyright 2001-2006
-# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-# (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw>
-#
-# SPDX-License-Identifier:	GPL-2.0+
-#
-
-obj-y	:= nios2-generic.o
-obj-$(CONFIG_CMD_IDE) += ../common/cfide.o
diff --git a/board/altera/nios2-generic/config.mk b/board/altera/nios2-generic/config.mk
deleted file mode 100644
index a673525..0000000
--- a/board/altera/nios2-generic/config.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# (C) Copyright 2005, Psyent Corporation <www.psyent.com>
-# Scott McNutt <smcnutt@psyent.com>
-#
-# SPDX-License-Identifier:	GPL-2.0+
-#
-
-PLATFORM_CPPFLAGS += -mno-hw-div -mno-hw-mul
-
-ifeq ($(debug),1)
-PLATFORM_CPPFLAGS += -DDEBUG
-endif
diff --git a/board/altera/nios2-generic/custom_fpga.h b/board/altera/nios2-generic/custom_fpga.h
deleted file mode 100644
index cf75d35..0000000
--- a/board/altera/nios2-generic/custom_fpga.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * This header is generated by sopc2dts
- * Sopc2dts is written by Walter Goossens <waltergoossens@home.nl>
- * in cooperation with the nios2 community <Nios2-dev@sopc.et.ntust.edu.tw>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-#ifndef _CUSTOM_FPGA_H_
-#define _CUSTOM_FPGA_H_
-
-/* generated from qsys_ghrd_3c120.sopcinfo */
-
-/* Dumping slaves of cpu.data_master */
-
-/* cpu.jtag_debug_module is a altera_nios2_qsys */
-#define CONFIG_SYS_CLK_FREQ	125000000
-#define CONFIG_SYS_DCACHE_SIZE	32768
-#define CONFIG_SYS_DCACHELINE_SIZE	32
-#define CONFIG_SYS_ICACHELINE_SIZE	32
-#define CONFIG_SYS_EXCEPTION_ADDR	0xd0000020
-#define CONFIG_SYS_ICACHE_SIZE	32768
-#define CONFIG_SYS_RESET_ADDR	0xc2800000
-#define IO_REGION_BASE	0xE0000000
-
-/* pb_cpu_to_ddr2_bot.s0 is a altera_avalon_mm_bridge */
-/* Dumping slaves of pb_cpu_to_ddr2_bot.m0 */
-
-/* ddr2_bot.s1 is a altmemddr2 */
-#define CONFIG_SYS_SDRAM_BASE	0xD0000000
-#define CONFIG_SYS_SDRAM_SIZE	0x08000000
-
-/* pb_cpu_to_io.s0 is a altera_avalon_mm_bridge */
-/* Dumping slaves of pb_cpu_to_io.m0 */
-
-/* timer_1ms.s1 is a altera_avalon_timer */
-#define CONFIG_SYS_TIMER_IRQ	11
-#define CONFIG_SYS_TIMER_FREQ	125000000
-#define CONFIG_SYS_TIMER_BASE	0xE8400000
-
-/* sysid.control_slave is a altera_avalon_sysid_qsys */
-#define CONFIG_SYS_SYSID_BASE	0xE8004D40
-
-/* jtag_uart.avalon_jtag_slave is a altera_avalon_jtag_uart */
-#define CONFIG_SYS_JTAG_UART_BASE	0xE8004D50
-
-/* tse_mac.control_port is a triple_speed_ethernet */
-#define CONFIG_SYS_ALTERA_TSE_RX_FIFO	2048
-#define CONFIG_SYS_ALTERA_TSE_SGDMA_TX_BASE	0xE8004800
-#define CONFIG_SYS_ALTERA_TSE_SGDMA_RX_BASE	0xE8004400
-#define CONFIG_SYS_ALTERA_TSE_TX_FIFO	2048
-#define CONFIG_SYS_ALTERA_TSE_DESC_SIZE	0x00002000
-#define CONFIG_SYS_ALTERA_TSE_MAC_BASE	0xE8004000
-#define CONFIG_SYS_ALTERA_TSE_DESC_BASE	0xE8002000
-#define CONFIG_ALTERA_TSE
-#define CONFIG_MII
-#define CONFIG_CMD_MII
-#define CONFIG_SYS_ALTERA_TSE_PHY_ADDR 18
-#define CONFIG_SYS_ALTERA_TSE_FLAGS 1
-
-/* uart.s1 is a altera_avalon_uart */
-#define CONFIG_SYS_UART_BAUD	115200
-#define CONFIG_SYS_UART_BASE	0xE8004C80
-#define CONFIG_SYS_UART_FREQ	62500000
-
-/* user_led_pio_8out.s1 is a altera_avalon_pio */
-#define USER_LED_PIO_8OUT_BASE	0xE8004CC0
-
-/* user_dipsw_pio_8in.s1 is a altera_avalon_pio */
-#define USER_DIPSW_PIO_8IN_BASE	0xE8004CE0
-#define USER_DIPSW_PIO_8IN_IRQ	8
-
-/* user_pb_pio_4in.s1 is a altera_avalon_pio */
-#define USER_PB_PIO_4IN_BASE	0xE8004D00
-#define USER_PB_PIO_4IN_IRQ	9
-
-/* cfi_flash_64m.uas is a altera_generic_tristate_controller */
-#define CFI_FLASH_64M_BASE	0xE0000000
-
-/* ext_flash.s1 is a altera_avalon_cfi_flash */
-#define CONFIG_SYS_FLASH_BASE CFI_FLASH_64M_BASE
-#define CONFIG_FLASH_CFI_DRIVER
-#define CONFIG_SYS_CFI_FLASH_STATUS_POLL /* fix amd flash issue */
-#define CONFIG_SYS_FLASH_CFI
-#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
-#define CONFIG_SYS_FLASH_PROTECTION
-#define CONFIG_SYS_MAX_FLASH_BANKS 1
-#define CONFIG_SYS_MAX_FLASH_SECT 512
-
-#endif /* _CUSTOM_FPGA_H_ */
diff --git a/board/altera/nios2-generic/nios2-generic.c b/board/altera/nios2-generic/nios2-generic.c
deleted file mode 100644
index 834cbeb..0000000
--- a/board/altera/nios2-generic/nios2-generic.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * (C) Copyright 2005, Psyent Corporation <www.psyent.com>
- * Scott McNutt <smcnutt@psyent.com>
- * (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw>
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#include <common.h>
-#include <netdev.h>
-#if defined(CONFIG_CFI_FLASH_MTD)
-#include <mtd/cfi_flash.h>
-#endif
-#include <asm/io.h>
-#include <asm/gpio.h>
-
-#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR) && \
-    defined(CONFIG_CFI_FLASH_MTD)
-static void __early_flash_cmd_reset(void)
-{
-	/* reset flash before we read env */
-	writeb(AMD_CMD_RESET, CONFIG_ENV_ADDR);
-	writeb(FLASH_CMD_RESET, CONFIG_ENV_ADDR);
-}
-void early_flash_cmd_reset(void)
-	__attribute__((weak,alias("__early_flash_cmd_reset")));
-#endif
-
-int board_early_init_f(void)
-{
-#ifdef CONFIG_ALTERA_PIO
-#ifdef LED_PIO_BASE
-	altera_pio_init(LED_PIO_BASE, LED_PIO_WIDTH, 'o',
-			LED_PIO_RSTVAL, (1 << LED_PIO_WIDTH) - 1,
-			"led");
-#endif
-#endif
-#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR) && \
-    defined(CONFIG_CFI_FLASH_MTD)
-	early_flash_cmd_reset();
-#endif
-	return 0;
-}
-
-int checkboard(void)
-{
-	printf("BOARD : %s\n", CONFIG_BOARD_NAME);
-	return 0;
-}
-
-phys_size_t initdram(int board_type)
-{
-	return 0;
-}
-
-#ifdef CONFIG_CMD_NET
-int board_eth_init(bd_t *bis)
-{
-	int rc = 0;
-#ifdef CONFIG_SMC91111
-	rc += smc91111_initialize(0, CONFIG_SMC91111_BASE);
-#endif
-#ifdef CONFIG_DRIVER_DM9000
-	rc += dm9000_initialize(bis);
-#endif
-#ifdef CONFIG_ALTERA_TSE
-	rc += altera_tse_initialize(0,
-				    CONFIG_SYS_ALTERA_TSE_MAC_BASE,
-				    CONFIG_SYS_ALTERA_TSE_SGDMA_RX_BASE,
-				    CONFIG_SYS_ALTERA_TSE_SGDMA_TX_BASE,
-#if defined(CONFIG_SYS_ALTERA_TSE_SGDMA_DESC_BASE) && \
-	(CONFIG_SYS_ALTERA_TSE_SGDMA_DESC_SIZE > 0)
-				    CONFIG_SYS_ALTERA_TSE_SGDMA_DESC_BASE,
-				    CONFIG_SYS_ALTERA_TSE_SGDMA_DESC_SIZE);
-#else
-				    0,
-				    0);
-#endif
-#endif
-#ifdef CONFIG_ETHOC
-	rc += ethoc_initialize(0, CONFIG_SYS_ETHOC_BASE);
-#endif
-	return rc;
-}
-#endif
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 942badb..6451d1d 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -242,10 +242,23 @@
 	return;
 }
 
+#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
+static void set_board_info(void)
+{
+	char str_rev[11];
+	sprintf(str_rev, "0x%X", rpi_board_rev);
+	setenv("board_rev", str_rev);
+	setenv("board_name", models[rpi_board_rev].name);
+}
+#endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */
+
 int misc_init_r(void)
 {
 	set_fdtfile();
 	set_usbethaddr();
+#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
+	set_board_info();
+#endif
 	return 0;
 }
 
diff --git a/board/samsung/origen/tools/mkorigenspl.c b/board/samsung/origen/tools/mkorigenspl.c
index 3ed20ef..8b0c3ac 100644
--- a/board/samsung/origen/tools/mkorigenspl.c
+++ b/board/samsung/origen/tools/mkorigenspl.c
@@ -52,7 +52,7 @@
 	}
 
 	ofd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
-	if (ifd < 0) {
+	if (ofd < 0) {
 		fprintf(stderr, "%s: Can't open %s: %s\n",
 			argv[0], argv[2], strerror(errno));
 		if (ifd)
diff --git a/board/samsung/smdkv310/tools/mksmdkv310spl.c b/board/samsung/smdkv310/tools/mksmdkv310spl.c
index 9a64ca6..ea61635 100644
--- a/board/samsung/smdkv310/tools/mksmdkv310spl.c
+++ b/board/samsung/smdkv310/tools/mksmdkv310spl.c
@@ -50,7 +50,7 @@
 	}
 
 	ofd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
-	if (ifd < 0) {
+	if (ofd < 0) {
 		fprintf(stderr, "%s: Can't open %s: %s\n",
 			argv[0], argv[2], strerror(errno));
 		if (ifd)
diff --git a/common/Makefile b/common/Makefile
index 8c7775a..d986cde 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -7,6 +7,7 @@
 
 # core
 ifndef CONFIG_SPL_BUILD
+obj-y += init/
 obj-y += main.o
 obj-y += exports.o
 obj-y += hash.o
diff --git a/common/board_f.c b/common/board_f.c
index 613332e..486e828 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -806,7 +806,7 @@
 #if defined(CONFIG_BOARD_POSTCLK_INIT)
 	board_postclk_init,
 #endif
-#ifdef CONFIG_FSL_ESDHC
+#ifdef CONFIG_FSL_CLK
 	get_clocks,
 #endif
 #ifdef CONFIG_M68K
@@ -1030,32 +1030,3 @@
 	hang();
 }
 #endif /* CONFIG_X86 */
-
-/* Unfortunately x86 can't compile this code as gd cannot be assigned */
-#ifndef CONFIG_X86
-__weak void arch_setup_gd(struct global_data *gd_ptr)
-{
-	gd = gd_ptr;
-}
-#endif /* !CONFIG_X86 */
-
-ulong board_init_f_mem(ulong top)
-{
-	struct global_data *gd_ptr;
-
-	/* Leave space for the stack we are running with now */
-	top -= 0x40;
-
-	top -= sizeof(struct global_data);
-	top = ALIGN(top, 16);
-	gd_ptr = (struct global_data *)top;
-	memset(gd_ptr, '\0', sizeof(*gd));
-	arch_setup_gd(gd_ptr);
-
-#ifdef CONFIG_SYS_MALLOC_F_LEN
-	top -= CONFIG_SYS_MALLOC_F_LEN;
-	gd->malloc_base = top;
-#endif
-
-	return top;
-}
diff --git a/common/board_r.c b/common/board_r.c
index 0a4dfe4..c4fd3ea 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -290,6 +290,9 @@
 	/* Save the pre-reloc driver model and start a new one */
 	gd->dm_root_f = gd->dm_root;
 	gd->dm_root = NULL;
+#ifdef CONFIG_TIMER
+	gd->timer = NULL;
+#endif
 	return dm_init_and_scan(false);
 }
 #endif
@@ -544,11 +547,14 @@
 }
 #endif
 
-#if defined(CONFIG_STATUS_LED) && defined(STATUS_LED_BOOT)
+#if defined(CONFIG_STATUS_LED)
 static int initr_status_led(void)
 {
+#if defined(STATUS_LED_BOOT)
 	status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING);
-
+#else
+	status_led_init();
+#endif
 	return 0;
 }
 #endif
@@ -835,7 +841,7 @@
 	|| defined(CONFIG_M68K)
 	timer_init,		/* initialize timer */
 #endif
-#if defined(CONFIG_STATUS_LED) && defined(STATUS_LED_BOOT)
+#if defined(CONFIG_STATUS_LED)
 	initr_status_led,
 #endif
 	/* PPC has a udelay(20) here dating from 2002. Why? */
diff --git a/common/cmd_itest.c b/common/cmd_itest.c
index 76af62b..596341c 100644
--- a/common/cmd_itest.c
+++ b/common/cmd_itest.c
@@ -15,6 +15,9 @@
 #include <common.h>
 #include <config.h>
 #include <command.h>
+#include <mapmem.h>
+
+#include <asm/io.h>
 
 #define EQ	0
 #define NE	1
@@ -49,16 +52,24 @@
 static long evalexp(char *s, int w)
 {
 	long l = 0;
-	long *p;
+	unsigned long addr;
+	void *buf;
 
 	/* if the parameter starts with a * then assume is a pointer to the value we want */
 	if (s[0] == '*') {
-		p = (long *)simple_strtoul(&s[1], NULL, 16);
-		switch (w) {
-		case 1: return((long)(*(unsigned char *)p));
-		case 2: return((long)(*(unsigned short *)p));
-		case 4: return(*p);
+		addr = simple_strtoul(&s[1], NULL, 16);
+		buf = map_physmem(addr, w, MAP_WRBACK);
+		if (!buf) {
+			puts("Failed to map physical memory\n");
+			return 0;
 		}
+		switch (w) {
+		case 1: l = (long)(*(unsigned char *)buf);
+		case 2: l = (long)(*(unsigned short *)buf);
+		case 4: l = (long)(*(unsigned long *)buf);
+		}
+		unmap_physmem(buf, w);
+		return l;
 	} else {
 		l = simple_strtoul(s, NULL, 16);
 	}
diff --git a/common/cmd_ubi.c b/common/cmd_ubi.c
index 0460b4c..753a4db 100644
--- a/common/cmd_ubi.c
+++ b/common/cmd_ubi.c
@@ -255,7 +255,7 @@
 
 	return 0;
 out_err:
-	ubi_err("cannot remove volume %s, error %d", volume, err);
+	ubi_err(ubi, "cannot remove volume %s, error %d", volume, err);
 	if (err < 0)
 		err = -err;
 	return err;
@@ -284,8 +284,8 @@
 			return -err;
 
 		if (err) {
-			ubi_warn("volume %d on UBI device %d is corrupted",
-					vol->vol_id, ubi->ubi_num);
+			ubi_warn(ubi, "volume %d on UBI device %d is corrupt",
+				 vol->vol_id, ubi->ubi_num);
 			vol->corrupted = 1;
 		}
 
diff --git a/common/cmd_ubifs.c b/common/cmd_ubifs.c
index 8e9a4e5..5e9d357 100644
--- a/common/cmd_ubifs.c
+++ b/common/cmd_ubifs.c
@@ -15,8 +15,7 @@
 #include <common.h>
 #include <config.h>
 #include <command.h>
-
-#include "../fs/ubifs/ubifs.h"
+#include <ubifs_uboot.h>
 
 static int ubifs_initialized;
 static int ubifs_mounted;
@@ -54,14 +53,7 @@
 
 void cmd_ubifs_umount(void)
 {
-
-	if (ubifs_sb) {
-		printf("Unmounting UBIFS volume %s!\n",
-		       ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name);
-		ubifs_umount(ubifs_sb->s_fs_info);
-	}
-
-	ubifs_sb = NULL;
+	uboot_ubifs_umount();
 	ubifs_mounted = 0;
 	ubifs_initialized = 0;
 }
diff --git a/common/cmd_ximg.c b/common/cmd_ximg.c
index 8b8645c..d033c15 100644
--- a/common/cmd_ximg.c
+++ b/common/cmd_ximg.c
@@ -88,7 +88,8 @@
 		image_print_contents(hdr);
 #endif
 
-		if (!image_check_type(hdr, IH_TYPE_MULTI)) {
+		if (!image_check_type(hdr, IH_TYPE_MULTI) &&
+		    !image_check_type(hdr, IH_TYPE_SCRIPT)) {
 			printf("Wrong Image Type for %s command\n",
 					cmdtp->name);
 			return 1;
diff --git a/common/image.c b/common/image.c
index e607109..85c4f39 100644
--- a/common/image.c
+++ b/common/image.c
@@ -913,7 +913,7 @@
 	 * Look for an Android boot image.
 	 */
 	buf = map_sysmem(images->os.start, 0);
-	if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID)
+	if (buf && genimg_get_format(buf) == IMAGE_FORMAT_ANDROID)
 		select = argv[0];
 #endif
 
diff --git a/common/init/Makefile b/common/init/Makefile
new file mode 100644
index 0000000..4902635
--- /dev/null
+++ b/common/init/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015 Google, Inc
+#
+# SPDX-License-Identifier:      GPL-2.0+
+#
+
+obj-y += board_init.o
diff --git a/common/init/board_init.c b/common/init/board_init.c
new file mode 100644
index 0000000..e74b63b
--- /dev/null
+++ b/common/init/board_init.c
@@ -0,0 +1,60 @@
+/*
+ * Code shared between SPL and U-Boot proper
+ *
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * It isn't trivial to figure out whether memcpy() exists. The arch-specific
+ * memcpy() is not normally available in SPL due to code size.
+ */
+#if !defined(CONFIG_SPL_BUILD) || \
+		(defined(CONFIG_SPL_LIBGENERIC_SUPPORT) && \
+		!defined(CONFIG_USE_ARCH_MEMSET))
+#define _USE_MEMCPY
+#endif
+
+/* Unfortunately x86 can't compile this code as gd cannot be assigned */
+#ifndef CONFIG_X86
+__weak void arch_setup_gd(struct global_data *gd_ptr)
+{
+	gd = gd_ptr;
+}
+#endif /* !CONFIG_X86 */
+
+ulong board_init_f_mem(ulong top)
+{
+	struct global_data *gd_ptr;
+#ifndef _USE_MEMCPY
+	int *ptr;
+#endif
+
+	/* Leave space for the stack we are running with now */
+	top -= 0x40;
+
+	top -= sizeof(struct global_data);
+	top = ALIGN(top, 16);
+	gd_ptr = (struct global_data *)top;
+#ifdef _USE_MEMCPY
+	memset(gd_ptr, '\0', sizeof(*gd));
+#else
+	for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )
+		*ptr++ = 0;
+#endif
+	arch_setup_gd(gd_ptr);
+
+#if defined(CONFIG_SYS_MALLOC_F) && \
+	(!defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SYS_SPL_MALLOC_START))
+	top -= CONFIG_SYS_MALLOC_F_LEN;
+	gd->malloc_base = top;
+#endif
+
+	return top;
+}
diff --git a/configs/nios2-generic_defconfig b/configs/nios2-generic_defconfig
index 573a084..fbc27ea 100644
--- a/configs/nios2-generic_defconfig
+++ b/configs/nios2-generic_defconfig
@@ -1,9 +1,26 @@
 CONFIG_NIOS2=y
-CONFIG_TARGET_NIOS2_GENERIC=y
+CONFIG_SYS_CONFIG_NAME="nios2-generic"
+CONFIG_DM_SERIAL=y
+CONFIG_DM_GPIO=y
+CONFIG_DEFAULT_DEVICE_TREE="3c120_devboard"
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
 # CONFIG_CMD_BOOTD is not set
 # CONFIG_CMD_IMLS is not set
 # CONFIG_CMD_XIMG is not set
 # CONFIG_CMD_FPGA is not set
 # CONFIG_CMD_ITEST is not set
 # CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
+CONFIG_CMD_PING=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_ALTERA_PIO=y
+CONFIG_MISC=y
+CONFIG_ALTERA_SYSID=y
+CONFIG_DM_ETH=y
+CONFIG_ALTERA_TSE=y
+CONFIG_ALTERA_JTAG_UART=y
+CONFIG_ALTERA_JTAG_UART_BYPASS=y
+CONFIG_TIMER=y
+CONFIG_ALTERA_TIMER=y
diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig
index a6757ac..e9c3209 100644
--- a/configs/zynq_microzed_defconfig
+++ b/configs/zynq_microzed_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_MICROZED=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-microzed"
 CONFIG_SPL=y
diff --git a/configs/zynq_zc702_defconfig b/configs/zynq_zc702_defconfig
index 8a388f3..0abb7a8 100644
--- a/configs/zynq_zc702_defconfig
+++ b/configs/zynq_zc702_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702"
 CONFIG_SPL=y
 CONFIG_FIT=y
diff --git a/configs/zynq_zc706_defconfig b/configs/zynq_zc706_defconfig
index f1009ee..d67f507 100644
--- a/configs/zynq_zc706_defconfig
+++ b/configs/zynq_zc706_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZC706=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc706"
 CONFIG_SPL=y
diff --git a/configs/zynq_zc70x_defconfig b/configs/zynq_zc70x_defconfig
index 6465040..37c249f 100644
--- a/configs/zynq_zc70x_defconfig
+++ b/configs/zynq_zc70x_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZC70X=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702"
 CONFIG_SPL=y
diff --git a/configs/zynq_zc770_xm010_defconfig b/configs/zynq_zc770_xm010_defconfig
index cafbb09..0e826bb 100644
--- a/configs/zynq_zc770_xm010_defconfig
+++ b/configs/zynq_zc770_xm010_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZC770=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm010"
 CONFIG_SPL=y
diff --git a/configs/zynq_zc770_xm011_defconfig b/configs/zynq_zc770_xm011_defconfig
index e6e1c30..46d043b 100644
--- a/configs/zynq_zc770_xm011_defconfig
+++ b/configs/zynq_zc770_xm011_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZC770=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm011"
 CONFIG_SPL=y
diff --git a/configs/zynq_zc770_xm012_defconfig b/configs/zynq_zc770_xm012_defconfig
index 9a44009..34d479f 100644
--- a/configs/zynq_zc770_xm012_defconfig
+++ b/configs/zynq_zc770_xm012_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZC770=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm012"
 CONFIG_SPL=y
diff --git a/configs/zynq_zc770_xm013_defconfig b/configs/zynq_zc770_xm013_defconfig
index 95e32a5..c59599f 100644
--- a/configs/zynq_zc770_xm013_defconfig
+++ b/configs/zynq_zc770_xm013_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZC770=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm013"
 CONFIG_SPL=y
diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig
index 43520d0..886b4a5 100644
--- a/configs/zynq_zed_defconfig
+++ b/configs/zynq_zed_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZED=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zed"
 CONFIG_SPL=y
diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig
index 46379e5..77b9409 100644
--- a/configs/zynq_zybo_defconfig
+++ b/configs/zynq_zybo_defconfig
@@ -1,6 +1,5 @@
 CONFIG_ARM=y
 CONFIG_ARCH_ZYNQ=y
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_TARGET_ZYNQ_ZYBO=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zybo"
 CONFIG_SPL=y
diff --git a/disk/part.c b/disk/part.c
index 43485c9..e57a252 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -10,6 +10,7 @@
 #include <ide.h>
 #include <malloc.h>
 #include <part.h>
+#include <ubifs_uboot.h>
 
 #undef	PART_DEBUG
 
@@ -511,6 +512,11 @@
 	int part;
 	disk_partition_t tmpinfo;
 
+#if defined CONFIG_SANDBOX && defined CONFIG_CMD_UBIFS
+#error Only one of CONFIG_SANDBOX and CONFIG_CMD_UBIFS may be selected
+#endif
+
+#ifdef CONFIG_SANDBOX
 	/*
 	 * Special-case a pseudo block device "hostfs", to allow access to the
 	 * host's own filesystem.
@@ -529,6 +535,29 @@
 
 		return 0;
 	}
+#endif
+
+#ifdef CONFIG_CMD_UBIFS
+	/*
+	 * Special-case ubi, ubi goes through a mtd, rathen then through
+	 * a regular block device.
+	 */
+	if (0 == strcmp(ifname, "ubi")) {
+		if (!ubifs_is_mounted()) {
+			printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
+			return -1;
+		}
+
+		*dev_desc = NULL;
+		memset(info, 0, sizeof(*info));
+		strcpy((char *)info->type, BOOT_PART_TYPE);
+		strcpy((char *)info->name, "UBI");
+#ifdef CONFIG_PARTITION_UUIDS
+		info->uuid[0] = 0;
+#endif
+		return 0;
+	}
+#endif
 
 	/* If no dev_part_str, use bootdevice environment variable */
 	if (!dev_part_str || !strlen(dev_part_str) ||
diff --git a/doc/README.nios2 b/doc/README.nios2
new file mode 100644
index 0000000..2dab7d1
--- /dev/null
+++ b/doc/README.nios2
@@ -0,0 +1,95 @@
+Nios II is a 32-bit embedded-processor architecture designed
+specifically for the Altera family of FPGAs.
+
+Please refer to the link for more information on Nios II,
+https://www.altera.com/products/processors/overview.html
+
+Please refer to the link for Linux port and toolchains,
+http://rocketboards.org/foswiki/view/Documentation/NiosIILinuxUserManual
+
+The Nios II port of u-boot is controlled by device tree. Please check
+out doc/README.fdt-control.
+
+To add a new board/configuration (eg, mysystem) to u-boot, you will need
+three files.
+
+1. The device tree source which describes the hardware, dts file.
+    arch/nios2/dts/mysystem.dts
+
+2. Default configuration of Kconfig, defconfig file.
+    configs/mysystem_defconfig
+
+3. The legacy board header file.
+    include/configs/mysystem.h
+
+The device tree source must be generated from your qsys/sopc design
+using the sopc2dts tool. Then modified to fit your configuration. Please
+find the sopc2dts download and usage at the wiki,
+http://www.alterawiki.com/wiki/Sopc2dts
+
+$ java -jar sopc2dts.jar --force-altr -i mysystem.sopcinfo -o mysystem.dts
+
+You will need to add additional properties to the dts. Please find an
+example at, arch/nios2/dts/3c120_devboard.dts.
+
+1. Add "stdout-path=..." property with your serial path to the chosen
+node, like this,
+	chosen {
+		stdout-path = &jtag_uart;
+	};
+
+2. If you use SPI/EPCS or I2C, you will need to add aliases to number
+the sequence of these devices, like this,
+	aliases {
+		spi0 = &epcs_controller;
+	};
+
+Next, you will need a default config file. You may start with
+nios2-generic_defconfig, modify the options and save it.
+
+$ make nios2-generic_defconfig
+$ make menuconfig
+$ make savedefconfig
+$ cp defconfig configs/mysystem_defconfig
+
+You will need to change the names of board header file and device tree,
+and select the drivers with menuconfig.
+
+Nios II architecture  --->
+  (mysystem) Board header file
+Device Tree Control  --->
+  (mysystem) Default Device Tree for DT control
+
+There is a selection of "Provider of DTB for DT control" in the Device
+Tree Control menu.
+
+( ) Separate DTB for DT control, will cat the dtb to end of u-boot
+binary, output u-boot-dtb.bin. This should be used for production.
+If you use boot copier, like EPCS boot copier, make sure the copier
+copies all the u-boot-dtb.bin, not just u-boot.bin.
+
+( ) Embedded DTB for DT control, will include the dtb inside the u-boot
+binary. This is handy for development, eg, using gdb or nios2-download.
+
+The last thing, legacy board header file describes those config options
+not covered in Kconfig yet. You may copy it from nios2-generic.h.
+
+$ cp include/configs/nios2-generic.h include/configs/mysystem.h
+
+Please change the SDRAM base and size to match your board. The base
+should be cached virtual address, for Nios II with MMU it is 0xCxxx_xxxx
+to 0xDxxx_xxxx.
+
+#define CONFIG_SYS_SDRAM_BASE		0xD0000000
+#define CONFIG_SYS_SDRAM_SIZE		0x08000000
+
+You will need to change the environment variables location and setting,
+too. You may change other configs to fit your board.
+
+After all these changes, you may build and test.
+
+$ export CROSS_COMPILE=nios2-elf-  (or nios2-linux-gnu-)
+$ make mysystem_defconfig
+$ make
+
+Enjoy!
diff --git a/doc/device-tree-bindings/cpu/nios2.txt b/doc/device-tree-bindings/cpu/nios2.txt
new file mode 100644
index 0000000..0ed2f44
--- /dev/null
+++ b/doc/device-tree-bindings/cpu/nios2.txt
@@ -0,0 +1,54 @@
+* Nios II Processor Binding
+
+This binding specifies what properties available in the device tree
+representation of a Nios II Processor Core.
+
+Users can use sopc2dts tool for generating device tree sources (dts) from a
+Qsys system. See more detail in: http://www.alterawiki.com/wiki/Sopc2dts
+
+Required properties:
+
+- compatible: Compatible property value should be "altr,nios2-1.0" or
+  "altr,nios2-1.1".
+- reg: Contains CPU index.
+- clock-frequency: Contains the clock frequency for CPU, in Hz.
+- dcache-line-size: Contains data cache line size.
+- icache-line-size: Contains instruction line size.
+- dcache-size: Contains data cache size.
+- icache-size: Contains instruction cache size.
+- altr,reset-addr: Specifies CPU reset address
+- altr,exception-addr: Specifies CPU exception address
+
+Optional properties:
+- altr,has-initda: Specifies CPU support initda instruction, should be 1.
+- altr,has-mmu: Specifies CPU support MMU support.
+- altr,has-mul: Specifies CPU hardware multipy support.
+- altr,has-div: Specifies CPU hardware divide support
+- altr,implementation: Nios II core implementation, this should be "fast";
+
+Example:
+
+cpu@0x0 {
+	device_type = "cpu";
+	compatible = "altr,nios2-1.0";
+	reg = <0>;
+	interrupt-controller;
+	#interrupt-cells = <1>;
+	clock-frequency = <125000000>;
+	dcache-line-size = <32>;
+	icache-line-size = <32>;
+	dcache-size = <32768>;
+	icache-size = <32768>;
+	altr,implementation = "fast";
+	altr,pid-num-bits = <8>;
+	altr,tlb-num-ways = <16>;
+	altr,tlb-num-entries = <128>;
+	altr,tlb-ptr-sz = <7>;
+	altr,has-div = <1>;
+	altr,has-mul = <1>;
+	altr,reset-addr = <0xc2800000>;
+	altr,fast-tlb-miss-addr = <0xc7fff400>;
+	altr,exception-addr = <0xd0000020>;
+	altr,has-initda = <1>;
+	altr,has-mmu = <1>;
+};
diff --git a/doc/device-tree-bindings/gpio/altera_pio.txt b/doc/device-tree-bindings/gpio/altera_pio.txt
new file mode 100644
index 0000000..cf71eb2
--- /dev/null
+++ b/doc/device-tree-bindings/gpio/altera_pio.txt
@@ -0,0 +1,28 @@
+Altera GPIO controller bindings
+
+Required properties:
+- compatible:
+  - "altr,pio-1.0"
+- reg: Physical base address and length of the controller's registers.
+
+Optional properties:
+- altr,gpio-bank-width: Width of the GPIO bank. This defines how many pins the
+  GPIO device has. Ranges between 1-32. Optional and defaults to 32 if not
+  specified.
+- gpio-bank-name: bank name attached to this device.
+
+Example:
+
+user_led_pio_8out: gpio@0x4cc0 {
+	compatible = "altr,pio-1.0";
+	reg = <0x00004cc0 0x00000010>;
+	resetvalue = <255>;
+	altr,gpio-bank-width = <8>;
+	#gpio-cells = <2>;
+	gpio-controller;
+	gpio-bank-name = "led";
+};
+
+In this example, the gpio can be accessed as led[0..7] using gpio command of
+u-boot.
+==> gpio clear led0
diff --git a/doc/device-tree-bindings/misc/altera_sysid.txt b/doc/device-tree-bindings/misc/altera_sysid.txt
new file mode 100644
index 0000000..54462eb
--- /dev/null
+++ b/doc/device-tree-bindings/misc/altera_sysid.txt
@@ -0,0 +1,4 @@
+Altera sysid
+
+Required properties:
+- compatible : should be "altr,sysid-1.0"
diff --git a/doc/device-tree-bindings/net/altera_tse.txt b/doc/device-tree-bindings/net/altera_tse.txt
new file mode 100644
index 0000000..cb190df
--- /dev/null
+++ b/doc/device-tree-bindings/net/altera_tse.txt
@@ -0,0 +1,112 @@
+* Altera Triple-Speed Ethernet MAC driver (TSE)
+
+Required properties:
+- compatible: Should be "altr,tse-1.0" for legacy SGDMA based TSE, and should
+		be "altr,tse-msgdma-1.0" for the preferred MSGDMA based TSE.
+- reg: Address and length of the register set for the device. It contains
+  the information of registers in the same order as described by reg-names
+- reg-names: Should contain the reg names
+  "control_port": MAC configuration space region
+  "tx_csr":       xDMA Tx dispatcher control and status space region
+  "tx_desc":      MSGDMA Tx dispatcher descriptor space region
+  "rx_csr" :      xDMA Rx dispatcher control and status space region
+  "rx_desc":      MSGDMA Rx dispatcher descriptor space region
+  "rx_resp":      MSGDMA Rx dispatcher response space region
+  "s1":		  SGDMA descriptor memory
+- interrupts: Should contain the TSE interrupts and it's mode.
+- interrupt-names: Should contain the interrupt names
+  "rx_irq":       xDMA Rx dispatcher interrupt
+  "tx_irq":       xDMA Tx dispatcher interrupt
+- rx-fifo-depth: MAC receive FIFO buffer depth in bytes
+- tx-fifo-depth: MAC transmit FIFO buffer depth in bytes
+- phy-mode: See ethernet.txt in the same directory.
+- phy-handle: See ethernet.txt in the same directory.
+- phy-addr: See ethernet.txt in the same directory. A configuration should
+		include phy-handle or phy-addr.
+- altr,has-supplementary-unicast:
+		If present, TSE supports additional unicast addresses.
+		Otherwise additional unicast addresses are not supported.
+- altr,has-hash-multicast-filter:
+		If present, TSE supports a hash based multicast filter.
+		Otherwise, hash-based multicast filtering is not supported.
+
+- mdio device tree subnode: When the TSE has a phy connected to its local
+		mdio, there must be device tree subnode with the following
+		required properties:
+
+	- compatible: Must be "altr,tse-mdio".
+	- #address-cells: Must be <1>.
+	- #size-cells: Must be <0>.
+
+	For each phy on the mdio bus, there must be a node with the following
+	fields:
+
+	- reg: phy id used to communicate to phy.
+	- device_type: Must be "ethernet-phy".
+
+Optional properties:
+- local-mac-address: See ethernet.txt in the same directory.
+- max-frame-size: See ethernet.txt in the same directory.
+
+Example:
+
+	tse_sub_0_eth_tse_0: ethernet@0x1,00000000 {
+		compatible = "altr,tse-msgdma-1.0";
+		reg =	<0x00000001 0x00000000 0x00000400>,
+			<0x00000001 0x00000460 0x00000020>,
+			<0x00000001 0x00000480 0x00000020>,
+			<0x00000001 0x000004A0 0x00000008>,
+			<0x00000001 0x00000400 0x00000020>,
+			<0x00000001 0x00000420 0x00000020>;
+		reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+		interrupt-parent = <&hps_0_arm_gic_0>;
+		interrupts = <0 41 4>, <0 40 4>;
+		interrupt-names = "rx_irq", "tx_irq";
+		rx-fifo-depth = <2048>;
+		tx-fifo-depth = <2048>;
+		address-bits = <48>;
+		max-frame-size = <1500>;
+		local-mac-address = [ 00 00 00 00 00 00 ];
+		phy-mode = "gmii";
+		altr,has-supplementary-unicast;
+		altr,has-hash-multicast-filter;
+		phy-handle = <&phy0>;
+		mdio {
+			compatible = "altr,tse-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			phy0: ethernet-phy@0 {
+				reg = <0x0>;
+				device_type = "ethernet-phy";
+			};
+
+			phy1: ethernet-phy@1 {
+				reg = <0x1>;
+				device_type = "ethernet-phy";
+			};
+
+		};
+	};
+
+	tse_sub_1_eth_tse_0: ethernet@0x1,00001000 {
+		compatible = "altr,tse-msgdma-1.0";
+		reg = 	<0x00000001 0x00001000 0x00000400>,
+			<0x00000001 0x00001460 0x00000020>,
+			<0x00000001 0x00001480 0x00000020>,
+			<0x00000001 0x000014A0 0x00000008>,
+			<0x00000001 0x00001400 0x00000020>,
+			<0x00000001 0x00001420 0x00000020>;
+		reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+		interrupt-parent = <&hps_0_arm_gic_0>;
+		interrupts = <0 43 4>, <0 42 4>;
+		interrupt-names = "rx_irq", "tx_irq";
+		rx-fifo-depth = <2048>;
+		tx-fifo-depth = <2048>;
+		address-bits = <48>;
+		max-frame-size = <1500>;
+		local-mac-address = [ 00 00 00 00 00 00 ];
+		phy-mode = "gmii";
+		altr,has-supplementary-unicast;
+		altr,has-hash-multicast-filter;
+		phy-handle = <&phy1>;
+	};
diff --git a/doc/device-tree-bindings/serial/altera_jtaguart.txt b/doc/device-tree-bindings/serial/altera_jtaguart.txt
new file mode 100644
index 0000000..97c7062
--- /dev/null
+++ b/doc/device-tree-bindings/serial/altera_jtaguart.txt
@@ -0,0 +1,4 @@
+Altera JTAG UART
+
+Required properties:
+- compatible : should be "altr,juart-1.0"
diff --git a/doc/device-tree-bindings/serial/altera_uart.txt b/doc/device-tree-bindings/serial/altera_uart.txt
new file mode 100644
index 0000000..ebac3f5
--- /dev/null
+++ b/doc/device-tree-bindings/serial/altera_uart.txt
@@ -0,0 +1,7 @@
+Altera UART
+
+Required properties:
+- compatible : should be "altr,uart-1.0"
+
+Optional properties:
+- clock-frequency : frequency of the clock input to the UART
diff --git a/doc/device-tree-bindings/spi/spi_altera.txt b/doc/device-tree-bindings/spi/spi_altera.txt
new file mode 100644
index 0000000..de4fae8
--- /dev/null
+++ b/doc/device-tree-bindings/spi/spi_altera.txt
@@ -0,0 +1,4 @@
+Altera SPI
+
+Required properties:
+- compatible : should be "altr,spi-1.0".
diff --git a/doc/device-tree-bindings/timer/altera_timer.txt b/doc/device-tree-bindings/timer/altera_timer.txt
new file mode 100644
index 0000000..904a584
--- /dev/null
+++ b/doc/device-tree-bindings/timer/altera_timer.txt
@@ -0,0 +1,19 @@
+Altera Timer
+
+Required properties:
+
+- compatible : should be "altr,timer-1.0"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-parent: phandle of the interrupt controller
+- interrupts : Should contain the timer interrupt number
+- clock-frequency : The frequency of the clock that drives the counter, in Hz.
+
+Example:
+
+timer {
+	compatible = "altr,timer-1.0";
+	reg = <0x00400000 0x00000020>;
+	interrupt-parent = <&cpu>;
+	interrupts = <11>;
+	clock-frequency = <125000000>;
+};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index c02f323..ba88b5e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -58,6 +58,8 @@
 
 source "drivers/thermal/Kconfig"
 
+source "drivers/timer/Kconfig"
+
 source "drivers/tpm/Kconfig"
 
 source "drivers/usb/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 1a30ad1..4f49bfd 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -48,6 +48,7 @@
 obj-y += dfu/
 obj-y += rtc/
 obj-y += sound/
+obj-y += timer/
 obj-y += tpm/
 obj-y += twserial/
 obj-y += video/
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ef57a89..9e49471 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -14,6 +14,13 @@
 	  particular GPIOs that they provide. The uclass interface
 	  is defined in include/asm-generic/gpio.h.
 
+config ALTERA_PIO
+	bool "Altera PIO driver"
+	depends on DM_GPIO
+	help
+	  Select this to enable PIO for Altera devices. Please find
+	  details on the "Embedded Peripherals IP User Guide" of Altera.
+
 config DWAPB_GPIO
 	bool "DWAPB GPIO driver"
 	depends on DM && DM_GPIO
diff --git a/drivers/gpio/altera_pio.c b/drivers/gpio/altera_pio.c
index 3ca5907..7ceb80e 100644
--- a/drivers/gpio/altera_pio.c
+++ b/drivers/gpio/altera_pio.c
@@ -1,286 +1,122 @@
 /*
- * Driver for Altera's PIO ip core
- *
+ * Copyright (C) 2015  Thomas Chou <thomas@wytron.com.tw>
  * Copyright (C) 2011  Missing Link Electronics
  *                     Joachim Foerster <joachim@missinglinkelectronics.com>
  *
  * SPDX-License-Identifier:	GPL-2.0+
- *
- * To use this driver, in your board's config. header:
- * #define CONFIG_ALTERA_PIO
- * #define CONFIG_SYS_ALTERA_PIO_NUM <number-of-pio-cores>
- * #define CONFIG_SYS_ALTERA_PIO_GPIO_NUM <total-number-of-gpios>
- * And in your board's early setup routine:
- * altera_pio_init(<baseaddr>, <width>, 'i'|'o'|'t',
- *                 <reset-value>, <neg-mask>, "label");
- *  - 'i'|'o'|'t': PIO is input-only/output-only/tri-state
- *  - <reset-value>: for correct initial status display, output-only
- *  - <neg-mask> is meant to be used to in cases of active-low
- *    GPIOs, such as LEDs and buttons (on/pressed == 0). Each bit
- *    which is 1 in <neg-mask> inverts the corresponding GPIO's value
- *    before set/after get. So: gpio_set_value(gpio, 1) => LED on .
- *
- * Do NOT define CONFIG_SYS_GPIO_BASE !
- *
- * Optionally, in your board's config. header:
- * - To force a GPIO numbering scheme like in Linux ...
- * #define CONFIG_GPIO_DOWNTO_NUMBERING
- * ... starting with 255 (default)
- * #define CONFIG_GPIO_DOWNTO_MAX 255
  */
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fdtdec.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
 
-#ifdef CONFIG_GPIO_DOWNTO_NUMBERING
-#ifndef CONFIG_GPIO_DOWNTO_MAX
-#define CONFIG_GPIO_DOWNTO_MAX 255
-#endif
-#endif
+DECLARE_GLOBAL_DATA_PTR;
 
-#define ALTERA_PIO_DATA		0x0
-#define ALTERA_PIO_DIR		0x4
+struct altera_pio_regs {
+	u32	data;			/* Data register */
+	u32	direction;		/* Direction register */
+};
 
-#define GPIO_LABEL_SIZE		9
+struct altera_pio_platdata {
+	struct altera_pio_regs *regs;
+	int gpio_count;
+	const char *bank_name;
+};
 
-
-static struct altera_pio {
-	u32 base;
-	u8 width;
-	char iot;
-	u32 negmask;
-	u32 sh_data;
-	u32 sh_dir;
-	int gidx;
-	char label[GPIO_LABEL_SIZE];
-} pios[CONFIG_SYS_ALTERA_PIO_NUM];
-
-static int pio_num;
-
-static struct altera_pio_gpio {
-	unsigned num;
-	struct altera_pio *pio;
-	char reqlabel[GPIO_LABEL_SIZE];
-} gpios[CONFIG_SYS_ALTERA_PIO_GPIO_NUM];
-
-static int pio_gpio_num;
-
-
-static int altera_pio_gidx(unsigned gpio)
+static int altera_pio_direction_input(struct udevice *dev, unsigned pin)
 {
-	int i;
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-	for (i = 0; i < pio_gpio_num; ++i) {
-		if (gpio == gpios[i].num)
-			break;
-	}
-	if (i >= pio_gpio_num)
-		return -1;
-	return i;
-}
+	clrbits_le32(&regs->direction, 1 << pin);
 
-static struct altera_pio *altera_pio_get_and_mask(unsigned gpio, u32 *mask)
-{
-	int gidx = altera_pio_gidx(gpio);
-	if (gidx < 0)
-		return NULL;
-	if (mask)
-		*mask = 1 << (gidx - gpios[gidx].pio->gidx);
-	return gpios[gidx].pio;
-}
-
-#define altera_pio_use_gidx(_gidx, _reqlabel) \
-	{ strncpy(gpios[_gidx].reqlabel, _reqlabel, GPIO_LABEL_SIZE); }
-#define altera_pio_unuse_gidx(_gidx) { gpios[_gidx].reqlabel[0] = '\0'; }
-#define altera_pio_is_gidx_used(_gidx) (gpios[_gidx].reqlabel[0] != '\0')
-
-static int altera_pio_gpio_init(struct altera_pio *pio, u8 width)
-{
-	u8 gidx = pio_gpio_num;
-	int i;
-
-	if (!width)
-		return -1;
-	if ((pio_gpio_num + width) > CONFIG_SYS_ALTERA_PIO_GPIO_NUM)
-		return -1;
-
-	for (i = 0; i < width; ++i) {
-#ifdef CONFIG_GPIO_DOWNTO_NUMBERING
-		gpios[pio_gpio_num + i].num = \
-			CONFIG_GPIO_DOWNTO_MAX + 1 - gidx - width + i;
-#else
-		gpios[pio_gpio_num + i].num = pio_gpio_num + i;
-#endif
-		gpios[pio_gpio_num + i].pio = pio;
-		altera_pio_unuse_gidx(pio_gpio_num + i);
-	}
-	pio_gpio_num += width;
-	return gidx;
-}
-
-int altera_pio_init(u32 base, u8 width, char iot, u32 rstval, u32 negmask,
-		 const char *label)
-{
-	if (pio_num >= CONFIG_SYS_ALTERA_PIO_NUM)
-		return -1;
-
-	pios[pio_num].base = base;
-	pios[pio_num].width = width;
-	pios[pio_num].iot = iot;
-	switch (iot) {
-	case 'i':
-		/* input only */
-		pios[pio_num].sh_dir = 0;
-		pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
-		break;
-	case 'o':
-		/* output only */
-		pios[pio_num].sh_dir = 0xffffffff & ((1 << width) - 1);
-		pios[pio_num].sh_data = rstval;
-		break;
-	case 't':
-		/* bidir, tri-state */
-		pios[pio_num].sh_dir = readl(base + ALTERA_PIO_DIR);
-		pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
-		break;
-	default:
-		return -1;
-	}
-	pios[pio_num].negmask = negmask & ((1 << width) - 1);
-	pios[pio_num].gidx = altera_pio_gpio_init(&pios[pio_num], width);
-	if (pios[pio_num].gidx < 0)
-		return -1;
-	strncpy(pios[pio_num].label, label, GPIO_LABEL_SIZE);
-	return pio_num++;
-}
-
-void altera_pio_info(void)
-{
-	int i;
-	int j;
-	int gidx;
-	u32 mask;
-
-	for (i = 0; i < pio_num; ++i) {
-		printf("Altera PIO % 2d, @0x%08x, "
-			"width: %u, label: %s\n",
-		       i, pios[i].base, pios[i].width, pios[i].label);
-		gidx = pios[i].gidx;
-		for (j = gidx; j < (gidx + pios[i].width); ++j) {
-			mask = 1 << (j - gidx);
-			printf("\tGPIO % 4d: %s %s [%c] %s\n",
-				gpios[j].num,
-				gpios[j].pio->sh_dir & mask ? "out" : " in",
-				gpio_get_value(gpios[j].num) ? "set" : "clr",
-				altera_pio_is_gidx_used(j) ? 'x' : ' ',
-				gpios[j].reqlabel);
-		}
-	}
-}
-
-
-int gpio_request(unsigned gpio, const char *label)
-{
-	int gidx = altera_pio_gidx(gpio);
-	if (gidx < 0)
-		return gidx;
-	if (altera_pio_is_gidx_used(gidx))
-		return -1;
-
-	altera_pio_use_gidx(gidx, label);
 	return 0;
 }
 
-int gpio_free(unsigned gpio)
+static int altera_pio_direction_output(struct udevice *dev, unsigned pin,
+				     int val)
 {
-	int gidx = altera_pio_gidx(gpio);
-	if (gidx < 0)
-		return gidx;
-	if (!altera_pio_is_gidx_used(gidx))
-		return -1;
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-	altera_pio_unuse_gidx(gidx);
-	return 0;
-}
-
-int gpio_direction_input(unsigned gpio)
-{
-	u32 mask;
-	struct altera_pio *pio;
-
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return -1;
-	if (pio->iot == 'o')
-		return -1;
-
-	writel(pio->sh_dir &= ~mask, pio->base + ALTERA_PIO_DIR);
-	return 0;
-}
-
-int gpio_direction_output(unsigned gpio, int value)
-{
-	u32 mask;
-	struct altera_pio *pio;
-
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return -1;
-	if (pio->iot == 'i')
-		return -1;
-
-	value = (pio->negmask & mask) ? !value : value;
-	if (value)
-		pio->sh_data |= mask;
+	if (val)
+		setbits_le32(&regs->data, 1 << pin);
 	else
-		pio->sh_data &= ~mask;
-	writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
-	writel(pio->sh_dir |= mask, pio->base + ALTERA_PIO_DIR);
+		clrbits_le32(&regs->data, 1 << pin);
+	/* change the data first, then the direction. to avoid glitch */
+	setbits_le32(&regs->direction, 1 << pin);
+
 	return 0;
 }
 
-int gpio_get_value(unsigned gpio)
+static int altera_pio_get_value(struct udevice *dev, unsigned pin)
 {
-	u32 mask;
-	struct altera_pio *pio;
-	u32 val;
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return -1;
-
-	if ((pio->sh_dir & mask) || (pio->iot == 'o'))
-		val = pio->sh_data & mask;
-	else
-		val = readl(pio->base + ALTERA_PIO_DATA) & mask;
-	return (pio->negmask & mask) ? !val : val;
+	return readl(&regs->data) & (1 << pin);
 }
 
-void gpio_set_value(unsigned gpio, int value)
+
+static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val)
 {
-	u32 mask;
-	struct altera_pio *pio;
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+	struct altera_pio_regs *const regs = plat->regs;
 
-	pio = altera_pio_get_and_mask(gpio, &mask);
-	if (!pio)
-		return;
-	if (pio->iot == 'i')
-		return;
-
-	value = (pio->negmask & mask) ? !value : value;
-	if (value)
-		pio->sh_data |= mask;
+	if (val)
+		setbits_le32(&regs->data, 1 << pin);
 	else
-		pio->sh_data &= ~mask;
-	writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
-	return;
-}
+		clrbits_le32(&regs->data, 1 << pin);
 
-int gpio_is_valid(int number)
-{
-	int gidx = altera_pio_gidx(number);
-
-	if (gidx < 0)
-		return 1;
 	return 0;
 }
+
+static int altera_pio_probe(struct udevice *dev)
+{
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+
+	uc_priv->gpio_count = plat->gpio_count;
+	uc_priv->bank_name = plat->bank_name;
+
+	return 0;
+}
+
+static int altera_pio_ofdata_to_platdata(struct udevice *dev)
+{
+	struct altera_pio_platdata *plat = dev_get_platdata(dev);
+
+	plat->regs = ioremap(dev_get_addr(dev),
+		sizeof(struct altera_pio_regs));
+	plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+		"altr,gpio-bank-width", 32);
+	plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset,
+		"gpio-bank-name", NULL);
+
+	return 0;
+}
+
+static const struct dm_gpio_ops altera_pio_ops = {
+	.direction_input	= altera_pio_direction_input,
+	.direction_output	= altera_pio_direction_output,
+	.get_value		= altera_pio_get_value,
+	.set_value		= altera_pio_set_value,
+};
+
+static const struct udevice_id altera_pio_ids[] = {
+	{ .compatible = "altr,pio-1.0" },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_pio) = {
+	.name		= "altera_pio",
+	.id		= UCLASS_GPIO,
+	.of_match	= altera_pio_ids,
+	.ops		= &altera_pio_ops,
+	.ofdata_to_platdata = altera_pio_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct altera_pio_platdata),
+	.probe		= altera_pio_probe,
+};
diff --git a/drivers/hwmon/lm81.c b/drivers/hwmon/lm81.c
index c1fc42a..bcc8d32 100644
--- a/drivers/hwmon/lm81.c
+++ b/drivers/hwmon/lm81.c
@@ -90,7 +90,7 @@
 	if (adr < 0)
 		return 1;
 	rev = dtt_read (sensor, DTT_REV);
-	if (adr < 0)
+	if (rev < 0)
 		return 1;
 
 	debug ("DTT:   Found LM81@%x Rev: %d\n", adr, rev);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 8b38a84..101a619 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -4,6 +4,22 @@
 
 menu "Multifunction device drivers"
 
+config MISC
+	bool "Enable Driver Model for Misc drivers"
+	depends on DM
+	help
+	  Enable driver model for miscellaneous devices. This class is
+	  used only for those do not fit other more general classes. A
+	  set of generic read, write and ioctl methods may be used to
+	  access the device.
+
+config ALTERA_SYSID
+	bool "Altera Sysid support"
+	depends on MISC
+	help
+	  Select this to enable a sysid for Altera devices. Please find
+	  details on the "Embedded Peripherals IP User Guide" of Altera.
+
 config CMD_CROS_EC
 	bool "Enable crosec command"
 	depends on CROS_EC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 8d0fc3c..aa137f5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -5,7 +5,9 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-$(CONFIG_MISC) += misc-uclass.o
 obj-$(CONFIG_ALI152X) += ali512x.o
+obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
 obj-$(CONFIG_DS4510)  += ds4510.o
 obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
 obj-$(CONFIG_CROS_EC) += cros_ec.o
diff --git a/drivers/misc/altera_sysid.c b/drivers/misc/altera_sysid.c
new file mode 100644
index 0000000..249b273
--- /dev/null
+++ b/drivers/misc/altera_sysid.c
@@ -0,0 +1,101 @@
+/*
+ * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
+ * Scott McNutt <smcnutt@psyent.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <errno.h>
+#include <misc.h>
+#include <linux/time.h>
+#include <asm/io.h>
+
+struct altera_sysid_regs {
+	u32	id;		/* The system build id */
+	u32	timestamp;	/* Timestamp */
+};
+
+struct altera_sysid_platdata {
+	struct altera_sysid_regs *regs;
+};
+
+void display_sysid(void)
+{
+	struct udevice *dev;
+	u32 sysid[2];
+	struct tm t;
+	char asc[32];
+	time_t stamp;
+	int ret;
+
+	/* the first misc device will be used */
+	ret = uclass_first_device(UCLASS_MISC, &dev);
+	if (ret)
+		return;
+	if (!dev)
+		return;
+	ret = misc_read(dev, 0, &sysid, sizeof(sysid));
+	if (ret)
+		return;
+
+	stamp = sysid[1];
+	localtime_r(&stamp, &t);
+	asctime_r(&t, asc);
+	printf("SYSID: %08x, %s", sysid[0], asc);
+}
+
+int do_sysid(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	display_sysid();
+	return 0;
+}
+
+U_BOOT_CMD(
+	sysid,	1,	1,	do_sysid,
+	"display Nios-II system id",
+	""
+);
+
+static int altera_sysid_read(struct udevice *dev,
+			     int offset, void *buf, int size)
+{
+	struct altera_sysid_platdata *plat = dev->platdata;
+	struct altera_sysid_regs *const regs = plat->regs;
+	u32 *sysid = buf;
+
+	sysid[0] = readl(&regs->id);
+	sysid[1] = readl(&regs->timestamp);
+
+	return 0;
+}
+
+static int altera_sysid_ofdata_to_platdata(struct udevice *dev)
+{
+	struct altera_sysid_platdata *plat = dev_get_platdata(dev);
+
+	plat->regs = ioremap(dev_get_addr(dev),
+		sizeof(struct altera_sysid_regs));
+
+	return 0;
+}
+
+static const struct misc_ops altera_sysid_ops = {
+	.read = altera_sysid_read,
+};
+
+static const struct udevice_id altera_sysid_ids[] = {
+	{ .compatible = "altr,sysid-1.0", },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_sysid) = {
+	.name	= "altera_sysid",
+	.id	= UCLASS_MISC,
+	.of_match = altera_sysid_ids,
+	.ofdata_to_platdata = altera_sysid_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct altera_sysid_platdata),
+	.ops	= &altera_sysid_ops,
+};
diff --git a/drivers/misc/gpio_led.c b/drivers/misc/gpio_led.c
index 3e95727..164c30d 100644
--- a/drivers/misc/gpio_led.c
+++ b/drivers/misc/gpio_led.c
@@ -51,3 +51,57 @@
 {
 	gpio_set_value(mask, !gpio_get_value(mask));
 }
+
+#ifdef CONFIG_GPIO_LED_STUBS
+
+/* 'generic' override of colored LED stubs, to use GPIO functions instead */
+
+#ifdef STATUS_LED_RED
+void red_led_on(void)
+{
+	__led_set(STATUS_LED_RED, STATUS_LED_ON);
+}
+
+void red_led_off(void)
+{
+	__led_set(STATUS_LED_RED, STATUS_LED_OFF);
+}
+#endif
+
+#ifdef STATUS_LED_GREEN
+void green_led_on(void)
+{
+	__led_set(STATUS_LED_GREEN, STATUS_LED_ON);
+}
+
+void green_led_off(void)
+{
+	__led_set(STATUS_LED_GREEN, STATUS_LED_OFF);
+}
+#endif
+
+#ifdef STATUS_LED_YELLOW
+void yellow_led_on(void)
+{
+	__led_set(STATUS_LED_YELLOW, STATUS_LED_ON);
+}
+
+void yellow_led_off(void)
+{
+	__led_set(STATUS_LED_YELLOW, STATUS_LED_OFF);
+}
+#endif
+
+#ifdef STATUS_LED_BLUE
+void blue_led_on(void)
+{
+	__led_set(STATUS_LED_BLUE, STATUS_LED_ON);
+}
+
+void blue_led_off(void)
+{
+	__led_set(STATUS_LED_BLUE, STATUS_LED_OFF);
+}
+#endif
+
+#endif /* CONFIG_GPIO_LED_STUBS */
diff --git a/drivers/misc/misc-uclass.c b/drivers/misc/misc-uclass.c
new file mode 100644
index 0000000..13a6ea5
--- /dev/null
+++ b/drivers/misc/misc-uclass.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <misc.h>
+
+/*
+ * Implement a  miscellaneous uclass for those do not fit other more
+ * general classes. A set of generic read, write and ioctl methods may
+ * be used to access the device.
+ */
+
+int misc_read(struct udevice *dev, int offset, void *buf, int size)
+{
+	const struct misc_ops *ops = device_get_ops(dev);
+
+	if (!ops->read)
+		return -ENOSYS;
+
+	return ops->read(dev, offset, buf, size);
+}
+
+int misc_write(struct udevice *dev, int offset, void *buf, int size)
+{
+	const struct misc_ops *ops = device_get_ops(dev);
+
+	if (!ops->write)
+		return -ENOSYS;
+
+	return ops->write(dev, offset, buf, size);
+}
+
+int misc_ioctl(struct udevice *dev, unsigned long request, void *buf)
+{
+	const struct misc_ops *ops = device_get_ops(dev);
+
+	if (!ops->ioctl)
+		return -ENOSYS;
+
+	return ops->ioctl(dev, request, buf);
+}
+
+UCLASS_DRIVER(misc) = {
+	.id		= UCLASS_MISC,
+	.name		= "misc",
+};
diff --git a/drivers/misc/pca9551_led.c b/drivers/misc/pca9551_led.c
index d4034f6..4da0319 100644
--- a/drivers/misc/pca9551_led.c
+++ b/drivers/misc/pca9551_led.c
@@ -116,8 +116,12 @@
 }
 
 /*
- * Functions referenced by cmd_led.c
+ * Functions referenced by cmd_led.c or status_led.c
  */
+void __led_init(led_id_t id, int state)
+{
+}
+
 void __led_set(led_id_t mask, int state)
 {
 	if (state == STATUS_LED_OFF)
diff --git a/drivers/misc/status_led.c b/drivers/misc/status_led.c
index 9869d98..31e8831 100644
--- a/drivers/misc/status_led.c
+++ b/drivers/misc/status_led.c
@@ -73,7 +73,7 @@
 
 static int status_led_init_done = 0;
 
-static void status_led_init (void)
+void status_led_init(void)
 {
 	led_dev_t *ld;
 	int i;
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index 1bdbfa7..90fb74a 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -172,6 +172,7 @@
 
 /**
  * validate_vid_hdr - check volume identifier header.
+ * @ubi: UBI device description object
  * @vid_hdr: the volume identifier header to check
  * @av: information about the volume this logical eraseblock belongs to
  * @pnum: physical eraseblock number the VID header came from
@@ -184,7 +185,8 @@
  * information in the VID header is consistent to the information in other VID
  * headers of the same volume.
  */
-static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
+static int validate_vid_hdr(const struct ubi_device *ubi,
+			    const struct ubi_vid_hdr *vid_hdr,
 			    const struct ubi_ainf_volume *av, int pnum)
 {
 	int vol_type = vid_hdr->vol_type;
@@ -202,7 +204,7 @@
 		 */
 
 		if (vol_id != av->vol_id) {
-			ubi_err("inconsistent vol_id");
+			ubi_err(ubi, "inconsistent vol_id");
 			goto bad;
 		}
 
@@ -212,17 +214,17 @@
 			av_vol_type = UBI_VID_DYNAMIC;
 
 		if (vol_type != av_vol_type) {
-			ubi_err("inconsistent vol_type");
+			ubi_err(ubi, "inconsistent vol_type");
 			goto bad;
 		}
 
 		if (used_ebs != av->used_ebs) {
-			ubi_err("inconsistent used_ebs");
+			ubi_err(ubi, "inconsistent used_ebs");
 			goto bad;
 		}
 
 		if (data_pad != av->data_pad) {
-			ubi_err("inconsistent data_pad");
+			ubi_err(ubi, "inconsistent data_pad");
 			goto bad;
 		}
 	}
@@ -230,7 +232,7 @@
 	return 0;
 
 bad:
-	ubi_err("inconsistent VID header at PEB %d", pnum);
+	ubi_err(ubi, "inconsistent VID header at PEB %d", pnum);
 	ubi_dump_vid_hdr(vid_hdr);
 	ubi_dump_av(av);
 	return -EINVAL;
@@ -332,7 +334,7 @@
 		 * support these images anymore. Well, those images still work,
 		 * but only if no unclean reboots happened.
 		 */
-		ubi_err("unsupported on-flash UBI format");
+		ubi_err(ubi, "unsupported on-flash UBI format");
 		return -EINVAL;
 	}
 
@@ -373,7 +375,7 @@
 			if (err == UBI_IO_BITFLIPS)
 				bitflips = 1;
 			else {
-				ubi_err("VID of PEB %d header is bad, but it was OK earlier, err %d",
+				ubi_err(ubi, "VID of PEB %d header is bad, but it was OK earlier, err %d",
 					pnum, err);
 				if (err > 0)
 					err = -EIO;
@@ -404,7 +406,7 @@
 		second_is_newer = !second_is_newer;
 	} else {
 		dbg_bld("PEB %d CRC is OK", pnum);
-		bitflips = !!err;
+		bitflips |= !!err;
 	}
 	mutex_unlock(&ubi->buf_mutex);
 
@@ -503,7 +505,7 @@
 		 * logical eraseblocks because there was an unclean reboot.
 		 */
 		if (aeb->sqnum == sqnum && sqnum != 0) {
-			ubi_err("two LEBs with same sequence number %llu",
+			ubi_err(ubi, "two LEBs with same sequence number %llu",
 				sqnum);
 			ubi_dump_aeb(aeb, 0);
 			ubi_dump_vid_hdr(vid_hdr);
@@ -523,7 +525,7 @@
 			 * This logical eraseblock is newer than the one
 			 * found earlier.
 			 */
-			err = validate_vid_hdr(vid_hdr, av, pnum);
+			err = validate_vid_hdr(ubi, vid_hdr, av, pnum);
 			if (err)
 				return err;
 
@@ -561,7 +563,7 @@
 	 * attaching information.
 	 */
 
-	err = validate_vid_hdr(vid_hdr, av, pnum);
+	err = validate_vid_hdr(ubi, vid_hdr, av, pnum);
 	if (err)
 		return err;
 
@@ -664,7 +666,8 @@
 		 * Erase counter overflow. Upgrade UBI and use 64-bit
 		 * erase counters internally.
 		 */
-		ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec);
+		ubi_err(ubi, "erase counter overflow at PEB %d, EC %d",
+			pnum, ec);
 		return -EINVAL;
 	}
 
@@ -732,7 +735,7 @@
 		return aeb;
 	}
 
-	ubi_err("no free eraseblocks");
+	ubi_err(ubi, "no free eraseblocks");
 	return ERR_PTR(-ENOSPC);
 }
 
@@ -781,9 +784,9 @@
 	if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
 		goto out_unlock;
 
-	ubi_err("PEB %d contains corrupted VID header, and the data does not contain all 0xFF",
+	ubi_err(ubi, "PEB %d contains corrupted VID header, and the data does not contain all 0xFF",
 		pnum);
-	ubi_err("this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection");
+	ubi_err(ubi, "this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection");
 	ubi_dump_vid_hdr(vid_hdr);
 	pr_err("hexdump of PEB %d offset %d, length %d",
 	       pnum, ubi->leb_start, ubi->leb_size);
@@ -855,7 +858,8 @@
 		bitflips = 1;
 		break;
 	default:
-		ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err);
+		ubi_err(ubi, "'ubi_io_read_ec_hdr()' returned unknown code %d",
+			err);
 		return -EINVAL;
 	}
 
@@ -864,7 +868,7 @@
 
 		/* Make sure UBI version is OK */
 		if (ech->version != UBI_VERSION) {
-			ubi_err("this UBI version is %d, image version is %d",
+			ubi_err(ubi, "this UBI version is %d, image version is %d",
 				UBI_VERSION, (int)ech->version);
 			return -EINVAL;
 		}
@@ -878,7 +882,7 @@
 			 * flash. Upgrade UBI and use 64-bit erase counters
 			 * internally.
 			 */
-			ubi_err("erase counter overflow, max is %d",
+			ubi_err(ubi, "erase counter overflow, max is %d",
 				UBI_MAX_ERASECOUNTER);
 			ubi_dump_ec_hdr(ech);
 			return -EINVAL;
@@ -899,7 +903,7 @@
 		if (!ubi->image_seq)
 			ubi->image_seq = image_seq;
 		if (image_seq && ubi->image_seq != image_seq) {
-			ubi_err("bad image sequence number %d in PEB %d, expected %d",
+			ubi_err(ubi, "bad image sequence number %d in PEB %d, expected %d",
 				image_seq, pnum, ubi->image_seq);
 			ubi_dump_ec_hdr(ech);
 			return -EINVAL;
@@ -977,7 +981,7 @@
 			return err;
 		goto adjust_mean_ec;
 	default:
-		ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d",
+		ubi_err(ubi, "'ubi_io_read_vid_hdr()' returned unknown code %d",
 			err);
 		return -EINVAL;
 	}
@@ -995,7 +999,7 @@
 		case UBI_COMPAT_DELETE:
 			if (vol_id != UBI_FM_SB_VOLUME_ID
 			    && vol_id != UBI_FM_DATA_VOLUME_ID) {
-				ubi_msg("\"delete\" compatible internal volume %d:%d found, will remove it",
+				ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
 					vol_id, lnum);
 			}
 			err = add_to_list(ai, pnum, vol_id, lnum,
@@ -1005,13 +1009,13 @@
 			return 0;
 
 		case UBI_COMPAT_RO:
-			ubi_msg("read-only compatible internal volume %d:%d found, switch to read-only mode",
+			ubi_msg(ubi, "read-only compatible internal volume %d:%d found, switch to read-only mode",
 				vol_id, lnum);
 			ubi->ro_mode = 1;
 			break;
 
 		case UBI_COMPAT_PRESERVE:
-			ubi_msg("\"preserve\" compatible internal volume %d:%d found",
+			ubi_msg(ubi, "\"preserve\" compatible internal volume %d:%d found",
 				vol_id, lnum);
 			err = add_to_list(ai, pnum, vol_id, lnum,
 					  ec, 0, &ai->alien);
@@ -1020,14 +1024,14 @@
 			return 0;
 
 		case UBI_COMPAT_REJECT:
-			ubi_err("incompatible internal volume %d:%d found",
+			ubi_err(ubi, "incompatible internal volume %d:%d found",
 				vol_id, lnum);
 			return -EINVAL;
 		}
 	}
 
 	if (ec_err)
-		ubi_warn("valid VID header but corrupted EC header at PEB %d",
+		ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d",
 			 pnum);
 	err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
 	if (err)
@@ -1071,7 +1075,7 @@
 	 * with the flash HW or driver.
 	 */
 	if (ai->corr_peb_count) {
-		ubi_err("%d PEBs are corrupted and preserved",
+		ubi_err(ubi, "%d PEBs are corrupted and preserved",
 			ai->corr_peb_count);
 		pr_err("Corrupted PEBs are:");
 		list_for_each_entry(aeb, &ai->corr, u.list)
@@ -1083,7 +1087,7 @@
 		 * otherwise, only print a warning.
 		 */
 		if (ai->corr_peb_count >= max_corr) {
-			ubi_err("too many corrupted PEBs, refusing");
+			ubi_err(ubi, "too many corrupted PEBs, refusing");
 			return -EINVAL;
 		}
 	}
@@ -1106,11 +1110,11 @@
 		 */
 		if (ai->maybe_bad_peb_count <= 2) {
 			ai->is_empty = 1;
-			ubi_msg("empty MTD device detected");
+			ubi_msg(ubi, "empty MTD device detected");
 			get_random_bytes(&ubi->image_seq,
 					 sizeof(ubi->image_seq));
 		} else {
-			ubi_err("MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it");
+			ubi_err(ubi, "MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it");
 			return -EINVAL;
 		}
 
@@ -1244,7 +1248,7 @@
 			goto out_vidh;
 	}
 
-	ubi_msg("scanning is finished");
+	ubi_msg(ubi, "scanning is finished");
 
 	/* Calculate mean erase counter */
 	if (ai->ec_count)
@@ -1293,6 +1297,30 @@
 	return err;
 }
 
+static struct ubi_attach_info *alloc_ai(void)
+{
+	struct ubi_attach_info *ai;
+
+	ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
+	if (!ai)
+		return ai;
+
+	INIT_LIST_HEAD(&ai->corr);
+	INIT_LIST_HEAD(&ai->free);
+	INIT_LIST_HEAD(&ai->erase);
+	INIT_LIST_HEAD(&ai->alien);
+	ai->volumes = RB_ROOT;
+	ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
+					       sizeof(struct ubi_ainf_peb),
+					       0, 0, NULL);
+	if (!ai->aeb_slab_cache) {
+		kfree(ai);
+		ai = NULL;
+	}
+
+	return ai;
+}
+
 #ifdef CONFIG_MTD_UBI_FASTMAP
 
 /**
@@ -1305,7 +1333,7 @@
  * UBI_NO_FASTMAP denotes that no fastmap was found.
  * UBI_BAD_FASTMAP denotes that the found fastmap was invalid.
  */
-static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info *ai)
+static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info **ai)
 {
 	int err, pnum, fm_anchor = -1;
 	unsigned long long max_sqnum = 0;
@@ -1326,7 +1354,7 @@
 		cond_resched();
 
 		dbg_gen("process PEB %d", pnum);
-		err = scan_peb(ubi, ai, pnum, &vol_id, &sqnum);
+		err = scan_peb(ubi, *ai, pnum, &vol_id, &sqnum);
 		if (err < 0)
 			goto out_vidh;
 
@@ -1342,7 +1370,12 @@
 	if (fm_anchor < 0)
 		return UBI_NO_FASTMAP;
 
-	return ubi_scan_fastmap(ubi, ai, fm_anchor);
+	destroy_ai(*ai);
+	*ai = alloc_ai();
+	if (!*ai)
+		return -ENOMEM;
+
+	return ubi_scan_fastmap(ubi, *ai, fm_anchor);
 
 out_vidh:
 	ubi_free_vid_hdr(ubi, vidh);
@@ -1354,30 +1387,6 @@
 
 #endif
 
-static struct ubi_attach_info *alloc_ai(const char *slab_name)
-{
-	struct ubi_attach_info *ai;
-
-	ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
-	if (!ai)
-		return ai;
-
-	INIT_LIST_HEAD(&ai->corr);
-	INIT_LIST_HEAD(&ai->free);
-	INIT_LIST_HEAD(&ai->erase);
-	INIT_LIST_HEAD(&ai->alien);
-	ai->volumes = RB_ROOT;
-	ai->aeb_slab_cache = kmem_cache_create(slab_name,
-					       sizeof(struct ubi_ainf_peb),
-					       0, 0, NULL);
-	if (!ai->aeb_slab_cache) {
-		kfree(ai);
-		ai = NULL;
-	}
-
-	return ai;
-}
-
 /**
  * ubi_attach - attach an MTD device.
  * @ubi: UBI device descriptor
@@ -1391,7 +1400,7 @@
 	int err;
 	struct ubi_attach_info *ai;
 
-	ai = alloc_ai("ubi_aeb_slab_cache");
+	ai = alloc_ai();
 	if (!ai)
 		return -ENOMEM;
 
@@ -1405,11 +1414,11 @@
 	if (force_scan)
 		err = scan_all(ubi, ai, 0);
 	else {
-		err = scan_fast(ubi, ai);
-		if (err > 0) {
+		err = scan_fast(ubi, &ai);
+		if (err > 0 || mtd_is_eccerr(err)) {
 			if (err != UBI_NO_FASTMAP) {
 				destroy_ai(ai);
-				ai = alloc_ai("ubi_aeb_slab_cache2");
+				ai = alloc_ai();
 				if (!ai)
 					return -ENOMEM;
 
@@ -1445,10 +1454,10 @@
 		goto out_wl;
 
 #ifdef CONFIG_MTD_UBI_FASTMAP
-	if (ubi->fm && ubi_dbg_chk_gen(ubi)) {
+	if (ubi->fm && ubi_dbg_chk_fastmap(ubi)) {
 		struct ubi_attach_info *scan_ai;
 
-		scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache");
+		scan_ai = alloc_ai();
 		if (!scan_ai) {
 			err = -ENOMEM;
 			goto out_wl;
@@ -1511,37 +1520,37 @@
 		vols_found += 1;
 
 		if (ai->is_empty) {
-			ubi_err("bad is_empty flag");
+			ubi_err(ubi, "bad is_empty flag");
 			goto bad_av;
 		}
 
 		if (av->vol_id < 0 || av->highest_lnum < 0 ||
 		    av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 ||
 		    av->data_pad < 0 || av->last_data_size < 0) {
-			ubi_err("negative values");
+			ubi_err(ubi, "negative values");
 			goto bad_av;
 		}
 
 		if (av->vol_id >= UBI_MAX_VOLUMES &&
 		    av->vol_id < UBI_INTERNAL_VOL_START) {
-			ubi_err("bad vol_id");
+			ubi_err(ubi, "bad vol_id");
 			goto bad_av;
 		}
 
 		if (av->vol_id > ai->highest_vol_id) {
-			ubi_err("highest_vol_id is %d, but vol_id %d is there",
+			ubi_err(ubi, "highest_vol_id is %d, but vol_id %d is there",
 				ai->highest_vol_id, av->vol_id);
 			goto out;
 		}
 
 		if (av->vol_type != UBI_DYNAMIC_VOLUME &&
 		    av->vol_type != UBI_STATIC_VOLUME) {
-			ubi_err("bad vol_type");
+			ubi_err(ubi, "bad vol_type");
 			goto bad_av;
 		}
 
 		if (av->data_pad > ubi->leb_size / 2) {
-			ubi_err("bad data_pad");
+			ubi_err(ubi, "bad data_pad");
 			goto bad_av;
 		}
 
@@ -1553,48 +1562,48 @@
 			leb_count += 1;
 
 			if (aeb->pnum < 0 || aeb->ec < 0) {
-				ubi_err("negative values");
+				ubi_err(ubi, "negative values");
 				goto bad_aeb;
 			}
 
 			if (aeb->ec < ai->min_ec) {
-				ubi_err("bad ai->min_ec (%d), %d found",
+				ubi_err(ubi, "bad ai->min_ec (%d), %d found",
 					ai->min_ec, aeb->ec);
 				goto bad_aeb;
 			}
 
 			if (aeb->ec > ai->max_ec) {
-				ubi_err("bad ai->max_ec (%d), %d found",
+				ubi_err(ubi, "bad ai->max_ec (%d), %d found",
 					ai->max_ec, aeb->ec);
 				goto bad_aeb;
 			}
 
 			if (aeb->pnum >= ubi->peb_count) {
-				ubi_err("too high PEB number %d, total PEBs %d",
+				ubi_err(ubi, "too high PEB number %d, total PEBs %d",
 					aeb->pnum, ubi->peb_count);
 				goto bad_aeb;
 			}
 
 			if (av->vol_type == UBI_STATIC_VOLUME) {
 				if (aeb->lnum >= av->used_ebs) {
-					ubi_err("bad lnum or used_ebs");
+					ubi_err(ubi, "bad lnum or used_ebs");
 					goto bad_aeb;
 				}
 			} else {
 				if (av->used_ebs != 0) {
-					ubi_err("non-zero used_ebs");
+					ubi_err(ubi, "non-zero used_ebs");
 					goto bad_aeb;
 				}
 			}
 
 			if (aeb->lnum > av->highest_lnum) {
-				ubi_err("incorrect highest_lnum or lnum");
+				ubi_err(ubi, "incorrect highest_lnum or lnum");
 				goto bad_aeb;
 			}
 		}
 
 		if (av->leb_count != leb_count) {
-			ubi_err("bad leb_count, %d objects in the tree",
+			ubi_err(ubi, "bad leb_count, %d objects in the tree",
 				leb_count);
 			goto bad_av;
 		}
@@ -1605,13 +1614,13 @@
 		aeb = last_aeb;
 
 		if (aeb->lnum != av->highest_lnum) {
-			ubi_err("bad highest_lnum");
+			ubi_err(ubi, "bad highest_lnum");
 			goto bad_aeb;
 		}
 	}
 
 	if (vols_found != ai->vols_found) {
-		ubi_err("bad ai->vols_found %d, should be %d",
+		ubi_err(ubi, "bad ai->vols_found %d, should be %d",
 			ai->vols_found, vols_found);
 		goto out;
 	}
@@ -1628,7 +1637,8 @@
 
 			err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1);
 			if (err && err != UBI_IO_BITFLIPS) {
-				ubi_err("VID header is not OK (%d)", err);
+				ubi_err(ubi, "VID header is not OK (%d)",
+					err);
 				if (err > 0)
 					err = -EIO;
 				return err;
@@ -1637,37 +1647,37 @@
 			vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
 				   UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
 			if (av->vol_type != vol_type) {
-				ubi_err("bad vol_type");
+				ubi_err(ubi, "bad vol_type");
 				goto bad_vid_hdr;
 			}
 
 			if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) {
-				ubi_err("bad sqnum %llu", aeb->sqnum);
+				ubi_err(ubi, "bad sqnum %llu", aeb->sqnum);
 				goto bad_vid_hdr;
 			}
 
 			if (av->vol_id != be32_to_cpu(vidh->vol_id)) {
-				ubi_err("bad vol_id %d", av->vol_id);
+				ubi_err(ubi, "bad vol_id %d", av->vol_id);
 				goto bad_vid_hdr;
 			}
 
 			if (av->compat != vidh->compat) {
-				ubi_err("bad compat %d", vidh->compat);
+				ubi_err(ubi, "bad compat %d", vidh->compat);
 				goto bad_vid_hdr;
 			}
 
 			if (aeb->lnum != be32_to_cpu(vidh->lnum)) {
-				ubi_err("bad lnum %d", aeb->lnum);
+				ubi_err(ubi, "bad lnum %d", aeb->lnum);
 				goto bad_vid_hdr;
 			}
 
 			if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) {
-				ubi_err("bad used_ebs %d", av->used_ebs);
+				ubi_err(ubi, "bad used_ebs %d", av->used_ebs);
 				goto bad_vid_hdr;
 			}
 
 			if (av->data_pad != be32_to_cpu(vidh->data_pad)) {
-				ubi_err("bad data_pad %d", av->data_pad);
+				ubi_err(ubi, "bad data_pad %d", av->data_pad);
 				goto bad_vid_hdr;
 			}
 		}
@@ -1676,12 +1686,13 @@
 			continue;
 
 		if (av->highest_lnum != be32_to_cpu(vidh->lnum)) {
-			ubi_err("bad highest_lnum %d", av->highest_lnum);
+			ubi_err(ubi, "bad highest_lnum %d", av->highest_lnum);
 			goto bad_vid_hdr;
 		}
 
 		if (av->last_data_size != be32_to_cpu(vidh->data_size)) {
-			ubi_err("bad last_data_size %d", av->last_data_size);
+			ubi_err(ubi, "bad last_data_size %d",
+				av->last_data_size);
 			goto bad_vid_hdr;
 		}
 	}
@@ -1722,7 +1733,7 @@
 	err = 0;
 	for (pnum = 0; pnum < ubi->peb_count; pnum++)
 		if (!buf[pnum]) {
-			ubi_err("PEB %d is not referred", pnum);
+			ubi_err(ubi, "PEB %d is not referred", pnum);
 			err = 1;
 		}
 
@@ -1732,18 +1743,18 @@
 	return 0;
 
 bad_aeb:
-	ubi_err("bad attaching information about LEB %d", aeb->lnum);
+	ubi_err(ubi, "bad attaching information about LEB %d", aeb->lnum);
 	ubi_dump_aeb(aeb, 0);
 	ubi_dump_av(av);
 	goto out;
 
 bad_av:
-	ubi_err("bad attaching information about volume %d", av->vol_id);
+	ubi_err(ubi, "bad attaching information about volume %d", av->vol_id);
 	ubi_dump_av(av);
 	goto out;
 
 bad_vid_hdr:
-	ubi_err("bad attaching information about volume %d", av->vol_id);
+	ubi_err(ubi, "bad attaching information about volume %d", av->vol_id);
 	ubi_dump_av(av);
 	ubi_dump_vid_hdr(vidh);
 
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 290d524..f0a3b67 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -80,6 +80,7 @@
 #ifdef CONFIG_MTD_UBI_FASTMAP
 /* UBI module parameter to enable fastmap automatically on non-fastmap images */
 static bool fm_autoconvert;
+static bool fm_debug;
 #endif
 #else
 #ifdef CONFIG_MTD_UBI_FASTMAP
@@ -87,10 +88,12 @@
 #define CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT 0
 #endif
 static bool fm_autoconvert = CONFIG_MTD_UBI_FASTMAP_AUTOCONVERT;
+#if !defined(CONFIG_MTD_UBI_FM_DEBUG)
+#define CONFIG_MTD_UBI_FM_DEBUG 0
+#endif
+static bool fm_debug = CONFIG_MTD_UBI_FM_DEBUG;
 #endif
 #endif
-/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
-struct class *ubi_class;
 
 /* Slab cache for wear-leveling entries */
 struct kmem_cache *ubi_wl_entry_slab;
@@ -110,7 +113,7 @@
 #else
 struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
 #endif
-
+ 
 #ifndef __UBOOT__
 /* Serializes UBI devices creations and removals */
 DEFINE_MUTEX(ubi_devices_mutex);
@@ -126,8 +129,17 @@
 }
 
 /* UBI version attribute ('/<sysfs>/class/ubi/version') */
-static struct class_attribute ubi_version =
-	__ATTR(version, S_IRUGO, ubi_version_show, NULL);
+static struct class_attribute ubi_class_attrs[] = {
+	__ATTR(version, S_IRUGO, ubi_version_show, NULL),
+	__ATTR_NULL
+};
+
+/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
+struct class ubi_class = {
+	.name		= UBI_NAME_STR,
+	.owner		= THIS_MODULE,
+	.class_attrs	= ubi_class_attrs,
+};
 
 static ssize_t dev_attribute_show(struct device *dev,
 				  struct device_attribute *attr, char *buf);
@@ -169,23 +181,22 @@
  */
 int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype)
 {
+	int ret;
 	struct ubi_notification nt;
 
 	ubi_do_get_device_info(ubi, &nt.di);
 	ubi_do_get_volume_info(ubi, vol, &nt.vi);
 
-#ifdef CONFIG_MTD_UBI_FASTMAP
 	switch (ntype) {
 	case UBI_VOLUME_ADDED:
 	case UBI_VOLUME_REMOVED:
 	case UBI_VOLUME_RESIZED:
 	case UBI_VOLUME_RENAMED:
-		if (ubi_update_fastmap(ubi)) {
-			ubi_err("Unable to update fastmap!");
-			ubi_ro_mode(ubi);
-		}
+		ret = ubi_update_fastmap(ubi);
+		if (ret)
+			ubi_msg(ubi, "Unable to write a new fastmap: %i", ret);
 	}
-#endif
+
 	return blocking_notifier_call_chain(&ubi_notifiers, ntype, &nt);
 }
 
@@ -406,6 +417,22 @@
 	return ret;
 }
 
+static struct attribute *ubi_dev_attrs[] = {
+	&dev_eraseblock_size.attr,
+	&dev_avail_eraseblocks.attr,
+	&dev_total_eraseblocks.attr,
+	&dev_volumes_count.attr,
+	&dev_max_ec.attr,
+	&dev_reserved_for_bad.attr,
+	&dev_bad_peb_count.attr,
+	&dev_max_vol_count.attr,
+	&dev_min_io_size.attr,
+	&dev_bgt_enabled.attr,
+	&dev_mtd_num.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(ubi_dev);
+
 static void dev_release(struct device *dev)
 {
 	struct ubi_device *ubi = container_of(dev, struct ubi_device, dev);
@@ -428,45 +455,15 @@
 
 	ubi->dev.release = dev_release;
 	ubi->dev.devt = ubi->cdev.dev;
-	ubi->dev.class = ubi_class;
+	ubi->dev.class = &ubi_class;
+	ubi->dev.groups = ubi_dev_groups;
 	dev_set_name(&ubi->dev, UBI_NAME_STR"%d", ubi->ubi_num);
 	err = device_register(&ubi->dev);
 	if (err)
 		return err;
 
 	*ref = 1;
-	err = device_create_file(&ubi->dev, &dev_eraseblock_size);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_total_eraseblocks);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_volumes_count);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_max_ec);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_reserved_for_bad);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_bad_peb_count);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_max_vol_count);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_min_io_size);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_bgt_enabled);
-	if (err)
-		return err;
-	err = device_create_file(&ubi->dev, &dev_mtd_num);
-	return err;
+	return 0;
 }
 
 /**
@@ -475,17 +472,6 @@
  */
 static void ubi_sysfs_close(struct ubi_device *ubi)
 {
-	device_remove_file(&ubi->dev, &dev_mtd_num);
-	device_remove_file(&ubi->dev, &dev_bgt_enabled);
-	device_remove_file(&ubi->dev, &dev_min_io_size);
-	device_remove_file(&ubi->dev, &dev_max_vol_count);
-	device_remove_file(&ubi->dev, &dev_bad_peb_count);
-	device_remove_file(&ubi->dev, &dev_reserved_for_bad);
-	device_remove_file(&ubi->dev, &dev_max_ec);
-	device_remove_file(&ubi->dev, &dev_volumes_count);
-	device_remove_file(&ubi->dev, &dev_total_eraseblocks);
-	device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
-	device_remove_file(&ubi->dev, &dev_eraseblock_size);
 	device_unregister(&ubi->dev);
 }
 #endif
@@ -541,7 +527,7 @@
 	 */
 	err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name);
 	if (err) {
-		ubi_err("cannot register UBI character devices");
+		ubi_err(ubi, "cannot register UBI character devices");
 		return err;
 	}
 
@@ -552,7 +538,7 @@
 
 	err = cdev_add(&ubi->cdev, dev, 1);
 	if (err) {
-		ubi_err("cannot add character device");
+		ubi_err(ubi, "cannot add character device");
 		goto out_unreg;
 	}
 
@@ -564,7 +550,7 @@
 		if (ubi->volumes[i]) {
 			err = ubi_add_volume(ubi, ubi->volumes[i]);
 			if (err) {
-				ubi_err("cannot add volume %d", i);
+				ubi_err(ubi, "cannot add volume %d", i);
 				goto out_volumes;
 			}
 		}
@@ -580,7 +566,8 @@
 	cdev_del(&ubi->cdev);
 out_unreg:
 	unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
-	ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
+	ubi_err(ubi, "cannot initialize UBI %s, error %d",
+		ubi->ubi_name, err);
 	return err;
 }
 
@@ -674,7 +661,7 @@
 		 * guess we should just pick the largest region. But this is
 		 * not implemented.
 		 */
-		ubi_err("multiple regions, not implemented");
+		ubi_err(ubi, "multiple regions, not implemented");
 		return -EINVAL;
 	}
 
@@ -709,7 +696,7 @@
 	 * which allows us to avoid costly division operations.
 	 */
 	if (!is_power_of_2(ubi->min_io_size)) {
-		ubi_err("min. I/O unit (%d) is not power of 2",
+		ubi_err(ubi, "min. I/O unit (%d) is not power of 2",
 			ubi->min_io_size);
 		return -EINVAL;
 	}
@@ -726,7 +713,7 @@
 	if (ubi->max_write_size < ubi->min_io_size ||
 	    ubi->max_write_size % ubi->min_io_size ||
 	    !is_power_of_2(ubi->max_write_size)) {
-		ubi_err("bad write buffer size %d for %d min. I/O unit",
+		ubi_err(ubi, "bad write buffer size %d for %d min. I/O unit",
 			ubi->max_write_size, ubi->min_io_size);
 		return -EINVAL;
 	}
@@ -763,7 +750,7 @@
 
 	/* The shift must be aligned to 32-bit boundary */
 	if (ubi->vid_hdr_shift % 4) {
-		ubi_err("unaligned VID header shift %d",
+		ubi_err(ubi, "unaligned VID header shift %d",
 			ubi->vid_hdr_shift);
 		return -EINVAL;
 	}
@@ -773,7 +760,7 @@
 	    ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||
 	    ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||
 	    ubi->leb_start & (ubi->min_io_size - 1)) {
-		ubi_err("bad VID header (%d) or data offsets (%d)",
+		ubi_err(ubi, "bad VID header (%d) or data offsets (%d)",
 			ubi->vid_hdr_offset, ubi->leb_start);
 		return -EINVAL;
 	}
@@ -793,14 +780,14 @@
 	 * read-only mode.
 	 */
 	if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) {
-		ubi_warn("EC and VID headers are in the same minimal I/O unit, switch to read-only mode");
+		ubi_warn(ubi, "EC and VID headers are in the same minimal I/O unit, switch to read-only mode");
 		ubi->ro_mode = 1;
 	}
 
 	ubi->leb_size = ubi->peb_size - ubi->leb_start;
 
 	if (!(ubi->mtd->flags & MTD_WRITEABLE)) {
-		ubi_msg("MTD device %d is write-protected, attach in read-only mode",
+		ubi_msg(ubi, "MTD device %d is write-protected, attach in read-only mode",
 			ubi->mtd->index);
 		ubi->ro_mode = 1;
 	}
@@ -833,7 +820,7 @@
 	int err, old_reserved_pebs = vol->reserved_pebs;
 
 	if (ubi->ro_mode) {
-		ubi_warn("skip auto-resize because of R/O mode");
+		ubi_warn(ubi, "skip auto-resize because of R/O mode");
 		return 0;
 	}
 
@@ -854,21 +841,22 @@
 		vtbl_rec = ubi->vtbl[vol_id];
 		err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
 		if (err)
-			ubi_err("cannot clean auto-resize flag for volume %d",
+			ubi_err(ubi, "cannot clean auto-resize flag for volume %d",
 				vol_id);
 	} else {
 		desc.vol = vol;
 		err = ubi_resize_volume(&desc,
 					old_reserved_pebs + ubi->avail_pebs);
 		if (err)
-			ubi_err("cannot auto-resize volume %d", vol_id);
+			ubi_err(ubi, "cannot auto-resize volume %d",
+				vol_id);
 	}
 
 	if (err)
 		return err;
 
-	ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id,
-		vol->name, old_reserved_pebs, vol->reserved_pebs);
+	ubi_msg(ubi, "volume %d (\"%s\") re-sized from %d to %d LEBs",
+		vol_id, vol->name, old_reserved_pebs, vol->reserved_pebs);
 	return 0;
 }
 
@@ -909,7 +897,7 @@
 	for (i = 0; i < UBI_MAX_DEVICES; i++) {
 		ubi = ubi_devices[i];
 		if (ubi && mtd->index == ubi->mtd->index) {
-			ubi_err("mtd%d is already attached to ubi%d",
+			ubi_err(ubi, "mtd%d is already attached to ubi%d",
 				mtd->index, i);
 			return -EEXIST;
 		}
@@ -924,7 +912,7 @@
 	 * no sense to attach emulated MTD devices, so we prohibit this.
 	 */
 	if (mtd->type == MTD_UBIVOLUME) {
-		ubi_err("refuse attaching mtd%d - it is already emulated on top of UBI",
+		ubi_err(ubi, "refuse attaching mtd%d - it is already emulated on top of UBI",
 			mtd->index);
 		return -EINVAL;
 	}
@@ -935,7 +923,7 @@
 			if (!ubi_devices[ubi_num])
 				break;
 		if (ubi_num == UBI_MAX_DEVICES) {
-			ubi_err("only %d UBI devices may be created",
+			ubi_err(ubi, "only %d UBI devices may be created",
 				UBI_MAX_DEVICES);
 			return -ENFILE;
 		}
@@ -945,7 +933,7 @@
 
 		/* Make sure ubi_num is not busy */
 		if (ubi_devices[ubi_num]) {
-			ubi_err("ubi%d already exists", ubi_num);
+			ubi_err(ubi, "already exists");
 			return -EEXIST;
 		}
 	}
@@ -969,21 +957,24 @@
 	 */
 	ubi->fm_pool.max_size = min(((int)mtd_div_by_eb(ubi->mtd->size,
 		ubi->mtd) / 100) * 5, UBI_FM_MAX_POOL_SIZE);
-	if (ubi->fm_pool.max_size < UBI_FM_MIN_POOL_SIZE)
-		ubi->fm_pool.max_size = UBI_FM_MIN_POOL_SIZE;
+	ubi->fm_pool.max_size = max(ubi->fm_pool.max_size,
+		UBI_FM_MIN_POOL_SIZE);
 
-	ubi->fm_wl_pool.max_size = UBI_FM_WL_POOL_SIZE;
+	ubi->fm_wl_pool.max_size = ubi->fm_pool.max_size / 2;
 	ubi->fm_disabled = !fm_autoconvert;
+	if (fm_debug)
+		ubi_enable_dbg_chk_fastmap(ubi);
 
 	if (!ubi->fm_disabled && (int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd)
 	    <= UBI_FM_MAX_START) {
-		ubi_err("More than %i PEBs are needed for fastmap, sorry.",
+		ubi_err(ubi, "More than %i PEBs are needed for fastmap, sorry.",
 			UBI_FM_MAX_START);
 		ubi->fm_disabled = 1;
 	}
 
-	ubi_msg("default fastmap pool size: %d", ubi->fm_pool.max_size);
-	ubi_msg("default fastmap WL pool size: %d", ubi->fm_wl_pool.max_size);
+	ubi_msg(ubi, "default fastmap pool size: %d", ubi->fm_pool.max_size);
+	ubi_msg(ubi, "default fastmap WL pool size: %d",
+		ubi->fm_wl_pool.max_size);
 #else
 	ubi->fm_disabled = 1;
 #endif
@@ -991,10 +982,10 @@
 	mutex_init(&ubi->ckvol_mutex);
 	mutex_init(&ubi->device_mutex);
 	spin_lock_init(&ubi->volumes_lock);
-	mutex_init(&ubi->fm_mutex);
-	init_rwsem(&ubi->fm_sem);
+	init_rwsem(&ubi->fm_protect);
+	init_rwsem(&ubi->fm_eba_sem);
 
-	ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
+	ubi_msg(ubi, "attaching mtd%d", mtd->index);
 
 	err = io_init(ubi, max_beb_per1024);
 	if (err)
@@ -1013,7 +1004,8 @@
 #endif
 	err = ubi_attach(ubi, 0);
 	if (err) {
-		ubi_err("failed to attach mtd%d, error %d", mtd->index, err);
+		ubi_err(ubi, "failed to attach mtd%d, error %d",
+			mtd->index, err);
 		goto out_free;
 	}
 
@@ -1034,28 +1026,28 @@
 	ubi->bgt_thread = kthread_create(ubi_thread, ubi, "%s", ubi->bgt_name);
 	if (IS_ERR(ubi->bgt_thread)) {
 		err = PTR_ERR(ubi->bgt_thread);
-		ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
-			err);
+		ubi_err(ubi, "cannot spawn \"%s\", error %d",
+			ubi->bgt_name, err);
 		goto out_debugfs;
 	}
 
-	ubi_msg("attached mtd%d (name \"%s\", size %llu MiB) to ubi%d",
-		mtd->index, mtd->name, ubi->flash_size >> 20, ubi_num);
-	ubi_msg("PEB size: %d bytes (%d KiB), LEB size: %d bytes",
+	ubi_msg(ubi, "attached mtd%d (name \"%s\", size %llu MiB)",
+		mtd->index, mtd->name, ubi->flash_size >> 20);
+	ubi_msg(ubi, "PEB size: %d bytes (%d KiB), LEB size: %d bytes",
 		ubi->peb_size, ubi->peb_size >> 10, ubi->leb_size);
-	ubi_msg("min./max. I/O unit sizes: %d/%d, sub-page size %d",
+	ubi_msg(ubi, "min./max. I/O unit sizes: %d/%d, sub-page size %d",
 		ubi->min_io_size, ubi->max_write_size, ubi->hdrs_min_io_size);
-	ubi_msg("VID header offset: %d (aligned %d), data offset: %d",
+	ubi_msg(ubi, "VID header offset: %d (aligned %d), data offset: %d",
 		ubi->vid_hdr_offset, ubi->vid_hdr_aloffset, ubi->leb_start);
-	ubi_msg("good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d",
+	ubi_msg(ubi, "good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d",
 		ubi->good_peb_count, ubi->bad_peb_count, ubi->corr_peb_count);
-	ubi_msg("user volume: %d, internal volumes: %d, max. volumes count: %d",
+	ubi_msg(ubi, "user volume: %d, internal volumes: %d, max. volumes count: %d",
 		ubi->vol_count - UBI_INT_VOL_COUNT, UBI_INT_VOL_COUNT,
 		ubi->vtbl_slots);
-	ubi_msg("max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u",
+	ubi_msg(ubi, "max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u",
 		ubi->max_ec, ubi->mean_ec, CONFIG_MTD_UBI_WL_THRESHOLD,
 		ubi->image_seq);
-	ubi_msg("available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d",
+	ubi_msg(ubi, "available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d",
 		ubi->avail_pebs, ubi->rsvd_pebs, ubi->beb_rsvd_pebs);
 
 	/*
@@ -1064,7 +1056,20 @@
 	 */
 	spin_lock(&ubi->wl_lock);
 	ubi->thread_enabled = 1;
+#ifndef __UBOOT__
 	wake_up_process(ubi->bgt_thread);
+#else
+	/*
+	 * U-Boot special: We have no bgt_thread in U-Boot!
+	 * So just call do_work() here directly.
+	 */
+	err = do_work(ubi);
+	if (err) {
+		ubi_err(ubi, "%s: work failed with error code %d",
+			ubi->bgt_name, err);
+	}
+#endif
+
 	spin_unlock(&ubi->wl_lock);
 
 	ubi_devices[ubi_num] = ubi;
@@ -1124,7 +1129,7 @@
 			return -EBUSY;
 		}
 		/* This may only happen if there is a bug */
-		ubi_err("%s reference count %d, destroy anyway",
+		ubi_err(ubi, "%s reference count %d, destroy anyway",
 			ubi->ubi_name, ubi->ref_count);
 	}
 	ubi_devices[ubi_num] = NULL;
@@ -1132,11 +1137,14 @@
 
 	ubi_assert(ubi_num == ubi->ubi_num);
 	ubi_notify_all(ubi, UBI_VOLUME_REMOVED, NULL);
-	ubi_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
+	ubi_msg(ubi, "detaching mtd%d", ubi->mtd->index);
 #ifdef CONFIG_MTD_UBI_FASTMAP
 	/* If we don't write a new fastmap at detach time we lose all
-	 * EC updates that have been made since the last written fastmap. */
-	ubi_update_fastmap(ubi);
+	 * EC updates that have been made since the last written fastmap.
+	 * In case of fastmap debugging we omit the update to simulate an
+	 * unclean shutdown. */
+	if (!ubi_dbg_chk_fastmap(ubi))
+		ubi_update_fastmap(ubi);
 #endif
 	/*
 	 * Before freeing anything, we have to stop the background thread to
@@ -1160,7 +1168,7 @@
 	put_mtd_device(ubi->mtd);
 	vfree(ubi->peb_buf);
 	vfree(ubi->fm_buf);
-	ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
+	ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index);
 	put_device(&ubi->dev);
 	return 0;
 }
@@ -1185,9 +1193,9 @@
 		return ERR_PTR(err);
 
 	/* MTD device number is defined by the major / minor numbers */
-	major = imajor(path.dentry->d_inode);
-	minor = iminor(path.dentry->d_inode);
-	mode = path.dentry->d_inode->i_mode;
+	major = imajor(d_backing_inode(path.dentry));
+	minor = iminor(d_backing_inode(path.dentry));
+	mode = d_backing_inode(path.dentry)->i_mode;
 	path_put(&path);
 	if (major != MTD_CHAR_MAJOR || !S_ISCHR(mode))
 		return ERR_PTR(-EINVAL);
@@ -1250,28 +1258,20 @@
 	BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
 
 	if (mtd_devs > UBI_MAX_DEVICES) {
-		ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES);
+		pr_err("UBI error: too many MTD devices, maximum is %d",
+		       UBI_MAX_DEVICES);
 		return -EINVAL;
 	}
 
 	/* Create base sysfs directory and sysfs files */
-	ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
-	if (IS_ERR(ubi_class)) {
-		err = PTR_ERR(ubi_class);
-		ubi_err("cannot create UBI class");
-		goto out;
-	}
-
-	err = class_create_file(ubi_class, &ubi_version);
-	if (err) {
-		ubi_err("cannot create sysfs file");
-		goto out_class;
-	}
+	err = class_register(&ubi_class);
+	if (err < 0)
+		return err;
 
 	err = misc_register(&ubi_ctrl_cdev);
 	if (err) {
-		ubi_err("cannot register device");
-		goto out_version;
+		pr_err("UBI error: cannot register device");
+		goto out;
 	}
 
 	ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
@@ -1297,7 +1297,8 @@
 		mtd = open_mtd_device(p->name);
 		if (IS_ERR(mtd)) {
 			err = PTR_ERR(mtd);
-			ubi_err("cannot open mtd %s, error %d", p->name, err);
+			pr_err("UBI error: cannot open mtd %s, error %d",
+			       p->name, err);
 			/* See comment below re-ubi_is_module(). */
 			if (ubi_is_module())
 				goto out_detach;
@@ -1309,7 +1310,8 @@
 					 p->vid_hdr_offs, p->max_beb_per1024);
 		mutex_unlock(&ubi_devices_mutex);
 		if (err < 0) {
-			ubi_err("cannot attach mtd%d", mtd->index);
+			pr_err("UBI error: cannot attach mtd%d",
+			       mtd->index);
 			put_mtd_device(mtd);
 
 			/*
@@ -1332,7 +1334,7 @@
 
 	err = ubiblock_init();
 	if (err) {
-		ubi_err("block: cannot initialize, error %d", err);
+		pr_err("UBI error: block: cannot initialize, error %d", err);
 
 		/* See comment above re-ubi_is_module(). */
 		if (ubi_is_module())
@@ -1353,16 +1355,13 @@
 	kmem_cache_destroy(ubi_wl_entry_slab);
 out_dev_unreg:
 	misc_deregister(&ubi_ctrl_cdev);
-out_version:
-	class_remove_file(ubi_class, &ubi_version);
-out_class:
-	class_destroy(ubi_class);
 out:
 #ifdef __UBOOT__
 	/* Reset any globals that the driver depends on being zeroed */
 	mtd_devs = 0;
 #endif
-	ubi_err("cannot initialize UBI, error %d", err);
+	class_unregister(&ubi_class);
+	pr_err("UBI error: cannot initialize UBI, error %d", err);
 	return err;
 }
 late_initcall(ubi_init);
@@ -1386,8 +1385,7 @@
 	ubi_debugfs_exit();
 	kmem_cache_destroy(ubi_wl_entry_slab);
 	misc_deregister(&ubi_ctrl_cdev);
-	class_remove_file(ubi_class, &ubi_version);
-	class_destroy(ubi_class);
+	class_unregister(&ubi_class);
 #ifdef __UBOOT__
 	/* Reset any globals that the driver depends on being zeroed */
 	mtd_devs = 0;
@@ -1409,7 +1407,7 @@
 
 	result = simple_strtoul(str, &endp, 0);
 	if (str == endp || result >= INT_MAX) {
-		ubi_err("incorrect bytes count: \"%s\"\n", str);
+		pr_err("UBI error: incorrect bytes count: \"%s\"\n", str);
 		return -EINVAL;
 	}
 
@@ -1425,7 +1423,7 @@
 	case '\0':
 		break;
 	default:
-		ubi_err("incorrect bytes count: \"%s\"\n", str);
+		pr_err("UBI error: incorrect bytes count: \"%s\"\n", str);
 		return -EINVAL;
 	}
 
@@ -1467,15 +1465,15 @@
 		return -EINVAL;
 
 	if (mtd_devs == UBI_MAX_DEVICES) {
-		ubi_err("too many parameters, max. is %d\n",
-			UBI_MAX_DEVICES);
+		pr_err("UBI error: too many parameters, max. is %d\n",
+		       UBI_MAX_DEVICES);
 		return -EINVAL;
 	}
 
 	len = strnlen(val, MTD_PARAM_LEN_MAX);
 	if (len == MTD_PARAM_LEN_MAX) {
-		ubi_err("parameter \"%s\" is too long, max. is %d\n",
-			val, MTD_PARAM_LEN_MAX);
+		pr_err("UBI error: parameter \"%s\" is too long, max. is %d\n",
+		       val, MTD_PARAM_LEN_MAX);
 		return -EINVAL;
 	}
 
@@ -1494,7 +1492,7 @@
 		tokens[i] = strsep(&pbuf, ",");
 
 	if (pbuf) {
-		ubi_err("too many arguments at \"%s\"\n", val);
+		pr_err("UBI error: too many arguments at \"%s\"\n", val);
 		return -EINVAL;
 	}
 
@@ -1514,8 +1512,8 @@
 		int err = kstrtoint(token, 10, &p->max_beb_per1024);
 
 		if (err) {
-			ubi_err("bad value for max_beb_per1024 parameter: %s",
-				token);
+			pr_err("UBI error: bad value for max_beb_per1024 parameter: %s",
+			       token);
 			return -EINVAL;
 		}
 	}
@@ -1525,7 +1523,8 @@
 		int err = kstrtoint(token, 10, &p->ubi_num);
 
 		if (err) {
-			ubi_err("bad value for ubi_num parameter: %s", token);
+			pr_err("UBI error: bad value for ubi_num parameter: %s",
+			       token);
 			return -EINVAL;
 		}
 	} else
@@ -1552,6 +1551,8 @@
 #ifdef CONFIG_MTD_UBI_FASTMAP
 module_param(fm_autoconvert, bool, 0644);
 MODULE_PARM_DESC(fm_autoconvert, "Set this parameter to enable fastmap automatically on images without a fastmap.");
+module_param(fm_debug, bool, 0);
+MODULE_PARM_DESC(fm_debug, "Set this parameter to enable fastmap debugging by default. Warning, this will make fastmap slow!");
 #endif
 MODULE_VERSION(__stringify(UBI_VERSION));
 MODULE_DESCRIPTION("UBI - Unsorted Block Images");
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 6dcc4e4..c35c85b 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -33,12 +33,12 @@
 		return;
 	err = mtd_read(ubi->mtd, addr, len, &read, buf);
 	if (err && err != -EUCLEAN) {
-		ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes",
+		ubi_err(ubi, "err %d while reading %d bytes from PEB %d:%d, read %zd bytes",
 			err, len, pnum, offset, read);
 		goto out;
 	}
 
-	ubi_msg("dumping %d bytes of data from PEB %d, offset %d",
+	ubi_msg(ubi, "dumping %d bytes of data from PEB %d, offset %d",
 		len, pnum, offset);
 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
 out:
@@ -229,8 +229,8 @@
 	if (IS_ERR_OR_NULL(dfs_rootdir)) {
 		int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);
 
-		ubi_err("cannot create \"ubi\" debugfs directory, error %d\n",
-			err);
+		pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n",
+		       err);
 		return err;
 	}
 
@@ -254,7 +254,7 @@
 	struct dentry *dent = file->f_path.dentry;
 	struct ubi_device *ubi;
 	struct ubi_debug_info *d;
-	char buf[3];
+	char buf[8];
 	int val;
 
 	ubi = ubi_get_device(ubi_num);
@@ -266,12 +266,30 @@
 		val = d->chk_gen;
 	else if (dent == d->dfs_chk_io)
 		val = d->chk_io;
+	else if (dent == d->dfs_chk_fastmap)
+		val = d->chk_fastmap;
 	else if (dent == d->dfs_disable_bgt)
 		val = d->disable_bgt;
 	else if (dent == d->dfs_emulate_bitflips)
 		val = d->emulate_bitflips;
 	else if (dent == d->dfs_emulate_io_failures)
 		val = d->emulate_io_failures;
+	else if (dent == d->dfs_emulate_power_cut) {
+		snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
+		count = simple_read_from_buffer(user_buf, count, ppos,
+						buf, strlen(buf));
+		goto out;
+	} else if (dent == d->dfs_power_cut_min) {
+		snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min);
+		count = simple_read_from_buffer(user_buf, count, ppos,
+						buf, strlen(buf));
+		goto out;
+	} else if (dent == d->dfs_power_cut_max) {
+		snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max);
+		count = simple_read_from_buffer(user_buf, count, ppos,
+						buf, strlen(buf));
+		goto out;
+	}
 	else {
 		count = -EINVAL;
 		goto out;
@@ -300,7 +318,7 @@
 	struct ubi_device *ubi;
 	struct ubi_debug_info *d;
 	size_t buf_size;
-	char buf[8];
+	char buf[8] = {0};
 	int val;
 
 	ubi = ubi_get_device(ubi_num);
@@ -314,6 +332,21 @@
 		goto out;
 	}
 
+	if (dent == d->dfs_power_cut_min) {
+		if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
+			count = -EINVAL;
+		goto out;
+	} else if (dent == d->dfs_power_cut_max) {
+		if (kstrtouint(buf, 0, &d->power_cut_max) != 0)
+			count = -EINVAL;
+		goto out;
+	} else if (dent == d->dfs_emulate_power_cut) {
+		if (kstrtoint(buf, 0, &val) != 0)
+			count = -EINVAL;
+		d->emulate_power_cut = val;
+		goto out;
+	}
+
 	if (buf[0] == '1')
 		val = 1;
 	else if (buf[0] == '0')
@@ -327,6 +360,8 @@
 		d->chk_gen = val;
 	else if (dent == d->dfs_chk_io)
 		d->chk_io = val;
+	else if (dent == d->dfs_chk_fastmap)
+		d->chk_fastmap = val;
 	else if (dent == d->dfs_disable_bgt)
 		d->disable_bgt = val;
 	else if (dent == d->dfs_emulate_bitflips)
@@ -397,6 +432,13 @@
 		goto out_remove;
 	d->dfs_chk_io = dent;
 
+	fname = "chk_fastmap";
+	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+				   &dfs_fops);
+	if (IS_ERR_OR_NULL(dent))
+		goto out_remove;
+	d->dfs_chk_fastmap = dent;
+
 	fname = "tst_disable_bgt";
 	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
 				   &dfs_fops);
@@ -418,13 +460,34 @@
 		goto out_remove;
 	d->dfs_emulate_io_failures = dent;
 
+	fname = "tst_emulate_power_cut";
+	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+				   &dfs_fops);
+	if (IS_ERR_OR_NULL(dent))
+		goto out_remove;
+	d->dfs_emulate_power_cut = dent;
+
+	fname = "tst_emulate_power_cut_min";
+	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+				   &dfs_fops);
+	if (IS_ERR_OR_NULL(dent))
+		goto out_remove;
+	d->dfs_power_cut_min = dent;
+
+	fname = "tst_emulate_power_cut_max";
+	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+				   &dfs_fops);
+	if (IS_ERR_OR_NULL(dent))
+		goto out_remove;
+	d->dfs_power_cut_max = dent;
+
 	return 0;
 
 out_remove:
 	debugfs_remove_recursive(d->dfs_dir);
 out:
 	err = dent ? PTR_ERR(dent) : -ENODEV;
-	ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n",
+	ubi_err(ubi, "cannot create \"%s\" debugfs file or directory, error %d\n",
 		fname, err);
 	return err;
 }
@@ -438,6 +501,39 @@
 	if (IS_ENABLED(CONFIG_DEBUG_FS))
 		debugfs_remove_recursive(ubi->dbg.dfs_dir);
 }
+
+/**
+ * ubi_dbg_power_cut - emulate a power cut if it is time to do so
+ * @ubi: UBI device description object
+ * @caller: Flags set to indicate from where the function is being called
+ *
+ * Returns non-zero if a power cut was emulated, zero if not.
+ */
+int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
+{
+	unsigned int range;
+
+	if ((ubi->dbg.emulate_power_cut & caller) == 0)
+		return 0;
+
+	if (ubi->dbg.power_cut_counter == 0) {
+		ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min;
+
+		if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) {
+			range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min;
+			ubi->dbg.power_cut_counter += prandom_u32() % range;
+		}
+		return 0;
+	}
+
+	ubi->dbg.power_cut_counter--;
+	if (ubi->dbg.power_cut_counter)
+		return 0;
+
+	ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
+	ubi_ro_mode(ubi);
+	return 1;
+}
 #else
 int ubi_debugfs_init(void)
 {
@@ -456,4 +552,9 @@
 void ubi_debugfs_exit_dev(struct ubi_device *ubi)
 {
 }
+
+int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
+{
+	return 0;
+}
 #endif
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index bfa9dfb..d8d824e 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -117,4 +117,16 @@
 {
 	return ubi->dbg.chk_gen;
 }
+
+static inline int ubi_dbg_chk_fastmap(const struct ubi_device *ubi)
+{
+	return ubi->dbg.chk_fastmap;
+}
+
+static inline void ubi_enable_dbg_chk_fastmap(struct ubi_device *ubi)
+{
+	ubi->dbg.chk_fastmap = 1;
+}
+
+int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);
 #endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index fce0ff8..6a78f67 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -333,9 +333,9 @@
 
 	dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
 
-	down_read(&ubi->fm_sem);
+	down_read(&ubi->fm_eba_sem);
 	vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
-	up_read(&ubi->fm_sem);
+	up_read(&ubi->fm_eba_sem);
 	err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
 
 out_unlock:
@@ -415,11 +415,13 @@
 				 */
 				if (err == UBI_IO_BAD_HDR_EBADMSG ||
 				    err == UBI_IO_BAD_HDR) {
-					ubi_warn("corrupted VID header at PEB %d, LEB %d:%d",
+					ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d",
 						 pnum, vol_id, lnum);
 					err = -EBADMSG;
-				} else
+				} else {
+					err = -EINVAL;
 					ubi_ro_mode(ubi);
+				}
 			}
 			goto out_free;
 		} else if (err == UBI_IO_BITFLIPS)
@@ -434,15 +436,14 @@
 
 	err = ubi_io_read_data(ubi, buf, pnum, offset, len);
 	if (err) {
-		if (err == UBI_IO_BITFLIPS) {
+		if (err == UBI_IO_BITFLIPS)
 			scrub = 1;
-			err = 0;
-		} else if (mtd_is_eccerr(err)) {
+		else if (mtd_is_eccerr(err)) {
 			if (vol->vol_type == UBI_DYNAMIC_VOLUME)
 				goto out_unlock;
 			scrub = 1;
 			if (!check) {
-				ubi_msg("force data checking");
+				ubi_msg(ubi, "force data checking");
 				check = 1;
 				goto retry;
 			}
@@ -453,7 +454,7 @@
 	if (check) {
 		uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len);
 		if (crc1 != crc) {
-			ubi_warn("CRC error: calculated %#08x, must be %#08x",
+			ubi_warn(ubi, "CRC error: calculated %#08x, must be %#08x",
 				 crc1, crc);
 			err = -EBADMSG;
 			goto out_unlock;
@@ -473,6 +474,63 @@
 	return err;
 }
 
+#ifndef __UBOOT__
+/**
+ * ubi_eba_read_leb_sg - read data into a scatter gather list.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @sgl: UBI scatter gather list to store the read data
+ * @offset: offset from where to read
+ * @len: how many bytes to read
+ * @check: data CRC check flag
+ *
+ * This function works exactly like ubi_eba_read_leb(). But instead of
+ * storing the read data into a buffer it writes to an UBI scatter gather
+ * list.
+ */
+int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
+			struct ubi_sgl *sgl, int lnum, int offset, int len,
+			int check)
+{
+	int to_read;
+	int ret;
+	struct scatterlist *sg;
+
+	for (;;) {
+		ubi_assert(sgl->list_pos < UBI_MAX_SG_COUNT);
+		sg = &sgl->sg[sgl->list_pos];
+		if (len < sg->length - sgl->page_pos)
+			to_read = len;
+		else
+			to_read = sg->length - sgl->page_pos;
+
+		ret = ubi_eba_read_leb(ubi, vol, lnum,
+				       sg_virt(sg) + sgl->page_pos, offset,
+				       to_read, check);
+		if (ret < 0)
+			return ret;
+
+		offset += to_read;
+		len -= to_read;
+		if (!len) {
+			sgl->page_pos += to_read;
+			if (sgl->page_pos == sg->length) {
+				sgl->list_pos++;
+				sgl->page_pos = 0;
+			}
+
+			break;
+		}
+
+		sgl->list_pos++;
+		sgl->page_pos = 0;
+	}
+
+	return ret;
+}
+#endif
+
 /**
  * recover_peb - recover from write failure.
  * @ubi: UBI device description object
@@ -504,22 +562,27 @@
 	new_pnum = ubi_wl_get_peb(ubi);
 	if (new_pnum < 0) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
+		up_read(&ubi->fm_eba_sem);
 		return new_pnum;
 	}
 
-	ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum);
+	ubi_msg(ubi, "recover PEB %d, move data to PEB %d",
+		pnum, new_pnum);
 
 	err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
 	if (err && err != UBI_IO_BITFLIPS) {
 		if (err > 0)
 			err = -EIO;
+		up_read(&ubi->fm_eba_sem);
 		goto out_put;
 	}
 
 	vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
 	err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
-	if (err)
+	if (err) {
+		up_read(&ubi->fm_eba_sem);
 		goto write_error;
+	}
 
 	data_size = offset + len;
 	mutex_lock(&ubi->buf_mutex);
@@ -528,8 +591,10 @@
 	/* Read everything before the area where the write failure happened */
 	if (offset > 0) {
 		err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
-		if (err && err != UBI_IO_BITFLIPS)
+		if (err && err != UBI_IO_BITFLIPS) {
+			up_read(&ubi->fm_eba_sem);
 			goto out_unlock;
+		}
 	}
 
 	memcpy(ubi->peb_buf + offset, buf, len);
@@ -537,18 +602,18 @@
 	err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
 	if (err) {
 		mutex_unlock(&ubi->buf_mutex);
+		up_read(&ubi->fm_eba_sem);
 		goto write_error;
 	}
 
 	mutex_unlock(&ubi->buf_mutex);
 	ubi_free_vid_hdr(ubi, vid_hdr);
 
-	down_read(&ubi->fm_sem);
 	vol->eba_tbl[lnum] = new_pnum;
-	up_read(&ubi->fm_sem);
+	up_read(&ubi->fm_eba_sem);
 	ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
 
-	ubi_msg("data was successfully recovered");
+	ubi_msg(ubi, "data was successfully recovered");
 	return 0;
 
 out_unlock:
@@ -563,13 +628,13 @@
 	 * Bad luck? This physical eraseblock is bad too? Crud. Let's try to
 	 * get another one.
 	 */
-	ubi_warn("failed to write to PEB %d", new_pnum);
+	ubi_warn(ubi, "failed to write to PEB %d", new_pnum);
 	ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
 	if (++tries > UBI_IO_RETRIES) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
 		return err;
 	}
-	ubi_msg("try again");
+	ubi_msg(ubi, "try again");
 	goto retry;
 }
 
@@ -607,7 +672,7 @@
 
 		err = ubi_io_write_data(ubi, buf, pnum, offset, len);
 		if (err) {
-			ubi_warn("failed to write data to PEB %d", pnum);
+			ubi_warn(ubi, "failed to write data to PEB %d", pnum);
 			if (err == -EIO && ubi->bad_allowed)
 				err = recover_peb(ubi, pnum, vol_id, lnum, buf,
 						  offset, len);
@@ -640,6 +705,7 @@
 	if (pnum < 0) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
 		leb_write_unlock(ubi, vol_id, lnum);
+		up_read(&ubi->fm_eba_sem);
 		return pnum;
 	}
 
@@ -648,23 +714,24 @@
 
 	err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
 	if (err) {
-		ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+		ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
 			 vol_id, lnum, pnum);
+		up_read(&ubi->fm_eba_sem);
 		goto write_error;
 	}
 
 	if (len) {
 		err = ubi_io_write_data(ubi, buf, pnum, offset, len);
 		if (err) {
-			ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
+			ubi_warn(ubi, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
 				 len, offset, vol_id, lnum, pnum);
+			up_read(&ubi->fm_eba_sem);
 			goto write_error;
 		}
 	}
 
-	down_read(&ubi->fm_sem);
 	vol->eba_tbl[lnum] = pnum;
-	up_read(&ubi->fm_sem);
+	up_read(&ubi->fm_eba_sem);
 
 	leb_write_unlock(ubi, vol_id, lnum);
 	ubi_free_vid_hdr(ubi, vid_hdr);
@@ -692,7 +759,7 @@
 	}
 
 	vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-	ubi_msg("try another PEB");
+	ubi_msg(ubi, "try another PEB");
 	goto retry;
 }
 
@@ -761,6 +828,7 @@
 	if (pnum < 0) {
 		ubi_free_vid_hdr(ubi, vid_hdr);
 		leb_write_unlock(ubi, vol_id, lnum);
+		up_read(&ubi->fm_eba_sem);
 		return pnum;
 	}
 
@@ -769,22 +837,23 @@
 
 	err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
 	if (err) {
-		ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+		ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
 			 vol_id, lnum, pnum);
+		up_read(&ubi->fm_eba_sem);
 		goto write_error;
 	}
 
 	err = ubi_io_write_data(ubi, buf, pnum, 0, len);
 	if (err) {
-		ubi_warn("failed to write %d bytes of data to PEB %d",
+		ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
 			 len, pnum);
+		up_read(&ubi->fm_eba_sem);
 		goto write_error;
 	}
 
 	ubi_assert(vol->eba_tbl[lnum] < 0);
-	down_read(&ubi->fm_sem);
 	vol->eba_tbl[lnum] = pnum;
-	up_read(&ubi->fm_sem);
+	up_read(&ubi->fm_eba_sem);
 
 	leb_write_unlock(ubi, vol_id, lnum);
 	ubi_free_vid_hdr(ubi, vid_hdr);
@@ -812,7 +881,7 @@
 	}
 
 	vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-	ubi_msg("try another PEB");
+	ubi_msg(ubi, "try another PEB");
 	goto retry;
 }
 
@@ -836,7 +905,7 @@
 int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
 			      int lnum, const void *buf, int len)
 {
-	int err, pnum, tries = 0, vol_id = vol->vol_id;
+	int err, pnum, old_pnum, tries = 0, vol_id = vol->vol_id;
 	struct ubi_vid_hdr *vid_hdr;
 	uint32_t crc;
 
@@ -879,6 +948,7 @@
 	pnum = ubi_wl_get_peb(ubi);
 	if (pnum < 0) {
 		err = pnum;
+		up_read(&ubi->fm_eba_sem);
 		goto out_leb_unlock;
 	}
 
@@ -887,28 +957,30 @@
 
 	err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
 	if (err) {
-		ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+		ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
 			 vol_id, lnum, pnum);
+		up_read(&ubi->fm_eba_sem);
 		goto write_error;
 	}
 
 	err = ubi_io_write_data(ubi, buf, pnum, 0, len);
 	if (err) {
-		ubi_warn("failed to write %d bytes of data to PEB %d",
+		ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
 			 len, pnum);
+		up_read(&ubi->fm_eba_sem);
 		goto write_error;
 	}
 
-	if (vol->eba_tbl[lnum] >= 0) {
-		err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0);
+	old_pnum = vol->eba_tbl[lnum];
+	vol->eba_tbl[lnum] = pnum;
+	up_read(&ubi->fm_eba_sem);
+
+	if (old_pnum >= 0) {
+		err = ubi_wl_put_peb(ubi, vol_id, lnum, old_pnum, 0);
 		if (err)
 			goto out_leb_unlock;
 	}
 
-	down_read(&ubi->fm_sem);
-	vol->eba_tbl[lnum] = pnum;
-	up_read(&ubi->fm_sem);
-
 out_leb_unlock:
 	leb_write_unlock(ubi, vol_id, lnum);
 out_mutex:
@@ -934,7 +1006,7 @@
 	}
 
 	vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-	ubi_msg("try another PEB");
+	ubi_msg(ubi, "try another PEB");
 	goto retry;
 }
 
@@ -1057,7 +1129,7 @@
 	dbg_wl("read %d bytes of data", aldata_size);
 	err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size);
 	if (err && err != UBI_IO_BITFLIPS) {
-		ubi_warn("error %d while reading data from PEB %d",
+		ubi_warn(ubi, "error %d while reading data from PEB %d",
 			 err, from);
 		err = MOVE_SOURCE_RD_ERR;
 		goto out_unlock_buf;
@@ -1107,7 +1179,7 @@
 	err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1);
 	if (err) {
 		if (err != UBI_IO_BITFLIPS) {
-			ubi_warn("error %d while reading VID header back from PEB %d",
+			ubi_warn(ubi, "error %d while reading VID header back from PEB %d",
 				 err, to);
 			if (is_error_sane(err))
 				err = MOVE_TARGET_RD_ERR;
@@ -1134,7 +1206,7 @@
 		err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size);
 		if (err) {
 			if (err != UBI_IO_BITFLIPS) {
-				ubi_warn("error %d while reading data back from PEB %d",
+				ubi_warn(ubi, "error %d while reading data back from PEB %d",
 					 err, to);
 				if (is_error_sane(err))
 					err = MOVE_TARGET_RD_ERR;
@@ -1146,7 +1218,7 @@
 		cond_resched();
 
 		if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) {
-			ubi_warn("read data back from PEB %d and it is different",
+			ubi_warn(ubi, "read data back from PEB %d and it is different",
 				 to);
 			err = -EINVAL;
 			goto out_unlock_buf;
@@ -1154,9 +1226,9 @@
 	}
 
 	ubi_assert(vol->eba_tbl[lnum] == from);
-	down_read(&ubi->fm_sem);
+	down_read(&ubi->fm_eba_sem);
 	vol->eba_tbl[lnum] = to;
-	up_read(&ubi->fm_sem);
+	up_read(&ubi->fm_eba_sem);
 
 out_unlock_buf:
 	mutex_unlock(&ubi->buf_mutex);
@@ -1199,10 +1271,10 @@
 			return;
 	}
 
-	ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d",
+	ubi_warn(ubi, "cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d",
 		 ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
 	if (ubi->corr_peb_count)
-		ubi_warn("%d PEBs are corrupted and not used",
+		ubi_warn(ubi, "%d PEBs are corrupted and not used",
 			 ubi->corr_peb_count);
 }
 
@@ -1280,7 +1352,7 @@
 					fm_eba[i][j] == UBI_LEB_UNMAPPED)
 					continue;
 
-				ubi_err("LEB:%i:%i is PEB:%i instead of %i!",
+				ubi_err(ubi, "LEB:%i:%i is PEB:%i instead of %i!",
 					vol->vol_id, i, fm_eba[i][j],
 					scan_eba[i][j]);
 				ubi_assert(0);
@@ -1355,15 +1427,16 @@
 				 * during re-size.
 				 */
 				ubi_move_aeb_to_list(av, aeb, &ai->erase);
-			vol->eba_tbl[aeb->lnum] = aeb->pnum;
+			else
+				vol->eba_tbl[aeb->lnum] = aeb->pnum;
 		}
 	}
 
 	if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
-		ubi_err("no enough physical eraseblocks (%d, need %d)",
+		ubi_err(ubi, "no enough physical eraseblocks (%d, need %d)",
 			ubi->avail_pebs, EBA_RESERVED_PEBS);
 		if (ubi->corr_peb_count)
-			ubi_err("%d PEBs are corrupted and not used",
+			ubi_err(ubi, "%d PEBs are corrupted and not used",
 				ubi->corr_peb_count);
 		err = -ENOSPC;
 		goto out_free;
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
new file mode 100644
index 0000000..a33d406
--- /dev/null
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2012 Linutronix GmbH
+ * Copyright (c) 2014 sigma star gmbh
+ * Author: Richard Weinberger <richard@nod.at>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ */
+
+/**
+ * update_fastmap_work_fn - calls ubi_update_fastmap from a work queue
+ * @wrk: the work description object
+ */
+#ifndef __UBOOT__
+static void update_fastmap_work_fn(struct work_struct *wrk)
+#else
+void update_fastmap_work_fn(struct ubi_device *ubi)
+#endif
+{
+#ifndef __UBOOT__
+	struct ubi_device *ubi = container_of(wrk, struct ubi_device, fm_work);
+#endif
+
+	ubi_update_fastmap(ubi);
+	spin_lock(&ubi->wl_lock);
+	ubi->fm_work_scheduled = 0;
+	spin_unlock(&ubi->wl_lock);
+}
+
+/**
+ * find_anchor_wl_entry - find wear-leveling entry to used as anchor PEB.
+ * @root: the RB-tree where to look for
+ */
+static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root)
+{
+	struct rb_node *p;
+	struct ubi_wl_entry *e, *victim = NULL;
+	int max_ec = UBI_MAX_ERASECOUNTER;
+
+	ubi_rb_for_each_entry(p, e, root, u.rb) {
+		if (e->pnum < UBI_FM_MAX_START && e->ec < max_ec) {
+			victim = e;
+			max_ec = e->ec;
+		}
+	}
+
+	return victim;
+}
+
+/**
+ * return_unused_pool_pebs - returns unused PEB to the free tree.
+ * @ubi: UBI device description object
+ * @pool: fastmap pool description object
+ */
+static void return_unused_pool_pebs(struct ubi_device *ubi,
+				    struct ubi_fm_pool *pool)
+{
+	int i;
+	struct ubi_wl_entry *e;
+
+	for (i = pool->used; i < pool->size; i++) {
+		e = ubi->lookuptbl[pool->pebs[i]];
+		wl_tree_add(e, &ubi->free);
+		ubi->free_count++;
+	}
+}
+
+static int anchor_pebs_avalible(struct rb_root *root)
+{
+	struct rb_node *p;
+	struct ubi_wl_entry *e;
+
+	ubi_rb_for_each_entry(p, e, root, u.rb)
+		if (e->pnum < UBI_FM_MAX_START)
+			return 1;
+
+	return 0;
+}
+
+/**
+ * ubi_wl_get_fm_peb - find a physical erase block with a given maximal number.
+ * @ubi: UBI device description object
+ * @anchor: This PEB will be used as anchor PEB by fastmap
+ *
+ * The function returns a physical erase block with a given maximal number
+ * and removes it from the wl subsystem.
+ * Must be called with wl_lock held!
+ */
+struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor)
+{
+	struct ubi_wl_entry *e = NULL;
+
+	if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1))
+		goto out;
+
+	if (anchor)
+		e = find_anchor_wl_entry(&ubi->free);
+	else
+		e = find_mean_wl_entry(ubi, &ubi->free);
+
+	if (!e)
+		goto out;
+
+	self_check_in_wl_tree(ubi, e, &ubi->free);
+
+	/* remove it from the free list,
+	 * the wl subsystem does no longer know this erase block */
+	rb_erase(&e->u.rb, &ubi->free);
+	ubi->free_count--;
+out:
+	return e;
+}
+
+/**
+ * ubi_refill_pools - refills all fastmap PEB pools.
+ * @ubi: UBI device description object
+ */
+void ubi_refill_pools(struct ubi_device *ubi)
+{
+	struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool;
+	struct ubi_fm_pool *pool = &ubi->fm_pool;
+	struct ubi_wl_entry *e;
+	int enough;
+
+	spin_lock(&ubi->wl_lock);
+
+	return_unused_pool_pebs(ubi, wl_pool);
+	return_unused_pool_pebs(ubi, pool);
+
+	wl_pool->size = 0;
+	pool->size = 0;
+
+	for (;;) {
+		enough = 0;
+		if (pool->size < pool->max_size) {
+			if (!ubi->free.rb_node)
+				break;
+
+			e = wl_get_wle(ubi);
+			if (!e)
+				break;
+
+			pool->pebs[pool->size] = e->pnum;
+			pool->size++;
+		} else
+			enough++;
+
+		if (wl_pool->size < wl_pool->max_size) {
+			if (!ubi->free.rb_node ||
+			   (ubi->free_count - ubi->beb_rsvd_pebs < 5))
+				break;
+
+			e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+			self_check_in_wl_tree(ubi, e, &ubi->free);
+			rb_erase(&e->u.rb, &ubi->free);
+			ubi->free_count--;
+
+			wl_pool->pebs[wl_pool->size] = e->pnum;
+			wl_pool->size++;
+		} else
+			enough++;
+
+		if (enough == 2)
+			break;
+	}
+
+	wl_pool->used = 0;
+	pool->used = 0;
+
+	spin_unlock(&ubi->wl_lock);
+}
+
+/**
+ * ubi_wl_get_peb - get a physical eraseblock.
+ * @ubi: UBI device description object
+ *
+ * This function returns a physical eraseblock in case of success and a
+ * negative error code in case of failure.
+ * Returns with ubi->fm_eba_sem held in read mode!
+ */
+int ubi_wl_get_peb(struct ubi_device *ubi)
+{
+	int ret, retried = 0;
+	struct ubi_fm_pool *pool = &ubi->fm_pool;
+	struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool;
+
+again:
+	down_read(&ubi->fm_eba_sem);
+	spin_lock(&ubi->wl_lock);
+
+	/* We check here also for the WL pool because at this point we can
+	 * refill the WL pool synchronous. */
+	if (pool->used == pool->size || wl_pool->used == wl_pool->size) {
+		spin_unlock(&ubi->wl_lock);
+		up_read(&ubi->fm_eba_sem);
+		ret = ubi_update_fastmap(ubi);
+		if (ret) {
+			ubi_msg(ubi, "Unable to write a new fastmap: %i", ret);
+			down_read(&ubi->fm_eba_sem);
+			return -ENOSPC;
+		}
+		down_read(&ubi->fm_eba_sem);
+		spin_lock(&ubi->wl_lock);
+	}
+
+	if (pool->used == pool->size) {
+		spin_unlock(&ubi->wl_lock);
+		if (retried) {
+			ubi_err(ubi, "Unable to get a free PEB from user WL pool");
+			ret = -ENOSPC;
+			goto out;
+		}
+		retried = 1;
+		up_read(&ubi->fm_eba_sem);
+		goto again;
+	}
+
+	ubi_assert(pool->used < pool->size);
+	ret = pool->pebs[pool->used++];
+	prot_queue_add(ubi, ubi->lookuptbl[ret]);
+	spin_unlock(&ubi->wl_lock);
+out:
+	return ret;
+}
+
+/* get_peb_for_wl - returns a PEB to be used internally by the WL sub-system.
+ *
+ * @ubi: UBI device description object
+ */
+static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
+{
+	struct ubi_fm_pool *pool = &ubi->fm_wl_pool;
+	int pnum;
+
+	if (pool->used == pool->size) {
+#ifndef __UBOOT__
+		/* We cannot update the fastmap here because this
+		 * function is called in atomic context.
+		 * Let's fail here and refill/update it as soon as possible. */
+		if (!ubi->fm_work_scheduled) {
+			ubi->fm_work_scheduled = 1;
+			schedule_work(&ubi->fm_work);
+		}
+		return NULL;
+#else
+		/*
+		 * No work queues in U-Boot, we must do this immediately
+		 */
+		update_fastmap_work_fn(ubi);
+#endif
+	}
+
+	pnum = pool->pebs[pool->used++];
+	return ubi->lookuptbl[pnum];
+}
+
+/**
+ * ubi_ensure_anchor_pebs - schedule wear-leveling to produce an anchor PEB.
+ * @ubi: UBI device description object
+ */
+int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
+{
+	struct ubi_work *wrk;
+
+	spin_lock(&ubi->wl_lock);
+	if (ubi->wl_scheduled) {
+		spin_unlock(&ubi->wl_lock);
+		return 0;
+	}
+	ubi->wl_scheduled = 1;
+	spin_unlock(&ubi->wl_lock);
+
+	wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
+	if (!wrk) {
+		spin_lock(&ubi->wl_lock);
+		ubi->wl_scheduled = 0;
+		spin_unlock(&ubi->wl_lock);
+		return -ENOMEM;
+	}
+
+	wrk->anchor = 1;
+	wrk->func = &wear_leveling_worker;
+	schedule_ubi_work(ubi, wrk);
+	return 0;
+}
+
+/**
+ * ubi_wl_put_fm_peb - returns a PEB used in a fastmap to the wear-leveling
+ * sub-system.
+ * see: ubi_wl_put_peb()
+ *
+ * @ubi: UBI device description object
+ * @fm_e: physical eraseblock to return
+ * @lnum: the last used logical eraseblock number for the PEB
+ * @torture: if this physical eraseblock has to be tortured
+ */
+int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e,
+		      int lnum, int torture)
+{
+	struct ubi_wl_entry *e;
+	int vol_id, pnum = fm_e->pnum;
+
+	dbg_wl("PEB %d", pnum);
+
+	ubi_assert(pnum >= 0);
+	ubi_assert(pnum < ubi->peb_count);
+
+	spin_lock(&ubi->wl_lock);
+	e = ubi->lookuptbl[pnum];
+
+	/* This can happen if we recovered from a fastmap the very
+	 * first time and writing now a new one. In this case the wl system
+	 * has never seen any PEB used by the original fastmap.
+	 */
+	if (!e) {
+		e = fm_e;
+		ubi_assert(e->ec >= 0);
+		ubi->lookuptbl[pnum] = e;
+	}
+
+	spin_unlock(&ubi->wl_lock);
+
+	vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID;
+	return schedule_erase(ubi, e, vol_id, lnum, torture);
+}
+
+/**
+ * ubi_is_erase_work - checks whether a work is erase work.
+ * @wrk: The work object to be checked
+ */
+int ubi_is_erase_work(struct ubi_work *wrk)
+{
+	return wrk->func == erase_worker;
+}
+
+static void ubi_fastmap_close(struct ubi_device *ubi)
+{
+	int i;
+
+#ifndef __UBOOT__
+	flush_work(&ubi->fm_work);
+#else
+	update_fastmap_work_fn(ubi);
+#endif
+	return_unused_pool_pebs(ubi, &ubi->fm_pool);
+	return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);
+
+	if (ubi->fm) {
+		for (i = 0; i < ubi->fm->used_blocks; i++)
+			kfree(ubi->fm->e[i]);
+	}
+	kfree(ubi->fm);
+}
+
+/**
+ * may_reserve_for_fm - tests whether a PEB shall be reserved for fastmap.
+ * See find_mean_wl_entry()
+ *
+ * @ubi: UBI device description object
+ * @e: physical eraseblock to return
+ * @root: RB tree to test against.
+ */
+static struct ubi_wl_entry *may_reserve_for_fm(struct ubi_device *ubi,
+					   struct ubi_wl_entry *e,
+					   struct rb_root *root) {
+	if (e && !ubi->fm_disabled && !ubi->fm &&
+	    e->pnum < UBI_FM_MAX_START)
+		e = rb_entry(rb_next(root->rb_node),
+			     struct ubi_wl_entry, u.rb);
+
+	return e;
+}
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index a2166e4..f824ec8 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012 Linutronix GmbH
+ * Copyright (c) 2014 sigma star gmbh
  * Author: Richard Weinberger <richard@nod.at>
  *
  * SPDX-License-Identifier:	GPL-2.0+
@@ -19,6 +20,69 @@
 #include "ubi.h"
 
 /**
+ * init_seen - allocate memory for used for debugging.
+ * @ubi: UBI device description object
+ */
+static inline int *init_seen(struct ubi_device *ubi)
+{
+	int *ret;
+
+	if (!ubi_dbg_chk_fastmap(ubi))
+		return NULL;
+
+	ret = kcalloc(ubi->peb_count, sizeof(int), GFP_KERNEL);
+	if (!ret)
+		return ERR_PTR(-ENOMEM);
+
+	return ret;
+}
+
+/**
+ * free_seen - free the seen logic integer array.
+ * @seen: integer array of @ubi->peb_count size
+ */
+static inline void free_seen(int *seen)
+{
+	kfree(seen);
+}
+
+/**
+ * set_seen - mark a PEB as seen.
+ * @ubi: UBI device description object
+ * @pnum: The PEB to be makred as seen
+ * @seen: integer array of @ubi->peb_count size
+ */
+static inline void set_seen(struct ubi_device *ubi, int pnum, int *seen)
+{
+	if (!ubi_dbg_chk_fastmap(ubi) || !seen)
+		return;
+
+	seen[pnum] = 1;
+}
+
+/**
+ * self_check_seen - check whether all PEB have been seen by fastmap.
+ * @ubi: UBI device description object
+ * @seen: integer array of @ubi->peb_count size
+ */
+static int self_check_seen(struct ubi_device *ubi, int *seen)
+{
+	int pnum, ret = 0;
+
+	if (!ubi_dbg_chk_fastmap(ubi) || !seen)
+		return 0;
+
+	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+		if (!seen[pnum] && ubi->lookuptbl[pnum]) {
+			ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum);
+			ret = -EINVAL;
+		}
+	}
+
+	return ret;
+}
+
+/**
  * ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device.
  * @ubi: UBI device description object
  */
@@ -26,12 +90,13 @@
 {
 	size_t size;
 
-	size = 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))) + \
+	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);
 }
@@ -129,22 +194,25 @@
 
 		if (vol_id > av->vol_id)
 			p = &(*p)->rb_left;
-		else if (vol_id > av->vol_id)
+		else if (vol_id < av->vol_id)
 			p = &(*p)->rb_right;
+		else
+			return ERR_PTR(-EINVAL);
 	}
 
 	av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL);
 	if (!av)
 		goto out;
 
-	av->highest_lnum = av->leb_count = 0;
+	av->highest_lnum = av->leb_count = av->used_ebs = 0;
 	av->vol_id = vol_id;
-	av->used_ebs = used_ebs;
 	av->data_pad = data_pad;
 	av->last_data_size = last_eb_bytes;
 	av->compat = 0;
 	av->vol_type = vol_type;
 	av->root = RB_ROOT;
+	if (av->vol_type == UBI_STATIC_VOLUME)
+		av->used_ebs = used_ebs;
 
 	dbg_bld("found volume (ID %i)", vol_id);
 
@@ -250,7 +318,7 @@
 			list_add_tail(&victim->u.list, &ai->erase);
 
 			if (av->highest_lnum == be32_to_cpu(new_vh->lnum))
-				av->last_data_size = \
+				av->last_data_size =
 					be32_to_cpu(new_vh->data_size);
 
 			dbg_bld("vol %i: AEB %i's PEB %i is the newer",
@@ -331,7 +399,8 @@
 	if (found)
 		av = tmp_av;
 	else {
-		ubi_err("orphaned volume in fastmap pool!");
+		ubi_err(ubi, "orphaned volume in fastmap pool!");
+		kmem_cache_free(ai->aeb_slab_cache, new_aeb);
 		return UBI_BAD_FASTMAP;
 	}
 
@@ -362,6 +431,7 @@
 			aeb = rb_entry(node2, struct ubi_ainf_peb, u.rb);
 			if (aeb->pnum == pnum) {
 				rb_erase(&aeb->u.rb, &av->root);
+				av->leb_count--;
 				kmem_cache_free(ai->aeb_slab_cache, aeb);
 				return;
 			}
@@ -376,7 +446,6 @@
  * @pebs: an array of all PEB numbers in the to be scanned pool
  * @pool_size: size of the pool (number of entries in @pebs)
  * @max_sqnum: pointer to the maximal sequence number
- * @eba_orphans: list of PEBs which need to be scanned
  * @free: list of PEBs which are most likely free (and go into @ai->free)
  *
  * Returns 0 on success, if the pool is unusable UBI_BAD_FASTMAP is returned.
@@ -384,18 +453,18 @@
  */
 #ifndef __UBOOT__
 static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
-		     int *pebs, int pool_size, unsigned long long *max_sqnum,
-		     struct list_head *eba_orphans, struct list_head *freef)
+		     __be32 *pebs, int pool_size, unsigned long long *max_sqnum,
+		     struct list_head *free)
 #else
 static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
 		     __be32 *pebs, int pool_size, unsigned long long *max_sqnum,
-		     struct list_head *eba_orphans, struct list_head *freef)
+		     struct list_head *free)
 #endif
 {
 	struct ubi_vid_hdr *vh;
 	struct ubi_ec_hdr *ech;
-	struct ubi_ainf_peb *new_aeb, *tmp_aeb;
-	int i, pnum, err, found_orphan, ret = 0;
+	struct ubi_ainf_peb *new_aeb;
+	int i, pnum, err, ret = 0;
 
 	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
 	if (!ech)
@@ -420,18 +489,18 @@
 		pnum = be32_to_cpu(pebs[i]);
 
 		if (ubi_io_is_bad(ubi, pnum)) {
-			ubi_err("bad PEB in fastmap pool!");
+			ubi_err(ubi, "bad PEB in fastmap pool!");
 			ret = UBI_BAD_FASTMAP;
 			goto out;
 		}
 
 		err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
 		if (err && err != UBI_IO_BITFLIPS) {
-			ubi_err("unable to read EC header! PEB:%i err:%i",
+			ubi_err(ubi, "unable to read EC header! PEB:%i err:%i",
 				pnum, err);
 			ret = err > 0 ? UBI_BAD_FASTMAP : err;
 			goto out;
-		} else if (ret == UBI_IO_BITFLIPS)
+		} else if (err == UBI_IO_BITFLIPS)
 			scrub = 1;
 
 		/*
@@ -441,7 +510,7 @@
 		image_seq = be32_to_cpu(ech->image_seq);
 
 		if (image_seq && (image_seq != ubi->image_seq)) {
-			ubi_err("bad image seq: 0x%x, expected: 0x%x",
+			ubi_err(ubi, "bad image seq: 0x%x, expected: 0x%x",
 				be32_to_cpu(ech->image_seq), ubi->image_seq);
 			ret = UBI_BAD_FASTMAP;
 			goto out;
@@ -453,9 +522,9 @@
 			unmap_peb(ai, pnum);
 			dbg_bld("Adding PEB to free: %i", pnum);
 			if (err == UBI_IO_FF_BITFLIPS)
-				add_aeb(ai, freef, pnum, ec, 1);
+				add_aeb(ai, free, pnum, ec, 1);
 			else
-				add_aeb(ai, freef, pnum, ec, 0);
+				add_aeb(ai, free, pnum, ec, 0);
 			continue;
 		} else if (err == 0 || err == UBI_IO_BITFLIPS) {
 			dbg_bld("Found non empty PEB:%i in pool", pnum);
@@ -463,18 +532,6 @@
 			if (err == UBI_IO_BITFLIPS)
 				scrub = 1;
 
-			found_orphan = 0;
-			list_for_each_entry(tmp_aeb, eba_orphans, u.list) {
-				if (tmp_aeb->pnum == pnum) {
-					found_orphan = 1;
-					break;
-				}
-			}
-			if (found_orphan) {
-				list_del(&tmp_aeb->u.list);
-				kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
-			}
-
 			new_aeb = kmem_cache_alloc(ai->aeb_slab_cache,
 						   GFP_KERNEL);
 			if (!new_aeb) {
@@ -499,7 +556,7 @@
 			}
 		} else {
 			/* We are paranoid and fall back to scanning mode */
-			ubi_err("fastmap pool PEBs contains damaged PEBs!");
+			ubi_err(ubi, "fastmap pool PEBs contains damaged PEBs!");
 			ret = err > 0 ? UBI_BAD_FASTMAP : err;
 			goto out;
 		}
@@ -549,13 +606,12 @@
 			      struct ubi_attach_info *ai,
 			      struct ubi_fastmap_layout *fm)
 {
-	struct list_head used, eba_orphans, freef;
+	struct list_head used, free;
 	struct ubi_ainf_volume *av;
 	struct ubi_ainf_peb *aeb, *tmp_aeb, *_tmp_aeb;
-	struct ubi_ec_hdr *ech;
 	struct ubi_fm_sb *fmsb;
 	struct ubi_fm_hdr *fmhdr;
-	struct ubi_fm_scan_pool *fmpl1, *fmpl2;
+	struct ubi_fm_scan_pool *fmpl, *fmpl_wl;
 	struct ubi_fm_ec *fmec;
 	struct ubi_fm_volhdr *fmvhdr;
 	struct ubi_fm_eba *fm_eba;
@@ -565,23 +621,9 @@
 	void *fm_raw = ubi->fm_buf;
 
 	INIT_LIST_HEAD(&used);
-	INIT_LIST_HEAD(&freef);
-	INIT_LIST_HEAD(&eba_orphans);
-	INIT_LIST_HEAD(&ai->corr);
-	INIT_LIST_HEAD(&ai->free);
-	INIT_LIST_HEAD(&ai->erase);
-	INIT_LIST_HEAD(&ai->alien);
-	ai->volumes = RB_ROOT;
+	INIT_LIST_HEAD(&free);
 	ai->min_ec = UBI_MAX_ERASECOUNTER;
 
-	ai->aeb_slab_cache = kmem_cache_create("ubi_ainf_peb_slab",
-					       sizeof(struct ubi_ainf_peb),
-					       0, 0, NULL);
-	if (!ai->aeb_slab_cache) {
-		ret = -ENOMEM;
-		goto fail;
-	}
-
 	fmsb = (struct ubi_fm_sb *)(fm_raw);
 	ai->max_sqnum = fmsb->sqnum;
 	fm_pos += sizeof(struct ubi_fm_sb);
@@ -594,56 +636,57 @@
 		goto fail_bad;
 
 	if (be32_to_cpu(fmhdr->magic) != UBI_FM_HDR_MAGIC) {
-		ubi_err("bad fastmap header magic: 0x%x, expected: 0x%x",
+		ubi_err(ubi, "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);
+	fmpl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
+	fm_pos += sizeof(*fmpl);
 	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);
+	if (be32_to_cpu(fmpl->magic) != UBI_FM_POOL_MAGIC) {
+		ubi_err(ubi, "bad fastmap pool magic: 0x%x, expected: 0x%x",
+			be32_to_cpu(fmpl->magic), UBI_FM_POOL_MAGIC);
 		goto fail_bad;
 	}
 
-	fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
-	fm_pos += sizeof(*fmpl2);
+	fmpl_wl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
+	fm_pos += sizeof(*fmpl_wl);
 	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);
+	if (be32_to_cpu(fmpl_wl->magic) != UBI_FM_POOL_MAGIC) {
+		ubi_err(ubi, "bad fastmap WL pool magic: 0x%x, expected: 0x%x",
+			be32_to_cpu(fmpl_wl->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);
+	pool_size = be16_to_cpu(fmpl->size);
+	wl_pool_size = be16_to_cpu(fmpl_wl->size);
+	fm->max_pool_size = be16_to_cpu(fmpl->max_size);
+	fm->max_wl_pool_size = be16_to_cpu(fmpl_wl->max_size);
 
 	if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) {
-		ubi_err("bad pool size: %i", pool_size);
+		ubi_err(ubi, "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);
+		ubi_err(ubi, "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);
+		ubi_err(ubi, "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);
+		ubi_err(ubi, "bad maximal WL pool size: %i",
+			fm->max_wl_pool_size);
 		goto fail_bad;
 	}
 
@@ -702,8 +745,7 @@
 			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",
+			ubi_err(ubi, "bad fastmap vol header magic: 0x%x, expected: 0x%x",
 				be32_to_cpu(fmvhdr->magic), UBI_FM_VHDR_MAGIC);
 			goto fail_bad;
 		}
@@ -716,6 +758,11 @@
 
 		if (!av)
 			goto fail_bad;
+		if (PTR_ERR(av) == -EINVAL) {
+			ubi_err(ubi, "volume (ID %i) already exists",
+				fmvhdr->vol_id);
+			goto fail_bad;
+		}
 
 		ai->vols_found++;
 		if (ai->highest_vol_id < be32_to_cpu(fmvhdr->vol_id))
@@ -728,8 +775,7 @@
 			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",
+			ubi_err(ubi, "bad fastmap EBA header magic: 0x%x, expected: 0x%x",
 				be32_to_cpu(fm_eba->magic), UBI_FM_EBA_MAGIC);
 			goto fail_bad;
 		}
@@ -748,28 +794,9 @@
 				}
 			}
 
-			/* This can happen if a PEB is already in an EBA known
-			 * by this fastmap but the PEB itself is not in the used
-			 * list.
-			 * In this case the PEB can be within the fastmap pool
-			 * or while writing the fastmap it was in the protection
-			 * queue.
-			 */
 			if (!aeb) {
-				aeb = kmem_cache_alloc(ai->aeb_slab_cache,
-						       GFP_KERNEL);
-				if (!aeb) {
-					ret = -ENOMEM;
-
-					goto fail;
-				}
-
-				aeb->lnum = j;
-				aeb->pnum = be32_to_cpu(fm_eba->pnum[j]);
-				aeb->ec = -1;
-				aeb->scrub = aeb->copy_flag = aeb->sqnum = 0;
-				list_add_tail(&aeb->u.list, &eba_orphans);
-				continue;
+				ubi_err(ubi, "PEB %i is in EBA but not in used list", pnum);
+				goto fail_bad;
 			}
 
 			aeb->lnum = j;
@@ -782,61 +809,26 @@
 			dbg_bld("inserting PEB:%i (LEB %i) to vol %i",
 				aeb->pnum, aeb->lnum, av->vol_id);
 		}
-
-		ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
-		if (!ech) {
-			ret = -ENOMEM;
-			goto fail;
-		}
-
-		list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans,
-					 u.list) {
-			int err;
-
-			if (ubi_io_is_bad(ubi, tmp_aeb->pnum)) {
-				ubi_err("bad PEB in fastmap EBA orphan list");
-				ret = UBI_BAD_FASTMAP;
-				kfree(ech);
-				goto fail;
-			}
-
-			err = ubi_io_read_ec_hdr(ubi, tmp_aeb->pnum, ech, 0);
-			if (err && err != UBI_IO_BITFLIPS) {
-				ubi_err("unable to read EC header! PEB:%i " \
-					"err:%i", tmp_aeb->pnum, err);
-				ret = err > 0 ? UBI_BAD_FASTMAP : err;
-				kfree(ech);
-
-				goto fail;
-			} else if (err == UBI_IO_BITFLIPS)
-				tmp_aeb->scrub = 1;
-
-			tmp_aeb->ec = be64_to_cpu(ech->ec);
-			assign_aeb_to_av(ai, tmp_aeb, av);
-		}
-
-		kfree(ech);
 	}
 
-	ret = scan_pool(ubi, ai, fmpl1->pebs, pool_size, &max_sqnum,
-			&eba_orphans, &freef);
+	ret = scan_pool(ubi, ai, fmpl->pebs, pool_size, &max_sqnum, &free);
 	if (ret)
 		goto fail;
 
-	ret = scan_pool(ubi, ai, fmpl2->pebs, wl_pool_size, &max_sqnum,
-			&eba_orphans, &freef);
+	ret = scan_pool(ubi, ai, fmpl_wl->pebs, wl_pool_size, &max_sqnum, &free);
 	if (ret)
 		goto fail;
 
 	if (max_sqnum > ai->max_sqnum)
 		ai->max_sqnum = max_sqnum;
 
-	list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &freef, u.list)
+	list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list)
 		list_move_tail(&tmp_aeb->u.list, &ai->free);
 
-	ubi_assert(list_empty(&used));
-	ubi_assert(list_empty(&eba_orphans));
-	ubi_assert(list_empty(&freef));
+	list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list)
+		list_move_tail(&tmp_aeb->u.list, &ai->erase);
+
+	ubi_assert(list_empty(&free));
 
 	/*
 	 * If fastmap is leaking PEBs (must not happen), raise a
@@ -865,11 +857,7 @@
 		list_del(&tmp_aeb->u.list);
 		kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
 	}
-	list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) {
-		list_del(&tmp_aeb->u.list);
-		kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
-	}
-	list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &freef, u.list) {
+	list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) {
 		list_del(&tmp_aeb->u.list);
 		kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
 	}
@@ -899,7 +887,7 @@
 	__be32 crc, tmp_crc;
 	unsigned long long sqnum = 0;
 
-	mutex_lock(&ubi->fm_mutex);
+	down_write(&ubi->fm_protect);
 	memset(ubi->fm_buf, 0, ubi->fm_size);
 
 	fmsb = kmalloc(sizeof(*fmsb), GFP_KERNEL);
@@ -922,14 +910,14 @@
 		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",
+		ubi_err(ubi, "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",
+		ubi_err(ubi, "bad fastmap version: %i, expected: %i",
 			fmsb->version, UBI_FM_FMT_VERSION);
 		ret = UBI_BAD_FASTMAP;
 		goto free_fm_sb;
@@ -937,15 +925,16 @@
 
 	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);
+		ubi_err(ubi, "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);
+		ubi_err(ubi, "bad fastmap size: %zi, expected: %zi",
+			fm_size, ubi->fm_size);
 		ret = UBI_BAD_FASTMAP;
 		goto free_fm_sb;
 	}
@@ -974,7 +963,7 @@
 
 		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)",
+			ubi_err(ubi, "unable to read fastmap block# %i EC (PEB: %i)",
 				i, pnum);
 			if (ret > 0)
 				ret = UBI_BAD_FASTMAP;
@@ -991,7 +980,7 @@
 		 * 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",
+			ubi_err(ubi, "wrong image seq:%d instead of %d",
 				be32_to_cpu(ech->image_seq), ubi->image_seq);
 			ret = UBI_BAD_FASTMAP;
 			goto free_hdr;
@@ -999,15 +988,14 @@
 
 		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)",
+			ubi_err(ubi, "unable to read fastmap block# %i (PEB: %i)",
 				i, pnum);
 			goto free_hdr;
 		}
 
 		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",
+				ubi_err(ubi, "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;
@@ -1015,8 +1003,7 @@
 			}
 		} 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",
+				ubi_err(ubi, "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;
@@ -1030,7 +1017,7 @@
 		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, " \
+			ubi_err(ubi, "unable to read fastmap block# %i (PEB: %i, "
 				"err: %i)", i, pnum, ret);
 			goto free_hdr;
 		}
@@ -1044,8 +1031,9 @@
 	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);
+		ubi_err(ubi, "fastmap data CRC is invalid");
+		ubi_err(ubi, "CRC should be: 0x%x, calc: 0x%x",
+			tmp_crc, crc);
 		ret = UBI_BAD_FASTMAP;
 		goto free_hdr;
 	}
@@ -1081,17 +1069,18 @@
 	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;
-	ubi_msg("attached by fastmap");
-	ubi_msg("fastmap pool size: %d", ubi->fm_pool.max_size);
-	ubi_msg("fastmap WL pool size: %d", ubi->fm_wl_pool.max_size);
+	ubi_msg(ubi, "attached by fastmap");
+	ubi_msg(ubi, "fastmap pool size: %d", ubi->fm_pool.max_size);
+	ubi_msg(ubi, "fastmap WL pool size: %d",
+		ubi->fm_wl_pool.max_size);
 	ubi->fm_disabled = 0;
 
 	ubi_free_vid_hdr(ubi, vh);
 	kfree(ech);
 out:
-	mutex_unlock(&ubi->fm_mutex);
+	up_write(&ubi->fm_protect);
 	if (ret == UBI_BAD_FASTMAP)
-		ubi_err("Attach by fastmap failed, doing a full scan!");
+		ubi_err(ubi, "Attach by fastmap failed, doing a full scan!");
 	return ret;
 
 free_hdr:
@@ -1117,17 +1106,18 @@
 	void *fm_raw;
 	struct ubi_fm_sb *fmsb;
 	struct ubi_fm_hdr *fmh;
-	struct ubi_fm_scan_pool *fmpl1, *fmpl2;
+	struct ubi_fm_scan_pool *fmpl, *fmpl_wl;
 	struct ubi_fm_ec *fec;
 	struct ubi_fm_volhdr *fvh;
 	struct ubi_fm_eba *feba;
-	struct rb_node *node;
 	struct ubi_wl_entry *wl_e;
 	struct ubi_volume *vol;
 	struct ubi_vid_hdr *avhdr, *dvhdr;
 	struct ubi_work *ubi_wrk;
+	struct rb_node *tmp_rb;
 	int ret, i, j, free_peb_count, used_peb_count, vol_count;
 	int scrub_peb_count, erase_peb_count;
+	int *seen_pebs = NULL;
 
 	fm_raw = ubi->fm_buf;
 	memset(ubi->fm_buf, 0, ubi->fm_size);
@@ -1144,6 +1134,12 @@
 		goto out_kfree;
 	}
 
+	seen_pebs = init_seen(ubi);
+	if (IS_ERR(seen_pebs)) {
+		ret = PTR_ERR(seen_pebs);
+		goto out_kfree;
+	}
+
 	spin_lock(&ubi->volumes_lock);
 	spin_lock(&ubi->wl_lock);
 
@@ -1168,29 +1164,33 @@
 	erase_peb_count = 0;
 	vol_count = 0;
 
-	fmpl1 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
-	fm_pos += sizeof(*fmpl1);
-	fmpl1->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
-	fmpl1->size = cpu_to_be16(ubi->fm_pool.size);
-	fmpl1->max_size = cpu_to_be16(ubi->fm_pool.max_size);
+	fmpl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
+	fm_pos += sizeof(*fmpl);
+	fmpl->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
+	fmpl->size = cpu_to_be16(ubi->fm_pool.size);
+	fmpl->max_size = cpu_to_be16(ubi->fm_pool.max_size);
 
-	for (i = 0; i < ubi->fm_pool.size; i++)
-		fmpl1->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]);
+	for (i = 0; i < ubi->fm_pool.size; i++) {
+		fmpl->pebs[i] = cpu_to_be32(ubi->fm_pool.pebs[i]);
+		set_seen(ubi, ubi->fm_pool.pebs[i], seen_pebs);
+	}
 
-	fmpl2 = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
-	fm_pos += sizeof(*fmpl2);
-	fmpl2->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
-	fmpl2->size = cpu_to_be16(ubi->fm_wl_pool.size);
-	fmpl2->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size);
+	fmpl_wl = (struct ubi_fm_scan_pool *)(fm_raw + fm_pos);
+	fm_pos += sizeof(*fmpl_wl);
+	fmpl_wl->magic = cpu_to_be32(UBI_FM_POOL_MAGIC);
+	fmpl_wl->size = cpu_to_be16(ubi->fm_wl_pool.size);
+	fmpl_wl->max_size = cpu_to_be16(ubi->fm_wl_pool.max_size);
 
-	for (i = 0; i < ubi->fm_wl_pool.size; i++)
-		fmpl2->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]);
+	for (i = 0; i < ubi->fm_wl_pool.size; i++) {
+		fmpl_wl->pebs[i] = cpu_to_be32(ubi->fm_wl_pool.pebs[i]);
+		set_seen(ubi, ubi->fm_wl_pool.pebs[i], seen_pebs);
+	}
 
-	for (node = rb_first(&ubi->free); node; node = rb_next(node)) {
-		wl_e = rb_entry(node, struct ubi_wl_entry, u.rb);
+	ubi_for_each_free_peb(ubi, wl_e, tmp_rb) {
 		fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
 
 		fec->pnum = cpu_to_be32(wl_e->pnum);
+		set_seen(ubi, wl_e->pnum, seen_pebs);
 		fec->ec = cpu_to_be32(wl_e->ec);
 
 		free_peb_count++;
@@ -1199,11 +1199,23 @@
 	}
 	fmh->free_peb_count = cpu_to_be32(free_peb_count);
 
-	for (node = rb_first(&ubi->used); node; node = rb_next(node)) {
-		wl_e = rb_entry(node, struct ubi_wl_entry, u.rb);
+	ubi_for_each_used_peb(ubi, wl_e, tmp_rb) {
 		fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
 
 		fec->pnum = cpu_to_be32(wl_e->pnum);
+		set_seen(ubi, wl_e->pnum, seen_pebs);
+		fec->ec = cpu_to_be32(wl_e->ec);
+
+		used_peb_count++;
+		fm_pos += sizeof(*fec);
+		ubi_assert(fm_pos <= ubi->fm_size);
+	}
+
+	ubi_for_each_protected_peb(ubi, i, wl_e) {
+		fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
+
+		fec->pnum = cpu_to_be32(wl_e->pnum);
+		set_seen(ubi, wl_e->pnum, seen_pebs);
 		fec->ec = cpu_to_be32(wl_e->ec);
 
 		used_peb_count++;
@@ -1212,11 +1224,11 @@
 	}
 	fmh->used_peb_count = cpu_to_be32(used_peb_count);
 
-	for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) {
-		wl_e = rb_entry(node, struct ubi_wl_entry, u.rb);
+	ubi_for_each_scrub_peb(ubi, wl_e, tmp_rb) {
 		fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
 
 		fec->pnum = cpu_to_be32(wl_e->pnum);
+		set_seen(ubi, wl_e->pnum, seen_pebs);
 		fec->ec = cpu_to_be32(wl_e->ec);
 
 		scrub_peb_count++;
@@ -1234,6 +1246,7 @@
 			fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
 
 			fec->pnum = cpu_to_be32(wl_e->pnum);
+			set_seen(ubi, wl_e->pnum, seen_pebs);
 			fec->ec = cpu_to_be32(wl_e->ec);
 
 			erase_peb_count++;
@@ -1287,12 +1300,13 @@
 	dbg_bld("writing fastmap SB to PEB %i", new_fm->e[0]->pnum);
 	ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avhdr);
 	if (ret) {
-		ubi_err("unable to write vid_hdr to fastmap SB!");
+		ubi_err(ubi, "unable to write vid_hdr to fastmap SB!");
 		goto out_kfree;
 	}
 
 	for (i = 0; i < new_fm->used_blocks; i++) {
 		fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum);
+		set_seen(ubi, new_fm->e[i]->pnum, seen_pebs);
 		fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec);
 	}
 
@@ -1307,7 +1321,7 @@
 			new_fm->e[i]->pnum, be64_to_cpu(dvhdr->sqnum));
 		ret = ubi_io_write_vid_hdr(ubi, new_fm->e[i]->pnum, dvhdr);
 		if (ret) {
-			ubi_err("unable to write vid_hdr to PEB %i!",
+			ubi_err(ubi, "unable to write vid_hdr to PEB %i!",
 				new_fm->e[i]->pnum);
 			goto out_kfree;
 		}
@@ -1317,7 +1331,7 @@
 		ret = ubi_io_write(ubi, fm_raw + (i * ubi->leb_size),
 			new_fm->e[i]->pnum, ubi->leb_start, ubi->leb_size);
 		if (ret) {
-			ubi_err("unable to write fastmap to PEB %i!",
+			ubi_err(ubi, "unable to write fastmap to PEB %i!",
 				new_fm->e[i]->pnum);
 			goto out_kfree;
 		}
@@ -1326,11 +1340,13 @@
 	ubi_assert(new_fm);
 	ubi->fm = new_fm;
 
+	ret = self_check_seen(ubi, seen_pebs);
 	dbg_bld("fastmap written!");
 
 out_kfree:
 	ubi_free_vid_hdr(ubi, avhdr);
 	ubi_free_vid_hdr(ubi, dvhdr);
+	free_seen(seen_pebs);
 out:
 	return ret;
 }
@@ -1385,31 +1401,87 @@
 /**
  * invalidate_fastmap - destroys a fastmap.
  * @ubi: UBI device object
- * @fm: the fastmap to be destroyed
  *
+ * This function ensures that upon next UBI attach a full scan
+ * is issued. We need this if UBI is about to write a new fastmap
+ * but is unable to do so. In this case we have two options:
+ * a) Make sure that the current fastmap will not be usued upon
+ * attach time and contine or b) fall back to RO mode to have the
+ * current fastmap in a valid state.
  * Returns 0 on success, < 0 indicates an internal error.
  */
-static int invalidate_fastmap(struct ubi_device *ubi,
-			      struct ubi_fastmap_layout *fm)
+static int invalidate_fastmap(struct ubi_device *ubi)
 {
 	int ret;
-	struct ubi_vid_hdr *vh;
+	struct ubi_fastmap_layout *fm;
+	struct ubi_wl_entry *e;
+	struct ubi_vid_hdr *vh = NULL;
 
-	ret = erase_block(ubi, fm->e[0]->pnum);
-	if (ret < 0)
-		return ret;
+	if (!ubi->fm)
+		return 0;
+
+	ubi->fm = NULL;
+
+	ret = -ENOMEM;
+	fm = kzalloc(sizeof(*fm), GFP_KERNEL);
+	if (!fm)
+		goto out;
 
 	vh = new_fm_vhdr(ubi, UBI_FM_SB_VOLUME_ID);
 	if (!vh)
-		return -ENOMEM;
+		goto out_free_fm;
 
-	/* deleting the current fastmap SB is not enough, an old SB may exist,
-	 * so create a (corrupted) SB such that fastmap will find it and fall
-	 * back to scanning mode in any case */
+	ret = -ENOSPC;
+	e = ubi_wl_get_fm_peb(ubi, 1);
+	if (!e)
+		goto out_free_fm;
+
+	/*
+	 * Create fake fastmap such that UBI will fall back
+	 * to scanning mode.
+	 */
 	vh->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-	ret = ubi_io_write_vid_hdr(ubi, fm->e[0]->pnum, vh);
+	ret = ubi_io_write_vid_hdr(ubi, e->pnum, vh);
+	if (ret < 0) {
+		ubi_wl_put_fm_peb(ubi, e, 0, 0);
+		goto out_free_fm;
+	}
 
+	fm->used_blocks = 1;
+	fm->e[0] = e;
+
+	ubi->fm = fm;
+
+out:
+	ubi_free_vid_hdr(ubi, vh);
 	return ret;
+
+out_free_fm:
+	kfree(fm);
+	goto out;
+}
+
+/**
+ * return_fm_pebs - returns all PEBs used by a fastmap back to the
+ * WL sub-system.
+ * @ubi: UBI device object
+ * @fm: fastmap layout object
+ */
+static void return_fm_pebs(struct ubi_device *ubi,
+			   struct ubi_fastmap_layout *fm)
+{
+	int i;
+
+	if (!fm)
+		return;
+
+	for (i = 0; i < fm->used_blocks; i++) {
+		if (fm->e[i]) {
+			ubi_wl_put_fm_peb(ubi, fm->e[i], i,
+					  fm->to_be_tortured[i]);
+			fm->e[i] = NULL;
+		}
+	}
 }
 
 /**
@@ -1421,50 +1493,37 @@
  */
 int ubi_update_fastmap(struct ubi_device *ubi)
 {
-	int ret, i;
+	int ret, i, j;
 	struct ubi_fastmap_layout *new_fm, *old_fm;
 	struct ubi_wl_entry *tmp_e;
 
-	mutex_lock(&ubi->fm_mutex);
+	down_write(&ubi->fm_protect);
 
 	ubi_refill_pools(ubi);
 
 	if (ubi->ro_mode || ubi->fm_disabled) {
-		mutex_unlock(&ubi->fm_mutex);
+		up_write(&ubi->fm_protect);
 		return 0;
 	}
 
 	ret = ubi_ensure_anchor_pebs(ubi);
 	if (ret) {
-		mutex_unlock(&ubi->fm_mutex);
+		up_write(&ubi->fm_protect);
 		return ret;
 	}
 
 	new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL);
 	if (!new_fm) {
-		mutex_unlock(&ubi->fm_mutex);
+		up_write(&ubi->fm_protect);
 		return -ENOMEM;
 	}
 
 	new_fm->used_blocks = ubi->fm_size / ubi->leb_size;
-
-	for (i = 0; i < new_fm->used_blocks; i++) {
-		new_fm->e[i] = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
-		if (!new_fm->e[i]) {
-			while (i--)
-				kfree(new_fm->e[i]);
-
-			kfree(new_fm);
-			mutex_unlock(&ubi->fm_mutex);
-			return -ENOMEM;
-		}
-	}
-
 	old_fm = ubi->fm;
 	ubi->fm = NULL;
 
 	if (new_fm->used_blocks > UBI_FM_MAX_BLOCKS) {
-		ubi_err("fastmap too large");
+		ubi_err(ubi, "fastmap too large");
 		ret = -ENOSPC;
 		goto err;
 	}
@@ -1474,37 +1533,49 @@
 		tmp_e = ubi_wl_get_fm_peb(ubi, 0);
 		spin_unlock(&ubi->wl_lock);
 
-		if (!tmp_e && !old_fm) {
-			int j;
-			ubi_err("could not get any free erase block");
+		if (!tmp_e) {
+			if (old_fm && old_fm->e[i]) {
+				ret = erase_block(ubi, old_fm->e[i]->pnum);
+				if (ret < 0) {
+					ubi_err(ubi, "could not erase old fastmap PEB");
 
-			for (j = 1; j < i; j++)
-				ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0);
+					for (j = 1; j < i; j++) {
+						ubi_wl_put_fm_peb(ubi, new_fm->e[j],
+								  j, 0);
+						new_fm->e[j] = NULL;
+					}
+					goto err;
+				}
+				new_fm->e[i] = old_fm->e[i];
+				old_fm->e[i] = NULL;
+			} else {
+				ubi_err(ubi, "could not get any free erase block");
 
-			ret = -ENOSPC;
-			goto err;
-		} else if (!tmp_e && old_fm) {
-			ret = erase_block(ubi, old_fm->e[i]->pnum);
-			if (ret < 0) {
-				int j;
+				for (j = 1; j < i; j++) {
+					ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0);
+					new_fm->e[j] = NULL;
+				}
 
-				for (j = 1; j < i; j++)
-					ubi_wl_put_fm_peb(ubi, new_fm->e[j],
-							  j, 0);
-
-				ubi_err("could not erase old fastmap PEB");
+				ret = -ENOSPC;
 				goto err;
 			}
-
-			new_fm->e[i]->pnum = old_fm->e[i]->pnum;
-			new_fm->e[i]->ec = old_fm->e[i]->ec;
 		} else {
-			new_fm->e[i]->pnum = tmp_e->pnum;
-			new_fm->e[i]->ec = tmp_e->ec;
+			new_fm->e[i] = tmp_e;
 
-			if (old_fm)
+			if (old_fm && old_fm->e[i]) {
 				ubi_wl_put_fm_peb(ubi, old_fm->e[i], i,
 						  old_fm->to_be_tortured[i]);
+				old_fm->e[i] = NULL;
+			}
+		}
+	}
+
+	/* Old fastmap is larger than the new one */
+	if (old_fm && new_fm->used_blocks < old_fm->used_blocks) {
+		for (i = new_fm->used_blocks; i < old_fm->used_blocks; i++) {
+			ubi_wl_put_fm_peb(ubi, old_fm->e[i], i,
+					  old_fm->to_be_tortured[i]);
+			old_fm->e[i] = NULL;
 		}
 	}
 
@@ -1517,67 +1588,67 @@
 		if (!tmp_e) {
 			ret = erase_block(ubi, old_fm->e[0]->pnum);
 			if (ret < 0) {
-				int i;
-				ubi_err("could not erase old anchor PEB");
+				ubi_err(ubi, "could not erase old anchor PEB");
 
-				for (i = 1; i < new_fm->used_blocks; i++)
+				for (i = 1; i < new_fm->used_blocks; i++) {
 					ubi_wl_put_fm_peb(ubi, new_fm->e[i],
 							  i, 0);
+					new_fm->e[i] = NULL;
+				}
 				goto err;
 			}
-
-			new_fm->e[0]->pnum = old_fm->e[0]->pnum;
+			new_fm->e[0] = old_fm->e[0];
 			new_fm->e[0]->ec = ret;
+			old_fm->e[0] = NULL;
 		} else {
 			/* we've got a new anchor PEB, return the old one */
 			ubi_wl_put_fm_peb(ubi, old_fm->e[0], 0,
 					  old_fm->to_be_tortured[0]);
-
-			new_fm->e[0]->pnum = tmp_e->pnum;
-			new_fm->e[0]->ec = tmp_e->ec;
+			new_fm->e[0] = tmp_e;
+			old_fm->e[0] = NULL;
 		}
 	} else {
 		if (!tmp_e) {
-			int i;
-			ubi_err("could not find any anchor PEB");
+			ubi_err(ubi, "could not find any anchor PEB");
 
-			for (i = 1; i < new_fm->used_blocks; i++)
+			for (i = 1; i < new_fm->used_blocks; i++) {
 				ubi_wl_put_fm_peb(ubi, new_fm->e[i], i, 0);
+				new_fm->e[i] = NULL;
+			}
 
 			ret = -ENOSPC;
 			goto err;
 		}
-
-		new_fm->e[0]->pnum = tmp_e->pnum;
-		new_fm->e[0]->ec = tmp_e->ec;
+		new_fm->e[0] = tmp_e;
 	}
 
 	down_write(&ubi->work_sem);
-	down_write(&ubi->fm_sem);
+	down_write(&ubi->fm_eba_sem);
 	ret = ubi_write_fastmap(ubi, new_fm);
-	up_write(&ubi->fm_sem);
+	up_write(&ubi->fm_eba_sem);
 	up_write(&ubi->work_sem);
 
 	if (ret)
 		goto err;
 
 out_unlock:
-	mutex_unlock(&ubi->fm_mutex);
+	up_write(&ubi->fm_protect);
 	kfree(old_fm);
 	return ret;
 
 err:
-	kfree(new_fm);
+	ubi_warn(ubi, "Unable to write new fastmap, err=%i", ret);
 
-	ubi_warn("Unable to write new fastmap, err=%i", ret);
-
-	ret = 0;
-	if (old_fm) {
-		ret = invalidate_fastmap(ubi, old_fm);
-		if (ret < 0)
-			ubi_err("Unable to invalidiate current fastmap!");
-		else if (ret)
-			ret = 0;
+	ret = invalidate_fastmap(ubi);
+	if (ret < 0) {
+		ubi_err(ubi, "Unable to invalidiate current fastmap!");
+		ubi_ro_mode(ubi);
+	} else {
+		return_fm_pebs(ubi, old_fm);
+		return_fm_pebs(ubi, new_fm);
+		ret = 0;
 	}
+
+	kfree(new_fm);
 	goto out_unlock;
 }
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 0e2e933..d1bdec3 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -169,19 +169,20 @@
 			 * enabled. A corresponding message will be printed
 			 * later, when it is has been scrubbed.
 			 */
-			ubi_msg("fixable bit-flip detected at PEB %d", pnum);
+			ubi_msg(ubi, "fixable bit-flip detected at PEB %d",
+				pnum);
 			ubi_assert(len == read);
 			return UBI_IO_BITFLIPS;
 		}
 
 		if (retries++ < UBI_IO_RETRIES) {
-			ubi_warn("error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry",
+			ubi_warn(ubi, "error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry",
 				 err, errstr, len, pnum, offset, read);
 			yield();
 			goto retry;
 		}
 
-		ubi_err("error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes",
+		ubi_err(ubi, "error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes",
 			err, errstr, len, pnum, offset, read);
 		dump_stack();
 
@@ -238,7 +239,7 @@
 	ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0);
 
 	if (ubi->ro_mode) {
-		ubi_err("read-only mode");
+		ubi_err(ubi, "read-only mode");
 		return -EROFS;
 	}
 
@@ -265,7 +266,7 @@
 	}
 
 	if (ubi_dbg_is_write_failure(ubi)) {
-		ubi_err("cannot write %d bytes to PEB %d:%d (emulated)",
+		ubi_err(ubi, "cannot write %d bytes to PEB %d:%d (emulated)",
 			len, pnum, offset);
 		dump_stack();
 		return -EIO;
@@ -274,7 +275,7 @@
 	addr = (loff_t)pnum * ubi->peb_size + offset;
 	err = mtd_write(ubi->mtd, addr, len, &written, buf);
 	if (err) {
-		ubi_err("error %d while writing %d bytes to PEB %d:%d, written %zd bytes",
+		ubi_err(ubi, "error %d while writing %d bytes to PEB %d:%d, written %zd bytes",
 			err, len, pnum, offset, written);
 		dump_stack();
 		ubi_dump_flash(ubi, pnum, offset, len);
@@ -330,7 +331,7 @@
 	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
 
 	if (ubi->ro_mode) {
-		ubi_err("read-only mode");
+		ubi_err(ubi, "read-only mode");
 		return -EROFS;
 	}
 
@@ -347,12 +348,12 @@
 	err = mtd_erase(ubi->mtd, &ei);
 	if (err) {
 		if (retries++ < UBI_IO_RETRIES) {
-			ubi_warn("error %d while erasing PEB %d, retry",
+			ubi_warn(ubi, "error %d while erasing PEB %d, retry",
 				 err, pnum);
 			yield();
 			goto retry;
 		}
-		ubi_err("cannot erase PEB %d, error %d", pnum, err);
+		ubi_err(ubi, "cannot erase PEB %d, error %d", pnum, err);
 		dump_stack();
 		return err;
 	}
@@ -360,17 +361,18 @@
 	err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE ||
 					   ei.state == MTD_ERASE_FAILED);
 	if (err) {
-		ubi_err("interrupted PEB %d erasure", pnum);
+		ubi_err(ubi, "interrupted PEB %d erasure", pnum);
 		return -EINTR;
 	}
 
 	if (ei.state == MTD_ERASE_FAILED) {
 		if (retries++ < UBI_IO_RETRIES) {
-			ubi_warn("error while erasing PEB %d, retry", pnum);
+			ubi_warn(ubi, "error while erasing PEB %d, retry",
+				 pnum);
 			yield();
 			goto retry;
 		}
-		ubi_err("cannot erase PEB %d", pnum);
+		ubi_err(ubi, "cannot erase PEB %d", pnum);
 		dump_stack();
 		return -EIO;
 	}
@@ -380,7 +382,7 @@
 		return err;
 
 	if (ubi_dbg_is_erase_failure(ubi)) {
-		ubi_err("cannot erase PEB %d (emulated)", pnum);
+		ubi_err(ubi, "cannot erase PEB %d (emulated)", pnum);
 		return -EIO;
 	}
 
@@ -403,7 +405,7 @@
 {
 	int err, i, patt_count;
 
-	ubi_msg("run torture test for PEB %d", pnum);
+	ubi_msg(ubi, "run torture test for PEB %d", pnum);
 	patt_count = ARRAY_SIZE(patterns);
 	ubi_assert(patt_count > 0);
 
@@ -420,7 +422,7 @@
 
 		err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size);
 		if (err == 0) {
-			ubi_err("erased PEB %d, but a non-0xFF byte found",
+			ubi_err(ubi, "erased PEB %d, but a non-0xFF byte found",
 				pnum);
 			err = -EIO;
 			goto out;
@@ -440,7 +442,7 @@
 		err = ubi_check_pattern(ubi->peb_buf, patterns[i],
 					ubi->peb_size);
 		if (err == 0) {
-			ubi_err("pattern %x checking failed for PEB %d",
+			ubi_err(ubi, "pattern %x checking failed for PEB %d",
 				patterns[i], pnum);
 			err = -EIO;
 			goto out;
@@ -448,7 +450,7 @@
 	}
 
 	err = patt_count;
-	ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum);
+	ubi_msg(ubi, "PEB %d passed torture test, do not mark it as bad", pnum);
 
 out:
 	mutex_unlock(&ubi->buf_mutex);
@@ -458,7 +460,7 @@
 		 * has not passed because it happened on a freshly erased
 		 * physical eraseblock which means something is wrong with it.
 		 */
-		ubi_err("read problems on freshly erased PEB %d, must be bad",
+		ubi_err(ubi, "read problems on freshly erased PEB %d, must be bad",
 			pnum);
 		err = -EIO;
 	}
@@ -534,7 +536,7 @@
 	 * it. Supposedly the flash media or the driver is screwed up, so
 	 * return an error.
 	 */
-	ubi_err("cannot invalidate PEB %d, write returned %d", pnum, err);
+	ubi_err(ubi, "cannot invalidate PEB %d, write returned %d", pnum, err);
 	ubi_dump_flash(ubi, pnum, 0, ubi->peb_size);
 	return -EIO;
 }
@@ -566,7 +568,7 @@
 		return err;
 
 	if (ubi->ro_mode) {
-		ubi_err("read-only mode");
+		ubi_err(ubi, "read-only mode");
 		return -EROFS;
 	}
 
@@ -608,7 +610,7 @@
 
 		ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
 		if (ret < 0)
-			ubi_err("error %d while checking if PEB %d is bad",
+			ubi_err(ubi, "error %d while checking if PEB %d is bad",
 				ret, pnum);
 		else if (ret)
 			dbg_io("PEB %d is bad", pnum);
@@ -634,7 +636,7 @@
 	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
 
 	if (ubi->ro_mode) {
-		ubi_err("read-only mode");
+		ubi_err(ubi, "read-only mode");
 		return -EROFS;
 	}
 
@@ -643,7 +645,7 @@
 
 	err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
 	if (err)
-		ubi_err("cannot mark PEB %d bad, error %d", pnum, err);
+		ubi_err(ubi, "cannot mark PEB %d bad, error %d", pnum, err);
 	return err;
 }
 
@@ -666,32 +668,32 @@
 	leb_start = be32_to_cpu(ec_hdr->data_offset);
 
 	if (ec_hdr->version != UBI_VERSION) {
-		ubi_err("node with incompatible UBI version found: this UBI version is %d, image version is %d",
+		ubi_err(ubi, "node with incompatible UBI version found: this UBI version is %d, image version is %d",
 			UBI_VERSION, (int)ec_hdr->version);
 		goto bad;
 	}
 
 	if (vid_hdr_offset != ubi->vid_hdr_offset) {
-		ubi_err("bad VID header offset %d, expected %d",
+		ubi_err(ubi, "bad VID header offset %d, expected %d",
 			vid_hdr_offset, ubi->vid_hdr_offset);
 		goto bad;
 	}
 
 	if (leb_start != ubi->leb_start) {
-		ubi_err("bad data offset %d, expected %d",
+		ubi_err(ubi, "bad data offset %d, expected %d",
 			leb_start, ubi->leb_start);
 		goto bad;
 	}
 
 	if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) {
-		ubi_err("bad erase counter %lld", ec);
+		ubi_err(ubi, "bad erase counter %lld", ec);
 		goto bad;
 	}
 
 	return 0;
 
 bad:
-	ubi_err("bad EC header");
+	ubi_err(ubi, "bad EC header");
 	ubi_dump_ec_hdr(ec_hdr);
 	dump_stack();
 	return 1;
@@ -757,7 +759,7 @@
 		if (ubi_check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
 			/* The physical eraseblock is supposedly empty */
 			if (verbose)
-				ubi_warn("no EC header found at PEB %d, only 0xFF bytes",
+				ubi_warn(ubi, "no EC header found at PEB %d, only 0xFF bytes",
 					 pnum);
 			dbg_bld("no EC header found at PEB %d, only 0xFF bytes",
 				pnum);
@@ -772,7 +774,7 @@
 		 * 0xFF bytes. Report that the header is corrupted.
 		 */
 		if (verbose) {
-			ubi_warn("bad magic number at PEB %d: %08x instead of %08x",
+			ubi_warn(ubi, "bad magic number at PEB %d: %08x instead of %08x",
 				 pnum, magic, UBI_EC_HDR_MAGIC);
 			ubi_dump_ec_hdr(ec_hdr);
 		}
@@ -786,7 +788,7 @@
 
 	if (hdr_crc != crc) {
 		if (verbose) {
-			ubi_warn("bad EC header CRC at PEB %d, calculated %#08x, read %#08x",
+			ubi_warn(ubi, "bad EC header CRC at PEB %d, calculated %#08x, read %#08x",
 				 pnum, crc, hdr_crc);
 			ubi_dump_ec_hdr(ec_hdr);
 		}
@@ -802,7 +804,7 @@
 	/* And of course validate what has just been read from the media */
 	err = validate_ec_hdr(ubi, ec_hdr);
 	if (err) {
-		ubi_err("validation failed for PEB %d", pnum);
+		ubi_err(ubi, "validation failed for PEB %d", pnum);
 		return -EINVAL;
 	}
 
@@ -849,6 +851,9 @@
 	if (err)
 		return err;
 
+	if (ubi_dbg_power_cut(ubi, POWER_CUT_EC_WRITE))
+		return -EROFS;
+
 	err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
 	return err;
 }
@@ -876,40 +881,40 @@
 	int usable_leb_size = ubi->leb_size - data_pad;
 
 	if (copy_flag != 0 && copy_flag != 1) {
-		ubi_err("bad copy_flag");
+		ubi_err(ubi, "bad copy_flag");
 		goto bad;
 	}
 
 	if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 ||
 	    data_pad < 0) {
-		ubi_err("negative values");
+		ubi_err(ubi, "negative values");
 		goto bad;
 	}
 
 	if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) {
-		ubi_err("bad vol_id");
+		ubi_err(ubi, "bad vol_id");
 		goto bad;
 	}
 
 	if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) {
-		ubi_err("bad compat");
+		ubi_err(ubi, "bad compat");
 		goto bad;
 	}
 
 	if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE &&
 	    compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE &&
 	    compat != UBI_COMPAT_REJECT) {
-		ubi_err("bad compat");
+		ubi_err(ubi, "bad compat");
 		goto bad;
 	}
 
 	if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
-		ubi_err("bad vol_type");
+		ubi_err(ubi, "bad vol_type");
 		goto bad;
 	}
 
 	if (data_pad >= ubi->leb_size / 2) {
-		ubi_err("bad data_pad");
+		ubi_err(ubi, "bad data_pad");
 		goto bad;
 	}
 
@@ -921,45 +926,45 @@
 		 * mapped logical eraseblocks.
 		 */
 		if (used_ebs == 0) {
-			ubi_err("zero used_ebs");
+			ubi_err(ubi, "zero used_ebs");
 			goto bad;
 		}
 		if (data_size == 0) {
-			ubi_err("zero data_size");
+			ubi_err(ubi, "zero data_size");
 			goto bad;
 		}
 		if (lnum < used_ebs - 1) {
 			if (data_size != usable_leb_size) {
-				ubi_err("bad data_size");
+				ubi_err(ubi, "bad data_size");
 				goto bad;
 			}
 		} else if (lnum == used_ebs - 1) {
 			if (data_size == 0) {
-				ubi_err("bad data_size at last LEB");
+				ubi_err(ubi, "bad data_size at last LEB");
 				goto bad;
 			}
 		} else {
-			ubi_err("too high lnum");
+			ubi_err(ubi, "too high lnum");
 			goto bad;
 		}
 	} else {
 		if (copy_flag == 0) {
 			if (data_crc != 0) {
-				ubi_err("non-zero data CRC");
+				ubi_err(ubi, "non-zero data CRC");
 				goto bad;
 			}
 			if (data_size != 0) {
-				ubi_err("non-zero data_size");
+				ubi_err(ubi, "non-zero data_size");
 				goto bad;
 			}
 		} else {
 			if (data_size == 0) {
-				ubi_err("zero data_size of copy");
+				ubi_err(ubi, "zero data_size of copy");
 				goto bad;
 			}
 		}
 		if (used_ebs != 0) {
-			ubi_err("bad used_ebs");
+			ubi_err(ubi, "bad used_ebs");
 			goto bad;
 		}
 	}
@@ -967,7 +972,7 @@
 	return 0;
 
 bad:
-	ubi_err("bad VID header");
+	ubi_err(ubi, "bad VID header");
 	ubi_dump_vid_hdr(vid_hdr);
 	dump_stack();
 	return 1;
@@ -1012,7 +1017,7 @@
 
 		if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
 			if (verbose)
-				ubi_warn("no VID header found at PEB %d, only 0xFF bytes",
+				ubi_warn(ubi, "no VID header found at PEB %d, only 0xFF bytes",
 					 pnum);
 			dbg_bld("no VID header found at PEB %d, only 0xFF bytes",
 				pnum);
@@ -1023,7 +1028,7 @@
 		}
 
 		if (verbose) {
-			ubi_warn("bad magic number at PEB %d: %08x instead of %08x",
+			ubi_warn(ubi, "bad magic number at PEB %d: %08x instead of %08x",
 				 pnum, magic, UBI_VID_HDR_MAGIC);
 			ubi_dump_vid_hdr(vid_hdr);
 		}
@@ -1037,7 +1042,7 @@
 
 	if (hdr_crc != crc) {
 		if (verbose) {
-			ubi_warn("bad CRC at PEB %d, calculated %#08x, read %#08x",
+			ubi_warn(ubi, "bad CRC at PEB %d, calculated %#08x, read %#08x",
 				 pnum, crc, hdr_crc);
 			ubi_dump_vid_hdr(vid_hdr);
 		}
@@ -1051,7 +1056,7 @@
 
 	err = validate_vid_hdr(ubi, vid_hdr);
 	if (err) {
-		ubi_err("validation failed for PEB %d", pnum);
+		ubi_err(ubi, "validation failed for PEB %d", pnum);
 		return -EINVAL;
 	}
 
@@ -1096,6 +1101,9 @@
 	if (err)
 		return err;
 
+	if (ubi_dbg_power_cut(ubi, POWER_CUT_VID_WRITE))
+		return -EROFS;
+
 	p = (char *)vid_hdr - ubi->vid_hdr_shift;
 	err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
 			   ubi->vid_hdr_alsize);
@@ -1121,7 +1129,7 @@
 	if (!err)
 		return err;
 
-	ubi_err("self-check failed for PEB %d", pnum);
+	ubi_err(ubi, "self-check failed for PEB %d", pnum);
 	dump_stack();
 	return err > 0 ? -EINVAL : err;
 }
@@ -1146,14 +1154,14 @@
 
 	magic = be32_to_cpu(ec_hdr->magic);
 	if (magic != UBI_EC_HDR_MAGIC) {
-		ubi_err("bad magic %#08x, must be %#08x",
+		ubi_err(ubi, "bad magic %#08x, must be %#08x",
 			magic, UBI_EC_HDR_MAGIC);
 		goto fail;
 	}
 
 	err = validate_ec_hdr(ubi, ec_hdr);
 	if (err) {
-		ubi_err("self-check failed for PEB %d", pnum);
+		ubi_err(ubi, "self-check failed for PEB %d", pnum);
 		goto fail;
 	}
 
@@ -1193,8 +1201,9 @@
 	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
 	hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
 	if (hdr_crc != crc) {
-		ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
-		ubi_err("self-check failed for PEB %d", pnum);
+		ubi_err(ubi, "bad CRC, calculated %#08x, read %#08x",
+			crc, hdr_crc);
+		ubi_err(ubi, "self-check failed for PEB %d", pnum);
 		ubi_dump_ec_hdr(ec_hdr);
 		dump_stack();
 		err = -EINVAL;
@@ -1228,21 +1237,21 @@
 
 	magic = be32_to_cpu(vid_hdr->magic);
 	if (magic != UBI_VID_HDR_MAGIC) {
-		ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
+		ubi_err(ubi, "bad VID header magic %#08x at PEB %d, must be %#08x",
 			magic, pnum, UBI_VID_HDR_MAGIC);
 		goto fail;
 	}
 
 	err = validate_vid_hdr(ubi, vid_hdr);
 	if (err) {
-		ubi_err("self-check failed for PEB %d", pnum);
+		ubi_err(ubi, "self-check failed for PEB %d", pnum);
 		goto fail;
 	}
 
 	return err;
 
 fail:
-	ubi_err("self-check failed for PEB %d", pnum);
+	ubi_err(ubi, "self-check failed for PEB %d", pnum);
 	ubi_dump_vid_hdr(vid_hdr);
 	dump_stack();
 	return -EINVAL;
@@ -1280,9 +1289,9 @@
 	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
 	hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
 	if (hdr_crc != crc) {
-		ubi_err("bad VID header CRC at PEB %d, calculated %#08x, read %#08x",
+		ubi_err(ubi, "bad VID header CRC at PEB %d, calculated %#08x, read %#08x",
 			pnum, crc, hdr_crc);
-		ubi_err("self-check failed for PEB %d", pnum);
+		ubi_err(ubi, "self-check failed for PEB %d", pnum);
 		ubi_dump_vid_hdr(vid_hdr);
 		dump_stack();
 		err = -EINVAL;
@@ -1321,7 +1330,7 @@
 
 	buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
 	if (!buf1) {
-		ubi_err("cannot allocate memory to check writes");
+		ubi_err(ubi, "cannot allocate memory to check writes");
 		return 0;
 	}
 
@@ -1339,14 +1348,15 @@
 		if (c == c1)
 			continue;
 
-		ubi_err("self-check failed for PEB %d:%d, len %d",
+		ubi_err(ubi, "self-check failed for PEB %d:%d, len %d",
 			pnum, offset, len);
-		ubi_msg("data differ at position %d", i);
-		ubi_msg("hex dump of the original buffer from %d to %d",
+		ubi_msg(ubi, "data differ at position %d", i);
+		dump_len = max_t(int, 128, len - i);
+		ubi_msg(ubi, "hex dump of the original buffer from %d to %d",
 			i, i + dump_len);
 		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
 			       buf + i, dump_len, 1);
-		ubi_msg("hex dump of the read buffer from %d to %d",
+		ubi_msg(ubi, "hex dump of the read buffer from %d to %d",
 			i, i + dump_len);
 		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
 			       buf1 + i, dump_len, 1);
@@ -1386,20 +1396,20 @@
 
 	buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
 	if (!buf) {
-		ubi_err("cannot allocate memory to check for 0xFFs");
+		ubi_err(ubi, "cannot allocate memory to check for 0xFFs");
 		return 0;
 	}
 
 	err = mtd_read(ubi->mtd, addr, len, &read, buf);
 	if (err && !mtd_is_bitflip(err)) {
-		ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes",
+		ubi_err(ubi, "err %d while reading %d bytes from PEB %d:%d, read %zd bytes",
 			err, len, pnum, offset, read);
 		goto error;
 	}
 
 	err = ubi_check_pattern(buf, 0xFF, len);
 	if (err == 0) {
-		ubi_err("flash region at PEB %d:%d, length %d does not contain all 0xFF bytes",
+		ubi_err(ubi, "flash region at PEB %d:%d, length %d does not contain all 0xFF bytes",
 			pnum, offset, len);
 		goto fail;
 	}
@@ -1408,8 +1418,8 @@
 	return 0;
 
 fail:
-	ubi_err("self-check failed for PEB %d", pnum);
-	ubi_msg("hex dump of the %d-%d region", offset, offset + len);
+	ubi_err(ubi, "self-check failed for PEB %d", pnum);
+	ubi_msg(ubi, "hex dump of the %d-%d region", offset, offset + len);
 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
 	err = -EINVAL;
 error:
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index fd2bbd6..06b9314 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -132,7 +132,7 @@
 		return ERR_PTR(-EINVAL);
 
 	if (mode != UBI_READONLY && mode != UBI_READWRITE &&
-	    mode != UBI_EXCLUSIVE)
+	    mode != UBI_EXCLUSIVE && mode != UBI_METAONLY)
 		return ERR_PTR(-EINVAL);
 
 	/*
@@ -177,10 +177,17 @@
 		break;
 
 	case UBI_EXCLUSIVE:
-		if (vol->exclusive || vol->writers || vol->readers)
+		if (vol->exclusive || vol->writers || vol->readers ||
+		    vol->metaonly)
 			goto out_unlock;
 		vol->exclusive = 1;
 		break;
+
+	case UBI_METAONLY:
+		if (vol->metaonly || vol->exclusive)
+			goto out_unlock;
+		vol->metaonly = 1;
+		break;
 	}
 	get_device(&vol->dev);
 	vol->ref_count += 1;
@@ -199,7 +206,7 @@
 			return ERR_PTR(err);
 		}
 		if (err == 1) {
-			ubi_warn("volume %d on UBI device %d is corrupted",
+			ubi_warn(ubi, "volume %d on UBI device %d is corrupted",
 				 vol_id, ubi->ubi_num);
 			vol->corrupted = 1;
 		}
@@ -216,7 +223,7 @@
 	kfree(desc);
 out_put_ubi:
 	ubi_put_device(ubi);
-	ubi_err("cannot open device %d, volume %d, error %d",
+	ubi_err(ubi, "cannot open device %d, volume %d, error %d",
 		ubi_num, vol_id, err);
 	return ERR_PTR(err);
 }
@@ -303,7 +310,7 @@
 	if (error)
 		return ERR_PTR(error);
 
-	inode = path.dentry->d_inode;
+	inode = d_backing_inode(path.dentry);
 	mod = inode->i_mode;
 	ubi_num = ubi_major2num(imajor(inode));
 	vol_id = iminor(inode) - 1;
@@ -340,6 +347,10 @@
 		break;
 	case UBI_EXCLUSIVE:
 		vol->exclusive = 0;
+		break;
+	case UBI_METAONLY:
+		vol->metaonly = 0;
+		break;
 	}
 	vol->ref_count -= 1;
 	spin_unlock(&ubi->volumes_lock);
@@ -352,6 +363,43 @@
 EXPORT_SYMBOL_GPL(ubi_close_volume);
 
 /**
+ * leb_read_sanity_check - does sanity checks on read requests.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ *
+ * This function is used by ubi_leb_read() and ubi_leb_read_sg()
+ * to perform sanity checks.
+ */
+static int leb_read_sanity_check(struct ubi_volume_desc *desc, int lnum,
+				 int offset, int len)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int vol_id = vol->vol_id;
+
+	if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
+	    lnum >= vol->used_ebs || offset < 0 || len < 0 ||
+	    offset + len > vol->usable_leb_size)
+		return -EINVAL;
+
+	if (vol->vol_type == UBI_STATIC_VOLUME) {
+		if (vol->used_ebs == 0)
+			/* Empty static UBI volume */
+			return 0;
+		if (lnum == vol->used_ebs - 1 &&
+		    offset + len > vol->last_eb_bytes)
+			return -EINVAL;
+	}
+
+	if (vol->upd_marker)
+		return -EBADF;
+
+	return 0;
+}
+
+/**
  * ubi_leb_read - read data.
  * @desc: volume descriptor
  * @lnum: logical eraseblock number to read from
@@ -387,28 +435,16 @@
 
 	dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
 
-	if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
-	    lnum >= vol->used_ebs || offset < 0 || len < 0 ||
-	    offset + len > vol->usable_leb_size)
-		return -EINVAL;
+	err = leb_read_sanity_check(desc, lnum, offset, len);
+	if (err < 0)
+		return err;
 
-	if (vol->vol_type == UBI_STATIC_VOLUME) {
-		if (vol->used_ebs == 0)
-			/* Empty static UBI volume */
-			return 0;
-		if (lnum == vol->used_ebs - 1 &&
-		    offset + len > vol->last_eb_bytes)
-			return -EINVAL;
-	}
-
-	if (vol->upd_marker)
-		return -EBADF;
 	if (len == 0)
 		return 0;
 
 	err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
 	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
-		ubi_warn("mark volume %d as corrupted", vol_id);
+		ubi_warn(ubi, "mark volume %d as corrupted", vol_id);
 		vol->corrupted = 1;
 	}
 
@@ -416,6 +452,47 @@
 }
 EXPORT_SYMBOL_GPL(ubi_leb_read);
 
+#ifndef __UBOOT__
+/**
+ * ubi_leb_read_sg - read data into a scatter gather list.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @buf: buffer where to store the read data
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ * @check: whether UBI has to check the read data's CRC or not.
+ *
+ * This function works exactly like ubi_leb_read_sg(). But instead of
+ * storing the read data into a buffer it writes to an UBI scatter gather
+ * list.
+ */
+int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
+		    int offset, int len, int check)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int err, vol_id = vol->vol_id;
+
+	dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
+
+	err = leb_read_sanity_check(desc, lnum, offset, len);
+	if (err < 0)
+		return err;
+
+	if (len == 0)
+		return 0;
+
+	err = ubi_eba_read_leb_sg(ubi, vol, sgl, lnum, offset, len, check);
+	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
+		ubi_warn(ubi, "mark volume %d as corrupted", vol_id);
+		vol->corrupted = 1;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ubi_leb_read_sg);
+#endif
+
 /**
  * ubi_leb_write - write data.
  * @desc: volume descriptor
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index 49530b7..504865b 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -63,6 +63,8 @@
 	for (i = 0; i < vol->used_ebs; i++) {
 		int size;
 
+		cond_resched();
+
 		if (i == vol->used_ebs - 1)
 			size = vol->last_eb_bytes;
 		else
@@ -100,7 +102,7 @@
 	ubi->avail_pebs -= need;
 	ubi->rsvd_pebs += need;
 	ubi->beb_rsvd_pebs += need;
-	ubi_msg("reserved more %d PEBs for bad PEB handling", need);
+	ubi_msg(ubi, "reserved more %d PEBs for bad PEB handling", need);
 }
 
 /**
@@ -117,7 +119,7 @@
 	ubi->beb_rsvd_level = ubi->bad_peb_limit - ubi->bad_peb_count;
 	if (ubi->beb_rsvd_level < 0) {
 		ubi->beb_rsvd_level = 0;
-		ubi_warn("number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)",
+		ubi_warn(ubi, "number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)",
 			 ubi->bad_peb_count, ubi->bad_peb_limit);
 	}
 }
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index 2809805..83345cd 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -395,8 +395,6 @@
 #define UBI_FM_MIN_POOL_SIZE	8
 #define UBI_FM_MAX_POOL_SIZE	256
 
-#define UBI_FM_WL_POOL_SIZE	25
-
 /**
  * struct ubi_fm_sb - UBI fastmap super block
  * @magic: fastmap super block magic number (%UBI_FM_SB_MAGIC)
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 754b337..540f721 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -43,17 +43,18 @@
 
 /* Normal UBI messages */
 #ifdef CONFIG_UBI_SILENCE_MSG
-#define ubi_msg(fmt, ...)
+#define ubi_msg(ubi, fmt, ...)
 #else
-#define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__)
+#define ubi_msg(ubi, fmt, ...) printk(UBI_NAME_STR "%d: " fmt "\n", \
+					 ubi->ubi_num, ##__VA_ARGS__)
 #endif
 
 /* UBI warning messages */
-#define ubi_warn(fmt, ...) pr_warn("UBI warning: %s: " fmt "\n",  \
-				   __func__, ##__VA_ARGS__)
+#define ubi_warn(ubi, fmt, ...) pr_warn(UBI_NAME_STR "%d warning: %s: " fmt "\n", \
+					ubi->ubi_num, __func__, ##__VA_ARGS__)
 /* UBI error messages */
-#define ubi_err(fmt, ...) pr_err("UBI error: %s: " fmt "\n",      \
-				 __func__, ##__VA_ARGS__)
+#define ubi_err(ubi, fmt, ...) pr_err(UBI_NAME_STR "%d error: %s: " fmt "\n", \
+				      ubi->ubi_num, __func__, ##__VA_ARGS__)
 
 /* Background thread name pattern */
 #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
@@ -147,6 +148,17 @@
 	UBI_BAD_FASTMAP,
 };
 
+/*
+ * Flags for emulate_power_cut in ubi_debug_info
+ *
+ * POWER_CUT_EC_WRITE: Emulate a power cut when writing an EC header
+ * POWER_CUT_VID_WRITE: Emulate a power cut when writing a VID header
+ */
+enum {
+	POWER_CUT_EC_WRITE = 0x01,
+	POWER_CUT_VID_WRITE = 0x02,
+};
+
 /**
  * struct ubi_wl_entry - wear-leveling entry.
  * @u.rb: link in the corresponding (free/used) RB-tree
@@ -257,6 +269,7 @@
  * @readers: number of users holding this volume in read-only mode
  * @writers: number of users holding this volume in read-write mode
  * @exclusive: whether somebody holds this volume in exclusive mode
+ * @metaonly: whether somebody is altering only meta data of this volume
  *
  * @reserved_pebs: how many physical eraseblocks are reserved for this volume
  * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
@@ -305,6 +318,7 @@
 	int readers;
 	int writers;
 	int exclusive;
+	int metaonly;
 
 	int reserved_pebs;
 	int vol_type;
@@ -339,7 +353,8 @@
 /**
  * struct ubi_volume_desc - UBI volume descriptor returned when it is opened.
  * @vol: reference to the corresponding volume description object
- * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE)
+ * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, %UBI_EXCLUSIVE
+ * or %UBI_METAONLY)
  */
 struct ubi_volume_desc {
 	struct ubi_volume *vol;
@@ -353,30 +368,48 @@
  *
  * @chk_gen: if UBI general extra checks are enabled
  * @chk_io: if UBI I/O extra checks are enabled
+ * @chk_fastmap: if UBI fastmap extra checks are enabled
  * @disable_bgt: disable the background task for testing purposes
  * @emulate_bitflips: emulate bit-flips for testing purposes
  * @emulate_io_failures: emulate write/erase failures for testing purposes
+ * @emulate_power_cut: emulate power cut for testing purposes
+ * @power_cut_counter: count down for writes left until emulated power cut
+ * @power_cut_min: minimum number of writes before emulating a power cut
+ * @power_cut_max: maximum number of writes until emulating a power cut
  * @dfs_dir_name: name of debugfs directory containing files of this UBI device
  * @dfs_dir: direntry object of the UBI device debugfs directory
  * @dfs_chk_gen: debugfs knob to enable UBI general extra checks
  * @dfs_chk_io: debugfs knob to enable UBI I/O extra checks
+ * @dfs_chk_fastmap: debugfs knob to enable UBI fastmap extra checks
  * @dfs_disable_bgt: debugfs knob to disable the background task
  * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips
  * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures
+ * @dfs_emulate_power_cut: debugfs knob to emulate power cuts
+ * @dfs_power_cut_min: debugfs knob for minimum writes before power cut
+ * @dfs_power_cut_max: debugfs knob for maximum writes until power cut
  */
 struct ubi_debug_info {
 	unsigned int chk_gen:1;
 	unsigned int chk_io:1;
+	unsigned int chk_fastmap:1;
 	unsigned int disable_bgt:1;
 	unsigned int emulate_bitflips:1;
 	unsigned int emulate_io_failures:1;
+	unsigned int emulate_power_cut:2;
+	unsigned int power_cut_counter;
+	unsigned int power_cut_min;
+	unsigned int power_cut_max;
 	char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
 	struct dentry *dfs_dir;
 	struct dentry *dfs_chk_gen;
 	struct dentry *dfs_chk_io;
+	struct dentry *dfs_chk_fastmap;
 	struct dentry *dfs_disable_bgt;
 	struct dentry *dfs_emulate_bitflips;
 	struct dentry *dfs_emulate_io_failures;
+	struct dentry *dfs_emulate_power_cut;
+	struct dentry *dfs_power_cut_min;
+	struct dentry *dfs_power_cut_max;
 };
 
 /**
@@ -390,7 +423,8 @@
  * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
  *                @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
  *                @vol->readers, @vol->writers, @vol->exclusive,
- *                @vol->ref_count, @vol->mapping and @vol->eba_tbl.
+ *                @vol->metaonly, @vol->ref_count, @vol->mapping and
+ *                @vol->eba_tbl.
  * @ref_count: count of references on the UBI device
  * @image_seq: image sequence number recorded on EC headers
  *
@@ -422,11 +456,13 @@
  * @fm_pool: in-memory data structure of the fastmap pool
  * @fm_wl_pool: in-memory data structure of the fastmap pool used by the WL
  *		sub-system
- * @fm_mutex: serializes ubi_update_fastmap() and protects @fm_buf
+ * @fm_protect: serializes ubi_update_fastmap(), protects @fm_buf and makes sure
+ * that critical sections cannot be interrupted by ubi_update_fastmap()
  * @fm_buf: vmalloc()'d buffer which holds the raw fastmap
  * @fm_size: fastmap size in bytes
- * @fm_sem: allows ubi_update_fastmap() to block EBA table changes
+ * @fm_eba_sem: allows ubi_update_fastmap() to block EBA table changes
  * @fm_work: fastmap work queue
+ * @fm_work_scheduled: non-zero if fastmap work was scheduled
  *
  * @used: RB-tree of used physical eraseblocks
  * @erroneous: RB-tree of erroneous used physical eraseblocks
@@ -438,9 +474,11 @@
  * @pq_head: protection queue head
  * @wl_lock: protects the @used, @free, @pq, @pq_head, @lookuptbl, @move_from,
  *	     @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
- *	     @erroneous, and @erroneous_peb_count fields
+ *	     @erroneous, @erroneous_peb_count, @fm_work_scheduled, @fm_pool,
+ *	     and @fm_wl_pool fields
  * @move_mutex: serializes eraseblock moves
- * @work_sem: synchronizes the WL worker with use tasks
+ * @work_sem: used to wait for all the scheduled works to finish and prevent
+ * new works from being submitted
  * @wl_scheduled: non-zero if the wear-leveling was scheduled
  * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any
  *             physical eraseblock
@@ -474,7 +512,7 @@
  * @vid_hdr_offset: starting offset of the volume identifier header (might be
  *                  unaligned)
  * @vid_hdr_aloffset: starting offset of the VID header aligned to
- * @hdrs_min_io_size
+ *                    @hdrs_min_io_size
  * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
  * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
  *               not
@@ -527,13 +565,14 @@
 	struct ubi_fastmap_layout *fm;
 	struct ubi_fm_pool fm_pool;
 	struct ubi_fm_pool fm_wl_pool;
-	struct rw_semaphore fm_sem;
-	struct mutex fm_mutex;
+	struct rw_semaphore fm_eba_sem;
+	struct rw_semaphore fm_protect;
 	void *fm_buf;
 	size_t fm_size;
 #ifndef __UBOOT__
 	struct work_struct fm_work;
 #endif
+	int fm_work_scheduled;
 
 	/* Wear-leveling sub-system's stuff */
 	struct rb_root used;
@@ -716,14 +755,15 @@
  * @torture: if the physical eraseblock has to be tortured
  * @anchor: produce a anchor PEB to by used by fastmap
  *
- * The @func pointer points to the worker function. If the @cancel argument is
- * not zero, the worker has to free the resources and exit immediately. The
- * worker has to return zero in case of success and a negative error code in
+ * The @func pointer points to the worker function. If the @shutdown argument is
+ * not zero, the worker has to free the resources and exit immediately as the
+ * WL sub-system is shutting down.
+ * The worker has to return zero in case of success and a negative error code in
  * case of failure.
  */
 struct ubi_work {
 	struct list_head list;
-	int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
+	int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int shutdown);
 	/* The below fields are only relevant to erasure works */
 	struct ubi_wl_entry *e;
 	int vol_id;
@@ -738,7 +778,7 @@
 extern const struct file_operations ubi_ctrl_cdev_operations;
 extern const struct file_operations ubi_cdev_operations;
 extern const struct file_operations ubi_vol_cdev_operations;
-extern struct class *ubi_class;
+extern struct class ubi_class;
 extern struct mutex ubi_devices_mutex;
 extern struct blocking_notifier_head ubi_notifiers;
 
@@ -807,6 +847,9 @@
 		      int lnum);
 int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 		     void *buf, int offset, int len, int check);
+int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
+			struct ubi_sgl *sgl, int lnum, int offset, int len,
+			int check);
 int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 		      const void *buf, int offset, int len);
 int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
@@ -877,10 +920,14 @@
 		      int pnum, const struct ubi_vid_hdr *vid_hdr);
 
 /* fastmap.c */
+#ifdef CONFIG_MTD_UBI_FASTMAP
 size_t ubi_calc_fm_size(struct ubi_device *ubi);
 int ubi_update_fastmap(struct ubi_device *ubi);
 int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
 		     int fm_anchor);
+#else
+static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
+#endif
 
 /* block.c */
 #ifdef CONFIG_MTD_UBI_BLOCK
@@ -901,6 +948,42 @@
 }
 #endif
 
+/*
+ * ubi_for_each_free_peb - walk the UBI free RB tree.
+ * @ubi: UBI device description object
+ * @e: a pointer to a ubi_wl_entry to use as cursor
+ * @pos: a pointer to RB-tree entry type to use as a loop counter
+ */
+#define ubi_for_each_free_peb(ubi, e, tmp_rb)	\
+	ubi_rb_for_each_entry((tmp_rb), (e), &(ubi)->free, u.rb)
+
+/*
+ * ubi_for_each_used_peb - walk the UBI used RB tree.
+ * @ubi: UBI device description object
+ * @e: a pointer to a ubi_wl_entry to use as cursor
+ * @pos: a pointer to RB-tree entry type to use as a loop counter
+ */
+#define ubi_for_each_used_peb(ubi, e, tmp_rb)	\
+	ubi_rb_for_each_entry((tmp_rb), (e), &(ubi)->used, u.rb)
+
+/*
+ * ubi_for_each_scub_peb - walk the UBI scub RB tree.
+ * @ubi: UBI device description object
+ * @e: a pointer to a ubi_wl_entry to use as cursor
+ * @pos: a pointer to RB-tree entry type to use as a loop counter
+ */
+#define ubi_for_each_scrub_peb(ubi, e, tmp_rb)	\
+	ubi_rb_for_each_entry((tmp_rb), (e), &(ubi)->scrub, u.rb)
+
+/*
+ * ubi_for_each_protected_peb - walk the UBI protection queue.
+ * @ubi: UBI device description object
+ * @i: a integer used as counter
+ * @e: a pointer to a ubi_wl_entry to use as cursor
+ */
+#define ubi_for_each_protected_peb(ubi, i, e)	\
+	for ((i) = 0; (i) < UBI_PROT_QUEUE_LEN; (i)++)	\
+		list_for_each_entry((e), &(ubi->pq[(i)]), u.list)
 
 /*
  * ubi_rb_for_each_entry - walk an RB-tree.
@@ -1004,7 +1087,7 @@
 {
 	if (!ubi->ro_mode) {
 		ubi->ro_mode = 1;
-		ubi_warn("switch to read-only mode");
+		ubi_warn(ubi, "switch to read-only mode");
 		dump_stack();
 	}
 }
@@ -1035,4 +1118,7 @@
 		return idx;
 }
 
+#ifdef __UBOOT__
+int do_work(struct ubi_device *ubi);
+#endif
 #endif /* !__UBI_UBI_H__ */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index c52c9ce..e0caf8e 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -127,6 +127,10 @@
 	ubi_assert(!vol->updating && !vol->changing_leb);
 	vol->updating = 1;
 
+	vol->upd_buf = vmalloc(ubi->leb_size);
+	if (!vol->upd_buf)
+		return -ENOMEM;
+
 	err = set_update_marker(ubi, vol);
 	if (err)
 		return err;
@@ -146,14 +150,12 @@
 		err = clear_update_marker(ubi, vol, 0);
 		if (err)
 			return err;
+
+		vfree(vol->upd_buf);
 		vol->updating = 0;
 		return 0;
 	}
 
-	vol->upd_buf = vmalloc(ubi->leb_size);
-	if (!vol->upd_buf)
-		return -ENOMEM;
-
 	vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1,
 			       vol->usable_leb_size);
 	vol->upd_bytes = bytes;
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index f4392f5..f8ab08f 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -114,6 +114,19 @@
 	ubi_put_device(ubi);
 	return ret;
 }
+
+static struct attribute *volume_dev_attrs[] = {
+	&attr_vol_reserved_ebs.attr,
+	&attr_vol_type.attr,
+	&attr_vol_name.attr,
+	&attr_vol_corrupted.attr,
+	&attr_vol_alignment.attr,
+	&attr_vol_usable_eb_size.attr,
+	&attr_vol_data_bytes.attr,
+	&attr_vol_upd_marker.attr,
+	NULL
+};
+ATTRIBUTE_GROUPS(volume_dev);
 #endif
 
 /* Release method for volume devices */
@@ -125,66 +138,6 @@
 	kfree(vol);
 }
 
-#ifndef __UBOOT__
-/**
- * volume_sysfs_init - initialize sysfs for new volume.
- * @ubi: UBI device description object
- * @vol: volume description object
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- *
- * Note, this function does not free allocated resources in case of failure -
- * the caller does it. This is because this would cause release() here and the
- * caller would oops.
- */
-static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
-{
-	int err;
-
-	err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
-	if (err)
-		return err;
-	err = device_create_file(&vol->dev, &attr_vol_type);
-	if (err)
-		return err;
-	err = device_create_file(&vol->dev, &attr_vol_name);
-	if (err)
-		return err;
-	err = device_create_file(&vol->dev, &attr_vol_corrupted);
-	if (err)
-		return err;
-	err = device_create_file(&vol->dev, &attr_vol_alignment);
-	if (err)
-		return err;
-	err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
-	if (err)
-		return err;
-	err = device_create_file(&vol->dev, &attr_vol_data_bytes);
-	if (err)
-		return err;
-	err = device_create_file(&vol->dev, &attr_vol_upd_marker);
-	return err;
-}
-
-/**
- * volume_sysfs_close - close sysfs for a volume.
- * @vol: volume description object
- */
-static void volume_sysfs_close(struct ubi_volume *vol)
-{
-	device_remove_file(&vol->dev, &attr_vol_upd_marker);
-	device_remove_file(&vol->dev, &attr_vol_data_bytes);
-	device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
-	device_remove_file(&vol->dev, &attr_vol_alignment);
-	device_remove_file(&vol->dev, &attr_vol_corrupted);
-	device_remove_file(&vol->dev, &attr_vol_name);
-	device_remove_file(&vol->dev, &attr_vol_type);
-	device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
-	device_unregister(&vol->dev);
-}
-#endif
-
 /**
  * ubi_create_volume - create volume.
  * @ubi: UBI device description object
@@ -221,7 +174,7 @@
 			}
 
 		if (vol_id == UBI_VOL_NUM_AUTO) {
-			ubi_err("out of volume IDs");
+			ubi_err(ubi, "out of volume IDs");
 			err = -ENFILE;
 			goto out_unlock;
 		}
@@ -235,7 +188,7 @@
 	/* Ensure that this volume does not exist */
 	err = -EEXIST;
 	if (ubi->volumes[vol_id]) {
-		ubi_err("volume %d already exists", vol_id);
+		ubi_err(ubi, "volume %d already exists", vol_id);
 		goto out_unlock;
 	}
 
@@ -244,20 +197,22 @@
 		if (ubi->volumes[i] &&
 		    ubi->volumes[i]->name_len == req->name_len &&
 		    !strcmp(ubi->volumes[i]->name, req->name)) {
-			ubi_err("volume \"%s\" exists (ID %d)", req->name, i);
+			ubi_err(ubi, "volume \"%s\" exists (ID %d)",
+				req->name, i);
 			goto out_unlock;
 		}
 
 	/* Calculate how many eraseblocks are requested */
 	vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
-	vol->reserved_pebs += div_u64(req->bytes + vol->usable_leb_size - 1,
-				      vol->usable_leb_size);
+	vol->reserved_pebs = div_u64(req->bytes + vol->usable_leb_size - 1,
+				     vol->usable_leb_size);
 
 	/* Reserve physical eraseblocks */
 	if (vol->reserved_pebs > ubi->avail_pebs) {
-		ubi_err("not enough PEBs, only %d available", ubi->avail_pebs);
+		ubi_err(ubi, "not enough PEBs, only %d available",
+			ubi->avail_pebs);
 		if (ubi->corr_peb_count)
-			ubi_err("%d PEBs are corrupted and not used",
+			ubi_err(ubi, "%d PEBs are corrupted and not used",
 				ubi->corr_peb_count);
 		err = -ENOSPC;
 		goto out_unlock;
@@ -312,26 +267,25 @@
 	dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);
 	err = cdev_add(&vol->cdev, dev, 1);
 	if (err) {
-		ubi_err("cannot add character device");
+		ubi_err(ubi, "cannot add character device");
 		goto out_mapping;
 	}
 
 	vol->dev.release = vol_release;
 	vol->dev.parent = &ubi->dev;
 	vol->dev.devt = dev;
-	vol->dev.class = ubi_class;
+#ifndef __UBOOT__
+	vol->dev.class = &ubi_class;
+	vol->dev.groups = volume_dev_groups;
+#endif
 
 	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
 	err = device_register(&vol->dev);
 	if (err) {
-		ubi_err("cannot register device");
+		ubi_err(ubi, "cannot register device");
 		goto out_cdev;
 	}
 
-	err = volume_sysfs_init(ubi, vol);
-	if (err)
-		goto out_sysfs;
-
 	/* Fill volume table record */
 	memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
 	vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
@@ -368,7 +322,7 @@
 	 */
 	do_free = 0;
 	get_device(&vol->dev);
-	volume_sysfs_close(vol);
+	device_unregister(&vol->dev);
 out_cdev:
 	cdev_del(&vol->cdev);
 out_mapping:
@@ -384,7 +338,7 @@
 		kfree(vol);
 	else
 		put_device(&vol->dev);
-	ubi_err("cannot create volume %d, error %d", vol_id, err);
+	ubi_err(ubi, "cannot create volume %d, error %d", vol_id, err);
 	return err;
 }
 
@@ -436,7 +390,7 @@
 	}
 
 	cdev_del(&vol->cdev);
-	volume_sysfs_close(vol);
+	device_unregister(&vol->dev);
 
 	spin_lock(&ubi->volumes_lock);
 	ubi->rsvd_pebs -= reserved_pebs;
@@ -452,7 +406,7 @@
 	return err;
 
 out_err:
-	ubi_err("cannot remove volume %d, error %d", vol_id, err);
+	ubi_err(ubi, "cannot remove volume %d, error %d", vol_id, err);
 	spin_lock(&ubi->volumes_lock);
 	ubi->volumes[vol_id] = vol;
 out_unlock:
@@ -485,7 +439,7 @@
 
 	if (vol->vol_type == UBI_STATIC_VOLUME &&
 	    reserved_pebs < vol->used_ebs) {
-		ubi_err("too small size %d, %d LEBs contain data",
+		ubi_err(ubi, "too small size %d, %d LEBs contain data",
 			reserved_pebs, vol->used_ebs);
 		return -EINVAL;
 	}
@@ -514,10 +468,10 @@
 	if (pebs > 0) {
 		spin_lock(&ubi->volumes_lock);
 		if (pebs > ubi->avail_pebs) {
-			ubi_err("not enough PEBs: requested %d, available %d",
+			ubi_err(ubi, "not enough PEBs: requested %d, available %d",
 				pebs, ubi->avail_pebs);
 			if (ubi->corr_peb_count)
-				ubi_err("%d PEBs are corrupted and not used",
+				ubi_err(ubi, "%d PEBs are corrupted and not used",
 					ubi->corr_peb_count);
 			spin_unlock(&ubi->volumes_lock);
 			err = -ENOSPC;
@@ -641,7 +595,7 @@
 	dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1);
 	err = cdev_add(&vol->cdev, dev, 1);
 	if (err) {
-		ubi_err("cannot add character device for volume %d, error %d",
+		ubi_err(ubi, "cannot add character device for volume %d, error %d",
 			vol_id, err);
 		return err;
 	}
@@ -649,19 +603,15 @@
 	vol->dev.release = vol_release;
 	vol->dev.parent = &ubi->dev;
 	vol->dev.devt = dev;
-	vol->dev.class = ubi_class;
+#ifndef __UBOOT__
+	vol->dev.class = &ubi_class;
+	vol->dev.groups = volume_dev_groups;
+#endif
 	dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
 	err = device_register(&vol->dev);
 	if (err)
 		goto out_cdev;
 
-	err = volume_sysfs_init(ubi, vol);
-	if (err) {
-		cdev_del(&vol->cdev);
-		volume_sysfs_close(vol);
-		return err;
-	}
-
 	self_check_volumes(ubi);
 	return err;
 
@@ -684,7 +634,7 @@
 
 	ubi->volumes[vol->vol_id] = NULL;
 	cdev_del(&vol->cdev);
-	volume_sysfs_close(vol);
+	device_unregister(&vol->dev);
 }
 
 /**
@@ -708,7 +658,7 @@
 
 	if (!vol) {
 		if (reserved_pebs) {
-			ubi_err("no volume info, but volume exists");
+			ubi_err(ubi, "no volume info, but volume exists");
 			goto fail;
 		}
 		spin_unlock(&ubi->volumes_lock);
@@ -717,90 +667,91 @@
 
 	if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 ||
 	    vol->name_len < 0) {
-		ubi_err("negative values");
+		ubi_err(ubi, "negative values");
 		goto fail;
 	}
 	if (vol->alignment > ubi->leb_size || vol->alignment == 0) {
-		ubi_err("bad alignment");
+		ubi_err(ubi, "bad alignment");
 		goto fail;
 	}
 
 	n = vol->alignment & (ubi->min_io_size - 1);
 	if (vol->alignment != 1 && n) {
-		ubi_err("alignment is not multiple of min I/O unit");
+		ubi_err(ubi, "alignment is not multiple of min I/O unit");
 		goto fail;
 	}
 
 	n = ubi->leb_size % vol->alignment;
 	if (vol->data_pad != n) {
-		ubi_err("bad data_pad, has to be %lld", n);
+		ubi_err(ubi, "bad data_pad, has to be %lld", n);
 		goto fail;
 	}
 
 	if (vol->vol_type != UBI_DYNAMIC_VOLUME &&
 	    vol->vol_type != UBI_STATIC_VOLUME) {
-		ubi_err("bad vol_type");
+		ubi_err(ubi, "bad vol_type");
 		goto fail;
 	}
 
 	if (vol->upd_marker && vol->corrupted) {
-		ubi_err("update marker and corrupted simultaneously");
+		ubi_err(ubi, "update marker and corrupted simultaneously");
 		goto fail;
 	}
 
 	if (vol->reserved_pebs > ubi->good_peb_count) {
-		ubi_err("too large reserved_pebs");
+		ubi_err(ubi, "too large reserved_pebs");
 		goto fail;
 	}
 
 	n = ubi->leb_size - vol->data_pad;
 	if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) {
-		ubi_err("bad usable_leb_size, has to be %lld", n);
+		ubi_err(ubi, "bad usable_leb_size, has to be %lld", n);
 		goto fail;
 	}
 
 	if (vol->name_len > UBI_VOL_NAME_MAX) {
-		ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX);
+		ubi_err(ubi, "too long volume name, max is %d",
+			UBI_VOL_NAME_MAX);
 		goto fail;
 	}
 
 	n = strnlen(vol->name, vol->name_len + 1);
 	if (n != vol->name_len) {
-		ubi_err("bad name_len %lld", n);
+		ubi_err(ubi, "bad name_len %lld", n);
 		goto fail;
 	}
 
 	n = (long long)vol->used_ebs * vol->usable_leb_size;
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
 		if (vol->corrupted) {
-			ubi_err("corrupted dynamic volume");
+			ubi_err(ubi, "corrupted dynamic volume");
 			goto fail;
 		}
 		if (vol->used_ebs != vol->reserved_pebs) {
-			ubi_err("bad used_ebs");
+			ubi_err(ubi, "bad used_ebs");
 			goto fail;
 		}
 		if (vol->last_eb_bytes != vol->usable_leb_size) {
-			ubi_err("bad last_eb_bytes");
+			ubi_err(ubi, "bad last_eb_bytes");
 			goto fail;
 		}
 		if (vol->used_bytes != n) {
-			ubi_err("bad used_bytes");
+			ubi_err(ubi, "bad used_bytes");
 			goto fail;
 		}
 	} else {
 		if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
-			ubi_err("bad used_ebs");
+			ubi_err(ubi, "bad used_ebs");
 			goto fail;
 		}
 		if (vol->last_eb_bytes < 0 ||
 		    vol->last_eb_bytes > vol->usable_leb_size) {
-			ubi_err("bad last_eb_bytes");
+			ubi_err(ubi, "bad last_eb_bytes");
 			goto fail;
 		}
 		if (vol->used_bytes < 0 || vol->used_bytes > n ||
 		    vol->used_bytes < n - vol->usable_leb_size) {
-			ubi_err("bad used_bytes");
+			ubi_err(ubi, "bad used_bytes");
 			goto fail;
 		}
 	}
@@ -818,7 +769,7 @@
 	if (alignment != vol->alignment || data_pad != vol->data_pad ||
 	    upd_marker != vol->upd_marker || vol_type != vol->vol_type ||
 	    name_len != vol->name_len || strncmp(name, vol->name, name_len)) {
-		ubi_err("volume info is different");
+		ubi_err(ubi, "volume info is different");
 		goto fail;
 	}
 
@@ -826,7 +777,7 @@
 	return 0;
 
 fail:
-	ubi_err("self-check failed for volume %d", vol_id);
+	ubi_err(ubi, "self-check failed for volume %d", vol_id);
 	if (vol)
 		ubi_dump_vol_info(vol);
 	ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index ae8ea38..993716f 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -18,9 +18,12 @@
  * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each
  * other. This redundancy guarantees robustness to unclean reboots. The volume
  * table is basically an array of volume table records. Each record contains
- * full information about the volume and protected by a CRC checksum.
+ * full information about the volume and protected by a CRC checksum. Note,
+ * nowadays we use the atomic LEB change operation when updating the volume
+ * table, so we do not really need 2 LEBs anymore, but we preserve the older
+ * design for the backward compatibility reasons.
  *
- * The volume table is changed, it is first changed in RAM. Then LEB 0 is
+ * When the volume table is changed, it is first changed in RAM. Then LEB 0 is
  * erased, and the updated volume table is written back to LEB 0. Then same for
  * LEB 1. This scheme guarantees recoverability from unclean reboots.
  *
@@ -61,6 +64,26 @@
 static struct ubi_vtbl_record empty_vtbl_record;
 
 /**
+ * ubi_update_layout_vol - helper for updatting layout volumes on flash
+ * @ubi: UBI device description object
+ */
+static int ubi_update_layout_vol(struct ubi_device *ubi)
+{
+	struct ubi_volume *layout_vol;
+	int i, err;
+
+	layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
+	for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
+		err = ubi_eba_atomic_leb_change(ubi, layout_vol, i, ubi->vtbl,
+						ubi->vtbl_size);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
  * ubi_change_vtbl_record - change volume table record.
  * @ubi: UBI device description object
  * @idx: table index to change
@@ -74,12 +97,10 @@
 int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
 			   struct ubi_vtbl_record *vtbl_rec)
 {
-	int i, err;
+	int err;
 	uint32_t crc;
-	struct ubi_volume *layout_vol;
 
 	ubi_assert(idx >= 0 && idx < ubi->vtbl_slots);
-	layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
 
 	if (!vtbl_rec)
 		vtbl_rec = &empty_vtbl_record;
@@ -89,19 +110,10 @@
 	}
 
 	memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
-	for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
-		err = ubi_eba_unmap_leb(ubi, layout_vol, i);
-		if (err)
-			return err;
-
-		err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
-					ubi->vtbl_size);
-		if (err)
-			return err;
-	}
+	err = ubi_update_layout_vol(ubi);
 
 	self_vtbl_check(ubi);
-	return 0;
+	return err ? err : 0;
 }
 
 /**
@@ -116,9 +128,7 @@
 int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
 			    struct list_head *rename_list)
 {
-	int i, err;
 	struct ubi_rename_entry *re;
-	struct ubi_volume *layout_vol;
 
 	list_for_each_entry(re, rename_list, list) {
 		uint32_t crc;
@@ -140,19 +150,7 @@
 		vtbl_rec->crc = cpu_to_be32(crc);
 	}
 
-	layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)];
-	for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
-		err = ubi_eba_unmap_leb(ubi, layout_vol, i);
-		if (err)
-			return err;
-
-		err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
-					ubi->vtbl_size);
-		if (err)
-			return err;
-	}
-
-	return 0;
+	return ubi_update_layout_vol(ubi);
 }
 
 /**
@@ -184,7 +182,7 @@
 
 		crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
 		if (be32_to_cpu(vtbl[i].crc) != crc) {
-			ubi_err("bad CRC at record %u: %#08x, not %#08x",
+			ubi_err(ubi, "bad CRC at record %u: %#08x, not %#08x",
 				 i, crc, be32_to_cpu(vtbl[i].crc));
 			ubi_dump_vtbl_record(&vtbl[i], i);
 			return 1;
@@ -218,7 +216,7 @@
 
 		n = ubi->leb_size % alignment;
 		if (data_pad != n) {
-			ubi_err("bad data_pad, has to be %d", n);
+			ubi_err(ubi, "bad data_pad, has to be %d", n);
 			err = 6;
 			goto bad;
 		}
@@ -234,7 +232,7 @@
 		}
 
 		if (reserved_pebs > ubi->good_peb_count) {
-			ubi_err("too large reserved_pebs %d, good PEBs %d",
+			ubi_err(ubi, "too large reserved_pebs %d, good PEBs %d",
 				reserved_pebs, ubi->good_peb_count);
 			err = 9;
 			goto bad;
@@ -268,7 +266,7 @@
 #else
 			    !strncmp((char *)vtbl[i].name, vtbl[n].name, len1)) {
 #endif
-				ubi_err("volumes %d and %d have the same name \"%s\"",
+				ubi_err(ubi, "volumes %d and %d have the same name \"%s\"",
 					i, n, vtbl[i].name);
 				ubi_dump_vtbl_record(&vtbl[i], i);
 				ubi_dump_vtbl_record(&vtbl[n], n);
@@ -280,7 +278,7 @@
 	return 0;
 
 bad:
-	ubi_err("volume table check failed: record %d, error %d", i, err);
+	ubi_err(ubi, "volume table check failed: record %d, error %d", i, err);
 	ubi_dump_vtbl_record(&vtbl[i], i);
 	return -EINVAL;
 }
@@ -444,11 +442,11 @@
 			leb_corrupted[1] = memcmp(leb[0], leb[1],
 						  ubi->vtbl_size);
 		if (leb_corrupted[1]) {
-			ubi_warn("volume table copy #2 is corrupted");
+			ubi_warn(ubi, "volume table copy #2 is corrupted");
 			err = create_vtbl(ubi, ai, 1, leb[0]);
 			if (err)
 				goto out_free;
-			ubi_msg("volume table was restored");
+			ubi_msg(ubi, "volume table was restored");
 		}
 
 		/* Both LEB 1 and LEB 2 are OK and consistent */
@@ -463,15 +461,15 @@
 		}
 		if (leb_corrupted[1]) {
 			/* Both LEB 0 and LEB 1 are corrupted */
-			ubi_err("both volume tables are corrupted");
+			ubi_err(ubi, "both volume tables are corrupted");
 			goto out_free;
 		}
 
-		ubi_warn("volume table copy #1 is corrupted");
+		ubi_warn(ubi, "volume table copy #1 is corrupted");
 		err = create_vtbl(ubi, ai, 0, leb[1]);
 		if (err)
 			goto out_free;
-		ubi_msg("volume table was restored");
+		ubi_msg(ubi, "volume table was restored");
 
 		vfree(leb[0]);
 		return leb[1];
@@ -560,7 +558,7 @@
 		if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
 			/* Auto re-size flag may be set only for one volume */
 			if (ubi->autoresize_vol_id != -1) {
-				ubi_err("more than one auto-resize volume (%d and %d)",
+				ubi_err(ubi, "more than one auto-resize volume (%d and %d)",
 					ubi->autoresize_vol_id, i);
 				kfree(vol);
 				return -EINVAL;
@@ -589,7 +587,7 @@
 
 		/* Static volumes only */
 		av = ubi_find_av(ai, i);
-		if (!av) {
+		if (!av || !av->leb_count) {
 			/*
 			 * No eraseblocks belonging to this volume found. We
 			 * don't actually know whether this static volume is
@@ -606,7 +604,7 @@
 			 * We found a static volume which misses several
 			 * eraseblocks. Treat it as corrupted.
 			 */
-			ubi_warn("static volume %d misses %d LEBs - corrupted",
+			ubi_warn(ubi, "static volume %d misses %d LEBs - corrupted",
 				 av->vol_id, av->used_ebs - av->leb_count);
 			vol->corrupted = 1;
 			continue;
@@ -644,10 +642,10 @@
 	vol->ubi = ubi;
 
 	if (reserved_pebs > ubi->avail_pebs) {
-		ubi_err("not enough PEBs, required %d, available %d",
+		ubi_err(ubi, "not enough PEBs, required %d, available %d",
 			reserved_pebs, ubi->avail_pebs);
 		if (ubi->corr_peb_count)
-			ubi_err("%d PEBs are corrupted and not used",
+			ubi_err(ubi, "%d PEBs are corrupted and not used",
 				ubi->corr_peb_count);
 	}
 	ubi->rsvd_pebs += reserved_pebs;
@@ -692,7 +690,7 @@
 	return 0;
 
 bad:
-	ubi_err("bad attaching information, error %d", err);
+	ubi_err(vol->ubi, "bad attaching information, error %d", err);
 	ubi_dump_av(av);
 	ubi_dump_vol_info(vol);
 	return -EINVAL;
@@ -716,14 +714,15 @@
 	struct ubi_volume *vol;
 
 	if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
-		ubi_err("found %d volumes while attaching, maximum is %d + %d",
+		ubi_err(ubi, "found %d volumes while attaching, maximum is %d + %d",
 			ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
 		return -EINVAL;
 	}
 
 	if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
 	    ai->highest_vol_id < UBI_INTERNAL_VOL_START) {
-		ubi_err("too large volume ID %d found", ai->highest_vol_id);
+		ubi_err(ubi, "too large volume ID %d found",
+			ai->highest_vol_id);
 		return -EINVAL;
 	}
 
@@ -751,7 +750,7 @@
 			 * reboot while the volume was being removed. Discard
 			 * these eraseblocks.
 			 */
-			ubi_msg("finish volume %d removal", av->vol_id);
+			ubi_msg(ubi, "finish volume %d removal", av->vol_id);
 			ubi_remove_av(ai, av);
 		} else if (av) {
 			err = check_av(vol, av);
@@ -805,13 +804,13 @@
 			if (IS_ERR(ubi->vtbl))
 				return PTR_ERR(ubi->vtbl);
 		} else {
-			ubi_err("the layout volume was not found");
+			ubi_err(ubi, "the layout volume was not found");
 			return -EINVAL;
 		}
 	} else {
 		if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) {
 			/* This must not happen with proper UBI images */
-			ubi_err("too many LEBs (%d) in layout volume",
+			ubi_err(ubi, "too many LEBs (%d) in layout volume",
 				av->leb_count);
 			return -EINVAL;
 		}
@@ -860,7 +859,7 @@
 		return;
 
 	if (vtbl_check(ubi, ubi->vtbl)) {
-		ubi_err("self-check failed");
+		ubi_err(ubi, "self-check failed");
 		BUG();
 	}
 }
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 6886f89..507b091 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -96,6 +96,7 @@
 #endif
 
 #include "ubi.h"
+#include "wl.h"
 
 /* Number of physical eraseblocks reserved for wear-leveling purposes */
 #define WL_RESERVED_PEBS 1
@@ -133,44 +134,6 @@
 static int self_check_in_pq(const struct ubi_device *ubi,
 			    struct ubi_wl_entry *e);
 
-#ifdef CONFIG_MTD_UBI_FASTMAP
-#ifndef __UBOOT__
-/**
- * update_fastmap_work_fn - calls ubi_update_fastmap from a work queue
- * @wrk: the work description object
- */
-static void update_fastmap_work_fn(struct work_struct *wrk)
-{
-	struct ubi_device *ubi = container_of(wrk, struct ubi_device, fm_work);
-	ubi_update_fastmap(ubi);
-}
-#endif
-
-/**
- *  ubi_ubi_is_fm_block - returns 1 if a PEB is currently used in a fastmap.
- *  @ubi: UBI device description object
- *  @pnum: the to be checked PEB
- */
-static int ubi_is_fm_block(struct ubi_device *ubi, int pnum)
-{
-	int i;
-
-	if (!ubi->fm)
-		return 0;
-
-	for (i = 0; i < ubi->fm->used_blocks; i++)
-		if (ubi->fm->e[i]->pnum == pnum)
-			return 1;
-
-	return 0;
-}
-#else
-static int ubi_is_fm_block(struct ubi_device *ubi, int pnum)
-{
-	return 0;
-}
-#endif
-
 /**
  * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
  * @e: the wear-leveling entry to add
@@ -208,13 +171,31 @@
 }
 
 /**
+ * wl_tree_destroy - destroy a wear-leveling entry.
+ * @ubi: UBI device description object
+ * @e: the wear-leveling entry to add
+ *
+ * This function destroys a wear leveling entry and removes
+ * the reference from the lookup table.
+ */
+static void wl_entry_destroy(struct ubi_device *ubi, struct ubi_wl_entry *e)
+{
+	ubi->lookuptbl[e->pnum] = NULL;
+	kmem_cache_free(ubi_wl_entry_slab, e);
+}
+
+/**
  * do_work - do one pending work.
  * @ubi: UBI device description object
  *
  * This function returns zero in case of success and a negative error code in
  * case of failure.
  */
+#ifndef __UBOOT__
 static int do_work(struct ubi_device *ubi)
+#else
+int do_work(struct ubi_device *ubi)
+#endif
 {
 	int err;
 	struct ubi_work *wrk;
@@ -248,40 +229,13 @@
 	 */
 	err = wrk->func(ubi, wrk, 0);
 	if (err)
-		ubi_err("work failed with error code %d", err);
+		ubi_err(ubi, "work failed with error code %d", err);
 	up_read(&ubi->work_sem);
 
 	return err;
 }
 
 /**
- * produce_free_peb - produce a free physical eraseblock.
- * @ubi: UBI device description object
- *
- * This function tries to make a free PEB by means of synchronous execution of
- * pending works. This may be needed if, for example the background thread is
- * disabled. Returns zero in case of success and a negative error code in case
- * of failure.
- */
-static int produce_free_peb(struct ubi_device *ubi)
-{
-	int err;
-
-	while (!ubi->free.rb_node) {
-		spin_unlock(&ubi->wl_lock);
-
-		dbg_wl("do one work synchronously");
-		err = do_work(ubi);
-
-		spin_lock(&ubi->wl_lock);
-		if (err)
-			return err;
-	}
-
-	return 0;
-}
-
-/**
  * in_wl_tree - check if wear-leveling entry is present in a WL RB-tree.
  * @e: the wear-leveling entry to check
  * @root: the root of the tree
@@ -404,119 +358,32 @@
 	if (last->ec - first->ec < WL_FREE_MAX_DIFF) {
 		e = rb_entry(root->rb_node, struct ubi_wl_entry, u.rb);
 
-#ifdef CONFIG_MTD_UBI_FASTMAP
 		/* If no fastmap has been written and this WL entry can be used
 		 * as anchor PEB, hold it back and return the second best
 		 * WL entry such that fastmap can use the anchor PEB later. */
-		if (e && !ubi->fm_disabled && !ubi->fm &&
-		    e->pnum < UBI_FM_MAX_START)
-			e = rb_entry(rb_next(root->rb_node),
-				     struct ubi_wl_entry, u.rb);
-#endif
+		e = may_reserve_for_fm(ubi, e, root);
 	} else
 		e = find_wl_entry(ubi, root, WL_FREE_MAX_DIFF/2);
 
 	return e;
 }
 
-#ifdef CONFIG_MTD_UBI_FASTMAP
 /**
- * find_anchor_wl_entry - find wear-leveling entry to used as anchor PEB.
- * @root: the RB-tree where to look for
- */
-static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root)
-{
-	struct rb_node *p;
-	struct ubi_wl_entry *e, *victim = NULL;
-	int max_ec = UBI_MAX_ERASECOUNTER;
-
-	ubi_rb_for_each_entry(p, e, root, u.rb) {
-		if (e->pnum < UBI_FM_MAX_START && e->ec < max_ec) {
-			victim = e;
-			max_ec = e->ec;
-		}
-	}
-
-	return victim;
-}
-
-static int anchor_pebs_avalible(struct rb_root *root)
-{
-	struct rb_node *p;
-	struct ubi_wl_entry *e;
-
-	ubi_rb_for_each_entry(p, e, root, u.rb)
-		if (e->pnum < UBI_FM_MAX_START)
-			return 1;
-
-	return 0;
-}
-
-/**
- * ubi_wl_get_fm_peb - find a physical erase block with a given maximal number.
- * @ubi: UBI device description object
- * @anchor: This PEB will be used as anchor PEB by fastmap
- *
- * The function returns a physical erase block with a given maximal number
- * and removes it from the wl subsystem.
- * Must be called with wl_lock held!
- */
-struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor)
-{
-	struct ubi_wl_entry *e = NULL;
-
-	if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1))
-		goto out;
-
-	if (anchor)
-		e = find_anchor_wl_entry(&ubi->free);
-	else
-		e = find_mean_wl_entry(ubi, &ubi->free);
-
-	if (!e)
-		goto out;
-
-	self_check_in_wl_tree(ubi, e, &ubi->free);
-
-	/* remove it from the free list,
-	 * the wl subsystem does no longer know this erase block */
-	rb_erase(&e->u.rb, &ubi->free);
-	ubi->free_count--;
-out:
-	return e;
-}
-#endif
-
-/**
- * __wl_get_peb - get a physical eraseblock.
+ * wl_get_wle - get a mean wl entry to be used by ubi_wl_get_peb() or
+ * refill_wl_user_pool().
  * @ubi: UBI device description object
  *
- * This function returns a physical eraseblock in case of success and a
- * negative error code in case of failure.
+ * This function returns a a wear leveling entry in case of success and
+ * NULL in case of failure.
  */
-static int __wl_get_peb(struct ubi_device *ubi)
+static struct ubi_wl_entry *wl_get_wle(struct ubi_device *ubi)
 {
-	int err;
 	struct ubi_wl_entry *e;
 
-retry:
-	if (!ubi->free.rb_node) {
-		if (ubi->works_count == 0) {
-			ubi_err("no free eraseblocks");
-			ubi_assert(list_empty(&ubi->works));
-			return -ENOSPC;
-		}
-
-		err = produce_free_peb(ubi);
-		if (err < 0)
-			return err;
-		goto retry;
-	}
-
 	e = find_mean_wl_entry(ubi, &ubi->free);
 	if (!e) {
-		ubi_err("no free eraseblocks");
-		return -ENOSPC;
+		ubi_err(ubi, "no free eraseblocks");
+		return NULL;
 	}
 
 	self_check_in_wl_tree(ubi, e, &ubi->free);
@@ -528,178 +395,10 @@
 	rb_erase(&e->u.rb, &ubi->free);
 	ubi->free_count--;
 	dbg_wl("PEB %d EC %d", e->pnum, e->ec);
-#ifndef CONFIG_MTD_UBI_FASTMAP
-	/* We have to enqueue e only if fastmap is disabled,
-	 * is fastmap enabled prot_queue_add() will be called by
-	 * ubi_wl_get_peb() after removing e from the pool. */
-	prot_queue_add(ubi, e);
-#endif
-	return e->pnum;
-}
-
-#ifdef CONFIG_MTD_UBI_FASTMAP
-/**
- * return_unused_pool_pebs - returns unused PEB to the free tree.
- * @ubi: UBI device description object
- * @pool: fastmap pool description object
- */
-static void return_unused_pool_pebs(struct ubi_device *ubi,
-				    struct ubi_fm_pool *pool)
-{
-	int i;
-	struct ubi_wl_entry *e;
-
-	for (i = pool->used; i < pool->size; i++) {
-		e = ubi->lookuptbl[pool->pebs[i]];
-		wl_tree_add(e, &ubi->free);
-		ubi->free_count++;
-	}
-}
-
-/**
- * refill_wl_pool - refills all the fastmap pool used by the
- * WL sub-system.
- * @ubi: UBI device description object
- */
-static void refill_wl_pool(struct ubi_device *ubi)
-{
-	struct ubi_wl_entry *e;
-	struct ubi_fm_pool *pool = &ubi->fm_wl_pool;
-
-	return_unused_pool_pebs(ubi, pool);
-
-	for (pool->size = 0; pool->size < pool->max_size; pool->size++) {
-		if (!ubi->free.rb_node ||
-		   (ubi->free_count - ubi->beb_rsvd_pebs < 5))
-			break;
-
-		e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
-		self_check_in_wl_tree(ubi, e, &ubi->free);
-		rb_erase(&e->u.rb, &ubi->free);
-		ubi->free_count--;
-
-		pool->pebs[pool->size] = e->pnum;
-	}
-	pool->used = 0;
-}
-
-/**
- * refill_wl_user_pool - refills all the fastmap pool used by ubi_wl_get_peb.
- * @ubi: UBI device description object
- */
-static void refill_wl_user_pool(struct ubi_device *ubi)
-{
-	struct ubi_fm_pool *pool = &ubi->fm_pool;
-
-	return_unused_pool_pebs(ubi, pool);
-
-	for (pool->size = 0; pool->size < pool->max_size; pool->size++) {
-		pool->pebs[pool->size] = __wl_get_peb(ubi);
-		if (pool->pebs[pool->size] < 0)
-			break;
-	}
-	pool->used = 0;
-}
-
-/**
- * ubi_refill_pools - refills all fastmap PEB pools.
- * @ubi: UBI device description object
- */
-void ubi_refill_pools(struct ubi_device *ubi)
-{
-	spin_lock(&ubi->wl_lock);
-	refill_wl_pool(ubi);
-	refill_wl_user_pool(ubi);
-	spin_unlock(&ubi->wl_lock);
-}
-
-/* ubi_wl_get_peb - works exaclty like __wl_get_peb but keeps track of
- * the fastmap pool.
- */
-int ubi_wl_get_peb(struct ubi_device *ubi)
-{
-	int ret;
-	struct ubi_fm_pool *pool = &ubi->fm_pool;
-	struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool;
-
-	if (!pool->size || !wl_pool->size || pool->used == pool->size ||
-	    wl_pool->used == wl_pool->size)
-		ubi_update_fastmap(ubi);
-
-	/* we got not a single free PEB */
-	if (!pool->size)
-		ret = -ENOSPC;
-	else {
-		spin_lock(&ubi->wl_lock);
-		ret = pool->pebs[pool->used++];
-		prot_queue_add(ubi, ubi->lookuptbl[ret]);
-		spin_unlock(&ubi->wl_lock);
-	}
-
-	return ret;
-}
-
-/* get_peb_for_wl - returns a PEB to be used internally by the WL sub-system.
- *
- * @ubi: UBI device description object
- */
-static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
-{
-	struct ubi_fm_pool *pool = &ubi->fm_wl_pool;
-	int pnum;
-
-	if (pool->used == pool->size || !pool->size) {
-		/* We cannot update the fastmap here because this
-		 * function is called in atomic context.
-		 * Let's fail here and refill/update it as soon as possible. */
-#ifndef __UBOOT__
-		schedule_work(&ubi->fm_work);
-#else
-		/* In U-Boot we must call this directly */
-	        ubi_update_fastmap(ubi);
-#endif
-		return NULL;
-	} else {
-		pnum = pool->pebs[pool->used++];
-		return ubi->lookuptbl[pnum];
-	}
-}
-#else
-static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
-{
-	struct ubi_wl_entry *e;
-
-	e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
-	self_check_in_wl_tree(ubi, e, &ubi->free);
-	ubi->free_count--;
-	ubi_assert(ubi->free_count >= 0);
-	rb_erase(&e->u.rb, &ubi->free);
 
 	return e;
 }
 
-int ubi_wl_get_peb(struct ubi_device *ubi)
-{
-	int peb, err;
-
-	spin_lock(&ubi->wl_lock);
-	peb = __wl_get_peb(ubi);
-	spin_unlock(&ubi->wl_lock);
-
-	if (peb < 0)
-		return peb;
-
-	err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset,
-				    ubi->peb_size - ubi->vid_hdr_aloffset);
-	if (err) {
-		ubi_err("new PEB %d does not contain all 0xFF bytes", peb);
-		return err;
-	}
-
-	return peb;
-}
-#endif
-
 /**
  * prot_queue_del - remove a physical eraseblock from the protection queue.
  * @ubi: UBI device description object
@@ -760,7 +459,7 @@
 		 * Erase counter overflow. Upgrade UBI and use 64-bit
 		 * erase counters internally.
 		 */
-		ubi_err("erase counter overflow at PEB %d, EC %llu",
+		ubi_err(ubi, "erase counter overflow at PEB %d, EC %llu",
 			e->pnum, ec);
 		err = -EINVAL;
 		goto out_free;
@@ -835,7 +534,7 @@
  * @wrk: the work to schedule
  *
  * This function adds a work defined by @wrk to the tail of the pending works
- * list. Can only be used of ubi->work_sem is already held in read mode!
+ * list. Can only be used if ubi->work_sem is already held in read mode!
  */
 static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
 {
@@ -847,11 +546,16 @@
 	if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled(ubi))
 		wake_up_process(ubi->bgt_thread);
 #else
+	int err;
 	/*
 	 * U-Boot special: We have no bgt_thread in U-Boot!
 	 * So just call do_work() here directly.
 	 */
-	do_work(ubi);
+	err = do_work(ubi);
+	if (err) {
+		ubi_err(ubi, "%s: work failed with error code %d",
+			ubi->bgt_name, err);
+	}
 #endif
 	spin_unlock(&ubi->wl_lock);
 }
@@ -872,18 +576,7 @@
 }
 
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
-			int cancel);
-
-#ifdef CONFIG_MTD_UBI_FASTMAP
-/**
- * ubi_is_erase_work - checks whether a work is erase work.
- * @wrk: The work object to be checked
- */
-int ubi_is_erase_work(struct ubi_work *wrk)
-{
-	return wrk->func == erase_worker;
-}
-#endif
+			int shutdown);
 
 /**
  * schedule_erase - schedule an erase work.
@@ -902,7 +595,6 @@
 	struct ubi_work *wl_wrk;
 
 	ubi_assert(e);
-	ubi_assert(!ubi_is_fm_block(ubi, e->pnum));
 
 	dbg_wl("schedule erasure of PEB %d, EC %d, torture %d",
 	       e->pnum, e->ec, torture);
@@ -949,66 +641,22 @@
 	return erase_worker(ubi, wl_wrk, 0);
 }
 
-#ifdef CONFIG_MTD_UBI_FASTMAP
-/**
- * ubi_wl_put_fm_peb - returns a PEB used in a fastmap to the wear-leveling
- * sub-system.
- * see: ubi_wl_put_peb()
- *
- * @ubi: UBI device description object
- * @fm_e: physical eraseblock to return
- * @lnum: the last used logical eraseblock number for the PEB
- * @torture: if this physical eraseblock has to be tortured
- */
-int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e,
-		      int lnum, int torture)
-{
-	struct ubi_wl_entry *e;
-	int vol_id, pnum = fm_e->pnum;
-
-	dbg_wl("PEB %d", pnum);
-
-	ubi_assert(pnum >= 0);
-	ubi_assert(pnum < ubi->peb_count);
-
-	spin_lock(&ubi->wl_lock);
-	e = ubi->lookuptbl[pnum];
-
-	/* This can happen if we recovered from a fastmap the very
-	 * first time and writing now a new one. In this case the wl system
-	 * has never seen any PEB used by the original fastmap.
-	 */
-	if (!e) {
-		e = fm_e;
-		ubi_assert(e->ec >= 0);
-		ubi->lookuptbl[pnum] = e;
-	} else {
-		e->ec = fm_e->ec;
-		kfree(fm_e);
-	}
-
-	spin_unlock(&ubi->wl_lock);
-
-	vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID;
-	return schedule_erase(ubi, e, vol_id, lnum, torture);
-}
-#endif
-
 /**
  * wear_leveling_worker - wear-leveling worker function.
  * @ubi: UBI device description object
  * @wrk: the work object
- * @cancel: non-zero if the worker has to free memory and exit
+ * @shutdown: non-zero if the worker has to free memory and exit
+ * because the WL-subsystem is shutting down
  *
  * This function copies a more worn out physical eraseblock to a less worn out
  * one. Returns zero in case of success and a negative error code in case of
  * failure.
  */
 static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
-				int cancel)
+				int shutdown)
 {
 	int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
-	int vol_id = -1, uninitialized_var(lnum);
+	int vol_id = -1, lnum = -1;
 #ifdef CONFIG_MTD_UBI_FASTMAP
 	int anchor = wrk->anchor;
 #endif
@@ -1016,7 +664,7 @@
 	struct ubi_vid_hdr *vid_hdr;
 
 	kfree(wrk);
-	if (cancel)
+	if (shutdown)
 		return 0;
 
 	vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
@@ -1144,7 +792,7 @@
 			goto out_not_moved;
 		}
 
-		ubi_err("error %d while reading VID header from PEB %d",
+		ubi_err(ubi, "error %d while reading VID header from PEB %d",
 			err, e1->pnum);
 		goto out_error;
 	}
@@ -1188,7 +836,7 @@
 			 * UBI from trying to move it over and over again.
 			 */
 			if (ubi->erroneous_peb_count > ubi->max_erroneous) {
-				ubi_err("too many erroneous eraseblocks (%d)",
+				ubi_err(ubi, "too many erroneous eraseblocks (%d)",
 					ubi->erroneous_peb_count);
 				goto out_error;
 			}
@@ -1204,7 +852,7 @@
 
 	/* The PEB has been successfully moved */
 	if (scrubbing)
-		ubi_msg("scrubbed PEB %d (LEB %d:%d), data moved to PEB %d",
+		ubi_msg(ubi, "scrubbed PEB %d (LEB %d:%d), data moved to PEB %d",
 			e1->pnum, vol_id, lnum, e2->pnum);
 	ubi_free_vid_hdr(ubi, vid_hdr);
 
@@ -1219,9 +867,8 @@
 
 	err = do_sync_erase(ubi, e1, vol_id, lnum, 0);
 	if (err) {
-		kmem_cache_free(ubi_wl_entry_slab, e1);
 		if (e2)
-			kmem_cache_free(ubi_wl_entry_slab, e2);
+			wl_entry_destroy(ubi, e2);
 		goto out_ro;
 	}
 
@@ -1233,10 +880,8 @@
 		dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase",
 		       e2->pnum, vol_id, lnum);
 		err = do_sync_erase(ubi, e2, vol_id, lnum, 0);
-		if (err) {
-			kmem_cache_free(ubi_wl_entry_slab, e2);
+		if (err)
 			goto out_ro;
-		}
 	}
 
 	dbg_wl("done");
@@ -1272,19 +917,18 @@
 
 	ubi_free_vid_hdr(ubi, vid_hdr);
 	err = do_sync_erase(ubi, e2, vol_id, lnum, torture);
-	if (err) {
-		kmem_cache_free(ubi_wl_entry_slab, e2);
+	if (err)
 		goto out_ro;
-	}
+
 	mutex_unlock(&ubi->move_mutex);
 	return 0;
 
 out_error:
 	if (vol_id != -1)
-		ubi_err("error %d while moving PEB %d to PEB %d",
+		ubi_err(ubi, "error %d while moving PEB %d to PEB %d",
 			err, e1->pnum, e2->pnum);
 	else
-		ubi_err("error %d while moving PEB %d (LEB %d:%d) to PEB %d",
+		ubi_err(ubi, "error %d while moving PEB %d (LEB %d:%d) to PEB %d",
 			err, e1->pnum, vol_id, lnum, e2->pnum);
 	spin_lock(&ubi->wl_lock);
 	ubi->move_from = ubi->move_to = NULL;
@@ -1292,8 +936,8 @@
 	spin_unlock(&ubi->wl_lock);
 
 	ubi_free_vid_hdr(ubi, vid_hdr);
-	kmem_cache_free(ubi_wl_entry_slab, e1);
-	kmem_cache_free(ubi_wl_entry_slab, e2);
+	wl_entry_destroy(ubi, e1);
+	wl_entry_destroy(ubi, e2);
 
 out_ro:
 	ubi_ro_mode(ubi);
@@ -1379,43 +1023,12 @@
 	return err;
 }
 
-#ifdef CONFIG_MTD_UBI_FASTMAP
-/**
- * ubi_ensure_anchor_pebs - schedule wear-leveling to produce an anchor PEB.
- * @ubi: UBI device description object
- */
-int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
-{
-	struct ubi_work *wrk;
-
-	spin_lock(&ubi->wl_lock);
-	if (ubi->wl_scheduled) {
-		spin_unlock(&ubi->wl_lock);
-		return 0;
-	}
-	ubi->wl_scheduled = 1;
-	spin_unlock(&ubi->wl_lock);
-
-	wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
-	if (!wrk) {
-		spin_lock(&ubi->wl_lock);
-		ubi->wl_scheduled = 0;
-		spin_unlock(&ubi->wl_lock);
-		return -ENOMEM;
-	}
-
-	wrk->anchor = 1;
-	wrk->func = &wear_leveling_worker;
-	schedule_ubi_work(ubi, wrk);
-	return 0;
-}
-#endif
-
 /**
  * erase_worker - physical eraseblock erase worker function.
  * @ubi: UBI device description object
  * @wl_wrk: the work object
- * @cancel: non-zero if the worker has to free memory and exit
+ * @shutdown: non-zero if the worker has to free memory and exit
+ * because the WL sub-system is shutting down
  *
  * This function erases a physical eraseblock and perform torture testing if
  * needed. It also takes care about marking the physical eraseblock bad if
@@ -1423,7 +1036,7 @@
  * failure.
  */
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
-			int cancel)
+			int shutdown)
 {
 	struct ubi_wl_entry *e = wl_wrk->e;
 	int pnum = e->pnum;
@@ -1431,18 +1044,16 @@
 	int lnum = wl_wrk->lnum;
 	int err, available_consumed = 0;
 
-	if (cancel) {
+	if (shutdown) {
 		dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
 		kfree(wl_wrk);
-		kmem_cache_free(ubi_wl_entry_slab, e);
+		wl_entry_destroy(ubi, e);
 		return 0;
 	}
 
 	dbg_wl("erase PEB %d EC %d LEB %d:%d",
 	       pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
 
-	ubi_assert(!ubi_is_fm_block(ubi, e->pnum));
-
 	err = sync_erase(ubi, e, wl_wrk->torture);
 	if (!err) {
 		/* Fine, we've erased it successfully */
@@ -1464,7 +1075,7 @@
 		return err;
 	}
 
-	ubi_err("failed to erase PEB %d, error %d", pnum, err);
+	ubi_err(ubi, "failed to erase PEB %d, error %d", pnum, err);
 	kfree(wl_wrk);
 
 	if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
@@ -1480,7 +1091,7 @@
 		return err;
 	}
 
-	kmem_cache_free(ubi_wl_entry_slab, e);
+	wl_entry_destroy(ubi, e);
 	if (err != -EIO)
 		/*
 		 * If this is not %-EIO, we have no idea what to do. Scheduling
@@ -1492,7 +1103,7 @@
 	/* It is %-EIO, the PEB went bad */
 
 	if (!ubi->bad_allowed) {
-		ubi_err("bad physical eraseblock %d detected", pnum);
+		ubi_err(ubi, "bad physical eraseblock %d detected", pnum);
 		goto out_ro;
 	}
 
@@ -1500,7 +1111,7 @@
 	if (ubi->beb_rsvd_pebs == 0) {
 		if (ubi->avail_pebs == 0) {
 			spin_unlock(&ubi->volumes_lock);
-			ubi_err("no reserved/available physical eraseblocks");
+			ubi_err(ubi, "no reserved/available physical eraseblocks");
 			goto out_ro;
 		}
 		ubi->avail_pebs -= 1;
@@ -1508,7 +1119,7 @@
 	}
 	spin_unlock(&ubi->volumes_lock);
 
-	ubi_msg("mark PEB %d as bad", pnum);
+	ubi_msg(ubi, "mark PEB %d as bad", pnum);
 	err = ubi_io_mark_bad(ubi, pnum);
 	if (err)
 		goto out_ro;
@@ -1529,11 +1140,12 @@
 	ubi->good_peb_count -= 1;
 	ubi_calculate_reserved(ubi);
 	if (available_consumed)
-		ubi_warn("no PEBs in the reserved pool, used an available PEB");
+		ubi_warn(ubi, "no PEBs in the reserved pool, used an available PEB");
 	else if (ubi->beb_rsvd_pebs)
-		ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs);
+		ubi_msg(ubi, "%d PEBs left in the reserve",
+			ubi->beb_rsvd_pebs);
 	else
-		ubi_warn("last PEB from the reserve was used");
+		ubi_warn(ubi, "last PEB from the reserve was used");
 	spin_unlock(&ubi->volumes_lock);
 
 	return err;
@@ -1571,6 +1183,8 @@
 	ubi_assert(pnum >= 0);
 	ubi_assert(pnum < ubi->peb_count);
 
+	down_read(&ubi->fm_protect);
+
 retry:
 	spin_lock(&ubi->wl_lock);
 	e = ubi->lookuptbl[pnum];
@@ -1601,6 +1215,7 @@
 		ubi_assert(!ubi->move_to_put);
 		ubi->move_to_put = 1;
 		spin_unlock(&ubi->wl_lock);
+		up_read(&ubi->fm_protect);
 		return 0;
 	} else {
 		if (in_wl_tree(e, &ubi->used)) {
@@ -1619,9 +1234,10 @@
 		} else {
 			err = prot_queue_del(ubi, e->pnum);
 			if (err) {
-				ubi_err("PEB %d not found", pnum);
+				ubi_err(ubi, "PEB %d not found", pnum);
 				ubi_ro_mode(ubi);
 				spin_unlock(&ubi->wl_lock);
+				up_read(&ubi->fm_protect);
 				return err;
 			}
 		}
@@ -1635,6 +1251,7 @@
 		spin_unlock(&ubi->wl_lock);
 	}
 
+	up_read(&ubi->fm_protect);
 	return err;
 }
 
@@ -1652,7 +1269,7 @@
 {
 	struct ubi_wl_entry *e;
 
-	ubi_msg("schedule PEB %d for scrubbing", pnum);
+	ubi_msg(ubi, "schedule PEB %d for scrubbing", pnum);
 
 retry:
 	spin_lock(&ubi->wl_lock);
@@ -1684,7 +1301,7 @@
 
 		err = prot_queue_del(ubi, e->pnum);
 		if (err) {
-			ubi_err("PEB %d not found", pnum);
+			ubi_err(ubi, "PEB %d not found", pnum);
 			ubi_ro_mode(ubi);
 			spin_unlock(&ubi->wl_lock);
 			return err;
@@ -1726,12 +1343,12 @@
 	       vol_id, lnum, ubi->works_count);
 
 	while (found) {
-		struct ubi_work *wrk;
+		struct ubi_work *wrk, *tmp;
 		found = 0;
 
 		down_read(&ubi->work_sem);
 		spin_lock(&ubi->wl_lock);
-		list_for_each_entry(wrk, &ubi->works, list) {
+		list_for_each_entry_safe(wrk, tmp, &ubi->works, list) {
 			if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) &&
 			    (lnum == UBI_ALL || wrk->lnum == lnum)) {
 				list_del(&wrk->list);
@@ -1766,9 +1383,10 @@
 
 /**
  * tree_destroy - destroy an RB-tree.
+ * @ubi: UBI device description object
  * @root: the root of the tree to destroy
  */
-static void tree_destroy(struct rb_root *root)
+static void tree_destroy(struct ubi_device *ubi, struct rb_root *root)
 {
 	struct rb_node *rb;
 	struct ubi_wl_entry *e;
@@ -1790,7 +1408,7 @@
 					rb->rb_right = NULL;
 			}
 
-			kmem_cache_free(ubi_wl_entry_slab, e);
+			wl_entry_destroy(ubi, e);
 		}
 	}
 }
@@ -1804,7 +1422,7 @@
 	int failures = 0;
 	struct ubi_device *ubi = u;
 
-	ubi_msg("background thread \"%s\" started, PID %d",
+	ubi_msg(ubi, "background thread \"%s\" started, PID %d",
 		ubi->bgt_name, task_pid_nr(current));
 
 	set_freezable();
@@ -1829,14 +1447,14 @@
 
 		err = do_work(ubi);
 		if (err) {
-			ubi_err("%s: work failed with error code %d",
+			ubi_err(ubi, "%s: work failed with error code %d",
 				ubi->bgt_name, err);
 			if (failures++ > WL_MAX_FAILURES) {
 				/*
 				 * Too many failures, disable the thread and
 				 * switch to read-only mode.
 				 */
-				ubi_msg("%s: %d consecutive failures",
+				ubi_msg(ubi, "%s: %d consecutive failures",
 					ubi->bgt_name, WL_MAX_FAILURES);
 				ubi_ro_mode(ubi);
 				ubi->thread_enabled = 0;
@@ -1853,11 +1471,18 @@
 }
 
 /**
- * cancel_pending - cancel all pending works.
+ * shutdown_work - shutdown all pending works.
  * @ubi: UBI device description object
  */
-static void cancel_pending(struct ubi_device *ubi)
+static void shutdown_work(struct ubi_device *ubi)
 {
+#ifdef CONFIG_MTD_UBI_FASTMAP
+#ifndef __UBOOT__
+	flush_work(&ubi->fm_work);
+#else
+	/* in U-Boot, we have all work done */
+#endif
+#endif
 	while (!list_empty(&ubi->works)) {
 		struct ubi_work *wrk;
 
@@ -1891,11 +1516,6 @@
 	init_rwsem(&ubi->work_sem);
 	ubi->max_ec = ai->max_ec;
 	INIT_LIST_HEAD(&ubi->works);
-#ifndef __UBOOT__
-#ifdef CONFIG_MTD_UBI_FASTMAP
-	INIT_WORK(&ubi->fm_work, update_fastmap_work_fn);
-#endif
-#endif
 
 	sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
 
@@ -1917,10 +1537,9 @@
 
 		e->pnum = aeb->pnum;
 		e->ec = aeb->ec;
-		ubi_assert(!ubi_is_fm_block(ubi, e->pnum));
 		ubi->lookuptbl[e->pnum] = e;
 		if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
-			kmem_cache_free(ubi_wl_entry_slab, e);
+			wl_entry_destroy(ubi, e);
 			goto out_free;
 		}
 
@@ -1938,7 +1557,6 @@
 		e->pnum = aeb->pnum;
 		e->ec = aeb->ec;
 		ubi_assert(e->ec >= 0);
-		ubi_assert(!ubi_is_fm_block(ubi, e->pnum));
 
 		wl_tree_add(e, &ubi->free);
 		ubi->free_count++;
@@ -1976,23 +1594,26 @@
 
 	dbg_wl("found %i PEBs", found_pebs);
 
-	if (ubi->fm)
-		ubi_assert(ubi->good_peb_count == \
+	if (ubi->fm) {
+		ubi_assert(ubi->good_peb_count ==
 			   found_pebs + ubi->fm->used_blocks);
+
+		for (i = 0; i < ubi->fm->used_blocks; i++) {
+			e = ubi->fm->e[i];
+			ubi->lookuptbl[e->pnum] = e;
+		}
+	}
 	else
 		ubi_assert(ubi->good_peb_count == found_pebs);
 
 	reserved_pebs = WL_RESERVED_PEBS;
-#ifdef CONFIG_MTD_UBI_FASTMAP
-	/* Reserve enough LEBs to store two fastmaps. */
-	reserved_pebs += (ubi->fm_size / ubi->leb_size) * 2;
-#endif
+	ubi_fastmap_init(ubi, &reserved_pebs);
 
 	if (ubi->avail_pebs < reserved_pebs) {
-		ubi_err("no enough physical eraseblocks (%d, need %d)",
+		ubi_err(ubi, "no enough physical eraseblocks (%d, need %d)",
 			ubi->avail_pebs, reserved_pebs);
 		if (ubi->corr_peb_count)
-			ubi_err("%d PEBs are corrupted and not used",
+			ubi_err(ubi, "%d PEBs are corrupted and not used",
 				ubi->corr_peb_count);
 		goto out_free;
 	}
@@ -2007,10 +1628,10 @@
 	return 0;
 
 out_free:
-	cancel_pending(ubi);
-	tree_destroy(&ubi->used);
-	tree_destroy(&ubi->free);
-	tree_destroy(&ubi->scrub);
+	shutdown_work(ubi);
+	tree_destroy(ubi, &ubi->used);
+	tree_destroy(ubi, &ubi->free);
+	tree_destroy(ubi, &ubi->scrub);
 	kfree(ubi->lookuptbl);
 	return err;
 }
@@ -2027,7 +1648,7 @@
 	for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) {
 		list_for_each_entry_safe(e, tmp, &ubi->pq[i], u.list) {
 			list_del(&e->u.list);
-			kmem_cache_free(ubi_wl_entry_slab, e);
+			wl_entry_destroy(ubi, e);
 		}
 	}
 }
@@ -2039,12 +1660,13 @@
 void ubi_wl_close(struct ubi_device *ubi)
 {
 	dbg_wl("close the WL sub-system");
-	cancel_pending(ubi);
+	ubi_fastmap_close(ubi);
+	shutdown_work(ubi);
 	protection_queue_destroy(ubi);
-	tree_destroy(&ubi->used);
-	tree_destroy(&ubi->erroneous);
-	tree_destroy(&ubi->free);
-	tree_destroy(&ubi->scrub);
+	tree_destroy(ubi, &ubi->used);
+	tree_destroy(ubi, &ubi->erroneous);
+	tree_destroy(ubi, &ubi->free);
+	tree_destroy(ubi, &ubi->scrub);
 	kfree(ubi->lookuptbl);
 }
 
@@ -2080,8 +1702,8 @@
 
 	read_ec = be64_to_cpu(ec_hdr->ec);
 	if (ec != read_ec && read_ec - ec > 1) {
-		ubi_err("self-check failed for PEB %d", pnum);
-		ubi_err("read EC is %lld, should be %d", read_ec, ec);
+		ubi_err(ubi, "self-check failed for PEB %d", pnum);
+		ubi_err(ubi, "read EC is %lld, should be %d", read_ec, ec);
 		dump_stack();
 		err = 1;
 	} else
@@ -2110,7 +1732,7 @@
 	if (in_wl_tree(e, root))
 		return 0;
 
-	ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ",
+	ubi_err(ubi, "self-check failed for PEB %d, EC %d, RB-tree %p ",
 		e->pnum, e->ec, root);
 	dump_stack();
 	return -EINVAL;
@@ -2138,8 +1760,99 @@
 			if (p == e)
 				return 0;
 
-	ubi_err("self-check failed for PEB %d, EC %d, Protect queue",
+	ubi_err(ubi, "self-check failed for PEB %d, EC %d, Protect queue",
 		e->pnum, e->ec);
 	dump_stack();
 	return -EINVAL;
 }
+#ifndef CONFIG_MTD_UBI_FASTMAP
+static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
+{
+	struct ubi_wl_entry *e;
+
+	e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+	self_check_in_wl_tree(ubi, e, &ubi->free);
+	ubi->free_count--;
+	ubi_assert(ubi->free_count >= 0);
+	rb_erase(&e->u.rb, &ubi->free);
+
+	return e;
+}
+
+/**
+ * produce_free_peb - produce a free physical eraseblock.
+ * @ubi: UBI device description object
+ *
+ * This function tries to make a free PEB by means of synchronous execution of
+ * pending works. This may be needed if, for example the background thread is
+ * disabled. Returns zero in case of success and a negative error code in case
+ * of failure.
+ */
+static int produce_free_peb(struct ubi_device *ubi)
+{
+	int err;
+
+	while (!ubi->free.rb_node && ubi->works_count) {
+		spin_unlock(&ubi->wl_lock);
+
+		dbg_wl("do one work synchronously");
+		err = do_work(ubi);
+
+		spin_lock(&ubi->wl_lock);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * ubi_wl_get_peb - get a physical eraseblock.
+ * @ubi: UBI device description object
+ *
+ * This function returns a physical eraseblock in case of success and a
+ * negative error code in case of failure.
+ * Returns with ubi->fm_eba_sem held in read mode!
+ */
+int ubi_wl_get_peb(struct ubi_device *ubi)
+{
+	int err;
+	struct ubi_wl_entry *e;
+
+retry:
+	down_read(&ubi->fm_eba_sem);
+	spin_lock(&ubi->wl_lock);
+	if (!ubi->free.rb_node) {
+		if (ubi->works_count == 0) {
+			ubi_err(ubi, "no free eraseblocks");
+			ubi_assert(list_empty(&ubi->works));
+			spin_unlock(&ubi->wl_lock);
+			return -ENOSPC;
+		}
+
+		err = produce_free_peb(ubi);
+		if (err < 0) {
+			spin_unlock(&ubi->wl_lock);
+			return err;
+		}
+		spin_unlock(&ubi->wl_lock);
+		up_read(&ubi->fm_eba_sem);
+		goto retry;
+
+	}
+	e = wl_get_wle(ubi);
+	prot_queue_add(ubi, e);
+	spin_unlock(&ubi->wl_lock);
+
+	err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
+				    ubi->peb_size - ubi->vid_hdr_aloffset);
+	if (err) {
+		ubi_err(ubi, "new PEB %d does not contain all 0xFF bytes", e->pnum);
+		return err;
+	}
+
+	return e->pnum;
+}
+#else
+#include "fastmap-wl.c"
+#endif
diff --git a/drivers/mtd/ubi/wl.h b/drivers/mtd/ubi/wl.h
new file mode 100644
index 0000000..662dbe3
--- /dev/null
+++ b/drivers/mtd/ubi/wl.h
@@ -0,0 +1,34 @@
+#ifndef UBI_WL_H
+#define UBI_WL_H
+#ifdef CONFIG_MTD_UBI_FASTMAP
+static int anchor_pebs_avalible(struct rb_root *root);
+#ifndef __UBOOT__
+static void update_fastmap_work_fn(struct work_struct *wrk);
+#else
+void update_fastmap_work_fn(struct ubi_device *ubi);
+#endif
+static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root);
+static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi);
+static void ubi_fastmap_close(struct ubi_device *ubi);
+static inline void ubi_fastmap_init(struct ubi_device *ubi, int *count)
+{
+	/* Reserve enough LEBs to store two fastmaps. */
+	*count += (ubi->fm_size / ubi->leb_size) * 2;
+#ifndef __UBOOT__
+	INIT_WORK(&ubi->fm_work, update_fastmap_work_fn);
+#endif
+}
+static struct ubi_wl_entry *may_reserve_for_fm(struct ubi_device *ubi,
+					       struct ubi_wl_entry *e,
+					       struct rb_root *root);
+#else /* !CONFIG_MTD_UBI_FASTMAP */
+static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi);
+static inline void ubi_fastmap_close(struct ubi_device *ubi) { }
+static inline void ubi_fastmap_init(struct ubi_device *ubi, int *count) { }
+static struct ubi_wl_entry *may_reserve_for_fm(struct ubi_device *ubi,
+					       struct ubi_wl_entry *e,
+					       struct rb_root *root) {
+	return e;
+}
+#endif /* CONFIG_MTD_UBI_FASTMAP */
+#endif /* UBI_WL_H */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bbec6a6..a03a95d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -25,6 +25,15 @@
 
 if NETDEVICES
 
+config ALTERA_TSE
+	bool "Altera Triple-Speed Ethernet MAC support"
+	depends on DM_ETH
+	select PHYLIB
+	help
+	  This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
+	  Please find details on the "Triple-Speed Ethernet MegaCore Function
+	  Resource Center" of Altera.
+
 config E1000
 	bool "Intel PRO/1000 Gigabit Ethernet support"
 	help
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c
index ad3bd1e..319983c 100644
--- a/drivers/net/altera_tse.c
+++ b/drivers/net/altera_tse.c
@@ -8,91 +8,44 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <config.h>
 #include <common.h>
-#include <malloc.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdt_support.h>
+#include <memalign.h>
+#include <miiphy.h>
 #include <net.h>
-#include <command.h>
 #include <asm/cache.h>
 #include <asm/dma-mapping.h>
-#include <miiphy.h>
+#include <asm/io.h>
 #include "altera_tse.h"
 
-/* sgdma debug - print descriptor */
-static void alt_sgdma_print_desc(volatile struct alt_sgdma_descriptor *desc)
-{
-	debug("SGDMA DEBUG :\n");
-	debug("desc->source : 0x%x \n", (unsigned int)desc->source);
-	debug("desc->destination : 0x%x \n", (unsigned int)desc->destination);
-	debug("desc->next : 0x%x \n", (unsigned int)desc->next);
-	debug("desc->source_pad : 0x%x \n", (unsigned int)desc->source_pad);
-	debug("desc->destination_pad : 0x%x \n",
-	      (unsigned int)desc->destination_pad);
-	debug("desc->next_pad : 0x%x \n", (unsigned int)desc->next_pad);
-	debug("desc->bytes_to_transfer : 0x%x \n",
-	      (unsigned int)desc->bytes_to_transfer);
-	debug("desc->actual_bytes_transferred : 0x%x \n",
-	      (unsigned int)desc->actual_bytes_transferred);
-	debug("desc->descriptor_status : 0x%x \n",
-	      (unsigned int)desc->descriptor_status);
-	debug("desc->descriptor_control : 0x%x \n",
-	      (unsigned int)desc->descriptor_control);
-}
+DECLARE_GLOBAL_DATA_PTR;
 
-/* This is a generic routine that the SGDMA mode-specific routines
- * call to populate a descriptor.
- * arg1	    :pointer to first SGDMA descriptor.
- * arg2	    :pointer to next  SGDMA descriptor.
- * arg3	    :Address to where data to be written.
- * arg4	    :Address from where data to be read.
- * arg5	    :no of byte to transaction.
- * arg6	    :variable indicating to generate start of packet or not
- * arg7	    :read fixed
- * arg8	    :write fixed
- * arg9	    :read burst
- * arg10    :write burst
- * arg11    :atlantic_channel number
- */
-static void alt_sgdma_construct_descriptor_burst(
-	volatile struct alt_sgdma_descriptor *desc,
-	volatile struct alt_sgdma_descriptor *next,
-	unsigned int *read_addr,
-	unsigned int *write_addr,
+static inline void alt_sgdma_construct_descriptor(
+	struct alt_sgdma_descriptor *desc,
+	struct alt_sgdma_descriptor *next,
+	void *read_addr,
+	void *write_addr,
 	unsigned short length_or_eop,
 	int generate_eop,
 	int read_fixed,
-	int write_fixed_or_sop,
-	int read_burst,
-	int write_burst,
-	unsigned char atlantic_channel)
+	int write_fixed_or_sop)
 {
+	unsigned char val;
+
 	/*
 	 * Mark the "next" descriptor as "not" owned by hardware. This prevents
-	 * The SGDMA controller from continuing to process the chain. This is
-	 * done as a single IO write to bypass cache, without flushing
-	 * the entire descriptor, since only the 8-bit descriptor status must
-	 * be flushed.
+	 * The SGDMA controller from continuing to process the chain.
 	 */
-	if (!next)
-		debug("Next descriptor not defined!!\n");
+	next->descriptor_control = next->descriptor_control &
+		~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK;
 
-	next->descriptor_control = (next->descriptor_control &
-		~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK);
-
-	desc->source = (unsigned int *)((unsigned int)read_addr & 0x1FFFFFFF);
-	desc->destination =
-	    (unsigned int *)((unsigned int)write_addr & 0x1FFFFFFF);
-	desc->next = (unsigned int *)((unsigned int)next & 0x1FFFFFFF);
-	desc->source_pad = 0x0;
-	desc->destination_pad = 0x0;
-	desc->next_pad = 0x0;
+	memset(desc, 0, sizeof(struct alt_sgdma_descriptor));
+	desc->source = virt_to_phys(read_addr);
+	desc->destination = virt_to_phys(write_addr);
+	desc->next = virt_to_phys(next);
 	desc->bytes_to_transfer = length_or_eop;
-	desc->actual_bytes_transferred = 0;
-	desc->descriptor_status = 0x0;
-
-	/* SGDMA burst not currently supported */
-	desc->read_burst = 0;
-	desc->write_burst = 0;
 
 	/*
 	 * Set the descriptor control block as follows:
@@ -108,108 +61,49 @@
 	 * pointing at this descriptor, it will not run (via the "owned by
 	 * hardware" bit) until all other descriptor has been set up.
 	 */
-
-	desc->descriptor_control =
-	    ((ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) |
-	     (generate_eop ?
-	      ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0x0) |
-	     (read_fixed ?
-	      ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0x0) |
-	     (write_fixed_or_sop ?
-	      ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0x0) |
-	     (atlantic_channel ? ((atlantic_channel & 0x0F) << 3) : 0)
-		    );
+	val = ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK;
+	if (generate_eop)
+		val |= ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK;
+	if (read_fixed)
+		val |= ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK;
+	if (write_fixed_or_sop)
+		val |= ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK;
+	desc->descriptor_control = val;
 }
 
-static int alt_sgdma_do_sync_transfer(volatile struct alt_sgdma_registers *dev,
-			       volatile struct alt_sgdma_descriptor *desc)
+static int alt_sgdma_wait_transfer(struct alt_sgdma_registers *regs)
 {
-	unsigned int status;
-	int counter = 0;
-
-	/* Wait for any pending transfers to complete */
-	alt_sgdma_print_desc(desc);
-	status = dev->status;
-
-	counter = 0;
-	while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) {
-		if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
-			break;
-	}
-
-	if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
-		debug("Timeout waiting sgdma in do sync!\n");
-
-	/*
-	 * Clear any (previous) status register information
-	 * that might occlude our error checking later.
-	 */
-	dev->status = 0xFF;
-
-	/* Point the controller at the descriptor */
-	dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF;
-	debug("next desc in sgdma 0x%x\n",
-	      (unsigned int)dev->next_descriptor_pointer);
-
-	/*
-	 * Set up SGDMA controller to:
-	 * - Disable interrupt generation
-	 * - Run once a valid descriptor is written to controller
-	 * - Stop on an error with any particular descriptor
-	 */
-	dev->control = (ALT_SGDMA_CONTROL_RUN_MSK |
-			ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK);
+	int status;
+	ulong ctime;
 
 	/* Wait for the descriptor (chain) to complete */
-	status = dev->status;
-	debug("wait for sgdma....");
-	while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK)
-		;
-	debug("done\n");
-
-	/* Clear Run */
-	dev->control = (dev->control & (~ALT_SGDMA_CONTROL_RUN_MSK));
-
-	/* Get & clear status register contents */
-	status = dev->status;
-	dev->status = 0xFF;
-
-	/* we really should check if the transfer completes properly */
-	debug("tx sgdma status = 0x%x", status);
-	return 0;
-}
-
-static int alt_sgdma_do_async_transfer(volatile struct alt_sgdma_registers *dev,
-				volatile struct alt_sgdma_descriptor *desc)
-{
-	int counter = 0;
-
-	/* Wait for any pending transfers to complete */
-	alt_sgdma_print_desc(desc);
-
-	counter = 0;
-	while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) {
-		if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
+	ctime = get_timer(0);
+	while (1) {
+		status = readl(&regs->status);
+		if (!(status & ALT_SGDMA_STATUS_BUSY_MSK))
 			break;
+		if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) {
+			status = -ETIMEDOUT;
+			debug("sgdma timeout\n");
+			break;
+		}
 	}
 
-	if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
-		debug("Timeout waiting sgdma in do async!\n");
+	/* Clear Run */
+	writel(0, &regs->control);
+	/* Clear status */
+	writel(0xff, &regs->status);
 
-	/*
-	 * Clear the RUN bit in the control register. This is needed
-	 * to restart the SGDMA engine later on.
-	 */
-	dev->control = 0;
+	return status;
+}
 
-	/*
-	 * Clear any (previous) status register information
-	 * that might occlude our error checking later.
-	 */
-	dev->status = 0xFF;
+static int alt_sgdma_start_transfer(struct alt_sgdma_registers *regs,
+				    struct alt_sgdma_descriptor *desc)
+{
+	unsigned int val;
 
 	/* Point the controller at the descriptor */
-	dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF;
+	writel(virt_to_phys(desc), &regs->next_descriptor_pointer);
 
 	/*
 	 * Set up SGDMA controller to:
@@ -217,26 +111,31 @@
 	 * - Run once a valid descriptor is written to controller
 	 * - Stop on an error with any particular descriptor
 	 */
-	dev->control = (ALT_SGDMA_CONTROL_RUN_MSK |
-			ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK);
+	val = ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK;
+	writel(val, &regs->control);
 
-	/* we really should check if the transfer completes properly */
 	return 0;
 }
 
-/* u-boot interface */
-static int tse_adjust_link(struct altera_tse_priv *priv)
+static void tse_adjust_link(struct altera_tse_priv *priv,
+			    struct phy_device *phydev)
 {
+	struct alt_tse_mac *mac_dev = priv->mac_dev;
 	unsigned int refvar;
 
-	refvar = priv->mac_dev->command_config.image;
+	if (!phydev->link) {
+		debug("%s: No link.\n", phydev->dev->name);
+		return;
+	}
 
-	if (!(priv->duplexity))
+	refvar = readl(&mac_dev->command_config);
+
+	if (phydev->duplex)
 		refvar |= ALTERA_TSE_CMD_HD_ENA_MSK;
 	else
 		refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK;
 
-	switch (priv->speed) {
+	switch (phydev->speed) {
 	case 1000:
 		refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK;
 		refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK;
@@ -250,721 +149,383 @@
 		refvar |= ALTERA_TSE_CMD_ENA_10_MSK;
 		break;
 	}
-	priv->mac_dev->command_config.image = refvar;
-
-	return 0;
+	writel(refvar, &mac_dev->command_config);
 }
 
-static int tse_eth_send(struct eth_device *dev, void *packet, int length)
+static int altera_tse_send(struct udevice *dev, void *packet, int length)
 {
-	struct altera_tse_priv *priv = dev->priv;
-	volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
-	volatile struct alt_sgdma_descriptor *tx_desc =
-	    (volatile struct alt_sgdma_descriptor *)priv->tx_desc;
+	struct altera_tse_priv *priv = dev_get_priv(dev);
+	struct alt_sgdma_descriptor *tx_desc = priv->tx_desc;
+	unsigned long tx_buf = (unsigned long)packet;
 
-	volatile struct alt_sgdma_descriptor *tx_desc_cur =
-	    (volatile struct alt_sgdma_descriptor *)&tx_desc[0];
-
-	flush_dcache_range((unsigned long)packet,
-			(unsigned long)packet + length);
-	alt_sgdma_construct_descriptor_burst(
-		(volatile struct alt_sgdma_descriptor *)&tx_desc[0],
-		(volatile struct alt_sgdma_descriptor *)&tx_desc[1],
-		(unsigned int *)packet,	/* read addr */
-		(unsigned int *)0,
+	flush_dcache_range(tx_buf, tx_buf + length);
+	alt_sgdma_construct_descriptor(
+		tx_desc,
+		tx_desc + 1,
+		packet,	/* read addr */
+		NULL,	/* write addr */
 		length,	/* length or EOP ,will change for each tx */
-		0x1,	/* gen eop */
-		0x0,	/* read fixed */
-		0x1,	/* write fixed or sop */
-		0x0,	/* read burst */
-		0x0,	/* write burst */
-		0x0	/* channel */
+		1,	/* gen eop */
+		0,	/* read fixed */
+		1	/* write fixed or sop */
 		);
-	debug("TX Packet @ 0x%x,0x%x bytes", (unsigned int)packet, length);
 
 	/* send the packet */
-	debug("sending packet\n");
-	alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur);
-	debug("sent %d bytes\n", tx_desc_cur->actual_bytes_transferred);
-	return tx_desc_cur->actual_bytes_transferred;
+	alt_sgdma_start_transfer(priv->sgdma_tx, tx_desc);
+	alt_sgdma_wait_transfer(priv->sgdma_tx);
+	debug("sent %d bytes\n", tx_desc->actual_bytes_transferred);
+
+	return tx_desc->actual_bytes_transferred;
 }
 
-static int tse_eth_rx(struct eth_device *dev)
+static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp)
 {
-	int packet_length = 0;
-	struct altera_tse_priv *priv = dev->priv;
-	volatile struct alt_sgdma_descriptor *rx_desc =
-	    (volatile struct alt_sgdma_descriptor *)priv->rx_desc;
-	volatile struct alt_sgdma_descriptor *rx_desc_cur = &rx_desc[0];
+	struct altera_tse_priv *priv = dev_get_priv(dev);
+	struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
+	int packet_length;
 
-	if (rx_desc_cur->descriptor_status &
+	if (rx_desc->descriptor_status &
 	    ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) {
-		debug("got packet\n");
 		packet_length = rx_desc->actual_bytes_transferred;
-		net_process_received_packet(net_rx_packets[0], packet_length);
-
-		/* start descriptor again */
-		flush_dcache_range((unsigned long)(net_rx_packets[0]),
-				   (unsigned long)(net_rx_packets[0] +
-						   PKTSIZE_ALIGN));
-		alt_sgdma_construct_descriptor_burst(
-			(volatile struct alt_sgdma_descriptor *)&rx_desc[0],
-			(volatile struct alt_sgdma_descriptor *)&rx_desc[1],
-			(unsigned int)0x0,	/* read addr */
-			(unsigned int *)net_rx_packets[0],
-			0x0,	/* length or EOP */
-			0x0,	/* gen eop */
-			0x0,	/* read fixed */
-			0x0,	/* write fixed or sop */
-			0x0,	/* read burst */
-			0x0,	/* write burst */
-			0x0	/* channel */
-		    );
-
-		/* setup the sgdma */
-		alt_sgdma_do_async_transfer(priv->sgdma_rx, &rx_desc[0]);
+		debug("recv %d bytes\n", packet_length);
+		*packetp = priv->rx_buf;
 
 		return packet_length;
 	}
 
-	return -1;
+	return -EAGAIN;
 }
 
-static void tse_eth_halt(struct eth_device *dev)
+static int altera_tse_free_pkt(struct udevice *dev, uchar *packet,
+			       int length)
 {
-	/* don't do anything! */
-	/* this gets called after each uboot  */
-	/* network command.  don't need to reset the thing all of the time */
+	struct altera_tse_priv *priv = dev_get_priv(dev);
+	struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
+	unsigned long rx_buf = (unsigned long)priv->rx_buf;
+
+	alt_sgdma_wait_transfer(priv->sgdma_rx);
+	invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN);
+	alt_sgdma_construct_descriptor(
+		rx_desc,
+		rx_desc + 1,
+		NULL,	/* read addr */
+		priv->rx_buf, /* write addr */
+		0,	/* length or EOP */
+		0,	/* gen eop */
+		0,	/* read fixed */
+		0	/* write fixed or sop */
+		);
+
+	/* setup the sgdma */
+	alt_sgdma_start_transfer(priv->sgdma_rx, rx_desc);
+	debug("recv setup\n");
+
+	return 0;
 }
 
-static void tse_eth_reset(struct eth_device *dev)
+static void altera_tse_stop(struct udevice *dev)
 {
-	/* stop sgdmas, disable tse receive */
-	struct altera_tse_priv *priv = dev->priv;
-	volatile struct alt_tse_mac *mac_dev = priv->mac_dev;
-	volatile struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;
-	volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
-	int counter;
-	volatile struct alt_sgdma_descriptor *rx_desc =
-	    (volatile struct alt_sgdma_descriptor *)&priv->rx_desc[0];
+	struct altera_tse_priv *priv = dev_get_priv(dev);
+	struct alt_tse_mac *mac_dev = priv->mac_dev;
+	struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;
+	struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
+	struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
+	unsigned int status;
+	int ret;
+	ulong ctime;
 
 	/* clear rx desc & wait for sgdma to complete */
 	rx_desc->descriptor_control = 0;
-	rx_sgdma->control = 0;
-	counter = 0;
-	while (rx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) {
-		if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
-			break;
-	}
+	writel(0, &rx_sgdma->control);
+	ret = alt_sgdma_wait_transfer(rx_sgdma);
+	if (ret == -ETIMEDOUT)
+		writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK,
+		       &rx_sgdma->control);
 
-	if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) {
-		debug("Timeout waiting for rx sgdma!\n");
-		rx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
-		rx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
-	}
+	writel(0, &tx_sgdma->control);
+	ret = alt_sgdma_wait_transfer(tx_sgdma);
+	if (ret == -ETIMEDOUT)
+		writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK,
+		       &tx_sgdma->control);
 
-	counter = 0;
-	tx_sgdma->control = 0;
-	while (tx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) {
-		if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR)
-			break;
-	}
-
-	if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) {
-		debug("Timeout waiting for tx sgdma!\n");
-		tx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
-		tx_sgdma->control = ALT_SGDMA_CONTROL_SOFTWARERESET_MSK;
-	}
 	/* reset the mac */
-	mac_dev->command_config.bits.transmit_enable = 1;
-	mac_dev->command_config.bits.receive_enable = 1;
-	mac_dev->command_config.bits.software_reset = 1;
-
-	counter = 0;
-	while (mac_dev->command_config.bits.software_reset) {
-		if (counter++ > ALT_TSE_SW_RESET_WATCHDOG_CNTR)
+	writel(ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config);
+	ctime = get_timer(0);
+	while (1) {
+		status = readl(&mac_dev->command_config);
+		if (!(status & ALTERA_TSE_CMD_SW_RESET_MSK))
 			break;
-	}
-
-	if (counter >= ALT_TSE_SW_RESET_WATCHDOG_CNTR)
-		debug("TSEMAC SW reset bit never cleared!\n");
-}
-
-static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum)
-{
-	volatile struct alt_tse_mac *mac_dev;
-	unsigned int *mdio_regs;
-	unsigned int data;
-	u16 value;
-
-	mac_dev = priv->mac_dev;
-
-	/* set mdio address */
-	mac_dev->mdio_phy1_addr = priv->phyaddr;
-	mdio_regs = (unsigned int *)&mac_dev->mdio_phy1;
-
-	/* get the data */
-	data = mdio_regs[regnum];
-
-	value = data & 0xffff;
-
-	return value;
-}
-
-static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum,
-		   unsigned int value)
-{
-	volatile struct alt_tse_mac *mac_dev;
-	unsigned int *mdio_regs;
-	unsigned int data;
-
-	mac_dev = priv->mac_dev;
-
-	/* set mdio address */
-	mac_dev->mdio_phy1_addr = priv->phyaddr;
-	mdio_regs = (unsigned int *)&mac_dev->mdio_phy1;
-
-	/* get the data */
-	data = (unsigned int)value;
-
-	mdio_regs[regnum] = data;
-
-	return 0;
-}
-
-/* MDIO access to phy */
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII)
-static int altera_tse_miiphy_write(const char *devname, unsigned char addr,
-				   unsigned char reg, unsigned short value)
-{
-	struct eth_device *dev;
-	struct altera_tse_priv *priv;
-	dev = eth_get_dev_by_name(devname);
-	priv = dev->priv;
-
-	tse_mdio_write(priv, (uint) reg, (uint) value);
-
-	return 0;
-}
-
-static int altera_tse_miiphy_read(const char *devname, unsigned char addr,
-				  unsigned char reg, unsigned short *value)
-{
-	struct eth_device *dev;
-	struct altera_tse_priv *priv;
-	volatile struct alt_tse_mac *mac_dev;
-	unsigned int *mdio_regs;
-
-	dev = eth_get_dev_by_name(devname);
-	priv = dev->priv;
-
-	mac_dev = priv->mac_dev;
-	mac_dev->mdio_phy1_addr = (int)addr;
-	mdio_regs = (unsigned int *)&mac_dev->mdio_phy1;
-
-	*value = 0xffff & mdio_regs[reg];
-
-	return 0;
-
-}
-#endif
-
-/*
- * Also copied from tsec.c
- */
-/* Parse the status register for link, and then do
- * auto-negotiation
- */
-static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv)
-{
-	/*
-	 * Wait if the link is up, and autonegotiation is in progress
-	 * (ie - we're capable and it's not done)
-	 */
-	mii_reg = tse_mdio_read(priv, MIIM_STATUS);
-
-	if (!(mii_reg & MIIM_STATUS_LINK) && (mii_reg & BMSR_ANEGCAPABLE)
-	    && !(mii_reg & BMSR_ANEGCOMPLETE)) {
-		int i = 0;
-
-		puts("Waiting for PHY auto negotiation to complete");
-		while (!(mii_reg & BMSR_ANEGCOMPLETE)) {
-			/*
-			 * Timeout reached ?
-			 */
-			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
-				puts(" TIMEOUT !\n");
-				priv->link = 0;
-				return 0;
-			}
-
-			if ((i++ % 1000) == 0)
-				putc('.');
-			udelay(1000);	/* 1 ms */
-			mii_reg = tse_mdio_read(priv, MIIM_STATUS);
-		}
-		puts(" done\n");
-		priv->link = 1;
-		udelay(500000);	/* another 500 ms (results in faster booting) */
-	} else {
-		if (mii_reg & MIIM_STATUS_LINK) {
-			debug("Link is up\n");
-			priv->link = 1;
-		} else {
-			debug("Link is down\n");
-			priv->link = 0;
-		}
-	}
-
-	return 0;
-}
-
-/* Parse the 88E1011's status register for speed and duplex
- * information
- */
-static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv)
-{
-	uint speed;
-
-	mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS);
-
-	if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) &&
-	    !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
-		int i = 0;
-
-		puts("Waiting for PHY realtime link");
-		while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) {
-			/* Timeout reached ? */
-			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
-				puts(" TIMEOUT !\n");
-				priv->link = 0;
-				break;
-			}
-
-			if ((i++ == 1000) == 0) {
-				i = 0;
-				puts(".");
-			}
-			udelay(1000);	/* 1 ms */
-			mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS);
-		}
-		puts(" done\n");
-		udelay(500000);	/* another 500 ms (results in faster booting) */
-	} else {
-		if (mii_reg & MIIM_88E1011_PHYSTAT_LINK)
-			priv->link = 1;
-		else
-			priv->link = 0;
-	}
-
-	if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX)
-		priv->duplexity = 1;
-	else
-		priv->duplexity = 0;
-
-	speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED);
-
-	switch (speed) {
-	case MIIM_88E1011_PHYSTAT_GBIT:
-		priv->speed = 1000;
-		debug("PHY Speed is 1000Mbit\n");
-		break;
-	case MIIM_88E1011_PHYSTAT_100:
-		debug("PHY Speed is 100Mbit\n");
-		priv->speed = 100;
-		break;
-	default:
-		debug("PHY Speed is 10Mbit\n");
-		priv->speed = 10;
-	}
-
-	return 0;
-}
-
-static uint mii_m88e1111s_setmode_sr(uint mii_reg, struct altera_tse_priv *priv)
-{
-	uint mii_data = tse_mdio_read(priv, mii_reg);
-	mii_data &= 0xfff0;
-	if ((priv->flags >= 1) && (priv->flags <= 4))
-		mii_data |= 0xb;
-	else if (priv->flags == 5)
-		mii_data |= 0x4;
-
-	return mii_data;
-}
-
-static uint mii_m88e1111s_setmode_cr(uint mii_reg, struct altera_tse_priv *priv)
-{
-	uint mii_data = tse_mdio_read(priv, mii_reg);
-	mii_data &= ~0x82;
-	if ((priv->flags >= 1) && (priv->flags <= 4))
-		mii_data |= 0x82;
-
-	return mii_data;
-}
-
-/*
- * Returns which value to write to the control register.
- * For 10/100, the value is slightly different
- */
-static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv)
-{
-	return MIIM_CONTROL_INIT;
-}
-
-/*
- * PHY & MDIO code
- * Need to add SGMII stuff
- *
- */
-
-static struct phy_info phy_info_M88E1111S = {
-	0x01410cc,
-	"Marvell 88E1111S",
-	4,
-	(struct phy_cmd[]){	/* config */
-			   /* Reset and configure the PHY */
-			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
-			   {MIIM_88E1111_PHY_EXT_SR, 0x848f,
-			    &mii_m88e1111s_setmode_sr},
-			   /* Delay RGMII TX and RX */
-			   {MIIM_88E1111_PHY_EXT_CR, 0x0cd2,
-			    &mii_m88e1111s_setmode_cr},
-			   {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
-			   {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
-			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
-			   {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
-			   {miim_end,}
-			   },
-	(struct phy_cmd[]){	/* startup */
-			   /* Status is read once to clear old link state */
-			   {MIIM_STATUS, miim_read, NULL},
-			   /* Auto-negotiate */
-			   {MIIM_STATUS, miim_read, &mii_parse_sr},
-			   /* Read the status */
-			   {MIIM_88E1011_PHY_STATUS, miim_read,
-			    &mii_parse_88E1011_psr},
-			   {miim_end,}
-			   },
-	(struct phy_cmd[]){	/* shutdown */
-			   {miim_end,}
-			   },
-};
-
-/* a generic flavor.  */
-static struct phy_info phy_info_generic = {
-	0,
-	"Unknown/Generic PHY",
-	32,
-	(struct phy_cmd[]){	/* config */
-			   {MII_BMCR, BMCR_RESET, NULL},
-			   {MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART, NULL},
-			   {miim_end,}
-			   },
-	(struct phy_cmd[]){	/* startup */
-			   {MII_BMSR, miim_read, NULL},
-			   {MII_BMSR, miim_read, &mii_parse_sr},
-			   {miim_end,}
-			   },
-	(struct phy_cmd[]){	/* shutdown */
-			   {miim_end,}
-			   }
-};
-
-static struct phy_info *phy_info[] = {
-	&phy_info_M88E1111S,
-	NULL
-};
-
- /* Grab the identifier of the device's PHY, and search through
-  * all of the known PHYs to see if one matches.	 If so, return
-  * it, if not, return NULL
-  */
-static struct phy_info *get_phy_info(struct eth_device *dev)
-{
-	struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv;
-	uint phy_reg, phy_ID;
-	int i;
-	struct phy_info *theInfo = NULL;
-
-	/* Grab the bits from PHYIR1, and put them in the upper half */
-	phy_reg = tse_mdio_read(priv, MIIM_PHYIR1);
-	phy_ID = (phy_reg & 0xffff) << 16;
-
-	/* Grab the bits from PHYIR2, and put them in the lower half */
-	phy_reg = tse_mdio_read(priv, MIIM_PHYIR2);
-	phy_ID |= (phy_reg & 0xffff);
-
-	/* loop through all the known PHY types, and find one that */
-	/* matches the ID we read from the PHY. */
-	for (i = 0; phy_info[i]; i++) {
-		if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) {
-			theInfo = phy_info[i];
+		if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) {
+			debug("Reset mac timeout\n");
 			break;
 		}
 	}
-
-	if (theInfo == NULL) {
-		theInfo = &phy_info_generic;
-		debug("%s: No support for PHY id %x; assuming generic\n",
-		      dev->name, phy_ID);
-	} else
-		debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
-
-	return theInfo;
 }
 
-/* Execute the given series of commands on the given device's
- * PHY, running functions as necessary
- */
-static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd)
+static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 {
-	int i;
-	uint result;
+	struct altera_tse_priv *priv = bus->priv;
+	struct alt_tse_mac *mac_dev = priv->mac_dev;
+	unsigned int value;
 
-	for (i = 0; cmd->mii_reg != miim_end; i++) {
-		if (cmd->mii_data == miim_read) {
-			result = tse_mdio_read(priv, cmd->mii_reg);
+	/* set mdio address */
+	writel(addr, &mac_dev->mdio_phy1_addr);
+	/* get the data */
+	value = readl(&mac_dev->mdio_phy1[reg]);
 
-			if (cmd->funct != NULL)
-				(*(cmd->funct)) (result, priv);
-
-		} else {
-			if (cmd->funct != NULL)
-				result = (*(cmd->funct)) (cmd->mii_reg, priv);
-			else
-				result = cmd->mii_data;
-
-			tse_mdio_write(priv, cmd->mii_reg, result);
-
-		}
-		cmd++;
-	}
+	return value & 0xffff;
 }
 
-/* Phy init code */
-static int init_phy(struct eth_device *dev)
+static int tse_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+			  u16 val)
 {
-	struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv;
-	struct phy_info *curphy;
+	struct altera_tse_priv *priv = bus->priv;
+	struct alt_tse_mac *mac_dev = priv->mac_dev;
 
-	/* Get the cmd structure corresponding to the attached
-	 * PHY */
-	curphy = get_phy_info(dev);
+	/* set mdio address */
+	writel(addr, &mac_dev->mdio_phy1_addr);
+	/* set the data */
+	writel(val, &mac_dev->mdio_phy1[reg]);
 
-	if (curphy == NULL) {
-		priv->phyinfo = NULL;
-		debug("%s: No PHY found\n", dev->name);
-
-		return 0;
-	} else
-		debug("%s found\n", curphy->name);
-	priv->phyinfo = curphy;
-
-	phy_run_commands(priv, priv->phyinfo->config);
-
-	return 1;
-}
-
-static int tse_set_mac_address(struct eth_device *dev)
-{
-	struct altera_tse_priv *priv = dev->priv;
-	volatile struct alt_tse_mac *mac_dev = priv->mac_dev;
-
-	debug("Setting MAC address to 0x%02x%02x%02x%02x%02x%02x\n",
-	      dev->enetaddr[5], dev->enetaddr[4],
-	      dev->enetaddr[3], dev->enetaddr[2],
-	      dev->enetaddr[1], dev->enetaddr[0]);
-	mac_dev->mac_addr_0 = ((dev->enetaddr[3]) << 24 |
-			       (dev->enetaddr[2]) << 16 |
-			       (dev->enetaddr[1]) << 8 | (dev->enetaddr[0]));
-
-	mac_dev->mac_addr_1 = ((dev->enetaddr[5] << 8 |
-				(dev->enetaddr[4])) & 0xFFFF);
-
-	/* Set the MAC address */
-	mac_dev->supp_mac_addr_0_0 = mac_dev->mac_addr_0;
-	mac_dev->supp_mac_addr_0_1 = mac_dev->mac_addr_1;
-
-	/* Set the MAC address */
-	mac_dev->supp_mac_addr_1_0 = mac_dev->mac_addr_0;
-	mac_dev->supp_mac_addr_1_1 = mac_dev->mac_addr_1;
-
-	/* Set the MAC address */
-	mac_dev->supp_mac_addr_2_0 = mac_dev->mac_addr_0;
-	mac_dev->supp_mac_addr_2_1 = mac_dev->mac_addr_1;
-
-	/* Set the MAC address */
-	mac_dev->supp_mac_addr_3_0 = mac_dev->mac_addr_0;
-	mac_dev->supp_mac_addr_3_1 = mac_dev->mac_addr_1;
 	return 0;
 }
 
-static int tse_eth_init(struct eth_device *dev, bd_t * bd)
+static int tse_mdio_init(const char *name, struct altera_tse_priv *priv)
 {
-	int dat;
-	struct altera_tse_priv *priv = dev->priv;
-	volatile struct alt_tse_mac *mac_dev = priv->mac_dev;
-	volatile struct alt_sgdma_descriptor *tx_desc = priv->tx_desc;
-	volatile struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
-	volatile struct alt_sgdma_descriptor *rx_desc_cur =
-	    (volatile struct alt_sgdma_descriptor *)&rx_desc[0];
+	struct mii_dev *bus = mdio_alloc();
 
-	/* stop controller */
-	debug("Reseting TSE & SGDMAs\n");
-	tse_eth_reset(dev);
+	if (!bus) {
+		printf("Failed to allocate MDIO bus\n");
+		return -ENOMEM;
+	}
 
-	/* start the phy */
-	debug("Configuring PHY\n");
-	phy_run_commands(priv, priv->phyinfo->startup);
+	bus->read = tse_mdio_read;
+	bus->write = tse_mdio_write;
+	snprintf(bus->name, sizeof(bus->name), name);
+
+	bus->priv = (void *)priv;
+
+	return mdio_register(bus);
+}
+
+static int tse_phy_init(struct altera_tse_priv *priv, void *dev)
+{
+	struct phy_device *phydev;
+	unsigned int mask = 0xffffffff;
+
+	if (priv->phyaddr)
+		mask = 1 << priv->phyaddr;
+
+	phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
+	if (!phydev)
+		return -ENODEV;
+
+	phy_connect_dev(phydev, dev);
+
+	phydev->supported &= PHY_GBIT_FEATURES;
+	phydev->advertising = phydev->supported;
+
+	priv->phydev = phydev;
+	phy_config(phydev);
+
+	return 0;
+}
+
+static int altera_tse_write_hwaddr(struct udevice *dev)
+{
+	struct altera_tse_priv *priv = dev_get_priv(dev);
+	struct alt_tse_mac *mac_dev = priv->mac_dev;
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	u8 *hwaddr = pdata->enetaddr;
+	unsigned int mac_lo, mac_hi;
+
+	mac_lo = (hwaddr[3] << 24) | (hwaddr[2] << 16) |
+		(hwaddr[1] << 8) | hwaddr[0];
+	mac_hi = (hwaddr[5] << 8) | hwaddr[4];
+	debug("Set MAC address to 0x%04x%08x\n", mac_hi, mac_lo);
+
+	writel(mac_lo, &mac_dev->mac_addr_0);
+	writel(mac_hi, &mac_dev->mac_addr_1);
+	writel(mac_lo, &mac_dev->supp_mac_addr_0_0);
+	writel(mac_hi, &mac_dev->supp_mac_addr_0_1);
+	writel(mac_lo, &mac_dev->supp_mac_addr_1_0);
+	writel(mac_hi, &mac_dev->supp_mac_addr_1_1);
+	writel(mac_lo, &mac_dev->supp_mac_addr_2_0);
+	writel(mac_hi, &mac_dev->supp_mac_addr_2_1);
+	writel(mac_lo, &mac_dev->supp_mac_addr_3_0);
+	writel(mac_hi, &mac_dev->supp_mac_addr_3_1);
+
+	return 0;
+}
+
+static int altera_tse_start(struct udevice *dev)
+{
+	struct altera_tse_priv *priv = dev_get_priv(dev);
+	struct alt_tse_mac *mac_dev = priv->mac_dev;
+	unsigned int val;
+	int ret;
 
 	/* need to create sgdma */
-	debug("Configuring tx desc\n");
-	alt_sgdma_construct_descriptor_burst(
-		(volatile struct alt_sgdma_descriptor *)&tx_desc[0],
-		(volatile struct alt_sgdma_descriptor *)&tx_desc[1],
-		(unsigned int *)NULL,	/* read addr */
-		(unsigned int *)0,
-		0,	/* length or EOP ,will change for each tx */
-		0x1,	/* gen eop */
-		0x0,	/* read fixed */
-		0x1,	/* write fixed or sop */
-		0x0,	/* read burst */
-		0x0,	/* write burst */
-		0x0	/* channel */
-		);
 	debug("Configuring rx desc\n");
-	flush_dcache_range((unsigned long)(net_rx_packets[0]),
-			   (unsigned long)(net_rx_packets[0]) + PKTSIZE_ALIGN);
-	alt_sgdma_construct_descriptor_burst(
-		(volatile struct alt_sgdma_descriptor *)&rx_desc[0],
-		(volatile struct alt_sgdma_descriptor *)&rx_desc[1],
-		(unsigned int)0x0,	/* read addr */
-		(unsigned int *)net_rx_packets[0],
-		0x0,	/* length or EOP */
-		0x0,	/* gen eop */
-		0x0,	/* read fixed */
-		0x0,	/* write fixed or sop */
-		0x0,	/* read burst */
-		0x0,	/* write burst */
-		0x0	/* channel */
-		);
-	/* start rx async transfer */
-	debug("Starting rx sgdma\n");
-	alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur);
-
+	altera_tse_free_pkt(dev, priv->rx_buf, PKTSIZE_ALIGN);
 	/* start TSE */
 	debug("Configuring TSE Mac\n");
 	/* Initialize MAC registers */
-	mac_dev->max_frame_length = PKTSIZE_ALIGN;
-	mac_dev->rx_almost_empty_threshold = 8;
-	mac_dev->rx_almost_full_threshold = 8;
-	mac_dev->tx_almost_empty_threshold = 8;
-	mac_dev->tx_almost_full_threshold = 3;
-	mac_dev->tx_sel_empty_threshold =
-	    CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16;
-	mac_dev->tx_sel_full_threshold = 0;
-	mac_dev->rx_sel_empty_threshold =
-	    CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16;
-	mac_dev->rx_sel_full_threshold = 0;
+	writel(PKTSIZE_ALIGN, &mac_dev->max_frame_length);
+	writel(priv->rx_fifo_depth - 16, &mac_dev->rx_sel_empty_threshold);
+	writel(0, &mac_dev->rx_sel_full_threshold);
+	writel(priv->tx_fifo_depth - 16, &mac_dev->tx_sel_empty_threshold);
+	writel(0, &mac_dev->tx_sel_full_threshold);
+	writel(8, &mac_dev->rx_almost_empty_threshold);
+	writel(8, &mac_dev->rx_almost_full_threshold);
+	writel(8, &mac_dev->tx_almost_empty_threshold);
+	writel(3, &mac_dev->tx_almost_full_threshold);
 
 	/* NO Shift */
-	mac_dev->rx_cmd_stat.bits.rx_shift16 = 0;
-	mac_dev->tx_cmd_stat.bits.tx_shift16 = 0;
+	writel(0, &mac_dev->rx_cmd_stat);
+	writel(0, &mac_dev->tx_cmd_stat);
 
 	/* enable MAC */
-	dat = 0;
-	dat = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK;
+	val = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK;
+	writel(val, &mac_dev->command_config);
 
-	mac_dev->command_config.image = dat;
-
-	/* configure the TSE core  */
-	/*  -- output clocks,  */
-	/*  -- and later config stuff for SGMII */
-	if (priv->link) {
-		debug("Adjusting TSE to link speed\n");
-		tse_adjust_link(priv);
+	/* Start up the PHY */
+	ret = phy_startup(priv->phydev);
+	if (ret) {
+		debug("Could not initialize PHY %s\n",
+		      priv->phydev->dev->name);
+		return ret;
 	}
 
-	return priv->link ? 0 : -1;
+	tse_adjust_link(priv, priv->phydev);
+
+	if (!priv->phydev->link)
+		return -EIO;
+
+	return 0;
 }
 
-/* TSE init code */
-int altera_tse_initialize(u8 dev_num, int mac_base,
-			  int sgdma_rx_base, int sgdma_tx_base,
-			  u32 sgdma_desc_base, u32 sgdma_desc_size)
+static int altera_tse_probe(struct udevice *dev)
 {
-	struct altera_tse_priv *priv;
-	struct eth_device *dev;
-	struct alt_sgdma_descriptor *rx_desc;
-	struct alt_sgdma_descriptor *tx_desc;
-	unsigned long dma_handle;
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct altera_tse_priv *priv = dev_get_priv(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	const char *list, *end;
+	const fdt32_t *cell;
+	void *base, *desc_mem = NULL;
+	unsigned long addr, size;
+	int len, idx;
+	int ret;
 
-	dev = (struct eth_device *)malloc(sizeof *dev);
-
-	if (NULL == dev)
-		return 0;
-
-	memset(dev, 0, sizeof *dev);
-
-	priv = malloc(sizeof(*priv));
-
-	if (!priv) {
-		free(dev);
-		return 0;
+	/*
+	 * decode regs, assume address-cells and size-cells are both one.
+	 * there are multiple reg tuples, and they need to match with
+	 * reg-names.
+	 */
+	list = fdt_getprop(blob, node, "reg-names", &len);
+	if (!list)
+		return -ENOENT;
+	end = list + len;
+	cell = fdt_getprop(blob, node, "reg", &len);
+	if (!cell)
+		return -ENOENT;
+	idx = 0;
+	while (list < end) {
+		addr = fdt_translate_address((void *)blob,
+					     node, cell + idx);
+		size = fdt_addr_to_cpu(cell[idx + 1]);
+		base = ioremap(addr, size);
+		len = strlen(list);
+		if (strcmp(list, "control_port") == 0)
+			priv->mac_dev = base;
+		else if (strcmp(list, "rx_csr") == 0)
+			priv->sgdma_rx = base;
+		else if (strcmp(list, "tx_csr") == 0)
+			priv->sgdma_tx = base;
+		else if (strcmp(list, "s1") == 0)
+			desc_mem = base;
+		idx += 2;
+		list += (len + 1);
 	}
-	if (sgdma_desc_size) {
-		if (sgdma_desc_size < (sizeof(*tx_desc) * (3 + PKTBUFSRX))) {
-			printf("ALTERA_TSE-%hu: "
-			       "descriptor memory is too small\n", dev_num);
-			free(priv);
-			free(dev);
-			return 0;
-		}
-		tx_desc = (struct alt_sgdma_descriptor *)sgdma_desc_base;
-	} else {
-		tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX),
-					     &dma_handle);
+	/* decode fifo depth */
+	priv->rx_fifo_depth = fdtdec_get_int(blob, node,
+		"rx-fifo-depth", 0);
+	priv->tx_fifo_depth = fdtdec_get_int(blob, node,
+		"tx-fifo-depth", 0);
+	/* decode phy */
+	addr = fdtdec_get_int(blob, node,
+			      "phy-handle", 0);
+	addr = fdt_node_offset_by_phandle(blob, addr);
+	priv->phyaddr = fdtdec_get_int(blob, addr,
+		"reg", 0);
+	/* init desc */
+	len = sizeof(struct alt_sgdma_descriptor) * 4;
+	if (!desc_mem) {
+		desc_mem = dma_alloc_coherent(len, &addr);
+		if (!desc_mem)
+			return -ENOMEM;
 	}
+	memset(desc_mem, 0, len);
+	priv->tx_desc = desc_mem;
+	priv->rx_desc = priv->tx_desc + 2;
+	/* allocate recv packet buffer */
+	priv->rx_buf = malloc_cache_aligned(PKTSIZE_ALIGN);
+	if (!priv->rx_buf)
+		return -ENOMEM;
 
-	rx_desc = tx_desc + 2;
-	debug("tx desc: address = 0x%x\n", (unsigned int)tx_desc);
-	debug("rx desc: address = 0x%x\n", (unsigned int)rx_desc);
+	/* stop controller */
+	debug("Reset TSE & SGDMAs\n");
+	altera_tse_stop(dev);
 
-	if (!tx_desc) {
-		free(priv);
-		free(dev);
-		return 0;
-	}
-	memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1));
-	memset(tx_desc, 0, (sizeof *tx_desc) * 2);
+	/* start the phy */
+	priv->interface = pdata->phy_interface;
+	tse_mdio_init(dev->name, priv);
+	priv->bus = miiphy_get_dev_by_name(dev->name);
 
-	/* initialize tse priv */
-	priv->mac_dev = (volatile struct alt_tse_mac *)mac_base;
-	priv->sgdma_rx = (volatile struct alt_sgdma_registers *)sgdma_rx_base;
-	priv->sgdma_tx = (volatile struct alt_sgdma_registers *)sgdma_tx_base;
-	priv->phyaddr = CONFIG_SYS_ALTERA_TSE_PHY_ADDR;
-	priv->flags = CONFIG_SYS_ALTERA_TSE_FLAGS;
-	priv->rx_desc = rx_desc;
-	priv->tx_desc = tx_desc;
+	ret = tse_phy_init(priv, dev);
 
-	/* init eth structure */
-	dev->priv = priv;
-	dev->init = tse_eth_init;
-	dev->halt = tse_eth_halt;
-	dev->send = tse_eth_send;
-	dev->recv = tse_eth_rx;
-	dev->write_hwaddr = tse_set_mac_address;
-	sprintf(dev->name, "%s-%hu", "ALTERA_TSE", dev_num);
-
-	eth_register(dev);
-
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII)
-	miiphy_register(dev->name, altera_tse_miiphy_read,
-			altera_tse_miiphy_write);
-#endif
-
-	init_phy(dev);
-
-	return 1;
+	return ret;
 }
+
+static int altera_tse_ofdata_to_platdata(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	const char *phy_mode;
+
+	pdata->phy_interface = -1;
+	phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == -1) {
+		debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct eth_ops altera_tse_ops = {
+	.start		= altera_tse_start,
+	.send		= altera_tse_send,
+	.recv		= altera_tse_recv,
+	.free_pkt	= altera_tse_free_pkt,
+	.stop		= altera_tse_stop,
+	.write_hwaddr	= altera_tse_write_hwaddr,
+};
+
+static const struct udevice_id altera_tse_ids[] = {
+	{ .compatible = "altr,tse-1.0", },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_tse) = {
+	.name	= "altera_tse",
+	.id	= UCLASS_ETH,
+	.of_match = altera_tse_ids,
+	.ops	= &altera_tse_ops,
+	.ofdata_to_platdata = altera_tse_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct altera_tse_priv),
+	.probe	= altera_tse_probe,
+};
diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h
index 8880bfc..08c4f66 100644
--- a/drivers/net/altera_tse.h
+++ b/drivers/net/altera_tse.h
@@ -13,102 +13,6 @@
 
 #define __packed_1_    __attribute__ ((packed, aligned(1)))
 
-/* PHY Stuff */
-#define miim_end -2
-#define miim_read -1
-
-#define PHY_AUTONEGOTIATE_TIMEOUT	5000	/* in ms */
-
-#ifndef CONFIG_SYS_TBIPA_VALUE
-#define CONFIG_SYS_TBIPA_VALUE	0x1f
-#endif
-#define MIIMCFG_INIT_VALUE	0x00000003
-#define MIIMCFG_RESET		0x80000000
-
-#define MIIMIND_BUSY		0x00000001
-#define MIIMIND_NOTVALID	0x00000004
-
-#define MIIM_CONTROL		0x00
-#define MIIM_CONTROL_RESET	0x00009140
-#define MIIM_CONTROL_INIT	0x00001140
-#define MIIM_CONTROL_RESTART	0x00001340
-#define MIIM_ANEN		0x00001000
-
-#define MIIM_CR		0x00
-#define MIIM_CR_RST		0x00008000
-#define MIIM_CR_INIT		0x00001000
-
-#define MIIM_STATUS		0x1
-#define MIIM_STATUS_AN_DONE	0x00000020
-#define MIIM_STATUS_LINK	0x0004
-
-#define MIIM_PHYIR1		0x2
-#define MIIM_PHYIR2		0x3
-
-#define MIIM_ANAR		0x4
-#define MIIM_ANAR_INIT		0x1e1
-
-#define MIIM_TBI_ANLPBPA	0x5
-#define MIIM_TBI_ANLPBPA_HALF	0x00000040
-#define MIIM_TBI_ANLPBPA_FULL	0x00000020
-
-#define MIIM_TBI_ANEX		0x6
-#define MIIM_TBI_ANEX_NP	0x00000004
-#define MIIM_TBI_ANEX_PRX	0x00000002
-
-#define MIIM_GBIT_CONTROL	0x9
-#define MIIM_GBIT_CONTROL_INIT	0xe00
-
-#define MIIM_EXT_PAGE_ACCESS	0x1f
-
-/* 88E1011 PHY Status Register */
-#define MIIM_88E1011_PHY_STATUS	0x11
-#define MIIM_88E1011_PHYSTAT_SPEED	0xc000
-#define MIIM_88E1011_PHYSTAT_GBIT	0x8000
-#define MIIM_88E1011_PHYSTAT_100	0x4000
-#define MIIM_88E1011_PHYSTAT_DUPLEX	0x2000
-#define MIIM_88E1011_PHYSTAT_SPDDONE	0x0800
-#define MIIM_88E1011_PHYSTAT_LINK	0x0400
-
-#define MIIM_88E1011_PHY_SCR		0x10
-#define MIIM_88E1011_PHY_MDI_X_AUTO	0x0060
-
-#define MIIM_88E1111_PHY_EXT_CR	0x14
-#define MIIM_88E1111_PHY_EXT_SR	0x1b
-
-/* 88E1111 PHY LED Control Register */
-#define MIIM_88E1111_PHY_LED_CONTROL	24
-#define MIIM_88E1111_PHY_LED_DIRECT	0x4100
-#define MIIM_88E1111_PHY_LED_COMBINE	0x411C
-
-#define MIIM_READ_COMMAND	0x00000001
-
-/* struct phy_info: a structure which defines attributes for a PHY
- * id will contain a number which represents the PHY.  During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is.  The 32-bit result
- * gotten from the PHY will be shifted right by "shift" bits to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * The struct phy_cmd entries represent pointers to an arrays of
- * commands which tell the driver what to do to the PHY.
- */
-struct phy_info {
-	uint id;
-	char *name;
-	uint shift;
-	/* Called to configure the PHY, and modify the controller
-	 * based on the results */
-	struct phy_cmd *config;
-
-	/* Called when starting up the controller */
-	struct phy_cmd *startup;
-
-	/* Called when bringing down the controller */
-	struct phy_cmd *shutdown;
-};
-
 /* SGDMA Stuff */
 #define ALT_SGDMA_STATUS_ERROR_MSK			(0x00000001)
 #define ALT_SGDMA_STATUS_EOP_ENCOUNTERED_MSK		(0x00000002)
@@ -116,18 +20,9 @@
 #define ALT_SGDMA_STATUS_CHAIN_COMPLETED_MSK		(0x00000008)
 #define ALT_SGDMA_STATUS_BUSY_MSK			(0x00000010)
 
-#define ALT_SGDMA_CONTROL_IE_ERROR_MSK			(0x00000001)
-#define ALT_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK	(0x00000002)
-#define ALT_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK	(0x00000004)
-#define ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK	(0x00000008)
-#define ALT_SGDMA_CONTROL_IE_GLOBAL_MSK		(0x00000010)
 #define ALT_SGDMA_CONTROL_RUN_MSK			(0x00000020)
 #define ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK		(0x00000040)
-#define ALT_SGDMA_CONTROL_IE_MAX_DESC_PROCESSED_MSK	(0x00000080)
-#define ALT_SGDMA_CONTROL_MAX_DESC_PROCESSED_MSK	(0x0000FF00)
 #define ALT_SGDMA_CONTROL_SOFTWARERESET_MSK		(0x00010000)
-#define ALT_SGDMA_CONTROL_PARK_MSK			(0x00020000)
-#define ALT_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK		(0x80000000)
 
 #define ALTERA_TSE_SGDMA_INTR_MASK  (ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK \
 			| ALT_SGDMA_STATUS_DESC_COMPLETED_MSK \
@@ -176,13 +71,13 @@
  *
  */
 struct alt_sgdma_descriptor {
-	unsigned int *source;	/* the address of data to be read. */
+	unsigned int source;	/* the address of data to be read. */
 	unsigned int source_pad;
 
-	unsigned int *destination;	/* the address to write data */
+	unsigned int destination;	/* the address to write data */
 	unsigned int destination_pad;
 
-	unsigned int *next;	/* the next descriptor in the list. */
+	unsigned int next;	/* the next descriptor in the list. */
 	unsigned int next_pad;
 
 	unsigned short bytes_to_transfer; /* the number of bytes to transfer */
@@ -241,112 +136,15 @@
 
 #define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16	(0x02000000)
 
-#define ALT_TSE_SW_RESET_WATCHDOG_CNTR		10000
-#define ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR	90000000
-
-/* Command_Config Register Bit Definitions */
-
-typedef volatile union __alt_tse_command_config {
-	unsigned int image;
-	struct {
-		unsigned int
-		 transmit_enable:1,		/* bit 0 */
-		 receive_enable:1,		/* bit 1 */
-		 pause_frame_xon_gen:1,	/* bit 2 */
-		 ethernet_speed:1,		/* bit 3 */
-		 promiscuous_enable:1,		/* bit 4 */
-		 pad_enable:1,			/* bit 5 */
-		 crc_forward:1,		/* bit 6 */
-		 pause_frame_forward:1,	/* bit 7 */
-		 pause_frame_ignore:1,		/* bit 8 */
-		 set_mac_address_on_tx:1,	/* bit 9 */
-		 halfduplex_enable:1,		/* bit 10 */
-		 excessive_collision:1,	/* bit 11 */
-		 late_collision:1,		/* bit 12 */
-		 software_reset:1,		/* bit 13 */
-		 multicast_hash_mode_sel:1,	/* bit 14 */
-		 loopback_enable:1,		/* bit 15 */
-		 src_mac_addr_sel_on_tx:3,	/* bit 18:16 */
-		 magic_packet_detect:1,	/* bit 19 */
-		 sleep_mode_enable:1,		/* bit 20 */
-		 wake_up_request:1,		/* bit 21 */
-		 pause_frame_xoff_gen:1,	/* bit 22 */
-		 control_frame_enable:1,	/* bit 23 */
-		 payload_len_chk_disable:1,	/* bit 24 */
-		 enable_10mbps_intf:1,		/* bit 25 */
-		 rx_error_discard_enable:1,	/* bit 26 */
-		 reserved_bits:4,		/* bit 30:27 */
-		 self_clear_counter_reset:1;	/* bit 31 */
-	} __packed_1_ bits;
-} __packed_1_ alt_tse_command_config;
-
-/* Tx_Cmd_Stat Register Bit Definitions */
-
-typedef volatile union __alt_tse_tx_cmd_stat {
-	unsigned int image;
-	struct {
-		unsigned int reserved_lsbs:17,	/* bit 16:0  */
-		 omit_crc:1,			/* bit 17 */
-		 tx_shift16:1,			/* bit 18 */
-		 reserved_msbs:13;		/* bit 31:19 */
-
-	} __packed_1_ bits;
-} alt_tse_tx_cmd_stat;
-
-/* Rx_Cmd_Stat Register Bit Definitions */
-
-typedef volatile union __alt_tse_rx_cmd_stat {
-	unsigned int image;
-	struct {
-		unsigned int reserved_lsbs:25,	/* bit 24:0  */
-		 rx_shift16:1,			/* bit 25 */
-		 reserved_msbs:6;		/* bit 31:26 */
-
-	} __packed_1_ bits;
-} alt_tse_rx_cmd_stat;
-
-struct alt_tse_mdio {
-	unsigned int control;	/*PHY device operation control register */
-	unsigned int status;	/*PHY device operation status register */
-	unsigned int phy_id1;	/*Bits 31:16 of PHY identifier. */
-	unsigned int phy_id2;	/*Bits 15:0 of PHY identifier. */
-	unsigned int auto_negotiation_advertisement;
-	unsigned int remote_partner_base_page_ability;
-
-	unsigned int reg6;
-	unsigned int reg7;
-	unsigned int reg8;
-	unsigned int reg9;
-	unsigned int rega;
-	unsigned int regb;
-	unsigned int regc;
-	unsigned int regd;
-	unsigned int rege;
-	unsigned int regf;
-	unsigned int reg10;
-	unsigned int reg11;
-	unsigned int reg12;
-	unsigned int reg13;
-	unsigned int reg14;
-	unsigned int reg15;
-	unsigned int reg16;
-	unsigned int reg17;
-	unsigned int reg18;
-	unsigned int reg19;
-	unsigned int reg1a;
-	unsigned int reg1b;
-	unsigned int reg1c;
-	unsigned int reg1d;
-	unsigned int reg1e;
-	unsigned int reg1f;
-};
+#define ALT_TSE_SW_RESET_TIMEOUT		(3 * CONFIG_SYS_HZ)
+#define ALT_TSE_SGDMA_BUSY_TIMEOUT		(3 * CONFIG_SYS_HZ)
 
 /* MAC register Space */
 
 struct alt_tse_mac {
 	unsigned int megacore_revision;
 	unsigned int scratch_pad;
-	alt_tse_command_config command_config;
+	unsigned int command_config;
 	unsigned int mac_addr_0;
 	unsigned int mac_addr_1;
 	unsigned int max_frame_length;
@@ -413,8 +211,8 @@
 	unsigned int reservedxE4;
 
 	/*FIFO control register. */
-	alt_tse_tx_cmd_stat tx_cmd_stat;
-	alt_tse_rx_cmd_stat rx_cmd_stat;
+	unsigned int tx_cmd_stat;
+	unsigned int rx_cmd_stat;
 
 	unsigned int ipaccTxConf;
 	unsigned int ipaccRxConf;
@@ -425,8 +223,8 @@
 	unsigned int hash_table[64];
 
 	/*Registers 0 to 31 within PHY device 0/1 */
-	struct alt_tse_mdio mdio_phy0;
-	struct alt_tse_mdio mdio_phy1;
+	unsigned int mdio_phy0[0x20];
+	unsigned int mdio_phy1[0x20];
 
 	/*4 Supplemental MAC Addresses */
 	unsigned int supp_mac_addr_0_0;
@@ -441,52 +239,19 @@
 	unsigned int reservedx320[56];
 };
 
-/* flags: TSE MII modes */
-/* GMII/MII	= 0 */
-/* RGMII	= 1 */
-/* RGMII_ID	= 2 */
-/* RGMII_TXID	= 3 */
-/* RGMII_RXID	= 4 */
-/* SGMII	= 5 */
 struct altera_tse_priv {
-	char devname[16];
-	volatile struct alt_tse_mac *mac_dev;
-	volatile struct alt_sgdma_registers *sgdma_rx;
-	volatile struct alt_sgdma_registers *sgdma_tx;
-	unsigned int rx_sgdma_irq;
-	unsigned int tx_sgdma_irq;
-	unsigned int has_descriptor_mem;
-	unsigned int descriptor_mem_base;
-	unsigned int descriptor_mem_size;
-	volatile struct alt_sgdma_descriptor *rx_desc;
-	volatile struct alt_sgdma_descriptor *tx_desc;
-	volatile unsigned char *rx_buf;
-	struct phy_info *phyinfo;
+	struct alt_tse_mac *mac_dev;
+	struct alt_sgdma_registers *sgdma_rx;
+	struct alt_sgdma_registers *sgdma_tx;
+	unsigned int rx_fifo_depth;
+	unsigned int tx_fifo_depth;
+	struct alt_sgdma_descriptor *rx_desc;
+	struct alt_sgdma_descriptor *tx_desc;
+	unsigned char *rx_buf;
 	unsigned int phyaddr;
-	unsigned int flags;
-	unsigned int link;
-	unsigned int duplexity;
-	unsigned int speed;
+	unsigned int interface;
+	struct phy_device *phydev;
+	struct mii_dev *bus;
 };
 
-/* Phy stuff continued */
-/*
- * struct phy_cmd:  A command for reading or writing a PHY register
- *
- * mii_reg:  The register to read or write
- *
- * mii_data:  For writes, the value to put in the register.
- *	A value of -1 indicates this is a read.
- *
- * funct: A function pointer which is invoked for each command.
- *	For reads, this function will be passed the value read
- *	from the PHY, and process it.
- *	For writes, the result of this function will be written
- *	to the PHY register
- */
-struct phy_cmd {
-	uint mii_reg;
-	uint mii_data;
-	uint(*funct) (uint mii_reg, struct altera_tse_priv *priv);
-};
 #endif /* _ALTERA_TSE_H_ */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index ac5920a..53b4e1b 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -54,6 +54,20 @@
 	prompt "Select which UART will provide the debug UART"
 	depends on DEBUG_UART
 
+config DEBUG_UART_ALTERA_JTAGUART
+	bool "Altera JTAG UART"
+	help
+	  Select this to enable a debug UART using the altera_jtag_uart driver.
+	  You will need to provide parameters to make this work. The driver will
+	  be available until the real driver model serial is running.
+
+config DEBUG_UART_ALTERA_UART
+	bool "Altera UART"
+	help
+	  Select this to enable a debug UART using the altera_uart driver.
+	  You will need to provide parameters to make this work. The driver will
+	  be available until the real driver model serial is running.
+
 config DEBUG_UART_NS16550
 	bool "ns16550"
 	help
@@ -130,6 +144,32 @@
 	  debug_uart_init()). This can be useful just as a check that
 	  everything is working.
 
+config ALTERA_JTAG_UART
+	bool "Altera JTAG UART support"
+	depends on DM_SERIAL
+	help
+	  Select this to enable an JTAG UART for Altera devices.The JTAG UART
+	  core implements a method to communicate serial character streams
+	  between a host PC and a Qsys system on an Altera FPGA. Please find
+	  details on the "Embedded Peripherals IP User Guide" of Altera.
+
+config ALTERA_JTAG_UART_BYPASS
+	bool "Bypass output when no connection"
+	depends on ALTERA_JTAG_UART
+	help
+	  Bypass console output and keep going even if there is no JTAG
+	  terminal connection with the host. The console output will resume
+	  once the JTAG terminal is connected. Without the bypass, the console
+	  output will wait forever until a JTAG terminal is connected. If you
+	  not are sure, say Y.
+
+config ALTERA_UART
+	bool "Altera UART support"
+	depends on DM_SERIAL
+	help
+	  Select this to enable an UART for Altera devices. Please find
+	  details on the "Embedded Peripherals IP User Guide" of Altera.
+
 config ROCKCHIP_SERIAL
 	bool "Rockchip on-chip UART support"
 	depends on ARCH_ROCKCHIP && DM_SERIAL
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 869ea7b..1818c7c 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -25,6 +25,7 @@
 obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
 obj-$(CONFIG_MCFUART) += mcfuart.o
 obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o
+obj-$(CONFIG_KEYSTONE_SERIAL) += serial_keystone.o
 obj-$(CONFIG_SYS_NS16550) += ns16550.o
 obj-$(CONFIG_S5P) += serial_s5p.o
 obj-$(CONFIG_IMX_SERIAL) += serial_imx.o
diff --git a/drivers/serial/altera_jtag_uart.c b/drivers/serial/altera_jtag_uart.c
index 9a81402..39d4a4e 100644
--- a/drivers/serial/altera_jtag_uart.c
+++ b/drivers/serial/altera_jtag_uart.c
@@ -6,98 +6,149 @@
  */
 
 #include <common.h>
-#include <watchdog.h>
+#include <dm.h>
+#include <errno.h>
 #include <asm/io.h>
 #include <linux/compiler.h>
 #include <serial.h>
 
-typedef volatile struct {
-	unsigned	data;			/* Data register */
-	unsigned	control;		/* Control register */
-} nios_jtag_t;
+struct altera_jtaguart_regs {
+	u32	data;			/* Data register */
+	u32	control;		/* Control register */
+};
+
+struct altera_jtaguart_platdata {
+	struct altera_jtaguart_regs *regs;
+};
 
 /* data register */
-#define NIOS_JTAG_RVALID	(1<<15)		/* Read valid */
-#define NIOS_JTAG_DATA(d)	((d)&0x0ff)	/* Read data */
-#define NIOS_JTAG_RAVAIL(d)	((d)>>16)	/* Read space avail */
+#define ALTERA_JTAG_RVALID	(1<<15)		/* Read valid */
 
 /* control register */
-#define NIOS_JTAG_RE		(1 << 0)	/* read intr enable */
-#define NIOS_JTAG_WE		(1 << 1)	/* write intr enable */
-#define NIOS_JTAG_RI		(1 << 8)	/* read intr pending */
-#define NIOS_JTAG_WI		(1 << 9)	/* write intr pending*/
-#define NIOS_JTAG_AC		(1 << 10)	/* activity indicator */
-#define NIOS_JTAG_RRDY		(1 << 12)	/* read available */
-#define NIOS_JTAG_WSPACE(d)	((d)>>16)	/* Write space avail */
+#define ALTERA_JTAG_AC		(1 << 10)	/* activity indicator */
+#define ALTERA_JTAG_RRDY	(1 << 12)	/* read available */
+#define ALTERA_JTAG_WSPACE(d)	((d)>>16)	/* Write space avail */
+/* Write fifo size. FIXME: this should be extracted with sopc2dts */
+#define ALTERA_JTAG_WRITE_DEPTH	64
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/*------------------------------------------------------------------
- * JTAG acts as the serial port
- *-----------------------------------------------------------------*/
-static nios_jtag_t *jtag = (nios_jtag_t *)CONFIG_SYS_NIOS_CONSOLE;
-
-static void altera_jtag_serial_setbrg(void)
-{
-}
-
-static int altera_jtag_serial_init(void)
+static int altera_jtaguart_setbrg(struct udevice *dev, int baudrate)
 {
 	return 0;
 }
 
-static void altera_jtag_serial_putc(char c)
+static int altera_jtaguart_putc(struct udevice *dev, const char ch)
 {
-	while (1) {
-		unsigned st = readl(&jtag->control);
-		if (NIOS_JTAG_WSPACE(st))
-			break;
+	struct altera_jtaguart_platdata *plat = dev->platdata;
+	struct altera_jtaguart_regs *const regs = plat->regs;
+	u32 st = readl(&regs->control);
+
 #ifdef CONFIG_ALTERA_JTAG_UART_BYPASS
-		if (!(st & NIOS_JTAG_AC)) /* no connection */
-			return;
+	if (!(st & ALTERA_JTAG_AC)) /* no connection yet */
+		return -ENETUNREACH;
 #endif
-		WATCHDOG_RESET();
-	}
-	writel ((unsigned char)c, &jtag->data);
+
+	if (ALTERA_JTAG_WSPACE(st) == 0)
+		return -EAGAIN;
+
+	writel(ch, &regs->data);
+
+	return 0;
 }
 
-static int altera_jtag_serial_tstc(void)
+static int altera_jtaguart_pending(struct udevice *dev, bool input)
 {
-	return ( readl (&jtag->control) & NIOS_JTAG_RRDY);
+	struct altera_jtaguart_platdata *plat = dev->platdata;
+	struct altera_jtaguart_regs *const regs = plat->regs;
+	u32 st = readl(&regs->control);
+
+	if (input)
+		return st & ALTERA_JTAG_RRDY ? 1 : 0;
+	else
+		return !(ALTERA_JTAG_WSPACE(st) == ALTERA_JTAG_WRITE_DEPTH);
 }
 
-static int altera_jtag_serial_getc(void)
+static int altera_jtaguart_getc(struct udevice *dev)
 {
-	int c;
-	unsigned val;
+	struct altera_jtaguart_platdata *plat = dev->platdata;
+	struct altera_jtaguart_regs *const regs = plat->regs;
+	u32 val;
 
-	while (1) {
-		WATCHDOG_RESET ();
-		val = readl (&jtag->data);
-		if (val & NIOS_JTAG_RVALID)
-			break;
-	}
-	c = val & 0x0ff;
-	return (c);
+	val = readl(&regs->data);
+
+	if (!(val & ALTERA_JTAG_RVALID))
+		return -EAGAIN;
+
+	return val & 0xff;
 }
 
-static struct serial_device altera_jtag_serial_drv = {
-	.name	= "altera_jtag_uart",
-	.start	= altera_jtag_serial_init,
-	.stop	= NULL,
-	.setbrg	= altera_jtag_serial_setbrg,
-	.putc	= altera_jtag_serial_putc,
-	.puts	= default_serial_puts,
-	.getc	= altera_jtag_serial_getc,
-	.tstc	= altera_jtag_serial_tstc,
+static int altera_jtaguart_probe(struct udevice *dev)
+{
+#ifdef CONFIG_ALTERA_JTAG_UART_BYPASS
+	struct altera_jtaguart_platdata *plat = dev->platdata;
+	struct altera_jtaguart_regs *const regs = plat->regs;
+
+	writel(ALTERA_JTAG_AC, &regs->control); /* clear AC flag */
+#endif
+	return 0;
+}
+
+static int altera_jtaguart_ofdata_to_platdata(struct udevice *dev)
+{
+	struct altera_jtaguart_platdata *plat = dev_get_platdata(dev);
+
+	plat->regs = ioremap(dev_get_addr(dev),
+		sizeof(struct altera_jtaguart_regs));
+
+	return 0;
+}
+
+static const struct dm_serial_ops altera_jtaguart_ops = {
+	.putc = altera_jtaguart_putc,
+	.pending = altera_jtaguart_pending,
+	.getc = altera_jtaguart_getc,
+	.setbrg = altera_jtaguart_setbrg,
 };
 
-void altera_jtag_serial_initialize(void)
+static const struct udevice_id altera_jtaguart_ids[] = {
+	{ .compatible = "altr,juart-1.0", },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_jtaguart) = {
+	.name	= "altera_jtaguart",
+	.id	= UCLASS_SERIAL,
+	.of_match = altera_jtaguart_ids,
+	.ofdata_to_platdata = altera_jtaguart_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata),
+	.probe = altera_jtaguart_probe,
+	.ops	= &altera_jtaguart_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART
+
+#include <debug_uart.h>
+
+void debug_uart_init(void)
 {
-	serial_register(&altera_jtag_serial_drv);
 }
 
-__weak struct serial_device *default_serial_console(void)
+static inline void _debug_uart_putc(int ch)
 {
-	return &altera_jtag_serial_drv;
+	struct altera_jtaguart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
+
+	while (1) {
+		u32 st = readl(&regs->control);
+
+		if (ALTERA_JTAG_WSPACE(st))
+			break;
+	}
+
+	writel(ch, &regs->data);
 }
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
index d6b1484..4ff9fe2 100644
--- a/drivers/serial/altera_uart.c
+++ b/drivers/serial/altera_uart.c
@@ -5,133 +5,149 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
-
 #include <common.h>
-#include <watchdog.h>
+#include <dm.h>
+#include <errno.h>
 #include <asm/io.h>
 #include <linux/compiler.h>
 #include <serial.h>
 
-typedef volatile struct {
-	unsigned	rxdata;		/* Rx data reg */
-	unsigned	txdata;		/* Tx data reg */
-	unsigned	status;		/* Status reg */
-	unsigned	control;	/* Control reg */
-	unsigned	divisor;	/* Baud rate divisor reg */
-	unsigned	endofpacket;	/* End-of-packet reg */
-} nios_uart_t;
+struct altera_uart_regs {
+	u32	rxdata;		/* Rx data reg */
+	u32	txdata;		/* Tx data reg */
+	u32	status;		/* Status reg */
+	u32	control;	/* Control reg */
+	u32	divisor;	/* Baud rate divisor reg */
+	u32	endofpacket;	/* End-of-packet reg */
+};
+
+struct altera_uart_platdata {
+	struct altera_uart_regs *regs;
+	unsigned int uartclk;
+};
 
 /* status register */
-#define NIOS_UART_PE		(1 << 0)	/* parity error */
-#define NIOS_UART_FE		(1 << 1)	/* frame error */
-#define NIOS_UART_BRK		(1 << 2)	/* break detect */
-#define NIOS_UART_ROE		(1 << 3)	/* rx overrun */
-#define NIOS_UART_TOE		(1 << 4)	/* tx overrun */
-#define NIOS_UART_TMT		(1 << 5)	/* tx empty */
-#define NIOS_UART_TRDY		(1 << 6)	/* tx ready */
-#define NIOS_UART_RRDY		(1 << 7)	/* rx ready */
-#define NIOS_UART_E		(1 << 8)	/* exception */
-#define NIOS_UART_DCTS		(1 << 10)	/* cts change */
-#define NIOS_UART_CTS		(1 << 11)	/* cts */
-#define NIOS_UART_EOP		(1 << 12)	/* eop detected */
-
-/* control register */
-#define NIOS_UART_IPE		(1 << 0)	/* parity error int ena*/
-#define NIOS_UART_IFE		(1 << 1)	/* frame error int ena */
-#define NIOS_UART_IBRK		(1 << 2)	/* break detect int ena */
-#define NIOS_UART_IROE		(1 << 3)	/* rx overrun int ena */
-#define NIOS_UART_ITOE		(1 << 4)	/* tx overrun int ena */
-#define NIOS_UART_ITMT		(1 << 5)	/* tx empty int ena */
-#define NIOS_UART_ITRDY		(1 << 6)	/* tx ready int ena */
-#define NIOS_UART_IRRDY		(1 << 7)	/* rx ready int ena */
-#define NIOS_UART_IE		(1 << 8)	/* exception int ena */
-#define NIOS_UART_TBRK		(1 << 9)	/* transmit break */
-#define NIOS_UART_IDCTS		(1 << 10)	/* cts change int ena */
-#define NIOS_UART_RTS		(1 << 11)	/* rts */
-#define NIOS_UART_IEOP		(1 << 12)	/* eop detected int ena */
+#define ALTERA_UART_TMT		(1 << 5)	/* tx empty */
+#define ALTERA_UART_TRDY	(1 << 6)	/* tx ready */
+#define ALTERA_UART_RRDY	(1 << 7)	/* rx ready */
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/*------------------------------------------------------------------
- * UART the serial port
- *-----------------------------------------------------------------*/
-
-static nios_uart_t *uart = (nios_uart_t *) CONFIG_SYS_NIOS_CONSOLE;
-
-#if defined(CONFIG_SYS_NIOS_FIXEDBAUD)
-
-/*
- * Everything's already setup for fixed-baud PTF
- * assignment
- */
-static void altera_serial_setbrg(void)
+static int altera_uart_setbrg(struct udevice *dev, int baudrate)
 {
+	struct altera_uart_platdata *plat = dev->platdata;
+	struct altera_uart_regs *const regs = plat->regs;
+	u32 div;
+
+	div = (plat->uartclk / baudrate) - 1;
+	writel(div, &regs->divisor);
+
+	return 0;
 }
 
-static int altera_serial_init(void)
+static int altera_uart_putc(struct udevice *dev, const char ch)
+{
+	struct altera_uart_platdata *plat = dev->platdata;
+	struct altera_uart_regs *const regs = plat->regs;
+
+	if (!(readl(&regs->status) & ALTERA_UART_TRDY))
+		return -EAGAIN;
+
+	writel(ch, &regs->txdata);
+
+	return 0;
+}
+
+static int altera_uart_pending(struct udevice *dev, bool input)
+{
+	struct altera_uart_platdata *plat = dev->platdata;
+	struct altera_uart_regs *const regs = plat->regs;
+	u32 st = readl(&regs->status);
+
+	if (input)
+		return st & ALTERA_UART_RRDY ? 1 : 0;
+	else
+		return !(st & ALTERA_UART_TMT);
+}
+
+static int altera_uart_getc(struct udevice *dev)
+{
+	struct altera_uart_platdata *plat = dev->platdata;
+	struct altera_uart_regs *const regs = plat->regs;
+
+	if (!(readl(&regs->status) & ALTERA_UART_RRDY))
+		return -EAGAIN;
+
+	return readl(&regs->rxdata) & 0xff;
+}
+
+static int altera_uart_probe(struct udevice *dev)
 {
 	return 0;
 }
 
-#else
-
-static void altera_serial_setbrg(void)
+static int altera_uart_ofdata_to_platdata(struct udevice *dev)
 {
-	unsigned div;
+	struct altera_uart_platdata *plat = dev_get_platdata(dev);
 
-	div = (CONFIG_SYS_CLK_FREQ/gd->baudrate)-1;
-	writel (div, &uart->divisor);
-}
+	plat->regs = ioremap(dev_get_addr(dev),
+		sizeof(struct altera_uart_regs));
+	plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+		"clock-frequency", 0);
 
-static int altera_serial_init(void)
-{
-	serial_setbrg();
 	return 0;
 }
 
-#endif /* CONFIG_SYS_NIOS_FIXEDBAUD */
-
-/*-----------------------------------------------------------------------
- * UART CONSOLE
- *---------------------------------------------------------------------*/
-static void altera_serial_putc(char c)
-{
-	if (c == '\n')
-		serial_putc ('\r');
-	while ((readl (&uart->status) & NIOS_UART_TRDY) == 0)
-		WATCHDOG_RESET ();
-	writel ((unsigned char)c, &uart->txdata);
-}
-
-static int altera_serial_tstc(void)
-{
-	return (readl (&uart->status) & NIOS_UART_RRDY);
-}
-
-static int altera_serial_getc(void)
-{
-	while (serial_tstc () == 0)
-		WATCHDOG_RESET ();
-	return (readl (&uart->rxdata) & 0x00ff );
-}
-
-static struct serial_device altera_serial_drv = {
-	.name	= "altera_serial",
-	.start	= altera_serial_init,
-	.stop	= NULL,
-	.setbrg	= altera_serial_setbrg,
-	.putc	= altera_serial_putc,
-	.puts	= default_serial_puts,
-	.getc	= altera_serial_getc,
-	.tstc	= altera_serial_tstc,
+static const struct dm_serial_ops altera_uart_ops = {
+	.putc = altera_uart_putc,
+	.pending = altera_uart_pending,
+	.getc = altera_uart_getc,
+	.setbrg = altera_uart_setbrg,
 };
 
-void altera_serial_initialize(void)
+static const struct udevice_id altera_uart_ids[] = {
+	{ .compatible = "altr,uart-1.0", },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_uart) = {
+	.name	= "altera_uart",
+	.id	= UCLASS_SERIAL,
+	.of_match = altera_uart_ids,
+	.ofdata_to_platdata = altera_uart_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct altera_uart_platdata),
+	.probe = altera_uart_probe,
+	.ops	= &altera_uart_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_ALTERA_UART
+
+#include <debug_uart.h>
+
+void debug_uart_init(void)
 {
-	serial_register(&altera_serial_drv);
+	struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
+	u32 div;
+
+	div = (CONFIG_DEBUG_UART_CLOCK / CONFIG_BAUDRATE) - 1;
+	writel(div, &regs->divisor);
 }
 
-__weak struct serial_device *default_serial_console(void)
+static inline void _debug_uart_putc(int ch)
 {
-	return &altera_serial_drv;
+	struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
+
+	while (1) {
+		u32 st = readl(&regs->status);
+
+		if (st & ALTERA_UART_TRDY)
+			break;
+	}
+
+	writel(ch, &regs->txdata);
 }
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index 699c410..422d3ae 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -109,8 +109,6 @@
 	void name(void)						\
 		__attribute__((weak, alias("serial_null")));
 
-serial_initfunc(altera_jtag_serial_initialize);
-serial_initfunc(altera_serial_initialize);
 serial_initfunc(amirix_serial_initialize);
 serial_initfunc(arc_serial_initialize);
 serial_initfunc(arm_dcc_initialize);
@@ -202,8 +200,6 @@
  */
 void serial_initialize(void)
 {
-	altera_jtag_serial_initialize();
-	altera_serial_initialize();
 	amirix_serial_initialize();
 	arc_serial_initialize();
 	arm_dcc_initialize();
diff --git a/drivers/serial/serial_keystone.c b/drivers/serial/serial_keystone.c
new file mode 100644
index 0000000..7b5ab6c
--- /dev/null
+++ b/drivers/serial/serial_keystone.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 Texas Instruments, <www.ti.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <ns16550.h>
+#include <serial.h>
+#include <asm/arch/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct udevice_id keystone_serial_ids[] = {
+	{ .compatible = "ti,keystone-uart" },
+	{ .compatible = "ns16550a" },
+	{ }
+};
+
+static int keystone_serial_ofdata_to_platdata(struct udevice *dev)
+{
+	struct ns16550_platdata *plat = dev_get_platdata(dev);
+	int ret;
+
+	ret = ns16550_serial_ofdata_to_platdata(dev);
+	if (ret)
+		return ret;
+	plat->clock = CONFIG_SYS_NS16550_CLK;
+	return 0;
+}
+#endif
+
+U_BOOT_DRIVER(serial_keystone_ns16550) = {
+	.name	= "serial_keystone",
+	.id	= UCLASS_SERIAL,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.of_match = of_match_ptr(keystone_serial_ids),
+	.ofdata_to_platdata = of_match_ptr(keystone_serial_ofdata_to_platdata),
+	.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+#endif
+	.priv_auto_alloc_size = sizeof(struct NS16550),
+	.probe = ns16550_serial_probe,
+	.ops	= &ns16550_serial_ops,
+	.flags	= DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8e04fce..2f8cf19 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -15,6 +15,14 @@
 
 if DM_SPI
 
+config ALTERA_SPI
+	bool "Altera SPI driver"
+	help
+	  Enable the Altera SPI driver. This driver can be used to
+	  access the SPI NOR flash on platforms embedding this Altera
+	  IP core. Please find details on the "Embedded Peripherals IP
+	  User Guide" of Altera.
+
 config CADENCE_QSPI
 	bool "Cadence QSPI driver"
 	help
diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c
index a4d03d9..ff3512a 100644
--- a/drivers/spi/altera_spi.c
+++ b/drivers/spi/altera_spi.c
@@ -8,18 +8,19 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 #include <common.h>
-#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
 #include <malloc.h>
 #include <spi.h>
+#include <fdtdec.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #ifndef CONFIG_ALTERA_SPI_IDLE_VAL
 #define CONFIG_ALTERA_SPI_IDLE_VAL 0xff
 #endif
 
-#ifndef CONFIG_SYS_ALTERA_SPI_LIST
-#define CONFIG_SYS_ALTERA_SPI_LIST { CONFIG_SYS_SPI_BASE }
-#endif
-
 struct altera_spi_regs {
 	u32	rxdata;
 	u32	txdata;
@@ -29,102 +30,68 @@
 	u32	slave_sel;
 };
 
-#define ALTERA_SPI_STATUS_ROE_MSK	(1 << 3)
-#define ALTERA_SPI_STATUS_TOE_MSK	(1 << 4)
-#define ALTERA_SPI_STATUS_TMT_MSK	(1 << 5)
-#define ALTERA_SPI_STATUS_TRDY_MSK	(1 << 6)
-#define ALTERA_SPI_STATUS_RRDY_MSK	(1 << 7)
-#define ALTERA_SPI_STATUS_E_MSK		(1 << 8)
+struct altera_spi_platdata {
+	struct altera_spi_regs *regs;
+};
 
-#define ALTERA_SPI_CONTROL_IROE_MSK	(1 << 3)
-#define ALTERA_SPI_CONTROL_ITOE_MSK	(1 << 4)
-#define ALTERA_SPI_CONTROL_ITRDY_MSK	(1 << 6)
-#define ALTERA_SPI_CONTROL_IRRDY_MSK	(1 << 7)
-#define ALTERA_SPI_CONTROL_IE_MSK	(1 << 8)
+struct altera_spi_priv {
+	struct altera_spi_regs *regs;
+};
+
+#define ALTERA_SPI_STATUS_RRDY_MSK	(1 << 7)
 #define ALTERA_SPI_CONTROL_SSO_MSK	(1 << 10)
 
-static ulong altera_spi_base_list[] = CONFIG_SYS_ALTERA_SPI_LIST;
-
-struct altera_spi_slave {
-	struct spi_slave	slave;
-	struct altera_spi_regs	*regs;
-};
-#define to_altera_spi_slave(s) container_of(s, struct altera_spi_slave, slave)
-
-__weak int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+static void spi_cs_activate(struct udevice *dev, uint cs)
 {
-	return bus < ARRAY_SIZE(altera_spi_base_list) && cs < 32;
+	struct udevice *bus = dev->parent;
+	struct altera_spi_priv *priv = dev_get_priv(bus);
+	struct altera_spi_regs *const regs = priv->regs;
+
+	writel(1 << cs, &regs->slave_sel);
+	writel(ALTERA_SPI_CONTROL_SSO_MSK, &regs->control);
 }
 
-__weak void spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
-	writel(1 << slave->cs, &altspi->regs->slave_sel);
-	writel(ALTERA_SPI_CONTROL_SSO_MSK, &altspi->regs->control);
+	struct udevice *bus = dev->parent;
+	struct altera_spi_priv *priv = dev_get_priv(bus);
+	struct altera_spi_regs *const regs = priv->regs;
+
+	writel(0, &regs->control);
+	writel(0, &regs->slave_sel);
 }
 
-__weak void spi_cs_deactivate(struct spi_slave *slave)
+static int altera_spi_claim_bus(struct udevice *dev)
 {
-	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
-	writel(0, &altspi->regs->control);
-	writel(0, &altspi->regs->slave_sel);
-}
+	struct udevice *bus = dev->parent;
+	struct altera_spi_priv *priv = dev_get_priv(bus);
+	struct altera_spi_regs *const regs = priv->regs;
 
-void spi_init(void)
-{
-}
+	writel(0, &regs->control);
+	writel(0, &regs->slave_sel);
 
-void spi_set_speed(struct spi_slave *slave, uint hz)
-{
-	/* altera spi core does not support programmable speed */
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-				  unsigned int max_hz, unsigned int mode)
-{
-	struct altera_spi_slave *altspi;
-
-	if (!spi_cs_is_valid(bus, cs))
-		return NULL;
-
-	altspi = spi_alloc_slave(struct altera_spi_slave, bus, cs);
-	if (!altspi)
-		return NULL;
-
-	altspi->regs = (struct altera_spi_regs *)altera_spi_base_list[bus];
-	debug("%s: bus:%i cs:%i base:%p\n", __func__, bus, cs, altspi->regs);
-
-	return &altspi->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
-	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
-	free(altspi);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
-	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
-
-	debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
-	writel(0, &altspi->regs->control);
-	writel(0, &altspi->regs->slave_sel);
 	return 0;
 }
 
-void spi_release_bus(struct spi_slave *slave)
+static int altera_spi_release_bus(struct udevice *dev)
 {
-	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
+	struct udevice *bus = dev->parent;
+	struct altera_spi_priv *priv = dev_get_priv(bus);
+	struct altera_spi_regs *const regs = priv->regs;
 
-	debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
-	writel(0, &altspi->regs->slave_sel);
+	writel(0, &regs->slave_sel);
+
+	return 0;
 }
 
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-	     void *din, unsigned long flags)
+static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			    const void *dout, void *din, unsigned long flags)
 {
-	struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
+	struct udevice *bus = dev->parent;
+	struct altera_spi_priv *priv = dev_get_priv(bus);
+	struct altera_spi_regs *const regs = priv->regs;
+	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
+
 	/* assume spi core configured to do 8 bit transfers */
 	unsigned int bytes = bitlen / 8;
 	const unsigned char *txp = dout;
@@ -132,7 +99,7 @@
 	uint32_t reg, data, start;
 
 	debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
-	      slave->bus, slave->cs, bitlen, bytes, flags);
+	      bus->seq, slave_plat->cs, bitlen, bytes, flags);
 
 	if (bitlen == 0)
 		goto done;
@@ -143,11 +110,11 @@
 	}
 
 	/* empty read buffer */
-	if (readl(&altspi->regs->status) & ALTERA_SPI_STATUS_RRDY_MSK)
-		readl(&altspi->regs->rxdata);
+	if (readl(&regs->status) & ALTERA_SPI_STATUS_RRDY_MSK)
+		readl(&regs->rxdata);
 
 	if (flags & SPI_XFER_BEGIN)
-		spi_cs_activate(slave);
+		spi_cs_activate(dev, slave_plat->cs);
 
 	while (bytes--) {
 		if (txp)
@@ -156,20 +123,20 @@
 			data = CONFIG_ALTERA_SPI_IDLE_VAL;
 
 		debug("%s: tx:%x ", __func__, data);
-		writel(data, &altspi->regs->txdata);
+		writel(data, &regs->txdata);
 
 		start = get_timer(0);
 		while (1) {
-			reg = readl(&altspi->regs->status);
+			reg = readl(&regs->status);
 			if (reg & ALTERA_SPI_STATUS_RRDY_MSK)
 				break;
 			if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
-				printf("%s: Transmission timed out!\n", __func__);
-				goto done;
+				debug("%s: Transmission timed out!\n", __func__);
+				return -1;
 			}
 		}
 
-		data = readl(&altspi->regs->rxdata);
+		data = readl(&regs->rxdata);
 		if (rxp)
 			*rxp++ = data & 0xff;
 
@@ -178,7 +145,65 @@
 
 done:
 	if (flags & SPI_XFER_END)
-		spi_cs_deactivate(slave);
+		spi_cs_deactivate(dev);
 
 	return 0;
 }
+
+static int altera_spi_set_speed(struct udevice *bus, uint speed)
+{
+	return 0;
+}
+
+static int altera_spi_set_mode(struct udevice *bus, uint mode)
+{
+	return 0;
+}
+
+static int altera_spi_probe(struct udevice *bus)
+{
+	struct altera_spi_platdata *plat = dev_get_platdata(bus);
+	struct altera_spi_priv *priv = dev_get_priv(bus);
+
+	priv->regs = plat->regs;
+
+	return 0;
+}
+
+static int altera_spi_ofdata_to_platdata(struct udevice *bus)
+{
+	struct altera_spi_platdata *plat = dev_get_platdata(bus);
+
+	plat->regs = ioremap(dev_get_addr(bus),
+		sizeof(struct altera_spi_regs));
+
+	return 0;
+}
+
+static const struct dm_spi_ops altera_spi_ops = {
+	.claim_bus	= altera_spi_claim_bus,
+	.release_bus	= altera_spi_release_bus,
+	.xfer		= altera_spi_xfer,
+	.set_speed	= altera_spi_set_speed,
+	.set_mode	= altera_spi_set_mode,
+	/*
+	 * cs_info is not needed, since we require all chip selects to be
+	 * in the device tree explicitly
+	 */
+};
+
+static const struct udevice_id altera_spi_ids[] = {
+	{ .compatible = "altr,spi-1.0", },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_spi) = {
+	.name	= "altera_spi",
+	.id	= UCLASS_SPI,
+	.of_match = altera_spi_ids,
+	.ops	= &altera_spi_ops,
+	.ofdata_to_platdata = altera_spi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct altera_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct altera_spi_priv),
+	.probe	= altera_spi_probe,
+};
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
new file mode 100644
index 0000000..97c4128
--- /dev/null
+++ b/drivers/timer/Kconfig
@@ -0,0 +1,19 @@
+menu "Timer Support"
+
+config TIMER
+	bool "Enable Driver Model for Timer drivers"
+	depends on DM
+	help
+	  Enable driver model for Timer access. It uses the same API as
+	  lib/time.c. But now implemented by the uclass. The first timer
+	  will be used. The timer is usually a 32 bits free-running up
+	  counter. There may be no real tick, and no timer interrupt.
+
+config ALTERA_TIMER
+	bool "Altera Timer support"
+	depends on TIMER
+	help
+	  Select this to enable an timer for Altera devices. Please find
+	  details on the "Embedded Peripherals IP User Guide" of Altera.
+
+endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
new file mode 100644
index 0000000..ae66c07
--- /dev/null
+++ b/drivers/timer/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_TIMER)		+= timer-uclass.o
+obj-$(CONFIG_ALTERA_TIMER)	+= altera_timer.o
diff --git a/drivers/timer/altera_timer.c b/drivers/timer/altera_timer.c
new file mode 100644
index 0000000..2ef9ad6
--- /dev/null
+++ b/drivers/timer/altera_timer.c
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
+ * Scott McNutt <smcnutt@psyent.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct altera_timer_regs {
+	u32	status;		/* Timer status reg */
+	u32	control;	/* Timer control reg */
+	u32	periodl;	/* Timeout period low */
+	u32	periodh;	/* Timeout period high */
+	u32	snapl;		/* Snapshot low */
+	u32	snaph;		/* Snapshot high */
+};
+
+struct altera_timer_platdata {
+	struct altera_timer_regs *regs;
+	unsigned long clock_rate;
+};
+
+/* control register */
+#define ALTERA_TIMER_CONT	(1 << 1)	/* Continuous mode */
+#define ALTERA_TIMER_START	(1 << 2)	/* Start timer */
+#define ALTERA_TIMER_STOP	(1 << 3)	/* Stop timer */
+
+static int altera_timer_get_count(struct udevice *dev, unsigned long *count)
+{
+	struct altera_timer_platdata *plat = dev->platdata;
+	struct altera_timer_regs *const regs = plat->regs;
+	u32 val;
+
+	/* Trigger update */
+	writel(0x0, &regs->snapl);
+
+	/* Read timer value */
+	val = readl(&regs->snapl) & 0xffff;
+	val |= (readl(&regs->snaph) & 0xffff) << 16;
+	*count = ~val;
+
+	return 0;
+}
+
+static int altera_timer_probe(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct altera_timer_platdata *plat = dev->platdata;
+	struct altera_timer_regs *const regs = plat->regs;
+
+	uc_priv->clock_rate = plat->clock_rate;
+
+	writel(0, &regs->status);
+	writel(0, &regs->control);
+	writel(ALTERA_TIMER_STOP, &regs->control);
+
+	writel(0xffff, &regs->periodl);
+	writel(0xffff, &regs->periodh);
+	writel(ALTERA_TIMER_CONT | ALTERA_TIMER_START, &regs->control);
+
+	return 0;
+}
+
+static int altera_timer_ofdata_to_platdata(struct udevice *dev)
+{
+	struct altera_timer_platdata *plat = dev_get_platdata(dev);
+
+	plat->regs = ioremap(dev_get_addr(dev),
+		sizeof(struct altera_timer_regs));
+	plat->clock_rate = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+		"clock-frequency", 0);
+
+	return 0;
+}
+
+static const struct timer_ops altera_timer_ops = {
+	.get_count = altera_timer_get_count,
+};
+
+static const struct udevice_id altera_timer_ids[] = {
+	{ .compatible = "altr,timer-1.0", },
+	{ }
+};
+
+U_BOOT_DRIVER(altera_timer) = {
+	.name	= "altera_timer",
+	.id	= UCLASS_TIMER,
+	.of_match = altera_timer_ids,
+	.ofdata_to_platdata = altera_timer_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct altera_timer_platdata),
+	.probe = altera_timer_probe,
+	.ops	= &altera_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
new file mode 100644
index 0000000..12aee5b
--- /dev/null
+++ b/drivers/timer/timer-uclass.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+
+/*
+ * Implement a Timer uclass to work with lib/time.c. The timer is usually
+ * a 32 bits free-running up counter. The get_rate() method is used to get
+ * the input clock frequency of the timer. The get_count() method is used
+ * get the current 32 bits count value. If the hardware is counting down,
+ * the value should be inversed inside the method. There may be no real
+ * tick, and no timer interrupt.
+ */
+
+int timer_get_count(struct udevice *dev, unsigned long *count)
+{
+	const struct timer_ops *ops = device_get_ops(dev);
+
+	if (!ops->get_count)
+		return -ENOSYS;
+
+	return ops->get_count(dev, count);
+}
+
+unsigned long timer_get_rate(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	return uc_priv->clock_rate;
+}
+
+UCLASS_DRIVER(timer) = {
+	.id		= UCLASS_TIMER,
+	.name		= "timer",
+	.per_device_auto_alloc_size = sizeof(struct timer_dev_priv),
+};
diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h
index b36f68f..6c9c279 100644
--- a/drivers/usb/dwc3/linux-compat.h
+++ b/drivers/usb/dwc3/linux-compat.h
@@ -30,9 +30,4 @@
 {
 	return kzalloc(size, flags);
 }
-
-static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
-{
-	return kzalloc(n * size, flags);
-}
 #endif
diff --git a/fs/fs.c b/fs/fs.c
index 827b143..b2d6a53 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -23,6 +23,7 @@
 #include <fat.h>
 #include <fs.h>
 #include <sandboxfs.h>
+#include <ubifs_uboot.h>
 #include <asm/io.h>
 #include <div64.h>
 #include <linux/math64.h>
@@ -157,6 +158,21 @@
 		.uuid = fs_uuid_unsupported,
 	},
 #endif
+#ifdef CONFIG_CMD_UBIFS
+	{
+		.fstype = FS_TYPE_UBIFS,
+		.name = "ubifs",
+		.null_dev_desc_ok = true,
+		.probe = ubifs_set_blk_dev,
+		.close = ubifs_close,
+		.ls = ubifs_ls,
+		.exists = ubifs_exists,
+		.size = ubifs_size,
+		.read = ubifs_read,
+		.write = fs_write_unsupported,
+		.uuid = fs_uuid_unsupported,
+	},
+#endif
 	{
 		.fstype = FS_TYPE_ANY,
 		.name = "unsupported",
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
index c626cbf..1b4683f 100644
--- a/fs/ubifs/budget.c
+++ b/fs/ubifs/budget.c
@@ -433,7 +433,6 @@
  */
 int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
 {
-	int uninitialized_var(cmt_retries), uninitialized_var(wb_retries);
 	int err, idx_growth, data_growth, dd_growth, retried = 0;
 
 	ubifs_assert(req->new_page <= 1);
@@ -506,7 +505,7 @@
 			c->bi.nospace_rp = 1;
 		smp_wmb();
 	} else
-		ubifs_err("cannot budget space, error %d", err);
+		ubifs_err(c, "cannot budget space, error %d", err);
 	return err;
 }
 
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 6e6f018..38c91d0 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -334,9 +334,9 @@
 		pr_err("\tkey_fmt        %d (%s)\n",
 		       (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
 		pr_err("\tflags          %#x\n", sup_flags);
-		pr_err("\t  big_lpt      %u\n",
+		pr_err("\tbig_lpt        %u\n",
 		       !!(sup_flags & UBIFS_FLG_BIGLPT));
-		pr_err("\t  space_fixup  %u\n",
+		pr_err("\tspace_fixup    %u\n",
 		       !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
 		pr_err("\tmin_io_size    %u\n", le32_to_cpu(sup->min_io_size));
 		pr_err("\tleb_size       %u\n", le32_to_cpu(sup->leb_size));
@@ -751,8 +751,10 @@
 
 	for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
 		err = ubifs_read_one_lp(c, lnum, &lp);
-		if (err)
-			ubifs_err("cannot read lprops for LEB %d", lnum);
+		if (err) {
+			ubifs_err(c, "cannot read lprops for LEB %d", lnum);
+			continue;
+		}
 
 		ubifs_dump_lprop(c, &lp);
 	}
@@ -823,13 +825,13 @@
 
 	buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
 	if (!buf) {
-		ubifs_err("cannot allocate memory for dumping LEB %d", lnum);
+		ubifs_err(c, "cannot allocate memory for dumping LEB %d", lnum);
 		return;
 	}
 
 	sleb = ubifs_scan(c, lnum, 0, buf, 0);
 	if (IS_ERR(sleb)) {
-		ubifs_err("scan error %d", (int)PTR_ERR(sleb));
+		ubifs_err(c, "scan error %d", (int)PTR_ERR(sleb));
 		goto out;
 	}
 
@@ -1037,7 +1039,7 @@
 	spin_unlock(&c->space_lock);
 
 	if (free != d->saved_free) {
-		ubifs_err("free space changed from %lld to %lld",
+		ubifs_err(c, "free space changed from %lld to %lld",
 			  d->saved_free, free);
 		goto out;
 	}
@@ -1045,15 +1047,15 @@
 	return 0;
 
 out:
-	ubifs_msg("saved lprops statistics dump");
+	ubifs_msg(c, "saved lprops statistics dump");
 	ubifs_dump_lstats(&d->saved_lst);
-	ubifs_msg("saved budgeting info dump");
+	ubifs_msg(c, "saved budgeting info dump");
 	ubifs_dump_budg(c, &d->saved_bi);
-	ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
-	ubifs_msg("current lprops statistics dump");
+	ubifs_msg(c, "saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
+	ubifs_msg(c, "current lprops statistics dump");
 	ubifs_get_lp_stats(c, &lst);
 	ubifs_dump_lstats(&lst);
-	ubifs_msg("current budgeting info dump");
+	ubifs_msg(c, "current budgeting info dump");
 	ubifs_dump_budg(c, &c->bi);
 	dump_stack();
 	return -EINVAL;
@@ -1082,9 +1084,9 @@
 	mutex_lock(&ui->ui_mutex);
 	spin_lock(&ui->ui_lock);
 	if (ui->ui_size != ui->synced_i_size && !ui->dirty) {
-		ubifs_err("ui_size is %lld, synced_i_size is %lld, but inode is clean",
+		ubifs_err(c, "ui_size is %lld, synced_i_size is %lld, but inode is clean",
 			  ui->ui_size, ui->synced_i_size);
-		ubifs_err("i_ino %lu, i_mode %#x, i_size %lld", inode->i_ino,
+		ubifs_err(c, "i_ino %lu, i_mode %#x, i_size %lld", inode->i_ino,
 			  inode->i_mode, i_size_read(inode));
 		dump_stack();
 		err = -EINVAL;
@@ -1145,7 +1147,7 @@
 	kfree(pdent);
 
 	if (i_size_read(dir) != size) {
-		ubifs_err("directory inode %lu has size %llu, but calculated size is %llu",
+		ubifs_err(c, "directory inode %lu has size %llu, but calculated size is %llu",
 			  dir->i_ino, (unsigned long long)i_size_read(dir),
 			  (unsigned long long)size);
 		ubifs_dump_inode(c, dir);
@@ -1153,7 +1155,7 @@
 		return -EINVAL;
 	}
 	if (dir->i_nlink != nlink) {
-		ubifs_err("directory inode %lu has nlink %u, but calculated nlink is %u",
+		ubifs_err(c, "directory inode %lu has nlink %u, but calculated nlink is %u",
 			  dir->i_ino, dir->i_nlink, nlink);
 		ubifs_dump_inode(c, dir);
 		dump_stack();
@@ -1212,10 +1214,10 @@
 	err = 1;
 	key_read(c, &dent1->key, &key);
 	if (keys_cmp(c, &zbr1->key, &key)) {
-		ubifs_err("1st entry at %d:%d has key %s", zbr1->lnum,
+		ubifs_err(c, "1st entry at %d:%d has key %s", zbr1->lnum,
 			  zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
 						       DBG_KEY_BUF_LEN));
-		ubifs_err("but it should have key %s according to tnc",
+		ubifs_err(c, "but it should have key %s according to tnc",
 			  dbg_snprintf_key(c, &zbr1->key, key_buf,
 					   DBG_KEY_BUF_LEN));
 		ubifs_dump_node(c, dent1);
@@ -1224,10 +1226,10 @@
 
 	key_read(c, &dent2->key, &key);
 	if (keys_cmp(c, &zbr2->key, &key)) {
-		ubifs_err("2nd entry at %d:%d has key %s", zbr1->lnum,
+		ubifs_err(c, "2nd entry at %d:%d has key %s", zbr1->lnum,
 			  zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
 						       DBG_KEY_BUF_LEN));
-		ubifs_err("but it should have key %s according to tnc",
+		ubifs_err(c, "but it should have key %s according to tnc",
 			  dbg_snprintf_key(c, &zbr2->key, key_buf,
 					   DBG_KEY_BUF_LEN));
 		ubifs_dump_node(c, dent2);
@@ -1243,14 +1245,14 @@
 		goto out_free;
 	}
 	if (cmp == 0 && nlen1 == nlen2)
-		ubifs_err("2 xent/dent nodes with the same name");
+		ubifs_err(c, "2 xent/dent nodes with the same name");
 	else
-		ubifs_err("bad order of colliding key %s",
+		ubifs_err(c, "bad order of colliding key %s",
 			  dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 
-	ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
+	ubifs_msg(c, "first node at %d:%d\n", zbr1->lnum, zbr1->offs);
 	ubifs_dump_node(c, dent1);
-	ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
+	ubifs_msg(c, "second node at %d:%d\n", zbr2->lnum, zbr2->offs);
 	ubifs_dump_node(c, dent2);
 
 out_free:
@@ -1452,11 +1454,11 @@
 	return 0;
 
 out:
-	ubifs_err("failed, error %d", err);
-	ubifs_msg("dump of the znode");
+	ubifs_err(c, "failed, error %d", err);
+	ubifs_msg(c, "dump of the znode");
 	ubifs_dump_znode(c, znode);
 	if (zp) {
-		ubifs_msg("dump of the parent znode");
+		ubifs_msg(c, "dump of the parent znode");
 		ubifs_dump_znode(c, zp);
 	}
 	dump_stack();
@@ -1552,9 +1554,9 @@
 			if (err < 0)
 				return err;
 			if (err) {
-				ubifs_msg("first znode");
+				ubifs_msg(c, "first znode");
 				ubifs_dump_znode(c, prev);
-				ubifs_msg("second znode");
+				ubifs_msg(c, "second znode");
 				ubifs_dump_znode(c, znode);
 				return -EINVAL;
 			}
@@ -1563,13 +1565,13 @@
 
 	if (extra) {
 		if (clean_cnt != atomic_long_read(&c->clean_zn_cnt)) {
-			ubifs_err("incorrect clean_zn_cnt %ld, calculated %ld",
+			ubifs_err(c, "incorrect clean_zn_cnt %ld, calculated %ld",
 				  atomic_long_read(&c->clean_zn_cnt),
 				  clean_cnt);
 			return -EINVAL;
 		}
 		if (dirty_cnt != atomic_long_read(&c->dirty_zn_cnt)) {
-			ubifs_err("incorrect dirty_zn_cnt %ld, calculated %ld",
+			ubifs_err(c, "incorrect dirty_zn_cnt %ld, calculated %ld",
 				  atomic_long_read(&c->dirty_zn_cnt),
 				  dirty_cnt);
 			return -EINVAL;
@@ -1648,7 +1650,7 @@
 		if (znode_cb) {
 			err = znode_cb(c, znode, priv);
 			if (err) {
-				ubifs_err("znode checking function returned error %d",
+				ubifs_err(c, "znode checking function returned error %d",
 					  err);
 				ubifs_dump_znode(c, znode);
 				goto out_dump;
@@ -1659,7 +1661,7 @@
 				zbr = &znode->zbranch[idx];
 				err = leaf_cb(c, zbr, priv);
 				if (err) {
-					ubifs_err("leaf checking function returned error %d, for leaf at LEB %d:%d",
+					ubifs_err(c, "leaf checking function returned error %d, for leaf at LEB %d:%d",
 						  err, zbr->lnum, zbr->offs);
 					goto out_dump;
 				}
@@ -1715,7 +1717,7 @@
 		zbr = &znode->parent->zbranch[znode->iip];
 	else
 		zbr = &c->zroot;
-	ubifs_msg("dump of znode at LEB %d:%d", zbr->lnum, zbr->offs);
+	ubifs_msg(c, "dump of znode at LEB %d:%d", zbr->lnum, zbr->offs);
 	ubifs_dump_znode(c, znode);
 out_unlock:
 	mutex_unlock(&c->tnc_mutex);
@@ -1762,12 +1764,12 @@
 
 	err = dbg_walk_index(c, NULL, add_size, &calc);
 	if (err) {
-		ubifs_err("error %d while walking the index", err);
+		ubifs_err(c, "error %d while walking the index", err);
 		return err;
 	}
 
 	if (calc != idx_size) {
-		ubifs_err("index size check failed: calculated size is %lld, should be %lld",
+		ubifs_err(c, "index size check failed: calculated size is %lld, should be %lld",
 			  calc, idx_size);
 		dump_stack();
 		return -EINVAL;
@@ -1855,7 +1857,7 @@
 	}
 
 	if (inum > c->highest_inum) {
-		ubifs_err("too high inode number, max. is %lu",
+		ubifs_err(c, "too high inode number, max. is %lu",
 			  (unsigned long)c->highest_inum);
 		return ERR_PTR(-EINVAL);
 	}
@@ -1962,17 +1964,17 @@
 	ino_key_init(c, &key, inum);
 	err = ubifs_lookup_level0(c, &key, &znode, &n);
 	if (!err) {
-		ubifs_err("inode %lu not found in index", (unsigned long)inum);
+		ubifs_err(c, "inode %lu not found in index", (unsigned long)inum);
 		return ERR_PTR(-ENOENT);
 	} else if (err < 0) {
-		ubifs_err("error %d while looking up inode %lu",
+		ubifs_err(c, "error %d while looking up inode %lu",
 			  err, (unsigned long)inum);
 		return ERR_PTR(err);
 	}
 
 	zbr = &znode->zbranch[n];
 	if (zbr->len < UBIFS_INO_NODE_SZ) {
-		ubifs_err("bad node %lu node length %d",
+		ubifs_err(c, "bad node %lu node length %d",
 			  (unsigned long)inum, zbr->len);
 		return ERR_PTR(-EINVAL);
 	}
@@ -1983,7 +1985,7 @@
 
 	err = ubifs_tnc_read_node(c, zbr, ino);
 	if (err) {
-		ubifs_err("cannot read inode node at LEB %d:%d, error %d",
+		ubifs_err(c, "cannot read inode node at LEB %d:%d, error %d",
 			  zbr->lnum, zbr->offs, err);
 		kfree(ino);
 		return ERR_PTR(err);
@@ -1992,7 +1994,7 @@
 	fscki = add_inode(c, fsckd, ino);
 	kfree(ino);
 	if (IS_ERR(fscki)) {
-		ubifs_err("error %ld while adding inode %lu node",
+		ubifs_err(c, "error %ld while adding inode %lu node",
 			  PTR_ERR(fscki), (unsigned long)inum);
 		return fscki;
 	}
@@ -2026,7 +2028,7 @@
 	struct fsck_inode *fscki;
 
 	if (zbr->len < UBIFS_CH_SZ) {
-		ubifs_err("bad leaf length %d (LEB %d:%d)",
+		ubifs_err(c, "bad leaf length %d (LEB %d:%d)",
 			  zbr->len, zbr->lnum, zbr->offs);
 		return -EINVAL;
 	}
@@ -2037,7 +2039,7 @@
 
 	err = ubifs_tnc_read_node(c, zbr, node);
 	if (err) {
-		ubifs_err("cannot read leaf node at LEB %d:%d, error %d",
+		ubifs_err(c, "cannot read leaf node at LEB %d:%d, error %d",
 			  zbr->lnum, zbr->offs, err);
 		goto out_free;
 	}
@@ -2047,7 +2049,7 @@
 		fscki = add_inode(c, priv, node);
 		if (IS_ERR(fscki)) {
 			err = PTR_ERR(fscki);
-			ubifs_err("error %d while adding inode node", err);
+			ubifs_err(c, "error %d while adding inode node", err);
 			goto out_dump;
 		}
 		goto out;
@@ -2055,7 +2057,7 @@
 
 	if (type != UBIFS_DENT_KEY && type != UBIFS_XENT_KEY &&
 	    type != UBIFS_DATA_KEY) {
-		ubifs_err("unexpected node type %d at LEB %d:%d",
+		ubifs_err(c, "unexpected node type %d at LEB %d:%d",
 			  type, zbr->lnum, zbr->offs);
 		err = -EINVAL;
 		goto out_free;
@@ -2063,7 +2065,7 @@
 
 	ch = node;
 	if (le64_to_cpu(ch->sqnum) > c->max_sqnum) {
-		ubifs_err("too high sequence number, max. is %llu",
+		ubifs_err(c, "too high sequence number, max. is %llu",
 			  c->max_sqnum);
 		err = -EINVAL;
 		goto out_dump;
@@ -2073,6 +2075,8 @@
 		long long blk_offs;
 		struct ubifs_data_node *dn = node;
 
+		ubifs_assert(zbr->len >= UBIFS_DATA_NODE_SZ);
+
 		/*
 		 * Search the inode node this data node belongs to and insert
 		 * it to the RB-tree of inodes.
@@ -2081,7 +2085,7 @@
 		fscki = read_add_inode(c, priv, inum);
 		if (IS_ERR(fscki)) {
 			err = PTR_ERR(fscki);
-			ubifs_err("error %d while processing data node and trying to find inode node %lu",
+			ubifs_err(c, "error %d while processing data node and trying to find inode node %lu",
 				  err, (unsigned long)inum);
 			goto out_dump;
 		}
@@ -2091,7 +2095,7 @@
 		blk_offs <<= UBIFS_BLOCK_SHIFT;
 		blk_offs += le32_to_cpu(dn->size);
 		if (blk_offs > fscki->size) {
-			ubifs_err("data node at LEB %d:%d is not within inode size %lld",
+			ubifs_err(c, "data node at LEB %d:%d is not within inode size %lld",
 				  zbr->lnum, zbr->offs, fscki->size);
 			err = -EINVAL;
 			goto out_dump;
@@ -2101,6 +2105,8 @@
 		struct ubifs_dent_node *dent = node;
 		struct fsck_inode *fscki1;
 
+		ubifs_assert(zbr->len >= UBIFS_DENT_NODE_SZ);
+
 		err = ubifs_validate_entry(c, dent);
 		if (err)
 			goto out_dump;
@@ -2113,7 +2119,7 @@
 		fscki = read_add_inode(c, priv, inum);
 		if (IS_ERR(fscki)) {
 			err = PTR_ERR(fscki);
-			ubifs_err("error %d while processing entry node and trying to find inode node %lu",
+			ubifs_err(c, "error %d while processing entry node and trying to find inode node %lu",
 				  err, (unsigned long)inum);
 			goto out_dump;
 		}
@@ -2125,7 +2131,7 @@
 		fscki1 = read_add_inode(c, priv, inum);
 		if (IS_ERR(fscki1)) {
 			err = PTR_ERR(fscki1);
-			ubifs_err("error %d while processing entry node and trying to find parent inode node %lu",
+			ubifs_err(c, "error %d while processing entry node and trying to find parent inode node %lu",
 				  err, (unsigned long)inum);
 			goto out_dump;
 		}
@@ -2148,7 +2154,7 @@
 	return 0;
 
 out_dump:
-	ubifs_msg("dump of node at LEB %d:%d", zbr->lnum, zbr->offs);
+	ubifs_msg(c, "dump of node at LEB %d:%d", zbr->lnum, zbr->offs);
 	ubifs_dump_node(c, node);
 out_free:
 	kfree(node);
@@ -2199,52 +2205,52 @@
 			 */
 			if (fscki->inum != UBIFS_ROOT_INO &&
 			    fscki->references != 1) {
-				ubifs_err("directory inode %lu has %d direntries which refer it, but should be 1",
+				ubifs_err(c, "directory inode %lu has %d direntries which refer it, but should be 1",
 					  (unsigned long)fscki->inum,
 					  fscki->references);
 				goto out_dump;
 			}
 			if (fscki->inum == UBIFS_ROOT_INO &&
 			    fscki->references != 0) {
-				ubifs_err("root inode %lu has non-zero (%d) direntries which refer it",
+				ubifs_err(c, "root inode %lu has non-zero (%d) direntries which refer it",
 					  (unsigned long)fscki->inum,
 					  fscki->references);
 				goto out_dump;
 			}
 			if (fscki->calc_sz != fscki->size) {
-				ubifs_err("directory inode %lu size is %lld, but calculated size is %lld",
+				ubifs_err(c, "directory inode %lu size is %lld, but calculated size is %lld",
 					  (unsigned long)fscki->inum,
 					  fscki->size, fscki->calc_sz);
 				goto out_dump;
 			}
 			if (fscki->calc_cnt != fscki->nlink) {
-				ubifs_err("directory inode %lu nlink is %d, but calculated nlink is %d",
+				ubifs_err(c, "directory inode %lu nlink is %d, but calculated nlink is %d",
 					  (unsigned long)fscki->inum,
 					  fscki->nlink, fscki->calc_cnt);
 				goto out_dump;
 			}
 		} else {
 			if (fscki->references != fscki->nlink) {
-				ubifs_err("inode %lu nlink is %d, but calculated nlink is %d",
+				ubifs_err(c, "inode %lu nlink is %d, but calculated nlink is %d",
 					  (unsigned long)fscki->inum,
 					  fscki->nlink, fscki->references);
 				goto out_dump;
 			}
 		}
 		if (fscki->xattr_sz != fscki->calc_xsz) {
-			ubifs_err("inode %lu has xattr size %u, but calculated size is %lld",
+			ubifs_err(c, "inode %lu has xattr size %u, but calculated size is %lld",
 				  (unsigned long)fscki->inum, fscki->xattr_sz,
 				  fscki->calc_xsz);
 			goto out_dump;
 		}
 		if (fscki->xattr_cnt != fscki->calc_xcnt) {
-			ubifs_err("inode %lu has %u xattrs, but calculated count is %lld",
+			ubifs_err(c, "inode %lu has %u xattrs, but calculated count is %lld",
 				  (unsigned long)fscki->inum,
 				  fscki->xattr_cnt, fscki->calc_xcnt);
 			goto out_dump;
 		}
 		if (fscki->xattr_nms != fscki->calc_xnms) {
-			ubifs_err("inode %lu has xattr names' size %u, but calculated names' size is %lld",
+			ubifs_err(c, "inode %lu has xattr names' size %u, but calculated names' size is %lld",
 				  (unsigned long)fscki->inum, fscki->xattr_nms,
 				  fscki->calc_xnms);
 			goto out_dump;
@@ -2258,11 +2264,11 @@
 	ino_key_init(c, &key, fscki->inum);
 	err = ubifs_lookup_level0(c, &key, &znode, &n);
 	if (!err) {
-		ubifs_err("inode %lu not found in index",
+		ubifs_err(c, "inode %lu not found in index",
 			  (unsigned long)fscki->inum);
 		return -ENOENT;
 	} else if (err < 0) {
-		ubifs_err("error %d while looking up inode %lu",
+		ubifs_err(c, "error %d while looking up inode %lu",
 			  err, (unsigned long)fscki->inum);
 		return err;
 	}
@@ -2274,13 +2280,13 @@
 
 	err = ubifs_tnc_read_node(c, zbr, ino);
 	if (err) {
-		ubifs_err("cannot read inode node at LEB %d:%d, error %d",
+		ubifs_err(c, "cannot read inode node at LEB %d:%d, error %d",
 			  zbr->lnum, zbr->offs, err);
 		kfree(ino);
 		return err;
 	}
 
-	ubifs_msg("dump of the inode %lu sitting in LEB %d:%d",
+	ubifs_msg(c, "dump of the inode %lu sitting in LEB %d:%d",
 		  (unsigned long)fscki->inum, zbr->lnum, zbr->offs);
 	ubifs_dump_node(c, ino);
 	kfree(ino);
@@ -2321,7 +2327,7 @@
 	return 0;
 
 out_free:
-	ubifs_err("file-system check failed with error %d", err);
+	ubifs_err(c, "file-system check failed with error %d", err);
 	dump_stack();
 	free_inodes(&fsckd);
 	return err;
@@ -2352,12 +2358,12 @@
 		sb = container_of(cur->next, struct ubifs_scan_node, list);
 
 		if (sa->type != UBIFS_DATA_NODE) {
-			ubifs_err("bad node type %d", sa->type);
+			ubifs_err(c, "bad node type %d", sa->type);
 			ubifs_dump_node(c, sa->node);
 			return -EINVAL;
 		}
 		if (sb->type != UBIFS_DATA_NODE) {
-			ubifs_err("bad node type %d", sb->type);
+			ubifs_err(c, "bad node type %d", sb->type);
 			ubifs_dump_node(c, sb->node);
 			return -EINVAL;
 		}
@@ -2368,7 +2374,7 @@
 		if (inuma < inumb)
 			continue;
 		if (inuma > inumb) {
-			ubifs_err("larger inum %lu goes before inum %lu",
+			ubifs_err(c, "larger inum %lu goes before inum %lu",
 				  (unsigned long)inuma, (unsigned long)inumb);
 			goto error_dump;
 		}
@@ -2377,11 +2383,11 @@
 		blkb = key_block(c, &sb->key);
 
 		if (blka > blkb) {
-			ubifs_err("larger block %u goes before %u", blka, blkb);
+			ubifs_err(c, "larger block %u goes before %u", blka, blkb);
 			goto error_dump;
 		}
 		if (blka == blkb) {
-			ubifs_err("two data nodes for the same block");
+			ubifs_err(c, "two data nodes for the same block");
 			goto error_dump;
 		}
 	}
@@ -2420,19 +2426,19 @@
 
 		if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
 		    sa->type != UBIFS_XENT_NODE) {
-			ubifs_err("bad node type %d", sa->type);
+			ubifs_err(c, "bad node type %d", sa->type);
 			ubifs_dump_node(c, sa->node);
 			return -EINVAL;
 		}
 		if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
 		    sa->type != UBIFS_XENT_NODE) {
-			ubifs_err("bad node type %d", sb->type);
+			ubifs_err(c, "bad node type %d", sb->type);
 			ubifs_dump_node(c, sb->node);
 			return -EINVAL;
 		}
 
 		if (sa->type != UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
-			ubifs_err("non-inode node goes before inode node");
+			ubifs_err(c, "non-inode node goes before inode node");
 			goto error_dump;
 		}
 
@@ -2442,7 +2448,7 @@
 		if (sa->type == UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
 			/* Inode nodes are sorted in descending size order */
 			if (sa->len < sb->len) {
-				ubifs_err("smaller inode node goes first");
+				ubifs_err(c, "smaller inode node goes first");
 				goto error_dump;
 			}
 			continue;
@@ -2458,7 +2464,7 @@
 		if (inuma < inumb)
 			continue;
 		if (inuma > inumb) {
-			ubifs_err("larger inum %lu goes before inum %lu",
+			ubifs_err(c, "larger inum %lu goes before inum %lu",
 				  (unsigned long)inuma, (unsigned long)inumb);
 			goto error_dump;
 		}
@@ -2467,7 +2473,7 @@
 		hashb = key_block(c, &sb->key);
 
 		if (hasha > hashb) {
-			ubifs_err("larger hash %u goes before %u",
+			ubifs_err(c, "larger hash %u goes before %u",
 				  hasha, hashb);
 			goto error_dump;
 		}
@@ -2476,9 +2482,9 @@
 	return 0;
 
 error_dump:
-	ubifs_msg("dumping first node");
+	ubifs_msg(c, "dumping first node");
 	ubifs_dump_node(c, sa->node);
-	ubifs_msg("dumping second node");
+	ubifs_msg(c, "dumping second node");
 	ubifs_dump_node(c, sb->node);
 	return -EINVAL;
 	return 0;
@@ -2503,17 +2509,17 @@
 
 			if (chance(1, 2)) {
 				d->pc_delay = 1;
-				/* Fail withing 1 minute */
+				/* Fail within 1 minute */
 				delay = prandom_u32() % 60000;
 				d->pc_timeout = jiffies;
 				d->pc_timeout += msecs_to_jiffies(delay);
-				ubifs_warn("failing after %lums", delay);
+				ubifs_warn(c, "failing after %lums", delay);
 			} else {
 				d->pc_delay = 2;
 				delay = prandom_u32() % 10000;
 				/* Fail within 10000 operations */
 				d->pc_cnt_max = delay;
-				ubifs_warn("failing after %lu calls", delay);
+				ubifs_warn(c, "failing after %lu calls", delay);
 			}
 		}
 
@@ -2531,55 +2537,55 @@
 			return 0;
 		if (chance(19, 20))
 			return 0;
-		ubifs_warn("failing in super block LEB %d", lnum);
+		ubifs_warn(c, "failing in super block LEB %d", lnum);
 	} else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
 		if (chance(19, 20))
 			return 0;
-		ubifs_warn("failing in master LEB %d", lnum);
+		ubifs_warn(c, "failing in master LEB %d", lnum);
 	} else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
 		if (write && chance(99, 100))
 			return 0;
 		if (chance(399, 400))
 			return 0;
-		ubifs_warn("failing in log LEB %d", lnum);
+		ubifs_warn(c, "failing in log LEB %d", lnum);
 	} else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
 		if (write && chance(7, 8))
 			return 0;
 		if (chance(19, 20))
 			return 0;
-		ubifs_warn("failing in LPT LEB %d", lnum);
+		ubifs_warn(c, "failing in LPT LEB %d", lnum);
 	} else if (lnum >= c->orph_first && lnum <= c->orph_last) {
 		if (write && chance(1, 2))
 			return 0;
 		if (chance(9, 10))
 			return 0;
-		ubifs_warn("failing in orphan LEB %d", lnum);
+		ubifs_warn(c, "failing in orphan LEB %d", lnum);
 	} else if (lnum == c->ihead_lnum) {
 		if (chance(99, 100))
 			return 0;
-		ubifs_warn("failing in index head LEB %d", lnum);
+		ubifs_warn(c, "failing in index head LEB %d", lnum);
 	} else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
 		if (chance(9, 10))
 			return 0;
-		ubifs_warn("failing in GC head LEB %d", lnum);
+		ubifs_warn(c, "failing in GC head LEB %d", lnum);
 	} else if (write && !RB_EMPTY_ROOT(&c->buds) &&
 		   !ubifs_search_bud(c, lnum)) {
 		if (chance(19, 20))
 			return 0;
-		ubifs_warn("failing in non-bud LEB %d", lnum);
+		ubifs_warn(c, "failing in non-bud LEB %d", lnum);
 	} else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
 		   c->cmt_state == COMMIT_RUNNING_REQUIRED) {
 		if (chance(999, 1000))
 			return 0;
-		ubifs_warn("failing in bud LEB %d commit running", lnum);
+		ubifs_warn(c, "failing in bud LEB %d commit running", lnum);
 	} else {
 		if (chance(9999, 10000))
 			return 0;
-		ubifs_warn("failing in bud LEB %d commit not running", lnum);
+		ubifs_warn(c, "failing in bud LEB %d commit not running", lnum);
 	}
 
 	d->pc_happened = 1;
-	ubifs_warn("========== Power cut emulated ==========");
+	ubifs_warn(c, "========== Power cut emulated ==========");
 	dump_stack();
 	return 1;
 }
@@ -2594,7 +2600,7 @@
 	/* Corruption span max to end of write unit */
 	to = min(len, ALIGN(from + 1, c->max_write_size));
 
-	ubifs_warn("filled bytes %u-%u with %s", from, to - 1,
+	ubifs_warn(c, "filled bytes %u-%u with %s", from, to - 1,
 		   ffs ? "0xFFs" : "random data");
 
 	if (ffs)
@@ -2616,7 +2622,7 @@
 	failing = power_cut_emulated(c, lnum, 1);
 	if (failing) {
 		len = corrupt_data(c, buf, len);
-		ubifs_warn("actually write %d bytes to LEB %d:%d (the buffer was corrupted)",
+		ubifs_warn(c, "actually write %d bytes to LEB %d:%d (the buffer was corrupted)",
 			   len, lnum, offs);
 	}
 	err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
@@ -2946,7 +2952,7 @@
 	debugfs_remove_recursive(d->dfs_dir);
 out:
 	err = dent ? PTR_ERR(dent) : -ENODEV;
-	ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
+	ubifs_err(c, "cannot create \"%s\" debugfs file or directory, error %d\n",
 		  fname, err);
 	return err;
 }
@@ -3100,8 +3106,8 @@
 	debugfs_remove_recursive(dfs_rootdir);
 out:
 	err = dent ? PTR_ERR(dent) : -ENODEV;
-	ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
-		  fname, err);
+	pr_err("UBIFS error (pid %d): cannot create \"%s\" debugfs file or directory, error %d\n",
+	       current->pid, fname, err);
 	return err;
 }
 
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index bdccdc4..51a95bb 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -79,7 +79,7 @@
 		c->ro_error = 1;
 		c->no_chk_data_crc = 0;
 		c->vfs_sb->s_flags |= MS_RDONLY;
-		ubifs_warn("switched to read-only mode, error %d", err);
+		ubifs_warn(c, "switched to read-only mode, error %d", err);
 		dump_stack();
 	}
 }
@@ -101,7 +101,7 @@
 	 * @even_ebadmsg is true.
 	 */
 	if (err && (err != -EBADMSG || even_ebadmsg)) {
-		ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
+		ubifs_err(c, "reading %d bytes from LEB %d:%d failed, error %d",
 			  len, lnum, offs, err);
 		dump_stack();
 	}
@@ -118,10 +118,12 @@
 		return -EROFS;
 	if (!dbg_is_tst_rcvry(c))
 		err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
+#ifndef __UBOOT__
 	else
 		err = dbg_leb_write(c, lnum, buf, offs, len);
+#endif
 	if (err) {
-		ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
+		ubifs_err(c, "writing %d bytes to LEB %d:%d failed, error %d",
 			  len, lnum, offs, err);
 		ubifs_ro_mode(c, err);
 		dump_stack();
@@ -138,10 +140,12 @@
 		return -EROFS;
 	if (!dbg_is_tst_rcvry(c))
 		err = ubi_leb_change(c->ubi, lnum, buf, len);
+#ifndef __UBOOT__
 	else
 		err = dbg_leb_change(c, lnum, buf, len);
+#endif
 	if (err) {
-		ubifs_err("changing %d bytes in LEB %d failed, error %d",
+		ubifs_err(c, "changing %d bytes in LEB %d failed, error %d",
 			  len, lnum, err);
 		ubifs_ro_mode(c, err);
 		dump_stack();
@@ -158,10 +162,12 @@
 		return -EROFS;
 	if (!dbg_is_tst_rcvry(c))
 		err = ubi_leb_unmap(c->ubi, lnum);
+#ifndef __UBOOT__
 	else
 		err = dbg_leb_unmap(c, lnum);
+#endif
 	if (err) {
-		ubifs_err("unmap LEB %d failed, error %d", lnum, err);
+		ubifs_err(c, "unmap LEB %d failed, error %d", lnum, err);
 		ubifs_ro_mode(c, err);
 		dump_stack();
 	}
@@ -177,10 +183,12 @@
 		return -EROFS;
 	if (!dbg_is_tst_rcvry(c))
 		err = ubi_leb_map(c->ubi, lnum);
+#ifndef __UBOOT__
 	else
 		err = dbg_leb_map(c, lnum);
+#endif
 	if (err) {
-		ubifs_err("mapping LEB %d failed, error %d", lnum, err);
+		ubifs_err(c, "mapping LEB %d failed, error %d", lnum, err);
 		ubifs_ro_mode(c, err);
 		dump_stack();
 	}
@@ -193,7 +201,7 @@
 
 	err = ubi_is_mapped(c->ubi, lnum);
 	if (err < 0) {
-		ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
+		ubifs_err(c, "ubi_is_mapped failed for LEB %d, error %d",
 			  lnum, err);
 		dump_stack();
 	}
@@ -241,7 +249,7 @@
 	magic = le32_to_cpu(ch->magic);
 	if (magic != UBIFS_NODE_MAGIC) {
 		if (!quiet)
-			ubifs_err("bad magic %#08x, expected %#08x",
+			ubifs_err(c, "bad magic %#08x, expected %#08x",
 				  magic, UBIFS_NODE_MAGIC);
 		err = -EUCLEAN;
 		goto out;
@@ -250,7 +258,7 @@
 	type = ch->node_type;
 	if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) {
 		if (!quiet)
-			ubifs_err("bad node type %d", type);
+			ubifs_err(c, "bad node type %d", type);
 		goto out;
 	}
 
@@ -273,7 +281,7 @@
 	node_crc = le32_to_cpu(ch->crc);
 	if (crc != node_crc) {
 		if (!quiet)
-			ubifs_err("bad CRC: calculated %#08x, read %#08x",
+			ubifs_err(c, "bad CRC: calculated %#08x, read %#08x",
 				  crc, node_crc);
 		err = -EUCLEAN;
 		goto out;
@@ -283,10 +291,10 @@
 
 out_len:
 	if (!quiet)
-		ubifs_err("bad node length %d", node_len);
+		ubifs_err(c, "bad node length %d", node_len);
 out:
 	if (!quiet) {
-		ubifs_err("bad node at LEB %d:%d", lnum, offs);
+		ubifs_err(c, "bad node at LEB %d:%d", lnum, offs);
 		ubifs_dump_node(c, buf);
 		dump_stack();
 	}
@@ -349,11 +357,11 @@
 
 	if (unlikely(sqnum >= SQNUM_WARN_WATERMARK)) {
 		if (sqnum >= SQNUM_WATERMARK) {
-			ubifs_err("sequence number overflow %llu, end of life",
+			ubifs_err(c, "sequence number overflow %llu, end of life",
 				  sqnum);
 			ubifs_ro_mode(c, -EINVAL);
 		}
-		ubifs_warn("running out of sequence numbers, end of life soon");
+		ubifs_warn(c, "running out of sequence numbers, end of life soon");
 	}
 
 	return sqnum;
@@ -426,7 +434,7 @@
 #ifndef __UBOOT__
 /**
  * wbuf_timer_callback - write-buffer timer callback function.
- * @data: timer data (write-buffer descriptor)
+ * @timer: timer data (write-buffer descriptor)
  *
  * This function is called when the write-buffer timer expires.
  */
@@ -635,7 +643,7 @@
 		err = ubifs_wbuf_sync_nolock(wbuf);
 		mutex_unlock(&wbuf->io_mutex);
 		if (err) {
-			ubifs_err("cannot sync write-buffer, error %d", err);
+			ubifs_err(c, "cannot sync write-buffer, error %d", err);
 			ubifs_ro_mode(c, err);
 			goto out_timers;
 		}
@@ -832,7 +840,7 @@
 	return 0;
 
 out:
-	ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
+	ubifs_err(c, "cannot write %d bytes to LEB %d:%d, error %d",
 		  len, wbuf->lnum, wbuf->offs, err);
 	ubifs_dump_node(c, buf);
 	dump_stack();
@@ -932,27 +940,27 @@
 	}
 
 	if (type != ch->node_type) {
-		ubifs_err("bad node type (%d but expected %d)",
+		ubifs_err(c, "bad node type (%d but expected %d)",
 			  ch->node_type, type);
 		goto out;
 	}
 
 	err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
 	if (err) {
-		ubifs_err("expected node type %d", type);
+		ubifs_err(c, "expected node type %d", type);
 		return err;
 	}
 
 	rlen = le32_to_cpu(ch->len);
 	if (rlen != len) {
-		ubifs_err("bad node length %d, expected %d", rlen, len);
+		ubifs_err(c, "bad node length %d, expected %d", rlen, len);
 		goto out;
 	}
 
 	return 0;
 
 out:
-	ubifs_err("bad node at LEB %d:%d", lnum, offs);
+	ubifs_err(c, "bad node at LEB %d:%d", lnum, offs);
 	ubifs_dump_node(c, buf);
 	dump_stack();
 	return -EINVAL;
@@ -988,30 +996,32 @@
 		return err;
 
 	if (type != ch->node_type) {
-		ubifs_err("bad node type (%d but expected %d)",
-			  ch->node_type, type);
+		ubifs_errc(c, "bad node type (%d but expected %d)",
+			   ch->node_type, type);
 		goto out;
 	}
 
 	err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
 	if (err) {
-		ubifs_err("expected node type %d", type);
+		ubifs_errc(c, "expected node type %d", type);
 		return err;
 	}
 
 	l = le32_to_cpu(ch->len);
 	if (l != len) {
-		ubifs_err("bad node length %d, expected %d", l, len);
+		ubifs_errc(c, "bad node length %d, expected %d", l, len);
 		goto out;
 	}
 
 	return 0;
 
 out:
-	ubifs_err("bad node at LEB %d:%d, LEB mapping status %d", lnum, offs,
-		  ubi_is_mapped(c->ubi, lnum));
-	ubifs_dump_node(c, buf);
-	dump_stack();
+	ubifs_errc(c, "bad node at LEB %d:%d, LEB mapping status %d", lnum,
+		   offs, ubi_is_mapped(c->ubi, lnum));
+	if (!c->probing) {
+		ubifs_dump_node(c, buf);
+		dump_stack();
+	}
 	return -EINVAL;
 }
 
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index 0355fe2..a07fdef 100644
--- a/fs/ubifs/log.c
+++ b/fs/ubifs/log.c
@@ -98,10 +98,14 @@
 	h = (long long)c->lhead_lnum * c->leb_size + c->lhead_offs;
 	t = (long long)c->ltail_lnum * c->leb_size;
 
-	if (h >= t)
+	if (h > t)
 		return c->log_bytes - h + t;
-	else
+	else if (h != t)
 		return t - h;
+	else if (c->lhead_lnum != c->ltail_lnum)
+		return 0;
+	else
+		return c->log_bytes;
 }
 
 /**
@@ -232,6 +236,7 @@
 
 	if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
 		c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+		ubifs_assert(c->lhead_lnum != c->ltail_lnum);
 		c->lhead_offs = 0;
 	}
 
@@ -396,15 +401,14 @@
 	/* Switch to the next log LEB */
 	if (c->lhead_offs) {
 		c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+		ubifs_assert(c->lhead_lnum != c->ltail_lnum);
 		c->lhead_offs = 0;
 	}
 
-	if (c->lhead_offs == 0) {
-		/* Must ensure next LEB has been unmapped */
-		err = ubifs_leb_unmap(c, c->lhead_lnum);
-		if (err)
-			goto out;
-	}
+	/* Must ensure next LEB has been unmapped */
+	err = ubifs_leb_unmap(c, c->lhead_lnum);
+	if (err)
+		goto out;
 
 	len = ALIGN(len, c->min_io_size);
 	dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len);
@@ -439,9 +443,9 @@
  * @ltail_lnum: new log tail LEB number
  *
  * This function is called on when the commit operation was finished. It
- * moves log tail to new position and unmaps LEBs which contain obsolete data.
- * Returns zero in case of success and a negative error code in case of
- * failure.
+ * moves log tail to new position and updates the master node so that it stores
+ * the new log tail LEB number. Returns zero in case of success and a negative
+ * error code in case of failure.
  */
 int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum)
 {
@@ -469,7 +473,12 @@
 	spin_unlock(&c->buds_lock);
 
 	err = dbg_check_bud_bytes(c);
+	if (err)
+		goto out;
 
+	err = ubifs_write_master(c);
+
+out:
 	mutex_unlock(&c->log_mutex);
 	return err;
 }
@@ -679,7 +688,7 @@
 	destroy_done_tree(&done_tree);
 	vfree(buf);
 	if (write_lnum == c->lhead_lnum) {
-		ubifs_err("log is too full");
+		ubifs_err(c, "log is too full");
 		return -EINVAL;
 	}
 	/* Unmap remaining LEBs */
@@ -726,7 +735,7 @@
 			bud_bytes += c->leb_size - bud->start;
 
 	if (c->bud_bytes != bud_bytes) {
-		ubifs_err("bad bud_bytes %lld, calculated %lld",
+		ubifs_err(c, "bad bud_bytes %lld, calculated %lld",
 			  c->bud_bytes, bud_bytes);
 		err = -EINVAL;
 	}
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index a1a814f..292ea7a 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -674,7 +674,7 @@
 out:
 	ubifs_release_lprops(c);
 	if (err)
-		ubifs_err("cannot change properties of LEB %d, error %d",
+		ubifs_err(c, "cannot change properties of LEB %d, error %d",
 			  lnum, err);
 	return err;
 }
@@ -713,7 +713,7 @@
 out:
 	ubifs_release_lprops(c);
 	if (err)
-		ubifs_err("cannot update properties of LEB %d, error %d",
+		ubifs_err(c, "cannot update properties of LEB %d, error %d",
 			  lnum, err);
 	return err;
 }
@@ -738,7 +738,7 @@
 	lpp = ubifs_lpt_lookup(c, lnum);
 	if (IS_ERR(lpp)) {
 		err = PTR_ERR(lpp);
-		ubifs_err("cannot read properties of LEB %d, error %d",
+		ubifs_err(c, "cannot read properties of LEB %d, error %d",
 			  lnum, err);
 		goto out;
 	}
@@ -865,13 +865,13 @@
 
 	list_for_each_entry(lprops, &c->empty_list, list) {
 		if (lprops->free != c->leb_size) {
-			ubifs_err("non-empty LEB %d on empty list (free %d dirty %d flags %d)",
+			ubifs_err(c, "non-empty LEB %d on empty list (free %d dirty %d flags %d)",
 				  lprops->lnum, lprops->free, lprops->dirty,
 				  lprops->flags);
 			return -EINVAL;
 		}
 		if (lprops->flags & LPROPS_TAKEN) {
-			ubifs_err("taken LEB %d on empty list (free %d dirty %d flags %d)",
+			ubifs_err(c, "taken LEB %d on empty list (free %d dirty %d flags %d)",
 				  lprops->lnum, lprops->free, lprops->dirty,
 				  lprops->flags);
 			return -EINVAL;
@@ -881,13 +881,13 @@
 	i = 0;
 	list_for_each_entry(lprops, &c->freeable_list, list) {
 		if (lprops->free + lprops->dirty != c->leb_size) {
-			ubifs_err("non-freeable LEB %d on freeable list (free %d dirty %d flags %d)",
+			ubifs_err(c, "non-freeable LEB %d on freeable list (free %d dirty %d flags %d)",
 				  lprops->lnum, lprops->free, lprops->dirty,
 				  lprops->flags);
 			return -EINVAL;
 		}
 		if (lprops->flags & LPROPS_TAKEN) {
-			ubifs_err("taken LEB %d on freeable list (free %d dirty %d flags %d)",
+			ubifs_err(c, "taken LEB %d on freeable list (free %d dirty %d flags %d)",
 				  lprops->lnum, lprops->free, lprops->dirty,
 				  lprops->flags);
 			return -EINVAL;
@@ -895,7 +895,7 @@
 		i += 1;
 	}
 	if (i != c->freeable_cnt) {
-		ubifs_err("freeable list count %d expected %d", i,
+		ubifs_err(c, "freeable list count %d expected %d", i,
 			  c->freeable_cnt);
 		return -EINVAL;
 	}
@@ -904,26 +904,26 @@
 	list_for_each(pos, &c->idx_gc)
 		i += 1;
 	if (i != c->idx_gc_cnt) {
-		ubifs_err("idx_gc list count %d expected %d", i,
+		ubifs_err(c, "idx_gc list count %d expected %d", i,
 			  c->idx_gc_cnt);
 		return -EINVAL;
 	}
 
 	list_for_each_entry(lprops, &c->frdi_idx_list, list) {
 		if (lprops->free + lprops->dirty != c->leb_size) {
-			ubifs_err("non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)",
+			ubifs_err(c, "non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)",
 				  lprops->lnum, lprops->free, lprops->dirty,
 				  lprops->flags);
 			return -EINVAL;
 		}
 		if (lprops->flags & LPROPS_TAKEN) {
-			ubifs_err("taken LEB %d on frdi_idx list (free %d dirty %d flags %d)",
+			ubifs_err(c, "taken LEB %d on frdi_idx list (free %d dirty %d flags %d)",
 				  lprops->lnum, lprops->free, lprops->dirty,
 				  lprops->flags);
 			return -EINVAL;
 		}
 		if (!(lprops->flags & LPROPS_INDEX)) {
-			ubifs_err("non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)",
+			ubifs_err(c, "non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)",
 				  lprops->lnum, lprops->free, lprops->dirty,
 				  lprops->flags);
 			return -EINVAL;
@@ -936,15 +936,15 @@
 		for (i = 0; i < heap->cnt; i++) {
 			lprops = heap->arr[i];
 			if (!lprops) {
-				ubifs_err("null ptr in LPT heap cat %d", cat);
+				ubifs_err(c, "null ptr in LPT heap cat %d", cat);
 				return -EINVAL;
 			}
 			if (lprops->hpos != i) {
-				ubifs_err("bad ptr in LPT heap cat %d", cat);
+				ubifs_err(c, "bad ptr in LPT heap cat %d", cat);
 				return -EINVAL;
 			}
 			if (lprops->flags & LPROPS_TAKEN) {
-				ubifs_err("taken LEB in LPT heap cat %d", cat);
+				ubifs_err(c, "taken LEB in LPT heap cat %d", cat);
 				return -EINVAL;
 			}
 		}
@@ -980,7 +980,7 @@
 			goto out;
 		}
 		if (lprops != lp) {
-			ubifs_err("lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
+			ubifs_err(c, "lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
 				  (size_t)lprops, (size_t)lp, lprops->lnum,
 				  lp->lnum);
 			err = 4;
@@ -1000,7 +1000,7 @@
 	}
 out:
 	if (err) {
-		ubifs_err("failed cat %d hpos %d err %d", cat, i, err);
+		ubifs_err(c, "failed cat %d hpos %d err %d", cat, i, err);
 		dump_stack();
 		ubifs_dump_heap(c, heap, cat);
 	}
@@ -1024,14 +1024,14 @@
 {
 	struct ubifs_scan_leb *sleb;
 	struct ubifs_scan_node *snod;
-	int cat, lnum = lp->lnum, is_idx = 0, used = 0, freef, dirty, ret;
+	int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
 	void *buf = NULL;
 
 	cat = lp->flags & LPROPS_CAT_MASK;
 	if (cat != LPROPS_UNCAT) {
 		cat = ubifs_categorize_lprops(c, lp);
 		if (cat != (lp->flags & LPROPS_CAT_MASK)) {
-			ubifs_err("bad LEB category %d expected %d",
+			ubifs_err(c, "bad LEB category %d expected %d",
 				  (lp->flags & LPROPS_CAT_MASK), cat);
 			return -EINVAL;
 		}
@@ -1066,7 +1066,7 @@
 				}
 			}
 			if (!found) {
-				ubifs_err("bad LPT list (category %d)", cat);
+				ubifs_err(c, "bad LPT list (category %d)", cat);
 				return -EINVAL;
 			}
 		}
@@ -1078,7 +1078,7 @@
 
 		if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
 		    lp != heap->arr[lp->hpos]) {
-			ubifs_err("bad LPT heap (category %d)", cat);
+			ubifs_err(c, "bad LPT heap (category %d)", cat);
 			return -EINVAL;
 		}
 	}
@@ -1125,7 +1125,7 @@
 			is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
 
 		if (is_idx && snod->type != UBIFS_IDX_NODE) {
-			ubifs_err("indexing node in data LEB %d:%d",
+			ubifs_err(c, "indexing node in data LEB %d:%d",
 				  lnum, snod->offs);
 			goto out_destroy;
 		}
@@ -1146,20 +1146,20 @@
 		}
 	}
 
-	freef = c->leb_size - sleb->endpt;
+	free = c->leb_size - sleb->endpt;
 	dirty = sleb->endpt - used;
 
-	if (freef > c->leb_size || freef < 0 || dirty > c->leb_size ||
+	if (free > c->leb_size || free < 0 || dirty > c->leb_size ||
 	    dirty < 0) {
-		ubifs_err("bad calculated accounting for LEB %d: free %d, dirty %d",
-			  lnum, freef, dirty);
+		ubifs_err(c, "bad calculated accounting for LEB %d: free %d, dirty %d",
+			  lnum, free, dirty);
 		goto out_destroy;
 	}
 
 	if (lp->free + lp->dirty == c->leb_size &&
-	    freef + dirty == c->leb_size)
+	    free + dirty == c->leb_size)
 		if ((is_idx && !(lp->flags & LPROPS_INDEX)) ||
-		    (!is_idx && freef == c->leb_size) ||
+		    (!is_idx && free == c->leb_size) ||
 		    lp->free == c->leb_size) {
 			/*
 			 * Empty or freeable LEBs could contain index
@@ -1168,12 +1168,12 @@
 			 * the same reason. Or it may simply not have been
 			 * unmapped.
 			 */
-			freef = lp->free;
+			free = lp->free;
 			dirty = lp->dirty;
 			is_idx = 0;
 		    }
 
-	if (is_idx && lp->free + lp->dirty == freef + dirty &&
+	if (is_idx && lp->free + lp->dirty == free + dirty &&
 	    lnum != c->ihead_lnum) {
 		/*
 		 * After an unclean unmount, an index LEB could have a different
@@ -1186,41 +1186,41 @@
 		 * write to the free space at the end of an index LEB - except
 		 * by the in-the-gaps method for which it is not a problem.
 		 */
-		freef = lp->free;
+		free = lp->free;
 		dirty = lp->dirty;
 	}
 
-	if (lp->free != freef || lp->dirty != dirty)
+	if (lp->free != free || lp->dirty != dirty)
 		goto out_print;
 
 	if (is_idx && !(lp->flags & LPROPS_INDEX)) {
-		if (freef == c->leb_size)
+		if (free == c->leb_size)
 			/* Free but not unmapped LEB, it's fine */
 			is_idx = 0;
 		else {
-			ubifs_err("indexing node without indexing flag");
+			ubifs_err(c, "indexing node without indexing flag");
 			goto out_print;
 		}
 	}
 
 	if (!is_idx && (lp->flags & LPROPS_INDEX)) {
-		ubifs_err("data node with indexing flag");
+		ubifs_err(c, "data node with indexing flag");
 		goto out_print;
 	}
 
-	if (freef == c->leb_size)
+	if (free == c->leb_size)
 		lst->empty_lebs += 1;
 
 	if (is_idx)
 		lst->idx_lebs += 1;
 
 	if (!(lp->flags & LPROPS_INDEX))
-		lst->total_used += c->leb_size - freef - dirty;
-	lst->total_free += freef;
+		lst->total_used += c->leb_size - free - dirty;
+	lst->total_free += free;
 	lst->total_dirty += dirty;
 
 	if (!(lp->flags & LPROPS_INDEX)) {
-		int spc = freef + dirty;
+		int spc = free + dirty;
 
 		if (spc < c->dead_wm)
 			lst->total_dead += spc;
@@ -1233,8 +1233,8 @@
 	return LPT_SCAN_CONTINUE;
 
 out_print:
-	ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d",
-		  lnum, lp->free, lp->dirty, lp->flags, freef, dirty);
+	ubifs_err(c, "bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d",
+		  lnum, lp->free, lp->dirty, lp->flags, free, dirty);
 	ubifs_dump_leb(c, lnum);
 out_destroy:
 	ubifs_scan_destroy(sleb);
@@ -1285,11 +1285,11 @@
 	    lst.total_free != c->lst.total_free ||
 	    lst.total_dirty != c->lst.total_dirty ||
 	    lst.total_used != c->lst.total_used) {
-		ubifs_err("bad overall accounting");
-		ubifs_err("calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
+		ubifs_err(c, "bad overall accounting");
+		ubifs_err(c, "calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
 			  lst.empty_lebs, lst.idx_lebs, lst.total_free,
 			  lst.total_dirty, lst.total_used);
-		ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
+		ubifs_err(c, "read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
 			  c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
 			  c->lst.total_dirty, c->lst.total_used);
 		err = -EINVAL;
@@ -1298,10 +1298,10 @@
 
 	if (lst.total_dead != c->lst.total_dead ||
 	    lst.total_dark != c->lst.total_dark) {
-		ubifs_err("bad dead/dark space accounting");
-		ubifs_err("calculated: total_dead %lld, total_dark %lld",
+		ubifs_err(c, "bad dead/dark space accounting");
+		ubifs_err(c, "calculated: total_dead %lld, total_dark %lld",
 			  lst.total_dead, lst.total_dark);
-		ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
+		ubifs_err(c, "read from lprops: total_dead %lld, total_dark %lld",
 			  c->lst.total_dead, c->lst.total_dark);
 		err = -EINVAL;
 		goto out;
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
index 8489e90..b22b63b 100644
--- a/fs/ubifs/lpt.c
+++ b/fs/ubifs/lpt.c
@@ -141,13 +141,13 @@
 	sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
 	lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
 	if (lebs_needed > c->lpt_lebs) {
-		ubifs_err("too few LPT LEBs");
+		ubifs_err(c, "too few LPT LEBs");
 		return -EINVAL;
 	}
 
 	/* Verify that ltab fits in a single LEB (since ltab is a single node */
 	if (c->ltab_sz > c->leb_size) {
-		ubifs_err("LPT ltab too big");
+		ubifs_err(c, "LPT ltab too big");
 		return -EINVAL;
 	}
 
@@ -209,7 +209,7 @@
 			continue;
 		}
 		if (c->ltab_sz > c->leb_size) {
-			ubifs_err("LPT ltab too big");
+			ubifs_err(c, "LPT ltab too big");
 			return -EINVAL;
 		}
 		*main_lebs = c->main_lebs;
@@ -907,7 +907,7 @@
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int check_lpt_crc(void *buf, int len)
+static int check_lpt_crc(const struct ubifs_info *c, void *buf, int len)
 {
 	int pos = 0;
 	uint8_t *addr = buf;
@@ -917,8 +917,8 @@
 	calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
 			 len - UBIFS_LPT_CRC_BYTES);
 	if (crc != calc_crc) {
-		ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc,
-			  calc_crc);
+		ubifs_err(c, "invalid crc in LPT node: crc %hx calc %hx",
+			  crc, calc_crc);
 		dump_stack();
 		return -EINVAL;
 	}
@@ -934,14 +934,15 @@
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-static int check_lpt_type(uint8_t **addr, int *pos, int type)
+static int check_lpt_type(const struct ubifs_info *c, uint8_t **addr,
+			  int *pos, int type)
 {
 	int node_type;
 
 	node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS);
 	if (node_type != type) {
-		ubifs_err("invalid type (%d) in LPT node type %d", node_type,
-			  type);
+		ubifs_err(c, "invalid type (%d) in LPT node type %d",
+			  node_type, type);
 		dump_stack();
 		return -EINVAL;
 	}
@@ -962,7 +963,7 @@
 	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
 	int i, pos = 0, err;
 
-	err = check_lpt_type(&addr, &pos, UBIFS_LPT_PNODE);
+	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_PNODE);
 	if (err)
 		return err;
 	if (c->big_lpt)
@@ -981,7 +982,7 @@
 			lprops->flags = 0;
 		lprops->flags |= ubifs_categorize_lprops(c, lprops);
 	}
-	err = check_lpt_crc(buf, c->pnode_sz);
+	err = check_lpt_crc(c, buf, c->pnode_sz);
 	return err;
 }
 
@@ -999,7 +1000,7 @@
 	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
 	int i, pos = 0, err;
 
-	err = check_lpt_type(&addr, &pos, UBIFS_LPT_NNODE);
+	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_NNODE);
 	if (err)
 		return err;
 	if (c->big_lpt)
@@ -1015,7 +1016,7 @@
 		nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
 						     c->lpt_offs_bits);
 	}
-	err = check_lpt_crc(buf, c->nnode_sz);
+	err = check_lpt_crc(c, buf, c->nnode_sz);
 	return err;
 }
 
@@ -1031,7 +1032,7 @@
 	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
 	int i, pos = 0, err;
 
-	err = check_lpt_type(&addr, &pos, UBIFS_LPT_LTAB);
+	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LTAB);
 	if (err)
 		return err;
 	for (i = 0; i < c->lpt_lebs; i++) {
@@ -1047,7 +1048,7 @@
 		c->ltab[i].tgc = 0;
 		c->ltab[i].cmt = 0;
 	}
-	err = check_lpt_crc(buf, c->ltab_sz);
+	err = check_lpt_crc(c, buf, c->ltab_sz);
 	return err;
 }
 
@@ -1064,7 +1065,7 @@
 	uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
 	int i, pos = 0, err;
 
-	err = check_lpt_type(&addr, &pos, UBIFS_LPT_LSAVE);
+	err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LSAVE);
 	if (err)
 		return err;
 	for (i = 0; i < c->lsave_cnt; i++) {
@@ -1074,7 +1075,7 @@
 			return -EINVAL;
 		c->lsave[i] = lnum;
 	}
-	err = check_lpt_crc(buf, c->lsave_sz);
+	err = check_lpt_crc(c, buf, c->lsave_sz);
 	return err;
 }
 #endif
@@ -1241,7 +1242,7 @@
 	return 0;
 
 out:
-	ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
+	ubifs_err(c, "error %d reading nnode at %d:%d", err, lnum, offs);
 	dump_stack();
 	kfree(nnode);
 	return err;
@@ -1306,10 +1307,10 @@
 	return 0;
 
 out:
-	ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
+	ubifs_err(c, "error %d reading pnode at %d:%d", err, lnum, offs);
 	ubifs_dump_pnode(c, pnode, parent, iip);
 	dump_stack();
-	ubifs_err("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
+	ubifs_err(c, "calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
 	kfree(pnode);
 	return err;
 }
@@ -1464,7 +1465,6 @@
 			return ERR_CAST(nnode);
 	}
 	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
-	shft -= UBIFS_LPT_FANOUT_SHIFT;
 	pnode = ubifs_get_pnode(c, nnode, iip);
 	if (IS_ERR(pnode))
 		return ERR_CAST(pnode);
@@ -1604,7 +1604,6 @@
 			return ERR_CAST(nnode);
 	}
 	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
-	shft -= UBIFS_LPT_FANOUT_SHIFT;
 	pnode = ubifs_get_pnode(c, nnode, iip);
 	if (IS_ERR(pnode))
 		return ERR_CAST(pnode);
@@ -1970,7 +1969,6 @@
 		}
 	}
 	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
-	shft -= UBIFS_LPT_FANOUT_SHIFT;
 	pnode = scan_get_pnode(c, path + h, nnode, iip);
 	if (IS_ERR(pnode)) {
 		err = PTR_ERR(pnode);
@@ -2104,7 +2102,7 @@
 	int i;
 
 	if (pnode->num != col) {
-		ubifs_err("pnode num %d expected %d parent num %d iip %d",
+		ubifs_err(c, "pnode num %d expected %d parent num %d iip %d",
 			  pnode->num, col, pnode->parent->num, pnode->iip);
 		return -EINVAL;
 	}
@@ -2119,13 +2117,13 @@
 		if (lnum >= c->leb_cnt)
 			continue;
 		if (lprops->lnum != lnum) {
-			ubifs_err("bad LEB number %d expected %d",
+			ubifs_err(c, "bad LEB number %d expected %d",
 				  lprops->lnum, lnum);
 			return -EINVAL;
 		}
 		if (lprops->flags & LPROPS_TAKEN) {
 			if (cat != LPROPS_UNCAT) {
-				ubifs_err("LEB %d taken but not uncat %d",
+				ubifs_err(c, "LEB %d taken but not uncat %d",
 					  lprops->lnum, cat);
 				return -EINVAL;
 			}
@@ -2138,7 +2136,7 @@
 			case LPROPS_FRDI_IDX:
 				break;
 			default:
-				ubifs_err("LEB %d index but cat %d",
+				ubifs_err(c, "LEB %d index but cat %d",
 					  lprops->lnum, cat);
 				return -EINVAL;
 			}
@@ -2151,7 +2149,7 @@
 			case LPROPS_FREEABLE:
 				break;
 			default:
-				ubifs_err("LEB %d not index but cat %d",
+				ubifs_err(c, "LEB %d not index but cat %d",
 					  lprops->lnum, cat);
 				return -EINVAL;
 			}
@@ -2192,26 +2190,28 @@
 			break;
 		}
 		if (!found) {
-			ubifs_err("LEB %d cat %d not found in cat heap/list",
+			ubifs_err(c, "LEB %d cat %d not found in cat heap/list",
 				  lprops->lnum, cat);
 			return -EINVAL;
 		}
 		switch (cat) {
 		case LPROPS_EMPTY:
 			if (lprops->free != c->leb_size) {
-				ubifs_err("LEB %d cat %d free %d dirty %d",
+				ubifs_err(c, "LEB %d cat %d free %d dirty %d",
 					  lprops->lnum, cat, lprops->free,
 					  lprops->dirty);
 				return -EINVAL;
 			}
+			break;
 		case LPROPS_FREEABLE:
 		case LPROPS_FRDI_IDX:
 			if (lprops->free + lprops->dirty != c->leb_size) {
-				ubifs_err("LEB %d cat %d free %d dirty %d",
+				ubifs_err(c, "LEB %d cat %d free %d dirty %d",
 					  lprops->lnum, cat, lprops->free,
 					  lprops->dirty);
 				return -EINVAL;
 			}
+			break;
 		}
 	}
 	return 0;
@@ -2243,7 +2243,7 @@
 			/* cnode is a nnode */
 			num = calc_nnode_num(row, col);
 			if (cnode->num != num) {
-				ubifs_err("nnode num %d expected %d parent num %d iip %d",
+				ubifs_err(c, "nnode num %d expected %d parent num %d iip %d",
 					  cnode->num, num,
 					  (nnode ? nnode->num : 0), cnode->iip);
 				return -EINVAL;
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index c818d4c..2df9130 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -301,7 +301,6 @@
 			ubifs_assert(lnum >= c->lpt_first &&
 				     lnum <= c->lpt_last);
 		}
-		done_ltab = 1;
 		c->ltab_lnum = lnum;
 		c->ltab_offs = offs;
 		offs += c->ltab_sz;
@@ -317,7 +316,7 @@
 	return 0;
 
 no_space:
-	ubifs_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, done_lsave %d",
+	ubifs_err(c, "LPT out of space at LEB %d:%d needing %d, done_ltab %d, done_lsave %d",
 		  lnum, offs, len, done_ltab, done_lsave);
 	ubifs_dump_lpt_info(c);
 	ubifs_dump_lpt_lebs(c);
@@ -458,9 +457,9 @@
 		 * important.
 		 */
 		clear_bit(DIRTY_CNODE, &cnode->flags);
-		smp_mb__before_clear_bit();
+		smp_mb__before_atomic();
 		clear_bit(COW_CNODE, &cnode->flags);
-		smp_mb__after_clear_bit();
+		smp_mb__after_atomic();
 		offs += len;
 		dbg_chk_lpt_sz(c, 1, len);
 		cnode = cnode->cnext;
@@ -512,7 +511,6 @@
 			if (err)
 				return err;
 		}
-		done_ltab = 1;
 		ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
 		offs += c->ltab_sz;
 		dbg_chk_lpt_sz(c, 1, c->ltab_sz);
@@ -543,7 +541,7 @@
 	return 0;
 
 no_space:
-	ubifs_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab %d, done_lsave %d",
+	ubifs_err(c, "LPT out of space mismatch at LEB %d:%d needing %d, done_ltab %d, done_lsave %d",
 		  lnum, offs, len, done_ltab, done_lsave);
 	ubifs_dump_lpt_info(c);
 	ubifs_dump_lpt_lebs(c);
@@ -1644,7 +1642,7 @@
 
 	buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
 	if (!buf) {
-		ubifs_err("cannot allocate memory for ltab checking");
+		ubifs_err(c, "cannot allocate memory for ltab checking");
 		return 0;
 	}
 
@@ -1666,18 +1664,18 @@
 				continue;
 			}
 			if (!dbg_is_all_ff(p, len)) {
-				ubifs_err("invalid empty space in LEB %d at %d",
+				ubifs_err(c, "invalid empty space in LEB %d at %d",
 					  lnum, c->leb_size - len);
 				err = -EINVAL;
 			}
 			i = lnum - c->lpt_first;
 			if (len != c->ltab[i].free) {
-				ubifs_err("invalid free space in LEB %d (free %d, expected %d)",
+				ubifs_err(c, "invalid free space in LEB %d (free %d, expected %d)",
 					  lnum, len, c->ltab[i].free);
 				err = -EINVAL;
 			}
 			if (dirty != c->ltab[i].dirty) {
-				ubifs_err("invalid dirty space in LEB %d (dirty %d, expected %d)",
+				ubifs_err(c, "invalid dirty space in LEB %d (dirty %d, expected %d)",
 					  lnum, dirty, c->ltab[i].dirty);
 				err = -EINVAL;
 			}
@@ -1731,7 +1729,7 @@
 	for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
 		err = dbg_check_ltab_lnum(c, lnum);
 		if (err) {
-			ubifs_err("failed at LEB %d", lnum);
+			ubifs_err(c, "failed at LEB %d", lnum);
 			return err;
 		}
 	}
@@ -1763,7 +1761,7 @@
 			free += c->leb_size;
 	}
 	if (free < c->lpt_sz) {
-		ubifs_err("LPT space error: free %lld lpt_sz %lld",
+		ubifs_err(c, "LPT space error: free %lld lpt_sz %lld",
 			  free, c->lpt_sz);
 		ubifs_dump_lpt_info(c);
 		ubifs_dump_lpt_lebs(c);
@@ -1803,12 +1801,12 @@
 		d->chk_lpt_lebs = 0;
 		d->chk_lpt_wastage = 0;
 		if (c->dirty_pn_cnt > c->pnode_cnt) {
-			ubifs_err("dirty pnodes %d exceed max %d",
+			ubifs_err(c, "dirty pnodes %d exceed max %d",
 				  c->dirty_pn_cnt, c->pnode_cnt);
 			err = -EINVAL;
 		}
 		if (c->dirty_nn_cnt > c->nnode_cnt) {
-			ubifs_err("dirty nnodes %d exceed max %d",
+			ubifs_err(c, "dirty nnodes %d exceed max %d",
 				  c->dirty_nn_cnt, c->nnode_cnt);
 			err = -EINVAL;
 		}
@@ -1826,22 +1824,22 @@
 		chk_lpt_sz *= d->chk_lpt_lebs;
 		chk_lpt_sz += len - c->nhead_offs;
 		if (d->chk_lpt_sz != chk_lpt_sz) {
-			ubifs_err("LPT wrote %lld but space used was %lld",
+			ubifs_err(c, "LPT wrote %lld but space used was %lld",
 				  d->chk_lpt_sz, chk_lpt_sz);
 			err = -EINVAL;
 		}
 		if (d->chk_lpt_sz > c->lpt_sz) {
-			ubifs_err("LPT wrote %lld but lpt_sz is %lld",
+			ubifs_err(c, "LPT wrote %lld but lpt_sz is %lld",
 				  d->chk_lpt_sz, c->lpt_sz);
 			err = -EINVAL;
 		}
 		if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) {
-			ubifs_err("LPT layout size %lld but wrote %lld",
+			ubifs_err(c, "LPT layout size %lld but wrote %lld",
 				  d->chk_lpt_sz, d->chk_lpt_sz2);
 			err = -EINVAL;
 		}
 		if (d->chk_lpt_sz2 && d->new_nhead_offs != len) {
-			ubifs_err("LPT new nhead offs: expected %d was %d",
+			ubifs_err(c, "LPT new nhead offs: expected %d was %d",
 				  d->new_nhead_offs, len);
 			err = -EINVAL;
 		}
@@ -1851,7 +1849,7 @@
 		if (c->big_lpt)
 			lpt_sz += c->lsave_sz;
 		if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) {
-			ubifs_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
+			ubifs_err(c, "LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
 				  d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
 			err = -EINVAL;
 		}
@@ -1893,7 +1891,7 @@
 	pr_err("(pid %d) start dumping LEB %d\n", current->pid, lnum);
 	buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
 	if (!buf) {
-		ubifs_err("cannot allocate memory to dump LPT");
+		ubifs_err(c, "cannot allocate memory to dump LPT");
 		return;
 	}
 
@@ -1945,6 +1943,11 @@
 				pr_err("LEB %d:%d, nnode, ",
 				       lnum, offs);
 			err = ubifs_unpack_nnode(c, p, &nnode);
+			if (err) {
+				pr_err("failed to unpack_node, error %d\n",
+				       err);
+				break;
+			}
 			for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
 				pr_cont("%d:%d", nnode.nbranch[i].lnum,
 				       nnode.nbranch[i].offs);
@@ -1963,7 +1966,7 @@
 			pr_err("LEB %d:%d, lsave len\n", lnum, offs);
 			break;
 		default:
-			ubifs_err("LPT node type %d not recognized", node_type);
+			ubifs_err(c, "LPT node type %d not recognized", node_type);
 			goto out;
 		}
 
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index 761e070..4dd0bbb 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -76,7 +76,7 @@
 	return -EUCLEAN;
 
 out_dump:
-	ubifs_err("unexpected node type %d master LEB %d:%d",
+	ubifs_err(c, "unexpected node type %d master LEB %d:%d",
 		  snod->type, lnum, snod->offs);
 	ubifs_scan_destroy(sleb);
 	return -EINVAL;
@@ -234,7 +234,7 @@
 	return 0;
 
 out:
-	ubifs_err("bad master node at offset %d error %d", c->mst_offs, err);
+	ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err);
 	ubifs_dump_node(c, c->mst_node);
 	return -EINVAL;
 }
@@ -310,7 +310,7 @@
 
 		if (c->leb_cnt < old_leb_cnt ||
 		    c->leb_cnt < UBIFS_MIN_LEB_CNT) {
-			ubifs_err("bad leb_cnt on master node");
+			ubifs_err(c, "bad leb_cnt on master node");
 			ubifs_dump_node(c, c->mst_node);
 			return -EINVAL;
 		}
@@ -349,10 +349,9 @@
  * ubifs_write_master - write master node.
  * @c: UBIFS file-system description object
  *
- * This function writes the master node. The caller has to take the
- * @c->mst_mutex lock before calling this function. Returns zero in case of
- * success and a negative error code in case of failure. The master node is
- * written twice to enable recovery.
+ * This function writes the master node. Returns zero in case of success and a
+ * negative error code in case of failure. The master node is written twice to
+ * enable recovery.
  */
 int ubifs_write_master(struct ubifs_info *c)
 {
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
index 4e42879..f5c8e23 100644
--- a/fs/ubifs/orphan.c
+++ b/fs/ubifs/orphan.c
@@ -78,7 +78,7 @@
 		else if (inum > o->inum)
 			p = &(*p)->rb_right;
 		else {
-			ubifs_err("orphaned twice");
+			ubifs_err(c, "orphaned twice");
 			spin_unlock(&c->orphan_lock);
 			kfree(orphan);
 			return 0;
@@ -145,7 +145,7 @@
 		}
 	}
 	spin_unlock(&c->orphan_lock);
-	ubifs_err("missing orphan ino %lu", (unsigned long)inum);
+	ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
 	dump_stack();
 }
 
@@ -277,7 +277,7 @@
 			 * We limit the number of orphans so that this should
 			 * never happen.
 			 */
-			ubifs_err("out of space in orphan area");
+			ubifs_err(c, "out of space in orphan area");
 			return -EINVAL;
 		}
 	}
@@ -336,7 +336,6 @@
 		int lnum;
 
 		/* Unmap any unused LEBs after consolidation */
-		lnum = c->ohead_lnum + 1;
 		for (lnum = c->ohead_lnum + 1; lnum <= c->orph_last; lnum++) {
 			err = ubifs_leb_unmap(c, lnum);
 			if (err)
@@ -388,7 +387,7 @@
 		 * We limit the number of orphans so that this should
 		 * never happen.
 		 */
-		ubifs_err("out of space in orphan area");
+		ubifs_err(c, "out of space in orphan area");
 		err = -EINVAL;
 	}
 	spin_unlock(&c->orphan_lock);
@@ -560,7 +559,7 @@
 
 	list_for_each_entry(snod, &sleb->nodes, list) {
 		if (snod->type != UBIFS_ORPH_NODE) {
-			ubifs_err("invalid node type %d in orphan area at %d:%d",
+			ubifs_err(c, "invalid node type %d in orphan area at %d:%d",
 				  snod->type, sleb->lnum, snod->offs);
 			ubifs_dump_node(c, snod->node);
 			return -EINVAL;
@@ -587,7 +586,7 @@
 			 * number. That makes this orphan node, out of date.
 			 */
 			if (!first) {
-				ubifs_err("out of order commit number %llu in orphan node at %d:%d",
+				ubifs_err(c, "out of order commit number %llu in orphan node at %d:%d",
 					  cmt_no, sleb->lnum, snod->offs);
 				ubifs_dump_node(c, snod->node);
 				return -EINVAL;
@@ -822,20 +821,20 @@
 	if (inum != ci->last_ino) {
 		/* Lowest node type is the inode node, so it comes first */
 		if (key_type(c, &zbr->key) != UBIFS_INO_KEY)
-			ubifs_err("found orphan node ino %lu, type %d",
+			ubifs_err(c, "found orphan node ino %lu, type %d",
 				  (unsigned long)inum, key_type(c, &zbr->key));
 		ci->last_ino = inum;
 		ci->tot_inos += 1;
 		err = ubifs_tnc_read_node(c, zbr, ci->node);
 		if (err) {
-			ubifs_err("node read failed, error %d", err);
+			ubifs_err(c, "node read failed, error %d", err);
 			return err;
 		}
 		if (ci->node->nlink == 0)
 			/* Must be recorded as an orphan */
 			if (!dbg_find_check_orphan(&ci->root, inum) &&
 			    !dbg_find_orphan(c, inum)) {
-				ubifs_err("missing orphan, ino %lu",
+				ubifs_err(c, "missing orphan, ino %lu",
 					  (unsigned long)inum);
 				ci->missing += 1;
 			}
@@ -878,7 +877,7 @@
 
 	buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
 	if (!buf) {
-		ubifs_err("cannot allocate memory to check orphans");
+		ubifs_err(c, "cannot allocate memory to check orphans");
 		return 0;
 	}
 
@@ -916,7 +915,7 @@
 	ci.root = RB_ROOT;
 	ci.node = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
 	if (!ci.node) {
-		ubifs_err("out of memory");
+		ubifs_err(c, "out of memory");
 		return -ENOMEM;
 	}
 
@@ -926,12 +925,12 @@
 
 	err = dbg_walk_index(c, &dbg_orphan_check, NULL, &ci);
 	if (err) {
-		ubifs_err("cannot scan TNC, error %d", err);
+		ubifs_err(c, "cannot scan TNC, error %d", err);
 		goto out;
 	}
 
 	if (ci.missing) {
-		ubifs_err("%lu missing orphan(s)", ci.missing);
+		ubifs_err(c, "%lu missing orphan(s)", ci.missing);
 		err = -EINVAL;
 		goto out;
 	}
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 7637707..386a9c5 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -298,7 +298,7 @@
 		mst = mst2;
 	}
 
-	ubifs_msg("recovered master node from LEB %d",
+	ubifs_msg(c, "recovered master node from LEB %d",
 		  (mst == mst1 ? UBIFS_MST_LNUM : UBIFS_MST_LNUM + 1));
 
 	memcpy(c->mst_node, mst, UBIFS_MST_NODE_SZ);
@@ -355,13 +355,13 @@
 out_err:
 	err = -EINVAL;
 out_free:
-	ubifs_err("failed to recover master node");
+	ubifs_err(c, "failed to recover master node");
 	if (mst1) {
-		ubifs_err("dumping first master node");
+		ubifs_err(c, "dumping first master node");
 		ubifs_dump_node(c, mst1);
 	}
 	if (mst2) {
-		ubifs_err("dumping second master node");
+		ubifs_err(c, "dumping second master node");
 		ubifs_dump_node(c, mst2);
 	}
 	vfree(buf2);
@@ -593,7 +593,6 @@
  * drop_last_node - drop the last node.
  * @sleb: scanned LEB information
  * @offs: offset of dropped nodes is returned here
- * @grouped: non-zero if whole group of nodes have to be dropped
  *
  * This is a helper function for 'ubifs_recover_leb()' which drops the last
  * node of the scanned LEB.
@@ -626,8 +625,8 @@
  *
  * This function does a scan of a LEB, but caters for errors that might have
  * been caused by the unclean unmount from which we are attempting to recover.
- * Returns %0 in case of success, %-EUCLEAN if an unrecoverable corruption is
- * found, and a negative error code in case of failure.
+ * Returns the scanned information on success and a negative error code on
+ * failure.
  */
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
 					 int offs, void *sbuf, int jhead)
@@ -680,7 +679,7 @@
 				  ret, lnum, offs);
 			break;
 		} else {
-			ubifs_err("unexpected return value %d", ret);
+			ubifs_err(c, "unexpected return value %d", ret);
 			err = -EINVAL;
 			goto error;
 		}
@@ -700,7 +699,7 @@
 			 * See header comment for this file for more
 			 * explanations about the reasons we have this check.
 			 */
-			ubifs_err("corrupt empty space LEB %d:%d, corruption starts at %d",
+			ubifs_err(c, "corrupt empty space LEB %d:%d, corruption starts at %d",
 				  lnum, offs, corruption);
 			/* Make sure we dump interesting non-0xFF data */
 			offs += corruption;
@@ -786,13 +785,13 @@
 
 corrupted_rescan:
 	/* Re-scan the corrupted data with verbose messages */
-	ubifs_err("corruption %d", ret);
+	ubifs_err(c, "corruption %d", ret);
 	ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
 corrupted:
 	ubifs_scanned_corruption(c, lnum, offs, buf);
 	err = -EUCLEAN;
 error:
-	ubifs_err("LEB %d scanning failed", lnum);
+	ubifs_err(c, "LEB %d scanning failed", lnum);
 	ubifs_scan_destroy(sleb);
 	return ERR_PTR(err);
 }
@@ -824,15 +823,15 @@
 		goto out_free;
 	ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
 	if (ret != SCANNED_A_NODE) {
-		ubifs_err("Not a valid node");
+		ubifs_err(c, "Not a valid node");
 		goto out_err;
 	}
 	if (cs_node->ch.node_type != UBIFS_CS_NODE) {
-		ubifs_err("Node a CS node, type is %d", cs_node->ch.node_type);
+		ubifs_err(c, "Node a CS node, type is %d", cs_node->ch.node_type);
 		goto out_err;
 	}
 	if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
-		ubifs_err("CS node cmt_no %llu != current cmt_no %llu",
+		ubifs_err(c, "CS node cmt_no %llu != current cmt_no %llu",
 			  (unsigned long long)le64_to_cpu(cs_node->cmt_no),
 			  c->cmt_no);
 		goto out_err;
@@ -845,7 +844,7 @@
 out_err:
 	err = -EINVAL;
 out_free:
-	ubifs_err("failed to get CS sqnum");
+	ubifs_err(c, "failed to get CS sqnum");
 	kfree(cs_node);
 	return err;
 }
@@ -897,7 +896,7 @@
 				}
 			}
 			if (snod->sqnum > cs_sqnum) {
-				ubifs_err("unrecoverable log corruption in LEB %d",
+				ubifs_err(c, "unrecoverable log corruption in LEB %d",
 					  lnum);
 				ubifs_scan_destroy(sleb);
 				return ERR_PTR(-EUCLEAN);
@@ -973,11 +972,8 @@
 		return err;
 
 	dbg_rcvry("checking LPT head at %d:%d", c->nhead_lnum, c->nhead_offs);
-	err = recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf);
-	if (err)
-		return err;
 
-	return 0;
+	return recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf);
 }
 
 /**
@@ -1002,10 +998,7 @@
 
 	if (len == 0) {
 		/* Nothing to read, just unmap it */
-		err = ubifs_leb_unmap(c, lnum);
-		if (err)
-			return err;
-		return 0;
+		return ubifs_leb_unmap(c, lnum);
 	}
 
 	err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
@@ -1041,7 +1034,7 @@
 		}
 
 		if (ret == SCANNED_EMPTY_SPACE) {
-			ubifs_err("unexpected empty space at %d:%d",
+			ubifs_err(c, "unexpected empty space at %d:%d",
 				  lnum, offs);
 			return -EUCLEAN;
 		}
@@ -1136,7 +1129,7 @@
 	 */
 	lnum = ubifs_find_free_leb_for_idx(c);
 	if (lnum < 0) {
-		ubifs_err("could not find an empty LEB");
+		ubifs_err(c, "could not find an empty LEB");
 		ubifs_dump_lprops(c);
 		ubifs_dump_budg(c, &c->bi);
 		return lnum;
@@ -1216,7 +1209,7 @@
 	}
 	mutex_unlock(&wbuf->io_mutex);
 	if (err < 0) {
-		ubifs_err("GC failed, error %d", err);
+		ubifs_err(c, "GC failed, error %d", err);
 		if (err == -EAGAIN)
 			err = -EINVAL;
 		return err;
@@ -1470,7 +1463,7 @@
 	return 0;
 
 out:
-	ubifs_warn("inode %lu failed to fix size %lld -> %lld error %d",
+	ubifs_warn(c, "inode %lu failed to fix size %lld -> %lld error %d",
 		   (unsigned long)e->inum, e->i_size, e->d_size, err);
 	return err;
 }
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 1064cb2..d0fcd83 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -451,13 +451,13 @@
 	    nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
 	    strnlen(dent->name, nlen) != nlen ||
 	    le64_to_cpu(dent->inum) > MAX_INUM) {
-		ubifs_err("bad %s node", key_type == UBIFS_DENT_KEY ?
+		ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ?
 			  "directory entry" : "extended attribute entry");
 		return -EINVAL;
 	}
 
 	if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) {
-		ubifs_err("bad key type %d", key_type);
+		ubifs_err(c, "bad key type %d", key_type);
 		return -EINVAL;
 	}
 
@@ -582,7 +582,7 @@
 		cond_resched();
 
 		if (snod->sqnum >= SQNUM_WATERMARK) {
-			ubifs_err("file system's life ended");
+			ubifs_err(c, "file system's life ended");
 			goto out_dump;
 		}
 
@@ -640,7 +640,7 @@
 			if (old_size < 0 || old_size > c->max_inode_sz ||
 			    new_size < 0 || new_size > c->max_inode_sz ||
 			    old_size <= new_size) {
-				ubifs_err("bad truncation node");
+				ubifs_err(c, "bad truncation node");
 				goto out_dump;
 			}
 
@@ -655,7 +655,7 @@
 			break;
 		}
 		default:
-			ubifs_err("unexpected node type %d in bud LEB %d:%d",
+			ubifs_err(c, "unexpected node type %d in bud LEB %d:%d",
 				  snod->type, lnum, snod->offs);
 			err = -EINVAL;
 			goto out_dump;
@@ -678,7 +678,7 @@
 	return err;
 
 out_dump:
-	ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs);
+	ubifs_err(c, "bad node is at LEB %d:%d", lnum, snod->offs);
 	ubifs_dump_node(c, snod->node);
 	ubifs_scan_destroy(sleb);
 	return -EINVAL;
@@ -798,7 +798,7 @@
 	if (bud) {
 		if (bud->jhead == jhead && bud->start <= offs)
 			return 1;
-		ubifs_err("bud at LEB %d:%d was already referred", lnum, offs);
+		ubifs_err(c, "bud at LEB %d:%d was already referred", lnum, offs);
 		return -EINVAL;
 	}
 
@@ -854,12 +854,12 @@
 		 * numbers.
 		 */
 		if (snod->type != UBIFS_CS_NODE) {
-			ubifs_err("first log node at LEB %d:%d is not CS node",
+			ubifs_err(c, "first log node at LEB %d:%d is not CS node",
 				  lnum, offs);
 			goto out_dump;
 		}
 		if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
-			ubifs_err("first CS node at LEB %d:%d has wrong commit number %llu expected %llu",
+			ubifs_err(c, "first CS node at LEB %d:%d has wrong commit number %llu expected %llu",
 				  lnum, offs,
 				  (unsigned long long)le64_to_cpu(node->cmt_no),
 				  c->cmt_no);
@@ -884,7 +884,7 @@
 
 	/* Make sure the first node sits at offset zero of the LEB */
 	if (snod->offs != 0) {
-		ubifs_err("first node is not at zero offset");
+		ubifs_err(c, "first node is not at zero offset");
 		goto out_dump;
 	}
 
@@ -892,12 +892,12 @@
 		cond_resched();
 
 		if (snod->sqnum >= SQNUM_WATERMARK) {
-			ubifs_err("file system's life ended");
+			ubifs_err(c, "file system's life ended");
 			goto out_dump;
 		}
 
 		if (snod->sqnum < c->cs_sqnum) {
-			ubifs_err("bad sqnum %llu, commit sqnum %llu",
+			ubifs_err(c, "bad sqnum %llu, commit sqnum %llu",
 				  snod->sqnum, c->cs_sqnum);
 			goto out_dump;
 		}
@@ -927,12 +927,12 @@
 		case UBIFS_CS_NODE:
 			/* Make sure it sits at the beginning of LEB */
 			if (snod->offs != 0) {
-				ubifs_err("unexpected node in log");
+				ubifs_err(c, "unexpected node in log");
 				goto out_dump;
 			}
 			break;
 		default:
-			ubifs_err("unexpected node in log");
+			ubifs_err(c, "unexpected node in log");
 			goto out_dump;
 		}
 	}
@@ -948,7 +948,7 @@
 	return err;
 
 out_dump:
-	ubifs_err("log error detected while replaying the log at LEB %d:%d",
+	ubifs_err(c, "log error detected while replaying the log at LEB %d:%d",
 		  lnum, offs + snod->offs);
 	ubifs_dump_node(c, snod->node);
 	ubifs_scan_destroy(sleb);
@@ -1010,7 +1010,7 @@
 		return free; /* Error code */
 
 	if (c->ihead_offs != c->leb_size - free) {
-		ubifs_err("bad index head LEB %d:%d", c->ihead_lnum,
+		ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum,
 			  c->ihead_offs);
 		return -EINVAL;
 	}
@@ -1021,9 +1021,22 @@
 
 	do {
 		err = replay_log_leb(c, lnum, 0, c->sbuf);
-		if (err == 1)
-			/* We hit the end of the log */
-			break;
+		if (err == 1) {
+			if (lnum != c->lhead_lnum)
+				/* We hit the end of the log */
+				break;
+
+			/*
+			 * The head of the log must always start with the
+			 * "commit start" node on a properly formatted UBIFS.
+			 * But we found no nodes at all, which means that
+			 * someting went wrong and we cannot proceed mounting
+			 * the file-system.
+			 */
+			ubifs_err(c, "no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",
+				  lnum, 0);
+			err = -EINVAL;
+		}
 		if (err)
 			goto out;
 		lnum = ubifs_next_log_lnum(c, lnum);
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 4983bf6..7c7d92a 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -330,8 +330,10 @@
 	cs->ch.node_type = UBIFS_CS_NODE;
 	err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, 0);
 	kfree(cs);
+	if (err)
+		return err;
 
-	ubifs_msg("default file-system created");
+	ubifs_msg(c, "default file-system created");
 	return 0;
 }
 #endif
@@ -362,13 +364,13 @@
 	}
 
 	if (le32_to_cpu(sup->min_io_size) != c->min_io_size) {
-		ubifs_err("min. I/O unit mismatch: %d in superblock, %d real",
+		ubifs_err(c, "min. I/O unit mismatch: %d in superblock, %d real",
 			  le32_to_cpu(sup->min_io_size), c->min_io_size);
 		goto failed;
 	}
 
 	if (le32_to_cpu(sup->leb_size) != c->leb_size) {
-		ubifs_err("LEB size mismatch: %d in superblock, %d real",
+		ubifs_err(c, "LEB size mismatch: %d in superblock, %d real",
 			  le32_to_cpu(sup->leb_size), c->leb_size);
 		goto failed;
 	}
@@ -390,33 +392,33 @@
 	min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6;
 
 	if (c->leb_cnt < min_leb_cnt || c->leb_cnt > c->vi.size) {
-		ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, %d minimum required",
+		ubifs_err(c, "bad LEB count: %d in superblock, %d on UBI volume, %d minimum required",
 			  c->leb_cnt, c->vi.size, min_leb_cnt);
 		goto failed;
 	}
 
 	if (c->max_leb_cnt < c->leb_cnt) {
-		ubifs_err("max. LEB count %d less than LEB count %d",
+		ubifs_err(c, "max. LEB count %d less than LEB count %d",
 			  c->max_leb_cnt, c->leb_cnt);
 		goto failed;
 	}
 
 	if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
-		ubifs_err("too few main LEBs count %d, must be at least %d",
+		ubifs_err(c, "too few main LEBs count %d, must be at least %d",
 			  c->main_lebs, UBIFS_MIN_MAIN_LEBS);
 		goto failed;
 	}
 
 	max_bytes = (long long)c->leb_size * UBIFS_MIN_BUD_LEBS;
 	if (c->max_bud_bytes < max_bytes) {
-		ubifs_err("too small journal (%lld bytes), must be at least %lld bytes",
+		ubifs_err(c, "too small journal (%lld bytes), must be at least %lld bytes",
 			  c->max_bud_bytes, max_bytes);
 		goto failed;
 	}
 
 	max_bytes = (long long)c->leb_size * c->main_lebs;
 	if (c->max_bud_bytes > max_bytes) {
-		ubifs_err("too large journal size (%lld bytes), only %lld bytes available in the main area",
+		ubifs_err(c, "too large journal size (%lld bytes), only %lld bytes available in the main area",
 			  c->max_bud_bytes, max_bytes);
 		goto failed;
 	}
@@ -446,7 +448,7 @@
 		goto failed;
 	}
 
-	if (c->default_compr < 0 || c->default_compr >= UBIFS_COMPR_TYPES_CNT) {
+	if (c->default_compr >= UBIFS_COMPR_TYPES_CNT) {
 		err = 13;
 		goto failed;
 	}
@@ -465,7 +467,7 @@
 	return 0;
 
 failed:
-	ubifs_err("bad superblock, error %d", err);
+	ubifs_err(c, "bad superblock, error %d", err);
 	ubifs_dump_node(c, sup);
 	return -EINVAL;
 }
@@ -551,12 +553,12 @@
 		ubifs_assert(!c->ro_media || c->ro_mount);
 		if (!c->ro_mount ||
 		    c->ro_compat_version > UBIFS_RO_COMPAT_VERSION) {
-			ubifs_err("on-flash format version is w%d/r%d, but software only supports up to version w%d/r%d",
+			ubifs_err(c, "on-flash format version is w%d/r%d, but software only supports up to version w%d/r%d",
 				  c->fmt_version, c->ro_compat_version,
 				  UBIFS_FORMAT_VERSION,
 				  UBIFS_RO_COMPAT_VERSION);
 			if (c->ro_compat_version <= UBIFS_RO_COMPAT_VERSION) {
-				ubifs_msg("only R/O mounting is possible");
+				ubifs_msg(c, "only R/O mounting is possible");
 				err = -EROFS;
 			} else
 				err = -EINVAL;
@@ -572,7 +574,7 @@
 	}
 
 	if (c->fmt_version < 3) {
-		ubifs_err("on-flash format version %d is not supported",
+		ubifs_err(c, "on-flash format version %d is not supported",
 			  c->fmt_version);
 		err = -EINVAL;
 		goto out;
@@ -597,7 +599,7 @@
 		c->key_len = UBIFS_SK_LEN;
 		break;
 	default:
-		ubifs_err("unsupported key format");
+		ubifs_err(c, "unsupported key format");
 		err = -EINVAL;
 		goto out;
 	}
@@ -794,7 +796,7 @@
 	ubifs_assert(c->space_fixup);
 	ubifs_assert(!c->ro_mount);
 
-	ubifs_msg("start fixing up free space");
+	ubifs_msg(c, "start fixing up free space");
 
 	err = fixup_free_space(c);
 	if (err)
@@ -813,6 +815,6 @@
 	if (err)
 		return err;
 
-	ubifs_msg("free space fixup complete");
+	ubifs_msg(c, "free space fixup complete");
 	return err;
 }
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index 6fc464b..12a3597 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -92,7 +92,7 @@
 		if (pad_len < 0 ||
 		    offs + node_len + pad_len > c->leb_size) {
 			if (!quiet) {
-				ubifs_err("bad pad node at LEB %d:%d",
+				ubifs_err(c, "bad pad node at LEB %d:%d",
 					  lnum, offs);
 				ubifs_dump_node(c, pad);
 			}
@@ -102,7 +102,7 @@
 		/* Make the node pads to 8-byte boundary */
 		if ((node_len + pad_len) & 7) {
 			if (!quiet)
-				ubifs_err("bad padding length %d - %d",
+				ubifs_err(c, "bad padding length %d - %d",
 					  offs, offs + node_len + pad_len);
 			return SCANNED_A_BAD_PAD_NODE;
 		}
@@ -123,7 +123,8 @@
  * @offs: offset to start at (usually zero)
  * @sbuf: scan buffer (must be c->leb_size)
  *
- * This function returns %0 on success and a negative error code on failure.
+ * This function returns the scanned information on success and a negative error
+ * code on failure.
  */
 struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
 					int offs, void *sbuf)
@@ -143,15 +144,16 @@
 
 	err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
 	if (err && err != -EBADMSG) {
-		ubifs_err("cannot read %d bytes from LEB %d:%d, error %d",
+		ubifs_err(c, "cannot read %d bytes from LEB %d:%d, error %d",
 			  c->leb_size - offs, lnum, offs, err);
 		kfree(sleb);
 		return ERR_PTR(err);
 	}
 
-	if (err == -EBADMSG)
-		sleb->ecc = 1;
-
+	/*
+	 * Note, we ignore integrity errors (EBASMSG) because all the nodes are
+	 * protected by CRC checksums.
+	 */
 	return sleb;
 }
 
@@ -161,8 +163,6 @@
  * @sleb: scanning information
  * @lnum: logical eraseblock number
  * @offs: offset to start at (usually zero)
- *
- * This function returns %0 on success and a negative error code on failure.
  */
 void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 		    int lnum, int offs)
@@ -232,11 +232,11 @@
 {
 	int len;
 
-	ubifs_err("corruption at LEB %d:%d", lnum, offs);
+	ubifs_err(c, "corruption at LEB %d:%d", lnum, offs);
 	len = c->leb_size - offs;
 	if (len > 8192)
 		len = 8192;
-	ubifs_err("first %d bytes from LEB %d:%d", len, lnum, offs);
+	ubifs_err(c, "first %d bytes from LEB %d:%d", len, lnum, offs);
 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
 }
 
@@ -249,7 +249,7 @@
  * @quiet: print no messages
  *
  * This function scans LEB number @lnum and returns complete information about
- * its contents. Returns the scaned information in case of success and,
+ * its contents. Returns the scanned information in case of success and,
  * %-EUCLEAN if the LEB neads recovery, and other negative error codes in case
  * of failure.
  *
@@ -291,16 +291,16 @@
 
 		switch (ret) {
 		case SCANNED_GARBAGE:
-			ubifs_err("garbage");
+			ubifs_err(c, "garbage");
 			goto corrupted;
 		case SCANNED_A_NODE:
 			break;
 		case SCANNED_A_CORRUPT_NODE:
 		case SCANNED_A_BAD_PAD_NODE:
-			ubifs_err("bad node");
+			ubifs_err(c, "bad node");
 			goto corrupted;
 		default:
-			ubifs_err("unknown");
+			ubifs_err(c, "unknown");
 			err = -EINVAL;
 			goto error;
 		}
@@ -317,7 +317,7 @@
 
 	if (offs % c->min_io_size) {
 		if (!quiet)
-			ubifs_err("empty space starts at non-aligned offset %d",
+			ubifs_err(c, "empty space starts at non-aligned offset %d",
 				  offs);
 		goto corrupted;
 	}
@@ -330,7 +330,7 @@
 	for (; len; offs++, buf++, len--)
 		if (*(uint8_t *)buf != 0xff) {
 			if (!quiet)
-				ubifs_err("corrupt empty space at LEB %d:%d",
+				ubifs_err(c, "corrupt empty space at LEB %d:%d",
 					  lnum, offs);
 			goto corrupted;
 		}
@@ -340,14 +340,14 @@
 corrupted:
 	if (!quiet) {
 		ubifs_scanned_corruption(c, lnum, offs, buf);
-		ubifs_err("LEB %d scanning failed", lnum);
+		ubifs_err(c, "LEB %d scanning failed", lnum);
 	}
 	err = -EUCLEAN;
 	ubifs_scan_destroy(sleb);
 	return ERR_PTR(err);
 
 error:
-	ubifs_err("LEB %d scanning failed, error %d", lnum, err);
+	ubifs_err(c, "LEB %d scanning failed, error %d", lnum, err);
 	ubifs_scan_destroy(sleb);
 	return ERR_PTR(err);
 }
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 41763a1..c474313 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -101,7 +101,7 @@
 	}
 
 	if (i >= INODE_LOCKED_MAX) {
-		ubifs_err("Error, can't lock (save) more inodes while recovery!!!");
+		dbg_gen("Error, can't lock (save) more inodes while recovery!!!");
 		return;
 	}
 
@@ -208,13 +208,13 @@
 	const struct ubifs_inode *ui = ubifs_inode(inode);
 
 	if (inode->i_size > c->max_inode_sz) {
-		ubifs_err("inode is too large (%lld)",
+		ubifs_err(c, "inode is too large (%lld)",
 			  (long long)inode->i_size);
 		return 1;
 	}
 
-	if (ui->compr_type < 0 || ui->compr_type >= UBIFS_COMPR_TYPES_CNT) {
-		ubifs_err("unknown compression type %d", ui->compr_type);
+	if (ui->compr_type >= UBIFS_COMPR_TYPES_CNT) {
+		ubifs_err(c, "unknown compression type %d", ui->compr_type);
 		return 2;
 	}
 
@@ -228,7 +228,7 @@
 		return 5;
 
 	if (!ubifs_compr_present(ui->compr_type)) {
-		ubifs_warn("inode %lu uses '%s' compression, but it was not compiled in",
+		ubifs_warn(c, "inode %lu uses '%s' compression, but it was not compiled in",
 			   inode->i_ino, ubifs_compr_name(ui->compr_type));
 	}
 
@@ -321,9 +321,6 @@
 		goto out_invalid;
 
 #ifndef __UBOOT__
-	/* Disable read-ahead */
-	inode->i_mapping->backing_dev_info = &c->bdi;
-
 	switch (inode->i_mode & S_IFMT) {
 	case S_IFREG:
 		inode->i_mapping->a_ops = &ubifs_file_address_operations;
@@ -363,6 +360,7 @@
 		}
 		memcpy(ui->data, ino->data, ui->data_len);
 		((char *)ui->data)[ui->data_len] = '\0';
+		inode->i_link = ui->data;
 		break;
 	case S_IFBLK:
 	case S_IFCHR:
@@ -427,14 +425,14 @@
 	return inode;
 
 out_invalid:
-	ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err);
+	ubifs_err(c, "inode %lu validation failed, error %d", inode->i_ino, err);
 	ubifs_dump_node(c, ino);
 	ubifs_dump_inode(c, inode);
 	err = -EINVAL;
 out_ino:
 	kfree(ino);
 out:
-	ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err);
+	ubifs_err(c, "failed to read inode %lu, error %d", inode->i_ino, err);
 	iget_failed(inode);
 	return ERR_PTR(err);
 }
@@ -505,7 +503,7 @@
 	if (inode->i_nlink) {
 		err = ubifs_jnl_write_inode(c, inode);
 		if (err)
-			ubifs_err("can't write inode %lu, error %d",
+			ubifs_err(c, "can't write inode %lu, error %d",
 				  inode->i_ino, err);
 		else
 			err = dbg_check_inode_size(c, inode, ui->ui_size);
@@ -549,7 +547,7 @@
 		 * Worst case we have a lost orphan inode wasting space, so a
 		 * simple error message is OK here.
 		 */
-		ubifs_err("can't delete inode %lu, error %d",
+		ubifs_err(c, "can't delete inode %lu, error %d",
 			  inode->i_ino, err);
 
 out:
@@ -609,19 +607,19 @@
 	struct ubifs_info *c = root->d_sb->s_fs_info;
 
 	if (c->mount_opts.unmount_mode == 2)
-		seq_printf(s, ",fast_unmount");
+		seq_puts(s, ",fast_unmount");
 	else if (c->mount_opts.unmount_mode == 1)
-		seq_printf(s, ",norm_unmount");
+		seq_puts(s, ",norm_unmount");
 
 	if (c->mount_opts.bulk_read == 2)
-		seq_printf(s, ",bulk_read");
+		seq_puts(s, ",bulk_read");
 	else if (c->mount_opts.bulk_read == 1)
-		seq_printf(s, ",no_bulk_read");
+		seq_puts(s, ",no_bulk_read");
 
 	if (c->mount_opts.chk_data_crc == 2)
-		seq_printf(s, ",chk_data_crc");
+		seq_puts(s, ",chk_data_crc");
 	else if (c->mount_opts.chk_data_crc == 1)
-		seq_printf(s, ",no_chk_data_crc");
+		seq_puts(s, ",no_chk_data_crc");
 
 	if (c->mount_opts.override_compr) {
 		seq_printf(s, ",compr=%s",
@@ -681,17 +679,17 @@
 static int init_constants_early(struct ubifs_info *c)
 {
 	if (c->vi.corrupted) {
-		ubifs_warn("UBI volume is corrupted - read-only mode");
+		ubifs_warn(c, "UBI volume is corrupted - read-only mode");
 		c->ro_media = 1;
 	}
 
 	if (c->di.ro_mode) {
-		ubifs_msg("read-only UBI device");
+		ubifs_msg(c, "read-only UBI device");
 		c->ro_media = 1;
 	}
 
 	if (c->vi.vol_type == UBI_STATIC_VOLUME) {
-		ubifs_msg("static UBI volume - read-only mode");
+		ubifs_msg(c, "static UBI volume - read-only mode");
 		c->ro_media = 1;
 	}
 
@@ -705,19 +703,19 @@
 	c->max_write_shift = fls(c->max_write_size) - 1;
 
 	if (c->leb_size < UBIFS_MIN_LEB_SZ) {
-		ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
+		ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes",
 			  c->leb_size, UBIFS_MIN_LEB_SZ);
 		return -EINVAL;
 	}
 
 	if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
-		ubifs_err("too few LEBs (%d), min. is %d",
+		ubifs_err(c, "too few LEBs (%d), min. is %d",
 			  c->leb_cnt, UBIFS_MIN_LEB_CNT);
 		return -EINVAL;
 	}
 
 	if (!is_power_of_2(c->min_io_size)) {
-		ubifs_err("bad min. I/O size %d", c->min_io_size);
+		ubifs_err(c, "bad min. I/O size %d", c->min_io_size);
 		return -EINVAL;
 	}
 
@@ -728,7 +726,7 @@
 	if (c->max_write_size < c->min_io_size ||
 	    c->max_write_size % c->min_io_size ||
 	    !is_power_of_2(c->max_write_size)) {
-		ubifs_err("bad write buffer size %d for %d min. I/O unit",
+		ubifs_err(c, "bad write buffer size %d for %d min. I/O unit",
 			  c->max_write_size, c->min_io_size);
 		return -EINVAL;
 	}
@@ -854,7 +852,7 @@
 	tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
 	tmp = ALIGN(tmp, c->min_io_size);
 	if (tmp > c->leb_size) {
-		ubifs_err("too small LEB size %d, at least %d needed",
+		ubifs_err(c, "too small LEB size %d, at least %d needed",
 			  c->leb_size, tmp);
 		return -EINVAL;
 	}
@@ -869,7 +867,7 @@
 	tmp /= c->leb_size;
 	tmp += 1;
 	if (c->log_lebs < tmp) {
-		ubifs_err("too small log %d LEBs, required min. %d LEBs",
+		ubifs_err(c, "too small log %d LEBs, required min. %d LEBs",
 			  c->log_lebs, tmp);
 		return -EINVAL;
 	}
@@ -961,7 +959,7 @@
 	int err;
 
 	if (c->gc_lnum == -1) {
-		ubifs_err("no LEB for GC");
+		ubifs_err(c, "no LEB for GC");
 		return -EINVAL;
 	}
 
@@ -982,8 +980,8 @@
 {
 	int i, err;
 
-	c->jheads = kzalloc(c->jhead_cnt * sizeof(struct ubifs_jhead),
-			   GFP_KERNEL);
+	c->jheads = kcalloc(c->jhead_cnt, sizeof(struct ubifs_jhead),
+			    GFP_KERNEL);
 	if (!c->jheads)
 		return -ENOMEM;
 
@@ -1046,7 +1044,7 @@
 		orph = list_entry(c->orph_list.next, struct ubifs_orphan, list);
 		list_del(&orph->list);
 		kfree(orph);
-		ubifs_err("orphan list not empty at unmount");
+		ubifs_err(c, "orphan list not empty at unmount");
 	}
 
 	vfree(c->orph_buf);
@@ -1144,7 +1142,8 @@
  */
 static int parse_standard_option(const char *option)
 {
-	ubifs_msg("parse %s", option);
+
+	pr_notice("UBIFS: parse %s\n", option);
 	if (!strcmp(option, "sync"))
 		return MS_SYNCHRONOUS;
 	return 0;
@@ -1216,7 +1215,7 @@
 			else if (!strcmp(name, "zlib"))
 				c->mount_opts.compr_type = UBIFS_COMPR_ZLIB;
 			else {
-				ubifs_err("unknown compressor \"%s\"", name);
+				ubifs_err(c, "unknown compressor \"%s\"", name); //FIXME: is c ready?
 				kfree(name);
 				return -EINVAL;
 			}
@@ -1232,7 +1231,7 @@
 
 			flag = parse_standard_option(p);
 			if (!flag) {
-				ubifs_err("unrecognized mount option \"%s\" or missing value",
+				ubifs_err(c, "unrecognized mount option \"%s\" or missing value",
 					  p);
 				return -EINVAL;
 			}
@@ -1296,7 +1295,7 @@
 		}
 
 		/* Just disable bulk-read */
-		ubifs_warn("cannot allocate %d bytes of memory for bulk-read, disabling it",
+		ubifs_warn(c, "cannot allocate %d bytes of memory for bulk-read, disabling it",
 			   c->max_bu_buf_len);
 		c->mount_opts.bulk_read = 1;
 		c->bulk_read = 0;
@@ -1316,7 +1315,7 @@
 {
 	ubifs_assert(c->dark_wm > 0);
 	if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
-		ubifs_err("insufficient free space to mount in R/W mode");
+		ubifs_err(c, "insufficient free space to mount in R/W mode");
 		ubifs_dump_budg(c, &c->bi);
 		ubifs_dump_lprops(c);
 		return -ENOSPC;
@@ -1339,6 +1338,8 @@
 	size_t sz;
 
 	c->ro_mount = !!(c->vfs_sb->s_flags & MS_RDONLY);
+	/* Suppress error messages while probing if MS_SILENT is set */
+	c->probing = !!(c->vfs_sb->s_flags & MS_SILENT);
 #ifdef __UBOOT__
 	if (!c->ro_mount) {
 		printf("UBIFS: only ro mode in U-Boot allowed.\n");
@@ -1363,14 +1364,14 @@
 		 * This UBI volume is empty, and read-only, or the file system
 		 * is mounted read-only - we cannot format it.
 		 */
-		ubifs_err("can't format empty UBI volume: read-only %s",
+		ubifs_err(c, "can't format empty UBI volume: read-only %s",
 			  c->ro_media ? "UBI volume" : "mount");
 		err = -EROFS;
 		goto out_free;
 	}
 
 	if (c->ro_media && !c->ro_mount) {
-		ubifs_err("cannot mount read-write - read-only media");
+		ubifs_err(c, "cannot mount read-write - read-only media");
 		err = -EROFS;
 		goto out_free;
 	}
@@ -1415,12 +1416,14 @@
 	if (err)
 		goto out_free;
 
+	c->probing = 0;
+
 	/*
 	 * Make sure the compressor which is set as default in the superblock
 	 * or overridden by mount options is actually compiled in.
 	 */
 	if (!ubifs_compr_present(c->default_compr)) {
-		ubifs_err("'compressor \"%s\" is not compiled in",
+		ubifs_err(c, "'compressor \"%s\" is not compiled in",
 			  ubifs_compr_name(c->default_compr));
 		err = -ENOTSUPP;
 		goto out_free;
@@ -1450,7 +1453,7 @@
 		if (IS_ERR(c->bgt)) {
 			err = PTR_ERR(c->bgt);
 			c->bgt = NULL;
-			ubifs_err("cannot spawn \"%s\", error %d",
+			ubifs_err(c, "cannot spawn \"%s\", error %d",
 				  c->bgt_name, err);
 			goto out_wbufs;
 		}
@@ -1465,7 +1468,7 @@
 	init_constants_master(c);
 
 	if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
-		ubifs_msg("recovery needed");
+		ubifs_msg(c, "recovery needed");
 		c->need_recovery = 1;
 	}
 
@@ -1488,7 +1491,7 @@
 			goto out_lpt;
 	}
 
-	if (!c->ro_mount) {
+	if (!c->ro_mount && !c->need_recovery) {
 		/*
 		 * Set the "dirty" flag so that if we reboot uncleanly we
 		 * will notice this immediately on the next mount.
@@ -1582,10 +1585,10 @@
 
 	if (c->need_recovery) {
 		if (c->ro_mount)
-			ubifs_msg("recovery deferred");
+			ubifs_msg(c, "recovery deferred");
 		else {
 			c->need_recovery = 0;
-			ubifs_msg("recovery completed");
+			ubifs_msg(c, "recovery completed");
 			/*
 			 * GC LEB has to be empty and taken at this point. But
 			 * the journal head LEBs may also be accounted as
@@ -1606,20 +1609,20 @@
 
 	c->mounting = 0;
 
-	ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"%s",
+	ubifs_msg(c, "UBIFS: mounted UBI device %d, volume %d, name \"%s\"%s",
 		  c->vi.ubi_num, c->vi.vol_id, c->vi.name,
 		  c->ro_mount ? ", R/O mode" : "");
 	x = (long long)c->main_lebs * c->leb_size;
 	y = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
-	ubifs_msg("LEB size: %d bytes (%d KiB), min./max. I/O unit sizes: %d bytes/%d bytes",
+	ubifs_msg(c, "LEB size: %d bytes (%d KiB), min./max. I/O unit sizes: %d bytes/%d bytes",
 		  c->leb_size, c->leb_size >> 10, c->min_io_size,
 		  c->max_write_size);
-	ubifs_msg("FS size: %lld bytes (%lld MiB, %d LEBs), journal size %lld bytes (%lld MiB, %d LEBs)",
+	ubifs_msg(c, "FS size: %lld bytes (%lld MiB, %d LEBs), journal size %lld bytes (%lld MiB, %d LEBs)",
 		  x, x >> 20, c->main_lebs,
 		  y, y >> 20, c->log_lebs + c->max_bud_cnt);
-	ubifs_msg("reserved for root: %llu bytes (%llu KiB)",
+	ubifs_msg(c, "reserved for root: %llu bytes (%llu KiB)",
 		  c->report_rp_size, c->report_rp_size >> 10);
-	ubifs_msg("media format: w%d/r%d (latest is w%d/r%d), UUID %pUB%s",
+	ubifs_msg(c, "media format: w%d/r%d (latest is w%d/r%d), UUID %pUB%s",
 		  c->fmt_version, c->ro_compat_version,
 		  UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION, c->uuid,
 		  c->big_lpt ? ", big LPT model" : ", small LPT model");
@@ -1768,8 +1771,8 @@
 	int err, lnum;
 
 	if (c->rw_incompat) {
-		ubifs_err("the file-system is not R/W-compatible");
-		ubifs_msg("on-flash format version is w%d/r%d, but software only supports up to version w%d/r%d",
+		ubifs_err(c, "the file-system is not R/W-compatible");
+		ubifs_msg(c, "on-flash format version is w%d/r%d, but software only supports up to version w%d/r%d",
 			  c->fmt_version, c->ro_compat_version,
 			  UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION);
 		return -EROFS;
@@ -1806,7 +1809,7 @@
 	}
 
 	if (c->need_recovery) {
-		ubifs_msg("completing deferred recovery");
+		ubifs_msg(c, "completing deferred recovery");
 		err = ubifs_write_rcvrd_mst_node(c);
 		if (err)
 			goto out;
@@ -1855,7 +1858,7 @@
 	if (IS_ERR(c->bgt)) {
 		err = PTR_ERR(c->bgt);
 		c->bgt = NULL;
-		ubifs_err("cannot spawn \"%s\", error %d",
+		ubifs_err(c, "cannot spawn \"%s\", error %d",
 			  c->bgt_name, err);
 		goto out;
 	}
@@ -1889,7 +1892,7 @@
 
 	if (c->need_recovery) {
 		c->need_recovery = 0;
-		ubifs_msg("deferred recovery completed");
+		ubifs_msg(c, "deferred recovery completed");
 	} else {
 		/*
 		 * Do not run the debugging space check if the were doing
@@ -1977,8 +1980,7 @@
 	int i;
 	struct ubifs_info *c = sb->s_fs_info;
 
-	ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num,
-		  c->vi.vol_id);
+	ubifs_msg(c, "un-mount UBI device %d", c->vi.ubi_num);
 
 	/*
 	 * The following asserts are only valid if there has not been a failure
@@ -2034,7 +2036,7 @@
 				 * next mount, so we just print a message and
 				 * continue to unmount normally.
 				 */
-				ubifs_err("failed to write master node, error %d",
+				ubifs_err(c, "failed to write master node, error %d",
 					  err);
 		} else {
 #ifndef __UBOOT__
@@ -2065,17 +2067,17 @@
 
 	err = ubifs_parse_options(c, data, 1);
 	if (err) {
-		ubifs_err("invalid or unknown remount parameter");
+		ubifs_err(c, "invalid or unknown remount parameter");
 		return err;
 	}
 
 	if (c->ro_mount && !(*flags & MS_RDONLY)) {
 		if (c->ro_error) {
-			ubifs_msg("cannot re-mount R/W due to prior errors");
+			ubifs_msg(c, "cannot re-mount R/W due to prior errors");
 			return -EROFS;
 		}
 		if (c->ro_media) {
-			ubifs_msg("cannot re-mount R/W - UBI volume is R/O");
+			ubifs_msg(c, "cannot re-mount R/W - UBI volume is R/O");
 			return -EROFS;
 		}
 		err = ubifs_remount_rw(c);
@@ -2083,7 +2085,7 @@
 			return err;
 	} else if (!c->ro_mount && (*flags & MS_RDONLY)) {
 		if (c->ro_error) {
-			ubifs_msg("cannot re-mount R/O due to prior errors");
+			ubifs_msg(c, "cannot re-mount R/O due to prior errors");
 			return -EROFS;
 		}
 		ubifs_remount_ro(c);
@@ -2200,7 +2202,6 @@
 		mutex_init(&c->lp_mutex);
 		mutex_init(&c->tnc_mutex);
 		mutex_init(&c->log_mutex);
-		mutex_init(&c->mst_mutex);
 		mutex_init(&c->umount_mutex);
 		mutex_init(&c->bu_mutex);
 		mutex_init(&c->write_reserve_mutex);
@@ -2261,8 +2262,8 @@
 	 *
 	 * Read-ahead will be disabled because @c->bdi.ra_pages is 0.
 	 */
-	co>bdi.name = "ubifs",
-	c->bdi.capabilities = BDI_CAP_MAP_COPY;
+	c->bdi.name = "ubifs",
+	c->bdi.capabilities = 0;
 	err  = bdi_init(&c->bdi);
 	if (err)
 		goto out_close;
@@ -2285,6 +2286,9 @@
 	if (c->max_inode_sz > MAX_LFS_FILESIZE)
 		sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
 	sb->s_op = &ubifs_super_operations;
+#ifndef __UBOOT__
+	sb->s_xattr = ubifs_xattr_handlers;
+#endif
 
 	mutex_lock(&c->umount_mutex);
 	err = mount_ubifs(c);
@@ -2453,8 +2457,8 @@
 	 */
 	ubi = open_ubi(name, UBI_READONLY);
 	if (IS_ERR(ubi)) {
-		ubifs_err("cannot open \"%s\", error %d",
-			  name, (int)PTR_ERR(ubi));
+		pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
+		       current->pid, name, (int)PTR_ERR(ubi));
 		return ERR_CAST(ubi);
 	}
 
@@ -2595,8 +2599,8 @@
 	 * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
 	 */
 	if (PAGE_CACHE_SIZE < UBIFS_BLOCK_SIZE) {
-		ubifs_err("VFS page cache size is %u bytes, but UBIFS requires at least 4096 bytes",
-			  (unsigned int)PAGE_CACHE_SIZE);
+		pr_err("UBIFS error (pid %d): VFS page cache size is %u bytes, but UBIFS requires at least 4096 bytes",
+		       current->pid, (unsigned int)PAGE_CACHE_SIZE);
 		return -EINVAL;
 	}
 
@@ -2608,7 +2612,9 @@
 	if (!ubifs_inode_slab)
 		return -ENOMEM;
 
-	register_shrinker(&ubifs_shrinker_info);
+	err = register_shrinker(&ubifs_shrinker_info);
+	if (err)
+		goto out_slab;
 #endif
 
 	err = ubifs_compressors_init();
@@ -2622,7 +2628,8 @@
 
 	err = register_filesystem(&ubifs_fs_type);
 	if (err) {
-		ubifs_err("cannot register file system, error %d", err);
+		pr_err("UBIFS error (pid %d): cannot register file system, error %d",
+		       current->pid, err);
 		goto out_dbg;
 	}
 #endif
@@ -2637,6 +2644,7 @@
 out_shrinker:
 #ifndef __UBOOT__
 	unregister_shrinker(&ubifs_shrinker_info);
+out_slab:
 #endif
 	kmem_cache_destroy(ubifs_inode_slab);
 	return err;
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index e20cedd..f6316a3 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -93,7 +93,7 @@
 		else if (offs > o->offs)
 			p = &(*p)->rb_right;
 		else {
-			ubifs_err("old idx added twice!");
+			ubifs_err(c, "old idx added twice!");
 			kfree(old_idx);
 			return 0;
 		}
@@ -442,7 +442,7 @@
 
 	err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
 	if (err) {
-		ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
+		ubifs_err(c, "cannot read node type %d from LEB %d:%d, error %d",
 			  type, lnum, offs, err);
 		return err;
 	}
@@ -1683,27 +1683,27 @@
 	int err, len;
 
 	if (ch->node_type != UBIFS_DATA_NODE) {
-		ubifs_err("bad node type (%d but expected %d)",
+		ubifs_err(c, "bad node type (%d but expected %d)",
 			  ch->node_type, UBIFS_DATA_NODE);
 		goto out_err;
 	}
 
 	err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0);
 	if (err) {
-		ubifs_err("expected node type %d", UBIFS_DATA_NODE);
+		ubifs_err(c, "expected node type %d", UBIFS_DATA_NODE);
 		goto out;
 	}
 
 	len = le32_to_cpu(ch->len);
 	if (len != zbr->len) {
-		ubifs_err("bad node length %d, expected %d", len, zbr->len);
+		ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);
 		goto out_err;
 	}
 
 	/* Make sure the key of the read node is correct */
 	key_read(c, buf + UBIFS_KEY_OFFSET, &key1);
 	if (!keys_eq(c, &zbr->key, &key1)) {
-		ubifs_err("bad key in node at LEB %d:%d",
+		ubifs_err(c, "bad key in node at LEB %d:%d",
 			  zbr->lnum, zbr->offs);
 		dbg_tnck(&zbr->key, "looked for key ");
 		dbg_tnck(&key1, "found node's key ");
@@ -1715,7 +1715,7 @@
 out_err:
 	err = -EINVAL;
 out:
-	ubifs_err("bad node at LEB %d:%d", zbr->lnum, zbr->offs);
+	ubifs_err(c, "bad node at LEB %d:%d", zbr->lnum, zbr->offs);
 	ubifs_dump_node(c, buf);
 	dump_stack();
 	return err;
@@ -1740,7 +1740,7 @@
 	len = bu->zbranch[bu->cnt - 1].offs;
 	len += bu->zbranch[bu->cnt - 1].len - offs;
 	if (len > bu->buf_len) {
-		ubifs_err("buffer too small %d vs %d", bu->buf_len, len);
+		ubifs_err(c, "buffer too small %d vs %d", bu->buf_len, len);
 		return -EINVAL;
 	}
 
@@ -1756,7 +1756,7 @@
 		return -EAGAIN;
 
 	if (err && err != -EBADMSG) {
-		ubifs_err("failed to read from LEB %d:%d, error %d",
+		ubifs_err(c, "failed to read from LEB %d:%d, error %d",
 			  lnum, offs, err);
 		dump_stack();
 		dbg_tnck(&bu->key, "key ");
@@ -2858,10 +2858,11 @@
 {
 	tnc_destroy_cnext(c);
 	if (c->zroot.znode) {
-		long n;
+		long n, freed;
 
-		ubifs_destroy_tnc_subtree(c->zroot.znode);
 		n = atomic_long_read(&c->clean_zn_cnt);
+		freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
+		ubifs_assert(freed == n);
 		atomic_long_sub(n, &ubifs_clean_zn_cnt);
 	}
 	kfree(c->gap_lebs);
@@ -3292,7 +3293,6 @@
 		goto out_unlock;
 
 	if (err) {
-		err = -EINVAL;
 		key = &from_key;
 		goto out_dump;
 	}
@@ -3312,7 +3312,7 @@
 
 out_dump:
 	block = key_block(c, key);
-	ubifs_err("inode %lu has size %lld, but there are data at offset %lld",
+	ubifs_err(c, "inode %lu has size %lld, but there are data at offset %lld",
 		  (unsigned long)inode->i_ino, size,
 		  ((loff_t)block) << UBIFS_BLOCK_SHIFT);
 	mutex_unlock(&c->tnc_mutex);
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index f808e0b..b1bb647 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -285,9 +285,9 @@
 		lnum, offs, znode->level, znode->child_cnt);
 
 	if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
-		ubifs_err("current fanout %d, branch count %d",
+		ubifs_err(c, "current fanout %d, branch count %d",
 			  c->fanout, znode->child_cnt);
-		ubifs_err("max levels %d, znode level %d",
+		ubifs_err(c, "max levels %d, znode level %d",
 			  UBIFS_MAX_LEVELS, znode->level);
 		err = 1;
 		goto out_dump;
@@ -308,7 +308,7 @@
 		if (zbr->lnum < c->main_first ||
 		    zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
 		    zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
-			ubifs_err("bad branch %d", i);
+			ubifs_err(c, "bad branch %d", i);
 			err = 2;
 			goto out_dump;
 		}
@@ -320,7 +320,7 @@
 		case UBIFS_XENT_KEY:
 			break;
 		default:
-			ubifs_err("bad key type at slot %d: %d",
+			ubifs_err(c, "bad key type at slot %d: %d",
 				  i, key_type(c, &zbr->key));
 			err = 3;
 			goto out_dump;
@@ -332,17 +332,17 @@
 		type = key_type(c, &zbr->key);
 		if (c->ranges[type].max_len == 0) {
 			if (zbr->len != c->ranges[type].len) {
-				ubifs_err("bad target node (type %d) length (%d)",
+				ubifs_err(c, "bad target node (type %d) length (%d)",
 					  type, zbr->len);
-				ubifs_err("have to be %d", c->ranges[type].len);
+				ubifs_err(c, "have to be %d", c->ranges[type].len);
 				err = 4;
 				goto out_dump;
 			}
 		} else if (zbr->len < c->ranges[type].min_len ||
 			   zbr->len > c->ranges[type].max_len) {
-			ubifs_err("bad target node (type %d) length (%d)",
+			ubifs_err(c, "bad target node (type %d) length (%d)",
 				  type, zbr->len);
-			ubifs_err("have to be in range of %d-%d",
+			ubifs_err(c, "have to be in range of %d-%d",
 				  c->ranges[type].min_len,
 				  c->ranges[type].max_len);
 			err = 5;
@@ -362,12 +362,12 @@
 
 		cmp = keys_cmp(c, key1, key2);
 		if (cmp > 0) {
-			ubifs_err("bad key order (keys %d and %d)", i, i + 1);
+			ubifs_err(c, "bad key order (keys %d and %d)", i, i + 1);
 			err = 6;
 			goto out_dump;
 		} else if (cmp == 0 && !is_hash_key(c, key1)) {
 			/* These can only be keys with colliding hash */
-			ubifs_err("keys %d and %d are not hashed but equivalent",
+			ubifs_err(c, "keys %d and %d are not hashed but equivalent",
 				  i, i + 1);
 			err = 7;
 			goto out_dump;
@@ -378,7 +378,7 @@
 	return 0;
 
 out_dump:
-	ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
+	ubifs_err(c, "bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
 	ubifs_dump_node(c, idx);
 	kfree(idx);
 	return -EINVAL;
@@ -474,7 +474,7 @@
 	/* Make sure the key of the read node is correct */
 	key_read(c, node + UBIFS_KEY_OFFSET, &key1);
 	if (!keys_eq(c, key, &key1)) {
-		ubifs_err("bad key in node at LEB %d:%d",
+		ubifs_err(c, "bad key in node at LEB %d:%d",
 			  zbr->lnum, zbr->offs);
 		dbg_tnck(key, "looked for key ");
 		dbg_tnck(&key1, "but found node's key ");
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index f7a0847..50355e9 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -103,8 +103,8 @@
 	int compressor;
 };
 
-static inline struct crypto_comp *crypto_alloc_comp(const char *alg_name,
-						u32 type, u32 mask)
+static inline struct crypto_comp
+*crypto_alloc_comp(const char *alg_name, u32 type, u32 mask)
 {
 	struct ubifs_compressor *comp;
 	struct crypto_comp *ptr;
@@ -124,15 +124,16 @@
 		i++;
 	}
 	if (i >= UBIFS_COMPR_TYPES_CNT) {
-		ubifs_err("invalid compression type %s", alg_name);
+		dbg_gen("invalid compression type %s", alg_name);
 		free (ptr);
 		return NULL;
 	}
 	return ptr;
 }
-static inline int crypto_comp_decompress(struct crypto_comp *tfm,
-				const u8 *src, unsigned int slen,
-				u8 *dst, unsigned int *dlen)
+static inline int
+crypto_comp_decompress(const struct ubifs_info *c, struct crypto_comp *tfm,
+		       const u8 *src, unsigned int slen, u8 *dst,
+		       unsigned int *dlen)
 {
 	struct ubifs_compressor *compr = ubifs_compressors[tfm->compressor];
 	int err;
@@ -145,7 +146,7 @@
 
 	err = compr->decompress(src, slen, dst, (size_t *)dlen);
 	if (err)
-		ubifs_err("cannot decompress %d bytes, compressor %s, "
+		ubifs_err(c, "cannot decompress %d bytes, compressor %s, "
 			  "error %d", slen, compr->name, err);
 
 	return err;
@@ -172,21 +173,21 @@
  * The length of the uncompressed data is returned in @out_len. This functions
  * returns %0 on success or a negative error code on failure.
  */
-int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
-		     int *out_len, int compr_type)
+int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
+		     int in_len, void *out_buf, int *out_len, int compr_type)
 {
 	int err;
 	struct ubifs_compressor *compr;
 
 	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
-		ubifs_err("invalid compression type %d", compr_type);
+		ubifs_err(c, "invalid compression type %d", compr_type);
 		return -EINVAL;
 	}
 
 	compr = ubifs_compressors[compr_type];
 
 	if (unlikely(!compr->capi_name)) {
-		ubifs_err("%s compression is not compiled in", compr->name);
+		ubifs_err(c, "%s compression is not compiled in", compr->name);
 		return -EINVAL;
 	}
 
@@ -198,13 +199,13 @@
 
 	if (compr->decomp_mutex)
 		mutex_lock(compr->decomp_mutex);
-	err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf,
+	err = crypto_comp_decompress(c, compr->cc, in_buf, in_len, out_buf,
 				     (unsigned int *)out_len);
 	if (compr->decomp_mutex)
 		mutex_unlock(compr->decomp_mutex);
 	if (err)
-		ubifs_err("cannot decompress %d bytes, compressor %s, error %d",
-			  in_len, compr->name, err);
+		ubifs_err(c, "cannot decompress %d bytes, compressor %s,"
+			  " error %d", in_len, compr->name, err);
 
 	return err;
 }
@@ -229,8 +230,9 @@
 	if (compr->capi_name) {
 		compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0);
 		if (IS_ERR(compr->cc)) {
-			ubifs_err("cannot initialize compressor %s, error %ld",
-				  compr->name, PTR_ERR(compr->cc));
+			dbg_gen("cannot initialize compressor %s,"
+				  " error %ld", compr->name,
+				  PTR_ERR(compr->cc));
 			return PTR_ERR(compr->cc);
 		}
 	}
@@ -384,7 +386,7 @@
 
 out:
 	if (err != -ENOENT) {
-		ubifs_err("cannot find next direntry, error %d", err);
+		ubifs_err(c, "cannot find next direntry, error %d", err);
 		return err;
 	}
 
@@ -468,7 +470,7 @@
 
 out:
 	if (err != -ENOENT)
-		ubifs_err("cannot find next direntry, error %d", err);
+		dbg_gen("cannot find next direntry, error %d", err);
 
 out_free:
 	if (file->private_data)
@@ -570,7 +572,26 @@
 	return 0;
 }
 
-int ubifs_ls(char *filename)
+int ubifs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info)
+{
+	if (rbdd) {
+		debug("UBIFS cannot be used with normal block devices\n");
+		return -1;
+	}
+
+	/*
+	 * Should never happen since get_device_and_partition() already checks
+	 * this, but better safe then sorry.
+	 */
+	if (!ubifs_is_mounted()) {
+		debug("UBIFS not mounted, use ubifsmount to mount volume first!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int ubifs_ls(const char *filename)
 {
 	struct ubifs_info *c = ubifs_sb->s_fs_info;
 	struct file *file;
@@ -581,7 +602,7 @@
 	int ret = 0;
 
 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
-	inum = ubifs_findfile(ubifs_sb, filename);
+	inum = ubifs_findfile(ubifs_sb, (char *)filename);
 	if (!inum) {
 		ret = -1;
 		goto out;
@@ -618,6 +639,48 @@
 	return ret;
 }
 
+int ubifs_exists(const char *filename)
+{
+	struct ubifs_info *c = ubifs_sb->s_fs_info;
+	unsigned long inum;
+
+	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+	inum = ubifs_findfile(ubifs_sb, (char *)filename);
+	ubi_close_volume(c->ubi);
+
+	return inum != 0;
+}
+
+int ubifs_size(const char *filename, loff_t *size)
+{
+	struct ubifs_info *c = ubifs_sb->s_fs_info;
+	unsigned long inum;
+	struct inode *inode;
+	int err = 0;
+
+	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
+
+	inum = ubifs_findfile(ubifs_sb, (char *)filename);
+	if (!inum) {
+		err = -1;
+		goto out;
+	}
+
+	inode = ubifs_iget(ubifs_sb, inum);
+	if (IS_ERR(inode)) {
+		printf("%s: Error reading inode %ld!\n", __func__, inum);
+		err = PTR_ERR(inode);
+		goto out;
+	}
+
+	*size = inode->i_size;
+
+	ubifs_iput(inode);
+out:
+	ubi_close_volume(c->ubi);
+	return err;
+}
+
 /*
  * ubifsload...
  */
@@ -654,7 +717,7 @@
 
 	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
 	out_len = UBIFS_BLOCK_SIZE;
-	err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
+	err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
 			       le16_to_cpu(dn->compr_type));
 	if (err || len != out_len)
 		goto dump;
@@ -670,7 +733,7 @@
 	return 0;
 
 dump:
-	ubifs_err("bad data node (block %u, inode %lu)",
+	ubifs_err(c, "bad data node (block %u, inode %lu)",
 		  block, inode->i_ino);
 	ubifs_dump_node(c, dn);
 	return -EINVAL;
@@ -772,7 +835,7 @@
 			dbg_gen("hole");
 			goto out_free;
 		}
-		ubifs_err("cannot read page %lu of inode %lu, error %d",
+		ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
 			  page->index, inode->i_ino, err);
 		goto error;
 	}
@@ -787,7 +850,8 @@
 	return err;
 }
 
-int ubifs_load(char *filename, u32 addr, u32 size)
+int ubifs_read(const char *filename, void *buf, loff_t offset,
+	       loff_t size, loff_t *actread)
 {
 	struct ubifs_info *c = ubifs_sb->s_fs_info;
 	unsigned long inum;
@@ -798,10 +862,18 @@
 	int count;
 	int last_block_size = 0;
 
+	*actread = 0;
+
+	if (offset & (PAGE_SIZE - 1)) {
+		printf("ubifs: Error offset must be a multple of %d\n",
+		       PAGE_SIZE);
+		return -1;
+	}
+
 	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
 	/* ubifs_findfile will resolve symlinks, so we know that we get
 	 * the real file here */
-	inum = ubifs_findfile(ubifs_sb, filename);
+	inum = ubifs_findfile(ubifs_sb, (char *)filename);
 	if (!inum) {
 		err = -1;
 		goto out;
@@ -817,19 +889,24 @@
 		goto out;
 	}
 
+	if (offset > inode->i_size) {
+		printf("ubifs: Error offset (%lld) > file-size (%lld)\n",
+		       offset, size);
+		err = -1;
+		goto put_inode;
+	}
+
 	/*
 	 * If no size was specified or if size bigger than filesize
 	 * set size to filesize
 	 */
-	if ((size == 0) || (size > inode->i_size))
-		size = inode->i_size;
+	if ((size == 0) || (size > (inode->i_size - offset)))
+		size = inode->i_size - offset;
 
 	count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
-	printf("Loading file '%s' to addr 0x%08x with size %d (0x%08x)...\n",
-	       filename, addr, size, size);
 
-	page.addr = (void *)addr;
-	page.index = 0;
+	page.addr = buf;
+	page.index = offset / PAGE_SIZE;
 	page.inode = inode;
 	for (i = 0; i < count; i++) {
 		/*
@@ -846,16 +923,48 @@
 		page.index++;
 	}
 
-	if (err)
+	if (err) {
 		printf("Error reading file '%s'\n", filename);
-	else {
-		setenv_hex("filesize", size);
-		printf("Done\n");
+		*actread = i * PAGE_SIZE;
+	} else {
+		*actread = size;
 	}
 
+put_inode:
 	ubifs_iput(inode);
 
 out:
 	ubi_close_volume(c->ubi);
 	return err;
 }
+
+void ubifs_close(void)
+{
+}
+
+/* Compat wrappers for common/cmd_ubifs.c */
+int ubifs_load(char *filename, u32 addr, u32 size)
+{
+	loff_t actread;
+	int err;
+
+	printf("Loading file '%s' to addr 0x%08x...\n", filename, addr);
+
+	err = ubifs_read(filename, (void *)addr, 0, size, &actread);
+	if (err == 0) {
+		setenv_hex("filesize", actread);
+		printf("Done\n");
+	}
+
+	return err;
+}
+
+void uboot_ubifs_umount(void)
+{
+	if (ubifs_sb) {
+		printf("Unmounting UBIFS volume %s!\n",
+		       ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name);
+		ubifs_umount(ubifs_sb->s_fs_info);
+		ubifs_sb = NULL;
+	}
+}
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index a51b237..1d89465 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -29,11 +29,13 @@
 #include <linux/mtd/ubi.h>
 #include <linux/pagemap.h>
 #include <linux/backing-dev.h>
+#include <linux/security.h>
 #include "ubifs-media.h"
 #else
 #include <asm/atomic.h>
 #include <asm-generic/atomic-long.h>
 #include <ubi_uboot.h>
+#include <ubifs_uboot.h>
 
 #include <linux/ctype.h>
 #include <linux/time.h>
@@ -616,24 +618,43 @@
 #define UBIFS_VERSION 1
 
 /* Normal UBIFS messages */
-#define ubifs_msg(fmt, ...) pr_notice("UBIFS: " fmt "\n", ##__VA_ARGS__)
+#define ubifs_msg(c, fmt, ...)                                      \
+	pr_notice("UBIFS (ubi%d:%d): " fmt "\n",                    \
+		  (c)->vi.ubi_num, (c)->vi.vol_id, ##__VA_ARGS__)
 /* UBIFS error messages */
 #ifndef __UBOOT__
-#define ubifs_err(fmt, ...)                                         \
-	pr_err("UBIFS error (pid %d): %s: " fmt "\n", current->pid, \
+#define ubifs_err(c, fmt, ...)                                      \
+	pr_err("UBIFS error (ubi%d:%d pid %d): %s: " fmt "\n",      \
+	       (c)->vi.ubi_num, (c)->vi.vol_id, current->pid,       \
 	       __func__, ##__VA_ARGS__)
 /* UBIFS warning messages */
-#define ubifs_warn(fmt, ...)                                        \
-	pr_warn("UBIFS warning (pid %d): %s: " fmt "\n",            \
-		current->pid, __func__, ##__VA_ARGS__)
+#define ubifs_warn(c, fmt, ...)                                     \
+	pr_warn("UBIFS warning (ubi%d:%d pid %d): %s: " fmt "\n",   \
+		(c)->vi.ubi_num, (c)->vi.vol_id, current->pid,      \
+		__func__, ##__VA_ARGS__)
 #else
-#define ubifs_err(fmt, ...)                                         \
-	pr_err("UBIFS error: %s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define ubifs_err(c, fmt, ...)                                      \
+	pr_err("UBIFS error (ubi%d:%d pid %d): %s: " fmt "\n",      \
+	       (c)->vi.ubi_num, (c)->vi.vol_id, 0,                  \
+	       __func__, ##__VA_ARGS__)
 /* UBIFS warning messages */
-#define ubifs_warn(fmt, ...)                                        \
-	pr_warn("UBIFS warning: %s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define ubifs_warn(c, fmt, ...)                                     \
+	pr_warn("UBIFS warning (ubi%d:%d pid %d): %s: " fmt "\n",   \
+		(c)->vi.ubi_num, (c)->vi.vol_id, 0,                 \
+		__func__, ##__VA_ARGS__)
+
 #endif
 
+/*
+ * A variant of 'ubifs_err()' which takes the UBIFS file-sytem description
+ * object as an argument.
+ */
+#define ubifs_errc(c, fmt, ...)                                     \
+	do {                                                        \
+		if (!(c)->probing)                                  \
+			ubifs_err(c, fmt, ##__VA_ARGS__);           \
+	} while (0)
+
 /* UBIFS file system VFS magic number */
 #define UBIFS_SUPER_MAGIC 0x24051905
 
@@ -730,7 +751,7 @@
 #define WORST_COMPR_FACTOR 2
 
 /*
- * How much memory is needed for a buffer where we comress a data node.
+ * How much memory is needed for a buffer where we compress a data node.
  */
 #define COMPRESSED_DATA_NODE_BUF_SZ \
 	(UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
@@ -887,7 +908,6 @@
  * @nodes_cnt: number of nodes scanned
  * @nodes: list of struct ubifs_scan_node
  * @endpt: end point (and therefore the start of empty space)
- * @ecc: read returned -EBADMSG
  * @buf: buffer containing entire LEB scanned
  */
 struct ubifs_scan_leb {
@@ -895,7 +915,6 @@
 	int nodes_cnt;
 	struct list_head nodes;
 	int endpt;
-	int ecc;
 	void *buf;
 };
 
@@ -1238,7 +1257,7 @@
  * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
  *        fields
  * @softlimit: soft write-buffer timeout interval
- * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit
+ * @delta: hard and soft timeouts delta (the timer expire interval is @softlimit
  *         and @softlimit + @delta)
  * @timer: write-buffer timer
  * @no_timer: non-zero if this write-buffer does not have a timer
@@ -1508,9 +1527,9 @@
 /**
  * struct ubifs_mount_opts - UBIFS-specific mount options information.
  * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
- * @bulk_read: enable/disable bulk-reads (%0 default, %1 disabe, %2 enable)
+ * @bulk_read: enable/disable bulk-reads (%0 default, %1 disable, %2 enable)
  * @chk_data_crc: enable/disable CRC data checking when reading data nodes
- *                (%0 default, %1 disabe, %2 enable)
+ *                (%0 default, %1 disable, %2 enable)
  * @override_compr: override default compressor (%0 - do not override and use
  *                  superblock compressor, %1 - override and use compressor
  *                  specified in @compr_type)
@@ -1540,9 +1559,9 @@
  *           optimization)
  * @nospace_rp: the same as @nospace, but additionally means that even reserved
  *              pool is full
- * @page_budget: budget for a page (constant, nenver changed after mount)
- * @inode_budget: budget for an inode (constant, nenver changed after mount)
- * @dent_budget: budget for a directory entry (constant, nenver changed after
+ * @page_budget: budget for a page (constant, never changed after mount)
+ * @inode_budget: budget for an inode (constant, never changed after mount)
+ * @dent_budget: budget for a directory entry (constant, never changed after
  *               mount)
  */
 struct ubifs_budg_info {
@@ -1628,7 +1647,6 @@
  *
  * @mst_node: master node
  * @mst_offs: offset of valid master node
- * @mst_mutex: protects the master node area, @mst_node, and @mst_offs
  *
  * @max_bu_buf_len: maximum bulk-read buffer length
  * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu
@@ -1795,6 +1813,7 @@
  * @need_recovery: %1 if the file-system needs recovery
  * @replaying: %1 during journal replay
  * @mounting: %1 while mounting
+ * @probing: %1 while attempting to mount if MS_SILENT mount flag is set
  * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
  * @replay_list: temporary list used during journal replay
  * @replay_buds: list of buds to replay
@@ -1870,7 +1889,6 @@
 
 	struct ubifs_mst_node *mst_node;
 	int mst_offs;
-	struct mutex mst_mutex;
 
 	int max_bu_buf_len;
 	struct mutex bu_mutex;
@@ -2029,6 +2047,7 @@
 	unsigned int replaying:1;
 	unsigned int mounting:1;
 	unsigned int remounting_rw:1;
+	unsigned int probing:1;
 	struct list_head replay_list;
 	struct list_head replay_buds;
 	unsigned long long cs_sqnum;
@@ -2048,6 +2067,7 @@
 extern atomic_long_t ubifs_clean_zn_cnt;
 extern struct kmem_cache *ubifs_inode_slab;
 extern const struct super_operations ubifs_super_operations;
+extern const struct xattr_handler *ubifs_xattr_handlers[];
 extern const struct address_space_operations ubifs_file_address_operations;
 extern const struct file_operations ubifs_file_operations;
 extern const struct inode_operations ubifs_file_inode_operations;
@@ -2339,6 +2359,8 @@
 		       size_t size);
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int ubifs_removexattr(struct dentry *dentry, const char *name);
+int ubifs_init_security(struct inode *dentry, struct inode *inode,
+			const struct qstr *qstr);
 
 /* super.c */
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
@@ -2369,21 +2391,16 @@
 /* compressor.c */
 int __init ubifs_compressors_init(void);
 void ubifs_compressors_exit(void);
-void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
-		    int *compr_type);
-int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
-		     int compr_type);
+void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len,
+		    void *out_buf, int *out_len, int *compr_type);
+int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
+		     void *out, int *out_len, int compr_type);
 
 #include "debug.h"
 #include "misc.h"
 #include "key.h"
 
 #ifdef __UBOOT__
-/* these are used in cmd_ubifs.c */
-int ubifs_init(void);
-int uboot_ubifs_mount(char *vol_name);
 void ubifs_umount(struct ubifs_info *c);
-int ubifs_ls(char *dir_name);
-int ubifs_load(char *filename, u32 addr, u32 size);
 #endif
 #endif /* !__UBIFS_H__ */
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 2155265..d0383f3 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -69,6 +69,9 @@
 	struct udevice	*dm_root_f;	/* Pre-relocation root instance */
 	struct list_head uclass_root;	/* Head of core tree */
 #endif
+#ifdef CONFIG_TIMER
+	struct udevice	*timer;	/* Timer instance for Driver Model */
+#endif
 
 	const void *fdt_blob;	/* Our device tree, NULL if none */
 	void *new_fdt;		/* Relocated FDT */
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index d2f49a1..66264ce 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -72,6 +72,24 @@
 	BOOT_TARGET_DEVICES_references_MMC_without_CONFIG_CMD_MMC
 #endif
 
+#ifdef CONFIG_CMD_UBIFS
+#define BOOTENV_SHARED_UBIFS \
+	"ubifs_boot=" \
+		"if ubi part UBI && ubifsmount ubi${devnum}:boot; then "  \
+			"setenv devtype ubi; "                            \
+			"setenv bootpart 0; "                             \
+			"run scan_dev_for_boot; "                         \
+		"fi\0"
+#define BOOTENV_DEV_UBIFS	BOOTENV_DEV_BLKDEV
+#define BOOTENV_DEV_NAME_UBIFS	BOOTENV_DEV_NAME_BLKDEV
+#else
+#define BOOTENV_SHARED_UBIFS
+#define BOOTENV_DEV_UBIFS \
+	BOOT_TARGET_DEVICES_references_UBIFS_without_CONFIG_CMD_UBIFS
+#define BOOTENV_DEV_NAME_UBIFS \
+	BOOT_TARGET_DEVICES_references_UBIFS_without_CONFIG_CMD_UBIFS
+#endif
+
 #ifdef CONFIG_CMD_SATA
 #define BOOTENV_SHARED_SATA	BOOTENV_SHARED_BLKDEV(sata)
 #define BOOTENV_DEV_SATA	BOOTENV_DEV_BLKDEV
@@ -185,6 +203,7 @@
 	BOOTENV_SHARED_SATA \
 	BOOTENV_SHARED_SCSI \
 	BOOTENV_SHARED_IDE \
+	BOOTENV_SHARED_UBIFS \
 	"boot_prefixes=/ /boot/\0" \
 	"boot_scripts=boot.scr.uimg boot.scr\0" \
 	"boot_script_dhcp=boot.scr.uimg\0" \
diff --git a/include/configs/B4860QDS.h b/include/configs/B4860QDS.h
index 858e25d..c83e5ce 100644
--- a/include/configs/B4860QDS.h
+++ b/include/configs/B4860QDS.h
@@ -7,7 +7,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/BSC9131RDB.h b/include/configs/BSC9131RDB.h
index 226a170..2754016 100644
--- a/include/configs/BSC9131RDB.h
+++ b/include/configs/BSC9131RDB.h
@@ -11,7 +11,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifdef CONFIG_BSC9131RDB
diff --git a/include/configs/BSC9132QDS.h b/include/configs/BSC9132QDS.h
index e545447..a006dce 100644
--- a/include/configs/BSC9132QDS.h
+++ b/include/configs/BSC9132QDS.h
@@ -11,13 +11,13 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifdef CONFIG_BSC9132QDS
 #define CONFIG_BSC9132
 #endif
 
+#define CONFIG_FSL_CLK
 #define CONFIG_MISC_INIT_R
 
 #ifdef CONFIG_SDCARD
diff --git a/include/configs/C29XPCIE.h b/include/configs/C29XPCIE.h
index f574994..94f991b 100644
--- a/include/configs/C29XPCIE.h
+++ b/include/configs/C29XPCIE.h
@@ -12,7 +12,6 @@
 #define __CONFIG_H
 
 #define CONFIG_PHYS_64BIT
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifdef CONFIG_C29XPCIE
diff --git a/include/configs/CPCI2DP.h b/include/configs/CPCI2DP.h
index ce7bc35..e00ab04 100644
--- a/include/configs/CPCI2DP.h
+++ b/include/configs/CPCI2DP.h
@@ -20,7 +20,6 @@
 #define CONFIG_405GP		1	/* This is a PPC405 CPU		*/
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFFC0000
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_BOARD_EARLY_INIT_F 1	/* call board_early_init_f()	*/
diff --git a/include/configs/CPCI4052.h b/include/configs/CPCI4052.h
index 2827a04..332a1df 100644
--- a/include/configs/CPCI4052.h
+++ b/include/configs/CPCI4052.h
@@ -23,7 +23,6 @@
 #undef  CONFIG_CPCI405_6U               /* enable this for 6U boards    */
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFFC0000
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_BOARD_EARLY_INIT_F 1	/* call board_early_init_f()	*/
diff --git a/include/configs/MIP405.h b/include/configs/MIP405.h
index 0757e67..ec62c8a 100644
--- a/include/configs/MIP405.h
+++ b/include/configs/MIP405.h
@@ -21,7 +21,6 @@
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFF80000
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /***********************************************************
  * Note that it may also be a MIP405T board which is a subset of the
diff --git a/include/configs/MPC8308RDB.h b/include/configs/MPC8308RDB.h
index 4150d5a..cfa5931 100644
--- a/include/configs/MPC8308RDB.h
+++ b/include/configs/MPC8308RDB.h
@@ -9,8 +9,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 /*
  * High Level Configuration Options
diff --git a/include/configs/MPC8313ERDB.h b/include/configs/MPC8313ERDB.h
index d558db7..7db67c2 100644
--- a/include/configs/MPC8313ERDB.h
+++ b/include/configs/MPC8313ERDB.h
@@ -10,7 +10,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/MPC8315ERDB.h b/include/configs/MPC8315ERDB.h
index cbe10af..eb50be6 100644
--- a/include/configs/MPC8315ERDB.h
+++ b/include/configs/MPC8315ERDB.h
@@ -9,7 +9,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_SYS_NAND_U_BOOT_SIZE  (512 << 10)
diff --git a/include/configs/MPC8323ERDB.h b/include/configs/MPC8323ERDB.h
index 7547c12..59d5e56 100644
--- a/include/configs/MPC8323ERDB.h
+++ b/include/configs/MPC8323ERDB.h
@@ -9,7 +9,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/MPC832XEMDS.h b/include/configs/MPC832XEMDS.h
index 9805df7..5ab7d5f 100644
--- a/include/configs/MPC832XEMDS.h
+++ b/include/configs/MPC832XEMDS.h
@@ -7,7 +7,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/MPC8349EMDS.h b/include/configs/MPC8349EMDS.h
index 57547a4..988a900 100644
--- a/include/configs/MPC8349EMDS.h
+++ b/include/configs/MPC8349EMDS.h
@@ -13,7 +13,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/MPC8349ITX.h b/include/configs/MPC8349ITX.h
index 834786d..091ca17 100644
--- a/include/configs/MPC8349ITX.h
+++ b/include/configs/MPC8349ITX.h
@@ -40,7 +40,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #if (CONFIG_SYS_TEXT_BASE == 0xFE000000)
diff --git a/include/configs/MPC837XEMDS.h b/include/configs/MPC837XEMDS.h
index cebd175..990fc04 100644
--- a/include/configs/MPC837XEMDS.h
+++ b/include/configs/MPC837XEMDS.h
@@ -8,8 +8,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 /*
  * High Level Configuration Options
diff --git a/include/configs/MPC837XERDB.h b/include/configs/MPC837XERDB.h
index 5c6ad19..fcc531b 100644
--- a/include/configs/MPC837XERDB.h
+++ b/include/configs/MPC837XERDB.h
@@ -16,7 +16,7 @@
 #define CONFIG_MPC837x		1 /* MPC837x CPU specific */
 #define CONFIG_MPC837XERDB	1
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 #define	CONFIG_SYS_TEXT_BASE	0xFE000000
 
diff --git a/include/configs/MPC8536DS.h b/include/configs/MPC8536DS.h
index 7c51eef..af8eb8c 100644
--- a/include/configs/MPC8536DS.h
+++ b/include/configs/MPC8536DS.h
@@ -11,8 +11,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 #include "../board/freescale/common/ics307_clk.h"
 
 #ifdef CONFIG_36BIT
diff --git a/include/configs/MPC8540ADS.h b/include/configs/MPC8540ADS.h
index dc6e395..157ca69 100644
--- a/include/configs/MPC8540ADS.h
+++ b/include/configs/MPC8540ADS.h
@@ -18,7 +18,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/MPC8541CDS.h b/include/configs/MPC8541CDS.h
index bf03603..68ea5d8 100644
--- a/include/configs/MPC8541CDS.h
+++ b/include/configs/MPC8541CDS.h
@@ -13,7 +13,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/MPC8544DS.h b/include/configs/MPC8544DS.h
index bef28b3..166fcda 100644
--- a/include/configs/MPC8544DS.h
+++ b/include/configs/MPC8544DS.h
@@ -11,7 +11,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/MPC8548CDS.h b/include/configs/MPC8548CDS.h
index 2bea604..517b449 100644
--- a/include/configs/MPC8548CDS.h
+++ b/include/configs/MPC8548CDS.h
@@ -13,7 +13,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifdef CONFIG_36BIT
diff --git a/include/configs/MPC8555CDS.h b/include/configs/MPC8555CDS.h
index 80b14cb..184f514 100644
--- a/include/configs/MPC8555CDS.h
+++ b/include/configs/MPC8555CDS.h
@@ -13,7 +13,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/MPC8560ADS.h b/include/configs/MPC8560ADS.h
index e1bc8cc..69ce13c 100644
--- a/include/configs/MPC8560ADS.h
+++ b/include/configs/MPC8560ADS.h
@@ -18,7 +18,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/MPC8568MDS.h b/include/configs/MPC8568MDS.h
index 064bd85..f6e43ce 100644
--- a/include/configs/MPC8568MDS.h
+++ b/include/configs/MPC8568MDS.h
@@ -10,7 +10,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/MPC8569MDS.h b/include/configs/MPC8569MDS.h
index 0af670b..9f784e0 100644
--- a/include/configs/MPC8569MDS.h
+++ b/include/configs/MPC8569MDS.h
@@ -10,9 +10,9 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
+#define CONFIG_FSL_CLK
 /* High Level Configuration Options */
 #define CONFIG_BOOKE		1	/* BOOKE */
 #define CONFIG_E500		1	/* BOOKE e500 family */
diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h
index 4b5467b..19da477 100644
--- a/include/configs/MPC8572DS.h
+++ b/include/configs/MPC8572DS.h
@@ -11,7 +11,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #include "../board/freescale/common/ics307_clk.h"
diff --git a/include/configs/MPC8610HPCD.h b/include/configs/MPC8610HPCD.h
index 9a487e0..4ce04a8 100644
--- a/include/configs/MPC8610HPCD.h
+++ b/include/configs/MPC8610HPCD.h
@@ -13,7 +13,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h
index f20ee79..6f1535e 100644
--- a/include/configs/MPC8641HPCN.h
+++ b/include/configs/MPC8641HPCN.h
@@ -16,7 +16,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* High Level Configuration Options */
diff --git a/include/configs/P1010RDB.h b/include/configs/P1010RDB.h
index b85e195..9e40730 100644
--- a/include/configs/P1010RDB.h
+++ b/include/configs/P1010RDB.h
@@ -14,8 +14,8 @@
 #ifdef CONFIG_36BIT
 #define CONFIG_PHYS_64BIT
 #endif
-#define	CONFIG_SYS_GENERIC_BOARD
 #define	CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #define CONFIG_P1010
 #define CONFIG_E500			/* BOOKE e500 family */
diff --git a/include/configs/P1022DS.h b/include/configs/P1022DS.h
index 95c81ab..c571fac 100644
--- a/include/configs/P1022DS.h
+++ b/include/configs/P1022DS.h
@@ -11,8 +11,8 @@
 
 #include "../board/freescale/common/ics307_clk.h"
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #ifdef CONFIG_36BIT
 #define CONFIG_PHYS_64BIT
diff --git a/include/configs/P1023RDB.h b/include/configs/P1023RDB.h
index e61db18..4d87198 100644
--- a/include/configs/P1023RDB.h
+++ b/include/configs/P1023RDB.h
@@ -10,7 +10,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifndef CONFIG_SYS_TEXT_BASE
diff --git a/include/configs/P2041RDB.h b/include/configs/P2041RDB.h
index de205e8..0cd9904 100644
--- a/include/configs/P2041RDB.h
+++ b/include/configs/P2041RDB.h
@@ -13,9 +13,9 @@
 
 #define CONFIG_P2041RDB
 #define CONFIG_PHYS_64BIT
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_PPC_P2041
+#define CONFIG_FSL_CLK
 
 #ifdef CONFIG_RAMBOOT_PBL
 #define CONFIG_RAMBOOT_TEXT_BASE	CONFIG_SYS_TEXT_BASE
diff --git a/include/configs/PATI.h b/include/configs/PATI.h
index 5d0e422..81d535f 100644
--- a/include/configs/PATI.h
+++ b/include/configs/PATI.h
@@ -21,7 +21,6 @@
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFF00000
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Serial Console Configuration */
 #define	CONFIG_5xx_CONS_SCI1
diff --git a/include/configs/PIP405.h b/include/configs/PIP405.h
index 4601bc8..45eecc4 100644
--- a/include/configs/PIP405.h
+++ b/include/configs/PIP405.h
@@ -21,7 +21,6 @@
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFF80000
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /***********************************************************
  * Clock
diff --git a/include/configs/PLU405.h b/include/configs/PLU405.h
index d5d3092..d668a15 100644
--- a/include/configs/PLU405.h
+++ b/include/configs/PLU405.h
@@ -21,7 +21,6 @@
 #define CONFIG_PLU405		1	/* ...on a PLU405 board		*/
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFF80000
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_BOARD_EARLY_INIT_F 1	/* call board_early_init_f()	*/
diff --git a/include/configs/PMC405DE.h b/include/configs/PMC405DE.h
index 2f35ca9..0fdd7e2 100644
--- a/include/configs/PMC405DE.h
+++ b/include/configs/PMC405DE.h
@@ -12,7 +12,6 @@
 #define CONFIG_PMC405DE		1	/* ...on a PMC405DE board	*/
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFFC0000
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_BOARD_EARLY_INIT_F 1	/* call board_early_init_f()	*/
diff --git a/include/configs/PMC440.h b/include/configs/PMC440.h
index fad5744..0227649 100644
--- a/include/configs/PMC440.h
+++ b/include/configs/PMC440.h
@@ -29,7 +29,6 @@
 #define CONFIG_SYS_TEXT_BASE	0xFFF90000
 #endif
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_SYS_CLK_FREQ	33333400
diff --git a/include/configs/T102xQDS.h b/include/configs/T102xQDS.h
index c9e5ea9..4f22657 100644
--- a/include/configs/T102xQDS.h
+++ b/include/configs/T102xQDS.h
@@ -12,7 +12,6 @@
 #define __T1024QDS_H
 
 /* High Level Configuration Options */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_BOOKE
 #define CONFIG_E500			/* BOOKE e500 family */
@@ -21,6 +20,7 @@
 #define CONFIG_MP			/* support multiple processors */
 #define CONFIG_PHYS_64BIT
 #define CONFIG_ENABLE_36BIT_PHYS
+#define CONFIG_FSL_CLK
 
 #ifdef CONFIG_PHYS_64BIT
 #define CONFIG_ADDR_MAP		1
diff --git a/include/configs/T102xRDB.h b/include/configs/T102xRDB.h
index 0601d73..d412d0b 100644
--- a/include/configs/T102xRDB.h
+++ b/include/configs/T102xRDB.h
@@ -12,7 +12,6 @@
 #define __T1024RDB_H
 
 /* High Level Configuration Options */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_BOOKE
 #define CONFIG_E500			/* BOOKE e500 family */
@@ -21,6 +20,7 @@
 #define CONFIG_MP			/* support multiple processors */
 #define CONFIG_PHYS_64BIT
 #define CONFIG_ENABLE_36BIT_PHYS
+#define CONFIG_FSL_CLK
 
 #ifdef CONFIG_PHYS_64BIT
 #define CONFIG_ADDR_MAP		1
diff --git a/include/configs/T1040QDS.h b/include/configs/T1040QDS.h
index 4b735b5..18df237 100644
--- a/include/configs/T1040QDS.h
+++ b/include/configs/T1040QDS.h
@@ -28,8 +28,8 @@
  */
 #define CONFIG_T1040QDS
 #define CONFIG_PHYS_64BIT
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #ifdef CONFIG_RAMBOOT_PBL
 #define CONFIG_RAMBOOT_TEXT_BASE	CONFIG_SYS_TEXT_BASE
diff --git a/include/configs/T104xRDB.h b/include/configs/T104xRDB.h
index 7f8d110..2091015 100644
--- a/include/configs/T104xRDB.h
+++ b/include/configs/T104xRDB.h
@@ -12,8 +12,8 @@
  */
 #define CONFIG_T104xRDB
 #define CONFIG_PHYS_64BIT
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #define CONFIG_E500			/* BOOKE e500 family */
 #include <asm/config_mpc85xx.h>
diff --git a/include/configs/T208xQDS.h b/include/configs/T208xQDS.h
index a804cbe..d35b9d2 100644
--- a/include/configs/T208xQDS.h
+++ b/include/configs/T208xQDS.h
@@ -11,9 +11,9 @@
 #ifndef __T208xQDS_H
 #define __T208xQDS_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_ICS307_REFCLK_HZ 25000000  /* ICS307 ref clk freq */
+#define CONFIG_FSL_CLK
 #define CONFIG_MMC
 #define CONFIG_USB_EHCI
 #if defined(CONFIG_PPC_T2080)
diff --git a/include/configs/T208xRDB.h b/include/configs/T208xRDB.h
index 307a0ea..c632b8e 100644
--- a/include/configs/T208xRDB.h
+++ b/include/configs/T208xRDB.h
@@ -11,10 +11,10 @@
 #ifndef __T2080RDB_H
 #define __T2080RDB_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_T2080RDB
 #define CONFIG_ICS307_REFCLK_HZ 25000000  /* ICS307 ref clk freq */
+#define CONFIG_FSL_CLK
 #define CONFIG_MMC
 #define CONFIG_USB_EHCI
 #define CONFIG_FSL_SATA_V2
diff --git a/include/configs/T4240QDS.h b/include/configs/T4240QDS.h
index 4edb3cb..dd8dd73 100644
--- a/include/configs/T4240QDS.h
+++ b/include/configs/T4240QDS.h
@@ -12,6 +12,7 @@
 
 #define CONFIG_T4240QDS
 #define CONFIG_PHYS_64BIT
+#define CONFIG_FSL_CLK
 
 #define CONFIG_FSL_SATA_V2
 #define CONFIG_PCIE4
diff --git a/include/configs/T4240RDB.h b/include/configs/T4240RDB.h
index 754d182..2c5f800 100644
--- a/include/configs/T4240RDB.h
+++ b/include/configs/T4240RDB.h
@@ -12,8 +12,8 @@
 
 #define CONFIG_T4240RDB
 #define CONFIG_PHYS_64BIT
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #define CONFIG_FSL_SATA_V2
 #define CONFIG_PCIE4
diff --git a/include/configs/TQM5200.h b/include/configs/TQM5200.h
index 5a59b80..342fdfe 100644
--- a/include/configs/TQM5200.h
+++ b/include/configs/TQM5200.h
@@ -19,7 +19,6 @@
 #define CONFIG_MPC5200		1	/* This is an MPC5200 CPU		*/
 #define CONFIG_TQM5200		1	/* ... on TQM5200 module		*/
 #undef CONFIG_TQM5200_REV100		/*  define for revision 100 modules	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/TQM823L.h b/include/configs/TQM823L.h
index cea3149..013e40e 100644
--- a/include/configs/TQM823L.h
+++ b/include/configs/TQM823L.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC823		1	/* This is a MPC823 CPU		*/
 #define CONFIG_TQM823L		1	/* ...on a TQM8xxL module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM823M.h b/include/configs/TQM823M.h
index 85215b1..fbb2f84 100644
--- a/include/configs/TQM823M.h
+++ b/include/configs/TQM823M.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC823		1	/* This is a MPC823 CPU		*/
 #define CONFIG_TQM823M		1	/* ...on a TQM8xxM module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM834x.h b/include/configs/TQM834x.h
index 4164303..0b046d1 100644
--- a/include/configs/TQM834x.h
+++ b/include/configs/TQM834x.h
@@ -12,7 +12,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/TQM850L.h b/include/configs/TQM850L.h
index 97a9fa7..0077105 100644
--- a/include/configs/TQM850L.h
+++ b/include/configs/TQM850L.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC850		1	/* This is a MPC850 CPU		*/
 #define CONFIG_TQM850L		1	/* ...on a TQM8xxL module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM850M.h b/include/configs/TQM850M.h
index 636ffc8..4a443ed 100644
--- a/include/configs/TQM850M.h
+++ b/include/configs/TQM850M.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC850		1	/* This is a MPC850 CPU		*/
 #define CONFIG_TQM850M		1	/* ...on a TQM8xxM module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM855L.h b/include/configs/TQM855L.h
index 3c82c73..3fbc1ad 100644
--- a/include/configs/TQM855L.h
+++ b/include/configs/TQM855L.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC855		1	/* This is a MPC855 CPU		*/
 #define CONFIG_TQM855L		1	/* ...on a TQM8xxL module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM855M.h b/include/configs/TQM855M.h
index 66f9a88..d2729d6 100644
--- a/include/configs/TQM855M.h
+++ b/include/configs/TQM855M.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC855		1	/* This is a MPC855 CPU		*/
 #define CONFIG_TQM855M		1	/* ...on a TQM8xxM module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM860L.h b/include/configs/TQM860L.h
index 3e20c71..764568d 100644
--- a/include/configs/TQM860L.h
+++ b/include/configs/TQM860L.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC860		1	/* This is a MPC860 CPU		*/
 #define CONFIG_TQM860L		1	/* ...on a TQM8xxL module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM860M.h b/include/configs/TQM860M.h
index be1cd3a..0894f59 100644
--- a/include/configs/TQM860M.h
+++ b/include/configs/TQM860M.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC860		1	/* This is a MPC860 CPU		*/
 #define CONFIG_TQM860M		1	/* ...on a TQM8xxM module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM862L.h b/include/configs/TQM862L.h
index f07b903..9650b8d 100644
--- a/include/configs/TQM862L.h
+++ b/include/configs/TQM862L.h
@@ -20,7 +20,6 @@
 #define CONFIG_MPC860		1
 #define CONFIG_MPC860T		1
 #define CONFIG_MPC862		1
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_TQM862L		1	/* ...on a TQM8xxL module	*/
diff --git a/include/configs/TQM862M.h b/include/configs/TQM862M.h
index c887a39..8b8db89 100644
--- a/include/configs/TQM862M.h
+++ b/include/configs/TQM862M.h
@@ -20,7 +20,6 @@
 #define CONFIG_MPC860		1
 #define CONFIG_MPC860T		1
 #define CONFIG_MPC862		1
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_TQM862M		1	/* ...on a TQM8xxM module	*/
diff --git a/include/configs/TQM866M.h b/include/configs/TQM866M.h
index a037b4f..a011d2e 100644
--- a/include/configs/TQM866M.h
+++ b/include/configs/TQM866M.h
@@ -19,7 +19,6 @@
 
 #define CONFIG_MPC866		1	/* This is a MPC866 CPU		*/
 #define CONFIG_TQM866M		1	/* ...on a TQM8xxM module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/TQM885D.h b/include/configs/TQM885D.h
index 76ddef5..023736e 100644
--- a/include/configs/TQM885D.h
+++ b/include/configs/TQM885D.h
@@ -22,7 +22,6 @@
 
 #define CONFIG_MPC885		1	/* This is a MPC885 CPU		*/
 #define CONFIG_TQM885D		1	/* ...on a TQM88D module	*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0x40000000
diff --git a/include/configs/UCP1020.h b/include/configs/UCP1020.h
index 0801117..0b609af 100644
--- a/include/configs/UCP1020.h
+++ b/include/configs/UCP1020.h
@@ -14,8 +14,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #define CONFIG_FSL_ELBC
 #define CONFIG_PCI
diff --git a/include/configs/VCMA9.h b/include/configs/VCMA9.h
index bfcfb40..42af34f 100644
--- a/include/configs/VCMA9.h
+++ b/include/configs/VCMA9.h
@@ -27,7 +27,6 @@
 
 #define CONFIG_SYS_TEXT_BASE	0x0
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
 
diff --git a/include/configs/VOM405.h b/include/configs/VOM405.h
index 99ee78b..60f266c 100644
--- a/include/configs/VOM405.h
+++ b/include/configs/VOM405.h
@@ -19,7 +19,6 @@
 #define CONFIG_VOM405		1	/* ...on a VOM405 board		*/
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFFC8000
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_BOARD_EARLY_INIT_F 1	/* call board_early_init_f()	*/
diff --git a/include/configs/a3m071.h b/include/configs/a3m071.h
index fc4595b..4839ede 100644
--- a/include/configs/a3m071.h
+++ b/include/configs/a3m071.h
@@ -15,7 +15,6 @@
 #define CONFIG_MPC5200
 #define CONFIG_A3M071			/* A3M071 board */
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define	CONFIG_SYS_TEXT_BASE	0x01000000	/* boot low for 32 MiB boards */
 
diff --git a/include/configs/a4m072.h b/include/configs/a4m072.h
index 1be78fd..0ff5164 100644
--- a/include/configs/a4m072.h
+++ b/include/configs/a4m072.h
@@ -20,7 +20,6 @@
 #define CONFIG_A4M072		1	/* ... on A4M072 board */
 #define CONFIG_MPC5200_DDR	1	/* ... use DDR RAM */
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_TEXT_BASE	0xFE000000
 
diff --git a/include/configs/ac14xx.h b/include/configs/ac14xx.h
index f05d9ec..320be8f 100644
--- a/include/configs/ac14xx.h
+++ b/include/configs/ac14xx.h
@@ -14,7 +14,6 @@
 
 #define CONFIG_AC14XX 1
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory map for the ifm AC14xx board:
diff --git a/include/configs/am3517_crane.h b/include/configs/am3517_crane.h
index 654b778..0bf0af7 100644
--- a/include/configs/am3517_crane.h
+++ b/include/configs/am3517_crane.h
@@ -19,7 +19,6 @@
 #define CONFIG_OMAP		1	/* in a TI OMAP core */
 #define CONFIG_OMAP3_AM3517CRANE	1	/* working with CRANEBOARD */
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/am3517_evm.h b/include/configs/am3517_evm.h
index 7049091..9aa14f4 100644
--- a/include/configs/am3517_evm.h
+++ b/include/configs/am3517_evm.h
@@ -19,7 +19,6 @@
 #define CONFIG_OMAP		1	/* in a TI OMAP core */
 #define CONFIG_OMAP3_AM3517EVM	1	/* working with AM3517EVM */
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/amcc-common.h b/include/configs/amcc-common.h
index c5ef650..e87c0cb 100644
--- a/include/configs/amcc-common.h
+++ b/include/configs/amcc-common.h
@@ -10,7 +10,6 @@
 #ifndef __AMCC_COMMON_H
 #define __AMCC_COMMON_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_SDRAM_BASE		0x00000000	/* _must_ be 0		*/
 #define CONFIG_SYS_MONITOR_BASE	CONFIG_SYS_TEXT_BASE	/* Start of U-Boot	*/
diff --git a/include/configs/apf27.h b/include/configs/apf27.h
index 49fbcac..5b286d2 100644
--- a/include/configs/apf27.h
+++ b/include/configs/apf27.h
@@ -20,7 +20,6 @@
  */
 #define CONFIG_MX27			/* This is a Freescale i.MX27 Chip */
 #define CONFIG_MACH_TYPE	1698	/* APF27 */
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Enable the call to miscellaneous platform dependent initialization.
diff --git a/include/configs/aria.h b/include/configs/aria.h
index 2265f3e..c38bf3c 100644
--- a/include/configs/aria.h
+++ b/include/configs/aria.h
@@ -14,7 +14,6 @@
 
 #define CONFIG_ARIA 1
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory map for the ARIA board:
diff --git a/include/configs/armadillo-800eva.h b/include/configs/armadillo-800eva.h
index 7f5cbcc..dfbd60d 100644
--- a/include/configs/armadillo-800eva.h
+++ b/include/configs/armadillo-800eva.h
@@ -41,7 +41,6 @@
 #define CONFIG_USE_ARCH_MEMCPY
 #define CONFIG_TMU_TIMER
 #define CONFIG_SYS_DCACHE_OFF
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* STACK */
 #define CONFIG_SYS_INIT_SP_ADDR		0xE8083000
diff --git a/include/configs/aspenite.h b/include/configs/aspenite.h
index 62c5374..fcb5f81 100644
--- a/include/configs/aspenite.h
+++ b/include/configs/aspenite.h
@@ -11,11 +11,6 @@
 #define __CONFIG_ASPENITE_H
 
 /*
- * Generic board support
- */
-#define CONFIG_SYS_GENERIC_BOARD
-
-/*
  * Version number information
  */
 #define CONFIG_IDENT_STRING	"\nMarvell-Aspenite DB"
diff --git a/include/configs/at91-sama5_common.h b/include/configs/at91-sama5_common.h
index a5990ce..f938534 100644
--- a/include/configs/at91-sama5_common.h
+++ b/include/configs/at91-sama5_common.h
@@ -31,7 +31,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT		/* Device Tree support */
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* general purpose I/O */
 #define CONFIG_AT91_GPIO
diff --git a/include/configs/at91rm9200ek.h b/include/configs/at91rm9200ek.h
index 7e026ef..9274024 100644
--- a/include/configs/at91rm9200ek.h
+++ b/include/configs/at91rm9200ek.h
@@ -61,7 +61,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory Configuration
diff --git a/include/configs/at91sam9260ek.h b/include/configs/at91sam9260ek.h
index 619f5da..cc3e69c 100644
--- a/include/configs/at91sam9260ek.h
+++ b/include/configs/at91sam9260ek.h
@@ -48,7 +48,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* general purpose I/O */
 #define CONFIG_ATMEL_LEGACY		/* required until (g)pio is fixed */
diff --git a/include/configs/at91sam9261ek.h b/include/configs/at91sam9261ek.h
index 4d260e9..64fb38b 100644
--- a/include/configs/at91sam9261ek.h
+++ b/include/configs/at91sam9261ek.h
@@ -33,7 +33,6 @@
 
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_ATMEL_LEGACY
 #define CONFIG_SYS_TEXT_BASE		0x21f00000
diff --git a/include/configs/at91sam9263ek.h b/include/configs/at91sam9263ek.h
index 2f251db..89ee9fe 100644
--- a/include/configs/at91sam9263ek.h
+++ b/include/configs/at91sam9263ek.h
@@ -48,7 +48,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Hardware drivers
diff --git a/include/configs/at91sam9m10g45ek.h b/include/configs/at91sam9m10g45ek.h
index 70eaf1d..cc42c90 100644
--- a/include/configs/at91sam9m10g45ek.h
+++ b/include/configs/at91sam9m10g45ek.h
@@ -33,7 +33,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* general purpose I/O */
 #define CONFIG_ATMEL_LEGACY		/* required until (g)pio is fixed */
diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h
index 44f821b..8fa5ff5 100644
--- a/include/configs/at91sam9n12ek.h
+++ b/include/configs/at91sam9n12ek.h
@@ -31,7 +31,6 @@
 #define CONFIG_DISPLAY_CPUINFO
 
 #define CONFIG_OF_LIBFDT
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* general purpose I/O */
 #define CONFIG_AT91_GPIO
diff --git a/include/configs/at91sam9rlek.h b/include/configs/at91sam9rlek.h
index cba927a..a7a0502 100644
--- a/include/configs/at91sam9rlek.h
+++ b/include/configs/at91sam9rlek.h
@@ -34,7 +34,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_ATMEL_LEGACY
 #define CONFIG_AT91_GPIO		1
diff --git a/include/configs/at91sam9x5ek.h b/include/configs/at91sam9x5ek.h
index 2068e0d..20a5581 100644
--- a/include/configs/at91sam9x5ek.h
+++ b/include/configs/at91sam9x5ek.h
@@ -29,7 +29,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* general purpose I/O */
 #define CONFIG_ATMEL_LEGACY		/* required until (g)pio is fixed */
diff --git a/include/configs/bcm28155_ap.h b/include/configs/bcm28155_ap.h
index 7b48875..6ea6fb0 100644
--- a/include/configs/bcm28155_ap.h
+++ b/include/configs/bcm28155_ap.h
@@ -13,7 +13,6 @@
 /* CPU, chip, mach, etc */
 #define CONFIG_KONA
 #define CONFIG_SKIP_LOWLEVEL_INIT
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory configuration
diff --git a/include/configs/bcm_ep_board.h b/include/configs/bcm_ep_board.h
index ba26964..c3ebb4d 100644
--- a/include/configs/bcm_ep_board.h
+++ b/include/configs/bcm_ep_board.h
@@ -11,7 +11,6 @@
 
 #define CONFIG_SKIP_LOWLEVEL_INIT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory configuration
diff --git a/include/configs/bur_am335x_common.h b/include/configs/bur_am335x_common.h
index c696092..1d96a2d 100644
--- a/include/configs/bur_am335x_common.h
+++ b/include/configs/bur_am335x_common.h
@@ -26,7 +26,6 @@
 #define CONFIG_PREBOOT			"run brdefaultip"
 #define CONFIG_CMD_TIME
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_AM33XX
 #define CONFIG_OMAP
diff --git a/include/configs/calimain.h b/include/configs/calimain.h
index c8b15fb..a5b2f9e 100644
--- a/include/configs/calimain.h
+++ b/include/configs/calimain.h
@@ -18,7 +18,6 @@
 #define CONFIG_DRIVER_TI_EMAC
 #define MACH_TYPE_CALIMAIN	3528
 #define CONFIG_MACH_TYPE	MACH_TYPE_CALIMAIN
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * SoC Configuration
diff --git a/include/configs/canmb.h b/include/configs/canmb.h
index 36cd50b..2a6c09f 100644
--- a/include/configs/canmb.h
+++ b/include/configs/canmb.h
@@ -15,7 +15,6 @@
 
 #define CONFIG_MPC5200		1	/* This is a MPC5200 CPU */
 #define CONFIG_CANMB		1	/* ... on canmb board - we need this for FEC.C */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/cm5200.h b/include/configs/cm5200.h
index 4607d9f..69b2674 100644
--- a/include/configs/cm5200.h
+++ b/include/configs/cm5200.h
@@ -9,7 +9,6 @@
 #define __CONFIG_H
 
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 
diff --git a/include/configs/cm_t35.h b/include/configs/cm_t35.h
index e5fb474..e951b2d 100644
--- a/include/configs/cm_t35.h
+++ b/include/configs/cm_t35.h
@@ -25,7 +25,6 @@
 #define CONFIG_CMD_GPIO
 #define CONFIG_CM_T3X	/* working with CM-T35 and CM-T3730 */
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/cm_t3517.h b/include/configs/cm_t3517.h
index f3d1f43..8a10e9c 100644
--- a/include/configs/cm_t3517.h
+++ b/include/configs/cm_t3517.h
@@ -16,7 +16,6 @@
 #define CONFIG_OMAP	/* in a TI OMAP core */
 #define CONFIG_CM_T3517	/* working with CM-T3517 */
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/cm_t54.h b/include/configs/cm_t54.h
index 95a5a60..6d57cd6 100644
--- a/include/configs/cm_t54.h
+++ b/include/configs/cm_t54.h
@@ -18,9 +18,6 @@
 
 #undef CONFIG_SPL_OS_BOOT
 
-/* Enable Generic board */
-#define CONFIG_SYS_GENERIC_BOARD
-
 /* Device Tree defines */
 #define CONFIG_OF_LIBFDT
 #define CONFIG_OF_BOARD_SETUP
diff --git a/include/configs/colibri_pxa270.h b/include/configs/colibri_pxa270.h
index 4efc9c5..0fc24a0 100644
--- a/include/configs/colibri_pxa270.h
+++ b/include/configs/colibri_pxa270.h
@@ -14,7 +14,6 @@
  * High Level Board Configuration Options
  */
 #define	CONFIG_CPU_PXA27X		1	/* Marvell PXA270 CPU */
-#define CONFIG_SYS_GENERIC_BOARD
 #define	CONFIG_SYS_TEXT_BASE		0x0
 /* Avoid overwriting factory configuration block */
 #define CONFIG_BOARD_SIZE_LIMIT		0x40000
diff --git a/include/configs/colibri_vf.h b/include/configs/colibri_vf.h
index 2583155..9fa8f81 100644
--- a/include/configs/colibri_vf.h
+++ b/include/configs/colibri_vf.h
@@ -18,8 +18,8 @@
 #define CONFIG_SYS_THUMB_BUILD
 #define CONFIG_USE_ARCH_MEMCPY
 #define CONFIG_USE_ARCH_MEMSET
+#define CONFIG_FSL_CLK
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_ARCH_MISC_INIT
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/controlcenterd.h b/include/configs/controlcenterd.h
index c879048..77c2edc 100644
--- a/include/configs/controlcenterd.h
+++ b/include/configs/controlcenterd.h
@@ -44,8 +44,8 @@
 #define CONFIG_P1022
 #define CONFIG_CONTROLCENTERD
 #define CONFIG_MP			/* support multiple processors */
+#define CONFIG_FSL_CLK
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_NO_FLASH
 #define CONFIG_ENABLE_36BIT_PHYS
diff --git a/include/configs/corenet_ds.h b/include/configs/corenet_ds.h
index 878fda2..3c9a529 100644
--- a/include/configs/corenet_ds.h
+++ b/include/configs/corenet_ds.h
@@ -10,8 +10,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #include "../board/freescale/common/ics307_clk.h"
 
diff --git a/include/configs/corvus.h b/include/configs/corvus.h
index 6805612..97797e2 100644
--- a/include/configs/corvus.h
+++ b/include/configs/corvus.h
@@ -17,7 +17,6 @@
 #include <asm/hardware.h>
 #include <linux/sizes.h>
 
-#define CONFIG_SYS_GENERIC_BOARD
 /*
  * Warning: changing CONFIG_SYS_TEXT_BASE requires
  * adapting the initial boot program.
diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h
index 1cd11c0..5aa643a 100644
--- a/include/configs/da850evm.h
+++ b/include/configs/da850evm.h
@@ -258,7 +258,6 @@
 /*
  * U-Boot general configuration
  */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_MISC_INIT_R
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_BOOTFILE		"uImage" /* Boot file name */
diff --git a/include/configs/db-88f6820-gp.h b/include/configs/db-88f6820-gp.h
index 74e5b47..9a0596c 100644
--- a/include/configs/db-88f6820-gp.h
+++ b/include/configs/db-88f6820-gp.h
@@ -19,7 +19,6 @@
 #ifdef CONFIG_SPL_BUILD
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
 #endif
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO_LATE
 
 /*
diff --git a/include/configs/db-mv784mp-gp.h b/include/configs/db-mv784mp-gp.h
index 672518b..b3b2de9 100644
--- a/include/configs/db-mv784mp-gp.h
+++ b/include/configs/db-mv784mp-gp.h
@@ -16,7 +16,6 @@
 #ifdef CONFIG_SPL_BUILD
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
 #endif
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO_LATE
 
 /*
diff --git a/include/configs/digsy_mtc.h b/include/configs/digsy_mtc.h
index 02b8f91..f802c8d 100644
--- a/include/configs/digsy_mtc.h
+++ b/include/configs/digsy_mtc.h
@@ -23,7 +23,6 @@
 #define CONFIG_MPC5200		1	/* This is an MPC5200 CPU */
 #define CONFIG_DIGSY_MTC	1	/* ... on InterControl digsyMTC board */
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Valid values for CONFIG_SYS_TEXT_BASE are:
diff --git a/include/configs/dlvision-10g.h b/include/configs/dlvision-10g.h
index e39f8ba..0b804eb 100644
--- a/include/configs/dlvision-10g.h
+++ b/include/configs/dlvision-10g.h
@@ -24,7 +24,6 @@
 #define CONFIG_BOARD_EARLY_INIT_R
 #define CONFIG_MISC_INIT_R
 #define CONFIG_LAST_STAGE_INIT
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_CLK_FREQ	33333333 /* external frequency to pll   */
 
diff --git a/include/configs/dlvision.h b/include/configs/dlvision.h
index 3c05534..90e839a 100644
--- a/include/configs/dlvision.h
+++ b/include/configs/dlvision.h
@@ -22,7 +22,6 @@
 
 #define CONFIG_BOARD_EARLY_INIT_F	/* call board_early_init_f */
 #define CONFIG_MISC_INIT_R		/* call misc_init_r */
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_CLK_FREQ	33333333 /* external frequency to pll   */
 
diff --git a/include/configs/dns325.h b/include/configs/dns325.h
index 54be415..c59a324 100644
--- a/include/configs/dns325.h
+++ b/include/configs/dns325.h
@@ -26,7 +26,6 @@
 #define CONFIG_FEROCEON_88FR131		/* CPU Core subversion */
 #define CONFIG_KW88F6281		/* SOC Name */
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Commands configuration
diff --git a/include/configs/dockstar.h b/include/configs/dockstar.h
index 6ebd703..efe5807 100644
--- a/include/configs/dockstar.h
+++ b/include/configs/dockstar.h
@@ -12,7 +12,6 @@
 #ifndef _CONFIG_DOCKSTAR_H
 #define _CONFIG_DOCKSTAR_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Version number information
diff --git a/include/configs/dreamplug.h b/include/configs/dreamplug.h
index 133c7f4..2815ad8 100644
--- a/include/configs/dreamplug.h
+++ b/include/configs/dreamplug.h
@@ -37,7 +37,6 @@
 #define CONFIG_KW88F6281	1	/* SOC Name */
 #define CONFIG_MACH_TYPE	MACH_TYPE_DREAMPLUG
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Add target to build it automatically upon "make" */
 #define CONFIG_BUILD_TARGET     "u-boot.kwb"
diff --git a/include/configs/ea20.h b/include/configs/ea20.h
index 2d1f1b3..b230d9c 100644
--- a/include/configs/ea20.h
+++ b/include/configs/ea20.h
@@ -24,7 +24,6 @@
 #define CONFIG_VIDEO
 #define CONFIG_PREBOOT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * SoC Configuration
diff --git a/include/configs/edb93xx.h b/include/configs/edb93xx.h
index e3e32aa..9fce1cd 100644
--- a/include/configs/edb93xx.h
+++ b/include/configs/edb93xx.h
@@ -25,7 +25,6 @@
 #error "no board defined"
 #endif
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Initial environment and monitor configuration options. */
 #define CONFIG_BOOTDELAY		2
diff --git a/include/configs/edminiv2.h b/include/configs/edminiv2.h
index 8b38d7e..7fb1894 100644
--- a/include/configs/edminiv2.h
+++ b/include/configs/edminiv2.h
@@ -12,9 +12,6 @@
 #ifndef _CONFIG_EDMINIV2_H
 #define _CONFIG_EDMINIV2_H
 
-/* general settings */
-#define CONFIG_SYS_GENERIC_BOARD
-
 /*
  * SPL
  */
diff --git a/include/configs/ethernut5.h b/include/configs/ethernut5.h
index b49b903..d6e0456 100644
--- a/include/configs/ethernut5.h
+++ b/include/configs/ethernut5.h
@@ -12,7 +12,6 @@
 
 #include <asm/hardware.h>
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* The first stage boot loader expects u-boot running at this address. */
 #define CONFIG_SYS_TEXT_BASE	0x27000000	/* 16MB available */
diff --git a/include/configs/exynos-common.h b/include/configs/exynos-common.h
index d7bf80b..852829c 100644
--- a/include/configs/exynos-common.h
+++ b/include/configs/exynos-common.h
@@ -16,7 +16,6 @@
 #include <asm/arch/cpu.h>		/* get chip and board defs */
 #include <linux/sizes.h>
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_ARCH_CPU_INIT
 #define CONFIG_DISPLAY_CPUINFO
diff --git a/include/configs/flea3.h b/include/configs/flea3.h
index f646fee..15905b9 100644
--- a/include/configs/flea3.h
+++ b/include/configs/flea3.h
@@ -22,7 +22,6 @@
 #define CONFIG_SYS_CACHELINE_SIZE	32
 
 #define CONFIG_DISPLAY_CPUINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Only in case the value is not present in mach-types.h */
 #ifndef MACH_TYPE_FLEA3
diff --git a/include/configs/gdppc440etx.h b/include/configs/gdppc440etx.h
index bfaba42..b514278 100644
--- a/include/configs/gdppc440etx.h
+++ b/include/configs/gdppc440etx.h
@@ -32,7 +32,6 @@
 
 #define CONFIG_BOARD_EARLY_INIT_F	1	/* call board_early_init_f*/
 #define CONFIG_MISC_INIT_R		1	/* call misc_init_r()     */
-#define CONFIG_SYS_GENERIC_BOARD
 
 #undef CONFIG_ZERO_BOOTDELAY_CHECK     /* ignore keypress on bootdelay==0 */
 
diff --git a/include/configs/goflexhome.h b/include/configs/goflexhome.h
index 2a42e7c..188d2e2 100644
--- a/include/configs/goflexhome.h
+++ b/include/configs/goflexhome.h
@@ -15,7 +15,6 @@
 #ifndef _CONFIG_GOFLEXHOME_H
 #define _CONFIG_GOFLEXHOME_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Version number information
diff --git a/include/configs/gplugd.h b/include/configs/gplugd.h
index 0de6ae8..f2fd2ae 100644
--- a/include/configs/gplugd.h
+++ b/include/configs/gplugd.h
@@ -26,11 +26,6 @@
 #endif
 
 /*
- * Generic board support
- */
-#define CONFIG_SYS_GENERIC_BOARD
-
-/*
  * Version number information
  */
 #define CONFIG_IDENT_STRING	"\nMarvell-gplugD"
diff --git a/include/configs/guruplug.h b/include/configs/guruplug.h
index 5f09567..675ec52 100644
--- a/include/configs/guruplug.h
+++ b/include/configs/guruplug.h
@@ -10,7 +10,6 @@
 #ifndef _CONFIG_GURUPLUG_H
 #define _CONFIG_GURUPLUG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Version number information
diff --git a/include/configs/h2200.h b/include/configs/h2200.h
index e8dfa74..6fbbe6e 100644
--- a/include/configs/h2200.h
+++ b/include/configs/h2200.h
@@ -12,7 +12,6 @@
 #define MACH_TYPE_H2200			341
 #define CONFIG_MACH_TYPE		MACH_TYPE_H2200
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_CPU_PXA25X		1
 #define CONFIG_BOARD_H2200
 
diff --git a/include/configs/highbank.h b/include/configs/highbank.h
index 7f331a6..f02575a 100644
--- a/include/configs/highbank.h
+++ b/include/configs/highbank.h
@@ -13,7 +13,6 @@
 #define CONFIG_SYS_THUMB_BUILD
 
 #define CONFIG_SYS_NO_FLASH
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_OF_BOARD_SETUP
 #define CONFIG_FIT
diff --git a/include/configs/hikey.h b/include/configs/hikey.h
index 3af0213..1a4381b 100644
--- a/include/configs/hikey.h
+++ b/include/configs/hikey.h
@@ -14,8 +14,6 @@
 
 #include <linux/sizes.h>
 
-/* We use generic board for hikey */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_POWER
 #define CONFIG_POWER_HI6553
 
diff --git a/include/configs/hrcon.h b/include/configs/hrcon.h
index 558edfc..e2b9deb 100644
--- a/include/configs/hrcon.h
+++ b/include/configs/hrcon.h
@@ -22,8 +22,8 @@
 
 #define CONFIG_IDENT_STRING	" hrcon 0.01"
 
-#define CONFIG_SYS_GENERIC_BOARD
 
+#define CONFIG_FSL_CLK
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_BOARD_EARLY_INIT_R
 #define CONFIG_LAST_STAGE_INIT
diff --git a/include/configs/ib62x0.h b/include/configs/ib62x0.h
index 6afe340..594fceb 100644
--- a/include/configs/ib62x0.h
+++ b/include/configs/ib62x0.h
@@ -9,7 +9,6 @@
 #ifndef _CONFIG_IB62x0_H
 #define _CONFIG_IB62x0_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Version number information
diff --git a/include/configs/iconnect.h b/include/configs/iconnect.h
index bce97dc..adf3703 100644
--- a/include/configs/iconnect.h
+++ b/include/configs/iconnect.h
@@ -9,7 +9,6 @@
 #ifndef _CONFIG_ICONNECT_H
 #define _CONFIG_ICONNECT_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Version number information
diff --git a/include/configs/ids8313.h b/include/configs/ids8313.h
index e60e753..ecb7f10 100644
--- a/include/configs/ids8313.h
+++ b/include/configs/ids8313.h
@@ -19,7 +19,6 @@
 #define CONFIG_MPC8313
 #define CONFIG_IDS8313
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_FSL_ELBC
 
diff --git a/include/configs/imx31_phycore.h b/include/configs/imx31_phycore.h
index 3bea71b..235fdd1 100644
--- a/include/configs/imx31_phycore.h
+++ b/include/configs/imx31_phycore.h
@@ -18,7 +18,6 @@
 #define CONFIG_MX31			/* This is a mx31 */
 #define CONFIG_MX31_CLK32	32000
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/inka4x0.h b/include/configs/inka4x0.h
index d3034cf..24da83c 100644
--- a/include/configs/inka4x0.h
+++ b/include/configs/inka4x0.h
@@ -18,7 +18,6 @@
 
 #define CONFIG_MPC5200		1	/* This is an MPC5200 CPU	*/
 #define CONFIG_INKA4X0		1	/* INKA4x0 board		*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/integrator-common.h b/include/configs/integrator-common.h
index a22efd6..639a30a 100644
--- a/include/configs/integrator-common.h
+++ b/include/configs/integrator-common.h
@@ -29,7 +29,6 @@
 #define CONFIG_SETUP_MEMORY_TAGS
 #define CONFIG_OF_LIBFDT		/* enable passing a Device Tree */
 #define CONFIG_MISC_INIT_R		/* call misc_init_r during start up */
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * There are various dependencies on the core module (CM) fitted
diff --git a/include/configs/intip.h b/include/configs/intip.h
index 18d3140..a676a20 100644
--- a/include/configs/intip.h
+++ b/include/configs/intip.h
@@ -45,7 +45,6 @@
 #define CONFIG_BOARD_EARLY_INIT_F	1	/* Call board_early_init_f */
 #define CONFIG_BOARD_EARLY_INIT_R	1	/* Call board_early_init_r */
 #define CONFIG_MISC_INIT_R		1	/* Call misc_init_r */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_BOARD_TYPES		1	/* support board types */
 #define CONFIG_FIT
 #define CFG_ALT_MEMTEST
diff --git a/include/configs/io.h b/include/configs/io.h
index 7d863fa..2c457d4 100644
--- a/include/configs/io.h
+++ b/include/configs/io.h
@@ -24,7 +24,6 @@
 #define CONFIG_BOARD_EARLY_INIT_R
 #define CONFIG_MISC_INIT_R
 #define CONFIG_LAST_STAGE_INIT
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_CLK_FREQ	33333333 /* external frequency to pll   */
 
diff --git a/include/configs/io64.h b/include/configs/io64.h
index 94ccb6b..25bd014 100644
--- a/include/configs/io64.h
+++ b/include/configs/io64.h
@@ -43,7 +43,6 @@
 #define CONFIG_BOARD_EARLY_INIT_R
 #define CONFIG_MISC_INIT_R
 #define CONFIG_LAST_STAGE_INIT
-#define CONFIG_SYS_GENERIC_BOARD
 
 #undef CONFIG_ZERO_BOOTDELAY_CHECK	/* ignore keypress on bootdelay==0 */
 
diff --git a/include/configs/iocon.h b/include/configs/iocon.h
index a4d05e5..385a644 100644
--- a/include/configs/iocon.h
+++ b/include/configs/iocon.h
@@ -23,7 +23,6 @@
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_BOARD_EARLY_INIT_R
 #define CONFIG_LAST_STAGE_INIT
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_CLK_FREQ	33333333 /* external frequency to pll   */
 
diff --git a/include/configs/ipam390.h b/include/configs/ipam390.h
index b1cd7df..583f7b3 100644
--- a/include/configs/ipam390.h
+++ b/include/configs/ipam390.h
@@ -18,7 +18,6 @@
 /*
  * Board
  */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DRIVER_TI_EMAC
 #define CONFIG_BARIX_IPAM390
 
diff --git a/include/configs/ipek01.h b/include/configs/ipek01.h
index 3f6f8dd..637bbb3 100644
--- a/include/configs/ipek01.h
+++ b/include/configs/ipek01.h
@@ -19,7 +19,6 @@
 #define CONFIG_MPX5200		1	/* MPX5200 board */
 #define CONFIG_MPC5200_DDR	1	/* use DDR RAM */
 #define CONFIG_IPEK01           	/* Motherboard is ipek01 */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0xfc000000
diff --git a/include/configs/jupiter.h b/include/configs/jupiter.h
index 5601cb4..ba96d97 100644
--- a/include/configs/jupiter.h
+++ b/include/configs/jupiter.h
@@ -15,7 +15,6 @@
 
 #define CONFIG_MPC5200		1	/* This is an MPC5200 CPU */
 #define CONFIG_JUPITER		1	/* ... on Jupiter board */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/km/km8309-common.h b/include/configs/km/km8309-common.h
index ec133f9..5cbb348 100644
--- a/include/configs/km/km8309-common.h
+++ b/include/configs/km/km8309-common.h
@@ -10,7 +10,6 @@
 #ifndef __CONFIG_KM8309_COMMON_H
 #define __CONFIG_KM8309_COMMON_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/km/km8321-common.h b/include/configs/km/km8321-common.h
index 058b0ab..cd56380 100644
--- a/include/configs/km/km8321-common.h
+++ b/include/configs/km/km8321-common.h
@@ -23,7 +23,6 @@
 #ifndef __CONFIG_KM8321_COMMON_H
 #define __CONFIG_KM8321_COMMON_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/km/km83xx-common.h b/include/configs/km/km83xx-common.h
index 940000e..cebe210 100644
--- a/include/configs/km/km83xx-common.h
+++ b/include/configs/km/km83xx-common.h
@@ -8,7 +8,6 @@
 #ifndef __CONFIG_KM83XX_H
 #define __CONFIG_KM83XX_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* include common defines/options for all Keymile boards */
diff --git a/include/configs/km/km_arm.h b/include/configs/km/km_arm.h
index 5e0f483..b89af53 100644
--- a/include/configs/km/km_arm.h
+++ b/include/configs/km/km_arm.h
@@ -20,7 +20,6 @@
 #ifndef _CONFIG_KM_ARM_H
 #define _CONFIG_KM_ARM_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* We got removed from Linux mach-types.h */
 #define MACH_TYPE_KM_KIRKWOOD          2255
diff --git a/include/configs/km/kmp204x-common.h b/include/configs/km/kmp204x-common.h
index 7536cbd..8a3c74e 100644
--- a/include/configs/km/kmp204x-common.h
+++ b/include/configs/km/kmp204x-common.h
@@ -21,7 +21,6 @@
 
 #define CONFIG_NAND_ECC_BCH
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* common KM defines */
diff --git a/include/configs/km82xx.h b/include/configs/km82xx.h
index 12f9d42..19e89ce 100644
--- a/include/configs/km82xx.h
+++ b/include/configs/km82xx.h
@@ -29,7 +29,6 @@
 #error ("Board unsupported")
 #endif
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0xFE000000
diff --git a/include/configs/km8360.h b/include/configs/km8360.h
index 04cde46..c517e78 100644
--- a/include/configs/km8360.h
+++ b/include/configs/km8360.h
@@ -9,7 +9,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /* KMBEC FPGA (PRIO) */
diff --git a/include/configs/kzm9g.h b/include/configs/kzm9g.h
index 8a451ec..94b0f03 100644
--- a/include/configs/kzm9g.h
+++ b/include/configs/kzm9g.h
@@ -14,7 +14,6 @@
 #define CONFIG_KZM_A9_GT
 #define CONFIG_RMOBILE_BOARD_STRING	"KMC KZM-A9-GT"
 #define CONFIG_MACH_TYPE MACH_TYPE_KZM9G
-#define CONFIG_SYS_GENERIC_BOARD
 
 #include <asm/arch/rmobile.h>
 
diff --git a/include/configs/lacie_kw.h b/include/configs/lacie_kw.h
index 7f878b7..f8cae40 100644
--- a/include/configs/lacie_kw.h
+++ b/include/configs/lacie_kw.h
@@ -8,11 +8,6 @@
 #define _CONFIG_LACIE_KW_H
 
 /*
- * Generic board support
- */
-#define CONFIG_SYS_GENERIC_BOARD
-
-/*
  * Machine number definition
  */
 #if defined(CONFIG_INETSPACE_V2)
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index f73900f..b8477e8 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -11,7 +11,7 @@
 
 #define CONFIG_ARMV7_PSCI
 
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h
index 02cc09c..784331f 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -11,7 +11,7 @@
 
 #define CONFIG_ARMV7_PSCI
 
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/ls2085a_common.h b/include/configs/ls2085a_common.h
index 55b909c..9c8a864 100644
--- a/include/configs/ls2085a_common.h
+++ b/include/configs/ls2085a_common.h
@@ -7,7 +7,6 @@
 #ifndef __LS2_COMMON_H
 #define __LS2_COMMON_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_REMAKE_ELF
 #define CONFIG_FSL_LSCH3
diff --git a/include/configs/ls2085aqds.h b/include/configs/ls2085aqds.h
index f7f3870..4cfcf98 100644
--- a/include/configs/ls2085aqds.h
+++ b/include/configs/ls2085aqds.h
@@ -16,6 +16,7 @@
 unsigned long get_board_ddr_clk(void);
 #endif
 
+#define CONFIG_FSL_CLK
 #define CONFIG_SYS_CLK_FREQ		get_board_sys_clk()
 #define CONFIG_DDR_CLK_FREQ		get_board_ddr_clk()
 #define COUNTER_FREQUENCY_REAL		(CONFIG_SYS_CLK_FREQ/4)
diff --git a/include/configs/ls2085ardb.h b/include/configs/ls2085ardb.h
index a190bc7..583fed5 100644
--- a/include/configs/ls2085ardb.h
+++ b/include/configs/ls2085ardb.h
@@ -18,6 +18,7 @@
 unsigned long get_board_sys_clk(void);
 #endif
 
+#define CONFIG_FSL_CLK
 #define CONFIG_SYS_CLK_FREQ		get_board_sys_clk()
 #define CONFIG_DDR_CLK_FREQ		133333333
 #define COUNTER_FREQUENCY_REAL		(CONFIG_SYS_CLK_FREQ/4)
diff --git a/include/configs/lsxl.h b/include/configs/lsxl.h
index a57e328..4194a0f 100644
--- a/include/configs/lsxl.h
+++ b/include/configs/lsxl.h
@@ -8,7 +8,6 @@
 #ifndef _CONFIG_LSXL_H
 #define _CONFIG_LSXL_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Version number information
diff --git a/include/configs/lwmon5.h b/include/configs/lwmon5.h
index 2d93d44..66d9710 100644
--- a/include/configs/lwmon5.h
+++ b/include/configs/lwmon5.h
@@ -23,7 +23,6 @@
 #define CONFIG_440EPX		1		/* Specific PPC440EPx	*/
 #define CONFIG_440		1		/* ... PPC440 family	*/
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_TEXT_BASE	0xFFF80000
 #define CONFIG_HOSTNAME		lwmon5
diff --git a/include/configs/m53evk.h b/include/configs/m53evk.h
index 8853d8f..152e295 100644
--- a/include/configs/m53evk.h
+++ b/include/configs/m53evk.h
@@ -9,7 +9,6 @@
 #define __M53EVK_CONFIG_H__
 
 #define CONFIG_MX53
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_MXC_GPIO
 
 #include <asm/arch/imx-regs.h>
@@ -18,6 +17,7 @@
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_REVISION_TAG
 #define CONFIG_SYS_NO_FLASH
+#define CONFIG_FSL_CLK
 
 #define CONFIG_FIT
 
diff --git a/include/configs/maxbcm.h b/include/configs/maxbcm.h
index 3bed9c7..3c4beeb 100644
--- a/include/configs/maxbcm.h
+++ b/include/configs/maxbcm.h
@@ -14,7 +14,6 @@
 #ifdef CONFIG_SPL_BUILD
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
 #endif
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO_LATE
 
 /*
diff --git a/include/configs/mcx.h b/include/configs/mcx.h
index 0f70c47..6240666 100644
--- a/include/configs/mcx.h
+++ b/include/configs/mcx.h
@@ -25,7 +25,6 @@
 #define CONFIG_MACH_TYPE	MACH_TYPE_MCX
 #define CONFIG_BOARD_LATE_INIT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_CACHELINE_SIZE	64
 
diff --git a/include/configs/mecp5123.h b/include/configs/mecp5123.h
index 84f1a40..0f39964 100644
--- a/include/configs/mecp5123.h
+++ b/include/configs/mecp5123.h
@@ -16,7 +16,6 @@
 
 #define CONFIG_MECP5123 1
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory map for the MECP5123 board:
diff --git a/include/configs/meesc.h b/include/configs/meesc.h
index ab6c910..9c53fb4 100644
--- a/include/configs/meesc.h
+++ b/include/configs/meesc.h
@@ -56,7 +56,6 @@
 #define CONFIG_DISPLAY_CPUINFO			/* display cpu info and speed */
 #define CONFIG_PREBOOT				/* enable preboot variable */
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Hardware drivers
diff --git a/include/configs/motionpro.h b/include/configs/motionpro.h
index 6eb6e51..97c614b 100644
--- a/include/configs/motionpro.h
+++ b/include/configs/motionpro.h
@@ -17,7 +17,6 @@
 /* CPU and board */
 #define CONFIG_MPC5200		1	/* This is a MPC5200 CPU */
 #define CONFIG_MOTIONPRO	1	/* ... on Promess Motion-PRO board */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define CONFIG_HIGH_BATS	1	/* High BATs supported */
diff --git a/include/configs/mpc5121ads.h b/include/configs/mpc5121ads.h
index 782b29d..5f4e157 100644
--- a/include/configs/mpc5121ads.h
+++ b/include/configs/mpc5121ads.h
@@ -13,7 +13,6 @@
 
 #define CONFIG_MPC5121ADS 1
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory map for the MPC5121ADS board:
diff --git a/include/configs/mpc8308_p1m.h b/include/configs/mpc8308_p1m.h
index 1b09e70..1a627fc 100644
--- a/include/configs/mpc8308_p1m.h
+++ b/include/configs/mpc8308_p1m.h
@@ -9,7 +9,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/munices.h b/include/configs/munices.h
index 072bd95..c34cba3 100644
--- a/include/configs/munices.h
+++ b/include/configs/munices.h
@@ -14,7 +14,6 @@
 #define CONFIG_MPC5200		1	/* This is an MPC5200 CPU */
 #define CONFIG_MPC5200_DDR	1	/* (with DDR-SDRAM) */
 #define CONFIG_MUNICES		1	/* ... on MUNICes board */
-#define CONFIG_SYS_GENERIC_BOARD
 
 #ifndef CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_TEXT_BASE	0xFFF00000
diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h
index 0414086..0ee8e0d 100644
--- a/include/configs/mx25pdk.h
+++ b/include/configs/mx25pdk.h
@@ -14,7 +14,7 @@
 #define CONFIG_MX25
 #define CONFIG_SYS_TEXT_BASE		0x81200000
 #define CONFIG_MXC_GPIO
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 #define CONFIG_SYS_TIMER_RATE		32768
 #define CONFIG_SYS_TIMER_COUNTER	\
diff --git a/include/configs/mx31ads.h b/include/configs/mx31ads.h
index c4513d2..ae9f091 100644
--- a/include/configs/mx31ads.h
+++ b/include/configs/mx31ads.h
@@ -14,7 +14,6 @@
  /* High Level Configuration Options */
 #define CONFIG_MX31		1		/* This is a mx31 */
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/mx31pdk.h b/include/configs/mx31pdk.h
index 72d28c9..863b032 100644
--- a/include/configs/mx31pdk.h
+++ b/include/configs/mx31pdk.h
@@ -19,7 +19,6 @@
 /* High Level Configuration Options */
 #define CONFIG_MX31			/* This is a mx31 */
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/mx35pdk.h b/include/configs/mx35pdk.h
index 6bfdaa6..41f518e 100644
--- a/include/configs/mx35pdk.h
+++ b/include/configs/mx35pdk.h
@@ -19,7 +19,7 @@
 #define CONFIG_MX35
 
 #define CONFIG_DISPLAY_CPUINFO
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 /* Set TEXT at the beginning of the NOR flash */
 #define CONFIG_SYS_TEXT_BASE	0xA0000000
diff --git a/include/configs/mx51evk.h b/include/configs/mx51evk.h
index 2203c15..35c9346 100644
--- a/include/configs/mx51evk.h
+++ b/include/configs/mx51evk.h
@@ -18,6 +18,7 @@
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
 
+#define CONFIG_FSL_CLK
 #define CONFIG_SYS_TEXT_BASE	0x97800000
 
 #include <asm/arch/imx-regs.h>
@@ -26,7 +27,6 @@
 #define CONFIG_SETUP_MEMORY_TAGS
 #define CONFIG_INITRD_TAG
 #define CONFIG_REVISION_TAG
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_OF_LIBFDT
 
diff --git a/include/configs/mx53ard.h b/include/configs/mx53ard.h
index b889c25..be37ce5 100644
--- a/include/configs/mx53ard.h
+++ b/include/configs/mx53ard.h
@@ -23,7 +23,7 @@
 #define CONFIG_INITRD_TAG
 #define CONFIG_REVISION_TAG
 
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 2 * 1024 * 1024)
diff --git a/include/configs/mx53evk.h b/include/configs/mx53evk.h
index 4f304ed..81af248 100644
--- a/include/configs/mx53evk.h
+++ b/include/configs/mx53evk.h
@@ -23,7 +23,7 @@
 #define CONFIG_INITRD_TAG
 #define CONFIG_REVISION_TAG
 
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 #define CONFIG_OF_LIBFDT
 
diff --git a/include/configs/mx53loco.h b/include/configs/mx53loco.h
index 3a65861..53fb4f7 100644
--- a/include/configs/mx53loco.h
+++ b/include/configs/mx53loco.h
@@ -22,7 +22,7 @@
 #define CONFIG_SETUP_MEMORY_TAGS
 #define CONFIG_INITRD_TAG
 
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN		(10 * 1024 * 1024)
diff --git a/include/configs/mx53smd.h b/include/configs/mx53smd.h
index e46f2ee..f5fcd83 100644
--- a/include/configs/mx53smd.h
+++ b/include/configs/mx53smd.h
@@ -23,7 +23,7 @@
 #define CONFIG_INITRD_TAG
 #define CONFIG_REVISION_TAG
 
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 2 * 1024 * 1024)
diff --git a/include/configs/mx6_common.h b/include/configs/mx6_common.h
index ef4cb68..ba13178 100644
--- a/include/configs/mx6_common.h
+++ b/include/configs/mx6_common.h
@@ -45,7 +45,7 @@
 
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_DISPLAY_CPUINFO
-#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_FSL_CLK
 
 /* ATAGs */
 #define CONFIG_CMDLINE_TAG
diff --git a/include/configs/mx7_common.h b/include/configs/mx7_common.h
index ea2be49..04468b9 100644
--- a/include/configs/mx7_common.h
+++ b/include/configs/mx7_common.h
@@ -33,7 +33,6 @@
 #define CONFIG_BOARD_LATE_INIT
 
 #define CONFIG_ROM_UNIFIED_SECTIONS
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
 
diff --git a/include/configs/mxs.h b/include/configs/mxs.h
index 9d823de..63fdf9e 100644
--- a/include/configs/mxs.h
+++ b/include/configs/mxs.h
@@ -40,7 +40,6 @@
 /*
  * CPU specifics
  */
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* MXS uses FDT */
 #define CONFIG_OF_LIBFDT
diff --git a/include/configs/nas220.h b/include/configs/nas220.h
index ebf6750..e5ff7e1 100644
--- a/include/configs/nas220.h
+++ b/include/configs/nas220.h
@@ -24,7 +24,6 @@
  */
 #define CONFIG_FEROCEON_88FR131		/* #define CPU Core subversion */
 #define CONFIG_KW88F6192		/* SOC Name */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
 
 /* power-on led, regulator, sata0, sata1 */
diff --git a/include/configs/neo.h b/include/configs/neo.h
index f178366..a60b3f7 100644
--- a/include/configs/neo.h
+++ b/include/configs/neo.h
@@ -25,7 +25,6 @@
 #define CONFIG_BOARD_EARLY_INIT_R
 #define CONFIG_MISC_INIT_R
 #define CONFIG_LAST_STAGE_INIT
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_CLK_FREQ	33333333 /* external frequency to pll   */
 
diff --git a/include/configs/nios2-generic.h b/include/configs/nios2-generic.h
index 945cbd4..b38513e 100644
--- a/include/configs/nios2-generic.h
+++ b/include/configs/nios2-generic.h
@@ -12,57 +12,34 @@
 /*
  * BOARD/CPU
  */
-#include "../board/altera/nios2-generic/custom_fpga.h" /* fpga parameters */
-#define CONFIG_BOARD_NAME "nios2-generic" /* custom board name */
-#define CONFIG_BOARD_EARLY_INIT_F	/* enable early board-spec. init */
 #define CONFIG_DISPLAY_CPUINFO
-#define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_NIOS_SYSID_BASE	CONFIG_SYS_SYSID_BASE
+#define CONFIG_DISPLAY_BOARDINFO_LATE
 
 /*
  * SERIAL
  */
-#define CONFIG_ALTERA_JTAG_UART
-#if defined(CONFIG_ALTERA_JTAG_UART)
-# define CONFIG_SYS_NIOS_CONSOLE	CONFIG_SYS_JTAG_UART_BASE
-#else
-# define CONFIG_SYS_NIOS_CONSOLE	CONFIG_SYS_UART_BASE
-#endif
-
-#define CONFIG_ALTERA_JTAG_UART_BYPASS
-#define CONFIG_SYS_NIOS_FIXEDBAUD
-#define CONFIG_BAUDRATE		CONFIG_SYS_UART_BAUD
-#define CONFIG_SYS_BAUDRATE_TABLE	{CONFIG_BAUDRATE}
+#define CONFIG_BAUDRATE			115200
 #define CONFIG_SYS_CONSOLE_INFO_QUIET	/* Suppress console info */
 
 /*
- * TIMER
+ * CFI Flash
  */
-#define CONFIG_SYS_LOW_RES_TIMER
-#define CONFIG_SYS_NIOS_TMRBASE	CONFIG_SYS_TIMER_BASE
-#define CONFIG_SYS_NIOS_TMRIRQ		CONFIG_SYS_TIMER_IRQ
-#define CONFIG_SYS_NIOS_TMRMS		10	/* Desired period (msec)*/
-#define CONFIG_SYS_NIOS_TMRCNT \
-	(CONFIG_SYS_NIOS_TMRMS * (CONFIG_SYS_TIMER_FREQ / 1000) - 1)
+#define CONFIG_SYS_FLASH_BASE		0xe0000000
+#define CONFIG_FLASH_CFI_DRIVER
+#define CONFIG_SYS_CFI_FLASH_STATUS_POLL /* fix amd flash issue */
+#define CONFIG_SYS_FLASH_CFI
+#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
+#define CONFIG_SYS_FLASH_PROTECTION
+#define CONFIG_SYS_MAX_FLASH_BANKS	1
+#define CONFIG_SYS_MAX_FLASH_SECT	512
 
 /*
- * STATUS LED
+ * MII/PHY
  */
-#define CONFIG_ALTERA_PIO
-#define CONFIG_SYS_ALTERA_PIO_NUM	1
-#define CONFIG_SYS_ALTERA_PIO_GPIO_NUM	LED_PIO_WIDTH
-
-#define CONFIG_STATUS_LED		/* Enable status driver */
-#define CONFIG_BOARD_SPECIFIC_LED
-#define CONFIG_GPIO_LED		/* Enable GPIO LED driver */
-#define CONFIG_GPIO			/* Enable GPIO driver */
-#define LED_PIO_BASE			USER_LED_PIO_8OUT_BASE
-#define LED_PIO_WIDTH			8
-#define LED_PIO_RSTVAL			0xff
-
-#define STATUS_LED_BIT			0	/* Bit-0 on GPIO */
-#define STATUS_LED_STATE		1	/* Blinking */
-#define STATUS_LED_PERIOD	(500 / CONFIG_SYS_NIOS_TMRMS) /* 500 msec */
+#define CONFIG_CMD_MII			1
+#define CONFIG_PHY_GIGE			1
+#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN	1
+#define CONFIG_PHY_MARVELL		1
 
 /*
  * BOOTP options
@@ -73,13 +50,8 @@
 #define CONFIG_BOOTP_HOSTNAME
 
 /*
- * Command line configuration.
+ * FDT options
  */
-#ifdef CONFIG_CMD_NET
-# define CONFIG_CMD_DHCP
-# define CONFIG_CMD_PING
-#endif
-
 #define CONFIG_OF_LIBFDT
 #define CONFIG_OF_BOARD_SETUP
 #define CONFIG_LMB
@@ -93,11 +65,9 @@
  */
 #define CONFIG_ENV_IS_IN_FLASH
 
-#define CONFIG_ENV_SIZE		0x20000	/* 128k, 1 sector */
+#define CONFIG_ENV_SIZE			0x20000	/* 128k, 1 sector */
 #define CONFIG_ENV_OVERWRITE		/* Serial change Ok	*/
-#define CONFIG_ENV_ADDR		((CONFIG_SYS_RESET_ADDR + \
-					  CONFIG_SYS_MONITOR_LEN) | \
-					 CONFIG_SYS_FLASH_BASE)
+#define CONFIG_ENV_ADDR			0xe2840000
 
 /*
  * MEMORY ORGANIZATION
@@ -105,6 +75,8 @@
  * -The heap is placed below the monitor
  * -The stack is placed below the heap (&grows down).
  */
+#define CONFIG_SYS_SDRAM_BASE		0xD0000000
+#define CONFIG_SYS_SDRAM_SIZE		0x08000000
 #define CONFIG_MONITOR_IS_IN_RAM
 #define CONFIG_SYS_MONITOR_LEN		0x40000	/* Reserve 256k */
 #define CONFIG_SYS_MONITOR_BASE	(CONFIG_SYS_SDRAM_BASE + \
@@ -129,7 +101,6 @@
 #define CONFIG_SYS_MEMTEST_START	CONFIG_SYS_SDRAM_BASE
 #define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_INIT_SP - 0x20000)
 #define CONFIG_CMDLINE_EDITING
-
-#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_CMD_GPIO
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/nokia_rx51.h b/include/configs/nokia_rx51.h
index 915df52..52369be 100644
--- a/include/configs/nokia_rx51.h
+++ b/include/configs/nokia_rx51.h
@@ -28,7 +28,6 @@
 #define CONFIG_OMAP3_RX51		/* working with RX51 */
 #define CONFIG_SYS_L2CACHE_OFF		/* pretend there is no L2 CACHE */
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/o2dnt-common.h b/include/configs/o2dnt-common.h
index 435f1a2..8b0dbdc 100644
--- a/include/configs/o2dnt-common.h
+++ b/include/configs/o2dnt-common.h
@@ -18,7 +18,6 @@
  */
 #define CONFIG_MPC5200
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_MPC5XXX_CLKIN	33000000 /* running at 33.000000MHz */
 
diff --git a/include/configs/omap3_evm_common.h b/include/configs/omap3_evm_common.h
index 0ebe5c1..7e7f6f2 100644
--- a/include/configs/omap3_evm_common.h
+++ b/include/configs/omap3_evm_common.h
@@ -15,7 +15,6 @@
 #define CONFIG_OMAP			/* This is TI OMAP core */
 #define CONFIG_OMAP_GPIO
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/omap3_zoom1.h b/include/configs/omap3_zoom1.h
index cef2243..a59fd42 100644
--- a/include/configs/omap3_zoom1.h
+++ b/include/configs/omap3_zoom1.h
@@ -17,7 +17,6 @@
  * High Level Configuration Options
  */
 #define CONFIG_OMAP3_ZOOM1	1	/* working with Zoom MDK Rev1 */
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_NAND
 #define CONFIG_NR_DRAM_BANKS	2	/* CS1 may or may not be populated */
diff --git a/include/configs/omapl138_lcdk.h b/include/configs/omapl138_lcdk.h
index d9a3aa4..80d57f4 100644
--- a/include/configs/omapl138_lcdk.h
+++ b/include/configs/omapl138_lcdk.h
@@ -195,7 +195,6 @@
 /*
  * U-Boot general configuration
  */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_MISC_INIT_R
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_BOOTFILE		"uImage" /* Boot file name */
diff --git a/include/configs/p1_p2_rdb_pc.h b/include/configs/p1_p2_rdb_pc.h
index 362cf30..03eb185 100644
--- a/include/configs/p1_p2_rdb_pc.h
+++ b/include/configs/p1_p2_rdb_pc.h
@@ -10,8 +10,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #ifdef CONFIG_36BIT
 #define CONFIG_PHYS_64BIT
diff --git a/include/configs/p1_twr.h b/include/configs/p1_twr.h
index 588a6c5..46f5f0f 100644
--- a/include/configs/p1_twr.h
+++ b/include/configs/p1_twr.h
@@ -10,8 +10,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define	CONFIG_SYS_GENERIC_BOARD
 #define	CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 #if defined(CONFIG_TWR_P1025)
 #define CONFIG_BOARDNAME "TWR-P1025"
 #define CONFIG_P1025
diff --git a/include/configs/pcm030.h b/include/configs/pcm030.h
index 4ea617a..29feb7b 100644
--- a/include/configs/pcm030.h
+++ b/include/configs/pcm030.h
@@ -15,7 +15,6 @@
 #define __CONFIG_H
 
 #define CONFIG_BOARDINFO	 "phyCORE-MPC5200B-tiny"
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*-----------------------------------------------------------------------------
 High Level Configuration Options
diff --git a/include/configs/pcm052.h b/include/configs/pcm052.h
index 18f45af..046ddb8 100644
--- a/include/configs/pcm052.h
+++ b/include/configs/pcm052.h
@@ -13,7 +13,6 @@
 
 #define CONFIG_VF610
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_SYS_THUMB_BUILD
diff --git a/include/configs/pdm360ng.h b/include/configs/pdm360ng.h
index e7413c9..a6e7e9c 100644
--- a/include/configs/pdm360ng.h
+++ b/include/configs/pdm360ng.h
@@ -14,7 +14,6 @@
 
 #define CONFIG_PDM360NG 1
 #define CONFIG_DISPLAY_BOARDINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Memory map for the PDM360NG board:
diff --git a/include/configs/picosam9g45.h b/include/configs/picosam9g45.h
index 9e9b1d0..47613de 100644
--- a/include/configs/picosam9g45.h
+++ b/include/configs/picosam9g45.h
@@ -36,7 +36,6 @@
 #define CONFIG_CMD_BOOTZ
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* general purpose I/O */
 #define CONFIG_ATMEL_LEGACY		/* required until (g)pio is fixed */
diff --git a/include/configs/pm9261.h b/include/configs/pm9261.h
index f4f96a7..407b83d 100644
--- a/include/configs/pm9261.h
+++ b/include/configs/pm9261.h
@@ -20,7 +20,6 @@
 #include <asm/hardware.h>
 /* ARM asynchronous clock */
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_DISPLAY_BOARDINFO
 
diff --git a/include/configs/pm9263.h b/include/configs/pm9263.h
index bd43577..f6886a6 100644
--- a/include/configs/pm9263.h
+++ b/include/configs/pm9263.h
@@ -18,7 +18,6 @@
  */
 #include <asm/hardware.h>
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* ARM asynchronous clock */
 #define CONFIG_DISPLAY_CPUINFO
diff --git a/include/configs/pm9g45.h b/include/configs/pm9g45.h
index 09f0744..ede0ee1 100644
--- a/include/configs/pm9g45.h
+++ b/include/configs/pm9g45.h
@@ -22,7 +22,6 @@
  */
 #include <asm/hardware.h>
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_PM9G45		1	/* It's an Ronetix PM9G45 */
 #define CONFIG_SYS_AT91_CPU_NAME	"AT91SAM9G45"
diff --git a/include/configs/pogo_e02.h b/include/configs/pogo_e02.h
index 8cf3ad8..b1a3dc7 100644
--- a/include/configs/pogo_e02.h
+++ b/include/configs/pogo_e02.h
@@ -13,7 +13,6 @@
 #ifndef _CONFIG_POGO_E02_H
 #define _CONFIG_POGO_E02_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Machine type definition and ID
diff --git a/include/configs/qemu-ppce500.h b/include/configs/qemu-ppce500.h
index 5cd0906..f45789f 100644
--- a/include/configs/qemu-ppce500.h
+++ b/include/configs/qemu-ppce500.h
@@ -19,7 +19,6 @@
 
 #undef CONFIG_SYS_TEXT_BASE
 #define CONFIG_SYS_TEXT_BASE	0xf01000 /* 15 MB */
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_MPC85XX_NO_RESETVEC
 
diff --git a/include/configs/rcar-gen2-common.h b/include/configs/rcar-gen2-common.h
index 7dd9260..f0a3a18 100644
--- a/include/configs/rcar-gen2-common.h
+++ b/include/configs/rcar-gen2-common.h
@@ -26,7 +26,6 @@
 #define CONFIG_CMD_EXT4_WRITE
 
 #define CONFIG_SYS_THUMB_BUILD
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Support File sytems */
 #define CONFIG_FAT_WRITE
diff --git a/include/configs/rk3288_common.h b/include/configs/rk3288_common.h
index e8aec28..36408b9 100644
--- a/include/configs/rk3288_common.h
+++ b/include/configs/rk3288_common.h
@@ -13,7 +13,6 @@
 #define CONFIG_NR_DRAM_BANKS		1
 #define CONFIG_ENV_IS_NOWHERE
 #define CONFIG_ENV_SIZE			0x2000
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_SYS_MAXARGS		16
 #define CONFIG_BAUDRATE			115200
 #define CONFIG_SYS_MALLOC_LEN		(32 << 20)
diff --git a/include/configs/rpi-common.h b/include/configs/rpi-common.h
index 06836cd..0b8c681 100644
--- a/include/configs/rpi-common.h
+++ b/include/configs/rpi-common.h
@@ -11,7 +11,6 @@
 #include <asm/arch/timer.h>
 
 /* Architecture, CPU, etc.*/
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_BCM2835
 #define CONFIG_ARCH_CPU_INIT
 
@@ -133,6 +132,7 @@
 #include <config_distro_defaults.h>
 
 /* Environment */
+#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
 #define ENV_DEVICE_SETTINGS \
 	"stdin=serial,lcd\0" \
 	"stdout=serial,lcd\0" \
diff --git a/include/configs/s5p_goni.h b/include/configs/s5p_goni.h
index aff264b..2877e19 100644
--- a/include/configs/s5p_goni.h
+++ b/include/configs/s5p_goni.h
@@ -278,6 +278,5 @@
 
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #endif	/* __CONFIG_H */
diff --git a/include/configs/sbc8349.h b/include/configs/sbc8349.h
index 9d89b2a..c8b14e9 100644
--- a/include/configs/sbc8349.h
+++ b/include/configs/sbc8349.h
@@ -15,7 +15,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/sbc8548.h b/include/configs/sbc8548.h
index 87e562e..1c309a4 100644
--- a/include/configs/sbc8548.h
+++ b/include/configs/sbc8548.h
@@ -13,7 +13,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Top level Makefile configuration choices
diff --git a/include/configs/sbc8641d.h b/include/configs/sbc8641d.h
index eed0f49..0b22ce0 100644
--- a/include/configs/sbc8641d.h
+++ b/include/configs/sbc8641d.h
@@ -20,7 +20,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* High Level Configuration Options */
 #define CONFIG_MPC8641		1	/* MPC8641 specific */
diff --git a/include/configs/sheevaplug.h b/include/configs/sheevaplug.h
index 272e3ca..76cdbe0 100644
--- a/include/configs/sheevaplug.h
+++ b/include/configs/sheevaplug.h
@@ -10,7 +10,6 @@
 #ifndef _CONFIG_SHEEVAPLUG_H
 #define _CONFIG_SHEEVAPLUG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
  * Version number information
diff --git a/include/configs/siemens-am33x-common.h b/include/configs/siemens-am33x-common.h
index bcc8dcb..6c374eb 100644
--- a/include/configs/siemens-am33x-common.h
+++ b/include/configs/siemens-am33x-common.h
@@ -45,7 +45,6 @@
 #define CONFIG_CMD_CACHE
 #define CONFIG_CMD_TIME
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_ENV_VARS_UBOOT_CONFIG
 #ifndef CONFIG_SPL_BUILD
diff --git a/include/configs/smartweb.h b/include/configs/smartweb.h
index e11c016..44d1d5a 100644
--- a/include/configs/smartweb.h
+++ b/include/configs/smartweb.h
@@ -51,7 +51,6 @@
 
 /* setting board specific options */
 # define CONFIG_MACH_TYPE		MACH_TYPE_SMARTWEB
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_CMDLINE_EDITING
 #define CONFIG_AUTO_COMPLETE
 
diff --git a/include/configs/smdk2410.h b/include/configs/smdk2410.h
index fb38502..9947dc0 100644
--- a/include/configs/smdk2410.h
+++ b/include/configs/smdk2410.h
@@ -23,7 +23,6 @@
 
 #define CONFIG_SYS_TEXT_BASE	0x0
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
 
diff --git a/include/configs/smdkc100.h b/include/configs/smdkc100.h
index 1d9ce92..c36e444 100644
--- a/include/configs/smdkc100.h
+++ b/include/configs/smdkc100.h
@@ -214,6 +214,5 @@
 
 #define CONFIG_OF_LIBFDT
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #endif	/* __CONFIG_H */
diff --git a/include/configs/snapper9260.h b/include/configs/snapper9260.h
index 7758b0f..afcd16a 100644
--- a/include/configs/snapper9260.h
+++ b/include/configs/snapper9260.h
@@ -20,7 +20,6 @@
 /* ARM asynchronous clock */
 #define CONFIG_SYS_AT91_MAIN_CLOCK	18432000 /* External Crystal, in Hz */
 #define CONFIG_SYS_AT91_SLOW_CLOCK	32768
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* CPU */
 #define CONFIG_ARCH_CPU_INIT
diff --git a/include/configs/sniper.h b/include/configs/sniper.h
index a0ee5bd..f168e8f 100644
--- a/include/configs/sniper.h
+++ b/include/configs/sniper.h
@@ -34,7 +34,6 @@
  * Board
  */
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_MISC_INIT_R
 
 /*
diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h
index cece095..3374683 100644
--- a/include/configs/socfpga_common.h
+++ b/include/configs/socfpga_common.h
@@ -6,7 +6,6 @@
 #ifndef __CONFIG_SOCFPGA_CYCLONE5_COMMON_H__
 #define __CONFIG_SOCFPGA_CYCLONE5_COMMON_H__
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Virtual target or real hardware */
 #undef CONFIG_SOCFPGA_VIRTUAL_TARGET
diff --git a/include/configs/socrates.h b/include/configs/socrates.h
index 50911ae..019cf30 100644
--- a/include/configs/socrates.h
+++ b/include/configs/socrates.h
@@ -27,7 +27,6 @@
 #define CONFIG_E500		1	/* BOOKE e500 family		*/
 #define CONFIG_MPC8544		1
 #define CONFIG_SOCRATES		1
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0xfff80000
diff --git a/include/configs/spear-common.h b/include/configs/spear-common.h
index edae831..1d69477 100644
--- a/include/configs/spear-common.h
+++ b/include/configs/spear-common.h
@@ -11,7 +11,6 @@
  * Common configurations used for both spear3xx as well as spear6xx
  */
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* U-boot Load Address */
 #define CONFIG_SYS_TEXT_BASE			0x00700000
diff --git a/include/configs/stm32f429-discovery.h b/include/configs/stm32f429-discovery.h
index 19d9cf9..1796995 100644
--- a/include/configs/stm32f429-discovery.h
+++ b/include/configs/stm32f429-discovery.h
@@ -10,7 +10,6 @@
 
 #define CONFIG_STM32F4
 #define CONFIG_STM32F4DISCOVERY
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_OF_LIBFDT
 
diff --git a/include/configs/stv0991.h b/include/configs/stv0991.h
index b1b6919..1526d13 100644
--- a/include/configs/stv0991.h
+++ b/include/configs/stv0991.h
@@ -13,7 +13,6 @@
 
 #define CONFIG_SYS_CORTEX_R4
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_SYS_NO_FLASH
 
 /* ram memory-related information */
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index ddcfe94..f5db4d3 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -158,7 +158,6 @@
 #define CONFIG_SYS_CBSIZE	1024	/* Console I/O Buffer Size */
 #define CONFIG_SYS_PBSIZE	1024	/* Print Buffer Size */
 #define CONFIG_SYS_MAXARGS	16	/* max number of command args */
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Boot Argument Buffer Size */
 #define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
diff --git a/include/configs/t4qds.h b/include/configs/t4qds.h
index 26028df..5754369 100644
--- a/include/configs/t4qds.h
+++ b/include/configs/t4qds.h
@@ -10,7 +10,6 @@
 #ifndef __T4QDS_H
 #define __T4QDS_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 #define CONFIG_CMD_REGINFO
 
diff --git a/include/configs/tam3517-common.h b/include/configs/tam3517-common.h
index 801220a..f993433 100644
--- a/include/configs/tam3517-common.h
+++ b/include/configs/tam3517-common.h
@@ -16,7 +16,6 @@
 #define CONFIG_OMAP		/* in a TI OMAP core */
 #define CONFIG_OMAP_GPIO
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/tao3530.h b/include/configs/tao3530.h
index bd1c07c..97fe796 100644
--- a/include/configs/tao3530.h
+++ b/include/configs/tao3530.h
@@ -20,7 +20,6 @@
 
 #define CONFIG_OMAP_GPIO
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 /* Common ARM Erratas */
 #define CONFIG_ARM_ERRATA_454179
 #define CONFIG_ARM_ERRATA_430973
diff --git a/include/configs/taurus.h b/include/configs/taurus.h
index 12994c8..a5e7090 100644
--- a/include/configs/taurus.h
+++ b/include/configs/taurus.h
@@ -22,7 +22,6 @@
 #include <asm/hardware.h>
 #include <linux/sizes.h>
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #if defined(CONFIG_SPL_BUILD)
 #define CONFIG_SYS_THUMB_BUILD
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index 1c469d0..a005e6a 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -130,7 +130,6 @@
 #define CONFIG_SPL_SERIAL_SUPPORT
 #define CONFIG_SPL_GPIO_SUPPORT
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_BOARD_LATE_INIT
 
diff --git a/include/configs/ti814x_evm.h b/include/configs/ti814x_evm.h
index ceeb7fe..7fa35a1 100644
--- a/include/configs/ti814x_evm.h
+++ b/include/configs/ti814x_evm.h
@@ -21,7 +21,6 @@
 #define CONFIG_SYS_NO_FLASH
 #define CONFIG_OMAP
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 
 #include <asm/arch/omap.h>
 
diff --git a/include/configs/ti816x_evm.h b/include/configs/ti816x_evm.h
index 4c19289..01d8233 100644
--- a/include/configs/ti816x_evm.h
+++ b/include/configs/ti816x_evm.h
@@ -15,7 +15,6 @@
 #define CONFIG_SYS_NO_FLASH
 #define CONFIG_OMAP
 #define CONFIG_OMAP_COMMON
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_ARCH_CPU_INIT
 
diff --git a/include/configs/ti_armv7_common.h b/include/configs/ti_armv7_common.h
index 586bd2b..32bb805 100644
--- a/include/configs/ti_armv7_common.h
+++ b/include/configs/ti_armv7_common.h
@@ -17,9 +17,6 @@
 #ifndef __CONFIG_TI_ARMV7_COMMON_H__
 #define __CONFIG_TI_ARMV7_COMMON_H__
 
-/* Common define for many platforms. */
-#define CONFIG_SYS_GENERIC_BOARD
-
 /*
  * We typically do not contain NOR flash.  In the cases where we do, we
  * undefine this later.
diff --git a/include/configs/tricorder.h b/include/configs/tricorder.h
index f04b572..02b0e63 100644
--- a/include/configs/tricorder.h
+++ b/include/configs/tricorder.h
@@ -38,7 +38,6 @@
 #include <asm/arch/cpu.h>		/* get chip and board defs */
 #include <asm/arch/omap.h>
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Display CPU and Board information */
 #define CONFIG_DISPLAY_CPUINFO
diff --git a/include/configs/ts4800.h b/include/configs/ts4800.h
index 21f1555..fbca8a6 100644
--- a/include/configs/ts4800.h
+++ b/include/configs/ts4800.h
@@ -37,9 +37,6 @@
 #define CONFIG_INITRD_TAG
 #define CONFIG_REVISION_TAG
 
-/* use common/board_f.c instead of arch/<arch>/lib/<board>.c */
-#define CONFIG_SYS_GENERIC_BOARD
-
 /*
  * Size of malloc() pool
  */
diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h
index 9109b7f..1e71703 100644
--- a/include/configs/uniphier.h
+++ b/include/configs/uniphier.h
@@ -82,7 +82,6 @@
 /* serial console configuration */
 #define CONFIG_BAUDRATE			115200
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #if !defined(CONFIG_SPL_BUILD)
 #define CONFIG_USE_ARCH_MEMSET
diff --git a/include/configs/usb_a9263.h b/include/configs/usb_a9263.h
index 10a1664..54daede 100644
--- a/include/configs/usb_a9263.h
+++ b/include/configs/usb_a9263.h
@@ -34,7 +34,6 @@
 #define CONFIG_DISPLAY_CPUINFO
 
 #define CONFIG_OF_LIBFDT
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_SYS_TEXT_BASE		0x23f00000
 
 /*
diff --git a/include/configs/usbarmory.h b/include/configs/usbarmory.h
index 714e3e2..6735055 100644
--- a/include/configs/usbarmory.h
+++ b/include/configs/usbarmory.h
@@ -14,9 +14,9 @@
 #define CONFIG_MX53
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_OF_LIBFDT
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_MXC_GPIO
 
 #include <asm/arch/imx-regs.h>
diff --git a/include/configs/v38b.h b/include/configs/v38b.h
index 3e51b9f..f154208 100644
--- a/include/configs/v38b.h
+++ b/include/configs/v38b.h
@@ -14,7 +14,6 @@
  */
 #define CONFIG_MPC5200			1	/* This is an MPC5200 CPU */
 #define CONFIG_V38B			1	/* ...on V38B board */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE		0xFF000000
diff --git a/include/configs/ve8313.h b/include/configs/ve8313.h
index a88216c..f5df4fb 100644
--- a/include/configs/ve8313.h
+++ b/include/configs/ve8313.h
@@ -13,7 +13,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/vexpress_aemv8a.h b/include/configs/vexpress_aemv8a.h
index 0f2f1a3..a99d712 100644
--- a/include/configs/vexpress_aemv8a.h
+++ b/include/configs/vexpress_aemv8a.h
@@ -8,9 +8,6 @@
 #ifndef __VEXPRESS_AEMV8A_H
 #define __VEXPRESS_AEMV8A_H
 
-/* We use generic board and device manager for v8 Versatile Express */
-#define CONFIG_SYS_GENERIC_BOARD
-
 #ifdef CONFIG_TARGET_VEXPRESS64_BASE_FVP
 #ifndef CONFIG_SEMIHOSTING
 #error CONFIG_TARGET_VEXPRESS64_BASE_FVP requires CONFIG_SEMIHOSTING
diff --git a/include/configs/vexpress_common.h b/include/configs/vexpress_common.h
index 98f6ae9..cec510c 100644
--- a/include/configs/vexpress_common.h
+++ b/include/configs/vexpress_common.h
@@ -122,7 +122,6 @@
 #define CONFIG_SETUP_MEMORY_TAGS	1
 #define CONFIG_SYS_L2CACHE_OFF		1
 #define CONFIG_INITRD_TAG		1
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 128 * 1024)
diff --git a/include/configs/vf610twr.h b/include/configs/vf610twr.h
index 7f4260a..abd1e98 100644
--- a/include/configs/vf610twr.h
+++ b/include/configs/vf610twr.h
@@ -13,9 +13,9 @@
 
 #define CONFIG_VF610
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_CPUINFO
 #define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_FSL_CLK
 
 #define CONFIG_MACH_TYPE		4146
 
diff --git a/include/configs/vme8349.h b/include/configs/vme8349.h
index a6f5d6a..7f5f089 100644
--- a/include/configs/vme8349.h
+++ b/include/configs/vme8349.h
@@ -18,7 +18,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 /*
diff --git a/include/configs/woodburn_common.h b/include/configs/woodburn_common.h
index fc46565..e6f3e28 100644
--- a/include/configs/woodburn_common.h
+++ b/include/configs/woodburn_common.h
@@ -16,12 +16,12 @@
  /* High Level Configuration Options */
 #define CONFIG_MX35
 #define CONFIG_MX35_HCLK_FREQ	24000000
+#define CONFIG_FSL_CLK
 
 #define CONFIG_SYS_DCACHE_OFF
 #define CONFIG_SYS_CACHELINE_SIZE	32
 
 #define CONFIG_DISPLAY_CPUINFO
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Only in case the value is not present in mach-types.h */
 #ifndef MACH_TYPE_FLEA3
diff --git a/include/configs/work_92105.h b/include/configs/work_92105.h
index 15ee284..f77d065 100644
--- a/include/configs/work_92105.h
+++ b/include/configs/work_92105.h
@@ -103,7 +103,6 @@
 /*
  * U-Boot General Configurations
  */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_SYS_LONGHELP
 #define CONFIG_SYS_CBSIZE		1024
 #define CONFIG_SYS_PBSIZE		\
diff --git a/include/configs/x600.h b/include/configs/x600.h
index 73ba67c..8534766 100644
--- a/include/configs/x600.h
+++ b/include/configs/x600.h
@@ -16,7 +16,6 @@
  */
 #define CONFIG_SPEAR600				/* SPEAr600 SoC */
 #define CONFIG_X600				/* on X600 board */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_SYS_THUMB_BUILD
 
 #include <asm/arch/hardware.h>
diff --git a/include/configs/xilinx-ppc.h b/include/configs/xilinx-ppc.h
index 6bd6be8..1abd0ef 100644
--- a/include/configs/xilinx-ppc.h
+++ b/include/configs/xilinx-ppc.h
@@ -12,7 +12,6 @@
 #ifndef __CONFIG_XLX_H
 #define __CONFIG_XLX_H
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /*
 #define DEBUG
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h
index ed09b7f..32ee0fc 100644
--- a/include/configs/xilinx_zynqmp.h
+++ b/include/configs/xilinx_zynqmp.h
@@ -17,7 +17,6 @@
 
 #define CONFIG_SYS_NO_FLASH
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 /* Generic Interrupt Controller Definitions */
 #define CONFIG_GICV2
diff --git a/include/configs/xpedite1000.h b/include/configs/xpedite1000.h
index 37a31c4..005f149 100644
--- a/include/configs/xpedite1000.h
+++ b/include/configs/xpedite1000.h
@@ -22,7 +22,6 @@
 #define CONFIG_440GX		1		/* 440 GX */
 #define CONFIG_BOARD_EARLY_INIT_F 1		/* Call board_pre_init	*/
 #define CONFIG_SYS_CLK_FREQ	33333333	/* external freq to pll */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0xFFF80000
diff --git a/include/configs/xpedite517x.h b/include/configs/xpedite517x.h
index 51781da..3e09635 100644
--- a/include/configs/xpedite517x.h
+++ b/include/configs/xpedite517x.h
@@ -23,7 +23,6 @@
 #define CONFIG_BAT_RW		1	/* Use common BAT rw code */
 #define CONFIG_HIGH_BATS	1	/* High BATs supported and enabled */
 #define CONFIG_ALTIVEC		1
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #define	CONFIG_SYS_TEXT_BASE	0xfff00000
diff --git a/include/configs/xpedite520x.h b/include/configs/xpedite520x.h
index e48960b..39bdb88 100644
--- a/include/configs/xpedite520x.h
+++ b/include/configs/xpedite520x.h
@@ -21,7 +21,6 @@
 #define CONFIG_SYS_BOARD_NAME	"XPedite5200"
 #define CONFIG_SYS_FORM_PMC_XMC	1
 #define CONFIG_BOARD_EARLY_INIT_R	/* Call board_pre_init */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifndef CONFIG_SYS_TEXT_BASE
diff --git a/include/configs/xpedite537x.h b/include/configs/xpedite537x.h
index 3645cb2..c687555 100644
--- a/include/configs/xpedite537x.h
+++ b/include/configs/xpedite537x.h
@@ -21,7 +21,6 @@
 #define CONFIG_SYS_BOARD_NAME	"XPedite5370"
 #define CONFIG_SYS_FORM_3U_VPX	1
 #define CONFIG_BOARD_EARLY_INIT_R	/* Call board_pre_init */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifndef CONFIG_SYS_TEXT_BASE
diff --git a/include/configs/xpedite550x.h b/include/configs/xpedite550x.h
index 7bf0cca..f971f8b 100644
--- a/include/configs/xpedite550x.h
+++ b/include/configs/xpedite550x.h
@@ -22,7 +22,6 @@
 #define CONFIG_SYS_FORM_PMC_XMC	1
 #define CONFIG_PRPMC_PCI_ALIAS	"pci0"	/* Processor PMC interface on pci0 */
 #define CONFIG_BOARD_EARLY_INIT_R	/* Call board_pre_init */
-#define CONFIG_SYS_GENERIC_BOARD
 #define CONFIG_DISPLAY_BOARDINFO
 
 #ifndef CONFIG_SYS_TEXT_BASE
diff --git a/include/configs/zmx25.h b/include/configs/zmx25.h
index b7134eb..bd8fdfb 100644
--- a/include/configs/zmx25.h
+++ b/include/configs/zmx25.h
@@ -15,7 +15,6 @@
 #define CONFIG_MX25
 #define CONFIG_SYS_TEXT_BASE		0xA0000000
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #define CONFIG_SYS_TIMER_RATE		32768
 #define CONFIG_SYS_TIMER_COUNTER	\
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h
index 873c42d..66b1e69 100644
--- a/include/configs/zynq-common.h
+++ b/include/configs/zynq-common.h
@@ -375,6 +375,5 @@
 
 #define CONFIG_SYS_UBOOT_START	CONFIG_SYS_TEXT_BASE
 
-#define CONFIG_SYS_GENERIC_BOARD
 
 #endif /* __CONFIG_ZYNQ_COMMON_H */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index da41499..886a44c 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -39,6 +39,7 @@
 	UCLASS_LED,		/* Light-emitting diode (LED) */
 	UCLASS_LPC,		/* x86 'low pin count' interface */
 	UCLASS_MASS_STORAGE,	/* Mass storage device */
+	UCLASS_MISC,		/* Miscellaneous device */
 	UCLASS_MMC,		/* SD / MMC card or chip */
 	UCLASS_MOD_EXP,		/* RSA Mod Exp device */
 	UCLASS_PCH,		/* x86 platform controller hub */
@@ -57,6 +58,7 @@
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
 	UCLASS_SYSCON,		/* System configuration device */
 	UCLASS_THERMAL,		/* Thermal sensor */
+	UCLASS_TIMER,		/* Timer device */
 	UCLASS_TPM,		/* Trusted Platform Module TIS interface */
 	UCLASS_USB,		/* USB bus */
 	UCLASS_USB_DEV_GENERIC,	/* USB generic device */
diff --git a/include/fs.h b/include/fs.h
index fd1e4ab..059a395 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -22,6 +22,7 @@
 #define FS_TYPE_FAT	1
 #define FS_TYPE_EXT	2
 #define FS_TYPE_SANDBOX	3
+#define FS_TYPE_UBIFS	4
 
 /*
  * Tell the fs layer which block device an partition to use for future
diff --git a/include/linux/compat.h b/include/linux/compat.h
index fbebf91..59937de 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -4,6 +4,7 @@
 #include <malloc.h>
 #include <linux/types.h>
 #include <linux/err.h>
+#include <linux/kernel.h>
 
 struct unused {};
 typedef struct unused unused_t;
@@ -49,22 +50,47 @@
 {
 	return kmalloc(size, flags | __GFP_ZERO);
 }
+
+static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)
+{
+	if (size != 0 && n > SIZE_MAX / size)
+		return NULL;
+	return kmalloc(n * size, flags | __GFP_ZERO);
+}
+
+static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
+{
+	return kmalloc_array(n, size, flags | __GFP_ZERO);
+}
+
 #define vmalloc(size)	kmalloc(size, 0)
 #define __vmalloc(size, flags, pgsz)	kmalloc(size, flags)
 static inline void *vzalloc(unsigned long size)
 {
 	return kzalloc(size, 0);
 }
-#define kfree(ptr)	free(ptr)
-#define vfree(ptr)	free(ptr)
+static inline void kfree(const void *block)
+{
+	free((void *)block);
+}
+static inline void vfree(const void *addr)
+{
+	free((void *)addr);
+}
 
 struct kmem_cache { int sz; };
 
 struct kmem_cache *get_mem(int element_sz);
 #define kmem_cache_create(a, sz, c, d, e)	get_mem(sz)
 void *kmem_cache_alloc(struct kmem_cache *obj, int flag);
-#define kmem_cache_free(obj, size)	free(size)
-#define kmem_cache_destroy(obj)		free(obj)
+static inline void kmem_cache_free(struct kmem_cache *cachep, void *obj)
+{
+	free(obj);
+}
+static inline void kmem_cache_destroy(struct kmem_cache *cachep)
+{
+	free(cachep);
+}
 
 #define DECLARE_WAITQUEUE(...)	do { } while (0)
 #define add_wait_queue(...)	do { } while (0)
@@ -159,6 +185,8 @@
 
 #define class_create(...)		__builtin_return_address(0)
 #define class_create_file(...)		0
+#define class_register(...)		0
+#define class_unregister(...)
 #define class_remove_file(...)
 #define class_destroy(...)
 #define misc_register(...)		0
@@ -171,6 +199,7 @@
 
 #define dev_set_name(...)		do { } while (0)
 #define device_register(...)		0
+#define device_unregister(...)
 #define volume_sysfs_init(...)		0
 #define volume_sysfs_close(...)		do { } while (0)
 
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index bc4d9bf..e3d3fc7 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -244,6 +244,7 @@
 #ifndef __UBOOT__
 	int (*_suspend) (struct mtd_info *mtd);
 	void (*_resume) (struct mtd_info *mtd);
+	void (*_reboot) (struct mtd_info *mtd);
 #endif
 	/*
 	 * If the driver is something smart, like UBI, it may need to maintain
@@ -478,6 +479,8 @@
 	return mtd_is_bitflip(err) || mtd_is_eccerr(err);
 }
 
+unsigned mtd_mmap_capabilities(struct mtd_info *mtd);
+
 #ifdef __UBOOT__
 /* drivers/mtd/mtdcore.h */
 int add_mtd_device(struct mtd_info *mtd);
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index 05d0ab5..036779b 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #ifndef __UBOOT__
 #include <linux/ioctl.h>
+#include <linux/scatterlist.h>
 #include <mtd/ubi-user.h>
 #endif
 
@@ -19,16 +20,25 @@
 #define UBI_ALL -1
 
 /*
+ * Maximum number of scatter gather list entries,
+ * we use only 64 to have a lower memory foot print.
+ */
+#define UBI_MAX_SG_COUNT 64
+
+/*
  * enum ubi_open_mode - UBI volume open mode constants.
  *
  * UBI_READONLY: read-only mode
  * UBI_READWRITE: read-write mode
  * UBI_EXCLUSIVE: exclusive mode
+ * UBI_METAONLY: modify only the volume meta-data,
+ *  i.e. the data stored in the volume table, but not in any of volume LEBs.
  */
 enum {
 	UBI_READONLY = 1,
 	UBI_READWRITE,
-	UBI_EXCLUSIVE
+	UBI_EXCLUSIVE,
+	UBI_METAONLY
 };
 
 /**
@@ -106,6 +116,37 @@
 };
 
 /**
+ * struct ubi_sgl - UBI scatter gather list data structure.
+ * @list_pos: current position in @sg[]
+ * @page_pos: current position in @sg[@list_pos]
+ * @sg: the scatter gather list itself
+ *
+ * ubi_sgl is a wrapper around a scatter list which keeps track of the
+ * current position in the list and the current list item such that
+ * it can be used across multiple ubi_leb_read_sg() calls.
+ */
+struct ubi_sgl {
+	int list_pos;
+	int page_pos;
+#ifndef __UBOOT__
+	struct scatterlist sg[UBI_MAX_SG_COUNT];
+#endif
+};
+
+/**
+ * ubi_sgl_init - initialize an UBI scatter gather list data structure.
+ * @usgl: the UBI scatter gather struct itself
+ *
+ * Please note that you still have to use sg_init_table() or any adequate
+ * function to initialize the unterlaying struct scatterlist.
+ */
+static inline void ubi_sgl_init(struct ubi_sgl *usgl)
+{
+	usgl->list_pos = 0;
+	usgl->page_pos = 0;
+}
+
+/**
  * struct ubi_device_info - UBI device description data structure.
  * @ubi_num: ubi device number
  * @leb_size: logical eraseblock size on this UBI device
@@ -214,6 +255,8 @@
 void ubi_close_volume(struct ubi_volume_desc *desc);
 int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
 		 int len, int check);
+int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
+		   int offset, int len, int check);
 int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
 		  int offset, int len);
 int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
@@ -234,4 +277,14 @@
 {
 	return ubi_leb_read(desc, lnum, buf, offset, len, 0);
 }
+
+/*
+ * This function is the same as the 'ubi_leb_read_sg()' function, but it does
+ * not provide the checking capability.
+ */
+static inline int ubi_read_sg(struct ubi_volume_desc *desc, int lnum,
+			      struct ubi_sgl *sgl, int offset, int len)
+{
+	return ubi_leb_read_sg(desc, lnum, sgl, offset, len, 0);
+}
 #endif /* !__LINUX_UBI_H__ */
diff --git a/include/misc.h b/include/misc.h
new file mode 100644
index 0000000..7e9badf
--- /dev/null
+++ b/include/misc.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _MISC_H_
+#define _MISC_H_
+
+/*
+ * Read the device to buffer, optional.
+ *
+ * @dev: the device
+ * @offset: offset to read the device
+ * @buf: pointer to data buffer
+ * @size: data size in bytes to read the device
+ * @return: 0 if OK, -ve on error
+ */
+int misc_read(struct udevice *dev, int offset, void *buf, int size);
+/*
+ * Write buffer to the device, optional.
+ *
+ * @dev: the device
+ * @offset: offset to write the device
+ * @buf: pointer to data buffer
+ * @size: data size in bytes to write the device
+ * @return: 0 if OK, -ve on error
+ */
+int misc_write(struct udevice *dev, int offset, void *buf, int size);
+/*
+ * Assert command to the device, optional.
+ *
+ * @dev: the device
+ * @request: command to be sent to the device
+ * @buf: pointer to buffer related to the requset
+ * @return: 0 if OK, -ve on error
+ */
+int misc_ioctl(struct udevice *dev, unsigned long request, void *buf);
+
+/*
+ * struct misc_ops - Driver model Misc operations
+ *
+ * The uclass interface is implemented by all miscellaneous devices which
+ * use driver model.
+ */
+struct misc_ops {
+	/*
+	 * Read the device to buffer, optional.
+	 *
+	 * @dev: the device
+	 * @offset: offset to read the device
+	 * @buf: pointer to data buffer
+	 * @size: data size in bytes to read the device
+	 * @return: 0 if OK, -ve on error
+	 */
+	int (*read)(struct udevice *dev, int offset, void *buf, int size);
+	/*
+	 * Write buffer to the device, optional.
+	 *
+	 * @dev: the device
+	 * @offset: offset to write the device
+	 * @buf: pointer to data buffer
+	 * @size: data size in bytes to write the device
+	 * @return: 0 if OK, -ve on error
+	 */
+	int (*write)(struct udevice *dev, int offset, const void *buf,
+		     int size);
+	/*
+	 * Assert command to the device, optional.
+	 *
+	 * @dev: the device
+	 * @request: command to be sent to the device
+	 * @buf: pointer to buffer related to the requset
+	 * @return: 0 if OK, -ve on error
+	 */
+	int (*ioctl)(struct udevice *dev, unsigned long request, void *buf);
+};
+
+#endif	/* _MISC_H_ */
diff --git a/include/serial.h b/include/serial.h
index de40e94..e490f9a 100644
--- a/include/serial.h
+++ b/include/serial.h
@@ -164,8 +164,6 @@
 /* Access the serial operations for a device */
 #define serial_get_ops(dev)	((struct dm_serial_ops *)(dev)->driver->ops)
 
-void altera_jtag_serial_initialize(void);
-void altera_serial_initialize(void);
 void amirix_serial_initialize(void);
 void arc_serial_initialize(void);
 void arm_dcc_initialize(void);
diff --git a/include/status_led.h b/include/status_led.h
index f6be181..396ea88 100644
--- a/include/status_led.h
+++ b/include/status_led.h
@@ -23,6 +23,7 @@
 #define STATUS_LED_BLINKING	1
 #define STATUS_LED_ON		2
 
+void status_led_init(void);
 void status_led_tick (unsigned long timestamp);
 void status_led_set  (int led, int state);
 
diff --git a/include/timer.h b/include/timer.h
new file mode 100644
index 0000000..cdf385d
--- /dev/null
+++ b/include/timer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+/*
+ * Get the current timer count
+ *
+ * @dev: The Timer device
+ * @count: pointer that returns the current timer count
+ * @return: 0 if OK, -ve on error
+ */
+int timer_get_count(struct udevice *dev, unsigned long *count);
+/*
+ * Get the timer input clock frequency
+ *
+ * @dev: The Timer device
+ * @return: the timer input clock frequency
+ */
+unsigned long timer_get_rate(struct udevice *dev);
+
+/*
+ * struct timer_ops - Driver model Timer operations
+ *
+ * The uclass interface is implemented by all Timer devices which use
+ * driver model.
+ */
+struct timer_ops {
+	/*
+	 * Get the current timer count
+	 *
+	 * @dev: The Timer device
+	 * @count: pointer that returns the current timer count
+	 * @return: 0 if OK, -ve on error
+	 */
+	int (*get_count)(struct udevice *dev, unsigned long *count);
+};
+
+/*
+ * struct timer_dev_priv - information about a device used by the uclass
+ *
+ * @clock_rate: the timer input clock frequency
+ */
+struct timer_dev_priv {
+	unsigned long clock_rate;
+};
+
+#endif	/* _TIMER_H_ */
diff --git a/include/ubifs_uboot.h b/include/ubifs_uboot.h
new file mode 100644
index 0000000..dab433a
--- /dev/null
+++ b/include/ubifs_uboot.h
@@ -0,0 +1,32 @@
+/*
+ * UBIFS u-boot wrapper functions header
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * (C) Copyright 2008-2009
+ * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+
+#ifndef __UBIFS_UBOOT_H__
+#define __UBIFS_UBOOT_H__
+
+int ubifs_init(void);
+int uboot_ubifs_mount(char *vol_name);
+void uboot_ubifs_umount(void);
+int ubifs_is_mounted(void);
+int ubifs_load(char *filename, u32 addr, u32 size);
+
+int ubifs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info);
+int ubifs_ls(const char *dir_name);
+int ubifs_exists(const char *filename);
+int ubifs_size(const char *filename, loff_t *size);
+int ubifs_read(const char *filename, void *buf, loff_t offset,
+	       loff_t size, loff_t *actread);
+void ubifs_close(void);
+
+#endif /* __UBIFS_UBOOT_H__ */
diff --git a/lib/time.c b/lib/time.c
index 477440d..b001745 100644
--- a/lib/time.c
+++ b/lib/time.c
@@ -6,6 +6,9 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
 #include <watchdog.h>
 #include <div64.h>
 #include <asm/io.h>
@@ -37,6 +40,52 @@
 extern unsigned long __weak timer_read_counter(void);
 #endif
 
+#ifdef CONFIG_TIMER
+static int notrace dm_timer_init(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	if (!gd->timer) {
+		ret = uclass_first_device(UCLASS_TIMER, &dev);
+		if (ret)
+			return ret;
+		if (!dev)
+			return -ENODEV;
+		gd->timer = dev;
+	}
+
+	return 0;
+}
+
+ulong notrace get_tbclk(void)
+{
+	int ret;
+
+	ret = dm_timer_init();
+	if (ret)
+		return ret;
+
+	return timer_get_rate(gd->timer);
+}
+
+unsigned long notrace timer_read_counter(void)
+{
+	unsigned long count;
+	int ret;
+
+	ret = dm_timer_init();
+	if (ret)
+		return ret;
+
+	ret = timer_get_count(gd->timer, &count);
+	if (ret)
+		return ret;
+
+	return count;
+}
+#endif /* CONFIG_TIMER */
+
 uint64_t __weak notrace get_ticks(void)
 {
 	unsigned long now = timer_read_counter();
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 58442f1..2df93c8 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -52,6 +52,7 @@
 libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
 
 libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
+libs-y += common/init/
 libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/
 libs-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/
 libs-y += drivers/
diff --git a/test/fs/fat-noncontig-test.sh b/test/fs/fat-noncontig-test.sh
new file mode 100755
index 0000000..f153c97
--- /dev/null
+++ b/test/fs/fat-noncontig-test.sh
@@ -0,0 +1,113 @@
+#!/bin/bash
+
+# (C) Copyright 2015 Stephen Warren
+#
+# SPDX-License-Identifier:	GPL-2.0+
+
+# This script tests U-Boot's FAT filesystem code's ability to read non-
+# contiguous files.
+
+# When porting the ff.c FAT parsing code into U-Boot, it was found that ff.c
+# always reads files cluster-by-cluster, which results in poor performance.
+# This was solved by adding a patch to ff.c to coalesce reads of adjacent
+# clusters. Since this patch needed to correctly handle non-contiguous files,
+# this test was written to validate that.
+#
+# To execute the test, simply run it from the U-Boot source root directory:
+#
+#    cd u-boot
+#    ./test/fs/fat-noncontig-test.sh
+#
+# The test will create a FAT filesystem image, record the CRC of a randomly
+# generated file in the image, build U-Boot sandbox, invoke U-Boot sandbox to
+# read the file and validate that the CRCs match. Expected output is shown
+# below. The important part of the log is the penultimate line that contains
+# either "PASS" or "FAILURE".
+#
+#    mkfs.fat 3.0.26 (2014-03-07)
+#
+#
+#    U-Boot 2015.10-rc4-00018-g4b22a3e5513f (Oct 03 2015 - 13:49:23 -0600)
+#
+#    DRAM:  128 MiB
+#    Using default environment
+#
+#    In:    serial
+#    Out:   lcd
+#    Err:   lcd
+#    Net:   No ethernet found.
+#    => host bind 0 sandbox/fat-noncontig.img
+#    => load host 0:0 1000 noncontig.img
+#    33584964 bytes read in 18 ms (1.7 GiB/s)
+#    => crc32 1000 $filesize 0
+#    crc32 for 00001000 ... 02008743 ==> 6a080523
+#    => if itest.l *0 != 2305086a; then echo FAILURE; else echo PASS; fi
+#    PASS
+#    => reset
+#
+# All temporary files used by this script are created in ./sandbox to avoid
+# polluting the source tree. test/fs/fs-test.sh also uses this directory for
+# the same purpose.
+#
+# TODO: Integrate this (and many other corner-cases e.g. different types of
+# FAT) with fs-test.sh so that a single script tests everything filesystem-
+# related.
+
+odir=sandbox
+img=${odir}/fat-noncontig.img
+mnt=${odir}/mnt
+fill=/dev/urandom
+testfn=noncontig.img
+mnttestfn=${mnt}/${testfn}
+crcaddr=0
+loadaddr=1000
+
+for prereq in fallocate mkfs.fat dd crc32; do
+    if [ ! -x "`which $prereq`" ]; then
+        echo "Missing $prereq binary. Exiting!"
+        exit 1
+    fi
+done
+
+make O=${odir} -s sandbox_defconfig && make O=${odir} -s -j8
+
+mkdir -p ${mnt}
+if [ ! -f ${img} ]; then
+    fallocate -l 40M ${img}
+    mkfs.fat ${img}
+
+    sudo mount -o loop,uid=$(id -u) ${img} ${mnt}
+
+    for ((sects=8; sects < 512; sects += 8)); do
+        fn=${mnt}/keep-${sects}.img
+        dd if=${fill} of=${fn} bs=512 count=${sects} >/dev/null 2>&1
+        fn=${mnt}/remove-${sects}.img
+        dd if=${fill} of=${fn} bs=512 count=${sects} >/dev/null 2>&1
+    done
+
+    rm -f ${mnt}/remove-*.img
+
+    # 511 deliberately to trigger a file size that's not a multiple of the
+    # sector size (ignoring sizes that are multiples of both).
+    dd if=${fill} of=${mnttestfn} bs=511 >/dev/null 2>&1
+
+    sudo umount ${mnt}
+fi
+
+sudo mount -o ro,loop,uid=$(id -u) ${img} ${mnt}
+crc=0x`crc32 ${mnttestfn}`
+sudo umount ${mnt}
+
+crc=`printf %02x%02x%02x%02x \
+    $((${crc} & 0xff)) \
+    $(((${crc} >> 8) & 0xff)) \
+    $(((${crc} >> 16) & 0xff)) \
+    $((${crc} >> 24))`
+
+./sandbox/u-boot << EOF
+host bind 0 ${img}
+load host 0:0 ${loadaddr} ${testfn}
+crc32 ${loadaddr} \$filesize ${crcaddr}
+if itest.l *${crcaddr} != ${crc}; then echo FAILURE; else echo PASS; fi
+reset
+EOF
diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh
index 6f0a345..fc41c04 100755
--- a/test/fs/fs-test.sh
+++ b/test/fs/fs-test.sh
@@ -58,7 +58,7 @@
 # Check if the prereq binaries exist, or exit
 function check_prereq() {
 	for prereq in $PREREQ_BINS; do
-		if [ ! -x `which $prereq` ]; then
+		if [ ! -x "`which $prereq`" ]; then
 			echo "Missing $prereq binary. Exiting!"
 			exit
 		fi
diff --git a/tools/fit_check_sign.c b/tools/fit_check_sign.c
index 69e99c0..d9361b0 100644
--- a/tools/fit_check_sign.c
+++ b/tools/fit_check_sign.c
@@ -75,7 +75,7 @@
 	if (ffd < 0)
 		return EXIT_FAILURE;
 	kfd = mmap_fdt(cmdname, keyfile, 0, &key_blob, &ksbuf, false);
-	if (ffd < 0)
+	if (kfd < 0)
 		return EXIT_FAILURE;
 
 	image_set_host_blob(key_blob);
diff --git a/tools/mkexynosspl.c b/tools/mkexynosspl.c
index 32b786c..46195aa 100644
--- a/tools/mkexynosspl.c
+++ b/tools/mkexynosspl.c
@@ -110,7 +110,7 @@
 	}
 
 	ofd = open(argv[of_index], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
-	if (ifd < 0) {
+	if (ofd < 0) {
 		fprintf(stderr, "%s: Can't open %s: %s\n",
 			prog_name, argv[of_index], strerror(errno));
 		exit(EXIT_FAILURE);