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")) |
