From 23a869d9be23a33962c55a1e6f62e6b91b2cbfc4 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 23 Feb 2012 02:07:38 +0000 Subject: (1) Fix a critical memory leak in the TCP read-ahead buffering logic; Add an option to suppress SDIO multi-block transfers in order to work around a buggy SDIO driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4415 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/drivers/mmcsd/mmcsd_sdio.c | 126 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 5 deletions(-) (limited to 'nuttx/drivers') diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c index 09c4efedf..20ef3ebe6 100644 --- a/nuttx/drivers/mmcsd/mmcsd_sdio.c +++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c @@ -188,13 +188,17 @@ static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv); static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv, sdio_eventset_t failevents, uint32_t timeout); static int mmcsd_transferready(FAR struct mmcsd_state_s *priv); +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv); +#endif static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv, uint32_t blocklen); static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, FAR uint8_t *buffer, off_t startblock); +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, FAR uint8_t *buffer, off_t startblock, size_t nblocks); +#endif #ifdef CONFIG_FS_READAHEAD static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock, size_t nblocks); @@ -202,8 +206,10 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, #ifdef CONFIG_FS_WRITABLE static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, FAR const uint8_t *buffer, off_t startblock); +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, FAR const uint8_t *buffer, off_t startblock, size_t nblocks); +#endif #ifdef CONFIG_FS_WRITEBUFFER static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock, size_t nblocks); @@ -1190,6 +1196,7 @@ static int mmcsd_transferready(FAR struct mmcsd_state_s *priv) * ****************************************************************************/ +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv) { int ret; @@ -1204,6 +1211,7 @@ static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv) } return ret; } +#endif /**************************************************************************** * Name: mmcsd_setblocklen @@ -1355,6 +1363,7 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, * ****************************************************************************/ +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, FAR uint8_t *buffer, off_t startblock, size_t nblocks) @@ -1461,6 +1470,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, return nblocks; } +#endif /**************************************************************************** * Name: mmcsd_reload @@ -1476,10 +1486,35 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock, size_t nblocks) { FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev; +#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE + size_t block; + size_t endblock; +#endif ssize_t ret; DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0) +#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE + /* Read each block using only the single block transfer method */ + + endblock = startblock + nblocks - 1; + for (block = startblock; block <= endblock; block++) + { + /* Read this block into the user buffer */ + + ret = mmcsd_readsingle(priv, buffer, block); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the block size */ + + buffer += priv->blocksize; + } +#else + /* Use either the single- or muliple-block transfer method */ + if (nblocks == 1) { ret = mmcsd_readsingle(priv, buffer, startblock); @@ -1488,6 +1523,7 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, { ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks); } +#endif /* On success, return the number of blocks read */ @@ -1614,7 +1650,7 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, * ****************************************************************************/ -#ifdef CONFIG_FS_WRITABLE +#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, FAR const uint8_t *buffer, off_t startblock, size_t nblocks) @@ -1773,10 +1809,33 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock, size_t nblocks) { FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev; +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE + size_t block; + size_t endblock; +#endif ssize_t ret; DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0) +#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE + /* Write each block using only the single block transfer method */ + + endblock = startblock + nblocks - 1; + for (block = startblock; block <= endblock; block++) + { + /* Write this block from the user buffer */ + + ret = mmcsd_writesingle(priv, buffer, block); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the block size */ + + buffer += priv->blocksize; + } +#else if (nblocks == 1) { ret = mmcsd_writesingle(priv, buffer, startblock); @@ -1785,6 +1844,7 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, { ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks); } +#endif /* On success, return the number of blocks written */ @@ -1856,6 +1916,10 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, size_t startsector, unsigned int nsectors) { FAR struct mmcsd_state_s *priv; +#if !defined(CONFIG_FS_READAHEAD) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + size_t sector; + size_t endsector; +#endif ssize_t ret = 0; DEBUGASSERT(inode && inode->i_private); @@ -1866,9 +1930,33 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, if (nsectors > 0) { mmcsd_takesem(priv); -#ifdef CONFIG_FS_READAHEAD + +#if defined(CONFIG_FS_READAHEAD) + /* Get the data from the read-ahead buffer */ + ret = rwb_read(&priv->rwbuffer, startsector, nsectors, buffer); + +#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + /* Read each block using only the single block transfer method */ + + endsector = startsector + nsectors - 1; + for (sector = startsector; sector <= endsector; sector++) + { + /* Read this sector into the user buffer */ + + ret = mmcsd_readsingle(priv, buffer, sector); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the sector size */ + + buffer += priv->blocksize; + } #else + /* Use either the single- or muliple-block transfer method */ + if (nsectors == 1) { ret = mmcsd_readsingle(priv, buffer, startsector); @@ -1896,20 +1984,48 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, ****************************************************************************/ #ifdef CONFIG_FS_WRITABLE -static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer, +static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buffer, size_t startsector, unsigned int nsectors) { FAR struct mmcsd_state_s *priv; - int ret; +#if !defined(CONFIG_FS_WRITEBUFFER) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + size_t sector; + size_t endsector; +#endif + ssize_t ret = 0; fvdbg("sector: %d nsectors: %d sectorsize: %d\n"); DEBUGASSERT(inode && inode->i_private); priv = (FAR struct mmcsd_state_s *)inode->i_private; mmcsd_takesem(priv); -#ifdef CONFIG_FS_WRITEBUFFER + +#if defined(CONFIG_FS_WRITEBUFFER) + /* Write the data to the write buffer */ + ret = rwb_write(&priv->rwbuffer, startsector, nsectors, buffer); + +#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + /* Write each block using only the single block transfer method */ + + endsector = startsector + nsectors - 1; + for (sector = startsector; sector <= endsector; sector++) + { + /* Write this block from the user buffer */ + + ret = mmcsd_writesingle(priv, buffer, sector); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the block size */ + + buffer += priv->blocksize; + } #else + /* Use either the single- or multiple-block transfer method */ + if (nsectors == 1) { ret = mmcsd_writesingle(priv, buffer, startsector); -- cgit v1.2.3