Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1473080 > unrolled thread

[PATCH 00/46] Nandsim facelift (part I of II)

Started byDaniel Walter <dwalter@sigma-star.at>
First post2016-08-31 09:30 +0200
Last post2016-08-31 09:40 +0200
Articles 20 on this page of 45 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH 00/46] Nandsim facelift (part I of II) Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:30 +0200
    [PATCH 10/46] mtd: nandsim: Add helper functions for pointer magic Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:30 +0200
    [PATCH 02/46] mtd: nand: TODO Propagate mtd_device_unregister() return value in tear down Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:30 +0200
    [PATCH 07/46] mtd: nandsim: Begin with removal of global state Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:30 +0200
    [PATCH 03/46] mtd: Don't unconditionally unregister reboot notifier Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:30 +0200
    [PATCH 45/46] mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 06/46] mtd: nandsim: Add basic control file support Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 43/46] mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 15/46] mtd: nandsim: Introduce backend operations Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 09/46] mtd: nandsim: Don't directly use module parameters Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 01/46] mtdpart: Propagate _get/put_device() Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 27/46] mtd: nandsim: Add no_oob mode Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 14/46] mtd: nandsim: Add simulator id to MTD parition name Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 44/46] mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 11/46] mtd: nandsim: Factor out nandsim parameters Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 33/46] mtd: nandsim: Relax page size restrictions Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 38/46] mtd: nandsim: Expose partition creation logic to user space Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 24/46] mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 39/46] mtd: nandsim: Rework init error paths Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 18/46] mtd: nandsim: Add basic support for a file backend Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 08/46] mtd: nandsim: Kill global nsmtd Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 40/46] mtd: nandsim: Expose BBT, delays, etc.. to userspace Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 17/46] mtd: nandsim: Allow external backends Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 46/46] mtd/nandsim: Add ioctl for info Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 36/46] mtd: nandsim: Cleanup constants Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 42/46] mtd: nandsim: Don't printk on ENOMEM Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 19/46] mtd: nandsim: UAPI v1 Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 20/46] mtd: nandsim: Implement preliminary constructor function Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 12/46] mtd: nandsim: Make debugfs logic multi instance capable Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 04/46] mtd: Don't unconditionally execute remove notifiers Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 22/46] mtd: nandsim: Cleanup destroy handlers Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 25/46] mtd: nandsim: Print backend name Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 28/46] mtd: nandsim: Refine exports Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 31/46] mtd: nandsim: Remove NS_RAW_OFFSET_OOB Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 21/46] mtd: nandsim: Implement preliminary destructor function Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 26/46] mtd: nandsim: use the existing output macros Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 37/46] mtd: nandsim: Turn parts[] into a integer Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 41/46] mtd: nandsim: Expose support for weakpages/blocks to userspace Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 23/46] mtd: nandsim: Unify file backend init logic Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 35/46] mtd: nandsim: Make NANDSIM_MAX_DEVICES part of uapi Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 32/46] mtd: nandsim: Remove NS_IS_INITIALIZED Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 29/46] um: Add nandsim backend driver Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 34/46] mtd: nandsim: Support bitflip and read error emulation in file backend Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 05/46] mtd: Don't print a scary message when trying to remove a busy MTD Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200
    [PATCH 13/46] mtd: nandsim: Add final logic for multiple instances Daniel Walter <dwalter@sigma-star.at> - 2016-08-31 09:40 +0200

Page 1 of 3  [1] 2 3  Next page →


#1473080 — [PATCH 00/46] Nandsim facelift (part I of II)

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:30 +0200
Subject[PATCH 00/46] Nandsim facelift (part I of II)
Message-ID<sc889-7Pb-1@gated-at.bofh.it>
Over a decade ago nandsim was introduced to Linux. The main purpose is having a software implementation of a NAND chip for rapid prototyping systems such as UBI on top of it. On
the other hand is it also heavily used to load and inspect dumps from real NAND flashes. The current design allows only having a single chip and all parameters are passed as
modules parameters. Another draw back is that it emulates all NAND chip internals including command parsing, this makes it slow and error prone wrt. changes in nand_base.c since
the emulated chip is not really ONFI compliant.

This series addresses the singleton property of nandsim. It allows having multiple instances which can be controlled by a new userspace tool, nandsimctl. Nandsimctl works like
losetup. You can add and remove instances with different settings.
To allow multiple instances nandsim offers an ioctl() interface via a new device file, /dev/nandsimctl, to userspace.

Currently nandsim has two backends, ram and cache. In the default backend mode, ram, all data you change is stored in main memory. For smaller chips this works well but becomes
problematic when modern multi-gigabyte chips are emulated. Cache mode addresses this drawback and redirects program commands to a local file. Using the cache_file module parameter
the path of the backing file can be set. When nandsim is not a module passing a file name to it can lead to unexpected behavior since during kernel bootup the real root filesystem
might not be ready and nandsim will populate the cache file on the initial root filesysem which is either tmpfs or worse a ramfs.

Via the new ioctl() interface a third backend mode can be used, file mode. File mode works like cache file but all data (including erases and OOB data) are stored on a local file.
This file can also also be reused later. It is also possible to operate nandsim in a mode to omit existing OOB data and masquerade OOB bytes to 0xFF. This allows using a nanddump
(without OOB) from a real NAND chip directly in nandsim using the file backend. That way you don't have to use nandwrite or other tools to write the dump into yout MTD before using
it. You can directly attach the dump in a losetup alike way.

The ioctl() accepts all existing nandsim parameters except that in cache mode you pass a file descriptor instead of a file name to nandsim. This allows utilizing O_TMPFILE.
To preserve existing behavior and no breaking any users of nandsim it is still possible to specify all parameters using module parameters but these parameters will only affect the
first nandsim instance which will be automatically created upon module loading. If you don't have to have a default instance and explicitly create nandsim instances using
nandsimctl pass defaults=n to the module.

There will be an additional patch series for mtd-utils containing nandsimctl.

A side effect of heavily reworking nandsim's backend internals it is now also possible to create custom backends. A custom backed was added to UserModeLinux. It allows directly
booting from a nanddump using UML such that UBIFS as rootfs can be tested nicely on virtual machines.
On step ahead for MTD testing.

The series itself is less straight forward than I wanted it to be, mostly because while adding new features it was needed to cleanup some parts, over and over.

Part II of that series will address the chip emulation nature of nandsim. It will add a second emulation mode. By default NAND chip emulation will be used but to allow arbitrary
sized MTDs a more simple mode will be added which just allocates a MTD with the expected sizes instead of mocking nand_base.c.



Daniel Walter (1):
  mtd/nandsim: Add ioctl for info

Mathias Kresin (1):
  mtd: nandsim: use the existing output macros

Richard Weinberger (44):
  mtdpart: Propagate _get/put_device()
  mtd: nand: TODO Propagate mtd_device_unregister() return value in tear
    down
  mtd: Don't unconditionally unregister reboot notifier
  mtd: Don't unconditionally execute remove notifiers
  mtd: Don't print a scary message when trying to remove a busy MTD
  mtd: nandsim: Add basic control file support
  mtd: nandsim: Begin with removal of global state
  mtd: nandsim: Kill global nsmtd
  mtd: nandsim: Don't directly use module parameters
  mtd: nandsim: Add helper functions for pointer magic
  mtd: nandsim: Factor out nandsim parameters
  mtd: nandsim: Make debugfs logic multi instance capable
  mtd: nandsim: Add final logic for multiple instances
  mtd: nandsim: Add simulator id to MTD parition name
  mtd: nandsim: Introduce backend operations
  mtd: nandsim: Print error when backend init failed
  mtd: nandsim: Allow external backends
  mtd: nandsim: Add basic support for a file backend
  mtd: nandsim: UAPI v1
  mtd: nandsim: Implement preliminary constructor function
  mtd: nandsim: Implement preliminary destructor function
  mtd: nandsim: Cleanup destroy handlers
  mtd: nandsim: Unify file backend init logic
  mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode
  mtd: nandsim: Print backend name
  mtd: nandsim: Add no_oob mode
  mtd: nandsim: Refine exports
  um: Add nandsim backend driver
  mtd: nandsim: Use pr_ style logging
  mtd: nandsim: Remove NS_RAW_OFFSET_OOB
  mtd: nandsim: Remove NS_IS_INITIALIZED
  mtd: nandsim: Relax page size restrictions
  mtd: nandsim: Support bitflip and read error emulation in file backend
  mtd: nandsim: Make NANDSIM_MAX_DEVICES part of uapi
  mtd: nandsim: Cleanup constants
  mtd: nandsim: Turn parts[] into a integer
  mtd: nandsim: Expose partition creation logic to user space
  mtd: nandsim: Rework init error paths
  mtd: nandsim: Expose BBT, delays, etc.. to userspace
  mtd: nandsim: Expose support for weakpages/blocks to userspace
  mtd: nandsim: Don't printk on ENOMEM
  mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE
  mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE
  mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID

 arch/um/Kconfig.um              |    6 +
 arch/um/drivers/Makefile        |    2 +
 arch/um/drivers/nand_kern.c     |  159 +++
 drivers/mtd/mtdcore.c           |   28 +-
 drivers/mtd/mtdpart.c           |   18 +
 drivers/mtd/nand/nand_base.c    |   15 +-
 drivers/mtd/nand/nandsim.c      | 2138 ++++++++++++++++++++++++++++-----------
 include/linux/mtd/nand.h        |   12 +-
 include/linux/mtd/nandsim.h     |   79 ++
 include/uapi/mtd/nandsim-user.h |  113 +++
 10 files changed, 1966 insertions(+), 604 deletions(-)
 create mode 100644 arch/um/drivers/nand_kern.c
 create mode 100644 include/linux/mtd/nandsim.h
 create mode 100644 include/uapi/mtd/nandsim-user.h

-- 
2.8.3

[toc] | [next] | [standalone]


#1473081 — [PATCH 10/46] mtd: nandsim: Add helper functions for pointer magic

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:30 +0200
Subject[PATCH 10/46] mtd: nandsim: Add helper functions for pointer magic
Message-ID<sc889-7Pb-7@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index fda670b..f26e983 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -461,6 +461,18 @@ struct grave_page {
 /* MTD structure for NAND controller */
 static struct mtd_info *ns_mtds[NS_MAX_DEVICES];
 
+static inline struct nandsim *chip_to_ns(struct nand_chip *chip)
+{
+	return (struct nandsim *)(chip + 1);
+}
+
+static inline struct mtd_info *ns_to_mtd(struct nandsim *ns)
+{
+	struct nand_chip *chip = ((struct nand_chip *)ns - 1);
+
+	return nand_to_mtd(chip);
+}
+
 static int nandsim_debugfs_show(struct seq_file *m, void *private)
 {
 	struct nandsim *ns = (struct nandsim *)m->private;
@@ -1462,8 +1474,7 @@ static int do_read_error(struct nandsim *ns, int num)
 
 static void do_bit_flips(struct nandsim *ns, int num)
 {
-	struct nand_chip *chip = ((struct nand_chip *)ns - 1);
-	struct mtd_info *nsmtd = nand_to_mtd(chip);
+	struct mtd_info *nsmtd = ns_to_mtd(ns);
 
 	if (ns->bitflips && prandom_u32() < (1 << 22)) {
 		int flips = 1;
@@ -2300,7 +2311,7 @@ static int __init ns_init_default(void)
 
 	WARN_ON(ns_mtds[0]);
 	nsmtd = ns_mtds[0] = nand_to_mtd(chip);
-	nand = (struct nandsim *)(chip + 1);
+	nand = chip_to_ns(chip);
 	nand_set_controller_data(chip, (void *)nand);
 
 	INIT_LIST_HEAD(&nand->weak_blocks);
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473083 — [PATCH 02/46] mtd: nand: TODO Propagate mtd_device_unregister() return value in tear down

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:30 +0200
Subject[PATCH 02/46] mtd: nand: TODO Propagate mtd_device_unregister() return value in tear down
Message-ID<sc889-7Pb-11@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Provide a __nand_release() function for drivers which can deal
with a failing nand release operation.
Most drivers should be safe since they rely on module refcounting.
To catch outliers implement a nand_release() with a WARN_ON().

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nand_base.c | 15 ++++++++++-----
 include/linux/mtd/nand.h     | 12 +++++++++++-
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 77533f7..d5608dd 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4601,19 +4601,22 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
 EXPORT_SYMBOL(nand_scan);
 
 /**
- * nand_release - [NAND Interface] Free resources held by the NAND device
+ * __nand_release - [NAND Interface] Free resources held by the NAND device
  * @mtd: MTD device structure
  */
-void nand_release(struct mtd_info *mtd)
+int __nand_release(struct mtd_info *mtd)
 {
+	int ret;
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
+	ret = mtd_device_unregister(mtd);
+	if (ret)
+		return ret;
+
 	if (chip->ecc.mode == NAND_ECC_SOFT &&
 	    chip->ecc.algo == NAND_ECC_BCH)
 		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
 
-	mtd_device_unregister(mtd);
-
 	/* Free bad block table memory */
 	kfree(chip->bbt);
 	if (!(chip->options & NAND_OWN_BUFFERS))
@@ -4623,8 +4626,10 @@ void nand_release(struct mtd_info *mtd)
 	if (chip->badblock_pattern && chip->badblock_pattern->options
 			& NAND_BBT_DYNAMICSTRUCT)
 		kfree(chip->badblock_pattern);
+
+	return 0;
 }
-EXPORT_SYMBOL_GPL(nand_release);
+EXPORT_SYMBOL_GPL(__nand_release);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 8dd6e01..06be25e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -39,7 +39,7 @@ extern int nand_scan_ident(struct mtd_info *mtd, int max_chips,
 extern int nand_scan_tail(struct mtd_info *mtd);
 
 /* Free resources held by the NAND device */
-extern void nand_release(struct mtd_info *mtd);
+extern int __nand_release(struct mtd_info *mtd);
 
 /* Internal helper for board drivers which need to override command function */
 extern void nand_wait_ready(struct mtd_info *mtd);
@@ -1023,6 +1023,16 @@ static inline int jedec_feature(struct nand_chip *chip)
 		: 0;
 }
 
+static inline void nand_release(struct mtd_info *mtd)
+{
+	/*
+	 * If you face this warning your driver is doing something bad.
+	 * Don't issue nand_release() when your MTD is in use.
+	 * Use __nand_release() and handle the error correctly.
+	 */
+	WARN_ON(__nand_release(mtd) != 0);
+}
+
 /*
  * struct nand_sdr_timings - SDR NAND chip timings
  *
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473085 — [PATCH 07/46] mtd: nandsim: Begin with removal of global state

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:30 +0200
Subject[PATCH 07/46] mtd: nandsim: Begin with removal of global state
Message-ID<sc889-7Pb-13@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

A first step to support multiple nandsim instances...
Remove global variables and put them into struct nandsim.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 115 ++++++++++++++++++++++++---------------------
 1 file changed, 61 insertions(+), 54 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 0abbc88..c49999d 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -373,6 +373,14 @@ struct nandsim {
 	struct page *held_pages[NS_MAX_HELD_PAGES];
 	int held_cnt;
 
+	struct list_head weak_blocks;
+	struct list_head weak_pages;
+	struct list_head grave_pages;
+
+	unsigned long *erase_block_wear;
+	unsigned int wear_eb_count;
+	unsigned long total_wear;
+
 	struct nandsim_debug_info dbg;
 };
 
@@ -426,8 +434,6 @@ struct weak_block {
 	unsigned int erases_done;
 };
 
-static LIST_HEAD(weak_blocks);
-
 struct weak_page {
 	struct list_head list;
 	unsigned int page_no;
@@ -435,8 +441,6 @@ struct weak_page {
 	unsigned int writes_done;
 };
 
-static LIST_HEAD(weak_pages);
-
 struct grave_page {
 	struct list_head list;
 	unsigned int page_no;
@@ -444,24 +448,19 @@ struct grave_page {
 	unsigned int reads_done;
 };
 
-static LIST_HEAD(grave_pages);
-
-static unsigned long *erase_block_wear = NULL;
-static unsigned int wear_eb_count = 0;
-static unsigned long total_wear = 0;
-
 /* MTD structure for NAND controller */
 static struct mtd_info *nsmtd;
 
 static int nandsim_debugfs_show(struct seq_file *m, void *private)
 {
+	struct nandsim *ns = (struct nandsim *)m->private;
 	unsigned long wmin = -1, wmax = 0, avg;
 	unsigned long deciles[10], decile_max[10], tot = 0;
 	unsigned int i;
 
 	/* Calc wear stats */
-	for (i = 0; i < wear_eb_count; ++i) {
-		unsigned long wear = erase_block_wear[i];
+	for (i = 0; i < ns->wear_eb_count; ++i) {
+		unsigned long wear = ns->erase_block_wear[i];
 		if (wear < wmin)
 			wmin = wear;
 		if (wear > wmax)
@@ -475,20 +474,20 @@ static int nandsim_debugfs_show(struct seq_file *m, void *private)
 	}
 	deciles[9] = 0;
 	decile_max[9] = wmax;
-	for (i = 0; i < wear_eb_count; ++i) {
+	for (i = 0; i < ns->wear_eb_count; ++i) {
 		int d;
-		unsigned long wear = erase_block_wear[i];
+		unsigned long wear = ns->erase_block_wear[i];
 		for (d = 0; d < 10; ++d)
 			if (wear <= decile_max[d]) {
 				deciles[d] += 1;
 				break;
 			}
 	}
-	avg = tot / wear_eb_count;
+	avg = tot / ns->wear_eb_count;
 
 	/* Output wear report */
 	seq_printf(m, "Total numbers of erases:  %lu\n", tot);
-	seq_printf(m, "Number of erase blocks:   %u\n", wear_eb_count);
+	seq_printf(m, "Number of erase blocks:   %u\n", ns->wear_eb_count);
 	seq_printf(m, "Average number of erases: %lu\n", avg);
 	seq_printf(m, "Maximum number of erases: %lu\n", wmax);
 	seq_printf(m, "Minimum number of erases: %lu\n", wmin);
@@ -843,7 +842,7 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
 	return 0;
 }
 
-static int parse_weakblocks(void)
+static int parse_weakblocks(struct nandsim *ns)
 {
 	char *w;
 	int zero_ok;
@@ -875,16 +874,16 @@ static int parse_weakblocks(void)
 		}
 		wb->erase_block_no = erase_block_no;
 		wb->max_erases = max_erases;
-		list_add(&wb->list, &weak_blocks);
+		list_add(&wb->list, &ns->weak_blocks);
 	} while (*w);
 	return 0;
 }
 
-static int erase_error(unsigned int erase_block_no)
+static int erase_error(struct nandsim *ns, unsigned int erase_block_no)
 {
 	struct weak_block *wb;
 
-	list_for_each_entry(wb, &weak_blocks, list)
+	list_for_each_entry(wb, &ns->weak_blocks, list)
 		if (wb->erase_block_no == erase_block_no) {
 			if (wb->erases_done >= wb->max_erases)
 				return 1;
@@ -894,7 +893,7 @@ static int erase_error(unsigned int erase_block_no)
 	return 0;
 }
 
-static int parse_weakpages(void)
+static int parse_weakpages(struct nandsim *ns)
 {
 	char *w;
 	int zero_ok;
@@ -926,16 +925,16 @@ static int parse_weakpages(void)
 		}
 		wp->page_no = page_no;
 		wp->max_writes = max_writes;
-		list_add(&wp->list, &weak_pages);
+		list_add(&wp->list, &ns->weak_pages);
 	} while (*w);
 	return 0;
 }
 
-static int write_error(unsigned int page_no)
+static int write_error(struct nandsim *ns, unsigned int page_no)
 {
 	struct weak_page *wp;
 
-	list_for_each_entry(wp, &weak_pages, list)
+	list_for_each_entry(wp, &ns->weak_pages, list)
 		if (wp->page_no == page_no) {
 			if (wp->writes_done >= wp->max_writes)
 				return 1;
@@ -945,7 +944,7 @@ static int write_error(unsigned int page_no)
 	return 0;
 }
 
-static int parse_gravepages(void)
+static int parse_gravepages(struct nandsim *ns)
 {
 	char *g;
 	int zero_ok;
@@ -977,16 +976,16 @@ static int parse_gravepages(void)
 		}
 		gp->page_no = page_no;
 		gp->max_reads = max_reads;
-		list_add(&gp->list, &grave_pages);
+		list_add(&gp->list, &ns->grave_pages);
 	} while (*g);
 	return 0;
 }
 
-static int read_error(unsigned int page_no)
+static int read_error(struct nandsim *ns, unsigned int page_no)
 {
 	struct grave_page *gp;
 
-	list_for_each_entry(gp, &grave_pages, list)
+	list_for_each_entry(gp, &ns->grave_pages, list)
 		if (gp->page_no == page_no) {
 			if (gp->reads_done >= gp->max_reads)
 				return 1;
@@ -996,55 +995,57 @@ static int read_error(unsigned int page_no)
 	return 0;
 }
 
-static void free_lists(void)
+static void free_lists(struct nandsim *ns)
 {
 	struct list_head *pos, *n;
-	list_for_each_safe(pos, n, &weak_blocks) {
+	list_for_each_safe(pos, n, &ns->weak_blocks) {
 		list_del(pos);
 		kfree(list_entry(pos, struct weak_block, list));
 	}
-	list_for_each_safe(pos, n, &weak_pages) {
+	list_for_each_safe(pos, n, &ns->weak_pages) {
 		list_del(pos);
 		kfree(list_entry(pos, struct weak_page, list));
 	}
-	list_for_each_safe(pos, n, &grave_pages) {
+	list_for_each_safe(pos, n, &ns->grave_pages) {
 		list_del(pos);
 		kfree(list_entry(pos, struct grave_page, list));
 	}
-	kfree(erase_block_wear);
+	kfree(ns->erase_block_wear);
 }
 
 static int setup_wear_reporting(struct mtd_info *mtd)
 {
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
 	size_t mem;
 
-	wear_eb_count = div_u64(mtd->size, mtd->erasesize);
-	mem = wear_eb_count * sizeof(unsigned long);
-	if (mem / sizeof(unsigned long) != wear_eb_count) {
+	ns->wear_eb_count = div_u64(mtd->size, mtd->erasesize);
+	mem = ns->wear_eb_count * sizeof(unsigned long);
+	if (mem / sizeof(unsigned long) != ns->wear_eb_count) {
 		NS_ERR("Too many erase blocks for wear reporting\n");
 		return -ENOMEM;
 	}
-	erase_block_wear = kzalloc(mem, GFP_KERNEL);
-	if (!erase_block_wear) {
+	ns->erase_block_wear = kzalloc(mem, GFP_KERNEL);
+	if (!ns->erase_block_wear) {
 		NS_ERR("Too many erase blocks for wear reporting\n");
 		return -ENOMEM;
 	}
 	return 0;
 }
 
-static void update_wear(unsigned int erase_block_no)
+static void update_wear(struct nandsim *ns, unsigned int erase_block_no)
 {
-	if (!erase_block_wear)
+	if (!ns->erase_block_wear)
 		return;
-	total_wear += 1;
+	ns->total_wear += 1;
 	/*
 	 * TODO: Notify this through a debugfs entry,
 	 * instead of showing an error message.
 	 */
-	if (total_wear == 0)
+	if (ns->total_wear == 0)
 		NS_ERR("Erase counter total overflow\n");
-	erase_block_wear[erase_block_no] += 1;
-	if (erase_block_wear[erase_block_no] == 0)
+	ns->erase_block_wear[erase_block_no] += 1;
+	if (ns->erase_block_wear[erase_block_no] == 0)
 		NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
 }
 
@@ -1440,7 +1441,7 @@ static int do_read_error(struct nandsim *ns, int num)
 {
 	unsigned int page_no = ns->regs.row;
 
-	if (read_error(page_no)) {
+	if (read_error(ns, page_no)) {
 		prandom_bytes(ns->buf.byte, num);
 		NS_WARN("simulating read error in page %u\n", page_no);
 		return 1;
@@ -1688,10 +1689,10 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 
 		NS_MDELAY(erase_delay);
 
-		if (erase_block_wear)
-			update_wear(erase_block_no);
+		if (ns->erase_block_wear)
+			update_wear(ns, erase_block_no);
 
-		if (erase_error(erase_block_no)) {
+		if (erase_error(ns, erase_block_no)) {
 			NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
 			return -1;
 		}
@@ -1727,7 +1728,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 		NS_UDELAY(programm_delay);
 		NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
 
-		if (write_error(page_no)) {
+		if (write_error(ns, page_no)) {
 			NS_WARN("simulating write failure in page %u\n", page_no);
 			return -1;
 		}
@@ -2281,10 +2282,16 @@ static int __init ns_init_default(void)
 		NS_ERR("unable to allocate core structures.\n");
 		return -ENOMEM;
 	}
+
 	nsmtd       = nand_to_mtd(chip);
 	nand        = (struct nandsim *)(chip + 1);
 	nand_set_controller_data(chip, (void *)nand);
 
+	INIT_LIST_HEAD(&nand->weak_blocks);
+	INIT_LIST_HEAD(&nand->grave_pages);
+	INIT_LIST_HEAD(&nand->weak_pages);
+	INIT_LIST_HEAD(&nand->weak_blocks);
+
 	/*
 	 * Register simulator's callbacks.
 	 */
@@ -2335,13 +2342,13 @@ static int __init ns_init_default(void)
 
 	nsmtd->owner = THIS_MODULE;
 
-	if ((retval = parse_weakblocks()) != 0)
+	if ((retval = parse_weakblocks(nand)) != 0)
 		goto error;
 
-	if ((retval = parse_weakpages()) != 0)
+	if ((retval = parse_weakpages(nand)) != 0)
 		goto error;
 
-	if ((retval = parse_gravepages()) != 0)
+	if ((retval = parse_gravepages(nand)) != 0)
 		goto error;
 
 	retval = nand_scan_ident(nsmtd, 1, NULL);
@@ -2432,8 +2439,8 @@ err_exit:
 	for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
 		kfree(nand->partitions[i].name);
 error:
+	free_lists(nand);
 	kfree(chip);
-	free_lists();
 
 	return retval;
 }
@@ -2445,12 +2452,12 @@ static void __exit ns_cleanup_default(void)
 	int i;
 
 	nandsim_debugfs_remove(ns);
+	free_lists(ns);
 	free_nandsim(ns);    /* Free nandsim private resources */
 	nand_release(nsmtd); /* Unregister driver */
 	for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
 		kfree(ns->partitions[i].name);
 	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
-	free_lists();
 }
 
 static int __init ns_init_module(void)
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473090 — [PATCH 03/46] mtd: Don't unconditionally unregister reboot notifier

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:30 +0200
Subject[PATCH 03/46] mtd: Don't unconditionally unregister reboot notifier
Message-ID<sc88a-7Pb-33@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

del_mtd_device() is allowed to fail.
i.e. when the MTD is busy.
Unregister the reboot notifier only when we're really
about to delete the MTD.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/mtdcore.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index e3936b8..36e5fb0 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -654,17 +654,22 @@ int mtd_device_unregister(struct mtd_info *master)
 {
 	int err;
 
-	if (master->_reboot)
-		unregister_reboot_notifier(&master->reboot_notifier);
-
 	err = del_mtd_partitions(master);
 	if (err)
 		return err;
 
 	if (!device_is_registered(&master->dev))
-		return 0;
+		goto unregister;
 
-	return del_mtd_device(master);
+	err = del_mtd_device(master);
+	if (err)
+		return err;
+
+unregister:
+	if (master->_reboot)
+		unregister_reboot_notifier(&master->reboot_notifier);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(mtd_device_unregister);
 
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473093 — [PATCH 45/46] mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 45/46] mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID
Message-ID<sc8hP-7T2-3@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

nand base reads the full 8 byte NAND ID, no matter
how many id bytes we have configured.

So, instead of getting confused return all bytes
even when they are not configured (0xff).

Fixes error messages such as:
nandsim: unexpected data output cycle, state is STATE_READY return 0x0

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 8a63812..b50568f 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -56,8 +56,6 @@
 
 #define NANDSIM_FIRST_ID_BYTE  0x98
 #define NANDSIM_SECOND_ID_BYTE 0x39
-#define NANDSIM_THIRD_ID_BYTE  0xFF /* No byte */
-#define NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
 #define NANDSIM_ACCESS_DELAY 25
 #define NANDSIM_PROGRAMM_DELAY 200
 #define NANDSIM_ERASE_DELAY 2
@@ -87,9 +85,7 @@ static unsigned int bch;
 static u_char id_bytes[8] = {
 	[0] = NANDSIM_FIRST_ID_BYTE,
 	[1] = NANDSIM_SECOND_ID_BYTE,
-	[2] = NANDSIM_THIRD_ID_BYTE,
-	[3] = NANDSIM_FOURTH_ID_BYTE,
-	[4 ... 7] = 0xFF,
+	[2 ... 7] = 0xFF,
 };
 static bool defaults = true;
 
@@ -3064,14 +3060,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	 * Perform minimum nandsim structure initialization to handle
 	 * the initial ID read command correctly
 	 */
-	if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
-		nand->geom.idbytes = 8;
-	else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
-		nand->geom.idbytes = 6;
-	else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
-		nand->geom.idbytes = 4;
-	else
-		nand->geom.idbytes = 2;
+	nand->geom.idbytes = sizeof(id_bytes);
 	nand->regs.status = NS_STATUS_OK(nand);
 	nand->nxstate = STATE_UNKNOWN;
 	nand->options |= OPT_PAGE512; /* temporary value */
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473094 — [PATCH 06/46] mtd: nandsim: Add basic control file support

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 06/46] mtd: nandsim: Add basic control file support
Message-ID<sc8hP-7T2-1@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

/dev/nandsim_ctrl accept ioctl() commands such that userspace
can configure nandsim.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 66 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 56 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 1eb9344..0abbc88 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -44,6 +44,9 @@
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/compat.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -2226,10 +2229,41 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 	return;
 }
 
-/*
- * Module initialization function
- */
-static int __init ns_init_module(void)
+static long ns_ctrl_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
+{
+	if (!capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+
+	return -ENOTTY;
+}
+
+#ifdef CONFIG_COMPAT
+static long ns_ctrl_compat_ioctl(struct file *file, unsigned int cmd,
+				 unsigned long arg)
+{
+	unsigned long translated_arg = (unsigned long)compat_ptr(arg);
+
+	return ns_ctrl_ioctl(file, cmd, translated_arg);
+}
+#else
+#define ns_ctrl_compat_ioctl NULL
+#endif
+
+static const struct file_operations nansim_ctrl_fops = {
+	.owner          = THIS_MODULE,
+	.unlocked_ioctl = ns_ctrl_ioctl,
+	.compat_ioctl   = ns_ctrl_compat_ioctl,
+	.llseek         = no_llseek,
+};
+
+static struct miscdevice nandsim_ctrl_cdev = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "nandsim_ctrl",
+	.fops = &nansim_ctrl_fops,
+};
+
+static int __init ns_init_default(void)
 {
 	struct nand_chip *chip;
 	struct nandsim *nand;
@@ -2404,12 +2438,7 @@ error:
 	return retval;
 }
 
-module_init(ns_init_module);
-
-/*
- * Module clean-up function
- */
-static void __exit ns_cleanup_module(void)
+static void __exit ns_cleanup_default(void)
 {
 	struct nand_chip *chip = mtd_to_nand(nsmtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
@@ -2424,6 +2453,23 @@ static void __exit ns_cleanup_module(void)
 	free_lists();
 }
 
+static int __init ns_init_module(void)
+{
+	int ret;
+
+	ret = ns_init_default();
+	if (ret)
+		return ret;
+
+	return misc_register(&nandsim_ctrl_cdev);
+}
+module_init(ns_init_module);
+
+static void __exit ns_cleanup_module(void)
+{
+	ns_cleanup_default();
+	misc_deregister(&nandsim_ctrl_cdev);
+}
 module_exit(ns_cleanup_module);
 
 MODULE_LICENSE ("GPL");
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473095 — [PATCH 43/46] mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 43/46] mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE
Message-ID<sc8hP-7T2-5@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Since we have now all what we need we can arm NANDSIM_IOC_NEW_INSTANCE.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 34b0c24..4145ab6 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2900,10 +2900,35 @@ out:
 static long ns_ctrl_ioctl(struct file *file, unsigned int cmd,
 			  unsigned long arg)
 {
-	if (!capable(CAP_SYS_RESOURCE))
-		return -EPERM;
+	int ret;
+	void __user *argp = (void __user *)arg;
+
+	if (!capable(CAP_SYS_RESOURCE)) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	switch (cmd) {
+		case NANDSIM_IOC_NEW_INSTANCE:
+		{
+			struct ns_new_instance_req req;
+
+			ret = copy_from_user(&req, argp, sizeof(struct ns_new_instance_req));
+			if (ret) {
+				ret = -EFAULT;
+				goto out;
+			}
 
-	return -ENOTTY;
+			ret = ns_ctrl_new_instance(&req, argp + sizeof(req));
+			break;
+		}
+
+		default:
+			ret = -ENOTTY;
+	}
+
+out:
+	return ret;
 }
 
 #ifdef CONFIG_COMPAT
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473096 — [PATCH 15/46] mtd: nandsim: Introduce backend operations

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 15/46] mtd: nandsim: Introduce backend operations
Message-ID<sc8hP-7T2-7@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

...to untangle the ram based and cachefile based
code.
It will help us later supporting different backends.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 400 ++++++++++++++++++++++++++-------------------
 1 file changed, 228 insertions(+), 172 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 2e02089..633872a 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -314,6 +314,7 @@ struct nandsim_params {
 	unsigned int bbt;
 	unsigned int bch;
 	unsigned char *id_bytes;
+	struct ns_backend_ops *bops;
 };
 
 struct nandsim_debug_info {
@@ -329,6 +330,22 @@ union ns_mem {
 	uint16_t *word;  /* for 16-bit word access */
 };
 
+struct ns_ram_data {
+	/* The simulated NAND flash pages array */
+	union ns_mem *pages;
+
+	/* Slab allocator for nand pages */
+	struct kmem_cache *nand_pages_slab;
+};
+
+struct ns_cachefile_data {
+	struct file *cfile; /* Open file */
+	unsigned long *pages_written; /* Which pages have been written */
+	void *file_buf;
+	struct page *held_pages[NS_MAX_HELD_PAGES];
+	int held_cnt;
+};
+
 /*
  * The structure which describes all the internal simulator data.
  */
@@ -348,12 +365,6 @@ struct nandsim {
 	uint16_t npstates;      /* number of previous states saved */
 	uint16_t stateidx;      /* current state index */
 
-	/* The simulated NAND flash pages array */
-	union ns_mem *pages;
-
-	/* Slab allocator for nand pages */
-	struct kmem_cache *nand_pages_slab;
-
 	/* Internal buffer of page + OOB size bytes */
 	union ns_mem buf;
 
@@ -394,12 +405,8 @@ struct nandsim {
                 int wp;  /* write Protect */
         } lines;
 
-	/* Fields needed when using a cache file */
-	struct file *cfile; /* Open file */
-	unsigned long *pages_written; /* Which pages have been written */
-	void *file_buf;
-	struct page *held_pages[NS_MAX_HELD_PAGES];
-	int held_cnt;
+	struct ns_backend_ops *bops;
+	void *backend_data;
 
 	struct list_head weak_blocks;
 	struct list_head weak_pages;
@@ -420,6 +427,17 @@ struct nandsim {
 	struct nandsim_debug_info dbg;
 };
 
+struct ns_backend_ops {
+	void (*erase_sector)(struct nandsim *ns);
+	int (*prog_page)(struct nandsim *ns, int num);
+	void (*read_page)(struct nandsim *ns, int num);
+	int (*init)(struct nandsim *ns, struct nandsim_params *nsparam);
+	void (*destroy)(struct nandsim *ns);
+};
+
+static struct ns_backend_ops ns_ram_bops;
+static struct ns_backend_ops ns_cachefile_bops;
+
 /*
  * Operations array. To perform any operation the simulator must pass
  * through the correspondent states chain.
@@ -641,95 +659,105 @@ static void nandsim_debugfs_remove(struct nandsim *ns)
 		debugfs_remove_recursive(ns->dbg.dfs_root);
 }
 
-/*
- * Allocate array of page pointers, create slab allocation for an array
- * and initialize the array by NULL pointers.
- *
- * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
- */
-static int alloc_device(struct nandsim *ns, struct nandsim_params *nsparam)
+static int ns_ram_init(struct nandsim *ns, struct nandsim_params *nsparam)
 {
-	struct file *cfile;
-	int i, err;
-
-	if (nsparam->cache_file) {
-		cfile = filp_open(nsparam->cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
-		if (IS_ERR(cfile))
-			return PTR_ERR(cfile);
-		if (!(cfile->f_mode & FMODE_CAN_READ)) {
-			NS_ERR("alloc_device: cache file not readable\n");
-			err = -EINVAL;
-			goto err_close;
-		}
-		if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
-			NS_ERR("alloc_device: cache file not writeable\n");
-			err = -EINVAL;
-			goto err_close;
-		}
-		ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
-					    sizeof(unsigned long));
-		if (!ns->pages_written) {
-			NS_ERR("alloc_device: unable to allocate pages written array\n");
-			err = -ENOMEM;
-			goto err_close;
-		}
-		ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
-		if (!ns->file_buf) {
-			NS_ERR("alloc_device: unable to allocate file buf\n");
-			err = -ENOMEM;
-			goto err_free;
-		}
-		ns->cfile = cfile;
-		return 0;
-	}
+	int i;
+	struct ns_ram_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
 
-	ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
-	if (!ns->pages) {
+	if (!data)
+		return -ENOMEM;
+
+	data->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
+	if (!data->pages) {
+		kfree(data);
 		NS_ERR("alloc_device: unable to allocate page array\n");
 		return -ENOMEM;
 	}
 	for (i = 0; i < ns->geom.pgnum; i++) {
-		ns->pages[i].byte = NULL;
+		data->pages[i].byte = NULL;
 	}
-	ns->nand_pages_slab = kmem_cache_create("nandsim",
+
+	data->nand_pages_slab = kmem_cache_create("nandsim",
 						ns->geom.pgszoob, 0, 0, NULL);
-	if (!ns->nand_pages_slab) {
+	if (!data->nand_pages_slab) {
+		vfree(data->pages);
+		kfree(data);
 		NS_ERR("cache_create: unable to create kmem_cache\n");
 		return -ENOMEM;
 	}
 
+	ns->backend_data = data;
+
+	return 0;
+}
+
+static int ns_cachefile_init(struct nandsim *ns, struct nandsim_params *nsparam)
+{
+	struct file *cfile;
+	int err;
+	struct ns_cachefile_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+
+	cfile = filp_open(nsparam->cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+	if (IS_ERR(cfile))
+		return PTR_ERR(cfile);
+	if (!(cfile->f_mode & FMODE_CAN_READ)) {
+		NS_ERR("alloc_device: cache file not readable\n");
+		err = -EINVAL;
+		goto err_close;
+	}
+	if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
+		NS_ERR("alloc_device: cache file not writeable\n");
+		err = -EINVAL;
+		goto err_close;
+	}
+	data->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
+				    sizeof(unsigned long));
+	if (!data->pages_written) {
+		NS_ERR("alloc_device: unable to allocate pages written array\n");
+		err = -ENOMEM;
+		goto err_close;
+	}
+	data->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+	if (!data->file_buf) {
+		NS_ERR("alloc_device: unable to allocate file buf\n");
+		err = -ENOMEM;
+		goto err_free;
+	}
+	data->cfile = cfile;
+
+	ns->backend_data = data;
+
 	return 0;
 
 err_free:
-	vfree(ns->pages_written);
+	vfree(data->pages_written);
 err_close:
 	filp_close(cfile, NULL);
 	return err;
 }
 
-/*
- * Free any allocated pages, and free the array of page pointers.
- */
-static void free_device(struct nandsim *ns)
+static void ns_ram_destroy(struct nandsim *ns)
 {
+	struct ns_ram_data *data = ns->backend_data;
 	int i;
 
-	if (ns->cfile) {
-		kfree(ns->file_buf);
-		vfree(ns->pages_written);
-		filp_close(ns->cfile, NULL);
-		return;
+	for (i = 0; i < ns->geom.pgnum; i++) {
+		if (data->pages[i].byte)
+			kmem_cache_free(data->nand_pages_slab,
+					data->pages[i].byte);
 	}
+	kmem_cache_destroy(data->nand_pages_slab);
+	vfree(data->pages);
+	kfree(data);
+}
 
-	if (ns->pages) {
-		for (i = 0; i < ns->geom.pgnum; i++) {
-			if (ns->pages[i].byte)
-				kmem_cache_free(ns->nand_pages_slab,
-						ns->pages[i].byte);
-		}
-		kmem_cache_destroy(ns->nand_pages_slab);
-		vfree(ns->pages);
-	}
+static void ns_cachefile_destroy(struct nandsim *ns)
+{
+	struct ns_cachefile_data *data = ns->backend_data;
+
+	kfree(data->file_buf);
+	vfree(data->pages_written);
+	filp_close(data->cfile, NULL);
 }
 
 static char *get_partition_name(struct nandsim *ns, int i)
@@ -864,7 +892,9 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
 	printk("options: %#x\n",                ns->options);
 
-	if ((ret = alloc_device(ns, nsparam)) != 0)
+	ns->bops = nsparam->bops;
+
+	if ((ret = ns->bops->init(ns, nsparam)) != 0)
 		return ret;
 
 	/* Allocate / initialize the internal buffer */
@@ -885,9 +915,7 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 static void free_nandsim(struct nandsim *ns)
 {
 	kfree(ns->buf.byte);
-	free_device(ns);
-
-	return;
+	ns->bops->destroy(ns);
 }
 
 static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd,
@@ -1418,9 +1446,10 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
 static void put_pages(struct nandsim *ns)
 {
 	int i;
+	struct ns_cachefile_data *data = ns->backend_data;
 
-	for (i = 0; i < ns->held_cnt; i++)
-		put_page(ns->held_pages[i]);
+	for (i = 0; i < data->held_cnt; i++)
+		put_page(data->held_pages[i]);
 }
 
 /* Get page cache pages in advance to provide NOFS memory allocation */
@@ -1429,12 +1458,13 @@ static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t
 	pgoff_t index, start_index, end_index;
 	struct page *page;
 	struct address_space *mapping = file->f_mapping;
+	struct ns_cachefile_data *data = ns->backend_data;
 
 	start_index = pos >> PAGE_SHIFT;
 	end_index = (pos + count - 1) >> PAGE_SHIFT;
 	if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
 		return -EINVAL;
-	ns->held_cnt = 0;
+	data->held_cnt = 0;
 	for (index = start_index; index <= end_index; index++) {
 		page = find_get_page(mapping, index);
 		if (page == NULL) {
@@ -1449,7 +1479,7 @@ static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t
 			}
 			unlock_page(page);
 		}
-		ns->held_pages[ns->held_cnt++] = page;
+		data->held_pages[data->held_cnt++] = page;
 	}
 	return 0;
 }
@@ -1503,7 +1533,9 @@ static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size
  */
 static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
 {
-	return &(ns->pages[ns->regs.row]);
+	struct ns_ram_data *data = ns->backend_data;
+
+	return &(data->pages[ns->regs.row]);
 }
 
 /*
@@ -1545,36 +1577,10 @@ static void do_bit_flips(struct nandsim *ns, int num)
 	}
 }
 
-/*
- * Fill the NAND buffer with data read from the specified page.
- */
-static void read_page(struct nandsim *ns, int num)
+static void ns_ram_read_page(struct nandsim *ns, int num)
 {
 	union ns_mem *mypage;
 
-	if (ns->cfile) {
-		if (!test_bit(ns->regs.row, ns->pages_written)) {
-			NS_DBG("read_page: page %d not written\n", ns->regs.row);
-			memset(ns->buf.byte, 0xFF, num);
-		} else {
-			loff_t pos;
-			ssize_t tx;
-
-			NS_DBG("read_page: page %d written, reading from %d\n",
-				ns->regs.row, ns->regs.column + ns->regs.off);
-			if (do_read_error(ns, num))
-				return;
-			pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
-			tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
-			if (tx != num) {
-				NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return;
-			}
-			do_bit_flips(ns, num);
-		}
-		return;
-	}
-
 	mypage = NS_GET_PAGE(ns);
 	if (mypage->byte == NULL) {
 		NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
@@ -1589,81 +1595,67 @@ static void read_page(struct nandsim *ns, int num)
 	}
 }
 
-/*
- * Erase all pages in the specified sector.
- */
-static void erase_sector(struct nandsim *ns)
+static void ns_cachefile_read_page(struct nandsim *ns, int num)
 {
-	union ns_mem *mypage;
-	int i;
+	struct ns_cachefile_data *data = ns->backend_data;
 
-	if (ns->cfile) {
-		for (i = 0; i < ns->geom.pgsec; i++)
-			if (__test_and_clear_bit(ns->regs.row + i,
-						 ns->pages_written)) {
-				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
-			}
-		return;
+	if (!test_bit(ns->regs.row, data->pages_written)) {
+		NS_DBG("read_page: page %d not written\n", ns->regs.row);
+		memset(ns->buf.byte, 0xFF, num);
+	} else {
+		loff_t pos;
+		ssize_t tx;
+
+		NS_DBG("read_page: page %d written, reading from %d\n",
+			ns->regs.row, ns->regs.column + ns->regs.off);
+		if (do_read_error(ns, num))
+			return;
+		pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+		tx = read_file(ns, data->cfile, ns->buf.byte, num, pos);
+		if (tx != num) {
+			NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+			return;
+		}
+		do_bit_flips(ns, num);
 	}
+}
+
+static void ns_ram_erase_sector(struct nandsim *ns)
+{
+	union ns_mem *mypage;
+	int i;
+	struct ns_ram_data *data = ns->backend_data;
 
 	mypage = NS_GET_PAGE(ns);
 	for (i = 0; i < ns->geom.pgsec; i++) {
 		if (mypage->byte != NULL) {
 			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
-			kmem_cache_free(ns->nand_pages_slab, mypage->byte);
+			kmem_cache_free(data->nand_pages_slab, mypage->byte);
 			mypage->byte = NULL;
 		}
 		mypage++;
 	}
 }
 
-/*
- * Program the specified page with the contents from the NAND buffer.
- */
-static int prog_page(struct nandsim *ns, int num)
+static void ns_cachefile_erase_sector(struct nandsim *ns)
 {
 	int i;
-	union ns_mem *mypage;
-	u_char *pg_off;
+	struct ns_cachefile_data *data = ns->backend_data;
 
-	if (ns->cfile) {
-		loff_t off;
-		ssize_t tx;
-		int all;
-
-		NS_DBG("prog_page: writing page %d\n", ns->regs.row);
-		pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
-		off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
-		if (!test_bit(ns->regs.row, ns->pages_written)) {
-			all = 1;
-			memset(ns->file_buf, 0xff, ns->geom.pgszoob);
-		} else {
-			all = 0;
-			tx = read_file(ns, ns->cfile, pg_off, num, off);
-			if (tx != num) {
-				NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return -1;
-			}
-		}
-		for (i = 0; i < num; i++)
-			pg_off[i] &= ns->buf.byte[i];
-		if (all) {
-			loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
-			tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, pos);
-			if (tx != ns->geom.pgszoob) {
-				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return -1;
-			}
-			__set_bit(ns->regs.row, ns->pages_written);
-		} else {
-			tx = write_file(ns, ns->cfile, pg_off, num, off);
-			if (tx != num) {
-				NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
-				return -1;
-			}
+	for (i = 0; i < ns->geom.pgsec; i++) {
+		if (__test_and_clear_bit(ns->regs.row + i,
+					 data->pages_written)) {
+			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
 		}
-		return 0;
 	}
+}
+
+static int ns_ram_prog_page(struct nandsim *ns, int num)
+{
+	int i;
+	union ns_mem *mypage;
+	u_char *pg_off;
+	struct ns_ram_data *data = ns->backend_data;
 
 	mypage = NS_GET_PAGE(ns);
 	if (mypage->byte == NULL) {
@@ -1674,7 +1666,7 @@ static int prog_page(struct nandsim *ns, int num)
 		 * then kernel memory alloc runs writeback which goes to the FS
 		 * again and deadlocks. This was seen in practice.
 		 */
-		mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
+		mypage->byte = kmem_cache_alloc(data->nand_pages_slab, GFP_NOFS);
 		if (mypage->byte == NULL) {
 			NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
 			return -1;
@@ -1689,6 +1681,65 @@ static int prog_page(struct nandsim *ns, int num)
 	return 0;
 }
 
+static int ns_cachefile_prog_page(struct nandsim *ns, int num)
+{
+	int i, all;
+	loff_t off;
+	ssize_t tx;
+	u_char *pg_off;
+	struct ns_cachefile_data *data = ns->backend_data;
+
+	NS_DBG("prog_page: writing page %d\n", ns->regs.row);
+	pg_off = data->file_buf + ns->regs.column + ns->regs.off;
+	off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+	if (!test_bit(ns->regs.row, data->pages_written)) {
+		all = 1;
+		memset(data->file_buf, 0xff, ns->geom.pgszoob);
+	} else {
+		all = 0;
+		tx = read_file(ns, data->cfile, pg_off, num, off);
+		if (tx != num) {
+			NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+			return -1;
+		}
+	}
+	for (i = 0; i < num; i++)
+		pg_off[i] &= ns->buf.byte[i];
+	if (all) {
+		loff_t pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
+		tx = write_file(ns, data->cfile, data->file_buf, ns->geom.pgszoob, pos);
+		if (tx != ns->geom.pgszoob) {
+			NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+			return -1;
+		}
+		__set_bit(ns->regs.row, data->pages_written);
+	} else {
+		tx = write_file(ns, data->cfile, pg_off, num, off);
+		if (tx != num) {
+			NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static struct ns_backend_ops ns_ram_bops = {
+	.erase_sector = ns_ram_erase_sector,
+	.prog_page = ns_ram_prog_page,
+	.read_page = ns_ram_read_page,
+	.init = ns_ram_init,
+	.destroy = ns_ram_destroy,
+};
+
+static struct ns_backend_ops ns_cachefile_bops = {
+	.erase_sector = ns_cachefile_erase_sector,
+	.prog_page = ns_cachefile_prog_page,
+	.read_page = ns_cachefile_read_page,
+	.init = ns_cachefile_init,
+	.destroy = ns_cachefile_destroy,
+};
+
+
 /*
  * If state has any action bit, perform this action.
  *
@@ -1721,7 +1772,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 			break;
 		}
 		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-		read_page(ns, num);
+		ns->bops->read_page(ns, num);
 
 		NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
 			num, NS_RAW_OFFSET(ns) + ns->regs.off);
@@ -1764,7 +1815,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 				ns->regs.row, NS_RAW_OFFSET(ns));
 		NS_LOG("erase sector %u\n", erase_block_no);
 
-		erase_sector(ns);
+		ns->bops->erase_sector(ns);
 
 		NS_MDELAY(ns, ns->erase_delay);
 
@@ -1795,7 +1846,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 			return -1;
 		}
 
-		if (prog_page(ns, num) == -1)
+		if (ns->bops->prog_page(ns, num) == -1)
 			return -1;
 
 		page_no = ns->regs.row;
@@ -2603,6 +2654,11 @@ static int __init ns_init_default(void)
 	nsparam->bch = bch;
 	nsparam->id_bytes = id_bytes;
 
+	if (!nsparam->cache_file)
+		nsparam->bops = &ns_ram_bops;
+	else
+		nsparam->bops = &ns_cachefile_bops;
+
 	ret = ns_new_instance(nsparam);
 	kfree(nsparam);
 
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473097 — [PATCH 09/46] mtd: nandsim: Don't directly use module parameters

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 09/46] mtd: nandsim: Don't directly use module parameters
Message-ID<sc8hP-7T2-9@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Move simulator related module params into struct nandsim
such that each instance can later use different parameters.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 57 ++++++++++++++++++++++++++++++----------------
 1 file changed, 37 insertions(+), 20 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index e24ef8c..fda670b 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -197,10 +197,10 @@ MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
 	do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
 
 /* Busy-wait delay macros (microseconds, milliseconds) */
-#define NS_UDELAY(us) \
-        do { if (do_delays) udelay(us); } while(0)
-#define NS_MDELAY(us) \
-        do { if (do_delays) mdelay(us); } while(0)
+#define NS_UDELAY(ns, us) \
+	do { if (ns->do_delays) udelay(us); } while (0)
+#define NS_MDELAY(ns, us) \
+	do { if (ns->do_delays) mdelay(us); } while (0)
 
 /* Is the nandsim structure initialized ? */
 #define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
@@ -381,6 +381,14 @@ struct nandsim {
 	unsigned int wear_eb_count;
 	unsigned long total_wear;
 
+	bool do_delays;
+	unsigned int access_delay;
+	unsigned int program_delay;
+	unsigned int erase_delay;
+	unsigned int output_cycle;
+	unsigned int input_cycle;
+	unsigned int bitflips;
+
 	struct nandsim_debug_info dbg;
 };
 
@@ -816,7 +824,8 @@ static void free_nandsim(struct nandsim *ns)
 	return;
 }
 
-static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
+static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd,
+			   unsigned char *badblocks)
 {
 	char *w;
 	int zero_ok;
@@ -844,7 +853,7 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
 	return 0;
 }
 
-static int parse_weakblocks(struct nandsim *ns)
+static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks)
 {
 	char *w;
 	int zero_ok;
@@ -895,7 +904,7 @@ static int erase_error(struct nandsim *ns, unsigned int erase_block_no)
 	return 0;
 }
 
-static int parse_weakpages(struct nandsim *ns)
+static int parse_weakpages(struct nandsim *ns, unsigned char *weakpages)
 {
 	char *w;
 	int zero_ok;
@@ -946,7 +955,7 @@ static int write_error(struct nandsim *ns, unsigned int page_no)
 	return 0;
 }
 
-static int parse_gravepages(struct nandsim *ns)
+static int parse_gravepages(struct nandsim *ns, unsigned char *gravepages)
 {
 	char *g;
 	int zero_ok;
@@ -1456,10 +1465,10 @@ static void do_bit_flips(struct nandsim *ns, int num)
 	struct nand_chip *chip = ((struct nand_chip *)ns - 1);
 	struct mtd_info *nsmtd = nand_to_mtd(chip);
 
-	if (bitflips && prandom_u32() < (1 << 22)) {
+	if (ns->bitflips && prandom_u32() < (1 << 22)) {
 		int flips = 1;
-		if (bitflips > 1)
-			flips = (prandom_u32() % (int) bitflips) + 1;
+		if (ns->bitflips > 1)
+			flips = (prandom_u32() % (int)ns->bitflips) + 1;
 		while (flips--) {
 			int pos = prandom_u32() % (num * 8);
 			ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
@@ -1659,8 +1668,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 		else
 			NS_LOG("read OOB of page %d\n", ns->regs.row);
 
-		NS_UDELAY(access_delay);
-		NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
+		NS_UDELAY(ns, ns->access_delay);
+		NS_UDELAY(ns, ns->input_cycle * ns->geom.pgsz / 1000 / busdiv);
 
 		break;
 
@@ -1692,7 +1701,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 
 		erase_sector(ns);
 
-		NS_MDELAY(erase_delay);
+		NS_MDELAY(ns, ns->erase_delay);
 
 		if (ns->erase_block_wear)
 			update_wear(ns, erase_block_no);
@@ -1730,8 +1739,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 			num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
 		NS_LOG("programm page %d\n", ns->regs.row);
 
-		NS_UDELAY(programm_delay);
-		NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
+		NS_UDELAY(ns, ns->program_delay);
+		NS_UDELAY(ns, ns->output_cycle * ns->geom.pgsz / 1000 / busdiv);
 
 		if (write_error(ns, page_no)) {
 			NS_WARN("simulating write failure in page %u\n", page_no);
@@ -2349,15 +2358,23 @@ static int __init ns_init_default(void)
 
 	nsmtd->owner = THIS_MODULE;
 
-	if ((retval = parse_weakblocks(nand)) != 0)
+	if ((retval = parse_weakblocks(nand, weakblocks)) != 0)
 		goto error;
 
-	if ((retval = parse_weakpages(nand)) != 0)
+	if ((retval = parse_weakpages(nand, weakpages)) != 0)
 		goto error;
 
-	if ((retval = parse_gravepages(nand)) != 0)
+	if ((retval = parse_gravepages(nand, gravepages)) != 0)
 		goto error;
 
+	nand->do_delays = do_delays;
+	nand->access_delay = access_delay;
+	nand->program_delay = programm_delay;
+	nand->erase_delay = erase_delay;
+	nand->output_cycle = output_cycle;
+	nand->input_cycle = input_cycle;
+	nand->bitflips = bitflips;
+
 	retval = nand_scan_ident(nsmtd, 1, NULL);
 	if (retval) {
 		NS_ERR("cannot scan NAND Simulator device\n");
@@ -2429,7 +2446,7 @@ static int __init ns_init_default(void)
 	if ((retval = chip->scan_bbt(nsmtd)) != 0)
 		goto err_exit;
 
-	if ((retval = parse_badblocks(nand, nsmtd)) != 0)
+	if ((retval = parse_badblocks(nand, nsmtd, badblocks)) != 0)
 		goto err_exit;
 
 	/* Register NAND partitions */
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473098 — [PATCH 01/46] mtdpart: Propagate _get/put_device()

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 01/46] mtdpart: Propagate _get/put_device()
Message-ID<sc8hP-7T2-15@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

If the master device has callbacks for _get/put_device()
and this MTD has slaves a get_mtd_device() call on paritions
will never issue the registered callbacks.
Fix this by propagating _get/put_device() down.

Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/mtdpart.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 1f13e32..ec852fa 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -317,6 +317,18 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	return res;
 }
 
+static int part_get_device(struct mtd_info *mtd)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+	return part->master->_get_device(part->master);
+}
+
+static void part_put_device(struct mtd_info *mtd)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+	part->master->_put_device(part->master);
+}
+
 static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
 			      struct mtd_oob_region *oobregion)
 {
@@ -463,6 +475,12 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 		slave->mtd._block_isbad = part_block_isbad;
 	if (master->_block_markbad)
 		slave->mtd._block_markbad = part_block_markbad;
+
+	if (master->_get_device)
+		slave->mtd._get_device = part_get_device;
+	if (master->_put_device)
+		slave->mtd._put_device = part_put_device;
+
 	slave->mtd._erase = part_erase;
 	slave->master = master;
 	slave->offset = part->offset;
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473099 — [PATCH 27/46] mtd: nandsim: Add no_oob mode

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 27/46] mtd: nandsim: Add no_oob mode
Message-ID<sc8hP-7T2-21@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

This allows using a nanddump image directly as file backend.
The use case is dumping without OOB from a real device,
startup nandsim with the same NAND ID an use the file.

That way NAND dumps can loaded into nandsim much faster
since no nandwrite is needed and, of course, less RAM is
consumed.

no_oob tells nandsim to not write nor read OOB data
from the backing file. If OOB data is requested it simply
returns 0xff.
This also means that no ECC is performed.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c  | 66 ++++++++++++++++++++++++++++++++++++++-------
 include/linux/mtd/nandsim.h |  1 +
 2 files changed, 58 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 116b1d1..f5aa0c4 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -221,7 +221,7 @@ MODULE_PARM_DESC(defaults,	 "Register a MTD during module load using default val
 
 /* Calculate the page offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET(ns) \
-	(((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
+	(((ns)->regs.row * ((ns)->no_oob ? (ns)->geom.pgsz : (ns)->geom.pgszoob)) + (ns)->regs.column)
 
 /* Calculate the OOB offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
@@ -360,6 +360,7 @@ struct nandsim {
                 int wp;  /* write Protect */
         } lines;
 
+	bool no_oob;
 	struct ns_backend_ops *bops;
 	void *backend_data;
 
@@ -1713,6 +1714,25 @@ static void ns_file_read_page(struct nandsim *ns, int num)
 
 	NS_DBG("read_page: page %d written, reading from %d\n",
 		ns->regs.row, ns->regs.column + ns->regs.off);
+
+	if (ns->no_oob) {
+		loff_t pg_read_end = ns->regs.column + ns->regs.off + num;
+
+		/* direct read from OOB */
+		if (ns->regs.column + ns->regs.off >= ns->geom.pgsz) {
+			memset(ns->buf.byte, 0xff, num);
+			return;
+		}
+
+		/* read overlapps into OOB, needs fixup */
+		if (pg_read_end > ns->geom.pgsz) {
+			loff_t oob_part = pg_read_end - ns->geom.pgsz;
+
+			memset(ns->buf.byte + pg_read_end - oob_part, 0xff, oob_part);
+			num -= oob_part;
+		}
+	}
+
 	pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
 	tx = kernel_read(data->file, pos, ns->buf.byte, num);
 	if (tx == 0)
@@ -1756,14 +1776,15 @@ static void ns_file_erase_sector(struct nandsim *ns)
 	int i;
 	loff_t pos;
 	ssize_t tx;
+	unsigned int pagesz = ns->no_oob ? ns->geom.pgsz : ns->geom.pgszoob;
 	struct ns_file_data *data = ns->backend_data;
 
-	memset(data->file_buf, 0xff, ns->geom.pgszoob);
+	memset(data->file_buf, 0xff, pagesz);
 
 	for (i = 0; i < ns->geom.pgsec; i++) {
-		pos = (loff_t)(ns->regs.row + i) * ns->geom.pgszoob;
-		tx = kernel_write(data->file, data->file_buf, ns->geom.pgszoob, pos);
-		if (tx != ns->geom.pgszoob) {
+		pos = (loff_t)(ns->regs.row + i) * pagesz;
+		tx = kernel_write(data->file, data->file_buf, pagesz, pos);
+		if (tx != pagesz) {
 			NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
 		}
 	}
@@ -1852,6 +1873,18 @@ static int ns_file_prog_page(struct nandsim *ns, int num)
 
 	NS_DBG("prog_page: writing page %d\n", ns->regs.row);
 
+	if (ns->no_oob) {
+		loff_t pg_write_end = ns->regs.column + ns->regs.off + num;
+
+		/* direct write into oob */
+		if (ns->regs.column + ns->regs.off >= ns->geom.pgsz)
+			return 0;
+
+		/* write overlapps into OOB, needs fixup */
+		if (pg_write_end > ns->geom.pgsz)
+			num -= pg_write_end - ns->geom.pgsz;
+	}
+
 	pg_off = data->file_buf + ns->regs.column + ns->regs.off;
 	off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
 
@@ -2001,7 +2034,11 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 			return -1;
 		}
 
-		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+		if (ns->no_oob)
+			num = ns->geom.pgsz - ns->regs.off - ns->regs.column;
+		else
+			num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+
 		if (num != ns->regs.count) {
 			NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
 					ns->regs.count, num);
@@ -2535,6 +2572,7 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 	memcpy(nsparam->id_bytes, req->id_bytes, sizeof(nsparam->id_bytes));
 	nsparam->bus_width = req->bus_width;
 	nsparam->file_fd = req->file_fd;
+	nsparam->no_oob = !!req->no_oob;
 
 	switch (req->backend) {
 		case NANDSIM_BACKEND_RAM:
@@ -2716,8 +2754,6 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	chip->write_buf  = ns_nand_write_buf;
 	chip->read_buf   = ns_nand_read_buf;
 	chip->read_word  = ns_nand_read_word;
-	chip->ecc.mode   = NAND_ECC_SOFT;
-	chip->ecc.algo   = NAND_ECC_HAMMING;
 	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
 	/* and 'badblocks' parameters to work */
 	chip->options   |= NAND_SKIP_BBTSCAN;
@@ -2784,7 +2820,16 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		goto error;
 	}
 
-	if (nsparam->bch) {
+	if (nsparam->no_oob) {
+		if (nsparam->bch) {
+			NS_ERR("Cannot use ECC without OOB\n");
+			retval = -EINVAL;
+			goto error;
+		}
+
+		chip->ecc.mode = NAND_ECC_NONE;
+		nand->no_oob = true;
+	} else if (nsparam->bch) {
 		unsigned int eccsteps, eccbytes;
 		if (!mtd_nand_has_bch()) {
 			NS_ERR("BCH ECC support is disabled\n");
@@ -2811,6 +2856,9 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		chip->ecc.strength = nsparam->bch;
 		chip->ecc.bytes = eccbytes;
 		NS_INFO("using %u-bit/%u bytes BCH ECC\n", nsparam->bch, chip->ecc.size);
+	} else {
+		chip->ecc.mode = NAND_ECC_SOFT;
+		chip->ecc.algo = NAND_ECC_HAMMING;
 	}
 
 	retval = nand_scan_tail(nsmtd);
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index d71a02f..05ac7e3 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -25,6 +25,7 @@ struct nandsim_params {
 	unsigned int bch;
 	unsigned char id_bytes[8];
 	unsigned int file_fd;
+	bool no_oob;
 	struct ns_backend_ops *bops;
 };
 
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473100 — [PATCH 14/46] mtd: nandsim: Add simulator id to MTD parition name

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 14/46] mtd: nandsim: Add simulator id to MTD parition name
Message-ID<sc8hQ-7T2-23@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

...also don't use spaces in the name. It allows
UBI attach via MTD name to function correctly.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index bef5afa..2e02089 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -732,9 +732,9 @@ static void free_device(struct nandsim *ns)
 	}
 }
 
-static char __init *get_partition_name(int i)
+static char *get_partition_name(struct nandsim *ns, int i)
 {
-	return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
+	return kasprintf(GFP_KERNEL, "nandsim%d_%d", ns->index, i);
 }
 
 /*
@@ -818,7 +818,7 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 			NS_ERR("bad partition size.\n");
 			return -EINVAL;
 		}
-		ns->partitions[i].name   = get_partition_name(i);
+		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
 			NS_ERR("unable to allocate memory.\n");
 			return -ENOMEM;
@@ -834,7 +834,7 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 			NS_ERR("too many partitions.\n");
 			return -EINVAL;
 		}
-		ns->partitions[i].name   = get_partition_name(i);
+		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
 			NS_ERR("unable to allocate memory.\n");
 			return -ENOMEM;
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473101 — [PATCH 44/46] mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 44/46] mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE
Message-ID<sc8hQ-7T2-29@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

The logic for destroying nandsim instances now also ready.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 4145ab6..8a63812 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2922,6 +2922,19 @@ static long ns_ctrl_ioctl(struct file *file, unsigned int cmd,
 			ret = ns_ctrl_new_instance(&req, argp + sizeof(req));
 			break;
 		}
+		case NANDSIM_IOC_DESTROY_INSTANCE:
+		{
+			struct ns_destroy_instance_req req;
+
+			ret = copy_from_user(&req, argp, sizeof(struct ns_destroy_instance_req));
+			if (ret) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			ret = ns_ctrl_destroy_instance(&req);
+			break;
+		}
 
 		default:
 			ret = -ENOTTY;
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473102 — [PATCH 11/46] mtd: nandsim: Factor out nandsim parameters

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 11/46] mtd: nandsim: Factor out nandsim parameters
Message-ID<sc8hQ-7T2-31@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

...such that we have a way to pass different
parameters to different instances.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 129 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 93 insertions(+), 36 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index f26e983..ab4859d 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -289,6 +289,28 @@ MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
 /* Maximum page cache pages needed to read or write a NAND page to the cache_file */
 #define NS_MAX_HELD_PAGES 16
 
+struct nandsim_params {
+	unsigned int access_delay;
+	unsigned int program_delay;
+	unsigned int erase_delay;
+	unsigned int output_cycle;
+	unsigned int input_cycle;
+	unsigned int bus_width;
+	unsigned int do_delays;
+	unsigned long *parts;
+	unsigned int parts_num;
+	char *badblocks;
+	char *weakblocks;
+	char *weakpages;
+	unsigned int bitflips;
+	char *gravepages;
+	unsigned int overridesize;
+	char *cache_file;
+	unsigned int bbt;
+	unsigned int bch;
+	unsigned char *id_bytes;
+};
+
 struct nandsim_debug_info {
 	struct dentry *dfs_root;
 	struct dentry *dfs_wear_report;
@@ -593,13 +615,13 @@ static void nandsim_debugfs_remove(struct nandsim *ns)
  *
  * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
  */
-static int __init alloc_device(struct nandsim *ns)
+static int alloc_device(struct nandsim *ns, struct nandsim_params *nsparam)
 {
 	struct file *cfile;
 	int i, err;
 
-	if (cache_file) {
-		cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+	if (nsparam->cache_file) {
+		cfile = filp_open(nsparam->cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
 		if (IS_ERR(cfile))
 			return PTR_ERR(cfile);
 		if (!(cfile->f_mode & FMODE_CAN_READ)) {
@@ -688,7 +710,7 @@ static char __init *get_partition_name(int i)
  *
  * RETURNS: 0 if success, -ERRNO if failure.
  */
-static int __init init_nandsim(struct mtd_info *mtd)
+static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 	struct nandsim   *ns   = nand_get_controller_data(chip);
@@ -751,14 +773,14 @@ static int __init init_nandsim(struct mtd_info *mtd)
 	}
 
 	/* Fill the partition_info structure */
-	if (parts_num > ARRAY_SIZE(ns->partitions)) {
+	if (nsparam->parts_num > ARRAY_SIZE(ns->partitions)) {
 		NS_ERR("too many partitions.\n");
 		return -EINVAL;
 	}
 	remains = ns->geom.totsz;
 	next_offset = 0;
-	for (i = 0; i < parts_num; ++i) {
-		uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;
+	for (i = 0; i < nsparam->parts_num; ++i) {
+		uint64_t part_sz = (uint64_t)nsparam->parts[i] * ns->geom.secsz;
 
 		if (!part_sz || part_sz > remains) {
 			NS_ERR("bad partition size.\n");
@@ -774,9 +796,9 @@ static int __init init_nandsim(struct mtd_info *mtd)
 		next_offset += ns->partitions[i].size;
 		remains -= ns->partitions[i].size;
 	}
-	ns->nbparts = parts_num;
+	ns->nbparts = nsparam->parts_num;
 	if (remains) {
-		if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
+		if (nsparam->parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
 			NS_ERR("too many partitions.\n");
 			return -EINVAL;
 		}
@@ -810,7 +832,7 @@ static int __init init_nandsim(struct mtd_info *mtd)
 	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
 	printk("options: %#x\n",                ns->options);
 
-	if ((ret = alloc_device(ns)) != 0)
+	if ((ret = alloc_device(ns, nsparam)) != 0)
 		return ret;
 
 	/* Allocate / initialize the internal buffer */
@@ -2289,15 +2311,16 @@ static struct miscdevice nandsim_ctrl_cdev = {
 	.fops = &nansim_ctrl_fops,
 };
 
-static int __init ns_init_default(void)
+static int ns_new_instance(struct nandsim_params *nsparam)
 {
 	struct nand_chip *chip;
 	struct nandsim *nand;
 	struct mtd_info *nsmtd;
 	int retval = -ENOMEM, i;
+	unsigned char *id_bytes = nsparam->id_bytes;
 
-	if (bus_width != 8 && bus_width != 16) {
-		NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
+	if (nsparam->bus_width != 8 && nsparam->bus_width != 16) {
+		NS_ERR("wrong bus width (%d), use only 8 or 16\n", nsparam->bus_width);
 		return -EINVAL;
 	}
 
@@ -2334,7 +2357,7 @@ static int __init ns_init_default(void)
 	/* and 'badblocks' parameters to work */
 	chip->options   |= NAND_SKIP_BBTSCAN;
 
-	switch (bbt) {
+	switch (nsparam->bbt) {
 	case 2:
 		 chip->bbt_options |= NAND_BBT_NO_OOB;
 	case 1:
@@ -2362,29 +2385,29 @@ static int __init ns_init_default(void)
 	nand->nxstate = STATE_UNKNOWN;
 	nand->options |= OPT_PAGE512; /* temporary value */
 	memcpy(nand->ids, id_bytes, sizeof(nand->ids));
-	if (bus_width == 16) {
+	if (nsparam->bus_width == 16) {
 		nand->busw = 16;
 		chip->options |= NAND_BUSWIDTH_16;
 	}
 
 	nsmtd->owner = THIS_MODULE;
 
-	if ((retval = parse_weakblocks(nand, weakblocks)) != 0)
+	if ((retval = parse_weakblocks(nand, nsparam->weakblocks)) != 0)
 		goto error;
 
-	if ((retval = parse_weakpages(nand, weakpages)) != 0)
+	if ((retval = parse_weakpages(nand, nsparam->weakpages)) != 0)
 		goto error;
 
-	if ((retval = parse_gravepages(nand, gravepages)) != 0)
+	if ((retval = parse_gravepages(nand, nsparam->gravepages)) != 0)
 		goto error;
 
-	nand->do_delays = do_delays;
-	nand->access_delay = access_delay;
-	nand->program_delay = programm_delay;
-	nand->erase_delay = erase_delay;
-	nand->output_cycle = output_cycle;
-	nand->input_cycle = input_cycle;
-	nand->bitflips = bitflips;
+	nand->do_delays = nsparam->do_delays;
+	nand->access_delay = nsparam->access_delay;
+	nand->program_delay = nsparam->program_delay;
+	nand->erase_delay = nsparam->erase_delay;
+	nand->output_cycle = nsparam->output_cycle;
+	nand->input_cycle = nsparam->input_cycle;
+	nand->bitflips = nsparam->bitflips;
 
 	retval = nand_scan_ident(nsmtd, 1, NULL);
 	if (retval) {
@@ -2394,7 +2417,7 @@ static int __init ns_init_default(void)
 		goto error;
 	}
 
-	if (bch) {
+	if (nsparam->bch) {
 		unsigned int eccsteps, eccbytes;
 		if (!mtd_nand_has_bch()) {
 			NS_ERR("BCH ECC support is disabled\n");
@@ -2403,7 +2426,7 @@ static int __init ns_init_default(void)
 		}
 		/* use 512-byte ecc blocks */
 		eccsteps = nsmtd->writesize/512;
-		eccbytes = (bch*13+7)/8;
+		eccbytes = (nsparam->bch * 13 + 7) / 8;
 		/* do not bother supporting small page devices */
 		if ((nsmtd->oobsize < 64) || !eccsteps) {
 			NS_ERR("bch not available on small page devices\n");
@@ -2411,16 +2434,16 @@ static int __init ns_init_default(void)
 			goto error;
 		}
 		if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
-			NS_ERR("invalid bch value %u\n", bch);
+			NS_ERR("invalid bch value %u\n", nsparam->bch);
 			retval = -EINVAL;
 			goto error;
 		}
 		chip->ecc.mode = NAND_ECC_SOFT;
 		chip->ecc.algo = NAND_ECC_BCH;
 		chip->ecc.size = 512;
-		chip->ecc.strength = bch;
+		chip->ecc.strength = nsparam->bch;
 		chip->ecc.bytes = eccbytes;
-		NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
+		NS_INFO("using %u-bit/%u bytes BCH ECC\n", nsparam->bch, chip->ecc.size);
 	}
 
 	retval = nand_scan_tail(nsmtd);
@@ -2431,9 +2454,9 @@ static int __init ns_init_default(void)
 		goto error;
 	}
 
-	if (overridesize) {
-		uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
-		if (new_size >> overridesize != nsmtd->erasesize) {
+	if (nsparam->overridesize) {
+		uint64_t new_size = (uint64_t)nsmtd->erasesize << nsparam->overridesize;
+		if (new_size >> nsparam->overridesize != nsmtd->erasesize) {
 			NS_ERR("overridesize is too big\n");
 			retval = -EINVAL;
 			goto err_exit;
@@ -2441,7 +2464,7 @@ static int __init ns_init_default(void)
 		/* N.B. This relies on nand_scan not doing anything with the size before we change it */
 		nsmtd->size = new_size;
 		chip->chipsize = new_size;
-		chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
+		chip->chip_shift = ffs(nsmtd->erasesize) + nsparam->overridesize - 1;
 		chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
 	}
 
@@ -2451,13 +2474,13 @@ static int __init ns_init_default(void)
 	if ((retval = nandsim_debugfs_create(nand)) != 0)
 		goto err_exit;
 
-	if ((retval = init_nandsim(nsmtd)) != 0)
+	if ((retval = init_nandsim(nsmtd, nsparam)) != 0)
 		goto err_exit;
 
 	if ((retval = chip->scan_bbt(nsmtd)) != 0)
 		goto err_exit;
 
-	if ((retval = parse_badblocks(nand, nsmtd, badblocks)) != 0)
+	if ((retval = parse_badblocks(nand, nsmtd, nsparam->badblocks)) != 0)
 		goto err_exit;
 
 	/* Register NAND partitions */
@@ -2496,6 +2519,40 @@ static void __exit ns_cleanup_default(void)
 	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
 }
 
+static int __init ns_init_default(void)
+{
+	int ret;
+	struct nandsim_params *nsparam = kzalloc(sizeof(*nsparam), GFP_KERNEL);
+
+	if (!nsparam)
+		return -ENOMEM;
+
+	nsparam->access_delay = access_delay;
+	nsparam->program_delay = programm_delay;
+	nsparam->erase_delay = erase_delay;
+	nsparam->output_cycle = output_cycle;
+	nsparam->input_cycle = input_cycle;
+	nsparam->bus_width = bus_width;
+	nsparam->do_delays = do_delays;
+	nsparam->parts = parts;
+	nsparam->parts_num = parts_num;
+	nsparam->badblocks = badblocks;
+	nsparam->weakblocks = weakblocks;
+	nsparam->weakpages = weakpages;
+	nsparam->bitflips = bitflips;
+	nsparam->gravepages = gravepages;
+	nsparam->overridesize = overridesize;
+	nsparam->cache_file = cache_file;
+	nsparam->bbt = bbt;
+	nsparam->bch = bch;
+	nsparam->id_bytes = id_bytes;
+
+	ret = ns_new_instance(nsparam);
+	kfree(nsparam);
+
+	return ret;
+}
+
 static int __init ns_init_module(void)
 {
 	int ret;
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473103 — [PATCH 33/46] mtd: nandsim: Relax page size restrictions

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 33/46] mtd: nandsim: Relax page size restrictions
Message-ID<sc8hQ-7T2-25@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Allow any page size as long it is a power of two and less
than KMALLOC_MAX_SIZE.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index f0b6c1f..75bf45a74 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -176,9 +176,6 @@ MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
 MODULE_PARM_DESC(defaults,	 "Register a MTD during module load using default values and module parametes. "
 				 "Set to N if you want to use the nandsimctl user space tool to setup nandsim.");
 
-/* The largest possible page size */
-#define NS_LARGEST_PAGE_SIZE	4096
-
 /* Busy-wait delay macros (microseconds, milliseconds) */
 #define NS_UDELAY(ns, us) \
 	do { if (ns->do_delays) udelay(us); } while (0)
@@ -247,10 +244,8 @@ MODULE_PARM_DESC(defaults,	 "Register a MTD during module load using default val
 
 #define OPT_ANY          0xFFFFFFFF /* any chip supports this operation */
 #define OPT_PAGE512      0x00000002 /* 512-byte  page chips */
-#define OPT_PAGE2048     0x00000008 /* 2048-byte page chips */
+#define OPT_LARGEPAGE    0x00000008 /* >= 2048-byte page chips */
 #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
-#define OPT_PAGE4096     0x00000080 /* 4096-byte page chips */
-#define OPT_LARGEPAGE    (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
 #define OPT_SMALLPAGE    (OPT_PAGE512) /* 512-byte page chips */
 
 /* Remove action bits from state */
@@ -858,13 +853,18 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 		ns->options |= OPT_PAGE512;
 		if (ns->busw == 8)
 			ns->options |= OPT_PAGE512_8BIT;
-	} else if (ns->geom.pgsz == 2048) {
-		ns->options |= OPT_PAGE2048;
-	} else if (ns->geom.pgsz == 4096) {
-		ns->options |= OPT_PAGE4096;
-	} else {
-		pr_err("unknown page size %u\n", ns->geom.pgsz);
-		return -EIO;
+	} else if (ns->geom.pgsz >= 2048) {
+		ns->options |= OPT_LARGEPAGE;
+	}
+
+	if (!is_power_of_2(ns->geom.pgsz)) {
+		pr_err("page size is not a power of two.\n");
+		return -EINVAL;
+	}
+
+	if (ns->geom.pgszoob > KMALLOC_MAX_SIZE) {
+		pr_err("page size plus oob too large: %u.\n", ns->geom.pgszoob);
+		return -EINVAL;
 	}
 
 	if (ns->options & OPT_SMALLPAGE) {
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473105 — [PATCH 38/46] mtd: nandsim: Expose partition creation logic to user space

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 38/46] mtd: nandsim: Expose partition creation logic to user space
Message-ID<sc8hQ-7T2-35@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c  | 12 +++++++++++-
 include/linux/mtd/nandsim.h |  2 +-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 584fc72..05a3088 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2585,6 +2585,16 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 	nsparam->file_fd = req->file_fd;
 	nsparam->no_oob = !!req->no_oob;
 
+	if (req->parts_num > NANDSIM_MAX_PARTS || req->parts_num < 0) {
+		kfree(nsparam);
+		return -EINVAL;
+	}
+
+	if (req->parts_num > 0) {
+		nsparam->parts_num = req->parts_num;
+		memcpy(nsparam->parts, req->parts, sizeof(nsparam->parts));
+	}
+
 	switch (req->backend) {
 		case NANDSIM_BACKEND_RAM:
 			nsparam->bops = &ns_ram_bops;
@@ -2978,7 +2988,7 @@ static int __init ns_init_default(void)
 	nsparam->input_cycle = input_cycle;
 	nsparam->bus_width = bus_width;
 	nsparam->do_delays = do_delays;
-	nsparam->parts = parts;
+	memcpy(nsparam->parts, parts, sizeof(nsparam->parts));
 	nsparam->parts_num = parts_num;
 	nsparam->badblocks = badblocks;
 	nsparam->weakblocks = weakblocks;
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index 61ff5dd..07d32a9 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -12,7 +12,7 @@ struct nandsim_params {
 	unsigned int input_cycle;
 	unsigned int bus_width;
 	unsigned int do_delays;
-	unsigned int *parts;
+	unsigned int parts[NANDSIM_MAX_PARTS];
 	unsigned int parts_num;
 	char *badblocks;
 	char *weakblocks;
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473106 — [PATCH 24/46] mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 24/46] mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode
Message-ID<sc8hQ-7T2-55@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Allow the userspace control tool also to setup a cache file.
In contrast to the cache_file module parameter the ioctl() only
accepts a fd. So, userspace should hand in an fd pointing to
a temp file.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index f936157..47d8d41 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2536,10 +2536,15 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 		case NANDSIM_BACKEND_RAM:
 			nsparam->bops = &ns_ram_bops;
 		break;
+
 		case NANDSIM_BACKEND_FILE:
 			nsparam->bops = &ns_file_bops;
 		break;
 
+		case NANDSIM_BACKEND_CACHEFILE:
+			nsparam->bops = &ns_cachefile_bops;
+		break;
+
 		default:
 			kfree(nsparam);
 			return -EINVAL;
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473107 — [PATCH 39/46] mtd: nandsim: Rework init error paths

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 39/46] mtd: nandsim: Rework init error paths
Message-ID<sc8hQ-7T2-37@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 97 +++++++++++++++++++++++++++-------------------
 1 file changed, 57 insertions(+), 40 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 05a3088..027b15d 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -871,12 +871,14 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 
 		if (!part_sz || part_sz > remains) {
 			pr_err("bad partition size.\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto err_names;
 		}
 		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
 			pr_err("unable to allocate memory.\n");
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_names;
 		}
 		ns->partitions[i].offset = next_offset;
 		ns->partitions[i].size   = part_sz;
@@ -887,12 +889,14 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	if (remains) {
 		if (nsparam->parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
 			pr_err("too many partitions.\n");
-			return -EINVAL;
+			ret = -EINVAL;
+			goto err_names;
 		}
 		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
 			pr_err("unable to allocate memory.\n");
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_names;
 		}
 		ns->partitions[i].offset = next_offset;
 		ns->partitions[i].size   = remains;
@@ -921,22 +925,24 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 
 	ns->bops = nsparam->bops;
 
-	pr_info("Using backend: %s\n", ns->bops->name);
-	if ((ret = ns->bops->init(ns, nsparam)) != 0) {
-		pr_err("Unable to initialize simulator backend: %i\n", ret);
-		return ret;
-	}
-
 	/* Allocate / initialize the internal buffer */
 	ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
 	if (!ns->buf.byte) {
 		pr_err("unable to allocate %u bytes for the internal buffer\n",
 			ns->geom.pgszoob);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_buf;
 	}
 	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
 
 	return 0;
+
+err_buf:
+	kfree(ns->buf.byte);
+err_names:
+	for (i = 0; i < ARRAY_SIZE(ns->partitions); i++)
+		kfree(ns->partitions[i].name);
+	return ret;
 }
 
 /*
@@ -944,8 +950,11 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
  */
 static void free_nandsim(struct nandsim *ns)
 {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ns->partitions); i++)
+		kfree(ns->partitions[i].name);
 	kfree(ns->buf.byte);
-	ns->bops->destroy(ns);
 }
 
 static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd,
@@ -2751,7 +2760,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		pr_err("Cannot allocate more than %i instances!\n", NANDSIM_MAX_DEVICES);
 		retval = -ENFILE;
 		mutex_unlock(&ns_mtd_mutex);
-		goto error;
+		goto err_chip;
 	}
 
 	nsmtd = ns_mtds[i] = nand_to_mtd(chip);
@@ -2789,7 +2798,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	default:
 		pr_err("bbt has to be 0..2\n");
 		retval = -EINVAL;
-		goto error;
+		goto err_mtds;
 	}
 	/*
 	 * Perform minimum nandsim structure initialization to handle
@@ -2817,13 +2826,13 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	nsmtd->_put_device = ns_put_device;
 
 	if ((retval = parse_weakblocks(nand, nsparam->weakblocks)) != 0)
-		goto error;
+		goto err_lists;
 
 	if ((retval = parse_weakpages(nand, nsparam->weakpages)) != 0)
-		goto error;
+		goto err_lists;
 
 	if ((retval = parse_gravepages(nand, nsparam->gravepages)) != 0)
-		goto error;
+		goto err_lists;
 
 	nand->do_delays = nsparam->do_delays;
 	nand->access_delay = nsparam->access_delay;
@@ -2838,14 +2847,14 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		pr_err("cannot scan NAND Simulator device\n");
 		if (retval > 0)
 			retval = -ENXIO;
-		goto error;
+		goto err_lists;
 	}
 
 	if (nsparam->no_oob) {
 		if (nsparam->bch) {
 			pr_err("Cannot use ECC without OOB\n");
 			retval = -EINVAL;
-			goto error;
+			goto err_lists;
 		}
 
 		chip->ecc.mode = NAND_ECC_NONE;
@@ -2855,7 +2864,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		if (!mtd_nand_has_bch()) {
 			pr_err("BCH ECC support is disabled\n");
 			retval = -EINVAL;
-			goto error;
+			goto err_lists;
 		}
 		/* use 512-byte ecc blocks */
 		eccsteps = nsmtd->writesize/512;
@@ -2864,12 +2873,12 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		if ((nsmtd->oobsize < 64) || !eccsteps) {
 			pr_err("bch not available on small page devices\n");
 			retval = -EINVAL;
-			goto error;
+			goto err_lists;
 		}
 		if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
 			pr_err("invalid bch value %u\n", nsparam->bch);
 			retval = -EINVAL;
-			goto error;
+			goto err_lists;
 		}
 		chip->ecc.mode = NAND_ECC_SOFT;
 		chip->ecc.algo = NAND_ECC_BCH;
@@ -2887,7 +2896,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		pr_err("can't register NAND Simulator\n");
 		if (retval > 0)
 			retval = -ENXIO;
-		goto error;
+		goto err_lists;
 	}
 
 	if (nsparam->overridesize) {
@@ -2895,7 +2904,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		if (new_size >> nsparam->overridesize != nsmtd->erasesize) {
 			pr_err("overridesize is too big\n");
 			retval = -EINVAL;
-			goto err_exit;
+			goto err_nand;
 		}
 		/* N.B. This relies on nand_scan not doing anything with the size before we change it */
 		nsmtd->size = new_size;
@@ -2905,35 +2914,45 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	}
 
 	if ((retval = setup_wear_reporting(nsmtd)) != 0)
-		goto err_exit;
+		goto err_nand;
 
 	if ((retval = nandsim_debugfs_create(nand)) != 0)
-		goto err_exit;
+		goto err_nand;
 
 	if ((retval = init_nandsim(nsmtd, nsparam)) != 0)
-		goto err_exit;
+		goto err_debugfs;
+
+	pr_info("Using backend: %s\n", nand->bops->name);
+	if ((retval = nand->bops->init(nand, nsparam)) != 0) {
+		pr_err("Unable to initialize simulator backend: %i\n", retval);
+		goto err_nandsim;
+	}
 
 	if ((retval = chip->scan_bbt(nsmtd)) != 0)
-		goto err_exit;
+		goto err_nandsim;
 
 	if ((retval = parse_badblocks(nand, nsmtd, nsparam->badblocks)) != 0)
-		goto err_exit;
+		goto err_nandsim;
 
 	/* Register NAND partitions */
 	retval = mtd_device_register(nsmtd, &nand->partitions[0],
 				     nand->nbparts);
 	if (retval != 0)
-		goto err_exit;
+		goto err_nandsim;
 
 	return nsmtd;
 
-err_exit:
+err_nandsim:
 	free_nandsim(nand);
+err_debugfs:
+	nandsim_debugfs_remove(nand);
+err_nand:
 	nand_release(nsmtd);
-	for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
-		kfree(nand->partitions[i].name);
-error:
+err_lists:
 	free_lists(nand);
+err_mtds:
+	ns_mtds[nand->index] = NULL;
+err_chip:
 	kfree(chip);
 
 	return ERR_PTR(retval);
@@ -2942,7 +2961,7 @@ EXPORT_SYMBOL_GPL(ns_new_instance);
 
 int ns_destroy_instance(struct mtd_info *nsmtd)
 {
-	int i, ret;
+	int ret;
 	struct nand_chip *chip = mtd_to_nand(nsmtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 
@@ -2951,12 +2970,10 @@ int ns_destroy_instance(struct mtd_info *nsmtd)
 		return ret;
 
 	nandsim_debugfs_remove(ns);
+	ns->bops->destroy(ns);
+	free_nandsim(ns);
 	free_lists(ns);
-	free_nandsim(ns);    /* Free nandsim private resources */
-	nand_release(nsmtd); /* Unregister driver */
-	for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
-		kfree(ns->partitions[i].name);
-	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
+	kfree(chip);
 
 	return 0;
 }
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


#1473108 — [PATCH 18/46] mtd: nandsim: Add basic support for a file backend

FromDaniel Walter <dwalter@sigma-star.at>
Date2016-08-31 09:40 +0200
Subject[PATCH 18/46] mtd: nandsim: Add basic support for a file backend
Message-ID<sc8hQ-7T2-45@gated-at.bofh.it>
In reply to#1473080
From: Richard Weinberger <richard@nod.at>

This is the first step to allow using a file as
backing store. Such that it is possible to directly
use nanddump images in nandsim.
The current file cache mode is not desiged for this
since it maintains an in memory list of erased block
to skipt 0xff reads/writes. Further more it utilizes
the page cache to be fast and caching only.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c  | 143 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nandsim.h |   1 +
 2 files changed, 144 insertions(+)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 21a6e1a..2e3c08e 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -49,6 +49,7 @@
 #include <linux/miscdevice.h>
 #include <linux/major.h>
 #include <linux/mutex.h>
+#include <linux/file.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -316,6 +317,12 @@ struct ns_cachefile_data {
 	int held_cnt;
 };
 
+struct ns_file_data {
+	struct file *file;
+	void *file_buf;
+	bool ro;
+};
+
 /*
  * The structure which describes all the internal simulator data.
  */
@@ -671,6 +678,59 @@ err_close:
 	return err;
 }
 
+static int ns_file_init(struct nandsim *ns, struct nandsim_params *nsparam)
+{
+	int ret;
+	struct file *file;
+	struct inode *inode;
+	struct ns_file_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+
+	if (!data) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	file = fget(nsparam->file_fd);
+	if (!file) {
+		ret = -EBADF;
+		goto out_free;
+	}
+
+	inode = file->f_mapping->host;
+	if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) {
+		NS_ERR("alloc_device: Backend file is not a regular file nor a block device\n");
+		ret = -EINVAL;
+		goto out_put;
+	}
+
+	if (!(file->f_mode & FMODE_WRITE)) {
+		NS_ERR("alloc_device: Backend file is not writeable\n");
+		ret = -EINVAL;
+		goto out_put;
+	}
+
+	data->file = file;
+
+	data->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+	if (!data->file_buf) {
+		NS_ERR("alloc_device: unable to allocate file buf\n");
+		ret = -ENOMEM;
+		goto out_put;
+	}
+
+	ns->backend_data = data;
+	ret = 0;
+
+	return ret;
+
+out_put:
+	fput(file);
+out_free:
+	kfree(data);
+out:
+	return ret;
+}
+
 struct nandsim_geom *nandsim_get_geom(struct nandsim *ns)
 {
 	return &ns->geom;
@@ -725,6 +785,15 @@ static void ns_cachefile_destroy(struct nandsim *ns)
 	filp_close(data->cfile, NULL);
 }
 
+static void ns_file_destroy(struct nandsim *ns)
+{
+	struct ns_file_data *data = ns->backend_data;
+
+	kfree(data->file_buf);
+	fput(data->file);
+	kfree(data);
+}
+
 static char *get_partition_name(struct nandsim *ns, int i)
 {
 	return kasprintf(GFP_KERNEL, "nandsim%d_%d", ns->index, i);
@@ -1587,6 +1656,22 @@ static void ns_cachefile_read_page(struct nandsim *ns, int num)
 	}
 }
 
+static void ns_file_read_page(struct nandsim *ns, int num)
+{
+	struct ns_file_data *data = ns->backend_data;
+	loff_t pos;
+	ssize_t tx;
+
+	NS_DBG("read_page: page %d written, reading from %d\n",
+		ns->regs.row, ns->regs.column + ns->regs.off);
+	pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+	tx = kernel_read(data->file, pos, ns->buf.byte, num);
+	if (tx == 0)
+		memset(ns->buf.byte, 0xff, num);
+	else if (tx != num)
+		NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+}
+
 static void ns_ram_erase_sector(struct nandsim *ns)
 {
 	union ns_mem *mypage;
@@ -1617,6 +1702,24 @@ static void ns_cachefile_erase_sector(struct nandsim *ns)
 	}
 }
 
+static void ns_file_erase_sector(struct nandsim *ns)
+{
+	int i;
+	loff_t pos;
+	ssize_t tx;
+	struct ns_file_data *data = ns->backend_data;
+
+	memset(data->file_buf, 0xff, ns->geom.pgszoob);
+
+	for (i = 0; i < ns->geom.pgsec; i++) {
+		pos = (loff_t)(ns->regs.row + i) * ns->geom.pgszoob;
+		tx = kernel_write(data->file, data->file_buf, ns->geom.pgszoob, pos);
+		if (tx != ns->geom.pgszoob) {
+			NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+		}
+	}
+}
+
 static int ns_ram_prog_page(struct nandsim *ns, int num)
 {
 	int i;
@@ -1690,6 +1793,39 @@ static int ns_cachefile_prog_page(struct nandsim *ns, int num)
 	return 0;
 }
 
+static int ns_file_prog_page(struct nandsim *ns, int num)
+{
+	int i;
+	loff_t off;
+	ssize_t tx;
+	u_char *pg_off;
+	struct ns_file_data *data = ns->backend_data;
+
+	NS_DBG("prog_page: writing page %d\n", ns->regs.row);
+
+	pg_off = data->file_buf + ns->regs.column + ns->regs.off;
+	off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+
+	tx = kernel_read(data->file, off, pg_off, num);
+	if (tx == 0)
+		memset(pg_off, 0xff, num);
+	else if (tx != num) {
+		NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+		return -1;
+	}
+
+	for (i = 0; i < num; i++)
+		pg_off[i] &= ns->buf.byte[i];
+
+	tx = kernel_write(data->file, pg_off, num, off);
+	if (tx != num) {
+		NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+		return -1;
+	}
+
+	return 0;
+}
+
 static struct ns_backend_ops ns_ram_bops = {
 	.erase_sector = ns_ram_erase_sector,
 	.prog_page = ns_ram_prog_page,
@@ -1706,6 +1842,13 @@ static struct ns_backend_ops ns_cachefile_bops = {
 	.destroy = ns_cachefile_destroy,
 };
 
+static struct ns_backend_ops ns_file_bops = {
+	.erase_sector = ns_file_erase_sector,
+	.prog_page = ns_file_prog_page,
+	.read_page = ns_file_read_page,
+	.init = ns_file_init,
+	.destroy = ns_file_destroy,
+};
 
 /*
  * If state has any action bit, perform this action.
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index 2d596ad..e3d2c9f 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -23,6 +23,7 @@ struct nandsim_params {
 	unsigned int bbt;
 	unsigned int bch;
 	unsigned char *id_bytes;
+	unsigned int file_fd;
 	struct ns_backend_ops *bops;
 };
 
-- 
2.8.3

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | linux.kernel


csiph-web