mirror of https://github.com/xemu-project/xemu.git
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:
parent
d28a1b6ec6
commit
26b258e138
97
hw/virtio.c
97
hw/virtio.c
|
@ -16,8 +16,6 @@
|
||||||
#include "virtio.h"
|
#include "virtio.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
|
|
||||||
//#define VIRTIO_ZERO_COPY
|
|
||||||
|
|
||||||
/* from Linux's linux/virtio_pci.h */
|
/* from Linux's linux/virtio_pci.h */
|
||||||
|
|
||||||
/* A 32-bit r/o bitmask of the features supported by the host */
|
/* 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
|
#define VIRTIO_PCI_QUEUE_MAX 16
|
||||||
|
|
||||||
/* virt queue functions */
|
/* 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)
|
static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa)
|
||||||
{
|
{
|
||||||
vq->vring.desc = pa;
|
vq->vring.desc = pa;
|
||||||
|
@ -274,35 +235,22 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
int i;
|
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;
|
offset = 0;
|
||||||
for (i = 0; i < elem->in_num; i++) {
|
for (i = 0; i < elem->in_num; i++) {
|
||||||
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
|
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
|
||||||
|
|
||||||
#ifdef VIRTIO_ZERO_COPY
|
cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
|
||||||
if (size) {
|
elem->in_sg[i].iov_len,
|
||||||
ram_addr_t addr = (uint8_t *)elem->in_sg[i].iov_base - phys_ram_base;
|
1, size);
|
||||||
ram_addr_t off;
|
|
||||||
|
|
||||||
for (off = 0; off < size; off += TARGET_PAGE_SIZE)
|
offset += elem->in_sg[i].iov_len;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
idx = (idx + vring_used_idx(vq)) % vq->vring.num;
|
||||||
|
|
||||||
/* Get a pointer to the next entry in the used ring. */
|
/* 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)
|
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
||||||
{
|
{
|
||||||
unsigned int i, head;
|
unsigned int i, head;
|
||||||
|
target_phys_addr_t len;
|
||||||
|
|
||||||
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
|
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -424,37 +373,23 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
||||||
i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
|
i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
|
||||||
do {
|
do {
|
||||||
struct iovec *sg;
|
struct iovec *sg;
|
||||||
|
int is_write = 0;
|
||||||
|
|
||||||
if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
|
if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
|
||||||
elem->in_addr[elem->in_num] = vring_desc_addr(vq, i);
|
elem->in_addr[elem->in_num] = vring_desc_addr(vq, i);
|
||||||
sg = &elem->in_sg[elem->in_num++];
|
sg = &elem->in_sg[elem->in_num++];
|
||||||
|
is_write = 1;
|
||||||
} else
|
} else
|
||||||
sg = &elem->out_sg[elem->out_num++];
|
sg = &elem->out_sg[elem->out_num++];
|
||||||
|
|
||||||
/* Grab the first descriptor, and check it's OK. */
|
/* Grab the first descriptor, and check it's OK. */
|
||||||
sg->iov_len = vring_desc_len(vq, i);
|
sg->iov_len = vring_desc_len(vq, i);
|
||||||
|
len = sg->iov_len;
|
||||||
|
|
||||||
#ifdef VIRTIO_ZERO_COPY
|
sg->iov_base = cpu_physical_memory_map(vring_desc_addr(vq, i), &len, is_write);
|
||||||
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 = qemu_malloc(sg->iov_len);
|
if (sg->iov_base == NULL || len != sg->iov_len) {
|
||||||
if (!(vring_desc_flags(vq, i) & VRING_DESC_F_WRITE)) {
|
fprintf(stderr, "virtio: trying to map MMIO memory\n");
|
||||||
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");
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue