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 <barrelfish/nameservice_client.h>
12
13#include <if/xeon_phi_manager_defs.h>
14
15#include "service.h"
16#include "cardmanager.h"
17
18#define XEON_PHI_MANAGER_SERVICE_NAME "xeon_phi_manager"
19
20#ifdef XEON_PHI_DEBUG_MANAGER
21#define DEBUG_SVC(x...) debug_printf(" svc | " x)
22#else
23#define DEBUG_SVC(x...)
24#endif
25
26#define PRINTF_SVC(x...) debug_printf(" svc | " x)
27
28
29/// enumeration of possible service state
30enum xpm_svc_state
31{
32    XPM_SVC_STATE_INVALID = 0,
33    XPM_SVC_STATE_EXPORTING,
34    XPM_SVC_STATE_EXPORT_OK,
35    XPM_SVC_STATE_EXPORT_FAIL,
36    XPM_SVC_STATE_NS_REGISTERING,
37    XPM_SVC_STATE_NS_REGISTER_OK,
38    XPM_SVC_STATE_NS_REGISTER_FAIL,
39    XPM_SVC_STATE_RUNNING
40};
41
42/// service state
43static enum xpm_svc_state svc_state = XPM_SVC_STATE_INVALID;
44
45/// our exported iref
46static iref_t manager_iref;
47
48/**
49 * --------------------------------------------------------------------------
50 * Registration protocol
51 */
52
53struct reg_data
54{
55    errval_t err;
56    uint8_t id;
57    xeon_phi_manager_cards_t irefs;
58    struct xeon_phi_manager_binding *b;
59};
60
61struct reg_data reg_data_fail = {
62    // TODO: ERROR CODE
63    .err = -1
64};
65
66static void register_response_sent_cb(void *a)
67{
68    if (a != &reg_data_fail) {
69        free(a);
70    }
71}
72
73static void register_response_send(void *a)
74{
75    errval_t err;
76
77    struct reg_data *rd = a;
78
79    DEBUG_SVC("Registration response: id=%u, #irefs=%u\n", rd->id, rd->irefs.num);
80
81    struct event_closure txcont = MKCONT(register_response_sent_cb, a);
82
83    err = xeon_phi_manager_register_driver_response__tx(rd->b,
84                                                        txcont,
85                                                        rd->id,
86                                                        rd->irefs,
87                                                        rd->err);
88    if (err_is_fail(err)) {
89        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
90            txcont = MKCONT(register_response_send, a);
91            err = rd->b->register_send(rd->b, get_default_waitset(), txcont);
92            if (err_is_fail(err)) {
93                USER_PANIC_ERR(err, "register_send on binding failed!");
94            }
95        }
96    }
97}
98
99static void register_call_recv(struct xeon_phi_manager_binding *_binding,
100                               iref_t svc)
101{
102    PRINTF_SVC("New registration request: iref=%u\n", svc);
103
104    struct reg_data *reply = malloc(sizeof(struct reg_data));
105    if (!reply) {
106        reg_data_fail.err = LIB_ERR_MALLOC_FAIL;
107        reg_data_fail.b = _binding;
108        register_response_send(&reg_data_fail);
109        return;
110    }
111    reply->b = _binding;
112    reply->err = cm_new_xeon_phi(_binding, svc, &reply->id);
113    if (err_is_fail(reply->err)) {
114        register_response_send(reply);
115        return;
116    }
117
118    reply->err = cm_get_irefs(&reply->irefs.card0, &reply->irefs.num);
119
120    register_response_send(reply);
121}
122
123static struct xeon_phi_manager_rx_vtbl xpm_rx_vtbl = {
124    .register_driver_call = register_call_recv
125};
126
127/*
128 * --------------------------------------------------------------------------
129 * Export and Connect functions
130 */
131
132static errval_t svc_connect_cb(void *st,
133                               struct xeon_phi_manager_binding *b)
134{
135    DEBUG_SVC("New connection from a Xeon Phi Driver\n");
136
137    b->rx_vtbl = xpm_rx_vtbl;
138
139    return SYS_ERR_OK;
140}
141
142/**
143 * \brief
144 */
145static void svc_export_cb(void *st,
146                          errval_t err,
147                          iref_t iref)
148{
149    if (err_is_fail(err)) {
150        svc_state = XPM_SVC_STATE_EXPORT_FAIL;
151        return;
152    }
153
154    manager_iref = iref;
155    svc_state = XPM_SVC_STATE_NS_REGISTERING;
156
157    DEBUG_SVC("registering "XEON_PHI_MANAGER_SERVICE_NAME" with iref:%u\n", iref);
158
159    err = nameservice_register(XEON_PHI_MANAGER_SERVICE_NAME, iref);
160    if (err_is_fail(err)) {
161        svc_state = XPM_SVC_STATE_NS_REGISTER_FAIL;
162    }
163    svc_state = XPM_SVC_STATE_NS_REGISTER_OK;
164}
165
166/**
167 * \brief   starts Xeon Phi manager service
168 *
169 * \returns  SYS_ERR_OK on success
170 *           errval on failure
171 *
172 * NOTE: this function should not return.
173 */
174errval_t service_start(void)
175{
176    errval_t err;
177
178    DEBUG_SVC("starting service {"XEON_PHI_MANAGER_SERVICE_NAME"}\n");
179
180    err = xeon_phi_manager_export(NULL,
181                                  svc_export_cb,
182                                  svc_connect_cb,
183                                  get_default_waitset(),
184                                  IDC_EXPORT_FLAGS_DEFAULT);
185    if (err_is_fail(err)) {
186        return err;
187    }
188
189    while (svc_state == XPM_SVC_STATE_EXPORTING || svc_state
190                    == XPM_SVC_STATE_NS_REGISTERING) {
191        messages_wait_and_handle_next();
192    }
193
194    if (svc_state == XPM_SVC_STATE_EXPORT_FAIL) {
195        return FLOUNDER_ERR_BIND;
196    } else if (svc_state == XPM_SVC_STATE_NS_REGISTER_FAIL) {
197        return LIB_ERR_NAMESERVICE_CLIENT_INIT;
198    }
199
200    svc_state = XPM_SVC_STATE_RUNNING;
201
202    PRINTF_SVC("Xeon Phi Manager service up and running.\n");
203
204    messages_handler_loop();
205
206    USER_PANIC("Xeon Phi Manager service terminated!\n");
207
208    return SYS_ERR_OK;
209}
210