summaryrefslogtreecommitdiff
path: root/nuttx
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 /nuttx
parent514a5a12acbfcf6a5f7f31eaa871fe88ae16b06c (diff)
downloadpx4-nuttx-bc4503a998d8bb3567a59fa6821ba9bd1a3b97b4.tar.gz
px4-nuttx-bc4503a998d8bb3567a59fa6821ba9bd1a3b97b4.tar.bz2
px4-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).
Diffstat (limited to 'nuttx')
-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,