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/*
9 *
10 *
11 */
12#include <stdio.h>
13#include <string.h>
14
15#include <barrelfish/barrelfish.h>
16#include <barrelfish/nameservice_client.h>
17#include <flounder/flounder_txqueue.h>
18#include <dma/dma_manager_client.h>
19
20#include <if/dma_mgr_defs.h>
21
22#include "dma_mgr.h"
23#include "debug.h"
24
25/**
26 * enumration of all possible states of the service exportation process
27 */
28enum svc_state
29{
30    SVC_STATE_EXPORTING,
31    SVC_STATE_EXPORT_OK,
32    SVC_STATE_EXPORT_FAIL,
33    SVC_STATE_NS_REGISTERING,
34    SVC_STATE_NS_REGISTER_OK,
35    SVC_STATE_NS_REGISTER_FAIL,
36    SVC_STATE_RUNNING
37};
38
39/// represents the current state of the exporting process
40static enum svc_state dma_svc_state = SVC_STATE_EXPORTING;
41
42/// our own iref of the exported service
43static iref_t svc_iref;
44
45/*
46 * ----------------------------------------------------------------------------
47 * Reply State Cache
48 * ----------------------------------------------------------------------------
49 */
50struct svc_reply_st
51{
52    struct txq_msg_st common;
53
54    /* union of arguments */
55    union
56    {
57        struct dma_mgr_driver_info *lookup;
58    } args;
59};
60
61/*
62 * ----------------------------------------------------------------------------
63 * Driver Registration
64 * ----------------------------------------------------------------------------
65 */
66
67static errval_t svc_register_response_tx(struct txq_msg_st *msg_st)
68{
69
70    return dma_mgr_register_driver_response__tx(msg_st->queue->binding,
71                                                TXQCONT(msg_st), msg_st->err);
72
73}
74
75static void svc_register_call_rx(struct dma_mgr_binding *_binding,
76                                 uint64_t mem_low,
77                                 uint64_t mem_high,
78                                 uint8_t numa_node,
79                                 uint8_t type,
80                                 iref_t iref)
81{
82    errval_t err;
83
84    SVC_DEBUG("register call: [%016lx, %016lx]\n", mem_low, mem_high);
85
86    struct tx_queue *txq = _binding->st;
87
88    struct txq_msg_st *msg_st = txq_msg_st_alloc(txq);
89    if (msg_st == NULL) {
90        USER_PANIC("could not allocate reply state\n");
91    }
92
93    msg_st->send = svc_register_response_tx;
94
95    msg_st->err = driver_store_insert(mem_low, mem_high, numa_node, type, iref);
96
97    if (err_is_ok(msg_st->err)) {
98        char buf[30];
99        snprintf(buf, 30, "%s_%u_%u", DMA_MGR_REGISTERED_DRIVER, type, numa_node);
100        SVC_DEBUG("registering with nameservice {%s}\n", buf);
101        err = nameservice_register(buf, 0x123);
102        if (err_is_fail(err)) {
103            SVC_DEBUG("registering failed: %s\n", err_getstring(err));
104        }
105    }
106
107    txq_send(msg_st);
108}
109
110/*
111 * ----------------------------------------------------------------------------
112 * Query for DMA driver service
113 * ----------------------------------------------------------------------------
114 */
115
116static errval_t svc_lookup_response_tx(struct txq_msg_st *msg_st)
117{
118    struct svc_reply_st *st = (struct svc_reply_st *) msg_st;
119    struct dma_mgr_driver_info *di = st->args.lookup;
120
121    if (err_is_fail(msg_st->err)) {
122        return dma_mgr_lookup_driver_response__tx(msg_st->queue->binding,
123                                                  TXQCONT(msg_st), msg_st->err, 0, 0,
124                                                  0, 0, 0);
125    } else {
126        assert(di);
127        return dma_mgr_lookup_driver_response__tx(msg_st->queue->binding,
128                                                  TXQCONT(msg_st), msg_st->err,
129                                                  di->mem_low, di->mem_high,
130                                                  di->numa_node, di->type, di->iref);
131    }
132}
133
134static errval_t svc_lookup_by_iref_response_tx(struct txq_msg_st *msg_st)
135{
136    struct svc_reply_st *st = (struct svc_reply_st *) msg_st;
137
138    struct dma_mgr_driver_info *di = st->args.lookup;
139
140    if (err_is_fail(msg_st->err)) {
141        return dma_mgr_lookup_driver_by_iref_response__tx(msg_st->queue->binding,
142                                                          TXQCONT(msg_st),
143                                                          msg_st->err, 0, 0, 0, 0);
144    } else {
145        assert(di);
146        return dma_mgr_lookup_driver_by_iref_response__tx(msg_st->queue->binding,
147                                                          TXQCONT(msg_st),
148                                                          msg_st->err, di->mem_low,
149                                                          di->mem_high,
150                                                          di->numa_node, di->type);
151    }
152}
153
154static void svc_lookup_call_rx(struct dma_mgr_binding *_binding,
155                               uint64_t addr,
156                               uint64_t size,
157                               uint8_t numa_node)
158{
159    SVC_DEBUG("lookup call: [%016lx, %016lx]\n", addr, size);
160
161    struct tx_queue *txq = _binding->st;
162
163    struct txq_msg_st *msg_st = txq_msg_st_alloc(txq);
164    if (msg_st == NULL) {
165        USER_PANIC("could not allocate reply state\n");
166    }
167
168    msg_st->send = svc_lookup_response_tx;
169
170    struct svc_reply_st *st = (struct svc_reply_st *) msg_st;
171
172    msg_st->err = driver_store_lookup(addr, size, numa_node, &st->args.lookup);
173
174    txq_send(msg_st);
175}
176
177static void svc_lookup_by_iref_call_rx(struct dma_mgr_binding *_binding,
178                                       iref_t iref)
179{
180    SVC_DEBUG("lookup call by iref: %"PRIxIREF"\n", iref);
181
182    struct tx_queue *txq = _binding->st;
183
184    struct txq_msg_st *msg_st = txq_msg_st_alloc(txq);
185    if (msg_st == NULL) {
186        USER_PANIC("could not allocate reply state\n");
187    }
188
189    msg_st->send = svc_lookup_by_iref_response_tx;
190
191    struct svc_reply_st *st = (struct svc_reply_st *) msg_st;
192
193    msg_st->err = driver_store_lookup_by_iref(iref, &st->args.lookup);
194
195    txq_send(msg_st);
196}
197
198struct dma_mgr_rx_vtbl svc_rx_vtbl = {
199    .register_driver_call = svc_register_call_rx,
200    .lookup_driver_call = svc_lookup_call_rx,
201    .lookup_driver_by_iref_call = svc_lookup_by_iref_call_rx
202};
203
204/*
205 * ----------------------------------------------------------------------------
206 * Service export and connect handling
207 * ----------------------------------------------------------------------------
208 */
209
210static errval_t svc_connect_cb(void *st,
211                               struct dma_mgr_binding *binding)
212{
213    SVC_DEBUG("New connection to the DMA service\n");
214
215    binding->rx_vtbl = svc_rx_vtbl;
216
217    struct tx_queue *txq = calloc(1, sizeof(*txq));
218    if (txq == NULL) {
219        return LIB_ERR_MALLOC_FAIL;
220    }
221
222    txq_init(txq, binding, binding->waitset,
223             (txq_register_fn_t) binding->register_send,
224             sizeof(struct svc_reply_st));
225
226    binding->st = txq;
227
228    return SYS_ERR_OK;
229}
230
231static void svc_export_cb(void *st,
232                          errval_t err,
233                          iref_t iref)
234{
235    *((errval_t *) st) = err;
236
237    if (err_is_fail(err)) {
238        dma_svc_state = SVC_STATE_EXPORT_FAIL;
239        return;
240    }
241
242    svc_iref = iref;
243    dma_svc_state = SVC_STATE_EXPORT_OK;
244}
245
246/*
247 * ============================================================================
248 * Public Interface
249 * ============================================================================
250 */
251
252/**
253 * \brief initializes the DMA manager service service
254 *
255 * \param svc_name  The name of the service for nameservice registration
256 * \param cb        Callback function pointers
257 *
258 * \returns SYS_ERR_OK on success
259 *          errval on error
260 */
261errval_t dma_mgr_svc_start(void)
262{
263    errval_t err, export_err;
264
265    SVC_DEBUG("Initializing DMA service...\n");
266
267    err = dma_mgr_export(&export_err, svc_export_cb, svc_connect_cb,
268                         get_default_waitset(),
269                         IDC_EXPORT_FLAGS_DEFAULT);
270    if (err_is_fail(err)) {
271        return err;
272    }
273
274    while (dma_svc_state == SVC_STATE_EXPORTING) {
275        messages_wait_and_handle_next();
276    }
277
278    if (dma_svc_state == SVC_STATE_EXPORT_FAIL) {
279        return export_err;
280    }
281
282    dma_svc_state = SVC_STATE_NS_REGISTERING;
283
284    SVC_DEBUG("Registering service [%s] with iref [0x%"PRIxIREF"]\n",
285              DMA_MGR_SVC_NAME, svc_iref);
286
287    err = nameservice_register(DMA_MGR_SVC_NAME, svc_iref);
288    if (err_is_fail(err)) {
289        dma_svc_state = SVC_STATE_NS_REGISTER_FAIL;
290        return err;
291    }
292
293    dma_svc_state = SVC_STATE_RUNNING;
294
295    SVC_DEBUG("DMA service up and running.\n");
296
297    return SYS_ERR_OK;
298}
299
300