diff options
author | Myron Stowe <mstowe@redhat.com> | 2012-01-20 21:13:24 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-01-21 01:08:17 -0500 |
commit | e615bf5b5519862ab66172f4dec7455d6543a578 (patch) | |
tree | c6d37861dc376b55bc5c4ece88f57faf9d51e99a /drivers/acpi/osl.c | |
parent | dcd6c92267155e70a94b3927bce681ce74b80d1f (diff) |
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>
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index fcc12d842bcc..5498a6d88ba2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -710,6 +710,67 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) | |||
710 | return AE_OK; | 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 | acpi_status | 774 | acpi_status |
714 | acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) | 775 | acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) |
715 | { | 776 | { |
@@ -749,6 +810,61 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) | |||
749 | return AE_OK; | 810 | return AE_OK; |
750 | } | 811 | } |
751 | 812 | ||
813 | #ifdef writeq | ||
814 | static inline void write64(u64 val, volatile void __iomem *addr) | ||
815 | { | ||
816 | writeq(val, addr); | ||
817 | } | ||
818 | #else | ||
819 | static inline void write64(u64 val, volatile void __iomem *addr) | ||
820 | { | ||
821 | writel(val, addr); | ||
822 | writel(val>>32, addr+4); | ||
823 | } | ||
824 | #endif | ||
825 | |||
826 | acpi_status | ||
827 | acpi_os_write_memory64(acpi_physical_address phys_addr, u64 value, u32 width) | ||
828 | { | ||
829 | void __iomem *virt_addr; | ||
830 | unsigned int size = width / 8; | ||
831 | bool unmap = false; | ||
832 | |||
833 | rcu_read_lock(); | ||
834 | virt_addr = acpi_map_vaddr_lookup(phys_addr, size); | ||
835 | if (!virt_addr) { | ||
836 | rcu_read_unlock(); | ||
837 | virt_addr = acpi_os_ioremap(phys_addr, size); | ||
838 | if (!virt_addr) | ||
839 | return AE_BAD_ADDRESS; | ||
840 | unmap = true; | ||
841 | } | ||
842 | |||
843 | switch (width) { | ||
844 | case 8: | ||
845 | writeb(value, virt_addr); | ||
846 | break; | ||
847 | case 16: | ||
848 | writew(value, virt_addr); | ||
849 | break; | ||
850 | case 32: | ||
851 | writel(value, virt_addr); | ||
852 | break; | ||
853 | case 64: | ||
854 | write64(value, virt_addr); | ||
855 | break; | ||
856 | default: | ||
857 | BUG(); | ||
858 | } | ||
859 | |||
860 | if (unmap) | ||
861 | iounmap(virt_addr); | ||
862 | else | ||
863 | rcu_read_unlock(); | ||
864 | |||
865 | return AE_OK; | ||
866 | } | ||
867 | |||
752 | acpi_status | 868 | acpi_status |
753 | acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, | 869 | acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, |
754 | u64 *value, u32 width) | 870 | u64 *value, u32 width) |