summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpx4dev <px4@purgatory.org>2013-09-08 10:38:01 -0700
committerpx4dev <px4@purgatory.org>2013-09-08 10:38:01 -0700
commitbc4503a998d8bb3567a59fa6821ba9bd1a3b97b4 (patch)
tree3eb797ae20cb63bf4150af4db0fb3557cc399eca
parent514a5a12acbfcf6a5f7f31eaa871fe88ae16b06c (diff)
downloadnuttx-bc4503a998d8bb3567a59fa6821ba9bd1a3b97b4.tar.gz
nuttx-bc4503a998d8bb3567a59fa6821ba9bd1a3b97b4.tar.bz2
nuttx-bc4503a998d8bb3567a59fa6821ba9bd1a3b97b4.zip
Add an explicit preflight call for SDIO DMA operations, since we can't error out of the DMA setup (the card is already committed at that point).
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_sdio.c75
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.c64
-rw-r--r--nuttx/include/nuttx/sdio.h28
3 files changed, 138 insertions, 29 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c
index e110b0a7a..a75d5fe7d 100644
--- a/nuttx/arch/arm/src/stm32/stm32_sdio.c
+++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c
@@ -452,6 +452,8 @@ static int stm32_registercallback(FAR struct sdio_dev_s *dev,
#ifdef CONFIG_SDIO_DMA
static bool stm32_dmasupported(FAR struct sdio_dev_s *dev);
+static int stm32_dmapreflight(FAR struct sdio_dev_s *dev,
+ FAR uint8_t *buffer, size_t buflen);
static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev,
FAR uint8_t *buffer, size_t buflen);
static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
@@ -497,6 +499,7 @@ struct stm32_dev_s g_sdiodev =
.registercallback = stm32_registercallback,
#ifdef CONFIG_SDIO_DMA
.dmasupported = stm32_dmasupported,
+ .dmarecvsetup = stm32_dmapreflight,
.dmarecvsetup = stm32_dmarecvsetup,
.dmasendsetup = stm32_dmasendsetup,
#endif
@@ -2446,37 +2449,28 @@ static bool stm32_dmasupported(FAR struct sdio_dev_s *dev)
#endif
/****************************************************************************
- * Name: stm32_dmarecvsetup
+ * Name: stm32_dmapreflight
*
* Description:
- * Setup to perform a read DMA. If the processor supports a data cache,
- * then this method will also make sure that the contents of the DMA memory
- * and the data cache are coherent. For read transfers this may mean
- * invalidating the data cache.
+ * Preflight an SDIO DMA operation. If the buffer is not well-formed for
+ * SDIO DMA transfer (alignment, size, etc.) returns an error.
*
* Input Parameters:
* dev - An instance of the SDIO device interface
- * buffer - The memory to DMA from
+ * buffer - The memory to DMA to/from
* buflen - The size of the DMA transfer in bytes
*
* Returned Value:
* OK on success; a negated errno on failure
- *
****************************************************************************/
#ifdef CONFIG_SDIO_DMA
-static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
+static int stm32_dmapreflight(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
size_t buflen)
{
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
- uint32_t dblocksize;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
- DEBUGASSERT(((uint32_t)buffer & 3) == 0);
-
- /* Reset the DPSM configuration */
-
- stm32_datadisable();
/* Wide bus operation is required for DMA */
@@ -2492,6 +2486,43 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
return -EFAULT;
}
+ return 0;
+}
+#endif
+
+/****************************************************************************
+ * Name: stm32_dmarecvsetup
+ *
+ * Description:
+ * Setup to perform a read DMA. If the processor supports a data cache,
+ * then this method will also make sure that the contents of the DMA memory
+ * and the data cache are coherent. For read transfers this may mean
+ * invalidating the data cache.
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ * buffer - The memory to DMA from
+ * buflen - The size of the DMA transfer in bytes
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SDIO_DMA
+static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
+ size_t buflen)
+{
+ struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+ uint32_t dblocksize;
+
+ DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
+ DEBUGASSERT(stm32_dmapreflight(dev, buffer, buflen) == 0);
+
+ /* Reset the DPSM configuration */
+
+ stm32_datadisable();
+
stm32_sampleinit();
stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
@@ -2552,26 +2583,12 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
int ret = -EINVAL;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
- DEBUGASSERT(((uint32_t)buffer & 3) == 0);
+ DEBUGASSERT(stm32_dmapreflight(dev, buffer, buflen) == 0);
/* Reset the DPSM configuration */
stm32_datadisable();
- /* Wide bus operation is required for DMA */
-
- if (!priv->widebus)
- {
- return -EINVAL;
- }
-
- /* DMA must be possible to the buffer */
-
- if (!stm32_dmacapable((uintptr_t)buffer, (buflen + 3) >> 2, SDIO_TXDMA32_CONFIG))
- {
- return -EFAULT;
- }
-
stm32_sampleinit();
stm32_sample(priv, SAMPLENDX_BEFORE_SETUP);
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index 6d975ad63..3afed2a93 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -1277,6 +1277,22 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
return -EPERM;
}
+ /*
+ * If we think we are going to perform a DMA transfer, make sure that we
+ * will be able to before we commit the card to the operation.
+ */
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ ret = SDIO_DMAPREFLIGHT(priv->dev, buffer, priv->blocksize);
+
+ if (ret != OK)
+ {
+ return ret;
+ }
+ }
+#endif
+
/* Verify that the card is ready for the transfer. The card may still be
* busy from the preceding write transfer. It would be simpler to check
* for write busy at the end of each write, rather than at the beginning of
@@ -1391,6 +1407,22 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
return -EPERM;
}
+ /*
+ * If we think we are going to perform a DMA transfer, make sure that we
+ * will be able to before we commit the card to the operation.
+ */
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ ret = SDIO_DMAPREFLIGHT(priv->dev, buffer, priv->blocksize);
+
+ if (ret != OK)
+ {
+ return ret;
+ }
+ }
+#endif
+
/* Verify that the card is ready for the transfer. The card may still be
* busy from the preceding write transfer. It would be simpler to check
* for write busy at the end of each write, rather than at the beginning of
@@ -1577,6 +1609,22 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
return -EPERM;
}
+ /*
+ * If we think we are going to perform a DMA transfer, make sure that we
+ * will be able to before we commit the card to the operation.
+ */
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ ret = SDIO_DMAPREFLIGHT(priv->dev, buffer, priv->blocksize);
+
+ if (ret != OK)
+ {
+ return ret;
+ }
+ }
+#endif
+
/* Verify that the card is ready for the transfer. The card may still be
* busy from the preceding write transfer. It would be simpler to check
* for write busy at the end of each write, rather than at the beginning of
@@ -1695,6 +1743,22 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
return -EPERM;
}
+ /*
+ * If we think we are going to perform a DMA transfer, make sure that we
+ * will be able to before we commit the card to the operation.
+ */
+#ifdef CONFIG_SDIO_DMA
+ if (priv->dma)
+ {
+ ret = SDIO_DMAPREFLIGHT(priv->dev, buffer, priv->blocksize);
+
+ if (ret != OK)
+ {
+ return ret;
+ }
+ }
+#endif
+
/* Verify that the card is ready for the transfer. The card may still be
* busy from the preceding write transfer. It would be simpler to check
* for write busy at the end of each write, rather than at the beginning of
diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h
index d5b15370d..e3a11090c 100644
--- a/nuttx/include/nuttx/sdio.h
+++ b/nuttx/include/nuttx/sdio.h
@@ -698,6 +698,30 @@
#endif
/****************************************************************************
+ * Name: SDIO_DMAPREFLIGHT
+ *
+ * Description:
+ * Preflight an SDIO DMA operation. If the buffer is not well-formed for
+ * SDIO DMA transfer (alignment, size, etc.) returns an error.
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ * buffer - The memory to DMA to/from
+ * buflen - The size of the DMA transfer in bytes
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SDIO_DMA
+# define SDIO_DMAPREFLIGHT(dev,buffer,len) ((dev)->dmapreflight && \
+ (dev)->dmapreflight(dev,buffer,len))
+#else
+# define SDIO_DMAPREFLIGHT(dev,buffer,len) (0)
+#endif
+
+/****************************************************************************
* Name: SDIO_DMARECVSETUP
*
* Description:
@@ -837,6 +861,10 @@ struct sdio_dev_s
#ifdef CONFIG_SDIO_DMA
bool (*dmasupported)(FAR struct sdio_dev_s *dev);
+# ifdef CONFIG_SDIO_DMA_PREFLIGHT
+ int (*dmapreflight)(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
+ size_t buflen);
+# endif
int (*dmarecvsetup)(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
size_t buflen);
int (*dmasendsetup)(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer,