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
31struct 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 */
46enum 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
56static enum xpm_svc_state xphi_svc_state = XPM_SVC_STATE_INVALID;
57
58/// error value for exporting
59static errval_t xphi_svc_err;
60
61struct 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
91struct xphi_svc_st *xphi_svc_clients;
92
93static 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
101static 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
121static 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
132static 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
138static 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
144static 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
154static 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
162static 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
168static 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
174static 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
182static 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
196static 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
220static 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
242static 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
271static 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
315static 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
326static 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
357static 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
382static 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
415static 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
446static 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
464static 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
488static 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 */
514errval_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
561errval_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
616errval_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}
636