| #ifndef _VIRTIO_RING_H |
| #define _VIRTIO_RING_H |
| |
| #include "types.h" // u64 |
| #include "memmap.h" // PAGE_SIZE |
| |
| /* Status byte for guest to report progress, and synchronize features. */ |
| /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ |
| #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 |
| /* We have found a driver for the device. */ |
| #define VIRTIO_CONFIG_S_DRIVER 2 |
| /* Driver has used its parts of the config, and is happy */ |
| #define VIRTIO_CONFIG_S_DRIVER_OK 4 |
| /* Driver has finished configuring features */ |
| #define VIRTIO_CONFIG_S_FEATURES_OK 8 |
| /* We've given up on this device. */ |
| #define VIRTIO_CONFIG_S_FAILED 0x80 |
| |
| /* v1.0 compliant. */ |
| #define VIRTIO_F_VERSION_1 32 |
| #define VIRTIO_F_IOMMU_PLATFORM 33 |
| |
| #define MAX_QUEUE_NUM (256) |
| |
| #define VRING_DESC_F_NEXT 1 |
| #define VRING_DESC_F_WRITE 2 |
| |
| #define VRING_AVAIL_F_NO_INTERRUPT 1 |
| |
| #define VRING_USED_F_NO_NOTIFY 1 |
| |
| struct vring_desc |
| { |
| u64 addr; |
| u32 len; |
| u16 flags; |
| u16 next; |
| }; |
| |
| struct vring_avail |
| { |
| u16 flags; |
| u16 idx; |
| u16 ring[0]; |
| }; |
| |
| struct vring_used_elem |
| { |
| u32 id; |
| u32 len; |
| }; |
| |
| struct vring_used |
| { |
| u16 flags; |
| u16 idx; |
| struct vring_used_elem ring[]; |
| }; |
| |
| struct vring { |
| unsigned int num; |
| struct vring_desc *desc; |
| struct vring_avail *avail; |
| struct vring_used *used; |
| }; |
| |
| #define vring_size(num) \ |
| (ALIGN(sizeof(struct vring_desc) * num + sizeof(struct vring_avail) \ |
| + sizeof(u16) * num, PAGE_SIZE) \ |
| + sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num) |
| |
| typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)]; |
| |
| struct vring_virtqueue { |
| virtio_queue_t queue; |
| struct vring vring; |
| u16 free_head; |
| u16 last_used_idx; |
| u16 vdata[MAX_QUEUE_NUM]; |
| /* PCI */ |
| int queue_index; |
| int queue_notify_off; |
| }; |
| |
| struct vring_list { |
| char *addr; |
| unsigned int length; |
| }; |
| |
| static inline void |
| vring_init(struct vring *vr, unsigned int num, unsigned char *queue) |
| { |
| ASSERT32FLAT(); |
| vr->num = num; |
| |
| /* physical address of desc must be page aligned */ |
| vr->desc = (void*)ALIGN((u32)queue, PAGE_SIZE); |
| |
| vr->avail = (struct vring_avail *)&vr->desc[num]; |
| /* disable interrupts */ |
| vr->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; |
| |
| /* physical address of used must be page aligned */ |
| vr->used = (void*)ALIGN((u32)&vr->avail->ring[num], PAGE_SIZE); |
| |
| int i; |
| for (i = 0; i < num - 1; i++) |
| vr->desc[i].next = i + 1; |
| vr->desc[i].next = 0; |
| } |
| |
| struct vp_device; |
| int vring_more_used(struct vring_virtqueue *vq); |
| void vring_detach(struct vring_virtqueue *vq, unsigned int head); |
| int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len); |
| void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[], |
| unsigned int out, unsigned int in, |
| int index, int num_added); |
| void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added); |
| |
| #endif /* _VIRTIO_RING_H_ */ |