Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / kernel / resource.c
diff --git a/kitten/kernel/resource.c b/kitten/kernel/resource.c
new file mode 100644 (file)
index 0000000..a8bcd7e
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ *     linux/kernel/resource.c
+ *
+ * Copyright (C) 1999  Linus Torvalds
+ * Copyright (C) 1999  Martin Mares <mj@ucw.cz>
+ *
+ * Arbitrary resource management.
+ */
+
+#include <lwk/errno.h>
+#include <lwk/resource.h>
+#include <lwk/init.h>
+#include <lwk/spinlock.h>
+#include <arch/io.h>
+
+struct resource ioport_resource = {
+       .name   = "PCI IO",
+       .start  = 0x0000,
+       .end    = IO_SPACE_LIMIT,
+       .flags  = IORESOURCE_IO,
+};
+
+struct resource iomem_resource = {
+       .name   = "PCI mem",
+       .start  = 0UL,
+       .end    = ~0UL,
+       .flags  = IORESOURCE_MEM,
+};
+
+static DEFINE_RWLOCK(resource_lock);
+
+/* Return the conflict entry if you can't request it */
+static struct resource * __request_resource(struct resource *root, struct resource *new)
+{
+       unsigned long start = new->start;
+       unsigned long end = new->end;
+       struct resource *tmp, **p;
+
+       if (end < start)
+               return root;
+       if (start < root->start)
+               return root;
+       if (end > root->end)
+               return root;
+       p = &root->child;
+       for (;;) {
+               tmp = *p;
+               if (!tmp || tmp->start > end) {
+                       new->sibling = tmp;
+                       *p = new;
+                       new->parent = root;
+                       return NULL;
+               }
+               p = &tmp->sibling;
+               if (tmp->end < start)
+                       continue;
+               return tmp;
+       }
+}
+
+static int __release_resource(struct resource *old)
+{
+       struct resource *tmp, **p;
+
+       BUG_ON(old->child);
+
+       p = &old->parent->child;
+       for (;;) {
+               tmp = *p;
+               if (!tmp)
+                       break;
+               if (tmp == old) {
+                       *p = tmp->sibling;
+                       old->parent = NULL;
+                       return 0;
+               }
+               p = &tmp->sibling;
+       }
+       return -EINVAL;
+}
+
+int request_resource(struct resource *root, struct resource *new)
+{
+       struct resource *conflict;
+
+       write_lock(&resource_lock);
+       conflict = __request_resource(root, new);
+       write_unlock(&resource_lock);
+       return conflict ? -EBUSY : 0;
+}
+
+struct resource *____request_resource(struct resource *root, struct resource *new)
+{
+       struct resource *conflict;
+
+       write_lock(&resource_lock);
+       conflict = __request_resource(root, new);
+       write_unlock(&resource_lock);
+       return conflict;
+}
+
+int release_resource(struct resource *old)
+{
+       int retval;
+
+       write_lock(&resource_lock);
+       retval = __release_resource(old);
+       write_unlock(&resource_lock);
+       return retval;
+}
+
+/*
+ * Find empty slot in the resource tree given range and alignment.
+ */
+static int find_resource(struct resource *root, struct resource *new,
+                        unsigned long size,
+                        unsigned long min, unsigned long max,
+                        unsigned long align,
+                        void (*alignf)(void *, struct resource *,
+                                       unsigned long, unsigned long),
+                        void *alignf_data)
+{
+       struct resource *this = root->child;
+
+       new->start = root->start;
+       /*
+        * Skip past an allocated resource that starts at 0, since the assignment
+        * of this->start - 1 to new->end below would cause an underflow.
+        */
+       if (this && this->start == 0) {
+               new->start = this->end + 1;
+               this = this->sibling;
+       }
+       for(;;) {
+               if (this)
+                       new->end = this->start - 1;
+               else
+                       new->end = root->end;
+               if (new->start < min)
+                       new->start = min;
+               if (new->end > max)
+                       new->end = max;
+               new->start = ALIGN(new->start, align);
+               if (alignf)
+                       alignf(alignf_data, new, size, align);
+               if (new->start < new->end && new->end - new->start >= size - 1) {
+                       new->end = new->start + size - 1;
+                       return 0;
+               }
+               if (!this)
+                       break;
+               new->start = this->end + 1;
+               this = this->sibling;
+       }
+       return -EBUSY;
+}
+
+/*
+ * Allocate empty slot in the resource tree given range and alignment.
+ */
+int allocate_resource(struct resource *root, struct resource *new,
+                     unsigned long size,
+                     unsigned long min, unsigned long max,
+                     unsigned long align,
+                     void (*alignf)(void *, struct resource *,
+                                    unsigned long, unsigned long),
+                     void *alignf_data)
+{
+       int err;
+
+       write_lock(&resource_lock);
+       err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
+       if (err >= 0 && __request_resource(root, new))
+               err = -EBUSY;
+       write_unlock(&resource_lock);
+       return err;
+}
+
+/**
+ * insert_resource - Inserts a resource in the resource tree
+ * @parent: parent of the new resource
+ * @new: new resource to insert
+ *
+ * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ *
+ * This function is equivalent to request_resource when no conflict
+ * happens. If a conflict happens, and the conflicting resources
+ * entirely fit within the range of the new resource, then the new
+ * resource is inserted and the conflicting resources become children of
+ * the new resource.
+ */
+int insert_resource(struct resource *parent, struct resource *new)
+{
+       int result;
+       struct resource *first, *next;
+
+       write_lock(&resource_lock);
+
+       for (;; parent = first) {
+               result = 0;
+               first = __request_resource(parent, new);
+               if (!first)
+                       goto out;
+
+               result = -EBUSY;
+               if (first == parent)
+                       goto out;
+
+               if ((first->start > new->start) || (first->end < new->end))
+                       break;
+               if ((first->start == new->start) && (first->end == new->end))
+                       break;
+       }
+
+       for (next = first; ; next = next->sibling) {
+               /* Partial overlap? Bad, and unfixable */
+               if (next->start < new->start || next->end > new->end)
+                       goto out;
+               if (!next->sibling)
+                       break;
+               if (next->sibling->start > new->end)
+                       break;
+       }
+
+       result = 0;
+
+       new->parent = parent;
+       new->sibling = next->sibling;
+       new->child = first;
+
+       next->sibling = NULL;
+       for (next = first; next; next = next->sibling)
+               next->parent = new;
+
+       if (parent->child == first) {
+               parent->child = new;
+       } else {
+               next = parent->child;
+               while (next->sibling != first)
+                       next = next->sibling;
+               next->sibling = new;
+       }
+
+ out:
+       write_unlock(&resource_lock);
+       return result;
+}
+
+/*
+ * Given an existing resource, change its start and size to match the
+ * arguments.  Returns -EBUSY if it can't fit.  Existing children of
+ * the resource are assumed to be immutable.
+ */
+int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
+{
+       struct resource *tmp, *parent = res->parent;
+       unsigned long end = start + size - 1;
+       int result = -EBUSY;
+
+       write_lock(&resource_lock);
+
+       if ((start < parent->start) || (end > parent->end))
+               goto out;
+
+       for (tmp = res->child; tmp; tmp = tmp->sibling) {
+               if ((tmp->start < start) || (tmp->end > end))
+                       goto out;
+       }
+
+       if (res->sibling && (res->sibling->start <= end))
+               goto out;
+
+       tmp = parent->child;
+       if (tmp != res) {
+               while (tmp->sibling != res)
+                       tmp = tmp->sibling;
+               if (start <= tmp->end)
+                       goto out;
+       }
+
+       res->start = start;
+       res->end = end;
+       result = 0;
+
+ out:
+       write_unlock(&resource_lock);
+       return result;
+}
+