summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
authorMyron Stowe <mstowe@redhat.com>2012-01-21 03:13:24 +0100
committerLen Brown <len.brown@intel.com>2012-01-21 07:08:17 +0100
commite615bf5b5519862ab66172f4dec7455d6543a578 (patch)
treec6d37861dc376b55bc5c4ece88f57faf9d51e99a /drivers/acpi/osl.c
parentLinux 3.3-rc1 (diff)
downloadlinux-e615bf5b5519862ab66172f4dec7455d6543a578.tar.xz
linux-e615bf5b5519862ab66172f4dec7455d6543a578.zip
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.c116
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)
return AE_OK;
}
+#ifdef readq
+static inline u64 read64(const volatile void __iomem *addr)
+{
+ return readq(addr);
+}
+#else
+static inline u64 read64(const volatile void __iomem *addr)
+{
+ u64 l, h;
+ l = readl(addr);
+ h = readl(addr+4);
+ return l | (h << 32);
+}
+#endif
+
+acpi_status
+acpi_os_read_memory64(acpi_physical_address phys_addr, u64 *value, u32 width)
+{
+ void __iomem *virt_addr;
+ unsigned int size = width / 8;
+ bool unmap = false;
+ u64 dummy;
+
+ rcu_read_lock();
+ virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+ if (!virt_addr) {
+ rcu_read_unlock();
+ virt_addr = acpi_os_ioremap(phys_addr, size);
+ if (!virt_addr)
+ return AE_BAD_ADDRESS;
+ unmap = true;
+ }
+
+ if (!value)
+ value = &dummy;
+
+ switch (width) {
+ case 8:
+ *(u8 *) value = readb(virt_addr);
+ break;
+ case 16:
+ *(u16 *) value = readw(virt_addr);
+ break;
+ case 32:
+ *(u32 *) value = readl(virt_addr);
+ break;
+ case 64:
+ *(u64 *) value = read64(virt_addr);
+ break;
+ default:
+ BUG();
+ }
+
+ if (unmap)
+ iounmap(virt_addr);
+ else
+ rcu_read_unlock();
+
+ return AE_OK;
+}
+
acpi_status
acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
{
@@ -749,6 +810,61 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
return AE_OK;
}
+#ifdef writeq
+static inline void write64(u64 val, volatile void __iomem *addr)
+{
+ writeq(val, addr);
+}
+#else
+static inline void write64(u64 val, volatile void __iomem *addr)
+{
+ writel(val, addr);
+ writel(val>>32, addr+4);
+}
+#endif
+
+acpi_status
+acpi_os_write_memory64(acpi_physical_address phys_addr, u64 value, u32 width)
+{
+ void __iomem *virt_addr;
+ unsigned int size = width / 8;
+ bool unmap = false;
+
+ rcu_read_lock();
+ virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+ if (!virt_addr) {
+ rcu_read_unlock();
+ virt_addr = acpi_os_ioremap(phys_addr, size);
+ if (!virt_addr)
+ return AE_BAD_ADDRESS;
+ unmap = true;
+ }
+
+ switch (width) {
+ case 8:
+ writeb(value, virt_addr);
+ break;
+ case 16:
+ writew(value, virt_addr);
+ break;
+ case 32:
+ writel(value, virt_addr);
+ break;
+ case 64:
+ write64(value, virt_addr);
+ break;
+ default:
+ BUG();
+ }
+
+ if (unmap)
+ iounmap(virt_addr);
+ else
+ rcu_read_unlock();
+
+ return AE_OK;
+}
+
acpi_status
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
u64 *value, u32 width)