diff mbox series

[RFC,2/2] hw/ppc/ppc440_uc: Handle mapping failure in DMA engine

Message ID 20220726182341.1888115-3-peter.maydell@linaro.org
State Handled Elsewhere
Headers show
Series Fix Coverity and other errors in ppc440_uc DMA | expand

Commit Message

Peter Maydell July 26, 2022, 6:23 p.m. UTC
Currently the code for doing DMA in dcr_write_dma() has no fallback
code for if its calls to cpu_physical_memory_map() fail. Add
handling for this situation, by using address_space_read() and
address_space_write() to do the data transfers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
I believe this to be equivalent to the fastpath code.  However, as
the comments note, I don't know what the intended behaviour on a DMA
memory access error is, because I couldn't find a datasheet for this
hardware.  I am also a bit suspicious that the current code does not
seem to update any of the count, source or destination addresses
after the memory transfer: is that really how the hardware behaves?
---
 hw/ppc/ppc440_uc.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
diff mbox series

Patch

diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 11fdb88c220..0879f180a14 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -905,6 +905,7 @@  static void dcr_write_dma(void *opaque, int dcrn, uint32_t val)
                     uint8_t *rptr, *wptr;
                     hwaddr rlen, wlen;
                     hwaddr xferlen;
+                    bool fastpathed = false;
 
                     sidx = didx = 0;
                     width = 1 << ((val & DMA0_CR_PW) >> 25);
@@ -915,6 +916,7 @@  static void dcr_write_dma(void *opaque, int dcrn, uint32_t val)
                     wptr = cpu_physical_memory_map(dma->ch[chnl].da, &wlen,
                                                    true);
                     if (rptr && rlen == xferlen && wptr && wlen == xferlen) {
+                        fastpathed = true;
                         if (!(val & DMA0_CR_DEC) &&
                             val & DMA0_CR_SAI && val & DMA0_CR_DAI) {
                             /* optimise common case */
@@ -940,6 +942,33 @@  static void dcr_write_dma(void *opaque, int dcrn, uint32_t val)
                     if (rptr) {
                         cpu_physical_memory_unmap(rptr, rlen, 0, sidx);
                     }
+                    if (!fastpathed) {
+                        /* Fast-path failed, do each access one at a time */
+                        for (sidx = didx = i = 0; i < count; i++) {
+                            uint8_t buf[8];
+                            assert(width <= sizeof(buf));
+                            if (address_space_read(&address_space_memory,
+                                                   dma->ch[chnl].sa + sidx,
+                                                   MEMTXATTRS_UNSPECIFIED,
+                                                   buf, width) != MEMTX_OK) {
+                                /* FIXME: model correct behaviour on errors */
+                                break;
+                            }
+                            if (address_space_write(&address_space_memory,
+                                                    dma->ch[chnl].da + didx,
+                                                    MEMTXATTRS_UNSPECIFIED,
+                                                    buf, width) != MEMTX_OK) {
+                                /* FIXME: model correct behaviour on errors */
+                                break;
+                            }
+                            if (val & DMA0_CR_SAI) {
+                                sidx += width;
+                            }
+                            if (val & DMA0_CR_DAI) {
+                                didx += width;
+                            }
+                        }
+                    }
                 }
             }
             break;