📄 resource.c
字号:
/** * insert_resource - Inserts a resource in the resource tree * @parent: parent of the new resource * @new: new resource to insert * * Returns 0 on success, -EBUSY if the resource can't be inserted. * * This function is equivalent to request_resource when no conflict * happens. If a conflict happens, and the conflicting resources * entirely fit within the range of the new resource, then the new * resource is inserted and the conflicting resources become children of * the new resource. */int insert_resource(struct resource *parent, struct resource *new){ int result; struct resource *first, *next; write_lock(&resource_lock); for (;; parent = first) { result = 0; first = __request_resource(parent, new); if (!first) goto out; result = -EBUSY; if (first == parent) goto out; if ((first->start > new->start) || (first->end < new->end)) break; if ((first->start == new->start) && (first->end == new->end)) break; } for (next = first; ; next = next->sibling) { /* Partial overlap? Bad, and unfixable */ if (next->start < new->start || next->end > new->end) goto out; if (!next->sibling) break; if (next->sibling->start > new->end) break; } result = 0; new->parent = parent; new->sibling = next->sibling; new->child = first; next->sibling = NULL; for (next = first; next; next = next->sibling) next->parent = new; if (parent->child == first) { parent->child = new; } else { next = parent->child; while (next->sibling != first) next = next->sibling; next->sibling = new; } out: write_unlock(&resource_lock); return result;}/** * adjust_resource - modify a resource's start and size * @res: resource to modify * @start: new start value * @size: new size * * Given an existing resource, change its start and size to match the * arguments. Returns 0 on success, -EBUSY if it can't fit. * Existing children of the resource are assumed to be immutable. */int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size){ struct resource *tmp, *parent = res->parent; resource_size_t end = start + size - 1; int result = -EBUSY; write_lock(&resource_lock); if ((start < parent->start) || (end > parent->end)) goto out; for (tmp = res->child; tmp; tmp = tmp->sibling) { if ((tmp->start < start) || (tmp->end > end)) goto out; } if (res->sibling && (res->sibling->start <= end)) goto out; tmp = parent->child; if (tmp != res) { while (tmp->sibling != res) tmp = tmp->sibling; if (start <= tmp->end) goto out; } res->start = start; res->end = end; result = 0; out: write_unlock(&resource_lock); return result;}EXPORT_SYMBOL(adjust_resource);/* * This is compatibility stuff for IO resources. * * Note how this, unlike the above, knows about * the IO flag meanings (busy etc). * * request_region creates a new busy region. * * check_region returns non-zero if the area is already busy. * * release_region releases a matching busy region. *//** * __request_region - create a new busy resource region * @parent: parent resource descriptor * @start: resource start address * @n: resource region size * @name: reserving caller's ID string */struct resource * __request_region(struct resource *parent, resource_size_t start, resource_size_t n, const char *name){ struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); if (res) { res->name = name; res->start = start; res->end = start + n - 1; res->flags = IORESOURCE_BUSY; write_lock(&resource_lock); for (;;) { struct resource *conflict; conflict = __request_resource(parent, res); if (!conflict) break; if (conflict != parent) { parent = conflict; if (!(conflict->flags & IORESOURCE_BUSY)) continue; } /* Uhhuh, that didn't work out.. */ kfree(res); res = NULL; break; } write_unlock(&resource_lock); } return res;}EXPORT_SYMBOL(__request_region);/** * __check_region - check if a resource region is busy or free * @parent: parent resource descriptor * @start: resource start address * @n: resource region size * * Returns 0 if the region is free at the moment it is checked, * returns %-EBUSY if the region is busy. * * NOTE: * This function is deprecated because its use is racy. * Even if it returns 0, a subsequent call to request_region() * may fail because another driver etc. just allocated the region. * Do NOT use it. It will be removed from the kernel. */int __check_region(struct resource *parent, resource_size_t start, resource_size_t n){ struct resource * res; res = __request_region(parent, start, n, "check-region"); if (!res) return -EBUSY; release_resource(res); kfree(res); return 0;}EXPORT_SYMBOL(__check_region);/** * __release_region - release a previously reserved resource region * @parent: parent resource descriptor * @start: resource start address * @n: resource region size * * The described resource region must match a currently busy region. */void __release_region(struct resource *parent, resource_size_t start, resource_size_t n){ struct resource **p; resource_size_t end; p = &parent->child; end = start + n - 1; write_lock(&resource_lock); for (;;) { struct resource *res = *p; if (!res) break; if (res->start <= start && res->end >= end) { if (!(res->flags & IORESOURCE_BUSY)) { p = &res->child; continue; } if (res->start != start || res->end != end) break; *p = res->sibling; write_unlock(&resource_lock); kfree(res); return; } p = &res->sibling; } write_unlock(&resource_lock); printk(KERN_WARNING "Trying to free nonexistent resource " "<%016llx-%016llx>\n", (unsigned long long)start, (unsigned long long)end);}EXPORT_SYMBOL(__release_region);/* * Managed region resource */struct region_devres { struct resource *parent; resource_size_t start; resource_size_t n;};static void devm_region_release(struct device *dev, void *res){ struct region_devres *this = res; __release_region(this->parent, this->start, this->n);}static int devm_region_match(struct device *dev, void *res, void *match_data){ struct region_devres *this = res, *match = match_data; return this->parent == match->parent && this->start == match->start && this->n == match->n;}struct resource * __devm_request_region(struct device *dev, struct resource *parent, resource_size_t start, resource_size_t n, const char *name){ struct region_devres *dr = NULL; struct resource *res; dr = devres_alloc(devm_region_release, sizeof(struct region_devres), GFP_KERNEL); if (!dr) return NULL; dr->parent = parent; dr->start = start; dr->n = n; res = __request_region(parent, start, n, name); if (res) devres_add(dev, dr); else devres_free(dr); return res;}EXPORT_SYMBOL(__devm_request_region);void __devm_release_region(struct device *dev, struct resource *parent, resource_size_t start, resource_size_t n){ struct region_devres match_data = { parent, start, n }; __release_region(parent, start, n); WARN_ON(devres_destroy(dev, devm_region_release, devm_region_match, &match_data));}EXPORT_SYMBOL(__devm_release_region);/* * Called from init/main.c to reserve IO ports. */#define MAXRESERVE 4static int __init reserve_setup(char *str){ static int reserved; static struct resource reserve[MAXRESERVE]; for (;;) { int io_start, io_num; int x = reserved; if (get_option (&str, &io_start) != 2) break; if (get_option (&str, &io_num) == 0) break; if (x < MAXRESERVE) { struct resource *res = reserve + x; res->name = "reserved"; res->start = io_start; res->end = io_start + io_num - 1; res->flags = IORESOURCE_BUSY; res->child = NULL; if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0) reserved = x+1; } } return 1;}__setup("reserve=", reserve_setup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -