From e8ee6f0ae5cd860e8e6c02807edfa3c1fa01bcb5 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 13 Apr 2008 01:41:58 -0700 Subject: x86: work around io allocation overlap of HT links normally BIOSes assign io/mmio range to different HT links without overlapping, even same node same link should get non overlapping entries. but Rafael L. Wysocki's buggy BIOS creates a link with overlapping entries for mmio and io: node 0 link 0: io port [1000, ffffff] node 0 link 0: mmio [e0000000, efffffff] node 0 link 0: mmio [a0000, bffff] node 0 link 0: mmio [80000000, ffffffff] try to merge them and we will get: bus: [00, ff] on node 0 link 0 bus: 00 index 0 io port: [0, ffff] bus: 00 index 1 mmio: [80000000, fcffffffff] bus: 00 index 2 mmio: [a0000, bffff] so later we will reduce the chance to assign used resource to unassigned device. Reported-by: "Rafael J. Wysocki" Signed-off-by: Yinghai Lu Tested-by: "Rafael J. Wysocki" Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/pci/k8-bus_64.c | 56 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 18 deletions(-) (limited to 'arch/x86/pci') diff --git a/arch/x86/pci/k8-bus_64.c b/arch/x86/pci/k8-bus_64.c index 4e64c58e17a0..ab6d4b18a88f 100644 --- a/arch/x86/pci/k8-bus_64.c +++ b/arch/x86/pci/k8-bus_64.c @@ -112,17 +112,25 @@ static void __init update_range(struct res_range *range, size_t start, for (j = 0; j < RANGE_NUM; j++) { if (!range[j].end) continue; - if (start == range[j].start && end < range[j].end) { - range[j].start = end + 1; - break; - } else if (start == range[j].start && end == range[j].end) { + + if (start <= range[j].start && end >= range[j].end) { range[j].start = 0; range[j].end = 0; - break; - } else if (start > range[j].start && end == range[j].end) { + continue; + } + + if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) { + range[j].start = end + 1; + continue; + } + + + if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) { range[j].end = start - 1; - break; - } else if (start > range[j].start && end < range[j].end) { + continue; + } + + if (start > range[j].start && end < range[j].end) { /* find the new spare */ for (i = 0; i < RANGE_NUM; i++) { if (range[i].end == 0) @@ -135,7 +143,7 @@ static void __init update_range(struct res_range *range, size_t start, printk(KERN_ERR "run of slot in ranges\n"); } range[j].end = start - 1; - break; + continue; } } } @@ -151,16 +159,24 @@ static void __init update_res(struct pci_root_info *info, size_t start, /* try to merge it with old one */ for (i = 0; i < info->res_num; i++) { + size_t final_start, final_end; + size_t common_start, common_end; + res = &info->res[i]; if (res->flags != flags) continue; - if (res->end + 1 == start) { - res->end = end; - return; - } else if (end + 1 == res->start) { - res->start = start; - return; - } + + common_start = max((size_t)res->start, start); + common_end = min((size_t)res->end, end); + if (common_start > common_end + 1) + continue; + + final_start = min((size_t)res->start, start); + final_end = max((size_t)res->end, end); + + res->start = final_start; + res->end = final_end; + return; } addit: @@ -336,7 +352,11 @@ static int __init early_fill_mp_bus_info(void) info = &pci_root_info[j]; printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", node, link, (u64)start, (u64)end); - update_res(info, start, end, IORESOURCE_IO, 0); + + /* kernel only handle 16 bit only */ + if (end > 0xffff) + end = 0xffff; + update_res(info, start, end, IORESOURCE_IO, 1); update_range(range, start, end); } /* add left over io port range to def node/link, [0, 0xffff] */ @@ -444,7 +464,7 @@ static int __init early_fill_mp_bus_info(void) } } - update_res(info, start, end, IORESOURCE_MEM, 0); + update_res(info, start, end, IORESOURCE_MEM, 1); update_range(range, start, end); printk(KERN_CONT "\n"); } -- cgit v1.2.3