Commit 268364a0f48aee2f851f9d1ef8a6cda0f3039ef1
Committed by
Ingo Molnar
1 parent
d210baf53b
Exists in
master
and in
4 other branches
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, |
kernel/resource.c
... | ... | @@ -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 | /** |