x86: split e820 reserved entries record to late v4 - fix v6
PATCH 1/1 x86: split e820 reserved entries record to late v4 - fix v6
try to insert_resource second time, by expand the resource...
for case: e820 reserved entry is partially overlapped with bar res...
hope it will never happen
v2: according to Linus, add insert_resource_expand_to_fit, and change
__insert_resource to static without lock
v3: use reserve_region_with_split() instead to hand overlapping
with test case by extend 0xe0000000 - 0xeffffff to 0xdd800000 - get e0000000-efffffff : PCI MMCONFIG 0 e0000000-efffffff : reserved in /proc/iomem 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
v4: take out __insert_resource and insert_resource_expand_to_fit : Linus already check in.
use reserve_region_with_split at the first point
use const char *name
v5: fix checking on overlapping
v6: only reserve common area in conflict
so got sth in /proc/iomem d8000000-dfffffff : PCI Bus #00 dc000000-dfffffff : GART dc000000-dfffffff : reserved e0000000-efffffff : PCI MMCONFIG 0 e0000000-efffffff : reserved when we have big range in e820 00000000dc000000-00000000f0000000 (reserved)
--- arch/x86/kernel/e820.c | 2 - include/linux/ioport.h | 3 ++ kernel/resource.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-)
arch/x86/kernel/e820.c +1 -1
@@ -1320,7 +1320,7 @@ void __init e820_reserve_resources_late( res = e820_res;for (i =0 ; i < e820.nr_map; i++) {if (!res->parent && res->end) -insert_resource (&iomem_resource, res); +reserve_region_with_split (&iomem_resource, res->start, res->end, res->name); res++; } }
include/linux/ioport.h +3 -0
@@ -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,
kernel/resource.c +68 -1
78 lines not on this page · raw message
Adding to : Ivan..
Quoted 157 lines · Yinghai Lu
try to
insert_resourcesecond time, by expand the resource...for case: e820 reserved entry is partially overlapped with bar res...
hope it will never happen
v2: according to Linus, add
insert_resource_expand_to_fit, and change
__insert_resourceto static without lockv3: use
reserve_region_with_split()instead to hand overlappingwith test case by extend 0xe0000000 - 0xeffffff to 0xdd800000 - get e0000000-efffffff : PCI MMCONFIG 0 e0000000-efffffff : reserved in /proc/iomem 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 dmesgv4: take out
__insert_resourceandinsert_resource_expand_to_fit: Linus already check in.
usereserve_region_with_splitat the first point
use const char *namev5: fix checking on overlapping
v6: only reserve common area in conflict
so got sth in /proc/iomem d8000000-dfffffff : PCI Bus #00 dc000000-dfffffff : GART dc000000-dfffffff : reserved e0000000-efffffff : PCI MMCONFIG 0 e0000000-efffffff : reserved when we have big range in e820 00000000dc000000-00000000f0000000 (reserved)Signed-off-by Yinghai Lu <[email protected]>--- arch/x86/kernel/e820.c | 2 - include/linux/ioport.h | 3 ++ kernel/resource.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-)Index:
linux-2.6/arch/x86/kernel/e820.c
===================================================================arch/x86/kernel/e820.c +1
-1@@ -1320,7 +1320,7 @@ void __init e820_reserve_resources_late( res = e820_res;for (i =0 ; i < e820.nr_map; i++) {if (!res->parent && res->end) -insert_resource (&iomem_resource, res); +reserve_region_with_split (&iomem_resource, res->start, res->end, res->name); res++; } }Index:
linux-2.6/include/linux/ioport.h
===================================================================include/linux/ioport.h +3
-0@@ -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,Index:
linux-2.6/kernel/resource.c
===================================================================kernel/resource.c +68
-1@@ -512,10 +512,77 @@ int adjust_resource(struct resource *res result =0 ; out: -write_unlock (&resource_lock);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);/**