Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI, APEI: Add 64-bit read/write support for APEI on i386

Base ACPI (CA) currently does not support atomic 64-bit reads and writes
(acpi_read() and acpi_write() split 64-bit loads/stores into two
32-bit transfers) yet APEI expects 64-bit transfer capability, even
when running on 32-bit systems.

This patch implements 64-bit read and write routines for APEI usage.

This patch re-factors similar functionality introduced in commit
04c25997c97, bringing it into the ACPI subsystem in preparation for
removing ./drivers/acpi/atomicio.[ch]. In the implementation I have
replicated acpi_os_read_memory() and acpi_os_write_memory(), creating
64-bit versions for APEI to utilize, as opposed to something more
elegant. My thinking is that we should attempt to see if we can get
ACPI's CA/OSL changed so that the existing acpi_read() and acpi_write()
interfaces are natively 64-bit capable and then subsequently remove the
replication.

Signed-off-by: Myron Stowe <myron.stowe@redhat.com>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Myron Stowe and committed by
Len Brown
e615bf5b dcd6c922

+124 -31
+4 -31
drivers/acpi/apei/apei-base.c
··· 596 596 { 597 597 int rc; 598 598 u64 address; 599 - u32 tmp, width = reg->bit_width; 600 599 acpi_status status; 601 600 602 601 rc = apei_check_gar(reg, &address); 603 602 if (rc) 604 603 return rc; 605 604 606 - if (width == 64) 607 - width = 32; /* Break into two 32-bit transfers */ 608 - 609 605 *val = 0; 610 606 switch(reg->space_id) { 611 607 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 612 - status = acpi_os_read_memory((acpi_physical_address) 613 - address, &tmp, width); 608 + status = acpi_os_read_memory64((acpi_physical_address) 609 + address, val, reg->bit_width); 614 610 if (ACPI_FAILURE(status)) 615 611 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 612 break; 627 613 case ACPI_ADR_SPACE_SYSTEM_IO: 628 614 status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); ··· 628 642 { 629 643 int rc; 630 644 u64 address; 631 - u32 width = reg->bit_width; 632 645 acpi_status status; 633 646 634 647 rc = apei_check_gar(reg, &address); 635 648 if (rc) 636 649 return rc; 637 650 638 - if (width == 64) 639 - width = 32; /* Break into two 32-bit transfers */ 640 - 641 651 switch (reg->space_id) { 642 652 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 643 - status = acpi_os_write_memory((acpi_physical_address) 644 - address, ACPI_LODWORD(val), 645 - width); 653 + status = acpi_os_write_memory64((acpi_physical_address) 654 + address, val, reg->bit_width); 646 655 if (ACPI_FAILURE(status)) 647 656 return -EIO; 648 - 649 - if (reg->bit_width == 64) { 650 - status = acpi_os_write_memory((acpi_physical_address) 651 - (address + 4), 652 - ACPI_HIDWORD(val), 32); 653 - if (ACPI_FAILURE(status)) 654 - return -EIO; 655 - } 656 657 break; 657 658 case ACPI_ADR_SPACE_SYSTEM_IO: 658 659 status = acpi_os_write_port(address, val, reg->bit_width);
+116
drivers/acpi/osl.c
··· 710 710 return AE_OK; 711 711 } 712 712 713 + #ifdef readq 714 + static inline u64 read64(const volatile void __iomem *addr) 715 + { 716 + return readq(addr); 717 + } 718 + #else 719 + static inline u64 read64(const volatile void __iomem *addr) 720 + { 721 + u64 l, h; 722 + l = readl(addr); 723 + h = readl(addr+4); 724 + return l | (h << 32); 725 + } 726 + #endif 727 + 728 + acpi_status 729 + acpi_os_read_memory64(acpi_physical_address phys_addr, u64 *value, u32 width) 730 + { 731 + void __iomem *virt_addr; 732 + unsigned int size = width / 8; 733 + bool unmap = false; 734 + u64 dummy; 735 + 736 + rcu_read_lock(); 737 + virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 738 + if (!virt_addr) { 739 + rcu_read_unlock(); 740 + virt_addr = acpi_os_ioremap(phys_addr, size); 741 + if (!virt_addr) 742 + return AE_BAD_ADDRESS; 743 + unmap = true; 744 + } 745 + 746 + if (!value) 747 + value = &dummy; 748 + 749 + switch (width) { 750 + case 8: 751 + *(u8 *) value = readb(virt_addr); 752 + break; 753 + case 16: 754 + *(u16 *) value = readw(virt_addr); 755 + break; 756 + case 32: 757 + *(u32 *) value = readl(virt_addr); 758 + break; 759 + case 64: 760 + *(u64 *) value = read64(virt_addr); 761 + break; 762 + default: 763 + BUG(); 764 + } 765 + 766 + if (unmap) 767 + iounmap(virt_addr); 768 + else 769 + rcu_read_unlock(); 770 + 771 + return AE_OK; 772 + } 773 + 713 774 acpi_status 714 775 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) 715 776 { ··· 797 736 break; 798 737 case 32: 799 738 writel(value, virt_addr); 739 + break; 740 + default: 741 + BUG(); 742 + } 743 + 744 + if (unmap) 745 + iounmap(virt_addr); 746 + else 747 + rcu_read_unlock(); 748 + 749 + return AE_OK; 750 + } 751 + 752 + #ifdef writeq 753 + static inline void write64(u64 val, volatile void __iomem *addr) 754 + { 755 + writeq(val, addr); 756 + } 757 + #else 758 + static inline void write64(u64 val, volatile void __iomem *addr) 759 + { 760 + writel(val, addr); 761 + writel(val>>32, addr+4); 762 + } 763 + #endif 764 + 765 + acpi_status 766 + acpi_os_write_memory64(acpi_physical_address phys_addr, u64 value, u32 width) 767 + { 768 + void __iomem *virt_addr; 769 + unsigned int size = width / 8; 770 + bool unmap = false; 771 + 772 + rcu_read_lock(); 773 + virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 774 + if (!virt_addr) { 775 + rcu_read_unlock(); 776 + virt_addr = acpi_os_ioremap(phys_addr, size); 777 + if (!virt_addr) 778 + return AE_BAD_ADDRESS; 779 + unmap = true; 780 + } 781 + 782 + switch (width) { 783 + case 8: 784 + writeb(value, virt_addr); 785 + break; 786 + case 16: 787 + writew(value, virt_addr); 788 + break; 789 + case 32: 790 + writel(value, virt_addr); 791 + break; 792 + case 64: 793 + write64(value, virt_addr); 800 794 break; 801 795 default: 802 796 BUG();
+4
include/acpi/acpiosxf.h
··· 218 218 */ 219 219 acpi_status 220 220 acpi_os_read_memory(acpi_physical_address address, u32 * value, u32 width); 221 + acpi_status 222 + acpi_os_read_memory64(acpi_physical_address address, u64 *value, u32 width); 221 223 222 224 acpi_status 223 225 acpi_os_write_memory(acpi_physical_address address, u32 value, u32 width); 226 + acpi_status 227 + acpi_os_write_memory64(acpi_physical_address address, u64 value, u32 width); 224 228 225 229 /* 226 230 * Platform and hardware-independent PCI configuration space access