diff options
Diffstat (limited to 'dma-helpers.c')
-rw-r--r-- | dma-helpers.c | 190 |
1 files changed, 11 insertions, 179 deletions
diff --git a/dma-helpers.c b/dma-helpers.c index 2e298b6ebb..5afba47478 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -14,41 +14,33 @@ /* #define DEBUG_IOMMU */ -static void do_dma_memory_set(AddressSpace *as, - dma_addr_t addr, uint8_t c, dma_addr_t len) +int dma_memory_set(AddressSpace *as, dma_addr_t addr, uint8_t c, dma_addr_t len) { + dma_barrier(as, DMA_DIRECTION_FROM_DEVICE); + #define FILLBUF_SIZE 512 uint8_t fillbuf[FILLBUF_SIZE]; int l; + bool error = false; memset(fillbuf, c, FILLBUF_SIZE); while (len > 0) { l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; - address_space_rw(as, addr, fillbuf, l, true); + error |= address_space_rw(as, addr, fillbuf, l, true); len -= l; addr += l; } -} - -int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len) -{ - dma_barrier(dma, DMA_DIRECTION_FROM_DEVICE); - - if (dma_has_iommu(dma)) { - return iommu_dma_memory_set(dma, addr, c, len); - } - do_dma_memory_set(dma->as, addr, c, len); - return 0; + return error; } -void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint, DMAContext *dma) +void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint, AddressSpace *as) { qsg->sg = g_malloc(alloc_hint * sizeof(ScatterGatherEntry)); qsg->nsg = 0; qsg->nalloc = alloc_hint; qsg->size = 0; - qsg->dma = dma; + qsg->as = as; } void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len) @@ -108,7 +100,7 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs) int i; for (i = 0; i < dbs->iov.niov; ++i) { - dma_memory_unmap(dbs->sg->dma, dbs->iov.iov[i].iov_base, + dma_memory_unmap(dbs->sg->as, dbs->iov.iov[i].iov_base, dbs->iov.iov[i].iov_len, dbs->dir, dbs->iov.iov[i].iov_len); } @@ -156,7 +148,7 @@ static void dma_bdrv_cb(void *opaque, int ret) while (dbs->sg_cur_index < dbs->sg->nsg) { cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte; cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte; - mem = dma_memory_map(dbs->sg->dma, cur_addr, &cur_len, dbs->dir); + mem = dma_memory_map(dbs->sg->as, cur_addr, &cur_len, dbs->dir); if (!mem) break; qemu_iovec_add(&dbs->iov, mem, cur_len); @@ -253,7 +245,7 @@ static uint64_t dma_buf_rw(uint8_t *ptr, int32_t len, QEMUSGList *sg, while (len > 0) { ScatterGatherEntry entry = sg->sg[sg_cur_index++]; int32_t xfer = MIN(len, entry.len); - dma_memory_rw(sg->dma, entry.base, ptr, xfer, dir); + dma_memory_rw(sg->as, entry.base, ptr, xfer, dir); ptr += xfer; len -= xfer; resid -= xfer; @@ -277,163 +269,3 @@ void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, { bdrv_acct_start(bs, cookie, sg->size, type); } - -bool iommu_dma_memory_valid(DMAContext *dma, dma_addr_t addr, dma_addr_t len, - DMADirection dir) -{ - hwaddr paddr, plen; - -#ifdef DEBUG_IOMMU - fprintf(stderr, "dma_memory_check context=%p addr=0x" DMA_ADDR_FMT - " len=0x" DMA_ADDR_FMT " dir=%d\n", dma, addr, len, dir); -#endif - - while (len) { - if (dma->translate(dma, addr, &paddr, &plen, dir) != 0) { - return false; - } - - /* The translation might be valid for larger regions. */ - if (plen > len) { - plen = len; - } - - if (!address_space_access_valid(dma->as, paddr, len, - dir == DMA_DIRECTION_FROM_DEVICE)) { - return false; - } - - len -= plen; - addr += plen; - } - - return true; -} - -int iommu_dma_memory_rw(DMAContext *dma, dma_addr_t addr, - void *buf, dma_addr_t len, DMADirection dir) -{ - hwaddr paddr, plen; - int err; - -#ifdef DEBUG_IOMMU - fprintf(stderr, "dma_memory_rw context=%p addr=0x" DMA_ADDR_FMT " len=0x" - DMA_ADDR_FMT " dir=%d\n", dma, addr, len, dir); -#endif - - while (len) { - err = dma->translate(dma, addr, &paddr, &plen, dir); - if (err) { - /* - * In case of failure on reads from the guest, we clean the - * destination buffer so that a device that doesn't test - * for errors will not expose qemu internal memory. - */ - memset(buf, 0, len); - return -1; - } - - /* The translation might be valid for larger regions. */ - if (plen > len) { - plen = len; - } - - address_space_rw(dma->as, paddr, buf, plen, dir == DMA_DIRECTION_FROM_DEVICE); - - len -= plen; - addr += plen; - buf += plen; - } - - return 0; -} - -int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, - dma_addr_t len) -{ - hwaddr paddr, plen; - int err; - -#ifdef DEBUG_IOMMU - fprintf(stderr, "dma_memory_set context=%p addr=0x" DMA_ADDR_FMT - " len=0x" DMA_ADDR_FMT "\n", dma, addr, len); -#endif - - while (len) { - err = dma->translate(dma, addr, &paddr, &plen, - DMA_DIRECTION_FROM_DEVICE); - if (err) { - return err; - } - - /* The translation might be valid for larger regions. */ - if (plen > len) { - plen = len; - } - - do_dma_memory_set(dma->as, paddr, c, plen); - - len -= plen; - addr += plen; - } - - return 0; -} - -void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate, - DMAMapFunc map, DMAUnmapFunc unmap) -{ -#ifdef DEBUG_IOMMU - fprintf(stderr, "dma_context_init(%p, %p, %p, %p)\n", - dma, translate, map, unmap); -#endif - dma->as = as; - dma->translate = translate; - dma->map = map; - dma->unmap = unmap; -} - -void *iommu_dma_memory_map(DMAContext *dma, dma_addr_t addr, dma_addr_t *len, - DMADirection dir) -{ - int err; - hwaddr paddr, plen; - void *buf; - - if (dma->map) { - return dma->map(dma, addr, len, dir); - } - - plen = *len; - err = dma->translate(dma, addr, &paddr, &plen, dir); - if (err) { - return NULL; - } - - /* - * If this is true, the virtual region is contiguous, - * but the translated physical region isn't. We just - * clamp *len, much like address_space_map() does. - */ - if (plen < *len) { - *len = plen; - } - - buf = address_space_map(dma->as, paddr, &plen, dir == DMA_DIRECTION_FROM_DEVICE); - *len = plen; - - return buf; -} - -void iommu_dma_memory_unmap(DMAContext *dma, void *buffer, dma_addr_t len, - DMADirection dir, dma_addr_t access_len) -{ - if (dma->unmap) { - dma->unmap(dma, buffer, len, dir, access_len); - return; - } - - address_space_unmap(dma->as, buffer, len, dir == DMA_DIRECTION_FROM_DEVICE, - access_len); - -} |