patch-2.3.13 linux/kernel/resource.c
Next file: linux/kernel/sched.c
Previous file: linux/kernel/printk.c
Back to the patch index
Back to the overall index
- Lines: 194
- Date:
Sat Aug 7 11:08:54 1999
- Orig file:
v2.3.12/linux/kernel/resource.c
- Orig date:
Wed Jul 21 15:46:48 1999
diff -u --recursive --new-file v2.3.12/linux/kernel/resource.c linux/kernel/resource.c
@@ -12,9 +12,13 @@
#include <linux/init.h>
#include <linux/malloc.h>
+#include <asm/spinlock.h>
+
struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF };
struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF };
+static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
+
/*
* This generates reports for /proc/ioports and /proc/memory
*/
@@ -47,25 +51,30 @@
int get_resource_list(struct resource *root, char *buf, int size)
{
char *fmt;
+ int retval;
fmt = " %08lx-%08lx : %s\n";
if (root == &ioport_resource)
fmt = " %04lx-%04lx : %s\n";
- return do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
+ read_lock(&resource_lock);
+ retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
+ read_unlock(&resource_lock);
+ return retval;
}
-int request_resource(struct resource *root, struct resource *new)
+/* 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 -EINVAL;
+ return root;
if (start < root->start)
- return -EINVAL;
+ return root;
if (end > root->end)
- return -EINVAL;
+ return root;
p = &root->child;
for (;;) {
tmp = *p;
@@ -73,15 +82,25 @@
new->sibling = tmp;
*p = new;
new->parent = root;
- return 0;
+ return NULL;
}
p = &tmp->sibling;
if (tmp->end < start)
continue;
- return -EBUSY;
+ return tmp;
}
}
+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;
+}
+
int release_resource(struct resource *old)
{
struct resource *tmp, **p;
@@ -101,6 +120,18 @@
return -EINVAL;
}
+/*
+ * This is compatibility stuff for IO resources.
+ *
+ * Note how this, unlike the above, knows about
+ * the IO flag meanings (busy etc).
+ *
+ * Request-region creates a new busy region.
+ *
+ * Check-region returns non-zero if the area is already busy
+ *
+ * Release-region releases a matching busy region.
+ */
struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
{
struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
@@ -110,21 +141,33 @@
res->name = name;
res->start = start;
res->end = start + n - 1;
- if (request_resource(parent, res) != 0) {
+ res->flags = IORESOURCE_BUSY;
+
+ write_lock(&resource_lock);
+
+ for (;;) {
+ struct resource *conflict;
+
+ conflict = __request_resource(parent, res);
+ if (!conflict)
+ break;
+ if (conflict != parent) {
+ parent = conflict;
+ if (!(conflict->flags & IORESOURCE_BUSY))
+ continue;
+ }
+
+ /* Uhhuh, that didn't work out.. */
kfree(res);
res = NULL;
+ break;
}
+ write_unlock(&resource_lock);
}
return res;
}
/*
- * Compatibility cruft.
- *
- * Check-region returns non-zero if something already exists.
- *
- * Release-region releases an anonymous region that matches
- * the IO port range.
*/
int __check_region(struct resource *parent, unsigned long start, unsigned long n)
{
@@ -152,35 +195,48 @@
if (!res)
break;
- if (res->start == start && res->end == end) {
+ if (res->start <= start && res->end >= end) {
+ if (!(res->flags & IORESOURCE_BUSY)) {
+ p = &res->child;
+ continue;
+ }
+ if (res->start != start || res->end != end)
+ break;
*p = res->sibling;
kfree(res);
- break;
+ return;
}
p = &res->sibling;
}
+ printk("Trying to free nonexistent resource <%04lx-%04lx>\n", start, end);
}
/*
* Called from init/main.c to reserve IO ports.
*/
#define MAXRESERVE 4
-void __init reserve_setup(char *str, int *ints)
+static int __init reserve_setup(char *str)
{
- int i;
+ int opt = 2, io_start, io_num;
static int reserved = 0;
static struct resource reserve[MAXRESERVE];
- for (i = 1; i < ints[0]; i += 2) {
+ while (opt==2) {
int x = reserved;
+
+ if (get_option (&str, &io_start) != 2) break;
+ if (get_option (&str, &io_num) == 0) break;
if (x < MAXRESERVE) {
struct resource *res = reserve + x;
res->name = "reserved";
- res->start = ints[i];
- res->end = res->start + ints[i] - 1;
+ res->start = io_start;
+ res->end = io_start + io_num - 1;
res->child = NULL;
if (request_resource(&ioport_resource, res) == 0)
reserved = x+1;
}
}
+ return 1;
}
+
+__setup("reserve=", reserve_setup);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)