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 <string.h>
11#include <barrelfish/barrelfish.h>
12#include <barrelfish/nameservice_client.h>
13
14#include <dma_internal.h>
15#include <dma/dma_manager_client.h>
16#include <debug.h>
17
18#include <if/dma_mgr_defs.h>
19#include <if/dma_mgr_defs.h>
20
21/// DMA manager RPC client
22static struct dma_mgr_binding *dma_mgr_client;
23
24/// connected flag
25uint8_t dma_mgr_connected = 0x0;
26
27/// state for binding
28struct dma_mgr_bind_st
29{
30    uint8_t bound;
31    errval_t err;
32};
33
34/*
35 * ---------------------------------------------------------------------------
36 * Service Binding
37 * ---------------------------------------------------------------------------
38 */
39
40static void bind_cb(void *st,
41                    errval_t err,
42                    struct dma_mgr_binding *b)
43{
44    assert(st);
45    struct dma_mgr_bind_st *bindst = st;
46
47    bindst->err = err;
48
49    if (err_is_fail(err)) {
50        DMAMGR_DEBUG("connect: connection to {%s} failed.\n", DMA_MGR_SVC_NAME);
51        bindst->bound = 0x1;
52        return;
53    }
54
55    DMAMGR_DEBUG("connect: connection to {%s} established.\n", DMA_MGR_SVC_NAME);
56    dma_mgr_client = b;
57    dma_mgr_rpc_client_init(dma_mgr_client);
58
59    bindst->bound = 0x1;
60}
61
62static errval_t dma_manager_connect(void)
63{
64    errval_t err;
65    iref_t iref;
66
67    DMAMGR_DEBUG("connect: looking up service name {%s}\n", DMA_MGR_SVC_NAME);
68    err = nameservice_blocking_lookup(DMA_MGR_SVC_NAME, &iref);
69    if (err_is_fail(err)) {
70        return err;
71    }
72
73    struct dma_mgr_bind_st st = {
74        .bound = 0x0
75    };
76
77    DMAMGR_DEBUG("connect: binding to iref [%"PRIxIREF"]\n", iref);
78    struct waitset *ws = get_default_waitset();
79    err = dma_mgr_bind(iref, bind_cb, &st, ws, IDC_BIND_FLAGS_DEFAULT);
80    if (err_is_fail(err)) {
81        return err;
82    }
83
84    while (st.bound == 0x0) {
85        messages_wait_and_handle_next();
86    }
87
88    if (err_is_ok(st.err)) {
89        dma_mgr_connected = 0x1;
90    }
91
92    return st.err;
93}
94
95/*
96 * ============================================================================
97 * Public Interface
98 * ============================================================================
99 */
100
101/**
102 * \brief initializes the connection to the DMA manager service in an eager way
103 *
104 * \returns SYS_ERR_OK on success
105 *          errval on error
106 */
107errval_t dma_manager_client_init(void)
108{
109    errval_t err;
110
111    if (dma_mgr_connected == 0) {
112        err = dma_manager_connect();
113        if (err_is_fail(err)) {
114            return err;
115        }
116    }
117    return SYS_ERR_OK;
118}
119
120/**
121 * \brief registers a DMA driver with the DMA driver manager
122 *
123 * \param mem_low   lower end of the supported memory range
124 * \param mem_high  upper end of the supported memory range
125 * \param type      DMA device type
126 * \param iref      the iref of the exported DMA service
127 *
128 * \returns SYS_ERR_OK on success
129 *          DMA_ERR_* on failure
130 */
131errval_t dma_manager_register_driver(lpaddr_t mem_low,
132                                     lpaddr_t mem_high,
133                                     uint8_t type,
134                                     iref_t iref)
135{
136#ifdef __k1om__
137    char buf[30];
138    snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER,
139             (uint8_t) DMA_DEV_TYPE_XEON_PHI, disp_xeon_phi_id());
140
141    DMAMGR_DEBUG("registering Xeon Phi Driver: {%s}\n", buf);
142
143    return nameservice_register(buf, iref);
144#else
145    errval_t err;
146    errval_t msgerr;
147
148    if (dma_mgr_connected == 0) {
149        err = dma_manager_connect();
150        if (err_is_fail(err)) {
151            return err;
152        }
153    }
154
155    DMAMGR_DEBUG("register driver: {%016lx, %016lx} @ %"PRIxIREF"\n", mem_low,
156                    mem_high, iref);
157
158    //XXX need to figure this out otherwise
159    uint8_t numa_node = (disp_get_core_id() >= 20);
160
161    err = dma_mgr_client->rpc_tx_vtbl.register_driver(dma_mgr_client, mem_low, mem_high,
162                    numa_node, type, iref, &msgerr);
163    if (err_is_fail(err)) {
164        DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err));
165        return err;
166    }
167
168    return msgerr;
169#endif
170}
171
172/**
173 * \brief queries the DMA manager for a suitable DMA driver for a address, size
174 *        pair
175 *
176 * \param addr      address of the transfer
177 * \param size      size of the desired transfer
178 * \param info      returns the driver info
179 *
180 * \returns SYS_ERR_OK on success
181 *          DMA_ERR_* on failure
182 */
183errval_t dma_manager_lookup_driver(lpaddr_t addr,
184                                   lpaddr_t size,
185                                   struct dma_mgr_driver_info *info)
186{
187#ifdef __k1om__
188    errval_t err;
189
190    if (addr + size > (1UL << 40)) {
191        return DMA_ERR_MEM_OUT_OF_RANGE;
192    }
193
194    char buf[30];
195    snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER,
196             (uint8_t) DMA_DEV_TYPE_XEON_PHI, disp_xeon_phi_id());
197
198    err = nameservice_lookup(buf, &info->iref);
199    if (err_is_fail(err)) {
200        return DMA_ERR_SVC_VOID;
201    }
202    info->mem_high = (1UL << 40);
203    info->mem_low = 0;
204    info->numa_node = disp_xeon_phi_id();
205    info->type = DMA_DEV_TYPE_XEON_PHI;
206    return SYS_ERR_OK;
207#else
208
209    errval_t err, msgerr;
210
211    if (dma_mgr_connected == 0) {
212        err = dma_manager_connect();
213        if (err_is_fail(err)) {
214            return err;
215        }
216    }
217
218    DMAMGR_DEBUG("lookup driver: [%016lx, %016lx]\n", addr, size);
219
220    uint8_t numa_node = (disp_get_core_id() >= 20);
221
222    err = dma_mgr_client->rpc_tx_vtbl.lookup_driver(dma_mgr_client, addr, size,
223                    numa_node, &msgerr, &info->mem_low,
224                    &info->mem_high, &info->numa_node,
225                    (uint8_t*) &info->type, &info->iref);
226    if (err_is_fail(err)) {
227        DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err));
228        return err;
229    }
230
231    return msgerr;
232#endif
233}
234
235/**
236 * \brief queries the DMA driver manager based on the service iref
237 *
238 * \param iref      iref ot the exported driver service
239 * \param info      returns the driver info
240 *
241 * \returns SYS_ERR_OK on success
242 *          DMA_ERR_* on failure
243 */
244errval_t dma_manager_lookup_by_iref(iref_t iref,
245                                    struct dma_mgr_driver_info *info)
246{
247#ifdef __k1om__
248    info->mem_high = (1UL << 40);
249    info->mem_low = 0;
250    info->numa_node = disp_xeon_phi_id();
251    info->type = DMA_DEV_TYPE_XEON_PHI;
252    info->iref = iref;
253    return SYS_ERR_OK;
254#else
255    errval_t err, msgerr;
256
257    if (dma_mgr_connected == 0) {
258        err = dma_manager_connect();
259        if (err_is_fail(err)) {
260            return err;
261        }
262    }
263
264    DMAMGR_DEBUG("lookup driver by iref:%"PRIxIREF"\n", iref);
265
266    err = dma_mgr_client->rpc_tx_vtbl.lookup_driver_by_iref(dma_mgr_client, iref,
267                                                    &msgerr, &info->mem_low,
268                                                    &info->mem_high,
269                                                    &info->numa_node,
270                                                    (uint8_t*) &info->type);
271    if (err_is_fail(err)) {
272        DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err));
273        return err;
274    }
275
276    info->iref = iref;
277
278    return msgerr;
279#endif
280}
281
282/**
283 * \brief waits until a device driver for the supplied device type is ready
284 *
285 * \param device    DMA device type
286 * \param numa_node Numanode of the DMA device driver
287 *
288 * \returns SYS_ERR_OK when the driver is ready
289 *          errval if there was something wrong
290 */
291errval_t dma_manager_wait_for_driver(dma_dev_type_t device,
292                                     uint8_t numa_node)
293{
294    char buf[30];
295    snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER, (uint8_t) device,
296             numa_node);
297
298    DMAMGR_DEBUG("waiting for driver: {%s}\n", buf);
299
300    iref_t dummy_iref;
301    return nameservice_blocking_lookup(buf, &dummy_iref);
302}
303