summaryrefslogtreecommitdiff
path: root/gpxe/src/include/gpxe/virtio-ring.h
blob: e96dd371d8dbaceb558ffe00a42330e4405f67b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#ifndef _VIRTIO_RING_H_
# define _VIRTIO_RING_H_
#define PAGE_SHIFT (12)
#define PAGE_SIZE  (1<<PAGE_SHIFT)
#define PAGE_MASK  (PAGE_SIZE-1)

/* 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
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED          0x80

#define MAX_QUEUE_NUM      (512)

#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) \
   (((((sizeof(struct vring_desc) * num) + \
      (sizeof(struct vring_avail) + sizeof(u16) * num)) \
         + PAGE_MASK) & ~PAGE_MASK) + \
         (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))

typedef unsigned char virtio_queue_t[PAGE_MASK + 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;
};

struct vring_list {
  char *addr;
  unsigned int length;
};

static inline void vring_init(struct vring *vr,
                         unsigned int num, unsigned char *queue)
{
   unsigned int i;
   unsigned long pa;

        vr->num = num;

   /* physical address of desc must be page aligned */

   pa = virt_to_phys(queue);
   pa = (pa + PAGE_MASK) & ~PAGE_MASK;
   vr->desc = phys_to_virt(pa);

        vr->avail = (struct vring_avail *)&vr->desc[num];

   /* physical address of used must be page aligned */

   pa = virt_to_phys(&vr->avail->ring[num]);
   pa = (pa + PAGE_MASK) & ~PAGE_MASK;
        vr->used = phys_to_virt(pa);

   for (i = 0; i < num - 1; i++)
           vr->desc[i].next = i + 1;
   vr->desc[i].next = 0;
}

static inline void vring_enable_cb(struct vring_virtqueue *vq)
{
   vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
}

static inline void vring_disable_cb(struct vring_virtqueue *vq)
{
   vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
}


/*
 * vring_more_used
 *
 * is there some used buffers ?
 *
 */

static inline int vring_more_used(struct vring_virtqueue *vq)
{
   wmb();
   return vq->last_used_idx != vq->vring.used->idx;
}

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(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);

#endif /* _VIRTIO_RING_H_ */