linux/drivers/mtd/nand/raw/nandsim.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * NAND flash simulator.
 *
 * Author: Artem B. Bityuckiy <[email protected]>, <[email protected]>
 *
 * Copyright (C) 2004 Nokia Corporation
 *
 * Note: NS means "NAND Simulator".
 * Note: Input means input TO flash chip, output means output FROM chip.
 */

#define pr_fmt(fmt)

#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/math64.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/sched/mm.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/debugfs.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
#define CONFIG_NANDSIM_SECOND_ID_BYTE
#define CONFIG_NANDSIM_THIRD_ID_BYTE
#define CONFIG_NANDSIM_FOURTH_ID_BYTE
#endif

#ifndef CONFIG_NANDSIM_ACCESS_DELAY
#define CONFIG_NANDSIM_ACCESS_DELAY
#endif
#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
#define CONFIG_NANDSIM_PROGRAMM_DELAY
#endif
#ifndef CONFIG_NANDSIM_ERASE_DELAY
#define CONFIG_NANDSIM_ERASE_DELAY
#endif
#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
#define CONFIG_NANDSIM_OUTPUT_CYCLE
#endif
#ifndef CONFIG_NANDSIM_INPUT_CYCLE
#define CONFIG_NANDSIM_INPUT_CYCLE
#endif
#ifndef CONFIG_NANDSIM_BUS_WIDTH
#define CONFIG_NANDSIM_BUS_WIDTH
#endif
#ifndef CONFIG_NANDSIM_DO_DELAYS
#define CONFIG_NANDSIM_DO_DELAYS
#endif
#ifndef CONFIG_NANDSIM_LOG
#define CONFIG_NANDSIM_LOG
#endif
#ifndef CONFIG_NANDSIM_DBG
#define CONFIG_NANDSIM_DBG
#endif
#ifndef CONFIG_NANDSIM_MAX_PARTS
#define CONFIG_NANDSIM_MAX_PARTS
#endif

static uint access_delay   =;
static uint programm_delay =;
static uint erase_delay    =;
static uint output_cycle   =;
static uint input_cycle    =;
static uint bus_width      =;
static uint do_delays      =;
static uint log            =;
static uint dbg            =;
static unsigned long parts[CONFIG_NANDSIM_MAX_PARTS];
static unsigned int parts_num;
static char *badblocks =;
static char *weakblocks =;
static char *weakpages =;
static unsigned int bitflips =;
static char *gravepages =;
static unsigned int overridesize =;
static char *cache_file =;
static unsigned int bbt;
static unsigned int bch;
static u_char id_bytes[8] =;

module_param_array();
module_param_named(first_id_byte, id_bytes[0], byte, 0400);
module_param_named(second_id_byte, id_bytes[1], byte, 0400);
module_param_named(third_id_byte, id_bytes[2], byte, 0400);
module_param_named(fourth_id_byte, id_bytes[3], byte, 0400);
module_param(access_delay,   uint, 0400);
module_param(programm_delay, uint, 0400);
module_param(erase_delay,    uint, 0400);
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();
module_param(badblocks,      charp, 0400);
module_param(weakblocks,     charp, 0400);
module_param(weakpages,      charp, 0400);
module_param(bitflips,       uint, 0400);
module_param(gravepages,     charp, 0400);
module_param(overridesize,   uint, 0400);
module_param(cache_file,     charp, 0400);
module_param(bbt,	     uint, 0400);
module_param(bch,	     uint, 0400);

MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
/* Page and erase block positions for the following parameters are independent of any partitions */
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();
MODULE_PARM_DESC();

/* The largest possible page size */
#define NS_LARGEST_PAGE_SIZE

/* Simulator's output macros (logging, debugging, warning, error) */
#define NS_LOG(args...)
#define NS_DBG(args...)
#define NS_WARN(args...)
#define NS_ERR(args...)
#define NS_INFO(args...)

/* Busy-wait delay macros (microseconds, milliseconds) */
#define NS_UDELAY(us)
#define NS_MDELAY(us)

/* Is the nandsim structure initialized ? */
#define NS_IS_INITIALIZED(ns)

/* Good operation completion status */
#define NS_STATUS_OK(ns)

/* Operation failed completion status */
#define NS_STATUS_FAILED(ns)

/* Calculate the page offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET(ns)

/* Calculate the OOB offset in flash RAM image by (row, column) address */
#define NS_RAW_OFFSET_OOB(ns)

