[PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks to userspace

2016-09-21 Thread Daniel Walter
From: Richard Weinberger 

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

Signed-off-by: Richard Weinberger 
---
 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(>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(>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(>list, >weak_blocks);
+   list_add(>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, >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 

[PATCH v2 41/46] mtd: nandsim: Expose support for weakpages/blocks to userspace

2016-09-21 Thread Daniel Walter
From: Richard Weinberger 

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

Signed-off-by: Richard Weinberger 
---
 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(>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(>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(>list, >weak_blocks);
+   list_add(>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, >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