LIBDMA: added implementation for handling flounder messages + attempt for tx queue.
authorReto Achermann <acreto@student.ethz.ch>
Sun, 20 Jul 2014 20:16:43 +0000 (22:16 +0200)
committerStefan Kaestle <stefan.kaestle@inf.ethz.ch>
Wed, 20 Aug 2014 21:39:54 +0000 (23:39 +0200)
errors/errno.fugu
include/dma/dma_service.h [new file with mode: 0644]
lib/dma/dma_service.c

index a0d2fef..641558f 100755 (executable)
@@ -1076,5 +1076,7 @@ errors dma DMA_ERR_ {
     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_RESOURCES         "No resources to handle the service",
        
 };
diff --git a/include/dma/dma_service.h b/include/dma/dma_service.h
new file mode 100644 (file)
index 0000000..8cabc4c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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_SERVICE_H
+#define LIB_DMA_SERVICE_H
+
+#include <if/dma_defs.h>
+
+/**
+ * DMA service callbacks called when the message event occurs
+ * if a callback is not set, this will trigger a not supported
+ * error in the client.
+ */
+struct dma_service_cb
+{
+    /** informs about the new connection on the service */
+    errval_t (*connect)(void **user_st);
+
+    /** registers a memory region to be used */
+    errval_t (*addregion)(void *user_st,
+                          struct capref cap);
+
+    /** deregisters a memory region*/
+    errval_t (*removeregion)(void *user_st,
+                             struct capref cap);
+
+    /** execute a memcpy request */
+    errval_t (*memcpy)(void *user_st,
+                       lpaddr_t dst,
+                       lpaddr_t src,
+                       size_t bytes,
+                       dma_req_id_t *id);
+};
+
+/**
+ * \brief initializes the DMA 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_service_init(const char *svc_name,
+                          struct dma_service_cb *cb);
+
+/**
+ * \brief sends a done notification about the transfer that has completed
+ *
+ * \param binding   DMA binding
+ * \param err       Outcome of the transfer
+ * \param id        The id of the completed transfer
+ *
+ * \returns SYS_ERR_OK on success
+ *          errval on error
+ */
+errval_t dma_service_send_done(struct dma_binding *binding,
+                               errval_t err,
+                               dma_req_id_t id);
+
+
+#endif  /* LIB_DMA_CLIENT_H */
index 6876f69..d48a71e 100644 (file)
 #include <debug.h>
 
 /**
+ * DMA service state that will be assigned to the
+ */
+struct dma_svc_st
+{
+    struct dma_mem_mgr *mem_mgr;
+    void *usr_st;
+};
+
+/**
  * enumration of all possible states of the service exportation process
  */
 enum dma_svc_state
@@ -140,34 +149,136 @@ static void xdma_reply_queue_next(void *a)
 
 /*
  * ----------------------------------------------------------------------------
- * Memory:  registration
+ * Reply State Cache
  * ----------------------------------------------------------------------------
  */
+struct dma_svc_reply_st
+{
+    void (*op)(void *arg);          ///<
+    struct dma_svc_reply_st *next;  ///<
+    struct dma_binding *b;          ///<
+    errval_t err;                   ///<
+
+    /* union of arguments */
+    union
+    {
+        /* request handling */
+        struct
+        {
+            dma_id_t id;            ///<
+        } request;
+    } args;
+};
 
+static struct dma_svc_reply_st *dma_reply_st_cache = NULL;
 
