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#include <bench/bench.h>
12
13#include <dma_internal.h>
14#include <dma_device_internal.h>
15#include <dma_channel_internal.h>
16#include <dma_request_internal.h>
17#include <debug.h>
18
19/*
20 * ---------------------------------------------------------------------------
21 * Request ID generation
22 * ---------------------------------------------------------------------------
23 */
24
25inline dma_req_id_t dma_request_generate_req_id(struct dma_channel *chan)
26{
27    return dma_request_id_build(chan, dma_channel_incr_req_count(chan));
28}
29
30/**
31 * \brief initializes the common part of a DMA request
32 *
33 * \param req   DMA request to initialize
34 * \param chan  Channel this request gets executed on
35 * \param type  The type of the DMA request
36 *
37 * \return SYS_ERR_OK on success
38 *         errval on failure
39 */
40errval_t dma_request_common_init(struct dma_request *req,
41                                 struct dma_channel *chan,
42                                 dma_req_st_t type)
43{
44    req->id = dma_request_id_build(chan, dma_channel_incr_req_count(chan));
45    req->type = type;
46    req->state = DMA_REQ_ST_INVALID;
47
48#if DMA_BENCH_ENABLED
49    req->timer_start = bench_tsc();
50#endif
51    return SYS_ERR_OK;
52}
53
54/**
55 * \brief handles the processing of completed DMA requests
56 *
57 * \param req   the DMA request to process
58 *
59 * \returns SYS_ERR_OK on sucess
60 *          errval on failure
61 */
62errval_t dma_request_process(struct dma_request *req)
63{
64    DMAREQ_DEBUG("Processing done request [%016lx]:\n", req->id);
65
66    errval_t err;
67
68    switch (req->state) {
69        case DMA_REQ_ST_DONE:
70            err = SYS_ERR_OK;
71            break;
72        default:
73            err = DMA_ERR_CHAN_ERROR;  // todo: error code
74            break;
75    }
76
77#if DMA_BENCH_ENABLED
78    cycles_t timer_end = bench_tsc();
79    debug_printf("DMA request %016lx took %lu cycles (%lu ms)\n",
80                 req->id, timer_end - req->timer_start,
81                 bench_tsc_to_ms(timer_end - req->timer_start));
82#endif
83
84    if (req->setup.done_cb) {
85        req->setup.done_cb(err, req->id, req->setup.cb_arg);
86    }
87
88    return SYS_ERR_OK;
89}
90
91/*
92 * ----------------------------------------------------------------------------
93 * Getter / Setter Functions
94 * ----------------------------------------------------------------------------
95 */
96
97/**
98 * \brief returns the state of a DMA request
99 *
100 * \param req   DMA request
101 *
102 * \returns DMA request state
103 */
104inline dma_req_st_t dma_request_get_state(struct dma_request *req)
105{
106    return req->state;
107}
108
109/**
110 * \brief returns the ID of a DMA request
111 *
112 * \param req   DMA request
113 *
114 * \returns DMA request ID
115 */
116inline dma_req_id_t dma_request_get_id(struct dma_request *req)
117{
118    return req->id;
119}
120
121/**
122 * \brief returns the next DMA request of the given request
123 *
124 * \param req   DMA request
125 *
126 * \returns DMA request if there was one
127 *          NULL if the request is at the end of the chain
128 */
129inline struct dma_request *dma_request_get_next(struct dma_request *req)
130{
131    return req->next;
132}
133
134/**
135 * \brief sets the next DMA request of the given request
136 *
137 * \param req   DMA request
138 * \param next  DMA request
139 */
140inline void dma_request_set_next(struct dma_request *req,
141                                 struct dma_request *next)
142{
143    req->next = next;
144}
145
146/*
147 * ============================================================================
148 * Public Interface
149 * ============================================================================
150 */
151
152/*
153 * ----------------------------------------------------------------------------
154 * Memory Registration
155 * ----------------------------------------------------------------------------
156 */
157
158/**
159 * \brief registers a memory region for future use
160 *
161 * \param frame the memory frame to register
162 *
163 * \returns SYS_ERR_OK on succes
164 *          errval on error
165 */
166errval_t dma_register_memory(struct dma_device *dev,
167                             struct capref frame)
168{
169    if (dev->f.register_memory == NULL) {
170        return DMA_ERR_REQUEST_UNSUPPORTED;
171    }
172    return dev->f.register_memory(dev, frame);
173}
174
175/**
176 * \brief deregisters a previously registered memory region
177 *
178 * \param frame the memory frame to register
179 *
180 * \returns SYS_ERR_OK on succes
181 *          errval on error
182 */
183errval_t dma_request_deregister_memory(struct dma_device *dev,
184                                       struct capref frame)
185{
186    if (dev->f.deregister_memory == NULL) {
187        return DMA_ERR_REQUEST_UNSUPPORTED;
188    }
189    return dev->f.deregister_memory(dev, frame);
190}
191
192/*
193 * ----------------------------------------------------------------------------
194 * Request Execution
195 * ----------------------------------------------------------------------------
196 */
197
198/**
199 * \brief issues a new DMA memcpy request based on the setup information
200 *
201 * \param chan  DMA channel
202 * \param setup DMA request setup information
203 * \param id    returns the DMA request ID
204 *
205 * \returns SYS_ERR_OK on success
206 *          errval on error
207 */
208errval_t dma_request_memcpy_chan(struct dma_channel *chan,
209                                 struct dma_req_setup *setup,
210                                 dma_req_id_t *id)
211{
212    /* check for overlap */
213    if (setup->args.memcpy.dst < setup->args.memcpy.src) {
214        if ((setup->args.memcpy.dst + setup->args.memcpy.bytes) > setup->args.memcpy.src) {
215            return DMA_ERR_MEM_OVERLAP;
216        }
217    } else if ((setup->args.memcpy.dst > setup->args.memcpy.src)) {
218        if ((setup->args.memcpy.src + setup->args.memcpy.bytes) > setup->args.memcpy.dst) {
219            return DMA_ERR_MEM_OVERLAP;
220        }
221    } else {
222        /* they are equal so they will overlap */
223        return DMA_ERR_MEM_OVERLAP;
224    }
225
226    if (chan->f.memcpy == NULL) {
227        return DMA_ERR_REQUEST_UNSUPPORTED;
228    }
229
230    return chan->f.memcpy(chan, setup, id);
231}
232
233/**
234 * \brief issues a new DMA memcpy request based on the setup information
235 *
236 * \param dev   DMA device
237 * \param setup DMA request setup information
238 * \param id    returns the DMA request ID
239 *
240 * \returns SYS_ERR_OK on success
241 *          errval on error
242 */
243errval_t dma_request_memcpy(struct dma_device *dev,
244                            struct dma_req_setup *setup,
245                            dma_req_id_t *id)
246{
247    struct dma_channel *chan = dma_device_get_channel(dev);
248    return dma_request_memcpy_chan(chan, setup, id);
249}
250
251/**
252 * \brief issues a new DMA memcpy request based on the setup information
253 *
254 * \param chan  DMA channel
255 * \param setup DMA request setup information
256 * \param id    returns the DMA request ID
257 *
258 * \returns SYS_ERR_OK on success
259 *          errval on error
260 */
261errval_t dma_request_memset_chan(struct dma_channel *chan,
262                                 struct dma_req_setup *setup,
263                                 dma_req_id_t *id)
264{
265    if (chan->f.memset == NULL) {
266        return DMA_ERR_REQUEST_UNSUPPORTED;
267    }
268
269    return chan->f.memset(chan, setup, id);
270}
271
272/**
273 * \brief issues a new DMA memcpy request based on the setup information
274 *
275 * \param dev   DMA device
276 * \param setup DMA request setup information
277 * \param id    returns the DMA request ID
278 *
279 * \returns SYS_ERR_OK on success
280 *          errval on error
281 */
282errval_t dma_request_memset(struct dma_device *dev,
283                            struct dma_req_setup *setup,
284                            dma_req_id_t *id)
285{
286    struct dma_channel *chan = dma_device_get_channel(dev);
287    return dma_request_memset_chan(chan, setup, id);
288}
289
290
291