This is an automated email from the ASF dual-hosted git repository.

GUIDINGLI pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 844ef9c678c1d00106690bcc8c9eba8bdc90285a
Author: msli-dev <[email protected]>
AuthorDate: Sat Oct 3 07:02:44 2026 +0800

    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 <[email protected]>
---
 drivers/mmcsd/Kconfig      |  4 ++-
 drivers/mmcsd/mmcsd_sdio.c | 74 +++++++++++++++++++++++++++++++++++++++++++---
 include/nuttx/sdio.h       | 28 ++++++++++++++++++
 3 files changed, 101 insertions(+), 5 deletions(-)

diff --git a/drivers/mmcsd/Kconfig b/drivers/mmcsd/Kconfig
index 648c41adde9..b7e03943c96 100644
--- a/drivers/mmcsd/Kconfig
+++ b/drivers/mmcsd/Kconfig
@@ -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"
diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c
index 3ea6b85a6a5..748f773e312 100644
--- a/drivers/mmcsd/mmcsd_sdio.c
+++ b/drivers/mmcsd/mmcsd_sdio.c
@@ -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)
diff --git a/include/nuttx/sdio.h b/include/nuttx/sdio.h
index ec3e6243ed9..8ce6bf3cc2b 100644
--- a/include/nuttx/sdio.h
+++ b/include/nuttx/sdio.h
@@ -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);
 };
 
 /****************************************************************************

Reply via email to