Skip to content

Commit

Permalink
IO resources: add reserve_region_with_split()
Browse files Browse the repository at this point in the history
add reserve_region_with_split() to not lose e820 reserved entries if
they overlap with existing IO regions:

with test case by extend 0xe0000000 - 0xeffffff to 0xdd800000 -
we get:
	e0000000-efffffff : PCI MMCONFIG 0
		 e0000000-efffffff : reserved

and in /proc/iomem we get:
	found conflict for reserved [dd800000, efffffff], try to reserve with split
	    __reserve_region_with_split: (PCI Bus #80) [dd000000, ddffffff], res: (reserved) [dd800000, efffffff]
	    __reserve_region_with_split: (PCI Bus #00) [de000000, dfffffff], res: (reserved) [de000000, efffffff]
	initcall pci_subsys_init+0x0/0x121 returned 0 after 381 msecs
in dmesg

various fixes and improvements suggested by Linus.

Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Yinghai Lu authored and Ingo Molnar committed Sep 4, 2008
1 parent d210baf commit 268364a
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/linux/ioport.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ extern struct resource iomem_resource;

extern int request_resource(struct resource *root, struct resource *new);
extern int release_resource(struct resource *new);
extern void reserve_region_with_split(struct resource *root,
resource_size_t start, resource_size_t end,
const char *name);
extern int insert_resource(struct resource *parent, struct resource *new);
extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
extern int allocate_resource(struct resource *root, struct resource *new,
Expand Down
68 changes: 68 additions & 0 deletions kernel/resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,74 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
return result;
}

static void __init __reserve_region_with_split(struct resource *root,
resource_size_t start, resource_size_t end,
const char *name)
{
struct resource *parent = root;
struct resource *conflict;
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);

if (!res)
return;

res->name = name;
res->start = start;
res->end = end;
res->flags = IORESOURCE_BUSY;

for (;;) {
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;
}

if (!res) {
printk(KERN_DEBUG " __reserve_region_with_split: (%s) [%llx, %llx], res: (%s) [%llx, %llx]\n",
conflict->name, conflict->start, conflict->end,
name, start, end);

/* failed, split and try again */

/* conflict coverred whole area */
if (conflict->start <= start && conflict->end >= end)
return;

if (conflict->start > start)
__reserve_region_with_split(root, start, conflict->start-1, name);
if (!(conflict->flags & IORESOURCE_BUSY)) {
resource_size_t common_start, common_end;

common_start = max(conflict->start, start);
common_end = min(conflict->end, end);
if (common_start < common_end)
__reserve_region_with_split(root, common_start, common_end, name);
}
if (conflict->end < end)
__reserve_region_with_split(root, conflict->end+1, end, name);
}

}

void reserve_region_with_split(struct resource *root,
resource_size_t start, resource_size_t end,
const char *name)
{
write_lock(&resource_lock);
__reserve_region_with_split(root, start, end, name);
write_unlock(&resource_lock);
}

EXPORT_SYMBOL(adjust_resource);

/**
Expand Down

0 comments on commit 268364a

Please sign in to comment.