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 <stdio.h>
12#include <barrelfish/barrelfish.h>
13#include <barrelfish/nameservice_client.h>
14#include <octopus/octopus.h>
15#include <flounder/flounder_txqueue.h>
16
17#include <if/xeon_phi_defs.h>
18
19#include <xeon_phi/xeon_phi.h>
20#include <xeon_phi/xeon_phi_client.h>
21#include <xeon_phi/xeon_phi_domain.h>
22
23#include "xeon_phi_client_internal.h"
24
25#ifdef XEON_PHI_DEBUG_MSG
26#define DEBUG_XPHI(x...) debug_printf("[xphi-client] " x);
27#else
28#define DEBUG_XPHI(x...)
29#endif
30#define PRINTF_XPHI(x...) debug_printf("[xphi-client] " x);
31
32/**
33 * enumeration of all possible states of the service exporting process
34 */
35enum xpm_svc_state
36{
37    XPM_SVC_STATE_INVALID,
38    XPM_SVC_STATE_BINDING,
39    XPM_SVC_STATE_BIND_OK,
40    XPM_SVC_STATE_BIND_FAIL,
41    XPM_SVC_STATE_REGISTERING,
42    XPM_SVC_STATE_REGISTER_OK,
43    XPM_SVC_STATE_REGISTER_FAIL,
44    XPM_SVC_STATE_CONNECTED
45};
46
47struct xeon_phi_client
48{
49    struct xeon_phi_binding *binding;
50    struct tx_queue txq;
51    volatile uint8_t rpc_wait_reply;
52    uint64_t rpc_data;
53    errval_t rpc_err;
54    struct capref rpc_cap;
55    errval_t err;
56    xphi_id_t xid;
57    enum xpm_svc_state state;
58};
59
60struct xeon_phi_client *xphi_svc[XEON_PHI_NUM_MAX] = {
61    0
62};
63
64uint8_t xphi_present[XEON_PHI_NUM_MAX] = {
65    0
66};
67
68static struct xeon_phi_callbacks client_cb;
69
70struct xphi_msg_st
71{
72    struct txq_msg_st common;
73    /* union of arguments */
74    union
75    {
76        struct
77        {
78            const char *name;
79            xphi_dom_id_t domid;
80            coreid_t core;
81        } domain;
82        struct
83        {
84            xphi_id_t xid;
85            coreid_t core;
86            uint8_t flags;
87            char *cmdline;
88            size_t cmdlen;
89            struct capref cap;
90        } spawn;
91        struct
92        {
93            xphi_id_t xid;
94            xphi_dom_id_t domid;
95        } kill;
96        struct
97        {
98            xphi_id_t xid;
99            struct capref msgframe;
100            xphi_chan_type_t type;
101            xphi_dom_id_t domid;
102            uint64_t usrdata;
103        } open;
104        struct
105        {
106            struct capref mem;
107        } dma_register;
108        struct
109        {
110            uint64_t to;
111            uint64_t from;
112            uint64_t length;
113        } dma_memcpy;
114        struct
115        {
116            uint64_t arg;
117        } get_nodeid;
118        struct {
119            uint64_t bytes;
120        } alloc;
121    } args;
122};
123
124/*
125 *
126 */
127static inline errval_t check_online(uint8_t xid)
128{
129    errval_t err;
130    if (xphi_present[xid]) {
131        return SYS_ERR_OK;
132    }
133
134#ifdef __k1om__
135    if (xid == disp_xeon_phi_id()) {
136        xphi_present[xid] = 1;
137        return SYS_ERR_OK;
138    }
139#endif
140
141    char buf[20];
142    snprintf(buf, 20, "xeon_phi.%u.ready", xid);
143    xphi_dom_id_t result;
144    err = xeon_phi_domain_blocking_lookup(buf, &result);
145    if (err_is_fail(err) || result != 0xcafebabe) {
146        USER_PANIC_ERR(err, "result: %lx, %x", result, (uint32_t )result);
147    }
148
149    xphi_present[xid] = 1;
150
151    return err;
152}
153
154/*
155 * ---------------------------------------------------------------------------
156 * RPC management
157 * ---------------------------------------------------------------------------
158 */
159
160/**
161 * \brief starts a new RPC to the DMA service
162 *
163 * \param chan  the DMA channel to start the RPC on
164 *
165 * \returns 1 if the RPC transaction could be started
166 *          0 if there was already a transaction in process
167 */
168static inline uint8_t rpc_start(struct xeon_phi_client *cl)
169{
170    if (!cl->rpc_wait_reply) {
171        cl->rpc_wait_reply = 0x1;
172        return 1;
173    }
174    return 0;
175}
176
177/**
178 * \brief waits until the started transaction is finished
179 *
180 * \param chan  the DMA channel
181 */
182static inline void rpc_wait_done(struct xeon_phi_client *cl)
183{
184    while (cl->rpc_wait_reply == 0x1) {
185        messages_wait_and_handle_next();
186    }
187}
188
189/**
190 * \brief signals the completion of the RPC
191 *
192 * \param chan  the DMA channel
193 */
194static inline void rpc_done(struct xeon_phi_client *cl)
195{
196    cl->rpc_wait_reply = 0x2;
197}
198
199/**
200 * \brief signals the completion of the RPC
201 *
202 * \param chan  the DMA channel
203 */
204static inline void rpc_clear(struct xeon_phi_client *cl)
205{
206    cl->rpc_wait_reply = 0x0;
207}
208
209/*
210 * ----------------------------------------------------------------------------
211 * Send handlers
212 * ----------------------------------------------------------------------------
213 */
214
215static errval_t domain_init_call_tx(struct txq_msg_st *msg_st)
216{
217    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
218    size_t length = strlen(st->args.domain.name) + 1;
219    return xeon_phi_domain_init_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
220                                         (domainid_t) st->args.domain.domid,
221                                         st->args.domain.core, st->args.domain.name,
222                                         length);
223}
224#ifdef __k1om__
225static errval_t domain_register_call_tx(struct txq_msg_st *msg_st)
226{
227    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
228    size_t length = strlen(st->args.domain.name) + 1;
229    return xeon_phi_domain_register_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
230                                             st->args.domain.name, length,
231                                             st->args.domain.domid);
232}
233static errval_t domain_lookup_call_tx(struct txq_msg_st *msg_st)
234{
235    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
236    size_t length = strlen(st->args.domain.name) + 1;
237    return xeon_phi_domain_lookup_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
238                                           st->args.domain.name, length);
239}
240
241static errval_t domain_wait_call_tx(struct txq_msg_st *msg_st)
242{
243    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
244    size_t length = strlen(st->args.domain.name) + 1;
245    return xeon_phi_domain_wait_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
246                                         st->args.domain.name, length);
247}
248#endif
249
250static errval_t spawn_call_tx(struct txq_msg_st *msg_st)
251{
252    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
253    return xeon_phi_spawn_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
254                                   st->args.spawn.xid, st->args.spawn.core,
255                                   st->args.spawn.cmdline, st->args.spawn.cmdlen,
256                                   st->args.spawn.flags);
257}
258
259static errval_t spawn_with_cap_call_tx(struct txq_msg_st *msg_st)
260{
261    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
262    return xeon_phi_spawn_with_cap_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
263                                            st->args.spawn.xid, st->args.spawn.core,
264                                            st->args.spawn.cmdline,
265                                            st->args.spawn.cmdlen,
266                                            st->args.spawn.flags,
267                                            st->args.spawn.cap);
268}
269
270static errval_t kill_call_tx(struct txq_msg_st *msg_st)
271{
272    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
273    return xeon_phi_kill_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
274                                  st->args.kill.xid, st->args.kill.domid);
275}
276
277static errval_t chan_open_request_call_tx(struct txq_msg_st *msg_st)
278{
279    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
280    return xeon_phi_chan_open_request_call__tx(msg_st->queue->binding,
281                                               TXQCONT(msg_st), st->args.open.xid,
282                                               st->args.open.msgframe,
283                                               st->args.open.type,
284                                               st->args.open.domid,
285                                               st->args.open.usrdata);
286}
287
288static errval_t dma_register_call_tx(struct txq_msg_st *msg_st)
289{
290    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
291    return xeon_phi_dma_register_call__tx(msg_st->queue->binding,
292                                          TXQCONT(msg_st),
293                                          st->args.dma_register.mem);
294}
295
296static errval_t dma_memcpy_call_tx(struct txq_msg_st *msg_st)
297{
298    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
299    return xeon_phi_dma_memcpy_call__tx(msg_st->queue->binding,
300                                          TXQCONT(msg_st),
301                                          st->args.dma_memcpy.to,
302                                          st->args.dma_memcpy.from,
303                                          st->args.dma_memcpy.length);
304}
305
306static errval_t get_nodeid_call_tx(struct txq_msg_st *msg_st)
307{
308    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
309    return xeon_phi_get_nodeid_call__tx(msg_st->queue->binding,
310                                        TXQCONT(msg_st),
311                                        st->args.get_nodeid.arg);
312}
313
314static errval_t chan_open_response_tx(struct txq_msg_st *msg_st)
315{
316    return xeon_phi_chan_open_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
317                                           msg_st->err);
318}
319
320static errval_t alloc_mem_call_tx(struct txq_msg_st *msg_st)
321{
322    struct xphi_msg_st *st = (struct xphi_msg_st *) msg_st;
323    return xeon_phi_alloc_mem_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
324                                       st->args.alloc.bytes);
325}
326
327/*
328 * ----------------------------------------------------------------------------
329 * Receive Handlers
330 * ----------------------------------------------------------------------------
331 */
332static void domain_lookup_response_rx(struct xeon_phi_binding *b,
333                                      xphi_dom_id_t domid,
334                                      errval_t msgerr)
335{
336    DEBUG_XPHI("domain_lookup_response_rx: %lx,  %s\n", domid, err_getstring(msgerr));
337
338    struct xeon_phi_client *cl = b->st;
339    assert(cl);
340
341    cl->rpc_err = msgerr;
342    cl->rpc_data = domid;
343
344    rpc_done(cl);
345}
346
347static void domain_wait_response_rx(struct xeon_phi_binding *b,
348                                    xphi_dom_id_t domid,
349                                    errval_t msgerr)
350{
351    DEBUG_XPHI("domain_wait_response_rx: %lx,  %s\n", domid, err_getstring(msgerr));
352
353    struct xeon_phi_client *cl = b->st;
354    assert(cl);
355
356    cl->rpc_err = msgerr;
357    cl->rpc_data = domid;
358
359    rpc_done(cl);
360}
361
362static void domain_init_response_rx(struct xeon_phi_binding *b,
363                                    errval_t msgerr)
364{
365    DEBUG_XPHI("domain_init_response_rx: %s\n", err_getstring(msgerr));
366
367    struct xeon_phi_client *cl = b->st;
368    assert(cl);
369    assert(cl->state == XPM_SVC_STATE_REGISTERING);
370
371    cl->rpc_err = msgerr;
372
373    rpc_done(cl);
374}
375
376static void domain_register_response_rx(struct xeon_phi_binding *b,
377                                        errval_t msgerr)
378{
379    DEBUG_XPHI("domain_regoster_response_rx: %s\n", err_getstring(msgerr));
380
381    struct xeon_phi_client *cl = b->st;
382    assert(cl);
383    assert(cl->state == XPM_SVC_STATE_REGISTERING);
384
385    cl->rpc_err = msgerr;
386
387    rpc_done(cl);
388}
389
390static void spawn_response_rx(struct xeon_phi_binding *b,
391                              uint64_t domainid,
392                              errval_t msgerr)
393{
394    DEBUG_XPHI("spawn_response_rx: %lx %s\n", domainid, err_getstring(msgerr));
395
396    struct xeon_phi_client *cl = b->st;
397    assert(cl);
398    assert(cl->state == XPM_SVC_STATE_CONNECTED);
399
400    cl->rpc_err = msgerr;
401    cl->rpc_data = domainid;
402
403    rpc_done(cl);
404}
405
406static void spawn_with_cap_response_rx(struct xeon_phi_binding *b,
407                                       uint64_t domainid,
408                                       errval_t msgerr)
409{
410    DEBUG_XPHI("spawn_with_cap_response_rx: %lx %s\n", domainid,
411               err_getstring(msgerr));
412
413    struct xeon_phi_client *cl = b->st;
414    assert(cl);
415    assert(cl->state == XPM_SVC_STATE_CONNECTED);
416
417    cl->rpc_err = msgerr;
418    cl->rpc_data = domainid;
419
420    rpc_done(cl);
421}
422
423static void kill_response_rx(struct xeon_phi_binding *b,
424                             errval_t msgerr)
425{
426    DEBUG_XPHI("kill_response_rx: %s\n", err_getstring(msgerr));
427
428    struct xeon_phi_client *cl = b->st;
429    assert(cl);
430    assert(cl->state == XPM_SVC_STATE_CONNECTED);
431
432    cl->rpc_err = msgerr;
433
434    rpc_done(cl);
435}
436
437static void dma_register_response_rx(struct xeon_phi_binding *b,
438                                     uint64_t devaddr,
439                                     errval_t msgerr)
440{
441    DEBUG_XPHI("dma_register_response_rx: %s\n", err_getstring(msgerr));
442
443    struct xeon_phi_client *cl = b->st;
444    assert(cl);
445    assert(cl->state == XPM_SVC_STATE_CONNECTED);
446
447    cl->rpc_err = msgerr;
448    cl->rpc_data = devaddr;
449
450    rpc_done(cl);
451}
452
453static void dma_memcpy_response_rx(struct xeon_phi_binding *b,
454                                   errval_t msgerr)
455{
456    DEBUG_XPHI("dma_memcpy_response_rx: %s\n", err_getstring(msgerr));
457
458    struct xeon_phi_client *cl = b->st;
459    assert(cl);
460    assert(cl->state == XPM_SVC_STATE_CONNECTED);
461
462    cl->rpc_err = msgerr;
463
464    rpc_done(cl);
465}
466
467static void get_nodeid_response_rx(struct xeon_phi_binding *b,
468                                   int32_t nodeid)
469{
470    DEBUG_XPHI("get_nodeid_response_rx: %s\n", err_getstring(msgerr));
471
472    struct xeon_phi_client *cl = b->st;
473    assert(cl);
474    assert(cl->state == XPM_SVC_STATE_CONNECTED);
475
476
477    cl->rpc_err = SYS_ERR_OK;
478    cl->rpc_data = (uint64_t)nodeid;
479
480    rpc_done(cl);
481}
482
483
484
485
486static void chan_open_request_response_rx(struct xeon_phi_binding *b,
487                                          errval_t msgerr)
488{
489    DEBUG_XPHI("chan_open_request_response_rx: %s\n", err_getstring(msgerr));
490
491    struct xeon_phi_client *cl = b->st;
492    assert(cl);
493    assert(cl->state == XPM_SVC_STATE_CONNECTED);
494
495    cl->rpc_err = msgerr;
496
497    rpc_done(cl);
498}
499
500static void alloc_mem_response_rx(struct xeon_phi_binding *b,
501                                  struct capref cap,
502                                  errval_t msgerr)
503{
504    debug_printf("alloc_mem_response_rx: %s\n", err_getstring(msgerr));
505
506    struct xeon_phi_client *cl = b->st;
507    assert(cl);
508    assert(cl->state == XPM_SVC_STATE_CONNECTED);
509
510    cl->rpc_err = msgerr;
511    cl->rpc_cap = cap;
512
513    rpc_done(cl);
514}
515
516static void chan_open_call_rx(struct xeon_phi_binding *b,
517                              uint64_t domain,
518                              uint64_t usrdata,
519                              struct capref msgframe,
520                              uint8_t type)
521{
522    DEBUG_XPHI("chan_open_request_call_rx: from domain:%lx, type:%u\n", domain, type);
523
524    struct xeon_phi_client *cl = b->st;
525    assert(cl);
526    assert(cl->state == XPM_SVC_STATE_CONNECTED);
527
528    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
529    if (msg_st == NULL) {
530        USER_PANIC("could not allocate reply state");
531    }
532
533    msg_st->cleanup = NULL;
534    msg_st->send = chan_open_response_tx;
535    msg_st->err = XEON_PHI_ERR_CLIENT_OPEN_REJECT;
536
537    if (client_cb.open) {
538        msg_st->err = client_cb.open(domain, usrdata, msgframe, type);
539    }
540
541    txq_send(msg_st);
542}
543
544struct xeon_phi_rx_vtbl xphi_svc_rx_vtbl = {
545    .domain_init_response = domain_init_response_rx,
546    .domain_register_response = domain_register_response_rx,
547    .domain_lookup_response = domain_lookup_response_rx,
548    .domain_wait_response = domain_wait_response_rx,
549    .spawn_response = spawn_response_rx,
550    .spawn_with_cap_response = spawn_with_cap_response_rx,
551    .kill_response = kill_response_rx,
552    .chan_open_request_response = chan_open_request_response_rx,
553    .chan_open_call = chan_open_call_rx,
554    .dma_register_response = dma_register_response_rx,
555    .dma_memcpy_response = dma_memcpy_response_rx,
556    .get_nodeid_response = get_nodeid_response_rx,
557    .alloc_mem_response = alloc_mem_response_rx,
558};
559
560/*
561 * ----------------------------------------------------------------------------
562 * Client Initialization
563 * ----------------------------------------------------------------------------
564 */
565
566static errval_t xphi_client_register(struct xeon_phi_client *cl)
567{
568    errval_t err;
569
570    assert(cl->binding != NULL);
571
572    while (!rpc_start(cl)) {
573        messages_wait_and_handle_next();
574    }
575
576    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
577    if (msg_st == NULL) {
578        rpc_clear(cl);
579        return LIB_ERR_MALLOC_FAIL;
580    }
581
582    msg_st->cleanup = NULL;
583    msg_st->send = domain_init_call_tx;
584
585    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
586    svc_st->args.domain.domid = disp_get_domain_id();
587    svc_st->args.domain.core = disp_get_core_id();
588
589    /// XXX: bug, this fails if disp_name() length == DISP_NAME_LEN
590    svc_st->args.domain.name = disp_name();
591
592    DEBUG_XPHI("registration {%s} with domid:%x\n", svc_st->args.domain.name,
593               (domainid_t )svc_st->args.domain.domid);
594
595    txq_send(msg_st);
596
597    rpc_wait_done(cl);
598
599    if (err_is_fail(cl->rpc_err)) {
600        cl->state = XPM_SVC_STATE_REGISTER_FAIL;
601    } else {
602        cl->state = XPM_SVC_STATE_REGISTER_OK;
603    }
604
605    err = cl->rpc_err;
606
607    rpc_clear(cl);
608
609    return err;
610}
611
612static void xphi_bind_cb(void *st,
613                         errval_t err,
614                         struct xeon_phi_binding *b)
615{
616    struct xeon_phi_client *cl = st;
617
618    DEBUG_XPHI("bound to service: %s\n", err_getstring(err));
619
620    if (err_is_fail(err)) {
621        cl->err = err;
622        cl->state = XPM_SVC_STATE_BIND_FAIL;
623        return;
624    }
625
626    txq_init(&cl->txq, b, get_default_waitset(),
627             (txq_register_fn_t) b->register_send, sizeof(struct xphi_msg_st));
628
629    b->rx_vtbl = xphi_svc_rx_vtbl;
630    b->st = cl;
631
632    cl->binding = b;
633    cl->state = XPM_SVC_STATE_BIND_OK;
634}
635
636/*
637 * ----------------------------------------------------------------------------
638 * Initialization
639 * ----------------------------------------------------------------------------
640 */
641
642/**
643 *
644 */
645static errval_t xphi_client_init(xphi_id_t xid)
646{
647    errval_t err;
648
649    if (xid >= XEON_PHI_NUM_MAX) {
650        return XEON_PHI_ERR_INVALID_ID;
651    }
652
653    struct xeon_phi_client *cl = xphi_svc[xid];
654    if (cl == NULL) {
655        cl = calloc(1, sizeof(*cl));
656        if (cl == NULL) {
657            return LIB_ERR_MALLOC_FAIL;
658        }
659    } else {
660        return cl->err;
661    }
662
663    iref_t svc_iref;
664#ifdef __k1om__
665    DEBUG_XPHI("looking up service {%s}\n", XEON_PHI_SERVICE_NAME);
666    err = nameservice_blocking_lookup(XEON_PHI_SERVICE_NAME, &svc_iref);
667#else
668    char iface[30];
669    snprintf(iface, sizeof(iface), "%s.%u", XEON_PHI_SERVICE_NAME, xid);
670    DEBUG_XPHI("looking up service {%s}\n", iface);
671    err = nameservice_blocking_lookup(iface, &svc_iref);
672#endif
673    if (err_is_fail(err)) {
674        free(cl);
675        return err;
676    }
677
678    DEBUG_XPHI("initializing client to xid:%u @ iref:%"PRIxIREF"\n", xid, svc_iref);
679
680    cl->state = XPM_SVC_STATE_BINDING;
681    cl->xid = xid;
682    struct waitset *ws = get_default_waitset();
683
684    err = xeon_phi_bind(svc_iref, xphi_bind_cb, cl, ws, IDC_BIND_FLAGS_DEFAULT);
685    if (err_is_fail(err)) {
686        return err;
687    }
688
689    while (cl->state == XPM_SVC_STATE_BINDING) {
690        messages_wait_and_handle_next();
691    }
692
693    if (cl->state == XPM_SVC_STATE_BIND_FAIL) {
694        err = cl->err;
695        free(cl);
696        return err;
697    }
698
699    cl->state = XPM_SVC_STATE_REGISTERING;
700    err = xphi_client_register(cl);
701    if (err_is_fail(err)) {
702        free(cl);
703        return err;
704    }
705
706    if (cl->state == XPM_SVC_STATE_REGISTER_FAIL) {
707        err = cl->err;
708        free(cl);
709        return err;
710    }
711
712    cl->state = XPM_SVC_STATE_CONNECTED;
713
714    xphi_svc[xid] = cl;
715
716#ifdef __k1om__
717    for (uint32_t i = 0; i < XEON_PHI_NUM_MAX; ++i) {
718        xphi_svc[i] = cl;
719    }
720#endif
721
722    return SYS_ERR_OK;
723}
724
725/*
726 * ============================================================================
727 * Public interface
728 * ============================================================================
729 */
730
731/**
732 * \brief sets the callbacks for incoming messages
733 *
734 * \param cb    Xeon Phi callbacks
735 */
736void xeon_phi_client_set_callbacks(struct xeon_phi_callbacks *cb)
737{
738    client_cb = *cb;
739}
740
741/**
742 * \brief initializes the Xeon Phi client
743 *
744 * \param xid   Xeon Phi ID of the card to initialize
745 */
746errval_t xeon_phi_client_init(xphi_id_t xid)
747{
748    assert(xid < XEON_PHI_NUM_MAX);
749
750    if (xphi_svc[xid] == NULL) {
751        return xphi_client_init(xid);
752    }
753    return SYS_ERR_OK;
754}
755
756/**
757 * \brief spawns a new domain on the Xeon Phi or on the host
758 *
759 * \param xid       Xeon Phi ID to start the domain
760 * \param core      Core to start
761 * \param path      Program to spawn
762 * \param argv      Program arguments
763 * \param cap       Capability to pass
764 * \param flags     spawn flags
765 * \param domid     returns the domain id of the spawned domain
766 *
767 * \return SYS_ERR_OK on success
768 *         errval on failure
769 */
770errval_t xeon_phi_client_spawn(xphi_id_t xid,
771                               coreid_t core,
772                               char *path,
773                               char *argv[],
774                               struct capref cap,
775                               uint8_t flags,
776                               xphi_dom_id_t *domid)
777{
778    errval_t err;
779
780    if (xid >= XEON_PHI_NUM_MAX) {
781        return XEON_PHI_ERR_INVALID_ID;
782    }
783
784    err = check_online(xid);
785    if (err_is_fail(err)) {
786        return err;
787    }
788
789    if (xphi_svc[xid] == NULL) {
790        err = xphi_client_init(xid);
791        if (err_is_fail(err)) {
792            return err;
793        }
794    }
795
796    struct xeon_phi_client *cl = xphi_svc[xid];
797    assert(cl);
798
799    if (!rpc_start(cl)) {
800        return XEON_PHI_ERR_CLIENT_BUSY;
801    }
802
803    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
804    if (msg_st == NULL) {
805        rpc_clear(cl);
806        return LIB_ERR_MALLOC_FAIL;
807    }
808
809    size_t argstrlen = strlen(path) + 1;
810
811    if (argv) {
812        for (int i = 0; argv[i] != NULL; i++) {
813            argstrlen += strlen(argv[i]) + 1;
814        }
815    }
816
817    char cmdline[argstrlen];
818    size_t argstrpos = strlen(path);
819    strcpy(&cmdline[0], path);
820    cmdline[argstrpos++] = '\0';
821
822    if (argv) {
823        for (int i = 0; argv[i] != NULL; i++) {
824            strcpy(&cmdline[argstrpos], argv[i]);
825            argstrpos += strlen(argv[i]);
826            cmdline[argstrpos++] = '\0';
827        }
828    }
829
830    msg_st->cleanup = NULL;
831
832    if (capref_is_null(cap)) {
833        DEBUG_XPHI("spawning %s on core:%u @ xid:%u\n", cmdline, core, xid);
834        msg_st->send = spawn_call_tx;
835    } else {
836        DEBUG_XPHI("spawning  %s with cap on core:%u @ xid:%u\n", cmdline, core, xid);
837        msg_st->send = spawn_with_cap_call_tx;
838    }
839
840    cl->rpc_data = 0;
841
842    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
843    svc_st->args.spawn.xid = xid;
844    svc_st->args.spawn.core = core;
845    svc_st->args.spawn.cmdline = cmdline;
846    svc_st->args.spawn.cmdlen = argstrlen;
847    svc_st->args.spawn.flags = flags;
848    svc_st->args.spawn.cap = cap;
849
850    txq_send(msg_st);
851
852    rpc_wait_done(cl);
853
854    if (domid) {
855        *domid = cl->rpc_data;
856    }
857
858    DEBUG_XPHI("spawned %s: domid:%lx %s\n", cmdline, cl->rpc_data,
859               err_getstring(cl->rpc_err));
860
861    err = cl->rpc_err;
862
863    rpc_clear(cl);
864
865    return err;
866}
867
868/**
869 * \brief sends a kill request to the Xeon Phi
870 *
871 * \param xid   Xeon Phi ID
872 * \param domid ID of the domain to kill
873 *
874 * \returns SYS_ERR_OK on success,
875 *          XEON_PHI_ERR_CLIENT_DOMAIN_VOID,
876 *          errval on error
877 */
878errval_t xeon_phi_client_kill(xphi_id_t xid,
879                              xphi_dom_id_t domid)
880{
881    errval_t err;
882
883    if (xid >= XEON_PHI_NUM_MAX) {
884        return XEON_PHI_ERR_INVALID_ID;
885    }
886
887    err = check_online(xid);
888    if (err_is_fail(err)) {
889        return err;
890    }
891
892    if (xphi_svc[xid] == NULL) {
893        err = xphi_client_init(xid);
894        if (err_is_fail(err)) {
895            return err;
896        }
897    }
898
899    struct xeon_phi_client *cl = xphi_svc[xid];
900
901    if (!rpc_start(cl)) {
902        return XEON_PHI_ERR_CLIENT_BUSY;
903    }
904
905    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
906    if (msg_st == NULL) {
907        rpc_clear(cl);
908        return LIB_ERR_MALLOC_FAIL;
909    }
910
911    msg_st->cleanup = NULL;
912    msg_st->send = kill_call_tx;
913
914    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
915
916    DEBUG_XPHI("killing domain:%lx @ xid:%u", domid, xid);
917
918    svc_st->args.kill.xid = xid;
919    svc_st->args.kill.domid = domid;
920
921    txq_send(msg_st);
922
923    rpc_wait_done(cl);
924
925    DEBUG_XPHI("killed %lx: %s\n", domid, err_getstring(cl->rpc_err));
926
927    err = cl->rpc_err;
928
929    rpc_clear(cl);
930
931    return err;
932}
933
934/**
935 * \brief sends an channel open request to the domain
936 *
937 * \param xid       Xeon Phi ID
938 * \param domid     Domain ID
939 * \param usrdata   Supplied data for the other side
940 * \param iface     Interface name of the domain
941 * \param msgframe  Message frame
942 * \param chantype  Type of the channel
943 *
944 * \returns SYS_ERR_OK on success
945 *          XEON_PHI_ERR_CLIENT_OPEN_REJCT if the client rejected
946 *          errval on error
947 *
948 * The function expectes to be either the domain or the interface specified.
949 * If both are non-null then the domain ID is taken
950 */
951errval_t xeon_phi_client_chan_open(xphi_id_t xid,
952                                   xphi_dom_id_t domid,
953                                   uint64_t usrdata,
954                                   struct capref msgframe,
955                                   xphi_chan_type_t chantype)
956{
957    errval_t err;
958    assert(domid);
959    assert(!capref_is_null(msgframe));
960
961    if (xid >= XEON_PHI_NUM_MAX) {
962        return XEON_PHI_ERR_INVALID_ID;
963    }
964
965    err = check_online(xid);
966    if (err_is_fail(err)) {
967        return err;
968    }
969
970    if (xphi_svc[xid] == NULL) {
971        err = xphi_client_init(xid);
972        if (err_is_fail(err)) {
973            return err;
974        }
975    }
976
977    struct xeon_phi_client *cl = xphi_svc[xid];
978
979    if (!rpc_start(cl)) {
980        return XEON_PHI_ERR_CLIENT_BUSY;
981    }
982
983    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
984    if (msg_st == NULL) {
985        rpc_clear(cl);
986        return LIB_ERR_MALLOC_FAIL;
987    }
988
989    msg_st->cleanup = NULL;
990
991    DEBUG_XPHI("xeon_phi_client_chan_open: domid:%lx, type:%u, @ xid:%u\n", domid,
992               chantype, xid);
993    msg_st->send = chan_open_request_call_tx;
994
995    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
996
997    svc_st->args.open.domid = domid;
998    svc_st->args.open.usrdata = usrdata;
999    svc_st->args.open.xid = xid;
1000    svc_st->args.open.type = chantype;
1001    svc_st->args.open.msgframe = msgframe;
1002
1003    txq_send(msg_st);
1004
1005    rpc_wait_done(cl);
1006
1007    err = cl->rpc_err;
1008
1009    rpc_clear(cl);
1010
1011    return err;
1012}
1013
1014/**
1015 * \brief looks up the domain ID given the information
1016 *
1017 * \param iface     Interface name of the domain
1018 * \param retdom    returned domain id
1019 *
1020 * \returns SYS_ERR_OK on success,
1021 *          XEON_PHI_ERR_CLIENT_DOMAIN_VOID,
1022 *          errval on error
1023 */
1024errval_t xeon_phi_client_domain_lookup(const char *iface,
1025                                       xphi_dom_id_t *retdom)
1026{
1027#ifndef __k1om__
1028    USER_PANIC("xeon_phi_client_domain_wait: not supporte on the host\n");
1029    return SYS_ERR_OK;
1030#else
1031    errval_t err;
1032
1033    uint8_t xid = disp_xeon_phi_id();
1034
1035    if (xphi_svc[xid] == NULL) {
1036        err = xphi_client_init(xid);
1037        if (err_is_fail(err)) {
1038            return err;
1039        }
1040    }
1041
1042    struct xeon_phi_client *cl = xphi_svc[xid];
1043
1044    if (!rpc_start(cl)) {
1045        return XEON_PHI_ERR_CLIENT_BUSY;
1046    }
1047
1048    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
1049    if (msg_st == NULL) {
1050        rpc_clear(cl);
1051        return LIB_ERR_MALLOC_FAIL;
1052    }
1053
1054    msg_st->cleanup = NULL;
1055
1056    DEBUG_XPHI("xeon_phi_client_domain_lookup: iface:%s\n", iface);
1057
1058    msg_st->send = domain_lookup_call_tx;
1059
1060    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
1061
1062    svc_st->args.domain.name = iface;
1063
1064    txq_send(msg_st);
1065
1066    rpc_wait_done(cl);
1067
1068    if (err_is_ok(cl->rpc_err)) {
1069        if (retdom) {
1070            *retdom = cl->rpc_data;
1071        }
1072    }
1073
1074    err = cl->rpc_err;
1075
1076    rpc_clear(cl);
1077
1078    return err;
1079#endif
1080    return SYS_ERR_OK;
1081}
1082
1083/**
1084 * \brief looks up the domain ID given the information and waits
1085 *        until the domain registers
1086 *
1087 * \param iface     Interface name of the domain
1088 * \param retdom    returned domain id
1089 *
1090 * \returns SYS_ERR_OK on success,
1091 *          XEON_PHI_ERR_CLIENT_DOMAIN_VOID,
1092 *          errval on error
1093 */
1094errval_t xeon_phi_client_domain_wait(const char *iface,
1095                                     xphi_dom_id_t *retdom)
1096{
1097#ifndef __k1om__
1098    USER_PANIC("xeon_phi_client_domain_wait: not supporte on the host\n");
1099    return SYS_ERR_OK;
1100#else
1101    errval_t err;
1102
1103    uint8_t xid = disp_xeon_phi_id();
1104
1105    if (xphi_svc[xid] == NULL) {
1106        err = xphi_client_init(xid);
1107        if (err_is_fail(err)) {
1108            return err;
1109        }
1110    }
1111
1112    static char* format = "%s { domid: _ }";
1113    int length = snprintf(NULL, 0, format, iface);
1114
1115    char* query = malloc(length + 1);
1116    if (query == NULL) {
1117        return LIB_ERR_MALLOC_FAIL;
1118    }
1119    snprintf(query, length + 1, format, iface);
1120
1121    struct xeon_phi_client *cl = xphi_svc[xid];
1122    if (!rpc_start(cl)) {
1123        free(query);
1124        return XEON_PHI_ERR_CLIENT_BUSY;
1125    }
1126
1127    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
1128    if (msg_st == NULL) {
1129        rpc_clear(cl);
1130        free(query);
1131        return LIB_ERR_MALLOC_FAIL;
1132    }
1133
1134    msg_st->cleanup = NULL;
1135
1136    DEBUG_XPHI("xeon_phi_client_domain_wait: iface:%s\n", iface);
1137
1138    msg_st->send = domain_wait_call_tx;
1139
1140    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
1141
1142    svc_st->args.domain.name = query;
1143
1144    txq_send(msg_st);
1145
1146    rpc_wait_done(cl);
1147
1148    if (err_is_ok(cl->rpc_err)) {
1149        if (retdom) {
1150            *retdom = cl->rpc_data;
1151        }
1152    }
1153
1154    free(query);
1155
1156    err = cl->rpc_err;
1157
1158    rpc_clear(cl);
1159
1160    return err;
1161#endif
1162}
1163
1164/**
1165 * \brief registers a a domain
1166 *
1167 * \param iface     Interface name of the domain
1168 * \param retdom    returned domain id
1169 *
1170 * \returns SYS_ERR_OK on success,
1171 *          errval on error
1172 */
1173errval_t xeon_phi_client_domain_register(const char *iface,
1174                                         xphi_dom_id_t dom)
1175{
1176#ifndef __k1om__
1177    USER_PANIC("xeon_phi_client_domain_wait: not supported on the host\n");
1178    return SYS_ERR_OK;
1179#else
1180
1181    errval_t err;
1182
1183    uint8_t xid = disp_xeon_phi_id();
1184
1185    if (xphi_svc[xid] == NULL) {
1186        err = xphi_client_init(xid);
1187        if (err_is_fail(err)) {
1188            return err;
1189        }
1190    }
1191
1192    struct xeon_phi_client *cl = xphi_svc[xid];
1193    while (!rpc_start(cl)) {
1194        return XEON_PHI_ERR_CLIENT_BUSY;
1195    }
1196
1197    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
1198    if (msg_st == NULL) {
1199        rpc_clear(cl);
1200        return LIB_ERR_MALLOC_FAIL;
1201    }
1202
1203    msg_st->cleanup = NULL;
1204    msg_st->send = domain_register_call_tx;
1205
1206    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
1207
1208    svc_st->args.domain.name = iface;
1209    svc_st->args.domain.domid = dom;
1210
1211    DEBUG_XPHI("registration {%s} with domid:%lx\n", svc_st->args.domain.name,
1212               svc_st->args.domain.domid);
1213
1214    txq_send(msg_st);
1215
1216    rpc_wait_done(cl);
1217
1218    if (err_is_fail(cl->rpc_err)) {
1219        cl->state = XPM_SVC_STATE_REGISTER_FAIL;
1220    } else {
1221        cl->state = XPM_SVC_STATE_REGISTER_OK;
1222    }
1223
1224    err = cl->rpc_err;
1225
1226    rpc_clear(cl);
1227
1228    return err;
1229#endif
1230}
1231
1232
1233/**
1234 * @brief obtains the hw model id for the specified xeon phi
1235 *
1236 * @param xid   the xeon phi id
1237 * @param path  which node to consider
1238 *
1239 * @return node id
1240 */
1241int32_t xeon_phi_client_get_node_id(xphi_id_t xid, const char *path)
1242{
1243    errval_t err;
1244
1245    if (xid >= XEON_PHI_NUM_MAX) {
1246        return XEON_PHI_ERR_INVALID_ID;
1247    }
1248
1249    err = check_online(xid);
1250    if (err_is_fail(err)) {
1251        return err;
1252    }
1253
1254    if (xphi_svc[xid] == NULL) {
1255        err = xphi_client_init(xid);
1256        if (err_is_fail(err)) {
1257            return err;
1258        }
1259    }
1260
1261    uint64_t arg;
1262    if (strncmp(path, "dma", 4) == 0) {
1263        /* The DMA engine */
1264        arg = (1UL << 63) | (1UL<<32);
1265    } else if (strncmp(path, "core:", 4) == 0) {
1266        arg = (1UL << 63) | (1UL<<33) | strtoul(path + 5, NULL, 10);;
1267    } else {
1268        arg = (1UL << 63);
1269    }
1270
1271
1272    struct xeon_phi_client *cl = xphi_svc[xid];
1273
1274    if (!rpc_start(cl)) {
1275        return XEON_PHI_ERR_CLIENT_BUSY;
1276    }
1277
1278    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
1279    if (msg_st == NULL) {
1280        rpc_clear(cl);
1281        return LIB_ERR_MALLOC_FAIL;
1282    }
1283
1284    msg_st->cleanup = NULL;
1285
1286    DEBUG_XPHI("xeon_phi_client_chan_open: domid:%lx, type:%u, @ xid:%u\n", domid,
1287               chantype, xid);
1288    msg_st->send = get_nodeid_call_tx;
1289
1290    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
1291
1292    svc_st->args.get_nodeid.arg = arg;
1293
1294    txq_send(msg_st);
1295
1296    rpc_wait_done(cl);
1297
1298    err = cl->rpc_err;
1299    int32_t id = (int32_t)cl->rpc_data;
1300
1301    rpc_clear(cl);
1302
1303    if (err_is_fail(err)) {
1304        return -1;
1305    }
1306    return id;
1307
1308}
1309
1310errval_t xeon_phi_client_dma_register(xphi_id_t xid, struct capref mem, uint64_t *devaddr)
1311{
1312    errval_t err;
1313
1314    if (xid >= XEON_PHI_NUM_MAX) {
1315        return XEON_PHI_ERR_INVALID_ID;
1316    }
1317
1318    err = check_online(xid);
1319    if (err_is_fail(err)) {
1320        return err;
1321    }
1322
1323    if (xphi_svc[xid] == NULL) {
1324        err = xphi_client_init(xid);
1325        if (err_is_fail(err)) {
1326            return err;
1327        }
1328    }
1329
1330    struct xeon_phi_client *cl = xphi_svc[xid];
1331
1332    if (!rpc_start(cl)) {
1333        return XEON_PHI_ERR_CLIENT_BUSY;
1334    }
1335
1336    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
1337    if (msg_st == NULL) {
1338        rpc_clear(cl);
1339        return LIB_ERR_MALLOC_FAIL;
1340    }
1341
1342    msg_st->cleanup = NULL;
1343
1344    DEBUG_XPHI("xeon_phi_client_chan_open: domid:%lx, type:%u, @ xid:%u\n", domid,
1345               chantype, xid);
1346    msg_st->send = dma_register_call_tx;
1347
1348    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
1349
1350    svc_st->args.dma_register.mem = mem;
1351
1352    txq_send(msg_st);
1353
1354    rpc_wait_done(cl);
1355
1356    err = cl->rpc_err;
1357    *devaddr = cl->rpc_data;
1358
1359    rpc_clear(cl);
1360
1361    return err;
1362
1363}
1364
1365errval_t xeon_phi_client_dma_memcpy(xphi_id_t xid, uint64_t to, uint64_t from, uint64_t size)
1366{
1367    errval_t err;
1368
1369    if (xid >= XEON_PHI_NUM_MAX) {
1370        return XEON_PHI_ERR_INVALID_ID;
1371    }
1372
1373    err = check_online(xid);
1374    if (err_is_fail(err)) {
1375        return err;
1376    }
1377
1378    if (xphi_svc[xid] == NULL) {
1379        err = xphi_client_init(xid);
1380        if (err_is_fail(err)) {
1381            return err;
1382        }
1383    }
1384
1385    struct xeon_phi_client *cl = xphi_svc[xid];
1386
1387    if (!rpc_start(cl)) {
1388        return XEON_PHI_ERR_CLIENT_BUSY;
1389    }
1390
1391    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
1392    if (msg_st == NULL) {
1393        rpc_clear(cl);
1394        return LIB_ERR_MALLOC_FAIL;
1395    }
1396
1397    msg_st->cleanup = NULL;
1398
1399    msg_st->send = dma_memcpy_call_tx;
1400
1401    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
1402
1403    svc_st->args.dma_memcpy.from = from;
1404    svc_st->args.dma_memcpy.to = to;
1405    svc_st->args.dma_memcpy.length = size;
1406
1407    txq_send(msg_st);
1408
1409    rpc_wait_done(cl);
1410
1411    err = cl->rpc_err;
1412
1413    rpc_clear(cl);
1414
1415    return err;
1416
1417}
1418
1419
1420errval_t xeon_phi_client_alloc_memory(xphi_id_t xid, struct capref *dst,
1421                                      size_t bytes)
1422{
1423    errval_t err;
1424
1425    if (xid >= XEON_PHI_NUM_MAX) {
1426        return XEON_PHI_ERR_INVALID_ID;
1427    }
1428
1429    err = check_online(xid);
1430    if (err_is_fail(err)) {
1431        return err;
1432    }
1433
1434    if (xphi_svc[xid] == NULL) {
1435        err = xphi_client_init(xid);
1436        if (err_is_fail(err)) {
1437            return err;
1438        }
1439    }
1440
1441    struct xeon_phi_client *cl = xphi_svc[xid];
1442
1443    if (!rpc_start(cl)) {
1444        return XEON_PHI_ERR_CLIENT_BUSY;
1445    }
1446
1447    struct txq_msg_st *msg_st = txq_msg_st_alloc(&cl->txq);
1448    if (msg_st == NULL) {
1449        rpc_clear(cl);
1450        return LIB_ERR_MALLOC_FAIL;
1451    }
1452
1453    msg_st->cleanup = NULL;
1454
1455    DEBUG_XPHI("xeon_phi_client_chan_open: domid:%lx, type:%u, @ xid:%u\n", domid,
1456               chantype, xid);
1457    msg_st->send = alloc_mem_call_tx;
1458
1459    struct xphi_msg_st *svc_st = (struct xphi_msg_st *) msg_st;
1460
1461    svc_st->args.alloc.bytes = bytes;
1462
1463    txq_send(msg_st);
1464
1465    rpc_wait_done(cl);
1466
1467    err = cl->rpc_err;
1468    *dst = cl->rpc_cap;
1469
1470    rpc_clear(cl);
1471
1472    return err;
1473}
1474