Use the DMA api to map virtio elements.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6904 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
aliguori 2009-03-28 17:46:18 +00:00
parent d28a1b6ec6
commit 26b258e138
1 changed files with 16 additions and 81 deletions

View File

@ -16,8 +16,6 @@
#include "virtio.h"
#include "sysemu.h"
//#define VIRTIO_ZERO_COPY
/* from Linux's linux/virtio_pci.h */
/* A 32-bit r/o bitmask of the features supported by the host */
@ -113,43 +111,6 @@ struct VirtQueue
#define VIRTIO_PCI_QUEUE_MAX 16
/* virt queue functions */
#ifdef VIRTIO_ZERO_COPY
static void *virtio_map_gpa(target_phys_addr_t addr, size_t size)
{
ram_addr_t off;
target_phys_addr_t addr1;
off = cpu_get_physical_page_desc(addr);
if ((off & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
fprintf(stderr, "virtio DMA to IO ram\n");
exit(1);
}
off = (off & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
for (addr1 = addr + TARGET_PAGE_SIZE;
addr1 < TARGET_PAGE_ALIGN(addr + size);
addr1 += TARGET_PAGE_SIZE) {
ram_addr_t off1;
off1 = cpu_get_physical_page_desc(addr1);
if ((off1 & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
fprintf(stderr, "virtio DMA to IO ram\n");
exit(1);
}
off1 = (off1 & TARGET_PAGE_MASK) | (addr1 & ~TARGET_PAGE_MASK);
if (off1 != (off + (addr1 - addr))) {
fprintf(stderr, "discontigous virtio memory\n");
exit(1);
}
}
return phys_ram_base + off;
}
#endif
static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa)
{
vq->vring.desc = pa;
@ -274,35 +235,22 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int offset;
int i;
#ifndef VIRTIO_ZERO_COPY
for (i = 0; i < elem->out_num; i++)
qemu_free(elem->out_sg[i].iov_base);
#endif
offset = 0;
for (i = 0; i < elem->in_num; i++) {
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
#ifdef VIRTIO_ZERO_COPY
if (size) {
ram_addr_t addr = (uint8_t *)elem->in_sg[i].iov_base - phys_ram_base;
ram_addr_t off;
cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
elem->in_sg[i].iov_len,
1, size);
for (off = 0; off < size; off += TARGET_PAGE_SIZE)
cpu_physical_memory_set_dirty(addr + off);
}
#else
if (size)
cpu_physical_memory_write(elem->in_addr[i],
elem->in_sg[i].iov_base,
size);
qemu_free(elem->in_sg[i].iov_base);
#endif
offset += size;
offset += elem->in_sg[i].iov_len;
}
for (i = 0; i < elem->out_num; i++)
cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
elem->out_sg[i].iov_len,
0, elem->out_sg[i].iov_len);
idx = (idx + vring_used_idx(vq)) % vq->vring.num;
/* Get a pointer to the next entry in the used ring. */
@ -414,6 +362,7 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
{
unsigned int i, head;
target_phys_addr_t len;
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
return 0;
@ -424,37 +373,23 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
do {
struct iovec *sg;
int is_write = 0;
if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
elem->in_addr[elem->in_num] = vring_desc_addr(vq, i);
sg = &elem->in_sg[elem->in_num++];
is_write = 1;
} else
sg = &elem->out_sg[elem->out_num++];
/* Grab the first descriptor, and check it's OK. */
sg->iov_len = vring_desc_len(vq, i);
len = sg->iov_len;
#ifdef VIRTIO_ZERO_COPY
sg->iov_base = virtio_map_gpa(vring_desc_addr(vq, i), sg->iov_len);
#else
/* cap individual scatter element size to prevent unbounded allocations
of memory from the guest. Practically speaking, no virtio driver
will ever pass more than a page in each element. We set the cap to
be 2MB in case for some reason a large page makes it way into the
sg list. When we implement a zero copy API, this limitation will
disappear */
if (sg->iov_len > (2 << 20))
sg->iov_len = 2 << 20;
sg->iov_base = cpu_physical_memory_map(vring_desc_addr(vq, i), &len, is_write);
sg->iov_base = qemu_malloc(sg->iov_len);
if (!(vring_desc_flags(vq, i) & VRING_DESC_F_WRITE)) {
cpu_physical_memory_read(vring_desc_addr(vq, i),
sg->iov_base,
sg->iov_len);
}
#endif
if (sg->iov_base == NULL) {
fprintf(stderr, "Invalid mapping\n");
if (sg->iov_base == NULL || len != sg->iov_len) {
fprintf(stderr, "virtio: trying to map MMIO memory\n");
exit(1);
}