1/*
2 * Copyright (c) 2014, ETH Zurich. All rights reserved.
3 *
4 * This file is distributed under the terms in the attached LICENSE file.
5 * If you do not find this file, copies can be found by writing to:
6 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
7 */
8#include <barrelfish/barrelfish.h>
9
10#include <dma/dma.h>
11#include <dma/dma_service.h>
12#include <dma/dma_mem_mgr.h>
13#include <dma/ioat/ioat_dma_request.h>
14
15#include "device.h"
16#include "dma_service.h"
17
18#include "debug.h"
19
20struct user_st
21{
22    struct dma_mem_mgr *mem_mgr;
23    uint64_t num_req;
24};
25
26/*
27 * ---------------------------------------------------------------------------
28 * Request done callbacks
29 * ---------------------------------------------------------------------------
30 */
31
32static void memcpy_req_cb(errval_t err, dma_req_id_t id, void *st)
33{
34    DMA_DEBUG("memcpy_req_cb %lx, %s\n", id, err_getstring(err));
35    dma_service_send_done(st, err, id);
36}
37
38/*
39 * ---------------------------------------------------------------------------
40 *
41 * ---------------------------------------------------------------------------
42 */
43
44
45/*
46 * \brief callback handler for new connect requests
47 *
48 * \param user_st   pointer to store the user state
49 *
50 * \returns SYS_ERR_OK if the connection is accepted
51 *          errval if connection is rejected
52 */
53errval_t dma_svc_connect_cb(void *arg, void **user_st)
54{
55    errval_t err;
56
57    struct user_st *st = calloc(1, sizeof(*st));
58    if (st == NULL) {
59        return LIB_ERR_MALLOC_FAIL;
60    }
61
62    DMA_DEBUG("dma_svc_connect_cb user_st = %p\n", st);
63
64    err = dma_mem_mgr_init(&st->mem_mgr, 0x0, (1UL << 48) - 1);
65    if (err_is_fail(err)) {
66        free(st);
67        return err;
68    }
69
70    *user_st = st;
71
72    return SYS_ERR_OK;
73}
74
75/**
76 * \brief registers a memory region with the client such that it can be used later
77 *
78 * \param user_st   pointer to stored user state
79 * \param cap       the capability to register
80 *
81 * \returns SYS_ERR_OK if the memory region was accepted
82 *          errval if the memory region was rejected
83 */
84errval_t dma_svc_addregion_cb(dma_svc_handle_t svc_handle,
85                              struct capref cap)
86{
87    struct user_st *user_st = dma_service_get_user_state(svc_handle);
88
89    DMA_DEBUG("dma_svc_addregion_cb user_st = %p\n", user_st);
90
91    return dma_mem_register(user_st->mem_mgr, cap, NULL);
92}
93
94/**
95 * \brief deregisters a memory region with the client
96 *
97 * \param user_st   pointer to stored user state
98 * \param cap       the capability to deregister
99 *
100 * \returns SYS_ERR_OK if the memory region was removed
101 *          errval if the memory region removal was rejected
102 */
103errval_t dma_svc_removeregion_cb(dma_svc_handle_t svc_handle,
104                                 struct capref cap)
105{
106    struct user_st *user_st = dma_service_get_user_state(svc_handle);
107
108    DMA_DEBUG("dma_svc_removeregion_cb user_st = %p\n", user_st);
109
110    return dma_mem_deregister(user_st->mem_mgr, cap);
111}
112
113/**
114 * \brief executes a DMA memcpy
115 *
116 * \param user_st   pointer to stored user state
117 * \param dst       the physical destination address
118 * \param src       the physical source address
119 * \param bytes     size of the transfer in bytes
120 * \param id        returns the DMA request ID of the transfer
121 *
122 * \returns SYS_ERR_OK if the memory region was removed
123 *          errval if the memory region removal was rejected
124 */
125errval_t dma_svc_memcpy_cb(dma_svc_handle_t svc_handle,
126                           lpaddr_t dst,
127                           lpaddr_t src,
128                           size_t bytes,
129                           dma_req_id_t *id)
130{
131    errval_t err;
132
133    struct user_st *st = dma_service_get_user_state(svc_handle);
134
135    DMA_DEBUG("dma_svc_memcpy_cb user_st = %p\n", st);
136
137    lpaddr_t dma_dst, dma_src;
138    err = dma_mem_verify(st->mem_mgr, dst, bytes, &dma_dst);
139    if (err_is_fail(err)) {
140        return err;
141    }
142    err = dma_mem_verify(st->mem_mgr, src, bytes, &dma_src);
143    if (err_is_fail(err)) {
144        return err;
145    }
146
147    DMA_DEBUG("[%016lx]->[%016lx] of %lu bytes\n", dma_src, dma_dst, bytes);
148
149
150    /* both addresses are valid and have been translated now */
151    struct ioat_dma_device *dev = ioat_device_get_next();
152    assert(dev);
153
154    struct dma_req_setup setup = {
155        .type = DMA_REQ_TYPE_MEMCPY,
156        .done_cb = memcpy_req_cb,
157        .cb_arg = svc_handle,
158        .args = {
159            .memcpy = {
160                .src = dma_src,
161                .dst = dma_dst,
162                .bytes = bytes
163            }
164        }
165    };
166
167    return ioat_dma_request_memcpy((struct dma_device *)dev, &setup, id);
168}
169