Statistics
| Branch: | Revision:

root / dma-helpers.c @ defb0e31

History | View | Annotate | Download (4.7 kB)

1 244ab90e aliguori
/*
2 244ab90e aliguori
 * DMA helper functions
3 244ab90e aliguori
 *
4 244ab90e aliguori
 * Copyright (c) 2009 Red Hat
5 244ab90e aliguori
 *
6 244ab90e aliguori
 * This work is licensed under the terms of the GNU General Public License
7 244ab90e aliguori
 * (GNU GPL), version 2 or later.
8 244ab90e aliguori
 */
9 244ab90e aliguori
10 244ab90e aliguori
#include "dma.h"
11 59a703eb aliguori
#include "block_int.h"
12 244ab90e aliguori
13 244ab90e aliguori
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint)
14 244ab90e aliguori
{
15 244ab90e aliguori
    qsg->sg = qemu_malloc(alloc_hint * sizeof(ScatterGatherEntry));
16 244ab90e aliguori
    qsg->nsg = 0;
17 244ab90e aliguori
    qsg->nalloc = alloc_hint;
18 244ab90e aliguori
    qsg->size = 0;
19 244ab90e aliguori
}
20 244ab90e aliguori
21 c227f099 Anthony Liguori
void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
22 c227f099 Anthony Liguori
                     target_phys_addr_t len)
23 244ab90e aliguori
{
24 244ab90e aliguori
    if (qsg->nsg == qsg->nalloc) {
25 244ab90e aliguori
        qsg->nalloc = 2 * qsg->nalloc + 1;
26 244ab90e aliguori
        qsg->sg = qemu_realloc(qsg->sg, qsg->nalloc * sizeof(ScatterGatherEntry));
27 244ab90e aliguori
    }
28 244ab90e aliguori
    qsg->sg[qsg->nsg].base = base;
29 244ab90e aliguori
    qsg->sg[qsg->nsg].len = len;
30 244ab90e aliguori
    qsg->size += len;
31 244ab90e aliguori
    ++qsg->nsg;
32 244ab90e aliguori
}
33 244ab90e aliguori
34 244ab90e aliguori
void qemu_sglist_destroy(QEMUSGList *qsg)
35 244ab90e aliguori
{
36 244ab90e aliguori
    qemu_free(qsg->sg);
37 244ab90e aliguori
}
38 244ab90e aliguori
39 59a703eb aliguori
typedef struct {
40 37b7842c aliguori
    BlockDriverAIOCB common;
41 59a703eb aliguori
    BlockDriverState *bs;
42 59a703eb aliguori
    BlockDriverAIOCB *acb;
43 59a703eb aliguori
    QEMUSGList *sg;
44 59a703eb aliguori
    uint64_t sector_num;
45 59a703eb aliguori
    int is_write;
46 59a703eb aliguori
    int sg_cur_index;
47 c227f099 Anthony Liguori
    target_phys_addr_t sg_cur_byte;
48 59a703eb aliguori
    QEMUIOVector iov;
49 59a703eb aliguori
    QEMUBH *bh;
50 37b7842c aliguori
} DMAAIOCB;
51 59a703eb aliguori
52 59a703eb aliguori
static void dma_bdrv_cb(void *opaque, int ret);
53 59a703eb aliguori
54 59a703eb aliguori
static void reschedule_dma(void *opaque)
55 59a703eb aliguori
{
56 37b7842c aliguori
    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
57 59a703eb aliguori
58 59a703eb aliguori
    qemu_bh_delete(dbs->bh);
59 59a703eb aliguori
    dbs->bh = NULL;
60 59a703eb aliguori
    dma_bdrv_cb(opaque, 0);
61 59a703eb aliguori
}
62 59a703eb aliguori
63 59a703eb aliguori
static void continue_after_map_failure(void *opaque)
64 59a703eb aliguori
{
65 37b7842c aliguori
    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
66 59a703eb aliguori
67 59a703eb aliguori
    dbs->bh = qemu_bh_new(reschedule_dma, dbs);
68 59a703eb aliguori
    qemu_bh_schedule(dbs->bh);
69 59a703eb aliguori
}
70 59a703eb aliguori
71 7403b14e aliguori
static void dma_bdrv_unmap(DMAAIOCB *dbs)
72 59a703eb aliguori
{
73 59a703eb aliguori
    int i;
74 59a703eb aliguori
75 59a703eb aliguori
    for (i = 0; i < dbs->iov.niov; ++i) {
76 59a703eb aliguori
        cpu_physical_memory_unmap(dbs->iov.iov[i].iov_base,
77 59a703eb aliguori
                                  dbs->iov.iov[i].iov_len, !dbs->is_write,
78 59a703eb aliguori
                                  dbs->iov.iov[i].iov_len);
79 59a703eb aliguori
    }
80 7403b14e aliguori
}
81 7403b14e aliguori
82 856ae5c3 blueswir1
static void dma_bdrv_cb(void *opaque, int ret)
83 7403b14e aliguori
{
84 7403b14e aliguori
    DMAAIOCB *dbs = (DMAAIOCB *)opaque;
85 c227f099 Anthony Liguori
    target_phys_addr_t cur_addr, cur_len;
86 7403b14e aliguori
    void *mem;
87 7403b14e aliguori
88 7403b14e aliguori
    dbs->acb = NULL;
89 7403b14e aliguori
    dbs->sector_num += dbs->iov.size / 512;
90 7403b14e aliguori
    dma_bdrv_unmap(dbs);
91 59a703eb aliguori
    qemu_iovec_reset(&dbs->iov);
92 59a703eb aliguori
93 59a703eb aliguori
    if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
94 37b7842c aliguori
        dbs->common.cb(dbs->common.opaque, ret);
95 59a703eb aliguori
        qemu_iovec_destroy(&dbs->iov);
96 37b7842c aliguori
        qemu_aio_release(dbs);
97 59a703eb aliguori
        return;
98 59a703eb aliguori
    }
