flounder: making const pointers in receiving handlers, using CONST_CAST as a temporar...
[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                                   const 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], (CONST_CAST)name,
216                                          &st->args.domain.domid);
217     txq_send(msg_st);
218 }
219
220 static void domain_wait_call_rx(struct xeon_phi_binding *binding,
221                                 const char *name,
222                                 size_t length)
223 {
224     XSERVICE_DEBUG("domain_wait_call_rx: %s\n", name);
225
226     struct xphi_svc_st *svc_st = binding->st;
227     struct xeon_phi *phi = svc_st->phi;
228
229     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
230     if (msg_st == NULL) {
231         USER_PANIC("ran out of reply state resources\n");
232     }
233
234     /* TODO: allocate reply state */
235
236     msg_st->err = interphi_domain_wait(&phi->topology[phi->id], (CONST_CAST)name, svc_st);
237     if (err_is_fail(msg_st->err)) {
238         txq_send(msg_st);
239     }
240 }
241
242 static void domain_register_call_rx(struct xeon_phi_binding *binding,
243                                     const char *name,
244                                     size_t length,
245                                     xphi_dom_id_t domid)
246 {
247     XSERVICE_DEBUG("domain_init_call_rx: %s @ domainid:%lx\n", name, domid);
248
249     struct xphi_svc_st *svc_st = binding->st;
250
251     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
252     if (msg_st == NULL) {
253         USER_PANIC("ran out of reply state resources\n");
254     }
255
256     msg_st->send = domain_register_response_tx;
257     msg_st->cleanup = NULL;
258
259     svc_st->domainid = domid;
260     svc_st->name = (CONST_CAST)name;
261
262 #ifdef __k1om__
263     struct xeon_phi *phi = svc_st->phi;
264     msg_st->err = interphi_domain_register(&phi->topology[phi->id], name, domid);
265 #else
266     msg_st->err = domain_register(name, domid);
267 #endif
268     txq_send(msg_st);
269 }
270
271 static void domain_init_call_rx(struct xeon_phi_binding *binding,
272                                 domainid_t domain,
273                                 coreid_t core,
274                                 const char *name,
275                                 size_t length)
276 {
277     XSERVICE_DEBUG("domain_init_call_rx: %s @ domainid:%"PRIuDOMAINID"\n", name,
278                    domain);
279
280     assert(domain != XEON_PHI_DOMAIN_DONT_CARE);
281     assert(core != XEON_PHI_DOMAIN_DONT_CARE);
282
283     struct xphi_svc_st *svc_st = binding->st;
284     struct xeon_phi *phi = svc_st->phi;
285
286     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
287     if (msg_st == NULL) {
288         USER_PANIC("ran out of reply state resources\n");
289     }
290
291     msg_st->send = domain_init_response_tx;
292     msg_st->cleanup = NULL;
293
294     if (svc_st->next != NULL) {
295         msg_st->err = XEON_PHI_ERR_CLIENT_REGISTER;
296         txq_send(msg_st);
297         return;
298     }
299
300 #ifdef __k1om__
301     svc_st->domainid = xeon_phi_domain_build_id(phi->id, core, 0x0, domain);
302     svc_st->name = xeon_phi_domain_build_iface(name, disp_xeon_phi_id(), core);
303     msg_st->err = interphi_domain_register(&phi->topology[phi->id], svc_st->name,
304                                            svc_st->domainid);
305
306 #else
307     svc_st->name = xeon_phi_domain_build_iface(name, XEON_PHI_DOMAIN_HOST, core);
308     svc_st->domainid = xeon_phi_domain_build_id(phi->id, core, 0x1, domain);
309     msg_st->err = domain_register(svc_st->name, svc_st->domainid);
310 #endif
311     xphi_svc_clients_insert(svc_st);
312     txq_send(msg_st);
313 }
314
315 static void chan_open_response_rx(struct xeon_phi_binding *binding,
316                                   errval_t msgerr)
317 {
318     XSERVICE_DEBUG("chan_open_response_rx: %s\n", err_getstring(msgerr));
319
320     struct xphi_svc_st *svc_st = binding->st;
321
322     svc_st->rpc_state |= RPC_STATE_DONE;
323     svc_st->rpc_err |= msgerr;
324 }
325
326 static void chan_open_request_call_rx(struct xeon_phi_binding *binding,
327                                       uint8_t xphi,
328                                       struct capref msgframe,
329                                       uint8_t type,
330                                       uint64_t domain,
331                                       uint64_t usrdata)
332 {
333     XSERVICE_DEBUG("chan_open_request_did_call_rx: xphi:%u, domain:%lx\n", xphi,
334                    domain);
335
336     struct xphi_svc_st *svc_st = binding->st;
337
338     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
339     if (msg_st == NULL) {
340         USER_PANIC("ran out of reply state resources\n");
341     }
342
343     msg_st->send = chan_open_request_response_tx;
344     msg_st->cleanup = NULL;
345
346 #ifdef __k1om__
347     struct xnode *node = &svc_st->phi->topology[xphi];
348 #else
349     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
350 #endif
351     msg_st->err = interphi_chan_open(node, domain, svc_st->domainid, usrdata,
352                                      msgframe, type);
353
354     txq_send(msg_st);
355 }
356
357 static void kill_call_rx(struct xeon_phi_binding *binding,
358                          uint8_t xid,
359                          uint64_t domainid)
360 {
361     struct xphi_svc_st *svc_st = binding->st;
362
363     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
364     if (msg_st == NULL) {
365         USER_PANIC("ran out of reply state resources\n");
366     }
367
368     msg_st->send = kill_response_tx;
369     msg_st->cleanup = NULL;
370
371 #ifdef __k1om__
372     struct xnode *node = &svc_st->phi->topology[xid];
373 #else
374     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
375 #endif
376
377     msg_st->err = interphi_kill(node, domainid);
378
379     txq_send(msg_st);
380 }
381
382 static void spawn_with_cap_call_rx(struct xeon_phi_binding *binding,
383                                    uint8_t xid,
384                                    uint8_t core,
385                                    const char *cmdline,
386                                    size_t length,
387                                    uint8_t flags,
388                                    struct capref cap)
389 {
390     struct xphi_svc_st *svc_st = binding->st;
391
392     XSERVICE_DEBUG("spawn_with_cap_call_rx: %s of length %lu\n", cmdline, length);
393
394     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
395     if (msg_st == NULL) {
396         USER_PANIC("ran out of reply state resources\n");
397     }
398
399     msg_st->send = spawn_with_cap_response_tx;
400     msg_st->cleanup = NULL;
401
402     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
403
404 #ifdef __k1om__
405     struct xnode *node = &svc_st->phi->topology[xid];
406 #else
407     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
408 #endif
409     msg_st->err = interphi_spawn_with_cap(node, core, (CONST_CAST)cmdline, length,
410                                           flags, cap,
411                                           &xphi_st->args.spawn.domainid);
412     txq_send(msg_st);
413 }
414
415 static void spawn_call_rx(struct xeon_phi_binding *binding,
416                           uint8_t xid,
417                           uint8_t core,
418                           const char *cmdline,
419                           size_t length,
420                           uint8_t flags)
421 {
422     struct xphi_svc_st *svc_st = binding->st;
423
424     XSERVICE_DEBUG("spawn_call_rx: %s of length %lu\n", cmdline, length);
425
426     struct txq_msg_st *msg_st = txq_msg_st_alloc(&svc_st->queue);
427     if (msg_st == NULL) {
428         USER_PANIC("ran out of reply state resources\n");
429     }
430
431     msg_st->send = spawn_response_tx;
432     msg_st->cleanup = NULL;
433
434     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
435
436 #ifdef __k1om__
437     struct xnode *node = &svc_st->phi->topology[xid];
438 #else
439     struct xnode *node = &svc_st->phi->topology[svc_st->phi->id];
440 #endif
441     msg_st->err = interphi_spawn(node, core, (CONST_CAST)cmdline, length, flags,
442                                  &xphi_st->args.spawn.domainid);
443     txq_send(msg_st);
444 }
445
446 static struct xeon_phi_rx_vtbl xphi_svc_rx_vtbl = {
447     .domain_init_call = domain_init_call_rx,
448     .domain_register_call = domain_register_call_rx,
449     .domain_lookup_call = domain_lookup_call_rx,
450     .domain_wait_call = domain_wait_call_rx,
451     .spawn_call = spawn_call_rx,
452     .spawn_with_cap_call = spawn_with_cap_call_rx,
453     .kill_call = kill_call_rx,
454     .chan_open_request_call = chan_open_request_call_rx,
455     .chan_open_response = chan_open_response_rx
456 };
457
458 /*
459  * ----------------------------------------------------------------------------
460  * Export / Connect / Bind Callbacks
461  * ----------------------------------------------------------------------------
462  */
463
464 static errval_t xphi_svc_connect_cb(void *st,
465                                     struct xeon_phi_binding *binding)
466 {
467     XSERVICE_DEBUG("xphi_svc_connect_cb: new connection from domain.\n");
468
469     struct xphi_svc_st *svc_st = calloc(1, sizeof(*svc_st));
470     if (svc_st == NULL) {
471         return LIB_ERR_MALLOC_FAIL;
472     }
473
474     svc_st->phi = st;
475
476     txq_init(&svc_st->queue, binding, binding->waitset,
477              (txq_register_fn_t) binding->register_send,
478              sizeof(struct xphi_svc_msg_st));
479
480     binding->st = svc_st;
481     binding->rx_vtbl = xphi_svc_rx_vtbl;
482     svc_st->binding = binding;
483
484     return SYS_ERR_OK;
485
486 }
487
488 static void xphi_svc_export_cb(void *st,
489                                errval_t err,
490                                iref_t iref)
491 {
492     XSERVICE_DEBUG("xphi_svc_export_cb @ iref:%"PRIxIREF" result: %s\n", iref,
493                    err_getstring(err));
494
495     if (err_is_ok(err)) {
496         struct xeon_phi *phi = st;
497         phi->xphi_svc_iref = iref;
498         xphi_svc_state = XPM_SVC_STATE_EXPORT_OK;
499         return;
500     }
501
502     xphi_svc_state = XPM_SVC_STATE_EXPORT_FAIL;
503 }
504
505 /*
506  * ----------------------------------------------------------------------------
507  * Initialization
508  * ----------------------------------------------------------------------------
509  */
510
511 /**
512  *
513  */
514 errval_t xeon_phi_service_init(struct xeon_phi *phi)
515 {
516     errval_t err;
517
518     XSERVICE_DEBUG("initializing Xeon Phi service\n");
519
520     if (xphi_svc_state != XPM_SVC_STATE_INVALID) {
521         return SYS_ERR_OK;
522     }
523
524     xphi_svc_state = XPM_SVC_STATE_EXPORTING;
525
526     err = xeon_phi_export(phi, xphi_svc_export_cb, xphi_svc_connect_cb,
527                           get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
528     if (err_is_fail(err)) {
529         return err;
530     }
531
532     while (xphi_svc_state == XPM_SVC_STATE_EXPORTING) {
533         messages_wait_and_handle_next();
534     }
535
536     if (xphi_svc_state == XPM_SVC_STATE_EXPORT_FAIL) {
537         return xphi_svc_err;
538     }
539
540 #ifdef __k1om__
541     XSERVICE_DEBUG("registering {%s} with iref:%"PRIxIREF"\n", XEON_PHI_SERVICE_NAME,
542                    phi->xphi_svc_iref);
543     err = nameservice_register(XEON_PHI_SERVICE_NAME, phi->xphi_svc_iref);
544     if (err_is_fail(err)) {
545         return err;
546     }
547 #else
548     char iface[30];
549     snprintf(iface, sizeof(iface), "%s.%u", XEON_PHI_SERVICE_NAME, phi->id);
550     XSERVICE_DEBUG("registering {%s} with iref:%"PRIxIREF"\n", iface, phi->xphi_svc_iref);
551     err = nameservice_register(iface, phi->xphi_svc_iref);
552 #endif
553
554     xphi_svc_state = XPM_SVC_STATE_RUNNING;
555
556     XSERVICE_DEBUG("service up and running\n");
557
558     return SYS_ERR_OK;
559 }
560
561 errval_t xeon_phi_service_open_channel(struct capref cap,
562                                        uint8_t type,
563                                        xphi_dom_id_t target_domain,
564                                        xphi_dom_id_t src_domain,
565                                        uint64_t userdata)
566 {
567     errval_t err;
568
569     struct xphi_svc_st *st = NULL;
570
571     st = xphi_svc_clients_lookup_by_did(target_domain);
572     XSERVICE_DEBUG("xeon_phi_service_open_channel: target_domain, st:%p\n", st);
573
574     if (st == NULL) {
575         return XEON_PHI_ERR_CLIENT_DOMAIN_VOID;
576     }
577
578     while (st->rpc_state != RPC_STATE_IDLE) {
579         err = xeon_phi_event_poll(true);
580         if (err_is_fail(err)) {
581             return err;
582         }
583     }
584
585     st->rpc_state = RPC_STATE_PROGRESS;
586
587     struct txq_msg_st *msg_st = txq_msg_st_alloc(&st->queue);
588     if (msg_st == NULL) {
589         USER_PANIC("ran out of reply state resources\n");
590     }
591
592     msg_st->send = chan_open_call_tx;
593     msg_st->cleanup = NULL;
594
595     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
596
597     xphi_st->args.open.cap = cap;
598     xphi_st->args.open.type = type;
599     xphi_st->args.open.domainid = src_domain;
600     xphi_st->args.open.usrdata = userdata;
601
602     txq_send(msg_st);
603
604     while (!(st->rpc_state & RPC_STATE_DONE)) {
605         err = xeon_phi_event_poll(true);
606         if (err_is_fail(err)) {
607             return err;
608         }
609     }
610
611     st->rpc_state = RPC_STATE_IDLE;
612
613     return st->rpc_err;
614 }
615
616 errval_t xeon_phi_service_domain_wait_response(struct xphi_svc_st *st,
617                                                errval_t err,
618                                                xphi_dom_id_t domain)
619 {
620     struct txq_msg_st *msg_st = txq_msg_st_alloc(&st->queue);
621     if (msg_st == NULL) {
622         USER_PANIC("ran out of reply state resources\n");
623     }
624
625     msg_st->send = domain_wait_response_tx;
626     msg_st->cleanup = NULL;
627
628     struct xphi_svc_msg_st *xphi_st = (struct xphi_svc_msg_st *) msg_st;
629
630     xphi_st->args.domain.domid = domain;
631
632     txq_send(msg_st);
633
634     return SYS_ERR_OK;
635 }