⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nandsim.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * NAND flash simulator. * * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org> * * Copyright (C) 2004 Nokia Corporation * * 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 */#include <linux/init.h>#include <linux/types.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/vmalloc.h>#include <asm/div64.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <linux/delay.h>#include <linux/list.h>#include <linux/random.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_LOG#define CONFIG_NANDSIM_LOG        0#endif#ifndef CONFIG_NANDSIM_DBG#define CONFIG_NANDSIM_DBG        0#endifstatic uint first_id_byte  = CONFIG_NANDSIM_FIRST_ID_BYTE;static uint second_id_byte = CONFIG_NANDSIM_SECOND_ID_BYTE;static uint third_id_byte  = CONFIG_NANDSIM_THIRD_ID_BYTE;static uint fourth_id_byte = CONFIG_NANDSIM_FOURTH_ID_BYTE;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 uint log            = CONFIG_NANDSIM_LOG;static uint dbg            = CONFIG_NANDSIM_DBG;static unsigned long parts[MAX_MTD_DEVICES];static unsigned int parts_num;static char *badblocks = NULL;static char *weakblocks = NULL;static char *weakpages = NULL;static unsigned int bitflips = 0;static char *gravepages = NULL;static unsigned int rptwear = 0;static unsigned int overridesize = 0;module_param(first_id_byte,  uint, 0400);module_param(second_id_byte, uint, 0400);module_param(third_id_byte,  uint, 0400);module_param(fourth_id_byte, uint, 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(parts, ulong, &parts_num, 0400);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(rptwear,        uint, 0400);module_param(overridesize,   uint, 0400);MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command");MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");MODULE_PARM_DESC(access_delay,   "Initial page access delay (microiseconds)");MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");MODULE_PARM_DESC(erase_delay,    "Sector erase delay (milliseconds)");MODULE_PARM_DESC(output_cycle,   "Word output (from flash) time (nanodeconds)");MODULE_PARM_DESC(input_cycle,    "Word input (to flash) time (nanodeconds)");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");MODULE_PARM_DESC(weakblocks,     "Weak erase blocks [: remaining erase cycles (defaults to 3)]"				 " separated by commas e.g. 113:2 means eb 113"				 " can be erased only twice before failing");MODULE_PARM_DESC(weakpages,      "Weak pages [: maximum writes (defaults to 3)]"				 " separated by commas e.g. 1401:2 means page 1401"				 " can be written only twice before failing");MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (zero by default)");MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"				 " separated by commas e.g. 1401:2 means page 1401"				 " can be read only twice before failing");MODULE_PARM_DESC(rptwear,        "Number of erases inbetween reporting wear, if not zero");MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "				 "The size is specified in erase blocks and as the exponent of a power of two"				 " e.g. 5 means a size of 32 erase blocks");/* The largest possible page size */#define NS_LARGEST_PAGE_SIZE	2048/* 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(us) \        do { if (do_delays) udelay(us); } while(0)#define NS_MDELAY(us) \        do { if (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)))/* Operation failed completion status */#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))/* Calculate the page offset in flash RAM image by (row, column) address */#define NS_RAW_OFFSET(ns) \	(((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (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 */#define STATE_CMD_READSTART    0x00000003 /* read data second command (large page devices) */#define STATE_CMD_PAGEPROG     0x00000004 /* start page programm */#define STATE_CMD_READOOB      0x00000005 /* read OOB area */#define STATE_CMD_ERASE1       0x00000006 /* sector erase first command */#define STATE_CMD_STATUS       0x00000007 /* read status */#define STATE_CMD_STATUS_M     0x00000008 /* read multi-plane status (isn't implemented) */#define STATE_CMD_SEQIN        0x00000009 /* sequential data imput */#define STATE_CMD_READID       0x0000000A /* read ID */#define STATE_CMD_ERASE2       0x0000000B /* sector erase second command */#define STATE_CMD_RESET        0x0000000C /* reset */#define STATE_CMD_RNDOUT       0x0000000D /* random output command */#define STATE_CMD_RNDOUTSTART  0x0000000E /* random output start command */#define STATE_CMD_MASK         0x0000000F /* command states mask *//* After an address is input, the simulator goes to one of these states */#define STATE_ADDR_PAGE        0x00000010 /* full (row, column) address is accepted */#define STATE_ADDR_SEC         0x00000020 /* sector address was accepted */#define STATE_ADDR_COLUMN      0x00000030 /* column address was accepted */#define STATE_ADDR_ZERO        0x00000040 /* one byte zero address was accepted */#define STATE_ADDR_MASK        0x00000070 /* address states mask *//* Durind data input/output the simulator is in these states */#define STATE_DATAIN           0x00000100 /* waiting for data input */#define STATE_DATAIN_MASK      0x00000100 /* data input states mask */#define STATE_DATAOUT          0x00001000 /* waiting for page data output */#define STATE_DATAOUT_ID       0x00002000 /* waiting for ID bytes output */#define STATE_DATAOUT_STATUS   0x00003000 /* waiting for status output */#define STATE_DATAOUT_STATUS_M 0x00004000 /* waiting for multi-plane status output */#define STATE_DATAOUT_MASK     0x00007000 /* data output states mask *//* Previous operation is done, ready to accept new requests */#define STATE_READY            0x00000000/* This state is used to mark that the next state isn't known yet */#define STATE_UNKNOWN          0x10000000/* Simulator's actions bit masks */#define ACTION_CPY       0x00100000 /* copy page/OOB to the internal buffer */#define ACTION_PRGPAGE   0x00200000 /* programm the internal buffer to flash */#define ACTION_SECERASE  0x00300000 /* erase sector */#define ACTION_ZEROOFF   0x00400000 /* don't add any offset to address */#define ACTION_HALFOFF   0x00500000 /* add to address half of page */#define ACTION_OOBOFF    0x00600000 /* add to address OOB offset */#define ACTION_MASK      0x00700000 /* action mask */#define NS_OPER_NUM      13 /* Number of operations supported by the simulator */#define NS_OPER_STATES   6  /* Maximum number of states in operation */#define OPT_ANY          0xFFFFFFFF /* any chip supports this operation */#define OPT_PAGE256      0x00000001 /* 256-byte  page chips */#define OPT_PAGE512      0x00000002 /* 512-byte  page chips */#define OPT_PAGE2048     0x00000008 /* 2048-byte page chips */#define OPT_SMARTMEDIA   0x00000010 /* SmartMedia technology chips */#define OPT_AUTOINCR     0x00000020 /* page number auto inctimentation is possible */#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */#define OPT_LARGEPAGE    (OPT_PAGE2048) /* 2048-byte page chips */#define OPT_SMALLPAGE    (OPT_PAGE256  | OPT_PAGE512)  /* 256 and 512-byte page chips *//* Remove action bits ftom state */#define NS_STATE(x) ((x) & ~ACTION_MASK)/* * Maximum previous states which need to be saved. Currently saving is * only needed for page programm operation with preceeded read command * (which is only valid for 512-byte pages). */#define NS_MAX_PREVSTATES 1/* * 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 */};/* * The structure which describes all the internal simulator data. */struct nandsim {	struct mtd_partition partitions[MAX_MTD_DEVICES];	unsigned int nbparts;	uint busw;              /* flash chip bus width (8 or 16) */	u_char ids[4];          /* chip's ID bytes */	uint32_t options;       /* chip's characteristic bits */	uint32_t state;         /* current chip state */	uint32_t nxstate;       /* next expected state */	uint32_t *op;           /* current operation, NULL operations isn't known yet  */	uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */	uint16_t npstates;      /* number of previous states saved */	uint16_t stateidx;      /* current state index */	/* The simulated NAND flash pages array */	union ns_mem *pages;	/* Internal buffer of page + OOB size bytes */	union ns_mem buf;	/* NAND flash "geometry" */	struct nandsin_geometry {		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 oobshift;      /* bits number in OOB 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 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 */	} regs;	/* NAND flash lines state */        struct ns_lines_status {                int ce;  /* chip Enable */                int cle; /* command Latch Enable */                int ale; /* address Latch Enable */                int wp;  /* write Protect */        } lines;};/* * Operations array. To perform any operation the simulator must pass * through the correspondent states chain. */static struct nandsim_operations {	uint32_t reqopts;  /* options which are required to perform the operation */	uint32_t states[NS_OPER_STATES]; /* operation's states */} ops[NS_OPER_NUM] = {	/* Read page + OOB from the beginning */	{OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY,			STATE_DATAOUT, STATE_READY}},	/* Read page + OOB from the second half */	{OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY,			STATE_DATAOUT, STATE_READY}},	/* Read OOB */	{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,			STATE_DATAOUT, STATE_READY}},	/* Programm page starting from the beginning */	{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,			STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},	/* Programm page starting from the beginning */	{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},	/* Programm page starting from the second half */	{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},	/* Programm OOB */	{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},	/* Erase sector */	{OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},	/* Read status */	{OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},	/* Read multi-plane status */	{OPT_SMARTMEDIA, {STATE_CMD_STATUS_M, STATE_DATAOUT_STATUS_M, STATE_READY}},	/* Read ID */	{OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},	/* Large page devices read page */	{OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY,			       STATE_DATAOUT, STATE_READY}},	/* Large page devices random page read */	{OPT_LARGEPAGE, {STATE_CMD_RNDOUT, STATE_ADDR_COLUMN, STATE_CMD_RNDOUTSTART | ACTION_CPY,			       STATE_DATAOUT, STATE_READY}},};struct weak_block {	struct list_head list;	unsigned int erase_block_no;	unsigned int max_erases;	unsigned int erases_done;};static LIST_HEAD(weak_blocks);struct weak_page {	struct list_head list;	unsigned int page_no;	unsigned int max_writes;	unsigned int writes_done;};static LIST_HEAD(weak_pages);struct grave_page {	struct list_head list;	unsigned int page_no;	unsigned int max_reads;	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;static unsigned int rptwear_cnt = 0;/* MTD structure for NAND controller */static struct mtd_info *nsmtd;static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];/* * Allocate array of page pointers and initialize the array to NULL * pointers. * * RETURNS: 0 if success, -ENOMEM if memory alloc fails. */static int alloc_device(struct nandsim *ns){	int i;	ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));	if (!ns->pages) {		NS_ERR("alloc_map: unable to allocate page array\n");		return -ENOMEM;	}	for (i = 0; i < ns->geom.pgnum; i++) {		ns->pages[i].byte = NULL;	}	return 0;}/* * Free any allocated pages, and free the array of page pointers. */static void free_device(struct nandsim *ns){	int i;	if (ns->pages) {		for (i = 0; i < ns->geom.pgnum; i++) {			if (ns->pages[i].byte)				kfree(ns->pages[i].byte);		}		vfree(ns->pages);	}}static char *get_partition_name(int i){	char buf[64];	sprintf(buf, "NAND simulator partition %d", i);	return kstrdup(buf, GFP_KERNEL);}static u_int64_t divide(u_int64_t n, u_int32_t d){	do_div(n, d);	return n;}/* * Initialize the nandsim structure. * * RETURNS: 0 if success, -ERRNO if failure. */static int init_nandsim(struct mtd_info *mtd){	struct nand_chip *chip = (struct nand_chip *)mtd->priv;	struct nandsim   *ns   = (struct nandsim *)(chip->priv);	int i, ret = 0;	u_int64_t remains;	u_int64_t next_offset;	if (NS_IS_INITIALIZED(ns)) {		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;	ns->geom.totsz    = mtd->size;	ns->geom.pgsz     = mtd->writesize;	ns->geom.oobsz    = mtd->oobsize;	ns->geom.secsz    = mtd->erasesize;	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;	ns->geom.pgnum    = divide(ns->geom.totsz, ns->geom.pgsz);	ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;	ns->geom.secshift = ffs(ns->geom.secsz) - 1;	ns->geom.pgshift  = chip->page_shift;	ns->geom.oobshift = ffs(ns->geom.oobsz) - 1;	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;	ns->options = 0;	if (ns->geom.pgsz == 256) {		ns->options |= OPT_PAGE256;	}	else if (ns->geom.pgsz == 512) {		ns->options |= (OPT_PAGE512 | OPT_AUTOINCR);		if (ns->busw == 8)			ns->options |= OPT_PAGE512_8BIT;	} else if (ns->geom.pgsz == 2048) {		ns->options |= OPT_PAGE2048;	} else {		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);		return -EIO;	}	if (ns->options & OPT_SMALLPAGE) {		if (ns->geom.totsz <= (32 << 20)) {			ns->geom.pgaddrbytes  = 3;			ns->geom.secaddrbytes = 2;		} else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -