1/*
2 * Copyright (c) 2016,2017 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <barrelfish/barrelfish.h>
11#include <barrelfish/deferred.h>
12#include <devif/queue_interface.h>
13#include <devif/backends/loopback_devif.h>
14#include <devif/queue_interface_backend.h>
15
16#define LOOPBACK_QUEUE_SIZE 256
17
18struct loopback_queue
19{
20    struct devq q;
21    struct devq_buf queue[LOOPBACK_QUEUE_SIZE];
22    size_t head;
23    size_t tail;
24    size_t num_ele;
25};
26
27static errval_t loopback_enqueue(struct devq* q, regionid_t rid, genoffset_t offset,
28                             genoffset_t length, genoffset_t valid_data,
29                             genoffset_t valid_length, uint64_t flags)
30{
31    struct loopback_queue *lq = (struct loopback_queue *)q;
32
33
34    if (lq->num_ele == LOOPBACK_QUEUE_SIZE) {
35        //debug_printf("enqueue: head=%lu tail=%lu full\n", lq->head, lq->tail);
36        return DEVQ_ERR_QUEUE_FULL;
37    }
38
39    //debug_printf("enqueue: head=%lu tail=%lu \n", lq->head, lq->tail);
40    lq->queue[lq->head].offset = offset; // 8
41    lq->queue[lq->head].length = length; // 16
42    lq->queue[lq->head].valid_data = valid_data; // 24
43    lq->queue[lq->head].valid_length = valid_length; // 32
44    lq->queue[lq->head].flags = flags; // 40
45    lq->queue[lq->head].rid = rid; // 44
46
47    lq->head = (lq->head + 1) % LOOPBACK_QUEUE_SIZE;
48    lq->num_ele++;
49
50    return SYS_ERR_OK;
51}
52
53static errval_t loopback_dequeue(struct devq* q, regionid_t* rid,
54                                 genoffset_t* offset, genoffset_t* length,
55                                 genoffset_t* valid_data,
56                                 genoffset_t* valid_length, uint64_t* flags)
57{
58    struct loopback_queue *lq = (struct loopback_queue *)q;
59
60    if (lq->num_ele == 0) {
61        //debug_printf("dequeue: head=%lu tail=%lu emtpy\n", lq->head, lq->tail);
62        return DEVQ_ERR_QUEUE_EMPTY;
63    }
64
65    //debug_printf("dequeue: head=%lu tail=%lu \n", lq->head, lq->tail);
66
67    *offset = lq->queue[lq->tail].offset; // 8
68    *length = lq->queue[lq->tail].length; // 16
69    *valid_data = lq->queue[lq->tail].valid_data; // 24
70    *valid_length  =lq->queue[lq->tail].valid_length; // 32
71    *flags  = lq->queue[lq->tail].flags; // 40
72    *rid = lq->queue[lq->tail].rid; // 44
73
74    lq->tail = (lq->tail + 1) % LOOPBACK_QUEUE_SIZE;
75    lq->num_ele--;
76    return SYS_ERR_OK;
77}
78
79
80static errval_t loopback_notify(struct devq *q)
81{
82
83#if 0
84        err = devq_dequeue(q, &(buf.rid), &(buf.addr),
85                           &(buf.len), &(buf.bid), &(buf.flags));
86        if (err_is_fail(err))  {
87            return err;
88        }
89
90        err = devq_enqueue(q, buf.rid, buf.addr, buf.len,
91                           buf.flags, &buf.bid);
92        if (err_is_fail(err))  {
93            return err;
94        }
95#endif
96
97
98    return SYS_ERR_OK;
99}
100
101static errval_t loopback_register(struct devq *q, struct capref cap,
102                                regionid_t region_id)
103{
104    return SYS_ERR_OK;
105}
106
107static errval_t loopback_deregister(struct devq *q, regionid_t region_id)
108{
109    return SYS_ERR_OK;
110}
111
112static errval_t loopback_control(struct devq *q,
113                                 uint64_t request,
114                                 uint64_t value,
115                                 uint64_t *result)
116{
117    // TODO Might have some options for loopback device?
118    return SYS_ERR_OK;
119}
120
121
122static errval_t loopback_destroy(struct devq* q)
123{
124    free((struct loopback_queue*)q);
125    return SYS_ERR_OK;
126}
127
128errval_t loopback_queue_create(struct loopback_queue** q)
129{
130    errval_t err;
131
132    struct loopback_queue *lq = calloc(1, sizeof(struct loopback_queue));
133    if (lq == NULL) {
134        return LIB_ERR_MALLOC_FAIL;
135    }
136
137    err = devq_init(&lq->q, false);
138    if (err_is_fail(err)) {
139        free(lq);
140        return err;
141    }
142
143    lq->head = 0;
144    lq->tail = 0;
145    lq->num_ele = 0;
146
147    lq->q.f.enq = loopback_enqueue;
148    lq->q.f.deq = loopback_dequeue;
149    lq->q.f.reg = loopback_register;
150    lq->q.f.dereg = loopback_deregister;
151    lq->q.f.ctrl = loopback_control;
152    lq->q.f.notify = loopback_notify;
153    lq->q.f.destroy = loopback_destroy;
154
155    *q = lq;
156
157    return SYS_ERR_OK;
158}
159