drivers/mtd/mtd_nandram: Adds virtual NAND Flash device simulator.

Adds virtual NAND Flash device simulator, NAND flash log wrapper, and documentation for it.

Signed-off-by: Saurav Pal <resyfer.dev@gmail.com>
This commit is contained in:
Saurav Pal 2024-03-04 06:04:05 +00:00 committed by Alan Carvalho de Assis
parent 3b3f2d97e9
commit 1bec133385
10 changed files with 1327 additions and 3 deletions

View File

@ -0,0 +1,171 @@
======================================
``nand`` - NAND Flash Device Simulator
======================================
In order to test the filesystems that work with NAND flash devices in a
simulator, this exists to provide a virtual NAND flash device, along with its
driver, to allow manual (or scripted) testing, as well as to provide an
option to log the various actions performed under-the-hood along with the
state of the device, which includes the read, write and erase counts of each
page in the device.
Structure of NAND Flash
=======================
Most NAND flashes share a common interface, specified by the
`Open NAND Flash Interface (ONFI) <https://www.onfi.org/>`_.
The important part from it, required in this context, is that a NAND Flash is
divided into a lot of blocks. And each blocks are divided into a lot of
pages.
Here's the peculiar bit. If you want to erase a page, you need to erase
the *entire* block that it is part of, ie. blocks are the smallest erasable
units in a NAND flash. However, a page is the smallest unit to which you can
write data, or read data from.
Why would you need erase operation? The Program/ Erase (P/E) cycle states
that a page (and thus its block) need to be erased first before data can be
written to it (Erase-Before-Write).
Each page has a data area, and a spare area. Depending on the data area's
size, the spare area may have different structures (schemes). All the
required schemes are defined in ``/drivers/mtd/mtd_nandscheme.c`` (in
the ``g_nand_sparescheme*`` structures).
Due to the nature of NAND flash, upon testing, a manufaturer may decide that
a certain block fails some test(s), and mark it as a **bad block** by
writing a certain value in a certain position in the spare area (depends on
data area's size, and thus, the spare area's scheme) of every page in it.
.. NOTE::
* While certain blocks may *still work* even if they are marked as bad,
it's inadvisable to store any data in it.
* The spare data is the **only** record of a block being bad or not.
Please do not erase it.
* Certain blocks may become bad after continuous usage, and would need
to be marked as such by either the filesystem or the driver.
Currently, this simulator supports only 512 B sized pages, which means it
will follow the ``g_nand_sparescheme512`` scheme for its spare area, and
thus have a bad block marker at index ``5``.
If a block is *not* bad, it contains a value of ``0xff`` in the place of a
bad block marker. Any other value denote it's a bad block.
RAM to Device (Lower Half)
==========================
Since this is an emulation, RAM of the host running the simulator is used
to create the device. While the speed of operations won't be even close to
the original, this being in the RAM, which works multitudes faster than
actual device, the functionality on the other hand has been kept consistent
to the utmost.
First, ``/include/nuttx/mtd/nand.h`` has a structure ``struct nand_dev_s``
defining a raw NAND MTD device (lowest level). Its field ``nand_dev_s->raw``
is of type ``struct nand_raw_s *`` (defined in
``include/nuttx/mtd/nand_raw.h``), and this is what will hold the methods
for the raw device. There are primarily 3 methods that need to be looked
into:
* eraseblock
* rawread
* rawwrite
Conforming to the functionality of NAND flashes, these three were implemented
as ``nand_ram_*`` in ``/drivers/mtd/nand_ram.c`` to emulate RAM into a
virtual NAND flash.
While in real devices, the spare area follows the data area (in most schemes)
, since this is virtual, we can get away with keeping the two into two
separate arrays, namely ``nand_ram_flash_data`` and ``nand_ram_flash_spare``
for data and spare respectively. Each array has as many elements as number
of pages in the device.
As the spare areas has some spare bytes we can use, some space is used as
counters for the reads/writes/erases each page faces, thus giving a clear
picture of wear of the virtual device to the tester.
.. NOTE::
ECC extension has not been implemented yet, so ECC bits in spare are
yet to be used or initialized properly.
The method ``nand_ram_initialize()`` takes in a preallocated space for a
raw device (of type ``struct nand_raw_s`` as defined in
``include/nuttx/mtd/nand_raw.h``) and attaches these 3 custom methods as well
as device information like page size, block size, etc. to it. These form
the lower half of the driver.
Upper Half
==========
The method ``nand_ram_initialize()`` also initializes a
``struct mtd_dev_s *`` (defined in ``include/nuttx/mtd/mtd.h``), which it
returns. This structure contains a reference to our custom lower half in
``mtd_dev_s->raw``, as well as an upper half containing methods ``nand_*``
(defined in ``drivers/mtd/mtd_nand.c``).
Wrapper Over Upper Half
=======================
The upper half, along with the lower half attached to it, received from
``nand_ram_initialize()`` contains these 5 methods for the upper half:
* erase
* bread
* bwrite
* ioctl
* isbad
* markbad
Each driver's upper half needs to be registered with NuttX before it can
appear in the list of devices (in ``/dev``). Instead of the previously
acquired upper-half, we'll be registering a wrapper over it, to improve
logging. The wrapper methods are defined as ``nand_wrapper_*`` in
``drivers/mtd/mtd_nandwrapper.c``.
Here's a complicated bit. The actual upper half is an MTD device, but
more specifically, it is a NAND MTD device, which is represented by
``struct nand_dev_s``. Due to how it is defined, ``struct mtd_dev_s`` forms
the very start of ``struct nand_dev_s``, and hence they can be type-casted
to each other (provided required memory is accessible). Our wrapper, being a
wrapper over an MTD device, is an MTD device itself as well. MTD device
methods take in a ``struct mtd_dev_s *dev`` which describe the device
itself (which is the actual device that is registered using
``register_mtddriver``), which includes its methods. Our wrapper methods
receive such a device as well, which contains the wrapper device including
the wrapper functions. But, this way, there is no way of accessing the
methods of the actual upper half itself. Thus, instead of ``dev`` being
of type ``struct nand_dev_s``, it is actually of type
``struct nand_wrapper_dev_s`` which is a superset of ``struct nand_dev_s``,
who itself is a superset of ``struct mtd_dev_s``. Similar to previous case,
``struct mtd_dev_s`` forms the very start of ``struct nand_wrapper_dev_s``,
and thus the types are inter-changeable.
The methods ``nand_wrapper_*`` in ``drivers/mtd/mtd_nandwrapper.c`` all
pass the parameters to corresponding method of the actual upper half
after logging it. *But, the device passed on to the actual upper half
is still the wrapper, not the actual upper half, as the upper half methods
may call the other methods as well internally and we might want to log
them as well*.
Registering Device & Daemon
===========================
This wrapper is then registered using ``register_mtddriver``, and this
whole thing is converted to be a daemon, so that the device can keep running
in the background.
Making it a daemon is achieved by using ``fork()``, killing the parent, and
using ``daemon()`` in child.
Known Issues
============
* ECC is not implemented yet.
* MLC NAND Flash is not implemented yet.
* Due to the fixed name of the device, there can't be more than one instance
of this virtual device.

