From 95099d4622f8cb224d94e314c7a8e0df60b13f87 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 08:38:01 +0000
Subject: [PATCH] enable docker ppp
---
kernel/drivers/mtd/nand/raw/nandsim.c | 624 +++++++++++++++++++++++++++++++-------------------------
1 files changed, 341 insertions(+), 283 deletions(-)
diff --git a/kernel/drivers/mtd/nand/raw/nandsim.c b/kernel/drivers/mtd/nand/raw/nandsim.c
index 6e908e4..9e7cf9f 100644
--- a/kernel/drivers/mtd/nand/raw/nandsim.c
+++ b/kernel/drivers/mtd/nand/raw/nandsim.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* NAND flash simulator.
*
@@ -7,20 +8,6 @@
*
* Note: NS means "NAND Simulator".
* Note: Input means input TO flash chip, output means output FROM chip.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#define pr_fmt(fmt) "[nandsim]" fmt
@@ -298,6 +285,8 @@
* The structure which describes all the internal simulator data.
*/
struct nandsim {
+ struct nand_chip chip;
+ struct nand_controller base;
struct mtd_partition partitions[CONFIG_NANDSIM_MAX_PARTS];
unsigned int nbparts;
@@ -364,6 +353,9 @@
void *file_buf;
struct page *held_pages[NS_MAX_HELD_PAGES];
int held_cnt;
+
+ /* debugfs entry */
+ struct dentry *dent;
};
/*
@@ -443,7 +435,7 @@
/* MTD structure for NAND controller */
static struct mtd_info *nsmtd;
-static int nandsim_debugfs_show(struct seq_file *m, void *private)
+static int ns_show(struct seq_file *m, void *private)
{
unsigned long wmin = -1, wmax = 0, avg;
unsigned long deciles[10], decile_max[10], tot = 0;
@@ -494,30 +486,18 @@
return 0;
}
-
-static int nandsim_debugfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, nandsim_debugfs_show, inode->i_private);
-}
-
-static const struct file_operations dfs_fops = {
- .open = nandsim_debugfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(ns);
/**
- * nandsim_debugfs_create - initialize debugfs
- * @dev: nandsim device description object
+ * ns_debugfs_create - initialize debugfs
+ * @ns: nandsim device description object
*
* This function creates all debugfs files for UBI device @ubi. Returns zero in
* case of success and a negative error code in case of failure.
*/
-static int nandsim_debugfs_create(struct nandsim *dev)
+static int ns_debugfs_create(struct nandsim *ns)
{
struct dentry *root = nsmtd->dbg.dfs_dir;
- struct dentry *dent;
/*
* Just skip debugfs initialization when the debugfs directory is
@@ -530,14 +510,19 @@
return 0;
}
- dent = debugfs_create_file("nandsim_wear_report", S_IRUSR,
- root, dev, &dfs_fops);
- if (IS_ERR_OR_NULL(dent)) {
+ ns->dent = debugfs_create_file("nandsim_wear_report", 0400, root, ns,
+ &ns_fops);
+ if (IS_ERR_OR_NULL(ns->dent)) {
NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n");
return -1;
}
return 0;
+}
+
+static void ns_debugfs_remove(struct nandsim *ns)
+{
+ debugfs_remove_recursive(ns->dent);
}
/*
@@ -546,7 +531,7 @@
*
* RETURNS: 0 if success, -ENOMEM if memory alloc fails.
*/
-static int __init alloc_device(struct nandsim *ns)
+static int __init ns_alloc_device(struct nandsim *ns)
{
struct file *cfile;
int i, err;
@@ -558,12 +543,12 @@
if (!(cfile->f_mode & FMODE_CAN_READ)) {
NS_ERR("alloc_device: cache file not readable\n");
err = -EINVAL;
- goto err_close;
+ goto err_close_filp;
}
if (!(cfile->f_mode & FMODE_CAN_WRITE)) {
NS_ERR("alloc_device: cache file not writeable\n");
err = -EINVAL;
- goto err_close;
+ goto err_close_filp;
}
ns->pages_written =
vzalloc(array_size(sizeof(unsigned long),
@@ -571,16 +556,24 @@
if (!ns->pages_written) {
NS_ERR("alloc_device: unable to allocate pages written array\n");
err = -ENOMEM;
- goto err_close;
+ goto err_close_filp;
}
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;
+ goto err_free_pw;
}
ns->cfile = cfile;
+
return 0;
+
+err_free_pw:
+ vfree(ns->pages_written);
+err_close_filp:
+ filp_close(cfile, NULL);
+
+ return err;
}
ns->pages = vmalloc(array_size(sizeof(union ns_mem), ns->geom.pgnum));
@@ -595,22 +588,22 @@
ns->geom.pgszoob, 0, 0, NULL);
if (!ns->nand_pages_slab) {
NS_ERR("cache_create: unable to create kmem_cache\n");
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_free_pg;
}
return 0;
-err_free:
- vfree(ns->pages_written);
-err_close:
- filp_close(cfile, NULL);
+err_free_pg:
+ vfree(ns->pages);
+
return err;
}
/*
* Free any allocated pages, and free the array of page pointers.
*/
-static void free_device(struct nandsim *ns)
+static void ns_free_device(struct nandsim *ns)
{
int i;
@@ -632,7 +625,7 @@
}
}
-static char __init *get_partition_name(int i)
+static char __init *ns_get_partition_name(int i)
{
return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
}
@@ -642,7 +635,7 @@
*
* RETURNS: 0 if success, -ERRNO if failure.
*/
-static int __init init_nandsim(struct mtd_info *mtd)
+static int __init ns_init(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
@@ -654,9 +647,6 @@
NS_ERR("init_nandsim: nandsim is already initialized\n");
return -EIO;
}
-
- /* Force mtd to not do delays */
- chip->chip_delay = 0;
/* Initialize the NAND flash parameters */
ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
@@ -718,7 +708,7 @@
NS_ERR("bad partition size.\n");
return -EINVAL;
}
- ns->partitions[i].name = get_partition_name(i);
+ ns->partitions[i].name = ns_get_partition_name(i);
if (!ns->partitions[i].name) {
NS_ERR("unable to allocate memory.\n");
return -ENOMEM;
@@ -732,12 +722,14 @@
if (remains) {
if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
NS_ERR("too many partitions.\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_partition_names;
}
- ns->partitions[i].name = get_partition_name(i);
+ ns->partitions[i].name = ns_get_partition_name(i);
if (!ns->partitions[i].name) {
NS_ERR("unable to allocate memory.\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_partition_names;
}
ns->partitions[i].offset = next_offset;
ns->partitions[i].size = remains;
@@ -764,33 +756,48 @@
printk("sector address bytes: %u\n", ns->geom.secaddrbytes);
printk("options: %#x\n", ns->options);
- if ((ret = alloc_device(ns)) != 0)
- return ret;
+ ret = ns_alloc_device(ns);
+ if (ret)
+ goto free_partition_names;
/* 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",
ns->geom.pgszoob);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_device;
}
memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
return 0;
+
+free_device:
+ ns_free_device(ns);
+free_partition_names:
+ for (i = 0; i < ARRAY_SIZE(ns->partitions); ++i)
+ kfree(ns->partitions[i].name);
+
+ return ret;
}
/*
* Free the nandsim structure.
*/
-static void free_nandsim(struct nandsim *ns)
+static void ns_free(struct nandsim *ns)
{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ns->partitions); ++i)
+ kfree(ns->partitions[i].name);
+
kfree(ns->buf.byte);
- free_device(ns);
+ ns_free_device(ns);
return;
}
-static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
+static int ns_parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
{
char *w;
int zero_ok;
@@ -818,7 +825,7 @@
return 0;
}
-static int parse_weakblocks(void)
+static int ns_parse_weakblocks(void)
{
char *w;
int zero_ok;
@@ -855,7 +862,7 @@
return 0;
}
-static int erase_error(unsigned int erase_block_no)
+static int ns_erase_error(unsigned int erase_block_no)
{
struct weak_block *wb;
@@ -869,7 +876,7 @@
return 0;
}
-static int parse_weakpages(void)
+static int ns_parse_weakpages(void)
{
char *w;
int zero_ok;
@@ -906,7 +913,7 @@
return 0;
}
-static int write_error(unsigned int page_no)
+static int ns_write_error(unsigned int page_no)
{
struct weak_page *wp;
@@ -920,7 +927,7 @@
return 0;
}
-static int parse_gravepages(void)
+static int ns_parse_gravepages(void)
{
char *g;
int zero_ok;
@@ -957,7 +964,7 @@
return 0;
}
-static int read_error(unsigned int page_no)
+static int ns_read_error(unsigned int page_no)
{
struct grave_page *gp;
@@ -971,25 +978,7 @@
return 0;
}
-static void free_lists(void)
-{
- struct list_head *pos, *n;
- list_for_each_safe(pos, n, &weak_blocks) {
- list_del(pos);
- kfree(list_entry(pos, struct weak_block, list));
- }
- list_for_each_safe(pos, n, &weak_pages) {
- list_del(pos);
- kfree(list_entry(pos, struct weak_page, list));
- }
- list_for_each_safe(pos, n, &grave_pages) {
- list_del(pos);
- kfree(list_entry(pos, struct grave_page, list));
- }
- kfree(erase_block_wear);
-}
-
-static int setup_wear_reporting(struct mtd_info *mtd)
+static int ns_setup_wear_reporting(struct mtd_info *mtd)
{
size_t mem;
@@ -1007,7 +996,7 @@
return 0;
}
-static void update_wear(unsigned int erase_block_no)
+static void ns_update_wear(unsigned int erase_block_no)
{
if (!erase_block_wear)
return;
@@ -1026,7 +1015,7 @@
/*
* Returns the string representation of 'state' state.
*/
-static char *get_state_name(uint32_t state)
+static char *ns_get_state_name(uint32_t state)
{
switch (NS_STATE(state)) {
case STATE_CMD_READ0:
@@ -1086,7 +1075,7 @@
*
* RETURNS: 1 if wrong command, 0 if right.
*/
-static int check_command(int cmd)
+static int ns_check_command(int cmd)
{
switch (cmd) {
@@ -1113,7 +1102,7 @@
/*
* Returns state after command is accepted by command number.
*/
-static uint32_t get_state_by_command(unsigned command)
+static uint32_t ns_get_state_by_command(unsigned command)
{
switch (command) {
case NAND_CMD_READ0:
@@ -1151,7 +1140,7 @@
/*
* Move an address byte to the correspondent internal register.
*/
-static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
+static inline void ns_accept_addr_byte(struct nandsim *ns, u_char bt)
{
uint byte = (uint)bt;
@@ -1169,9 +1158,10 @@
/*
* Switch to STATE_READY state.
*/
-static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
+static inline void ns_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));
+ NS_DBG("switch_to_ready_state: switch to %s state\n",
+ ns_get_state_name(STATE_READY));
ns->state = STATE_READY;
ns->nxstate = STATE_UNKNOWN;
@@ -1228,7 +1218,7 @@
* -1 - several matches.
* 0 - operation is found.
*/
-static int find_operation(struct nandsim *ns, uint32_t flag)
+static int ns_find_operation(struct nandsim *ns, uint32_t flag)
{
int opsfound = 0;
int i, j, idx = 0;
@@ -1281,7 +1271,8 @@
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",
- idx, get_state_name(ns->state), get_state_name(ns->nxstate));
+ idx, ns_get_state_name(ns->state),
+ ns_get_state_name(ns->nxstate));
return 0;
}
@@ -1289,13 +1280,13 @@
/* 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",
- get_state_name(ns->state));
+ ns_get_state_name(ns->state));
ns->npstates = 0;
- return find_operation(ns, 0);
+ return ns_find_operation(ns, 0);
}
NS_DBG("find_operation: no operations found\n");
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return -2;
}
@@ -1312,7 +1303,7 @@
return -1;
}
-static void put_pages(struct nandsim *ns)
+static void ns_put_pages(struct nandsim *ns)
{
int i;
@@ -1321,7 +1312,8 @@
}
/* Get page cache pages in advance to provide NOFS memory allocation */
-static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
+static int ns_get_pages(struct nandsim *ns, struct file *file, size_t count,
+ loff_t pos)
{
pgoff_t index, start_index, end_index;
struct page *page;
@@ -1341,7 +1333,7 @@
page = find_or_create_page(mapping, index, GFP_NOFS);
}
if (page == NULL) {
- put_pages(ns);
+ ns_put_pages(ns);
return -ENOMEM;
}
unlock_page(page);
@@ -1351,35 +1343,37 @@
return 0;
}
-static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
+static ssize_t ns_read_file(struct nandsim *ns, struct file *file, void *buf,
+ size_t count, loff_t pos)
{
ssize_t tx;
int err;
unsigned int noreclaim_flag;
- err = get_pages(ns, file, count, pos);
+ err = ns_get_pages(ns, file, count, pos);
if (err)
return err;
noreclaim_flag = memalloc_noreclaim_save();
tx = kernel_read(file, buf, count, &pos);
memalloc_noreclaim_restore(noreclaim_flag);
- put_pages(ns);
+ ns_put_pages(ns);
return tx;
}
-static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t pos)
+static ssize_t ns_write_file(struct nandsim *ns, struct file *file, void *buf,
+ size_t count, loff_t pos)
{
ssize_t tx;
int err;
unsigned int noreclaim_flag;
- err = get_pages(ns, file, count, pos);
+ err = ns_get_pages(ns, file, count, pos);
if (err)
return err;
noreclaim_flag = memalloc_noreclaim_save();
tx = kernel_write(file, buf, count, &pos);
memalloc_noreclaim_restore(noreclaim_flag);
- put_pages(ns);
+ ns_put_pages(ns);
return tx;
}
@@ -1399,11 +1393,11 @@
return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
}
-static int do_read_error(struct nandsim *ns, int num)
+static int ns_do_read_error(struct nandsim *ns, int num)
{
unsigned int page_no = ns->regs.row;
- if (read_error(page_no)) {
+ if (ns_read_error(page_no)) {
prandom_bytes(ns->buf.byte, num);
NS_WARN("simulating read error in page %u\n", page_no);
return 1;
@@ -1411,7 +1405,7 @@
return 0;
}
-static void do_bit_flips(struct nandsim *ns, int num)
+static void ns_do_bit_flips(struct nandsim *ns, int num)
{
if (bitflips && prandom_u32() < (1 << 22)) {
int flips = 1;
@@ -1431,7 +1425,7 @@
/*
* Fill the NAND buffer with data read from the specified page.
*/
-static void read_page(struct nandsim *ns, int num)
+static void ns_read_page(struct nandsim *ns, int num)
{
union ns_mem *mypage;
@@ -1445,15 +1439,16 @@
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))
+ if (ns_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);
+ tx = ns_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);
+ ns_do_bit_flips(ns, num);
}
return;
}
@@ -1465,17 +1460,17 @@
} else {
NS_DBG("read_page: page %d allocated, reading from %d\n",
ns->regs.row, ns->regs.column + ns->regs.off);
- if (do_read_error(ns, num))
+ if (ns_do_read_error(ns, num))
return;
memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
- do_bit_flips(ns, num);
+ ns_do_bit_flips(ns, num);
}
}
/*
* Erase all pages in the specified sector.
*/
-static void erase_sector(struct nandsim *ns)
+static void ns_erase_sector(struct nandsim *ns)
{
union ns_mem *mypage;
int i;
@@ -1503,7 +1498,7 @@
/*
* Program the specified page with the contents from the NAND buffer.
*/
-static int prog_page(struct nandsim *ns, int num)
+static int ns_prog_page(struct nandsim *ns, int num)
{
int i;
union ns_mem *mypage;
@@ -1522,7 +1517,7 @@
memset(ns->file_buf, 0xff, ns->geom.pgszoob);
} else {
all = 0;
- tx = read_file(ns, ns->cfile, pg_off, num, off);
+ tx = ns_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;
@@ -1532,14 +1527,15 @@
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);
+ tx = ns_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);
+ tx = ns_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;
@@ -1577,7 +1573,7 @@
*
* RETURNS: 0 if success, -1 if error.
*/
-static int do_state_action(struct nandsim *ns, uint32_t action)
+static int ns_do_state_action(struct nandsim *ns, uint32_t action)
{
int num;
int busdiv = ns->busw == 8 ? 1 : 2;
@@ -1604,7 +1600,7 @@
break;
}
num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
- read_page(ns, num);
+ ns_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);
@@ -1647,14 +1643,14 @@
ns->regs.row, NS_RAW_OFFSET(ns));
NS_LOG("erase sector %u\n", erase_block_no);
- erase_sector(ns);
+ ns_erase_sector(ns);
NS_MDELAY(erase_delay);
if (erase_block_wear)
- update_wear(erase_block_no);
+ ns_update_wear(erase_block_no);
- if (erase_error(erase_block_no)) {
+ if (ns_erase_error(erase_block_no)) {
NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
return -1;
}
@@ -1678,7 +1674,7 @@
return -1;
}
- if (prog_page(ns, num) == -1)
+ if (ns_prog_page(ns, num) == -1)
return -1;
page_no = ns->regs.row;
@@ -1690,7 +1686,7 @@
NS_UDELAY(programm_delay);
NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
- if (write_error(page_no)) {
+ if (ns_write_error(page_no)) {
NS_WARN("simulating write failure in page %u\n", page_no);
return -1;
}
@@ -1727,7 +1723,7 @@
/*
* Switch simulator's state.
*/
-static void switch_state(struct nandsim *ns)
+static void ns_switch_state(struct nandsim *ns)
{
if (ns->op) {
/*
@@ -1741,11 +1737,13 @@
NS_DBG("switch_state: operation is known, switch to the next state, "
"state: %s, nxstate: %s\n",
- get_state_name(ns->state), get_state_name(ns->nxstate));
+ ns_get_state_name(ns->state),
+ ns_get_state_name(ns->nxstate));
/* See, whether we need to do some action */
- if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ if ((ns->state & ACTION_MASK) &&
+ ns_do_state_action(ns, ns->state) < 0) {
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
@@ -1759,15 +1757,16 @@
* The only event causing the switch_state function to
* be called with yet unknown operation is new command.
*/
- ns->state = get_state_by_command(ns->regs.command);
+ ns->state = ns_get_state_by_command(ns->regs.command);
NS_DBG("switch_state: operation is unknown, try to find it\n");
- if (find_operation(ns, 0) != 0)
+ if (ns_find_operation(ns, 0))
return;
- if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ if ((ns->state & ACTION_MASK) &&
+ ns_do_state_action(ns, ns->state) < 0) {
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
}
@@ -1795,7 +1794,7 @@
NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
- switch_to_ready_state(ns, status);
+ ns_switch_to_ready_state(ns, status);
return;
} else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
@@ -1809,7 +1808,8 @@
NS_DBG("switch_state: the next state is data I/O, switch, "
"state: %s, nxstate: %s\n",
- get_state_name(ns->state), get_state_name(ns->nxstate));
+ ns_get_state_name(ns->state),
+ ns_get_state_name(ns->nxstate));
/*
* Set the internal register to the count of bytes which
@@ -1872,9 +1872,8 @@
}
}
-static u_char ns_nand_read_byte(struct mtd_info *mtd)
+static u_char ns_nand_read_byte(struct nand_chip *chip)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
u_char outb = 0x00;
@@ -1888,8 +1887,8 @@
return outb;
}
if (!(ns->state & STATE_DATAOUT_MASK)) {
- NS_WARN("read_byte: unexpected data output cycle, state is %s "
- "return %#x\n", get_state_name(ns->state), (uint)outb);
+ NS_WARN("read_byte: unexpected data output cycle, state is %s return %#x\n",
+ ns_get_state_name(ns->state), (uint)outb);
return outb;
}
@@ -1928,15 +1927,14 @@
NS_DBG("read_byte: all bytes were read\n");
if (NS_STATE(ns->nxstate) == STATE_READY)
- switch_state(ns);
+ ns_switch_state(ns);
}
return outb;
}
-static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+static void ns_nand_write_byte(struct nand_chip *chip, u_char byte)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
@@ -1956,12 +1954,12 @@
if (byte == NAND_CMD_RESET) {
NS_LOG("reset chip\n");
- switch_to_ready_state(ns, NS_STATUS_OK(ns));
+ ns_switch_to_ready_state(ns, NS_STATUS_OK(ns));
return;
}
/* Check that the command byte is correct */
- if (check_command(byte)) {
+ if (ns_check_command(byte)) {
NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
return;
}
@@ -1970,7 +1968,7 @@
|| NS_STATE(ns->state) == STATE_DATAOUT) {
int row = ns->regs.row;
- switch_state(ns);
+ ns_switch_state(ns);
if (byte == NAND_CMD_RNDOUT)
ns->regs.row = row;
}
@@ -1985,16 +1983,17 @@
* 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, "
- "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
+ NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, ignore previous states\n",
+ (uint)byte,
+ ns_get_state_name(ns->nxstate));
}
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
}
NS_DBG("command byte corresponding to %s state accepted\n",
- get_state_name(get_state_by_command(byte)));
+ ns_get_state_name(ns_get_state_by_command(byte)));
ns->regs.command = byte;
- switch_state(ns);
+ ns_switch_state(ns);
} else if (ns->lines.ale == 1) {
/*
@@ -2005,11 +2004,13 @@
NS_DBG("write_byte: operation isn't known yet, identify it\n");
- if (find_operation(ns, 1) < 0)
+ if (ns_find_operation(ns, 1) < 0)
return;
- if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ if ((ns->state & ACTION_MASK) &&
+ ns_do_state_action(ns, ns->state) < 0) {
+ ns_switch_to_ready_state(ns,
+ NS_STATUS_FAILED(ns));
return;
}
@@ -2031,20 +2032,20 @@
/* 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, "
- "switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, switch to STATE_READY\n",
+ (uint)byte, ns_get_state_name(ns->nxstate));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
/* Check if this is expected byte */
if (ns->regs.count == ns->regs.num) {
NS_ERR("write_byte: no more address bytes expected\n");
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
- accept_addr_byte(ns, byte);
+ ns_accept_addr_byte(ns, byte);
ns->regs.count += 1;
@@ -2053,7 +2054,7 @@
if (ns->regs.count == ns->regs.num) {
NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
- switch_state(ns);
+ ns_switch_state(ns);
}
} else {
@@ -2063,10 +2064,10 @@
/* 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, "
- "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));
+ NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, switch to %s\n",
+ (uint)byte, ns_get_state_name(ns->state),
+ ns_get_state_name(STATE_READY));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
@@ -2089,51 +2090,23 @@
return;
}
-static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf,
+ int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
- struct nandsim *ns = nand_get_controller_data(chip);
-
- ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
- ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
- ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
-
- if (cmd != NAND_CMD_NONE)
- ns_nand_write_byte(mtd, cmd);
-}
-
-static int ns_device_ready(struct mtd_info *mtd)
-{
- NS_DBG("device_ready\n");
- return 1;
-}
-
-static uint16_t ns_nand_read_word(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
-
- NS_DBG("read_word\n");
-
- return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
-}
-
-static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* 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, "
- "switch to STATE_READY\n", get_state_name(ns->state));
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ NS_ERR("write_buf: data input isn't expected, state is %s, switch to STATE_READY\n",
+ ns_get_state_name(ns->state));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
/* Check if these are expected bytes */
if (ns->regs.count + len > ns->regs.num) {
NS_ERR("write_buf: too many input bytes\n");
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
@@ -2145,9 +2118,8 @@
}
}
-static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{
- struct nand_chip *chip = mtd_to_nand(mtd);
struct nandsim *ns = nand_get_controller_data(chip);
/* Sanity and correctness checks */
@@ -2161,7 +2133,7 @@
}
if (!(ns->state & STATE_DATAOUT_MASK)) {
NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
- get_state_name(ns->state));
+ ns_get_state_name(ns->state));
return;
}
@@ -2169,7 +2141,7 @@
int i;
for (i = 0; i < len; i++)
- buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+ buf[i] = ns_nand_read_byte(chip);
return;
}
@@ -2177,7 +2149,7 @@
/* Check if these are expected bytes */
if (ns->regs.count + len > ns->regs.num) {
NS_ERR("read_buf: too many bytes to read\n");
- switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+ ns_switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
return;
}
@@ -2186,15 +2158,61 @@
if (ns->regs.count == ns->regs.num) {
if (NS_STATE(ns->nxstate) == STATE_READY)
- switch_state(ns);
+ ns_switch_state(ns);
}
return;
}
+static int ns_exec_op(struct nand_chip *chip, const struct nand_operation *op,
+ bool check_only)
+{
+ int i;
+ unsigned int op_id;
+ const struct nand_op_instr *instr = NULL;
+ struct nandsim *ns = nand_get_controller_data(chip);
+
+ if (check_only)
+ return 0;
+
+ ns->lines.ce = 1;
+
+ for (op_id = 0; op_id < op->ninstrs; op_id++) {
+ instr = &op->instrs[op_id];
+ ns->lines.cle = 0;
+ ns->lines.ale = 0;
+
+ switch (instr->type) {
+ case NAND_OP_CMD_INSTR:
+ ns->lines.cle = 1;
+ ns_nand_write_byte(chip, instr->ctx.cmd.opcode);
+ break;
+ case NAND_OP_ADDR_INSTR:
+ ns->lines.ale = 1;
+ for (i = 0; i < instr->ctx.addr.naddrs; i++)
+ ns_nand_write_byte(chip, instr->ctx.addr.addrs[i]);
+ break;
+ case NAND_OP_DATA_IN_INSTR:
+ ns_nand_read_buf(chip, instr->ctx.data.buf.in, instr->ctx.data.len);
+ break;
+ case NAND_OP_DATA_OUT_INSTR:
+ ns_nand_write_buf(chip, instr->ctx.data.buf.out, instr->ctx.data.len);
+ break;
+ case NAND_OP_WAITRDY_INSTR:
+ /* we are always ready */
+ break;
+ }
+ }
+
+ return 0;
+}
+
static int ns_attach_chip(struct nand_chip *chip)
{
unsigned int eccsteps, eccbytes;
+
+ chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
+ chip->ecc.algo = bch ? NAND_ECC_ALGO_BCH : NAND_ECC_ALGO_HAMMING;
if (!bch)
return 0;
@@ -2219,8 +2237,6 @@
return -EINVAL;
}
- chip->ecc.mode = NAND_ECC_SOFT;
- chip->ecc.algo = NAND_ECC_BCH;
chip->ecc.size = 512;
chip->ecc.strength = bch;
chip->ecc.bytes = eccbytes;
@@ -2232,6 +2248,7 @@
static const struct nand_controller_ops ns_controller_ops = {
.attach_chip = ns_attach_chip,
+ .exec_op = ns_exec_op,
};
/*
@@ -2239,139 +2256,163 @@
*/
static int __init ns_init_module(void)
{
+ struct list_head *pos, *n;
struct nand_chip *chip;
- struct nandsim *nand;
- int retval = -ENOMEM, i;
+ struct nandsim *ns;
+ int ret;
if (bus_width != 8 && bus_width != 16) {
NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
return -EINVAL;
}
- /* Allocate and initialize mtd_info, nand_chip and nandsim structures */
- chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
- GFP_KERNEL);
- if (!chip) {
+ ns = kzalloc(sizeof(struct nandsim), GFP_KERNEL);
+ if (!ns) {
NS_ERR("unable to allocate core structures.\n");
return -ENOMEM;
}
+ chip = &ns->chip;
nsmtd = nand_to_mtd(chip);
- nand = (struct nandsim *)(chip + 1);
- nand_set_controller_data(chip, (void *)nand);
+ nand_set_controller_data(chip, (void *)ns);
- /*
- * Register simulator's callbacks.
- */
- chip->cmd_ctrl = ns_hwcontrol;
- chip->read_byte = ns_nand_read_byte;
- chip->dev_ready = ns_device_ready;
- 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;
switch (bbt) {
case 2:
- chip->bbt_options |= NAND_BBT_NO_OOB;
+ chip->bbt_options |= NAND_BBT_NO_OOB;
+ fallthrough;
case 1:
- chip->bbt_options |= NAND_BBT_USE_FLASH;
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+ fallthrough;
case 0:
break;
default:
NS_ERR("bbt has to be 0..2\n");
- retval = -EINVAL;
- goto error;
+ ret = -EINVAL;
+ goto free_ns_struct;
}
/*
* 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;
+ ns->geom.idbytes = 8;
else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
- nand->geom.idbytes = 6;
+ ns->geom.idbytes = 6;
else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
- nand->geom.idbytes = 4;
+ ns->geom.idbytes = 4;
else
- nand->geom.idbytes = 2;
- nand->regs.status = NS_STATUS_OK(nand);
- nand->nxstate = STATE_UNKNOWN;
- nand->options |= OPT_PAGE512; /* temporary value */
- memcpy(nand->ids, id_bytes, sizeof(nand->ids));
+ ns->geom.idbytes = 2;
+ ns->regs.status = NS_STATUS_OK(ns);
+ ns->nxstate = STATE_UNKNOWN;
+ ns->options |= OPT_PAGE512; /* temporary value */
+ memcpy(ns->ids, id_bytes, sizeof(ns->ids));
if (bus_width == 16) {
- nand->busw = 16;
+ ns->busw = 16;
chip->options |= NAND_BUSWIDTH_16;
}
nsmtd->owner = THIS_MODULE;
- if ((retval = parse_weakblocks()) != 0)
- goto error;
+ ret = ns_parse_weakblocks();
+ if (ret)
+ goto free_ns_struct;
- if ((retval = parse_weakpages()) != 0)
- goto error;
+ ret = ns_parse_weakpages();
+ if (ret)
+ goto free_wb_list;
- if ((retval = parse_gravepages()) != 0)
- goto error;
+ ret = ns_parse_gravepages();
+ if (ret)
+ goto free_wp_list;
- chip->dummy_controller.ops = &ns_controller_ops;
- retval = nand_scan(chip, 1);
- if (retval) {
+ nand_controller_init(&ns->base);
+ ns->base.ops = &ns_controller_ops;
+ chip->controller = &ns->base;
+
+ ret = nand_scan(chip, 1);
+ if (ret) {
NS_ERR("Could not scan NAND Simulator device\n");
- goto error;
+ goto free_gp_list;
}
if (overridesize) {
uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
+ struct nand_memory_organization *memorg;
+ u64 targetsize;
+
+ memorg = nanddev_get_memorg(&chip->base);
+
if (new_size >> overridesize != nsmtd->erasesize) {
NS_ERR("overridesize is too big\n");
- retval = -EINVAL;
- goto err_exit;
+ ret = -EINVAL;
+ goto cleanup_nand;
}
+
/* 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;
+ memorg->eraseblocks_per_lun = 1 << overridesize;
+ targetsize = nanddev_target_size(&chip->base);
chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
- chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
+ chip->pagemask = (targetsize >> chip->page_shift) - 1;
}
- if ((retval = setup_wear_reporting(nsmtd)) != 0)
- goto err_exit;
+ ret = ns_setup_wear_reporting(nsmtd);
+ if (ret)
+ goto cleanup_nand;
- if ((retval = init_nandsim(nsmtd)) != 0)
- goto err_exit;
+ ret = ns_init(nsmtd);
+ if (ret)
+ goto free_ebw;
- if ((retval = nand_create_bbt(chip)) != 0)
- goto err_exit;
+ ret = nand_create_bbt(chip);
+ if (ret)
+ goto free_ns_object;
- if ((retval = parse_badblocks(nand, nsmtd)) != 0)
- goto err_exit;
+ ret = ns_parse_badblocks(ns, nsmtd);
+ if (ret)
+ goto free_ns_object;
/* Register NAND partitions */
- retval = mtd_device_register(nsmtd, &nand->partitions[0],
- nand->nbparts);
- if (retval != 0)
- goto err_exit;
+ ret = mtd_device_register(nsmtd, &ns->partitions[0], ns->nbparts);
+ if (ret)
+ goto free_ns_object;
- if ((retval = nandsim_debugfs_create(nand)) != 0)
- goto err_exit;
+ ret = ns_debugfs_create(ns);
+ if (ret)
+ goto unregister_mtd;
return 0;
-err_exit:
- free_nandsim(nand);
- nand_release(chip);
- for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
- kfree(nand->partitions[i].name);
-error:
- kfree(chip);
- free_lists();
+unregister_mtd:
+ WARN_ON(mtd_device_unregister(nsmtd));
+free_ns_object:
+ ns_free(ns);
+free_ebw:
+ kfree(erase_block_wear);
+cleanup_nand:
+ nand_cleanup(chip);
+free_gp_list:
+ list_for_each_safe(pos, n, &grave_pages) {
+ list_del(pos);
+ kfree(list_entry(pos, struct grave_page, list));
+ }
+free_wp_list:
+ list_for_each_safe(pos, n, &weak_pages) {
+ list_del(pos);
+ kfree(list_entry(pos, struct weak_page, list));
+ }
+free_wb_list:
+ list_for_each_safe(pos, n, &weak_blocks) {
+ list_del(pos);
+ kfree(list_entry(pos, struct weak_block, list));
+ }
+free_ns_struct:
+ kfree(ns);
- return retval;
+ return ret;
}
module_init(ns_init_module);
@@ -2383,18 +2424,35 @@
{
struct nand_chip *chip = mtd_to_nand(nsmtd);
struct nandsim *ns = nand_get_controller_data(chip);
- int i;
+ struct list_head *pos, *n;
- free_nandsim(ns); /* Free nandsim private resources */
- nand_release(chip); /* 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();
+ ns_debugfs_remove(ns);
+ WARN_ON(mtd_device_unregister(nsmtd));
+ ns_free(ns);
+ kfree(erase_block_wear);
+ nand_cleanup(chip);
+
+ list_for_each_safe(pos, n, &grave_pages) {
+ list_del(pos);
+ kfree(list_entry(pos, struct grave_page, list));
+ }
+
+ list_for_each_safe(pos, n, &weak_pages) {
+ list_del(pos);
+ kfree(list_entry(pos, struct weak_page, list));
+ }
+
+ list_for_each_safe(pos, n, &weak_blocks) {
+ list_del(pos);
+ kfree(list_entry(pos, struct weak_block, list));
+ }
+
+ kfree(ns);
}
module_exit(ns_cleanup_module);
MODULE_LICENSE ("GPL");
+MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
MODULE_AUTHOR ("Artem B. Bityuckiy");
MODULE_DESCRIPTION ("The NAND flash simulator");
--
Gitblit v1.6.2