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