diff options
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 129 |
1 files changed, 104 insertions, 25 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3f07cb6bae32..3539171d8a98 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -61,6 +61,63 @@ static struct pci_host_bridge *pci_host_bridge(struct pci_dev *dev) | |||
61 | return NULL; | 61 | return NULL; |
62 | } | 62 | } |
63 | 63 | ||
64 | static bool resource_contains(struct resource *res1, struct resource *res2) | ||
65 | { | ||
66 | return res1->start <= res2->start && res1->end >= res2->end; | ||
67 | } | ||
68 | |||
69 | void pci_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, | ||
70 | struct resource *res) | ||
71 | { | ||
72 | struct pci_host_bridge *bridge = pci_host_bridge(dev); | ||
73 | struct pci_host_bridge_window *window; | ||
74 | resource_size_t offset = 0; | ||
75 | |||
76 | list_for_each_entry(window, &bridge->windows, list) { | ||
77 | if (resource_type(res) != resource_type(window->res)) | ||
78 | continue; | ||
79 | |||
80 | if (resource_contains(window->res, res)) { | ||
81 | offset = window->offset; | ||
82 | break; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | region->start = res->start - offset; | ||
87 | region->end = res->end - offset; | ||
88 | } | ||
89 | |||
90 | static bool region_contains(struct pci_bus_region *region1, | ||
91 | struct pci_bus_region *region2) | ||
92 | { | ||
93 | return region1->start <= region2->start && region1->end >= region2->end; | ||
94 | } | ||
95 | |||
96 | void pci_bus_to_resource(struct pci_dev *dev, struct resource *res, | ||
97 | struct pci_bus_region *region) | ||
98 | { | ||
99 | struct pci_host_bridge *bridge = pci_host_bridge(dev); | ||
100 | struct pci_host_bridge_window *window; | ||
101 | struct pci_bus_region bus_region; | ||
102 | resource_size_t offset = 0; | ||
103 | |||
104 | list_for_each_entry(window, &bridge->windows, list) { | ||
105 | if (resource_type(res) != resource_type(window->res)) | ||
106 | continue; | ||
107 | |||
108 | bus_region.start = window->res->start - window->offset; | ||
109 | bus_region.end = window->res->end - window->offset; | ||
110 | |||
111 | if (region_contains(&bus_region, region)) { | ||
112 | offset = window->offset; | ||
113 | break; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | res->start = region->start + offset; | ||
118 | res->end = region->end + offset; | ||
119 | } | ||
120 | |||
64 | /* | 121 | /* |
65 | * PCI Bus Class | 122 | * PCI Bus Class |
66 | */ | 123 | */ |
@@ -154,6 +211,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
154 | { | 211 | { |
155 | u32 l, sz, mask; | 212 | u32 l, sz, mask; |
156 | u16 orig_cmd; | 213 | u16 orig_cmd; |
214 | struct pci_bus_region region; | ||
157 | 215 | ||
158 | mask = type ? PCI_ROM_ADDRESS_MASK : ~0; | 216 | mask = type ? PCI_ROM_ADDRESS_MASK : ~0; |
159 | 217 | ||
@@ -233,11 +291,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
233 | /* Address above 32-bit boundary; disable the BAR */ | 291 | /* Address above 32-bit boundary; disable the BAR */ |
234 | pci_write_config_dword(dev, pos, 0); | 292 | pci_write_config_dword(dev, pos, 0); |
235 | pci_write_config_dword(dev, pos + 4, 0); | 293 | pci_write_config_dword(dev, pos + 4, 0); |
236 | res->start = 0; | 294 | region.start = 0; |
237 | res->end = sz64; | 295 | region.end = sz64; |
296 | pci_bus_to_resource(dev, res, ®ion); | ||
238 | } else { | 297 | } else { |
239 | res->start = l64; | 298 | region.start = l64; |
240 | res->end = l64 + sz64; | 299 | region.end = l64 + sz64; |
300 | pci_bus_to_resource(dev, res, ®ion); | ||
241 | dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", | 301 | dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", |
242 | pos, res); | 302 | pos, res); |
243 | } | 303 | } |
@@ -247,8 +307,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
247 | if (!sz) | 307 | if (!sz) |
248 | goto fail; | 308 | goto fail; |
249 | 309 | ||
250 | res->start = l; | 310 | region.start = l; |
251 | res->end = l + sz; | 311 | region.end = l + sz; |
312 | pci_bus_to_resource(dev, res, ®ion); | ||
252 | 313 | ||
253 | dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); | 314 | dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); |
254 | } | 315 | } |
@@ -285,7 +346,8 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) | |||
285 | struct pci_dev *dev = child->self; | 346 | struct pci_dev *dev = child->self; |
286 | u8 io_base_lo, io_limit_lo; | 347 | u8 io_base_lo, io_limit_lo; |
287 | unsigned long base, limit; | 348 | unsigned long base, limit; |
288 | struct resource *res; | 349 | struct pci_bus_region region; |
350 | struct resource *res, res2; | ||
289 | 351 | ||
290 | res = child->resource[0]; | 352 | res = child->resource[0]; |
291 | pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); | 353 | pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); |
@@ -303,10 +365,13 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) | |||
303 | 365 | ||
304 | if (base && base <= limit) { | 366 | if (base && base <= limit) { |
305 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; | 367 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; |
368 | region.start = base; | ||
369 | region.end = limit + 0xfff; | ||
370 | pci_bus_to_resource(dev, &res2, ®ion); | ||
306 | if (!res->start) | 371 | if (!res->start) |
307 | res->start = base; | 372 | res->start = res2.start; |
308 | if (!res->end) | 373 | if (!res->end) |
309 | res->end = limit + 0xfff; | 374 | res->end = res2.end; |
310 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); | 375 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); |
311 | } | 376 | } |
312 | } | 377 | } |
@@ -316,6 +381,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child) | |||
316 | struct pci_dev *dev = child->self; | 381 | struct pci_dev *dev = child->self; |
317 | u16 mem_base_lo, mem_limit_lo; | 382 | u16 mem_base_lo, mem_limit_lo; |
318 | unsigned long base, limit; | 383 | unsigned long base, limit; |
384 | struct pci_bus_region region; | ||
319 | struct resource *res; | 385 | struct resource *res; |
320 | 386 | ||
321 | res = child->resource[1]; | 387 | res = child->resource[1]; |
@@ -325,8 +391,9 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child) | |||
325 | limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; | 391 | limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; |
326 | if (base && base <= limit) { | 392 | if (base && base <= limit) { |
327 | res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; | 393 | res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; |
328 | res->start = base; | 394 | region.start = base; |
329 | res->end = limit + 0xfffff; | 395 | region.end = limit + 0xfffff; |
396 | pci_bus_to_resource(dev, res, ®ion); | ||
330 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); | 397 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); |
331 | } | 398 | } |
332 | } | 399 | } |
@@ -336,6 +403,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) | |||
336 | struct pci_dev *dev = child->self; | 403 | struct pci_dev *dev = child->self; |
337 | u16 mem_base_lo, mem_limit_lo; | 404 | u16 mem_base_lo, mem_limit_lo; |
338 | unsigned long base, limit; | 405 | unsigned long base, limit; |
406 | struct pci_bus_region region; | ||
339 | struct resource *res; | 407 | struct resource *res; |
340 | 408 | ||
341 | res = child->resource[2]; | 409 | res = child->resource[2]; |
@@ -372,8 +440,9 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) | |||
372 | IORESOURCE_MEM | IORESOURCE_PREFETCH; | 440 | IORESOURCE_MEM | IORESOURCE_PREFETCH; |
373 | if (res->flags & PCI_PREF_RANGE_TYPE_64) | 441 | if (res->flags & PCI_PREF_RANGE_TYPE_64) |
374 | res->flags |= IORESOURCE_MEM_64; | 442 | res->flags |= IORESOURCE_MEM_64; |
375 | res->start = base; | 443 | region.start = base; |
376 | res->end = limit + 0xfffff; | 444 | region.end = limit + 0xfffff; |
445 | pci_bus_to_resource(dev, res, ®ion); | ||
377 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); | 446 | dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); |
378 | } | 447 | } |
379 | } | 448 | } |
@@ -919,6 +988,8 @@ int pci_setup_device(struct pci_dev *dev) | |||
919 | u8 hdr_type; | 988 | u8 hdr_type; |
920 | struct pci_slot *slot; | 989 | struct pci_slot *slot; |
921 | int pos = 0; | 990 | int pos = 0; |
991 | struct pci_bus_region region; | ||
992 | struct resource *res; | ||
922 | 993 | ||
923 | if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) | 994 | if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) |
924 | return -EIO; | 995 | return -EIO; |
@@ -980,20 +1051,28 @@ int pci_setup_device(struct pci_dev *dev) | |||
980 | u8 progif; | 1051 | u8 progif; |
981 | pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); | 1052 | pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); |
982 | if ((progif & 1) == 0) { | 1053 | if ((progif & 1) == 0) { |
983 | dev->resource[0].start = 0x1F0; | 1054 | region.start = 0x1F0; |
984 | dev->resource[0].end = 0x1F7; | 1055 | region.end = 0x1F7; |
985 | dev->resource[0].flags = LEGACY_IO_RESOURCE; | 1056 | res = &dev->resource[0]; |
986 | dev->resource[1].start = 0x3F6; | 1057 | res->flags = LEGACY_IO_RESOURCE; |
987 | dev->resource[1].end = 0x3F6; | 1058 | pci_bus_to_resource(dev, res, ®ion); |
988 | dev->resource[1].flags = LEGACY_IO_RESOURCE; | 1059 | region.start = 0x3F6; |
1060 | region.end = 0x3F6; | ||
1061 | res = &dev->resource[1]; | ||
1062 | res->flags = LEGACY_IO_RESOURCE; | ||
1063 | pci_bus_to_resource(dev, res, ®ion); | ||
989 | } | 1064 | } |
990 | if ((progif & 4) == 0) { | 1065 | if ((progif & 4) == 0) { |
991 | dev->resource[2].start = 0x170; | 1066 | region.start = 0x170; |
992 | dev->resource[2].end = 0x177; | 1067 | region.end = 0x177; |
993 | dev->resource[2].flags = LEGACY_IO_RESOURCE; | 1068 | res = &dev->resource[2]; |
994 | dev->resource[3].start = 0x376; | 1069 | res->flags = LEGACY_IO_RESOURCE; |
995 | dev->resource[3].end = 0x376; | 1070 | pci_bus_to_resource(dev, res, ®ion); |
996 | dev->resource[3].flags = LEGACY_IO_RESOURCE; | 1071 | region.start = 0x376; |
1072 | region.end = 0x376; | ||
1073 | res = &dev->resource[3]; | ||
1074 | res->flags = LEGACY_IO_RESOURCE; | ||
1075 | pci_bus_to_resource(dev, res, ®ion); | ||
997 | } | 1076 | } |
998 | } | 1077 | } |
999 | break; | 1078 | break; |