aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci/acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/pci/acpi.c')
-rw-r--r--arch/x86/pci/acpi.c70
1 files changed, 40 insertions, 30 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index c0ecf250fe51..1014eb4bfc37 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -38,15 +38,26 @@ count_resource(struct acpi_resource *acpi_res, void *data)
38 struct acpi_resource_address64 addr; 38 struct acpi_resource_address64 addr;
39 acpi_status status; 39 acpi_status status;
40 40
41 if (info->res_num >= PCI_BUS_NUM_RESOURCES)
42 return AE_OK;
43
44 status = resource_to_addr(acpi_res, &addr); 41 status = resource_to_addr(acpi_res, &addr);
45 if (ACPI_SUCCESS(status)) 42 if (ACPI_SUCCESS(status))
46 info->res_num++; 43 info->res_num++;
47 return AE_OK; 44 return AE_OK;
48} 45}
49 46
47static int
48bus_has_transparent_bridge(struct pci_bus *bus)
49{
50 struct pci_dev *dev;
51
52 list_for_each_entry(dev, &bus->devices, bus_list) {
53 u16 class = dev->class >> 8;
54
55 if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent)
56 return true;
57 }
58 return false;
59}
60
50static acpi_status 61static acpi_status
51setup_resource(struct acpi_resource *acpi_res, void *data) 62setup_resource(struct acpi_resource *acpi_res, void *data)
52{ 63{
@@ -56,9 +67,11 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
56 acpi_status status; 67 acpi_status status;
57 unsigned long flags; 68 unsigned long flags;
58 struct resource *root; 69 struct resource *root;
70 int max_root_bus_resources = PCI_BUS_NUM_RESOURCES;
71 u64 start, end;
59 72
60 if (info->res_num >= PCI_BUS_NUM_RESOURCES) 73 if (bus_has_transparent_bridge(info->bus))
61 return AE_OK; 74 max_root_bus_resources -= 3;
62 75
63 status = resource_to_addr(acpi_res, &addr); 76 status = resource_to_addr(acpi_res, &addr);
64 if (!ACPI_SUCCESS(status)) 77 if (!ACPI_SUCCESS(status))
@@ -75,11 +88,22 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
75 } else 88 } else
76 return AE_OK; 89 return AE_OK;
77 90
91 start = addr.minimum + addr.translation_offset;
92 end = start + addr.address_length - 1;
93 if (info->res_num >= max_root_bus_resources) {
94 printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx "
95 "from %s for %s due to _CRS returning more than "
96 "%d resource descriptors\n", (unsigned long) start,
97 (unsigned long) end, root->name, info->name,
98 max_root_bus_resources);
99 return AE_OK;
100 }
101
78 res = &info->res[info->res_num]; 102 res = &info->res[info->res_num];
79 res->name = info->name; 103 res->name = info->name;
80 res->flags = flags; 104 res->flags = flags;
81 res->start = addr.minimum + addr.translation_offset; 105 res->start = start;
82 res->end = res->start + addr.address_length - 1; 106 res->end = end;
83 res->child = NULL; 107 res->child = NULL;
84 108
85 if (insert_resource(root, res)) { 109 if (insert_resource(root, res)) {
@@ -94,23 +118,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
94} 118}
95 119
96static void 120static void
97adjust_transparent_bridge_resources(struct pci_bus *bus)
98{
99 struct pci_dev *dev;
100
101 list_for_each_entry(dev, &bus->devices, bus_list) {
102 int i;
103 u16 class = dev->class >> 8;
104
105 if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) {
106 for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
107 dev->subordinate->resource[i] =
108 dev->bus->resource[i - 3];
109 }
110 }
111}
112
113static void
114get_current_resources(struct acpi_device *device, int busnum, 121get_current_resources(struct acpi_device *device, int busnum,
115 int domain, struct pci_bus *bus) 122 int domain, struct pci_bus *bus)
116{ 123{
@@ -137,8 +144,6 @@ get_current_resources(struct acpi_device *device, int busnum,
137 info.res_num = 0; 144 info.res_num = 0;
138 acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, 145 acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
139 &info); 146 &info);
140 if (info.res_num)
141 adjust_transparent_bridge_resources(bus);
142 147
143 return; 148 return;
144 149
@@ -201,8 +206,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
201 */ 206 */
202 memcpy(bus->sysdata, sd, sizeof(*sd)); 207 memcpy(bus->sysdata, sd, sizeof(*sd));
203 kfree(sd); 208 kfree(sd);
204 } else 209 } else {
205 bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); 210 bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
211 if (bus) {
212 if (pci_probe & PCI_USE__CRS)
213 get_current_resources(device, busnum, domain,
214 bus);
215 bus->subordinate = pci_scan_child_bus(bus);
216 }
217 }
206 218
207 if (!bus) 219 if (!bus)
208 kfree(sd); 220 kfree(sd);
@@ -217,8 +229,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
217#endif 229#endif
218 } 230 }
219 231
220 if (bus && (pci_probe & PCI_USE__CRS))
221 get_current_resources(device, busnum, domain, bus);
222 return bus; 232 return bus;
223} 233}
224 234