virtio: make vring_desc_*() take phys addrs
Change the vring descriptor helpers to take the physical address of the descriptor table rather than a virtqueue. This is needed in order to allow these helpers to be used with an indirect descriptor table. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
		
							parent
							
								
									024431b3d8
								
							
						
					
					
						commit
						5774cf98ca
					
				
							
								
								
									
										59
									
								
								hw/virtio.c
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								hw/virtio.c
									
									
									
									
									
								
							@ -85,31 +85,31 @@ static void virtqueue_init(VirtQueue *vq)
 | 
				
			|||||||
                                 VIRTIO_PCI_VRING_ALIGN);
 | 
					                                 VIRTIO_PCI_VRING_ALIGN);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline uint64_t vring_desc_addr(VirtQueue *vq, int i)
 | 
					static inline uint64_t vring_desc_addr(target_phys_addr_t desc_pa, int i)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    target_phys_addr_t pa;
 | 
					    target_phys_addr_t pa;
 | 
				
			||||||
    pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
 | 
					    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
 | 
				
			||||||
    return ldq_phys(pa);
 | 
					    return ldq_phys(pa);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline uint32_t vring_desc_len(VirtQueue *vq, int i)
 | 
					static inline uint32_t vring_desc_len(target_phys_addr_t desc_pa, int i)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    target_phys_addr_t pa;
 | 
					    target_phys_addr_t pa;
 | 
				
			||||||
    pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
 | 
					    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
 | 
				
			||||||
    return ldl_phys(pa);
 | 
					    return ldl_phys(pa);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline uint16_t vring_desc_flags(VirtQueue *vq, int i)
 | 
					static inline uint16_t vring_desc_flags(target_phys_addr_t desc_pa, int i)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    target_phys_addr_t pa;
 | 
					    target_phys_addr_t pa;
 | 
				
			||||||
    pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
 | 
					    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
 | 
				
			||||||
    return lduw_phys(pa);
 | 
					    return lduw_phys(pa);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline uint16_t vring_desc_next(VirtQueue *vq, int i)
 | 
					static inline uint16_t vring_desc_next(target_phys_addr_t desc_pa, int i)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    target_phys_addr_t pa;
 | 
					    target_phys_addr_t pa;
 | 
				
			||||||
    pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
 | 
					    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
 | 
				
			||||||
    return lduw_phys(pa);
 | 
					    return lduw_phys(pa);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -269,20 +269,21 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
 | 
				
			|||||||
    return head;
 | 
					    return head;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i)
 | 
					static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa,
 | 
				
			||||||
 | 
					                                    unsigned int i, unsigned int max)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    unsigned int next;
 | 
					    unsigned int next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If this descriptor says it doesn't chain, we're done. */
 | 
					    /* If this descriptor says it doesn't chain, we're done. */
 | 
				
			||||||
    if (!(vring_desc_flags(vq, i) & VRING_DESC_F_NEXT))
 | 
					    if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT))
 | 
				
			||||||
        return vq->vring.num;
 | 
					        return max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Check they're not leading us off end of descriptors. */
 | 
					    /* Check they're not leading us off end of descriptors. */
 | 
				
			||||||
    next = vring_desc_next(vq, i);
 | 
					    next = vring_desc_next(desc_pa, i);
 | 
				
			||||||
    /* Make sure compiler knows to grab that: we don't want it changing! */
 | 
					    /* Make sure compiler knows to grab that: we don't want it changing! */
 | 
				
			||||||
    wmb();
 | 
					    wmb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (next >= vq->vring.num) {
 | 
					    if (next >= max) {
 | 
				
			||||||
        fprintf(stderr, "Desc next is %u", next);
 | 
					        fprintf(stderr, "Desc next is %u", next);
 | 
				
			||||||
        exit(1);
 | 
					        exit(1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -292,10 +293,12 @@ static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
 | 
					int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    unsigned int idx;
 | 
					    target_phys_addr_t desc_pa = vq->vring.desc;
 | 
				
			||||||
 | 
					    unsigned int idx, max;
 | 
				
			||||||
    int num_bufs, in_total, out_total;
 | 
					    int num_bufs, in_total, out_total;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    idx = vq->last_avail_idx;
 | 
					    idx = vq->last_avail_idx;
 | 
				
			||||||
 | 
					    max = vq->vring.num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    num_bufs = in_total = out_total = 0;
 | 
					    num_bufs = in_total = out_total = 0;
 | 
				
			||||||
    while (virtqueue_num_heads(vq, idx)) {
 | 
					    while (virtqueue_num_heads(vq, idx)) {
 | 
				
			||||||
@ -304,21 +307,21 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
 | 
				
			|||||||
        i = virtqueue_get_head(vq, idx++);
 | 
					        i = virtqueue_get_head(vq, idx++);
 | 
				
			||||||
        do {
 | 
					        do {
 | 
				
			||||||
            /* If we've got too many, that implies a descriptor loop. */
 | 
					            /* If we've got too many, that implies a descriptor loop. */
 | 
				
			||||||
            if (++num_bufs > vq->vring.num) {
 | 
					            if (++num_bufs > max) {
 | 
				
			||||||
                fprintf(stderr, "Looped descriptor");
 | 
					                fprintf(stderr, "Looped descriptor");
 | 
				
			||||||
                exit(1);
 | 
					                exit(1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
 | 
					            if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
 | 
				
			||||||
                if (in_bytes > 0 &&
 | 
					                if (in_bytes > 0 &&
 | 
				
			||||||
                    (in_total += vring_desc_len(vq, i)) >= in_bytes)
 | 
					                    (in_total += vring_desc_len(desc_pa, i)) >= in_bytes)
 | 
				
			||||||
                    return 1;
 | 
					                    return 1;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                if (out_bytes > 0 &&
 | 
					                if (out_bytes > 0 &&
 | 
				
			||||||
                    (out_total += vring_desc_len(vq, i)) >= out_bytes)
 | 
					                    (out_total += vring_desc_len(desc_pa, i)) >= out_bytes)
 | 
				
			||||||
                    return 1;
 | 
					                    return 1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num);
 | 
					        } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
@ -326,7 +329,8 @@ 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, max;
 | 
				
			||||||
 | 
					    target_phys_addr_t desc_pa = vq->vring.desc;
 | 
				
			||||||
    target_phys_addr_t len;
 | 
					    target_phys_addr_t len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!virtqueue_num_heads(vq, vq->last_avail_idx))
 | 
					    if (!virtqueue_num_heads(vq, vq->last_avail_idx))
 | 
				
			||||||
@ -335,23 +339,26 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
 | 
				
			|||||||
    /* When we start there are none of either input nor output. */
 | 
					    /* When we start there are none of either input nor output. */
 | 
				
			||||||
    elem->out_num = elem->in_num = 0;
 | 
					    elem->out_num = elem->in_num = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    max = vq->vring.num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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;
 | 
					        int is_write = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
 | 
					        if (vring_desc_flags(desc_pa, 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(desc_pa, i);
 | 
				
			||||||
            sg = &elem->in_sg[elem->in_num++];
 | 
					            sg = &elem->in_sg[elem->in_num++];
 | 
				
			||||||
            is_write = 1;
 | 
					            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(desc_pa, i);
 | 
				
			||||||
        len = sg->iov_len;
 | 
					        len = sg->iov_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sg->iov_base = cpu_physical_memory_map(vring_desc_addr(vq, i), &len, is_write);
 | 
					        sg->iov_base = cpu_physical_memory_map(vring_desc_addr(desc_pa, i),
 | 
				
			||||||
 | 
					                                               &len, is_write);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sg->iov_base == NULL || len != sg->iov_len) {
 | 
					        if (sg->iov_base == NULL || len != sg->iov_len) {
 | 
				
			||||||
            fprintf(stderr, "virtio: trying to map MMIO memory\n");
 | 
					            fprintf(stderr, "virtio: trying to map MMIO memory\n");
 | 
				
			||||||
@ -359,11 +366,11 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* If we've got too many, that implies a descriptor loop. */
 | 
					        /* If we've got too many, that implies a descriptor loop. */
 | 
				
			||||||
        if ((elem->in_num + elem->out_num) > vq->vring.num) {
 | 
					        if ((elem->in_num + elem->out_num) > max) {
 | 
				
			||||||
            fprintf(stderr, "Looped descriptor");
 | 
					            fprintf(stderr, "Looped descriptor");
 | 
				
			||||||
            exit(1);
 | 
					            exit(1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num);
 | 
					    } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    elem->index = head;
 | 
					    elem->index = head;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user