diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-07-11 11:20:11 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-07-11 11:20:11 -0600 |
commit | 7594ec796b254151652e897f30657a8af4c9162c (patch) | |
tree | c5b72544a56ffcab8569bdd579dd09b17e50ada0 /nuttx/drivers/mtd | |
parent | 5981a437a5bc14a2f0f72f8b8821af24dbb8f78d (diff) | |
download | px4-nuttx-7594ec796b254151652e897f30657a8af4c9162c.tar.gz px4-nuttx-7594ec796b254151652e897f30657a8af4c9162c.tar.bz2 px4-nuttx-7594ec796b254151652e897f30657a8af4c9162c.zip |
Add an MTD layer that will add read-ahead or write buffering to any MTD driver (incomplete)
Diffstat (limited to 'nuttx/drivers/mtd')
-rw-r--r-- | nuttx/drivers/mtd/Kconfig | 39 | ||||
-rw-r--r-- | nuttx/drivers/mtd/Make.defs | 8 | ||||
-rw-r--r-- | nuttx/drivers/mtd/ftl.c | 22 | ||||
-rw-r--r-- | nuttx/drivers/mtd/mtd_procfs.c | 3 | ||||
-rw-r--r-- | nuttx/drivers/mtd/mtd_rwbuffer.c | 417 | ||||
-rw-r--r-- | nuttx/drivers/mtd/smart.c | 3 |
6 files changed, 480 insertions, 12 deletions
diff --git a/nuttx/drivers/mtd/Kconfig b/nuttx/drivers/mtd/Kconfig index 1d56a8960..26945d5c6 100644 --- a/nuttx/drivers/mtd/Kconfig +++ b/nuttx/drivers/mtd/Kconfig @@ -66,6 +66,40 @@ config MTD_BYTE_WRITE support such writes. The SMART file system can take advantage of this option if it is enabled. +config MTD_WRBUFFER + bool "Enable MTD write buffering + default n + depends on DRVR_WRITEBUFFER + ---help--- + Build the mtd_rwbuffer layer and enable support for write buffering. + +if MTD_WRBUFFER + +config MTD_NWRBLOCKS + int "MTD write buffer size" + default 4 + ---help--- + The size of the MTD write buffer (in blocks) + +endif # MTD_WRBUFFER + +config MTD_READAHEAD + bool "Enable MTD read-ahead buffering + default n + depends on DRVR_READAHEAD + ---help--- + Build the mtd_rwbuffer layer and enable support for read-ahead buffering. + +if MTD_READAHEAD + +config MTD_NRDBLOCKS + int "MTD read-head buffer size" + default 4 + ---help--- + The size of the MTD read-ahead buffer (in blocks) + +endif # MTD_READAHEAD + config MTD_CONFIG bool "Enable Dev Config (MTD based) device" default n @@ -73,6 +107,8 @@ config MTD_CONFIG Provides a /dev/config device for saving / restoring application configuration data to a standard MTD device or partition. +if MTD_CONFIG + config MTD_CONFIG_RAM_CONSOLIDATE bool "Always use RAM consolidation method (work in progress)" default n @@ -97,13 +133,14 @@ config MTD_CONFIG_RAM_CONSOLIDATE config MTD_CONFIG_ERASEDVALUE hex "Erased value of bytes on the MTD device" - depends on MTD_CONFIG default 0xff ---help--- Specifies the value of the erased state of the MTD FLASH. For most FLASH parts, this is 0xff, but could also be zero depending on the device. +endif # MTD_CONFIG + comment "MTD Device Drivers" menuconfig MTD_NAND diff --git a/nuttx/drivers/mtd/Make.defs b/nuttx/drivers/mtd/Make.defs index c7d8ea18d..ff1b899d9 100644 --- a/nuttx/drivers/mtd/Make.defs +++ b/nuttx/drivers/mtd/Make.defs @@ -49,6 +49,14 @@ ifeq ($(CONFIG_MTD_SECT512),y) CSRCS += sector512.c endif +ifeq ($(CONFIG_MTD_WRBUFFER),y) +CSRCS += mtd_rwbuffer.c +else +ifeq ($(CONFIG_MTD_READAHEAD),y) +CSRCS += mtd_rwbuffer.c +endif +endif + ifeq ($(CONFIG_MTD_NAND),y) CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandmodel.c mtd_modeltab.c ifeq ($(CONFIG_MTD_NAND_SWECC),y) diff --git a/nuttx/drivers/mtd/ftl.c b/nuttx/drivers/mtd/ftl.c index 364da3695..f2fb3b6d1 100644 --- a/nuttx/drivers/mtd/ftl.c +++ b/nuttx/drivers/mtd/ftl.c @@ -56,11 +56,11 @@ #include <nuttx/rwbuffer.h> /**************************************************************************** - * Private Definitions + * Pre-processor Definitions ****************************************************************************/ -#if defined(CONFIG_FS_READAHEAD) || (defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER)) -# defined CONFIG_FTL_RWBUFFER 1 +#if defined(CONFIG_DRVR_READAHEAD) || defined(CONFIG_DRVR_WRITEBUFFER) +# define CONFIG_FTL_RWBUFFER 1 #endif /**************************************************************************** @@ -111,7 +111,7 @@ static const struct block_operations g_bops = #ifdef CONFIG_FS_WRITABLE ftl_write, /* write */ #else - NULL, /* write */ + NULL, /* write */ #endif ftl_geometry, /* geometry */ ftl_ioctl /* ioctl */ @@ -181,13 +181,14 @@ static ssize_t ftl_reload(FAR void *priv, FAR uint8_t *buffer, static ssize_t ftl_read(FAR struct inode *inode, unsigned char *buffer, size_t start_sector, unsigned int nsectors) { - struct ftl_struct_s *dev; + FAR struct ftl_struct_s *dev; fvdbg("sector: %d nsectors: %d\n", start_sector, nsectors); DEBUGASSERT(inode && inode->i_private); - dev = (struct ftl_struct_s *)inode->i_private; -#ifdef CONFIG_FS_READAHEAD + + dev = (FAR struct ftl_struct_s *)inode->i_private; +#ifdef CONFIG_DRVR_READAHEAD return rwb_read(&dev->rwb, start_sector, nsectors, buffer); #else return ftl_reload(dev, buffer, start_sector, nsectors); @@ -388,7 +389,7 @@ static ssize_t ftl_write(FAR struct inode *inode, const unsigned char *buffer, DEBUGASSERT(inode && inode->i_private); dev = (struct ftl_struct_s *)inode->i_private; -#ifdef CONFIG_FS_WRITEBUFFER +#ifdef CONFIG_DRVR_WRITEBUFFER return rwb_write(&dev->rwb, start_sector, nsectors, buffer); #else return ftl_flush(dev, buffer, start_sector, nsectors); @@ -566,15 +567,16 @@ int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd) dev->rwb.nblocks = dev->geo.neraseblocks * dev->blkper; dev->rwb.dev = (FAR void *)dev; -#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER) +#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_DRVR_WRITEBUFFER) dev->rwb.wrmaxblocks = dev->blkper; dev->rwb.wrflush = ftl_flush; #endif -#ifdef CONFIG_FS_READAHEAD +#ifdef CONFIG_DRVR_READAHEAD dev->rwb.rhmaxblocks = dev->blkper; dev->rwb.rhreload = ftl_reload; #endif + ret = rwb_initialize(&dev->rwb); if (ret < 0) { diff --git a/nuttx/drivers/mtd/mtd_procfs.c b/nuttx/drivers/mtd/mtd_procfs.c index 26f2880b8..54366789b 100644 --- a/nuttx/drivers/mtd/mtd_procfs.c +++ b/nuttx/drivers/mtd/mtd_procfs.c @@ -327,6 +327,7 @@ static int mtd_stat(const char *relpath, struct stat *buf) * in the procfs system simply for information purposes (if desired). * ****************************************************************************/ + int mtd_register(FAR struct mtd_dev_s *mtd, FAR const char *name) { FAR struct mtd_dev_s *plast; @@ -359,6 +360,8 @@ int mtd_register(FAR struct mtd_dev_s *mtd, FAR const char *name) plast->pnext = mtd; } + + return OK; } #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */ diff --git a/nuttx/drivers/mtd/mtd_rwbuffer.c b/nuttx/drivers/mtd/mtd_rwbuffer.c new file mode 100644 index 000000000..3aed371af --- /dev/null +++ b/nuttx/drivers/mtd/mtd_rwbuffer.c @@ -0,0 +1,417 @@ +/************************************************************************************ + * drivers/mtd/mtd_rwbuffer.c + * MTD driver that contains another MTD driver and provides read-ahead and/or write + * buffering. + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/kmalloc.h> +#include <nuttx/rwbuffer.h> +#include <nuttx/fs/ioctl.h> +#include <nuttx/mtd/mtd.h> + +#if defined(CONFIG_DRVR_WRITEBUFFER) || defined(CONFIG_DRVR_READAHEAD) + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +#ifndef CONFIG_MTD_NWRBLOCKS +# define CONFIG_MTD_NWRBLOCKS 4 +#endif + +#ifndef CONFIG_MTD_NRDBLOCKS +# define CONFIG_MTD_NRDBLOCKS 4 +#endif + +/************************************************************************************ + * Private Types + ************************************************************************************/ + +/* This type represents the state of the MTD device. The struct mtd_dev_s must + * appear at the beginning of the definition so that you can freely cast between + * pointers to struct mtd_dev_s and struct mtd_rwbuffer_s. + */ + +struct mtd_rwbuffer_s +{ + struct mtd_dev_s mtd; /* Our exported MTD interface */ + FAR struct mtd_dev_s *dev; /* Saved lower level MTD interface instance */ + struct rwbuffer_s rwb; /* The rwbuffer state structure */ + uint16_t spb; /* Number of sectors per block */ +}; + +/************************************************************************************ + * Private Function Prototypes + ************************************************************************************/ + +/* rwbuffer callouts */ + +static ssize_t mtd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock, + size_t nblocks); +static ssize_t mtd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock, + size_t nblocks); + +/* MTD driver methods */ + +static int mtd_erase(FAR struct mtd_dev_s *dev, off_t block, size_t nsectors); +static ssize_t mtd_bread(FAR struct mtd_dev_s *dev, off_t block, + size_t nsectors, FAR uint8_t *buf); +static ssize_t mtd_bwrite(FAR struct mtd_dev_s *dev, off_t block, + size_t nsectors, FAR const uint8_t *buf); +static ssize_t mtd_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR uint8_t *buffer); +static int mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: mtd_reload + * + * Description: + * Reload the read-ahead buffer + * + ************************************************************************************/ + +static ssize_t mtd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock, + size_t nblocks) +{ + FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev; + DEBUGASSERT(priv && priv->dev); + + /* This is just a pass-through to the contained MTD */ + + return priv->dev->bread(priv->dev, startblock, nblocks, buffer); +} + +/************************************************************************************ + * Name: mtd_flush + * + * Description: + * Flush the write buffer to hardware + * + ************************************************************************************/ + +static ssize_t mtd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock, + size_t nblocks) +{ + FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev; + DEBUGASSERT(priv && priv->dev); + + /* This is just a pass-through to the contained MTD */ + + return priv->dev->bwrite(priv->dev, startblock, nblocks, buffer); +} + +/************************************************************************************ + * Name: mtd_erase + ************************************************************************************/ + +static int mtd_erase(FAR struct mtd_dev_s *dev, off_t block, size_t nblocks) +{ + FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev; + off_t sector; + size_t nsectors; + int ret; + + fvdbg("block: %08lx nsectors: %lu\n", + (unsigned long)block, (unsigned int)nsectors); + + /* Convert to logical sectors and sector numbers */ + + sector = block * priv->spb; + nsectors = nblocks * priv->spb; + + /* Then invalidate in cached data */ + + ret = rwb_invalidate(&priv->rwb, sector, nsectors); + if (ret < 0) + { + fdbg("ERROR: rwb_invalidate failed: %d\n", ret); + return ret; + } + + /* Then let the lower level MTD driver do the real erase */ + + return priv->dev->erase(priv->dev, block, nblocks); +} + +/************************************************************************************ + * Name: mtd_bread + ************************************************************************************/ + +static ssize_t mtd_bread(FAR struct mtd_dev_s *dev, off_t sector, + size_t nsectors, FAR uint8_t *buffer) +{ + FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev; + + /* Let the rwbuffer logic do it real work. It will call out to mtd_reload if is + * needs to read any data. + */ + + return rwb_read(&priv->rwb, sector, nsectors, buffer); +} + +/************************************************************************************ + * Name: mtd_bwrite + ************************************************************************************/ + +static ssize_t mtd_bwrite(FAR struct mtd_dev_s *dev, off_t block, size_t nsectors, + FAR const uint8_t *buffer) +{ + FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev; + + /* Let the rwbuffer logic do it real work. It will call out to wrb_reload it is + * needs to read any data. + */ + + return rwb_write(&priv->rwb, block, nsectors, buffer); +} + +/************************************************************************************ + * Name: mtd_read + ************************************************************************************/ + +static ssize_t mtd_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, + FAR uint8_t *buffer) +{ + FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev; + + /* Let the rwbuffer logic do it real work. It will call out to mtd_reload it is + * needs to read any data. + */ + + return mtd_readbytes(&priv->rwb, offset, nbytes, buffer); +} + +/************************************************************************************ + * Name: mtd_ioctl + ************************************************************************************/ + +static int mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) +{ + FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev; + int ret = -EINVAL; /* Assume good command with bad parameters */ + + fvdbg("cmd: %d \n", cmd); + + switch (cmd) + { + case MTDIOC_GEOMETRY: + { + FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); + if (geo) + { + /* Populate the geometry structure with information need to know + * the capacity and how to access the device. + * + * NOTE: that the device is treated as though it where just an array + * of fixed size blocks. That is most likely not true, but the client + * will expect the device logic to do whatever is necessary to make it + * appear so. + */ + + geo->blocksize = priv->rwb.blocksize; + geo->erasesize = priv->rwb.blocksize* priv->spb; + geo->neraseblocks = priv->rwb.nblocks * priv->spb; + ret = OK; + + fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n", + geo->blocksize, geo->erasesize, geo->neraseblocks); + } + } + break; + + case MTDIOC_BULKERASE: + { + /* Erase the entire device */ + + ret = priv->dev->ioctl(priv->dev, MTDIOC_BULKERASE, 0); + if (ret >= 0) + { + fdbg("ERROR: Device ioctl failed: %d\n", ret); + break; + } + + /* Then invalidate in cached data */ + + ret = rwb_invalidate(&priv->rwb,0, priv->rwb.nblocks); + if (ret < 0) + { + fdbg("ERROR: rwb_invalidate failed: %d\n", ret); + } + } + break; + + case MTDIOC_XIPBASE: + default: + ret = -ENOTTY; /* Bad command */ + break; + } + + fvdbg("return %d\n", ret); + return ret; +} + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: mtd_rwb_initialize + * + * Description: + * Create an initialized MTD device instance. This MTD driver contains another + * MTD driver and converts a larger sector size to a standard 512 byte sector + * size. + * + * MTD devices are not registered in the file system, but are created as instances + * that can be bound to other functions (such as a block or character driver front + * end). + * + ************************************************************************************/ + +FAR struct mtd_dev_s *mtd_rwb_initialize(FAR struct mtd_dev_s *mtd) +{ + FAR struct mtd_rwbuffer_s *priv; + struct mtd_geometry_s geo; + int ret; + + fvdbg("mtd: %p\n", mtd); + DEBUGASSERT(mtd && mtd->ioctl); + + /* Get the device geometry */ + + ret = mtd->ioctl(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo)); + if (ret < 0) + { + fdbg("ERROR: MTDIOC_GEOMETRY ioctl failed: %d\n", ret); + return NULL; + } + + /* Allocate a state structure (we allocate the structure instead of using + * a fixed, static allocation so that we can handle multiple FLASH devices. + * The current implementation would handle only one FLASH part per SPI + * device (only because of the SPIDEV_FLASH definition) and so would have + * to be extended to handle multiple FLASH parts on the same SPI bus. + */ + + priv = (FAR struct mtd_rwbuffer_s *)kzalloc(sizeof(struct mtd_rwbuffer_s)); + if (priv) + { + /* Initialize the allocated structure. (unsupported methods/fields + * were already nullified by kzalloc). + */ + + priv->mtd.erase = mtd_erase; /* Our MTD erase method */ + priv->mtd.bread = mtd_bread; /* Our MTD bread method */ + priv->mtd.bwrite = mtd_bwrite; /* Our MTD bwrite method */ + priv->mtd.read = mtd_read; /* Our MTD read method */ + priv->mtd.ioctl = mtd_ioctl; /* Our MTD ioctl method */ + + priv->dev = mtd; /* The contained MTD instance */ + + /* Sectors per block. The erase block size must be an even multiple + * of the sector size. + */ + + priv->spb = geo.erasesize / geo.blocksize; + DEBUGASSERT((size_t)priv->spb * geo_blocksize = geo.erasesize); + + /* Values must be provided to rwb_initialize() */ + /* Supported geometry */ + + priv->rwb.blocksize = geo.blocksize; + priv->rwb.nblocks = geo.neraseblocks * priv->spb; + + /* Buffer setup */ + +#ifdef CONFIG_DRVR_WRITEBUFFER + priv->rwb.wrmaxblocks = CONFIG_MTD_NWRBLOCKS; +#endif +#ifdef CONFIG_DRVR_READAHEAD + priv->rwb.rhmaxblocks = CONFIG_MTD_NRDBLOCKS; +#endif + + /* Callouts */ + + priv->rwb.dev = priv; /* Device state passed to callouts */ + priv->rwb.wrflush = mtd_flush; /* Callout to flush buffer */ + priv->rwb.rhreload = mtd_reload; /* Callout to reload buffer */ + + /* Initialize read-ahead/write buffering */ + + ret = rwb_initialize(&priv->rwb); + if (ret < 0) + { + fdbg("ERROR: rwb_initialize failed: %d\n", ret); + kfree(priv); + return NULL; + } + } + + /* Register the MTD with the procfs system if enabled */ + +#ifdef CONFIG_MTD_REGISTRATION + mtd_register(&priv->mtd, "rwbuffer"); +#endif + + /* Return the implementation-specific state structure as the MTD device */ + + fvdbg("Return %p\n", priv); + return &priv->mtd; +} + +#endif /* CONFIG_DRVR_WRITEBUFFER || CONFIG_DRVR_READAHEAD */ diff --git a/nuttx/drivers/mtd/smart.c b/nuttx/drivers/mtd/smart.c index 002a9fe5d..b16f58b68 100644 --- a/nuttx/drivers/mtd/smart.c +++ b/nuttx/drivers/mtd/smart.c @@ -105,7 +105,8 @@ * other for our use, such as format * sector, etc. */ -#if defined(CONFIG_FS_READAHEAD) || (defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER)) +#if defined(CONFIG_DRVR_READAHEAD) || (defined(CONFIG_DRVR_WRITABLE) && \ + defined(CONFIG_DRVR_WRITEBUFFER)) # define CONFIG_SMART_RWBUFFER 1 #endif |