-struct dma_reg_resp_st
+static struct dma_svc_reply_st *reply_st_alloc(void)
 {
-    struct dma_binding *b;
-    errval_t err;
-};
+    if (dma_reply_st_cache) {
+        struct dma_svc_reply_st *st = dma_reply_st_cache;
+        dma_reply_st_cache = dma_reply_st_cache->next;
+        return st;
+    }
+    return calloc(1, sizeof(struct dma_svc_reply_st));
+}
+
+static inline void reply_st_free(struct dma_svc_reply_st *st)
+{
+    st->next = dma_reply_st_cache;
+    dma_reply_st_cache = st;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Reply send queue
+ * ----------------------------------------------------------------------------
+ */
+
+static struct
+{
+    struct dma_svc_reply_st *head;
+    struct dma_svc_reply_st *tail;
+} dma_reply_txq;
+
+static void send_reply_cont(void *a)
+{
+    struct dma_svc_reply_st *st = (struct dma_svc_reply_st *) a;
+
+    /* we are likely to be able to send the reply so send it */
+    assert(dma_reply_txq.head == st);
+
+    dma_reply_txq.head->op(st);
+}
+
+static void send_reply_done(void *a)
+{
+    struct dma_svc_reply_st *st = (struct dma_svc_reply_st *) a;
+
+    /* callback when the message has been sent */
+    if (dma_reply_txq.head == NULL) {
+        reply_st_free((struct dma_svc_reply_st *) a);
+        return;
+    }
+    assert(dma_reply_txq.head == st);
+
+    dma_reply_txq.head = dma_reply_txq.head->next;
+    if (dma_reply_txq.head == NULL) {
+        dma_reply_txq.tail = NULL;
+    } else {
+        struct dma_svc_reply_st *next = dma_reply_txq.head;
+        /* it should not matter if we already registered */
+        dma_reply_txq.head->b->register_send(dma_reply_txq.head->b,
+                                             get_default_waitset(),
+                                             MKCONT(send_reply_cont, next));
+    }
+    reply_st_free(st);
+}
+
+static errval_t send_reply_enqueue(struct dma_svc_reply_st *st)
+{
+    st->next = NULL;
+
+    if (dma_reply_txq.tail == NULL) {
+        dma_reply_txq.head = st;
+    } else {
+        dma_reply_txq.tail->next = st;
+    }
+    dma_reply_txq.tail = st;
+
+    /* register if queue was empty i.e. head == tail */
+    if (dma_reply_txq.tail == dma_reply_txq.head) {
+        return st->b->register_send(st->b, get_default_waitset(),
+                                    MKCONT(send_reply_cont, NULL));
+    }
+
+    return SYS_ERR_OK;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Memory:  registration
+ * ----------------------------------------------------------------------------
+ */
 
 static void dma_register_response_tx(void *a)
 {
     errval_t err;
 
-    struct dma_reg_resp_st *st = a;
-
-    struct event_closure txcont = MKCONT(free, a);
+    struct dma_svc_reply_st *st = a;
 
-    err = dma_register_response__tx(st->b, txcont, st->err);
-    if (err_is_fail(err)) {
-        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
-            txcont = MKCONT(dma_register_response_tx, a);
-            err = st->b->register_send(st->b, get_default_waitset(), txcont);
+    err = dma_register_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;
     }
 }
 
@@ -176,12 +287,17 @@ static void dma_register_call_rx(struct dma_binding *_binding,
 {
     errval_t err;
 
-    err = event_handlers->memadd(_binding, memory);
+    struct dma_svc_st *st = _binding->st;
 
-    struct dma_reg_resp_st *st = malloc(sizeof(struct dma_reg_resp_st));
-    assert(st);
-    st->b = _binding;
-    st->err = err;
+    err = event_handlers->addregion(st->usr_st, memory);
+
+    struct dma_svc_reply_st *state = reply_st_alloc();
+    if (state == NULL) {
+        /* todo: error handling */
+    }
+
+    state->b = _binding;
+    state->err = err;
 
     dma_register_response_tx(st);
 }
@@ -192,29 +308,25 @@ static void dma_register_call_rx(struct dma_binding *_binding,
  * ----------------------------------------------------------------------------
  */
 
-struct dma_dereg_resp_st
-{
-    struct dma_binding *b;
-    errval_t err;
-};
-
 static void dma_deregister_response_tx(void *a)
 {
     errval_t err;
 
-    struct dma_dereg_resp_st *st = a;
-
-    struct event_closure txcont = MKCONT(free, a);
+    struct dma_svc_reply_st *st = a;
 
-    err = dma_deregister_response__tx(st->b, txcont, st->err);
-    if (err_is_fail(err)) {
-        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
-            txcont = MKCONT(dma_deregister_response_tx, a);
-            err = st->b->register_send(st->b, get_default_waitset(), txcont);
+    err = dma_deregister_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;
     }
 }
 
@@ -223,10 +335,9 @@ static void dma_deregister_call_rx(struct dma_binding *_binding,
 {
     errval_t err;
 
-    err = event_handlers->memremove(_binding, memory);
-
+    err = event_handlers->removeregion(_binding, memory);
 
-    struct dma_dereg_resp_st *st = malloc(sizeof(struct dma_dereg_resp_st));
+    struct dma_svc_reply_st *st = reply_st_alloc();
     assert(st);
     st->b = _binding;
     st->err = err;
@@ -239,64 +350,57 @@ static void dma_deregister_call_rx(struct dma_binding *_binding,
  * Transfer Control: START
  * ----------------------------------------------------------------------------
  */
-struct dma_memcpy_resp_st
-{
-    struct dma_binding *b;
-    dma_id_t id;
-    errval_t err;
-    uint8_t sent;
-};
-
-struct dma_memcpy_resp_st exec_resp_err;
-
-static void dma_memcpy_response_sent(void *a)
-{
-    struct dma_memcpy_resp_st *st = a;
-    st->sent = 0x1;
-}
 
 static void dma_memcpy_response_tx(void *a)
 {
     errval_t err;
 
-    struct dma_memcpy_resp_st *st = a;
-
-    struct event_closure txcont = MKCONT(dma_memcpy_response_sent, a);
+    struct dma_svc_reply_st *st = a;
 
-    err = dma_memcpy_response__tx(st->b, txcont, st->err, st->id);
-    if (err_is_fail(err)) {
-        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
-            txcont = MKCONT(dma_memcpy_response_tx, a);
-            DMASVC_DEBUG("dma_memcpy_response_tx: register sending...\n");
-            err = st->b->register_send(st->b, get_default_waitset(), txcont);
+    err = dma_memcpy_response__tx(st->b, MKCONT(send_reply_done, a), st->err,
+                                  st->args.request.id);
+    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");
             }
-        }
-        return;
+            break;
+        default:
+            USER_PANIC_ERR(err, "could not send reply");
+            break;
     }
 }
 
 static void dma_memcpy_call_rx(struct dma_binding *_binding,
-                             uint64_t src,
-                             uint64_t dst,
-                             uint64_t length)
+                               uint64_t src,
+                               uint64_t dst,
+                               uint64_t length)
 {
-    errval_t err;
 
     DMASVC_DEBUG("memcopy request [0x%016lx]->[0x%016lx] of size 0x%lx\n", src,
-                dst, length);
+                 dst, length);
 
-    dma_req_id_t id;
-    err = event_handlers->memcpy(_binding, dst, src, length, &id);
+    struct dma_svc_reply_st *reply = reply_st_alloc();
+    if (reply == NULL) {
+        USER_PANIC("ran out of reply state resources\n");
+    }
 
-    dma_memcpy_response_tx(_binding);
+    reply->b = _binding;
+    reply->op = dma_memcpy_response_tx;
 
+    if (event_handlers->memcpy) {
+        reply->err = event_handlers->memcpy(_binding, dst, src, length,
+                                            &reply->args.request.id);
+    } else {
+        reply->err = DMA_ERR_SVC_REJECT;
+    }
 
+    dma_memcpy_response_tx(reply);
 }
 
-
-
 struct dma_rx_vtbl dma_rx_vtbl = {
     .register_call = dma_register_call_rx,
     .deregister_call = dma_deregister_call_rx,
@@ -304,48 +408,36 @@ struct dma_rx_vtbl dma_rx_vtbl = {
 };
 
 /*
- * ---------------------------------------------------------------------------
- * Send the done notification
- * ---------------------------------------------------------------------------
+ * ----------------------------------------------------------------------------
+ * Transmission of done notifications
+ * ----------------------------------------------------------------------------
  */
-struct dma_done_st
-{
-    struct dma_binding *b;
-    dma_id_t id;
-    errval_t err;
-};
 
 static void dma_done_tx(void *a)
 {
     errval_t err;
 
-    struct dma_done_st *st = a;
-
-    struct event_closure txcont = MKCONT(free, a);
+    struct dma_svc_reply_st *st = a;
 
-    err = dma_done__tx(st->b, txcont, st->id, st->err);
-    if (err_is_fail(err)) {
-        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
-            txcont = MKCONT(dma_done_tx, a);
-            err = st->b->register_send(st->b, get_default_waitset(), txcont);
+    err = dma_done__tx(st->b, MKCONT(send_reply_done, a), st->args.request.id,
+                       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");
             }
-        }
-        return;
+            break;
+        default:
+            USER_PANIC_ERR(err, "could not send reply");
+            break;
     }
 }
 
 /*
  * ----------------------------------------------------------------------------
- * Transmission of done notifications
- * ----------------------------------------------------------------------------
- */
-
-
-
-/*
- * ----------------------------------------------------------------------------
  * Service export and connect handling
  * ----------------------------------------------------------------------------
  */
@@ -359,16 +451,23 @@ static errval_t svc_connect_cb(void *st,
 
     if (event_handlers->connect == NULL) {
         /* the service is not interested in new connections (anymore) */
-        /* TODO: error number */
-        return -1;
+        return DMA_ERR_SVC_REJECT;
     }
 
-    err = event_handlers->connect(binding);
+    struct dma_svc_st *state = malloc(sizeof(*st));
+    if (state == NULL) {
+        return LIB_ERR_MALLOC_FAIL;
+    }
+
+    err = event_handlers->connect(&state->usr_st);
     if (err_is_fail(err)) {
         /* reject the connection */
-        return err;
+        DMASVC_DEBUG("application rejected the connection: %s\n",
+                     err_getstring(err));
+        return DMA_ERR_SVC_REJECT;
     }
 
+    binding->st = state;
     binding->rx_vtbl = dma_rx_vtbl;
 
     return SYS_ERR_OK;
@@ -378,7 +477,7 @@ static void svc_export_cb(void *st,
                           errval_t err,
                           iref_t iref)
 {
-    *((errval_t *)st) = err;
+    *((errval_t *) st) = err;
 
     if (err_is_fail(err)) {
         dma_svc_state = DMA_SVC_STATE_EXPORT_FAIL;
@@ -411,6 +510,10 @@ errval_t dma_service_init(const char *svc_name,
 
     DMASVC_DEBUG("Initializing DMA service...\n");
 
+    dma_reply_txq.head = NULL;
+    dma_reply_txq.tail = NULL;
+
+
     err = dma_export(&export_err, svc_export_cb, svc_connect_cb,
                      get_default_waitset(),
                      IDC_EXPORT_FLAGS_DEFAULT);
@@ -442,7 +545,6 @@ errval_t dma_service_init(const char *svc_name,
 
     DMASVC_DEBUG("DMA service up and running.\n");
 
-
     return SYS_ERR_OK;
 }
 
@@ -460,13 +562,13 @@ errval_t dma_service_send_done(struct dma_binding *binding,
                                errval_t err,
                                dma_req_id_t id)
 {
-    struct dma_done_st *msgst = malloc(sizeof(struct dma_done_st));
+    struct dma_svc_reply_st *msgst = reply_st_alloc();
     if (msgst == NULL) {
         return LIB_ERR_MALLOC_FAIL;
     }
 
     msgst->b = binding;
-    msgst->id = id;
+    msgst->args.request.id = id;
     msgst->err = err;
 
     dma_done_tx(msgst);