The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/resource.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   18 struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
   19 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };
   20 
   21 static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
   22 
   23 /*
   24  * This generates reports for /proc/ioports and /proc/iomem
   25  */
   26 static 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 
   52 int 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 */
   67 static 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 
   95 static 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 
  114 int 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 
  124 int 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 
  134 int 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  */
  151 static 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  */
  189 int 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  */
  219 struct 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 
  254 int __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 
  267 void __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("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
  300 static 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);

Cache object: 59f45bdb27f6fc42109e1e09614ceefd


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.