/* Calculate the byte shift in the next page to access */
#define NS_PAGE_BYTE_SHIFT(ns)

/* After a command is input, the simulator goes to one of the following states */
#define STATE_CMD_READ0
#define STATE_CMD_READ1
#define STATE_CMD_READSTART
#define STATE_CMD_PAGEPROG
#define STATE_CMD_READOOB
#define STATE_CMD_ERASE1
#define STATE_CMD_STATUS
#define STATE_CMD_SEQIN
#define STATE_CMD_READID
#define STATE_CMD_ERASE2
#define STATE_CMD_RESET
#define STATE_CMD_RNDOUT
#define STATE_CMD_RNDOUTSTART
#define STATE_CMD_MASK

/* After an address is input, the simulator goes to one of these states */
#define STATE_ADDR_PAGE
#define STATE_ADDR_SEC
#define STATE_ADDR_COLUMN
#define STATE_ADDR_ZERO
#define STATE_ADDR_MASK

/* During data input/output the simulator is in these states */
#define STATE_DATAIN
#define STATE_DATAIN_MASK

#define STATE_DATAOUT
#define STATE_DATAOUT_ID
#define STATE_DATAOUT_STATUS
#define STATE_DATAOUT_MASK

/* Previous operation is done, ready to accept new requests */
#define STATE_READY

/* This state is used to mark that the next state isn't known yet */
#define STATE_UNKNOWN

/* Simulator's actions bit masks */
#define ACTION_CPY
#define ACTION_PRGPAGE
#define ACTION_SECERASE
#define ACTION_ZEROOFF
#define ACTION_HALFOFF
#define ACTION_OOBOFF
#define ACTION_MASK

#define NS_OPER_NUM
#define NS_OPER_STATES

#define OPT_ANY
#define OPT_PAGE512
#define OPT_PAGE2048
#define OPT_PAGE512_8BIT
#define OPT_PAGE4096
#define OPT_LARGEPAGE
#define OPT_SMALLPAGE

/* Remove action bits from state */
#define NS_STATE(x)

/*
 * Maximum previous states which need to be saved. Currently saving is
 * only needed for page program operation with preceded read command
 * (which is only valid for 512-byte pages).
 */
#define NS_MAX_PREVSTATES

/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
#define NS_MAX_HELD_PAGES

/*
 * A union to represent flash memory contents and flash buffer.
 */
ns_mem;

/*
 * The structure which describes all the internal simulator data.
 */
struct nandsim {};

/*
 * Operations array. To perform any operation the simulator must pass
 * through the correspondent states chain.
 */
static struct nandsim_operations {} ops[NS_OPER_NUM] =;

struct weak_block {};

static LIST_HEAD(weak_blocks);

struct weak_page {};

static LIST_HEAD(weak_pages);

struct grave_page {};

static LIST_HEAD(grave_pages);

static unsigned long *erase_block_wear =;
static unsigned int wear_eb_count =;
static unsigned long total_wear =;

/* MTD structure for NAND controller */
static struct mtd_info *nsmtd;

static int ns_show(struct seq_file *m, void *private)
{}
DEFINE_SHOW_ATTRIBUTE();

/**
 * 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 ns_debugfs_create(struct nandsim *ns)
{}

static void ns_debugfs_remove(struct nandsim *ns)
{}

/*
 * 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 __init ns_alloc_device(struct nandsim *ns)
{}

/*
 * Free any allocated pages, and free the array of page pointers.
 */
static void ns_free_device(struct nandsim *ns)
{}

static char __init *ns_get_partition_name(int i)
{}

/*
 * Initialize the nandsim structure.
 *
 * RETURNS: 0 if success, -ERRNO if failure.
 */
static int __init ns_init(struct mtd_info *mtd)
{}

/*
 * Free the nandsim structure.
 */
static void ns_free(struct nandsim *ns)
{}

static int ns_parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
{}

static int ns_parse_weakblocks(void)
{}

static int ns_erase_error(unsigned int erase_block_no)
{}

static int ns_parse_weakpages(void)
{}

static int ns_write_error(unsigned int page_no)
{}

static int ns_parse_gravepages(void)
{}

static int ns_read_error(unsigned int page_no)
{}

static int ns_setup_wear_reporting(struct mtd_info *mtd)
{}

static void ns_update_wear(unsigned int erase_block_no)
{}

