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 <xeon_phi/xeon_phi.h>
14#include <xeon_phi/xeon_phi_manager_client.h>
15
16#include <if/xeon_phi_manager_defs.h>
17#include <if/xeon_phi_manager_defs.h>
18
19/// the name of the Xeon Phi Manager service
20#define XEON_PHI_MANAGER_SERVICE_NAME "xeon_phi_manager"
21
22/// Enabling the debug output of the Xeon Phi Manager client
23#ifdef XEON_PHI_DEBUG_MANAGER
24#define DEBUG_XPMC(x...) debug_printf(" [xpmc] " x)
25#else
26#define DEBUG_XPMC(x...)
27#endif
28
29/**
30 * represents the connection state of the Xeon Phi Manager client with the
31 * Xeon Phi Manager
32 */
33enum xpm_state
34{
35    XPM_STATE_INVALID = 0,
36    XPM_STATE_NSLOOKUP,
37    XPM_STATE_BINDING,
38    XPM_STATE_BIND_OK,
39    XPM_STATE_BIND_FAIL,
40    XPM_STATE_REGISTERING,
41    XPM_STATE_REGISTER_OK,
42    XPM_STATE_REGISTER_FAIL,
43    XPM_STATE_CONNECTED
44};
45
46/// iref of the Xeon Phi manager service
47static iref_t xpm_iref = 0;
48
49/// Flounder binind go the Xeon Phi manager
50static struct xeon_phi_manager_binding *xpm_binding = NULL;
51
52/// connection state
53static enum xpm_state conn_state = XPM_STATE_INVALID;
54
55/*
56 * --------------------------------------------------------------------------
57 * Registration Protocol
58 * ----------------------------------------------------------------------------
59 */
60
61/**
62 * contains the necessary data for the Xeon Phi manager connection
63 */
64struct xpm_register_data
65{
66    iref_t svc_iref;                  ///< our exported service iref
67    errval_t err;                     ///< error code of the registration
68    uint8_t id;                       ///< our own Xeon Phi ID.
69    xeon_phi_manager_cards_t irefs;   ///< irefs to the other Xeon Phi drivers
70} xpm_reg_data;
71
72/*
73 * ----------------------------------------------------------------------------
74 * Xeon Phi Manager binding functions
75 * ----------------------------------------------------------------------------
76 */
77
78/**
79 * \brief Flounder bind callback
80 *
81 * \param st      state associated with the binding
82 * \param err     error code of the binding attempt
83 * \param binding Xeon Phi Manager Flounder binding
84 */
85static void xpm_bind_cb(void *st,
86                        errval_t err,
87                        struct xeon_phi_manager_binding *binding)
88{
89
90    if (err_is_fail(err)) {
91        conn_state = XPM_STATE_BIND_FAIL;
92        xpm_reg_data.err = err;
93        return;
94    }
95
96    xpm_binding = binding;
97
98    conn_state = XPM_STATE_BIND_OK;
99
100    xeon_phi_manager_rpc_client_init(xpm_binding);
101
102    DEBUG_XPMC("binding to "XEON_PHI_MANAGER_SERVICE_NAME" succeeded\n");
103}
104
105/**
106 * \brief binds to the Xeon Phi Manager service
107 *
108 * \returns SYS_ERR_OK on success
109 *          FLOUNDER_ERR_* on failure
110 */
111static errval_t xpm_bind(void)
112{
113    errval_t err;
114
115    if (xpm_binding != NULL) {
116        return SYS_ERR_OK;
117    }
118
119    assert(conn_state == XPM_STATE_INVALID);
120
121    conn_state = XPM_STATE_NSLOOKUP;
122
123    DEBUG_XPMC("nameservice lookup: "XEON_PHI_MANAGER_SERVICE_NAME"\n");
124
125    err = nameservice_blocking_lookup(XEON_PHI_MANAGER_SERVICE_NAME, &xpm_iref);
126    if (err_is_fail(err)) {
127        return err;
128    }
129
130    conn_state = XPM_STATE_BINDING;
131
132    DEBUG_XPMC("binding: "XEON_PHI_MANAGER_SERVICE_NAME" @ iref:%u\n", xpm_iref);
133
134    err = xeon_phi_manager_bind(xpm_iref, xpm_bind_cb, NULL, get_default_waitset(),
135    IDC_BIND_FLAGS_DEFAULT);
136    if (err_is_fail(err)) {
137        return err;
138    }
139
140    while (conn_state == XPM_STATE_BINDING) {
141        messages_wait_and_handle_next();
142    }
143
144    if (conn_state == XPM_STATE_BIND_FAIL) {
145        return FLOUNDER_ERR_BIND;
146    }
147
148    return SYS_ERR_OK;
149}
150
151/*
152 * ----------------------------------------------------------------------------
153 * Public Interface
154 * ----------------------------------------------------------------------------
155 */
156
157/**
158 * \brief registers the Xeon Phi driver card with the Xeon Phi Manager
159 *
160 * \param svc_iref  iref of the own exported Xeon Phi driver interface
161 * \param id        returns the assigned Xeon Phi card ID
162 * \param num       returns the size of the cards array
163 * \param irefs     returns array of irefs to the other cards
164 *
165 * NOTE: this is a blocking function. The function will only return after
166 *       the Xeon Phi manager connection has been fully established and the
167 *       registration protocol has been executed.
168 *
169 * \returns SYS_ERR_OK on success
170 *          errval on failure
171 */
172errval_t xeon_phi_manager_client_register(iref_t svc_iref,
173                                          uint8_t *id,
174                                          uint8_t *num,
175                                          iref_t **irefs)
176{
177    errval_t err, msgerr;
178
179    if (strcmp(disp_name(), "xeon_phi") != 0) {
180        USER_PANIC("client register called on non xeon phi driver");
181        return -1;
182    }
183
184    if (conn_state >= XPM_STATE_REGISTER_OK) {
185        return SYS_ERR_OK;
186    }
187
188    DEBUG_XPMC("Registration with Xeon Phi Manager service.\n");
189
190    err = xpm_bind();
191    if (err_is_fail(err)) {
192        return err;
193    }
194
195    xpm_reg_data.svc_iref = svc_iref;
196
197    xeon_phi_manager_cards_t cards;
198
199    err = xpm_binding->rpc_tx_vtbl.register_driver(xpm_binding, svc_iref, id,
200                                              &cards, &msgerr);
201    if (err_is_fail(err)) {
202        return err;
203    }
204
205    if (err_is_fail(msgerr)) {
206        return msgerr;
207    }
208    conn_state = XPM_STATE_REGISTER_OK;
209
210    iref_t *cardiref =calloc(cards.num, sizeof(iref_t));
211    assert(cardiref);
212    for(uint32_t i = 0; i < cards.num; ++i) {
213        cardiref[i] = ((iref_t *)&cards.card0)[i];
214    }
215    *irefs = cardiref;
216    *num = cards.num;
217
218    return SYS_ERR_OK;
219}
220
221/**
222 * \brief   deregisters the Xeon Phi driver with the Xeon Phi Manager
223 *
224 * \return SYS_ERR_OK on success
225 */
226errval_t xeon_phi_manager_client_deregister(void)
227{
228    assert(!"NYI");
229    return SYS_ERR_OK;
230}
231
232/**
233 * \brief looks up the iref of a Xeon Phi with the given id
234 *
235 * \param xid       Xeon Phi ID
236 * \param svc_iref  the returned svc_iref of the xeon phi
237 *
238 * \returns SYS_ERR_OK on success
239 */
240errval_t xeon_phi_manager_lookup(xphi_id_t xid,
241                                 iref_t *svc_iref)
242{
243    errval_t err, msgerr;
244
245    DEBUG_XPMC("Registration with Xeon Phi Manager service.\n");
246
247    err = xpm_bind();
248    if (err_is_fail(err)) {
249        return err;
250    }
251
252    err = xpm_binding->rpc_tx_vtbl.lookup(xpm_binding, xid, svc_iref, &msgerr);
253    if (err_is_fail(err)) {
254        return err;
255    }
256
257    return msgerr;
258}
259