4 * Copyright (c) 2009 Red Hat
6 * This work is licensed under the terms of the GNU General Public License
7 * (GNU GPL), version 2 or later.
10 #include "qemu/osdep.h"
11 #include "sysemu/block-backend.h"
12 #include "sysemu/dma.h"
13 #include "trace-root.h"
14 #include "qemu/thread.h"
15 #include "qemu/main-loop.h"
17 /* #define DEBUG_IOMMU */
19 int dma_memory_set(AddressSpace
*as
, dma_addr_t addr
, uint8_t c
, dma_addr_t len
)
21 dma_barrier(as
, DMA_DIRECTION_FROM_DEVICE
);
23 #define FILLBUF_SIZE 512
24 uint8_t fillbuf
[FILLBUF_SIZE
];
28 memset(fillbuf
, c
, FILLBUF_SIZE
);
30 l
= len
< FILLBUF_SIZE
? len
: FILLBUF_SIZE
;
31 error
|= address_space_rw(as
, addr
, MEMTXATTRS_UNSPECIFIED
,
40 void qemu_sglist_init(QEMUSGList
*qsg
, DeviceState
*dev
, int alloc_hint
,
43 qsg
->sg
= g_malloc(alloc_hint
* sizeof(ScatterGatherEntry
));
45 qsg
->nalloc
= alloc_hint
;
49 object_ref(OBJECT(dev
));
52 void qemu_sglist_add(QEMUSGList
*qsg
, dma_addr_t base
, dma_addr_t len
)
54 if (qsg
->nsg
== qsg
->nalloc
) {
55 qsg
->nalloc
= 2 * qsg
->nalloc
+ 1;
56 qsg
->sg
= g_realloc(qsg
->sg
, qsg
->nalloc
* sizeof(ScatterGatherEntry
));
58 qsg
->sg
[qsg
->nsg
].base
= base
;
59 qsg
->sg
[qsg
->nsg
].len
= len
;
64 void qemu_sglist_destroy(QEMUSGList
*qsg
)
66 object_unref(OBJECT(qsg
->dev
));
68 memset(qsg
, 0, sizeof(*qsg
));
80 dma_addr_t sg_cur_byte
;
87 static void dma_blk_cb(void *opaque
, int ret
);
89 static void reschedule_dma(void *opaque
)
91 DMAAIOCB
*dbs
= (DMAAIOCB
*)opaque
;
93 qemu_bh_delete(dbs
->bh
);
98 static void dma_blk_unmap(DMAAIOCB
*dbs
)
102 for (i
= 0; i
< dbs
->iov
.niov
; ++i
) {
103 dma_memory_unmap(dbs
->sg
->as
, dbs
->iov
.iov
[i
].iov_base
,
104 dbs
->iov
.iov
[i
].iov_len
, dbs
->dir
,
105 dbs
->iov
.iov
[i
].iov_len
);
107 qemu_iovec_reset(&dbs
->iov
);
110 static void dma_complete(DMAAIOCB
*dbs
, int ret
)
112 trace_dma_complete(dbs
, ret
, dbs
->common
.cb
);
115 if (dbs
->common
.cb
) {
116 dbs
->common
.cb(dbs
->common
.opaque
, ret
);
118 qemu_iovec_destroy(&dbs
->iov
);
120 qemu_bh_delete(dbs
->bh
);
126 static void dma_blk_cb(void *opaque
, int ret
)
128 DMAAIOCB
*dbs
= (DMAAIOCB
*)opaque
;
129 dma_addr_t cur_addr
, cur_len
;
132 trace_dma_blk_cb(dbs
, ret
);
135 dbs
->offset
+= dbs
->iov
.size
;
137 if (dbs
->sg_cur_index
== dbs
->sg
->nsg
|| ret
< 0) {
138 dma_complete(dbs
, ret
);
143 while (dbs
->sg_cur_index
< dbs
->sg
->nsg
) {
144 cur_addr
= dbs
->sg
->sg
[dbs
->sg_cur_index
].base
+ dbs
->sg_cur_byte
;
145 cur_len
= dbs
->sg
->sg
[dbs
->sg_cur_index
].len
- dbs
->sg_cur_byte
;
146 mem
= dma_memory_map(dbs
->sg
->as
, cur_addr
, &cur_len
, dbs
->dir
);
149 qemu_iovec_add(&dbs
->iov
, mem
, cur_len
);
150 dbs
->sg_cur_byte
+= cur_len
;
151 if (dbs
->sg_cur_byte
== dbs
->sg
->sg
[dbs
->sg_cur_index
].len
) {
152 dbs
->sg_cur_byte
= 0;
157 if (dbs
->iov
.size
== 0) {
158 trace_dma_map_wait(dbs
);
159 dbs
->bh
= aio_bh_new(dbs
->ctx
, reschedule_dma
, dbs
);
160 cpu_register_map_client(dbs
->bh
);
164 if (!QEMU_IS_ALIGNED(dbs
->iov
.size
, dbs
->align
)) {
165 qemu_iovec_discard_back(&dbs
->iov
,
166 QEMU_ALIGN_DOWN(dbs
->iov
.size
, dbs
->align
));
169 aio_context_acquire(dbs
->ctx
);
170 dbs
->acb
= dbs
->io_func(dbs
->offset
, &dbs
->iov
,
171 dma_blk_cb
, dbs
, dbs
->io_func_opaque
);
172 aio_context_release(dbs
->ctx
);
176 static void dma_aio_cancel(BlockAIOCB
*acb
)
178 DMAAIOCB
*dbs
= container_of(acb
, DMAAIOCB
, common
);
180 trace_dma_aio_cancel(dbs
);
183 blk_aio_cancel_async(dbs
->acb
);
186 cpu_unregister_map_client(dbs
->bh
);
187 qemu_bh_delete(dbs
->bh
);
192 static AioContext
*dma_get_aio_context(BlockAIOCB
*acb
)
194 DMAAIOCB
*dbs
= container_of(acb
, DMAAIOCB
, common
);
199 static const AIOCBInfo dma_aiocb_info
= {
200 .aiocb_size
= sizeof(DMAAIOCB
),
201 .cancel_async
= dma_aio_cancel
,
202 .get_aio_context
= dma_get_aio_context
,
205 BlockAIOCB
*dma_blk_io(AioContext
*ctx
,
206 QEMUSGList
*sg
, uint64_t offset
, uint32_t align
,
207 DMAIOFunc
*io_func
, void *io_func_opaque
,
208 BlockCompletionFunc
*cb
,
209 void *opaque
, DMADirection dir
)
211 DMAAIOCB
*dbs
= qemu_aio_get(&dma_aiocb_info
, NULL
, cb
, opaque
);
213 trace_dma_blk_io(dbs
, io_func_opaque
, offset
, (dir
== DMA_DIRECTION_TO_DEVICE
));
218 dbs
->offset
= offset
;
220 dbs
->sg_cur_index
= 0;
221 dbs
->sg_cur_byte
= 0;
223 dbs
->io_func
= io_func
;
224 dbs
->io_func_opaque
= io_func_opaque
;
226 qemu_iovec_init(&dbs
->iov
, sg
->nsg
);
233 BlockAIOCB
*dma_blk_read_io_func(int64_t offset
, QEMUIOVector
*iov
,
234 BlockCompletionFunc
*cb
, void *cb_opaque
,
237 BlockBackend
*blk
= opaque
;
238 return blk_aio_preadv(blk
, offset
, iov
, 0, cb
, cb_opaque
);
241 BlockAIOCB
*dma_blk_read(BlockBackend
*blk
,
242 QEMUSGList
*sg
, uint64_t offset
, uint32_t align
,
243 void (*cb
)(void *opaque
, int ret
), void *opaque
)
245 return dma_blk_io(blk_get_aio_context(blk
), sg
, offset
, align
,
246 dma_blk_read_io_func
, blk
, cb
, opaque
,
247 DMA_DIRECTION_FROM_DEVICE
);
251 BlockAIOCB
*dma_blk_write_io_func(int64_t offset
, QEMUIOVector
*iov
,
252 BlockCompletionFunc
*cb
, void *cb_opaque
,
255 BlockBackend
*blk
= opaque
;
256 return blk_aio_pwritev(blk
, offset
, iov
, 0, cb
, cb_opaque
);
259 BlockAIOCB
*dma_blk_write(BlockBackend
*blk
,
260 QEMUSGList
*sg
, uint64_t offset
, uint32_t align
,
261 void (*cb
)(void *opaque
, int ret
), void *opaque
)
263 return dma_blk_io(blk_get_aio_context(blk
), sg
, offset
, align
,
264 dma_blk_write_io_func
, blk
, cb
, opaque
,
265 DMA_DIRECTION_TO_DEVICE
);
269 static uint64_t dma_buf_rw(uint8_t *ptr
, int32_t len
, QEMUSGList
*sg
,
277 len
= MIN(len
, resid
);
279 ScatterGatherEntry entry
= sg
->sg
[sg_cur_index
++];
280 int32_t xfer
= MIN(len
, entry
.len
);
281 dma_memory_rw(sg
->as
, entry
.base
, ptr
, xfer
, dir
);
290 uint64_t dma_buf_read(uint8_t *ptr
, int32_t len
, QEMUSGList
*sg
)
292 return dma_buf_rw(ptr
, len
, sg
, DMA_DIRECTION_FROM_DEVICE
);
295 uint64_t dma_buf_write(uint8_t *ptr
, int32_t len
, QEMUSGList
*sg
)
297 return dma_buf_rw(ptr
, len
, sg
, DMA_DIRECTION_TO_DEVICE
);
300 void dma_acct_start(BlockBackend
*blk
, BlockAcctCookie
*cookie
,
301 QEMUSGList
*sg
, enum BlockAcctType type
)
303 block_acct_start(blk_get_stats(blk
), cookie
, sg
->size
, type
);