Loading drivers/acpi/apei/apei-base.c +96 −6 Original line number Diff line number Diff line Loading @@ -34,13 +34,13 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> #include <linux/acpi_io.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/kref.h> #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/debugfs.h> #include <acpi/atomicio.h> #include "apei-internal.h" Loading Loading @@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val) { int rc; rc = acpi_atomic_read(val, &entry->register_region); rc = apei_read(val, &entry->register_region); if (rc) return rc; *val >>= entry->register_region.bit_offset; Loading Loading @@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val) val <<= entry->register_region.bit_offset; if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { u64 valr = 0; rc = acpi_atomic_read(&valr, &entry->register_region); rc = apei_read(&valr, &entry->register_region); if (rc) return rc; valr &= ~(entry->mask << entry->register_region.bit_offset); val |= valr; } rc = acpi_atomic_write(val, &entry->register_region); rc = apei_write(val, &entry->register_region); return rc; } Loading Loading @@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) return acpi_pre_map_gar(&entry->register_region); return acpi_os_map_generic_address(&entry->register_region); return 0; } Loading Loading @@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) acpi_post_unmap_gar(&entry->register_region); acpi_os_unmap_generic_address(&entry->register_region); return 0; } Loading Loading @@ -591,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr) return 0; } /* read GAR in interrupt (including NMI) or process context */ int apei_read(u64 *val, struct acpi_generic_address *reg) { int rc; u64 address; u32 tmp, width = reg->bit_width; acpi_status status; rc = apei_check_gar(reg, &address); if (rc) return rc; if (width == 64) width = 32; /* Break into two 32-bit transfers */ *val = 0; switch(reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_read_memory((acpi_physical_address) address, &tmp, width); if (ACPI_FAILURE(status)) return -EIO; *val = tmp; if (reg->bit_width == 64) { /* Read the top 32 bits */ status = acpi_os_read_memory((acpi_physical_address) (address + 4), &tmp, 32); if (ACPI_FAILURE(status)) return -EIO; *val |= ((u64)tmp << 32); } break; case ACPI_ADR_SPACE_SYSTEM_IO: status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); if (ACPI_FAILURE(status)) return -EIO; break; default: return -EINVAL; } return 0; } EXPORT_SYMBOL_GPL(apei_read); /* write GAR in interrupt (including NMI) or process context */ int apei_write(u64 val, struct acpi_generic_address *reg) { int rc; u64 address; u32 width = reg->bit_width; acpi_status status; rc = apei_check_gar(reg, &address); if (rc) return rc; if (width == 64) width = 32; /* Break into two 32-bit transfers */ switch (reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_write_memory((acpi_physical_address) address, ACPI_LODWORD(val), width); if (ACPI_FAILURE(status)) return -EIO; if (reg->bit_width == 64) { status = acpi_os_write_memory((acpi_physical_address) (address + 4), ACPI_HIDWORD(val), 32); if (ACPI_FAILURE(status)) return -EIO; } break; case ACPI_ADR_SPACE_SYSTEM_IO: status = acpi_os_write_port(address, val, reg->bit_width); if (ACPI_FAILURE(status)) return -EIO; break; default: return -EINVAL; } return 0; } EXPORT_SYMBOL_GPL(apei_write); static int collect_res_callback(struct apei_exec_context *ctx, struct acpi_whea_header *entry, void *data) Loading drivers/acpi/apei/apei-internal.h +3 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio /* IP has been set in instruction function */ #define APEI_EXEC_SET_IP 1 int apei_read(u64 *val, struct acpi_generic_address *reg); int apei_write(u64 val, struct acpi_generic_address *reg); int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val); int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val); int apei_exec_read_register(struct apei_exec_context *ctx, Loading drivers/acpi/apei/ghes.c +5 −5 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> #include <linux/acpi_io.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/timer.h> Loading @@ -48,7 +49,6 @@ #include <linux/pci.h> #include <linux/aer.h> #include <acpi/apei.h> #include <acpi/atomicio.h> #include <acpi/hed.h> #include <asm/mce.h> #include <asm/tlbflush.h> Loading Loading @@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) if (!ghes) return ERR_PTR(-ENOMEM); ghes->generic = generic; rc = acpi_pre_map_gar(&generic->error_status_address); rc = acpi_os_map_generic_address(&generic->error_status_address); if (rc) goto err_free; error_block_length = generic->error_block_length; Loading @@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) return ghes; err_unmap: acpi_post_unmap_gar(&generic->error_status_address); acpi_os_unmap_generic_address(&generic->error_status_address); err_free: kfree(ghes); return ERR_PTR(rc); Loading @@ -330,7 +330,7 @@ err_free: static void ghes_fini(struct ghes *ghes) { kfree(ghes->estatus); acpi_post_unmap_gar(&ghes->generic->error_status_address); acpi_os_unmap_generic_address(&ghes->generic->error_status_address); } enum { Loading Loading @@ -401,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) u32 len; int rc; rc = acpi_atomic_read(&buf_paddr, &g->error_status_address); rc = apei_read(&buf_paddr, &g->error_status_address); if (rc) { if (!silent && printk_ratelimit()) pr_warning(FW_WARN GHES_PFX Loading drivers/acpi/osl.c +26 −14 Original line number Diff line number Diff line Loading @@ -153,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) return supported; } static void __init acpi_request_region (struct acpi_generic_address *addr, static void __init acpi_request_region (struct acpi_generic_address *gas, unsigned int length, char *desc) { if (!addr->address || !length) u64 addr; /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !length) return; /* Resources are never freed */ if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) request_region(addr->address, length, desc); else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) request_mem_region(addr->address, length, desc); if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) request_region(addr, length, desc); else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) request_mem_region(addr, length, desc); } static int __init acpi_reserve_resources(void) Loading Loading @@ -414,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) __acpi_unmap_table(virt, size); } static int acpi_os_map_generic_address(struct acpi_generic_address *addr) int acpi_os_map_generic_address(struct acpi_generic_address *gas) { u64 addr; void __iomem *virt; if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return 0; if (!addr->address || !addr->bit_width) /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !gas->bit_width) return -EINVAL; virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); virt = acpi_os_map_memory(addr, gas->bit_width / 8); if (!virt) return -EIO; return 0; } EXPORT_SYMBOL(acpi_os_map_generic_address); static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) { u64 addr; struct acpi_ioremap *map; if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return; if (!addr->address || !addr->bit_width) /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !gas->bit_width) return; mutex_lock(&acpi_ioremap_lock); map = acpi_map_lookup(addr->address, addr->bit_width / 8); map = acpi_map_lookup(addr, gas->bit_width / 8); if (!map) { mutex_unlock(&acpi_ioremap_lock); return; Loading @@ -452,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) acpi_os_map_cleanup(map); } EXPORT_SYMBOL(acpi_os_unmap_generic_address); #ifdef ACPI_FUTURE_USAGE acpi_status Loading include/linux/acpi_io.h +3 −0 Original line number Diff line number Diff line Loading @@ -12,4 +12,7 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); int acpi_os_map_generic_address(struct acpi_generic_address *addr); void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); #endif Loading
drivers/acpi/apei/apei-base.c +96 −6 Original line number Diff line number Diff line Loading @@ -34,13 +34,13 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> #include <linux/acpi_io.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/kref.h> #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/debugfs.h> #include <acpi/atomicio.h> #include "apei-internal.h" Loading Loading @@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val) { int rc; rc = acpi_atomic_read(val, &entry->register_region); rc = apei_read(val, &entry->register_region); if (rc) return rc; *val >>= entry->register_region.bit_offset; Loading Loading @@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val) val <<= entry->register_region.bit_offset; if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { u64 valr = 0; rc = acpi_atomic_read(&valr, &entry->register_region); rc = apei_read(&valr, &entry->register_region); if (rc) return rc; valr &= ~(entry->mask << entry->register_region.bit_offset); val |= valr; } rc = acpi_atomic_write(val, &entry->register_region); rc = apei_write(val, &entry->register_region); return rc; } Loading Loading @@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) return acpi_pre_map_gar(&entry->register_region); return acpi_os_map_generic_address(&entry->register_region); return 0; } Loading Loading @@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) acpi_post_unmap_gar(&entry->register_region); acpi_os_unmap_generic_address(&entry->register_region); return 0; } Loading Loading @@ -591,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr) return 0; } /* read GAR in interrupt (including NMI) or process context */ int apei_read(u64 *val, struct acpi_generic_address *reg) { int rc; u64 address; u32 tmp, width = reg->bit_width; acpi_status status; rc = apei_check_gar(reg, &address); if (rc) return rc; if (width == 64) width = 32; /* Break into two 32-bit transfers */ *val = 0; switch(reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_read_memory((acpi_physical_address) address, &tmp, width); if (ACPI_FAILURE(status)) return -EIO; *val = tmp; if (reg->bit_width == 64) { /* Read the top 32 bits */ status = acpi_os_read_memory((acpi_physical_address) (address + 4), &tmp, 32); if (ACPI_FAILURE(status)) return -EIO; *val |= ((u64)tmp << 32); } break; case ACPI_ADR_SPACE_SYSTEM_IO: status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); if (ACPI_FAILURE(status)) return -EIO; break; default: return -EINVAL; } return 0; } EXPORT_SYMBOL_GPL(apei_read); /* write GAR in interrupt (including NMI) or process context */ int apei_write(u64 val, struct acpi_generic_address *reg) { int rc; u64 address; u32 width = reg->bit_width; acpi_status status; rc = apei_check_gar(reg, &address); if (rc) return rc; if (width == 64) width = 32; /* Break into two 32-bit transfers */ switch (reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_write_memory((acpi_physical_address) address, ACPI_LODWORD(val), width); if (ACPI_FAILURE(status)) return -EIO; if (reg->bit_width == 64) { status = acpi_os_write_memory((acpi_physical_address) (address + 4), ACPI_HIDWORD(val), 32); if (ACPI_FAILURE(status)) return -EIO; } break; case ACPI_ADR_SPACE_SYSTEM_IO: status = acpi_os_write_port(address, val, reg->bit_width); if (ACPI_FAILURE(status)) return -EIO; break; default: return -EINVAL; } return 0; } EXPORT_SYMBOL_GPL(apei_write); static int collect_res_callback(struct apei_exec_context *ctx, struct acpi_whea_header *entry, void *data) Loading
drivers/acpi/apei/apei-internal.h +3 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio /* IP has been set in instruction function */ #define APEI_EXEC_SET_IP 1 int apei_read(u64 *val, struct acpi_generic_address *reg); int apei_write(u64 val, struct acpi_generic_address *reg); int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val); int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val); int apei_exec_read_register(struct apei_exec_context *ctx, Loading
drivers/acpi/apei/ghes.c +5 −5 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> #include <linux/acpi_io.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/timer.h> Loading @@ -48,7 +49,6 @@ #include <linux/pci.h> #include <linux/aer.h> #include <acpi/apei.h> #include <acpi/atomicio.h> #include <acpi/hed.h> #include <asm/mce.h> #include <asm/tlbflush.h> Loading Loading @@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) if (!ghes) return ERR_PTR(-ENOMEM); ghes->generic = generic; rc = acpi_pre_map_gar(&generic->error_status_address); rc = acpi_os_map_generic_address(&generic->error_status_address); if (rc) goto err_free; error_block_length = generic->error_block_length; Loading @@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) return ghes; err_unmap: acpi_post_unmap_gar(&generic->error_status_address); acpi_os_unmap_generic_address(&generic->error_status_address); err_free: kfree(ghes); return ERR_PTR(rc); Loading @@ -330,7 +330,7 @@ err_free: static void ghes_fini(struct ghes *ghes) { kfree(ghes->estatus); acpi_post_unmap_gar(&ghes->generic->error_status_address); acpi_os_unmap_generic_address(&ghes->generic->error_status_address); } enum { Loading Loading @@ -401,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) u32 len; int rc; rc = acpi_atomic_read(&buf_paddr, &g->error_status_address); rc = apei_read(&buf_paddr, &g->error_status_address); if (rc) { if (!silent && printk_ratelimit()) pr_warning(FW_WARN GHES_PFX Loading
drivers/acpi/osl.c +26 −14 Original line number Diff line number Diff line Loading @@ -153,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) return supported; } static void __init acpi_request_region (struct acpi_generic_address *addr, static void __init acpi_request_region (struct acpi_generic_address *gas, unsigned int length, char *desc) { if (!addr->address || !length) u64 addr; /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !length) return; /* Resources are never freed */ if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) request_region(addr->address, length, desc); else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) request_mem_region(addr->address, length, desc); if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) request_region(addr, length, desc); else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) request_mem_region(addr, length, desc); } static int __init acpi_reserve_resources(void) Loading Loading @@ -414,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) __acpi_unmap_table(virt, size); } static int acpi_os_map_generic_address(struct acpi_generic_address *addr) int acpi_os_map_generic_address(struct acpi_generic_address *gas) { u64 addr; void __iomem *virt; if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return 0; if (!addr->address || !addr->bit_width) /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !gas->bit_width) return -EINVAL; virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); virt = acpi_os_map_memory(addr, gas->bit_width / 8); if (!virt) return -EIO; return 0; } EXPORT_SYMBOL(acpi_os_map_generic_address); static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) { u64 addr; struct acpi_ioremap *map; if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return; if (!addr->address || !addr->bit_width) /* Handle possible alignment issues */ memcpy(&addr, &gas->address, sizeof(addr)); if (!addr || !gas->bit_width) return; mutex_lock(&acpi_ioremap_lock); map = acpi_map_lookup(addr->address, addr->bit_width / 8); map = acpi_map_lookup(addr, gas->bit_width / 8); if (!map) { mutex_unlock(&acpi_ioremap_lock); return; Loading @@ -452,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) acpi_os_map_cleanup(map); } EXPORT_SYMBOL(acpi_os_unmap_generic_address); #ifdef ACPI_FUTURE_USAGE acpi_status Loading
include/linux/acpi_io.h +3 −0 Original line number Diff line number Diff line Loading @@ -12,4 +12,7 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); int acpi_os_map_generic_address(struct acpi_generic_address *addr); void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); #endif