linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/46] Nandsim facelift (part I of II)
@ 2016-09-21  9:43 Daniel Walter
  2016-09-21  9:43 ` [PATCH v2 01/46] mtdpart: Propagate _get/put_device() Daniel Walter
                   ` (46 more replies)
  0 siblings, 47 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:43 UTC (permalink / raw)
  To: linux-mtd; +Cc: linux-kernel, Daniel Walter

Changes since V1:
  Incooperate feedback for nand_cleanup()
  Improve commit messages



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: Provide nand_cleanup() function to free NAND related
    resources
  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    |   18 +-
 drivers/mtd/nand/nandsim.c      | 2141 ++++++++++++++++++++++++++++-----------
 include/linux/mtd/nand.h        |    1 +
 include/linux/mtd/nandsim.h     |   79 ++
 include/uapi/mtd/nandsim-user.h |  113 +++
 10 files changed, 1961 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

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
@ 2016-09-21  9:43 ` Daniel Walter
  2016-09-21 10:15   ` Boris Brezillon
  2016-09-21  9:44 ` [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources Daniel Walter
                   ` (45 subsequent siblings)
  46 siblings, 1 reply; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:43 UTC (permalink / raw)
  To: linux-mtd; +Cc: linux-kernel, computersforpeace, dwmw2, Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
  2016-09-21  9:43 ` [PATCH v2 01/46] mtdpart: Propagate _get/put_device() Daniel Walter
@ 2016-09-21  9:44 ` Daniel Walter
  2016-09-21  9:58   ` Boris Brezillon
                     ` (2 more replies)
  2016-09-21  9:45 ` [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier Daniel Walter
                   ` (44 subsequent siblings)
  46 siblings, 3 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:44 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, boris.brezillon,
	Richard Weinberger, Daniel Walter

From: Richard Weinberger <richard@nod.at>

Provide a nand_cleanup() function to free all nand related resources
without unregistering the mtd device.
This should allow drivers to call mtd_device_unregister() and handle
its return value and still being able to cleanup all nand related
resources.

Signed-off-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Daniel Walter <dwalter@sigma-star.at>
---
 drivers/mtd/nand/nand_base.c | 18 +++++++++++++-----
 include/linux/mtd/nand.h     |  1 +
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 77533f7..e743052 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4601,10 +4601,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
 EXPORT_SYMBOL(nand_scan);
 
 /**
- * nand_release - [NAND Interface] Free resources held by the NAND device
- * @mtd: MTD device structure
+ * nand_cleanup - [NAND Interface] Free resources held by the NAND device
+ * @mts: MTD device structure
  */
-void nand_release(struct mtd_info *mtd)
+void nand_cleanup(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
@@ -4612,8 +4612,6 @@ void nand_release(struct mtd_info *mtd)
 	    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))
@@ -4624,6 +4622,16 @@ void nand_release(struct mtd_info *mtd)
 			& NAND_BBT_DYNAMICSTRUCT)
 		kfree(chip->badblock_pattern);
 }
