aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-04-13 04:41:58 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-26 17:41:04 -0400
commite8ee6f0ae5cd860e8e6c02807edfa3c1fa01bcb5 (patch)
tree800e742a999207617506a9475dc40e3c6234d11a /arch/x86/pci
parentcbf9bd603ab1fc4d2ecb1c6a4b7bd1cc50a7e82a (diff)
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" <rjw@sisk.pl> Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> Tested-by: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/pci')
-rw-r--r--arch/x86/pci/k8-bus_64.c56
1 files changed, 38 insertions, 18 deletions
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,
112 for (j = 0; j < RANGE_NUM; j++) { 112 for (j = 0; j < RANGE_NUM; j++) {
113 if (!range[j].end) 113 if (!range[j].end)
114 continue; 114 continue;
115 if (start == range[j].start && end < range[j].end) { 115
116 range[j].start = end + 1; 116 if (start <= range[j].start && end >= range[j].end) {
117 break;
118 } else if (start == range[j].start && end == range[j].end) {
119 range[j].start = 0; 117 range[j].start = 0;
120 range[j].end = 0; 118 range[j].end = 0;
121 break; 119 continue;
122 } else if (start > range[j].start && end == range[j].end) { 120 }
121
122 if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) {
123 range[j].start = end + 1;
124 continue;
125 }
126
127
128 if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) {
123 range[j].end = start - 1; 129 range[j].end = start - 1;
124 break; 130 continue;
125 } else if (start > range[j].start && end < range[j].end) { 131 }
132
133 if (start > range[j].start && end < range[j].end) {
126 /* find the new spare */ 134 /* find the new spare */
127 for (i = 0; i < RANGE_NUM; i++) { 135 for (i = 0; i < RANGE_NUM; i++) {
128 if (range[i].end == 0) 136 if (range[i].end == 0)
@@ -135,7 +143,7 @@ static void __init update_range(struct res_range *range, size_t start,
135 printk(KERN_ERR "run of slot in ranges\n"); 143 printk(KERN_ERR "run of slot in ranges\n");
136 } 144 }
137 range[j].end = start - 1; 145 range[j].end = start - 1;
138 break; 146 continue;
139 } 147 }
140 } 148 }
141} 149}
@@ -151,16 +159,24 @@ static void __init update_res(struct pci_root_info *info, size_t start,
151 159
152 /* try to merge it with old one */ 160 /* try to merge it with old one */
153 for (i = 0; i < info->res_num; i++) { 161 for (i = 0; i < info->res_num; i++) {
162 size_t final_start, final_end;
163 size_t common_start, common_end;
164
154 res = &info->res[i]; 165 res = &info->res[i];
155 if (res->flags != flags) 166 if (res->flags != flags)
156 continue; 167 continue;
157 if (res->end + 1 == start) { 168
158 res->end = end; 169 common_start = max((size_t)res->start, start);
159 return; 170 common_end = min((size_t)res->end, end);
160 } else if (end + 1 == res->start) { 171 if (common_start > common_end + 1)
161 res->start = start; 172 continue;
162 return; 173
163 } 174 final_start = min((size_t)res->start, start);
175 final_end = max((size_t)res->end, end);
176
177 res->start = final_start;
178 res->end = final_end;
179 return;
164 } 180 }
165 181
166addit: 182addit:
@@ -336,7 +352,11 @@ static int __init early_fill_mp_bus_info(void)
336 info = &pci_root_info[j]; 352 info = &pci_root_info[j];
337 printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", 353 printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n",
338 node, link, (u64)start, (u64)end); 354 node, link, (u64)start, (u64)end);
339 update_res(info, start, end, IORESOURCE_IO, 0); 355
356 /* kernel only handle 16 bit only */
357 if (end > 0xffff)
358 end = 0xffff;
359 update_res(info, start, end, IORESOURCE_IO, 1);
340 update_range(range, start, end); 360 update_range(range, start, end);
341 } 361 }
342 /* add left over io port range to def node/link, [0, 0xffff] */ 362 /* 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)
444 } 464 }
445 } 465 }
446 466
447 update_res(info, start, end, IORESOURCE_MEM, 0); 467 update_res(info, start, end, IORESOURCE_MEM, 1);
448 update_range(range, start, end); 468 update_range(range, start, end);
449 printk(KERN_CONT "\n"); 469 printk(KERN_CONT "\n");
450 } 470 }