2a4d075e821ee9ec00fa5decd2abb0b485c4e4e1
[barrelfish] / usr / drivers / xeon_phi / xphi_service.c
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 #include <flounder/flounder_txqueue.h>
14 #include <xeon_phi/xeon_phi.h>
15 #include <xeon_phi/xeon_phi_domain.h>
16
17 #include <if/xeon_phi_defs.h>
18
19 #include "xeon_phi_internal.h"
20 #include "interphi.h"
21 #include "xphi_service.h"
22 #include "domain.h"
23 #include "debug.h"
24
25 #define XEON_PHI_SERVICE_NAME "xeon_phi_svc"
26
27 #define RPC_STATE_IDLE     0x00
28 #define RPC_STATE_PROGRESS 0x01
29 #define RPC_STATE_DONE     0x80
30
31 struct xphi_svc_st
32 {
33     struct xeon_phi *phi;
34     struct tx_queue queue;
35     char *name;
36     errval_t rpc_err;
37     uint8_t rpc_state;
38     uint64_t domainid;
39     struct xeon_phi_binding *binding;
40     struct xphi_svc_st *next;
41 };
42
43 /**
44  * enumeration of all possible states of the service exporting process
45  */
46 enum xpm_svc_state
47 {
48     XPM_SVC_STATE_INVALID,
49     XPM_SVC_STATE_EXPORTING,
50     XPM_SVC_STATE_EXPORT_OK,
51     XPM_SVC_STATE_EXPORT_FAIL,
52     XPM_SVC_STATE_RUNNING
53 };
54
55 /// represents the current state of the exporting process
56 static enum xpm_svc_state xphi_svc_state = XPM_SVC_STATE_INVALID;
57
58 /// error value for exporting
59 static errval_t xphi_svc_err;
60
61 struct xphi_svc_msg_st
62 {
63     struct txq_msg_st common;
64     /* union of arguments */
65     union
66     {
67         struct
68         {
69             xphi_dom_id_t domainid;
70         } spawn;
71         struct
72         {
73             xphi_dom_id_t domainid;
74             uint64_t usrdata;
75             struct capref cap;
76             uint8_t type;
77         } open;
78         struct
79         {
80             uint64_t domid;
81         } domain;
82     } args;
83 };
84
85 /*
86  * ----------------------------------------------------------------------------
87  * Connected Client management
88  * ----------------------------------------------------------------------------
89  */
90
91 struct xphi_svc_st *xphi_svc_clients;
92
93 static void xphi_svc_clients_insert(struct xphi_svc_st *new)
94 {
95     XSERVICE_DEBUG("inserting client: {%s} domainid:%lx\n", new->name,
96                    new->domainid);
97     new->next = xphi_svc_clients;
98     xphi_svc_clients = new;
99 }
100
101 static struct xphi_svc_st *xphi_svc_clients_lookup_by_did(uint64_t did)
102 {
103     XSERVICE_DEBUG("lookup client: domainid:%lx\n", did);
104     struct xphi_svc_st *current = xphi_svc_clients;
105     while (current) {
106         if (current->domainid == did) {
107             return current;
108         }
109         current = current->next;
110     }
111
112     return current;
113 }
114
115 /*
116  * ----------------------------------------------------------------------------
117  * Send handlers
118  * ----------------------------------------------------------------------------
119  */
120
121 static errval_t chan_open_call_tx(struct txq_msg_st* msg_st)
122 {
123     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
124
125     return xeon_phi_chan_open_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
126                                        xphi_st->args.open.domainid,
127                                        xphi_st->args.open.usrdata,
128                                        xphi_st->args.open.cap,
129                                        xphi_st->args.open.type);
130 }
131
132 static errval_t chan_open_request_response_tx(struct txq_msg_st* msg_st)
133 {
134     return xeon_phi_chan_open_request_response__tx(msg_st->queue->binding,
135                                                    TXQCONT(msg_st), msg_st->err);
136 }
137
138 static errval_t kill_response_tx(struct txq_msg_st* msg_st)
139 {
140     return xeon_phi_kill_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
141                                       msg_st->err);
142 }
143
144 static errval_t spawn_with_cap_response_tx(struct txq_msg_st* msg_st)
145 {
146     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
147
148     return xeon_phi_spawn_with_cap_response__tx(msg_st->queue->binding,
149                                                 TXQCONT(msg_st),
150                                                 xphi_st->args.spawn.domainid,
151                                                 msg_st->err);
152 }
153
154 static errval_t spawn_response_tx(struct txq_msg_st* msg_st)
155 {
156     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
157
158     return xeon_phi_spawn_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
159                                        xphi_st->args.spawn.domainid, msg_st->err);
160 }
161
162 static errval_t domain_init_response_tx(struct txq_msg_st* msg_st)
163 {
164     return xeon_phi_domain_init_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
165                                              msg_st->err);
166 }
167
168 static errval_t domain_register_response_tx(struct txq_msg_st* msg_st)
169 {
170     return xeon_phi_domain_register_response__tx(msg_st->queue->binding,
171                                                  TXQCONT(msg_st), msg_st->err);
172 }
173
174 static errval_t domain_lookup_response_tx(struct txq_msg_st* msg_st)
175 {
176     struct xphi_svc_msg_st *st = (struct xphi_svc_msg_st *) msg_st;
177     return xeon_phi_domain_lookup_response__tx(msg_st->queue->binding,
178                                                TXQCONT(msg_st),
179                                                st->args.domain.domid, msg_st->err);
180 }
181
182 static errval_t domain_wait_response_tx(struct txq_msg_st* msg_st)
183 {
184     struct xphi_svc_msg_st *st = (struct xphi_svc_msg_st *) msg_st;
185
186     return xeon_phi_domain_wait_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
187                                              st->args.domain.domid, msg_st->err);
188 }
189
190 /*
191  * ----------------------------------------------------------------------------
192  * Receive Handlers
193  * ----------------------------------------------------------------------------
194  */
195
196 static void domain_lookup_call_rx(struct xeon_phi_binding *binding,
197                                   char *name,
198                                   size_t length)
199 {
200     XSERVICE_DEBUG("domain_lookup_call_rx: %s\n", name);
201
202     struct xphi_svc_st *svc_st = binding->st;
203     struct xeon_phi *phi = svc_st->phi;
204
205     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
206     if (msg_st == NULL) {
207         USER_PANIC("ran out of reply state resources\n");
208     }
209
210     msg_st->send = domain_lookup_response_tx;
211     msg_st->cleanup = NULL;
212
213     struct xphi_svc_msg_st *st = (struct xphi_svc_msg_st *) msg_st;
214
215     msg_st->err = interphi_domain_lookup(&phi->topology[phi->id], name,
216                                          &st->args.domain.domid);
217     free(name);
218
219     txq_send(msg_st);
220 }
221
222 static void domain_wait_call_rx(struct xeon_phi_binding *binding,
223                                 char *name,
224                                 size_t length)
225 {
226     XSERVICE_DEBUG("domain_wait_call_rx: %s\n", name);
227
228     struct xphi_svc_st *svc_st = binding->st;
229     struct xeon_phi *phi = svc_st->phi;
230
231     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
232     if (msg_st == NULL) {
233         USER_PANIC("ran out of reply state resources\n");
234     }
235
236     /* TODO: allocate reply state */
237
238     msg_st->err = interphi_domain_wait(&phi->topology[phi->id], name, svc_st);
239     if (err_is_fail(msg_st->err)) {
240         txq_send(msg_st);
241     }
242
243     free(name);
244
245 }
246
247 static void domain_register_call_rx(struct xeon_phi_binding *binding,
248                                     char *name,
249                                     size_t length,
250                                     xphi_dom_id_t domid)
251 {
252     XSERVICE_DEBUG("domain_init_call_rx: %s @ domainid:%lx\n", name, domid);
253
254     struct xphi_svc_st *svc_st = binding->st;
255
256     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
257     if (msg_st == NULL) {
258         USER_PANIC("ran out of reply state resources\n");
259     }
260
261     msg_st->send = domain_register_response_tx;
262     msg_st->cleanup = NULL;
263
264     svc_st->domainid = domid;
265     svc_st->name = name;
266
267 #ifdef __k1om__
268     struct xeon_phi *phi = svc_st->phi;
269     msg_st->err = interphi_domain_register(&phi->topology[phi->id], name, domid);
270 #else
271     msg_st->err = domain_register(name, domid);
272 #endif
273
274     free(name);
275
276     txq_send(msg_st);
277 }
278
279 static void domain_init_call_rx(struct xeon_phi_binding *binding,
280                                 domainid_t domain,
281                                 coreid_t core,
282                                 char *name,
283                                 size_t length)
284 {
285     XSERVICE_DEBUG("domain_init_call_rx: %s @ domainid:%"PRIuDOMAINID"\n", name,
286                    domain);
287
288     assert(domain != XEON_PHI_DOMAIN_DONT_CARE);
289     assert(core != XEON_PHI_DOMAIN_DONT_CARE);
290
291     struct xphi_svc_st *svc_st = binding->st;
292     struct xeon_phi *phi = svc_st->phi;
293
294     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
295     if (msg_st == NULL) {
296         USER_PANIC("ran out of reply state resources\n");
297     }
298
299     msg_st->send = domain_init_response_tx;
300     msg_st->cleanup = NULL;
301
302     if (svc_st->next != NULL) {
303         msg_st->err = XEON_PHI_ERR_CLIENT_REGISTER;
304         txq_send(msg_st);
305         return;
306     }
307
308 #ifdef __k1om__
309     svc_st->domainid = xeon_phi_domain_build_id(phi->id, core, 0x0, domain);
310     svc_st->name = xeon_phi_domain_build_iface(name, disp_xeon_phi_id(), core);
311     msg_st->err = interphi_domain_register(&phi->topology[phi->id], svc_st->name,
312                                            svc_st->domainid);
313
314 #else
315     svc_st->name = xeon_phi_domain_build_iface(name, XEON_PHI_DOMAIN_HOST, core);
316     svc_st->domainid = xeon_phi_domain_build_id(phi->id, core, 0x1, domain);
317     msg_st->err = domain_register(svc_st->name, svc_st->domainid);
318 #endif
319     xphi_svc_clients_insert(svc_st);
320
321     free(name);
322
323     txq_send(msg_st);
324 }
325
326 static void chan_open_response_rx(struct xeon_phi_binding *binding,
327                                   errval_t msgerr)
328 {
329     XSERVICE_DEBUG("chan_open_response_rx: %s\n", err_getstring(msgerr));
330
331     struct xphi_svc_st *svc_st = binding->st;
332
333     svc_st->rpc_state |= RPC_STATE_DONE;
334     svc_st->rpc_err |= msgerr;
335 }
336
337 static void chan_open_request_call_rx(struct xeon_phi_binding *binding,
338                                       uint8_t xphi,
339                                       struct capref msgframe,
340                                       uint8_t type,
341                                       uint64_t domain,
342                                       uint64_t usrdata)
343 {
344     XSERVICE_DEBUG("chan_open_request_did_call_rx: xphi:%u, domain:%lx\n", xphi,
345                    domain);
346
347     struct xphi_svc_st *svc_st = binding->st;
348
349     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
350     if (msg_st == NULL) {
351         USER_PANIC("ran out of reply state resources\n");
352     }
353
354     msg_st->send = chan_open_request_response_tx;
355     msg_st->cleanup = NULL;
356
357 #ifdef __k1om__
358     struct xnode *node = &svc_st->phi->topology[xphi];
359 #else
360     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
361 #endif
362     msg_st->err = interphi_chan_open(node, domain, svc_st->domainid, usrdata,
363                                      msgframe, type);
364
365     txq_send(msg_st);
366 }
367
368 static void kill_call_rx(struct xeon_phi_binding *binding,
369                          uint8_t xid,
370                          uint64_t domainid)
371 {
372     struct xphi_svc_st *svc_st = binding->st;
373
374     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
375     if (msg_st == NULL) {
376         USER_PANIC("ran out of reply state resources\n");
377     }
378
379     msg_st->send = kill_response_tx;
380     msg_st->cleanup = NULL;
381
382 #ifdef __k1om__
383     struct xnode *node = &svc_st->phi->topology[xid];
384 #else
385     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
386 #endif
387
388     msg_st->err = interphi_kill(node, domainid);
389
390     txq_send(msg_st);
391 }
392
393 static void spawn_with_cap_call_rx(struct xeon_phi_binding *binding,
394                                    uint8_t xid,
395                                    uint8_t core,
396                                    char *cmdline,
397                                    size_t length,
398                                    uint8_t flags,
399                                    struct capref cap)
400 {
401     struct xphi_svc_st *svc_st = binding->st;
402
403     XSERVICE_DEBUG("spawn_with_cap_call_rx: %s of length %lu\n", cmdline, length);
404
405     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
406     if (msg_st == NULL) {
407         USER_PANIC("ran out of reply state resources\n");
408     }
409
410     msg_st->send = spawn_with_cap_response_tx;
411     msg_st->cleanup = NULL;
412
413     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
414
415 #ifdef __k1om__
416     struct xnode *node = &svc_st->phi->topology[xid];
417 #else
418     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
419 #endif
420     msg_st->err = interphi_spawn_with_cap(node, core, cmdline, length, flags, cap,
421                                           &xphi_st->args.spawn.domainid);
422
423     free(cmdline);
424
425     txq_send(msg_st);
426 }
427
428 static void spawn_call_rx(struct xeon_phi_binding *binding,
429                           uint8_t xid,
430                           uint8_t core,
431                           char *cmdline,
432                           size_t length,
433                           uint8_t flags)
434 {
435     struct xphi_svc_st *svc_st = binding->st;
436
437     XSERVICE_DEBUG("spawn_call_rx: %s of length %lu\n", cmdline, length);
438
439     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
440     if (msg_st == NULL) {
441         USER_PANIC("ran out of reply state resources\n");
442     }
443
444     msg_st->send = spawn_response_tx;
445     msg_st->cleanup = NULL;
446
447     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
448
449 #ifdef __k1om__
450     struct xnode *node = &svc_st->phi->topology[xid];
451 #else
452     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
453 #endif
454     msg_st->err = interphi_spawn(node, core, cmdline, length, flags,
455                                  &xphi_st->args.spawn.domainid);
456
457     free(cmdline);
458
459     txq_send(msg_st);
460 }
461
462 static struct xeon_phi_rx_vtbl xphi_svc_rx_vtbl = {
463     .domain_init_call = domain_init_call_rx,
464     .domain_register_call = domain_register_call_rx,
465     .domain_lookup_call = domain_lookup_call_rx,
466     .domain_wait_call = domain_wait_call_rx,
467     .spawn_call = spawn_call_rx,
468     .spawn_with_cap_call = spawn_with_cap_call_rx,
469     .kill_call = kill_call_rx,
470     .chan_open_request_call = chan_open_request_call_rx,
471     .chan_open_response = chan_open_response_rx
472 };
473
474 /*
475  * ----------------------------------------------------------------------------
476  * Export / Connect / Bind Callbacks
477  * ----------------------------------------------------------------------------
478  */
479
480 static errval_t xphi_svc_connect_cb(void *st,
481                                     struct xeon_phi_binding *binding)
482 {
483     XSERVICE_DEBUG("xphi_svc_connect_cb: new connection from domain.\n");
484
485     struct xphi_svc_st *svc_st = calloc(1, sizeof(*svc_st));
486     if (svc_st == NULL) {
487         return LIB_ERR_MALLOC_FAIL;
488     }
489
490     svc_st->phi = st;
491
492     txq_init(&svc_st->queue, binding, binding->waitset,
493              (txq_register_fn_t) binding->register_send,
494              sizeof(struct xphi_svc_msg_st));
495
496     binding->st = svc_st;
497     binding->rx_vtbl = xphi_svc_rx_vtbl;
498     svc_st->binding = binding;
499
500     return SYS_ERR_OK;
501
502 }
503
504 static void xphi_svc_export_cb(void *st,
505                                errval_t err,
506                                iref_t iref)
507 {
508     XSERVICE_DEBUG("xphi_svc_export_cb @ iref:%"PRIxIREF" result: %s\n", iref,
509                    err_getstring(err));
510
511     if (err_is_ok(err)) {
512         struct xeon_phi *phi = st;
513         phi->xphi_svc_iref = iref;
514         xphi_svc_state = XPM_SVC_STATE_EXPORT_OK;
515         return;
516     }
517
518     xphi_svc_state = XPM_SVC_STATE_EXPORT_FAIL;
519 }
520
521 /*
522  * ----------------------------------------------------------------------------
523  * Initialization
524  * ----------------------------------------------------------------------------
525  */
526
527 /**
528  *
529  */
530 errval_t xeon_phi_service_init(struct xeon_phi *phi)
531 {
532     errval_t err;
533
534     XSERVICE_DEBUG("initializing Xeon Phi service\n");
535
536     if (xphi_svc_state != XPM_SVC_STATE_INVALID) {
537         return SYS_ERR_OK;
538     }
539
540     xphi_svc_state = XPM_SVC_STATE_EXPORTING;
541
542     err = xeon_phi_export(phi, xphi_svc_export_cb, xphi_svc_connect_cb,
543                           get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
544     if (err_is_fail(err)) {
545         return err;
546     }
547
548     while (xphi_svc_state == XPM_SVC_STATE_EXPORTING) {
549         messages_wait_and_handle_next();
550     }
551
552     if (xphi_svc_state == XPM_SVC_STATE_EXPORT_FAIL) {
553         return xphi_svc_err;
554     }
555
556 #ifdef __k1om__
557     XSERVICE_DEBUG("registering {%s} with iref:%"PRIxIREF"\n", XEON_PHI_SERVICE_NAME,
558                    phi->xphi_svc_iref);
559     err = nameservice_register(XEON_PHI_SERVICE_NAME, phi->xphi_svc_iref);
560     if (err_is_fail(err)) {
561         return err;
562     }
563 #else
564     char iface[30];
565     snprintf(iface, sizeof(iface), "%s.%u", XEON_PHI_SERVICE_NAME, phi->id);
566     XSERVICE_DEBUG("registering {%s} with iref:%"PRIxIREF"\n", iface, phi->xphi_svc_iref);
567     err = nameservice_register(iface, phi->xphi_svc_iref);
568 #endif
569
570     xphi_svc_state = XPM_SVC_STATE_RUNNING;
571
572     XSERVICE_DEBUG("service up and running\n");
573
574     return SYS_ERR_OK;
575 }
576
577 errval_t xeon_phi_service_open_channel(struct capref cap,
578                                        uint8_t type,
579                                        xphi_dom_id_t target_domain,
580                                        xphi_dom_id_t src_domain,
581                                        uint64_t userdata)
582 {
583     errval_t err;
584
585     struct xphi_svc_st *st = NULL;
586
587     st = xphi_svc_clients_lookup_by_did(target_domain);
588     XSERVICE_DEBUG("xeon_phi_service_open_channel: target_domain, st:%p\n", st);
589
590     if (st == NULL) {
591         return XEON_PHI_ERR_CLIENT_DOMAIN_VOID;
592     }
593
594     while (st->rpc_state != RPC_STATE_IDLE) {
595         err = xeon_phi_event_poll(true);
596         if (err_is_fail(err)) {
597             return err;
598         }
599     }
600
601     st->rpc_state = RPC_STATE_PROGRESS;
602
603     struct txq_msg_st *msg_st = txq_msg_st_alloc(&st->queue);
604     if (msg_st == NULL) {
605         USER_PANIC("ran out of reply state resources\n");
606     }
607
608     msg_st->send = chan_open_call_tx;
609     msg_st->cleanup = NULL;
610
611     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
612
613     xphi_st->args.open.cap = cap;
614     xphi_st->args.open.type = type;
615     xphi_st->args.open.domainid = src_domain;
616     xphi_st->args.open.usrdata = userdata;
617
618     txq_send(msg_st);
619
620     while (!(st->rpc_state & RPC_STATE_DONE)) {
621         err = xeon_phi_event_poll(true);
622         if (err_is_fail(err)) {
623             return err;
624         }
625     }
626
627     st->rpc_state = RPC_STATE_IDLE;
628
629     return st->rpc_err;
630 }
631
632 errval_t xeon_phi_service_domain_wait_response(struct xphi_svc_st *st,
633                                                errval_t err,
634                                                xphi_dom_id_t domain)
635 {
636     struct txq_msg_st *msg_st = txq_msg_st_alloc(&st->queue);
637     if (msg_st == NULL) {
638         USER_PANIC("ran out of reply state resources\n");
639     }
640
641     msg_st->send = domain_wait_response_tx;
642     msg_st->cleanup = NULL;
643
644     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
645
646     xphi_st->args.domain.domid = domain;
647
648     txq_send(msg_st);
649
650     return SYS_ERR_OK;
651 }