RHEL4/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/config.h>
  11#include <linux/module.h>
  12#include <linux/sched.h>
  13#include <linux/errno.h>
  14#include <linux/ioport.h>
  15#include <linux/init.h>
  16#include <linux/slab.h>
  17#include <linux/spinlock.h>
  18#include <linux/fs.h>
  19#include <linux/proc_fs.h>
  20#include <linux/seq_file.h>
  21#include <asm/io.h>
  22
  23
  24struct resource ioport_resource = {
  25        .name   = "PCI IO",
  26        .start  = 0x0000,
  27        .end    = IO_SPACE_LIMIT,
  28        .flags  = IORESOURCE_IO,
  29};
  30
  31EXPORT_SYMBOL(ioport_resource);
  32
  33struct resource iomem_resource = {
  34        .name   = "PCI mem",
  35        .start  = 0UL,
  36        .end    = ~0UL,
  37        .flags  = IORESOURCE_MEM,
  38};
  39
  40EXPORT_SYMBOL(iomem_resource);
  41
  42static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
  43
  44#ifdef CONFIG_PROC_FS
  45
  46enum { MAX_IORES_LEVEL = 5 };
  47
  48static void *r_next(struct seq_file *m, void *v, loff_t *pos)
  49{
  50        struct resource *p = v;
  51        (*pos)++;
  52        if (p->child)
  53                return p->child;
  54        while (!p->sibling && p->parent)
  55                p = p->parent;
  56        return p->sibling;
  57}
  58
  59static void *r_start(struct seq_file *m, loff_t *pos)
  60{
  61        struct resource *p = m->private;
  62        loff_t l = 0;
  63        read_lock(&resource_lock);
  64        for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
  65                ;
  66        return p;
  67}
  68
  69static void r_stop(struct seq_file *m, void *v)
  70{
  71        read_unlock(&resource_lock);
  72}
  73
  74static int r_show(struct seq_file *m, void *v)
  75{
  76        struct resource *root = m->private;
  77        struct resource *r = v, *p;
  78        int width = root->end < 0x10000 ? 4 : 8;
  79        int depth;
  80
  81        for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
  82                if (p->parent == root)
  83                        break;
  84        seq_printf(m, "%*s%0*lx-%0*lx : %s\n",
  85                        depth * 2, "",
  86                        width, r->start,
  87                        width, r->end,
  88                        r->name ? r->name : "<BAD>");
  89        return 0;
  90}
  91
  92struct seq_operations resource_op = {
  93        .start  = r_start,
  94        .next   = r_next,
  95        .stop   = r_stop,
  96        .show   = r_show,
  97};
  98
  99static int ioports_open(struct inode *inode, struct file *file)
 100{
 101        int res = seq_open(file, &resource_op);
 102        if (!res) {
 103                struct seq_file *m = file->private_data;
 104                m->private = &ioport_resource;
 105        }
 106        return res;
 107}
 108
 109static int iomem_open(struct inode *inode, struct file *file)
 110{
 111        int res = seq_open(file, &resource_op);
 112        if (!res) {
 113                struct seq_file *m = file->private_data;
 114                m->private = &iomem_resource;
 115        }
 116        return res;
 117}
 118
 119static struct file_operations proc_ioports_operations = {
 120        .open           = ioports_open,
 121        .read           = seq_read,
 122        .llseek         = seq_lseek,
 123        .release        = seq_release,
 124};
 125
 126static struct file_operations proc_iomem_operations = {
 127        .open           = iomem_open,
 128        .read           = seq_read,
 129        .llseek         = seq_lseek,
 130        .release        = seq_release,
 131};
 132
 133static int __init ioresources_init(void)
 134{
 135        struct proc_dir_entry *entry;
 136
 137        entry = create_proc_entry("ioports", 0, NULL);
 138        if (entry)
 139                entry->proc_fops = &proc_ioports_operations;
 140        entry = create_proc_entry("iomem", 0, NULL);
 141        if (entry)
 142                entry->proc_fops = &proc_iomem_operations;
 143        return 0;
 144}
 145__initcall(ioresources_init);
 146
 147#endif /* CONFIG_PROC_FS */
 148
 149/* Return the conflict entry if you can't request it */
 150static struct resource * __request_resource(struct resource *root, struct resource *new)
 151{
 152        unsigned long start = new->start;
 153        unsigned long end = new->end;
 154        struct resource *tmp, **p;
 155
 156        if (end < start)
 157                return root;
 158        if (start < root->start)
 159                return root;
 160        if (end > root->end)
 161                return root;
 162        p = &root->child;
 163        for (;;) {
 164                tmp = *p;
 165                if (!tmp || tmp->start > end) {
 166                        new->sibling = tmp;
 167                        *p = new;
 168                        new->parent = root;
 169                        return NULL;
 170                }
 171                p = &tmp->sibling;
 172                if (tmp->end < start)
 173                        continue;
 174                return tmp;
 175        }
 176}
 177
 178static int __release_resource(struct resource *old)
 179{
 180        struct resource *tmp, **p;
 181
 182        p = &old->parent->child;
 183        for (;;) {
 184                tmp = *p;
 185                if (!tmp)
 186                        break;
 187                if (tmp == old) {
 188                        *p = tmp->sibling;
 189                        old->parent = NULL;
 190                        return 0;
 191                }
 192                p = &tmp->sibling;
 193        }
 194        return -EINVAL;
 195}
 196
 197int request_resource(struct resource *root, struct resource *new)
 198{
 199        struct resource *conflict;
 200
 201        write_lock(&resource_lock);
 202        conflict = __request_resource(root, new);
 203        write_unlock(&resource_lock);
 204        return conflict ? -EBUSY : 0;
 205}
 206
 207EXPORT_SYMBOL(request_resource);
 208
 209struct resource *____request_resource(struct resource *root, struct resource *new)
 210{
 211        struct resource *conflict;
 212
 213        write_lock(&resource_lock);
 214        conflict = __request_resource(root, new);
 215        write_unlock(&resource_lock);
 216        return conflict;
 217}
 218
 219EXPORT_SYMBOL(____request_resource);
 220
 221int release_resource(struct resource *old)
 222{
 223        int retval;
 224
 225        write_lock(&resource_lock);
 226        retval = __release_resource(old);
 227        write_unlock(&resource_lock);
 228        return retval;
 229}
 230
 231EXPORT_SYMBOL(release_resource);
 232
 233/*
 234 * Find empty slot in the resource tree given range and alignment.
 235 */
 236static int find_resource(struct resource *root, struct resource *new,
 237                         unsigned long size,
 238                         unsigned long min, unsigned long max,
 239                         unsigned long align,
 240                         void (*alignf)(void *, struct resource *,
 241                                        unsigned long, unsigned long),
 242                         void *alignf_data)
 243{
 244        struct resource *this = root->child;
 245
 246        new->start = root->start;
 247        /*
 248         * Skip past an allocated resource that starts at 0, since the assignment
 249         * of this->start - 1 to new->end below would cause an underflow.
 250         */
 251        if (this && this->start == 0) {
 252                new->start = this->end + 1;
 253                this = this->sibling;
 254        }
 255        for(;;) {
 256                if (this)
 257                        new->end = this->start - 1;
 258                else
 259                        new->end = root->end;
 260                if (new->start < min)
 261                        new->start = min;
 262                if (new->end > max)
 263                        new->end = max;
 264                new->start = (new->start + align - 1) & ~(align - 1);
 265                if (alignf)
 266                        alignf(alignf_data, new, size, align);
 267                if (new->start < new->end && new->end - new->start + 1 >= size) {
 268                        new->end = new->start + size - 1;
 269                        return 0;
 270                }
 271                if (!this)
 272                        break;
 273                new->start = this->end + 1;
 274                this = this->sibling;
 275        }
 276        return -EBUSY;
 277}
 278
 279/*
 280 * Allocate empty slot in the resource tree given range and alignment.
 281 */
 282int allocate_resource(struct resource *root, struct resource *new,
 283                      unsigned long size,
 284                      unsigned long min, unsigned long max,
 285                      unsigned long align,
 286                      void (*alignf)(void *, struct resource *,
 287                                     unsigned long, unsigned long),
 288                      void *alignf_data)
 289{
 290        int err;
 291
 292        write_lock(&resource_lock);
 293        err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
 294        if (err >= 0 && __request_resource(root, new))
 295                err = -EBUSY;
 296        write_unlock(&resource_lock);
 297        return err;
 298}
 299
 300EXPORT_SYMBOL(allocate_resource);
 301
 302/**
 303 * insert_resource - Inserts a resource in the resource tree
 304 * @parent: parent of the new resource
 305 * @new: new resource to insert
 306 *
 307 * Returns 0 on success, -EBUSY if the resource can't be inserted.
 308 *
 309 * This function is equivalent of request_resource when no conflict
 310 * happens. If a conflict happens, and the conflicting resources
 311 * entirely fit within the range of the new resource, then the new
 312 * resource is inserted and the conflicting resources become childs of
 313 * the new resource.  Otherwise the new resource becomes the child of
 314 * the conflicting resource
 315 */
 316int insert_resource(struct resource *parent, struct resource *new)
 317{
 318        int result;
 319        struct resource *first, *next;
 320
 321        write_lock(&resource_lock);
 322 begin:
 323        result = 0;
 324        first = __request_resource(parent, new);
 325        if (!first)
 326                goto out;
 327
 328        result = -EBUSY;
 329        if (first == parent)
 330                goto out;
 331
 332        /* Resource fully contained by the clashing resource? Recurse into it */
 333        if (first->start <= new->start && first->end >= new->end) {
 334                parent = first;
 335                goto begin;
 336        }
 337
 338        for (next = first; ; next = next->sibling) {
 339                /* Partial overlap? Bad, and unfixable */
 340                if (next->start < new->start || next->end > new->end)
 341                        goto out;
 342                if (!next->sibling)
 343                        break;
 344                if (next->sibling->start > new->end)
 345                        break;
 346        }
 347
 348        result = 0;
 349
 350        new->parent = parent;
 351        new->sibling = next->sibling;
 352        new->child = first;
 353
 354        next->sibling = NULL;
 355        for (next = first; next; next = next->sibling)
 356                next->parent = new;
 357
 358        if (parent->child == first) {
 359                parent->child = new;
 360        } else {
 361                next = parent->child;
 362                while (next->sibling != first)
 363                        next = next->sibling;
 364                next->sibling = new;
 365        }
 366
 367 out:
 368        write_unlock(&resource_lock);
 369        return result;
 370}
 371
 372EXPORT_SYMBOL(insert_resource);
 373
 374/*
 375 * Given an existing resource, change its start and size to match the
 376 * arguments.  Returns -EBUSY if it can't fit.  Existing children of
 377 * the resource are assumed to be immutable.
 378 */
 379int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
 380{
 381        struct resource *tmp, *parent = res->parent;
 382        unsigned long end = start + size - 1;
 383        int result = -EBUSY;
 384
 385        write_lock(&resource_lock);
 386
 387        if ((start < parent->start) || (end > parent->end))
 388                goto out;
 389
 390        for (tmp = res->child; tmp; tmp = tmp->sibling) {
 391                if ((tmp->start < start) || (tmp->end > end))
 392                        goto out;
 393        }
 394
 395        if (res->sibling && (res->sibling->start <= end))
 396                goto out;
 397
 398        tmp = parent->child;
 399        if (tmp != res) {
 400                while (tmp->sibling != res)
 401                        tmp = tmp->sibling;
 402                if (start <= tmp->end)
 403                        goto out;
 404        }
 405
 406        res->start = start;
 407        res->end = end;
 408        result = 0;
 409
 410 out:
 411        write_unlock(&resource_lock);
 412        return result;
 413}
 414
 415EXPORT_SYMBOL(adjust_resource);
 416
 417/*
 418 * This is compatibility stuff for IO resources.
 419 *
 420 * Note how this, unlike the above, knows about
 421 * the IO flag meanings (busy etc).
 422 *
 423 * Request-region creates a new busy region.
 424 *
 425 * Check-region returns non-zero if the area is already busy
 426 *
 427 * Release-region releases a matching busy region.
 428 */
 429struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
 430{
 431        struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
 432
 433        if (res) {
 434                memset(res, 0, sizeof(*res));
 435                res->name = name;
 436                res->start = start;
 437                res->end = start + n - 1;
 438                res->flags = IORESOURCE_BUSY;
 439
 440                write_lock(&resource_lock);
 441
 442                for (;;) {
 443                        struct resource *conflict;
 444
 445                        conflict = __request_resource(parent, res);
 446                        if (!conflict)
 447                                break;
 448                        if (conflict != parent) {
 449                                parent = conflict;
 450                                if (!(conflict->flags & IORESOURCE_BUSY))
 451                                        continue;
 452                        }
 453
 454                        /* Uhhuh, that didn't work out.. */
 455                        kfree(res);
 456                        res = NULL;
 457                        break;
 458                }
 459                write_unlock(&resource_lock);
 460        }
 461        return res;
 462}
 463
 464EXPORT_SYMBOL(__request_region);
 465
 466int __deprecated __check_region(struct resource *parent, unsigned long start, unsigned long n)
 467{
 468        struct resource * res;
 469
 470        res = __request_region(parent, start, n, "check-region");
 471        if (!res)
 472                return -EBUSY;
 473
 474        release_resource(res);
 475        kfree(res);
 476        return 0;
 477}
 478
 479EXPORT_SYMBOL(__check_region);
 480
 481void __release_region(struct resource *parent, unsigned long start, unsigned long n)
 482{
 483        struct resource **p;
 484        unsigned long end;
 485
 486        p = &parent->child;
 487        end = start + n - 1;
 488
 489        write_lock(&resource_lock);
 490
 491        for (;;) {
 492                struct resource *res = *p;
 493
 494                if (!res)
 495                        break;
 496                if (res->start <= start && res->end >= end) {
 497                        if (!(res->flags & IORESOURCE_BUSY)) {
 498                                p = &res->child;
 499                                continue;
 500                        }
 501                        if (res->start != start || res->end != end)
 502                                break;
 503                        *p = res->sibling;
 504                        write_unlock(&resource_lock);
 505                        kfree(res);
 506                        return;
 507                }
 508                p = &res->sibling;
 509        }
 510
 511        write_unlock(&resource_lock);
 512
 513        printk(KERN_WARNING "Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
 514}
 515
 516EXPORT_SYMBOL(__release_region);
 517
 518/*
 519 * Called from init/main.c to reserve IO ports.
 520 */
 521#define MAXRESERVE 4
 522static int __init reserve_setup(char *str)
 523{
 524        static int reserved;
 525        static struct resource reserve[MAXRESERVE];
 526
 527        for (;;) {
 528                int io_start, io_num;
 529                int x = reserved;
 530
 531                if (get_option (&str, &io_start) != 2)
 532                        break;
 533                if (get_option (&str, &io_num)   == 0)
 534                        break;
 535                if (x < MAXRESERVE) {
 536                        struct resource *res = reserve + x;
 537                        res->name = "reserved";
 538                        res->start = io_start;
 539                        res->end = io_start + io_num - 1;
 540                        res->flags = IORESOURCE_BUSY;
 541                        res->child = NULL;
 542                        if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
 543                                reserved = x+1;
 544                }
 545        }
 546        return 1;
 547}
 548
 549__setup("reserve=", reserve_setup);
 550