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 | |
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')
-rw-r--r-- | drivers/acpi/apei/apei-base.c | 35 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 116 |
2 files changed, 120 insertions, 31 deletions
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index e45350cb6ac8..e5d53b7ddc7e 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c | |||
@@ -596,33 +596,19 @@ int apei_read(u64 *val, struct acpi_generic_address *reg) | |||
596 | { | 596 | { |
597 | int rc; | 597 | int rc; |
598 | u64 address; | 598 | u64 address; |
599 | u32 tmp, width = reg->bit_width; | ||
600 | acpi_status status; | 599 | acpi_status status; |
601 | 600 | ||
602 | rc = apei_check_gar(reg, &address); | 601 | rc = apei_check_gar(reg, &address); |
603 | if (rc) | 602 | if (rc) |
604 | return rc; | 603 | return rc; |
605 | 604 | ||
606 | if (width == 64) | ||
607 | width = 32; /* Break into two 32-bit transfers */ | ||
608 | |||
609 | *val = 0; | 605 | *val = 0; |
610 | switch(reg->space_id) { | 606 | switch(reg->space_id) { |
611 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 607 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
612 | status = acpi_os_read_memory((acpi_physical_address) | 608 | status = acpi_os_read_memory64((acpi_physical_address) |
613 | address, &tmp, width); | 609 | address, val, reg->bit_width); |
614 | if (ACPI_FAILURE(status)) | 610 | if (ACPI_FAILURE(status)) |
615 | return -EIO; | 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 | break; | 612 | break; |
627 | case ACPI_ADR_SPACE_SYSTEM_IO: | 613 | case ACPI_ADR_SPACE_SYSTEM_IO: |
628 | status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); | 614 | status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); |
@@ -642,31 +628,18 @@ int apei_write(u64 val, struct acpi_generic_address *reg) | |||
642 | { | 628 | { |
643 | int rc; | 629 | int rc; |
644 | u64 address; | 630 | u64 address; |
645 | u32 width = reg->bit_width; | ||
646 | acpi_status status; | 631 | acpi_status status; |
647 | 632 | ||
648 | rc = apei_check_gar(reg, &address); | 633 | rc = apei_check_gar(reg, &address); |
649 | if (rc) | 634 | if (rc) |
650 | return rc; | 635 | return rc; |
651 | 636 | ||
652 | if (width == 64) | ||
653 | width = 32; /* Break into two 32-bit transfers */ | ||
654 | |||
655 | switch (reg->space_id) { | 637 | switch (reg->space_id) { |
656 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 638 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
657 | status = acpi_os_write_memory((acpi_physical_address) | 639 | status = acpi_os_write_memory64((acpi_physical_address) |
658 | address, ACPI_LODWORD(val), | 640 | address, val, reg->bit_width); |
659 | width); | ||
660 | if (ACPI_FAILURE(status)) | 641 | if (ACPI_FAILURE(status)) |
661 | return -EIO; | 642 | 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; | 643 | break; |
671 | case ACPI_ADR_SPACE_SYSTEM_IO: | 644 | case ACPI_ADR_SPACE_SYSTEM_IO: |
672 | status = acpi_os_write_port(address, val, reg->bit_width); | 645 | status = acpi_os_write_port(address, val, reg->bit_width); |
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) |