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 <barrelfish/barrelfish.h>
11
12#include <dma_internal.h>
13#include <dma_device_internal.h>
14#include <dma_channel_internal.h>
15#include <dma_request_internal.h>
16
17#include <debug.h>
18
19/*
20 * ============================================================================
21 * Library Internal Interface
22 * ============================================================================
23 */
24
25/*
26 * ----------------------------------------------------------------------------
27 * Request List Management
28 * ----------------------------------------------------------------------------
29 */
30
31/**
32 * \brief returns the first request on the submitted request queue of the channel
33 *
34 * \param chan  DMA channel
35 *
36 * \returns pointer to the DMA request
37 *          NULL if queue was empty
38 */
39struct dma_request *dma_channel_deq_request_head(struct dma_channel *chan)
40{
41    struct dma_request *req = chan->req_list.head;
42    if (req == NULL) {
43        assert(chan->req_list.count == 0);
44        return NULL;
45    }
46
47    chan->req_list.count--;
48
49    chan->req_list.head = dma_request_get_next(req);
50    if (chan->req_list.head == NULL) {
51        chan->req_list.tail = NULL;
52        assert(chan->req_list.count == 0);
53    }
54
55    DMACHAN_DEBUG("request : deq head [%016lx] count=%u\n", chan->id,
56                  dma_request_get_id(req), chan->req_list.count);
57
58    return req;
59}
60
61/**
62 * \brief returns the request with the given request ID
63 *
64 * \param chan  DMA channel
65 * \param id    DMA request id
66 *
67 * \returns pointer to the DMA request
68 *          NULL if queue was empty
69 */
70struct dma_request *dma_channel_deq_request_by_id(struct dma_channel *chan,
71                                                  dma_req_id_t id)
72{
73    struct dma_request *req = chan->req_list.head;
74    if (req == NULL) {
75        assert(chan->req_list.count == 0);
76        return NULL;
77    }
78    while(req) {
79        if (req->id == id) {
80            if (req->prev != NULL) {
81                req->prev->next = req->next;
82            }
83
84            if (req->next != NULL) {
85                req->next->prev = req->prev;
86            }
87            chan->req_list.count--;
88            if (chan->req_list.count == 0) {
89                assert(chan->req_list.head == chan->req_list.tail);
90                chan->req_list.head = NULL;
91                chan->req_list.tail = NULL;
92            }
93            req->next = NULL;
94            req->prev = NULL;
95            return req;
96        }
97        req = req->next;
98    }
99    return NULL;
100}
101
102/**
103 * \brief inserts a request into the channels request list
104 *
105 * \param chan  DMA channel
106 * \param req   DMA request to be inserted
107 */
108void dma_channel_enq_request_head(struct dma_channel *chan,
109                                  struct dma_request *req)
110{
111    dma_request_set_next(req, chan->req_list.head);
112
113    chan->req_list.count++;
114
115    chan->req_list.head = req;
116    if (chan->req_list.tail == NULL) {
117        chan->req_list.tail = req;
118        assert(chan->req_list.count == 1);
119    }
120
121    DMACHAN_DEBUG("request : enq head [%016lx] count=%u\n", chan->id,
122                  dma_request_get_id(req), chan->req_list.count);
123}
124
125/**
126 * \brief inserts a request at the end of the channels request list
127 *
128 * \param chan  DMA channel
129 * \param req   DMA request to be inserted
130 */
131void dma_channel_enq_request_tail(struct dma_channel *chan,
132                                  struct dma_request *req)
133{
134    dma_request_set_next(req, NULL);
135
136    if (chan->req_list.head == NULL) {
137        assert(chan->req_list.count == 0);
138        chan->req_list.head = req;
139    } else {
140        assert(chan->req_list.count > 0);
141        dma_request_set_next(chan->req_list.tail, req);
142    }
143
144    chan->req_list.tail = req;
145
146    chan->req_list.count++;
147
148    DMACHAN_DEBUG("request : enq tail [%016lx] count=%u\n", chan->id,
149                  dma_request_get_id(req), chan->req_list.count);
150}
151
152/*
153 * ============================================================================
154 * Public Interface
155 * ============================================================================
156 */
157
158/**
159 * \brief polls the DMA channel for completed events
160 *
161 * \param chan  DMA Channel
162 *
163 * \returns SYS_ERR_OK if there was something processed
164 *          DMA_ERR_CHAN_IDLE if there was no request on the channel
165 *          DMA_ERR_REQUEST_UNFINISHED if the request has not been completed yet
166 *
167 */
168inline errval_t dma_channel_poll(struct dma_channel *chan)
169{
170    if (chan->f.poll) {
171        return chan->f.poll(chan);
172    }
173    return DMA_ERR_DEVICE_UNSUPPORTED;
174}
175
176/*
177 * ----------------------------------------------------------------------------
178 * Getter / Setter Methods
179 * ----------------------------------------------------------------------------
180 */
181
182/**
183 * \brief gets the ID of the channel
184 *
185 * \param DMA channel
186 *
187 * \returns DMA channel ID
188 */
189inline dma_chan_id_t dma_channel_get_id(struct dma_channel *chan)
190{
191    return chan->id;
192}
193
194/**
195 * \brief gets the state of the channel
196 *
197 * \param DMA channel
198 *
199 * \returns DMA channel state
200 */
201inline dma_chan_st_t dma_channel_get_state(struct dma_channel *chan)
202{
203    return chan->state;
204}
205
206/**
207 * \brief gets the DMA device this channel belongs to
208 *
209 * \param DMA channel
210 *
211 * \returns DMA device
212 */
213inline struct dma_device *dma_channel_get_device(struct dma_channel *chan)
214{
215    return chan->device;
216}
217
218/**
219 * \brief gets the number of unfinished requests on this channel
220 *
221 * \param DMA channel
222 *
223 * \returns request count
224 */
225inline uint32_t dma_channel_get_request_count(struct dma_channel *chan)
226{
227    return chan->req_list.count;
228}
229
230/**
231 * \brief gets the address where the MMIO registers are mapped
232 *
233 * \param DMA channel
234 *
235 * \returns MMIO register vbase
236 */
237inline lvaddr_t dma_channel_get_mmio_vbase(struct dma_channel *chan)
238{
239    return chan->mmio.vaddr;
240}
241
242/**
243 * \brief gets the maximum transfer size of the channel
244 *
245 * \param DMA channel
246 *
247 * \returns maximum transfer size in bytes
248 */
249inline uint32_t dma_channel_get_max_xfer_size(struct dma_channel *chan)
250{
251    return chan->max_xfer_size;
252}
253