diff options
| -rw-r--r-- | drivers/acpi/apei/apei-base.c | 102 | ||||
| -rw-r--r-- | drivers/acpi/apei/apei-internal.h | 3 | ||||
| -rw-r--r-- | drivers/acpi/apei/ghes.c | 10 | ||||
| -rw-r--r-- | drivers/acpi/osl.c | 40 | ||||
| -rw-r--r-- | include/linux/acpi_io.h | 3 |
5 files changed, 133 insertions, 25 deletions
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 4abb6c74a93..e45350cb6ac 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c | |||
| @@ -34,13 +34,13 @@ | |||
| 34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <linux/acpi.h> | 36 | #include <linux/acpi.h> |
| 37 | #include <linux/acpi_io.h> | ||
| 37 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
| 38 | #include <linux/io.h> | 39 | #include <linux/io.h> |
| 39 | #include <linux/kref.h> | 40 | #include <linux/kref.h> |
| 40 | #include <linux/rculist.h> | 41 | #include <linux/rculist.h> |
| 41 | #include <linux/interrupt.h> | 42 | #include <linux/interrupt.h> |
| 42 | #include <linux/debugfs.h> | 43 | #include <linux/debugfs.h> |
| 43 | #include <acpi/atomicio.h> | ||
| 44 | 44 | ||
| 45 | #include "apei-internal.h" | 45 | #include "apei-internal.h" |
| 46 | 46 | ||
| @@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val) | |||
| 70 | { | 70 | { |
| 71 | int rc; | 71 | int rc; |
| 72 | 72 | ||
| 73 | rc = acpi_atomic_read(val, &entry->register_region); | 73 | rc = apei_read(val, &entry->register_region); |
| 74 | if (rc) | 74 | if (rc) |
| 75 | return rc; | 75 | return rc; |
| 76 | *val >>= entry->register_region.bit_offset; | 76 | *val >>= entry->register_region.bit_offset; |
| @@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val) | |||
| 116 | val <<= entry->register_region.bit_offset; | 116 | val <<= entry->register_region.bit_offset; |
| 117 | if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { | 117 | if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { |
| 118 | u64 valr = 0; | 118 | u64 valr = 0; |
| 119 | rc = acpi_atomic_read(&valr, &entry->register_region); | 119 | rc = apei_read(&valr, &entry->register_region); |
| 120 | if (rc) | 120 | if (rc) |
| 121 | return rc; | 121 | return rc; |
| 122 | valr &= ~(entry->mask << entry->register_region.bit_offset); | 122 | valr &= ~(entry->mask << entry->register_region.bit_offset); |
| 123 | val |= valr; | 123 | val |= valr; |
| 124 | } | 124 | } |
| 125 | rc = acpi_atomic_write(val, &entry->register_region); | 125 | rc = apei_write(val, &entry->register_region); |
| 126 | 126 | ||
| 127 | return rc; | 127 | return rc; |
| 128 | } | 128 | } |
| @@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx, | |||
| 243 | u8 ins = entry->instruction; | 243 | u8 ins = entry->instruction; |
| 244 | 244 | ||
| 245 | if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) | 245 | if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) |
| 246 | return acpi_pre_map_gar(&entry->register_region); | 246 | return acpi_os_map_generic_address(&entry->register_region); |
| 247 | 247 | ||
| 248 | return 0; | 248 | return 0; |
| 249 | } | 249 | } |
| @@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx, | |||
| 276 | u8 ins = entry->instruction; | 276 | u8 ins = entry->instruction; |
| 277 | 277 | ||
| 278 | if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) | 278 | if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) |
| 279 | acpi_post_unmap_gar(&entry->register_region); | 279 | acpi_os_unmap_generic_address(&entry->register_region); |
| 280 | 280 | ||
| 281 | return 0; | 281 | return 0; |
| 282 | } | 282 | } |
| @@ -591,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr) | |||
| 591 | return 0; | 591 | return 0; |
| 592 | } | 592 | } |
| 593 | 593 | ||
| 594 | /* read GAR in interrupt (including NMI) or process context */ | ||
| 595 | int apei_read(u64 *val, struct acpi_generic_address *reg) | ||
| 596 | { | ||
| 597 | int rc; | ||
| 598 | u64 address; | ||
| 599 | u32 tmp, width = reg->bit_width; | ||
| 600 | acpi_status status; | ||
| 601 | |||
| 602 | rc = apei_check_gar(reg, &address); | ||
| 603 | if (rc) | ||
| 604 | return rc; | ||
| 605 | |||
| 606 | if (width == 64) | ||
| 607 | width = 32; /* Break into two 32-bit transfers */ | ||
| 608 | |||
| 609 | *val = 0; | ||
| 610 | switch(reg->space_id) { | ||
| 611 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | ||
| 612 | status = acpi_os_read_memory((acpi_physical_address) | ||
| 613 | address, &tmp, width); | ||
| 614 | if (ACPI_FAILURE(status)) | ||
| 615 | return -EIO; | ||
| 616 | *val = tmp; | ||
| 617 | |||
| 618 | if (reg->bit_width == 64) { | ||
| 619 | /* Read the top 32 bits */ | ||
| 620 | status = acpi_os_read_memory((acpi_physical_address) | ||
| 621 | (address + 4), &tmp, 32); | ||
| 622 | if (ACPI_FAILURE(status)) | ||
| 623 | return -EIO; | ||
| 624 | *val |= ((u64)tmp << 32); | ||
| 625 | } | ||
| 626 | break; | ||
| 627 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
| 628 | status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); | ||
| 629 | if (ACPI_FAILURE(status)) | ||
| 630 | return -EIO; | ||
| 631 | break; | ||
| 632 | default: | ||
| 633 | return -EINVAL; | ||
| 634 | } | ||
| 635 | |||
| 636 | return 0; | ||
| 637 | } | ||
| 638 | EXPORT_SYMBOL_GPL(apei_read); | ||
| 639 | |||
| 640 | /* write GAR in interrupt (including NMI) or process context */ | ||
| 641 | int apei_write(u64 val, struct acpi_generic_address *reg) | ||
| 642 | { | ||
| 643 | int rc; | ||
| 644 | u64 address; | ||
| 645 | u32 width = reg->bit_width; | ||
| 646 | acpi_status status; | ||
| 647 | |||
| 648 | rc = apei_check_gar(reg, &address); | ||
| 649 | if (rc) | ||
| 650 | return rc; | ||
| 651 | |||
| 652 | if (width == 64) | ||
| 653 | width = 32; /* Break into two 32-bit transfers */ | ||
| 654 | |||
| 655 | switch (reg->space_id) { | ||
| 656 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | ||
| 657 | status = acpi_os_write_memory((acpi_physical_address) | ||
| 658 | address, ACPI_LODWORD(val), | ||
| 659 | width); | ||
| 660 | if (ACPI_FAILURE(status)) | ||
| 661 | return -EIO; | ||
| 662 | |||
| 663 | if (reg->bit_width == 64) { | ||
| 664 | status = acpi_os_write_memory((acpi_physical_address) | ||
| 665 | (address + 4), | ||
| 666 | ACPI_HIDWORD(val), 32); | ||
| 667 | if (ACPI_FAILURE(status)) | ||
| 668 | return -EIO; | ||
| 669 | } | ||
| 670 | break; | ||
| 671 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
| 672 | status = acpi_os_write_port(address, val, reg->bit_width); | ||
| 673 | if (ACPI_FAILURE(status)) | ||
| 674 | return -EIO; | ||
| 675 | break; | ||
| 676 | default: | ||
| 677 | return -EINVAL; | ||
| 678 | } | ||
| 679 | |||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | EXPORT_SYMBOL_GPL(apei_write); | ||
| 683 | |||
| 594 | static int collect_res_callback(struct apei_exec_context *ctx, | 684 | static int collect_res_callback(struct apei_exec_context *ctx, |
| 595 | struct acpi_whea_header *entry, | 685 | struct acpi_whea_header *entry, |
| 596 | void *data) | 686 | void *data) |
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index d778edd34fb..cca240a3303 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h | |||
| @@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio | |||
| 68 | /* IP has been set in instruction function */ | 68 | /* IP has been set in instruction function */ |
| 69 | #define APEI_EXEC_SET_IP 1 | 69 | #define APEI_EXEC_SET_IP 1 |
| 70 | 70 | ||
| 71 | int apei_read(u64 *val, struct acpi_generic_address *reg); | ||
| 72 | int apei_write(u64 val, struct acpi_generic_address *reg); | ||
| 73 | |||
| 71 | int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val); | 74 | int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val); |
| 72 | int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val); | 75 | int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val); |
| 73 | int apei_exec_read_register(struct apei_exec_context *ctx, | 76 | int apei_exec_read_register(struct apei_exec_context *ctx, |
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index aaf36090de1..b3207e16670 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 35 | #include <linux/acpi.h> | 35 | #include <linux/acpi.h> |
| 36 | #include <linux/acpi_io.h> | ||
| 36 | #include <linux/io.h> | 37 | #include <linux/io.h> |
| 37 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
| 38 | #include <linux/timer.h> | 39 | #include <linux/timer.h> |
| @@ -48,7 +49,6 @@ | |||
| 48 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
| 49 | #include <linux/aer.h> | 50 | #include <linux/aer.h> |
| 50 | #include <acpi/apei.h> | 51 | #include <acpi/apei.h> |
| 51 | #include <acpi/atomicio.h> | ||
| 52 | #include <acpi/hed.h> | 52 | #include <acpi/hed.h> |
| 53 | #include <asm/mce.h> | 53 | #include <asm/mce.h> |
| 54 | #include <asm/tlbflush.h> | 54 | #include <asm/tlbflush.h> |
| @@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) | |||
| 301 | if (!ghes) | 301 | if (!ghes) |
| 302 | return ERR_PTR(-ENOMEM); | 302 | return ERR_PTR(-ENOMEM); |
| 303 | ghes->generic = generic; | 303 | ghes->generic = generic; |
| 304 | rc = acpi_pre_map_gar(&generic->error_status_address); | 304 | rc = acpi_os_map_generic_address(&generic->error_status_address); |
| 305 | if (rc) | 305 | if (rc) |
| 306 | goto err_free; | 306 | goto err_free; |
| 307 | error_block_length = generic->error_block_length; | 307 | error_block_length = generic->error_block_length; |
| @@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) | |||
| 321 | return ghes; | 321 | return ghes; |
| 322 | 322 | ||
| 323 | err_unmap: | 323 | err_unmap: |
| 324 | acpi_post_unmap_gar(&generic->error_status_address); | 324 | acpi_os_unmap_generic_address(&generic->error_status_address); |
| 325 | err_free: | 325 | err_free: |
| 326 | kfree(ghes); | 326 | kfree(ghes); |
| 327 | return ERR_PTR(rc); | 327 | return ERR_PTR(rc); |
| @@ -330,7 +330,7 @@ err_free: | |||
| 330 | static void ghes_fini(struct ghes *ghes) | 330 | static void ghes_fini(struct ghes *ghes) |
| 331 | { | 331 | { |
| 332 | kfree(ghes->estatus); | 332 | kfree(ghes->estatus); |
| 333 | acpi_post_unmap_gar(&ghes->generic->error_status_address); | 333 | acpi_os_unmap_generic_address(&ghes->generic->error_status_address); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | enum { | 336 | enum { |
| @@ -401,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) | |||
| 401 | u32 len; | 401 | u32 len; |
| 402 | int rc; | 402 | int rc; |
| 403 | 403 | ||
| 404 | rc = acpi_atomic_read(&buf_paddr, &g->error_status_address); | 404 | rc = apei_read(&buf_paddr, &g->error_status_address); |
| 405 | if (rc) { | 405 | if (rc) { |
| 406 | if (!silent && printk_ratelimit()) | 406 | if (!silent && printk_ratelimit()) |
| 407 | pr_warning(FW_WARN GHES_PFX | 407 | pr_warning(FW_WARN GHES_PFX |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3e57fbdf50a..fcc12d842bc 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
| @@ -153,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) | |||
| 153 | return supported; | 153 | return supported; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | static void __init acpi_request_region (struct acpi_generic_address *addr, | 156 | static void __init acpi_request_region (struct acpi_generic_address *gas, |
| 157 | unsigned int length, char *desc) | 157 | unsigned int length, char *desc) |
| 158 | { | 158 | { |
| 159 | if (!addr->address || !length) | 159 | u64 addr; |
| 160 | |||
| 161 | /* Handle possible alignment issues */ | ||
| 162 | memcpy(&addr, &gas->address, sizeof(addr)); | ||
| 163 | if (!addr || !length) | ||
| 160 | return; | 164 | return; |
| 161 | 165 | ||
| 162 | /* Resources are never freed */ | 166 | /* Resources are never freed */ |
| 163 | if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) | 167 | if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) |
| 164 | request_region(addr->address, length, desc); | 168 | request_region(addr, length, desc); |
| 165 | else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) | 169 | else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) |
| 166 | request_mem_region(addr->address, length, desc); | 170 | request_mem_region(addr, length, desc); |
| 167 | } | 171 | } |
| 168 | 172 | ||
| 169 | static int __init acpi_reserve_resources(void) | 173 | static int __init acpi_reserve_resources(void) |
| @@ -414,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | |||
| 414 | __acpi_unmap_table(virt, size); | 418 | __acpi_unmap_table(virt, size); |
| 415 | } | 419 | } |
| 416 | 420 | ||
| 417 | static int acpi_os_map_generic_address(struct acpi_generic_address *addr) | 421 | int acpi_os_map_generic_address(struct acpi_generic_address *gas) |
| 418 | { | 422 | { |
| 423 | u64 addr; | ||
| 419 | void __iomem *virt; | 424 | void __iomem *virt; |
| 420 | 425 | ||
| 421 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | 426 | if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
| 422 | return 0; | 427 | return 0; |
| 423 | 428 | ||
| 424 | if (!addr->address || !addr->bit_width) | 429 | /* Handle possible alignment issues */ |
| 430 | memcpy(&addr, &gas->address, sizeof(addr)); | ||
| 431 | if (!addr || !gas->bit_width) | ||
| 425 | return -EINVAL; | 432 | return -EINVAL; |
| 426 | 433 | ||
| 427 | virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); | 434 | virt = acpi_os_map_memory(addr, gas->bit_width / 8); |
| 428 | if (!virt) | 435 | if (!virt) |
| 429 | return -EIO; | 436 | return -EIO; |
| 430 | 437 | ||
| 431 | return 0; | 438 | return 0; |
| 432 | } | 439 | } |
| 440 | EXPORT_SYMBOL(acpi_os_map_generic_address); | ||
| 433 | 441 | ||
| 434 | static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | 442 | void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) |
| 435 | { | 443 | { |
| 444 | u64 addr; | ||
| 436 | struct acpi_ioremap *map; | 445 | struct acpi_ioremap *map; |
| 437 | 446 | ||
| 438 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | 447 | if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
| 439 | return; | 448 | return; |
| 440 | 449 | ||
| 441 | if (!addr->address || !addr->bit_width) | 450 | /* Handle possible alignment issues */ |
| 451 | memcpy(&addr, &gas->address, sizeof(addr)); | ||
| 452 | if (!addr || !gas->bit_width) | ||
| 442 | return; | 453 | return; |
| 443 | 454 | ||
| 444 | mutex_lock(&acpi_ioremap_lock); | 455 | mutex_lock(&acpi_ioremap_lock); |
| 445 | map = acpi_map_lookup(addr->address, addr->bit_width / 8); | 456 | map = acpi_map_lookup(addr, gas->bit_width / 8); |
| 446 | if (!map) { | 457 | if (!map) { |
| 447 | mutex_unlock(&acpi_ioremap_lock); | 458 | mutex_unlock(&acpi_ioremap_lock); |
| 448 | return; | 459 | return; |
| @@ -452,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | |||
| 452 | 463 | ||
| 453 | acpi_os_map_cleanup(map); | 464 | acpi_os_map_cleanup(map); |
| 454 | } | 465 | } |
| 466 | EXPORT_SYMBOL(acpi_os_unmap_generic_address); | ||
| 455 | 467 | ||
| 456 | #ifdef ACPI_FUTURE_USAGE | 468 | #ifdef ACPI_FUTURE_USAGE |
| 457 | acpi_status | 469 | acpi_status |
diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h index 4afd7102459..b0ffa219993 100644 --- a/include/linux/acpi_io.h +++ b/include/linux/acpi_io.h | |||
| @@ -12,4 +12,7 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, | |||
| 12 | 12 | ||
| 13 | void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); | 13 | void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); |
| 14 | 14 | ||
| 15 | int acpi_os_map_generic_address(struct acpi_generic_address *addr); | ||
| 16 | void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); | ||
| 17 | |||
| 15 | #endif | 18 | #endif |
