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