diff options
author | px4dev <px4@purgatory.org> | 2013-09-08 10:38:01 -0700 |
---|---|---|
committer | px4dev <px4@purgatory.org> | 2013-09-08 10:38:01 -0700 |
commit | bc4503a998d8bb3567a59fa6821ba9bd1a3b97b4 (patch) | |
tree | 3eb797ae20cb63bf4150af4db0fb3557cc399eca /nuttx | |
parent | 514a5a12acbfcf6a5f7f31eaa871fe88ae16b06c (diff) | |
download | px4-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.c | 75 | ||||
-rw-r--r-- | nuttx/drivers/mmcsd/mmcsd_sdio.c | 64 | ||||
-rw-r--r-- | nuttx/include/nuttx/sdio.h | 28 |
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, |