summaryrefslogtreecommitdiff
path: root/chip/stm32/dma-stm32f4.c
diff options
context:
space:
mode:
authorTom Hughes <tomhughes@chromium.org>2019-08-02 10:19:43 -0700
committerCommit Bot <commit-bot@chromium.org>2019-08-13 00:46:05 +0000
commit4609b59404bd6e32c4cdb267658511a46557dab2 (patch)
treefd2182960546330dd7b0d222e49d29be6a4643c1 /chip/stm32/dma-stm32f4.c
parentd09bc18d46c37070e3309b4f72a33d27134dea45 (diff)
downloadchrome-ec-4609b59404bd6e32c4cdb267658511a46557dab2.tar.gz
dma: separate out DMA enable status from wait_for_bytes
When wait_for_bytes returns 0 when DMA is disabled, we can't differentiate between DMA being disabled and a transfer having completed when it has reached the end of the requested transfer. Separating out into separate functions lets us distinguish the two cases. The reason we didn't hit this in the past is that the requested receive size is generally larger than the actual amount we're sending. Since we know the amount that we're waiting for from the header, we would stop the transfer in software. BRANCH=none BUG=b:132444384 TEST=On DUTs with bloonchipper and dartmonkey: ectool --name=cros_fp testmaxtransfer TEST=make buildall -j Change-Id: I885161a3e04b7a12d597d8dc8691f599990bda8b Signed-off-by: Tom Hughes <tomhughes@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1734010 Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
Diffstat (limited to 'chip/stm32/dma-stm32f4.c')
-rw-r--r--chip/stm32/dma-stm32f4.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/chip/stm32/dma-stm32f4.c b/chip/stm32/dma-stm32f4.c
index a821ee3d08..abb33befda 100644
--- a/chip/stm32/dma-stm32f4.c
+++ b/chip/stm32/dma-stm32f4.c
@@ -15,6 +15,7 @@
/* Console output macros */
#define CPUTS(outstr) cputs(CC_DMA, outstr)
#define CPRINTF(format, args...) cprintf(CC_DMA, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_DMA, format, ## args)
stm32_dma_regs_t *STM32_DMA_REGS[] = { STM32_DMA1_REGS, STM32_DMA2_REGS };
@@ -144,11 +145,29 @@ void dma_start_rx(const struct dma_option *option, unsigned count,
int dma_bytes_done(stm32_dma_stream_t *stream, int orig_count)
{
- if (!(stream->scr & STM32_DMA_CCR_EN))
- return 0;
+ /*
+ * Note that we're intentionally not checking that DMA is enabled here
+ * because there is a race when the hardware stops the transfer:
+ *
+ * From Section 9.3.14 DMA transfer completion in RM0402 Rev 5
+ * https://www.st.com/resource/en/reference_manual/dm00180369.pdf:
+ * If the stream is configured in non-circular mode, after the end of
+ * the transfer (that is when the number of data to be transferred
+ * reaches zero), the DMA is stopped (EN bit in DMA_SxCR register is
+ * cleared by Hardware) and no DMA request is served unless the software
+ * reprograms the stream and re-enables it (by setting the EN bit in the
+ * DMA_SxCR register).
+ *
+ * See http://b/132444384 for full details.
+ */
return orig_count - stream->sndtr;
}
+bool dma_is_enabled(stm32_dma_stream_t *stream)
+{
+ return (stream->scr & STM32_DMA_CCR_EN);
+}
+
#ifdef CONFIG_DMA_HELP
void dma_dump(enum dma_channel stream)
{