View File

@ -271,6 +271,71 @@ config MTD_NAND_EMBEDDEDECC
only one supported) is Micron, 4-bit ECC, device size = 1Gb or 2Gb
or 4Gb.
config MTD_NAND_RAM
bool "Enable virtual NAND Flash"
default n
---help---
Enable a virtual NAND Flash device emulated from RAM in the simulator.
if MTD_NAND_RAM
config MTD_NAND_RAM_SIZE
int "Size of the virtual NAND Flash in MB."
default 2
---help---
Size of the virtual NAND Flash in megabytes.
config MTD_NAND_RAM_DEBUG
bool "Enable debugging of virtual NAND Flash."
default n
---help---
Enables debug info being written to syslog for virtual NAND Flash
device emulated from RAM in the simulator.
config MTD_NAND_RAM_DEBUG_LEVEL
int "Debugging level of virtual NAND Flash raw lower half operations."
depends on MTD_NAND_RAM_DEBUG
default 1
range 1 3
---help---
1 - Log every instruction.
2 - Log every 5 instructions.
3 - Log every 10 instructions.
config MTD_NAND_RAM_STATUS
int "Log status of virtual NAND Flash."
depends on MTD_NAND_RAM_DEBUG
default 3
range 1 8
---help---
1 - Log every instruction.
2 - Log every 5 instructions.
3 - Log every 10 instructions.
4 - Log every 50 instructions.
5 - Log every 100 instructions.
6 - Log every 500 instructions.
7 - Log every 1000 instructions.
8 - Log every 5000 instructions.
endif #MTD_NAND_RAM
config MTD_NAND_WRAPPER
bool "Enable logging wrapper for NAND flash upper half operations."
default n
if MTD_NAND_WRAPPER
config MTD_NAND_WRAPPER_DEBUG_LEVEL
int "Log level of upper half of virtual NAND Flash."
default 1
range 1 3
---help---
1 - Log every instruction.
2 - Log every 5 instructions.
3 - Log every 10 instructions.
endif # MTD_NAND_WRAPPER
endif # MTD_NAND
config RPMSGMTD