+
+/**
+ * nand_release - [NAND Interface] Free resources held by the NAND device
+ * @mtd: MTD device structure
+ */
+void nand_release(struct mtd_info *mtd)
+{
+	mtd_device_unregister(mtd);
+	nand_cleanup(mtd);
+}
 EXPORT_SYMBOL_GPL(nand_release);
 
 MODULE_LICENSE("GPL");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 8dd6e01..c692c06 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -39,6 +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_cleanup(struct mtd_info *mtd);
 extern void nand_release(struct mtd_info *mtd);
 
 /* Internal helper for board drivers which need to override command function */
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
  2016-09-21  9:43 ` [PATCH v2 01/46] mtdpart: Propagate _get/put_device() Daniel Walter
  2016-09-21  9:44 ` [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources Daniel Walter
@ 2016-09-21  9:45 ` Daniel Walter
  2016-09-21 14:31   ` Boris Brezillon
  2016-10-09  5:20   ` Brian Norris
  2016-09-21  9:45 ` [PATCH v2 04/46] mtd: Don't unconditionally execute remove notifiers Daniel Walter
                   ` (43 subsequent siblings)
  46 siblings, 2 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:45 UTC (permalink / raw)
  To: linux-mtd; +Cc: linux-kernel, computersforpeace, Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 04/46] mtd: Don't unconditionally execute remove notifiers
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (2 preceding siblings ...)
  2016-09-21  9:45 ` [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier Daniel Walter
@ 2016-09-21  9:45 ` Daniel Walter
  2016-09-21  9:46 ` [PATCH v2 05/46] mtd: Don't print a scary message when trying to remove a busy MTD Daniel Walter
                   ` (42 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:45 UTC (permalink / raw)
  To: linux-mtd; +Cc: linux-kernel, computersforpeace, dwmw2, Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Only call them when we're really removing the MTD.

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

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 36e5fb0..b8205ec 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -499,16 +499,17 @@ int del_mtd_device(struct mtd_info *mtd)
 		goto out_error;
 	}
 
-	/* No need to get a refcount on the module containing
-		the notifier, since we hold the mtd_table_mutex */
-	list_for_each_entry(not, &mtd_notifiers, list)
-		not->remove(mtd);
-
 	if (mtd->usecount) {
 		printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
 		       mtd->index, mtd->name, mtd->usecount);
 		ret = -EBUSY;
 	} else {
+		/* No need to get a refcount on the module containing
+		 * the notifier, since we hold the mtd_table_mutex
+		 */
+		list_for_each_entry(not, &mtd_notifiers, list)
+			not->remove(mtd);
+
 		device_unregister(&mtd->dev);
 
 		idr_remove(&mtd_idr, mtd->index);
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 05/46] mtd: Don't print a scary message when trying to remove a busy MTD
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (3 preceding siblings ...)
  2016-09-21  9:45 ` [PATCH v2 04/46] mtd: Don't unconditionally execute remove notifiers Daniel Walter
@ 2016-09-21  9:46 ` Daniel Walter
  2016-09-21  9:46 ` [PATCH v2 06/46] mtd: nandsim: Add basic control file support Daniel Walter
                   ` (41 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:46 UTC (permalink / raw)
  To: linux-mtd; +Cc: linux-kernel, computersforpeace, dwmw2, Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Just return -EBUSY and everything is fine.

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

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index b8205ec..32f1088 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -500,8 +500,6 @@ int del_mtd_device(struct mtd_info *mtd)
 	}
 
 	if (mtd->usecount) {
-		printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
-		       mtd->index, mtd->name, mtd->usecount);
 		ret = -EBUSY;
 	} else {
 		/* No need to get a refcount on the module containing
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 06/46] mtd: nandsim: Add basic control file support
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (4 preceding siblings ...)
  2016-09-21  9:46 ` [PATCH v2 05/46] mtd: Don't print a scary message when trying to remove a busy MTD Daniel Walter
@ 2016-09-21  9:46 ` Daniel Walter
  2016-09-21  9:47 ` [PATCH v2 07/46] mtd: nandsim: Begin with removal of global state Daniel Walter
                   ` (40 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:46 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 07/46] mtd: nandsim: Begin with removal of global state
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (5 preceding siblings ...)
  2016-09-21  9:46 ` [PATCH v2 06/46] mtd: nandsim: Add basic control file support Daniel Walter
@ 2016-09-21  9:47 ` Daniel Walter
  2016-09-21  9:47 ` [PATCH v2 08/46] mtd: nandsim: Kill global nsmtd Daniel Walter
                   ` (39 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:47 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 08/46] mtd: nandsim: Kill global nsmtd
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (6 preceding siblings ...)
  2016-09-21  9:47 ` [PATCH v2 07/46] mtd: nandsim: Begin with removal of global state Daniel Walter
@ 2016-09-21  9:47 ` Daniel Walter
  2016-09-21  9:47 ` [PATCH v2 09/46] mtd: nandsim: Don't directly use module parameters Daniel Walter
                   ` (38 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:47 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Do it like UBI and support in future up to 32 instances.
For now we still keep a single instance and allow more when
all global state has been removed.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index c49999d..e24ef8c 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -448,8 +448,10 @@ struct grave_page {
 	unsigned int reads_done;
 };
 
+#define NS_MAX_DEVICES 32
+
 /* MTD structure for NAND controller */
-static struct mtd_info *nsmtd;
+static struct mtd_info *ns_mtds[NS_MAX_DEVICES];
 
 static int nandsim_debugfs_show(struct seq_file *m, void *private)
 {
@@ -1451,6 +1453,9 @@ 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);
+
 	if (bitflips && prandom_u32() < (1 << 22)) {
 		int flips = 1;
 		if (bitflips > 1)
@@ -2268,6 +2273,7 @@ static int __init ns_init_default(void)
 {
 	struct nand_chip *chip;
 	struct nandsim *nand;
+	struct mtd_info *nsmtd;
 	int retval = -ENOMEM, i;
 
 	if (bus_width != 8 && bus_width != 16) {
@@ -2283,8 +2289,9 @@ static int __init ns_init_default(void)
 		return -ENOMEM;
 	}
 
-	nsmtd       = nand_to_mtd(chip);
-	nand        = (struct nandsim *)(chip + 1);
+	WARN_ON(ns_mtds[0]);
+	nsmtd = ns_mtds[0] = nand_to_mtd(chip);
+	nand = (struct nandsim *)(chip + 1);
 	nand_set_controller_data(chip, (void *)nand);
 
 	INIT_LIST_HEAD(&nand->weak_blocks);
@@ -2447,6 +2454,7 @@ error:
 
 static void __exit ns_cleanup_default(void)
 {
+	struct mtd_info *nsmtd = ns_mtds[0];
 	struct nand_chip *chip = mtd_to_nand(nsmtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 	int i;
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 09/46] mtd: nandsim: Don't directly use module parameters
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (7 preceding siblings ...)
  2016-09-21  9:47 ` [PATCH v2 08/46] mtd: nandsim: Kill global nsmtd Daniel Walter
@ 2016-09-21  9:47 ` Daniel Walter
  2016-09-21  9:48 ` [PATCH v2 10/46] mtd: nandsim: Add helper functions for pointer magic Daniel Walter
                   ` (37 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:47 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 10/46] mtd: nandsim: Add helper functions for pointer magic
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (8 preceding siblings ...)
  2016-09-21  9:47 ` [PATCH v2 09/46] mtd: nandsim: Don't directly use module parameters Daniel Walter
@ 2016-09-21  9:48 ` Daniel Walter
  2016-09-21  9:48 ` [PATCH v2 11/46] mtd: nandsim: Factor out nandsim parameters Daniel Walter
                   ` (36 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:48 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Add chip_to_ns() and ns_to_mtd() helper functions

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 11/46] mtd: nandsim: Factor out nandsim parameters
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (9 preceding siblings ...)
  2016-09-21  9:48 ` [PATCH v2 10/46] mtd: nandsim: Add helper functions for pointer magic Daniel Walter
@ 2016-09-21  9:48 ` Daniel Walter
  2016-09-21  9:48 ` [PATCH v2 12/46] mtd: nandsim: Make debugfs logic multi instance capable Daniel Walter
                   ` (35 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:48 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 12/46] mtd: nandsim: Make debugfs logic multi instance capable
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (10 preceding siblings ...)
  2016-09-21  9:48 ` [PATCH v2 11/46] mtd: nandsim: Factor out nandsim parameters Daniel Walter
@ 2016-09-21  9:48 ` Daniel Walter
  2016-09-21  9:49 ` [PATCH v2 13/46] mtd: nandsim: Add final logic for multiple instances Daniel Walter
                   ` (34 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:48 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Instead of creating our files in <debugfs>/nandsim/,
create one directory per instance.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index ab4859d..057cc7a 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -328,6 +328,7 @@ union ns_mem {
  * The structure which describes all the internal simulator data.
  */
 struct nandsim {
+	unsigned int index;
 	struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
 	unsigned int nbparts;
 
@@ -483,6 +484,8 @@ struct grave_page {
 /* MTD structure for NAND controller */
 static struct mtd_info *ns_mtds[NS_MAX_DEVICES];
 
+static struct dentry *dfs_root;
+
 static inline struct nandsim *chip_to_ns(struct nand_chip *chip)
 {
 	return (struct nandsim *)(chip + 1);
@@ -560,6 +563,23 @@ static const struct file_operations dfs_fops = {
 	.release	= single_release,
 };
 
+static int nandsim_debugfs_init(void)
+{
+	if (!IS_ENABLED(CONFIG_DEBUG_FS))
+		return 0;
+
+	dfs_root = debugfs_create_dir("nandsim", NULL);
+	if (IS_ERR_OR_NULL(dfs_root)) {
+		int err = dfs_root ? -ENODEV : PTR_ERR(dfs_root);
+
+		NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
+			err);
+		return err;
+	}
+
+	return 0;
+}
+
 /**
  * nandsim_debugfs_create - initialize debugfs
  * @dev: nandsim device description object
@@ -572,15 +592,21 @@ static int nandsim_debugfs_create(struct nandsim *dev)
 	struct nandsim_debug_info *dbg = &dev->dbg;
 	struct dentry *dent;
 	int err;
+	char *dirname;
 
 	if (!IS_ENABLED(CONFIG_DEBUG_FS))
 		return 0;
 
-	dent = debugfs_create_dir("nandsim", NULL);
+	dirname = kasprintf(GFP_KERNEL, "nandsim%i", dev->index);
+	if (!dirname)
+		return -ENOMEM;
+
+	dent = debugfs_create_dir(dirname, dfs_root);
+	kfree(dirname);
 	if (IS_ERR_OR_NULL(dent)) {
 		int err = dent ? -ENODEV : PTR_ERR(dent);
 
-		NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
+		NS_ERR("cannot create nandsim debugfs sub-directory, err %d\n",
 			err);
 		return err;
 	}
@@ -2336,6 +2362,7 @@ static int ns_new_instance(struct nandsim_params *nsparam)
 	nsmtd = ns_mtds[0] = nand_to_mtd(chip);
 	nand = chip_to_ns(chip);
 	nand_set_controller_data(chip, (void *)nand);
+	nand->index = 0;
 
 	INIT_LIST_HEAD(&nand->weak_blocks);
 	INIT_LIST_HEAD(&nand->grave_pages);
@@ -2557,6 +2584,10 @@ static int __init ns_init_module(void)
 {
 	int ret;
 
+	ret = nandsim_debugfs_init();
+	if (ret)
+		return ret;
+
 	ret = ns_init_default();
 	if (ret)
 		return ret;
@@ -2569,6 +2600,7 @@ static void __exit ns_cleanup_module(void)
 {
 	ns_cleanup_default();
 	misc_deregister(&nandsim_ctrl_cdev);
+	debugfs_remove_recursive(dfs_root);
 }
 module_exit(ns_cleanup_module);
 
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 13/46] mtd: nandsim: Add final logic for multiple instances
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (11 preceding siblings ...)
  2016-09-21  9:48 ` [PATCH v2 12/46] mtd: nandsim: Make debugfs logic multi instance capable Daniel Walter
@ 2016-09-21  9:49 ` Daniel Walter
  2016-09-21  9:49 ` [PATCH v2 14/46] mtd: nandsim: Add simulator id to MTD parition name Daniel Walter
                   ` (33 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:49 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Add support to create and delete multiple instances
of nandsim.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 057cc7a..bef5afa 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -47,6 +47,7 @@
 #include <linux/compat.h>
 #include <linux/miscdevice.h>
 #include <linux/major.h>
+#include <linux/mutex.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -117,6 +118,7 @@ static u_char id_bytes[8] = {
 	[3] = CONFIG_NANDSIM_FOURTH_ID_BYTE,
 	[4 ... 7] = 0xFF,
 };
+static bool defaults = true;
 
 module_param_array(id_bytes, byte, NULL, 0400);
 module_param_named(first_id_byte, id_bytes[0], byte, 0400);
@@ -142,6 +144,7 @@ module_param(overridesize,   uint, 0400);
 module_param(cache_file,     charp, 0400);
 module_param(bbt,	     uint, 0400);
 module_param(bch,	     uint, 0400);
+module_param(defaults,	     bool, 0400);
 
 MODULE_PARM_DESC(id_bytes,       "The ID bytes returned by NAND Flash 'read ID' command");
 MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (obsolete)");
@@ -177,6 +180,8 @@ MODULE_PARM_DESC(cache_file,     "File to use to cache nand pages instead of mem
 MODULE_PARM_DESC(bbt,		 "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
 MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
 				 "be correctable in 512-byte blocks");
+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
@@ -483,6 +488,7 @@ struct grave_page {
 
 /* MTD structure for NAND controller */
 static struct mtd_info *ns_mtds[NS_MAX_DEVICES];
+static DEFINE_MUTEX(ns_mtd_mutex);
 
 static struct dentry *dfs_root;
 
@@ -2358,11 +2364,24 @@ static int ns_new_instance(struct nandsim_params *nsparam)
 		return -ENOMEM;
 	}
 
-	WARN_ON(ns_mtds[0]);
-	nsmtd = ns_mtds[0] = nand_to_mtd(chip);
+	mutex_lock(&ns_mtd_mutex);
+	for (i = 0; i < NS_MAX_DEVICES; i++) {
+		if (!ns_mtds[i])
+			break;
+	}
+
+	if (i == NS_MAX_DEVICES) {
+		NS_ERR("Cannot allocate more than %i instances!\n", NS_MAX_DEVICES);
+		retval = -ENFILE;
+		mutex_unlock(&ns_mtd_mutex);
+		goto error;
+	}
+
+	nsmtd = ns_mtds[i] = nand_to_mtd(chip);
 	nand = chip_to_ns(chip);
 	nand_set_controller_data(chip, (void *)nand);
-	nand->index = 0;
+	nand->index = i;
+	mutex_unlock(&ns_mtd_mutex);
 
 	INIT_LIST_HEAD(&nand->weak_blocks);
 	INIT_LIST_HEAD(&nand->grave_pages);
@@ -2530,9 +2549,8 @@ error:
 	return retval;
 }
 
-static void __exit ns_cleanup_default(void)
+static void ns_destroy_instance(struct mtd_info *nsmtd)
 {
-	struct mtd_info *nsmtd = ns_mtds[0];
 	struct nand_chip *chip = mtd_to_nand(nsmtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
 	int i;
@@ -2546,6 +2564,17 @@ static void __exit ns_cleanup_default(void)
 	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
 }
 
+static void ns_destroy_all(void)
+{
+	int i;
+
+	mutex_lock(&ns_mtd_mutex);
+	for (i = 0; i < NS_MAX_DEVICES; i++)
+		if (ns_mtds[i])
+			ns_destroy_instance(ns_mtds[i]);
+	mutex_unlock(&ns_mtd_mutex);
+}
+
 static int __init ns_init_default(void)
 {
 	int ret;
@@ -2588,18 +2617,28 @@ static int __init ns_init_module(void)
 	if (ret)
 		return ret;
 
-	ret = ns_init_default();
-	if (ret)
-		return ret;
+	if (defaults) {
+		ret = ns_init_default();
+		if (ret) {
+			debugfs_remove_recursive(dfs_root);
+			return ret;
+		}
+	}
+
+	ret = misc_register(&nandsim_ctrl_cdev);
+	if (ret) {
+		ns_destroy_all();
+		debugfs_remove_recursive(dfs_root);
+	}
 
-	return misc_register(&nandsim_ctrl_cdev);
+	return ret;
 }
 module_init(ns_init_module);
 
 static void __exit ns_cleanup_module(void)
 {
-	ns_cleanup_default();
 	misc_deregister(&nandsim_ctrl_cdev);
+	ns_destroy_all();
 	debugfs_remove_recursive(dfs_root);
 }
 module_exit(ns_cleanup_module);
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 14/46] mtd: nandsim: Add simulator id to MTD parition name
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (12 preceding siblings ...)
  2016-09-21  9:49 ` [PATCH v2 13/46] mtd: nandsim: Add final logic for multiple instances Daniel Walter
@ 2016-09-21  9:49 ` Daniel Walter
  2016-09-21  9:49 ` [PATCH v2 15/46] mtd: nandsim: Introduce backend operations Daniel Walter
                   ` (32 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:49 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 15/46] mtd: nandsim: Introduce backend operations
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (13 preceding siblings ...)
  2016-09-21  9:49 ` [PATCH v2 14/46] mtd: nandsim: Add simulator id to MTD parition name Daniel Walter
@ 2016-09-21  9:49 ` Daniel Walter
  2016-09-21  9:49 ` [PATCH v2 16/46] mtd: nandsim: Print error when backend init failed Daniel Walter
                   ` (31 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:49 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 16/46] mtd: nandsim: Print error when backend init failed
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (14 preceding siblings ...)
  2016-09-21  9:49 ` [PATCH v2 15/46] mtd: nandsim: Introduce backend operations Daniel Walter
@ 2016-09-21  9:49 ` Daniel Walter
  2016-09-21  9:50 ` [PATCH v2 17/46] mtd: nandsim: Allow external backends Daniel Walter
                   ` (30 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:49 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 633872a..e333c5c 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -894,8 +894,10 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 
 	ns->bops = nsparam->bops;
 
-	if ((ret = ns->bops->init(ns, nsparam)) != 0)
+	if ((ret = ns->bops->init(ns, nsparam)) != 0) {
+		NS_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);
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 17/46] mtd: nandsim: Allow external backends
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (15 preceding siblings ...)
  2016-09-21  9:49 ` [PATCH v2 16/46] mtd: nandsim: Print error when backend init failed Daniel Walter
@ 2016-09-21  9:50 ` Daniel Walter
  2016-09-21  9:50 ` [PATCH v2 18/46] mtd: nandsim: Add basic support for a file backend Daniel Walter
                   ` (29 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:50 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

This turns nandsim into a mini framework to allow
backends implemented in different drivers.
i.e. virtio or usermodelinux.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index e333c5c..21a6e1a 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -36,6 +36,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_bch.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/nandsim.h>
 #include <linux/delay.h>
 #include <linux/list.h>
 #include <linux/random.h>
@@ -294,42 +295,11 @@ MODULE_PARM_DESC(defaults,	 "Register a MTD during module load using default val
 /* 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 ns_backend_ops *bops;
-};
-
 struct nandsim_debug_info {
 	struct dentry *dfs_root;
 	struct dentry *dfs_wear_report;
 };
 
-/*
- * A union to represent flash memory contents and flash buffer.
- */
-union ns_mem {
-	u_char *byte;    /* for byte access */
-	uint16_t *word;  /* for 16-bit word access */
-};
-
 struct ns_ram_data {
 	/* The simulated NAND flash pages array */
 	union ns_mem *pages;
@@ -367,35 +337,8 @@ struct nandsim {
 
 	/* Internal buffer of page + OOB size bytes */
 	union ns_mem buf;
-
-	/* NAND flash "geometry" */
-	struct {
-		uint64_t totsz;     /* total flash size, bytes */
-		uint32_t secsz;     /* flash sector (erase block) size, bytes */
-		uint pgsz;          /* NAND flash page size, bytes */
-		uint oobsz;         /* page OOB area size, bytes */
-		uint64_t totszoob;  /* total flash size including OOB, bytes */
-		uint pgszoob;       /* page size including OOB , bytes*/
-		uint secszoob;      /* sector size including OOB, bytes */
-		uint pgnum;         /* total number of pages */
-		uint pgsec;         /* number of pages per sector */
-		uint secshift;      /* bits number in sector size */
-		uint pgshift;       /* bits number in page size */
-		uint pgaddrbytes;   /* bytes per page address */
-		uint secaddrbytes;  /* bytes per sector address */
-		uint idbytes;       /* the number ID bytes that this chip outputs */
-	} geom;
-
-	/* NAND flash internal registers */
-	struct {
-		unsigned command; /* the command register */
-		u_char   status;  /* the status register */
-		uint     row;     /* the page number */
-		uint     column;  /* the offset within page */
-		uint     count;   /* internal counter */
-		uint     num;     /* number of bytes which must be processed */
-		uint     off;     /* fixed page offset */
-	} regs;
+	struct nandsim_geom geom;
+	struct nandsim_regs regs;
 
 	/* NAND flash lines state */
         struct {
@@ -427,14 +370,6 @@ 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;
 
@@ -736,6 +671,36 @@ err_close:
 	return err;
 }
 
+struct nandsim_geom *nandsim_get_geom(struct nandsim *ns)
+{
+	return &ns->geom;
+}
+EXPORT_SYMBOL_GPL(nandsim_get_geom);
+
+struct nandsim_regs *nandsim_get_regs(struct nandsim *ns)
+{
+	return &ns->regs;
+}
+EXPORT_SYMBOL_GPL(nandsim_get_regs);
+
+void nandsim_set_backend_data(struct nandsim *ns, void *data)
+{
+	ns->backend_data = data;
+}
+EXPORT_SYMBOL_GPL(nandsim_set_backend_data);
+
+void *nandsim_get_backend_data(struct nandsim *ns)
+{
+	return ns->backend_data;
+}
+EXPORT_SYMBOL_GPL(nandsim_get_backend_data);
+
+union ns_mem *nandsim_get_buf(struct nandsim *ns)
+{
+	return &ns->buf;
+}
+EXPORT_SYMBOL_GPL(nandsim_get_buf);
+
 static void ns_ram_destroy(struct nandsim *ns)
 {
 	struct ns_ram_data *data = ns->backend_data;
@@ -2396,7 +2361,7 @@ static struct miscdevice nandsim_ctrl_cdev = {
 	.fops = &nansim_ctrl_fops,
 };
 
-static int ns_new_instance(struct nandsim_params *nsparam)
+struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 {
 	struct nand_chip *chip;
 	struct nandsim *nand;
@@ -2406,7 +2371,7 @@ static int ns_new_instance(struct nandsim_params *nsparam)
 
 	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;
+		return ERR_PTR(-EINVAL);
 	}
 
 	/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
@@ -2414,7 +2379,7 @@ static int ns_new_instance(struct nandsim_params *nsparam)
 		       GFP_KERNEL);
 	if (!chip) {
 		NS_ERR("unable to allocate core structures.\n");
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	mutex_lock(&ns_mtd_mutex);
@@ -2588,7 +2553,7 @@ static int ns_new_instance(struct nandsim_params *nsparam)
 	if (retval != 0)
 		goto err_exit;
 
-        return 0;
+	return nsmtd;
 
 err_exit:
 	free_nandsim(nand);
@@ -2599,10 +2564,11 @@ error:
 	free_lists(nand);
 	kfree(chip);
 
-	return retval;
+	return ERR_PTR(retval);
 }
+EXPORT_SYMBOL_GPL(ns_new_instance);
 
-static void ns_destroy_instance(struct mtd_info *nsmtd)
+void ns_destroy_instance(struct mtd_info *nsmtd)
 {
 	struct nand_chip *chip = mtd_to_nand(nsmtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
@@ -2616,6 +2582,7 @@ static void ns_destroy_instance(struct mtd_info *nsmtd)
 		kfree(ns->partitions[i].name);
 	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
 }
+EXPORT_SYMBOL_GPL(ns_destroy_instance);
 
 static void ns_destroy_all(void)
 {
@@ -2630,7 +2597,7 @@ static void ns_destroy_all(void)
 
 static int __init ns_init_default(void)
 {
-	int ret;
+	struct mtd_info *nsmtd;
 	struct nandsim_params *nsparam = kzalloc(sizeof(*nsparam), GFP_KERNEL);
 
 	if (!nsparam)
@@ -2661,10 +2628,13 @@ static int __init ns_init_default(void)
 	else
 		nsparam->bops = &ns_cachefile_bops;
 
-	ret = ns_new_instance(nsparam);
+	nsmtd = ns_new_instance(nsparam);
 	kfree(nsparam);
 
-	return ret;
+	if (IS_ERR(nsmtd))
+		return PTR_ERR(nsmtd);
+
+	return 0;
 }
 
 static int __init ns_init_module(void)
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
new file mode 100644
index 0000000..2d596ad
--- /dev/null
+++ b/include/linux/mtd/nandsim.h
@@ -0,0 +1,83 @@
+#ifndef __LINUX_NANDSIM_H__
+#define __LINUX_NANDSIM_H__
+
+#include <linux/mtd/mtd.h>
+
+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 ns_backend_ops *bops;
+};
+
+/* NAND flash "geometry" */
+struct nandsim_geom {
+	uint64_t totsz;     /* total flash size, bytes */
+	uint32_t secsz;     /* flash sector (erase block) size, bytes */
+	uint pgsz;          /* NAND flash page size, bytes */
+	uint oobsz;         /* page OOB area size, bytes */
+	uint64_t totszoob;  /* total flash size including OOB, bytes */
+	uint pgszoob;       /* page size including OOB , bytes*/
+	uint secszoob;      /* sector size including OOB, bytes */
+	uint pgnum;         /* total number of pages */
+	uint pgsec;         /* number of pages per sector */
+	uint secshift;      /* bits number in sector size */
+	uint pgshift;       /* bits number in page size */
+	uint pgaddrbytes;   /* bytes per page address */
+	uint secaddrbytes;  /* bytes per sector address */
+	uint idbytes;       /* the number ID bytes that this chip outputs */
+};
+
+/* NAND flash internal registers */
+struct nandsim_regs {
+	unsigned command; /* the command register */
+	u_char   status;  /* the status register */
+	uint     row;     /* the page number */
+	uint     column;  /* the offset within page */
+	uint     count;   /* internal counter */
+	uint     num;     /* number of bytes which must be processed */
+	uint     off;     /* fixed page offset */
+};
+
+/*
+ * A union to represent flash memory contents and flash buffer.
+ */
+union ns_mem {
+	u_char *byte;    /* for byte access */
+	uint16_t *word;  /* for 16-bit word access */
+};
+
+struct nandsim;
+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);
+};
+
+struct mtd_info *ns_new_instance(struct nandsim_params *nsparam);
+void ns_destroy_instance(struct mtd_info *nsmtd);
+struct nandsim_geom *nandsim_get_geom(struct nandsim *ns);
+struct nandsim_regs *nandsim_get_regs(struct nandsim *ns);
+void nandsim_set_backend_data(struct nandsim *ns, void *data);
+void *nandsim_get_backend_data(struct nandsim *ns);
+union ns_mem *nandsim_get_buf(struct nandsim *ns);
+
+#endif /* __LINUX_NANDSIM_H__ */
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 18/46] mtd: nandsim: Add basic support for a file backend
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (16 preceding siblings ...)
  2016-09-21  9:50 ` [PATCH v2 17/46] mtd: nandsim: Allow external backends Daniel Walter
@ 2016-09-21  9:50 ` Daniel Walter
  2016-09-21  9:50 ` [PATCH v2 19/46] mtd: nandsim: UAPI v1 Daniel Walter
                   ` (28 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:50 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 19/46] mtd: nandsim: UAPI v1
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (17 preceding siblings ...)
  2016-09-21  9:50 ` [PATCH v2 18/46] mtd: nandsim: Add basic support for a file backend Daniel Walter
@ 2016-09-21  9:50 ` Daniel Walter
  2016-11-20 10:13   ` Boris Brezillon
  2016-09-21  9:51 ` [PATCH v2 20/46] mtd: nandsim: Implement preliminary constructor function Daniel Walter
                   ` (27 subsequent siblings)
  46 siblings, 1 reply; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:50 UTC (permalink / raw)
  To: linux-mtd; +Cc: linux-kernel, computersforpeace, dwmw2, Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Expose nandsim creation and delete functions
to user-space

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 include/uapi/mtd/nandsim-user.h | 102 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 include/uapi/mtd/nandsim-user.h

diff --git a/include/uapi/mtd/nandsim-user.h b/include/uapi/mtd/nandsim-user.h
new file mode 100644
index 0000000..b52d620
--- /dev/null
+++ b/include/uapi/mtd/nandsim-user.h
@@ -0,0 +1,102 @@
+#ifndef __NANDSIM_USER_H__
+#define __NANDSIM_USER_H__
+
+#include <linux/types.h>
+
+#define NANDSIM_IOC_MAGIC 'n'
+
+#define NANDSIM_IOC_NEW_INSTANCE _IOW(NANDSIM_IOC_MAGIC, 0, struct ns_new_instance_req)
+#define NANDSIM_IOC_DESTROY_INSTANCE _IOW(NANDSIM_IOC_MAGIC, 1, struct ns_destroy_instance_req)
+
+#define NANDSIM_MAX_DEVICES 32
+#define NANDSIM_MAX_PARTS 32
+
+enum ns_backend_type {
+	NANDSIM_BACKEND_RAM = 0,
+	NANDSIM_BACKEND_CACHEFILE = 1,
+	NANDSIM_BACKEND_FILE = 2,
+	NANDSIM_BACKEND_MAX,
+};
+
+/**
+ * struct ns_new_instance_req - Create a new nandsim instance.
+ *
+ * @id_bytes: NAND ID of the simulated NAND chip
+ * @bus_width: bus width to emulate, either 8 or 16
+ * @bbt_mode: bad block table mode, 0 OOB, 1 BBT with marker in OOB,
+ *            2 BBT with marker in data area
+ * @no_oob: backing file contains no OOB data
+ * @bch_strength: instead of hamming ECC use BCH with given strength
+ * @parts_num: number of MTD partitions to create
+ * @parts: partition sizes in physical erase blocks, used then @parts_num > 0
+ * @backend: backend type, see @ns_backend_type
+ * @file_fd: file describtor of backend, only for @NANDSIM_BACKEND_CACHEFILE
+ *           and @NANDSIM_BACKEND_FILE.
+ * @bitflips: maximum number of random bit flips per page
+ * @overridesize: specifies the NAND size overriding the ID bytes
+ * @access_delay: initial page access delay (microseconds)
+ * @program_delay: page program delay (microseconds)
+ * @erase_delay: sector erase delay (milliseconds)
+ * @output_cycle: word output, from flash, time (nanoseconds)
+ * @input_cycle: word input, to flash, time (nanoseconds)
+ * @simelem_num: number of simulation elements appened to this
+ *               data structure. see @ns_simelement_prop
+ *
+ * This struct is used with the @NANDSIM_IOC_NEW_INSTANCE ioctl command.
+ * It creates a new nandsim instance from the given parameter.
+ * The ioctl command returns in case of success the nandsim id of the new
+ * instance, in case of error a negative value.
+ *
+ * Not all fields in the struct have to be filled, if nandsim should
+ * use a default ignore the value, fill with 0.
+ * The only mandatory fields are @id_bytes and @bus_width.
+ * When @no_oob is non-zero @bch_strength cannot be used since
+ * @no_oob implies that no ECC is used.
+ */
+struct ns_new_instance_req {
+	__s8 id_bytes[8];
+
+	__s8 bus_width;
+	__s8 bbt_mode;
+	__s8 no_oob;
+	__s32 bch_strength;
+
+	__s8 parts_num;
+	__s32 parts[NANDSIM_MAX_PARTS];
+
+	__s8 backend;
+	__s32 file_fd;
+
+	__s32 bitflips;
+	__s32 overridesize;
+	__s32 access_delay;
+	__s32 program_delay;
+	__s32 erase_delay;
+	__s32 output_cycle;
+	__s32 input_cycle;
+
+	__s32 padding[4];
+
+	__s32 simelem_num;
+} __packed;
+
+enum {
+	NANDSIM_SIMELEM_BADBLOCK = 0,
+	NANDSIM_SIMELEM_WEAKBLOCK,
+	NANDSIM_SIMELEM_WEAKPAGE,
+	NANDSIM_SIMELEM_GRAVEPAGE,
+};
+
+struct ns_simelement_prop {
+	__s8 elem_type;
+	__s32 elem_id;
+	__s32 elem_attr;
+	__s8 padding[7];
+} __packed;
+
+struct ns_destroy_instance_req {
+	__s8 id;
+	__s8 padding[7];
+} __packed;
+
+#endif /* __NANDSIM_USER_H__ */
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 20/46] mtd: nandsim: Implement preliminary constructor function
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (18 preceding siblings ...)
  2016-09-21  9:50 ` [PATCH v2 19/46] mtd: nandsim: UAPI v1 Daniel Walter
@ 2016-09-21  9:51 ` Daniel Walter
  2016-09-21  9:51 ` [PATCH v2 21/46] mtd: nandsim: Implement preliminary destructor function Daniel Walter
                   ` (26 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:51 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

This function will be used later by the ioctl() interface
for creating new nandsim instances.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 2e3c08e..344f5c4 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2470,6 +2470,45 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 	return;
 }
 
+static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
+{
+	struct mtd_info *nsmtd;
+	struct nand_chip *chip;
+	struct nandsim *ns;
+	struct nandsim_params *nsparam = kzalloc(sizeof(*nsparam), GFP_KERNEL);
+
+	if (!nsparam)
+		return -ENOMEM;
+
+	memcpy(nsparam->id_bytes, req->id_bytes, sizeof(nsparam->id_bytes));
+	nsparam->bus_width = req->bus_width;
+	nsparam->file_fd = req->file_fd;
+
+	switch (req->backend) {
+		case NANDSIM_BACKEND_RAM:
+			nsparam->bops = &ns_ram_bops;
+		break;
+		case NANDSIM_BACKEND_FILE:
+			nsparam->bops = &ns_file_bops;
+		break;
+
+		default:
+			kfree(nsparam);
+			return -EINVAL;
+	}
+
+	nsmtd = ns_new_instance(nsparam);
+	kfree(nsparam);
+
+	if (IS_ERR(nsmtd))
+		return PTR_ERR(nsmtd);
+
+	chip = mtd_to_nand(nsmtd);
+	ns = nand_get_controller_data(chip);
+
+	return ns->index;
+}
+
 static long ns_ctrl_ioctl(struct file *file, unsigned int cmd,
 			  unsigned long arg)
 {
@@ -2764,7 +2803,7 @@ static int __init ns_init_default(void)
 	nsparam->cache_file = cache_file;
 	nsparam->bbt = bbt;
 	nsparam->bch = bch;
-	nsparam->id_bytes = id_bytes;
+	memcpy(nsparam->id_bytes, id_bytes, sizeof(nsparam->id_bytes));
 
 	if (!nsparam->cache_file)
 		nsparam->bops = &ns_ram_bops;
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index e3d2c9f..6e3b4a2 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -2,6 +2,7 @@
 #define __LINUX_NANDSIM_H__
 
 #include <linux/mtd/mtd.h>
+#include <mtd/nandsim-user.h>
 
 struct nandsim_params {
 	unsigned int access_delay;
@@ -22,7 +23,7 @@ struct nandsim_params {
 	char *cache_file;
 	unsigned int bbt;
 	unsigned int bch;
-	unsigned char *id_bytes;
+	unsigned char id_bytes[8];
 	unsigned int file_fd;
 	struct ns_backend_ops *bops;
 };
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 21/46] mtd: nandsim: Implement preliminary destructor function
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (19 preceding siblings ...)
  2016-09-21  9:51 ` [PATCH v2 20/46] mtd: nandsim: Implement preliminary constructor function Daniel Walter
@ 2016-09-21  9:51 ` Daniel Walter
  2016-09-21 12:56   ` kbuild test robot
  2016-09-21  9:51 ` [PATCH v2 22/46] mtd: nandsim: Cleanup destroy handlers Daniel Walter
                   ` (25 subsequent siblings)
  46 siblings, 1 reply; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:51 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

This function will be used via ioctl() to remove nandsim instances.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 344f5c4..bac3fde 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -39,6 +39,7 @@
 #include <linux/mtd/nandsim.h>
 #include <linux/delay.h>
 #include <linux/list.h>
+#include <linux/spinlock.h>
 #include <linux/random.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -328,7 +329,10 @@ struct ns_file_data {
  */
 struct nandsim {
 	unsigned int index;
+	unsigned int refcnt;
+	spinlock_t refcnt_lock;
 	struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
+	bool destroying;
 	unsigned int nbparts;
 
 	uint busw;              /* flash chip bus width (8 or 16) */
@@ -2509,6 +2513,41 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 	return ns->index;
 }
 
+static int ns_ctrl_destroy_instance(struct ns_destroy_instance_req *req)
+{
+	struct mtd_info *nsmtd;
+	int id = req->id, ret = 0;
+	struct nand_chip *chip;
+	struct nandsim *ns;
+
+	if (id < 0 || id >= NS_MAX_DEVICES)
+		return -EINVAL;
+
+	mutex_lock(&ns_mtd_mutex);
+	nsmtd = ns_mtds[id];
+	if (nsmtd) {
+		chip = mtd_to_nand(nsmtd);
+		ns = nand_get_controller_data(chip);
+		spin_lock(&ns->refcnt_lock);
+		if (ns->refcnt > 0) {
+			ret = -EBUSY;
+			spin_unlock(&ns->refcnt_lock);
+			goto out;
+		}
+		ns->destroying = true;
+		spin_unlock(&ns->refcnt_lock);
+		ret = ns_destroy_instance(nsmtd);
+		if (ret)
+			goto out;
+		ns_mtds[id] = NULL;
+	}
+
+out:
+	mutex_unlock(&ns_mtd_mutex);
+
+	return ret;
+}
+
 static long ns_ctrl_ioctl(struct file *file, unsigned int cmd,
 			  unsigned long arg)
 {
@@ -2543,6 +2582,32 @@ static struct miscdevice nandsim_ctrl_cdev = {
 	.fops = &nansim_ctrl_fops,
 };
 
+static void ns_put_device(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+
+	spin_lock(&ns->refcnt_lock);
+	ns->refcnt -= 1;
+	spin_unlock(&ns->refcnt_lock);
+}
+
+static int ns_get_device(struct mtd_info *mtd)
+{
+	int ret = 0;
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	struct nandsim *ns = nand_get_controller_data(chip);
+
+	spin_lock(&ns->refcnt_lock);
+	if (ns->destroying)
+		ret = -EBUSY;
+	else
+		ns->refcnt += 1;
+	spin_unlock(&ns->refcnt_lock);
+
+	return ret;
+}
+
 struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 {
 	struct nand_chip *chip;
@@ -2587,6 +2652,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	INIT_LIST_HEAD(&nand->grave_pages);
 	INIT_LIST_HEAD(&nand->weak_pages);
 	INIT_LIST_HEAD(&nand->weak_blocks);
+	spin_lock_init(&nand->refcnt_lock);
 
 	/*
 	 * Register simulator's callbacks.
@@ -2637,6 +2703,8 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	}
 
 	nsmtd->owner = THIS_MODULE;
+	nsmtd->_get_device = ns_get_device;
+	nsmtd->_put_device = ns_put_device;
 
 	if ((retval = parse_weakblocks(nand, nsparam->weakblocks)) != 0)
 		goto error;
@@ -2750,11 +2818,16 @@ error:
 }
 EXPORT_SYMBOL_GPL(ns_new_instance);
 
-void ns_destroy_instance(struct mtd_info *nsmtd)
+int ns_destroy_instance(struct mtd_info *nsmtd)
 {
+	int i, ret;
 	struct nand_chip *chip = mtd_to_nand(nsmtd);
 	struct nandsim *ns = nand_get_controller_data(chip);
-	int i;
+
+	ret = mtd_device_unregister(nsmtd);
+	if (ret)
+		return ret;
+	nand_cleanup(nsmtd);
 
 	nandsim_debugfs_remove(ns);
 	free_lists(ns);
@@ -2763,6 +2836,8 @@ void ns_destroy_instance(struct mtd_info *nsmtd)
 	for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
 		kfree(ns->partitions[i].name);
 	kfree(mtd_to_nand(nsmtd));        /* Free other structures */
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(ns_destroy_instance);
 
@@ -2773,7 +2848,7 @@ static void ns_destroy_all(void)
 	mutex_lock(&ns_mtd_mutex);
 	for (i = 0; i < NS_MAX_DEVICES; i++)
 		if (ns_mtds[i])
-			ns_destroy_instance(ns_mtds[i]);
+			WARN_ON(ns_destroy_instance(ns_mtds[i]) != 0);
 	mutex_unlock(&ns_mtd_mutex);
 }
 
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index 6e3b4a2..a0ca0fb 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -75,7 +75,7 @@ struct ns_backend_ops {
 };
 
 struct mtd_info *ns_new_instance(struct nandsim_params *nsparam);
-void ns_destroy_instance(struct mtd_info *nsmtd);
+int ns_destroy_instance(struct mtd_info *nsmtd);
 struct nandsim_geom *nandsim_get_geom(struct nandsim *ns);
 struct nandsim_regs *nandsim_get_regs(struct nandsim *ns);
 void nandsim_set_backend_data(struct nandsim *ns, void *data);
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 22/46] mtd: nandsim: Cleanup destroy handlers
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (20 preceding siblings ...)
  2016-09-21  9:51 ` [PATCH v2 21/46] mtd: nandsim: Implement preliminary destructor function Daniel Walter
@ 2016-09-21  9:51 ` Daniel Walter
  2016-09-21  9:51 ` [PATCH v2 23/46] mtd: nandsim: Unify file backend init logic Daniel Walter
                   ` (24 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:51 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Make sure that we free stuff only after it has been
initialized.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index bac3fde..816d795 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -770,6 +770,9 @@ static void ns_ram_destroy(struct nandsim *ns)
 	struct ns_ram_data *data = ns->backend_data;
 	int i;
 
+	if (!data)
+		return;
+
 	for (i = 0; i < ns->geom.pgnum; i++) {
 		if (data->pages[i].byte)
 			kmem_cache_free(data->nand_pages_slab,
@@ -784,15 +787,22 @@ static void ns_cachefile_destroy(struct nandsim *ns)
 {
 	struct ns_cachefile_data *data = ns->backend_data;
 
+	if (!data)
+		return;
+
 	kfree(data->file_buf);
 	vfree(data->pages_written);
 	filp_close(data->cfile, NULL);
+	kfree(data);
 }
 
 static void ns_file_destroy(struct nandsim *ns)
 {
 	struct ns_file_data *data = ns->backend_data;
 
+	if (!data)
+		return;
+
 	kfree(data->file_buf);
 	fput(data->file);
 	kfree(data);
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 23/46] mtd: nandsim: Unify file backend init logic
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (21 preceding siblings ...)
  2016-09-21  9:51 ` [PATCH v2 22/46] mtd: nandsim: Cleanup destroy handlers Daniel Walter
@ 2016-09-21  9:51 ` Daniel Walter
  2016-09-21  9:51 ` [PATCH v2 24/46] mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode Daniel Walter
                   ` (23 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:51 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

file and cache file backend do more or less the same,
so share some code.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 816d795..56a2904 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -312,6 +312,7 @@ struct ns_ram_data {
 
 struct ns_cachefile_data {
 	struct file *cfile; /* Open file */
+	bool file_opened; /* False when we operate on an already opened file */
 	unsigned long *pages_written; /* Which pages have been written */
 	void *file_buf;
 	struct page *held_pages[NS_MAX_HELD_PAGES];
@@ -637,25 +638,70 @@ static int ns_ram_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	return 0;
 }
 
-static int ns_cachefile_init(struct nandsim *ns, struct nandsim_params *nsparam)
+static struct file *get_file_from_nsparam(struct nandsim_params *nsparam, bool *opened)
 {
-	struct file *cfile;
 	int err;
-	struct ns_cachefile_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+	struct file *file;
+	struct inode *inode;
 
-	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)) {
+	if (nsparam->cache_file) {
+		file = filp_open(nsparam->cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+		if (IS_ERR(file))
+			return file;
+
+		*opened = true;
+	} else {
+		file = fget(nsparam->file_fd);
+		if (!file)
+			return ERR_PTR(-EBADF);
+
+		*opened = false;
+	}
+
+	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");
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (!(file->f_mode & FMODE_CAN_READ)) {
 		NS_ERR("alloc_device: cache file not readable\n");
 		err = -EINVAL;
-		goto err_close;
+		goto out;
 	}
-	if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
+
+	if (!(file->f_mode & FMODE_CAN_WRITE)) {
 		NS_ERR("alloc_device: cache file not writeable\n");
 		err = -EINVAL;
-		goto err_close;
+		goto out;
 	}
+
+	return file;
+
+out:
+	if (*opened)
+		filp_close(file, NULL);
+	else
+		fput(file);
+
+	return ERR_PTR(err);
+}
+
+static int ns_cachefile_init(struct nandsim *ns, struct nandsim_params *nsparam)
+{
+	int err;
+	struct ns_cachefile_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+
+	if (!data)
+		return -ENOMEM;
+
+	data->cfile = get_file_from_nsparam(nsparam, &data->file_opened);
+	if (IS_ERR(data->cfile)) {
+		err = PTR_ERR(data->cfile);
+		goto out;
+	}
+
 	data->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
 				    sizeof(unsigned long));
 	if (!data->pages_written) {
@@ -669,7 +715,6 @@ static int ns_cachefile_init(struct nandsim *ns, struct nandsim_params *nsparam)
 		err = -ENOMEM;
 		goto err_free;
 	}
-	data->cfile = cfile;
 
 	ns->backend_data = data;
 
@@ -678,15 +723,16 @@ static int ns_cachefile_init(struct nandsim *ns, struct nandsim_params *nsparam)
 err_free:
 	vfree(data->pages_written);
 err_close:
-	filp_close(cfile, NULL);
+	filp_close(data->cfile, NULL);
+out:
+	kfree(data);
 	return err;
 }
 
 static int ns_file_init(struct nandsim *ns, struct nandsim_params *nsparam)
 {
 	int ret;
-	struct file *file;
-	struct inode *inode;
+	bool dummy;
 	struct ns_file_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
 
 	if (!data) {
@@ -694,27 +740,12 @@ static int ns_file_init(struct nandsim *ns, struct nandsim_params *nsparam)
 		goto out;
 	}
 
-	file = fget(nsparam->file_fd);
-	if (!file) {
-		ret = -EBADF;
+	data->file = get_file_from_nsparam(nsparam, &dummy);
+	if (IS_ERR(data->file)) {
+		ret = PTR_ERR(data->file);
 		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");
@@ -728,7 +759,7 @@ static int ns_file_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	return ret;
 
 out_put:
-	fput(file);
+	fput(data->file);
 out_free:
 	kfree(data);
 out:
@@ -792,7 +823,10 @@ static void ns_cachefile_destroy(struct nandsim *ns)
 
 	kfree(data->file_buf);
 	vfree(data->pages_written);
-	filp_close(data->cfile, NULL);
+	if (data->file_opened)
+		filp_close(data->cfile, NULL);
+	else
+		fput(data->cfile);
 	kfree(data);
 }
 
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 24/46] mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (22 preceding siblings ...)
  2016-09-21  9:51 ` [PATCH v2 23/46] mtd: nandsim: Unify file backend init logic Daniel Walter
@ 2016-09-21  9:51 ` Daniel Walter
  2016-09-21  9:52 ` [PATCH v2 25/46] mtd: nandsim: Print backend name Daniel Walter
                   ` (22 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:51 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 56a2904..0e8574e 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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 25/46] mtd: nandsim: Print backend name
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (23 preceding siblings ...)
  2016-09-21  9:51 ` [PATCH v2 24/46] mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode Daniel Walter
@ 2016-09-21  9:52 ` Daniel Walter
  2016-09-21  9:52 ` [PATCH v2 26/46] mtd: nandsim: use the existing output macros Daniel Walter
                   ` (21 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:52 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

...useful to figure what backend is currently in use.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 0e8574e..f8e5687 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -976,6 +976,7 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 
 	ns->bops = nsparam->bops;
 
+	NS_INFO("Using backend: %s\n", ns->bops->name);
 	if ((ret = ns->bops->init(ns, nsparam)) != 0) {
 		NS_ERR("Unable to initialize simulator backend: %i\n", ret);
 		return ret;
@@ -1880,6 +1881,7 @@ static struct ns_backend_ops ns_ram_bops = {
 	.read_page = ns_ram_read_page,
 	.init = ns_ram_init,
 	.destroy = ns_ram_destroy,
+	.name = "ram",
 };
 
 static struct ns_backend_ops ns_cachefile_bops = {
@@ -1888,6 +1890,7 @@ static struct ns_backend_ops ns_cachefile_bops = {
 	.read_page = ns_cachefile_read_page,
 	.init = ns_cachefile_init,
 	.destroy = ns_cachefile_destroy,
+	.name = "cache_file",
 };
 
 static struct ns_backend_ops ns_file_bops = {
@@ -1896,6 +1899,7 @@ static struct ns_backend_ops ns_file_bops = {
 	.read_page = ns_file_read_page,
 	.init = ns_file_init,
 	.destroy = ns_file_destroy,
+	.name = "file",
 };
 
 /*
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index a0ca0fb..d71a02f 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -72,6 +72,7 @@ struct ns_backend_ops {
 	void (*read_page)(struct nandsim *ns, int num);
 	int (*init)(struct nandsim *ns, struct nandsim_params *nsparam);
 	void (*destroy)(struct nandsim *ns);
+	char *name;
 };
 
 struct mtd_info *ns_new_instance(struct nandsim_params *nsparam);
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 26/46] mtd: nandsim: use the existing output macros
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (24 preceding siblings ...)
  2016-09-21  9:52 ` [PATCH v2 25/46] mtd: nandsim: Print backend name Daniel Walter
@ 2016-09-21  9:52 ` Daniel Walter
  2016-09-21  9:52 ` [PATCH v2 27/46] mtd: nandsim: Add no_oob mode Daniel Walter
                   ` (20 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:52 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Mathias Kresin, Richard Weinberger

From: Mathias Kresin <dev@kresin.me>

Without using the output macros, it isn't possible to suppress these
messages on the console by specifying an appropriate console log level.

Signed-off-by: Mathias Kresin <dev@kresin.me>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/nand/nandsim.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index f8e5687..7a95802 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -957,22 +957,22 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	if (ns->busw == 16)
 		NS_WARN("16-bit flashes support wasn't tested\n");
 
-	printk("flash size: %llu MiB\n",
+	NS_INFO("flash size: %llu MiB\n",
 			(unsigned long long)ns->geom.totsz >> 20);
-	printk("page size: %u bytes\n",         ns->geom.pgsz);
-	printk("OOB area size: %u bytes\n",     ns->geom.oobsz);
-	printk("sector size: %u KiB\n",         ns->geom.secsz >> 10);
-	printk("pages number: %u\n",            ns->geom.pgnum);
-	printk("pages per sector: %u\n",        ns->geom.pgsec);
-	printk("bus width: %u\n",               ns->busw);
-	printk("bits in sector size: %u\n",     ns->geom.secshift);
-	printk("bits in page size: %u\n",       ns->geom.pgshift);
-	printk("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
-	printk("flash size with OOB: %llu KiB\n",
+	NS_INFO("page size: %u bytes\n",         ns->geom.pgsz);
+	NS_INFO("OOB area size: %u bytes\n",     ns->geom.oobsz);
+	NS_INFO("sector size: %u KiB\n",         ns->geom.secsz >> 10);
+	NS_INFO("pages number: %u\n",            ns->geom.pgnum);
+	NS_INFO("pages per sector: %u\n",        ns->geom.pgsec);
+	NS_INFO("bus width: %u\n",               ns->busw);
+	NS_INFO("bits in sector size: %u\n",     ns->geom.secshift);
+	NS_INFO("bits in page size: %u\n",       ns->geom.pgshift);
+	NS_INFO("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
+	NS_INFO("flash size with OOB: %llu KiB\n",
 			(unsigned long long)ns->geom.totszoob >> 10);
-	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
-	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
-	printk("options: %#x\n",                ns->options);
+	NS_INFO("page address bytes: %u\n",      ns->geom.pgaddrbytes);
+	NS_INFO("sector address bytes: %u\n",    ns->geom.secaddrbytes);
+	NS_INFO("options: %#x\n",                ns->options);
 
 	ns->bops = nsparam->bops;
 
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 27/46] mtd: nandsim: Add no_oob mode
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (25 preceding siblings ...)
  2016-09-21  9:52 ` [PATCH v2 26/46] mtd: nandsim: use the existing output macros Daniel Walter
@ 2016-09-21  9:52 ` Daniel Walter
  2016-09-21  9:52 ` [PATCH v2 28/46] mtd: nandsim: Refine exports Daniel Walter
                   ` (19 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:52 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 7a95802..c93d946 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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 28/46] mtd: nandsim: Refine exports
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (26 preceding siblings ...)
  2016-09-21  9:52 ` [PATCH v2 27/46] mtd: nandsim: Add no_oob mode Daniel Walter
@ 2016-09-21  9:52 ` Daniel Walter
  2016-09-21  9:54 ` [PATCH v2 29/46] um: Add nandsim backend driver Daniel Walter
                   ` (18 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:52 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Keep the file backend logic directly in nandsim such that
other users of only have to implement simple read/write
functions.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index c93d946..cf2694f 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -302,6 +302,14 @@ struct nandsim_debug_info {
 	struct dentry *dfs_wear_report;
 };
 
+/*
+ * A union to represent flash memory contents and flash buffer.
+ */
+union ns_mem {
+	u_char *byte;    /* for byte access */
+	uint16_t *word;  /* for 16-bit word access */
+};
+
 struct ns_ram_data {
 	/* The simulated NAND flash pages array */
 	union ns_mem *pages;
@@ -350,7 +358,17 @@ struct nandsim {
 	/* Internal buffer of page + OOB size bytes */
 	union ns_mem buf;
 	struct nandsim_geom geom;
-	struct nandsim_regs regs;
+
+	/* NAND flash internal registers */
+	struct {
+		unsigned int command; /* the command register */
+		u_char   status;  /* the status register */
+		uint     row;     /* the page number */
+		uint     column;  /* the offset within page */
+		uint     count;   /* internal counter */
+		uint     num;     /* number of bytes which must be processed */
+		uint     off;     /* fixed page offset */
+	} regs;
 
 	/* NAND flash lines state */
         struct {
@@ -773,12 +791,6 @@ struct nandsim_geom *nandsim_get_geom(struct nandsim *ns)
 }
 EXPORT_SYMBOL_GPL(nandsim_get_geom);
 
-struct nandsim_regs *nandsim_get_regs(struct nandsim *ns)
-{
-	return &ns->regs;
-}
-EXPORT_SYMBOL_GPL(nandsim_get_regs);
-
 void nandsim_set_backend_data(struct nandsim *ns, void *data)
 {
 	ns->backend_data = data;
@@ -791,12 +803,6 @@ void *nandsim_get_backend_data(struct nandsim *ns)
 }
 EXPORT_SYMBOL_GPL(nandsim_get_backend_data);
 
-union ns_mem *nandsim_get_buf(struct nandsim *ns)
-{
-	return &ns->buf;
-}
-EXPORT_SYMBOL_GPL(nandsim_get_buf);
-
 static void ns_ram_destroy(struct nandsim *ns)
 {
 	struct ns_ram_data *data = ns->backend_data;
@@ -1706,9 +1712,10 @@ static void ns_cachefile_read_page(struct nandsim *ns, int num)
 	}
 }
 
-static void ns_file_read_page(struct nandsim *ns, int num)
+void __ns_file_read_page(struct nandsim *ns, int num,
+			 int (*read_fn)(struct nandsim *ns, char *addr,
+					unsigned long count, loff_t offset))
 {
-	struct ns_file_data *data = ns->backend_data;
 	loff_t pos;
 	ssize_t tx;
 
@@ -1734,12 +1741,26 @@ static void ns_file_read_page(struct nandsim *ns, int num)
 	}
 
 	pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
-	tx = kernel_read(data->file, pos, ns->buf.byte, num);
+	tx = read_fn(ns, ns->buf.byte, num, pos);
 	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);
 }
+EXPORT_SYMBOL_GPL(__ns_file_read_page);
+
+static inline int do_kernel_read(struct nandsim *ns, char *addr,
+				 unsigned long count, loff_t offset)
+{
+	struct ns_file_data *data = ns->backend_data;
+
+	return kernel_read(data->file, offset, addr, count);
+}
+
+static void ns_file_read_page(struct nandsim *ns, int num)
+{
+	__ns_file_read_page(ns, num, do_kernel_read);
+}
 
 static void ns_ram_erase_sector(struct nandsim *ns)
 {
@@ -1771,24 +1792,42 @@ static void ns_cachefile_erase_sector(struct nandsim *ns)
 	}
 }
 
-static void ns_file_erase_sector(struct nandsim *ns)
+static inline ssize_t do_kernel_write(struct nandsim *ns, const char *addr,
+				      size_t count, loff_t offset)
+{
+	struct ns_file_data *data = ns->backend_data;
+
+	return kernel_write(data->file, addr, count, offset);
+}
+
+
+void __ns_file_erase_sector(struct nandsim *ns, char *file_buf,
+			    ssize_t (*write_fn)(struct nandsim *ns, const char *buf,
+			    size_t count, loff_t pos))
 {
 	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, pagesz);
+	memset(file_buf, 0xff, pagesz);
 
 	for (i = 0; i < ns->geom.pgsec; i++) {
 		pos = (loff_t)(ns->regs.row + i) * pagesz;
-		tx = kernel_write(data->file, data->file_buf, pagesz, pos);
+		tx = write_fn(ns, file_buf, pagesz, pos);
 		if (tx != pagesz) {
 			NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
 		}
 	}
 }
+EXPORT_SYMBOL_GPL(__ns_file_erase_sector);
+
+static void ns_file_erase_sector(struct nandsim *ns)
+{
+	struct ns_file_data *data = ns->backend_data;
+
+	__ns_file_erase_sector(ns, data->file_buf, do_kernel_write);
+}
 
 static int ns_ram_prog_page(struct nandsim *ns, int num)
 {
@@ -1863,13 +1902,16 @@ 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 __ns_file_prog_page(struct nandsim *ns, int num, char *file_buf,
+			int (*read_fn)(struct nandsim *ns, char *addr,
+				       unsigned long count, loff_t offset),
+			ssize_t (*write_fn)(struct nandsim *ns, const char *buf,
+					    size_t count, loff_t pos))
 {
 	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);
 
@@ -1885,10 +1927,10 @@ static int ns_file_prog_page(struct nandsim *ns, int num)
 			num -= pg_write_end - ns->geom.pgsz;
 	}
 
-	pg_off = data->file_buf + ns->regs.column + ns->regs.off;
+	pg_off = 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);
+	tx = read_fn(ns, pg_off, num, off);
 	if (tx == 0)
 		memset(pg_off, 0xff, num);
 	else if (tx != num) {
@@ -1899,7 +1941,7 @@ static int ns_file_prog_page(struct nandsim *ns, int num)
 	for (i = 0; i < num; i++)
 		pg_off[i] &= ns->buf.byte[i];
 
-	tx = kernel_write(data->file, pg_off, num, off);
+	tx = write_fn(ns, 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;
@@ -1907,6 +1949,15 @@ static int ns_file_prog_page(struct nandsim *ns, int num)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(__ns_file_prog_page);
+
+static int ns_file_prog_page(struct nandsim *ns, int num)
+{
+	struct ns_file_data *data = ns->backend_data;
+
+	return __ns_file_prog_page(ns, num, data->file_buf, do_kernel_read,
+				   do_kernel_write);
+}
 
 static struct ns_backend_ops ns_ram_bops = {
 	.erase_sector = ns_ram_erase_sector,
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index 05ac7e3..85d4d7e 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -47,25 +47,6 @@ struct nandsim_geom {
 	uint idbytes;       /* the number ID bytes that this chip outputs */
 };
 
-/* NAND flash internal registers */
-struct nandsim_regs {
-	unsigned command; /* the command register */
-	u_char   status;  /* the status register */
-	uint     row;     /* the page number */
-	uint     column;  /* the offset within page */
-	uint     count;   /* internal counter */
-	uint     num;     /* number of bytes which must be processed */
-	uint     off;     /* fixed page offset */
-};
-
-/*
- * A union to represent flash memory contents and flash buffer.
- */
-union ns_mem {
-	u_char *byte;    /* for byte access */
-	uint16_t *word;  /* for 16-bit word access */
-};
-
 struct nandsim;
 struct ns_backend_ops {
 	void (*erase_sector)(struct nandsim *ns);
@@ -79,9 +60,19 @@ struct ns_backend_ops {
 struct mtd_info *ns_new_instance(struct nandsim_params *nsparam);
 int ns_destroy_instance(struct mtd_info *nsmtd);
 struct nandsim_geom *nandsim_get_geom(struct nandsim *ns);
-struct nandsim_regs *nandsim_get_regs(struct nandsim *ns);
 void nandsim_set_backend_data(struct nandsim *ns, void *data);
 void *nandsim_get_backend_data(struct nandsim *ns);
-union ns_mem *nandsim_get_buf(struct nandsim *ns);
 
+void __ns_file_read_page(struct nandsim *ns, int num,
+			 int (*read_fn)(struct nandsim *ns, char *addr,
+					unsigned long count, loff_t offset));
+
+int __ns_file_prog_page(struct nandsim *ns, int num, char *file_buf,
+			int (*read_fn)(struct nandsim *ns, char *addr,
+				       unsigned long count, loff_t offset),
+			ssize_t (*write_fn)(struct nandsim *ns, const char *buf,
+					    size_t count, loff_t pos));
+void __ns_file_erase_sector(struct nandsim *ns, char *file_buf,
+			    ssize_t (*write_fn)(struct nandsim *ns, const char *buf,
+						size_t count, loff_t pos));
 #endif /* __LINUX_NANDSIM_H__ */
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 29/46] um: Add nandsim backend driver
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (27 preceding siblings ...)
  2016-09-21  9:52 ` [PATCH v2 28/46] mtd: nandsim: Refine exports Daniel Walter
@ 2016-09-21  9:54 ` Daniel Walter
  2016-09-21  9:54 ` [PATCH v2 30/46] mtd: nandsim: Use pr_ style logging Daniel Walter
                   ` (17 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:54 UTC (permalink / raw)
  To: user-mode-linux-devel; +Cc: linux-kernel, jdike, richard

From: Richard Weinberger <richard@nod.at>

Add a small UML driver to act as nandsim backend.
This allows us to use the nandsim MTD as root device
and boot from it.
e.g. ./linux mem=512M unand.backing_file=/home/rw/work/ubifs/mtd4.raw \
 unand.id_bytes=0x1c,0xd3,0x90,0xa6 unand.no_oob=y nandsim.defaults=n \
 ubi.mtd=0 rootfstype=ubifs root=ubi0:rootfs

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 arch/um/Kconfig.um          |   6 ++
 arch/um/drivers/Makefile    |   2 +
 arch/um/drivers/nand_kern.c | 159 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 167 insertions(+)
 create mode 100644 arch/um/drivers/nand_kern.c

diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um
index 4b2ed58..f7a1a17 100644
--- a/arch/um/Kconfig.um
+++ b/arch/um/Kconfig.um
@@ -44,6 +44,12 @@ config HOSTFS
           If you'd like to be able to work with files stored on the host,
           say Y or M here; otherwise say N.
 
+config UML_NANDSIM
+	tristate "UML nandsim backend"
+	help
+	  Use a file on the host directly as backend for nandsim.
+	  For more help, see modinfo unand.
+
 config MCONSOLE
 	bool "Management console"
 	depends on PROC_FS
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index e7582e1..08a806e 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -16,6 +16,7 @@ hostaudio-objs := hostaudio_kern.o
 ubd-objs := ubd_kern.o ubd_user.o
 port-objs := port_kern.o port_user.o
 harddog-objs := harddog_kern.o harddog_user.o
+unand-objs := nand_kern.o
 
 LDFLAGS_pcap.o := -r $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libpcap.a)
 
@@ -59,6 +60,7 @@ obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
 obj-$(CONFIG_UML_WATCHDOG) += harddog.o
 obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
 obj-$(CONFIG_UML_RANDOM) += random.o
+obj-$(CONFIG_UML_NANDSIM) += unand.o
 
 # pcap_user.o must be added explicitly.
 USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o
diff --git a/arch/um/drivers/nand_kern.c b/arch/um/drivers/nand_kern.c
new file mode 100644
index 0000000..399d9e6
--- /dev/null
+++ b/arch/um/drivers/nand_kern.c
@@ -0,0 +1,159 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nandsim.h>
+#include <init.h>
+#include <os.h>
+
+static u_char id_bytes[8] = {
+	[0 ... 7] = 0xFF,
+};
+static bool no_oob;
+static char *backing_file;
+static unsigned int bus_width;
+
+module_param_array(id_bytes, byte, NULL, 0400);
+module_param(no_oob, bool, 0400);
+module_param(backing_file, charp, 0400);
+module_param(bus_width, uint, 0400);
+
+MODULE_PARM_DESC(backing_file, "File to use as backing store");
+MODULE_PARM_DESC(id_bytes, "The ID bytes returned by NAND Flash 'read ID' command");
+MODULE_PARM_DESC(no_oob, "Set to use an image without OOB data, i.e created by nanddump");
+MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)");
+
+struct ns_uml_data {
+	int fd;
+	void *file_buf;
+};
+
+/*
+ * We support only one instance so far, just to boot from MTD.
+ * If you need more MTDs, use nandsimctl(8).
+ */
+static struct mtd_info *nsmtd;
+
+static int file_read(struct nandsim *ns, char *addr, unsigned long count,
+		     loff_t offset)
+{
+	struct ns_uml_data *data = nandsim_get_backend_data(ns);
+
+	return os_pread_file(data->fd, addr, count, offset);
+}
+
+static ssize_t file_write(struct nandsim *ns, const char *addr, size_t count,
+			  loff_t offset)
+{
+	struct ns_uml_data *data = nandsim_get_backend_data(ns);
+
+	return os_pwrite_file(data->fd, addr, count, offset);
+}
+
+static void ns_uml_read_page(struct nandsim *ns, int num)
+{
+	__ns_file_read_page(ns, num, file_read);
+}
+
+static int ns_uml_prog_page(struct nandsim *ns, int num)
+{
+	struct ns_uml_data *data = nandsim_get_backend_data(ns);
+
+	return __ns_file_prog_page(ns, num, data->file_buf, file_read,
+				   file_write);
+}
+
+static void ns_uml_erase_sector(struct nandsim *ns)
+{
+	struct ns_uml_data *data = nandsim_get_backend_data(ns);
+
+	__ns_file_erase_sector(ns, data->file_buf, file_write);
+}
+
+static int ns_uml_init(struct nandsim *ns, struct nandsim_params *nsparam)
+{
+	struct ns_uml_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+
+	if (!data)
+		return -ENOMEM;
+
+	data->file_buf = kmalloc(nandsim_get_geom(ns)->pgszoob, GFP_KERNEL);
+	if (!data->file_buf) {
+		kfree(data);
+		return -ENOMEM;
+	}
+
+	data->fd = os_open_file(nsparam->cache_file, of_set_rw(OPENFLAGS(), 1, 1), 0);
+	if (data->fd < 0) {
+		printk(KERN_ERR "Unable to open %s: %i\n", nsparam->cache_file, data->fd);
+		kfree(data->file);
+		kfree(data);
+		return data->fd;
+	}
+
+	nandsim_set_backend_data(ns, data);
+
+	return 0;
+}
+
+static void ns_uml_destroy(struct nandsim *ns)
+{
+	struct ns_uml_data *data = nandsim_get_backend_data(ns);
+
+	if (!data)
+		return;
+
+	os_close_file(data->fd);
+	kfree(data->file_buf);
+	kfree(data);
+}
+
+static struct ns_backend_ops ns_uml_bops = {
+	.erase_sector = ns_uml_erase_sector,
+	.prog_page = ns_uml_prog_page,
+	.read_page = ns_uml_read_page,
+	.init = ns_uml_init,
+	.destroy = ns_uml_destroy,
+	.name = "uml",
+};
+
+static struct nandsim_params params = {
+	.bops = &ns_uml_bops,
+};
+
+static int __init uml_ns_init(void)
+{
+	struct mtd_info *ret;
+
+	if (!backing_file)
+		return 0;
+
+	params.cache_file = backing_file;
+	params.bus_width = bus_width;
+	params.no_oob = no_oob;
+	memcpy(params.id_bytes, id_bytes, sizeof(params.id_bytes));
+
+	ret = ns_new_instance(&params);
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	nsmtd = ret;
+
+	return 0;
+}
+late_initcall(uml_ns_init);
+
+static void __exit uml_ns_exit(void)
+{
+	/*
+	 * Since this driver is a singleton we can rely on module refcounting,
+	 * and assume that ns_destroy_instance() will succeed in any case.
+	 * If not, print a frindly warning. B-)
+	 */
+	WARN_ON(ns_destroy_instance(nsmtd) != 0);
+}
+module_exit(uml_ns_exit);
+
+MODULE_AUTHOR("Richard Weinberger");
+MODULE_DESCRIPTION("UML nandsim backend");
+MODULE_LICENSE("GPL");
+
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 30/46] mtd: nandsim: Use pr_ style logging
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (28 preceding siblings ...)
  2016-09-21  9:54 ` [PATCH v2 29/46] um: Add nandsim backend driver Daniel Walter
@ 2016-09-21  9:54 ` Daniel Walter
  2016-09-21  9:54 ` [PATCH v2 31/46] mtd: nandsim: Remove NS_RAW_OFFSET_OOB Daniel Walter
                   ` (16 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:54 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

These days we have CONFIG_DYNAMIC_DEBUG and stuff, there
is no need to open code logging.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index cf2694f..048beb0 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -23,6 +23,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/module.h>
@@ -84,12 +86,6 @@
 #ifndef CONFIG_NANDSIM_DO_DELAYS
 #define CONFIG_NANDSIM_DO_DELAYS  0
 #endif
-#ifndef CONFIG_NANDSIM_LOG
-#define CONFIG_NANDSIM_LOG        0
-#endif
-#ifndef CONFIG_NANDSIM_DBG
-#define CONFIG_NANDSIM_DBG        0
-#endif
 #ifndef CONFIG_NANDSIM_MAX_PARTS
 #define CONFIG_NANDSIM_MAX_PARTS  32
 #endif
@@ -101,8 +97,6 @@ static uint output_cycle   = CONFIG_NANDSIM_OUTPUT_CYCLE;
 static uint input_cycle    = CONFIG_NANDSIM_INPUT_CYCLE;
 static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
 static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
-static uint log            = CONFIG_NANDSIM_LOG;
-static uint dbg            = CONFIG_NANDSIM_DBG;
 static unsigned long parts[CONFIG_NANDSIM_MAX_PARTS];
 static unsigned int parts_num;
 static char *badblocks = NULL;
@@ -135,8 +129,6 @@ module_param(output_cycle,   uint, 0400);
 module_param(input_cycle,    uint, 0400);
 module_param(bus_width,      uint, 0400);
 module_param(do_delays,      uint, 0400);
-module_param(log,            uint, 0400);
-module_param(dbg,            uint, 0400);
 module_param_array(parts, ulong, &parts_num, 0400);
 module_param(badblocks,      charp, 0400);
 module_param(weakblocks,     charp, 0400);
@@ -155,14 +147,12 @@ MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read I
 MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command (obsolete)");
 MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command (obsolete)");
 MODULE_PARM_DESC(access_delay,   "Initial page access delay (microseconds)");
-MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
+MODULE_PARM_DESC(programm_delay, "Page program delay (microseconds");
 MODULE_PARM_DESC(erase_delay,    "Sector erase delay (milliseconds)");
 MODULE_PARM_DESC(output_cycle,   "Word output (from flash) time (nanoseconds)");
 MODULE_PARM_DESC(input_cycle,    "Word input (to flash) time (nanoseconds)");
 MODULE_PARM_DESC(bus_width,      "Chip's bus width (8- or 16-bit)");
 MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
-MODULE_PARM_DESC(log,            "Perform logging if not zero");
-MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
 MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
 /* Page and erase block positions for the following parameters are independent of any partitions */
 MODULE_PARM_DESC(badblocks,      "Erase blocks that are initially marked bad, separated by commas");
@@ -189,21 +179,6 @@ MODULE_PARM_DESC(defaults,	 "Register a MTD during module load using default val
 /* The largest possible page size */
 #define NS_LARGEST_PAGE_SIZE	4096
 
-/* The prefix for simulator output */
-#define NS_OUTPUT_PREFIX "[nandsim]"
-
-/* Simulator's output macros (logging, debugging, warning, error) */
-#define NS_LOG(args...) \
-	do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)
-#define NS_DBG(args...) \
-	do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
-#define NS_WARN(args...) \
-	do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
-#define NS_ERR(args...) \
-	do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
-#define NS_INFO(args...) \
-	do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
-
 /* Busy-wait delay macros (microseconds, milliseconds) */
 #define NS_UDELAY(ns, us) \
 	do { if (ns->do_delays) udelay(us); } while (0)
@@ -562,7 +537,7 @@ static int nandsim_debugfs_init(void)
 	if (IS_ERR_OR_NULL(dfs_root)) {
 		int err = dfs_root ? -ENODEV : PTR_ERR(dfs_root);
 
-		NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
+		pr_err("cannot create \"nandsim\" debugfs directory, err %d\n",
 			err);
 		return err;
 	}
@@ -596,7 +571,7 @@ static int nandsim_debugfs_create(struct nandsim *dev)
 	if (IS_ERR_OR_NULL(dent)) {
 		int err = dent ? -ENODEV : PTR_ERR(dent);
 
-		NS_ERR("cannot create nandsim debugfs sub-directory, err %d\n",
+		pr_err("cannot create nandsim debugfs sub-directory, err %d\n",
 			err);
 		return err;
 	}
@@ -636,7 +611,7 @@ static int ns_ram_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	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");
+		pr_err("unable to allocate page array\n");
 		return -ENOMEM;
 	}
 	for (i = 0; i < ns->geom.pgnum; i++) {
@@ -648,7 +623,7 @@ static int ns_ram_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	if (!data->nand_pages_slab) {
 		vfree(data->pages);
 		kfree(data);
-		NS_ERR("cache_create: unable to create kmem_cache\n");
+		pr_err("unable to create kmem_cache\n");
 		return -ENOMEM;
 	}
 
@@ -679,19 +654,19 @@ static struct file *get_file_from_nsparam(struct nandsim_params *nsparam, bool *
 
 	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");
+		pr_err("backing file is not a regular file nor a block device\n");
 		err = -EINVAL;
 		goto out;
 	}
 
 	if (!(file->f_mode & FMODE_CAN_READ)) {
-		NS_ERR("alloc_device: cache file not readable\n");
+		pr_err("cache file not readable\n");
 		err = -EINVAL;
 		goto out;
 	}
 
 	if (!(file->f_mode & FMODE_CAN_WRITE)) {
-		NS_ERR("alloc_device: cache file not writeable\n");
+		pr_err("cache file not writeable\n");
 		err = -EINVAL;
 		goto out;
 	}
@@ -724,13 +699,13 @@ static int ns_cachefile_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	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");
+		pr_err("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");
+		pr_err("unable to allocate file buf\n");
 		err = -ENOMEM;
 		goto err_free;
 	}
@@ -767,7 +742,7 @@ static int ns_file_init(struct nandsim *ns, struct nandsim_params *nsparam)
 
 	data->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
 	if (!data->file_buf) {
-		NS_ERR("alloc_device: unable to allocate file buf\n");
+		pr_err("unable to allocate file buf\n");
 		ret = -ENOMEM;
 		goto out_put;
 	}
@@ -868,7 +843,7 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	uint64_t next_offset;
 
 	if (NS_IS_INITIALIZED(ns)) {
-		NS_ERR("init_nandsim: nandsim is already initialized\n");
+		pr_err("init_nandsim: nandsim is already initialized\n");
 		return -EIO;
 	}
 
@@ -899,7 +874,7 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	} else if (ns->geom.pgsz == 4096) {
 		ns->options |= OPT_PAGE4096;
 	} else {
-		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
+		pr_err("unknown page size %u\n", ns->geom.pgsz);
 		return -EIO;
 	}
 
@@ -923,7 +898,7 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 
 	/* Fill the partition_info structure */
 	if (nsparam->parts_num > ARRAY_SIZE(ns->partitions)) {
-		NS_ERR("too many partitions.\n");
+		pr_err("too many partitions.\n");
 		return -EINVAL;
 	}
 	remains = ns->geom.totsz;
@@ -932,12 +907,12 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 		uint64_t part_sz = (uint64_t)nsparam->parts[i] * ns->geom.secsz;
 
 		if (!part_sz || part_sz > remains) {
-			NS_ERR("bad partition size.\n");
+			pr_err("bad partition size.\n");
 			return -EINVAL;
 		}
 		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
-			NS_ERR("unable to allocate memory.\n");
+			pr_err("unable to allocate memory.\n");
 			return -ENOMEM;
 		}
 		ns->partitions[i].offset = next_offset;
@@ -948,12 +923,12 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	ns->nbparts = nsparam->parts_num;
 	if (remains) {
 		if (nsparam->parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
-			NS_ERR("too many partitions.\n");
+			pr_err("too many partitions.\n");
 			return -EINVAL;
 		}
 		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
-			NS_ERR("unable to allocate memory.\n");
+			pr_err("unable to allocate memory.\n");
 			return -ENOMEM;
 		}
 		ns->partitions[i].offset = next_offset;
@@ -962,37 +937,37 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	}
 
 	if (ns->busw == 16)
-		NS_WARN("16-bit flashes support wasn't tested\n");
+		pr_warn("16-bit flashes support wasn't tested\n");
 
-	NS_INFO("flash size: %llu MiB\n",
+	pr_info("flash size: %llu MiB\n",
 			(unsigned long long)ns->geom.totsz >> 20);
-	NS_INFO("page size: %u bytes\n",         ns->geom.pgsz);
-	NS_INFO("OOB area size: %u bytes\n",     ns->geom.oobsz);
-	NS_INFO("sector size: %u KiB\n",         ns->geom.secsz >> 10);
-	NS_INFO("pages number: %u\n",            ns->geom.pgnum);
-	NS_INFO("pages per sector: %u\n",        ns->geom.pgsec);
-	NS_INFO("bus width: %u\n",               ns->busw);
-	NS_INFO("bits in sector size: %u\n",     ns->geom.secshift);
-	NS_INFO("bits in page size: %u\n",       ns->geom.pgshift);
-	NS_INFO("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
-	NS_INFO("flash size with OOB: %llu KiB\n",
+	pr_info("page size: %u bytes\n",         ns->geom.pgsz);
+	pr_info("OOB area size: %u bytes\n",     ns->geom.oobsz);
+	pr_info("sector size: %u KiB\n",         ns->geom.secsz >> 10);
+	pr_info("pages number: %u\n",            ns->geom.pgnum);
+	pr_info("pages per sector: %u\n",        ns->geom.pgsec);
+	pr_info("bus width: %u\n",               ns->busw);
+	pr_info("bits in sector size: %u\n",     ns->geom.secshift);
+	pr_info("bits in page size: %u\n",       ns->geom.pgshift);
+	pr_info("bits in OOB size: %u\n",	ffs(ns->geom.oobsz) - 1);
+	pr_info("flash size with OOB: %llu KiB\n",
 			(unsigned long long)ns->geom.totszoob >> 10);
-	NS_INFO("page address bytes: %u\n",      ns->geom.pgaddrbytes);
-	NS_INFO("sector address bytes: %u\n",    ns->geom.secaddrbytes);
-	NS_INFO("options: %#x\n",                ns->options);
+	pr_info("page address bytes: %u\n",      ns->geom.pgaddrbytes);
+	pr_info("sector address bytes: %u\n",    ns->geom.secaddrbytes);
+	pr_info("options: %#x\n",                ns->options);
 
 	ns->bops = nsparam->bops;
 
-	NS_INFO("Using backend: %s\n", ns->bops->name);
+	pr_info("Using backend: %s\n", ns->bops->name);
 	if ((ret = ns->bops->init(ns, nsparam)) != 0) {
-		NS_ERR("Unable to initialize simulator backend: %i\n", ret);
+		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) {
-		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
+		pr_err("unable to allocate %u bytes for the internal buffer\n",
 			ns->geom.pgszoob);
 		return -ENOMEM;
 	}
@@ -1025,12 +1000,12 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd,
 		zero_ok = (*w == '0' ? 1 : 0);
 		erase_block_no = simple_strtoul(w, &w, 0);
 		if (!zero_ok && !erase_block_no) {
-			NS_ERR("invalid badblocks.\n");
+			pr_err("invalid badblocks.\n");
 			return -EINVAL;
 		}
 		offset = (loff_t)erase_block_no * ns->geom.secsz;
 		if (mtd_block_markbad(mtd, offset)) {
-			NS_ERR("invalid badblocks.\n");
+			pr_err("invalid badblocks.\n");
 			return -EINVAL;
 		}
 		if (*w == ',')
@@ -1054,7 +1029,7 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks)
 		zero_ok = (*w == '0' ? 1 : 0);
 		erase_block_no = simple_strtoul(w, &w, 0);
 		if (!zero_ok && !erase_block_no) {
-			NS_ERR("invalid weakblocks.\n");
+			pr_err("invalid weakblocks.\n");
 			return -EINVAL;
 		}
 		max_erases = 3;
@@ -1066,7 +1041,7 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks)
 			w += 1;
 		wb = kzalloc(sizeof(*wb), GFP_KERNEL);
 		if (!wb) {
-			NS_ERR("unable to allocate memory.\n");
+			pr_err("unable to allocate memory.\n");
 			return -ENOMEM;
 		}
 		wb->erase_block_no = erase_block_no;
@@ -1105,7 +1080,7 @@ static int parse_weakpages(struct nandsim *ns, unsigned char *weakpages)
 		zero_ok = (*w == '0' ? 1 : 0);
 		page_no = simple_strtoul(w, &w, 0);
 		if (!zero_ok && !page_no) {
-			NS_ERR("invalid weakpagess.\n");
+			pr_err("invalid weakpagess.\n");
 			return -EINVAL;
 		}
 		max_writes = 3;
@@ -1117,7 +1092,7 @@ static int parse_weakpages(struct nandsim *ns, unsigned char *weakpages)
 			w += 1;
 		wp = kzalloc(sizeof(*wp), GFP_KERNEL);
 		if (!wp) {
-			NS_ERR("unable to allocate memory.\n");
+			pr_err("unable to allocate memory.\n");
 			return -ENOMEM;
 		}
 		wp->page_no = page_no;
@@ -1156,7 +1131,7 @@ static int parse_gravepages(struct nandsim *ns, unsigned char *gravepages)
 		zero_ok = (*g == '0' ? 1 : 0);
 		page_no = simple_strtoul(g, &g, 0);
 		if (!zero_ok && !page_no) {
-			NS_ERR("invalid gravepagess.\n");
+			pr_err("invalid gravepagess.\n");
 			return -EINVAL;
 		}
 		max_reads = 3;
@@ -1168,7 +1143,7 @@ static int parse_gravepages(struct nandsim *ns, unsigned char *gravepages)
 			g += 1;
 		gp = kzalloc(sizeof(*gp), GFP_KERNEL);
 		if (!gp) {
-			NS_ERR("unable to allocate memory.\n");
+			pr_err("unable to allocate memory.\n");
 			return -ENOMEM;
 		}
 		gp->page_no = page_no;
@@ -1219,12 +1194,12 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 	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");
+		pr_err("Too many erase blocks for wear reporting\n");
 		return -ENOMEM;
 	}
 	ns->erase_block_wear = kzalloc(mem, GFP_KERNEL);
 	if (!ns->erase_block_wear) {
-		NS_ERR("Too many erase blocks for wear reporting\n");
+		pr_err("Too many erase blocks for wear reporting\n");
 		return -ENOMEM;
 	}
 	return 0;
@@ -1240,10 +1215,10 @@ static void update_wear(struct nandsim *ns, unsigned int erase_block_no)
 	 * instead of showing an error message.
 	 */
 	if (ns->total_wear == 0)
-		NS_ERR("Erase counter total overflow\n");
+		pr_err("Erase counter total overflow\n");
 	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);
+		pr_err("Erase counter overflow for erase block %u\n", erase_block_no);
 }
 
 /*
@@ -1300,7 +1275,7 @@ static char *get_state_name(uint32_t state)
 			return "STATE_UNKNOWN";
 	}
 
-	NS_ERR("get_state_name: unknown state, BUG\n");
+	pr_err("unknown state, BUG\n");
 	return NULL;
 }
 
@@ -1367,7 +1342,7 @@ static uint32_t get_state_by_command(unsigned command)
 			return STATE_CMD_RNDOUTSTART;
 	}
 
-	NS_ERR("get_state_by_command: unknown command, BUG\n");
+	pr_err("unknown command, BUG\n");
 	return 0;
 }
 
@@ -1394,7 +1369,7 @@ static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
  */
 static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
 {
-	NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
+	pr_debug("switch to %s state\n", get_state_name(STATE_READY));
 
 	ns->state       = STATE_READY;
 	ns->nxstate     = STATE_UNKNOWN;
@@ -1503,7 +1478,7 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
 		ns->npstates = 0;
 		ns->state = ns->op[ns->stateidx];
 		ns->nxstate = ns->op[ns->stateidx + 1];
-		NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
+		pr_debug("operation found, index: %d, state: %s, nxstate %s\n",
 				idx, get_state_name(ns->state), get_state_name(ns->nxstate));
 		return 0;
 	}
@@ -1511,24 +1486,24 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
 	if (opsfound == 0) {
 		/* Nothing was found. Try to ignore previous commands (if any) and search again */
 		if (ns->npstates != 0) {
-			NS_DBG("find_operation: no operation found, try again with state %s\n",
+			pr_debug("no operation found, try again with state %s\n",
 					get_state_name(ns->state));
 			ns->npstates = 0;
 			return find_operation(ns, 0);
 
 		}
-		NS_DBG("find_operation: no operations found\n");
+		pr_debug("no operations found\n");
 		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
 		return -2;
 	}
 
 	if (flag) {
 		/* This shouldn't happen */
-		NS_DBG("find_operation: BUG, operation must be known if address is input\n");
+		pr_err("BUG, operation must be known if address is input\n");
 		return -2;
 	}
 
-	NS_DBG("find_operation: there is still ambiguity\n");
+	pr_debug("there is still ambiguity\n");
 
 	ns->pstates[ns->npstates++] = ns->state;
 
@@ -1644,7 +1619,7 @@ static int do_read_error(struct nandsim *ns, int num)
 
 	if (read_error(ns, page_no)) {
 		prandom_bytes(ns->buf.byte, num);
-		NS_WARN("simulating read error in page %u\n", page_no);
+		pr_warn("simulating read error in page %u\n", page_no);
 		return 1;
 	}
 	return 0;
@@ -1661,7 +1636,7 @@ static void do_bit_flips(struct nandsim *ns, int num)
 		while (flips--) {
 			int pos = prandom_u32() % (num * 8);
 			ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
-			NS_WARN("read_page: flipping bit %d in page %d "
+			pr_warn("flipping bit %d in page %d "
 				"reading from %d ecc: corrected=%u failed=%u\n",
 				pos, ns->regs.row, ns->regs.column + ns->regs.off,
 				nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
@@ -1675,10 +1650,10 @@ static void ns_ram_read_page(struct nandsim *ns, int num)
 
 	mypage = NS_GET_PAGE(ns);
 	if (mypage->byte == NULL) {
-		NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
+		pr_debug("page %d not allocated\n", ns->regs.row);
 		memset(ns->buf.byte, 0xFF, num);
 	} else {
-		NS_DBG("read_page: page %d allocated, reading from %d\n",
+		pr_debug("page %d allocated, reading from %d\n",
 			ns->regs.row, ns->regs.column + ns->regs.off);
 		if (do_read_error(ns, num))
 			return;
@@ -1692,20 +1667,20 @@ static void ns_cachefile_read_page(struct nandsim *ns, int num)
 	struct ns_cachefile_data *data = ns->backend_data;
 
 	if (!test_bit(ns->regs.row, data->pages_written)) {
-		NS_DBG("read_page: page %d not written\n", ns->regs.row);
+		pr_debug("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",
+		pr_debug("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);
+			pr_err("read error for page %d ret %ld\n", ns->regs.row, (long)tx);
 			return;
 		}
 		do_bit_flips(ns, num);
@@ -1719,7 +1694,7 @@ void __ns_file_read_page(struct nandsim *ns, int num,
 	loff_t pos;
 	ssize_t tx;
 
-	NS_DBG("read_page: page %d written, reading from %d\n",
+	pr_debug("page %d written, reading from %d\n",
 		ns->regs.row, ns->regs.column + ns->regs.off);
 
 	if (ns->no_oob) {
@@ -1745,7 +1720,7 @@ void __ns_file_read_page(struct nandsim *ns, int 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);
+		pr_err("read error for page %d ret %ld\n", ns->regs.row, (long)tx);
 }
 EXPORT_SYMBOL_GPL(__ns_file_read_page);
 
@@ -1771,7 +1746,7 @@ static void ns_ram_erase_sector(struct nandsim *ns)
 	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);
+			pr_debug("freeing page %d\n", ns->regs.row+i);
 			kmem_cache_free(data->nand_pages_slab, mypage->byte);
 			mypage->byte = NULL;
 		}
@@ -1787,7 +1762,7 @@ static void ns_cachefile_erase_sector(struct nandsim *ns)
 	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);
+			pr_debug("freeing page %d\n", ns->regs.row + i);
 		}
 	}
 }
@@ -1816,7 +1791,7 @@ void __ns_file_erase_sector(struct nandsim *ns, char *file_buf,
 		pos = (loff_t)(ns->regs.row + i) * pagesz;
 		tx = write_fn(ns, file_buf, pagesz, pos);
 		if (tx != pagesz) {
-			NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+			pr_err("write error for page %d ret %ld\n", ns->regs.row, (long)tx);
 		}
 	}
 }
@@ -1838,7 +1813,7 @@ static int ns_ram_prog_page(struct nandsim *ns, int num)
 
 	mypage = NS_GET_PAGE(ns);
 	if (mypage->byte == NULL) {
-		NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
+		pr_debug("allocating page %d\n", ns->regs.row);
 		/*
 		 * We allocate memory with GFP_NOFS because a flash FS may
 		 * utilize this. If it is holding an FS lock, then gets here,
@@ -1847,7 +1822,7 @@ static int ns_ram_prog_page(struct nandsim *ns, int num)
 		 */
 		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);
+			pr_err("error allocating memory for page %d\n", ns->regs.row);
 			return -1;
 		}
 		memset(mypage->byte, 0xFF, ns->geom.pgszoob);
@@ -1868,7 +1843,7 @@ static int ns_cachefile_prog_page(struct nandsim *ns, int num)
 	u_char *pg_off;
 	struct ns_cachefile_data *data = ns->backend_data;
 
-	NS_DBG("prog_page: writing page %d\n", ns->regs.row);
+	pr_debug("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)) {
@@ -1878,7 +1853,7 @@ static int ns_cachefile_prog_page(struct nandsim *ns, int num)
 		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);
+			pr_err("read error for page %d ret %ld\n", ns->regs.row, (long)tx);
 			return -1;
 		}
 	}
@@ -1888,14 +1863,14 @@ static int ns_cachefile_prog_page(struct nandsim *ns, int num)
 		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);
+			pr_err("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);
+			pr_err("write error for page %d ret %ld\n", ns->regs.row, (long)tx);
 			return -1;
 		}
 	}
@@ -1913,7 +1888,7 @@ int __ns_file_prog_page(struct nandsim *ns, int num, char *file_buf,
 	ssize_t tx;
 	u_char *pg_off;
 
-	NS_DBG("prog_page: writing page %d\n", ns->regs.row);
+	pr_debug("writing page %d\n", ns->regs.row);
 
 	if (ns->no_oob) {
 		loff_t pg_write_end = ns->regs.column + ns->regs.off + num;
@@ -1934,7 +1909,7 @@ int __ns_file_prog_page(struct nandsim *ns, int num, char *file_buf,
 	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);
+		pr_err("read error for page %d ret %ld\n", ns->regs.row, (long)tx);
 		return -1;
 	}
 
@@ -1943,7 +1918,7 @@ int __ns_file_prog_page(struct nandsim *ns, int num, char *file_buf,
 
 	tx = write_fn(ns, pg_off, num, off);
 	if (tx != num) {
-		NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+		pr_err("write error for page %d ret %ld\n", ns->regs.row, (long)tx);
 		return -1;
 	}
 
@@ -2001,7 +1976,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 
 	/* Check that page address input is correct */
 	if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
-		NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
+		pr_warn("wrong page number (%#x)\n", ns->regs.row);
 		return -1;
 	}
 
@@ -2014,21 +1989,21 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 
 		/* Column shouldn't be very large */
 		if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
-			NS_ERR("do_state_action: column number is too large\n");
+			pr_err("column number is too large\n");
 			break;
 		}
 		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
 		ns->bops->read_page(ns, num);
 
-		NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
+		pr_debug("ACTION_CPY: copy %d bytes to int buf, raw offset %d\n",
 			num, NS_RAW_OFFSET(ns) + ns->regs.off);
 
 		if (ns->regs.off == 0)
-			NS_LOG("read page %d\n", ns->regs.row);
+			pr_debug("read page %d\n", ns->regs.row);
 		else if (ns->regs.off < ns->geom.pgsz)
-			NS_LOG("read page %d (second half)\n", ns->regs.row);
+			pr_debug("read page %d (second half)\n", ns->regs.row);
 		else
-			NS_LOG("read OOB of page %d\n", ns->regs.row);
+			pr_debug("read OOB of page %d\n", ns->regs.row);
 
 		NS_UDELAY(ns, ns->access_delay);
 		NS_UDELAY(ns, ns->input_cycle * ns->geom.pgsz / 1000 / busdiv);
@@ -2041,13 +2016,13 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 		 */
 
 		if (ns->lines.wp) {
-			NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
+			pr_err("device is write-protected, ignore sector erase\n");
 			return -1;
 		}
 
 		if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
 			|| (ns->regs.row & ~(ns->geom.secsz - 1))) {
-			NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
+			pr_err("wrong sector address (%#x)\n", ns->regs.row);
 			return -1;
 		}
 
@@ -2057,9 +2032,9 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 
 		erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
 
-		NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
+		pr_debug("erase sector at address %#x, off = %d\n",
 				ns->regs.row, NS_RAW_OFFSET(ns));
-		NS_LOG("erase sector %u\n", erase_block_no);
+		pr_debug("erase sector %u\n", erase_block_no);
 
 		ns->bops->erase_sector(ns);
 
@@ -2069,7 +2044,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 			update_wear(ns, erase_block_no);
 
 		if (erase_error(ns, erase_block_no)) {
-			NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
+			pr_warn("simulating erase failure in erase block %u\n", erase_block_no);
 			return -1;
 		}
 
@@ -2081,7 +2056,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 		 */
 
 		if (ns->lines.wp) {
-			NS_WARN("do_state_action: device is write-protected, programm\n");
+			pr_warn("device is write-protected, program\n");
 			return -1;
 		}
 
@@ -2091,7 +2066,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 			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",
+			pr_err("too few bytes were input (%d instead of %d)\n",
 					ns->regs.count, num);
 			return -1;
 		}
@@ -2101,42 +2076,42 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 
 		page_no = ns->regs.row;
 
-		NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
+		pr_debug("copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
 			num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
-		NS_LOG("programm page %d\n", ns->regs.row);
+		pr_debug("program page %d\n", ns->regs.row);
 
 		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);
+			pr_warn("simulating write failure in page %u\n", page_no);
 			return -1;
 		}
 
 		break;
 
 	case ACTION_ZEROOFF:
-		NS_DBG("do_state_action: set internal offset to 0\n");
+		pr_debug("set internal offset to 0\n");
 		ns->regs.off = 0;
 		break;
 
 	case ACTION_HALFOFF:
 		if (!(ns->options & OPT_PAGE512_8BIT)) {
-			NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
+			pr_err("BUG! can't skip half of page for non-512"
 				"byte page size 8x chips\n");
 			return -1;
 		}
-		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
+		pr_debug("set internal offset to %d\n", ns->geom.pgsz/2);
 		ns->regs.off = ns->geom.pgsz/2;
 		break;
 
 	case ACTION_OOBOFF:
-		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
+		pr_debug("set internal offset to %d\n", ns->geom.pgsz);
 		ns->regs.off = ns->geom.pgsz;
 		break;
 
 	default:
-		NS_DBG("do_state_action: BUG! unknown action\n");
+		pr_err("BUG! unknown action\n");
 	}
 
 	return 0;
@@ -2157,7 +2132,7 @@ static void switch_state(struct nandsim *ns)
 		ns->state = ns->nxstate;
 		ns->nxstate = ns->op[ns->stateidx + 1];
 
-		NS_DBG("switch_state: operation is known, switch to the next state, "
+		pr_debug("operation is known, switch to the next state, "
 			"state: %s, nxstate: %s\n",
 			get_state_name(ns->state), get_state_name(ns->nxstate));
 
@@ -2179,7 +2154,7 @@ static void switch_state(struct nandsim *ns)
 		 */
 		ns->state = get_state_by_command(ns->regs.command);
 
-		NS_DBG("switch_state: operation is unknown, try to find it\n");
+		pr_debug("operation is unknown, try to find it\n");
 
 		if (find_operation(ns, 0) != 0)
 			return;
@@ -2192,7 +2167,7 @@ static void switch_state(struct nandsim *ns)
 
 	/* For 16x devices column means the page offset in words */
 	if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
-		NS_DBG("switch_state: double the column number for 16x device\n");
+		pr_debug("double the column number for 16x device\n");
 		ns->regs.column <<= 1;
 	}
 
@@ -2206,12 +2181,12 @@ static void switch_state(struct nandsim *ns)
 		/* In case of data states, see if all bytes were input/output */
 		if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
 			&& ns->regs.count != ns->regs.num) {
-			NS_WARN("switch_state: not all bytes were processed, %d left\n",
+			pr_warn("not all bytes were processed, %d left\n",
 					ns->regs.num - ns->regs.count);
 			status = NS_STATUS_FAILED(ns);
 		}
 
-		NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
+		pr_debug("operation complete, switch to STATE_READY state\n");
 
 		switch_to_ready_state(ns, status);
 
@@ -2225,7 +2200,7 @@ static void switch_state(struct nandsim *ns)
 		ns->nxstate    = ns->op[++ns->stateidx + 1];
 		ns->regs.num   = ns->regs.count = 0;
 
-		NS_DBG("switch_state: the next state is data I/O, switch, "
+		pr_debug("the next state is data I/O, switch, "
 			"state: %s, nxstate: %s\n",
 			get_state_name(ns->state), get_state_name(ns->nxstate));
 
@@ -2248,7 +2223,7 @@ static void switch_state(struct nandsim *ns)
 				break;
 
 			default:
-				NS_ERR("switch_state: BUG! unknown data state\n");
+				pr_err("BUG! unknown data state\n");
 		}
 
 	} else if (ns->nxstate & STATE_ADDR_MASK) {
@@ -2278,7 +2253,7 @@ static void switch_state(struct nandsim *ns)
 				break;
 
 			default:
-				NS_ERR("switch_state: BUG! unknown address state\n");
+				pr_err("BUG! unknown address state\n");
 		}
 	} else {
 		/*
@@ -2298,28 +2273,28 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
 
 	/* Sanity and correctness checks */
 	if (!ns->lines.ce) {
-		NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
+		pr_err("chip is disabled, return %#x\n", (uint)outb);
 		return outb;
 	}
 	if (ns->lines.ale || ns->lines.cle) {
-		NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
+		pr_err("ALE or CLE pin is high, return %#x\n", (uint)outb);
 		return outb;
 	}
 	if (!(ns->state & STATE_DATAOUT_MASK)) {
-		NS_WARN("read_byte: unexpected data output cycle, state is %s "
+		pr_warn("unexpected data output cycle, state is %s "
 			"return %#x\n", get_state_name(ns->state), (uint)outb);
 		return outb;
 	}
 
 	/* Status register may be read as many times as it is wanted */
 	if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
-		NS_DBG("read_byte: return %#x status\n", ns->regs.status);
+		pr_debug("return %#x status\n", ns->regs.status);
 		return ns->regs.status;
 	}
 
 	/* Check if there is any data in the internal buffer which may be read */
 	if (ns->regs.count == ns->regs.num) {
-		NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
+		pr_warn("no more data to output, return %#x\n", (uint)outb);
 		return outb;
 	}
 
@@ -2334,7 +2309,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
 			}
 			break;
 		case STATE_DATAOUT_ID:
-			NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
+			pr_debug("read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
 			outb = ns->ids[ns->regs.count];
 			ns->regs.count += 1;
 			break;
@@ -2343,7 +2318,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
 	}
 
 	if (ns->regs.count == ns->regs.num) {
-		NS_DBG("read_byte: all bytes were read\n");
+		pr_debug("all bytes were read\n");
 
 		if (NS_STATE(ns->nxstate) == STATE_READY)
 			switch_state(ns);
@@ -2359,11 +2334,11 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 	/* Sanity and correctness checks */
 	if (!ns->lines.ce) {
-		NS_ERR("write_byte: chip is disabled, ignore write\n");
+		pr_err("chip is disabled, ignore write\n");
 		return;
 	}
 	if (ns->lines.ale && ns->lines.cle) {
-		NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
+		pr_err("ALE and CLE pins are high simultaneously, ignore write\n");
 		return;
 	}
 
@@ -2373,14 +2348,14 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 		 */
 
 		if (byte == NAND_CMD_RESET) {
-			NS_LOG("reset chip\n");
+			pr_debug("reset chip\n");
 			switch_to_ready_state(ns, NS_STATUS_OK(ns));
 			return;
 		}
 
 		/* Check that the command byte is correct */
 		if (check_command(byte)) {
-			NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
+			pr_err("unknown command %#x\n", (uint)byte);
 			return;
 		}
 
@@ -2403,13 +2378,13 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 				 * was expected but command was input. In this case ignore
 				 * previous command(s)/state(s) and accept the last one.
 				 */
-				NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
+				pr_warn("command (%#x) wasn't expected, expected state is %s, "
 					"ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
 			}
 			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
 		}
 
-		NS_DBG("command byte corresponding to %s state accepted\n",
+		pr_debug("command byte corresponding to %s state accepted\n",
 			get_state_name(get_state_by_command(byte)));
 		ns->regs.command = byte;
 		switch_state(ns);
@@ -2421,7 +2396,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 		if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
 
-			NS_DBG("write_byte: operation isn't known yet, identify it\n");
+			pr_debug("operation isn't known yet, identify it\n");
 
 			if (find_operation(ns, 1) < 0)
 				return;
@@ -2449,7 +2424,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 		/* Check that chip is expecting address */
 		if (!(ns->nxstate & STATE_ADDR_MASK)) {
-			NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
+			pr_err("address (%#x) isn't expected, expected state is %s, "
 				"switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
 			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
 			return;
@@ -2457,7 +2432,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 		/* Check if this is expected byte */
 		if (ns->regs.count == ns->regs.num) {
-			NS_ERR("write_byte: no more address bytes expected\n");
+			pr_err("no more address bytes expected\n");
 			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
 			return;
 		}
@@ -2466,11 +2441,11 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 		ns->regs.count += 1;
 
-		NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
+		pr_debug("address byte %#x was accepted (%d bytes input, %d expected)\n",
 				(uint)byte, ns->regs.count, ns->regs.num);
 
 		if (ns->regs.count == ns->regs.num) {
-			NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
+			pr_debug("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
 			switch_state(ns);
 		}
 
@@ -2481,7 +2456,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 		/* Check that chip is expecting data input */
 		if (!(ns->state & STATE_DATAIN_MASK)) {
-			NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
+			pr_err("data input (%#x) isn't expected, state is %s, "
 				"switch to %s\n", (uint)byte,
 				get_state_name(ns->state), get_state_name(STATE_READY));
 			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
@@ -2490,7 +2465,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
 		/* Check if this is expected byte */
 		if (ns->regs.count == ns->regs.num) {
-			NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
+			pr_warn("%u input bytes has already been accepted, ignore write\n",
 					ns->regs.num);
 			return;
 		}
@@ -2522,7 +2497,7 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
 
 static int ns_device_ready(struct mtd_info *mtd)
 {
-	NS_DBG("device_ready\n");
+	pr_debug("device_ready\n");
 	return 1;
 }
 
@@ -2530,7 +2505,7 @@ static uint16_t ns_nand_read_word(struct mtd_info *mtd)
 {
 	struct nand_chip *chip = mtd_to_nand(mtd);
 
-	NS_DBG("read_word\n");
+	pr_debug("read_word\n");
 
 	return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
 }
@@ -2542,7 +2517,7 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 
 	/* Check that chip is expecting data input */
 	if (!(ns->state & STATE_DATAIN_MASK)) {
-		NS_ERR("write_buf: data input isn't expected, state is %s, "
+		pr_err("data input isn't expected, state is %s, "
 			"switch to STATE_READY\n", get_state_name(ns->state));
 		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
 		return;
@@ -2550,7 +2525,7 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 
 	/* Check if these are expected bytes */
 	if (ns->regs.count + len > ns->regs.num) {
-		NS_ERR("write_buf: too many input bytes\n");
+		pr_err("too many input bytes\n");
 		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
 		return;
 	}
@@ -2559,7 +2534,7 @@ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 	ns->regs.count += len;
 
 	if (ns->regs.count == ns->regs.num) {
-		NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
+		pr_debug("%d bytes were written\n", ns->regs.count);
 	}
 }
 
@@ -2570,15 +2545,15 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 
 	/* Sanity and correctness checks */
 	if (!ns->lines.ce) {
-		NS_ERR("read_buf: chip is disabled\n");
+		pr_err("chip is disabled\n");
 		return;
 	}
 	if (ns->lines.ale || ns->lines.cle) {
-		NS_ERR("read_buf: ALE or CLE pin is high\n");
+		pr_err("ALE or CLE pin is high\n");
 		return;
 	}
 	if (!(ns->state & STATE_DATAOUT_MASK)) {
-		NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
+		pr_warn("unexpected data output cycle, current state is %s\n",
 			get_state_name(ns->state));
 		return;
 	}
@@ -2594,7 +2569,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 
 	/* Check if these are expected bytes */
 	if (ns->regs.count + len > ns->regs.num) {
-		NS_ERR("read_buf: too many bytes to read\n");
+		pr_err("too many bytes to read\n");
 		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
 		return;
 	}
@@ -2759,7 +2734,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	unsigned char *id_bytes = nsparam->id_bytes;
 
 	if (nsparam->bus_width != 8 && nsparam->bus_width != 16) {
-		NS_ERR("wrong bus width (%d), use only 8 or 16\n", nsparam->bus_width);
+		pr_err("wrong bus width (%d), use only 8 or 16\n", nsparam->bus_width);
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -2767,7 +2742,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
 		       GFP_KERNEL);
 	if (!chip) {
-		NS_ERR("unable to allocate core structures.\n");
+		pr_err("unable to allocate core structures.\n");
 		return ERR_PTR(-ENOMEM);
 	}
 
@@ -2778,7 +2753,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	}
 
 	if (i == NS_MAX_DEVICES) {
-		NS_ERR("Cannot allocate more than %i instances!\n", NS_MAX_DEVICES);
+		pr_err("Cannot allocate more than %i instances!\n", NS_MAX_DEVICES);
 		retval = -ENFILE;
 		mutex_unlock(&ns_mtd_mutex);
 		goto error;
@@ -2817,7 +2792,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	case 0:
 		break;
 	default:
-		NS_ERR("bbt has to be 0..2\n");
+		pr_err("bbt has to be 0..2\n");
 		retval = -EINVAL;
 		goto error;
 	}
@@ -2865,7 +2840,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 
 	retval = nand_scan_ident(nsmtd, 1, NULL);
 	if (retval) {
-		NS_ERR("cannot scan NAND Simulator device\n");
+		pr_err("cannot scan NAND Simulator device\n");
 		if (retval > 0)
 			retval = -ENXIO;
 		goto error;
@@ -2873,7 +2848,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 
 	if (nsparam->no_oob) {
 		if (nsparam->bch) {
-			NS_ERR("Cannot use ECC without OOB\n");
+			pr_err("Cannot use ECC without OOB\n");
 			retval = -EINVAL;
 			goto error;
 		}
@@ -2883,7 +2858,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	} else if (nsparam->bch) {
 		unsigned int eccsteps, eccbytes;
 		if (!mtd_nand_has_bch()) {
-			NS_ERR("BCH ECC support is disabled\n");
+			pr_err("BCH ECC support is disabled\n");
 			retval = -EINVAL;
 			goto error;
 		}
@@ -2892,12 +2867,12 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		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");
+			pr_err("bch not available on small page devices\n");
 			retval = -EINVAL;
 			goto error;
 		}
 		if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
-			NS_ERR("invalid bch value %u\n", nsparam->bch);
+			pr_err("invalid bch value %u\n", nsparam->bch);
 			retval = -EINVAL;
 			goto error;
 		}
@@ -2906,7 +2881,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 		chip->ecc.size = 512;
 		chip->ecc.strength = nsparam->bch;
 		chip->ecc.bytes = eccbytes;
-		NS_INFO("using %u-bit/%u bytes BCH ECC\n", nsparam->bch, chip->ecc.size);
+		pr_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;
@@ -2914,7 +2889,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 
 	retval = nand_scan_tail(nsmtd);
 	if (retval) {
-		NS_ERR("can't register NAND Simulator\n");
+		pr_err("can't register NAND Simulator\n");
 		if (retval > 0)
 			retval = -ENXIO;
 		goto error;
@@ -2923,7 +2898,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	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");
+			pr_err("overridesize is too big\n");
 			retval = -EINVAL;
 			goto err_exit;
 		}
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 31/46] mtd: nandsim: Remove NS_RAW_OFFSET_OOB
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (29 preceding siblings ...)
  2016-09-21  9:54 ` [PATCH v2 30/46] mtd: nandsim: Use pr_ style logging Daniel Walter
@ 2016-09-21  9:54 ` Daniel Walter
  2016-09-21  9:54 ` [PATCH v2 32/46] mtd: nandsim: Remove NS_IS_INITIALIZED Daniel Walter
                   ` (15 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:54 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

This helper macro has no users, kill it.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 048beb0..915e3bb 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -198,9 +198,6 @@ MODULE_PARM_DESC(defaults,	 "Register a MTD during module load using default val
 #define NS_RAW_OFFSET(ns) \
 	(((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)
-
 /* After a command is input, the simulator goes to one of the following states */
 #define STATE_CMD_READ0        0x00000001 /* read data from the beginning of page */
 #define STATE_CMD_READ1        0x00000002 /* read data from the second half of page */
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 32/46] mtd: nandsim: Remove NS_IS_INITIALIZED
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (30 preceding siblings ...)
  2016-09-21  9:54 ` [PATCH v2 31/46] mtd: nandsim: Remove NS_RAW_OFFSET_OOB Daniel Walter
@ 2016-09-21  9:54 ` Daniel Walter
  2016-09-21  9:55 ` [PATCH v2 33/46] mtd: nandsim: Relax page size restrictions Daniel Walter
                   ` (14 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:54 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

init_nandsim() has exactly one caller, the construction
function. So, checking for this condition makes no sense.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 915e3bb..971f7b4 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -185,9 +185,6 @@ MODULE_PARM_DESC(defaults,	 "Register a MTD during module load using default val
 #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)
-
 /* Good operation completion status */
 #define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
 
@@ -839,11 +836,6 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	uint64_t remains;
 	uint64_t next_offset;
 
-	if (NS_IS_INITIALIZED(ns)) {
-		pr_err("init_nandsim: nandsim is already initialized\n");
-		return -EIO;
-	}
-
 	/* Force mtd to not do delays */
 	chip->chip_delay = 0;
 
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 33/46] mtd: nandsim: Relax page size restrictions
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (31 preceding siblings ...)
  2016-09-21  9:54 ` [PATCH v2 32/46] mtd: nandsim: Remove NS_IS_INITIALIZED Daniel Walter
@ 2016-09-21  9:55 ` Daniel Walter
  2016-09-21  9:55 ` [PATCH v2 34/46] mtd: nandsim: Support bitflip and read error emulation in file backend Daniel Walter
                   ` (13 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:55 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 971f7b4..8cfdfea 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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 34/46] mtd: nandsim: Support bitflip and read error emulation in file backend
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (32 preceding siblings ...)
  2016-09-21  9:55 ` [PATCH v2 33/46] mtd: nandsim: Relax page size restrictions Daniel Walter
@ 2016-09-21  9:55 ` Daniel Walter
  2016-09-21  9:55 ` [PATCH v2 35/46] mtd: nandsim: Make NANDSIM_MAX_DEVICES part of uapi Daniel Walter
                   ` (12 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:55 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Since we don't track the empty state we have to check
whether the buffer is full with 0xff bytes or not.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 8cfdfea..185ca4d 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -1602,11 +1602,26 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
 	return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
 }
 
-static int do_read_error(struct nandsim *ns, int num)
+static bool buffer_is_ff(struct nandsim *ns, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++) {
+		if (ns->buf.byte[i] != 0xff)
+			return false;
+	}
+
+	return true;
+}
+
+static int do_read_error(struct nandsim *ns, int num, bool check_ff)
 {
 	unsigned int page_no = ns->regs.row;
 
 	if (read_error(ns, page_no)) {
+		if (check_ff && buffer_is_ff(ns, num))
+			return 0;
+
 		prandom_bytes(ns->buf.byte, num);
 		pr_warn("simulating read error in page %u\n", page_no);
 		return 1;
@@ -1614,12 +1629,16 @@ static int do_read_error(struct nandsim *ns, int num)
 	return 0;
 }
 
-static void do_bit_flips(struct nandsim *ns, int num)
+static void do_bit_flips(struct nandsim *ns, int num, bool check_ff)
 {
 	struct mtd_info *nsmtd = ns_to_mtd(ns);
 
 	if (ns->bitflips && prandom_u32() < (1 << 22)) {
 		int flips = 1;
+
+		if (check_ff && buffer_is_ff(ns, num))
+			return;
+
 		if (ns->bitflips > 1)
 			flips = (prandom_u32() % (int)ns->bitflips) + 1;
 		while (flips--) {
@@ -1644,10 +1663,10 @@ static void ns_ram_read_page(struct nandsim *ns, int num)
 	} else {
 		pr_debug("page %d allocated, reading from %d\n",
 			ns->regs.row, ns->regs.column + ns->regs.off);
-		if (do_read_error(ns, num))
+		if (do_read_error(ns, num, false))
 			return;
 		memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
-		do_bit_flips(ns, num);
+		do_bit_flips(ns, num, false);
 	}
 }
 
@@ -1664,7 +1683,7 @@ static void ns_cachefile_read_page(struct nandsim *ns, int num)
 
 		pr_debug("page %d written, reading from %d\n",
 			ns->regs.row, ns->regs.column + ns->regs.off);
-		if (do_read_error(ns, num))
+		if (do_read_error(ns, num, false))
 			return;
 		pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
 		tx = read_file(ns, data->cfile, ns->buf.byte, num, pos);
@@ -1672,7 +1691,7 @@ static void ns_cachefile_read_page(struct nandsim *ns, int num)
 			pr_err("read error for page %d ret %ld\n", ns->regs.row, (long)tx);
 			return;
 		}
-		do_bit_flips(ns, num);
+		do_bit_flips(ns, num, false);
 	}
 }
 
@@ -1710,6 +1729,9 @@ void __ns_file_read_page(struct nandsim *ns, int num,
 		memset(ns->buf.byte, 0xff, num);
 	else if (tx != num)
 		pr_err("read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+
+	do_read_error(ns, num, true);
+	do_bit_flips(ns, num, true);
 }
 EXPORT_SYMBOL_GPL(__ns_file_read_page);
 
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 35/46] mtd: nandsim: Make NANDSIM_MAX_DEVICES part of uapi
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (33 preceding siblings ...)
  2016-09-21  9:55 ` [PATCH v2 34/46] mtd: nandsim: Support bitflip and read error emulation in file backend Daniel Walter
@ 2016-09-21  9:55 ` Daniel Walter
  2016-09-21  9:55 ` [PATCH v2 36/46] mtd: nandsim: Cleanup constants Daniel Walter
                   ` (11 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:55 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

...such that userspace very easy remove all nandsim instances.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 185ca4d..31a9f89 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -432,10 +432,8 @@ struct grave_page {
 	unsigned int reads_done;
 };
 
-#define NS_MAX_DEVICES 32
-
 /* MTD structure for NAND controller */
-static struct mtd_info *ns_mtds[NS_MAX_DEVICES];
+static struct mtd_info *ns_mtds[NANDSIM_MAX_DEVICES];
 static DEFINE_MUTEX(ns_mtd_mutex);
 
 static struct dentry *dfs_root;
@@ -2648,7 +2646,7 @@ static int ns_ctrl_destroy_instance(struct ns_destroy_instance_req *req)
 	struct nand_chip *chip;
 	struct nandsim *ns;
 
-	if (id < 0 || id >= NS_MAX_DEVICES)
+	if (id < 0 || id >= NANDSIM_MAX_DEVICES)
 		return -EINVAL;
 
 	mutex_lock(&ns_mtd_mutex);
@@ -2758,13 +2756,13 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	}
 
 	mutex_lock(&ns_mtd_mutex);
-	for (i = 0; i < NS_MAX_DEVICES; i++) {
+	for (i = 0; i < NANDSIM_MAX_DEVICES; i++) {
 		if (!ns_mtds[i])
 			break;
 	}
 
-	if (i == NS_MAX_DEVICES) {
-		pr_err("Cannot allocate more than %i instances!\n", NS_MAX_DEVICES);
+	if (i == NANDSIM_MAX_DEVICES) {
+		pr_err("Cannot allocate more than %i instances!\n", NANDSIM_MAX_DEVICES);
 		retval = -ENFILE;
 		mutex_unlock(&ns_mtd_mutex);
 		goto error;
@@ -2984,7 +2982,7 @@ static void ns_destroy_all(void)
 	int i;
 
 	mutex_lock(&ns_mtd_mutex);
-	for (i = 0; i < NS_MAX_DEVICES; i++)
+	for (i = 0; i < NANDSIM_MAX_DEVICES; i++)
 		if (ns_mtds[i])
 			WARN_ON(ns_destroy_instance(ns_mtds[i]) != 0);
 	mutex_unlock(&ns_mtd_mutex);
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 36/46] mtd: nandsim: Cleanup constants
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (34 preceding siblings ...)
  2016-09-21  9:55 ` [PATCH v2 35/46] mtd: nandsim: Make NANDSIM_MAX_DEVICES part of uapi Daniel Walter
@ 2016-09-21  9:55 ` Daniel Walter
  2016-09-21  9:55 ` [PATCH v2 37/46] mtd: nandsim: Turn parts[] into a integer Daniel Walter
                   ` (10 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:55 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Rename CONFIG_NANDSIM_* to NANDSIM_* since these
constants are not exposed to kconfig.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 31a9f89..d46eb18 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -54,50 +54,26 @@
 #include <linux/mutex.h>
 #include <linux/file.h>
 
-/* Default simulator parameters values */
-#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
-    !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \
-    !defined(CONFIG_NANDSIM_THIRD_ID_BYTE)  || \
-    !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE)
-#define CONFIG_NANDSIM_FIRST_ID_BYTE  0x98
-#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x39
-#define CONFIG_NANDSIM_THIRD_ID_BYTE  0xFF /* No byte */
-#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
-#endif
-
-#ifndef CONFIG_NANDSIM_ACCESS_DELAY
-#define CONFIG_NANDSIM_ACCESS_DELAY 25
-#endif
-#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
-#define CONFIG_NANDSIM_PROGRAMM_DELAY 200
-#endif
-#ifndef CONFIG_NANDSIM_ERASE_DELAY
-#define CONFIG_NANDSIM_ERASE_DELAY 2
-#endif
-#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
-#define CONFIG_NANDSIM_OUTPUT_CYCLE 40
-#endif
-#ifndef CONFIG_NANDSIM_INPUT_CYCLE
-#define CONFIG_NANDSIM_INPUT_CYCLE  50
-#endif
-#ifndef CONFIG_NANDSIM_BUS_WIDTH
-#define CONFIG_NANDSIM_BUS_WIDTH  8
-#endif
-#ifndef CONFIG_NANDSIM_DO_DELAYS
-#define CONFIG_NANDSIM_DO_DELAYS  0
-#endif
-#ifndef CONFIG_NANDSIM_MAX_PARTS
-#define CONFIG_NANDSIM_MAX_PARTS  32
-#endif
-
-static uint access_delay   = CONFIG_NANDSIM_ACCESS_DELAY;
-static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
-static uint erase_delay    = CONFIG_NANDSIM_ERASE_DELAY;
-static uint output_cycle   = CONFIG_NANDSIM_OUTPUT_CYCLE;
-static uint input_cycle    = CONFIG_NANDSIM_INPUT_CYCLE;
-static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
-static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
-static unsigned long parts[CONFIG_NANDSIM_MAX_PARTS];
+#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
+#define NANDSIM_OUTPUT_CYCLE 40
+#define NANDSIM_INPUT_CYCLE  50
+#define NANDSIM_BUS_WIDTH  8
+#define NANDSIM_DO_DELAYS  0
+
+static uint access_delay   = NANDSIM_ACCESS_DELAY;
+static uint programm_delay = NANDSIM_PROGRAMM_DELAY;
+static uint erase_delay    = NANDSIM_ERASE_DELAY;
+static uint output_cycle   = NANDSIM_OUTPUT_CYCLE;
+static uint input_cycle    = NANDSIM_INPUT_CYCLE;
+static uint bus_width      = NANDSIM_BUS_WIDTH;
+static uint do_delays      = NANDSIM_DO_DELAYS;
+static unsigned long parts[NANDSIM_MAX_PARTS];
 static unsigned int parts_num;
 static char *badblocks = NULL;
 static char *weakblocks = NULL;
@@ -109,10 +85,10 @@ static char *cache_file = NULL;
 static unsigned int bbt;
 static unsigned int bch;
 static u_char id_bytes[8] = {
-	[0] = CONFIG_NANDSIM_FIRST_ID_BYTE,
-	[1] = CONFIG_NANDSIM_SECOND_ID_BYTE,
-	[2] = CONFIG_NANDSIM_THIRD_ID_BYTE,
-	[3] = CONFIG_NANDSIM_FOURTH_ID_BYTE,
+	[0] = NANDSIM_FIRST_ID_BYTE,
+	[1] = NANDSIM_SECOND_ID_BYTE,
+	[2] = NANDSIM_THIRD_ID_BYTE,
+	[3] = NANDSIM_FOURTH_ID_BYTE,
 	[4 ... 7] = 0xFF,
 };
 static bool defaults = true;
@@ -304,8 +280,8 @@ struct nandsim {
 	unsigned int index;
 	unsigned int refcnt;
 	spinlock_t refcnt_lock;
-	struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
 	bool destroying;
+	struct mtd_partition partitions[NANDSIM_MAX_PARTS];
 	unsigned int nbparts;
 
 	uint busw;              /* flash chip bus width (8 or 16) */
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 37/46] mtd: nandsim: Turn parts[] into a integer
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (35 preceding siblings ...)
  2016-09-21  9:55 ` [PATCH v2 36/46] mtd: nandsim: Cleanup constants Daniel Walter
@ 2016-09-21  9:55 ` Daniel Walter
  2016-09-21  9:56 ` [PATCH v2 38/46] mtd: nandsim: Expose partition creation logic to user space Daniel Walter
                   ` (9 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:55 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

The parts array denotes how many erase blocks each partition
has. Therefore a plain integer can also do it.
If someone shows me a NAND with more than 2^32 erase blocks we can
turn it back into a long. ;)

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index d46eb18..615dde3 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -73,7 +73,7 @@ static uint output_cycle   = NANDSIM_OUTPUT_CYCLE;
 static uint input_cycle    = NANDSIM_INPUT_CYCLE;
 static uint bus_width      = NANDSIM_BUS_WIDTH;
 static uint do_delays      = NANDSIM_DO_DELAYS;
-static unsigned long parts[NANDSIM_MAX_PARTS];
+static unsigned int parts[NANDSIM_MAX_PARTS];
 static unsigned int parts_num;
 static char *badblocks = NULL;
 static char *weakblocks = NULL;
@@ -105,7 +105,7 @@ module_param(output_cycle,   uint, 0400);
 module_param(input_cycle,    uint, 0400);
 module_param(bus_width,      uint, 0400);
 module_param(do_delays,      uint, 0400);
-module_param_array(parts, ulong, &parts_num, 0400);
+module_param_array(parts,    uint, &parts_num, 0400);
 module_param(badblocks,      charp, 0400);
 module_param(weakblocks,     charp, 0400);
 module_param(weakpages,      charp, 0400);
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index 85d4d7e..61ff5dd 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 long *parts;
+	unsigned int *parts;
 	unsigned int parts_num;
 	char *badblocks;
 	char *weakblocks;
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 38/46] mtd: nandsim: Expose partition creation logic to user space
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (36 preceding siblings ...)
  2016-09-21  9:55 ` [PATCH v2 37/46] mtd: nandsim: Turn parts[] into a integer Daniel Walter
@ 2016-09-21  9:56 ` Daniel Walter
  2016-09-21  9:56 ` [PATCH v2 39/46] mtd: nandsim: Rework init error paths Daniel Walter
                   ` (8 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:56 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 615dde3..6b7570b 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;
@@ -2979,7 +2989,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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 39/46] mtd: nandsim: Rework init error paths
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (37 preceding siblings ...)
  2016-09-21  9:56 ` [PATCH v2 38/46] mtd: nandsim: Expose partition creation logic to user space Daniel Walter
@ 2016-09-21  9:56 ` Daniel Walter
  2016-09-21  9:56 ` [PATCH v2 40/46] mtd: nandsim: Expose BBT, delays, etc.. to userspace Daniel Walter
                   ` (7 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:56 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 6b7570b..92f5efc 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);
 
@@ -2952,12 +2971,10 @@ int ns_destroy_instance(struct mtd_info *nsmtd)
 	nand_cleanup(nsmtd);
 
 	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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 40/46] mtd: nandsim: Expose BBT, delays, etc.. to userspace
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (38 preceding siblings ...)
  2016-09-21  9:56 ` [PATCH v2 39/46] mtd: nandsim: Rework init error paths Daniel Walter
@ 2016-09-21  9:56 ` Daniel Walter
  2016-09-21  9:56 ` [PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks " Daniel Walter
                   ` (6 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:56 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Allow userspace to define nandsim parameters like
delays, bitflips, ...

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 92f5efc..d1402df 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2593,11 +2593,37 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 	nsparam->bus_width = req->bus_width;
 	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;
-	}
+	nsparam->bbt = req->bbt_mode;
+	nsparam->bch = req->bch_strength;
+	nsparam->bitflips = req->bitflips;
+	nsparam->overridesize = req->overridesize;
+
+	if (req->bch_strength && req->no_oob)
+		goto err_inval;
+
+	if (req->access_delay && req->program_delay && req->erase_delay &&
+	    req->output_cycle && req->input_cycle) {
+		if (req->access_delay > MAX_UDELAY_MS * 1000)
+			goto err_inval;
+		if (req->program_delay > MAX_UDELAY_MS * 1000)
+			goto err_inval;
+		if (req->erase_delay > 1000)
+			goto err_inval;
+		if (req->output_cycle > MAX_UDELAY_MS * 1000)
+			goto err_inval;
+		if (req->input_cycle > MAX_UDELAY_MS * 1000)
+			goto err_inval;
+
+		nsparam->access_delay = req->access_delay;
+		nsparam->program_delay = req->program_delay;
+		nsparam->erase_delay = req->erase_delay;
+		nsparam->output_cycle = req->output_cycle;
+		nsparam->input_cycle = req->input_cycle;
+		nsparam->do_delays = true;
+	}
+
+	if (req->parts_num > NANDSIM_MAX_PARTS || req->parts_num < 0)
+		goto err_inval;
 
 	if (req->parts_num > 0) {
 		nsparam->parts_num = req->parts_num;
@@ -2618,8 +2644,7 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 		break;
 
 		default:
-			kfree(nsparam);
-			return -EINVAL;
+			goto err_inval;
 	}
 
 	nsmtd = ns_new_instance(nsparam);
@@ -2632,6 +2657,10 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 	ns = nand_get_controller_data(chip);
 
 	return ns->index;
+
+err_inval:
+	kfree(nsparam);
+	return -EINVAL;
 }
 
 static int ns_ctrl_destroy_instance(struct ns_destroy_instance_req *req)
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index 07d32a9..880c0b1 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -11,7 +11,7 @@ struct nandsim_params {
 	unsigned int output_cycle;
 	unsigned int input_cycle;
 	unsigned int bus_width;
-	unsigned int do_delays;
+	bool do_delays;
 	unsigned int parts[NANDSIM_MAX_PARTS];
 	unsigned int parts_num;
 	char *badblocks;
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks to userspace
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (39 preceding siblings ...)
  2016-09-21  9:56 ` [PATCH v2 40/46] mtd: nandsim: Expose BBT, delays, etc.. to userspace Daniel Walter
@ 2016-09-21  9:56 ` Daniel Walter
  2016-09-21  9:57 ` [PATCH v2 42/46] mtd: nandsim: Don't printk on ENOMEM Daniel Walter
                   ` (5 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:56 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Allow users to define weakpages/blocks while creating
a new nandsim instance.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index d1402df..b58d1348 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -322,9 +322,9 @@ struct nandsim {
 	struct ns_backend_ops *bops;
 	void *backend_data;
 
-	struct list_head weak_blocks;
-	struct list_head weak_pages;
-	struct list_head grave_pages;
+	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;
@@ -387,6 +387,11 @@ static struct nandsim_operations {
 			       STATE_DATAOUT, STATE_READY}},
 };
 
+struct bad_block {
+	struct list_head list;
+	unsigned int erase_block_no;
+};
+
 struct weak_block {
 	struct list_head list;
 	unsigned int erase_block_no;
@@ -957,16 +962,46 @@ static void free_nandsim(struct nandsim *ns)
 	kfree(ns->buf.byte);
 }
 
-static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd,
+static int process_badblocks(struct nandsim_params *nsparam, struct nandsim *ns)
+{
+	loff_t offset;
+	struct bad_block *bb, *_bb;
+	struct mtd_info *nsmtd = ns_to_mtd(ns);
+
+	if (!nsparam->bad_blocks)
+		return 0;
+
+	list_for_each_entry_safe(bb, _bb, nsparam->bad_blocks, list) {
+		offset = (loff_t)bb->erase_block_no * ns->geom.secsz;
+		if (mtd_block_markbad(nsmtd, offset))
+			pr_err("invalid badblocks: %i:\n", bb->erase_block_no);
+
+		list_del(&bb->list);
+		kfree(bb);
+	}
+
+	kfree(nsparam->bad_blocks);
+	nsparam->bad_blocks = NULL;
+
+	return 0;
+}
+
+static int parse_badblocks(struct nandsim_params *nsparam,
 			   unsigned char *badblocks)
 {
 	char *w;
 	int zero_ok;
 	unsigned int erase_block_no;
-	loff_t offset;
+	struct bad_block *bb;
+
+	nsparam->bad_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+	if (!nsparam->bad_blocks)
+		return -ENOMEM;
 
+	INIT_LIST_HEAD(nsparam->bad_blocks);
 	if (!badblocks)
 		return 0;
+
 	w = badblocks;
 	do {
 		zero_ok = (*w == '0' ? 1 : 0);
@@ -975,18 +1010,21 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd,
 			pr_err("invalid badblocks.\n");
 			return -EINVAL;
 		}
-		offset = (loff_t)erase_block_no * ns->geom.secsz;
-		if (mtd_block_markbad(mtd, offset)) {
-			pr_err("invalid badblocks.\n");
-			return -EINVAL;
-		}
+		bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+		if (!bb)
+			return -ENOMEM;
+
+		bb->erase_block_no = erase_block_no;
+		list_add(&bb->list, nsparam->bad_blocks);
+
 		if (*w == ',')
 			w += 1;
 	} while (*w);
 	return 0;
 }
 
-static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks)
+static int parse_weakblocks(struct nandsim_params *nsparam,
+			    unsigned char *weakblocks)
 {
 	char *w;
 	int zero_ok;
@@ -994,8 +1032,14 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks)
 	unsigned int max_erases;
 	struct weak_block *wb;
 
+	nsparam->weak_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+	if (!nsparam->weak_blocks)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(nsparam->weak_blocks);
 	if (!weakblocks)
 		return 0;
+
 	w = weakblocks;
 	do {
 		zero_ok = (*w == '0' ? 1 : 0);
@@ -1018,7 +1062,7 @@ static int parse_weakblocks(struct nandsim *ns, unsigned char *weakblocks)
 		}
 		wb->erase_block_no = erase_block_no;
 		wb->max_erases = max_erases;
-		list_add(&wb->list, &ns->weak_blocks);
+		list_add(&wb->list, nsparam->weak_blocks);
 	} while (*w);
 	return 0;
 }
@@ -1027,7 +1071,7 @@ static int erase_error(struct nandsim *ns, unsigned int erase_block_no)
 {
 	struct weak_block *wb;
 
-	list_for_each_entry(wb, &ns->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;
@@ -1037,7 +1081,8 @@ static int erase_error(struct nandsim *ns, unsigned int erase_block_no)
 	return 0;
 }
 
-static int parse_weakpages(struct nandsim *ns, unsigned char *weakpages)
+static int parse_weakpages(struct nandsim_params *nsparam,
+			   unsigned char *weakpages)
 {
 	char *w;
 	int zero_ok;
@@ -1045,8 +1090,14 @@ static int parse_weakpages(struct nandsim *ns, unsigned char *weakpages)
 	unsigned int max_writes;
 	struct weak_page *wp;
 
+	nsparam->weak_pages = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+	if (!nsparam->weak_pages)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(nsparam->weak_pages);
 	if (!weakpages)
 		return 0;
+
 	w = weakpages;
 	do {
 		zero_ok = (*w == '0' ? 1 : 0);
@@ -1069,7 +1120,7 @@ static int parse_weakpages(struct nandsim *ns, unsigned char *weakpages)
 		}
 		wp->page_no = page_no;
 		wp->max_writes = max_writes;
-		list_add(&wp->list, &ns->weak_pages);
+		list_add(&wp->list, nsparam->weak_pages);
 	} while (*w);
 	return 0;
 }
@@ -1078,7 +1129,7 @@ static int write_error(struct nandsim *ns, unsigned int page_no)
 {
 	struct weak_page *wp;
 
-	list_for_each_entry(wp, &ns->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;
@@ -1088,7 +1139,7 @@ static int write_error(struct nandsim *ns, unsigned int page_no)
 	return 0;
 }
 
-static int parse_gravepages(struct nandsim *ns, unsigned char *gravepages)
+static int parse_gravepages(struct nandsim_params *nsparam, unsigned char *gravepages)
 {
 	char *g;
 	int zero_ok;
@@ -1096,8 +1147,14 @@ static int parse_gravepages(struct nandsim *ns, unsigned char *gravepages)
 	unsigned int max_reads;
 	struct grave_page *gp;
 
+	nsparam->grave_pages = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+	if (!nsparam->grave_pages)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(nsparam->grave_pages);
 	if (!gravepages)
 		return 0;
+
 	g = gravepages;
 	do {
 		zero_ok = (*g == '0' ? 1 : 0);
@@ -1120,7 +1177,7 @@ static int parse_gravepages(struct nandsim *ns, unsigned char *gravepages)
 		}
 		gp->page_no = page_no;
 		gp->max_reads = max_reads;
-		list_add(&gp->list, &ns->grave_pages);
+		list_add(&gp->list, nsparam->grave_pages);
 	} while (*g);
 	return 0;
 }
@@ -1129,7 +1186,7 @@ static int read_error(struct nandsim *ns, unsigned int page_no)
 {
 	struct grave_page *gp;
 
-	list_for_each_entry(gp, &ns->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;
@@ -1142,17 +1199,31 @@ static int read_error(struct nandsim *ns, unsigned int page_no)
 static void free_lists(struct nandsim *ns)
 {
 	struct list_head *pos, *n;
-	list_for_each_safe(pos, n, &ns->weak_blocks) {
-		list_del(pos);
-		kfree(list_entry(pos, struct weak_block, list));
+
+	if (ns->weak_blocks) {
+		list_for_each_safe(pos, n, ns->weak_blocks) {
+			list_del(pos);
+			kfree(list_entry(pos, struct weak_block, list));
+		}
+
+		kfree(ns->weak_blocks);
+		ns->weak_blocks = NULL;
 	}
-	list_for_each_safe(pos, n, &ns->weak_pages) {
-		list_del(pos);
-		kfree(list_entry(pos, struct weak_page, list));
+	if (ns->weak_pages) {
+		list_for_each_safe(pos, n, ns->weak_pages) {
+			list_del(pos);
+			kfree(list_entry(pos, struct weak_page, list));
+		}
+		kfree(ns->weak_pages);
+		ns->weak_pages = NULL;
 	}
-	list_for_each_safe(pos, n, &ns->grave_pages) {
-		list_del(pos);
-		kfree(list_entry(pos, struct grave_page, list));
+	if (ns->grave_pages) {
+		list_for_each_safe(pos, n, ns->grave_pages) {
+			list_del(pos);
+			kfree(list_entry(pos, struct grave_page, list));
+		}
+		kfree(ns->grave_pages);
+		ns->grave_pages = NULL;
 	}
 	kfree(ns->erase_block_wear);
 }
@@ -2579,8 +2650,122 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 	return;
 }
 
-static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
+static void destroy_nsparam_lists(struct nandsim_params *nsparam)
+{
+	struct list_head *pos, *n;
+
+	if (nsparam->bad_blocks) {
+		list_for_each_safe(pos, n, nsparam->bad_blocks) {
+			list_del(pos);
+			kfree(list_entry(pos, struct bad_block, list));
+		}
+	}
+
+	if (nsparam->weak_blocks) {
+		list_for_each_safe(pos, n, nsparam->weak_blocks) {
+			list_del(pos);
+			kfree(list_entry(pos, struct weak_block, list));
+		}
+	}
+
+	if (nsparam->weak_pages) {
+		list_for_each_safe(pos, n, nsparam->weak_pages) {
+			list_del(pos);
+			kfree(list_entry(pos, struct weak_page, list));
+		}
+	}
+
+	if (nsparam->grave_pages) {
+		list_for_each_safe(pos, n, nsparam->grave_pages) {
+			list_del(pos);
+			kfree(list_entry(pos, struct grave_page, list));
+		}
+	}
+
+	kfree(nsparam->bad_blocks);
+	kfree(nsparam->weak_blocks);
+	kfree(nsparam->weak_pages);
+	kfree(nsparam->grave_pages);
+}
+
+static int process_element_params(struct nandsim_params *nsparam, int num,
+				  void __user *elem_argp)
+{
+	int i, err;
+	struct ns_simelement_prop sep;
+
+	for (i = 0; i < num; i++) {
+		err = copy_from_user(&sep, elem_argp + (i * sizeof(sep)),
+				     sizeof(sep));
+		if (err)
+			goto out_err;
+
+		err = -ENOMEM;
+
+		switch (sep.elem_type) {
+		case NANDSIM_SIMELEM_BADBLOCK:
+		{
+			struct bad_block *bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+
+			if (!bb)
+				goto out_err;
+
+			bb->erase_block_no = sep.elem_id;
+			list_add(&bb->list, nsparam->bad_blocks);
+		}
+		break;
+		case NANDSIM_SIMELEM_WEAKBLOCK:
+		{
+			struct weak_block *wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+
+			if (!wb)
+				goto out_err;
+
+			wb->erase_block_no = sep.elem_id;
+			wb->max_erases = sep.elem_attr;
+			list_add(&wb->list, nsparam->weak_blocks);
+		}
+		break;
+		case NANDSIM_SIMELEM_WEAKPAGE:
+		{
+			struct weak_page *wp = kzalloc(sizeof(*wp), GFP_KERNEL);
+
+			if (!wp)
+				goto out_err;
+
+			wp->page_no = sep.elem_id;
+			wp->max_writes = sep.elem_attr;
+			list_add(&wp->list, nsparam->weak_pages);
+		}
+		break;
+		case NANDSIM_SIMELEM_GRAVEPAGE:
+		{
+			struct grave_page *gp = kzalloc(sizeof(*gp), GFP_KERNEL);
+
+			if (!gp)
+				goto out_err;
+
+			gp->page_no = sep.elem_id;
+			gp->max_reads = sep.elem_attr;
+			list_add(&gp->list, nsparam->grave_pages);
+		}
+		break;
+		default:
+			err = -EINVAL;
+			goto out_err;
+		}
+	}
+
+	return 0;
+
+out_err:
+	destroy_nsparam_lists(nsparam);
+	return err;
+}
+
+static int ns_ctrl_new_instance(struct ns_new_instance_req *req, void __user *elem_argp)
 {
+	int ret = -EINVAL;
 	struct mtd_info *nsmtd;
 	struct nand_chip *chip;
 	struct nandsim *ns;
@@ -2599,20 +2784,20 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 	nsparam->overridesize = req->overridesize;
 
 	if (req->bch_strength && req->no_oob)
-		goto err_inval;
+		goto err;
 
 	if (req->access_delay && req->program_delay && req->erase_delay &&
 	    req->output_cycle && req->input_cycle) {
 		if (req->access_delay > MAX_UDELAY_MS * 1000)
-			goto err_inval;
+			goto err;
 		if (req->program_delay > MAX_UDELAY_MS * 1000)
-			goto err_inval;
+			goto err;
 		if (req->erase_delay > 1000)
-			goto err_inval;
+			goto err;
 		if (req->output_cycle > MAX_UDELAY_MS * 1000)
-			goto err_inval;
+			goto err;
 		if (req->input_cycle > MAX_UDELAY_MS * 1000)
-			goto err_inval;
+			goto err;
 
 		nsparam->access_delay = req->access_delay;
 		nsparam->program_delay = req->program_delay;
@@ -2623,7 +2808,7 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 	}
 
 	if (req->parts_num > NANDSIM_MAX_PARTS || req->parts_num < 0)
-		goto err_inval;
+		goto err;
 
 	if (req->parts_num > 0) {
 		nsparam->parts_num = req->parts_num;
@@ -2644,7 +2829,37 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 		break;
 
 		default:
-			goto err_inval;
+			goto err;
+	}
+
+	nsparam->bad_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+	nsparam->weak_blocks = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+	nsparam->weak_pages = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+	nsparam->grave_pages = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+
+	if (!nsparam->bad_blocks || !nsparam->weak_blocks ||
+	    !nsparam->weak_pages || !nsparam->grave_pages) {
+		kfree(nsparam->bad_blocks);
+		kfree(nsparam->weak_blocks);
+		kfree(nsparam->weak_pages);
+		kfree(nsparam->grave_pages);
+
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	INIT_LIST_HEAD(nsparam->bad_blocks);
+	INIT_LIST_HEAD(nsparam->weak_blocks);
+	INIT_LIST_HEAD(nsparam->weak_pages);
+	INIT_LIST_HEAD(nsparam->grave_pages);
+
+	if (req->simelem_num > 0) {
+		if (req->simelem_num > 1000)
+			goto err;
+
+		ret = process_element_params(nsparam, req->simelem_num, elem_argp);
+		if (ret)
+			goto err;
 	}
 
 	nsmtd = ns_new_instance(nsparam);
@@ -2658,9 +2873,10 @@ static int ns_ctrl_new_instance(struct ns_new_instance_req *req)
 
 	return ns->index;
 
-err_inval:
+err:
+	destroy_nsparam_lists(nsparam);
 	kfree(nsparam);
-	return -EINVAL;
+	return ret;
 }
 
 static int ns_ctrl_destroy_instance(struct ns_destroy_instance_req *req)
@@ -2798,10 +3014,6 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	nand->index = i;
 	mutex_unlock(&ns_mtd_mutex);
 
-	INIT_LIST_HEAD(&nand->weak_blocks);
-	INIT_LIST_HEAD(&nand->grave_pages);
-	INIT_LIST_HEAD(&nand->weak_pages);
-	INIT_LIST_HEAD(&nand->weak_blocks);
 	spin_lock_init(&nand->refcnt_lock);
 
 	/*
@@ -2854,14 +3066,9 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	nsmtd->_get_device = ns_get_device;
 	nsmtd->_put_device = ns_put_device;
 
-	if ((retval = parse_weakblocks(nand, nsparam->weakblocks)) != 0)
-		goto err_lists;
-
-	if ((retval = parse_weakpages(nand, nsparam->weakpages)) != 0)
-		goto err_lists;
-
-	if ((retval = parse_gravepages(nand, nsparam->gravepages)) != 0)
-		goto err_lists;
+	nand->weak_blocks = nsparam->weak_blocks;
+	nand->weak_pages = nsparam->weak_pages;
+	nand->grave_pages = nsparam->grave_pages;
 
 	nand->do_delays = nsparam->do_delays;
 	nand->access_delay = nsparam->access_delay;
@@ -2960,7 +3167,7 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	if ((retval = chip->scan_bbt(nsmtd)) != 0)
 		goto err_nandsim;
 
-	if ((retval = parse_badblocks(nand, nsmtd, nsparam->badblocks)) != 0)
+	if ((retval = process_badblocks(nsparam, nand)) != 0)
 		goto err_nandsim;
 
 	/* Register NAND partitions */
@@ -3022,6 +3229,7 @@ static void ns_destroy_all(void)
 
 static int __init ns_init_default(void)
 {
+	int ret;
 	struct mtd_info *nsmtd;
 	struct nandsim_params *nsparam = kzalloc(sizeof(*nsparam), GFP_KERNEL);
 
@@ -3037,11 +3245,6 @@ static int __init ns_init_default(void)
 	nsparam->do_delays = do_delays;
 	memcpy(nsparam->parts, parts, sizeof(nsparam->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;
@@ -3053,6 +3256,22 @@ static int __init ns_init_default(void)
 	else
 		nsparam->bops = &ns_cachefile_bops;
 
+	ret = parse_badblocks(nsparam, badblocks);
+	if (ret)
+		goto err_lists;
+
+	ret = parse_weakblocks(nsparam, weakblocks);
+	if (ret)
+		goto err_lists;
+
+	ret = parse_weakpages(nsparam, weakpages);
+	if (ret)
+		goto err_lists;
+
+	ret = parse_gravepages(nsparam, gravepages);
+	if (ret)
+		goto err_lists;
+
 	nsmtd = ns_new_instance(nsparam);
 	kfree(nsparam);
 
@@ -3060,6 +3279,11 @@ static int __init ns_init_default(void)
 		return PTR_ERR(nsmtd);
 
 	return 0;
+
+err_lists:
+	destroy_nsparam_lists(nsparam);
+	kfree(nsparam);
+	return ret;
 }
 
 static int __init ns_init_module(void)
diff --git a/include/linux/mtd/nandsim.h b/include/linux/mtd/nandsim.h
index 880c0b1..702e49d 100644
--- a/include/linux/mtd/nandsim.h
+++ b/include/linux/mtd/nandsim.h
@@ -14,9 +14,10 @@ struct nandsim_params {
 	bool do_delays;
 	unsigned int parts[NANDSIM_MAX_PARTS];
 	unsigned int parts_num;
-	char *badblocks;
-	char *weakblocks;
-	char *weakpages;
+	struct list_head *bad_blocks;
+	struct list_head *weak_blocks;
+	struct list_head *weak_pages;
+	struct list_head *grave_pages;
 	unsigned int bitflips;
 	char *gravepages;
 	unsigned int overridesize;
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 42/46] mtd: nandsim: Don't printk on ENOMEM
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (40 preceding siblings ...)
  2016-09-21  9:56 ` [PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks " Daniel Walter
@ 2016-09-21  9:57 ` Daniel Walter
  2016-09-21  9:57 ` [PATCH v2 43/46] mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE Daniel Walter
                   ` (4 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:57 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

From: Richard Weinberger <richard@nod.at>

Memory allocation failures are tabu, we don't talk
about them.

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

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index b58d1348..d0cc24d 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -579,7 +579,6 @@ static int ns_ram_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	data->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
 	if (!data->pages) {
 		kfree(data);
-		pr_err("unable to allocate page array\n");
 		return -ENOMEM;
 	}
 	for (i = 0; i < ns->geom.pgnum; i++) {
@@ -591,7 +590,6 @@ static int ns_ram_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	if (!data->nand_pages_slab) {
 		vfree(data->pages);
 		kfree(data);
-		pr_err("unable to create kmem_cache\n");
 		return -ENOMEM;
 	}
 
@@ -667,13 +665,11 @@ static int ns_cachefile_init(struct nandsim *ns, struct nandsim_params *nsparam)
 	data->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
 				    sizeof(unsigned long));
 	if (!data->pages_written) {
-		pr_err("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) {
-		pr_err("unable to allocate file buf\n");
 		err = -ENOMEM;
 		goto err_free;
 	}
@@ -710,7 +706,6 @@ static int ns_file_init(struct nandsim *ns, struct nandsim_params *nsparam)
 
 	data->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
 	if (!data->file_buf) {
-		pr_err("unable to allocate file buf\n");
 		ret = -ENOMEM;
 		goto out_put;
 	}
@@ -881,7 +876,6 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 		}
 		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
-			pr_err("unable to allocate memory.\n");
 			ret = -ENOMEM;
 			goto err_names;
 		}
@@ -899,7 +893,6 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 		}
 		ns->partitions[i].name = get_partition_name(ns, i);
 		if (!ns->partitions[i].name) {
-			pr_err("unable to allocate memory.\n");
 			ret = -ENOMEM;
 			goto err_names;
 		}
@@ -933,8 +926,6 @@ static int init_nandsim(struct mtd_info *mtd, struct nandsim_params *nsparam)
 	/* 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);
 		ret = -ENOMEM;
 		goto err_buf;
 	}
@@ -1057,7 +1048,6 @@ static int parse_weakblocks(struct nandsim_params *nsparam,
 			w += 1;
 		wb = kzalloc(sizeof(*wb), GFP_KERNEL);
 		if (!wb) {
-			pr_err("unable to allocate memory.\n");
 			return -ENOMEM;
 		}
 		wb->erase_block_no = erase_block_no;
@@ -1114,10 +1104,9 @@ static int parse_weakpages(struct nandsim_params *nsparam,
 		if (*w == ',')
 			w += 1;
 		wp = kzalloc(sizeof(*wp), GFP_KERNEL);
-		if (!wp) {
-			pr_err("unable to allocate memory.\n");
+		if (!wp)
 			return -ENOMEM;
-		}
+
 		wp->page_no = page_no;
 		wp->max_writes = max_writes;
 		list_add(&wp->list, nsparam->weak_pages);
@@ -1171,10 +1160,9 @@ static int parse_gravepages(struct nandsim_params *nsparam, unsigned char *grave
 		if (*g == ',')
 			g += 1;
 		gp = kzalloc(sizeof(*gp), GFP_KERNEL);
-		if (!gp) {
-			pr_err("unable to allocate memory.\n");
+		if (!gp)
 			return -ENOMEM;
-		}
+
 		gp->page_no = page_no;
 		gp->max_reads = max_reads;
 		list_add(&gp->list, nsparam->grave_pages);
@@ -1236,15 +1224,11 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 
 	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) {
-		pr_err("Too many erase blocks for wear reporting\n");
+	if (mem / sizeof(unsigned long) != ns->wear_eb_count)
 		return -ENOMEM;
-	}
 	ns->erase_block_wear = kzalloc(mem, GFP_KERNEL);
-	if (!ns->erase_block_wear) {
-		pr_err("Too many erase blocks for wear reporting\n");
+	if (!ns->erase_block_wear)
 		return -ENOMEM;
-	}
 	return 0;
 }
 
@@ -1886,10 +1870,9 @@ static int ns_ram_prog_page(struct nandsim *ns, int num)
 		 * again and deadlocks. This was seen in practice.
 		 */
 		mypage->byte = kmem_cache_alloc(data->nand_pages_slab, GFP_NOFS);
-		if (mypage->byte == NULL) {
-			pr_err("error allocating memory for page %d\n", ns->regs.row);
+		if (mypage->byte == NULL)
 			return -1;
-		}
+
 		memset(mypage->byte, 0xFF, ns->geom.pgszoob);
 	}
 
@@ -2990,10 +2973,8 @@ struct mtd_info *ns_new_instance(struct nandsim_params *nsparam)
 	/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
 	chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
 		       GFP_KERNEL);
-	if (!chip) {
-		pr_err("unable to allocate core structures.\n");
+	if (!chip)
 		return ERR_PTR(-ENOMEM);
-	}
 
 	mutex_lock(&ns_mtd_mutex);
 	for (i = 0; i < NANDSIM_MAX_DEVICES; i++) {
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 43/46] mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (41 preceding siblings ...)
  2016-09-21  9:57 ` [PATCH v2 42/46] mtd: nandsim: Don't printk on ENOMEM Daniel Walter
@ 2016-09-21  9:57 ` Daniel Walter
  2016-09-21  9:57 ` [PATCH v2 44/46] mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE Daniel Walter
                   ` (3 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:57 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 d0cc24d..bb30763 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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 44/46] mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (42 preceding siblings ...)
  2016-09-21  9:57 ` [PATCH v2 43/46] mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE Daniel Walter
@ 2016-09-21  9:57 ` Daniel Walter
  2016-09-21  9:57 ` [PATCH v2 45/46] mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID Daniel Walter
                   ` (2 subsequent siblings)
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:57 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 bb30763..5d82a0a 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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 45/46] mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (43 preceding siblings ...)
  2016-09-21  9:57 ` [PATCH v2 44/46] mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE Daniel Walter
@ 2016-09-21  9:57 ` Daniel Walter
  2016-09-21  9:57 ` [PATCH v2 46/46] mtd/nandsim: Add ioctl for info Daniel Walter
  2016-10-16 16:24 ` [PATCH v2 00/46] Nandsim facelift (part I of II) Boris Brezillon
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:57 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon,
	Richard Weinberger

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 5d82a0a..b901155 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

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [PATCH v2 46/46] mtd/nandsim: Add ioctl for info
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (44 preceding siblings ...)
  2016-09-21  9:57 ` [PATCH v2 45/46] mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID Daniel Walter
@ 2016-09-21  9:57 ` Daniel Walter
  2016-10-16 16:24 ` [PATCH v2 00/46] Nandsim facelift (part I of II) Boris Brezillon
  46 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21  9:57 UTC (permalink / raw)
  To: linux-mtd
  Cc: linux-kernel, computersforpeace, dwmw2, boris.brezillon, Daniel Walter

Add a ioctl() call for nandsim information.
This information includes, nand id, backend type
and path to the file if the file backend is used

Signed-off-by: Daniel Walter <dwalter@sigma-star.at>
---
 drivers/mtd/nand/nandsim.c      | 65 +++++++++++++++++++++++++++++++++++++++++
 include/uapi/mtd/nandsim-user.h | 11 +++++++
 2 files changed, 76 insertions(+)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index b901155..dd78fc3 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -2893,6 +2893,56 @@ out:
 	return ret;
 }
 
+static void ns_put_device(struct mtd_info *);
+static int ns_get_device(struct mtd_info *);
+
+static int ns_ctrl_info_instance(struct ns_info_instance_req *req)
+{
+	struct mtd_info *nsmtd;
+	int id = req->id, ret = 0;
+	struct nand_chip *chip;
+	struct nandsim *ns;
+	struct ns_file_data *file_data;
+	char buf[NANDSIM_FILENAME_SIZE];
+	char *tmp;
+
+	if (id < 0 || id >= NANDSIM_MAX_DEVICES)
+		return -EINVAL;
+
+	mutex_lock(&ns_mtd_mutex);
+	nsmtd = ns_mtds[id];
+	if (nsmtd) {
+		ret = ns_get_device(nsmtd);
+		if (ret)
+			goto out;
+		chip = mtd_to_nand(nsmtd);
+		ns = nand_get_controller_data(chip);
+		req->no_oob = ns->no_oob;
+		memcpy(req->id_bytes, ns->ids, 8);
+		req->parts_num = ns->nbparts;
+		if (ns->bops == &ns_cachefile_bops) {
+			req->backend = NANDSIM_BACKEND_CACHEFILE;
+		} else if (ns->bops == &ns_file_bops) {
+			req->backend = NANDSIM_BACKEND_FILE;
+			file_data = ns->backend_data;
+			tmp = d_path(&file_data->file->f_path, buf, NANDSIM_FILENAME_SIZE);
+			memcpy(req->filename, tmp, NANDSIM_FILENAME_SIZE);
+		} else if (ns->bops == &ns_ram_bops) {
+			req->backend = NANDSIM_BACKEND_RAM;
+		} else {
+			req->backend = -1;
+		}
+
+		ns_put_device(nsmtd);
+	} else {
+		ret = -EINVAL;
+	}
+out:
+	mutex_unlock(&ns_mtd_mutex);
+	return ret;
+
+}
+
 static long ns_ctrl_ioctl(struct file *file, unsigned int cmd,
 			  unsigned long arg)
 {
@@ -2931,6 +2981,21 @@ static long ns_ctrl_ioctl(struct file *file, unsigned int cmd,
 			ret = ns_ctrl_destroy_instance(&req);
 			break;
 		}
+		case NANDSIM_IOC_INFO_INSTANCE:
+		{
+			struct ns_info_instance_req req;
+
+			ret = copy_from_user(&req, argp, sizeof(struct ns_info_instance_req));
+			if (ret) {
+				ret = -EFAULT;
+				goto out;
+			}
+			ret = ns_ctrl_info_instance(&req);
+			if (ret)
+				goto out;
+			ret = copy_to_user(argp, &req, sizeof(struct ns_info_instance_req));
+			break;
+		}
 
 		default:
 			ret = -ENOTTY;
diff --git a/include/uapi/mtd/nandsim-user.h b/include/uapi/mtd/nandsim-user.h
index b52d620..a00ab2d 100644
--- a/include/uapi/mtd/nandsim-user.h
+++ b/include/uapi/mtd/nandsim-user.h
@@ -7,9 +7,11 @@
 
 #define NANDSIM_IOC_NEW_INSTANCE _IOW(NANDSIM_IOC_MAGIC, 0, struct ns_new_instance_req)
 #define NANDSIM_IOC_DESTROY_INSTANCE _IOW(NANDSIM_IOC_MAGIC, 1, struct ns_destroy_instance_req)
+#define NANDSIM_IOC_INFO_INSTANCE _IOW(NANDSIM_IOC_MAGIC, 2, struct ns_info_instance_req)
 
 #define NANDSIM_MAX_DEVICES 32
 #define NANDSIM_MAX_PARTS 32
+#define NANDSIM_FILENAME_SIZE 64
 
 enum ns_backend_type {
 	NANDSIM_BACKEND_RAM = 0,
@@ -99,4 +101,13 @@ struct ns_destroy_instance_req {
 	__s8 padding[7];
 } __packed;
 
+struct ns_info_instance_req {
+	__s8 id;
+	__s8 no_oob;
+	__s8 id_bytes[8];
+	__s8 parts_num;
+	__s8 backend;
+	__u8 filename[NANDSIM_FILENAME_SIZE];
+} __packed;
+
 #endif /* __NANDSIM_USER_H__ */
-- 
2.8.3

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources
  2016-09-21  9:44 ` [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources Daniel Walter
@ 2016-09-21  9:58   ` Boris Brezillon
  2016-09-21 12:43   ` kbuild test robot
  2016-09-21 14:25   ` Boris Brezillon
  2 siblings, 0 replies; 69+ messages in thread
From: Boris Brezillon @ 2016-09-21  9:58 UTC (permalink / raw)
  To: Daniel Walter
  Cc: linux-mtd, linux-kernel, computersforpeace, Richard Weinberger

On Wed, 21 Sep 2016 11:44:41 +0200
Daniel Walter <dwalter@sigma-star.at> wrote:

> From: Richard Weinberger <richard@nod.at>
> 
> Provide a nand_cleanup() function to free all nand related resources
> without unregistering the mtd device.
> This should allow drivers to call mtd_device_unregister() and handle
> its return value and still being able to cleanup all nand related
> resources.
> 
> Signed-off-by: Richard Weinberger <richard@nod.at>
> Signed-off-by: Daniel Walter <dwalter@sigma-star.at>
> ---
>  drivers/mtd/nand/nand_base.c | 18 +++++++++++++-----
>  include/linux/mtd/nand.h     |  1 +
>  2 files changed, 14 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index 77533f7..e743052 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -4601,10 +4601,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
>  EXPORT_SYMBOL(nand_scan);
>  
>  /**
> - * nand_release - [NAND Interface] Free resources held by the NAND device
> - * @mtd: MTD device structure
> + * nand_cleanup - [NAND Interface] Free resources held by the NAND device
> + * @mts: MTD device structure

      ^ @mtd.

>   */
> -void nand_release(struct mtd_info *mtd)
> +void nand_cleanup(struct mtd_info *mtd)

Can we pass a pointer to a nand_chip here.

>  {
>  	struct nand_chip *chip = mtd_to_nand(mtd);
>  
> @@ -4612,8 +4612,6 @@ void nand_release(struct mtd_info *mtd)
>  	    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))
> @@ -4624,6 +4622,16 @@ void nand_release(struct mtd_info *mtd)
>  			& NAND_BBT_DYNAMICSTRUCT)
>  		kfree(chip->badblock_pattern);
>  }
> +
> +/**
> + * nand_release - [NAND Interface] Free resources held by the NAND device

Unregister the MTD device and free resources...

> + * @mtd: MTD device structure
> + */
> +void nand_release(struct mtd_info *mtd)
> +{
> +	mtd_device_unregister(mtd);
> +	nand_cleanup(mtd);
> +}
>  EXPORT_SYMBOL_GPL(nand_release);
>  
>  MODULE_LICENSE("GPL");
> diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> index 8dd6e01..c692c06 100644
> --- a/include/linux/mtd/nand.h
> +++ b/include/linux/mtd/nand.h
> @@ -39,6 +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_cleanup(struct mtd_info *mtd);

The extern keyword is unneeded here. Actually all extern qualifiers
have been removed recently.

BTW, no need to resend the patch. I'll fix the problems when applying
it (I'd like to have this function in 4.9).

>  extern void nand_release(struct mtd_info *mtd);
>  
>  /* Internal helper for board drivers which need to override command function */

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-09-21  9:43 ` [PATCH v2 01/46] mtdpart: Propagate _get/put_device() Daniel Walter
@ 2016-09-21 10:15   ` Boris Brezillon
  2016-09-28 20:16     ` Brian Norris
  0 siblings, 1 reply; 69+ messages in thread
From: Boris Brezillon @ 2016-09-21 10:15 UTC (permalink / raw)
  To: Daniel Walter, computersforpeace
  Cc: linux-mtd, Richard Weinberger, dwmw2, linux-kernel

On Wed, 21 Sep 2016 11:43:56 +0200
Daniel Walter <dwalter@sigma-star.at> wrote:

> 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.

Brian, can we have this one queued for 4.9? I can't take it in my tree
if you want, but it's probably better if it's in the mtd tree.

> 
> 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;

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources
  2016-09-21  9:44 ` [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources Daniel Walter
  2016-09-21  9:58   ` Boris Brezillon
@ 2016-09-21 12:43   ` kbuild test robot
  2016-09-21 14:25   ` Boris Brezillon
  2 siblings, 0 replies; 69+ messages in thread
From: kbuild test robot @ 2016-09-21 12:43 UTC (permalink / raw)
  To: Daniel Walter
  Cc: kbuild-all, linux-mtd, linux-kernel, computersforpeace,
	boris.brezillon, Richard Weinberger, Daniel Walter

[-- Attachment #1: Type: text/plain, Size: 3331 bytes --]

Hi Richard,

[auto build test WARNING on mtd/master]
[also build test WARNING on v4.8-rc7]
[cannot apply to next-20160921]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Daniel-Walter/Nandsim-facelift-part-I-of-II/20160921-182636
base:   git://git.infradead.org/linux-mtd.git master
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

>> drivers/mtd/nand/nand_base.c:4608: warning: No description found for parameter 'mtd'
>> drivers/mtd/nand/nand_base.c:4608: warning: Excess function parameter 'mts' description in 'nand_cleanup'
   drivers/mtd/nand/nand_bbt.c:1: warning: no structured comments found
>> drivers/mtd/nand/nand_base.c:4608: warning: No description found for parameter 'mtd'
>> drivers/mtd/nand/nand_base.c:4608: warning: Excess function parameter 'mts' description in 'nand_cleanup'

vim +/mtd +4608 drivers/mtd/nand/nand_base.c

3b85c321 David Woodhouse    2006-09-25  4592  int nand_scan(struct mtd_info *mtd, int maxchips)
3b85c321 David Woodhouse    2006-09-25  4593  {
3b85c321 David Woodhouse    2006-09-25  4594  	int ret;
3b85c321 David Woodhouse    2006-09-25  4595  
5e81e88a David Woodhouse    2010-02-26  4596  	ret = nand_scan_ident(mtd, maxchips, NULL);
3b85c321 David Woodhouse    2006-09-25  4597  	if (!ret)
3b85c321 David Woodhouse    2006-09-25  4598  		ret = nand_scan_tail(mtd);
3b85c321 David Woodhouse    2006-09-25  4599  	return ret;
3b85c321 David Woodhouse    2006-09-25  4600  }
7351d3a5 Florian Fainelli   2010-09-07  4601  EXPORT_SYMBOL(nand_scan);
3b85c321 David Woodhouse    2006-09-25  4602  
^1da177e Linus Torvalds     2005-04-16  4603  /**
26e1c20c Richard Weinberger 2016-09-21  4604   * nand_cleanup - [NAND Interface] Free resources held by the NAND device
26e1c20c Richard Weinberger 2016-09-21  4605   * @mts: MTD device structure
^1da177e Linus Torvalds     2005-04-16  4606   */
26e1c20c Richard Weinberger 2016-09-21  4607  void nand_cleanup(struct mtd_info *mtd)
^1da177e Linus Torvalds     2005-04-16 @4608  {
862eba51 Boris Brezillon    2015-12-01  4609  	struct nand_chip *chip = mtd_to_nand(mtd);
^1da177e Linus Torvalds     2005-04-16  4610  
e4225ae8 Rafał Miłecki      2016-04-17  4611  	if (chip->ecc.mode == NAND_ECC_SOFT &&
06f384c9 Rafał Miłecki      2016-04-17  4612  	    chip->ecc.algo == NAND_ECC_BCH)
193bd400 Ivan Djelic        2011-03-11  4613  		nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
193bd400 Ivan Djelic        2011-03-11  4614  
fa671646 Jesper Juhl        2005-11-07  4615  	/* Free bad block table memory */
ace4dfee Thomas Gleixner    2006-05-24  4616  	kfree(chip->bbt);

:::::: The code at line 4608 was first introduced by commit
:::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2

:::::: TO: Linus Torvalds <torvalds@ppc970.osdl.org>
:::::: CC: Linus Torvalds <torvalds@ppc970.osdl.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 6381 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 21/46] mtd: nandsim: Implement preliminary destructor function
  2016-09-21  9:51 ` [PATCH v2 21/46] mtd: nandsim: Implement preliminary destructor function Daniel Walter
@ 2016-09-21 12:56   ` kbuild test robot
  0 siblings, 0 replies; 69+ messages in thread
From: kbuild test robot @ 2016-09-21 12:56 UTC (permalink / raw)
  To: Daniel Walter
  Cc: kbuild-all, linux-mtd, linux-kernel, computersforpeace, dwmw2,
	boris.brezillon, Richard Weinberger

[-- Attachment #1: Type: text/plain, Size: 1080 bytes --]

Hi Richard,

[auto build test ERROR on mtd/master]
[also build test ERROR on v4.8-rc7]
[cannot apply to next-20160921]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Daniel-Walter/Nandsim-facelift-part-I-of-II/20160921-182636
base:   git://git.infradead.org/linux-mtd.git master
config: i386-randconfig-s1-201638 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> ERROR: "nand_cleanup" [drivers/mtd/nand/nandsim.ko] undefined!

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 22976 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources
  2016-09-21  9:44 ` [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources Daniel Walter
  2016-09-21  9:58   ` Boris Brezillon
  2016-09-21 12:43   ` kbuild test robot
@ 2016-09-21 14:25   ` Boris Brezillon
  2016-09-21 14:38     ` Daniel Walter
  2 siblings, 1 reply; 69+ messages in thread
From: Boris Brezillon @ 2016-09-21 14:25 UTC (permalink / raw)
  To: Daniel Walter
  Cc: linux-mtd, computersforpeace, linux-kernel, Richard Weinberger

Daniel, Richard,

On Wed, 21 Sep 2016 11:44:41 +0200
Daniel Walter <dwalter@sigma-star.at> wrote:

> From: Richard Weinberger <richard@nod.at>
> 
> Provide a nand_cleanup() function to free all nand related resources
> without unregistering the mtd device.
> This should allow drivers to call mtd_device_unregister() and handle
> its return value and still being able to cleanup all nand related
> resources.
> 

Can you check this version?

--->8---
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0cd663040a9c..9ee50189f98a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4798,19 +4798,15 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
 EXPORT_SYMBOL(nand_scan);
 
 /**
- * nand_release - [NAND Interface] Free resources held by the NAND device
- * @mtd: MTD device structure
+ * nand_cleanup - [NAND Interface] Free resources held by the NAND device
+ * @chip: NAND chip object
  */
-void nand_release(struct mtd_info *mtd)
+void nand_cleanup(struct nand_chip *chip)
 {
-	struct nand_chip *chip = mtd_to_nand(mtd);
-
 	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);
-
 	nand_release_data_interface(chip);
 
 	/* Free bad block table memory */
@@ -4823,6 +4819,18 @@ void nand_release(struct mtd_info *mtd)
 			& NAND_BBT_DYNAMICSTRUCT)
 		kfree(chip->badblock_pattern);
 }
+EXPORT_SYMBOL_GPL(nand_cleanup);
+
+/**
+ * nand_release - [NAND Interface] Unregister the MTD device and free resources
+ *		  held by the NAND device
+ * @mtd: MTD device structure
+ */
+void nand_release(struct mtd_info *mtd)
+{
+	mtd_device_unregister(mtd);
+	nand_cleanup(mtd_to_nand(mtd));
+}
 EXPORT_SYMBOL_GPL(nand_release);
 
 MODULE_LICENSE("GPL");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 331caf987b16..c5d3d5024fc8 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -38,7 +38,7 @@ int nand_scan_ident(struct mtd_info *mtd, int max_chips,
 			   struct nand_flash_dev *table);
 int nand_scan_tail(struct mtd_info *mtd);
 
-/* Free resources held by the NAND device */
+/* Unregister the MTD device and free resources held by the NAND device */
 void nand_release(struct mtd_info *mtd);
 
 /* Internal helper for board drivers which need to override command function */
@@ -1186,4 +1186,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
 /* Reset and initialize a NAND device */
 int nand_reset(struct nand_chip *chip);
 
+/* Free resources held by the NAND device */
+void nand_cleanup(struct nand_chip *chip);
+
 #endif /* __LINUX_MTD_NAND_H */

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier
  2016-09-21  9:45 ` [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier Daniel Walter
@ 2016-09-21 14:31   ` Boris Brezillon
  2016-09-21 14:33     ` Daniel Walter
  2016-10-09  5:20   ` Brian Norris
  1 sibling, 1 reply; 69+ messages in thread
From: Boris Brezillon @ 2016-09-21 14:31 UTC (permalink / raw)
  To: Daniel Walter
  Cc: linux-mtd, Richard Weinberger, computersforpeace, linux-kernel

On Wed, 21 Sep 2016 11:45:12 +0200
Daniel Walter <dwalter@sigma-star.at> wrote:

> 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;

How about:

	if (device_is_registered(&master->dev)) {
		err = del_mtd_device(master);
		if (err)
			return err;
	}

	if (master->_reboot)
		unregister_reboot_notifier(&master->reboot_notifier);

	return 0;

This way you get rid of the unregister label, which IMHO improves
readability.

>  }
>  EXPORT_SYMBOL_GPL(mtd_device_unregister);
>  

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier
  2016-09-21 14:31   ` Boris Brezillon
@ 2016-09-21 14:33     ` Daniel Walter
  0 siblings, 0 replies; 69+ messages in thread
From: Daniel Walter @ 2016-09-21 14:33 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: linux-mtd, Richard Weinberger, computersforpeace, linux-kernel

On 09/21/2016 04:31 PM, Boris Brezillon wrote:
> On Wed, 21 Sep 2016 11:45:12 +0200
> Daniel Walter <dwalter@sigma-star.at> wrote:
> 
>> 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;
> 
> How about:
> 
> 	if (device_is_registered(&master->dev)) {
> 		err = del_mtd_device(master);
> 		if (err)
> 			return err;
> 	}
> 
> 	if (master->_reboot)
> 		unregister_reboot_notifier(&master->reboot_notifier);
> 
> 	return 0;
> 
> This way you get rid of the unregister label, which IMHO improves
> readability.

Agree, will fix this in v3 of the series.



-- 
sigma star gmbh | Eduard-Bodem-Gasse 6, 6020 Innsbruck, Austria
UID/VAT Nr: ATU 66964118 | FN: 374287y

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources
  2016-09-21 14:25   ` Boris Brezillon
@ 2016-09-21 14:38     ` Daniel Walter
  2016-09-21 14:42       ` Boris Brezillon
  0 siblings, 1 reply; 69+ messages in thread
From: Daniel Walter @ 2016-09-21 14:38 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: linux-mtd, computersforpeace, linux-kernel, Richard Weinberger

Boris,

On 09/21/2016 04:25 PM, Boris Brezillon wrote:
> Daniel, Richard,
> 
> On Wed, 21 Sep 2016 11:44:41 +0200
> Daniel Walter <dwalter@sigma-star.at> wrote:
> 
>> From: Richard Weinberger <richard@nod.at>
>>
>> Provide a nand_cleanup() function to free all nand related resources
>> without unregistering the mtd device.
>> This should allow drivers to call mtd_device_unregister() and handle
>> its return value and still being able to cleanup all nand related
>> resources.
>>
> 
> Can you check this version?

looks good to me.
I'll incooperate the change in v3 (AFAIR this change will break the last
patch of the series).



> 
> --->8---
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index 0cd663040a9c..9ee50189f98a 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -4798,19 +4798,15 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
>  EXPORT_SYMBOL(nand_scan);
>  
>  /**
> - * nand_release - [NAND Interface] Free resources held by the NAND device
> - * @mtd: MTD device structure
> + * nand_cleanup - [NAND Interface] Free resources held by the NAND device
> + * @chip: NAND chip object
>   */
> -void nand_release(struct mtd_info *mtd)
> +void nand_cleanup(struct nand_chip *chip)
>  {
> -	struct nand_chip *chip = mtd_to_nand(mtd);
> -
>  	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);
> -
>  	nand_release_data_interface(chip);
>  
>  	/* Free bad block table memory */
> @@ -4823,6 +4819,18 @@ void nand_release(struct mtd_info *mtd)
>  			& NAND_BBT_DYNAMICSTRUCT)
>  		kfree(chip->badblock_pattern);
>  }
> +EXPORT_SYMBOL_GPL(nand_cleanup);
> +
> +/**
> + * nand_release - [NAND Interface] Unregister the MTD device and free resources
> + *		  held by the NAND device
> + * @mtd: MTD device structure
> + */
> +void nand_release(struct mtd_info *mtd)
> +{
> +	mtd_device_unregister(mtd);
> +	nand_cleanup(mtd_to_nand(mtd));
> +}
>  EXPORT_SYMBOL_GPL(nand_release);
>  
>  MODULE_LICENSE("GPL");
> diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> index 331caf987b16..c5d3d5024fc8 100644
> --- a/include/linux/mtd/nand.h
> +++ b/include/linux/mtd/nand.h
> @@ -38,7 +38,7 @@ int nand_scan_ident(struct mtd_info *mtd, int max_chips,
>  			   struct nand_flash_dev *table);
>  int nand_scan_tail(struct mtd_info *mtd);
>  
> -/* Free resources held by the NAND device */
> +/* Unregister the MTD device and free resources held by the NAND device */
>  void nand_release(struct mtd_info *mtd);
>  
>  /* Internal helper for board drivers which need to override command function */
> @@ -1186,4 +1186,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
>  /* Reset and initialize a NAND device */
>  int nand_reset(struct nand_chip *chip);
>  
> +/* Free resources held by the NAND device */
> +void nand_cleanup(struct nand_chip *chip);
> +
>  #endif /* __LINUX_MTD_NAND_H */
> 

-- 
sigma star gmbh | Eduard-Bodem-Gasse 6, 6020 Innsbruck, Austria
UID/VAT Nr: ATU 66964118 | FN: 374287y

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources
  2016-09-21 14:38     ` Daniel Walter
@ 2016-09-21 14:42       ` Boris Brezillon
  0 siblings, 0 replies; 69+ messages in thread
From: Boris Brezillon @ 2016-09-21 14:42 UTC (permalink / raw)
  To: Daniel Walter
  Cc: linux-mtd, computersforpeace, linux-kernel, Richard Weinberger

On Wed, 21 Sep 2016 16:38:28 +0200
Daniel Walter <dwalter@sigma-star.at> wrote:

> Boris,
> 
> On 09/21/2016 04:25 PM, Boris Brezillon wrote:
> > Daniel, Richard,
> > 
> > On Wed, 21 Sep 2016 11:44:41 +0200
> > Daniel Walter <dwalter@sigma-star.at> wrote:
> >   
> >> From: Richard Weinberger <richard@nod.at>
> >>
> >> Provide a nand_cleanup() function to free all nand related resources
> >> without unregistering the mtd device.
> >> This should allow drivers to call mtd_device_unregister() and handle
> >> its return value and still being able to cleanup all nand related
> >> resources.
> >>  
> > 
> > Can you check this version?  
> 
> looks good to me.
> I'll incooperate the change in v3 (AFAIR this change will break the last
> patch of the series).

I applied the patch to my nand/next branch [1] (which means it's queued
for 4.9). Rebase your work on top of this branch and you should be good.

Thanks,

Boris

[1]https://github.com/linux-nand/linux/commits/nand/next

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-09-21 10:15   ` Boris Brezillon
@ 2016-09-28 20:16     ` Brian Norris
  2016-12-14 19:24       ` Karl Beldan
  0 siblings, 1 reply; 69+ messages in thread
From: Brian Norris @ 2016-09-28 20:16 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Daniel Walter, linux-mtd, Richard Weinberger, dwmw2, linux-kernel

On Wed, Sep 21, 2016 at 12:15:31PM +0200, Boris Brezillon wrote:
> On Wed, 21 Sep 2016 11:43:56 +0200
> Daniel Walter <dwalter@sigma-star.at> wrote:
> 
> > 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.
> 
> Brian, can we have this one queued for 4.9? I can't take it in my tree
> if you want, but it's probably better if it's in the mtd tree.

Applied this patch to l2-mtd.git

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier
  2016-09-21  9:45 ` [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier Daniel Walter
  2016-09-21 14:31   ` Boris Brezillon
@ 2016-10-09  5:20   ` Brian Norris
  1 sibling, 0 replies; 69+ messages in thread
From: Brian Norris @ 2016-10-09  5:20 UTC (permalink / raw)
  To: Daniel Walter; +Cc: linux-mtd, linux-kernel, Richard Weinberger

I realize I didn't comment on the latest copy of this patch, so copying
my questions here:

On Wed, Sep 21, 2016 at 11:45:12AM +0200, Daniel Walter wrote:
> 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);

Is there any kind of race issue with unregistering the notifier *after*
we've deleted the device? I had intentionally unregistered first,
because I didn't want any chance of the driver/module and/or data
structures being freed before we call the notifier.

I can't think of any particular issue yet, but I wanted to ask.

Brian

> +	return 0;
>  }
>  EXPORT_SYMBOL_GPL(mtd_device_unregister);
>  
> -- 
> 2.8.3
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 00/46] Nandsim facelift (part I of II)
  2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
                   ` (45 preceding siblings ...)
  2016-09-21  9:57 ` [PATCH v2 46/46] mtd/nandsim: Add ioctl for info Daniel Walter
@ 2016-10-16 16:24 ` Boris Brezillon
  2016-11-14 16:24   ` Richard Weinberger
  46 siblings, 1 reply; 69+ messages in thread
From: Boris Brezillon @ 2016-10-16 16:24 UTC (permalink / raw)
  To: Daniel Walter; +Cc: linux-mtd, linux-kernel

Daniel, Richard,

On Wed, 21 Sep 2016 11:43:29 +0200
Daniel Walter <dwalter@sigma-star.at> wrote:

> Changes since V1:
>   Incooperate feedback for nand_cleanup()
>   Improve commit messages
> 
> 
> 
> 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.

I really like the new approach for 2 reasons:
1/ it allows creating several NAND devs, and you can do that after the
   module has been loaded.
2/ it fixes the partial NAND detection support by allowing one to
   describe its NAND in term of page size, eraseblock size, oob
   size, ...

But I'm wondering if we should not create a new driver instead of
trying to fix the old one (I must admit I haven't been through the 46
patches of this series, but last time we discussed it on IRC, Richard
said it actually was a complete rewrite of the nandsim driver).

Moreover, if we specify the flash layout manually, maybe we could make
it an mtdsim driver instead of restricting the emulation to NAND
devices.

What do you think?

Regards,

Boris

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 00/46] Nandsim facelift (part I of II)
  2016-10-16 16:24 ` [PATCH v2 00/46] Nandsim facelift (part I of II) Boris Brezillon
@ 2016-11-14 16:24   ` Richard Weinberger
  2016-11-20 10:26     ` Boris Brezillon
  0 siblings, 1 reply; 69+ messages in thread
From: Richard Weinberger @ 2016-11-14 16:24 UTC (permalink / raw)
  To: Boris Brezillon; +Cc: Daniel Walter, linux-mtd, LKML

Boris,

sorry for the late answer. I was not on CC, therefore this mail was
unnoticed by me. :-(

On Sun, Oct 16, 2016 at 6:24 PM, Boris Brezillon
<boris.brezillon@free-electrons.com> wrote:
> Daniel, Richard,
>
> On Wed, 21 Sep 2016 11:43:29 +0200
> Daniel Walter <dwalter@sigma-star.at> wrote:
>
>> Changes since V1:
>>   Incooperate feedback for nand_cleanup()
>>   Improve commit messages

[..-]

> I really like the new approach for 2 reasons:
> 1/ it allows creating several NAND devs, and you can do that after the
>    module has been loaded.
> 2/ it fixes the partial NAND detection support by allowing one to
>    describe its NAND in term of page size, eraseblock size, oob
>    size, ...
>
> But I'm wondering if we should not create a new driver instead of
> trying to fix the old one (I must admit I haven't been through the 46
> patches of this series, but last time we discussed it on IRC, Richard
> said it actually was a complete rewrite of the nandsim driver).
>
> Moreover, if we specify the flash layout manually, maybe we could make
> it an mtdsim driver instead of restricting the emulation to NAND
> devices.
>
> What do you think?

I think we don't need a completely new driver. This series just adds
functionality to nandsim without much cost, in fact we reuse also some
bits from nandsim.
If we add a new nandsim alike driver we basically give up the current nandsim
and it will die a painful death. This series tries to avoid that.
What we can do is splitting nandsim into three files (common, old and new).

P.s: Yes, I'm aware of the fact that then I'll have to maintain the beast. ;-\

-- 
Thanks,
//richard

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 19/46] mtd: nandsim: UAPI v1
  2016-09-21  9:50 ` [PATCH v2 19/46] mtd: nandsim: UAPI v1 Daniel Walter
@ 2016-11-20 10:13   ` Boris Brezillon
  0 siblings, 0 replies; 69+ messages in thread
From: Boris Brezillon @ 2016-11-20 10:13 UTC (permalink / raw)
  To: Daniel Walter
  Cc: linux-mtd, Richard Weinberger, computersforpeace, dwmw2, linux-kernel

Daniel, Richard,

On Wed, 21 Sep 2016 11:50:45 +0200
Daniel Walter <dwalter@sigma-star.at> wrote:

> From: Richard Weinberger <richard@nod.at>
> 
> Expose nandsim creation and delete functions
> to user-space

Did you consider using configfs for nandsim dev creation/removal. The
main benefit I see in using configfs is that you can extend the
parameters without breaking the ABI.

Here is an example of what I have in mind:

mtdsim subsystem:

 <configfs-mountpoint>/mtdsim

nand backend:

 <configfs-mountpoint>/mtdsim/nand

create and configure a new nandsim device:

 mkdir <configfs-mountpoint>/mtdsim/nand/<dev-name>
 echo xxx >  <configfs-mountpoint>/mtdsim/nand/<dev-name>/pagesize
 echo xxx >  <configfs-mountpoint>/mtdsim/nand/<dev-name>/oobsize
 ...

create and configure a partitition:

 mkdir <configfs-mountpoint>/mtdsim/nand/<dev-name>/<part-name>
 echo xxx > <configfs-mountpoint>/mtdsim/nand/<dev-name>/<part-name>/offset
 echo xxx > <configfs-mountpoint>/mtdsim/nand/<dev-name>/<part-name>/size

Once your done with the configuration of your nandsim device, you
can register it by doing:

 echo 1 >  <configfs-mountpoint>/mtdsim/nand/<dev-name>/enable

and unregister it with:

 echo 0 >  <configfs-mountpoint>/mtdsim/nand/<dev-name>/enable

This way, each time you need to add a new feature (bitflips emulation,
paired pages emulation, ...) or a new property, you can just add an
extra attribute to the configfs interface without breaking the previous
ABI.

I'd really prefer this solution over the nandsim_ctrl dev exposed in
/dev/.

What do you think.

> 
> Signed-off-by: Richard Weinberger <richard@nod.at>
> ---
>  include/uapi/mtd/nandsim-user.h | 102 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 102 insertions(+)
>  create mode 100644 include/uapi/mtd/nandsim-user.h
> 
> diff --git a/include/uapi/mtd/nandsim-user.h b/include/uapi/mtd/nandsim-user.h
> new file mode 100644
> index 0000000..b52d620
> --- /dev/null
> +++ b/include/uapi/mtd/nandsim-user.h
> @@ -0,0 +1,102 @@
> +#ifndef __NANDSIM_USER_H__
> +#define __NANDSIM_USER_H__
> +
> +#include <linux/types.h>
> +
> +#define NANDSIM_IOC_MAGIC 'n'
> +
> +#define NANDSIM_IOC_NEW_INSTANCE _IOW(NANDSIM_IOC_MAGIC, 0, struct ns_new_instance_req)
> +#define NANDSIM_IOC_DESTROY_INSTANCE _IOW(NANDSIM_IOC_MAGIC, 1, struct ns_destroy_instance_req)
> +
> +#define NANDSIM_MAX_DEVICES 32
> +#define NANDSIM_MAX_PARTS 32
> +
> +enum ns_backend_type {
> +	NANDSIM_BACKEND_RAM = 0,
> +	NANDSIM_BACKEND_CACHEFILE = 1,
> +	NANDSIM_BACKEND_FILE = 2,
> +	NANDSIM_BACKEND_MAX,
> +};
> +
> +/**
> + * struct ns_new_instance_req - Create a new nandsim instance.
> + *
> + * @id_bytes: NAND ID of the simulated NAND chip
> + * @bus_width: bus width to emulate, either 8 or 16
> + * @bbt_mode: bad block table mode, 0 OOB, 1 BBT with marker in OOB,
> + *            2 BBT with marker in data area
> + * @no_oob: backing file contains no OOB data
> + * @bch_strength: instead of hamming ECC use BCH with given strength
> + * @parts_num: number of MTD partitions to create
> + * @parts: partition sizes in physical erase blocks, used then @parts_num > 0
> + * @backend: backend type, see @ns_backend_type
> + * @file_fd: file describtor of backend, only for @NANDSIM_BACKEND_CACHEFILE
> + *           and @NANDSIM_BACKEND_FILE.
> + * @bitflips: maximum number of random bit flips per page
> + * @overridesize: specifies the NAND size overriding the ID bytes
> + * @access_delay: initial page access delay (microseconds)
> + * @program_delay: page program delay (microseconds)
> + * @erase_delay: sector erase delay (milliseconds)
> + * @output_cycle: word output, from flash, time (nanoseconds)
> + * @input_cycle: word input, to flash, time (nanoseconds)
> + * @simelem_num: number of simulation elements appened to this
> + *               data structure. see @ns_simelement_prop
> + *
> + * This struct is used with the @NANDSIM_IOC_NEW_INSTANCE ioctl command.
> + * It creates a new nandsim instance from the given parameter.
> + * The ioctl command returns in case of success the nandsim id of the new
> + * instance, in case of error a negative value.
> + *
> + * Not all fields in the struct have to be filled, if nandsim should
> + * use a default ignore the value, fill with 0.
> + * The only mandatory fields are @id_bytes and @bus_width.
> + * When @no_oob is non-zero @bch_strength cannot be used since
> + * @no_oob implies that no ECC is used.
> + */
> +struct ns_new_instance_req {
> +	__s8 id_bytes[8];
> +
> +	__s8 bus_width;
> +	__s8 bbt_mode;
> +	__s8 no_oob;
> +	__s32 bch_strength;
> +
> +	__s8 parts_num;
> +	__s32 parts[NANDSIM_MAX_PARTS];
> +
> +	__s8 backend;
> +	__s32 file_fd;
> +
> +	__s32 bitflips;
> +	__s32 overridesize;
> +	__s32 access_delay;
> +	__s32 program_delay;
> +	__s32 erase_delay;
> +	__s32 output_cycle;
> +	__s32 input_cycle;
> +
> +	__s32 padding[4];
> +
> +	__s32 simelem_num;
> +} __packed;
> +
> +enum {
> +	NANDSIM_SIMELEM_BADBLOCK = 0,
> +	NANDSIM_SIMELEM_WEAKBLOCK,
> +	NANDSIM_SIMELEM_WEAKPAGE,
> +	NANDSIM_SIMELEM_GRAVEPAGE,
> +};
> +
> +struct ns_simelement_prop {
> +	__s8 elem_type;
> +	__s32 elem_id;
> +	__s32 elem_attr;
> +	__s8 padding[7];
> +} __packed;
> +
> +struct ns_destroy_instance_req {
> +	__s8 id;
> +	__s8 padding[7];
> +} __packed;
> +
> +#endif /* __NANDSIM_USER_H__ */

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 00/46] Nandsim facelift (part I of II)
  2016-11-14 16:24   ` Richard Weinberger
@ 2016-11-20 10:26     ` Boris Brezillon
  0 siblings, 0 replies; 69+ messages in thread
From: Boris Brezillon @ 2016-11-20 10:26 UTC (permalink / raw)
  To: Richard Weinberger; +Cc: linux-mtd, LKML, Daniel Walter

Hi Richard,

On Mon, 14 Nov 2016 17:24:18 +0100
Richard Weinberger <richard.weinberger@gmail.com> wrote:

> Boris,
> 
> sorry for the late answer. I was not on CC, therefore this mail was
> unnoticed by me. :-(
> 
> On Sun, Oct 16, 2016 at 6:24 PM, Boris Brezillon
> <boris.brezillon@free-electrons.com> wrote:
> > Daniel, Richard,
> >
> > On Wed, 21 Sep 2016 11:43:29 +0200
> > Daniel Walter <dwalter@sigma-star.at> wrote:
> >  
> >> Changes since V1:
> >>   Incooperate feedback for nand_cleanup()
> >>   Improve commit messages  
> 
> [..-]
> 
> > I really like the new approach for 2 reasons:
> > 1/ it allows creating several NAND devs, and you can do that after the
> >    module has been loaded.
> > 2/ it fixes the partial NAND detection support by allowing one to
> >    describe its NAND in term of page size, eraseblock size, oob
> >    size, ...
> >
> > But I'm wondering if we should not create a new driver instead of
> > trying to fix the old one (I must admit I haven't been through the 46
> > patches of this series, but last time we discussed it on IRC, Richard
> > said it actually was a complete rewrite of the nandsim driver).
> >
> > Moreover, if we specify the flash layout manually, maybe we could make
> > it an mtdsim driver instead of restricting the emulation to NAND
> > devices.
> >
> > What do you think?  
> 
> I think we don't need a completely new driver. This series just adds
> functionality to nandsim without much cost, in fact we reuse also some
> bits from nandsim.
> If we add a new nandsim alike driver we basically give up the current nandsim
> and it will die a painful death. This series tries to avoid that.

Well, the whole problem with the current nandsim driver is that it
tries to do too many things. It not only tries to emulate a NAND device,
with all its constraint (bitflips, and many more), but it also tries to
register as a NAND driver with the NAND dev detection flow, and all
the convoluted page read/write logic (with/without ECC, ...).

Life (and code) would be much easier if the emulation driver was just
trying to emulate a NAND device without registering to the NAND
framework. All you'd have to do is implement your own mtd_info hooks,
without this nandsim device state burden that is required for
->cmd_ctrl() to work properly.

Of course, adding a new driver means marking the old one as deprecated
and keeping it around for some time, but that's IMHO, cleaner than
keeping a lot of code for something that we do not want to maintain.
One example is the NAND ID detection: it is a real pain, and we have
no easy solution to support ONFI chips.
If we go for a solution where the user select all the NAND properties
manually, we get rid of this complex beast, while leaving more freedom
to test some corner cases (non-powerof2 number of blocks per die for
example).

> What we can do is splitting nandsim into three files (common, old and new).

Well, it's not really about creating new files, it's more about
maintaining things that IMO are not so useful...

Regards,

Boris

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-09-28 20:16     ` Brian Norris
@ 2016-12-14 19:24       ` Karl Beldan
  2016-12-14 21:09         ` Brian Norris
  0 siblings, 1 reply; 69+ messages in thread
From: Karl Beldan @ 2016-12-14 19:24 UTC (permalink / raw)
  To: Brian Norris
  Cc: Boris Brezillon, Richard Weinberger, linux-mtd, David Woodhouse,
	linux-kernel, Daniel Walter, Stable

On Wed, Sep 28, 2016 at 8:16 PM, Brian Norris
<computersforpeace@gmail.com> wrote:
> On Wed, Sep 21, 2016 at 12:15:31PM +0200, Boris Brezillon wrote:
>> On Wed, 21 Sep 2016 11:43:56 +0200
>> Daniel Walter <dwalter@sigma-star.at> wrote:
>>
>> > 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.
>>
>> Brian, can we have this one queued for 4.9? I can't take it in my tree
>> if you want, but it's probably better if it's in the mtd tree.
>
> Applied this patch to l2-mtd.git
>

I think this should also go into -stable.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-12-14 19:24       ` Karl Beldan
@ 2016-12-14 21:09         ` Brian Norris
  2016-12-14 21:12           ` Richard Weinberger
  2016-12-15  7:09           ` Karl Beldan
  0 siblings, 2 replies; 69+ messages in thread
From: Brian Norris @ 2016-12-14 21:09 UTC (permalink / raw)
  To: Karl Beldan
  Cc: Boris Brezillon, Richard Weinberger, linux-mtd, David Woodhouse,
	linux-kernel, Daniel Walter, Stable

On Wed, Dec 14, 2016 at 07:24:46PM +0000, Karl Beldan wrote:
> On Wed, Sep 28, 2016 at 8:16 PM, Brian Norris
> <computersforpeace@gmail.com> wrote:
> > On Wed, Sep 21, 2016 at 12:15:31PM +0200, Boris Brezillon wrote:
> >> On Wed, 21 Sep 2016 11:43:56 +0200
> >> Daniel Walter <dwalter@sigma-star.at> wrote:
> >>
> >> > 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.
> >>
> >> Brian, can we have this one queued for 4.9? I can't take it in my tree
> >> if you want, but it's probably better if it's in the mtd tree.
> >
> > Applied this patch to l2-mtd.git
> >
> 
> I think this should also go into -stable.

Why? Do you have real use cases that are broken by this? I understand
this is a problem, but I'm curious on how this satisfies the stable
rules.

Also, note that this isn't a regression; it's been broken forever and
apparently no one noticed. IMO that raises the bar a bit (but not
impossibly so) for -stable.

Anyway, if we decide to do this, you'll also want to include the git
hash and applicable kernel versions, per Option 2 [1].

Brian

[1] Documentation/stable_kernel_rules.txt.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-12-14 21:09         ` Brian Norris
@ 2016-12-14 21:12           ` Richard Weinberger
  2016-12-14 23:40             ` Brian Norris
  2016-12-15  7:09           ` Karl Beldan
  1 sibling, 1 reply; 69+ messages in thread
From: Richard Weinberger @ 2016-12-14 21:12 UTC (permalink / raw)
  To: Brian Norris, Karl Beldan
  Cc: Boris Brezillon, linux-mtd, David Woodhouse, linux-kernel,
	Daniel Walter, Stable

Hi!

On 14.12.2016 22:09, Brian Norris wrote:
> On Wed, Dec 14, 2016 at 07:24:46PM +0000, Karl Beldan wrote:
>> On Wed, Sep 28, 2016 at 8:16 PM, Brian Norris
>> <computersforpeace@gmail.com> wrote:
>>> On Wed, Sep 21, 2016 at 12:15:31PM +0200, Boris Brezillon wrote:
>>>> On Wed, 21 Sep 2016 11:43:56 +0200
>>>> Daniel Walter <dwalter@sigma-star.at> wrote:
>>>>
>>>>> 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.
>>>>
>>>> Brian, can we have this one queued for 4.9? I can't take it in my tree
>>>> if you want, but it's probably better if it's in the mtd tree.
>>>
>>> Applied this patch to l2-mtd.git
>>>
>>
>> I think this should also go into -stable.
> 
> Why? Do you have real use cases that are broken by this? I understand
> this is a problem, but I'm curious on how this satisfies the stable
> rules.
> 
> Also, note that this isn't a regression; it's been broken forever and
> apparently no one noticed. IMO that raises the bar a bit (but not
> impossibly so) for -stable.

Yes. AFAICT you can only trigger it using my "new" nandsim
which is not mainline so far.

Thanks,
//richard

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-12-14 21:12           ` Richard Weinberger
@ 2016-12-14 23:40             ` Brian Norris
  0 siblings, 0 replies; 69+ messages in thread
From: Brian Norris @ 2016-12-14 23:40 UTC (permalink / raw)
  To: Richard Weinberger
  Cc: Karl Beldan, Boris Brezillon, linux-mtd, David Woodhouse,
	linux-kernel, Daniel Walter, Stable

On Wed, Dec 14, 2016 at 10:12:42PM +0100, Richard Weinberger wrote:
> On 14.12.2016 22:09, Brian Norris wrote:
> > Also, note that this isn't a regression; it's been broken forever and
> > apparently no one noticed. IMO that raises the bar a bit (but not
> > impossibly so) for -stable.
> 
> Yes. AFAICT you can only trigger it using my "new" nandsim
> which is not mainline so far.

Ah, OK. So the only current _{get,put}_device() implementor in mainline
is gluebi, so far. And it's OK for now to just have the master device be
refcounted, and just rely on the partitions being removed before the
master, right?

In that case, no, this shouldn't go to -stable.

Brian

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-12-14 21:09         ` Brian Norris
  2016-12-14 21:12           ` Richard Weinberger
@ 2016-12-15  7:09           ` Karl Beldan
  2016-12-15  7:51             ` Richard Weinberger
  1 sibling, 1 reply; 69+ messages in thread
From: Karl Beldan @ 2016-12-15  7:09 UTC (permalink / raw)
  To: Brian Norris
  Cc: Boris Brezillon, Richard Weinberger, linux-mtd, David Woodhouse,
	linux-kernel, Daniel Walter, Stable

On Wed, Dec 14, 2016 at 9:09 PM, Brian Norris
<computersforpeace@gmail.com> wrote:
> On Wed, Dec 14, 2016 at 07:24:46PM +0000, Karl Beldan wrote:
>> On Wed, Sep 28, 2016 at 8:16 PM, Brian Norris
>> <computersforpeace@gmail.com> wrote:
>> > On Wed, Sep 21, 2016 at 12:15:31PM +0200, Boris Brezillon wrote:
>> >> On Wed, 21 Sep 2016 11:43:56 +0200
>> >> Daniel Walter <dwalter@sigma-star.at> wrote:
>> >>
>> >> > 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.
>> >>
>> >> Brian, can we have this one queued for 4.9? I can't take it in my tree
>> >> if you want, but it's probably better if it's in the mtd tree.
>> >
>> > Applied this patch to l2-mtd.git
>> >
>>
>> I think this should also go into -stable.
>
> Why? Do you have real use cases that are broken by this? I understand

I do, some code adding partitions on a gluebi master.

> this is a problem, but I'm curious on how this satisfies the stable
> rules.
>
> Also, note that this isn't a regression; it's been broken forever and
> apparently no one noticed. IMO that raises the bar a bit (but not
> impossibly so) for -stable.
>

I just encountered the bug yesterday and yes it is obvious it has been
broken forever.
I don't have strong opinion about these things so no worries.

Karl

> Anyway, if we decide to do this, you'll also want to include the git
> hash and applicable kernel versions, per Option 2 [1].
>
> Brian
>
> [1] Documentation/stable_kernel_rules.txt.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-12-15  7:09           ` Karl Beldan
@ 2016-12-15  7:51             ` Richard Weinberger
  2016-12-28 18:53               ` Karl Beldan
  0 siblings, 1 reply; 69+ messages in thread
From: Richard Weinberger @ 2016-12-15  7:51 UTC (permalink / raw)
  To: Karl Beldan, Brian Norris
  Cc: Boris Brezillon, linux-mtd, David Woodhouse, linux-kernel,
	Daniel Walter, Stable

On 15.12.2016 08:09, Karl Beldan wrote:
>>> I think this should also go into -stable.
>>
>> Why? Do you have real use cases that are broken by this? I understand
> 
> I do, some code adding partitions on a gluebi master.

What exactly are you doing?

>> this is a problem, but I'm curious on how this satisfies the stable
>> rules.
>>
>> Also, note that this isn't a regression; it's been broken forever and
>> apparently no one noticed. IMO that raises the bar a bit (but not
>> impossibly so) for -stable.
>>
> 
> I just encountered the bug yesterday and yes it is obvious it has been
> broken forever.
> I don't have strong opinion about these things so no worries.

If existing stuff is broken, and you can trigger it. Please let us
know. Then it should go into -stable.

Thanks,
//richard

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2 01/46] mtdpart: Propagate _get/put_device()
  2016-12-15  7:51             ` Richard Weinberger
@ 2016-12-28 18:53               ` Karl Beldan
  0 siblings, 0 replies; 69+ messages in thread
From: Karl Beldan @ 2016-12-28 18:53 UTC (permalink / raw)
  To: Richard Weinberger
  Cc: Brian Norris, Boris Brezillon, linux-mtd, David Woodhouse,
	linux-kernel, Daniel Walter, Stable

On Thu, Dec 15, 2016 at 08:51:06AM +0100, Richard Weinberger wrote:
> On 15.12.2016 08:09, Karl Beldan wrote:
> >>> I think this should also go into -stable.
> >>
> >> Why? Do you have real use cases that are broken by this? I understand
> > 
> > I do, some code adding partitions on a gluebi master.
> 
> What exactly are you doing?
> 
> >> this is a problem, but I'm curious on how this satisfies the stable
> >> rules.
> >>
> >> Also, note that this isn't a regression; it's been broken forever and
> >> apparently no one noticed. IMO that raises the bar a bit (but not
> >> impossibly so) for -stable.
> >>
> > 
> > I just encountered the bug yesterday and yes it is obvious it has been
> > broken forever.
> > I don't have strong opinion about these things so no worries.
> 
> If existing stuff is broken, and you can trigger it. Please let us
> know. Then it should go into -stable.
> 

I thought that's what I already did.

Anyways, it didn't require much imagination to come up with a script
triggering the issue so here you are:

#{{

modprobe nandsim
modprobe gluebi
ubiattach -p /dev/mtd1 -b 1
ubimkvol /dev/ubi0 -S 4 -N vol_0
mtdpart add /dev/mtd2 vol_0_0 0 0x1000
tail -F /dev/mtd2 &
while :; do dd bs=1 count=1 if=/dev/mtd3 >/dev/null 2>&1 || break; done
kill -9 %1 # Oops

#}}

 
Karl

^ permalink raw reply	[flat|nested] 69+ messages in thread

end of thread, other threads:[~2016-12-28 18:55 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-21  9:43 [PATCH v2 00/46] Nandsim facelift (part I of II) Daniel Walter
2016-09-21  9:43 ` [PATCH v2 01/46] mtdpart: Propagate _get/put_device() Daniel Walter
2016-09-21 10:15   ` Boris Brezillon
2016-09-28 20:16     ` Brian Norris
2016-12-14 19:24       ` Karl Beldan
2016-12-14 21:09         ` Brian Norris
2016-12-14 21:12           ` Richard Weinberger
2016-12-14 23:40             ` Brian Norris
2016-12-15  7:09           ` Karl Beldan
2016-12-15  7:51             ` Richard Weinberger
2016-12-28 18:53               ` Karl Beldan
2016-09-21  9:44 ` [PATCH v2 02/46] mtd: nand: Provide nand_cleanup() function to free NAND related resources Daniel Walter
2016-09-21  9:58   ` Boris Brezillon
2016-09-21 12:43   ` kbuild test robot
2016-09-21 14:25   ` Boris Brezillon
2016-09-21 14:38     ` Daniel Walter
2016-09-21 14:42       ` Boris Brezillon
2016-09-21  9:45 ` [PATCH v2 03/46] mtd: Don't unconditionally unregister reboot notifier Daniel Walter
2016-09-21 14:31   ` Boris Brezillon
2016-09-21 14:33     ` Daniel Walter
2016-10-09  5:20   ` Brian Norris
2016-09-21  9:45 ` [PATCH v2 04/46] mtd: Don't unconditionally execute remove notifiers Daniel Walter
2016-09-21  9:46 ` [PATCH v2 05/46] mtd: Don't print a scary message when trying to remove a busy MTD Daniel Walter
2016-09-21  9:46 ` [PATCH v2 06/46] mtd: nandsim: Add basic control file support Daniel Walter
2016-09-21  9:47 ` [PATCH v2 07/46] mtd: nandsim: Begin with removal of global state Daniel Walter
2016-09-21  9:47 ` [PATCH v2 08/46] mtd: nandsim: Kill global nsmtd Daniel Walter
2016-09-21  9:47 ` [PATCH v2 09/46] mtd: nandsim: Don't directly use module parameters Daniel Walter
2016-09-21  9:48 ` [PATCH v2 10/46] mtd: nandsim: Add helper functions for pointer magic Daniel Walter
2016-09-21  9:48 ` [PATCH v2 11/46] mtd: nandsim: Factor out nandsim parameters Daniel Walter
2016-09-21  9:48 ` [PATCH v2 12/46] mtd: nandsim: Make debugfs logic multi instance capable Daniel Walter
2016-09-21  9:49 ` [PATCH v2 13/46] mtd: nandsim: Add final logic for multiple instances Daniel Walter
2016-09-21  9:49 ` [PATCH v2 14/46] mtd: nandsim: Add simulator id to MTD parition name Daniel Walter
2016-09-21  9:49 ` [PATCH v2 15/46] mtd: nandsim: Introduce backend operations Daniel Walter
2016-09-21  9:49 ` [PATCH v2 16/46] mtd: nandsim: Print error when backend init failed Daniel Walter
2016-09-21  9:50 ` [PATCH v2 17/46] mtd: nandsim: Allow external backends Daniel Walter
2016-09-21  9:50 ` [PATCH v2 18/46] mtd: nandsim: Add basic support for a file backend Daniel Walter
2016-09-21  9:50 ` [PATCH v2 19/46] mtd: nandsim: UAPI v1 Daniel Walter
2016-11-20 10:13   ` Boris Brezillon
2016-09-21  9:51 ` [PATCH v2 20/46] mtd: nandsim: Implement preliminary constructor function Daniel Walter
2016-09-21  9:51 ` [PATCH v2 21/46] mtd: nandsim: Implement preliminary destructor function Daniel Walter
2016-09-21 12:56   ` kbuild test robot
2016-09-21  9:51 ` [PATCH v2 22/46] mtd: nandsim: Cleanup destroy handlers Daniel Walter
2016-09-21  9:51 ` [PATCH v2 23/46] mtd: nandsim: Unify file backend init logic Daniel Walter
2016-09-21  9:51 ` [PATCH v2 24/46] mtd: nandsim: Wire up NANDSIM_MODE_CACHEFILE ioctl mode Daniel Walter
2016-09-21  9:52 ` [PATCH v2 25/46] mtd: nandsim: Print backend name Daniel Walter
2016-09-21  9:52 ` [PATCH v2 26/46] mtd: nandsim: use the existing output macros Daniel Walter
2016-09-21  9:52 ` [PATCH v2 27/46] mtd: nandsim: Add no_oob mode Daniel Walter
2016-09-21  9:52 ` [PATCH v2 28/46] mtd: nandsim: Refine exports Daniel Walter
2016-09-21  9:54 ` [PATCH v2 29/46] um: Add nandsim backend driver Daniel Walter
2016-09-21  9:54 ` [PATCH v2 30/46] mtd: nandsim: Use pr_ style logging Daniel Walter
2016-09-21  9:54 ` [PATCH v2 31/46] mtd: nandsim: Remove NS_RAW_OFFSET_OOB Daniel Walter
2016-09-21  9:54 ` [PATCH v2 32/46] mtd: nandsim: Remove NS_IS_INITIALIZED Daniel Walter
2016-09-21  9:55 ` [PATCH v2 33/46] mtd: nandsim: Relax page size restrictions Daniel Walter
2016-09-21  9:55 ` [PATCH v2 34/46] mtd: nandsim: Support bitflip and read error emulation in file backend Daniel Walter
2016-09-21  9:55 ` [PATCH v2 35/46] mtd: nandsim: Make NANDSIM_MAX_DEVICES part of uapi Daniel Walter
2016-09-21  9:55 ` [PATCH v2 36/46] mtd: nandsim: Cleanup constants Daniel Walter
2016-09-21  9:55 ` [PATCH v2 37/46] mtd: nandsim: Turn parts[] into a integer Daniel Walter
2016-09-21  9:56 ` [PATCH v2 38/46] mtd: nandsim: Expose partition creation logic to user space Daniel Walter
2016-09-21  9:56 ` [PATCH v2 39/46] mtd: nandsim: Rework init error paths Daniel Walter
2016-09-21  9:56 ` [PATCH v2 40/46] mtd: nandsim: Expose BBT, delays, etc.. to userspace Daniel Walter
2016-09-21  9:56 ` [PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks " Daniel Walter
2016-09-21  9:57 ` [PATCH v2 42/46] mtd: nandsim: Don't printk on ENOMEM Daniel Walter
2016-09-21  9:57 ` [PATCH v2 43/46] mtd: nandsim: Wire up NANDSIM_IOC_NEW_INSTANCE Daniel Walter
2016-09-21  9:57 ` [PATCH v2 44/46] mtd: nandsim: Wire up NANDSIM_IOC_DESTROY_INSTANCE Daniel Walter
2016-09-21  9:57 ` [PATCH v2 45/46] mtd: nandsim: Always answer all 8 bytes from NAND_CMD_READID Daniel Walter
2016-09-21  9:57 ` [PATCH v2 46/46] mtd/nandsim: Add ioctl for info Daniel Walter
2016-10-16 16:24 ` [PATCH v2 00/46] Nandsim facelift (part I of II) Boris Brezillon
2016-11-14 16:24   ` Richard Weinberger
2016-11-20 10:26     ` Boris Brezillon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).