/*
 * Returns the string representation of 'state' state.
 */
static char *ns_get_state_name(uint32_t state)
{}

/*
 * Check if command is valid.
 *
 * RETURNS: 1 if wrong command, 0 if right.
 */
static int ns_check_command(int cmd)
{}

/*
 * Returns state after command is accepted by command number.
 */
static uint32_t ns_get_state_by_command(unsigned command)
{}

/*
 * Move an address byte to the correspondent internal register.
 */
static inline void ns_accept_addr_byte(struct nandsim *ns, u_char bt)
{}

/*
 * Switch to STATE_READY state.
 */
static inline void ns_switch_to_ready_state(struct nandsim *ns, u_char status)
{}

/*
 * If the operation isn't known yet, try to find it in the global array
 * of supported operations.
 *
 * Operation can be unknown because of the following.
 *   1. New command was accepted and this is the first call to find the
 *      correspondent states chain. In this case ns->npstates = 0;
 *   2. There are several operations which begin with the same command(s)
 *      (for example program from the second half and read from the
 *      second half operations both begin with the READ1 command). In this
 *      case the ns->pstates[] array contains previous states.
 *
 * Thus, the function tries to find operation containing the following
 * states (if the 'flag' parameter is 0):
 *    ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
 *
 * If (one and only one) matching operation is found, it is accepted (
 * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
 * zeroed).
 *
 * If there are several matches, the current state is pushed to the
 * ns->pstates.
 *
 * The operation can be unknown only while commands are input to the chip.
 * As soon as address command is accepted, the operation must be known.
 * In such situation the function is called with 'flag' != 0, and the
 * operation is searched using the following pattern:
 *     ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
 *
 * It is supposed that this pattern must either match one operation or
 * none. There can't be ambiguity in that case.
 *
 * If no matches found, the function does the following:
 *   1. if there are saved states present, try to ignore them and search
 *      again only using the last command. If nothing was found, switch
 *      to the STATE_READY state.
 *   2. if there are no saved states, switch to the STATE_READY state.
 *
 * RETURNS: -2 - no matched operations found.
 *          -1 - several matches.
 *           0 - operation is found.
 */
static int ns_find_operation(struct nandsim *ns, uint32_t flag)
{}

static void ns_put_pages(struct nandsim *ns)
{}

/* Get page cache pages in advance to provide NOFS memory allocation */
static int ns_get_pages(struct nandsim *ns, struct file *file, 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)
{}

static ssize_t ns_write_file(struct nandsim *ns, struct file *file, void *buf,
			     size_t count, loff_t pos)
{}

/*
 * Returns a pointer to the current page.
 */
static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
{}

/*
 * Retuns a pointer to the current byte, within the current page.
 */
static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
{}

static int ns_do_read_error(struct nandsim *ns, int num)
{}

static void ns_do_bit_flips(struct nandsim *ns, int num)
{}

/*
 * Fill the NAND buffer with data read from the specified page.
 */
static void ns_read_page(struct nandsim *ns, int num)
{}

/*
 * Erase all pages in the specified sector.
 */
static void ns_erase_sector(struct nandsim *ns)
{}

/*
 * Program the specified page with the contents from the NAND buffer.
 */
static int ns_prog_page(struct nandsim *ns, int num)
{}

/*
 * If state has any action bit, perform this action.
 *
 * RETURNS: 0 if success, -1 if error.
 */
static int ns_do_state_action(struct nandsim *ns, uint32_t action)
{}

/*
 * Switch simulator's state.
 */
static void ns_switch_state(struct nandsim *ns)
{}

static u_char ns_nand_read_byte(struct nand_chip *chip)
{}

static void ns_nand_write_byte(struct nand_chip *chip, u_char byte)
{}

static void ns_nand_write_buf(struct nand_chip *chip, const u_char *buf,
			      int len)
{}

static void ns_nand_read_buf(struct nand_chip *chip, u_char *buf, int len)
{}

static int ns_exec_op(struct nand_chip *chip, const struct nand_operation *op,
		      bool check_only)
{}

static int ns_attach_chip(struct nand_chip *chip)
{}

static const struct nand_controller_ops ns_controller_ops =;

/*
 * Module initialization function
 */
static int __init ns_init_module(void)
{}

module_init();

/*
 * Module clean-up function
 */
static void __exit ns_cleanup_module(void)
{}

module_exit(ns_cleanup_module);

MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_DESCRIPTION();