diff options
30 files changed, 873 insertions, 450 deletions
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index a4effd6d8f2f..016991792b0b 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c | |||
@@ -422,17 +422,16 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | |||
422 | static int pcibios_init_resources(int busnr, struct pci_sys_data *sys) | 422 | static int pcibios_init_resources(int busnr, struct pci_sys_data *sys) |
423 | { | 423 | { |
424 | int ret; | 424 | int ret; |
425 | struct pci_host_bridge_window *window; | 425 | struct resource_entry *window; |
426 | 426 | ||
427 | if (list_empty(&sys->resources)) { | 427 | if (list_empty(&sys->resources)) { |
428 | pci_add_resource_offset(&sys->resources, | 428 | pci_add_resource_offset(&sys->resources, |
429 | &iomem_resource, sys->mem_offset); | 429 | &iomem_resource, sys->mem_offset); |
430 | } | 430 | } |
431 | 431 | ||
432 | list_for_each_entry(window, &sys->resources, list) { | 432 | resource_list_for_each_entry(window, &sys->resources) |
433 | if (resource_type(window->res) == IORESOURCE_IO) | 433 | if (resource_type(window->res) == IORESOURCE_IO) |
434 | return 0; | 434 | return 0; |
435 | } | ||
436 | 435 | ||
437 | sys->io_res.start = (busnr * SZ_64K) ? : pcibios_min_io; | 436 | sys->io_res.start = (busnr * SZ_64K) ? : pcibios_min_io; |
438 | sys->io_res.end = (busnr + 1) * SZ_64K - 1; | 437 | sys->io_res.end = (busnr + 1) * SZ_64K - 1; |
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index 164e3f8d3c3d..fa1195dae425 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h | |||
@@ -93,8 +93,6 @@ extern raw_spinlock_t pci_config_lock; | |||
93 | extern int (*pcibios_enable_irq)(struct pci_dev *dev); | 93 | extern int (*pcibios_enable_irq)(struct pci_dev *dev); |
94 | extern void (*pcibios_disable_irq)(struct pci_dev *dev); | 94 | extern void (*pcibios_disable_irq)(struct pci_dev *dev); |
95 | 95 | ||
96 | extern bool mp_should_keep_irq(struct device *dev); | ||
97 | |||
98 | struct pci_raw_ops { | 96 | struct pci_raw_ops { |
99 | int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, | 97 | int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, |
100 | int reg, int len, u32 *val); | 98 | int reg, int len, u32 *val); |
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index bb98afd0591e..6ac273832f28 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -10,9 +10,6 @@ | |||
10 | struct pci_root_info { | 10 | struct pci_root_info { |
11 | struct acpi_device *bridge; | 11 | struct acpi_device *bridge; |
12 | char name[16]; | 12 | char name[16]; |
13 | unsigned int res_num; | ||
14 | struct resource *res; | ||
15 | resource_size_t *res_offset; | ||
16 | struct pci_sysdata sd; | 13 | struct pci_sysdata sd; |
17 | #ifdef CONFIG_PCI_MMCONFIG | 14 | #ifdef CONFIG_PCI_MMCONFIG |
18 | bool mcfg_added; | 15 | bool mcfg_added; |
@@ -218,130 +215,41 @@ static void teardown_mcfg_map(struct pci_root_info *info) | |||
218 | } | 215 | } |
219 | #endif | 216 | #endif |
220 | 217 | ||
221 | static acpi_status resource_to_addr(struct acpi_resource *resource, | 218 | static void validate_resources(struct device *dev, struct list_head *crs_res, |
222 | struct acpi_resource_address64 *addr) | 219 | unsigned long type) |
223 | { | ||
224 | acpi_status status; | ||
225 | struct acpi_resource_memory24 *memory24; | ||
226 | struct acpi_resource_memory32 *memory32; | ||
227 | struct acpi_resource_fixed_memory32 *fixed_memory32; | ||
228 | |||
229 | memset(addr, 0, sizeof(*addr)); | ||
230 | switch (resource->type) { | ||
231 | case ACPI_RESOURCE_TYPE_MEMORY24: | ||
232 | memory24 = &resource->data.memory24; | ||
233 | addr->resource_type = ACPI_MEMORY_RANGE; | ||
234 | addr->address.minimum = memory24->minimum; | ||
235 | addr->address.address_length = memory24->address_length; | ||
236 | addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; | ||
237 | return AE_OK; | ||
238 | case ACPI_RESOURCE_TYPE_MEMORY32: | ||
239 | memory32 = &resource->data.memory32; | ||
240 | addr->resource_type = ACPI_MEMORY_RANGE; | ||
241 | addr->address.minimum = memory32->minimum; | ||
242 | addr->address.address_length = memory32->address_length; | ||
243 | addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; | ||
244 | return AE_OK; | ||
245 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | ||
246 | fixed_memory32 = &resource->data.fixed_memory32; | ||
247 | addr->resource_type = ACPI_MEMORY_RANGE; | ||
248 | addr->address.minimum = fixed_memory32->address; | ||
249 | addr->address.address_length = fixed_memory32->address_length; | ||
250 | addr->address.maximum = addr->address.minimum + addr->address.address_length - 1; | ||
251 | return AE_OK; | ||
252 | case ACPI_RESOURCE_TYPE_ADDRESS16: | ||
253 | case ACPI_RESOURCE_TYPE_ADDRESS32: | ||
254 | case ACPI_RESOURCE_TYPE_ADDRESS64: | ||
255 | status = acpi_resource_to_address64(resource, addr); | ||
256 | if (ACPI_SUCCESS(status) && | ||
257 | (addr->resource_type == ACPI_MEMORY_RANGE || | ||
258 | addr->resource_type == ACPI_IO_RANGE) && | ||
259 | addr->address.address_length > 0) { | ||
260 | return AE_OK; | ||
261 | } | ||
262 | break; | ||
263 | } | ||
264 | return AE_ERROR; | ||
265 | } | ||
266 | |||
267 | static acpi_status count_resource(struct acpi_resource *acpi_res, void *data) | ||
268 | { | 220 | { |
269 | struct pci_root_info *info = data; | 221 | LIST_HEAD(list); |
270 | struct acpi_resource_address64 addr; | 222 | struct resource *res1, *res2, *root = NULL; |
271 | acpi_status status; | 223 | struct resource_entry *tmp, *entry, *entry2; |
272 | |||
273 | status = resource_to_addr(acpi_res, &addr); | ||
274 | if (ACPI_SUCCESS(status)) | ||
275 | info->res_num++; | ||
276 | return AE_OK; | ||
277 | } | ||
278 | |||
279 | static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data) | ||
280 | { | ||
281 | struct pci_root_info *info = data; | ||
282 | struct resource *res; | ||
283 | struct acpi_resource_address64 addr; | ||
284 | acpi_status status; | ||
285 | unsigned long flags; | ||
286 | u64 start, orig_end, end; | ||
287 | |||
288 | status = resource_to_addr(acpi_res, &addr); | ||
289 | if (!ACPI_SUCCESS(status)) | ||
290 | return AE_OK; | ||
291 | |||
292 | if (addr.resource_type == ACPI_MEMORY_RANGE) { | ||
293 | flags = IORESOURCE_MEM; | ||
294 | if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) | ||
295 | flags |= IORESOURCE_PREFETCH; | ||
296 | } else if (addr.resource_type == ACPI_IO_RANGE) { | ||
297 | flags = IORESOURCE_IO; | ||
298 | } else | ||
299 | return AE_OK; | ||
300 | |||
301 | start = addr.address.minimum + addr.address.translation_offset; | ||
302 | orig_end = end = addr.address.maximum + addr.address.translation_offset; | ||
303 | |||
304 | /* Exclude non-addressable range or non-addressable portion of range */ | ||
305 | end = min(end, (u64)iomem_resource.end); | ||
306 | if (end <= start) { | ||
307 | dev_info(&info->bridge->dev, | ||
308 | "host bridge window [%#llx-%#llx] " | ||
309 | "(ignored, not CPU addressable)\n", start, orig_end); | ||
310 | return AE_OK; | ||
311 | } else if (orig_end != end) { | ||
312 | dev_info(&info->bridge->dev, | ||
313 | "host bridge window [%#llx-%#llx] " | ||
314 | "([%#llx-%#llx] ignored, not CPU addressable)\n", | ||
315 | start, orig_end, end + 1, orig_end); | ||
316 | } | ||
317 | 224 | ||
318 | res = &info->res[info->res_num]; | 225 | BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0); |
319 | res->name = info->name; | 226 | root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource; |
320 | res->flags = flags; | ||
321 | res->start = start; | ||
322 | res->end = end; | ||
323 | info->res_offset[info->res_num] = addr.address.translation_offset; | ||
324 | info->res_num++; | ||
325 | 227 | ||
326 | if (!pci_use_crs) | 228 | list_splice_init(crs_res, &list); |
327 | dev_printk(KERN_DEBUG, &info->bridge->dev, | 229 | resource_list_for_each_entry_safe(entry, tmp, &list) { |
328 | "host bridge window %pR (ignored)\n", res); | 230 | bool free = false; |
231 | resource_size_t end; | ||
329 | 232 | ||
330 | return AE_OK; | 233 | res1 = entry->res; |
331 | } | ||
332 | |||
333 | static void coalesce_windows(struct pci_root_info *info, unsigned long type) | ||
334 | { | ||
335 | int i, j; | ||
336 | struct resource *res1, *res2; | ||
337 | |||
338 | for (i = 0; i < info->res_num; i++) { | ||
339 | res1 = &info->res[i]; | ||
340 | if (!(res1->flags & type)) | 234 | if (!(res1->flags & type)) |
341 | continue; | 235 | goto next; |
236 | |||
237 | /* Exclude non-addressable range or non-addressable portion */ | ||
238 | end = min(res1->end, root->end); | ||
239 | if (end <= res1->start) { | ||
240 | dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n", | ||
241 | res1); | ||
242 | free = true; | ||
243 | goto next; | ||
244 | } else if (res1->end != end) { | ||
245 | dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n", | ||
246 | res1, (unsigned long long)end + 1, | ||
247 | (unsigned long long)res1->end); | ||
248 | res1->end = end; | ||
249 | } | ||
342 | 250 | ||
343 | for (j = i + 1; j < info->res_num; j++) { | 251 | resource_list_for_each_entry(entry2, crs_res) { |
344 | res2 = &info->res[j]; | 252 | res2 = entry2->res; |
345 | if (!(res2->flags & type)) | 253 | if (!(res2->flags & type)) |
346 | continue; | 254 | continue; |
347 | 255 | ||
@@ -353,118 +261,92 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type) | |||
353 | if (resource_overlaps(res1, res2)) { | 261 | if (resource_overlaps(res1, res2)) { |
354 | res2->start = min(res1->start, res2->start); | 262 | res2->start = min(res1->start, res2->start); |
355 | res2->end = max(res1->end, res2->end); | 263 | res2->end = max(res1->end, res2->end); |
356 | dev_info(&info->bridge->dev, | 264 | dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n", |
357 | "host bridge window expanded to %pR; %pR ignored\n", | ||
358 | res2, res1); | 265 | res2, res1); |
359 | res1->flags = 0; | 266 | free = true; |
267 | goto next; | ||
360 | } | 268 | } |
361 | } | 269 | } |
270 | |||
271 | next: | ||
272 | resource_list_del(entry); | ||
273 | if (free) | ||
274 | resource_list_free_entry(entry); | ||
275 | else | ||
276 | resource_list_add_tail(entry, crs_res); | ||
362 | } | 277 | } |
363 | } | 278 | } |
364 | 279 | ||
365 | static void add_resources(struct pci_root_info *info, | 280 | static void add_resources(struct pci_root_info *info, |
366 | struct list_head *resources) | 281 | struct list_head *resources, |
282 | struct list_head *crs_res) | ||
367 | { | 283 | { |
368 | int i; | 284 | struct resource_entry *entry, *tmp; |
369 | struct resource *res, *root, *conflict; | 285 | struct resource *res, *conflict, *root = NULL; |
370 | |||
371 | coalesce_windows(info, IORESOURCE_MEM); | ||
372 | coalesce_windows(info, IORESOURCE_IO); | ||
373 | 286 | ||
374 | for (i = 0; i < info->res_num; i++) { | 287 | validate_resources(&info->bridge->dev, crs_res, IORESOURCE_MEM); |
375 | res = &info->res[i]; | 288 | validate_resources(&info->bridge->dev, crs_res, IORESOURCE_IO); |
376 | 289 | ||
290 | resource_list_for_each_entry_safe(entry, tmp, crs_res) { | ||
291 | res = entry->res; | ||
377 | if (res->flags & IORESOURCE_MEM) | 292 | if (res->flags & IORESOURCE_MEM) |
378 | root = &iomem_resource; | 293 | root = &iomem_resource; |
379 | else if (res->flags & IORESOURCE_IO) | 294 | else if (res->flags & IORESOURCE_IO) |
380 | root = &ioport_resource; | 295 | root = &ioport_resource; |
381 | else | 296 | else |
382 | continue; | 297 | BUG_ON(res); |
383 | 298 | ||
384 | conflict = insert_resource_conflict(root, res); | 299 | conflict = insert_resource_conflict(root, res); |
385 | if (conflict) | 300 | if (conflict) { |
386 | dev_info(&info->bridge->dev, | 301 | dev_info(&info->bridge->dev, |
387 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", | 302 | "ignoring host bridge window %pR (conflicts with %s %pR)\n", |
388 | res, conflict->name, conflict); | 303 | res, conflict->name, conflict); |
389 | else | 304 | resource_list_destroy_entry(entry); |
390 | pci_add_resource_offset(resources, res, | 305 | } |
391 | info->res_offset[i]); | ||
392 | } | 306 | } |
393 | } | ||
394 | 307 | ||
395 | static void free_pci_root_info_res(struct pci_root_info *info) | 308 | list_splice_tail(crs_res, resources); |
396 | { | ||
397 | kfree(info->res); | ||
398 | info->res = NULL; | ||
399 | kfree(info->res_offset); | ||
400 | info->res_offset = NULL; | ||
401 | info->res_num = 0; | ||
402 | } | 309 | } |
403 | 310 | ||
404 | static void __release_pci_root_info(struct pci_root_info *info) | 311 | static void release_pci_root_info(struct pci_host_bridge *bridge) |
405 | { | 312 | { |
406 | int i; | ||
407 | struct resource *res; | 313 | struct resource *res; |
314 | struct resource_entry *entry; | ||
315 | struct pci_root_info *info = bridge->release_data; | ||
408 | 316 | ||
409 | for (i = 0; i < info->res_num; i++) { | 317 | resource_list_for_each_entry(entry, &bridge->windows) { |
410 | res = &info->res[i]; | 318 | res = entry->res; |
411 | 319 | if (res->parent && | |
412 | if (!res->parent) | 320 | (res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) |
413 | continue; | 321 | release_resource(res); |
414 | |||
415 | if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
416 | continue; | ||
417 | |||
418 | release_resource(res); | ||
419 | } | 322 | } |
420 | 323 | ||
421 | free_pci_root_info_res(info); | ||
422 | |||
423 | teardown_mcfg_map(info); | 324 | teardown_mcfg_map(info); |
424 | |||
425 | kfree(info); | 325 | kfree(info); |
426 | } | 326 | } |
427 | 327 | ||
428 | static void release_pci_root_info(struct pci_host_bridge *bridge) | ||
429 | { | ||
430 | struct pci_root_info *info = bridge->release_data; | ||
431 | |||
432 | __release_pci_root_info(info); | ||
433 | } | ||
434 | |||
435 | static void probe_pci_root_info(struct pci_root_info *info, | 328 | static void probe_pci_root_info(struct pci_root_info *info, |
436 | struct acpi_device *device, | 329 | struct acpi_device *device, |
437 | int busnum, int domain) | 330 | int busnum, int domain, |
331 | struct list_head *list) | ||
438 | { | 332 | { |
439 | size_t size; | 333 | int ret; |
334 | struct resource_entry *entry; | ||
440 | 335 | ||
441 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); | 336 | sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); |
442 | info->bridge = device; | 337 | info->bridge = device; |
443 | 338 | ret = acpi_dev_get_resources(device, list, | |
444 | info->res_num = 0; | 339 | acpi_dev_filter_resource_type_cb, |
445 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, | 340 | (void *)(IORESOURCE_IO | IORESOURCE_MEM)); |
446 | info); | 341 | if (ret < 0) |
447 | if (!info->res_num) | 342 | dev_warn(&device->dev, |
448 | return; | 343 | "failed to parse _CRS method, error code %d\n", ret); |
449 | 344 | else if (ret == 0) | |
450 | size = sizeof(*info->res) * info->res_num; | 345 | dev_dbg(&device->dev, |
451 | info->res = kzalloc_node(size, GFP_KERNEL, info->sd.node); | 346 | "no IO and memory resources present in _CRS\n"); |
452 | if (!info->res) { | 347 | else |
453 | info->res_num = 0; | 348 | resource_list_for_each_entry(entry, list) |
454 | return; | 349 | entry->res->name = info->name; |
455 | } | ||
456 | |||
457 | size = sizeof(*info->res_offset) * info->res_num; | ||
458 | info->res_num = 0; | ||
459 | info->res_offset = kzalloc_node(size, GFP_KERNEL, info->sd.node); | ||
460 | if (!info->res_offset) { | ||
461 | kfree(info->res); | ||
462 | info->res = NULL; | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, | ||
467 | info); | ||
468 | } | 350 | } |
469 | 351 | ||
470 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 352 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) |
@@ -473,6 +355,8 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
473 | struct pci_root_info *info; | 355 | struct pci_root_info *info; |
474 | int domain = root->segment; | 356 | int domain = root->segment; |
475 | int busnum = root->secondary.start; | 357 | int busnum = root->secondary.start; |
358 | struct resource_entry *res_entry; | ||
359 | LIST_HEAD(crs_res); | ||
476 | LIST_HEAD(resources); | 360 | LIST_HEAD(resources); |
477 | struct pci_bus *bus; | 361 | struct pci_bus *bus; |
478 | struct pci_sysdata *sd; | 362 | struct pci_sysdata *sd; |
@@ -520,18 +404,22 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
520 | memcpy(bus->sysdata, sd, sizeof(*sd)); | 404 | memcpy(bus->sysdata, sd, sizeof(*sd)); |
521 | kfree(info); | 405 | kfree(info); |
522 | } else { | 406 | } else { |
523 | probe_pci_root_info(info, device, busnum, domain); | ||
524 | |||
525 | /* insert busn res at first */ | 407 | /* insert busn res at first */ |
526 | pci_add_resource(&resources, &root->secondary); | 408 | pci_add_resource(&resources, &root->secondary); |
409 | |||
527 | /* | 410 | /* |
528 | * _CRS with no apertures is normal, so only fall back to | 411 | * _CRS with no apertures is normal, so only fall back to |
529 | * defaults or native bridge info if we're ignoring _CRS. | 412 | * defaults or native bridge info if we're ignoring _CRS. |
530 | */ | 413 | */ |
531 | if (pci_use_crs) | 414 | probe_pci_root_info(info, device, busnum, domain, &crs_res); |
532 | add_resources(info, &resources); | 415 | if (pci_use_crs) { |
533 | else { | 416 | add_resources(info, &resources, &crs_res); |
534 | free_pci_root_info_res(info); | 417 | } else { |
418 | resource_list_for_each_entry(res_entry, &crs_res) | ||
419 | dev_printk(KERN_DEBUG, &device->dev, | ||
420 | "host bridge window %pR (ignored)\n", | ||
421 | res_entry->res); | ||
422 | resource_list_free(&crs_res); | ||
535 | x86_pci_root_bus_resources(busnum, &resources); | 423 | x86_pci_root_bus_resources(busnum, &resources); |
536 | } | 424 | } |
537 | 425 | ||
@@ -546,8 +434,9 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
546 | to_pci_host_bridge(bus->bridge), | 434 | to_pci_host_bridge(bus->bridge), |
547 | release_pci_root_info, info); | 435 | release_pci_root_info, info); |
548 | } else { | 436 | } else { |
549 | pci_free_resource_list(&resources); | 437 | resource_list_free(&resources); |
550 | __release_pci_root_info(info); | 438 | teardown_mcfg_map(info); |
439 | kfree(info); | ||
551 | } | 440 | } |
552 | } | 441 | } |
553 | 442 | ||
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c index f3a2cfc14125..7bcf06a7cd12 100644 --- a/arch/x86/pci/bus_numa.c +++ b/arch/x86/pci/bus_numa.c | |||
@@ -31,7 +31,7 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) | |||
31 | { | 31 | { |
32 | struct pci_root_info *info = x86_find_pci_root_info(bus); | 32 | struct pci_root_info *info = x86_find_pci_root_info(bus); |
33 | struct pci_root_res *root_res; | 33 | struct pci_root_res *root_res; |
34 | struct pci_host_bridge_window *window; | 34 | struct resource_entry *window; |
35 | bool found = false; | 35 | bool found = false; |
36 | 36 | ||
37 | if (!info) | 37 | if (!info) |
@@ -41,7 +41,7 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources) | |||
41 | bus); | 41 | bus); |
42 | 42 | ||
43 | /* already added by acpi ? */ | 43 | /* already added by acpi ? */ |
44 | list_for_each_entry(window, resources, list) | 44 | resource_list_for_each_entry(window, resources) |
45 | if (window->res->flags & IORESOURCE_BUS) { | 45 | if (window->res->flags & IORESOURCE_BUS) { |
46 | found = true; | 46 | found = true; |
47 | break; | 47 | break; |
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 2fb384724ebb..3d2612b68694 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
@@ -513,6 +513,31 @@ void __init pcibios_set_cache_line_size(void) | |||
513 | } | 513 | } |
514 | } | 514 | } |
515 | 515 | ||
516 | /* | ||
517 | * Some device drivers assume dev->irq won't change after calling | ||
518 | * pci_disable_device(). So delay releasing of IRQ resource to driver | ||
519 | * unbinding time. Otherwise it will break PM subsystem and drivers | ||
520 | * like xen-pciback etc. | ||
521 | */ | ||
522 | static int pci_irq_notifier(struct notifier_block *nb, unsigned long action, | ||
523 | void *data) | ||
524 | { | ||
525 | struct pci_dev *dev = to_pci_dev(data); | ||
526 | |||
527 | if (action != BUS_NOTIFY_UNBOUND_DRIVER) | ||
528 | return NOTIFY_DONE; | ||
529 | |||
530 | if (pcibios_disable_irq) | ||
531 | pcibios_disable_irq(dev); | ||
532 | |||
533 | return NOTIFY_OK; | ||
534 | } | ||
535 | |||
536 | static struct notifier_block pci_irq_nb = { | ||
537 | .notifier_call = pci_irq_notifier, | ||
538 | .priority = INT_MIN, | ||
539 | }; | ||
540 | |||
516 | int __init pcibios_init(void) | 541 | int __init pcibios_init(void) |
517 | { | 542 | { |
518 | if (!raw_pci_ops) { | 543 | if (!raw_pci_ops) { |
@@ -525,6 +550,9 @@ int __init pcibios_init(void) | |||
525 | 550 | ||
526 | if (pci_bf_sort >= pci_force_bf) | 551 | if (pci_bf_sort >= pci_force_bf) |
527 | pci_sort_breadthfirst(); | 552 | pci_sort_breadthfirst(); |
553 | |||
554 | bus_register_notifier(&pci_bus_type, &pci_irq_nb); | ||
555 | |||
528 | return 0; | 556 | return 0; |
529 | } | 557 | } |
530 | 558 | ||
@@ -683,12 +711,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) | |||
683 | return 0; | 711 | return 0; |
684 | } | 712 | } |
685 | 713 | ||
686 | void pcibios_disable_device (struct pci_dev *dev) | ||
687 | { | ||
688 | if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq) | ||
689 | pcibios_disable_irq(dev); | ||
690 | } | ||
691 | |||
692 | int pci_ext_cfg_avail(void) | 714 | int pci_ext_cfg_avail(void) |
693 | { | 715 | { |
694 | if (raw_pci_ext_ops) | 716 | if (raw_pci_ext_ops) |
diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 44b9271580b5..95c2471f6819 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c | |||
@@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) | |||
234 | 234 | ||
235 | static void intel_mid_pci_irq_disable(struct pci_dev *dev) | 235 | static void intel_mid_pci_irq_disable(struct pci_dev *dev) |
236 | { | 236 | { |
237 | if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed && | 237 | if (dev->irq_managed && dev->irq > 0) { |
238 | dev->irq > 0) { | ||
239 | mp_unmap_irq(dev->irq); | 238 | mp_unmap_irq(dev->irq); |
240 | dev->irq_managed = 0; | 239 | dev->irq_managed = 0; |
240 | dev->irq = 0; | ||
241 | } | 241 | } |
242 | } | 242 | } |
243 | 243 | ||
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 5dc6ca5e1741..e71b3dbd87b8 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c | |||
@@ -1256,22 +1256,9 @@ static int pirq_enable_irq(struct pci_dev *dev) | |||
1256 | return 0; | 1256 | return 0; |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | bool mp_should_keep_irq(struct device *dev) | ||
1260 | { | ||
1261 | if (dev->power.is_prepared) | ||
1262 | return true; | ||
1263 | #ifdef CONFIG_PM | ||
1264 | if (dev->power.runtime_status == RPM_SUSPENDING) | ||
1265 | return true; | ||
1266 | #endif | ||
1267 | |||
1268 | return false; | ||
1269 | } | ||
1270 | |||
1271 | static void pirq_disable_irq(struct pci_dev *dev) | 1259 | static void pirq_disable_irq(struct pci_dev *dev) |
1272 | { | 1260 | { |
1273 | if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) && | 1261 | if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) { |
1274 | dev->irq_managed && dev->irq) { | ||
1275 | mp_unmap_irq(dev->irq); | 1262 | mp_unmap_irq(dev->irq); |
1276 | dev->irq = 0; | 1263 | dev->irq = 0; |
1277 | dev->irq_managed = 0; | 1264 | dev->irq_managed = 0; |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8951cefb0a96..e6c3ddd92665 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -315,6 +315,12 @@ config ACPI_HOTPLUG_MEMORY | |||
315 | To compile this driver as a module, choose M here: | 315 | To compile this driver as a module, choose M here: |
316 | the module will be called acpi_memhotplug. | 316 | the module will be called acpi_memhotplug. |
317 | 317 | ||
318 | config ACPI_HOTPLUG_IOAPIC | ||
319 | bool | ||
320 | depends on PCI | ||
321 | depends on X86_IO_APIC | ||
322 | default y | ||
323 | |||
318 | config ACPI_SBS | 324 | config ACPI_SBS |
319 | tristate "Smart Battery System" | 325 | tristate "Smart Battery System" |
320 | depends on X86 | 326 | depends on X86 |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 0071141b6bbc..b18cd2151ddb 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -70,6 +70,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o | |||
70 | obj-y += container.o | 70 | obj-y += container.o |
71 | obj-$(CONFIG_ACPI_THERMAL) += thermal.o | 71 | obj-$(CONFIG_ACPI_THERMAL) += thermal.o |
72 | obj-y += acpi_memhotplug.o | 72 | obj-y += acpi_memhotplug.o |
73 | obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o | ||
73 | obj-$(CONFIG_ACPI_BATTERY) += battery.o | 74 | obj-$(CONFIG_ACPI_BATTERY) += battery.o |
74 | obj-$(CONFIG_ACPI_SBS) += sbshc.o | 75 | obj-$(CONFIG_ACPI_SBS) += sbshc.o |
75 | obj-$(CONFIG_ACPI_SBS) += sbs.o | 76 | obj-$(CONFIG_ACPI_SBS) += sbs.o |
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 08fbff507dc4..02e835f3cf8a 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c | |||
@@ -307,7 +307,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
307 | { | 307 | { |
308 | struct lpss_device_desc *dev_desc; | 308 | struct lpss_device_desc *dev_desc; |
309 | struct lpss_private_data *pdata; | 309 | struct lpss_private_data *pdata; |
310 | struct resource_list_entry *rentry; | 310 | struct resource_entry *rentry; |
311 | struct list_head resource_list; | 311 | struct list_head resource_list; |
312 | struct platform_device *pdev; | 312 | struct platform_device *pdev; |
313 | int ret; | 313 | int ret; |
@@ -327,12 +327,12 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
327 | goto err_out; | 327 | goto err_out; |
328 | 328 | ||
329 | list_for_each_entry(rentry, &resource_list, node) | 329 | list_for_each_entry(rentry, &resource_list, node) |
330 | if (resource_type(&rentry->res) == IORESOURCE_MEM) { | 330 | if (resource_type(rentry->res) == IORESOURCE_MEM) { |
331 | if (dev_desc->prv_size_override) | 331 | if (dev_desc->prv_size_override) |
332 | pdata->mmio_size = dev_desc->prv_size_override; | 332 | pdata->mmio_size = dev_desc->prv_size_override; |
333 | else | 333 | else |
334 | pdata->mmio_size = resource_size(&rentry->res); | 334 | pdata->mmio_size = resource_size(rentry->res); |
335 | pdata->mmio_base = ioremap(rentry->res.start, | 335 | pdata->mmio_base = ioremap(rentry->res->start, |
336 | pdata->mmio_size); | 336 | pdata->mmio_size); |
337 | if (!pdata->mmio_base) | 337 | if (!pdata->mmio_base) |
338 | goto err_out; | 338 | goto err_out; |
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 6ba8beb6b9d2..1284138e42ab 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c | |||
@@ -45,7 +45,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) | |||
45 | struct platform_device *pdev = NULL; | 45 | struct platform_device *pdev = NULL; |
46 | struct acpi_device *acpi_parent; | 46 | struct acpi_device *acpi_parent; |
47 | struct platform_device_info pdevinfo; | 47 | struct platform_device_info pdevinfo; |
48 | struct resource_list_entry *rentry; | 48 | struct resource_entry *rentry; |
49 | struct list_head resource_list; | 49 | struct list_head resource_list; |
50 | struct resource *resources = NULL; | 50 | struct resource *resources = NULL; |
51 | int count; | 51 | int count; |
@@ -71,7 +71,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) | |||
71 | } | 71 | } |
72 | count = 0; | 72 | count = 0; |
73 | list_for_each_entry(rentry, &resource_list, node) | 73 | list_for_each_entry(rentry, &resource_list, node) |
74 | resources[count++] = rentry->res; | 74 | resources[count++] = *rentry->res; |
75 | 75 | ||
76 | acpi_dev_free_resource_list(&resource_list); | 76 | acpi_dev_free_resource_list(&resource_list); |
77 | } | 77 | } |
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 81ae69fde7d5..56b321aa2b1c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -35,6 +35,13 @@ void acpi_int340x_thermal_init(void); | |||
35 | int acpi_sysfs_init(void); | 35 | int acpi_sysfs_init(void); |
36 | void acpi_container_init(void); | 36 | void acpi_container_init(void); |
37 | void acpi_memory_hotplug_init(void); | 37 | void acpi_memory_hotplug_init(void); |
38 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC | ||
39 | int acpi_ioapic_add(struct acpi_pci_root *root); | ||
40 | int acpi_ioapic_remove(struct acpi_pci_root *root); | ||
41 | #else | ||
42 | static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } | ||
43 | static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } | ||
44 | #endif | ||
38 | #ifdef CONFIG_ACPI_DOCK | 45 | #ifdef CONFIG_ACPI_DOCK |
39 | void register_dock_dependent_device(struct acpi_device *adev, | 46 | void register_dock_dependent_device(struct acpi_device *adev, |
40 | acpi_handle dshandle); | 47 | acpi_handle dshandle); |
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c new file mode 100644 index 000000000000..ccdc8db16bb8 --- /dev/null +++ b/drivers/acpi/ioapic.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /* | ||
2 | * IOAPIC/IOxAPIC/IOSAPIC driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Fujitsu Limited. | ||
5 | * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. | ||
6 | * | ||
7 | * Copyright (C) 2014 Intel Corporation | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Based on original drivers/pci/ioapic.c | ||
14 | * Yinghai Lu <yinghai@kernel.org> | ||
15 | * Jiang Liu <jiang.liu@intel.com> | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * This driver manages I/O APICs added by hotplug after boot. | ||
20 | * We try to claim all I/O APIC devices, but those present at boot were | ||
21 | * registered when we parsed the ACPI MADT. | ||
22 | */ | ||
23 | |||
24 | #define pr_fmt(fmt) "ACPI : IOAPIC: " fmt | ||
25 | |||
26 | #include <linux/slab.h> | ||
27 | #include <linux/acpi.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <acpi/acpi.h> | ||
30 | |||
31 | struct acpi_pci_ioapic { | ||
32 | acpi_handle root_handle; | ||
33 | acpi_handle handle; | ||
34 | u32 gsi_base; | ||
35 | struct resource res; | ||
36 | struct pci_dev *pdev; | ||
37 | struct list_head list; | ||
38 | }; | ||
39 | |||
40 | static LIST_HEAD(ioapic_list); | ||
41 | static DEFINE_MUTEX(ioapic_list_lock); | ||
42 | |||
43 | static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) | ||
44 | { | ||
45 | struct resource *res = data; | ||
46 | struct resource_win win; | ||
47 | |||
48 | res->flags = 0; | ||
49 | if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM) == 0) | ||
50 | return AE_OK; | ||
51 | |||
52 | if (!acpi_dev_resource_memory(acpi_res, res)) { | ||
53 | if (acpi_dev_resource_address_space(acpi_res, &win) || | ||
54 | acpi_dev_resource_ext_address_space(acpi_res, &win)) | ||
55 | *res = win.res; | ||
56 | } | ||
57 | if ((res->flags & IORESOURCE_PREFETCH) || | ||
58 | (res->flags & IORESOURCE_DISABLED)) | ||
59 | res->flags = 0; | ||
60 | |||
61 | return AE_CTRL_TERMINATE; | ||
62 | } | ||
63 | |||
64 | static bool acpi_is_ioapic(acpi_handle handle, char **type) | ||
65 | { | ||
66 | acpi_status status; | ||
67 | struct acpi_device_info *info; | ||
68 | char *hid = NULL; | ||
69 | bool match = false; | ||
70 | |||
71 | if (!acpi_has_method(handle, "_GSB")) | ||
72 | return false; | ||
73 | |||
74 | status = acpi_get_object_info(handle, &info); | ||
75 | if (ACPI_SUCCESS(status)) { | ||
76 | if (info->valid & ACPI_VALID_HID) | ||
77 | hid = info->hardware_id.string; | ||
78 | if (hid) { | ||
79 | if (strcmp(hid, "ACPI0009") == 0) { | ||
80 | *type = "IOxAPIC"; | ||
81 | match = true; | ||
82 | } else if (strcmp(hid, "ACPI000A") == 0) { | ||
83 | *type = "IOAPIC"; | ||
84 | match = true; | ||
85 | } | ||
86 | } | ||
87 | kfree(info); | ||
88 | } | ||
89 | |||
90 | return match; | ||
91 | } | ||
92 | |||
93 | static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl, | ||
94 | void *context, void **rv) | ||
95 | { | ||
96 | acpi_status status; | ||
97 | unsigned long long gsi_base; | ||
98 | struct acpi_pci_ioapic *ioapic; | ||
99 | struct pci_dev *dev = NULL; | ||
100 | struct resource *res = NULL; | ||
101 | char *type = NULL; | ||
102 | |||
103 | if (!acpi_is_ioapic(handle, &type)) | ||
104 | return AE_OK; | ||
105 | |||
106 | mutex_lock(&ioapic_list_lock); | ||
107 | list_for_each_entry(ioapic, &ioapic_list, list) | ||
108 | if (ioapic->handle == handle) { | ||
109 | mutex_unlock(&ioapic_list_lock); | ||
110 | return AE_OK; | ||
111 | } | ||
112 | |||
113 | status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base); | ||
114 | if (ACPI_FAILURE(status)) { | ||
115 | acpi_handle_warn(handle, "failed to evaluate _GSB method\n"); | ||
116 | goto exit; | ||
117 | } | ||
118 | |||
119 | ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL); | ||
120 | if (!ioapic) { | ||
121 | pr_err("cannot allocate memory for new IOAPIC\n"); | ||
122 | goto exit; | ||
123 | } else { | ||
124 | ioapic->root_handle = (acpi_handle)context; | ||
125 | ioapic->handle = handle; | ||
126 | ioapic->gsi_base = (u32)gsi_base; | ||
127 | INIT_LIST_HEAD(&ioapic->list); | ||
128 | } | ||
129 | |||
130 | if (acpi_ioapic_registered(handle, (u32)gsi_base)) | ||
131 | goto done; | ||
132 | |||
133 | dev = acpi_get_pci_dev(handle); | ||
134 | if (dev && pci_resource_len(dev, 0)) { | ||
135 | if (pci_enable_device(dev) < 0) | ||
136 | goto exit_put; | ||
137 | pci_set_master(dev); | ||
138 | if (pci_request_region(dev, 0, type)) | ||
139 | goto exit_disable; | ||
140 | res = &dev->resource[0]; | ||
141 | ioapic->pdev = dev; | ||
142 | } else { | ||
143 | pci_dev_put(dev); | ||
144 | dev = NULL; | ||
145 | |||
146 | res = &ioapic->res; | ||
147 | acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res); | ||
148 | if (res->flags == 0) { | ||
149 | acpi_handle_warn(handle, "failed to get resource\n"); | ||
150 | goto exit_free; | ||
151 | } else if (request_resource(&iomem_resource, res)) { | ||
152 | acpi_handle_warn(handle, "failed to insert resource\n"); | ||
153 | goto exit_free; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) { | ||
158 | acpi_handle_warn(handle, "failed to register IOAPIC\n"); | ||
159 | goto exit_release; | ||
160 | } | ||
161 | done: | ||
162 | list_add(&ioapic->list, &ioapic_list); | ||
163 | mutex_unlock(&ioapic_list_lock); | ||
164 | |||
165 | if (dev) | ||
166 | dev_info(&dev->dev, "%s at %pR, GSI %u\n", | ||
167 | type, res, (u32)gsi_base); | ||
168 | else | ||
169 | acpi_handle_info(handle, "%s at %pR, GSI %u\n", | ||
170 | type, res, (u32)gsi_base); | ||
171 | |||
172 | return AE_OK; | ||
173 | |||
174 | exit_release: | ||
175 | if (dev) | ||
176 | pci_release_region(dev, 0); | ||
177 | else | ||
178 | release_resource(res); | ||
179 | exit_disable: | ||
180 | if (dev) | ||
181 | pci_disable_device(dev); | ||
182 | exit_put: | ||
183 | pci_dev_put(dev); | ||
184 | exit_free: | ||
185 | kfree(ioapic); | ||
186 | exit: | ||
187 | mutex_unlock(&ioapic_list_lock); | ||
188 | *(acpi_status *)rv = AE_ERROR; | ||
189 | return AE_OK; | ||
190 | } | ||
191 | |||
192 | int acpi_ioapic_add(struct acpi_pci_root *root) | ||
193 | { | ||
194 | acpi_status status, retval = AE_OK; | ||
195 | |||
196 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle, | ||
197 | UINT_MAX, handle_ioapic_add, NULL, | ||
198 | root->device->handle, (void **)&retval); | ||
199 | |||
200 | return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV; | ||
201 | } | ||
202 | |||
203 | int acpi_ioapic_remove(struct acpi_pci_root *root) | ||
204 | { | ||
205 | int retval = 0; | ||
206 | struct acpi_pci_ioapic *ioapic, *tmp; | ||
207 | |||
208 | mutex_lock(&ioapic_list_lock); | ||
209 | list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { | ||
210 | if (root->device->handle != ioapic->root_handle) | ||
211 | continue; | ||
212 | |||
213 | if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base)) | ||
214 | retval = -EBUSY; | ||
215 | |||
216 | if (ioapic->pdev) { | ||
217 | pci_release_region(ioapic->pdev, 0); | ||
218 | pci_disable_device(ioapic->pdev); | ||
219 | pci_dev_put(ioapic->pdev); | ||
220 | } else if (ioapic->res.flags && ioapic->res.parent) { | ||
221 | release_resource(&ioapic->res); | ||
222 | } | ||
223 | list_del(&ioapic->list); | ||
224 | kfree(ioapic); | ||
225 | } | ||
226 | mutex_unlock(&ioapic_list_lock); | ||
227 | |||
228 | return retval; | ||
229 | } | ||
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index b1def411c0b8..e7f718d6918a 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c | |||
@@ -485,14 +485,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) | |||
485 | if (!pin || !dev->irq_managed || dev->irq <= 0) | 485 | if (!pin || !dev->irq_managed || dev->irq <= 0) |
486 | return; | 486 | return; |
487 | 487 | ||
488 | /* Keep IOAPIC pin configuration when suspending */ | ||
489 | if (dev->dev.power.is_prepared) | ||
490 | return; | ||
491 | #ifdef CONFIG_PM | ||
492 | if (dev->dev.power.runtime_status == RPM_SUSPENDING) | ||
493 | return; | ||
494 | #endif | ||
495 | |||
496 | entry = acpi_pci_irq_lookup(dev, pin); | 488 | entry = acpi_pci_irq_lookup(dev, pin); |
497 | if (!entry) | 489 | if (!entry) |
498 | return; | 490 | return; |
@@ -513,5 +505,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) | |||
513 | if (gsi >= 0) { | 505 | if (gsi >= 0) { |
514 | acpi_unregister_gsi(gsi); | 506 | acpi_unregister_gsi(gsi); |
515 | dev->irq_managed = 0; | 507 | dev->irq_managed = 0; |
508 | dev->irq = 0; | ||
516 | } | 509 | } |
517 | } | 510 | } |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e53e0f659204..68a5f712cd19 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -621,6 +621,7 @@ static int acpi_pci_root_add(struct acpi_device *device, | |||
621 | if (hotadd) { | 621 | if (hotadd) { |
622 | pcibios_resource_survey_bus(root->bus); | 622 | pcibios_resource_survey_bus(root->bus); |
623 | pci_assign_unassigned_root_bus_resources(root->bus); | 623 | pci_assign_unassigned_root_bus_resources(root->bus); |
624 | acpi_ioapic_add(root); | ||
624 | } | 625 | } |
625 | 626 | ||
626 | pci_lock_rescan_remove(); | 627 | pci_lock_rescan_remove(); |
@@ -644,6 +645,8 @@ static void acpi_pci_root_remove(struct acpi_device *device) | |||
644 | 645 | ||
645 | pci_stop_root_bus(root->bus); | 646 | pci_stop_root_bus(root->bus); |
646 | 647 | ||
648 | WARN_ON(acpi_ioapic_remove(root)); | ||
649 | |||
647 | device_set_run_wake(root->bus->bridge, false); | 650 | device_set_run_wake(root->bus->bridge, false); |
648 | pci_acpi_remove_bus_pm_notifier(device); | 651 | pci_acpi_remove_bus_pm_notifier(device); |
649 | 652 | ||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02e48394276c..7962651cdbd4 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
@@ -4,6 +4,10 @@ | |||
4 | * | 4 | * |
5 | * Alex Chiang <achiang@hp.com> | 5 | * Alex Chiang <achiang@hp.com> |
6 | * - Unified x86/ia64 implementations | 6 | * - Unified x86/ia64 implementations |
7 | * | ||
8 | * I/O APIC hotplug support | ||
9 | * Yinghai Lu <yinghai@kernel.org> | ||
10 | * Jiang Liu <jiang.liu@intel.com> | ||
7 | */ | 11 | */ |
8 | #include <linux/export.h> | 12 | #include <linux/export.h> |
9 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
@@ -12,6 +16,21 @@ | |||
12 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT | 16 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT |
13 | ACPI_MODULE_NAME("processor_core"); | 17 | ACPI_MODULE_NAME("processor_core"); |
14 | 18 | ||
19 | static struct acpi_table_madt *get_madt_table(void) | ||
20 | { | ||
21 | static struct acpi_table_madt *madt; | ||
22 | static int read_madt; | ||
23 | |||
24 | if (!read_madt) { | ||
25 | if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, | ||
26 | (struct acpi_table_header **)&madt))) | ||
27 | madt = NULL; | ||
28 | read_madt++; | ||
29 | } | ||
30 | |||
31 | return madt; | ||
32 | } | ||
33 | |||
15 | static int map_lapic_id(struct acpi_subtable_header *entry, | 34 | static int map_lapic_id(struct acpi_subtable_header *entry, |
16 | u32 acpi_id, int *apic_id) | 35 | u32 acpi_id, int *apic_id) |
17 | { | 36 | { |
@@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, | |||
67 | static int map_madt_entry(int type, u32 acpi_id) | 86 | static int map_madt_entry(int type, u32 acpi_id) |
68 | { | 87 | { |
69 | unsigned long madt_end, entry; | 88 | unsigned long madt_end, entry; |
70 | static struct acpi_table_madt *madt; | ||
71 | static int read_madt; | ||
72 | int phys_id = -1; /* CPU hardware ID */ | 89 | int phys_id = -1; /* CPU hardware ID */ |
90 | struct acpi_table_madt *madt; | ||
73 | 91 | ||
74 | if (!read_madt) { | 92 | madt = get_madt_table(); |
75 | if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, | ||
76 | (struct acpi_table_header **)&madt))) | ||
77 | madt = NULL; | ||
78 | read_madt++; | ||
79 | } | ||
80 | |||
81 | if (!madt) | 93 | if (!madt) |
82 | return phys_id; | 94 | return phys_id; |
83 | 95 | ||
@@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) | |||
203 | return acpi_map_cpuid(phys_id, acpi_id); | 215 | return acpi_map_cpuid(phys_id, acpi_id); |
204 | } | 216 | } |
205 | EXPORT_SYMBOL_GPL(acpi_get_cpuid); | 217 | EXPORT_SYMBOL_GPL(acpi_get_cpuid); |
218 | |||
219 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC | ||
220 | static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, | ||
221 | u64 *phys_addr, int *ioapic_id) | ||
222 | { | ||
223 | struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; | ||
224 | |||
225 | if (ioapic->global_irq_base != gsi_base) | ||
226 | return 0; | ||
227 | |||
228 | *phys_addr = ioapic->address; | ||
229 | *ioapic_id = ioapic->id; | ||
230 | return 1; | ||
231 | } | ||
232 | |||
233 | static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr) | ||
234 | { | ||
235 | struct acpi_subtable_header *hdr; | ||
236 | unsigned long madt_end, entry; | ||
237 | struct acpi_table_madt *madt; | ||
238 | int apic_id = -1; | ||
239 | |||
240 | madt = get_madt_table(); | ||
241 | if (!madt) | ||
242 | return apic_id; | ||
243 | |||
244 | entry = (unsigned long)madt; | ||
245 | madt_end = entry + madt->header.length; | ||
246 | |||
247 | /* Parse all entries looking for a match. */ | ||
248 | entry += sizeof(struct acpi_table_madt); | ||
249 | while (entry + sizeof(struct acpi_subtable_header) < madt_end) { | ||
250 | hdr = (struct acpi_subtable_header *)entry; | ||
251 | if (hdr->type == ACPI_MADT_TYPE_IO_APIC && | ||
252 | get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id)) | ||
253 | break; | ||
254 | else | ||
255 | entry += hdr->length; | ||
256 | } | ||
257 | |||
258 | return apic_id; | ||
259 | } | ||
260 | |||
261 | static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, | ||
262 | u64 *phys_addr) | ||
263 | { | ||
264 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
265 | struct acpi_subtable_header *header; | ||
266 | union acpi_object *obj; | ||
267 | int apic_id = -1; | ||
268 | |||
269 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) | ||
270 | goto exit; | ||
271 | |||
272 | if (!buffer.length || !buffer.pointer) | ||
273 | goto exit; | ||
274 | |||
275 | obj = buffer.pointer; | ||
276 | if (obj->type != ACPI_TYPE_BUFFER || | ||
277 | obj->buffer.length < sizeof(struct acpi_subtable_header)) | ||
278 | goto exit; | ||
279 | |||
280 | header = (struct acpi_subtable_header *)obj->buffer.pointer; | ||
281 | if (header->type == ACPI_MADT_TYPE_IO_APIC) | ||
282 | get_ioapic_id(header, gsi_base, phys_addr, &apic_id); | ||
283 | |||
284 | exit: | ||
285 | kfree(buffer.pointer); | ||
286 | return apic_id; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base | ||
291 | * @handle: ACPI object for IOAPIC device | ||
292 | * @gsi_base: GSI base to match with | ||
293 | * @phys_addr: Pointer to store physical address of matching IOAPIC record | ||
294 | * | ||
295 | * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search | ||
296 | * for an ACPI IOAPIC record matching @gsi_base. | ||
297 | * Return IOAPIC id and store physical address in @phys_addr if found a match, | ||
298 | * otherwise return <0. | ||
299 | */ | ||
300 | int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr) | ||
301 | { | ||
302 | int apic_id; | ||
303 | |||
304 | apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr); | ||
305 | if (apic_id == -1) | ||
306 | apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr); | ||
307 | |||
308 | return apic_id; | ||
309 | } | ||
310 | #endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */ | ||
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index d0a4d90c6bcc..4752b9939987 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c | |||
@@ -34,21 +34,34 @@ | |||
34 | #define valid_IRQ(i) (true) | 34 | #define valid_IRQ(i) (true) |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect, | 37 | static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) |
38 | bool window) | ||
39 | { | 38 | { |
40 | unsigned long flags = IORESOURCE_MEM; | 39 | u64 reslen = end - start + 1; |
41 | 40 | ||
42 | if (len == 0) | 41 | /* |
43 | flags |= IORESOURCE_DISABLED; | 42 | * CHECKME: len might be required to check versus a minimum |
43 | * length as well. 1 for io is fine, but for memory it does | ||
44 | * not make any sense at all. | ||
45 | */ | ||
46 | if (len && reslen && reslen == len && start <= end) | ||
47 | return true; | ||
44 | 48 | ||
45 | if (write_protect == ACPI_READ_WRITE_MEMORY) | 49 | pr_info("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", |
46 | flags |= IORESOURCE_MEM_WRITEABLE; | 50 | io ? "io" : "mem", start, end, len); |
51 | |||
52 | return false; | ||
53 | } | ||
54 | |||
55 | static void acpi_dev_memresource_flags(struct resource *res, u64 len, | ||
56 | u8 write_protect) | ||
57 | { | ||
58 | res->flags = IORESOURCE_MEM; | ||
47 | 59 | ||
48 | if (window) | 60 | if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) |
49 | flags |= IORESOURCE_WINDOW; | 61 | res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; |
50 | 62 | ||
51 | return flags; | 63 | if (write_protect == ACPI_READ_WRITE_MEMORY) |
64 | res->flags |= IORESOURCE_MEM_WRITEABLE; | ||
52 | } | 65 | } |
53 | 66 | ||
54 | static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, | 67 | static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, |
@@ -56,7 +69,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, | |||
56 | { | 69 | { |
57 | res->start = start; | 70 | res->start = start; |
58 | res->end = start + len - 1; | 71 | res->end = start + len - 1; |
59 | res->flags = acpi_dev_memresource_flags(len, write_protect, false); | 72 | acpi_dev_memresource_flags(res, len, write_protect); |
60 | } | 73 | } |
61 | 74 | ||
62 | /** | 75 | /** |
@@ -67,6 +80,11 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, | |||
67 | * Check if the given ACPI resource object represents a memory resource and | 80 | * Check if the given ACPI resource object represents a memory resource and |
68 | * if that's the case, use the information in it to populate the generic | 81 | * if that's the case, use the information in it to populate the generic |
69 | * resource object pointed to by @res. | 82 | * resource object pointed to by @res. |
83 | * | ||
84 | * Return: | ||
85 | * 1) false with res->flags setting to zero: not the expected resource type | ||
86 | * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource | ||
87 | * 3) true: valid assigned resource | ||
70 | */ | 88 | */ |
71 | bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) | 89 | bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) |
72 | { | 90 | { |
@@ -77,60 +95,52 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) | |||
77 | switch (ares->type) { | 95 | switch (ares->type) { |
78 | case ACPI_RESOURCE_TYPE_MEMORY24: | 96 | case ACPI_RESOURCE_TYPE_MEMORY24: |
79 | memory24 = &ares->data.memory24; | 97 | memory24 = &ares->data.memory24; |
80 | if (!memory24->minimum && !memory24->address_length) | 98 | acpi_dev_get_memresource(res, memory24->minimum << 8, |
81 | return false; | 99 | memory24->address_length << 8, |
82 | acpi_dev_get_memresource(res, memory24->minimum, | ||
83 | memory24->address_length, | ||
84 | memory24->write_protect); | 100 | memory24->write_protect); |
85 | break; | 101 | break; |
86 | case ACPI_RESOURCE_TYPE_MEMORY32: | 102 | case ACPI_RESOURCE_TYPE_MEMORY32: |
87 | memory32 = &ares->data.memory32; | 103 | memory32 = &ares->data.memory32; |
88 | if (!memory32->minimum && !memory32->address_length) | ||
89 | return false; | ||
90 | acpi_dev_get_memresource(res, memory32->minimum, | 104 | acpi_dev_get_memresource(res, memory32->minimum, |
91 | memory32->address_length, | 105 | memory32->address_length, |
92 | memory32->write_protect); | 106 | memory32->write_protect); |
93 | break; | 107 | break; |
94 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | 108 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
95 | fixed_memory32 = &ares->data.fixed_memory32; | 109 | fixed_memory32 = &ares->data.fixed_memory32; |
96 | if (!fixed_memory32->address && !fixed_memory32->address_length) | ||
97 | return false; | ||
98 | acpi_dev_get_memresource(res, fixed_memory32->address, | 110 | acpi_dev_get_memresource(res, fixed_memory32->address, |
99 | fixed_memory32->address_length, | 111 | fixed_memory32->address_length, |
100 | fixed_memory32->write_protect); | 112 | fixed_memory32->write_protect); |
101 | break; | 113 | break; |
102 | default: | 114 | default: |
115 | res->flags = 0; | ||
103 | return false; | 116 | return false; |
104 | } | 117 | } |
105 | return true; | 118 | |
119 | return !(res->flags & IORESOURCE_DISABLED); | ||
106 | } | 120 | } |
107 | EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); | 121 | EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); |
108 | 122 | ||
109 | static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode, | 123 | static void acpi_dev_ioresource_flags(struct resource *res, u64 len, |
110 | bool window) | 124 | u8 io_decode) |
111 | { | 125 | { |
112 | int flags = IORESOURCE_IO; | 126 | res->flags = IORESOURCE_IO; |
113 | 127 | ||
114 | if (io_decode == ACPI_DECODE_16) | 128 | if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) |
115 | flags |= IORESOURCE_IO_16BIT_ADDR; | 129 | res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; |
116 | 130 | ||
117 | if (start > end || end >= 0x10003) | 131 | if (res->end >= 0x10003) |
118 | flags |= IORESOURCE_DISABLED; | 132 | res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; |
119 | 133 | ||
120 | if (window) | 134 | if (io_decode == ACPI_DECODE_16) |
121 | flags |= IORESOURCE_WINDOW; | 135 | res->flags |= IORESOURCE_IO_16BIT_ADDR; |
122 | |||
123 | return flags; | ||
124 | } | 136 | } |
125 | 137 | ||
126 | 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, |
127 | u8 io_decode) | 139 | u8 io_decode) |
128 | { | 140 | { |
129 | u64 end = start + len - 1; | ||
130 | |||
131 | res->start = start; | 141 | res->start = start; |
132 | res->end = end; | 142 | res->end = start + len - 1; |
133 | res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false); | 143 | acpi_dev_ioresource_flags(res, len, io_decode); |
134 | } | 144 | } |
135 | 145 | ||
136 | /** | 146 | /** |
@@ -141,6 +151,11 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, | |||
141 | * Check if the given ACPI resource object represents an I/O resource and | 151 | * Check if the given ACPI resource object represents an I/O resource and |
142 | * if that's the case, use the information in it to populate the generic | 152 | * if that's the case, use the information in it to populate the generic |
143 | * resource object pointed to by @res. | 153 | * resource object pointed to by @res. |
154 | * | ||
155 | * Return: | ||
156 | * 1) false with res->flags setting to zero: not the expected resource type | ||
157 | * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource | ||
158 | * 3) true: valid assigned resource | ||
144 | */ | 159 | */ |
145 | bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) | 160 | bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) |
146 | { | 161 | { |
@@ -150,135 +165,143 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) | |||
150 | switch (ares->type) { | 165 | switch (ares->type) { |
151 | case ACPI_RESOURCE_TYPE_IO: | 166 | case ACPI_RESOURCE_TYPE_IO: |
152 | io = &ares->data.io; | 167 | io = &ares->data.io; |
153 | if (!io->minimum && !io->address_length) | ||
154 | return false; | ||
155 | acpi_dev_get_ioresource(res, io->minimum, | 168 | acpi_dev_get_ioresource(res, io->minimum, |
156 | io->address_length, | 169 | io->address_length, |
157 | io->io_decode); | 170 | io->io_decode); |
158 | break; | 171 | break; |
159 | case ACPI_RESOURCE_TYPE_FIXED_IO: | 172 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
160 | fixed_io = &ares->data.fixed_io; | 173 | fixed_io = &ares->data.fixed_io; |
161 | if (!fixed_io->address && !fixed_io->address_length) | ||
162 | return false; | ||
163 | acpi_dev_get_ioresource(res, fixed_io->address, | 174 | acpi_dev_get_ioresource(res, fixed_io->address, |
164 | fixed_io->address_length, | 175 | fixed_io->address_length, |
165 | ACPI_DECODE_10); | 176 | ACPI_DECODE_10); |
166 | break; | 177 | break; |
167 | default: | 178 | default: |
179 | res->flags = 0; | ||
168 | return false; | 180 | return false; |
169 | } | 181 | } |
170 | return true; | 182 | |
183 | return !(res->flags & IORESOURCE_DISABLED); | ||
171 | } | 184 | } |
172 | EXPORT_SYMBOL_GPL(acpi_dev_resource_io); | 185 | EXPORT_SYMBOL_GPL(acpi_dev_resource_io); |
173 | 186 | ||
174 | /** | 187 | static bool acpi_decode_space(struct resource_win *win, |
175 | * acpi_dev_resource_address_space - Extract ACPI address space information. | 188 | struct acpi_resource_address *addr, |
176 | * @ares: Input ACPI resource object. | 189 | struct acpi_address64_attribute *attr) |
177 | * @res: Output generic resource object. | ||
178 | * | ||
179 | * Check if the given ACPI resource object represents an address space resource | ||
180 | * and if that's the case, use the information in it to populate the generic | ||
181 | * resource object pointed to by @res. | ||
182 | */ | ||
183 | bool acpi_dev_resource_address_space(struct acpi_resource *ares, | ||
184 | struct resource *res) | ||
185 | { | 190 | { |
186 | acpi_status status; | 191 | u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; |
187 | struct acpi_resource_address64 addr; | 192 | bool wp = addr->info.mem.write_protect; |
188 | bool window; | 193 | u64 len = attr->address_length; |
189 | u64 len; | 194 | struct resource *res = &win->res; |
190 | u8 io_decode; | ||
191 | 195 | ||
192 | switch (ares->type) { | 196 | /* |
193 | case ACPI_RESOURCE_TYPE_ADDRESS16: | 197 | * Filter out invalid descriptor according to ACPI Spec 5.0, section |
194 | case ACPI_RESOURCE_TYPE_ADDRESS32: | 198 | * 6.4.3.5 Address Space Resource Descriptors. |
195 | case ACPI_RESOURCE_TYPE_ADDRESS64: | 199 | */ |
196 | break; | 200 | if ((addr->min_address_fixed != addr->max_address_fixed && len) || |
197 | default: | 201 | (addr->min_address_fixed && addr->max_address_fixed && !len)) |
198 | return false; | 202 | pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n", |
199 | } | 203 | addr->min_address_fixed, addr->max_address_fixed, len); |
200 | 204 | ||
201 | status = acpi_resource_to_address64(ares, &addr); | 205 | res->start = attr->minimum; |
202 | if (ACPI_FAILURE(status)) | 206 | res->end = attr->maximum; |
203 | return false; | ||
204 | 207 | ||
205 | res->start = addr.address.minimum; | 208 | /* |
206 | res->end = addr.address.maximum; | 209 | * For bridges that translate addresses across the bridge, |
207 | window = addr.producer_consumer == ACPI_PRODUCER; | 210 | * translation_offset is the offset that must be added to the |
211 | * address on the secondary side to obtain the address on the | ||
212 | * primary side. Non-bridge devices must list 0 for all Address | ||
213 | * Translation offset bits. | ||
214 | */ | ||
215 | if (addr->producer_consumer == ACPI_PRODUCER) { | ||
216 | res->start += attr->translation_offset; | ||
217 | res->end += attr->translation_offset; | ||
218 | } else if (attr->translation_offset) { | ||
219 | pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n", | ||
220 | attr->translation_offset); | ||
221 | } | ||
208 | 222 | ||
209 | switch(addr.resource_type) { | 223 | switch (addr->resource_type) { |
210 | case ACPI_MEMORY_RANGE: | 224 | case ACPI_MEMORY_RANGE: |
211 | len = addr.address.maximum - addr.address.minimum + 1; | 225 | acpi_dev_memresource_flags(res, len, wp); |
212 | res->flags = acpi_dev_memresource_flags(len, | ||
213 | addr.info.mem.write_protect, | ||
214 | window); | ||
215 | break; | 226 | break; |
216 | case ACPI_IO_RANGE: | 227 | case ACPI_IO_RANGE: |
217 | io_decode = addr.address.granularity == 0xfff ? | 228 | acpi_dev_ioresource_flags(res, len, iodec); |
218 | ACPI_DECODE_10 : ACPI_DECODE_16; | ||
219 | res->flags = acpi_dev_ioresource_flags(addr.address.minimum, | ||
220 | addr.address.maximum, | ||
221 | io_decode, window); | ||
222 | break; | 229 | break; |
223 | case ACPI_BUS_NUMBER_RANGE: | 230 | case ACPI_BUS_NUMBER_RANGE: |
224 | res->flags = IORESOURCE_BUS; | 231 | res->flags = IORESOURCE_BUS; |
225 | break; | 232 | break; |
226 | default: | 233 | default: |
227 | res->flags = 0; | 234 | return false; |
228 | } | 235 | } |
229 | 236 | ||
230 | return true; | 237 | win->offset = attr->translation_offset; |
238 | |||
239 | if (addr->producer_consumer == ACPI_PRODUCER) | ||
240 | res->flags |= IORESOURCE_WINDOW; | ||
241 | |||
242 | if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) | ||
243 | res->flags |= IORESOURCE_PREFETCH; | ||
244 | |||
245 | return !(res->flags & IORESOURCE_DISABLED); | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * acpi_dev_resource_address_space - Extract ACPI address space information. | ||
250 | * @ares: Input ACPI resource object. | ||
251 | * @win: Output generic resource object. | ||
252 | * | ||
253 | * Check if the given ACPI resource object represents an address space resource | ||
254 | * and if that's the case, use the information in it to populate the generic | ||
255 | * resource object pointed to by @win. | ||
256 | * | ||
257 | * Return: | ||
258 | * 1) false with win->res.flags setting to zero: not the expected resource type | ||
259 | * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned | ||
260 | * resource | ||
261 | * 3) true: valid assigned resource | ||
262 | */ | ||
263 | bool acpi_dev_resource_address_space(struct acpi_resource *ares, | ||
264 | struct resource_win *win) | ||
265 | { | ||
266 | struct acpi_resource_address64 addr; | ||
267 | |||
268 | win->res.flags = 0; | ||
269 | if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) | ||
270 | return false; | ||
271 | |||
272 | return acpi_decode_space(win, (struct acpi_resource_address *)&addr, | ||
273 | &addr.address); | ||
231 | } | 274 | } |
232 | EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); | 275 | EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); |
233 | 276 | ||
234 | /** | 277 | /** |
235 | * acpi_dev_resource_ext_address_space - Extract ACPI address space information. | 278 | * acpi_dev_resource_ext_address_space - Extract ACPI address space information. |
236 | * @ares: Input ACPI resource object. | 279 | * @ares: Input ACPI resource object. |
237 | * @res: Output generic resource object. | 280 | * @win: Output generic resource object. |
238 | * | 281 | * |
239 | * Check if the given ACPI resource object represents an extended address space | 282 | * Check if the given ACPI resource object represents an extended address space |
240 | * resource and if that's the case, use the information in it to populate the | 283 | * resource and if that's the case, use the information in it to populate the |
241 | * generic resource object pointed to by @res. | 284 | * generic resource object pointed to by @win. |
285 | * | ||
286 | * Return: | ||
287 | * 1) false with win->res.flags setting to zero: not the expected resource type | ||
288 | * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned | ||
289 | * resource | ||
290 | * 3) true: valid assigned resource | ||
242 | */ | 291 | */ |
243 | bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, | 292 | bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, |
244 | struct resource *res) | 293 | struct resource_win *win) |
245 | { | 294 | { |
246 | struct acpi_resource_extended_address64 *ext_addr; | 295 | struct acpi_resource_extended_address64 *ext_addr; |
247 | bool window; | ||
248 | u64 len; | ||
249 | u8 io_decode; | ||
250 | 296 | ||
297 | win->res.flags = 0; | ||
251 | if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) | 298 | if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) |
252 | return false; | 299 | return false; |
253 | 300 | ||
254 | ext_addr = &ares->data.ext_address64; | 301 | ext_addr = &ares->data.ext_address64; |
255 | 302 | ||
256 | res->start = ext_addr->address.minimum; | 303 | return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr, |
257 | res->end = ext_addr->address.maximum; | 304 | &ext_addr->address); |
258 | window = ext_addr->producer_consumer == ACPI_PRODUCER; | ||
259 | |||
260 | switch(ext_addr->resource_type) { | ||
261 | case ACPI_MEMORY_RANGE: | ||
262 | len = ext_addr->address.maximum - ext_addr->address.minimum + 1; | ||
263 | res->flags = acpi_dev_memresource_flags(len, | ||
264 | ext_addr->info.mem.write_protect, | ||
265 | window); | ||
266 | break; | ||
267 | case ACPI_IO_RANGE: | ||
268 | io_decode = ext_addr->address.granularity == 0xfff ? | ||
269 | ACPI_DECODE_10 : ACPI_DECODE_16; | ||
270 | res->flags = acpi_dev_ioresource_flags(ext_addr->address.minimum, | ||
271 | ext_addr->address.maximum, | ||
272 | io_decode, window); | ||
273 | break; | ||
274 | case ACPI_BUS_NUMBER_RANGE: | ||
275 | res->flags = IORESOURCE_BUS; | ||
276 | break; | ||
277 | default: | ||
278 | res->flags = 0; | ||
279 | } | ||
280 | |||
281 | return true; | ||
282 | } | 305 | } |
283 | EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); | 306 | EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); |
284 | 307 | ||
@@ -310,7 +333,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) | |||
310 | { | 333 | { |
311 | res->start = gsi; | 334 | res->start = gsi; |
312 | res->end = gsi; | 335 | res->end = gsi; |
313 | res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; | 336 | res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; |
314 | } | 337 | } |
315 | 338 | ||
316 | static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, | 339 | static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, |
@@ -369,6 +392,11 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, | |||
369 | * represented by the resource and populate the generic resource object pointed | 392 | * represented by the resource and populate the generic resource object pointed |
370 | * to by @res accordingly. If the registration of the GSI is not successful, | 393 | * to by @res accordingly. If the registration of the GSI is not successful, |
371 | * IORESOURCE_DISABLED will be set it that object's flags. | 394 | * IORESOURCE_DISABLED will be set it that object's flags. |
395 | * | ||
396 | * Return: | ||
397 | * 1) false with res->flags setting to zero: not the expected resource type | ||
398 | * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource | ||
399 | * 3) true: valid assigned resource | ||
372 | */ | 400 | */ |
373 | bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, | 401 | bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, |
374 | struct resource *res) | 402 | struct resource *res) |
@@ -402,6 +430,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, | |||
402 | ext_irq->sharable, false); | 430 | ext_irq->sharable, false); |
403 | break; | 431 | break; |
404 | default: | 432 | default: |
433 | res->flags = 0; | ||
405 | return false; | 434 | return false; |
406 | } | 435 | } |
407 | 436 | ||
@@ -415,12 +444,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); | |||
415 | */ | 444 | */ |
416 | void acpi_dev_free_resource_list(struct list_head *list) | 445 | void acpi_dev_free_resource_list(struct list_head *list) |
417 | { | 446 | { |
418 | struct resource_list_entry *rentry, *re; | 447 | resource_list_free(list); |
419 | |||
420 | list_for_each_entry_safe(rentry, re, list, node) { | ||
421 | list_del(&rentry->node); | ||
422 | kfree(rentry); | ||
423 | } | ||
424 | } | 448 | } |
425 | EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); | 449 | EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); |
426 | 450 | ||
@@ -432,18 +456,19 @@ struct res_proc_context { | |||
432 | int error; | 456 | int error; |
433 | }; | 457 | }; |
434 | 458 | ||
435 | static acpi_status acpi_dev_new_resource_entry(struct resource *r, | 459 | static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, |
436 | struct res_proc_context *c) | 460 | struct res_proc_context *c) |
437 | { | 461 | { |
438 | struct resource_list_entry *rentry; | 462 | struct resource_entry *rentry; |
439 | 463 | ||
440 | rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); | 464 | rentry = resource_list_create_entry(NULL, 0); |
441 | if (!rentry) { | 465 | if (!rentry) { |
442 | c->error = -ENOMEM; | 466 | c->error = -ENOMEM; |
443 | return AE_NO_MEMORY; | 467 | return AE_NO_MEMORY; |
444 | } | 468 | } |
445 | rentry->res = *r; | 469 | *rentry->res = win->res; |
446 | list_add_tail(&rentry->node, c->list); | 470 | rentry->offset = win->offset; |
471 | resource_list_add_tail(rentry, c->list); | ||
447 | c->count++; | 472 | c->count++; |
448 | return AE_OK; | 473 | return AE_OK; |
449 | } | 474 | } |
@@ -452,7 +477,8 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, | |||
452 | void *context) | 477 | void *context) |
453 | { | 478 | { |
454 | struct res_proc_context *c = context; | 479 | struct res_proc_context *c = context; |
455 | struct resource r; | 480 | struct resource_win win; |
481 | struct resource *res = &win.res; | ||
456 | int i; | 482 | int i; |
457 | 483 | ||
458 | if (c->preproc) { | 484 | if (c->preproc) { |
@@ -467,18 +493,18 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, | |||
467 | } | 493 | } |
468 | } | 494 | } |
469 | 495 | ||
470 | memset(&r, 0, sizeof(r)); | 496 | memset(&win, 0, sizeof(win)); |
471 | 497 | ||
472 | if (acpi_dev_resource_memory(ares, &r) | 498 | if (acpi_dev_resource_memory(ares, res) |
473 | || acpi_dev_resource_io(ares, &r) | 499 | || acpi_dev_resource_io(ares, res) |
474 | || acpi_dev_resource_address_space(ares, &r) | 500 | || acpi_dev_resource_address_space(ares, &win) |
475 | || acpi_dev_resource_ext_address_space(ares, &r)) | 501 | || acpi_dev_resource_ext_address_space(ares, &win)) |
476 | return acpi_dev_new_resource_entry(&r, c); | 502 | return acpi_dev_new_resource_entry(&win, c); |
477 | 503 | ||
478 | for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { | 504 | for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) { |
479 | acpi_status status; | 505 | acpi_status status; |
480 | 506 | ||
481 | status = acpi_dev_new_resource_entry(&r, c); | 507 | status = acpi_dev_new_resource_entry(&win, c); |
482 | if (ACPI_FAILURE(status)) | 508 | if (ACPI_FAILURE(status)) |
483 | return status; | 509 | return status; |
484 | } | 510 | } |
@@ -503,7 +529,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, | |||
503 | * returned as the final error code. | 529 | * returned as the final error code. |
504 | * | 530 | * |
505 | * The resultant struct resource objects are put on the list pointed to by | 531 | * The resultant struct resource objects are put on the list pointed to by |
506 | * @list, that must be empty initially, as members of struct resource_list_entry | 532 | * @list, that must be empty initially, as members of struct resource_entry |
507 | * objects. Callers of this routine should use %acpi_dev_free_resource_list() to | 533 | * objects. Callers of this routine should use %acpi_dev_free_resource_list() to |
508 | * free that list. | 534 | * free that list. |
509 | * | 535 | * |
@@ -538,3 +564,58 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, | |||
538 | return c.count; | 564 | return c.count; |
539 | } | 565 | } |
540 | EXPORT_SYMBOL_GPL(acpi_dev_get_resources); | 566 | EXPORT_SYMBOL_GPL(acpi_dev_get_resources); |
567 | |||
568 | /** | ||
569 | * acpi_dev_filter_resource_type - Filter ACPI resource according to resource | ||
570 | * types | ||
571 | * @ares: Input ACPI resource object. | ||
572 | * @types: Valid resource types of IORESOURCE_XXX | ||
573 | * | ||
574 | * This is a hepler function to support acpi_dev_get_resources(), which filters | ||
575 | * ACPI resource objects according to resource types. | ||
576 | */ | ||
577 | int acpi_dev_filter_resource_type(struct acpi_resource *ares, | ||
578 | unsigned long types) | ||
579 | { | ||
580 | unsigned long type = 0; | ||
581 | |||
582 | switch (ares->type) { | ||
583 | case ACPI_RESOURCE_TYPE_MEMORY24: | ||
584 | case ACPI_RESOURCE_TYPE_MEMORY32: | ||
585 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | ||
586 | type = IORESOURCE_MEM; | ||
587 | break; | ||
588 | case ACPI_RESOURCE_TYPE_IO: | ||
589 | case ACPI_RESOURCE_TYPE_FIXED_IO: | ||
590 | type = IORESOURCE_IO; | ||
591 | break; | ||
592 | case ACPI_RESOURCE_TYPE_IRQ: | ||
593 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | ||
594 | type = IORESOURCE_IRQ; | ||
595 | break; | ||
596 | case ACPI_RESOURCE_TYPE_DMA: | ||
597 | case ACPI_RESOURCE_TYPE_FIXED_DMA: | ||
598 | type = IORESOURCE_DMA; | ||
599 | break; | ||
600 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | ||
601 | type = IORESOURCE_REG; | ||
602 | break; | ||
603 | case ACPI_RESOURCE_TYPE_ADDRESS16: | ||
604 | case ACPI_RESOURCE_TYPE_ADDRESS32: | ||
605 | case ACPI_RESOURCE_TYPE_ADDRESS64: | ||
606 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | ||
607 | if (ares->data.address.resource_type == ACPI_MEMORY_RANGE) | ||
608 | type = IORESOURCE_MEM; | ||
609 | else if (ares->data.address.resource_type == ACPI_IO_RANGE) | ||
610 | type = IORESOURCE_IO; | ||
611 | else if (ares->data.address.resource_type == | ||
612 | ACPI_BUS_NUMBER_RANGE) | ||
613 | type = IORESOURCE_BUS; | ||
614 | break; | ||
615 | default: | ||
616 | break; | ||
617 | } | ||
618 | |||
619 | return (type & types) ? 0 : 1; | ||
620 | } | ||
621 | EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); | ||
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index de361a156b34..5a635646e05c 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c | |||
@@ -43,7 +43,7 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, | |||
43 | { | 43 | { |
44 | const struct acpi_csrt_shared_info *si; | 44 | const struct acpi_csrt_shared_info *si; |
45 | struct list_head resource_list; | 45 | struct list_head resource_list; |
46 | struct resource_list_entry *rentry; | 46 | struct resource_entry *rentry; |
47 | resource_size_t mem = 0, irq = 0; | 47 | resource_size_t mem = 0, irq = 0; |
48 | int ret; | 48 | int ret; |
49 | 49 | ||
@@ -56,10 +56,10 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, | |||
56 | return 0; | 56 | return 0; |
57 | 57 | ||
58 | list_for_each_entry(rentry, &resource_list, node) { | 58 | list_for_each_entry(rentry, &resource_list, node) { |
59 | if (resource_type(&rentry->res) == IORESOURCE_MEM) | 59 | if (resource_type(rentry->res) == IORESOURCE_MEM) |
60 | mem = rentry->res.start; | 60 | mem = rentry->res->start; |
61 | else if (resource_type(&rentry->res) == IORESOURCE_IRQ) | 61 | else if (resource_type(rentry->res) == IORESOURCE_IRQ) |
62 | irq = rentry->res.start; | 62 | irq = rentry->res->start; |
63 | } | 63 | } |
64 | 64 | ||
65 | acpi_dev_free_resource_list(&resource_list); | 65 | acpi_dev_free_resource_list(&resource_list); |
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 88471d3d98cd..62426d81a4d6 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c | |||
@@ -140,6 +140,7 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, | |||
140 | unsigned char busno, unsigned char bus_max, | 140 | unsigned char busno, unsigned char bus_max, |
141 | struct list_head *resources, resource_size_t *io_base) | 141 | struct list_head *resources, resource_size_t *io_base) |
142 | { | 142 | { |
143 | struct resource_entry *window; | ||
143 | struct resource *res; | 144 | struct resource *res; |
144 | struct resource *bus_range; | 145 | struct resource *bus_range; |
145 | struct of_pci_range range; | 146 | struct of_pci_range range; |
@@ -225,6 +226,8 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, | |||
225 | conversion_failed: | 226 | conversion_failed: |
226 | kfree(res); | 227 | kfree(res); |
227 | parse_failed: | 228 | parse_failed: |
229 | resource_list_for_each_entry(window, resources) | ||
230 | kfree(window->res); | ||
228 | pci_free_resource_list(resources); | 231 | pci_free_resource_list(resources); |
229 | return err; | 232 | return err; |
230 | } | 233 | } |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 8fb16188cd82..90fa3a78fb7c 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
@@ -20,17 +20,16 @@ | |||
20 | void pci_add_resource_offset(struct list_head *resources, struct resource *res, | 20 | void pci_add_resource_offset(struct list_head *resources, struct resource *res, |
21 | resource_size_t offset) | 21 | resource_size_t offset) |
22 | { | 22 | { |
23 | struct pci_host_bridge_window *window; | 23 | struct resource_entry *entry; |
24 | 24 | ||
25 | window = kzalloc(sizeof(struct pci_host_bridge_window), GFP_KERNEL); | 25 | entry = resource_list_create_entry(res, 0); |
26 | if (!window) { | 26 | if (!entry) { |
27 | printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res); | 27 | printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res); |
28 | return; | 28 | return; |
29 | } | 29 | } |
30 | 30 | ||
31 | window->res = res; | 31 | entry->offset = offset; |
32 | window->offset = offset; | 32 | resource_list_add_tail(entry, resources); |
33 | list_add_tail(&window->list, resources); | ||
34 | } | 33 | } |
35 | EXPORT_SYMBOL(pci_add_resource_offset); | 34 | EXPORT_SYMBOL(pci_add_resource_offset); |
36 | 35 | ||
@@ -42,12 +41,7 @@ EXPORT_SYMBOL(pci_add_resource); | |||
42 | 41 | ||
43 | void pci_free_resource_list(struct list_head *resources) | 42 | void pci_free_resource_list(struct list_head *resources) |
44 | { | 43 | { |
45 | struct pci_host_bridge_window *window, *tmp; | 44 | resource_list_free(resources); |
46 | |||
47 | list_for_each_entry_safe(window, tmp, resources, list) { | ||
48 | list_del(&window->list); | ||
49 | kfree(window); | ||
50 | } | ||
51 | } | 45 | } |
52 | EXPORT_SYMBOL(pci_free_resource_list); | 46 | EXPORT_SYMBOL(pci_free_resource_list); |
53 | 47 | ||
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c index 0e5f3c95af5b..39b2dbe585aa 100644 --- a/drivers/pci/host-bridge.c +++ b/drivers/pci/host-bridge.c | |||
@@ -35,10 +35,10 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, | |||
35 | struct resource *res) | 35 | struct resource *res) |
36 | { | 36 | { |
37 | struct pci_host_bridge *bridge = find_pci_host_bridge(bus); | 37 | struct pci_host_bridge *bridge = find_pci_host_bridge(bus); |
38 | struct pci_host_bridge_window *window; | 38 | struct resource_entry *window; |
39 | resource_size_t offset = 0; | 39 | resource_size_t offset = 0; |
40 | 40 | ||
41 | list_for_each_entry(window, &bridge->windows, list) { | 41 | resource_list_for_each_entry(window, &bridge->windows) { |
42 | if (resource_contains(window->res, res)) { | 42 | if (resource_contains(window->res, res)) { |
43 | offset = window->offset; | 43 | offset = window->offset; |
44 | break; | 44 | break; |
@@ -60,10 +60,10 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res, | |||
60 | struct pci_bus_region *region) | 60 | struct pci_bus_region *region) |
61 | { | 61 | { |
62 | struct pci_host_bridge *bridge = find_pci_host_bridge(bus); | 62 | struct pci_host_bridge *bridge = find_pci_host_bridge(bus); |
63 | struct pci_host_bridge_window *window; | 63 | struct resource_entry *window; |
64 | resource_size_t offset = 0; | 64 | resource_size_t offset = 0; |
65 | 65 | ||
66 | list_for_each_entry(window, &bridge->windows, list) { | 66 | resource_list_for_each_entry(window, &bridge->windows) { |
67 | struct pci_bus_region bus_region; | 67 | struct pci_bus_region bus_region; |
68 | 68 | ||
69 | if (resource_type(res) != resource_type(window->res)) | 69 | if (resource_type(res) != resource_type(window->res)) |
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 6eb1aa75bd37..aee3c620ecf9 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c | |||
@@ -149,14 +149,14 @@ static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) | |||
149 | struct device *dev = pci->host.dev.parent; | 149 | struct device *dev = pci->host.dev.parent; |
150 | struct device_node *np = dev->of_node; | 150 | struct device_node *np = dev->of_node; |
151 | resource_size_t iobase; | 151 | resource_size_t iobase; |
152 | struct pci_host_bridge_window *win; | 152 | struct resource_entry *win; |
153 | 153 | ||
154 | err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, | 154 | err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, |
155 | &iobase); | 155 | &iobase); |
156 | if (err) | 156 | if (err) |
157 | return err; | 157 | return err; |
158 | 158 | ||
159 | list_for_each_entry(win, &pci->resources, list) { | 159 | resource_list_for_each_entry(win, &pci->resources) { |
160 | struct resource *parent, *res = win->res; | 160 | struct resource *parent, *res = win->res; |
161 | 161 | ||
162 | switch (resource_type(res)) { | 162 | switch (resource_type(res)) { |
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index b1d0596457c5..a704257bab7f 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c | |||
@@ -401,11 +401,11 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, | |||
401 | struct list_head *res, | 401 | struct list_head *res, |
402 | resource_size_t io_base) | 402 | resource_size_t io_base) |
403 | { | 403 | { |
404 | struct pci_host_bridge_window *window; | 404 | struct resource_entry *window; |
405 | struct device *dev = port->dev; | 405 | struct device *dev = port->dev; |
406 | int ret; | 406 | int ret; |
407 | 407 | ||
408 | list_for_each_entry(window, res, list) { | 408 | resource_list_for_each_entry(window, res) { |
409 | struct resource *res = window->res; | 409 | struct resource *res = window->res; |
410 | u64 restype = resource_type(res); | 410 | u64 restype = resource_type(res); |
411 | 411 | ||
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index ef3ebaf9a738..601261df7663 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c | |||
@@ -737,7 +737,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port) | |||
737 | resource_size_t offset; | 737 | resource_size_t offset; |
738 | struct of_pci_range_parser parser; | 738 | struct of_pci_range_parser parser; |
739 | struct of_pci_range range; | 739 | struct of_pci_range range; |
740 | struct pci_host_bridge_window *win; | 740 | struct resource_entry *win; |
741 | int err = 0, mem_resno = 0; | 741 | int err = 0, mem_resno = 0; |
742 | 742 | ||
743 | /* Get the ranges */ | 743 | /* Get the ranges */ |
@@ -807,7 +807,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port) | |||
807 | 807 | ||
808 | free_resources: | 808 | free_resources: |
809 | release_child_resources(&iomem_resource); | 809 | release_child_resources(&iomem_resource); |
810 | list_for_each_entry(win, &port->resources, list) | 810 | resource_list_for_each_entry(win, &port->resources) |
811 | devm_kfree(dev, win->res); | 811 | devm_kfree(dev, win->res); |
812 | pci_free_resource_list(&port->resources); | 812 | pci_free_resource_list(&port->resources); |
813 | 813 | ||
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 23212f8ae09b..8d2f400e96cb 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1895,7 +1895,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1895 | int error; | 1895 | int error; |
1896 | struct pci_host_bridge *bridge; | 1896 | struct pci_host_bridge *bridge; |
1897 | struct pci_bus *b, *b2; | 1897 | struct pci_bus *b, *b2; |
1898 | struct pci_host_bridge_window *window, *n; | 1898 | struct resource_entry *window, *n; |
1899 | struct resource *res; | 1899 | struct resource *res; |
1900 | resource_size_t offset; | 1900 | resource_size_t offset; |
1901 | char bus_addr[64]; | 1901 | char bus_addr[64]; |
@@ -1959,8 +1959,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, | |||
1959 | printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev)); | 1959 | printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev)); |
1960 | 1960 | ||
1961 | /* Add initial resources to the bus */ | 1961 | /* Add initial resources to the bus */ |
1962 | list_for_each_entry_safe(window, n, resources, list) { | 1962 | resource_list_for_each_entry_safe(window, n, resources) { |
1963 | list_move_tail(&window->list, &bridge->windows); | 1963 | list_move_tail(&window->node, &bridge->windows); |
1964 | res = window->res; | 1964 | res = window->res; |
1965 | offset = window->offset; | 1965 | offset = window->offset; |
1966 | if (res->flags & IORESOURCE_BUS) | 1966 | if (res->flags & IORESOURCE_BUS) |
@@ -2060,12 +2060,12 @@ void pci_bus_release_busn_res(struct pci_bus *b) | |||
2060 | struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, | 2060 | struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, |
2061 | struct pci_ops *ops, void *sysdata, struct list_head *resources) | 2061 | struct pci_ops *ops, void *sysdata, struct list_head *resources) |
2062 | { | 2062 | { |
2063 | struct pci_host_bridge_window *window; | 2063 | struct resource_entry *window; |
2064 | bool found = false; | 2064 | bool found = false; |
2065 | struct pci_bus *b; | 2065 | struct pci_bus *b; |
2066 | int max; | 2066 | int max; |
2067 | 2067 | ||
2068 | list_for_each_entry(window, resources, list) | 2068 | resource_list_for_each_entry(window, resources) |
2069 | if (window->res->flags & IORESOURCE_BUS) { | 2069 | if (window->res->flags & IORESOURCE_BUS) { |
2070 | found = true; | 2070 | found = true; |
2071 | break; | 2071 | break; |
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 2d9bc789af0f..ff0356fb378f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -180,20 +180,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
180 | struct pnp_dev *dev = data; | 180 | struct pnp_dev *dev = data; |
181 | struct acpi_resource_dma *dma; | 181 | struct acpi_resource_dma *dma; |
182 | struct acpi_resource_vendor_typed *vendor_typed; | 182 | struct acpi_resource_vendor_typed *vendor_typed; |
183 | struct resource r = {0}; | 183 | struct resource_win win = {{0}, 0}; |
184 | struct resource *r = &win.res; | ||
184 | int i, flags; | 185 | int i, flags; |
185 | 186 | ||
186 | if (acpi_dev_resource_address_space(res, &r) | 187 | if (acpi_dev_resource_address_space(res, &win) |
187 | || acpi_dev_resource_ext_address_space(res, &r)) { | 188 | || acpi_dev_resource_ext_address_space(res, &win)) { |
188 | pnp_add_resource(dev, &r); | 189 | pnp_add_resource(dev, &win.res); |
189 | return AE_OK; | 190 | return AE_OK; |
190 | } | 191 | } |
191 | 192 | ||
192 | r.flags = 0; | 193 | r->flags = 0; |
193 | if (acpi_dev_resource_interrupt(res, 0, &r)) { | 194 | if (acpi_dev_resource_interrupt(res, 0, r)) { |
194 | pnpacpi_add_irqresource(dev, &r); | 195 | pnpacpi_add_irqresource(dev, r); |
195 | for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) | 196 | for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++) |
196 | pnpacpi_add_irqresource(dev, &r); | 197 | pnpacpi_add_irqresource(dev, r); |
197 | 198 | ||
198 | if (i > 1) { | 199 | if (i > 1) { |
199 | /* | 200 | /* |
@@ -209,7 +210,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
209 | } | 210 | } |
210 | } | 211 | } |
211 | return AE_OK; | 212 | return AE_OK; |
212 | } else if (r.flags & IORESOURCE_DISABLED) { | 213 | } else if (r->flags & IORESOURCE_DISABLED) { |
213 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); | 214 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); |
214 | return AE_OK; | 215 | return AE_OK; |
215 | } | 216 | } |
@@ -218,13 +219,13 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
218 | case ACPI_RESOURCE_TYPE_MEMORY24: | 219 | case ACPI_RESOURCE_TYPE_MEMORY24: |
219 | case ACPI_RESOURCE_TYPE_MEMORY32: | 220 | case ACPI_RESOURCE_TYPE_MEMORY32: |
220 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | 221 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
221 | if (acpi_dev_resource_memory(res, &r)) | 222 | if (acpi_dev_resource_memory(res, r)) |
222 | pnp_add_resource(dev, &r); | 223 | pnp_add_resource(dev, r); |
223 | break; | 224 | break; |
224 | case ACPI_RESOURCE_TYPE_IO: | 225 | case ACPI_RESOURCE_TYPE_IO: |
225 | case ACPI_RESOURCE_TYPE_FIXED_IO: | 226 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
226 | if (acpi_dev_resource_io(res, &r)) | 227 | if (acpi_dev_resource_io(res, r)) |
227 | pnp_add_resource(dev, &r); | 228 | pnp_add_resource(dev, r); |
228 | break; | 229 | break; |
229 | case ACPI_RESOURCE_TYPE_DMA: | 230 | case ACPI_RESOURCE_TYPE_DMA: |
230 | dma = &res->data.dma; | 231 | dma = &res->data.dma; |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d459cd17b477..24c7aa8b1d20 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
29 | #include <linux/ioport.h> /* for struct resource */ | 29 | #include <linux/ioport.h> /* for struct resource */ |
30 | #include <linux/resource_ext.h> | ||
30 | #include <linux/device.h> | 31 | #include <linux/device.h> |
31 | #include <linux/property.h> | 32 | #include <linux/property.h> |
32 | 33 | ||
@@ -151,6 +152,10 @@ int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu); | |||
151 | int acpi_unmap_cpu(int cpu); | 152 | int acpi_unmap_cpu(int cpu); |
152 | #endif /* CONFIG_ACPI_HOTPLUG_CPU */ | 153 | #endif /* CONFIG_ACPI_HOTPLUG_CPU */ |
153 | 154 | ||
155 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC | ||
156 | int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr); | ||
157 | #endif | ||
158 | |||
154 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); | 159 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); |
155 | int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); | 160 | int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); |
156 | int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base); | 161 | int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base); |
@@ -288,22 +293,25 @@ extern int pnpacpi_disabled; | |||
288 | bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res); | 293 | bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res); |
289 | bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res); | 294 | bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res); |
290 | bool acpi_dev_resource_address_space(struct acpi_resource *ares, | 295 | bool acpi_dev_resource_address_space(struct acpi_resource *ares, |
291 | struct resource *res); | 296 | struct resource_win *win); |
292 | bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, | 297 | bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, |
293 | struct resource *res); | 298 | struct resource_win *win); |
294 | unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); | 299 | unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); |
295 | bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, | 300 | bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, |
296 | struct resource *res); | 301 | struct resource *res); |
297 | 302 | ||
298 | struct resource_list_entry { | ||
299 | struct list_head node; | ||
300 | struct resource res; | ||
301 | }; | ||
302 | |||
303 | void acpi_dev_free_resource_list(struct list_head *list); | 303 | void acpi_dev_free_resource_list(struct list_head *list); |
304 | int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, | 304 | int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, |
305 | int (*preproc)(struct acpi_resource *, void *), | 305 | int (*preproc)(struct acpi_resource *, void *), |
306 | void *preproc_data); | 306 | void *preproc_data); |
307 | int acpi_dev_filter_resource_type(struct acpi_resource *ares, | ||
308 | unsigned long types); | ||
309 | |||
310 | static inline int acpi_dev_filter_resource_type_cb(struct acpi_resource *ares, | ||
311 | void *arg) | ||
312 | { | ||
313 | return acpi_dev_filter_resource_type(ares, (unsigned long)arg); | ||
314 | } | ||
307 | 315 | ||
308 | int acpi_check_resource_conflict(const struct resource *res); | 316 | int acpi_check_resource_conflict(const struct resource *res); |
309 | 317 | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index 9603094ed59b..faa60fa26314 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/atomic.h> | 29 | #include <linux/atomic.h> |
30 | #include <linux/device.h> | 30 | #include <linux/device.h> |
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/resource_ext.h> | ||
32 | #include <uapi/linux/pci.h> | 33 | #include <uapi/linux/pci.h> |
33 | 34 | ||
34 | #include <linux/pci_ids.h> | 35 | #include <linux/pci_ids.h> |
@@ -397,16 +398,10 @@ static inline int pci_channel_offline(struct pci_dev *pdev) | |||
397 | return (pdev->error_state != pci_channel_io_normal); | 398 | return (pdev->error_state != pci_channel_io_normal); |
398 | } | 399 | } |
399 | 400 | ||
400 | struct pci_host_bridge_window { | ||
401 | struct list_head list; | ||
402 | struct resource *res; /* host bridge aperture (CPU address) */ | ||
403 | resource_size_t offset; /* bus address + offset = CPU address */ | ||
404 | }; | ||
405 | |||
406 | struct pci_host_bridge { | 401 | struct pci_host_bridge { |
407 | struct device dev; | 402 | struct device dev; |
408 | struct pci_bus *bus; /* root bus */ | 403 | struct pci_bus *bus; /* root bus */ |
409 | struct list_head windows; /* pci_host_bridge_windows */ | 404 | struct list_head windows; /* resource_entry */ |
410 | void (*release_fn)(struct pci_host_bridge *); | 405 | void (*release_fn)(struct pci_host_bridge *); |
411 | void *release_data; | 406 | void *release_data; |
412 | }; | 407 | }; |
diff --git a/include/linux/resource_ext.h b/include/linux/resource_ext.h new file mode 100644 index 000000000000..e2bf63d881d4 --- /dev/null +++ b/include/linux/resource_ext.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015, Intel Corporation | ||
3 | * Author: Jiang Liu <jiang.liu@linux.intel.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | #ifndef _LINUX_RESOURCE_EXT_H | ||
15 | #define _LINUX_RESOURCE_EXT_H | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/list.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | /* Represent resource window for bridge devices */ | ||
22 | struct resource_win { | ||
23 | struct resource res; /* In master (CPU) address space */ | ||
24 | resource_size_t offset; /* Translation offset for bridge */ | ||
25 | }; | ||
26 | |||
27 | /* | ||
28 | * Common resource list management data structure and interfaces to support | ||
29 | * ACPI, PNP and PCI host bridge etc. | ||
30 | */ | ||
31 | struct resource_entry { | ||
32 | struct list_head node; | ||
33 | struct resource *res; /* In master (CPU) address space */ | ||
34 | resource_size_t offset; /* Translation offset for bridge */ | ||
35 | struct resource __res; /* Default storage for res */ | ||
36 | }; | ||
37 | |||
38 | extern struct resource_entry * | ||
39 | resource_list_create_entry(struct resource *res, size_t extra_size); | ||
40 | extern void resource_list_free(struct list_head *head); | ||
41 | |||
42 | static inline void resource_list_add(struct resource_entry *entry, | ||
43 | struct list_head *head) | ||
44 | { | ||
45 | list_add(&entry->node, head); | ||
46 | } | ||
47 | |||
48 | static inline void resource_list_add_tail(struct resource_entry *entry, | ||
49 | struct list_head *head) | ||
50 | { | ||
51 | list_add_tail(&entry->node, head); | ||
52 | } | ||
53 | |||
54 | static inline void resource_list_del(struct resource_entry *entry) | ||
55 | { | ||
56 | list_del(&entry->node); | ||
57 | } | ||
58 | |||
59 | static inline void resource_list_free_entry(struct resource_entry *entry) | ||
60 | { | ||
61 | kfree(entry); | ||
62 | } | ||
63 | |||
64 | static inline void | ||
65 | resource_list_destroy_entry(struct resource_entry *entry) | ||
66 | { | ||
67 | resource_list_del(entry); | ||
68 | resource_list_free_entry(entry); | ||
69 | } | ||
70 | |||
71 | #define resource_list_for_each_entry(entry, list) \ | ||
72 | list_for_each_entry((entry), (list), node) | ||
73 | |||
74 | #define resource_list_for_each_entry_safe(entry, tmp, list) \ | ||
75 | list_for_each_entry_safe((entry), (tmp), (list), node) | ||
76 | |||
77 | #endif /* _LINUX_RESOURCE_EXT_H */ | ||
diff --git a/kernel/resource.c b/kernel/resource.c index 0bcebffc4e77..19f2357dfda3 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/pfn.h> | 23 | #include <linux/pfn.h> |
24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
25 | #include <linux/resource_ext.h> | ||
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
26 | 27 | ||
27 | 28 | ||
@@ -1529,6 +1530,30 @@ int iomem_is_exclusive(u64 addr) | |||
1529 | return err; | 1530 | return err; |
1530 | } | 1531 | } |
1531 | 1532 | ||
1533 | struct resource_entry *resource_list_create_entry(struct resource *res, | ||
1534 | size_t extra_size) | ||
1535 | { | ||
1536 | struct resource_entry *entry; | ||
1537 | |||
1538 | entry = kzalloc(sizeof(*entry) + extra_size, GFP_KERNEL); | ||
1539 | if (entry) { | ||
1540 | INIT_LIST_HEAD(&entry->node); | ||
1541 | entry->res = res ? res : &entry->__res; | ||
1542 | } | ||
1543 | |||
1544 | return entry; | ||
1545 | } | ||
1546 | EXPORT_SYMBOL(resource_list_create_entry); | ||
1547 | |||
1548 | void resource_list_free(struct list_head *head) | ||
1549 | { | ||
1550 | struct resource_entry *entry, *tmp; | ||
1551 | |||
1552 | list_for_each_entry_safe(entry, tmp, head, node) | ||
1553 | resource_list_destroy_entry(entry); | ||
1554 | } | ||
1555 | EXPORT_SYMBOL(resource_list_free); | ||
1556 | |||
1532 | static int __init strict_iomem(char *str) | 1557 | static int __init strict_iomem(char *str) |
1533 | { | 1558 | { |
1534 | if (strstr(str, "relaxed")) | 1559 | if (strstr(str, "relaxed")) |