1/**
2 * \file
3 * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
4 */
5
6/*
7 * Copyright (c) 2014 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17#include <barrelfish/barrelfish.h>
18
19#include <if/octopus_defs.h>
20#include <if/octopus_thc.h>
21
22#include <octopus/octopus.h>
23#include <octopus/trigger.h>
24
25#include "xeon_phi_internal.h"
26#include "domain.h"
27#include "interphi.h"
28
29struct wait_state
30{
31    void *usr_state;
32    struct xnode *node;
33    octopus_trigger_id_t tid;
34};
35
36static void domain_wait_trigger_handler(octopus_mode_t mode,
37                                        const char* record,
38                                        void* state)
39{
40    errval_t err;
41
42    struct wait_state *ws = state;
43
44    oct_remove_trigger(ws->tid);
45
46    xphi_dom_id_t domid = 0;
47    err = oct_read(record, "_ { domid: %d }", &domid);
48    if (err_is_fail(err) || domid == 0) {
49        err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
50    }
51
52    interphi_domain_wait_reply(ws->node, err, ws->usr_state, domid);
53
54    free(state);
55}
56
57/**
58 * \brief Non-blocking name service lookup
59 *
60 * \param iface     Name of the domain
61 * \param retdomid  returns the Xeon Phi Domain ID
62 */
63errval_t domain_lookup(const char *iface,
64                       xphi_dom_id_t *retdomid)
65{
66    errval_t err;
67
68    struct octopus_binding *r = get_octopus_binding();
69    if (r == NULL) {
70        return LIB_ERR_NAMESERVICE_NOT_BOUND;
71    }
72
73    struct octopus_get_response__rx_args reply;
74    err = r->rpc_tx_vtbl.get(r, iface, NOP_TRIGGER, reply.output, &reply.tid,
75                      &reply.error_code);
76    if (err_is_fail(err)) {
77        goto out;
78    }
79    err = reply.error_code;
80    if (err_is_fail(err)) {
81        if (err_no(err) == OCT_ERR_NO_RECORD) {
82            err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
83        }
84        goto out;
85    }
86
87    xphi_dom_id_t domid = 0;
88    err = oct_read(reply.output, "_ { domid: %d }", &domid);
89    if (err_is_fail(err) || domid == 0) {
90        err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
91        goto out;
92    }
93
94    if (retdomid != NULL) {
95        *retdomid = domid;
96    }
97
98    out:
99    return err;
100}
101
102/**
103 * \brief looks up the name and registers a callback
104 *
105 * \param iface     Name of the domain
106 * \param retdomid  returns the Xeon Phi Domain ID
107 */
108errval_t domain_wait(const char *iface,
109                     struct xnode *node,
110                     void *state,
111                     xphi_dom_id_t *retdom)
112{
113    errval_t err;
114
115    struct octopus_thc_client_binding_t* c = oct_get_thc_client();
116    if (c == NULL) {
117        return LIB_ERR_NAMESERVICE_NOT_BOUND;
118    }
119
120    struct wait_state *ws = malloc(sizeof(*ws));
121    if (ws == NULL) {
122        return LIB_ERR_MALLOC_FAIL;
123    }
124
125    ws->usr_state = state;
126    ws->node = node;
127
128    octopus_mode_t m = OCT_ON_SET;
129    octopus_trigger_t iface_set_trigger = oct_mktrigger(
130                    OCT_ERR_NO_RECORD, octopus_BINDING_EVENT, m,
131                    domain_wait_trigger_handler, ws);
132
133    struct octopus_get_response__rx_args reply;
134
135    assert(!"FIXME");
136    err = c->call_seq.get(c, iface, iface_set_trigger, NULL, &ws->tid,
137                      &reply.error_code);
138
139    if (err_is_fail(err)) {
140        return err;
141    }
142
143    if (err_is_fail(reply.error_code)) {
144        return reply.error_code;
145    }
146
147    free(ws);
148
149    xphi_dom_id_t domid = 0;
150    err = oct_read(reply.output, "_ { domid: %d }", &domid);
151    if (err_is_fail(err) || domid == 0) {
152        err = err_push(err, XEON_PHI_ERR_CLIENT_DOMAIN_VOID);
153        return err;
154    }
155
156    if (retdom) {
157        *retdom = domid;
158    }
159
160    return err;
161}
162
163/**
164 * \brief Register with name service
165 *
166 * \param iface     Name of the domain
167 * \param retdomid  returns the Xeon Phi Domain ID
168 */
169errval_t domain_register(const char *iface,
170                         xphi_dom_id_t domid)
171{
172    errval_t err = SYS_ERR_OK;
173
174    struct octopus_binding *r = get_octopus_binding();
175    if (r == NULL) {
176        return LIB_ERR_NAMESERVICE_NOT_BOUND;
177    }
178
179    // Format record
180    static const char* format = "%s { domid: %"PRIu64" }";
181    size_t len = snprintf(NULL, 0, format, iface, domid);
182    char* record = malloc(len + 1);
183    if (record == NULL) {
184        return LIB_ERR_MALLOC_FAIL;
185    }
186    snprintf(record, len + 1, format, iface, domid);
187
188    octopus_trigger_id_t tid;
189    errval_t error_code;
190    err = r->rpc_tx_vtbl.set(r, record, 0, NOP_TRIGGER, 0, NULL, &tid, &error_code);
191    if (err_is_fail(err)) {
192        goto out;
193    }
194    err = error_code;
195
196    out: free(record);
197
198    return err;
199}
200