Patches b03c1b through 3f00b5
[barrelfish] / usr / drivers / xeon_phi / service.c
1 /**
2  * \file
3  * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
4  */
5
6 /*
7  * Copyright (c) 2014 ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <barrelfish/barrelfish.h>
18 #include <xeon_phi/xeon_phi.h>
19
20 #include <if/xeon_phi_defs.h>
21
22 #include "xeon_phi.h"
23 #include "service.h"
24 #include "messaging.h"
25
26 static uint32_t is_exported;
27
28 static iref_t svc_iref;
29
30 static inline errval_t handle_messages(void)
31 {
32     uint32_t data = xeon_phi_serial_handle_recv();
33     errval_t err = event_dispatch_non_block(get_default_waitset());
34     if (err_is_fail(err)) {
35         if (err_no(err) == LIB_ERR_NO_EVENT) {
36             if (!data) {
37                 thread_yield();
38             }
39             return SYS_ERR_OK;
40         }
41         return err;
42     }
43     return SYS_ERR_OK;
44 }
45
46 /*
47  * ---------------------------------------------------------------------------
48  * Intra Xeon Phi Driver Communication Regigistration
49  */
50
51 static void register_response_sent_cb(void *a)
52 {
53
54 }
55
56 static void register_response_send(void *a)
57 {
58     errval_t err;
59
60     struct xnode *topology = a;
61
62     struct event_closure txcont = MKCONT(register_response_sent_cb, a);
63
64     if (topology->state == XNODE_STATE_READY) {
65         err = SYS_ERR_OK;
66     } else {
67         err = -1;  // TODO> ERROR NUMBEr
68     }
69
70     err = xeon_phi_register_response__tx(topology->binding, txcont, err);
71     if (err_is_fail(err)) {
72         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
73             struct waitset *ws = get_default_waitset();
74             txcont = MKCONT(register_response_send, a);
75             err = topology->binding->register_send(topology->binding, ws, txcont);
76             if (err_is_fail(err)) {
77                 topology->state = XNODE_STATE_FAILURE;
78             }
79         }
80     }
81 }
82
83 /**
84  *
85  */
86 static void register_call_recv(struct xeon_phi_binding *_binding,
87                                uint8_t id)
88 {
89
90     assert(((struct xnode * )(_binding->st))->binding != _binding);
91     struct xeon_phi *phi = _binding->st;
92
93     assert(id < XEON_PHI_NUM_MAX);
94     phi->topology[id].binding = _binding;
95     phi->topology[id].state = XNODE_STATE_READY;
96
97     phi->connected++;
98
99     XSERVICE_DEBUG("[%u] New register call: id=0x%x, num_connected=%i\n",
100                    phi->id,
101                    id,
102                    phi->connected);
103
104     _binding->st = &phi->topology[id];
105
106     register_response_send(&phi->topology[id]);
107 }
108
109 /**
110  *
111  */
112 static void register_response_recv(struct xeon_phi_binding *_binding,
113                                    xeon_phi_errval_t msgerr)
114 {
115     assert(((struct xnode * )(_binding->st))->binding == _binding);
116
117     struct xnode *topology = _binding->st;
118
119     if (err_is_fail(msgerr)) {
120         topology->state = XNODE_STATE_FAILURE;
121     } else {
122         topology->local->connected++;
123         topology->state = XNODE_STATE_READY;
124     }
125
126     XSERVICE_DEBUG("[%u] New register response: 0x%lx, num_connected=%u\n",
127                    topology->local->id,
128                    msgerr,
129                    topology->local->connected);
130 }
131
132 static void register_call_sent_cb(void *a)
133 {
134
135 }
136
137 static void register_call_send(void *a)
138 {
139     errval_t err;
140
141     struct xnode *topology = a;
142
143     struct event_closure txcont = MKCONT(register_call_sent_cb, a);
144
145     topology->state = XNODE_STATE_REGISTERING;
146
147     err = xeon_phi_register_call__tx(topology->binding, txcont, topology->local->id);
148     if (err_is_fail(err)) {
149         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
150             struct waitset *ws = get_default_waitset();
151             txcont = MKCONT(register_call_send, a);
152             err = topology->binding->register_send(topology->binding, ws, txcont);
153             if (err_is_fail(err)) {
154                 topology->state = XNODE_STATE_FAILURE;
155             }
156         }
157     }
158 }
159
160 /// Receive handler table
161 static struct xeon_phi_rx_vtbl xps_rx_vtbl = {
162     .register_call = register_call_recv,
163     .register_response = register_response_recv
164 };
165
166 /*
167  * ---------------------------------------------------------------------------
168  * Service Setup
169  */
170 static void svc_bind_cb(void *st,
171                         errval_t err,
172                         struct xeon_phi_binding *b)
173 {
174     struct xnode *node = st;
175
176     XSERVICE_DEBUG("binding done.\n");
177     b->rx_vtbl = xps_rx_vtbl;
178     node->binding = b;
179     b->st = node;
180     node->state = XNODE_STATE_REGISTERING;
181 }
182
183 static errval_t svc_register(struct xnode *node)
184 {
185     XSERVICE_DEBUG("binding to node %i (iref = 0x%x)\n", node->id, node->iref);
186     errval_t err;
187
188     err = xeon_phi_bind(node->iref,
189                         svc_bind_cb,
190                         node,
191                         get_default_waitset(),
192                         IDC_BIND_FLAGS_DEFAULT);
193     if (err_is_fail(err)) {
194         node->state = XNODE_STATE_FAILURE;
195         return err;
196     }
197
198     return SYS_ERR_OK;
199 }
200
201 static errval_t svc_connect_cb(void *st,
202                                struct xeon_phi_binding *b)
203 {
204     struct xeon_phi *phi = st;
205
206     XSERVICE_DEBUG("[%u] New connection\n", phi->id);
207
208     b->st = st;
209     b->rx_vtbl = xps_rx_vtbl;
210     return SYS_ERR_OK;
211 }
212
213 static void svc_export_cb(void *st,
214                           errval_t err,
215                           iref_t iref)
216 {
217     if (err_is_fail(err)) {
218         svc_iref = 0x0;
219         return;
220     }
221
222     svc_iref = iref;
223
224     struct xeon_phi *phi = st;
225     phi->iref = iref;
226
227     is_exported = 0x1;
228 }
229
230 /**
231  * \brief initializes the service
232  *
233  * \param iref  returns the iref of the initialized service
234  *
235  * \return SYS_ERR_OK on success
236  */
237 errval_t service_init(struct xeon_phi *phi)
238 {
239     errval_t err;
240
241     for (uint32_t i = 0; i < XEON_PHI_NUM_MAX; ++i) {
242         phi->topology[i].local = phi;
243     }
244
245     err = xeon_phi_export(phi,
246                           svc_export_cb,
247                           svc_connect_cb,
248                           get_default_waitset(),
249                           IDC_EXPORT_FLAGS_DEFAULT);
250     if (err_is_fail(err)) {
251         return err;
252     }
253
254     while (!is_exported) {
255         messages_wait_and_handle_next();
256     }
257
258     if (svc_iref == 0x0) {
259         return -1;
260     }
261
262     return SYS_ERR_OK;
263
264 }
265
266 /**
267  * \brief registers the local service with the other Xeon Phi drivers
268  *        in the topology
269  *
270  * \param phi   pointer to the local card structure
271  * \param irefs the irefs of the other cards
272  * \param num   the number of irefs in the array
273  */
274 errval_t service_register(struct xeon_phi *phi,
275                           iref_t *irefs,
276                           size_t num)
277 {
278     errval_t err;
279     struct xnode *xnode;
280     XSERVICE_DEBUG("start binding to nodes\n");
281     for (uint32_t i = 0; i < num; ++i) {
282         xnode = &phi->topology[i];
283         if (i == phi->id) {
284             xnode->iref = phi->iref;
285             xnode->id = i;
286             xnode->state = XNODE_STATE_READY;
287             continue;
288         }
289
290         xnode->iref = irefs[i];
291         xnode->id = i;
292         xnode->state = XNODE_STATE_NONE;
293         svc_register(xnode);
294         while (xnode->state == XNODE_STATE_NONE) {
295             err = handle_messages();
296             if (err_is_fail(err)) {
297                 return err;
298             }
299         }
300     }
301
302     XSERVICE_DEBUG("Start registring\n");
303
304     for (uint32_t i = 0; i < num; ++i) {
305         if (i == phi->id) {
306             continue;
307         }
308         xnode = &phi->topology[i];
309         register_call_send(xnode);
310         while (xnode->state == XNODE_STATE_READY) {
311             err = handle_messages();
312             if (err_is_fail(err)) {
313                 return err;
314             }
315         }
316     }
317
318     XSERVICE_DEBUG("Registring with other %i Xeon Phi done.\n", (uint32_t )num - 1);
319
320     return SYS_ERR_OK;
321 }
322
323 /**
324  * \brief starts the service request handling
325  */
326 errval_t service_start(struct xeon_phi *phi)
327 {
328     errval_t err;
329     while (1) {
330         err = messaging_poll(phi);
331         err = handle_messages();
332         if (err_is_fail(err)) {
333             return err;
334         }
335     }
336
337     return SYS_ERR_OK;
338 }
339