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