debuggers.hg

annotate xen/common/resource.c @ 3658:0ef6e8e6e85d

bitkeeper revision 1.1159.212.71 (4200f0afX_JumfbEHQex6TdFENULMQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/iap10/xeno-clone/xen-unstable.bk
author iap10@labyrinth.cl.cam.ac.uk
date Wed Feb 02 15:24:31 2005 +0000 (2005-02-02)
parents dae98734f12e beb0887c54bc
children bbe8541361dd 4294cfa9fad3
rev   line source
iap10@274 1 /*
iap10@274 2 * linux/kernel/resource.c
iap10@274 3 *
iap10@274 4 * Copyright (C) 1999 Linus Torvalds
iap10@274 5 * Copyright (C) 1999 Martin Mares <mj@ucw.cz>
iap10@274 6 *
iap10@274 7 * Arbitrary resource management.
iap10@274 8 */
iap10@274 9
kaf24@1248 10 #include <xen/config.h>
kaf24@1248 11 #include <xen/lib.h>
kaf24@1248 12 #include <xen/sched.h>
kaf24@1248 13 #include <xen/errno.h>
kaf24@1248 14 #include <xen/ioport.h>
kaf24@1248 15 #include <xen/init.h>
kaf24@1248 16 #include <xen/slab.h>
kaf24@1248 17 #include <xen/spinlock.h>
iap10@274 18 #include <asm/io.h>
iap10@274 19
iap10@274 20 struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
iap10@274 21 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };
iap10@274 22
iap10@274 23 static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
iap10@274 24
iap10@274 25 /*
iap10@274 26 * This generates reports for /proc/ioports and /proc/iomem
iap10@274 27 */
iap10@274 28 static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end)
iap10@274 29 {
iap10@274 30 if (offset < 0)
iap10@274 31 offset = 0;
iap10@274 32
iap10@274 33 while (entry) {
iap10@274 34 const char *name = entry->name;
iap10@274 35 unsigned long from, to;
iap10@274 36
iap10@274 37 if ((int) (end-buf) < 80)
iap10@274 38 return buf;
iap10@274 39
iap10@274 40 from = entry->start;
iap10@274 41 to = entry->end;
iap10@274 42 if (!name)
iap10@274 43 name = "<BAD>";
iap10@274 44
iap10@274 45 buf += sprintf(buf, fmt + offset, from, to, name);
iap10@274 46 if (entry->child)
iap10@274 47 buf = do_resource_list(entry->child, fmt, offset-2, buf, end);
iap10@274 48 entry = entry->sibling;
iap10@274 49 }
iap10@274 50
iap10@274 51 return buf;
iap10@274 52 }
iap10@274 53
iap10@274 54 int get_resource_list(struct resource *root, char *buf, int size)
iap10@274 55 {
iap10@274 56 char *fmt;
iap10@274 57 int retval;
iap10@274 58
iap10@274 59 fmt = " %08lx-%08lx : %s\n";
iap10@274 60 if (root->end < 0x10000)
iap10@274 61 fmt = " %04lx-%04lx : %s\n";
iap10@274 62 read_lock(&resource_lock);
iap10@274 63 retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
iap10@274 64 read_unlock(&resource_lock);
iap10@274 65 return retval;
iap10@274 66 }
iap10@274 67
iap10@274 68 /* Return the conflict entry if you can't request it */
iap10@274 69 static struct resource * __request_resource(struct resource *root, struct resource *new)
iap10@274 70 {
iap10@274 71 unsigned long start = new->start;
iap10@274 72 unsigned long end = new->end;
iap10@274 73 struct resource *tmp, **p;
iap10@274 74
iap10@274 75 if (end < start)
iap10@274 76 return root;
iap10@274 77 if (start < root->start)
iap10@274 78 return root;
iap10@274 79 if (end > root->end)
iap10@274 80 return root;
iap10@274 81 p = &root->child;
iap10@274 82 for (;;) {
iap10@274 83 tmp = *p;
iap10@274 84 if (!tmp || tmp->start > end) {
iap10@274 85 new->sibling = tmp;
iap10@274 86 *p = new;
iap10@274 87 new->parent = root;
iap10@274 88 return NULL;
iap10@274 89 }
iap10@274 90 p = &tmp->sibling;
iap10@274 91 if (tmp->end < start)
iap10@274 92 continue;
iap10@274 93 return tmp;
iap10@274 94 }
iap10@274 95 }
iap10@274 96
iap10@274 97 static int __release_resource(struct resource *old)
iap10@274 98 {
iap10@274 99 struct resource *tmp, **p;
iap10@274 100
iap10@274 101 p = &old->parent->child;
iap10@274 102 for (;;) {
iap10@274 103 tmp = *p;
iap10@274 104 if (!tmp)
iap10@274 105 break;
iap10@274 106 if (tmp == old) {
iap10@274 107 *p = tmp->sibling;
iap10@274 108 old->parent = NULL;
iap10@274 109 return 0;
iap10@274 110 }
iap10@274 111 p = &tmp->sibling;
iap10@274 112 }
iap10@274 113 return -EINVAL;
iap10@274 114 }
iap10@274 115
iap10@274 116 int request_resource(struct resource *root, struct resource *new)
iap10@274 117 {
iap10@274 118 struct resource *conflict;
iap10@274 119
iap10@274 120 write_lock(&resource_lock);
iap10@274 121 conflict = __request_resource(root, new);
iap10@274 122 write_unlock(&resource_lock);
iap10@274 123 return conflict ? -EBUSY : 0;
iap10@274 124 }
iap10@274 125
iap10@274 126 int release_resource(struct resource *old)
iap10@274 127 {
iap10@274 128 int retval;
iap10@274 129
iap10@274 130 write_lock(&resource_lock);
iap10@274 131 retval = __release_resource(old);
iap10@274 132 write_unlock(&resource_lock);
iap10@274 133 return retval;
iap10@274 134 }
iap10@274 135
iap10@274 136 int check_resource(struct resource *root, unsigned long start, unsigned long len)
iap10@274 137 {
iap10@274 138 struct resource *conflict, tmp;
iap10@274 139
iap10@274 140 tmp.start = start;
iap10@274 141 tmp.end = start + len - 1;
iap10@274 142 write_lock(&resource_lock);
iap10@274 143 conflict = __request_resource(root, &tmp);
iap10@274 144 if (!conflict)
iap10@274 145 __release_resource(&tmp);
iap10@274 146 write_unlock(&resource_lock);
iap10@274 147 return conflict ? -EBUSY : 0;
iap10@274 148 }
iap10@274 149
iap10@274 150 /*
iap10@274 151 * Find empty slot in the resource tree given range and alignment.
iap10@274 152 */
iap10@274 153 static int find_resource(struct resource *root, struct resource *new,
iap10@274 154 unsigned long size,
iap10@274 155 unsigned long min, unsigned long max,
iap10@274 156 unsigned long align,
iap10@274 157 void (*alignf)(void *, struct resource *,
iap10@274 158 unsigned long, unsigned long),
iap10@274 159 void *alignf_data)
iap10@274 160 {
iap10@274 161 struct resource *this = root->child;
iap10@274 162
iap10@274 163 new->start = root->start;
iap10@274 164 for(;;) {
iap10@274 165 if (this)
iap10@274 166 new->end = this->start;
iap10@274 167 else
iap10@274 168 new->end = root->end;
iap10@274 169 if (new->start < min)
iap10@274 170 new->start = min;
iap10@274 171 if (new->end > max)
iap10@274 172 new->end = max;
iap10@274 173 new->start = (new->start + align - 1) & ~(align - 1);
iap10@274 174 if (alignf)
iap10@274 175 alignf(alignf_data, new, size, align);
iap10@274 176 if (new->start < new->end && new->end - new->start + 1 >= size) {
iap10@274 177 new->end = new->start + size - 1;
iap10@274 178 return 0;
iap10@274 179 }
iap10@274 180 if (!this)
iap10@274 181 break;
iap10@274 182 new->start = this->end + 1;
iap10@274 183 this = this->sibling;
iap10@274 184 }
iap10@274 185 return -EBUSY;
iap10@274 186 }
iap10@274 187
iap10@274 188 /*
iap10@274 189 * Allocate empty slot in the resource tree given range and alignment.
iap10@274 190 */
iap10@274 191 int allocate_resource(struct resource *root, struct resource *new,
iap10@274 192 unsigned long size,
iap10@274 193 unsigned long min, unsigned long max,
iap10@274 194 unsigned long align,
iap10@274 195 void (*alignf)(void *, struct resource *,
iap10@274 196 unsigned long, unsigned long),
iap10@274 197 void *alignf_data)
iap10@274 198 {
iap10@274 199 int err;
iap10@274 200
iap10@274 201 write_lock(&resource_lock);
iap10@274 202 err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
iap10@274 203 if (err >= 0 && __request_resource(root, new))
iap10@274 204 err = -EBUSY;
iap10@274 205 write_unlock(&resource_lock);
iap10@274 206 return err;
iap10@274 207 }
iap10@274 208
iap10@274 209 /*
iap10@274 210 * This is compatibility stuff for IO resources.
iap10@274 211 *
iap10@274 212 * Note how this, unlike the above, knows about
iap10@274 213 * the IO flag meanings (busy etc).
iap10@274 214 *
iap10@274 215 * Request-region creates a new busy region.
iap10@274 216 *
iap10@274 217 * Check-region returns non-zero if the area is already busy
iap10@274 218 *
iap10@274 219 * Release-region releases a matching busy region.
iap10@274 220 */
iap10@274 221 struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
iap10@274 222 {
iap10@3650 223 struct resource *res = xmalloc(struct resource);
iap10@274 224
iap10@274 225 if (res) {
iap10@274 226 memset(res, 0, sizeof(*res));
iap10@274 227 res->name = name;
iap10@274 228 res->start = start;
iap10@274 229 res->end = start + n - 1;
iap10@274 230 res->flags = IORESOURCE_BUSY;
iap10@274 231
iap10@274 232 write_lock(&resource_lock);
iap10@274 233
iap10@274 234 for (;;) {
iap10@274 235 struct resource *conflict;
iap10@274 236
iap10@274 237 conflict = __request_resource(parent, res);
iap10@274 238 if (!conflict)
iap10@274 239 break;
iap10@274 240 if (conflict != parent) {
iap10@274 241 parent = conflict;
iap10@274 242 if (!(conflict->flags & IORESOURCE_BUSY))
iap10@274 243 continue;
iap10@274 244 }
iap10@274 245
iap10@274 246 /* Uhhuh, that didn't work out.. */
kaf24@1958 247 xfree(res);
iap10@274 248 res = NULL;
iap10@274 249 break;
iap10@274 250 }
iap10@274 251 write_unlock(&resource_lock);
iap10@274 252 }
iap10@274 253 return res;
iap10@274 254 }
iap10@274 255
iap10@274 256 int __check_region(struct resource *parent, unsigned long start, unsigned long n)
iap10@274 257 {
iap10@274 258 struct resource * res;
iap10@274 259
iap10@274 260 res = __request_region(parent, start, n, "check-region");
iap10@274 261 if (!res)
iap10@274 262 return -EBUSY;
iap10@274 263
iap10@274 264 release_resource(res);
kaf24@1958 265 xfree(res);
iap10@274 266 return 0;
iap10@274 267 }
iap10@274 268
iap10@274 269 void __release_region(struct resource *parent, unsigned long start, unsigned long n)
iap10@274 270 {
iap10@274 271 struct resource **p;
iap10@274 272 unsigned long end;
iap10@274 273
iap10@274 274 p = &parent->child;
iap10@274 275 end = start + n - 1;
iap10@274 276
iap10@274 277 for (;;) {
iap10@274 278 struct resource *res = *p;
iap10@274 279
iap10@274 280 if (!res)
iap10@274 281 break;
iap10@274 282 if (res->start <= start && res->end >= end) {
iap10@274 283 if (!(res->flags & IORESOURCE_BUSY)) {
iap10@274 284 p = &res->child;
iap10@274 285 continue;
iap10@274 286 }
iap10@274 287 if (res->start != start || res->end != end)
iap10@274 288 break;
iap10@274 289 *p = res->sibling;
kaf24@1958 290 xfree(res);
iap10@274 291 return;
iap10@274 292 }
iap10@274 293 p = &res->sibling;
iap10@274 294 }
iap10@274 295 printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
iap10@274 296 }
iap10@274 297
iap10@274 298
iap10@274 299 #if 0
iap10@274 300 /*
iap10@274 301 * Called from init/main.c to reserve IO ports.
iap10@274 302 */
iap10@274 303 #define MAXRESERVE 4
iap10@274 304 static int __init reserve_setup(char *str)
iap10@274 305 {
iap10@274 306 static int reserved = 0;
iap10@274 307 static struct resource reserve[MAXRESERVE];
iap10@274 308
iap10@274 309 for (;;) {
iap10@274 310 int io_start, io_num;
iap10@274 311 int x = reserved;
iap10@274 312
iap10@274 313 if (get_option (&str, &io_start) != 2)
iap10@274 314 break;
iap10@274 315 if (get_option (&str, &io_num) == 0)
iap10@274 316 break;
iap10@274 317 if (x < MAXRESERVE) {
iap10@274 318 struct resource *res = reserve + x;
iap10@274 319 res->name = "reserved";
iap10@274 320 res->start = io_start;
iap10@274 321 res->end = io_start + io_num - 1;
iap10@274 322 res->flags = IORESOURCE_BUSY;
iap10@274 323 res->child = NULL;
iap10@274 324 if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
iap10@274 325 reserved = x+1;
iap10@274 326 }
iap10@274 327 }
iap10@274 328 return 1;
iap10@274 329 }
iap10@274 330
iap10@274 331 __setup("reserve=", reserve_setup);
iap10@274 332 #endif