mirror of
https://github.com/apache/nuttx.git
synced 2026-10-10 07:40:27 +00:00
mmcsd: Honor optional SDIO host request limits.
Add an optional maxrequest callback at the end of sdio_dev_s. A zero or unset callback adds no host-specific limit; nonzero values are byte limits that apply to all request buffers. Combine the host limit with MMCSD_MULTIBLOCK_LIMIT when splitting block reads and writes. Reject a host limit smaller than one block and oversized raw multi-block commands before starting the transfer. Cancel receive setup after a failed CMD23, attempt CMD12 after failed open-ended multi-block reads, and propagate stop-command failures. Keep these generic MMC/SD changes separate from the STM32H7 driver. Assisted-by: Codex:GPT-6 Signed-off-by: msli-dev <747640013@qq.com>
This commit is contained in:
parent
693513f034
commit
844ef9c678
3 changed files with 101 additions and 5 deletions
|
|
@ -62,7 +62,9 @@ config MMCSD_MULTIBLOCK_LIMIT
|
|||
Default to 0, means no limitation. Block count larger than this
|
||||
limit will be split to multiple multi-block transfer. Set it to 1 will
|
||||
only use single-block transfer mode, and can be used to work around
|
||||
buggy SDIO drivers that cannot handle multiple block transfers.
|
||||
buggy SDIO drivers that cannot handle multiple block transfers. If
|
||||
the SDIO host advertises a smaller maximum request size, the smaller
|
||||
host limit is used automatically.
|
||||
|
||||
config MMCSD_MMCSUPPORT
|
||||
bool "MMC cards support"
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ static int mmcsd_switch(FAR struct mmcsd_state_s *priv, uint32_t arg);
|
|||
/* Transfer helpers *********************************************************/
|
||||
|
||||
static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv);
|
||||
static size_t mmcsd_blocklimit(FAR struct mmcsd_state_s *priv);
|
||||
static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv,
|
||||
sdio_eventset_t failevents);
|
||||
static int mmcsd_transferready(FAR struct mmcsd_state_s *priv);
|
||||
|
|
@ -1280,6 +1281,36 @@ static int mmcsd_verifystate(FAR struct mmcsd_state_s *priv, uint32_t state)
|
|||
* Transfer Helpers
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mmcsd_blocklimit
|
||||
*
|
||||
* Description:
|
||||
* Return the maximum number of blocks for one transfer. Combine the
|
||||
* generic MMC/SD configuration limit with a limit advertised by the host
|
||||
* controller.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static size_t mmcsd_blocklimit(FAR struct mmcsd_state_s *priv)
|
||||
{
|
||||
size_t maxrequest = SDIO_MAXREQUEST(priv->dev);
|
||||
size_t blocklimit = MMCSD_MULTIBLOCK_LIMIT;
|
||||
|
||||
DEBUGASSERT(priv->blocksize > 0);
|
||||
|
||||
if (maxrequest > 0)
|
||||
{
|
||||
size_t hostlimit = maxrequest / priv->blocksize;
|
||||
|
||||
if (blocklimit > hostlimit)
|
||||
{
|
||||
blocklimit = hostlimit;
|
||||
}
|
||||
}
|
||||
|
||||
return blocklimit;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mmcsd_wrprotected
|
||||
*
|
||||
|
|
@ -1715,6 +1746,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_part_s *part,
|
|||
{
|
||||
FAR struct mmcsd_state_s *priv = part->priv;
|
||||
size_t nbytes = nblocks << priv->blockshift;
|
||||
size_t maxrequest = SDIO_MAXREQUEST(priv->dev);
|
||||
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||
uint32_t partnum = part - priv->part;
|
||||
#endif
|
||||
|
|
@ -1724,6 +1756,11 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_part_s *part,
|
|||
finfo("startblock=%jd nblocks=%zu\n", (intmax_t)startblock, nblocks);
|
||||
DEBUGASSERT(priv != NULL && buffer != NULL);
|
||||
|
||||
if (maxrequest > 0 && nbytes > maxrequest)
|
||||
{
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
/* Check if the card is locked */
|
||||
|
||||
if (priv->locked)
|
||||
|
|
@ -1842,6 +1879,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_part_s *part,
|
|||
ret = mmcsd_setblockcount(priv, nblocks);
|
||||
if (ret != OK)
|
||||
{
|
||||
SDIO_CANCEL(priv->dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -1865,6 +1903,11 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_part_s *part,
|
|||
if (ret != OK)
|
||||
{
|
||||
ferr("ERROR: CMD18 transfer failed: %d\n", ret);
|
||||
if (IS_SD(priv->type) && !priv->cmd23support)
|
||||
{
|
||||
mmcsd_stoptransmission(priv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1877,6 +1920,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_part_s *part,
|
|||
if (ret != OK)
|
||||
{
|
||||
ferr("ERROR: mmcsd_stoptransmission failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2094,6 +2138,7 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_part_s *part,
|
|||
{
|
||||
FAR struct mmcsd_state_s *priv = part->priv;
|
||||
size_t nbytes = nblocks << priv->blockshift;
|
||||
size_t maxrequest = SDIO_MAXREQUEST(priv->dev);
|
||||
#ifdef CONFIG_MMCSD_MMCSUPPORT
|
||||
uint32_t partnum = part - priv->part;
|
||||
#endif
|
||||
|
|
@ -2104,6 +2149,11 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_part_s *part,
|
|||
finfo("startblock=%jd nblocks=%zu\n", (intmax_t)startblock, nblocks);
|
||||
DEBUGASSERT(priv != NULL && buffer != NULL);
|
||||
|
||||
if (maxrequest > 0 && nbytes > maxrequest)
|
||||
{
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
/* Check if the card is locked or write protected (either via software or
|
||||
* via the mechanical write protect on the card)
|
||||
*/
|
||||
|
|
@ -2448,6 +2498,7 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
|
|||
FAR struct mmcsd_part_s *part;
|
||||
size_t sector;
|
||||
size_t endsector;
|
||||
size_t blocklimit;
|
||||
ssize_t nread;
|
||||
ssize_t ret = nsectors;
|
||||
|
||||
|
|
@ -2468,6 +2519,13 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
|
|||
|
||||
ret = nsectors;
|
||||
endsector = startsector + nsectors;
|
||||
blocklimit = mmcsd_blocklimit(priv);
|
||||
if (blocklimit == 0)
|
||||
{
|
||||
mmcsd_unlock(priv);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
for (sector = startsector; sector < endsector; sector += nread)
|
||||
{
|
||||
/* Read this sector into the user buffer */
|
||||
|
|
@ -2478,9 +2536,9 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer,
|
|||
nread = mmcsd_readsingle(part, buffer, sector);
|
||||
#else
|
||||
nread = endsector - sector;
|
||||
if (nread > MMCSD_MULTIBLOCK_LIMIT)
|
||||
if (nread > blocklimit)
|
||||
{
|
||||
nread = MMCSD_MULTIBLOCK_LIMIT;
|
||||
nread = blocklimit;
|
||||
}
|
||||
|
||||
if (nread == 1)
|
||||
|
|
@ -2529,6 +2587,7 @@ static ssize_t mmcsd_write(FAR struct inode *inode,
|
|||
FAR struct mmcsd_part_s *part;
|
||||
size_t sector;
|
||||
size_t endsector;
|
||||
size_t blocklimit;
|
||||
ssize_t nwrite;
|
||||
ssize_t ret = nsectors;
|
||||
|
||||
|
|
@ -2549,6 +2608,13 @@ static ssize_t mmcsd_write(FAR struct inode *inode,
|
|||
|
||||
ret = nsectors;
|
||||
endsector = startsector + nsectors;
|
||||
blocklimit = mmcsd_blocklimit(priv);
|
||||
if (blocklimit == 0)
|
||||
{
|
||||
mmcsd_unlock(priv);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
for (sector = startsector; sector < endsector; sector += nwrite)
|
||||
{
|
||||
/* Write this sector into the user buffer */
|
||||
|
|
@ -2559,9 +2625,9 @@ static ssize_t mmcsd_write(FAR struct inode *inode,
|
|||
nwrite = mmcsd_writesingle(part, buffer, sector);
|
||||
#else
|
||||
nwrite = endsector - sector;
|
||||
if (nwrite > MMCSD_MULTIBLOCK_LIMIT)
|
||||
if (nwrite > blocklimit)
|
||||
{
|
||||
nwrite = MMCSD_MULTIBLOCK_LIMIT;
|
||||
nwrite = blocklimit;
|
||||
}
|
||||
|
||||
if (nwrite == 1)
|
||||
|
|
|
|||
|
|
@ -485,6 +485,28 @@
|
|||
#define SDIO_CAPS_MMC_HS_MODE 0x40 /* Bit 6=1: Supports eMMC high speed mode */
|
||||
#define SDIO_CAPS_SD_HS_MODE 0x80 /* Bit 7=1: Supports SD card high speed mode */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: SDIO_MAXREQUEST
|
||||
*
|
||||
* Description:
|
||||
* Return the maximum number of bytes that the host can transfer in one
|
||||
* request. A return value of zero means that the host does not impose an
|
||||
* additional limit. A nonzero limit applies to all buffers, including
|
||||
* directly DMA-accessible buffers. Callers must split requests or reject
|
||||
* commands that cannot be split. A limit smaller than a block cannot
|
||||
* support block I/O.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
*
|
||||
* Returned Value:
|
||||
* Maximum request size in bytes, or zero for no host-specific limit.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define SDIO_MAXREQUEST(dev) \
|
||||
((dev)->maxrequest ? (dev)->maxrequest(dev) : 0)
|
||||
|
||||
/****************************************************************************
|
||||
* Name: SDIO_STATUS
|
||||
*
|
||||
|
|
@ -1066,6 +1088,12 @@ struct sdio_dev_s
|
|||
#endif /* CONFIG_SDIO_DMA */
|
||||
CODE void (*gotextcsd)(FAR struct sdio_dev_s *dev,
|
||||
FAR const uint8_t *buffer);
|
||||
|
||||
/* Optional request limit in bytes; NULL means no additional limit.
|
||||
* Keep optional extensions at the end for positional initializers.
|
||||
*/
|
||||
|
||||
CODE size_t (*maxrequest)(FAR struct sdio_dev_s *dev);
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue