};
errors dma DMA_ERR_ {
- failure PCI_ADDRESS "The PCI address of the device is not as expected",
+ failure PCI_ADDRESS "The PCI address of the device is not as expected",
failure DEVICE_UNSUPPORTED "Device ID not supported / wrong configuration",
failure DEVICE_IDLE "The device is idle, no transfers finished",
failure ARG_INVALID "Supplied argument was not valid",
failure MEM_OVERLAP "The memory regions overlap",
failure MEM_NOT_REGISTERED "The memory region was not registered",
failure MEM_OUT_OF_RANGE "Memory region is out of supported range",
- failure SVC_REJECT "Service request was rejected",
+ failure SVC_REJECT "Service request was rejected",
failure SVC_RESOURCES "No resources to handle the service",
+ failure SVC_VOID "There is no service that could serve the request",
};
sbin/xeon_phi_test \
sbin/virtio_blk_host \
sbin/virtio_blk \
- sbin/ioat_dma
+ sbin/ioat_dma \
+ sbin/dma_test \
+ sbin/dma_mgr
# sbin/block_server \
# sbin/block_server_client \
# sbin/bs_user \
"bulkbench",
"diskd",
"dma",
+ "dma_mgr",
"e10k",
"ehci",
"net_queue_manager",
-/** \file
- * \brief Xeon Phi Service Interface
- */
-
/*
* Copyright (c) 2012, ETH Zurich.
* All rights reserved.
--- /dev/null
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+interface dma_mgr "DMA Manager Interface" {
+
+ /**
+ * \brief registers a driver with the DMA device manager
+ *
+ * \param IN mem_low low end of the supported memory range
+ * \param IN mem_high high end of the supported memory range
+ * \param IN numa_node numa node the domain is running on
+ * \param IN type the driver type
+ * \param IN svc_iref iref of the exported service
+ * \param OUT msgerr the result of the operation
+ */
+ rpc register_driver(in uint64 mem_low,
+ in uint64 mem_high,
+ in uint8 numa_node,
+ in uint8 type,
+ in iref svc_iref,
+ out errval msgerr);
+
+ /**
+ * \brief queries the DMA device manager if there is a service with the
+ * needed memory range
+ *
+ * \param IN base low end of the supported memory range
+ * \param IN size size of the memory region
+ * \param IN numa_node numa node the domain is running on
+ * \param OUT msgerr the result of the operation
+ * \param OUT driver_info information about the driver
+ */
+ rpc lookup_driver(in uint64 base,
+ in uint64 size,
+ in uint8 numa,
+ out errval msgerr,
+ out uint64 mem_low,
+ out uint64 mem_high,
+ out uint8 numa_node,
+ out uint8 type,
+ out iref svc_iref);
+};
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef LIB_DMA_MGR_CLIENT_H
+#define LIB_DMA_MGR_CLIENT_H
+
+#include <dma/dma.h>
+
+/// name of the DMA manager service
+#define DMA_MGR_SVC_NAME "dma_mgr_svc"
+
+struct dma_mgr_driver_info
+{
+ lpaddr_t mem_low;
+ lpaddr_t mem_high;
+ iref_t iref;
+ dma_dev_type_t type;
+ uint8_t numa_node;
+};
+
+/**
+ * \brief initializes the connection to the DMA manager service in an eager way
+ *
+ * \returns SYS_ERR_OK on success
+ * errval on error
+ */
+errval_t dma_manager_client_init(void);
+
+/**
+ * \brief registers a DMA driver with the DMA driver manager
+ *
+ * \param mem_low lower end of the supported memory range
+ * \param mem_high upper end of the supported memory range
+ * \param type DMA device type
+ * \param iref the iref of the exported DMA service
+ *
+ * \returns SYS_ERR_OK on success
+ * DMA_ERR_* on failure
+ */
+errval_t dma_manager_register_driver(lpaddr_t mem_low,
+ lpaddr_t mem_high,
+ uint8_t type,
+ iref_t iref);
+
+/**
+ * \brief queries the DMA manager for a suitable DMA driver for a address, size
+ * pair
+ *
+ * \param addr address of the transfer
+ * \param size size of the desired transfer
+ * \param info returns the driver info
+ *
+ * \returns SYS_ERR_OK on success
+ * DMA_ERR_* on failure
+ */
+errval_t dma_manager_lookup_driver(lpaddr_t addr,
+ lpaddr_t size,
+ struct dma_mgr_driver_info *info);
+
+#endif /* LIB_DMA_CLIENT_H */
--- /dev/null
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <string.h>
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/nameservice_client.h>
+
+#include <dma_internal.h>
+#include <dma/dma_manager_client.h>
+#include <debug.h>
+
+#include <if/dma_mgr_defs.h>
+#include <if/dma_mgr_rpcclient_defs.h>
+
+/// DMA manager RPC client
+static struct dma_mgr_rpc_client dma_mgr_client;
+
+/// connected flag
+uint8_t dma_mgr_connected = 0x0;
+
+/// state for binding
+struct dma_mgr_bind_st
+{
+ uint8_t bound;
+ errval_t err;
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Service Binding
+ * ---------------------------------------------------------------------------
+ */
+
+static void bind_cb(void *st,
+ errval_t err,
+ struct dma_mgr_binding *b)
+{
+ assert(st);
+ struct dma_mgr_bind_st *bindst = st;
+
+ bindst->err = err;
+
+ if (err_is_fail(err)) {
+ DMAMGR_DEBUG("connect: connection to {%s} failed.\n", DMA_MGR_SVC_NAME);
+ bindst->bound = 0x1;
+ return;
+ }
+
+ DMAMGR_DEBUG("connect: connection to {%s} established.\n", DMA_MGR_SVC_NAME);
+
+ bindst->err = dma_mgr_rpc_client_init(&dma_mgr_client, b);
+
+ if (err_is_fail(bindst->err)) {
+ DMAMGR_DEBUG("connect: RPC client init failed.\n");
+ }
+
+ bindst->bound = 0x1;
+}
+
+static errval_t dma_manager_connect(void)
+{
+ errval_t err;
+ iref_t iref;
+
+ DMAMGR_DEBUG("connect: looking up service name {%s}\n", DMA_MGR_SVC_NAME);
+ err = nameservice_blocking_lookup(DMA_MGR_SVC_NAME, &iref);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ struct dma_mgr_bind_st st = {
+ .bound = 0x0
+ };
+
+ DMAMGR_DEBUG("connect: binding to iref [%"PRIxIREF"]\n", iref);
+ struct waitset *ws = get_default_waitset();
+ err = dma_mgr_bind(iref, bind_cb, &st, ws, IDC_BIND_FLAGS_DEFAULT);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ while (st.bound == 0x0) {
+ messages_wait_and_handle_next();
+ }
+
+ if (err_is_ok(st.err)) {
+ dma_mgr_connected = 0x1;
+ }
+
+ return st.err;
+}
+
+/*
+ * ============================================================================
+ * Public Interface
+ * ============================================================================
+ */
+
+/**
+ * \brief initializes the connection to the DMA manager service in an eager way
+ *
+ * \returns SYS_ERR_OK on success
+ * errval on error
+ */
+errval_t dma_manager_client_init(void)
+{
+ errval_t err;
+
+ if (dma_mgr_connected == 0) {
+ err = dma_manager_connect();
+ if (err_is_fail(err)) {
+ return err;
+ }
+ }
+ return SYS_ERR_OK;
+}
+
+/**
+ * \brief registers a DMA driver with the DMA driver manager
+ *
+ * \param mem_low lower end of the supported memory range
+ * \param mem_high upper end of the supported memory range
+ * \param type DMA device type
+ * \param iref the iref of the exported DMA service
+ *
+ * \returns SYS_ERR_OK on success
+ * DMA_ERR_* on failure
+ */
+errval_t dma_manager_register_driver(lpaddr_t mem_low,
+ lpaddr_t mem_high,
+ uint8_t type,
+ iref_t iref)
+{
+ errval_t err;
+ errval_t msgerr;
+
+ if (dma_mgr_connected == 0) {
+ err = dma_manager_connect();
+ if (err_is_fail(err)) {
+ return err;
+ }
+ }
+
+ DMAMGR_DEBUG("register driver: [%016lx, %016lx, %"PRIxIREF"]\n", mem_low,
+ mem_high, iref);
+
+ //XXX need to figure this out otherwise
+ uint8_t numa_node = (disp_get_core_id() >= 20);
+
+ err = dma_mgr_client.vtbl.register_driver(&dma_mgr_client, mem_low, mem_high,
+ numa_node, type, iref, &msgerr);
+ if (err_is_fail(err)) {
+ DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err));
+ return err;
+ }
+
+ return msgerr;
+}
+
+/**
+ * \brief queries the DMA manager for a suitable DMA driver for a address, size
+ * pair
+ *
+ * \param addr address of the transfer
+ * \param size size of the desired transfer
+ * \param info returns the driver info
+ *
+ * \returns SYS_ERR_OK on success
+ * DMA_ERR_* on failure
+ */
+errval_t dma_manager_lookup_driver(lpaddr_t addr,
+ lpaddr_t size,
+ struct dma_mgr_driver_info *info)
+{
+ errval_t err, msgerr;
+
+ if (dma_mgr_connected == 0) {
+ err = dma_manager_connect();
+ if (err_is_fail(err)) {
+ return err;
+ }
+ }
+
+ DMAMGR_DEBUG("lookup driver: [%016lx, %016lx]\n", addr, size);
+
+ uint8_t numa_node = (disp_get_core_id() >= 20);
+
+ err = dma_mgr_client.vtbl.lookup_driver(&dma_mgr_client, addr, size, numa_node,
+ &msgerr, &info->mem_low, &info->mem_high,
+ &info->numa_node, (uint8_t*)&info->type,
+ &info->iref);
+ if (err_is_fail(err)) {
+ DMAMGR_DEBUG("register driver: RPC failed %s\n", err_getstring(err));
+ return err;
+ }
+
+ return msgerr;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef DMA_CLIENT_INTERNAL_H
+#define DMA_CLIENT_INTERNAL_H
+
+#include <dma/dma_client.h>
+
+
+
+#endif /* DMA_CLIENT_INTERNAL_H */
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2014, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/device_managers/dma_mgr
+--
+--------------------------------------------------------------------------
+
+[ build application {
+ target = "dma_mgr",
+ cFiles = [
+ "dma_mgr.c",
+ "dma_mgr_svc.c",
+ "dma_mgr_drivers.c"
+ ],
+ flounderBindings = [ "dma_mgr" ],
+ architectures = [ "x86_64"]
+ }
+]
--- /dev/null
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef DMA_MGR_DEBUG_H_
+#define DMA_MGR_DEBUG_H_
+
+
+/*
+ * Debug output switches
+ */
+#define DEBUG_ENABLED 1
+#define DEBUG_SVC_ENABLED 1
+#define DEBUG_DS_ENABLED 1
+
+
+/*
+ * --------------------------------------------------------------------------
+ * Debug output generation
+ */
+#if DEBUG_ENABLED
+#define DEBUGPRINT(x...) debug_printf(x)
+#else
+#define DEBUGPRINT(x... )
+#endif
+#if DEBUG_SVC_ENABLED
+#define SVC_DEBUG(x...) DEBUGPRINT("svc | " x)
+#else
+#define SVC_DEBUG(x...)
+#endif
+#if DEBUG_DS_ENABLED
+#define DS_DEBUG(x...) DEBUGPRINT("ds | " x)
+#else
+#define DS_DEBUG(x...)
+#endif
+
+
+#define ERRPRINT(x...) debug_printf(x)
+#define SVC_ERR(x...) ERRPRINT("svc | ERROR: " x)
+#define DS_ERR(x...) ERRPRINT("ds | ERROR: " x)
+
+#endif /* DMA_MGR_DEBUG_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+/*
+ *
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+
+#include "dma_mgr.h"
+#include "debug.h"
+
+#define BUFFER_SIZE (1<<22)
+
+
+int main(int argc,
+ char *argv[])
+{
+ errval_t err;
+
+ debug_printf("DMA Manager started\n");
+
+ err = driver_store_init();
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "could not initialize the driver store\n");
+ }
+
+ err = dma_mgr_svc_start();
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "could not start the service\n");
+ }
+
+ while(1) {
+ messages_wait_and_handle_next();
+ }
+
+ debug_printf("DMA Manager terminated\n");
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef DMA_MGR_H_
+#define DMA_MGR_H_
+
+struct dma_mgr_driver_info;
+
+errval_t driver_store_init(void);
+
+errval_t driver_store_insert(lpaddr_t mem_low,
+ lpaddr_t mem_high,
+ uint8_t numa_node,
+ uint8_t type,
+ iref_t iref);
+
+
+errval_t driver_store_lookup(lpaddr_t mem_low,
+ size_t size,
+ uint8_t numa_node,
+ struct dma_mgr_driver_info **info);
+
+/**
+ * \brief initializes the DMA manager service service
+ *
+ * \param svc_name The name of the service for nameservice registration
+ * \param cb Callback function pointers
+ *
+ * \returns SYS_ERR_OK on success
+ * errval on error
+ */
+errval_t dma_mgr_svc_start(void);
+
+#endif /* DMA_MGR_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+/*
+ *
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+
+#include <dma/dma_manager_client.h>
+
+#include "dma_mgr.h"
+#include "debug.h"
+
+
+
+struct dma_service
+{
+ struct dma_mgr_driver_info info;
+ struct dma_service *prev;
+ struct dma_service *next;
+};
+
+static struct dma_service *dma_services = NULL;
+
+static void service_insert(struct dma_service *svc)
+{
+ if (dma_services == NULL) {
+ svc->next = NULL;
+ svc->prev = NULL;
+ dma_services = svc;
+ return;
+ }
+
+ struct dma_service *current = dma_services;
+ while(current) {
+ if (current->info.mem_low > svc->info.mem_low) {
+ if (current->prev) {
+ svc->prev = current->prev;
+ current->prev->next = svc;
+ } else {
+ svc->prev = NULL;
+ dma_services = svc;
+ }
+ svc->next = current;
+ current->prev = svc;
+ break;
+ }
+ current = current->next;
+ }
+}
+
+static inline uint8_t get_diff(uint8_t a, uint8_t b)
+{
+ if (a > b) {
+ return a-b;
+ } else {
+ return b-a;
+ }
+}
+
+static struct dma_service *service_lookup(lpaddr_t mem_low,
+ size_t size,
+ uint8_t numa_node)
+{
+ struct dma_service *current = dma_services;
+ struct dma_service *best = NULL;
+ while(current) {
+ if (current->info.mem_low <= mem_low) {
+ if(current->info.mem_high >= (mem_low + size)) {
+ /* we have a match */
+ if (best == NULL) {
+ best = current;
+ } else {
+ uint8_t best_numa_diff = get_diff(numa_node, best->info.numa_node);
+ uint8_t curr_numa_diff = get_diff(numa_node, current->info.numa_node);
+ if (curr_numa_diff < best_numa_diff) {
+ best = current;
+ }
+ }
+ }
+ }
+ current = current->next;
+ }
+ return best;
+}
+
+/*
+ * ============================================================================
+ *
+ * ============================================================================
+ */
+
+errval_t driver_store_init(void)
+{
+
+ return SYS_ERR_OK;
+}
+
+errval_t driver_store_insert(lpaddr_t mem_low,
+ lpaddr_t mem_high,
+ uint8_t numa_node,
+ uint8_t type,
+ iref_t iref)
+{
+ struct dma_service *driver = calloc(1, sizeof(*driver));
+ if (driver == NULL) {
+ return LIB_ERR_MALLOC_FAIL;
+ }
+ driver->info.mem_low = mem_low;
+ driver->info.mem_high = mem_high;
+ driver->info.numa_node = numa_node;
+ driver->info.type = type;
+ driver->info.iref = iref;
+
+ service_insert(driver);
+
+ return SYS_ERR_OK;
+}
+
+
+errval_t driver_store_lookup(lpaddr_t mem_low,
+ size_t size,
+ uint8_t numa_node,
+ struct dma_mgr_driver_info **info)
+{
+ struct dma_service *svc = service_lookup(mem_low, size, numa_node);
+ if (svc == NULL) {
+ return DMA_ERR_SVC_VOID;
+ }
+ *info = &svc->info;
+
+ return SYS_ERR_OK;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+/*
+ *
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/nameservice_client.h>
+
+#include <dma/dma_manager_client.h>
+
+#include <if/dma_mgr_defs.h>
+
+#include "dma_mgr.h"
+#include "debug.h"
+
+/**
+ * enumration of all possible states of the service exportation process
+ */
+enum svc_state
+{
+ SVC_STATE_EXPORTING,
+ SVC_STATE_EXPORT_OK,
+ SVC_STATE_EXPORT_FAIL,
+ SVC_STATE_NS_REGISTERING,
+ SVC_STATE_NS_REGISTER_OK,
+ SVC_STATE_NS_REGISTER_FAIL,
+ SVC_STATE_RUNNING
+};
+
+/// represents the current state of the exporting process
+static enum svc_state dma_svc_state = SVC_STATE_EXPORTING;
+
+/// our own iref of the exported service
+static iref_t svc_iref;
+
+/*
+ * ----------------------------------------------------------------------------
+ * Reply State Cache
+ * ----------------------------------------------------------------------------
+ */
+struct svc_reply_st
+{
+ void (*op)(void *arg); ///<
+ struct svc_reply_st *next; ///<
+ struct dma_mgr_binding *b; ///<
+ errval_t err; ///<
+
+ /* union of arguments */
+ union
+ {
+ struct dma_mgr_driver_info *lookup;
+ } args;
+};
+
+static struct svc_reply_st *dma_reply_st_cache = NULL;
+
+static struct svc_reply_st *reply_st_alloc(void)
+{
+ if (dma_reply_st_cache) {
+ struct svc_reply_st *st = dma_reply_st_cache;
+ dma_reply_st_cache = dma_reply_st_cache->next;
+ return st;
+ }
+ return calloc(1, sizeof(struct svc_reply_st));
+}
+
+static inline void reply_st_free(struct svc_reply_st *st)
+{
+ st->next = dma_reply_st_cache;
+ dma_reply_st_cache = st;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Reply send queue
+ * ----------------------------------------------------------------------------
+ */
+
+static struct
+{
+ struct svc_reply_st *head;
+ struct svc_reply_st *tail;
+} svc_reply_txq;
+
+static void send_reply_cont(void *a)
+{
+ struct svc_reply_st *st = (struct svc_reply_st *) a;
+
+ /* we are likely to be able to send the reply so send it */
+ assert(svc_reply_txq.head == st);
+
+ svc_reply_txq.head->op(st);
+}
+
+static void send_reply_done(void *a)
+{
+ struct svc_reply_st *st = (struct svc_reply_st *) a;
+
+ /* callback when the message has been sent */
+ if (svc_reply_txq.head == NULL) {
+ reply_st_free((struct svc_reply_st *) a);
+ return;
+ }
+ assert(svc_reply_txq.head == st);
+
+ svc_reply_txq.head = svc_reply_txq.head->next;
+ if (svc_reply_txq.head == NULL) {
+ svc_reply_txq.tail = NULL;
+ } else {
+ struct svc_reply_st *next = svc_reply_txq.head;
+ /* it should not matter if we already registered */
+ svc_reply_txq.head->b->register_send(svc_reply_txq.head->b,
+ get_default_waitset(),
+ MKCONT(send_reply_cont, next));
+ }
+ reply_st_free(st);
+}
+
+static errval_t send_reply_enqueue(struct svc_reply_st *st)
+{
+ st->next = NULL;
+
+ if (svc_reply_txq.tail == NULL) {
+ svc_reply_txq.head = st;
+ } else {
+ svc_reply_txq.tail->next = st;
+ }
+ svc_reply_txq.tail = st;
+
+ /* register if queue was empty i.e. head == tail */
+ if (svc_reply_txq.tail == svc_reply_txq.head) {
+ return st->b->register_send(st->b, get_default_waitset(),
+ MKCONT(send_reply_cont, NULL));
+ }
+
+ return SYS_ERR_OK;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Driver Registration
+ * ----------------------------------------------------------------------------
+ */
+
+static void svc_register_response_tx(void *a)
+{
+ errval_t err;
+
+ struct svc_reply_st *st = a;
+
+ err = dma_mgr_register_driver_response__tx(st->b, MKCONT(send_reply_done, a),
+ st->err);
+ switch (err_no(err)) {
+ case SYS_ERR_OK:
+ break;
+ case FLOUNDER_ERR_TX_BUSY:
+ err = send_reply_enqueue(st);
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "could not send reply");
+ }
+ break;
+ default:
+ USER_PANIC_ERR(err, "could not send reply");
+ break;
+ }
+}
+
+static void svc_register_call_rx(struct dma_mgr_binding *_binding,
+ uint64_t mem_low,
+ uint64_t mem_high,
+ uint8_t numa_node,
+ uint8_t type,
+ iref_t iref)
+{
+ SVC_DEBUG("register call: [%016lx, %016lx]\n", mem_low, mem_high);
+
+ struct svc_reply_st *state = reply_st_alloc();
+ assert(state);
+
+ state->b = _binding;
+ state->op = svc_register_response_tx;
+
+ state->err = driver_store_insert(mem_low, mem_high, numa_node, type, iref);
+
+ svc_register_response_tx(state);
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Query for DMA driver service
+ * ----------------------------------------------------------------------------
+ */
+
+static void svc_lookup_response_tx(void *a)
+{
+ errval_t err;
+
+ struct svc_reply_st *st = a;
+
+ struct dma_mgr_driver_info *di = st->args.lookup;
+
+ if (err_is_fail(st->err)) {
+ err = dma_mgr_lookup_driver_response__tx(st->b, MKCONT(send_reply_done, a),
+ st->err, 0, 0, 0, 0, 0);
+ } else {
+ err = dma_mgr_lookup_driver_response__tx(st->b, MKCONT(send_reply_done, a),
+ st->err, di->mem_low, di->mem_high,
+ di->numa_node, di->type, di->iref);
+ }
+
+ switch (err_no(err)) {
+ case SYS_ERR_OK:
+ break;
+ case FLOUNDER_ERR_TX_BUSY:
+ err = send_reply_enqueue(st);
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "could not send reply");
+ }
+ break;
+ default:
+ USER_PANIC_ERR(err, "could not send reply");
+ break;
+ }
+}
+
+static void svc_lookup_call_rx(struct dma_mgr_binding *_binding,
+ uint64_t addr,
+ uint64_t size,
+ uint8_t numa_node)
+{
+ SVC_DEBUG("lookup call: [%016lx, %016lx]\n", addr, size);
+
+ struct svc_reply_st *st = reply_st_alloc();
+ assert(st);
+
+ st->b = _binding;
+ st->op = svc_lookup_response_tx;
+
+ st->err = driver_store_lookup(addr, size, numa_node, &st->args.lookup);
+
+ svc_lookup_response_tx(st);
+}
+
+struct dma_mgr_rx_vtbl svc_rx_vtbl = {
+ .register_driver_call = svc_register_call_rx,
+ .lookup_driver_call = svc_lookup_call_rx,
+};
+
+/*
+ * ----------------------------------------------------------------------------
+ * Service export and connect handling
+ * ----------------------------------------------------------------------------
+ */
+
+static errval_t svc_connect_cb(void *st,
+ struct dma_mgr_binding *binding)
+{
+ SVC_DEBUG("New connection to the DMA service\n");
+
+ binding->rx_vtbl = svc_rx_vtbl;
+
+ return SYS_ERR_OK;
+}
+
+static void svc_export_cb(void *st,
+ errval_t err,
+ iref_t iref)
+{
+ *((errval_t *) st) = err;
+
+ if (err_is_fail(err)) {
+ dma_svc_state = SVC_STATE_EXPORT_FAIL;
+ return;
+ }
+
+ svc_iref = iref;
+ dma_svc_state = SVC_STATE_EXPORT_OK;
+}
+
+/*
+ * ============================================================================
+ * Public Interface
+ * ============================================================================
+ */
+
+/**
+ * \brief initializes the DMA manager service service
+ *
+ * \param svc_name The name of the service for nameservice registration
+ * \param cb Callback function pointers
+ *
+ * \returns SYS_ERR_OK on success
+ * errval on error
+ */
+errval_t dma_mgr_svc_start(void)
+{
+ errval_t err, export_err;
+
+ SVC_DEBUG("Initializing DMA service...\n");
+
+ svc_reply_txq.head = NULL;
+ svc_reply_txq.tail = NULL;
+
+ err = dma_mgr_export(&export_err, svc_export_cb, svc_connect_cb,
+ get_default_waitset(),
+ IDC_EXPORT_FLAGS_DEFAULT);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ while (dma_svc_state == SVC_STATE_EXPORTING) {
+ messages_wait_and_handle_next();
+ }
+
+ if (dma_svc_state == SVC_STATE_EXPORT_FAIL) {
+ return export_err;
+ }
+
+ dma_svc_state = SVC_STATE_NS_REGISTERING;
+
+ SVC_DEBUG("Registering service [%s] with iref [0x%"PRIxIREF"]\n",
+ DMA_MGR_SVC_NAME, svc_iref);
+
+ err = nameservice_register(DMA_MGR_SVC_NAME, svc_iref);
+ if (err_is_fail(err)) {
+ dma_svc_state = SVC_STATE_NS_REGISTER_FAIL;
+ return err;
+ }
+
+ dma_svc_state = SVC_STATE_RUNNING;
+
+ SVC_DEBUG("DMA service up and running.\n");
+
+ return SYS_ERR_OK;
+}
+