aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMyron Stowe <mstowe@redhat.com>2012-01-20 21:13:24 -0500
committerLen Brown <len.brown@intel.com>2012-01-21 01:08:17 -0500
commite615bf5b5519862ab66172f4dec7455d6543a578 (patch)
treec6d37861dc376b55bc5c4ece88f57faf9d51e99a /drivers
parentdcd6c92267155e70a94b3927bce681ce74b80d1f (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')
-rw-r--r--drivers/acpi/apei/apei-base.c35
-rw-r--r--drivers/acpi/osl.c116
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
714static inline u64 read64(const volatile void __iomem *addr)
715{
716 return readq(addr);
717}
718#else
719static 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
728acpi_status
729acpi_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
713acpi_status 774acpi_status
714acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) 775acpi_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
814static inline void write64(u64 val, volatile void __iomem *addr)
815{
816 writeq(val, addr);
817}
818#else
819static inline void write64(u64 val, volatile void __iomem *addr)
820{
821 writel(val, addr);
822 writel(val>>32, addr+4);
823}
824#endif
825
826acpi_status
827acpi_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
752acpi_status 868acpi_status
753acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, 869acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
754 u64 *value, u32 width) 870 u64 *value, u32 width)