Commit f487b677 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

dma: keep a device alive while it has SGLists

parent cac3c384
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -34,13 +34,16 @@ int dma_memory_set(AddressSpace *as, dma_addr_t addr, uint8_t c, dma_addr_t len)
    return error;
}

void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint, AddressSpace *as)
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->as = as;
    qsg->dev = dev;
    object_ref(OBJECT(dev));
}

void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len)
@@ -57,6 +60,7 @@ 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));
}
+4 −1
Original line number Diff line number Diff line
@@ -650,6 +650,8 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
    int off_idx = -1;
    int off_pos = -1;
    int tbl_entry_size;
    IDEBus *bus = &ad->port;
    BusState *qbus = BUS(bus);

    if (!sglist_alloc_hint) {
        DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
@@ -691,7 +693,8 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
            goto out;
        }

        qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->as);
        qemu_sglist_init(sglist, qbus->parent, (sglist_alloc_hint - off_idx),
                         ad->hba->as);
        qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
                        le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);

+2 −2
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)

    s->io_buffer_size = io->len;

    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
                     &address_space_memory);
    qemu_sglist_add(&s->sg, io->addr, io->len);
    io->addr += io->len;
@@ -127,7 +127,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
    s->io_buffer_index = 0;
    s->io_buffer_size = io->len;

    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
                     &address_space_memory);
    qemu_sglist_add(&s->sg, io->addr, io->len);
    io->addr += io->len;
+6 −4
Original line number Diff line number Diff line
@@ -77,10 +77,12 @@ static void virtio_scsi_bad_req(void)
    exit(1);
}

static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
static void qemu_sgl_init_external(VirtIOSCSIReq *req, struct iovec *sg,
                                   hwaddr *addr, int num)
{
    qemu_sglist_init(qsgl, num, &address_space_memory);
    QEMUSGList *qsgl = &req->qsgl;

    qemu_sglist_init(qsgl, DEVICE(req->dev), num, &address_space_memory);
    while (num--) {
        qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len);
    }
@@ -99,11 +101,11 @@ static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq,
    req->resp.buf = req->elem.in_sg[0].iov_base;

    if (req->elem.out_num > 1) {
        qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1],
        qemu_sgl_init_external(req, &req->elem.out_sg[1],
                               &req->elem.out_addr[1],
                               req->elem.out_num - 1);
    } else {
        qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1],
        qemu_sgl_init_external(req, &req->elem.in_sg[1],
                               &req->elem.in_addr[1],
                               req->elem.in_num - 1);
    }
+4 −2
Original line number Diff line number Diff line
@@ -1241,11 +1241,13 @@ static int ehci_init_transfer(EHCIPacket *p)
{
    uint32_t cpage, offset, bytes, plen;
    dma_addr_t page;
    USBBus *bus = &p->queue->ehci->bus;
    BusState *qbus = BUS(bus);

    cpage  = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
    bytes  = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
    offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
    qemu_sglist_init(&p->sgl, 5, p->queue->ehci->as);
    qemu_sglist_init(&p->sgl, qbus->parent, 5, p->queue->ehci->as);

    while (bytes > 0) {
        if (cpage > 4) {
@@ -1484,7 +1486,7 @@ static int ehci_process_itd(EHCIState *ehci,
                return -1;
            }

            qemu_sglist_init(&ehci->isgl, 2, ehci->as);
            qemu_sglist_init(&ehci->isgl, DEVICE(ehci), 2, ehci->as);
            if (off + len > 4096) {
                /* transfer crosses page border */
                uint32_t len2 = off + len - 4096;
Loading