X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=dma-helpers.c;h=2d7e02d35e57613b3921e5621829f3ba1a736bdc;hb=32e70aad7e984f7a609850985895e97fc03579ab;hp=c53705a63df708052d879417ad394053d5d9a026;hpb=24addbc76dcbb1d1c85b3062bbf7a030831cc7a9;p=mirror_qemu.git diff --git a/dma-helpers.c b/dma-helpers.c index c53705a63d..2d7e02d35e 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -7,18 +7,18 @@ * (GNU GPL), version 2 or later. */ +#include "qemu/osdep.h" +#include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "trace.h" -#include "qemu/range.h" +#include "trace-root.h" #include "qemu/thread.h" +#include "qemu/main-loop.h" /* #define DEBUG_IOMMU */ -int dma_memory_set(DMAContext *dma, 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) { - AddressSpace *as = dma->as; - - dma_barrier(dma, DMA_DIRECTION_FROM_DEVICE); + dma_barrier(as, DMA_DIRECTION_FROM_DEVICE); #define FILLBUF_SIZE 512 uint8_t fillbuf[FILLBUF_SIZE]; @@ -28,7 +28,8 @@ int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len) memset(fillbuf, c, FILLBUF_SIZE); while (len > 0) { l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; - error |= address_space_rw(as, addr, fillbuf, l, true); + error |= address_space_rw(as, addr, MEMTXATTRS_UNSPECIFIED, + fillbuf, l, true); len -= l; addr += l; } @@ -36,13 +37,16 @@ int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len) return error; } -void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint, DMAContext *dma) +void qemu_sglist_init(QEMUSGList *qsg, DeviceState *dev, 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; + qsg->dev = dev; + object_ref(OBJECT(dev)); } void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len) @@ -59,26 +63,28 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len) void qemu_sglist_destroy(QEMUSGList *qsg) { + object_unref(OBJECT(qsg->dev)); g_free(qsg->sg); memset(qsg, 0, sizeof(*qsg)); } typedef struct { - BlockDriverAIOCB common; - BlockDriverState *bs; - BlockDriverAIOCB *acb; + BlockAIOCB common; + AioContext *ctx; + BlockAIOCB *acb; QEMUSGList *sg; - uint64_t sector_num; + uint32_t align; + uint64_t offset; DMADirection dir; - bool in_cancel; int sg_cur_index; dma_addr_t sg_cur_byte; QEMUIOVector iov; QEMUBH *bh; DMAIOFunc *io_func; + void *io_func_opaque; } DMAAIOCB; -static void dma_bdrv_cb(void *opaque, int ret); +static void dma_blk_cb(void *opaque, int ret); static void reschedule_dma(void *opaque) { @@ -86,23 +92,15 @@ static void reschedule_dma(void *opaque) qemu_bh_delete(dbs->bh); dbs->bh = NULL; - dma_bdrv_cb(dbs, 0); + dma_blk_cb(dbs, 0); } -static void continue_after_map_failure(void *opaque) -{ - DMAAIOCB *dbs = (DMAAIOCB *)opaque; - - dbs->bh = qemu_bh_new(reschedule_dma, dbs); - qemu_bh_schedule(dbs->bh); -} - -static void dma_bdrv_unmap(DMAAIOCB *dbs) +static void dma_blk_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); } @@ -113,7 +111,7 @@ static void dma_complete(DMAAIOCB *dbs, int ret) { trace_dma_complete(dbs, ret, dbs->common.cb); - dma_bdrv_unmap(dbs); + dma_blk_unmap(dbs); if (dbs->common.cb) { dbs->common.cb(dbs->common.opaque, ret); } @@ -122,35 +120,30 @@ static void dma_complete(DMAAIOCB *dbs, int ret) qemu_bh_delete(dbs->bh); dbs->bh = NULL; } - if (!dbs->in_cancel) { - /* Requests may complete while dma_aio_cancel is in progress. In - * this case, the AIOCB should not be released because it is still - * referenced by dma_aio_cancel. */ - qemu_aio_release(dbs); - } + qemu_aio_unref(dbs); } -static void dma_bdrv_cb(void *opaque, int ret) +static void dma_blk_cb(void *opaque, int ret) { DMAAIOCB *dbs = (DMAAIOCB *)opaque; dma_addr_t cur_addr, cur_len; void *mem; - trace_dma_bdrv_cb(dbs, ret); + trace_dma_blk_cb(dbs, ret); dbs->acb = NULL; - dbs->sector_num += dbs->iov.size / 512; - dma_bdrv_unmap(dbs); + dbs->offset += dbs->iov.size; if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) { dma_complete(dbs, ret); return; } + dma_blk_unmap(dbs); 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); @@ -163,75 +156,113 @@ static void dma_bdrv_cb(void *opaque, int ret) if (dbs->iov.size == 0) { trace_dma_map_wait(dbs); - cpu_register_map_client(dbs, continue_after_map_failure); + dbs->bh = aio_bh_new(dbs->ctx, reschedule_dma, dbs); + cpu_register_map_client(dbs->bh); return; } - dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov, - dbs->iov.size / 512, dma_bdrv_cb, dbs); + if (!QEMU_IS_ALIGNED(dbs->iov.size, dbs->align)) { + qemu_iovec_discard_back(&dbs->iov, + QEMU_ALIGN_DOWN(dbs->iov.size, dbs->align)); + } + + aio_context_acquire(dbs->ctx); + dbs->acb = dbs->io_func(dbs->offset, &dbs->iov, + dma_blk_cb, dbs, dbs->io_func_opaque); + aio_context_release(dbs->ctx); assert(dbs->acb); } -static void dma_aio_cancel(BlockDriverAIOCB *acb) +static void dma_aio_cancel(BlockAIOCB *acb) { DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common); trace_dma_aio_cancel(dbs); if (dbs->acb) { - BlockDriverAIOCB *acb = dbs->acb; - dbs->acb = NULL; - dbs->in_cancel = true; - bdrv_aio_cancel(acb); - dbs->in_cancel = false; + blk_aio_cancel_async(dbs->acb); + } + if (dbs->bh) { + cpu_unregister_map_client(dbs->bh); + qemu_bh_delete(dbs->bh); + dbs->bh = NULL; } - dbs->common.cb = NULL; - dma_complete(dbs, 0); +} + +static AioContext *dma_get_aio_context(BlockAIOCB *acb) +{ + DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common); + + return dbs->ctx; } static const AIOCBInfo dma_aiocb_info = { .aiocb_size = sizeof(DMAAIOCB), - .cancel = dma_aio_cancel, + .cancel_async = dma_aio_cancel, + .get_aio_context = dma_get_aio_context, }; -BlockDriverAIOCB *dma_bdrv_io( - BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num, - DMAIOFunc *io_func, BlockDriverCompletionFunc *cb, +BlockAIOCB *dma_blk_io(AioContext *ctx, + QEMUSGList *sg, uint64_t offset, uint32_t align, + DMAIOFunc *io_func, void *io_func_opaque, + BlockCompletionFunc *cb, void *opaque, DMADirection dir) { - DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, bs, cb, opaque); + DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, NULL, cb, opaque); - trace_dma_bdrv_io(dbs, bs, sector_num, (dir == DMA_DIRECTION_TO_DEVICE)); + trace_dma_blk_io(dbs, io_func_opaque, offset, (dir == DMA_DIRECTION_TO_DEVICE)); dbs->acb = NULL; - dbs->bs = bs; dbs->sg = sg; - dbs->sector_num = sector_num; + dbs->ctx = ctx; + dbs->offset = offset; + dbs->align = align; dbs->sg_cur_index = 0; dbs->sg_cur_byte = 0; dbs->dir = dir; dbs->io_func = io_func; + dbs->io_func_opaque = io_func_opaque; dbs->bh = NULL; qemu_iovec_init(&dbs->iov, sg->nsg); - dma_bdrv_cb(dbs, 0); + dma_blk_cb(dbs, 0); return &dbs->common; } -BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs, - QEMUSGList *sg, uint64_t sector, - void (*cb)(void *opaque, int ret), void *opaque) +static +BlockAIOCB *dma_blk_read_io_func(int64_t offset, QEMUIOVector *iov, + BlockCompletionFunc *cb, void *cb_opaque, + void *opaque) { - return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, - DMA_DIRECTION_FROM_DEVICE); + BlockBackend *blk = opaque; + return blk_aio_preadv(blk, offset, iov, 0, cb, cb_opaque); } -BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, - QEMUSGList *sg, uint64_t sector, - void (*cb)(void *opaque, int ret), void *opaque) +BlockAIOCB *dma_blk_read(BlockBackend *blk, + QEMUSGList *sg, uint64_t offset, uint32_t align, + void (*cb)(void *opaque, int ret), void *opaque) { - return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, - DMA_DIRECTION_TO_DEVICE); + return dma_blk_io(blk_get_aio_context(blk), sg, offset, align, + dma_blk_read_io_func, blk, cb, opaque, + DMA_DIRECTION_FROM_DEVICE); +} + +static +BlockAIOCB *dma_blk_write_io_func(int64_t offset, QEMUIOVector *iov, + BlockCompletionFunc *cb, void *cb_opaque, + void *opaque) +{ + BlockBackend *blk = opaque; + return blk_aio_pwritev(blk, offset, iov, 0, cb, cb_opaque); +} + +BlockAIOCB *dma_blk_write(BlockBackend *blk, + QEMUSGList *sg, uint64_t offset, uint32_t align, + void (*cb)(void *opaque, int ret), void *opaque) +{ + return dma_blk_io(blk_get_aio_context(blk), sg, offset, align, + dma_blk_write_io_func, blk, cb, opaque, + DMA_DIRECTION_TO_DEVICE); } @@ -247,7 +278,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; @@ -266,16 +297,8 @@ uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg) return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE); } -void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, +void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, QEMUSGList *sg, enum BlockAcctType type) { - bdrv_acct_start(bs, cookie, sg->size, type); -} - -void dma_context_init(DMAContext *dma, AddressSpace *as) -{ -#ifdef DEBUG_IOMMU - fprintf(stderr, "dma_context_init(%p -> %p)\n", dma, as); -#endif - dma->as = as; + block_acct_start(blk_get_stats(blk), cookie, sg->size, type); }