View File

@ -60,6 +60,15 @@ CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandmodel.c mtd_modeltab.c
ifeq ($(CONFIG_MTD_NAND_SWECC),y)
CSRCS += mtd_nandecc.c hamming.c
endif
ifeq ($(CONFIG_MTD_NAND_RAM), y)
CSRCS += mtd_nandram.c
endif
ifeq ($(CONFIG_MTD_NAND_WRAPPER), y)
CSRCS += mtd_nandwrapper.c
endif
endif
ifeq ($(CONFIG_RAMMTD),y)

View File

@ -44,6 +44,7 @@
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <stdio.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fs/ioctl.h>

475
drivers/mtd/mtd_nandram.c Normal file
View File

@ -0,0 +1,475 @@
/****************************************************************************
* drivers/mtd/mtd_nandram.c
* This file deals with the raw lower half of the device driver, and manages
* reading and writing to the actual NAND Flash device that has been emulated
* from RAM.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stddef.h>
#include <nuttx/compiler.h>
#include <nuttx/mutex.h>
#include <nuttx/mtd/nand_ram.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_MTD_NAND_RAM_DEBUG
#define NAND_RAM_DEBUG_1 1
#define NAND_RAM_DEBUG_2 5
#define NAND_RAM_DEBUG_3 10
#define NAND_RAM_STATUS_1 1
#define NAND_RAM_STATUS_2 5
#define NAND_RAM_STATUS_3 10
#define NAND_RAM_STATUS_4 50
#define NAND_RAM_STATUS_5 100
#define NAND_RAM_STATUS_6 500
#define NAND_RAM_STATUS_7 1000
#define NAND_RAM_STATUS_8 5000
#if CONFIG_MTD_NAND_RAM_DEBUG_LEVEL == 1
#define NAND_RAM_DEBUG_LEVEL NAND_RAM_DEBUG_1
#elif CONFIG_MTD_NAND_RAM_DEBUG_LEVEL == 2
#define NAND_RAM_DEBUG_LEVEL NAND_RAM_DEBUG_2
#elif CONFIG_MTD_NAND_RAM_DEBUG_LEVEL == 3
#define NAND_RAM_DEBUG_LEVEL NAND_RAM_DEBUG_3
#endif /* CONFIG_MTD_NAND_RAM_DEBUG_LEVEL */
#if CONFIG_MTD_NAND_RAM_STATUS == 1
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_1
#elif CONFIG_MTD_NAND_RAM_STATUS == 2
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_2
#elif CONFIG_MTD_NAND_RAM_STATUS == 3
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_3
#elif CONFIG_MTD_NAND_RAM_STATUS == 4
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_4
#elif CONFIG_MTD_NAND_RAM_STATUS == 5
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_5
#elif CONFIG_MTD_NAND_RAM_STATUS == 6
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_6
#elif CONFIG_MTD_NAND_RAM_STATUS == 7
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_7
#elif CONFIG_MTD_NAND_RAM_STATUS == 8
#define NAND_RAM_STATUS_LEVEL NAND_RAM_STATUS_8
#endif /* CONFIG_MTD_NAND_RAM_STATUS */
#define NAND_RAM_LOG(str, ...) \
{ \
if (nand_ram_ins_i % NAND_RAM_DEBUG_LEVEL == 0) \
{ \
syslog(LOG_DEBUG, "nand_ram: " str, __VA_ARGS__); \
} \
} \
#define NAND_RAM_STATUS_LOG(str, ...) \
syslog(LOG_DEBUG, "nand_ram_status: " str, __VA_ARGS__);
#else
#define NAND_RAM_LOG
#define NAND_RAM_STATUS_LOG
#endif /* CONFIG_MTD_NAND_RAM_DEBUG */
/****************************************************************************
* Private Types
****************************************************************************/
struct nand_ram_data_s
{
uint8_t page[NAND_RAM_PAGE_SIZE / 8];
};
/* 512 B page spare scheme */
struct nand_ram_spare_s
{
uint8_t ecc_0; /* 0 */
uint8_t ecc_1;
uint8_t ecc_2;
uint8_t ecc_3;
uint8_t __res1;
uint8_t bad; /* 5 */ /* NAND_RAM_BLOCK_* */
uint8_t ecc_4;
uint8_t ecc_5;
/* Using reserved (8 bytes) */
uint16_t n_read;
uint16_t n_write; /* 10 */
uint16_t n_erase;
uint8_t free; /* Erased page: NAND_RAM_PAGE_* */
uint8_t __res2;
};
/****************************************************************************
* Private Data
****************************************************************************/
static uint64_t nand_ram_ins_i = 0; /* Instruction counter */
static mutex_t nand_ram_dev_mut;
static struct nand_ram_data_s nand_ram_flash_data[NAND_RAM_N_PAGES];
static struct nand_ram_spare_s nand_ram_flash_spare[NAND_RAM_N_PAGES];
/* Hard coded array for bad block indexes */
static int g_nand_ram_rand_bad_blk_indx[] =
{
4, 14, 19, 21, 28, 30, 107,
108, 164, 173, 179, 229, 268,
362, 377, 382, 396, 410, 412,
419, 428, 456, 500, 0
};
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* External Functions
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nand_ram_storage_status
*
* Description:
* Writes per-page status of virtual NAND Flash.
*
****************************************************************************/
static void nand_ram_storage_status(void)
{
uint32_t i;
uint16_t reads;
uint16_t writes;
uint16_t erases;
uint8_t bad;
/* Wear */
for (i = 0; i < NAND_RAM_N_PAGES; i++)
{
reads = nand_ram_flash_spare[i].n_read;
writes = nand_ram_flash_spare[i].n_write;
erases = nand_ram_flash_spare[i].n_erase;
bad = (nand_ram_flash_spare[i].bad != NAND_RAM_BLOCK_GOOD);
NAND_RAM_STATUS_LOG(
"Block %3d, Page %6d, Bad: %1d |"
" Reads: %6d, Writes: %6d, Erases: %6d\n",
i >> NAND_RAM_LOG_PAGES_PER_BLOCK, i, bad,
reads, writes, erases);
}
return;
}
static inline void nand_ram_status(void)
{
if (nand_ram_ins_i % NAND_RAM_STATUS_LEVEL == 0)
{
nand_ram_storage_status();
}
}
/****************************************************************************
* Name: nand_ram_storage_init
*
* Description:
* Initializes the actual NAND Device that is emulated from RAM.
*
****************************************************************************/
static void nand_ram_storage_init(void)
{
int i;
memset(nand_ram_flash_data, 0xff,
sizeof(struct nand_ram_data_s) * NAND_RAM_N_PAGES);
memset(nand_ram_flash_spare, 0,
sizeof(struct nand_ram_spare_s) * NAND_RAM_N_PAGES);
for (i = 0; i < NAND_RAM_N_PAGES; i++)
{
nand_ram_flash_spare[i].free = NAND_RAM_PAGE_FREE;
nand_ram_flash_spare[i].bad = NAND_RAM_BLOCK_GOOD;
}
/* Bad blocks */
for (i = 0;
g_nand_ram_rand_bad_blk_indx[i] != 0 &&
g_nand_ram_rand_bad_blk_indx[i] < NAND_RAM_N_BLOCKS;
i++)
{
int j;
for (j = 0; j < NAND_RAM_PAGES_PER_BLOCK; j++)
{
int page = (g_nand_ram_rand_bad_blk_indx[i] <<
NAND_RAM_LOG_PAGES_PER_BLOCK)+j;
/* Set bad block marker to Anything but NAND_RAM_BLOCK_GOOD */
nand_ram_flash_spare[page].bad = 0;
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nand_ram_eraseblock
*
* Description:
* Erases a block on the device.
*
* Input Parameters:
* raw: NAND MTD Device raw structure.
* block: Block number (0 indexing) to erase
*
* Returned Value:
* 0: Successful
* < 0: Error
*
****************************************************************************/
int nand_ram_eraseblock(FAR struct nand_raw_s *raw, off_t block)
{
int i;
uint32_t start_page;
uint32_t end_page;
start_page = block << NAND_RAM_LOG_PAGES_PER_BLOCK;
end_page = start_page + NAND_RAM_PAGES_PER_BLOCK;
nxmutex_lock(&nand_ram_dev_mut);
nand_ram_ins_i++;
NAND_RAM_LOG(
"[LOWER %lu | %s] Block %d, Start Page: %d, Last Page: %d",
nand_ram_ins_i, "eraseblock", block, start_page, end_page - 1
);
nand_ram_status();
/* [start_page, end_page) is cleared (all bits are set) */
memset(nand_ram_flash_data + start_page, 0xff,
(end_page - start_page) * sizeof(struct nand_ram_data_s));
for (i = start_page; i < end_page; i++)
{
nand_ram_flash_spare[i].n_erase++;
nand_ram_flash_spare[i].free = 1;
}
NAND_RAM_LOG("[LOWER %lu | %s] Done\n", nand_ram_ins_i, "eraseblock");
nxmutex_unlock(&nand_ram_dev_mut);
return OK;
}
/****************************************************************************
* Name: nand_ram_rawread
*
* Description:
* Reads a page from the device.
*
* Input Parameters:
* raw: NAND MTD Device raw structure.
* block: Block number (0 indexing) to erase
* page: Page number (0 indexing) in (relative to) that block
* data: Preallocated memory where the data will be copied to
* spare: Preallocated memory where the spare data will be copied to
*
* Returned Value:
* 0: Successful
*
****************************************************************************/
int nand_ram_rawread(FAR struct nand_raw_s *raw, off_t block,
unsigned int page, FAR void *data, FAR void *spare)
{
int ret;
uint32_t read_page;
struct nand_ram_data_s *read_page_data;
struct nand_ram_spare_s *read_page_spare;
read_page = (block << NAND_RAM_LOG_PAGES_PER_BLOCK) + page;
read_page_data = nand_ram_flash_data + read_page;
read_page_spare = nand_ram_flash_spare + read_page;
ret = OK;
nxmutex_lock(&nand_ram_dev_mut);
nand_ram_ins_i++;
NAND_RAM_LOG("[LOWER %lu | %s] Page %d\n",
nand_ram_ins_i, "rawread", read_page);
nand_ram_status();
if (nand_ram_flash_spare[read_page].bad != NAND_RAM_BLOCK_GOOD)
{
ret = -EFAULT;
NAND_RAM_LOG("[LOWER %lu | %s] Failed: %s\n",
nand_ram_ins_i, "rawread", EFAULT_STR);
goto errout;
}
nand_ram_flash_spare[read_page].n_read++;
if (data != NULL)
{
memcpy(data, (const void *)read_page_data, NAND_RAM_PAGE_SIZE);
}
if (spare != NULL)
{
memcpy(spare, (const void *)read_page_spare, NAND_RAM_PAGE_SIZE);
}
NAND_RAM_LOG("[LOWER %lu | %s] Done\n", nand_ram_ins_i, "rawread");
errout:
nxmutex_unlock(&nand_ram_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_ram_rawread
*
* Description:
* Writes a page to the device.
*
* Input Parameters:
* raw: NAND MTD Device raw structure.
* block: Block number (0 indexing) to erase
* page: Page number (0 indexing) in (relative to) that block
* data: Preallocated memory where the data will be copied to
* spare: Preallocated memory where the spare data will be copied to
*
* Returned Value:
* 0: Successful
* -EACCESS: The page's block needs to be erased first before writing to it
*
****************************************************************************/
int nand_ram_rawwrite(FAR struct nand_raw_s *raw, off_t block,
unsigned int page, FAR const void *data,
FAR const void *spare)
{
int ret;
uint32_t write_page;
struct nand_ram_data_s *write_page_data;
struct nand_ram_spare_s *write_page_spare;
write_page = (block << NAND_RAM_LOG_PAGES_PER_BLOCK) + page;
write_page_data = nand_ram_flash_data + write_page;
write_page_spare = nand_ram_flash_spare + write_page;
ret = OK;
nxmutex_lock(&nand_ram_dev_mut);
nand_ram_ins_i++;
NAND_RAM_LOG("[LOWER %lu | %s] Page %d\n",
nand_ram_ins_i, "rawwrite", write_page);
nand_ram_status();
if (nand_ram_flash_spare[write_page].free != NAND_RAM_PAGE_FREE)
{
ret = -EACCES;
NAND_RAM_LOG("[LOWER %lu | %s] Failed: %s\n",
nand_ram_ins_i, "rawwrite", EACCES_STR);
goto errout;
}
nand_ram_flash_spare[write_page].n_write++;
if (data != NULL)
{
memcpy((void *)write_page_data, data, NAND_RAM_PAGE_SIZE);
}
if (spare != NULL)
{
memcpy((void *)write_page_spare, data, NAND_RAM_PAGE_SIZE);
}
NAND_RAM_LOG("[LOWER %lu | %s] Done\n", nand_ram_ins_i, "rawwrite");
errout:
nxmutex_unlock(&nand_ram_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_ram_init
*
* Description:
* Driver init.
*
* Input Parameters:
* raw: NAND MTD Device raw structure.
*
* Returned Value:
* A non-NULL MTD driver instance is returned on success. NULL is
* returned on any failure.
*
****************************************************************************/
FAR struct mtd_dev_s *nand_ram_initialize(struct nand_raw_s *raw)
{
NAND_RAM_LOG("[LOWER | %s]\n", "initialize");
nand_ram_storage_init();
nxmutex_init(&nand_ram_dev_mut);
raw->model.devid = 123;
raw->model.pagesize = NAND_RAM_PAGE_SIZE;
raw->model.sparesize = NAND_RAM_SPARE_SIZE;
raw->model.devsize = NAND_RAM_SIZE / (1024 * 1024);
raw->model.blocksize = NAND_RAM_BLOCK_SIZE / 1024;
raw->model.scheme = &g_nand_sparescheme512;
raw->eraseblock = nand_ram_eraseblock;
raw->rawread = nand_ram_rawread;
raw->rawwrite = nand_ram_rawwrite;
return nand_raw_initialize(raw);
}

View File

@ -0,0 +1,418 @@
/****************************************************************************
* drivers/mtd/mtd_nandwrapper.c
* This deals with the wrapper over the upper half of the driver, to enable
* logging for debugging, and essentially passes the parameters right to the
* actual upper half of the NAND Flash device driver without changing them.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <assert.h>
#include <stddef.h>
#include <nuttx/config.h>
#include <nuttx/mtd/nand.h>
#include <nuttx/mtd/nand_ram.h>
#include <nuttx/mtd/nand_scheme.h>
#include <nuttx/mtd/nand_wrapper.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NAND_WRAPPER_DEBUG_1 1
#define NAND_WRAPPER_DEBUG_2 5
#define NAND_WRAPPER_DEBUG_3 10
#if CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL == 1
#define NAND_WRAPPER_DEBUG_LEVEL NAND_WRAPPER_DEBUG_1
#elif CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL == 2
#define NAND_WRAPPER_DEBUG_LEVEL NAND_WRAPPER_DEBUG_2
#elif CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL == 3
#define NAND_WRAPPER_DEBUG_LEVEL NAND_WRAPPER_DEBUG_3
#endif /* CONFIG_MTD_NAND_WRAPPER_DEBUG_LEVEL */
#define NAND_WRAPPER_LOG(str, ...) \
{ \
if(nand_wrapper_ins_i % NAND_WRAPPER_DEBUG_LEVEL == 0) \
{ \
syslog(LOG_DEBUG, "nand_wrapper: " str, __VA_ARGS__); \
} \
}
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static uint64_t nand_wrapper_ins_i = 0; /* Instruction counter */
static mutex_t nand_wrapper_dev_mut;
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* External Functions
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nand_wrapper_erase
*
* Description:
* Wrapper for NAND MTD erase method.
*
* Input Parameters:
* dev: NAND MTD Device (with an actual type of `nand_wrapper_dev_s`
* startblock: Block number (0-indexing) to start erasing
* nblocks: Number of blocks to erase
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_erase(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %lu | %s] Startblock: %d, N Blocks: %ld\n",
nand_wrapper_ins_i, "erase", startblock, nblocks);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.erase);
ret = nand_dev->under.mtd.erase(dev, startblock, nblocks);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Done\n",
nand_wrapper_ins_i, "erase");
}
else
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Failed: %d!\n",
nand_wrapper_ins_i, "erase", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_bread
*
* Description:
* Wrapper for NAND MTD bread method.
*
* Input Parameters:
* dev: MTD Device
* startpage: Page number (0-indexing) to start reading
* npages: Number of pages to read.
* buffer: Preallocated memory where the data will be copied to
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
ssize_t nand_wrapper_bread(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR uint8_t *buffer)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %lu | %s] "
"Startblock: %d, N Pages: %ld, Buffer: %p\n",
nand_wrapper_ins_i, "bread", startpage, npages, buffer);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.bread);
ret = nand_dev->under.mtd.bread(dev, startpage, npages, buffer);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Done\n",
nand_wrapper_ins_i, "bread");
}
else
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Failed: %d!\n",
nand_wrapper_ins_i, "bread", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_bwrite
*
* Description:
* Wrapper for NAND MTD bwrite method.
*
* Input Parameters:
* dev: MTD Device
* startpage: Page number (0-indexing) to start reading
* npages: Number of pages to read.
* buffer: Data which will be written to the device
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes the length of `buffer` would be the same as the size of
* `npages * block_size`. This also assumes `dev` is specifically of
* type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
ssize_t nand_wrapper_bwrite(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR const uint8_t *buffer)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %lu | %s] "
"Startblock: %d, N Pages: %ld, Buffer: %p \n",
nand_wrapper_ins_i, "bwrite", startpage, npages, buffer);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.bwrite);
ret = nand_dev->under.mtd.bwrite(dev, startpage, npages, buffer);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Done\n",
nand_wrapper_ins_i, "bwrite");
}
else
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Failed: %d!\n",
nand_wrapper_ins_i, "bwrite", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_ioctl
*
* Description:
* Wrapper for NAND MTD ioctl method.
*
* Input Parameters:
* dev: MTD Device
* cmd: Command for IOCTL
* arg: Any argument required by command
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_ioctl(FAR struct mtd_dev_s *dev, int cmd,
unsigned long arg)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %lu | %s] Command: %d, Arg : %ld\n",
nand_wrapper_ins_i, "ioctl", cmd, arg);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.ioctl);
ret = nand_dev->under.mtd.ioctl(dev, cmd, arg);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Done\n",
nand_wrapper_ins_i, "ioctl");
}
else
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Failed: %d!\n",
nand_wrapper_ins_i, "ioctl", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_isbad
*
* Description:
* Wrapper for NAND MTD isbad method.
*
* Input Parameters:
* dev: MTD Device
* block: Block number (0-indexing) to check if it is bad
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_isbad(FAR struct mtd_dev_s *dev, off_t block)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %lu | %s] Blocks: %d\n",
nand_wrapper_ins_i, "isbad", block);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.isbad);
ret = nand_dev->under.mtd.isbad(dev, block);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Done\n",
nand_wrapper_ins_i, "isbad");
}
else
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Failed: %d!\n",
nand_wrapper_ins_i, "isbad", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_markbad
*
* Description:
* Wrapper for NAND MTD markbad method.
*
* Input Parameters:
* dev: MTD Device
* block: Block number (0-indexing) to mark it as bad
*
* Returned Value:
* 0: Successful
* < 0: Error
*
* Assumptions/Limitations:
* This assumes `dev` is specifically of type `struct nand_wrapper_dev_s *`
*
****************************************************************************/
int nand_wrapper_markbad(FAR struct mtd_dev_s *dev, off_t block)
{
int ret;
FAR struct nand_wrapper_dev_s *nand_dev;
nand_dev = (struct nand_wrapper_dev_s *)dev;
nxmutex_lock(&nand_wrapper_dev_mut);
nand_wrapper_ins_i++;
NAND_WRAPPER_LOG("[UPPER %lu | %s] Blocks: %d\n",
nand_wrapper_ins_i, "markbad", block);
DEBUGASSERT(nand_dev && nand_dev->under.mtd.markbad);
ret = nand_dev->under.mtd.markbad(dev, block);
if (ret >= 0)
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Done\n",
nand_wrapper_ins_i, "markbad");
}
else
{
NAND_WRAPPER_LOG("[UPPER %lu | %s] Failed: %d!\n",
nand_wrapper_ins_i, "markbad", ret);
}
nxmutex_unlock(&nand_wrapper_dev_mut);
return ret;
}
/****************************************************************************
* Name: nand_wrapper_initialize
*
* Description:
* Initializes wrapper.
*
* Returned Value:
* 0: Successful
* < 0: Error
*
****************************************************************************/
void nand_wrapper_initialize(void)
{
nxmutex_init(&nand_wrapper_dev_mut);
}

