mmc: sh_mobile_sdhi: enable SDIO IRQs for RCar Gen3
[linux-2.6-block.git] / kernel / resource.c
index 4d466052426b3e993e7e3c3550e948308e377c51..9b5f04404152c296af3a96132f27cfc80ffa9af9 100644 (file)
@@ -105,16 +105,25 @@ static int r_show(struct seq_file *m, void *v)
 {
        struct resource *root = m->private;
        struct resource *r = v, *p;
+       unsigned long long start, end;
        int width = root->end < 0x10000 ? 4 : 8;
        int depth;
 
        for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
                if (p->parent == root)
                        break;
+
+       if (file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN)) {
+               start = r->start;
+               end = r->end;
+       } else {
+               start = end = 0;
+       }
+
        seq_printf(m, "%*s%0*llx-%0*llx : %s\n",
                        depth * 2, "",
-                       width, (unsigned long long) r->start,
-                       width, (unsigned long long) r->end,
+                       width, start,
+                       width, end,
                        r->name ? r->name : "<BAD>");
        return 0;
 }
@@ -233,9 +242,9 @@ static struct resource * __request_resource(struct resource *root, struct resour
        }
 }
 
-static int __release_resource(struct resource *old)
+static int __release_resource(struct resource *old, bool release_child)
 {
-       struct resource *tmp, **p;
+       struct resource *tmp, **p, *chd;
 
        p = &old->parent->child;
        for (;;) {
@@ -243,7 +252,17 @@ static int __release_resource(struct resource *old)
                if (!tmp)
                        break;
                if (tmp == old) {
-                       *p = tmp->sibling;
+                       if (release_child || !(tmp->child)) {
+                               *p = tmp->sibling;
+                       } else {
+                               for (chd = tmp->child;; chd = chd->sibling) {
+                                       chd->parent = tmp->parent;
+                                       if (!(chd->sibling))
+                                               break;
+                               }
+                               *p = tmp->child;
+                               chd->sibling = tmp->sibling;
+                       }
                        old->parent = NULL;
                        return 0;
                }
@@ -325,7 +344,7 @@ int release_resource(struct resource *old)
        int retval;
 
        write_lock(&resource_lock);
-       retval = __release_resource(old);
+       retval = __release_resource(old, true);
        write_unlock(&resource_lock);
        return retval;
 }
@@ -679,7 +698,7 @@ static int reallocate_resource(struct resource *root, struct resource *old,
                old->start = new.start;
                old->end = new.end;
        } else {
-               __release_resource(old);
+               __release_resource(old, true);
                *old = new;
                conflict = __request_resource(root, old);
                BUG_ON(conflict);
@@ -825,6 +844,9 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
  * 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.
+ *
+ * This function is intended for producers of resources, such as FW modules
+ * and bus drivers.
  */
 struct resource *insert_resource_conflict(struct resource *parent, struct resource *new)
 {
@@ -842,6 +864,9 @@ struct resource *insert_resource_conflict(struct resource *parent, struct resour
  * @new: new resource to insert
  *
  * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ *
+ * This function is intended for producers of resources, such as FW modules
+ * and bus drivers.
  */
 int insert_resource(struct resource *parent, struct resource *new)
 {
@@ -850,6 +875,7 @@ int insert_resource(struct resource *parent, struct resource *new)
        conflict = insert_resource_conflict(parent, new);
        return conflict ? -EBUSY : 0;
 }
+EXPORT_SYMBOL_GPL(insert_resource);
 
 /**
  * insert_resource_expand_to_fit - Insert a resource into the resource tree
@@ -885,6 +911,32 @@ void insert_resource_expand_to_fit(struct resource *root, struct resource *new)
        write_unlock(&resource_lock);
 }
 
+/**
+ * remove_resource - Remove a resource in the resource tree
+ * @old: resource to remove
+ *
+ * Returns 0 on success, -EINVAL if the resource is not valid.
+ *
+ * This function removes a resource previously inserted by insert_resource()
+ * or insert_resource_conflict(), and moves the children (if any) up to
+ * where they were before.  insert_resource() and insert_resource_conflict()
+ * insert a new resource, and move any conflicting resources down to the
+ * children of the new resource.
+ *
+ * insert_resource(), insert_resource_conflict() and remove_resource() are
+ * intended for producers of resources, such as FW modules and bus drivers.
+ */
+int remove_resource(struct resource *old)
+{
+       int retval;
+
+       write_lock(&resource_lock);
+       retval = __release_resource(old, false);
+       write_unlock(&resource_lock);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(remove_resource);
+
 static int __adjust_resource(struct resource *res, resource_size_t start,
                                resource_size_t size)
 {
@@ -1085,15 +1137,16 @@ struct resource * __request_region(struct resource *parent,
        res->name = name;
        res->start = start;
        res->end = start + n - 1;
-       res->flags = resource_type(parent) | resource_ext_type(parent);
-       res->flags |= IORESOURCE_BUSY | flags;
-       res->desc = IORES_DESC_NONE;
 
        write_lock(&resource_lock);
 
        for (;;) {
                struct resource *conflict;
 
+               res->flags = resource_type(parent) | resource_ext_type(parent);
+               res->flags |= IORESOURCE_BUSY | flags;
+               res->desc = parent->desc;
+
                conflict = __request_resource(parent, res);
                if (!conflict)
                        break;