Bump version to 0.3.5next
[archipelago] / xseg / drivers / kernel / xseg_segdev.c
index f0bfb12..a11cee4 100644 (file)
@@ -1,3 +1,37 @@
+/*
+ * Copyright 2012 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ */
+
 /* xseg_segdev.c
  *
  */
 #include <xseg/xseg.h>
 #include <sys/kernel/segdev.h>
 #include <sys/util.h>
-
+#include <drivers/xseg_segdev.h>
+#include <peers/kernel/xsegbd.h>
 MODULE_DESCRIPTION("xseg_segdev");
 MODULE_AUTHOR("XSEG");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("BSD");
 
-/* for now, support only one peer */
-static struct xseg *xsegments[1];
+/* FIXME */
+static struct xseg *xsegments[65536];
 static unsigned int nr_xsegments = 1;
 
 struct segpriv {
@@ -61,20 +96,23 @@ static long segdev_allocate(const char *name, uint64_t size)
                goto out;
        }
 
+       /*
        if (segdev->segment) {
                XSEGLOG("destroying existing segdev segment");
                r = segdev_destroy_segment(segdev);
                if (r)
                        goto out;
        }
+       */
 
        XSEGLOG("creating segdev segment size %llu", size);
        r = segdev_create_segment(segdev, size, 1);
        if (r)
-               goto out;
+               goto out_put;
 
-       segdev_put(segdev);
        r = 0;
+out_put:
+       segdev_put(segdev);
 out:
        return r;
 }
@@ -95,11 +133,12 @@ static long segdev_deallocate(const char *name)
        return r;
 }
 
-static void *segdev_map(const char *name, uint64_t size)
+static void *segdev_map(const char *name, uint64_t size, struct xseg *seg)
 {
        struct xseg *xseg = NULL;
        /* map() holds a reference to the segment */
        struct segdev *dev = segdev_get(0);
+       struct segpriv *priv;
        int r;
        r = IS_ERR(dev) ? PTR_ERR(dev) : 0;
        if (r)
@@ -111,6 +150,13 @@ static void *segdev_map(const char *name, uint64_t size)
        if (size > dev->segsize)
                goto out;
 
+       priv = dev->priv;
+       if (priv->segno >= nr_xsegments)
+               goto out;
+
+//     if (seg)
+//             xsegments[priv->segno] = seg;
+
        xseg = (void *)dev->segment;
 out:
        return xseg;
@@ -119,33 +165,51 @@ out:
 static void segdev_unmap(void *ptr, uint64_t size)
 {
        struct segdev *segdev = segdev_get(0);
+       struct segpriv *priv;
        int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
        if (r)
                return;
 
+       priv = segdev->priv;
+       if (priv->segno >= nr_xsegments)
+               goto out;
+
+//     xsegments[priv->segno] = NULL;
+
+out:
        /* unmap() releases the reference taken by map() */
        segdev_put(segdev);
+
+       segdev_put(segdev);
 }
 
-static void segdev_callback(struct segdev *dev)
+static void segdev_callback(struct segdev *dev, xport portno)
 {
        struct xseg *xseg;
        struct segpriv *priv = dev->priv;
        struct xseg_private *xpriv;
-       uint32_t portno;
-       if (priv->segno > nr_xsegments)
+       struct xseg_port *port;
+       struct segdev_signal_desc *ssd;
+
+       xseg = xsegments[portno];
+       if (!xseg)
+               return;
+       if (priv->segno >= nr_xsegments)
                return;
 
-       if (dev->buffer_index != sizeof(uint32_t)) {
-               WARN_ON(1);
+       xpriv = xseg->priv;
+       port = xseg_get_port(xseg, portno);
+       if (!port)
+               return;
+       ssd = xseg_get_signal_desc(xseg, port);
+       if (!ssd || !ssd->waitcue){
                return;
        }
 
-       portno = *(uint32_t *)dev->buffer;
-       xseg = xsegments[priv->segno];
-       xpriv = xseg->priv;
-       if (xpriv->wakeup)
-               xpriv->wakeup(xseg, portno);
+       if (xpriv->wakeup) {
+               xpriv->wakeup(portno);
+       }
+       return;
 }
 
 static struct xseg_type xseg_segdev = {
@@ -160,52 +224,59 @@ static struct xseg_type xseg_segdev = {
        "segdev"
 };
 
-static int segdev_signal_init(void)
+static int segdev_remote_signal_init(void)
 {
-       struct segdev *segdev = segdev_get(0);
-       struct segpriv *segpriv;
-       int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
-       if (r)
-               goto out;
-
-       r = -EADDRINUSE;
-       if (xsegments[0]) 
-               goto out;
+       return 0;
+}
 
-       r = -ENOMEM;
-       segpriv = kmalloc(sizeof(struct segpriv), GFP_KERNEL);
-       if (!segpriv)
-               goto out;
+static void segdev_remote_signal_quit(void)
+{
+       return;
+}
 
-       segpriv->segno = 0;
-       segdev->callback = segdev_callback;
-       segdev->priv = segpriv;
-       r = 0;
-out:
-       return r;
+static int segdev_local_signal_init(struct xseg *xseg, xport portno)
+{
+       //assert xsegments[portno] == NULL;
+       xsegments[portno] = xseg;
+       return 0;
 }
 
-static void segdev_signal_quit(void)
+static void segdev_local_signal_quit(struct xseg *xseg, xport portno)
 {
-       struct segdev *segdev = segdev_get(0);
-       int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
-       xsegments[0] = NULL;
-       if (!r)
-               segdev->callback = NULL;
+       //assert xsegments[portno] == xseg;
+       xsegments[portno] = NULL;
        return;
 }
 
 static int segdev_prepare_wait(struct xseg *xseg, uint32_t portno)
 {
-       return -1;
+       struct segdev_signal_desc *ssd; 
+       struct xseg_port *port = xseg_get_port(xseg, portno);
+       if (!port)
+               return -1;
+       ssd = xseg_get_signal_desc(xseg, port);
+       if (!ssd)
+               return -1;
+       /* true/false value */
+       ssd->waitcue = 1;
+       return 0;
 }
 
 static int segdev_cancel_wait(struct xseg *xseg, uint32_t portno)
 {
-       return -1;
+       struct segdev_signal_desc *ssd; 
+       struct xseg_port *port = xseg_get_port(xseg, portno);
+       if (!port)
+               return -1;
+       ssd = xseg_get_signal_desc(xseg, port);
+       if (!ssd)
+               return -1;
+       /* true/false value */
+       ssd->waitcue = 0;
+       return -0;
 }
 
-static int segdev_wait_signal(struct xseg *xseg, uint32_t timeout)
+static int segdev_wait_signal(struct xseg *xseg, void *sd, uint32_t timeout)
 {
        return -1;
 }
@@ -215,11 +286,69 @@ static int segdev_signal(struct xseg *xseg, uint32_t portno)
        return -1;
 }
 
+static int segdev_init_signal_desc(struct xseg *xseg, void *sd)
+{
+       struct segdev_signal_desc *ssd = sd;
+       if (!ssd)
+               return -1;
+       ssd->waitcue = 0;
+       return 0;
+}
+
+static void segdev_quit_signal_desc(struct xseg *xseg, void *sd)
+{
+       return;
+}
+
+static void *segdev_alloc_data(struct xseg *xseg)
+{
+       struct xobject_h *sd_h = xseg_get_objh(xseg, MAGIC_SEGDEV_SD,
+                               sizeof(struct segdev_signal_desc));
+       return sd_h;
+}
+
+static void segdev_free_data(struct xseg *xseg, void *data)
+{
+       if (data)
+               xseg_put_objh(xseg, (struct xobject_h *)data);
+}
+
+static void *segdev_alloc_signal_desc(struct xseg *xseg, void *data)
+{
+       struct segdev_signal_desc *ssd;
+       struct xobject_h *sd_h = (struct xobject_h *) data;
+       if (!sd_h)
+               return NULL;
+       ssd = xobj_get_obj(sd_h, X_ALLOC);
+       if (!ssd)
+               return NULL;
+       ssd->waitcue = 0;
+       return ssd;
+}
+
+static void segdev_free_signal_desc(struct xseg *xseg, void *data, void *sd)
+{
+       struct xobject_h *sd_h = (struct xobject_h *) data;
+       if (!sd_h)
+               return;
+       if (sd)
+               xobj_put_obj(sd_h, sd);
+       return;
+}
+
 static struct xseg_peer xseg_peer_segdev = {
        /* xseg signal operations */
        {
-               .signal_init = segdev_signal_init,
-               .signal_quit = segdev_signal_quit,
+               .init_signal_desc   = segdev_init_signal_desc,
+               .quit_signal_desc   = segdev_quit_signal_desc,
+               .alloc_data         = segdev_alloc_data,
+               .free_data          = segdev_free_data,
+               .alloc_signal_desc  = segdev_alloc_signal_desc,
+               .free_signal_desc   = segdev_free_signal_desc,
+               .local_signal_init  = segdev_local_signal_init,
+               .local_signal_quit  = segdev_local_signal_quit,
+               .remote_signal_init = segdev_remote_signal_init,
+               .remote_signal_quit = segdev_remote_signal_quit,
                .cancel_wait = segdev_cancel_wait,
                .prepare_wait = segdev_prepare_wait,
                .wait_signal = segdev_wait_signal,
@@ -239,6 +368,8 @@ static struct xseg_peer xseg_peer_segdev = {
 
 static int segdev_init(void)
 {
+       struct segdev *segdev;
+       struct segpriv *segpriv;
        int r;
 
        XSEGLOG("registering xseg types");
@@ -249,8 +380,28 @@ static int segdev_init(void)
        r = xseg_register_peer(&xseg_peer_segdev);
        if (r)
                goto err1;
+       
+       segdev = segdev_get(0);
+       r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
+       if (r)
+               goto err2;
 
+       r = -ENOMEM;
+       segpriv = kmalloc(sizeof(struct segpriv), GFP_KERNEL);
+       if (!segpriv)
+               goto err3;
+
+       segpriv->segno = 0;
+       segdev->callback = segdev_callback;
+       segdev->priv = segpriv;
+
+       segdev_put(segdev);
        return 0;
+
+err3:
+       segdev_put(segdev);
+err2:
+       xseg_unregister_peer(xseg_peer_segdev.name);
 err1:
        xseg_unregister_type(xseg_segdev.name);
 err0:
@@ -259,13 +410,15 @@ err0:
 
 static int segdev_quit(void)
 {
-       struct segdev *segdev;
-
-       /* make sure to unmap the segment first */
-       segdev = segdev_get(0);
-       clear_bit(SEGDEV_RESERVED, &segdev->flags);
-       segdev_put(segdev);
-
+       struct segdev *segdev = segdev_get(0);
+       int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
+       if (!r){
+               /* make sure to unmap the segment first */
+               clear_bit(SEGDEV_RESERVED, &segdev->flags);
+               segdev->callback = NULL;
+               //FIXME what aboud segdev->priv?
+               segdev_put(segdev);
+       }
        xseg_unregister_peer(xseg_peer_segdev.name);
        xseg_unregister_type(xseg_segdev.name);