View File

@ -207,8 +207,8 @@
/* Branch prediction */
# define predict_true(x) __builtin_expect(!!(x), 1)
# define predict_false(x) __builtin_expect((x), 0)
# define predict_true(x) __builtin_expect(!!(x), 1)
# define predict_false(x) __builtin_expect(!!(x), 0)
/* Code locate */

View File

@ -98,7 +98,7 @@ extern "C"
*
* Returned Value:
* A non-NULL MTD driver instance is returned on success. NULL is
* returned on any failaure.
* returned on any failure.
*
****************************************************************************/

View File

@ -0,0 +1,101 @@
/****************************************************************************
* include/nuttx/mtd/nand_ram.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_MTD_NAND_RAM_H
#define __INCLUDE_NUTTX_MTD_NAND_RAM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <syslog.h>
#include <nuttx/drivers/drivers.h>
#include <nuttx/mtd/nand.h>
#include <nuttx/mtd/nand_scheme.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NAND_RAM_DEBUG CONFIG_MTD_NAND_RAM_DEBUG
#define NAND_RAM_B(x) (x)
#define NAND_RAM_KB(x) (NAND_RAM_B(x) << 10)
#define NAND_RAM_MB(x) (NAND_RAM_KB(x) << 10)
#define NAND_RAM_SIZE NAND_RAM_MB(CONFIG_MTD_NAND_RAM_SIZE)
#define NAND_RAM_LOG_PAGES_PER_BLOCK ((uint32_t) 7)
#define NAND_RAM_PAGE_SIZE ((uint32_t) (1 << 9)) /* 512 B */
#define NAND_RAM_SPARE_SIZE ((uint32_t) (1 << 4)) /* 16 B */
#define NAND_RAM_N_PAGES ((uint32_t) NAND_RAM_SIZE / NAND_RAM_PAGE_SIZE)
#define NAND_RAM_TOTAL_PAGE_SIZE ((uint32_t) (NAND_RAM_PAGE_SIZE + NAND_RAM_SPARE_SIZE))
#define NAND_RAM_PAGES_PER_BLOCK ((uint32_t) (NAND_RAM_BLOCK_SIZE / NAND_RAM_PAGE_SIZE))
#define NAND_RAM_N_BLOCKS ((uint32_t) (NAND_RAM_N_PAGES / NAND_RAM_PAGES_PER_BLOCK))
#define NAND_RAM_BLOCK_SIZE ((uint32_t) ((1 << NAND_RAM_LOG_PAGES_PER_BLOCK) * NAND_RAM_PAGE_SIZE))
#define NAND_RAM_PAGE_WRITTEN 0
#define NAND_RAM_PAGE_FREE 1
#define NAND_RAM_BLOCK_GOOD 0xff
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
EXTERN FAR struct mtd_dev_s *g_nand_ram_mtd_wrapper;
EXTERN FAR struct mtd_dev_s *g_nand_ram_mtd_under;
EXTERN FAR struct nand_raw_s *g_nand_mtd_raw;
/****************************************************************************
* Inline Functions
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int nand_ram_eraseblock(FAR struct nand_raw_s *raw, off_t block);
int nand_ram_rawread(FAR struct nand_raw_s *raw, off_t block,
unsigned int page, FAR void *data, FAR void *spare);
int nand_ram_rawwrite(FAR struct nand_raw_s *raw, off_t block,
unsigned int page, FAR const void *data,
FAR const void *spare);
FAR struct mtd_dev_s *nand_ram_initialize(struct nand_raw_s *raw);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __TESTING_NAND_RAM_NAND_RAM_H */

View File

@ -0,0 +1,84 @@
/****************************************************************************
* include/nuttx/mtd/nand_wrapper.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_MTD_NAND_WRAPPER_H
#define __INCLUDE_NUTTX_MTD_NAND_WRAPPER_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <syslog.h>
#include <nuttx/drivers/drivers.h>
#include <nuttx/mtd/nand.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
struct nand_wrapper_dev_s
{
struct nand_dev_s wrapper; /* Wrapper device */
struct nand_dev_s under; /* Underlying actuall upper half device */
};
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Inline Functions
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int nand_wrapper_erase(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks);
ssize_t nand_wrapper_bread(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR uint8_t *buffer);
ssize_t nand_wrapper_bwrite(FAR struct mtd_dev_s *dev, off_t startpage,
size_t npages, FAR const uint8_t *buffer);
int nand_wrapper_ioctl(FAR struct mtd_dev_s *dev, int cmd,
unsigned long arg);
int nand_wrapper_isbad(FAR struct mtd_dev_s *dev, off_t block);
int nand_wrapper_markbad(FAR struct mtd_dev_s *dev, off_t block);
void nand_wrapper_initialize(void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __TESTING_NAND_RAM_NAND_RAM_H */