Bugfixes Xeon Phi Driver startup - removed check for boot info - added initialization...
[barrelfish] / lib / virtio / vbuffer.c
1 /*
2  * Copyright (c) 2014 ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 #include <string.h>
11
12 #include <barrelfish/barrelfish.h>
13
14 #include <virtio/virtio.h>
15
16 #include "vbuffer.h"
17
18 /**
19  * \brief   initializes the buffer allocator and allocates memory for the
20  *          buffers
21  *
22  * \param   alloc   the allocator struct to initialize
23  * \param   nbufs   number of buffers to allocate
24  * \param   bufsz   size of each buffer to allocate
25  *
26  * \return  SYS_ERR_OK on success
27  */
28 errval_t virtio_buffer_alloc_init(struct virtio_buffer_allocator **alloc,
29                                   size_t nbufs,
30                                   size_t bufsz)
31 {
32     errval_t err;
33
34     if (!alloc) {
35         return VIRTIO_ERR_ARG_INVALID;
36     }
37
38     if (nbufs == 0) {
39         return VIRTIO_ERR_NO_BUFFER;
40     }
41
42     size_t size = ROUND_UP(bufsz, BASE_PAGE_SIZE);
43     if (size != bufsz) {
44         debug_printf("WARNING: buffer size rounded up to multiple of page size:"
45                      "[%lx] -> [%lx]\n",
46                      (uint64_t) bufsz, (uint64_t) size);
47     }
48
49     struct capref frame;
50     err = frame_alloc(&frame, size * nbufs, NULL);
51     if (err_is_fail(err)) {
52         return err;
53     }
54
55     struct frame_identity id;
56     err = invoke_frame_identify(frame, &id);
57     if (err_is_fail(err)) {
58         cap_destroy(frame);
59         return err;
60     }
61
62     void *buf;
63     err = vspace_map_one_frame_attr(&buf,
64                                     size * nbufs,
65                                     frame,
66                                     VIRTIO_VREGION_FLAGS_RING,
67                                     NULL,
68                                     NULL);
69     if (err_is_fail(err)) {
70         cap_destroy(frame);
71         return err;
72     }
73
74     struct virtio_buffer_allocator *vbuf_alloc;
75
76     vbuf_alloc = malloc(sizeof(*vbuf_alloc));
77     if (vbuf_alloc == NULL) {
78         vspace_unmap(buf);
79         return LIB_ERR_MALLOC_FAIL;
80     }
81
82     vbuf_alloc->buffers = calloc(nbufs, sizeof(void *));
83     if (vbuf_alloc->buffers == NULL) {
84         vspace_unmap(buf);
85         free(vbuf_alloc);
86         return LIB_ERR_MALLOC_FAIL;
87     }
88
89     void *buffers = malloc(nbufs * sizeof(struct virtio_buffer));
90     if (buffers == NULL) {
91         vspace_unmap(buf);
92         free(vbuf_alloc->buffers);
93         free(vbuf_alloc);
94         return LIB_ERR_MALLOC_FAIL;
95     }
96
97     vbuf_alloc->cap = frame;
98     vbuf_alloc->size = nbufs;
99     vbuf_alloc-> top = nbufs;
100
101     struct virtio_buffer *vbuf;
102     for (uint32_t i = 0; i < nbufs; ++i) {
103         vbuf = buffers + i;
104         vbuf = vbuf_alloc->buffers[i];
105         vbuf->buf = (((uint8_t*)buf)+i*size);
106         vbuf->length = size;
107         vbuf->paddr = id.base +i*size;
108         vbuf->state = VIRTIO_BUFFER_S_FREE;
109         vbuf->a = vbuf_alloc;
110         vbuf_alloc->buffers[i] = vbuf;
111     }
112     vbuf_alloc->size = size;
113     vbuf_alloc->top = size;
114
115     *alloc = vbuf_alloc;
116
117     return SYS_ERR_OK;
118 }
119
120 /**
121  * \brief   destroys a buffer allocator by freeing up all the resources used
122  *          by the buffers
123  *
124  * \param   alloc   the allocator to destroy
125  *
126  * \returns SYS_ERR_OK on success
127  */
128 errval_t virtio_buffer_alloc_destroy(struct virtio_buffer_allocator *alloc)
129 {
130     assert(!"NYI: virtio_buffer_alloc_destroy");
131     return SYS_ERR_OK;
132 }
133
134 struct virtio_buffer *virtio_buffer_alloc(struct virtio_buffer_allocator *alloc)
135 {
136     if (alloc->top == 0) {
137         return NULL;
138     }
139     struct virtio_buffer *buf = alloc->buffers[--alloc->top];
140
141     assert(buf->state == VIRTIO_BUFFER_S_FREE);
142     buf->state = VIRTIO_BUFFER_S_ALLOCED;
143     return buf;
144 }
145
146 /**
147  * \brief   frees up a unused buffer by returning it to the allocator
148  *
149  * \param   buf     the buffer to be freed
150  */
151 errval_t virtio_buffer_free(struct virtio_buffer *buf)
152 {
153     struct virtio_buffer_allocator *alloc = buf->a;
154     if (alloc->top >= alloc->size) {
155         /* this should actually not happen */
156         return VIRTIO_ERR_ALLOC_FULL;
157     }
158
159     assert(buf->state == VIRTIO_BUFFER_S_ALLOCED);
160     buf->state = VIRTIO_BUFFER_S_FREE;
161
162     alloc->buffers[alloc->top++] = buf;
163
164     return SYS_ERR_OK;
165 }
166
167 /**
168  * \brief   returns the backing frame capability of a buffer allocator
169  */
170 errval_t virtio_buffer_alloc_get_cap(struct virtio_buffer_allocator *alloc,
171                                      struct capref *ret_cap)
172 {
173     *ret_cap = alloc->cap;
174     return SYS_ERR_OK;
175 }
176
177 /**
178  * \brief initializes a new VirtIO buffer list to be used for chaining buffers
179  *
180  * \param bl buffer list to initialize
181  *
182  * \return SYS_ERR_OK on success
183  */
184 errval_t virtio_blist_init(struct virtio_buffer_list *bl)
185 {
186     memset(bl, 0, sizeof(*bl));
187     return SYS_ERR_OK;
188 }
189
190 /**
191  * \brief frees up the buffer list by returning the buffers to the allocator
192  *
193  * \param bl buffer list to be freed
194  *
195  * \returns SYS_ERR_OK on success
196  */
197 errval_t virtio_blist_free(struct virtio_buffer_list *bl)
198 {
199     errval_t err;
200     struct virtio_buffer *buf = virtio_blist_get(bl);
201     while(buf) {
202         err = virtio_buffer_free(buf);
203         assert(err_is_ok(err));
204         buf = virtio_blist_get(bl);
205     }
206     return SYS_ERR_OK;
207 }
208
209 /**
210  * \brief appends a buffer to the tail of buffer list
211  *
212  * \param bl    the list to append the buffer to
213  * \param buf   the buffer to be appended
214  */
215 errval_t virtio_blist_append(struct virtio_buffer_list *bl,
216                              struct virtio_buffer *buf)
217 {
218     if (buf->lhead) {
219         return VIRTIO_ERR_BUF_USED;
220     }
221     if (bl->length == 0) {
222         bl->head = buf;
223         bl->tail = buf;
224     } else {
225         bl->tail->next = buf;
226         bl->tail = buf;
227     }
228     buf->lhead = bl;
229     buf->next = NULL;
230     bl->length++;
231     return SYS_ERR_OK;
232 }
233
234 /**
235  * \brief returns and removes the head of the list
236  *
237  * \param bl buffer list
238  *
239  * \returns pointer to virtio_buffer on sucess
240  *          NULL on failuer
241  */
242 struct virtio_buffer *virtio_blist_get(struct virtio_buffer_list *bl)
243 {
244     if (bl->length == 0) {
245         return NULL;
246     }
247
248     struct virtio_buffer *buf;
249     buf = bl->head;
250     if (bl->length == 1) {
251         bl->head = NULL;
252         bl->tail = NULL;
253     } else {
254         bl->head = buf->next;
255     }
256
257     bl->length--;
258
259     buf->next = NULL;
260     buf->lhead = NULL;
261
262     return buf;
263 }
264