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.mayd...@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 --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; -- 2.25.1