File:  [Qemu by Fabrice Bellard] / qemu / dma-helpers.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:06 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu0150, qemu0141, qemu0140, qemu0130, qemu0125, qemu0124, qemu0123, qemu0122, qemu0121, qemu0120, qemu0111, qemu0110, HEAD
qemu 0.11.0

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

unix.superglobalmegacorp.com