diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-10-25 17:55:31 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-10-25 17:55:31 -0400 |
commit | ba210f5de42f4604730ffaea96bfb6e591740bde (patch) | |
tree | ed8e64cefdf21fc5339ee1b9fa9355c094ef5752 | |
parent | e3ed766b4958bf7889539f09aec3f6a72d2c4dd2 (diff) | |
parent | 02715e86b21955f107f376d84d165424ba9cd372 (diff) |
Merge branch 'acpi-pci'
* acpi-pci:
ia64/PCI/ACPI: Use common interface to support PCI host bridge
x86/PCI/ACPI: Use common interface to support PCI host bridge
ACPI/PCI: Reset acpi_root_dev->domain to 0 when pci_ignore_seg is set
PCI/ACPI: Add interface acpi_pci_root_create()
ia64/PCI: Use common struct resource_entry to replace struct iospace_resource
ia64/PCI/ACPI: Use common ACPI resource parsing interface for host bridge
ACPI/PCI: Enhance ACPI core to support sparse IO space
-rw-r--r-- | arch/ia64/include/asm/pci.h | 5 | ||||
-rw-r--r-- | arch/ia64/pci/pci.c | 368 | ||||
-rw-r--r-- | arch/x86/pci/acpi.c | 296 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 204 | ||||
-rw-r--r-- | drivers/acpi/resource.c | 9 | ||||
-rw-r--r-- | include/linux/ioport.h | 1 | ||||
-rw-r--r-- | include/linux/pci-acpi.h | 24 |
7 files changed, 423 insertions, 484 deletions
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h index 36d2c1e3928b..07039d168f37 100644 --- a/arch/ia64/include/asm/pci.h +++ b/arch/ia64/include/asm/pci.h | |||
@@ -64,11 +64,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus, | |||
64 | #define pci_legacy_read platform_pci_legacy_read | 64 | #define pci_legacy_read platform_pci_legacy_read |
65 | #define pci_legacy_write platform_pci_legacy_write | 65 | #define pci_legacy_write platform_pci_legacy_write |
66 | 66 | ||
67 | struct iospace_resource { | ||
68 | struct list_head list; | ||
69 | struct resource res; | ||
70 | }; | ||
71 | |||
72 | struct pci_controller { | 67 | struct pci_controller { |
73 | struct acpi_device *companion; | 68 | struct acpi_device *companion; |
74 | void *iommu; | 69 | void *iommu; |
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 7cc3be9fa7c6..8f6ac2f8ae4c 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -115,33 +115,13 @@ struct pci_ops pci_root_ops = { | |||
115 | .write = pci_write, | 115 | .write = pci_write, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | /* Called by ACPI when it finds a new root bus. */ | ||
119 | |||
120 | static struct pci_controller *alloc_pci_controller(int seg) | ||
121 | { | ||
122 | struct pci_controller *controller; | ||
123 | |||
124 | controller = kzalloc(sizeof(*controller), GFP_KERNEL); | ||
125 | if (!controller) | ||
126 | return NULL; | ||
127 | |||
128 | controller->segment = seg; | ||
129 | return controller; | ||
130 | } | ||
131 | |||
132 | struct pci_root_info { | 118 | struct pci_root_info { |
133 | struct acpi_device *bridge; | 119 | struct acpi_pci_root_info common; |
134 | struct pci_controller *controller; | 120 | struct pci_controller controller; |
135 | struct list_head resources; | ||
136 | struct resource *res; | ||
137 | resource_size_t *res_offset; | ||
138 | unsigned int res_num; | ||
139 | struct list_head io_resources; | 121 | struct list_head io_resources; |
140 | char *name; | ||
141 | }; | 122 | }; |
142 | 123 | ||
143 | static unsigned int | 124 | static unsigned int new_space(u64 phys_base, int sparse) |
144 | new_space (u64 phys_base, int sparse) | ||
145 | { | 125 | { |
146 | u64 mmio_base; | 126 | u64 mmio_base; |
147 | int i; | 127 | int i; |
@@ -168,39 +148,36 @@ new_space (u64 phys_base, int sparse) | |||
168 | return i; | 148 | return i; |
169 | } | 149 | } |
170 | 150 | ||
171 | static u64 add_io_space(struct pci_root_info *info, | 151 | static int add_io_space(struct device *dev, struct pci_root_info *info, |
172 | struct acpi_resource_address64 *addr) | 152 | struct resource_entry *entry) |
173 | { | 153 | { |
174 | struct iospace_resource *iospace; | 154 | struct resource_entry *iospace; |
175 | struct resource *resource; | 155 | struct resource *resource, *res = entry->res; |
176 | char *name; | 156 | char *name; |
177 | unsigned long base, min, max, base_port; | 157 | unsigned long base, min, max, base_port; |
178 | unsigned int sparse = 0, space_nr, len; | 158 | unsigned int sparse = 0, space_nr, len; |
179 | 159 | ||
180 | len = strlen(info->name) + 32; | 160 | len = strlen(info->common.name) + 32; |
181 | iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL); | 161 | iospace = resource_list_create_entry(NULL, len); |
182 | if (!iospace) { | 162 | if (!iospace) { |
183 | dev_err(&info->bridge->dev, | 163 | dev_err(dev, "PCI: No memory for %s I/O port space\n", |
184 | "PCI: No memory for %s I/O port space\n", | 164 | info->common.name); |
185 | info->name); | 165 | return -ENOMEM; |
186 | goto out; | ||
187 | } | 166 | } |
188 | 167 | ||
189 | name = (char *)(iospace + 1); | 168 | if (res->flags & IORESOURCE_IO_SPARSE) |
190 | |||
191 | min = addr->address.minimum; | ||
192 | max = min + addr->address.address_length - 1; | ||
193 | if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION) | ||
194 | sparse = 1; | 169 | sparse = 1; |
195 | 170 | space_nr = new_space(entry->offset, sparse); | |
196 | space_nr = new_space(addr->address.translation_offset, sparse); | ||
197 | if (space_nr == ~0) | 171 | if (space_nr == ~0) |
198 | goto free_resource; | 172 | goto free_resource; |
199 | 173 | ||
174 | name = (char *)(iospace + 1); | ||
175 | min = res->start - entry->offset; | ||
176 | max = res->end - entry->offset; | ||
200 | base = __pa(io_space[space_nr].mmio_base); | 177 | base = __pa(io_space[space_nr].mmio_base); |
201 | base_port = IO_SPACE_BASE(space_nr); | 178 | base_port = IO_SPACE_BASE(space_nr); |
202 | snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name, | 179 | snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->common.name, |
203 | base_port + min, base_port + max); | 180 | base_port + min, base_port + max); |
204 | 181 | ||
205 | /* | 182 | /* |
206 | * The SDM guarantees the legacy 0-64K space is sparse, but if the | 183 | * The SDM guarantees the legacy 0-64K space is sparse, but if the |
@@ -210,270 +187,125 @@ static u64 add_io_space(struct pci_root_info *info, | |||
210 | if (space_nr == 0) | 187 | if (space_nr == 0) |
211 | sparse = 1; | 188 | sparse = 1; |
212 | 189 | ||
213 | resource = &iospace->res; | 190 | resource = iospace->res; |
214 | resource->name = name; | 191 | resource->name = name; |
215 | resource->flags = IORESOURCE_MEM; | 192 | resource->flags = IORESOURCE_MEM; |
216 | resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); | 193 | resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); |
217 | resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); | 194 | resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); |
218 | if (insert_resource(&iomem_resource, resource)) { | 195 | if (insert_resource(&iomem_resource, resource)) { |
219 | dev_err(&info->bridge->dev, | 196 | dev_err(dev, |
220 | "can't allocate host bridge io space resource %pR\n", | 197 | "can't allocate host bridge io space resource %pR\n", |
221 | resource); | 198 | resource); |
222 | goto free_resource; | 199 | goto free_resource; |
223 | } | 200 | } |
224 | 201 | ||
225 | list_add_tail(&iospace->list, &info->io_resources); | 202 | entry->offset = base_port; |
226 | return base_port; | 203 | res->start = min + base_port; |
204 | res->end = max + base_port; | ||
205 | resource_list_add_tail(iospace, &info->io_resources); | ||
227 | 206 | ||
228 | free_resource: | 207 | return 0; |
229 | kfree(iospace); | ||
230 | out: | ||
231 | return ~0; | ||
232 | } | ||
233 | |||
234 | static acpi_status resource_to_window(struct acpi_resource *resource, | ||
235 | struct acpi_resource_address64 *addr) | ||
236 | { | ||
237 | acpi_status status; | ||
238 | 208 | ||
239 | /* | 209 | free_resource: |
240 | * We're only interested in _CRS descriptors that are | 210 | resource_list_free_entry(iospace); |
241 | * - address space descriptors for memory or I/O space | 211 | return -ENOSPC; |
242 | * - non-zero size | ||
243 | */ | ||
244 | status = acpi_resource_to_address64(resource, addr); | ||
245 | if (ACPI_SUCCESS(status) && | ||
246 | (addr->resource_type == ACPI_MEMORY_RANGE || | ||
247 | addr->resource_type == ACPI_IO_RANGE) && | ||
248 | addr->address.address_length) | ||
249 | return AE_OK; | ||
250 | |||
251 | return AE_ERROR; | ||
252 | } | 212 | } |
253 | 213 | ||
254 | static acpi_status count_window(struct acpi_resource *resource, void *data) | 214 | /* |
215 | * An IO port or MMIO resource assigned to a PCI host bridge may be | ||
216 | * consumed by the host bridge itself or available to its child | ||
217 | * bus/devices. The ACPI specification defines a bit (Producer/Consumer) | ||
218 | * to tell whether the resource is consumed by the host bridge itself, | ||
219 | * but firmware hasn't used that bit consistently, so we can't rely on it. | ||
220 | * | ||
221 | * On x86 and IA64 platforms, all IO port and MMIO resources are assumed | ||
222 | * to be available to child bus/devices except one special case: | ||
223 | * IO port [0xCF8-0xCFF] is consumed by the host bridge itself | ||
224 | * to access PCI configuration space. | ||
225 | * | ||
226 | * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF]. | ||
227 | */ | ||
228 | static bool resource_is_pcicfg_ioport(struct resource *res) | ||
255 | { | 229 | { |
256 | unsigned int *windows = (unsigned int *) data; | 230 | return (res->flags & IORESOURCE_IO) && |
257 | struct acpi_resource_address64 addr; | 231 | res->start == 0xCF8 && res->end == 0xCFF; |
258 | acpi_status status; | ||
259 | |||
260 | status = resource_to_window(resource, &addr); | ||
261 | if (ACPI_SUCCESS(status)) | ||
262 | (*windows)++; | ||
263 | |||
264 | return AE_OK; | ||
265 | } | 232 | } |
266 | 233 | ||
267 | static acpi_status add_window(struct acpi_resource *res, void *data) | 234 | static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) |
268 | { | 235 | { |
269 | struct pci_root_info *info = data; | 236 | struct device *dev = &ci->bridge->dev; |
270 | struct resource *resource; | 237 | struct pci_root_info *info; |
271 | struct acpi_resource_address64 addr; | 238 | struct resource *res; |
272 | acpi_status status; | 239 | struct resource_entry *entry, *tmp; |
273 | unsigned long flags, offset = 0; | 240 | int status; |
274 | struct resource *root; | 241 | |
275 | 242 | status = acpi_pci_probe_root_resources(ci); | |
276 | /* Return AE_OK for non-window resources to keep scanning for more */ | 243 | if (status > 0) { |
277 | status = resource_to_window(res, &addr); | 244 | info = container_of(ci, struct pci_root_info, common); |
278 | if (!ACPI_SUCCESS(status)) | 245 | resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { |
279 | return AE_OK; | 246 | res = entry->res; |
280 | 247 | if (res->flags & IORESOURCE_MEM) { | |
281 | if (addr.resource_type == ACPI_MEMORY_RANGE) { | 248 | /* |
282 | flags = IORESOURCE_MEM; | 249 | * HP's firmware has a hack to work around a |
283 | root = &iomem_resource; | 250 | * Windows bug. Ignore these tiny memory ranges. |
284 | offset = addr.address.translation_offset; | 251 | */ |
285 | } else if (addr.resource_type == ACPI_IO_RANGE) { | 252 | if (resource_size(res) <= 16) { |
286 | flags = IORESOURCE_IO; | 253 | resource_list_del(entry); |
287 | root = &ioport_resource; | 254 | insert_resource(&iomem_resource, |
288 | offset = add_io_space(info, &addr); | 255 | entry->res); |
289 | if (offset == ~0) | 256 | resource_list_add_tail(entry, |
290 | return AE_OK; | 257 | &info->io_resources); |
291 | } else | 258 | } |
292 | return AE_OK; | 259 | } else if (res->flags & IORESOURCE_IO) { |
293 | 260 | if (resource_is_pcicfg_ioport(entry->res)) | |
294 | resource = &info->res[info->res_num]; | 261 | resource_list_destroy_entry(entry); |
295 | resource->name = info->name; | 262 | else if (add_io_space(dev, info, entry)) |
296 | resource->flags = flags; | 263 | resource_list_destroy_entry(entry); |
297 | resource->start = addr.address.minimum + offset; | 264 | } |
298 | resource->end = resource->start + addr.address.address_length - 1; | 265 | } |
299 | info->res_offset[info->res_num] = offset; | ||
300 | |||
301 | if (insert_resource(root, resource)) { | ||
302 | dev_err(&info->bridge->dev, | ||
303 | "can't allocate host bridge window %pR\n", | ||
304 | resource); | ||
305 | } else { | ||
306 | if (offset) | ||
307 | dev_info(&info->bridge->dev, "host bridge window %pR " | ||
308 | "(PCI address [%#llx-%#llx])\n", | ||
309 | resource, | ||
310 | resource->start - offset, | ||
311 | resource->end - offset); | ||
312 | else | ||
313 | dev_info(&info->bridge->dev, | ||
314 | "host bridge window %pR\n", resource); | ||
315 | } | 266 | } |
316 | /* HP's firmware has a hack to work around a Windows bug. | ||
317 | * Ignore these tiny memory ranges */ | ||
318 | if (!((resource->flags & IORESOURCE_MEM) && | ||
319 | (resource->end - resource->start < 16))) | ||
320 | pci_add_resource_offset(&info->resources, resource, | ||
321 | info->res_offset[info->res_num]); | ||
322 | |||
323 | info->res_num++; | ||
324 | return AE_OK; | ||
325 | } | ||
326 | 267 | ||
327 | static void free_pci_root_info_res(struct pci_root_info *info) | 268 | return status; |
328 | { | ||
329 | struct iospace_resource *iospace, *tmp; | ||
330 | |||
331 | list_for_each_entry_safe(iospace, tmp, &info->io_resources, list) | ||
332 | kfree(iospace); | ||
333 | |||
334 | kfree(info->name); | ||
335 | kfree(info->res); | ||
336 | info->res = NULL; | ||
337 | kfree(info->res_offset); | ||
338 | info->res_offset = NULL; | ||
339 | info->res_num = 0; | ||
340 | kfree(info->controller); | ||
341 | info->controller = NULL; | ||
342 | } | 269 | } |
343 | 270 | ||
344 | static void __release_pci_root_info(struct pci_root_info *info) | 271 | static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci) |
345 | { | 272 | { |
346 | int i; | 273 | struct pci_root_info *info; |
347 | struct resource *res; | 274 | struct resource_entry *entry, *tmp; |
348 | struct iospace_resource *iospace; | ||
349 | 275 | ||
350 | list_for_each_entry(iospace, &info->io_resources, list) | 276 | info = container_of(ci, struct pci_root_info, common); |
351 | release_resource(&iospace->res); | 277 | resource_list_for_each_entry_safe(entry, tmp, &info->io_resources) { |
352 | 278 | release_resource(entry->res); | |
353 | for (i = 0; i < info->res_num; i++) { | 279 | resource_list_destroy_entry(entry); |
354 | res = &info->res[i]; | ||
355 | |||
356 | if (!res->parent) | ||
357 | continue; | ||
358 | |||
359 | if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
360 | continue; | ||
361 | |||
362 | release_resource(res); | ||
363 | } | 280 | } |
364 | |||
365 | free_pci_root_info_res(info); | ||
366 | kfree(info); | 281 | kfree(info); |
367 | } | 282 | } |
368 | 283 | ||
369 | static void release_pci_root_info(struct pci_host_bridge *bridge) | 284 | static struct acpi_pci_root_ops pci_acpi_root_ops = { |
370 | { | 285 | .pci_ops = &pci_root_ops, |
371 | struct pci_root_info *info = bridge->release_data; | 286 | .release_info = pci_acpi_root_release_info, |
372 | 287 | .prepare_resources = pci_acpi_root_prepare_resources, | |
373 | __release_pci_root_info(info); | 288 | }; |
374 | } | ||
375 | |||
376 | static int | ||
377 | probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device, | ||
378 | int busnum, int domain) | ||
379 | { | ||
380 | char *name; | ||
381 | |||
382 | name = kmalloc(16, GFP_KERNEL); | ||
383 | if (!name) | ||
384 | return -ENOMEM; | ||
385 | |||
386 | sprintf(name, "PCI Bus %04x:%02x", domain, busnum); | ||
387 | info->bridge = device; | ||
388 | info->name = name; | ||
389 | |||
390 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, | ||
391 | &info->res_num); | ||
392 | if (info->res_num) { | ||
393 | info->res = | ||
394 | kzalloc_node(sizeof(*info->res) * info->res_num, | ||
395 | GFP_KERNEL, info->controller->node); | ||
396 | if (!info->res) { | ||
397 | kfree(name); | ||
398 | return -ENOMEM; | ||
399 | } | ||
400 | |||
401 | info->res_offset = | ||
402 | kzalloc_node(sizeof(*info->res_offset) * info->res_num, | ||
403 | GFP_KERNEL, info->controller->node); | ||
404 | if (!info->res_offset) { | ||
405 | kfree(name); | ||
406 | kfree(info->res); | ||
407 | info->res = NULL; | ||
408 | return -ENOMEM; | ||
409 | } | ||
410 | |||
411 | info->res_num = 0; | ||
412 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, | ||
413 | add_window, info); | ||
414 | } else | ||
415 | kfree(name); | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | 289 | ||
420 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 290 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) |
421 | { | 291 | { |
422 | struct acpi_device *device = root->device; | 292 | struct acpi_device *device = root->device; |
423 | int domain = root->segment; | 293 | struct pci_root_info *info; |
424 | int bus = root->secondary.start; | ||
425 | struct pci_controller *controller; | ||
426 | struct pci_root_info *info = NULL; | ||
427 | int busnum = root->secondary.start; | ||
428 | struct pci_bus *pbus; | ||
429 | int ret; | ||
430 | |||
431 | controller = alloc_pci_controller(domain); | ||
432 | if (!controller) | ||
433 | return NULL; | ||
434 | |||
435 | controller->companion = device; | ||
436 | controller->node = acpi_get_node(device->handle); | ||
437 | 294 | ||
438 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 295 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
439 | if (!info) { | 296 | if (!info) { |
440 | dev_err(&device->dev, | 297 | dev_err(&device->dev, |
441 | "pci_bus %04x:%02x: ignored (out of memory)\n", | 298 | "pci_bus %04x:%02x: ignored (out of memory)\n", |
442 | domain, busnum); | 299 | root->segment, (int)root->secondary.start); |
443 | kfree(controller); | ||
444 | return NULL; | 300 | return NULL; |
445 | } | 301 | } |
446 | 302 | ||
447 | info->controller = controller; | 303 | info->controller.segment = root->segment; |
304 | info->controller.companion = device; | ||
305 | info->controller.node = acpi_get_node(device->handle); | ||
448 | INIT_LIST_HEAD(&info->io_resources); | 306 | INIT_LIST_HEAD(&info->io_resources); |
449 | INIT_LIST_HEAD(&info->resources); | 307 | return acpi_pci_root_create(root, &pci_acpi_root_ops, |
450 | 308 | &info->common, &info->controller); | |
451 | ret = probe_pci_root_info(info, device, busnum, domain); | ||
452 | if (ret) { | ||
453 | kfree(info->controller); | ||
454 | kfree(info); | ||
455 | return NULL; | ||
456 | } | ||
457 | /* insert busn resource at first */ | ||
458 | pci_add_resource(&info->resources, &root->secondary); | ||
459 | /* | ||
460 | * See arch/x86/pci/acpi.c. | ||
461 | * The desired pci bus might already be scanned in a quirk. We | ||
462 | * should handle the case here, but it appears that IA64 hasn't | ||
463 | * such quirk. So we just ignore the case now. | ||
464 | */ | ||
465 | pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller, | ||
466 | &info->resources); | ||
467 | if (!pbus) { | ||
468 | pci_free_resource_list(&info->resources); | ||
469 | __release_pci_root_info(info); | ||
470 | return NULL; | ||
471 | } | ||
472 | |||
473 | pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge), | ||
474 | release_pci_root_info, info); | ||
475 | pci_scan_child_bus(pbus); | ||
476 | return pbus; | ||
477 | } | 309 | } |
478 | 310 | ||
479 | int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) | 311 | int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) |
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index ff9911707160..3cd69832d7f4 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -4,16 +4,15 @@ | |||
4 | #include <linux/irq.h> | 4 | #include <linux/irq.h> |
5 | #include <linux/dmi.h> | 5 | #include <linux/dmi.h> |
6 | #include <linux/slab.h> | 6 | #include <linux/slab.h> |
7 | #include <linux/pci-acpi.h> | ||
7 | #include <asm/numa.h> | 8 | #include <asm/numa.h> |
8 | #include <asm/pci_x86.h> | 9 | #include <asm/pci_x86.h> |
9 | 10 | ||
10 | struct pci_root_info { | 11 | struct pci_root_info { |
11 | struct acpi_device *bridge; | 12 | struct acpi_pci_root_info common; |
12 | char name[16]; | ||
13 | struct pci_sysdata sd; | 13 | struct pci_sysdata sd; |
14 | #ifdef CONFIG_PCI_MMCONFIG | 14 | #ifdef CONFIG_PCI_MMCONFIG |
15 | bool mcfg_added; | 15 | bool mcfg_added; |
16 | u16 segment; | ||
17 | u8 start_bus; | 16 | u8 start_bus; |
18 | u8 end_bus; | 17 | u8 end_bus; |
19 | #endif | 18 | #endif |
@@ -178,15 +177,18 @@ static int check_segment(u16 seg, struct device *dev, char *estr) | |||
178 | return 0; | 177 | return 0; |
179 | } | 178 | } |
180 | 179 | ||
181 | static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start, | 180 | static int setup_mcfg_map(struct acpi_pci_root_info *ci) |
182 | u8 end, phys_addr_t addr) | ||
183 | { | 181 | { |
184 | int result; | 182 | int result, seg; |
185 | struct device *dev = &info->bridge->dev; | 183 | struct pci_root_info *info; |
184 | struct acpi_pci_root *root = ci->root; | ||
185 | struct device *dev = &ci->bridge->dev; | ||
186 | 186 | ||
187 | info->start_bus = start; | 187 | info = container_of(ci, struct pci_root_info, common); |
188 | info->end_bus = end; | 188 | info->start_bus = (u8)root->secondary.start; |
189 | info->end_bus = (u8)root->secondary.end; | ||
189 | info->mcfg_added = false; | 190 | info->mcfg_added = false; |
191 | seg = info->sd.domain; | ||
190 | 192 | ||
191 | /* return success if MMCFG is not in use */ | 193 | /* return success if MMCFG is not in use */ |
192 | if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg) | 194 | if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg) |
@@ -195,7 +197,8 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start, | |||
195 | if (!(pci_probe & PCI_PROBE_MMCONF)) | 197 | if (!(pci_probe & PCI_PROBE_MMCONF)) |
196 | return check_segment(seg, dev, "MMCONFIG is disabled,"); | 198 | return check_segment(seg, dev, "MMCONFIG is disabled,"); |
197 | 199 | ||
198 | result = pci_mmconfig_insert(dev, seg, start, end, addr); | 200 | result = pci_mmconfig_insert(dev, seg, info->start_bus, info->end_bus, |
201 | root->mcfg_addr); | ||
199 | if (result == 0) { | 202 | if (result == 0) { |
200 | /* enable MMCFG if it hasn't been enabled yet */ | 203 | /* enable MMCFG if it hasn't been enabled yet */ |
201 | if (raw_pci_ext_ops == NULL) | 204 | if (raw_pci_ext_ops == NULL) |
@@ -208,134 +211,55 @@ static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start, | |||
208 | return 0; | 211 | return 0; |
209 | } | 212 | } |
210 | 213 | ||
211 | static void teardown_mcfg_map(struct pci_root_info *info) | 214 | static void teardown_mcfg_map(struct acpi_pci_root_info *ci) |
212 | { | 215 | { |
216 | struct pci_root_info *info; | ||
217 | |||
218 | info = container_of(ci, struct pci_root_info, common); | ||
213 | if (info->mcfg_added) { | 219 | if (info->mcfg_added) { |
214 | pci_mmconfig_delete(info->segment, info->start_bus, | 220 | pci_mmconfig_delete(info->sd.domain, |
215 | info->end_bus); | 221 | info->start_bus, info->end_bus); |
216 | info->mcfg_added = false; | 222 | info->mcfg_added = false; |
217 | } | 223 | } |
218 | } | 224 | } |
219 | #else | 225 | #else |
220 | static int setup_mcfg_map(struct pci_root_info *info, | 226 | static int setup_mcfg_map(struct acpi_pci_root_info *ci) |
221 | u16 seg, u8 start, u8 end, | ||
222 | phys_addr_t addr) | ||
223 | { | 227 | { |
224 | return 0; | 228 | return 0; |
225 | } | 229 | } |
226 | static void teardown_mcfg_map(struct pci_root_info *info) | 230 | |
231 | static void teardown_mcfg_map(struct acpi_pci_root_info *ci) | ||
227 | { | 232 | { |
228 | } | 233 | } |
229 | #endif | 234 | #endif |
230 | 235 | ||
231 | static void validate_resources(struct device *dev, struct list_head *crs_res, | 236 | static int pci_acpi_root_get_node(struct acpi_pci_root *root) |
232 | unsigned long type) | ||
233 | { | 237 | { |
234 | LIST_HEAD(list); | 238 | int busnum = root->secondary.start; |
235 | struct resource *res1, *res2, *root = NULL; | 239 | struct acpi_device *device = root->device; |
236 | struct resource_entry *tmp, *entry, *entry2; | 240 | int node = acpi_get_node(device->handle); |
237 | |||
238 | BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); | ||
239 | root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; | ||
240 | |||
241 | list_splice_init(crs_res, &list); | ||
242 | resource_list_for_each_entry_safe(entry, tmp, &list) { | ||
243 | bool free = false; | ||
244 | resource_size_t end; | ||
245 | |||
246 | res1 = entry->res; | ||
247 | if (!(res1->flags & type)) | ||
248 | goto next; | ||
249 | |||
250 | /* Exclude non-addressable range or non-addressable portion */ | ||
251 | end = min(res1->end, root->end); | ||
252 | if (end <= res1->start) { | ||
253 | dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", | ||
254 | res1); | ||
255 | free = true; | ||
256 | goto next; | ||
257 | } else if (res1->end != end) { | ||
258 | dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", | ||
259 | res1, (unsigned long long)end + 1, | ||
260 | (unsigned long long)res1->end); | ||
261 | res1->end = end; | ||
262 | } | ||
263 | |||
264 | resource_list_for_each_entry(entry2, crs_res) { | ||
265 | res2 = entry2->res; | ||
266 | if (!(res2->flags & type)) | ||
267 | continue; | ||
268 | |||
269 | /* | ||
270 | * I don't like throwing away windows because then | ||
271 | * our resources no longer match the ACPI _CRS, but | ||
272 | * the kernel resource tree doesn't allow overlaps. | ||
273 | */ | ||
274 | if (resource_overlaps(res1, res2)) { | ||
275 | res2->start = min(res1->start, res2->start); | ||
276 | res2->end = max(res1->end, res2->end); | ||
277 | dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", | ||
278 | res2, res1); | ||
279 | free = true; | ||
280 | goto next; | ||
281 | } | ||
282 | } | ||
283 | 241 | ||
284 | next: | 242 | if (node == NUMA_NO_NODE) { |
285 | resource_list_del(entry); | 243 | node = x86_pci_root_bus_node(busnum); |
286 | if (free) | 244 | if (node != 0 && node != NUMA_NO_NODE) |
287 | resource_list_free_entry(entry); | 245 | dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n", |
288 | else | 246 | node); |
289 | resource_list_add_tail(entry, crs_res); | ||
290 | } | 247 | } |
248 | if (node != NUMA_NO_NODE && !node_online(node)) | ||
249 | node = NUMA_NO_NODE; | ||
250 | |||
251 | return node; | ||
291 | } | 252 | } |
292 | 253 | ||
293 | static void add_resources(struct pci_root_info *info, | 254 | static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci) |
294 | struct list_head *resources, | ||
295 | struct list_head *crs_res) | ||
296 | { | 255 | { |
297 | struct resource_entry *entry, *tmp; | 256 | return setup_mcfg_map(ci); |
298 | struct resource *res, *conflict, *root = NULL; | ||
299 | |||
300 | validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM); | ||
301 | validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO); | ||
302 | |||
303 | resource_list_for_each_entry_safe(entry, tmp, crs_res) { | ||
304 | res = entry->res; | ||
305 | if (res->flags & IORESOURCE_MEM) | ||
306 | root = &iomem_resource; | ||
307 | else if (res->flags & IORESOURCE_IO) | ||
308 | root = &ioport_resource; | ||
309 | else | ||
310 | BUG_ON(res); | ||
311 | |||
312 | conflict = insert_resource_conflict(root, res); | ||
313 | if (conflict) { | ||
314 | dev_info(&info->bridge->dev, | ||
315 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | ||
316 | res, conflict->name, conflict); | ||
317 | resource_list_destroy_entry(entry); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | list_splice_tail(crs_res, resources); | ||
322 | } | 257 | } |
323 | 258 | ||
324 | static void release_pci_root_info(struct pci_host_bridge *bridge) | 259 | static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci) |
325 | { | 260 | { |
326 | struct resource *res; | 261 | teardown_mcfg_map(ci); |
327 | struct resource_entry *entry; | 262 | kfree(container_of(ci, struct pci_root_info, common)); |
328 | struct pci_root_info *info = bridge->release_data; | ||
329 | |||
330 | resource_list_for_each_entry(entry, &bridge->windows) { | ||
331 | res = entry->res; | ||
332 | if (res->parent && | ||
333 | (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
334 | release_resource(res); | ||
335 | } | ||
336 | |||
337 | teardown_mcfg_map(info); | ||
338 | kfree(info); | ||
339 | } | 263 | } |
340 | 264 | ||
341 | /* | 265 | /* |
@@ -358,50 +282,47 @@ static bool resource_is_pcicfg_ioport(struct resource *res) | |||
358 | res->start == 0xCF8 && res->end == 0xCFF; | 282 | res->start == 0xCF8 && res->end == 0xCFF; |
359 | } | 283 | } |
360 | 284 | ||
361 | static void probe_pci_root_info(struct pci_root_info *info, | 285 | static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) |
362 | struct acpi_device *device, | ||
363 | int busnum, int domain, | ||
364 | struct list_head *list) | ||
365 | { | 286 | { |
366 | int ret; | 287 | struct acpi_device *device = ci->bridge; |
288 | int busnum = ci->root->secondary.start; | ||
367 | struct resource_entry *entry, *tmp; | 289 | struct resource_entry *entry, *tmp; |
290 | int status; | ||
368 | 291 | ||
369 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); | 292 | status = acpi_pci_probe_root_resources(ci); |
370 | info->bridge = device; | 293 | if (pci_use_crs) { |
371 | ret = acpi_dev_get_resources(device, list, | 294 | resource_list_for_each_entry_safe(entry, tmp, &ci->resources) |
372 | acpi_dev_filter_resource_type_cb, | 295 | if (resource_is_pcicfg_ioport(entry->res)) |
373 | (void *)(IORESOURCE_IO | IORESOURCE_MEM)); | ||
374 | if (ret < 0) | ||
375 | dev_warn(&device->dev, | ||
376 | "failed to parse _CRS method, error code %d\n", ret); | ||
377 | else if (ret == 0) | ||
378 | dev_dbg(&device->dev, | ||
379 | "no IO and memory resources present in _CRS\n"); | ||
380 | else | ||
381 | resource_list_for_each_entry_safe(entry, tmp, list) { | ||
382 | if ((entry->res->flags & IORESOURCE_DISABLED) || | ||
383 | resource_is_pcicfg_ioport(entry->res)) | ||
384 | resource_list_destroy_entry(entry); | 296 | resource_list_destroy_entry(entry); |
385 | else | 297 | return status; |
386 | entry->res->name = info->name; | 298 | } |
387 | } | 299 | |
300 | resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { | ||
301 | dev_printk(KERN_DEBUG, &device->dev, | ||
302 | "host bridge window %pR (ignored)\n", entry->res); | ||
303 | resource_list_destroy_entry(entry); | ||
304 | } | ||
305 | x86_pci_root_bus_resources(busnum, &ci->resources); | ||
306 | |||
307 | return 0; | ||
388 | } | 308 | } |
389 | 309 | ||
310 | static struct acpi_pci_root_ops acpi_pci_root_ops = { | ||
311 | .pci_ops = &pci_root_ops, | ||
312 | .init_info = pci_acpi_root_init_info, | ||
313 | .release_info = pci_acpi_root_release_info, | ||
314 | .prepare_resources = pci_acpi_root_prepare_resources, | ||
315 | }; | ||
316 | |||
390 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 317 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) |
391 | { | 318 | { |
392 | struct acpi_device *device = root->device; | ||
393 | struct pci_root_info *info; | ||
394 | int domain = root->segment; | 319 | int domain = root->segment; |
395 | int busnum = root->secondary.start; | 320 | int busnum = root->secondary.start; |
396 | struct resource_entry *res_entry; | 321 | int node = pci_acpi_root_get_node(root); |
397 | LIST_HEAD(crs_res); | ||
398 | LIST_HEAD(resources); | ||
399 | struct pci_bus *bus; | 322 | struct pci_bus *bus; |
400 | struct pci_sysdata *sd; | ||
401 | int node; | ||
402 | 323 | ||
403 | if (pci_ignore_seg) | 324 | if (pci_ignore_seg) |
404 | domain = 0; | 325 | root->segment = domain = 0; |
405 | 326 | ||
406 | if (domain && !pci_domains_supported) { | 327 | if (domain && !pci_domains_supported) { |
407 | printk(KERN_WARNING "pci_bus %04x:%02x: " | 328 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
@@ -410,71 +331,33 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
410 | return NULL; | 331 | return NULL; |
411 | } | 332 | } |
412 | 333 | ||
413 | node = acpi_get_node(device->handle); | ||
414 | if (node == NUMA_NO_NODE) { | ||
415 | node = x86_pci_root_bus_node(busnum); | ||
416 | if (node != 0 && node != NUMA_NO_NODE) | ||
417 | dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n", | ||
418 | node); | ||
419 | } | ||
420 | |||
421 | if (node != NUMA_NO_NODE && !node_online(node)) | ||
422 | node = NUMA_NO_NODE; | ||
423 | |||
424 | info = kzalloc_node(sizeof(*info), GFP_KERNEL, node); | ||
425 | if (!info) { | ||
426 | printk(KERN_WARNING "pci_bus %04x:%02x: " | ||
427 | "ignored (out of memory)\n", domain, busnum); | ||
428 | return NULL; | ||
429 | } | ||
430 | |||
431 | sd = &info->sd; | ||
432 | sd->domain = domain; | ||
433 | sd->node = node; | ||
434 | sd->companion = device; | ||
435 | |||
436 | bus = pci_find_bus(domain, busnum); | 334 | bus = pci_find_bus(domain, busnum); |
437 | if (bus) { | 335 | if (bus) { |
438 | /* | 336 | /* |
439 | * If the desired bus has been scanned already, replace | 337 | * If the desired bus has been scanned already, replace |
440 | * its bus->sysdata. | 338 | * its bus->sysdata. |
441 | */ | 339 | */ |
442 | memcpy(bus->sysdata, sd, sizeof(*sd)); | 340 | struct pci_sysdata sd = { |
443 | kfree(info); | 341 | .domain = domain, |
444 | } else { | 342 | .node = node, |
445 | /* insert busn res at first */ | 343 | .companion = root->device |
446 | pci_add_resource(&resources, &root->secondary); | 344 | }; |
447 | 345 | ||
448 | /* | 346 | memcpy(bus->sysdata, &sd, sizeof(sd)); |
449 | * _CRS with no apertures is normal, so only fall back to | 347 | } else { |
450 | * defaults or native bridge info if we're ignoring _CRS. | 348 | struct pci_root_info *info; |
451 | */ | 349 | |
452 | probe_pci_root_info(info, device, busnum, domain, &crs_res); | 350 | info = kzalloc_node(sizeof(*info), GFP_KERNEL, node); |
453 | if (pci_use_crs) { | 351 | if (!info) |
454 | add_resources(info, &resources, &crs_res); | 352 | dev_err(&root->device->dev, |
455 | } else { | 353 | "pci_bus %04x:%02x: ignored (out of memory)\n", |
456 | resource_list_for_each_entry(res_entry, &crs_res) | 354 | domain, busnum); |
457 | dev_printk(KERN_DEBUG, &device->dev, | 355 | else { |
458 | "host bridge window %pR (ignored)\n", | 356 | info->sd.domain = domain; |
459 | res_entry->res); | 357 | info->sd.node = node; |
460 | resource_list_free(&crs_res); | 358 | info->sd.companion = root->device; |
461 | x86_pci_root_bus_resources(busnum, &resources); | 359 | bus = acpi_pci_root_create(root, &acpi_pci_root_ops, |
462 | } | 360 | &info->common, &info->sd); |
463 | |||
464 | if (!setup_mcfg_map(info, domain, (u8)root->secondary.start, | ||
465 | (u8)root->secondary.end, root->mcfg_addr)) | ||
466 | bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, | ||
467 | sd, &resources); | ||
468 | |||
469 | if (bus) { | ||
470 | pci_scan_child_bus(bus); | ||
471 | pci_set_host_bridge_release( | ||
472 | to_pci_host_bridge(bus->bridge), | ||
473 | release_pci_root_info, info); | ||
474 | } else { | ||
475 | resource_list_free(&resources); | ||
476 | teardown_mcfg_map(info); | ||
477 | kfree(info); | ||
478 | } | 361 | } |
479 | } | 362 | } |
480 | 363 | ||
@@ -487,9 +370,6 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
487 | pcie_bus_configure_settings(child); | 370 | pcie_bus_configure_settings(child); |
488 | } | 371 | } |
489 | 372 | ||
490 | if (bus && node != NUMA_NO_NODE) | ||
491 | dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node); | ||
492 | |||
493 | return bus; | 373 | return bus; |
494 | } | 374 | } |
495 | 375 | ||
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 393706a5261b..850d7bf0c873 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -652,6 +652,210 @@ static void acpi_pci_root_remove(struct acpi_device *device) | |||
652 | kfree(root); | 652 | kfree(root); |
653 | } | 653 | } |
654 | 654 | ||
655 | /* | ||
656 | * Following code to support acpi_pci_root_create() is copied from | ||
657 | * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64 | ||
658 | * and ARM64. | ||
659 | */ | ||
660 | static void acpi_pci_root_validate_resources(struct device *dev, | ||
661 | struct list_head *resources, | ||
662 | unsigned long type) | ||
663 | { | ||
664 | LIST_HEAD(list); | ||
665 | struct resource *res1, *res2, *root = NULL; | ||
666 | struct resource_entry *tmp, *entry, *entry2; | ||
667 | |||
668 | BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); | ||
669 | root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; | ||
670 | |||
671 | list_splice_init(resources, &list); | ||
672 | resource_list_for_each_entry_safe(entry, tmp, &list) { | ||
673 | bool free = false; | ||
674 | resource_size_t end; | ||
675 | |||
676 | res1 = entry->res; | ||
677 | if (!(res1->flags & type)) | ||
678 | goto next; | ||
679 | |||
680 | /* Exclude non-addressable range or non-addressable portion */ | ||
681 | end = min(res1->end, root->end); | ||
682 | if (end <= res1->start) { | ||
683 | dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", | ||
684 | res1); | ||
685 | free = true; | ||
686 | goto next; | ||
687 | } else if (res1->end != end) { | ||
688 | dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", | ||
689 | res1, (unsigned long long)end + 1, | ||
690 | (unsigned long long)res1->end); | ||
691 | res1->end = end; | ||
692 | } | ||
693 | |||
694 | resource_list_for_each_entry(entry2, resources) { | ||
695 | res2 = entry2->res; | ||
696 | if (!(res2->flags & type)) | ||
697 | continue; | ||
698 | |||
699 | /* | ||
700 | * I don't like throwing away windows because then | ||
701 | * our resources no longer match the ACPI _CRS, but | ||
702 | * the kernel resource tree doesn't allow overlaps. | ||
703 | */ | ||
704 | if (resource_overlaps(res1, res2)) { | ||
705 | res2->start = min(res1->start, res2->start); | ||
706 | res2->end = max(res1->end, res2->end); | ||
707 | dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", | ||
708 | res2, res1); | ||
709 | free = true; | ||
710 | goto next; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | next: | ||
715 | resource_list_del(entry); | ||
716 | if (free) | ||
717 | resource_list_free_entry(entry); | ||
718 | else | ||
719 | resource_list_add_tail(entry, resources); | ||
720 | } | ||
721 | } | ||
722 | |||
723 | int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info) | ||
724 | { | ||
725 | int ret; | ||
726 | struct list_head *list = &info->resources; | ||
727 | struct acpi_device *device = info->bridge; | ||
728 | struct resource_entry *entry, *tmp; | ||
729 | unsigned long flags; | ||
730 | |||
731 | flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT; | ||
732 | ret = acpi_dev_get_resources(device, list, | ||
733 | acpi_dev_filter_resource_type_cb, | ||
734 | (void *)flags); | ||
735 | if (ret < 0) | ||
736 | dev_warn(&device->dev, | ||
737 | "failed to parse _CRS method, error code %d\n", ret); | ||
738 | else if (ret == 0) | ||
739 | dev_dbg(&device->dev, | ||
740 | "no IO and memory resources present in _CRS\n"); | ||
741 | else { | ||
742 | resource_list_for_each_entry_safe(entry, tmp, list) { | ||
743 | if (entry->res->flags & IORESOURCE_DISABLED) | ||
744 | resource_list_destroy_entry(entry); | ||
745 | else | ||
746 | entry->res->name = info->name; | ||
747 | } | ||
748 | acpi_pci_root_validate_resources(&device->dev, list, | ||
749 | IORESOURCE_MEM); | ||
750 | acpi_pci_root_validate_resources(&device->dev, list, | ||
751 | IORESOURCE_IO); | ||
752 | } | ||
753 | |||
754 | return ret; | ||
755 | } | ||
756 | |||
757 | static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info) | ||
758 | { | ||
759 | struct resource_entry *entry, *tmp; | ||
760 | struct resource *res, *conflict, *root = NULL; | ||
761 | |||
762 | resource_list_for_each_entry_safe(entry, tmp, &info->resources) { | ||
763 | res = entry->res; | ||
764 | if (res->flags & IORESOURCE_MEM) | ||
765 | root = &iomem_resource; | ||
766 | else if (res->flags & IORESOURCE_IO) | ||
767 | root = &ioport_resource; | ||
768 | else | ||
769 | continue; | ||
770 | |||
771 | conflict = insert_resource_conflict(root, res); | ||
772 | if (conflict) { | ||
773 | dev_info(&info->bridge->dev, | ||
774 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | ||
775 | res, conflict->name, conflict); | ||
776 | resource_list_destroy_entry(entry); | ||
777 | } | ||
778 | } | ||
779 | } | ||
780 | |||
781 | static void __acpi_pci_root_release_info(struct acpi_pci_root_info *info) | ||
782 | { | ||
783 | struct resource *res; | ||
784 | struct resource_entry *entry, *tmp; | ||
785 | |||
786 | if (!info) | ||
787 | return; | ||
788 | |||
789 | resource_list_for_each_entry_safe(entry, tmp, &info->resources) { | ||
790 | res = entry->res; | ||
791 | if (res->parent && | ||
792 | (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
793 | release_resource(res); | ||
794 | resource_list_destroy_entry(entry); | ||
795 | } | ||
796 | |||
797 | info->ops->release_info(info); | ||
798 | } | ||
799 | |||
800 | static void acpi_pci_root_release_info(struct pci_host_bridge *bridge) | ||
801 | { | ||
802 | struct resource *res; | ||
803 | struct resource_entry *entry; | ||
804 | |||
805 | resource_list_for_each_entry(entry, &bridge->windows) { | ||
806 | res = entry->res; | ||
807 | if (res->parent && | ||
808 | (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
809 | release_resource(res); | ||
810 | } | ||
811 | __acpi_pci_root_release_info(bridge->release_data); | ||
812 | } | ||
813 | |||
814 | struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, | ||
815 | struct acpi_pci_root_ops *ops, | ||
816 | struct acpi_pci_root_info *info, | ||
817 | void *sysdata) | ||
818 | { | ||
819 | int ret, busnum = root->secondary.start; | ||
820 | struct acpi_device *device = root->device; | ||
821 | int node = acpi_get_node(device->handle); | ||
822 | struct pci_bus *bus; | ||
823 | |||
824 | info->root = root; | ||
825 | info->bridge = device; | ||
826 | info->ops = ops; | ||
827 | INIT_LIST_HEAD(&info->resources); | ||
828 | snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x", | ||
829 | root->segment, busnum); | ||
830 | |||
831 | if (ops->init_info && ops->init_info(info)) | ||
832 | goto out_release_info; | ||
833 | if (ops->prepare_resources) | ||
834 | ret = ops->prepare_resources(info); | ||
835 | else | ||
836 | ret = acpi_pci_probe_root_resources(info); | ||
837 | if (ret < 0) | ||
838 | goto out_release_info; | ||
839 | |||
840 | pci_acpi_root_add_resources(info); | ||
841 | pci_add_resource(&info->resources, &root->secondary); | ||
842 | bus = pci_create_root_bus(NULL, busnum, ops->pci_ops, | ||
843 | sysdata, &info->resources); | ||
844 | if (!bus) | ||
845 | goto out_release_info; | ||
846 | |||
847 | pci_scan_child_bus(bus); | ||
848 | pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge), | ||
849 | acpi_pci_root_release_info, info); | ||
850 | if (node != NUMA_NO_NODE) | ||
851 | dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node); | ||
852 | return bus; | ||
853 | |||
854 | out_release_info: | ||
855 | __acpi_pci_root_release_info(info); | ||
856 | return NULL; | ||
857 | } | ||
858 | |||
655 | void __init acpi_pci_root_init(void) | 859 | void __init acpi_pci_root_init(void) |
656 | { | 860 | { |
657 | acpi_hest_init(); | 861 | acpi_hest_init(); |
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 15d22db05054..cdc5c2599beb 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c | |||
@@ -119,7 +119,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) | |||
119 | EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); | 119 | EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); |
120 | 120 | ||
121 | static void acpi_dev_ioresource_flags(struct resource *res, u64 len, | 121 | static void acpi_dev_ioresource_flags(struct resource *res, u64 len, |
122 | u8 io_decode) | 122 | u8 io_decode, u8 translation_type) |
123 | { | 123 | { |
124 | res->flags = IORESOURCE_IO; | 124 | res->flags = IORESOURCE_IO; |
125 | 125 | ||
@@ -131,6 +131,8 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len, | |||
131 | 131 | ||
132 | if (io_decode == ACPI_DECODE_16) | 132 | if (io_decode == ACPI_DECODE_16) |
133 | res->flags |= IORESOURCE_IO_16BIT_ADDR; | 133 | res->flags |= IORESOURCE_IO_16BIT_ADDR; |
134 | if (translation_type == ACPI_SPARSE_TRANSLATION) | ||
135 | res->flags |= IORESOURCE_IO_SPARSE; | ||
134 | } | 136 | } |
135 | 137 | ||
136 | static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, | 138 | static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, |
@@ -138,7 +140,7 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, | |||
138 | { | 140 | { |
139 | res->start = start; | 141 | res->start = start; |
140 | res->end = start + len - 1; | 142 | res->end = start + len - 1; |
141 | acpi_dev_ioresource_flags(res, len, io_decode); | 143 | acpi_dev_ioresource_flags(res, len, io_decode, 0); |
142 | } | 144 | } |
143 | 145 | ||
144 | /** | 146 | /** |
@@ -231,7 +233,8 @@ static bool acpi_decode_space(struct resource_win *win, | |||
231 | acpi_dev_memresource_flags(res, len, wp); | 233 | acpi_dev_memresource_flags(res, len, wp); |
232 | break; | 234 | break; |
233 | case ACPI_IO_RANGE: | 235 | case ACPI_IO_RANGE: |
234 | acpi_dev_ioresource_flags(res, len, iodec); | 236 | acpi_dev_ioresource_flags(res, len, iodec, |
237 | addr->info.io.translation_type); | ||
235 | break; | 238 | break; |
236 | case ACPI_BUS_NUMBER_RANGE: | 239 | case ACPI_BUS_NUMBER_RANGE: |
237 | res->flags = IORESOURCE_BUS; | 240 | res->flags = IORESOURCE_BUS; |
diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 388e3ae94f7a..24bea087e7af 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h | |||
@@ -94,6 +94,7 @@ struct resource { | |||
94 | /* PnP I/O specific bits (IORESOURCE_BITS) */ | 94 | /* PnP I/O specific bits (IORESOURCE_BITS) */ |
95 | #define IORESOURCE_IO_16BIT_ADDR (1<<0) | 95 | #define IORESOURCE_IO_16BIT_ADDR (1<<0) |
96 | #define IORESOURCE_IO_FIXED (1<<1) | 96 | #define IORESOURCE_IO_FIXED (1<<1) |
97 | #define IORESOURCE_IO_SPARSE (1<<2) | ||
97 | 98 | ||
98 | /* PCI ROM control bits (IORESOURCE_BITS) */ | 99 | /* PCI ROM control bits (IORESOURCE_BITS) */ |
99 | #define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ | 100 | #define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ |
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index a965efa52152..89ab0572dbc6 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h | |||
@@ -52,6 +52,30 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus) | |||
52 | return ACPI_HANDLE(dev); | 52 | return ACPI_HANDLE(dev); |
53 | } | 53 | } |
54 | 54 | ||
55 | struct acpi_pci_root; | ||
56 | struct acpi_pci_root_ops; | ||
57 | |||
58 | struct acpi_pci_root_info { | ||
59 | struct acpi_pci_root *root; | ||
60 | struct acpi_device *bridge; | ||
61 | struct acpi_pci_root_ops *ops; | ||
62 | struct list_head resources; | ||
63 | char name[16]; | ||
64 | }; | ||
65 | |||
66 | struct acpi_pci_root_ops { | ||
67 | struct pci_ops *pci_ops; | ||
68 | int (*init_info)(struct acpi_pci_root_info *info); | ||
69 | void (*release_info)(struct acpi_pci_root_info *info); | ||
70 | int (*prepare_resources)(struct acpi_pci_root_info *info); | ||
71 | }; | ||
72 | |||
73 | extern int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info); | ||
74 | extern struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, | ||
75 | struct acpi_pci_root_ops *ops, | ||
76 | struct acpi_pci_root_info *info, | ||
77 | void *sd); | ||
78 | |||
55 | void acpi_pci_add_bus(struct pci_bus *bus); | 79 | void acpi_pci_add_bus(struct pci_bus *bus); |
56 | void acpi_pci_remove_bus(struct pci_bus *bus); | 80 | void acpi_pci_remove_bus(struct pci_bus *bus); |
57 | 81 | ||