2 * Copyright (c) 2016 ETH Zurich.
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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
10 #include <barrelfish/barrelfish.h>
11 #include <devif/queue_interface.h>
12 #include "desc_queue.h"
13 #include "dqi_debug.h"
16 struct __attribute__((aligned(DESCQ_ALIGNMENT))) desc {
25 union __attribute__((aligned(DESCQ_ALIGNMENT))) pointer {
31 // Shared memory of the queue
38 volatile union pointer* head;
39 volatile union pointer* tail;
47 * @brief initialized a descriptor queue
49 * @param q Return pointer to the descriptor queue
50 * @param shm Cap of the shared memory of the queue
51 * @param slots Number of slots in the queue
53 * @returns error on failure or SYS_ERR_OK on success
55 errval_t descq_init(struct descq** q,
62 // Init basic struct fields
63 tmp = malloc(sizeof(struct descq));
69 struct frame_identity id;
70 // Check if the frame is big enough
71 err = invoke_frame_identify(shm, &id);
72 if (err_is_fail(err)) {
74 return DEVQ_ERR_DESCQ_INIT;
77 if (id.bytes < DESCQ_ALIGNMENT*slots) {
79 return DEVQ_ERR_DESCQ_INIT;
82 // TODO what about the non cache coherent case?
83 err = vspace_map_one_frame_attr((void**) &(tmp->head),
84 slots*DESCQ_ALIGNMENT, shm,
85 VREGION_FLAGS_READ_WRITE, NULL, NULL);
86 if (err_is_fail(err)) {
88 return DEVQ_ERR_DESCQ_INIT;
91 tmp->tail = tmp->head + 1;
92 tmp->descs = (struct desc*) tmp->head + 2;
104 * @brief Destroys a descriptor queue and frees its resources
106 * @param q The descriptor queue
108 * @returns error on failure or SYS_ERR_OK on success
110 errval_t descq_destroy(struct descq* q)
113 err = vspace_unmap((void*) (q->descs));
114 if (err_is_fail(err)){
124 * @brief Enqueue a descriptor (as seperate fields)
125 * into the descriptor queue
127 * @param q The descriptor queue
128 * @param region_id Region id of the enqueued buffer
129 * @param buffer_id Buffer id of the buffer
130 * @param base Physical address of hte buffer
131 * @param len Lenght of the buffer
132 * @param misc_flags Miscellaneous flags
134 * @returns error if queue is full or SYS_ERR_OK on success
136 errval_t descq_enqueue(struct descq* q,
137 regionid_t region_id,
138 bufferid_t buffer_id,
144 return DEVQ_ERR_TX_FULL;
147 size_t head = q->local_head;
148 q->descs[head].rid = region_id;
149 q->descs[head].bid = buffer_id;
150 q->descs[head].addr = base;
151 q->descs[head].len = len;
152 q->descs[head].flags = misc_flags;
154 // only write local head
155 q->local_head = q->local_head + 1 % q->slots;
160 * @brief Dequeue a descriptor (as seperate fields)
161 * from the descriptor queue
163 * @param q The descriptor queue
164 * @param region_id Return pointer to the region id of
165 * the denqueued buffer
166 * @param buffer_id Return pointer to the buffer id of the buffer
167 * @param base Return pointer to the physical address
169 * @param len Return pointer to the lenght of the buffer
170 * @param misc_flags Return pointer to miscellaneous flags
172 * @returns error if queue is empty or SYS_ERR_OK on success
174 errval_t descq_dequeue(struct descq* q,
175 regionid_t* region_id,
176 bufferid_t* buffer_id,
179 uint64_t* misc_flags)
181 if (descq_empty(q)) {
182 return DEVQ_ERR_RX_EMPTY;
185 size_t tail = q->local_tail;
186 *region_id = q->descs[tail].rid;
187 *buffer_id = q->descs[tail].bid;
188 *base = q->descs[tail].addr;
189 *len = q->descs[tail].len;
190 *misc_flags = q->descs[tail].flags;
192 q->local_tail = q->local_tail + 1 % q->slots;
198 * @brief Writes the local head pointer into the shared memory
199 * making the state of the queue visible to the other end
201 * @param q The descriptor queue
204 void descq_writeout_head(struct descq* q)
206 q->head->value = q->local_head;
210 * @brief Writes the local tail pointer into the shared memory
211 * making the state of the queue visible to the other end
213 * @param q The descriptor queue
216 void descq_writeout_tail(struct descq* q)
218 q->tail->value = q->local_tail;
222 * @brief Check if the descriptor queue is full
224 * @param q The descriptor queue
226 * @returns true if the queue is full, otherwise false
228 bool descq_full(struct descq* q)
230 size_t head = q->local_head;
231 size_t tail = q->tail->value;
233 return ((q->slots - (head - tail)) == 0);
235 return ((q->slots - (head + q->slots - tail)) == 0);
239 * @brief Check if the descriptor queue is empty
241 * @param q The descriptor queue
243 * @returns true if the queue is empty, otherwise false
245 bool descq_empty(struct descq* q)
247 size_t head = q->head->value;
248 size_t tail = q->local_tail;
250 return ((head - tail) == 0);
252 return (((head + q->slots) - tail) == 0);
256 * @brief Returns the number of occupied slots in the queue
258 * @param q The descriptor queue
260 * @returns the number of occupied slots
262 size_t descq_full_slots(struct descq* q)
264 size_t head = q->head->value;
265 size_t tail = q->local_tail;
267 return (head - tail);
269 return (head + q->slots) - tail;