Commit 268364a0f48aee2f851f9d1ef8a6cda0f3039ef1

Authored by Yinghai Lu
Committed by Ingo Molnar
1 parent d210baf53b

IO resources: add reserve_region_with_split()

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>

Showing 2 changed files with 71 additions and 0 deletions Side-by-side Diff

include/linux/ioport.h
... ... @@ -108,6 +108,9 @@
108 108  
109 109 extern int request_resource(struct resource *root, struct resource *new);
110 110 extern int release_resource(struct resource *new);
  111 +extern void reserve_region_with_split(struct resource *root,
  112 + resource_size_t start, resource_size_t end,
  113 + const char *name);
111 114 extern int insert_resource(struct resource *parent, struct resource *new);
112 115 extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new);
113 116 extern int allocate_resource(struct resource *root, struct resource *new,
... ... @@ -516,6 +516,74 @@
516 516 return result;
517 517 }
518 518  
  519 +static void __init __reserve_region_with_split(struct resource *root,
  520 + resource_size_t start, resource_size_t end,
  521 + const char *name)
  522 +{
  523 + struct resource *parent = root;
  524 + struct resource *conflict;
  525 + struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
  526 +
  527 + if (!res)
  528 + return;
  529 +
  530 + res->name = name;
  531 + res->start = start;
  532 + res->end = end;
  533 + res->flags = IORESOURCE_BUSY;
  534 +
  535 + for (;;) {
  536 + conflict = __request_resource(parent, res);
  537 + if (!conflict)
  538 + break;
  539 + if (conflict != parent) {
  540 + parent = conflict;
  541 + if (!(conflict->flags & IORESOURCE_BUSY))
  542 + continue;
  543 + }
  544 +
  545 + /* Uhhuh, that didn't work out.. */
  546 + kfree(res);
  547 + res = NULL;
  548 + break;
  549 + }
  550 +
  551 + if (!res) {
  552 + printk(KERN_DEBUG " __reserve_region_with_split: (%s) [%llx, %llx], res: (%s) [%llx, %llx]\n",
  553 + conflict->name, conflict->start, conflict->end,
  554 + name, start, end);
  555 +
  556 + /* failed, split and try again */
  557 +
  558 + /* conflict coverred whole area */
  559 + if (conflict->start <= start && conflict->end >= end)
  560 + return;
  561 +
  562 + if (conflict->start > start)
  563 + __reserve_region_with_split(root, start, conflict->start-1, name);
  564 + if (!(conflict->flags & IORESOURCE_BUSY)) {
  565 + resource_size_t common_start, common_end;
  566 +
  567 + common_start = max(conflict->start, start);
  568 + common_end = min(conflict->end, end);
  569 + if (common_start < common_end)
  570 + __reserve_region_with_split(root, common_start, common_end, name);
  571 + }
  572 + if (conflict->end < end)
  573 + __reserve_region_with_split(root, conflict->end+1, end, name);
  574 + }
  575 +
  576 +}
  577 +
  578 +void reserve_region_with_split(struct resource *root,
  579 + resource_size_t start, resource_size_t end,
  580 + const char *name)
  581 +{
  582 + write_lock(&resource_lock);
  583 + __reserve_region_with_split(root, start, end, name);
  584 + write_unlock(&resource_lock);
  585 +}
  586 +
519 587 EXPORT_SYMBOL(adjust_resource);
520 588  
521 589 /**