From 7622722daf826d0cd747d85b8baa9ce1b1387899 Mon Sep 17 00:00:00 2001
From: Waldemar Brodkorb <wbx@openadk.org>
Date: Sun, 1 Jun 2014 16:57:14 +0200
Subject: add watchdog support for cubox, inlude weim by default

---
 target/linux/config/Config.in.audio              |     8 +-
 target/linux/config/Config.in.misc               |     6 +
 target/linux/config/Config.in.watchdog           |    10 +
 target/linux/patches/3.15-rc7/patch-yaffs2       | 16551 +++++++++++++++++++++
 target/linux/patches/3.15-rc7/tcp-fastopen.patch |  2083 ++-
 target/linux/patches/3.15-rc7/yaffs2.patch       | 16551 ---------------------
 target/linux/patches/3.15-rc7/zlib-inflate.patch |    12 -
 7 files changed, 18529 insertions(+), 16692 deletions(-)
 create mode 100644 target/linux/patches/3.15-rc7/patch-yaffs2
 delete mode 100644 target/linux/patches/3.15-rc7/yaffs2.patch
 delete mode 100644 target/linux/patches/3.15-rc7/zlib-inflate.patch

(limited to 'target/linux')

diff --git a/target/linux/config/Config.in.audio b/target/linux/config/Config.in.audio
index 6ba4f4842..7813c1800 100644
--- a/target/linux/config/Config.in.audio
+++ b/target/linux/config/Config.in.audio
@@ -16,6 +16,9 @@ config ADK_KERNEL_SND_ARM
 config ADK_KERNEL_SND_SOC_GENERIC_DMAENGINE_PCM
 	boolean
 
+config ADK_KERNEL_SND_DMAENGINE_PCM
+	tristate
+
 config ADK_KERNEL_SND_SOC_SPDIF
 	tristate
 
@@ -175,7 +178,8 @@ config ADK_KERNEL_SND_IMX_SOC
 	select ADK_KERNEL_SND_SOC
 	select ADK_KERNEL_SND_COMPRESS
 	select ADK_KERNEL_SND_PCM_DMAENGINE if !ADK_KERNEL_VERSION_3_10_30
-	select ADK_KERNEL_SND_SOC_GENERIC_DMAENGINE_PCM if ADK_KERNEL_VERSION_3_10_30
+	select ADK_KERNEL_SND_SOC_GENERIC_DMAENGINE_PCM
+	select ADK_KERNEL_SND_DMAENGINE_PCM
 	select ADK_KERNEL_SND_SOC_FSL_SPDIF if ADK_KERNEL_VERSION_3_10_30
 	select ADK_KERNEL_SND_SOC_IMX_PCM_DMA
 	select ADK_KERNEL_SND_SOC_IMX_HDMI_DMA
@@ -185,7 +189,7 @@ config ADK_KERNEL_SND_IMX_SOC
 	select ADK_KERNEL_REGMAP_SPI
 	select ADK_KERNEL_REGMAP_I2C
 	depends on ADK_TARGET_SYSTEM_CUBOX_I
-	default m if ADK_TARGET_SYSTEM_CUBOX_I && !ADK_KERNEL_VERSION_3_14
+	default m if ADK_TARGET_SYSTEM_CUBOX_I
 	default n
 
 endmenu
diff --git a/target/linux/config/Config.in.misc b/target/linux/config/Config.in.misc
index 463a8f369..41e8edc0c 100644
--- a/target/linux/config/Config.in.misc
+++ b/target/linux/config/Config.in.misc
@@ -12,6 +12,12 @@ config ADK_KERNEL_KEYS
 config ADK_KERNEL_SBUS
 	boolean
 
+config ADK_KERNEL_IMX_WEIM
+	boolean
+	depends on ADK_TARGET_SYSTEM_CUBOX_I
+	default y if ADK_TARGET_SYSTEM_CUBOX_I
+	default n
+
 menu "Miscellaneous devices support"
 
 source "target/linux/config/Config.in.rtc"
diff --git a/target/linux/config/Config.in.watchdog b/target/linux/config/Config.in.watchdog
index d8cc5932e..1b9d183cc 100644
--- a/target/linux/config/Config.in.watchdog
+++ b/target/linux/config/Config.in.watchdog
@@ -15,6 +15,16 @@ config ADK_KERNEL_CS5535_CLOCK_EVENT_SRC
 
 menu "Watchdog driver support"
 
+config ADK_KERNEL_IMX2_WDT
+	prompt "Cubox-i Hardware Watchdog"
+	boolean
+	select ADK_KERNEL_WATCHDOG
+	depends on ADK_TARGET_SYSTEM_CUBOX_I
+	default y if ADK_TARGET_SYSTEM_CUBOX_I
+	default n
+	help
+	  Watchdog driver for Cubox-i
+
 config ADK_KERNEL_SCx200_WDT
 	prompt "Natsemi Hardware Watchdog" 
 	boolean
diff --git a/target/linux/patches/3.15-rc7/patch-yaffs2 b/target/linux/patches/3.15-rc7/patch-yaffs2
new file mode 100644
index 000000000..bb244c7ca
--- /dev/null
+++ b/target/linux/patches/3.15-rc7/patch-yaffs2
@@ -0,0 +1,16551 @@
+diff -Nur linux-3.15-rc5.orig/fs/Kconfig linux-3.15-rc5/fs/Kconfig
+--- linux-3.15-rc5.orig/fs/Kconfig	2014-05-09 22:10:52.000000000 +0200
++++ linux-3.15-rc5/fs/Kconfig	2014-05-17 01:53:17.000000000 +0200
+@@ -190,6 +190,7 @@
+ source "fs/befs/Kconfig"
+ source "fs/bfs/Kconfig"
+ source "fs/efs/Kconfig"
++source "fs/yaffs2/Kconfig"
+ source "fs/jffs2/Kconfig"
+ # UBIFS File system configuration
+ source "fs/ubifs/Kconfig"
+diff -Nur linux-3.15-rc5.orig/fs/Makefile linux-3.15-rc5/fs/Makefile
+--- linux-3.15-rc5.orig/fs/Makefile	2014-05-09 22:10:52.000000000 +0200
++++ linux-3.15-rc5/fs/Makefile	2014-05-17 01:53:25.000000000 +0200
+@@ -126,3 +126,4 @@
+ obj-$(CONFIG_CEPH_FS)		+= ceph/
+ obj-$(CONFIG_PSTORE)		+= pstore/
+ obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
++obj-$(CONFIG_YAFFS_FS)		+= yaffs2/
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/Kconfig linux-3.15-rc5/fs/yaffs2/Kconfig
+--- linux-3.15-rc5.orig/fs/yaffs2/Kconfig	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/Kconfig	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,171 @@
++#
++# yaffs file system configurations
++#
++
++config YAFFS_FS
++	tristate "yaffs2 file system support"
++	default n
++	depends on MTD_BLOCK
++	select YAFFS_YAFFS1
++	select YAFFS_YAFFS2
++	help
++	  yaffs2, or Yet Another Flash File System, is a file system
++	  optimised for NAND Flash chips.
++
++	  To compile the yaffs2 file system support as a module, choose M
++	  here: the module will be called yaffs2.
++
++	  If unsure, say N.
++
++	  Further information on yaffs2 is available at
++	  <http://www.aleph1.co.uk/yaffs/>.
++
++config YAFFS_YAFFS1
++	bool "512 byte / page devices"
++	depends on YAFFS_FS
++	default y
++	help
++	  Enable yaffs1 support -- yaffs for 512 byte / page devices
++
++	  Not needed for 2K-page devices.
++
++	  If unsure, say Y.
++
++config YAFFS_9BYTE_TAGS
++	bool "Use older-style on-NAND data format with pageStatus byte"
++	depends on YAFFS_YAFFS1
++	default n
++	help
++
++	  Older-style on-NAND data format has a "pageStatus" byte to record
++	  chunk/page state.  This byte is zero when the page is discarded.
++	  Choose this option if you have existing on-NAND data using this
++	  format that you need to continue to support.  New data written
++	  also uses the older-style format.  Note: Use of this option
++	  generally requires that MTD's oob layout be adjusted to use the
++	  older-style format.  See notes on tags formats and MTD versions
++	  in yaffs_mtdif1.c.
++
++	  If unsure, say N.
++
++config YAFFS_DOES_ECC
++	bool "Lets yaffs do its own ECC"
++	depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
++	default n
++	help
++	  This enables yaffs to use its own ECC functions instead of using
++	  the ones from the generic MTD-NAND driver.
++
++	  If unsure, say N.
++
++config YAFFS_ECC_WRONG_ORDER
++	bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
++	depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
++	default n
++	help
++	  This makes yaffs_ecc.c use the same ecc byte order as Steven
++	  Hill's nand_ecc.c. If not set, then you get the same ecc byte
++	  order as SmartMedia.
++
++	  If unsure, say N.
++
++config YAFFS_YAFFS2
++	bool "2048 byte (or larger) / page devices"
++	depends on YAFFS_FS
++	default y
++	help
++	  Enable yaffs2 support -- yaffs for >= 2K bytes per page devices
++
++	  If unsure, say Y.
++
++config YAFFS_AUTO_YAFFS2
++	bool "Autoselect yaffs2 format"
++	depends on YAFFS_YAFFS2
++	default y
++	help
++	  Without this, you need to explicitely use yaffs2 as the file
++	  system type. With this, you can say "yaffs" and yaffs or yaffs2
++	  will be used depending on the device page size (yaffs on
++	  512-byte page devices, yaffs2 on 2K page devices).
++
++	  If unsure, say Y.
++
++config YAFFS_DISABLE_TAGS_ECC
++	bool "Disable yaffs from doing ECC on tags by default"
++	depends on YAFFS_FS && YAFFS_YAFFS2
++	default n
++	help
++	  This defaults yaffs to using its own ECC calculations on tags instead of
++	  just relying on the MTD.
++	  This behavior can also be overridden with tags_ecc_on and
++	  tags_ecc_off mount options.
++
++	  If unsure, say N.
++
++config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
++	bool "Force chunk erase check"
++	depends on YAFFS_FS
++	default n
++	help
++          Normally yaffs only checks chunks before writing until an erased
++	  chunk is found. This helps to detect any partially written
++	  chunks that might have happened due to power loss.
++
++	  Enabling this forces on the test that chunks are erased in flash
++	  before writing to them. This takes more time but is potentially
++	  a bit more secure.
++
++	  Suggest setting Y during development and ironing out driver
++	  issues etc. Suggest setting to N if you want faster writing.
++
++	  If unsure, say Y.
++
++config YAFFS_EMPTY_LOST_AND_FOUND
++	bool "Empty lost and found on boot"
++	depends on YAFFS_FS
++	default n
++	help
++	  If this is enabled then the contents of lost and found is
++	  automatically dumped at mount.
++
++	  If unsure, say N.
++
++config YAFFS_DISABLE_BLOCK_REFRESHING
++	bool "Disable yaffs2 block refreshing"
++	depends on YAFFS_FS
++	default n
++	help
++	 If this is set, then block refreshing is disabled.
++	 Block refreshing infrequently refreshes the oldest block in
++	 a yaffs2 file system. This mechanism helps to refresh flash to
++	 mitigate against data loss. This is particularly useful for MLC.
++
++	  If unsure, say N.
++
++config YAFFS_DISABLE_BACKGROUND
++	bool "Disable yaffs2 background processing"
++	depends on YAFFS_FS
++	default n
++	help
++	 If this is set, then background processing is disabled.
++	 Background processing makes many foreground activities faster.
++
++	 If unsure, say N.
++
++config YAFFS_DISABLE_BAD_BLOCK_MARKING
++	bool "Disable yaffs2 bad block marking"
++	depends on YAFFS_FS
++	default n
++	help
++	 Useful during early flash bring up to prevent problems causing
++	 lots of bad block marking.
++
++	 If unsure, say N.
++
++config YAFFS_XATTR
++	bool "Enable yaffs2 xattr support"
++	depends on YAFFS_FS
++	default y
++	help
++	 If this is set then yaffs2 will provide xattr support.
++	 If unsure, say Y.
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/Makefile linux-3.15-rc5/fs/yaffs2/Makefile
+--- linux-3.15-rc5.orig/fs/yaffs2/Makefile	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/Makefile	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,18 @@
++#
++# Makefile for the linux YAFFS filesystem routines.
++#
++
++obj-$(CONFIG_YAFFS_FS) += yaffs.o
++
++yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
++yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
++yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
++yaffs-y += yaffs_mtdif.o
++yaffs-y += yaffs_nameval.o yaffs_attribs.o
++yaffs-y += yaffs_allocator.o
++yaffs-y += yaffs_yaffs1.o
++yaffs-y += yaffs_yaffs2.o
++yaffs-y += yaffs_bitmap.o
++yaffs-y += yaffs_summary.o
++yaffs-y += yaffs_verify.o
++
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.c linux-3.15-rc5/fs/yaffs2/yaffs_allocator.c
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_allocator.c	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,357 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_allocator.h"
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++#include "yportenv.h"
++
++/*
++ * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
++ * of approx 100 objects that are themn allocated singly.
++ * This is basically a simplified slab allocator.
++ *
++ * We don't use the Linux slab allocator because slab does not allow
++ * us to dump all the objects in one hit when we do a umount and tear
++ * down  all the tnodes and objects. slab requires that we first free
++ * the individual objects.
++ *
++ * Once yaffs has been mainlined I shall try to motivate for a change
++ * to slab to provide the extra features we need here.
++ */
++
++struct yaffs_tnode_list {
++	struct yaffs_tnode_list *next;
++	struct yaffs_tnode *tnodes;
++};
++
++struct yaffs_obj_list {
++	struct yaffs_obj_list *next;
++	struct yaffs_obj *objects;
++};
++
++struct yaffs_allocator {
++	int n_tnodes_created;
++	struct yaffs_tnode *free_tnodes;
++	int n_free_tnodes;
++	struct yaffs_tnode_list *alloc_tnode_list;
++
++	int n_obj_created;
++	struct list_head free_objs;
++	int n_free_objects;
++
++	struct yaffs_obj_list *allocated_obj_list;
++};
++
++static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator =
++	    (struct yaffs_allocator *)dev->allocator;
++	struct yaffs_tnode_list *tmp;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	while (allocator->alloc_tnode_list) {
++		tmp = allocator->alloc_tnode_list->next;
++
++		kfree(allocator->alloc_tnode_list->tnodes);
++		kfree(allocator->alloc_tnode_list);
++		allocator->alloc_tnode_list = tmp;
++	}
++
++	allocator->free_tnodes = NULL;
++	allocator->n_free_tnodes = 0;
++	allocator->n_tnodes_created = 0;
++}
++
++static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	allocator->alloc_tnode_list = NULL;
++	allocator->free_tnodes = NULL;
++	allocator->n_free_tnodes = 0;
++	allocator->n_tnodes_created = 0;
++}
++
++static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
++{
++	struct yaffs_allocator *allocator =
++	    (struct yaffs_allocator *)dev->allocator;
++	int i;
++	struct yaffs_tnode *new_tnodes;
++	u8 *mem;
++	struct yaffs_tnode *curr;
++	struct yaffs_tnode *next;
++	struct yaffs_tnode_list *tnl;
++
++	if (!allocator) {
++		BUG();
++		return YAFFS_FAIL;
++	}
++
++	if (n_tnodes < 1)
++		return YAFFS_OK;
++
++	/* make these things */
++	new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
++	mem = (u8 *) new_tnodes;
++
++	if (!new_tnodes) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"yaffs: Could not allocate Tnodes");
++		return YAFFS_FAIL;
++	}
++
++	/* New hookup for wide tnodes */
++	for (i = 0; i < n_tnodes - 1; i++) {
++		curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
++		next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
++		curr->internal[0] = next;
++	}
++
++	curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
++	curr->internal[0] = allocator->free_tnodes;
++	allocator->free_tnodes = (struct yaffs_tnode *)mem;
++
++	allocator->n_free_tnodes += n_tnodes;
++	allocator->n_tnodes_created += n_tnodes;
++
++	/* Now add this bunch of tnodes to a list for freeing up.
++	 * NB If we can't add this to the management list it isn't fatal
++	 * but it just means we can't free this bunch of tnodes later.
++	 */
++	tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
++	if (!tnl) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"Could not add tnodes to management list");
++		return YAFFS_FAIL;
++	} else {
++		tnl->tnodes = new_tnodes;
++		tnl->next = allocator->alloc_tnode_list;
++		allocator->alloc_tnode_list = tnl;
++	}
++
++	yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
++
++	return YAFFS_OK;
++}
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator =
++	    (struct yaffs_allocator *)dev->allocator;
++	struct yaffs_tnode *tn = NULL;
++
++	if (!allocator) {
++		BUG();
++		return NULL;
++	}
++
++	/* If there are none left make more */
++	if (!allocator->free_tnodes)
++		yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
++
++	if (allocator->free_tnodes) {
++		tn = allocator->free_tnodes;
++		allocator->free_tnodes = allocator->free_tnodes->internal[0];
++		allocator->n_free_tnodes--;
++	}
++
++	return tn;
++}
++
++/* FreeTnode frees up a tnode and puts it back on the free list */
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	if (tn) {
++		tn->internal[0] = allocator->free_tnodes;
++		allocator->free_tnodes = tn;
++		allocator->n_free_tnodes++;
++	}
++	dev->checkpoint_blocks_required = 0;	/* force recalculation */
++}
++
++/*--------------- yaffs_obj alloaction ------------------------
++ *
++ * Free yaffs_objs are stored in a list using obj->siblings.
++ * The blocks of allocated objects are stored in a linked list.
++ */
++
++static void yaffs_init_raw_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	allocator->allocated_obj_list = NULL;
++	INIT_LIST_HEAD(&allocator->free_objs);
++	allocator->n_free_objects = 0;
++}
++
++static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++	struct yaffs_obj_list *tmp;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	while (allocator->allocated_obj_list) {
++		tmp = allocator->allocated_obj_list->next;
++		kfree(allocator->allocated_obj_list->objects);
++		kfree(allocator->allocated_obj_list);
++		allocator->allocated_obj_list = tmp;
++	}
++
++	INIT_LIST_HEAD(&allocator->free_objs);
++	allocator->n_free_objects = 0;
++	allocator->n_obj_created = 0;
++}
++
++static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
++{
++	struct yaffs_allocator *allocator = dev->allocator;
++	int i;
++	struct yaffs_obj *new_objs;
++	struct yaffs_obj_list *list;
++
++	if (!allocator) {
++		BUG();
++		return YAFFS_FAIL;
++	}
++
++	if (n_obj < 1)
++		return YAFFS_OK;
++
++	/* make these things */
++	new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
++	list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
++
++	if (!new_objs || !list) {
++		kfree(new_objs);
++		new_objs = NULL;
++		kfree(list);
++		list = NULL;
++		yaffs_trace(YAFFS_TRACE_ALLOCATE,
++			"Could not allocate more objects");
++		return YAFFS_FAIL;
++	}
++
++	/* Hook them into the free list */
++	for (i = 0; i < n_obj; i++)
++		list_add(&new_objs[i].siblings, &allocator->free_objs);
++
++	allocator->n_free_objects += n_obj;
++	allocator->n_obj_created += n_obj;
++
++	/* Now add this bunch of Objects to a list for freeing up. */
++
++	list->objects = new_objs;
++	list->next = allocator->allocated_obj_list;
++	allocator->allocated_obj_list = list;
++
++	return YAFFS_OK;
++}
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
++{
++	struct yaffs_obj *obj = NULL;
++	struct list_head *lh;
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return obj;
++	}
++
++	/* If there are none left make more */
++	if (list_empty(&allocator->free_objs))
++		yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
++
++	if (!list_empty(&allocator->free_objs)) {
++		lh = allocator->free_objs.next;
++		obj = list_entry(lh, struct yaffs_obj, siblings);
++		list_del_init(lh);
++		allocator->n_free_objects--;
++	}
++
++	return obj;
++}
++
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
++{
++
++	struct yaffs_allocator *allocator = dev->allocator;
++
++	if (!allocator) {
++		BUG();
++		return;
++	}
++
++	/* Link into the free list. */
++	list_add(&obj->siblings, &allocator->free_objs);
++	allocator->n_free_objects++;
++}
++
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++
++	if (!dev->allocator) {
++		BUG();
++		return;
++	}
++
++	yaffs_deinit_raw_tnodes(dev);
++	yaffs_deinit_raw_objs(dev);
++	kfree(dev->allocator);
++	dev->allocator = NULL;
++}
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
++{
++	struct yaffs_allocator *allocator;
++
++	if (dev->allocator) {
++		BUG();
++		return;
++	}
++
++	allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
++	if (allocator) {
++		dev->allocator = allocator;
++		yaffs_init_raw_tnodes(dev);
++		yaffs_init_raw_objs(dev);
++	}
++}
++
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.h linux-3.15-rc5/fs/yaffs2/yaffs_allocator.h
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_allocator.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_allocator.h	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,30 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ALLOCATOR_H__
++#define __YAFFS_ALLOCATOR_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
++void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
++
++struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
++void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
++
++struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
++void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
++
++#endif
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.c linux-3.15-rc5/fs/yaffs2/yaffs_attribs.c
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_attribs.c	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,166 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_guts.h"
++#include "yaffs_attribs.h"
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++	return from_kuid(&init_user_ns, iattr->ia_uid);
++}
++
++static inline gid_t ia_gid_read(const struct iattr *iattr)
++{
++	return from_kgid(&init_user_ns, iattr->ia_gid);
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++	iattr->ia_uid = make_kuid(&init_user_ns, uid);
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++	iattr->ia_gid = make_kgid(&init_user_ns, gid);
++}
++#else
++static inline uid_t ia_uid_read(const struct iattr *iattr)
++{
++	return iattr->ia_uid;
++}
++
++static inline gid_t ia_gid_read(const struct iattr *inode)
++{
++	return iattr->ia_gid;
++}
++
++static inline void ia_uid_write(struct iattr *iattr, uid_t uid)
++{
++	iattr->ia_uid = uid;
++}
++
++static inline void ia_gid_write(struct iattr *iattr, gid_t gid)
++{
++	iattr->ia_gid = gid;
++}
++#endif
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
++{
++	obj->yst_uid = oh->yst_uid;
++	obj->yst_gid = oh->yst_gid;
++	obj->yst_atime = oh->yst_atime;
++	obj->yst_mtime = oh->yst_mtime;
++	obj->yst_ctime = oh->yst_ctime;
++	obj->yst_rdev = oh->yst_rdev;
++}
++
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
++{
++	oh->yst_uid = obj->yst_uid;
++	oh->yst_gid = obj->yst_gid;
++	oh->yst_atime = obj->yst_atime;
++	oh->yst_mtime = obj->yst_mtime;
++	oh->yst_ctime = obj->yst_ctime;
++	oh->yst_rdev = obj->yst_rdev;
++
++}
++
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
++{
++	obj->yst_mtime = Y_CURRENT_TIME;
++	if (do_a)
++		obj->yst_atime = obj->yst_mtime;
++	if (do_c)
++		obj->yst_ctime = obj->yst_mtime;
++}
++
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
++{
++	yaffs_load_current_time(obj, 1, 1);
++	obj->yst_rdev = rdev;
++	obj->yst_uid = uid;
++	obj->yst_gid = gid;
++}
++
++static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
++{
++	YCHAR *alias = NULL;
++	obj = yaffs_get_equivalent_obj(obj);
++
++	switch (obj->variant_type) {
++	case YAFFS_OBJECT_TYPE_FILE:
++		return obj->variant.file_variant.file_size;
++	case YAFFS_OBJECT_TYPE_SYMLINK:
++		alias = obj->variant.symlink_variant.alias;
++		if (!alias)
++			return 0;
++		return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
++	default:
++		return 0;
++	}
++}
++
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++	unsigned int valid = attr->ia_valid;
++
++	if (valid & ATTR_MODE)
++		obj->yst_mode = attr->ia_mode;
++	if (valid & ATTR_UID)
++		obj->yst_uid =  ia_uid_read(attr);
++	if (valid & ATTR_GID)
++		obj->yst_gid =  ia_gid_read(attr);
++
++	if (valid & ATTR_ATIME)
++		obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
++	if (valid & ATTR_CTIME)
++		obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
++	if (valid & ATTR_MTIME)
++		obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
++
++	if (valid & ATTR_SIZE)
++		yaffs_resize_file(obj, attr->ia_size);
++
++	yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
++
++	return YAFFS_OK;
++
++}
++
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
++{
++	unsigned int valid = 0;
++
++	attr->ia_mode = obj->yst_mode;
++	valid |= ATTR_MODE;
++	ia_uid_write(attr, obj->yst_uid);
++	valid |= ATTR_UID;
++	ia_gid_write(attr, obj->yst_gid);
++	valid |= ATTR_GID;
++
++	Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
++	valid |= ATTR_ATIME;
++	Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
++	valid |= ATTR_CTIME;
++	Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
++	valid |= ATTR_MTIME;
++
++	attr->ia_size = yaffs_get_file_size(obj);
++	valid |= ATTR_SIZE;
++
++	attr->ia_valid = valid;
++
++	return YAFFS_OK;
++}
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.h linux-3.15-rc5/fs/yaffs2/yaffs_attribs.h
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_attribs.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_attribs.h	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_ATTRIBS_H__
++#define __YAFFS_ATTRIBS_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
++void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
++void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
++void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
++int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
++int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
++
++#endif
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.c linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.c
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.c	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_bitmap.h"
++#include "yaffs_trace.h"
++/*
++ * Chunk bitmap manipulations
++ */
++
++static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
++{
++	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"BlockBits block %d is not valid",
++			blk);
++		BUG();
++	}
++	return dev->chunk_bits +
++	    (dev->chunk_bit_stride * (blk - dev->internal_start_block));
++}
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
++{
++	if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
++	    chunk < 0 || chunk >= dev->param.chunks_per_block) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"Chunk Id (%d:%d) invalid",
++			blk, chunk);
++		BUG();
++	}
++}
++
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	memset(blk_bits, 0, dev->chunk_bit_stride);
++}
++
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	yaffs_verify_chunk_bit_id(dev, blk, chunk);
++	blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
++}
++
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	yaffs_verify_chunk_bit_id(dev, blk, chunk);
++	blk_bits[chunk / 8] |= (1 << (chunk & 7));
++}
++
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++
++	yaffs_verify_chunk_bit_id(dev, blk, chunk);
++	return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
++}
++
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++	int i;
++
++	for (i = 0; i < dev->chunk_bit_stride; i++) {
++		if (*blk_bits)
++			return 1;
++		blk_bits++;
++	}
++	return 0;
++}
++
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
++{
++	u8 *blk_bits = yaffs_block_bits(dev, blk);
++	int i;
++	int n = 0;
++
++	for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
++		n += hweight8(*blk_bits);
++
++	return n;
++}
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.h linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.h
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_bitmap.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_bitmap.h	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * Chunk bitmap manipulations
++ */
++
++#ifndef __YAFFS_BITMAP_H__
++#define __YAFFS_BITMAP_H__
++
++#include "yaffs_guts.h"
++
++void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
++void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
++int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
++int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
++
++#endif
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.c
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.c	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,474 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yaffs_checkptrw.h"
++#include "yaffs_getblockinfo.h"
++
++struct yaffs_checkpt_chunk_hdr {
++	int version;
++	int seq;
++	u32 sum;
++	u32 xor;
++} ;
++
++
++static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
++{
++	return chunk - dev->chunk_offset;
++}
++
++static int apply_block_offset(struct yaffs_dev *dev, int block)
++{
++	return block - dev->block_offset;
++}
++
++static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
++{
++	struct yaffs_checkpt_chunk_hdr hdr;
++
++	hdr.version = YAFFS_CHECKPOINT_VERSION;
++	hdr.seq = dev->checkpt_page_seq;
++	hdr.sum = dev->checkpt_sum;
++	hdr.xor = dev->checkpt_xor;
++
++	dev->checkpt_byte_offs = sizeof(hdr);
++
++	memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
++}
++
++static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
++{
++	struct yaffs_checkpt_chunk_hdr hdr;
++
++	memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
++
++	dev->checkpt_byte_offs = sizeof(hdr);
++
++	return hdr.version == YAFFS_CHECKPOINT_VERSION &&
++		hdr.seq == dev->checkpt_page_seq &&
++		hdr.sum == dev->checkpt_sum &&
++		hdr.xor == dev->checkpt_xor;
++}
++
++static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
++{
++	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checkpt blocks_avail = %d", blocks_avail);
++
++	return (blocks_avail <= 0) ? 0 : 1;
++}
++
++static int yaffs_checkpt_erase(struct yaffs_dev *dev)
++{
++	int i;
++
++	if (!dev->drv.drv_erase_fn)
++		return 0;
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checking blocks %d to %d",
++		dev->internal_start_block, dev->internal_end_block);
++
++	for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
++		struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
++		int offset_i = apply_block_offset(dev, i);
++		int result;
++
++		if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
++			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++			"erasing checkpt block %d", i);
++
++			dev->n_erasures++;
++
++			result = dev->drv.drv_erase_fn(dev, offset_i);
++			if(result) {
++				bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
++				dev->n_erased_blocks++;
++				dev->n_free_chunks +=
++				    dev->param.chunks_per_block;
++			} else {
++				dev->drv.drv_mark_bad_fn(dev, offset_i);
++				bi->block_state = YAFFS_BLOCK_STATE_DEAD;
++			}
++		}
++	}
++
++	dev->blocks_in_checkpt = 0;
++
++	return 1;
++}
++
++static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
++{
++	int i;
++	int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"allocating checkpt block: erased %d reserved %d avail %d next %d ",
++		dev->n_erased_blocks, dev->param.n_reserved_blocks,
++		blocks_avail, dev->checkpt_next_block);
++
++	if (dev->checkpt_next_block >= 0 &&
++	    dev->checkpt_next_block <= dev->internal_end_block &&
++	    blocks_avail > 0) {
++
++		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++		     i++) {
++			struct yaffs_block_info *bi;
++
++			bi = yaffs_get_block_info(dev, i);
++			if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
++				dev->checkpt_next_block = i + 1;
++				dev->checkpt_cur_block = i;
++				yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++					"allocating checkpt block %d", i);
++				return;
++			}
++		}
++	}
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
++
++	dev->checkpt_next_block = -1;
++	dev->checkpt_cur_block = -1;
++}
++
++static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
++{
++	int i;
++	struct yaffs_ext_tags tags;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"find next checkpt block: start:  blocks %d next %d",
++		dev->blocks_in_checkpt, dev->checkpt_next_block);
++
++	if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
++		for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
++		     i++) {
++			int chunk = i * dev->param.chunks_per_block;
++			enum yaffs_block_state state;
++			u32 seq;
++
++			dev->tagger.read_chunk_tags_fn(dev,
++					apply_chunk_offset(dev, chunk),
++					NULL, &tags);
++			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++				"find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
++				i, (int) state,
++				tags.obj_id, tags.seq_number,
++				tags.ecc_result);
++
++			if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
++				continue;
++
++			dev->tagger.query_block_fn(dev,
++						apply_block_offset(dev, i),
++						&state, &seq);
++			if (state == YAFFS_BLOCK_STATE_DEAD)
++				continue;
++
++			/* Right kind of block */
++			dev->checkpt_next_block = tags.obj_id;
++			dev->checkpt_cur_block = i;
++			dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
++			dev->blocks_in_checkpt++;
++			yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++				"found checkpt block %d", i);
++			return;
++		}
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
++
++	dev->checkpt_next_block = -1;
++	dev->checkpt_cur_block = -1;
++}
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
++{
++	int i;
++
++	dev->checkpt_open_write = writing;
++
++	/* Got the functions we need? */
++	if (!dev->tagger.write_chunk_tags_fn ||
++	    !dev->tagger.read_chunk_tags_fn ||
++	    !dev->drv.drv_erase_fn ||
++	    !dev->drv.drv_mark_bad_fn)
++		return 0;
++
++	if (writing && !yaffs2_checkpt_space_ok(dev))
++		return 0;
++
++	if (!dev->checkpt_buffer)
++		dev->checkpt_buffer =
++		    kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++	if (!dev->checkpt_buffer)
++		return 0;
++
++	dev->checkpt_page_seq = 0;
++	dev->checkpt_byte_count = 0;
++	dev->checkpt_sum = 0;
++	dev->checkpt_xor = 0;
++	dev->checkpt_cur_block = -1;
++	dev->checkpt_cur_chunk = -1;
++	dev->checkpt_next_block = dev->internal_start_block;
++
++	if (writing) {
++		memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++		yaffs2_checkpt_init_chunk_hdr(dev);
++		return yaffs_checkpt_erase(dev);
++	}
++
++	/* Opening for a read */
++	/* Set to a value that will kick off a read */
++	dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
++	/* A checkpoint block list of 1 checkpoint block per 16 block is
++	 * (hopefully) going to be way more than we need */
++	dev->blocks_in_checkpt = 0;
++	dev->checkpt_max_blocks =
++	    (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
++	dev->checkpt_block_list =
++	    kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
++
++	if (!dev->checkpt_block_list)
++		return 0;
++
++	for (i = 0; i < dev->checkpt_max_blocks; i++)
++		dev->checkpt_block_list[i] = -1;
++
++	return 1;
++}
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
++{
++	u32 composite_sum;
++
++	composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
++	*sum = composite_sum;
++	return 1;
++}
++
++static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
++{
++	int chunk;
++	int offset_chunk;
++	struct yaffs_ext_tags tags;
++
++	if (dev->checkpt_cur_block < 0) {
++		yaffs2_checkpt_find_erased_block(dev);
++		dev->checkpt_cur_chunk = 0;
++	}
++
++	if (dev->checkpt_cur_block < 0)
++		return 0;
++
++	tags.is_deleted = 0;
++	tags.obj_id = dev->checkpt_next_block;	/* Hint to next place to look */
++	tags.chunk_id = dev->checkpt_page_seq + 1;
++	tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
++	tags.n_bytes = dev->data_bytes_per_chunk;
++	if (dev->checkpt_cur_chunk == 0) {
++		/* First chunk we write for the block? Set block state to
++		   checkpoint */
++		struct yaffs_block_info *bi =
++		    yaffs_get_block_info(dev, dev->checkpt_cur_block);
++		bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++		dev->blocks_in_checkpt++;
++	}
++
++	chunk =
++	    dev->checkpt_cur_block * dev->param.chunks_per_block +
++	    dev->checkpt_cur_chunk;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
++		chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
++		tags.obj_id, tags.chunk_id);
++
++	offset_chunk = apply_chunk_offset(dev, chunk);
++
++	dev->n_page_writes++;
++
++	dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
++				       dev->checkpt_buffer, &tags);
++	dev->checkpt_page_seq++;
++	dev->checkpt_cur_chunk++;
++	if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
++		dev->checkpt_cur_chunk = 0;
++		dev->checkpt_cur_block = -1;
++	}
++	memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
++
++	yaffs2_checkpt_init_chunk_hdr(dev);
++
++
++	return 1;
++}
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
++{
++	int i = 0;
++	int ok = 1;
++	u8 *data_bytes = (u8 *) data;
++
++	if (!dev->checkpt_buffer)
++		return 0;
++
++	if (!dev->checkpt_open_write)
++		return -1;
++
++	while (i < n_bytes && ok) {
++		dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
++		dev->checkpt_sum += *data_bytes;
++		dev->checkpt_xor ^= *data_bytes;
++
++		dev->checkpt_byte_offs++;
++		i++;
++		data_bytes++;
++		dev->checkpt_byte_count++;
++
++		if (dev->checkpt_byte_offs < 0 ||
++		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
++			ok = yaffs2_checkpt_flush_buffer(dev);
++	}
++
++	return i;
++}
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
++{
++	int i = 0;
++	int ok = 1;
++	struct yaffs_ext_tags tags;
++	int chunk;
++	int offset_chunk;
++	u8 *data_bytes = (u8 *) data;
++
++	if (!dev->checkpt_buffer)
++		return 0;
++
++	if (dev->checkpt_open_write)
++		return -1;
++
++	while (i < n_bytes && ok) {
++
++		if (dev->checkpt_byte_offs < 0 ||
++		    dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
++
++			if (dev->checkpt_cur_block < 0) {
++				yaffs2_checkpt_find_block(dev);
++				dev->checkpt_cur_chunk = 0;
++			}
++
++			if (dev->checkpt_cur_block < 0) {
++				ok = 0;
++				break;
++			}
++
++			chunk = dev->checkpt_cur_block *
++			    dev->param.chunks_per_block +
++			    dev->checkpt_cur_chunk;
++
++			offset_chunk = apply_chunk_offset(dev, chunk);
++			dev->n_page_reads++;
++
++			/* read in the next chunk */
++			dev->tagger.read_chunk_tags_fn(dev,
++						offset_chunk,
++						dev->checkpt_buffer,
++						&tags);
++
++			if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
++			    tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
++			    tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) {
++				ok = 0;
++				break;
++			}
++			if(!yaffs2_checkpt_check_chunk_hdr(dev)) {
++				ok = 0;
++				break;
++			}
++
++			dev->checkpt_page_seq++;
++			dev->checkpt_cur_chunk++;
++
++			if (dev->checkpt_cur_chunk >=
++					dev->param.chunks_per_block)
++				dev->checkpt_cur_block = -1;
++
++		}
++
++		*data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
++		dev->checkpt_sum += *data_bytes;
++		dev->checkpt_xor ^= *data_bytes;
++		dev->checkpt_byte_offs++;
++		i++;
++		data_bytes++;
++		dev->checkpt_byte_count++;
++	}
++
++	return i;
++}
++
++int yaffs_checkpt_close(struct yaffs_dev *dev)
++{
++	int i;
++
++	if (dev->checkpt_open_write) {
++		if (dev->checkpt_byte_offs !=
++			sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
++			yaffs2_checkpt_flush_buffer(dev);
++	} else if (dev->checkpt_block_list) {
++		for (i = 0;
++		     i < dev->blocks_in_checkpt &&
++		     dev->checkpt_block_list[i] >= 0; i++) {
++			int blk = dev->checkpt_block_list[i];
++			struct yaffs_block_info *bi = NULL;
++
++			if (dev->internal_start_block <= blk &&
++			    blk <= dev->internal_end_block)
++				bi = yaffs_get_block_info(dev, blk);
++			if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
++				bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
++		}
++		kfree(dev->checkpt_block_list);
++		dev->checkpt_block_list = NULL;
++	}
++
++	dev->n_free_chunks -=
++		dev->blocks_in_checkpt * dev->param.chunks_per_block;
++	dev->n_erased_blocks -= dev->blocks_in_checkpt;
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
++		dev->checkpt_byte_count);
++
++	if (dev->checkpt_buffer) {
++		/* free the buffer */
++		kfree(dev->checkpt_buffer);
++		dev->checkpt_buffer = NULL;
++		return 1;
++	} else {
++		return 0;
++	}
++}
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
++{
++	/* Erase the checkpoint data */
++
++	yaffs_trace(YAFFS_TRACE_CHECKPOINT,
++		"checkpoint invalidate of %d blocks",
++		dev->blocks_in_checkpt);
++
++	return yaffs_checkpt_erase(dev);
++}
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.h
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_checkptrw.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_checkptrw.h	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_CHECKPTRW_H__
++#define __YAFFS_CHECKPTRW_H__
++
++#include "yaffs_guts.h"
++
++int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
++
++int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
++
++int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
++
++int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
++
++int yaffs_checkpt_close(struct yaffs_dev *dev);
++
++int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
++
++#endif
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.c linux-3.15-rc5/fs/yaffs2/yaffs_ecc.c
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_ecc.c	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,281 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
++ * such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#include "yportenv.h"
++
++#include "yaffs_ecc.h"
++
++/* Table generated by gen-ecc.c
++ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
++ * for each byte of data. These are instead provided in a table in bits7..2.
++ * Bit 0 of each entry indicates whether the entry has an odd or even parity,
++ * and therefore this bytes influence on the line parity.
++ */
++
++static const unsigned char column_parity_table[] = {
++	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
++	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
++	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
++	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
++	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
++	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
++	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
++	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
++	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
++	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
++	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
++	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
++	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
++	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
++	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
++	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
++};
++
++
++/* Calculate the ECC for a 256-byte block of data */
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
++{
++	unsigned int i;
++	unsigned char col_parity = 0;
++	unsigned char line_parity = 0;
++	unsigned char line_parity_prime = 0;
++	unsigned char t;
++	unsigned char b;
++
++	for (i = 0; i < 256; i++) {
++		b = column_parity_table[*data++];
++		col_parity ^= b;
++
++		if (b & 0x01) {	/* odd number of bits in the byte */
++			line_parity ^= i;
++			line_parity_prime ^= ~i;
++		}
++	}
++
++	ecc[2] = (~col_parity) | 0x03;
++
++	t = 0;
++	if (line_parity & 0x80)
++		t |= 0x80;
++	if (line_parity_prime & 0x80)
++		t |= 0x40;
++	if (line_parity & 0x40)
++		t |= 0x20;
++	if (line_parity_prime & 0x40)
++		t |= 0x10;
++	if (line_parity & 0x20)
++		t |= 0x08;
++	if (line_parity_prime & 0x20)
++		t |= 0x04;
++	if (line_parity & 0x10)
++		t |= 0x02;
++	if (line_parity_prime & 0x10)
++		t |= 0x01;
++	ecc[1] = ~t;
++
++	t = 0;
++	if (line_parity & 0x08)
++		t |= 0x80;
++	if (line_parity_prime & 0x08)
++		t |= 0x40;
++	if (line_parity & 0x04)
++		t |= 0x20;
++	if (line_parity_prime & 0x04)
++		t |= 0x10;
++	if (line_parity & 0x02)
++		t |= 0x08;
++	if (line_parity_prime & 0x02)
++		t |= 0x04;
++	if (line_parity & 0x01)
++		t |= 0x02;
++	if (line_parity_prime & 0x01)
++		t |= 0x01;
++	ecc[0] = ~t;
++
++}
++
++/* Correct the ECC on a 256 byte block of data */
++
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++		      const unsigned char *test_ecc)
++{
++	unsigned char d0, d1, d2;	/* deltas */
++
++	d0 = read_ecc[0] ^ test_ecc[0];
++	d1 = read_ecc[1] ^ test_ecc[1];
++	d2 = read_ecc[2] ^ test_ecc[2];
++
++	if ((d0 | d1 | d2) == 0)
++		return 0;	/* no error */
++
++	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
++	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
++	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
++		/* Single bit (recoverable) error in data */
++
++		unsigned byte;
++		unsigned bit;
++
++		bit = byte = 0;
++
++		if (d1 & 0x80)
++			byte |= 0x80;
++		if (d1 & 0x20)
++			byte |= 0x40;
++		if (d1 & 0x08)
++			byte |= 0x20;
++		if (d1 & 0x02)
++			byte |= 0x10;
++		if (d0 & 0x80)
++			byte |= 0x08;
++		if (d0 & 0x20)
++			byte |= 0x04;
++		if (d0 & 0x08)
++			byte |= 0x02;
++		if (d0 & 0x02)
++			byte |= 0x01;
++
++		if (d2 & 0x80)
++			bit |= 0x04;
++		if (d2 & 0x20)
++			bit |= 0x02;
++		if (d2 & 0x08)
++			bit |= 0x01;
++
++		data[byte] ^= (1 << bit);
++
++		return 1;	/* Corrected the error */
++	}
++
++	if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
++		/* Reccoverable error in ecc */
++
++		read_ecc[0] = test_ecc[0];
++		read_ecc[1] = test_ecc[1];
++		read_ecc[2] = test_ecc[2];
++
++		return 1;	/* Corrected the error */
++	}
++
++	/* Unrecoverable error */
++
++	return -1;
++
++}
++
++/*
++ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
++ */
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++			  struct yaffs_ecc_other *ecc_other)
++{
++	unsigned int i;
++	unsigned char col_parity = 0;
++	unsigned line_parity = 0;
++	unsigned line_parity_prime = 0;
++	unsigned char b;
++
++	for (i = 0; i < n_bytes; i++) {
++		b = column_parity_table[*data++];
++		col_parity ^= b;
++
++		if (b & 0x01) {
++			/* odd number of bits in the byte */
++			line_parity ^= i;
++			line_parity_prime ^= ~i;
++		}
++
++	}
++
++	ecc_other->col_parity = (col_parity >> 2) & 0x3f;
++	ecc_other->line_parity = line_parity;
++	ecc_other->line_parity_prime = line_parity_prime;
++}
++
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++			    struct yaffs_ecc_other *read_ecc,
++			    const struct yaffs_ecc_other *test_ecc)
++{
++	unsigned char delta_col;	/* column parity delta */
++	unsigned delta_line;	/* line parity delta */
++	unsigned delta_line_prime;	/* line parity delta */
++	unsigned bit;
++
++	delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
++	delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
++	delta_line_prime =
++	    read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
++
++	if ((delta_col | delta_line | delta_line_prime) == 0)
++		return 0;	/* no error */
++
++	if (delta_line == ~delta_line_prime &&
++	    (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
++		/* Single bit (recoverable) error in data */
++
++		bit = 0;
++
++		if (delta_col & 0x20)
++			bit |= 0x04;
++		if (delta_col & 0x08)
++			bit |= 0x02;
++		if (delta_col & 0x02)
++			bit |= 0x01;
++
++		if (delta_line >= n_bytes)
++			return -1;
++
++		data[delta_line] ^= (1 << bit);
++
++		return 1;	/* corrected */
++	}
++
++	if ((hweight32(delta_line) +
++	     hweight32(delta_line_prime) +
++	     hweight8(delta_col)) == 1) {
++		/* Reccoverable error in ecc */
++
++		*read_ecc = *test_ecc;
++		return 1;	/* corrected */
++	}
++
++	/* Unrecoverable error */
++
++	return -1;
++}
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.h linux-3.15-rc5/fs/yaffs2/yaffs_ecc.h
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_ecc.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_ecc.h	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++/*
++ * This code implements the ECC algorithm used in SmartMedia.
++ *
++ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
++ * The two unused bit are set to 1.
++ * The ECC can correct single bit errors in a 256-byte page of data.
++ * Thus, two such ECC blocks are used on a 512-byte NAND page.
++ *
++ */
++
++#ifndef __YAFFS_ECC_H__
++#define __YAFFS_ECC_H__
++
++struct yaffs_ecc_other {
++	unsigned char col_parity;
++	unsigned line_parity;
++	unsigned line_parity_prime;
++};
++
++void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
++int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
++		      const unsigned char *test_ecc);
++
++void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
++			  struct yaffs_ecc_other *ecc);
++int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
++			    struct yaffs_ecc_other *read_ecc,
++			    const struct yaffs_ecc_other *test_ecc);
++#endif
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.15-rc5/fs/yaffs2/yaffs_getblockinfo.h
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_getblockinfo.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_getblockinfo.h	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,35 @@
++/*
++ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1 as
++ * published by the Free Software Foundation.
++ *
++ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
++ */
++
++#ifndef __YAFFS_GETBLOCKINFO_H__
++#define __YAFFS_GETBLOCKINFO_H__
++
++#include "yaffs_guts.h"
++#include "yaffs_trace.h"
++
++/* Function to manipulate block info */
++static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
++							      *dev, int blk)
++{
++	if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
++		yaffs_trace(YAFFS_TRACE_ERROR,
++			"**>> yaffs: get_block_info block %d is not valid",
++			blk);
++		BUG();
++	}
++	return &dev->block_info[blk - dev->internal_start_block];
++}
++
++#endif
+diff -Nur linux-3.15-rc5.orig/fs/yaffs2/yaffs_guts.c linux-3.15-rc5/fs/yaffs2/yaffs_guts.c
+--- linux-3.15-rc5.orig/fs/yaffs2/yaffs_guts.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-3.15-rc5/fs/yaffs2/yaffs_guts.c	2014-05-17 01:53:27.000000000 +0200
+@@ -0,0 +1,5146 @@
++/*
++ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
++ *
++ * Copyright (C) 2002-2011 Aleph One Ltd.
++ *   for Toby Churchill Ltd and Brightstar Engineering
++ *
++ * Created by Charles Manning <charles@aleph1.co.uk>
++ *
++ * 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 "yportenv.h"
++#include "yaffs_trace.h"
++
++#include "yaffs_guts.h"
++#include "yaffs_getblockinfo.h"
++#include "yaffs_tagscompat.h"
++#include "yaffs_tagsmarshall.h"
++#include "yaffs_nand.h"
++#include "yaffs_yaffs1.h"
++#include "yaffs_yaffs2.h"
++#include "yaffs_bitmap.h"
++#include "yaffs_verify.h"
++#include "yaffs_nand.h"
++#include "yaffs_packedtags2.h"
++#include "yaffs_nameval.h"
++#include "yaffs_allocator.h"
++#include "yaffs_attribs.h"
++#include "yaffs_summary.h"
++
++/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
++#define YAFFS_GC_GOOD_ENOUGH 2
++#define YAFFS_GC_PASSIVE_THRESHOLD 4
++
++#include "yaffs_ecc.h"
++
++/* Forward declarations */
++
++static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
++			     const u8 *buffer, int n_bytes, int use_reserve);
++
++static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
++				int buffer_size);
++
++/* Function to calculate chunk and offset */
++
++void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
++				int *chunk_out, u32 *offset_out)
++{
++	int chunk;
++	u32 offset;
++
++	chunk = (u32) (addr >> dev->chunk_shift);
++
++	if (dev->chunk_div == 1) {
++		/* easy power of 2 case */
++		offset = (u32) (addr & dev->chunk_mask);
++	} else {
++		/* Non power-of-2 case */
++
++		loff_t chunk_base;
++
++		chunk /= dev->chunk_div;
++
++		chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
++		offset = (u32) (addr - chunk_base);
++	}
++
++	*chunk_out = chunk;
++	*offset_out = offset;
++}
++
++/* Function to return the number of shifts for a power of 2 greater than or
++ * equal to the given number
++ * Note we don't try to cater for all possible numbers and this does not have to
++ * be hellishly efficient.
++ */
++
++static inline u32 calc_shifts_ceiling(u32 x)
++{
++	int extra_bits;
++	int shifts;
++
++	shifts = extra_bits = 0;
++
++	while (x > 1) {
++		if (x & 1)
++			extra_bits++;
++		x >>= 1;
++		shifts++;
++	}
++
++	if (extra_bits)
++		shifts++;
++
++	return shifts;
++}
++
++/* Function to return the number of shifts to get a 1 in bit 0
++ */
++
++static inline u32 calc_shifts(u32 x)
++{
++	u32 shifts;
++
++	shifts = 0;
++
++	if (!x)
++		return 0;
++
++	while (!(x & 1)) {
++		x >>= 1;
++		shifts++;
++	}
++
++	return shifts;
++}
++
++/*
++ * Temporary buffer manipulations.
++ */
++
++static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
++{
++	int i;
++	u8 *buf = (u8 *) 1;
++
++	memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
++
++	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
++		dev->temp_buffer[i].in_use = 0;
++		buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
++		dev->temp_buffer[i].buffer = buf;
++	}
++
++	return buf ? YAFFS_OK : YAFFS_FAIL;
++}
++
++u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
++{
++	int i;
++
++	dev->temp_in_use++;
++	if (dev->temp_in_use > dev->max_temp)
++		dev->max_temp = dev->temp_in_use;
++
++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++		if (dev->temp_buffer[i].in_use == 0) {
++			dev->temp_buffer[i].in_use = 1;
++			return dev->temp_buffer[i].buffer;
++		}
++	}
++
++	yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
++	/*
++	 * If we got here then we have to allocate an unmanaged one
++	 * This is not good.
++	 */
++
++	dev->unmanaged_buffer_allocs++;
++	return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
++
++}
++
++void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
++{
++	int i;
++
++	dev->temp_in_use--;
++
++	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
++		if (dev->temp_buffer[i].buffer == buffer) {
++			dev->temp_buffer[i].in_use = 0;
++			return;
++		}
++	}
++
++	if (buffer) {
++		/* assume it is an unmanaged one. */
++		yaffs_trace(YAFFS_TRACE_BUFFERS,
++			"Releasing unmanaged temp buffer");
++		kfree(buffer);
++		dev->unmanaged_buffer_deallocs++;
++	}
++
++}
++
++/*
++ * Functions for robustisizing TODO
++ *
++ */
++
++static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
++				     const u8 *data,
++				     const struct yaffs_ext_tags *tags)
++{
++	(void) dev;
++	(void) nand_chunk;
++	(void) data;
++	(void) tags;
++}
++
++static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
++				      const struct yaffs_ext_tags *tags)
++{
++	(void) dev;
++	(void) nand_chunk;
++	(void) tags;
++}
++
++void yaffs_handle_chunk_error(struct yaffs_dev *dev,
++			      struct yaffs_block_info *bi)
++{
++	if (!bi->gc_prioritise) {
++		bi->gc_prioritise = 1;
++		dev->has_pending_prioritised_gc = 1;
++		bi->chunk_error_strikes++;
++
++		if (bi->chunk_error_strikes > 3) {
++			bi->needs_retiring = 1;	/* Too many stikes, so retire */
++			yaffs_trace(YAFFS_TRACE_ALWAYS,
++				"yaffs: Block struck out");
++
++		}
++	}
++}
++
++static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
++					int erased_ok)
++{
++	int flash_block = nand_chunk / dev->param.chunks_per_block;
++	struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
++
++	yaffs_handle_chunk_error(dev, bi);
++
++	if (erased_ok) {
++		/* Was an actual write failure,
++		 * so mark the block for retirement.*/
++		bi->needs_retiring = 1;
++		yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
++		  "**>> Block %d needs retiring", flash_block);
++	}
++
++	/* Delete the chunk */
++	yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
++	yaffs_skip_rest_of_block(dev);
++}
++
++/*
++ * Verification code
++ */
++
++/*
++ *  Simple hash function. Needs to have a reasonable spread
++ */
++
++static inline int yaffs_hash_fn(int n)
++{
++	if (n < 0)
++		n = -n;
++	return n % YAFFS_NOBJECT_BUCKETS;
++}
++
++/*
++ * Access functions to useful fake objects.
++ * Note that root might have a presence in NAND if permissions are set.
++ */
++
++struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
++{
++	return dev->root_dir;
++}
++
++struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
++{
++	return dev->lost_n_found;
++}
++
++/*
++ *  Erased NAND checking functions
++ */
++
++int yaffs_check_ff(u8 *buffer, int n_bytes)
++{
++	/* Horrible, slow implementation */
++	while (n_bytes--) {
++		if (*buffer != 0xff)
++			return 0;
++		buffer++;
++	}
++	return 1;
++}
++
++static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
++{
++	int retval = YAFFS_OK;
++	u8 *data = yaffs_get_temp_buffer(dev);
++	struct yaffs_ext_tags tags;
++	int result;
++
++	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
++
++	if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
++		retval = YAFFS_FAIL;
++
++	if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
++		tags.chunk_used) {
++		yaffs_trace(YAFFS_TRACE_NANDACCESS,
++			"Chunk %d not erased", nand_chunk);
++		retval = YAFFS_FAIL;
++	}
++
++	yaffs_release_temp_buffer(dev, data);
++
++	return retval;
++
++}
++
++static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
++				      int nand_chunk,
++				      const u8 *data,
++				      struct yaffs_ext_tags *tags)
++{
++	int retval = YAFFS_OK;
++	struct yaffs_ext_tags temp_tags;
++	u8 *buffer = yaffs_get_temp_buffer(dev);
++	int result;
++
++	result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
++	if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
++	    temp_tags.obj_id != tags->obj_id ||
++	    temp_tags.chunk_id != tags->chunk_id ||
++	    temp_tags.n_bytes != tags->n_bytes)
++		retval = YAFFS_FAIL;
++
++	yaffs_release_temp_buffer(dev, buffer);
++
++	return retval;
++}
++
++
++int yaffs_check_alloc_available(struct