99 59a703eb aliguori
100 59a703eb aliguori
    while (dbs->sg_cur_index < dbs->sg->nsg) {
101 59a703eb aliguori
        cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
102 59a703eb aliguori
        cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
103 59a703eb aliguori
        mem = cpu_physical_memory_map(cur_addr, &cur_len, !dbs->is_write);
104 59a703eb aliguori
        if (!mem)
105 59a703eb aliguori
            break;
106 59a703eb aliguori
        qemu_iovec_add(&dbs->iov, mem, cur_len);
107 59a703eb aliguori
        dbs->sg_cur_byte += cur_len;
108 59a703eb aliguori
        if (dbs->sg_cur_byte == dbs->sg->sg[dbs->sg_cur_index].len) {
109 59a703eb aliguori
            dbs->sg_cur_byte = 0;
110 59a703eb aliguori
            ++dbs->sg_cur_index;
111 59a703eb aliguori
        }
112 59a703eb aliguori
    }
113 59a703eb aliguori
114 59a703eb aliguori
    if (dbs->iov.size == 0) {
115 59a703eb aliguori
        cpu_register_map_client(dbs, continue_after_map_failure);
116 59a703eb aliguori
        return;
117 59a703eb aliguori
    }
118 59a703eb aliguori
119 59a703eb aliguori
    if (dbs->is_write) {
120 37b7842c aliguori
        dbs->acb = bdrv_aio_writev(dbs->bs, dbs->sector_num, &dbs->iov,
121 37b7842c aliguori
                                   dbs->iov.size / 512, dma_bdrv_cb, dbs);
122 59a703eb aliguori
    } else {
123 37b7842c aliguori
        dbs->acb = bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov,
124 37b7842c aliguori
                                  dbs->iov.size / 512, dma_bdrv_cb, dbs);
125 59a703eb aliguori
    }
126 7403b14e aliguori
    if (!dbs->acb) {
127 7403b14e aliguori
        dma_bdrv_unmap(dbs);
128 7403b14e aliguori
        qemu_iovec_destroy(&dbs->iov);
129 7403b14e aliguori
        return;
130 7403b14e aliguori
    }
131 59a703eb aliguori
}
132 59a703eb aliguori
133 c16b5a2c Christoph Hellwig
static void dma_aio_cancel(BlockDriverAIOCB *acb)
134 c16b5a2c Christoph Hellwig
{
135 c16b5a2c Christoph Hellwig
    DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
136 c16b5a2c Christoph Hellwig
137 c16b5a2c Christoph Hellwig
    if (dbs->acb) {
138 c16b5a2c Christoph Hellwig
        bdrv_aio_cancel(dbs->acb);
139 c16b5a2c Christoph Hellwig
    }
140 c16b5a2c Christoph Hellwig
}
141 c16b5a2c Christoph Hellwig
142 c16b5a2c Christoph Hellwig
static AIOPool dma_aio_pool = {
143 c16b5a2c Christoph Hellwig
    .aiocb_size         = sizeof(DMAAIOCB),
144 c16b5a2c Christoph Hellwig
    .cancel             = dma_aio_cancel,
145 c16b5a2c Christoph Hellwig
};
146 c16b5a2c Christoph Hellwig
147 59a703eb aliguori
static BlockDriverAIOCB *dma_bdrv_io(
148 59a703eb aliguori
    BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
149 59a703eb aliguori
    BlockDriverCompletionFunc *cb, void *opaque,
150 59a703eb aliguori
    int is_write)
151 59a703eb aliguori
{
152 c16b5a2c Christoph Hellwig
    DMAAIOCB *dbs =  qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
153 59a703eb aliguori
154 37b7842c aliguori
    dbs->acb = NULL;
155 59a703eb aliguori
    dbs->bs = bs;
156 59a703eb aliguori
    dbs->sg = sg;
157 59a703eb aliguori
    dbs->sector_num = sector_num;
158 59a703eb aliguori
    dbs->sg_cur_index = 0;
159 59a703eb aliguori
    dbs->sg_cur_byte = 0;
160 59a703eb aliguori
    dbs->is_write = is_write;
161 59a703eb aliguori
    dbs->bh = NULL;
162 59a703eb aliguori
    qemu_iovec_init(&dbs->iov, sg->nsg);
163 59a703eb aliguori
    dma_bdrv_cb(dbs, 0);
164 7403b14e aliguori
    if (!dbs->acb) {
165 7403b14e aliguori
        qemu_aio_release(dbs);
166 7403b14e aliguori
        return NULL;
167 7403b14e aliguori
    }
168 37b7842c aliguori
    return &dbs->common;
169 59a703eb aliguori
}
170 59a703eb aliguori
171 59a703eb aliguori
172 59a703eb aliguori
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
173 59a703eb aliguori
                                QEMUSGList *sg, uint64_t sector,
174 59a703eb aliguori
                                void (*cb)(void *opaque, int ret), void *opaque)
175 59a703eb aliguori
{
176 59a703eb aliguori
    return dma_bdrv_io(bs, sg, sector, cb, opaque, 0);
177 59a703eb aliguori
}
178 59a703eb aliguori
179 59a703eb aliguori
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
180 59a703eb aliguori
                                 QEMUSGList *sg, uint64_t sector,
181 59a703eb aliguori
                                 void (*cb)(void *opaque, int ret), void *opaque)
182 59a703eb aliguori
{
183 59a703eb aliguori
    return dma_bdrv_io(bs, sg, sector, cb, opaque, 1);
184 59a703eb aliguori
}