Add an MTD layer that will add read-ahead or write buffering to any MTD driver (incomplete)

This commit is contained in:
Gregory Nutt
2014-07-11 11:20:11 -06:00
parent b224f08fd7
commit 8516551e54
11 changed files with 1051 additions and 233 deletions
+27
View File
@@ -35,6 +35,33 @@ config LOOP
file (or character device) as a block device. See losetup() and file (or character device) as a block device. See losetup() and
loteardown() in include/nuttx/fs/fs.h. loteardown() in include/nuttx/fs/fs.h.
config DRVR_WRITEBUFFER
bool "Enable write buffer support"
default n
---help---
Enable generic write buffering support that can be used by a variety
of drivers.
if DRVR_WRITEBUFFER
config DRVR_WRDELAY
int "Write flush delay"
default 350
---help---
If there is no write activity for this configured amount of time,
then the contents will be automatically flushed to the media. This
reduces the likelihood that data will be stuck in the write buffer
at the time of power down.
endif # DRVR_WRITEBUFFER
config DRVR_READAHEAD
bool "Enable read-ahead buffer support"
default n
---help---
Enable generic read-ahead buffering support that can be used by a
variety of drivers.
config RAMDISK config RAMDISK
bool "RAM Disk Support" bool "RAM Disk Support"
default n default n
+9 -2
View File
@@ -1,7 +1,7 @@
############################################################################ ############################################################################
# drivers/Makefile # drivers/Makefile
# #
# Copyright (C) 2007-2013 Gregory Nutt. All rights reserved. # Copyright (C) 2007-2014 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org> # Author: Gregory Nutt <gnutt@nuttx.org>
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,14 @@ ifneq ($(CONFIG_NFILE_DESCRIPTORS),0)
CSRCS += dev_null.c dev_zero.c loop.c CSRCS += dev_null.c dev_zero.c loop.c
ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
CSRCS += ramdisk.c rwbuffer.c CSRCS += ramdisk.c
ifneq ($(CONFIG_DRVR_WRITEBUFFER),y)
CSRCS += rwbuffer.c
else
ifneq ($(CONFIG_DRVR_READAHEAD),y)
CSRCS += rwbuffer.c
endif
endif
endif endif
ifeq ($(CONFIG_CAN),y) ifeq ($(CONFIG_CAN),y)
+13 -12
View File
@@ -144,7 +144,7 @@ struct mmcsd_state_s
#endif #endif
/* Read-ahead and write buffering support */ /* Read-ahead and write buffering support */
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) #if defined(CONFIG_DRVR_WRITEBUFFER) || defined(CONFIG_DRVR_READAHEAD)
struct rwbuffer_s rwbuffer; struct rwbuffer_s rwbuffer;
#endif #endif
}; };
@@ -203,7 +203,7 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
FAR uint8_t *buffer, off_t startblock, size_t nblocks); FAR uint8_t *buffer, off_t startblock, size_t nblocks);
#endif #endif
#ifdef CONFIG_FS_READAHEAD #ifdef CONFIG_DRVR_READAHEAD
static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
off_t startblock, size_t nblocks); off_t startblock, size_t nblocks);
#endif #endif
@@ -214,7 +214,7 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
FAR const uint8_t *buffer, off_t startblock, size_t nblocks); FAR const uint8_t *buffer, off_t startblock, size_t nblocks);
#endif #endif
#ifdef CONFIG_FS_WRITEBUFFER #ifdef CONFIG_DRVR_WRITEBUFFER
static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
off_t startblock, size_t nblocks); off_t startblock, size_t nblocks);
#endif #endif
@@ -1538,7 +1538,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
* *
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_FS_READAHEAD #ifdef CONFIG_DRVR_READAHEAD
static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer,
off_t startblock, size_t nblocks) off_t startblock, size_t nblocks)
{ {
@@ -1911,12 +1911,12 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
* *
****************************************************************************/ ****************************************************************************/
#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER) #if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_DRVR_WRITEBUFFER)
static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer,
off_t startblock, size_t nblocks) off_t startblock, size_t nblocks)
{ {
FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev; FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev;
#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE #ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE
size_t block; size_t block;
size_t endblock; size_t endblock;
#endif #endif
@@ -2028,7 +2028,7 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
size_t startsector, unsigned int nsectors) size_t startsector, unsigned int nsectors)
{ {
FAR struct mmcsd_state_s *priv; FAR struct mmcsd_state_s *priv;
#if !defined(CONFIG_FS_READAHEAD) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) #if !defined(CONFIG_DRVR_READAHEAD) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE)
size_t sector; size_t sector;
size_t endsector; size_t endsector;
#endif #endif
@@ -2043,7 +2043,7 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
{ {
mmcsd_takesem(priv); mmcsd_takesem(priv);
#if defined(CONFIG_FS_READAHEAD) #if defined(CONFIG_DRVR_READAHEAD)
/* Get the data from the read-ahead buffer */ /* Get the data from the read-ahead buffer */
ret = rwb_read(&priv->rwbuffer, startsector, nsectors, buffer); ret = rwb_read(&priv->rwbuffer, startsector, nsectors, buffer);
@@ -2103,7 +2103,7 @@ static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buf
size_t startsector, unsigned int nsectors) size_t startsector, unsigned int nsectors)
{ {
FAR struct mmcsd_state_s *priv; FAR struct mmcsd_state_s *priv;
#if !defined(CONFIG_FS_WRITEBUFFER) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) #if defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE)
size_t sector; size_t sector;
size_t endsector; size_t endsector;
#endif #endif
@@ -2115,7 +2115,7 @@ static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buf
mmcsd_takesem(priv); mmcsd_takesem(priv);
#if defined(CONFIG_FS_WRITEBUFFER) #if defined(CONFIG_DRVR_WRITEBUFFER)
/* Write the data to the write buffer */ /* Write the data to the write buffer */
ret = rwb_write(&priv->rwbuffer, startsector, nsectors, buffer); ret = rwb_write(&priv->rwbuffer, startsector, nsectors, buffer);
@@ -3271,9 +3271,10 @@ int mmcsd_slotinitialize(int minor, FAR struct sdio_dev_s *dev)
} }
} }
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) #if defined(CONFIG_DRVR_WRITEBUFFER) || defined(CONFIG_DRVR_READAHEAD)
/* Initialize buffering */ /* Initialize buffering */
#warning "Missing setup of rwbuffer"
ret = rwb_initialize(&priv->rwbuffer); ret = rwb_initialize(&priv->rwbuffer);
if (ret < 0) if (ret < 0)
{ {
@@ -3298,7 +3299,7 @@ int mmcsd_slotinitialize(int minor, FAR struct sdio_dev_s *dev)
return OK; return OK;
errout_with_buffers: errout_with_buffers:
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) #if defined(CONFIG_DRVR_WRITEBUFFER) || defined(CONFIG_DRVR_READAHEAD)
rwb_uninitialize(&priv->rwbuffer); rwb_uninitialize(&priv->rwbuffer);
errout_with_hwinit: errout_with_hwinit:
#endif #endif
+38 -1
View File
@@ -66,6 +66,40 @@ config MTD_BYTE_WRITE
support such writes. The SMART file system can take advantage of support such writes. The SMART file system can take advantage of
this option if it is enabled. 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 config MTD_CONFIG
bool "Enable Dev Config (MTD based) device" bool "Enable Dev Config (MTD based) device"
default n default n
@@ -73,6 +107,8 @@ config MTD_CONFIG
Provides a /dev/config device for saving / restoring application Provides a /dev/config device for saving / restoring application
configuration data to a standard MTD device or partition. configuration data to a standard MTD device or partition.
if MTD_CONFIG
config MTD_CONFIG_RAM_CONSOLIDATE config MTD_CONFIG_RAM_CONSOLIDATE
bool "Always use RAM consolidation method (work in progress)" bool "Always use RAM consolidation method (work in progress)"
default n default n
@@ -97,13 +133,14 @@ config MTD_CONFIG_RAM_CONSOLIDATE
config MTD_CONFIG_ERASEDVALUE config MTD_CONFIG_ERASEDVALUE
hex "Erased value of bytes on the MTD device" hex "Erased value of bytes on the MTD device"
depends on MTD_CONFIG
default 0xff default 0xff
---help--- ---help---
Specifies the value of the erased state of the MTD FLASH. For Specifies the value of the erased state of the MTD FLASH. For
most FLASH parts, this is 0xff, but could also be zero depending most FLASH parts, this is 0xff, but could also be zero depending
on the device. on the device.
endif # MTD_CONFIG
comment "MTD Device Drivers" comment "MTD Device Drivers"
menuconfig MTD_NAND menuconfig MTD_NAND
+8
View File
@@ -49,6 +49,14 @@ ifeq ($(CONFIG_MTD_SECT512),y)
CSRCS += sector512.c CSRCS += sector512.c
endif 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) ifeq ($(CONFIG_MTD_NAND),y)
CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandmodel.c mtd_modeltab.c CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandmodel.c mtd_modeltab.c
ifeq ($(CONFIG_MTD_NAND_SWECC),y) ifeq ($(CONFIG_MTD_NAND_SWECC),y)
+12 -10
View File
@@ -56,11 +56,11 @@
#include <nuttx/rwbuffer.h> #include <nuttx/rwbuffer.h>
/**************************************************************************** /****************************************************************************
* Private Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
#if defined(CONFIG_FS_READAHEAD) || (defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FS_WRITEBUFFER)) #if defined(CONFIG_DRVR_READAHEAD) || defined(CONFIG_DRVR_WRITEBUFFER)
# defined CONFIG_FTL_RWBUFFER 1 # define CONFIG_FTL_RWBUFFER 1
#endif #endif
/**************************************************************************** /****************************************************************************
@@ -111,7 +111,7 @@ static const struct block_operations g_bops =
#ifdef CONFIG_FS_WRITABLE #ifdef CONFIG_FS_WRITABLE
ftl_write, /* write */ ftl_write, /* write */
#else #else
NULL, /* write */ NULL, /* write */
#endif #endif
ftl_geometry, /* geometry */ ftl_geometry, /* geometry */
ftl_ioctl /* ioctl */ 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, static ssize_t ftl_read(FAR struct inode *inode, unsigned char *buffer,
size_t start_sector, unsigned int nsectors) 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); fvdbg("sector: %d nsectors: %d\n", start_sector, nsectors);
DEBUGASSERT(inode && inode->i_private); 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); return rwb_read(&dev->rwb, start_sector, nsectors, buffer);
#else #else
return ftl_reload(dev, buffer, start_sector, nsectors); 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); DEBUGASSERT(inode && inode->i_private);
dev = (struct ftl_struct_s *)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); return rwb_write(&dev->rwb, start_sector, nsectors, buffer);
#else #else
return ftl_flush(dev, buffer, start_sector, nsectors); 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.nblocks = dev->geo.neraseblocks * dev->blkper;
dev->rwb.dev = (FAR void *)dev; 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.wrmaxblocks = dev->blkper;
dev->rwb.wrflush = ftl_flush; dev->rwb.wrflush = ftl_flush;
#endif #endif
#ifdef CONFIG_FS_READAHEAD #ifdef CONFIG_DRVR_READAHEAD
dev->rwb.rhmaxblocks = dev->blkper; dev->rwb.rhmaxblocks = dev->blkper;
dev->rwb.rhreload = ftl_reload; dev->rwb.rhreload = ftl_reload;
#endif #endif
ret = rwb_initialize(&dev->rwb); ret = rwb_initialize(&dev->rwb);
if (ret < 0) if (ret < 0)
{ {
+3
View File
@@ -327,6 +327,7 @@ static int mtd_stat(const char *relpath, struct stat *buf)
* in the procfs system simply for information purposes (if desired). * in the procfs system simply for information purposes (if desired).
* *
****************************************************************************/ ****************************************************************************/
int mtd_register(FAR struct mtd_dev_s *mtd, FAR const char *name) int mtd_register(FAR struct mtd_dev_s *mtd, FAR const char *name)
{ {
FAR struct mtd_dev_s *plast; 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; plast->pnext = mtd;
} }
return OK;
} }
#endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */ #endif /* !CONFIG_DISABLE_MOUNTPOINT && CONFIG_FS_PROCFS */
+417
View File
@@ -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 */
+2 -1
View File
@@ -105,7 +105,8 @@
* other for our use, such as format * other for our use, such as format
* sector, etc. */ * 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 # define CONFIG_SMART_RWBUFFER 1
#endif #endif
+475 -172
View File
File diff suppressed because it is too large Load Diff
Regular → Executable
+47 -35
View File
@@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
* include/nuttx/rwbuffer.h * include/nuttx/rwbuffer.h
* *
* Copyright (C) 2009 Gregory Nutt. All rights reserved. * Copyright (C) 2009, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -33,10 +33,6 @@
* *
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#ifndef __INCLUDE_NUTTX_RWBUFFER_H #ifndef __INCLUDE_NUTTX_RWBUFFER_H
#define __INCLUDE_NUTTX_RWBUFFER_H #define __INCLUDE_NUTTX_RWBUFFER_H
@@ -51,7 +47,7 @@
#include <semaphore.h> #include <semaphore.h>
#include <nuttx/wqueue.h> #include <nuttx/wqueue.h>
#if defined(CONFIG_FS_WRITEBUFFER) || defined(CONFIG_FS_READAHEAD) #if defined(CONFIG_DRVR_WRITEBUFFER) || defined(CONFIG_DRVR_READAHEAD)
/********************************************************************** /**********************************************************************
* Pre-processor Definitions * Pre-processor Definitions
@@ -107,45 +103,50 @@ struct rwbuffer_s
uint16_t blocksize; /* The size of one block */ uint16_t blocksize; /* The size of one block */
size_t nblocks; /* The total number blocks supported */ size_t nblocks; /* The total number blocks supported */
FAR void *dev; /* Device state passed to callout functions */
/* Write buffer setup. If CONFIG_FS_WRITEBUFFER is defined, but you /* Read-ahead/Write buffer sizes. Buffering can be disabled (even if it
* want read-ahead-only operation, (1) set wrmaxblocks to zero and do * is enabled in the configuration) by setting the buffer size to zero
* not use rwb_write(). * blocks.
*/ */
#ifdef CONFIG_FS_WRITEBUFFER #ifdef CONFIG_DRVR_WRITEBUFFER
uint16_t wrmaxblocks; /* The number of blocks to buffer in memory */ uint16_t wrmaxblocks; /* The number of blocks to buffer in memory */
rwbflush_t wrflush; /* Callout to flush the write buffer */ #endif
#ifdef CONFIG_DRVR_READAHEAD
uint16_t rhmaxblocks; /* The number of blocks to buffer in memory */
#endif #endif
/* Read-ahead buffer setup. If CONFIG_FS_READAHEAD is defined but you /* Callback functions.
* want write-buffer-only operation, then (1) set rhmaxblocks to zero and *
* do not use rwb_read(). * wrflush. This callback is normally used to flush the contents of
* the write buffer. If write buffering is disabled, then this
* function will instead be used to perform unbuffered writes.
* rhrelad. This callback is normally used to read new data into the
* read-ahead buffer. If read-ahead buffering is disabled, then this
* function will instead be used to perform unbuffered reads.
*/ */
#ifdef CONFIG_FS_READAHEAD FAR void *dev; /* Device state passed to callout functions */
uint16_t rhmaxblocks; /* The number of blocks to buffer in memory */ rwbflush_t wrflush; /* Callout to flush the write buffer */
rwbreload_t rhreload; /* Callout to reload the read-ahead buffer */ rwbreload_t rhreload; /* Callout to reload the read-ahead buffer */
#endif
/********************************************************************/ /********************************************************************/
/* The user should never modify any of the remaing fields */ /* The user should never modify any of the remaining fields */
/* This is the state of the write buffer */ /* This is the state of the write buffering */
#ifdef CONFIG_FS_WRITEBUFFER #ifdef CONFIG_DRVR_WRITEBUFFER
sem_t wrsem; /* Enforces exclusive access to the write buffer */ sem_t wrsem; /* Enforces exclusive access to the write buffer */
struct work_s work; /* Delayed work to flush buffer after adelay with no activity */ struct work_s work; /* Delayed work to flush buffer after a delay with no activity */
uint8_t *wrbuffer; /* Allocated write buffer */ uint8_t *wrbuffer; /* Allocated write buffer */
uint16_t wrnblocks; /* Number of blocks in write buffer */ uint16_t wrnblocks; /* Number of blocks in write buffer */
off_t wrblockstart; /* First block in write buffer */ off_t wrblockstart; /* First block in write buffer */
off_t wrexpectedblock; /* Next block expected */ off_t wrexpectedblock; /* Next block expected */
#endif #endif
/* This is the state of the read-ahead buffer */ /* This is the state of the read-ahead buffering */
#ifdef CONFIG_FS_READAHEAD #ifdef CONFIG_DRVR_READAHEAD
sem_t rhsem; /* Enforces exclusive access to the write buffer */ sem_t rhsem; /* Enforces exclusive access to the write buffer */
uint8_t *rhbuffer; /* Allocated read-ahead buffer */ uint8_t *rhbuffer; /* Allocated read-ahead buffer */
uint16_t rhnblocks; /* Number of blocks in read-ahead buffer */ uint16_t rhnblocks; /* Number of blocks in read-ahead buffer */
@@ -160,7 +161,8 @@ struct rwbuffer_s
#undef EXTERN #undef EXTERN
#if defined(__cplusplus) #if defined(__cplusplus)
#define EXTERN EXTERN "C" #define EXTERN EXTERN "C"
EXTERN "C" { EXTERN "C"
{
#else #else
#define EXTERN extern #define EXTERN extern
#endif #endif
@@ -171,22 +173,32 @@ EXTERN "C" {
/* Buffer initialization */ /* Buffer initialization */
EXTERN int rwb_initialize(FAR struct rwbuffer_s *rwb); int rwb_initialize(FAR struct rwbuffer_s *rwb);
EXTERN void rwb_uninitialize(FAR struct rwbuffer_s *rwb); void rwb_uninitialize(FAR struct rwbuffer_s *rwb);
/* Buffer transfers */ /* Block oriented transfers */
EXTERN ssize_t rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock, ssize_t rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock,
size_t blockcount, FAR uint8_t *rdbuffer); size_t blockcount, FAR uint8_t *rdbuffer);
EXTERN ssize_t rwb_write(FAR struct rwbuffer_s *rwb, ssize_t rwb_write(FAR struct rwbuffer_s *rwb,
off_t startblock, size_t blockcount, off_t startblock, size_t blockcount,
FAR const uint8_t *wrbuffer); FAR const uint8_t *wrbuffer);
EXTERN int rwb_mediaremoved(FAR struct rwbuffer_s *rwb);
/* Character oriented transfers */
ssize_t mtd_readbytes(FAR struct rwbuffer_s *dev, off_t offset,
size_t nbytes, FAR uint8_t *buffer);
/* Media events */
int rwb_mediaremoved(FAR struct rwbuffer_s *rwb);
int rwb_invalidate(FAR struct rwbuffer_s *rwb,
off_t startblock, size_t blockcount);
#undef EXTERN #undef EXTERN
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif
#endif /* CONFIG_FS_WRITEBUFFER || CONFIG_READAHEAD_BUFFER */ #endif /* CONFIG_DRVR_WRITEBUFFER || CONFIG_DRVR_READAHEAD */
#endif /* __INCLUDE_NUTTX_RWBUFFER_H */ #endif /* __INCLUDE_NUTTX_RWBUFFER_H */