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:
parent
3b3f2d97e9
commit
1bec133385
171
Documentation/applications/testing/nand_sim/index.rst
Normal file
171
Documentation/applications/testing/nand_sim/index.rst
Normal 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.
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
475
drivers/mtd/mtd_nandram.c
Normal 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);
|
||||
}
|
418
drivers/mtd/mtd_nandwrapper.c
Normal file
418
drivers/mtd/mtd_nandwrapper.c
Normal 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);
|
||||
}
|
@ -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 */
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
101
include/nuttx/mtd/nand_ram.h
Normal file
101
include/nuttx/mtd/nand_ram.h
Normal 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 */
|
84
include/nuttx/mtd/nand_wrapper.h
Normal file
84
include/nuttx/mtd/nand_wrapper.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user