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
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 |