linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Len Brown <lenb@kernel.org>
To: linux-acpi@vger.kernel.org, linux-pm@lists.linux-foundation.org
Cc: Myron Stowe <mstowe@redhat.com>,
	Myron Stowe <myron.stowe@redhat.com>,
	Len Brown <len.brown@intel.com>
Subject: [PATCH 03/10] ACPI, APEI: Add 64-bit read/write support for APEI on i386
Date: Mon, 23 Jan 2012 20:30:02 -0500	[thread overview]
Message-ID: <e615bf5b5519862ab66172f4dec7455d6543a578.1327368464.git.len.brown@intel.com> (raw)
In-Reply-To: <1327368609-28409-1-git-send-email-lenb@kernel.org>
In-Reply-To: <54d5dcc45af7adbb907072d042bbece4c2b4de6e.1327368464.git.len.brown@intel.com>

From: Myron Stowe <mstowe@redhat.com>

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>
---
 drivers/acpi/apei/apei-base.c |   35 ++-----------
 drivers/acpi/osl.c            |  116 +++++++++++++++++++++++++++++++++++++++++
 include/acpi/acpiosxf.h       |    4 ++
 3 files changed, 124 insertions(+), 31 deletions(-)

diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index e45350c..e5d53b7 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)
 {
 	int rc;
 	u64 address;
-	u32 tmp, width = reg->bit_width;
 	acpi_status status;
 
 	rc = apei_check_gar(reg, &address);
 	if (rc)
 		return rc;
 
-	if (width == 64)
-		width = 32;	/* Break into two 32-bit transfers */
-
 	*val = 0;
 	switch(reg->space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-		status = acpi_os_read_memory((acpi_physical_address)
-					     address, &tmp, width);
+		status = acpi_os_read_memory64((acpi_physical_address)
+					     address, val, reg->bit_width);
 		if (ACPI_FAILURE(status))
 			return -EIO;
-		*val = tmp;
-
-		if (reg->bit_width == 64) {
-			/* Read the top 32 bits */
-			status = acpi_os_read_memory((acpi_physical_address)
-						     (address + 4), &tmp, 32);
-			if (ACPI_FAILURE(status))
-				return -EIO;
-			*val |= ((u64)tmp << 32);
-		}
 		break;
 	case ACPI_ADR_SPACE_SYSTEM_IO:
 		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)
 {
 	int rc;
 	u64 address;
-	u32 width = reg->bit_width;
 	acpi_status status;
 
 	rc = apei_check_gar(reg, &address);
 	if (rc)
 		return rc;
 
-	if (width == 64)
-		width = 32;	/* Break into two 32-bit transfers */
-
 	switch (reg->space_id) {
 	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-		status = acpi_os_write_memory((acpi_physical_address)
-					      address, ACPI_LODWORD(val),
-					      width);
+		status = acpi_os_write_memory64((acpi_physical_address)
+					      address, val, reg->bit_width);
 		if (ACPI_FAILURE(status))
 			return -EIO;
-
-		if (reg->bit_width == 64) {
-			status = acpi_os_write_memory((acpi_physical_address)
-						      (address + 4),
-						      ACPI_HIDWORD(val), 32);
-			if (ACPI_FAILURE(status))
-				return -EIO;
-		}
 		break;
 	case ACPI_ADR_SPACE_SYSTEM_IO:
 		status = acpi_os_write_port(address, val, reg->bit_width);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index fcc12d8..5498a6d 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)
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 2fe8639..7c9aebe 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -218,9 +218,13 @@ acpi_status acpi_os_write_port(acpi_io_address address, u32 value, u32 width);
  */
 acpi_status
 acpi_os_read_memory(acpi_physical_address address, u32 * value, u32 width);
+acpi_status
+acpi_os_read_memory64(acpi_physical_address address, u64 *value, u32 width);
 
 acpi_status
 acpi_os_write_memory(acpi_physical_address address, u32 value, u32 width);
+acpi_status
+acpi_os_write_memory64(acpi_physical_address address, u64 value, u32 width);
 
 /*
  * Platform and hardware-independent PCI configuration space access
-- 
1.7.9.rc2


  parent reply	other threads:[~2012-01-24  1:30 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-01-24  1:29 ACPI & Power Management Patches for Linux 3.3-rc1 Len Brown
2012-01-24  1:30 ` [PATCH 01/10] ACPI processor hotplug: Split up acpi_processor_add Len Brown
2012-01-24  1:30   ` [PATCH 02/10] ACPI processor hotplug: Delay acpi_processor_start() call for hotplugged cores Len Brown
2012-01-24  1:30   ` Len Brown [this message]
2012-01-24  1:30   ` [PATCH 04/10] ACPI, APEI: Add RAM mapping support to ACPI Len Brown
2012-01-24  1:30   ` [PATCH 05/10] ACPI: Remove ./drivers/acpi/atomicio.[ch] Len Brown
2012-01-24  1:30   ` [PATCH 06/10] ACPI / PM: Add Sony Vaio VPCCW29FX to nonvs blacklist Len Brown
2012-01-24  1:30   ` [PATCH 07/10] thermal: Rename generate_netlink_event Len Brown
2012-01-24  1:30   ` [PATCH 08/10] ACPI, APEI, EINJ Allow empty Trigger Error Action Table Len Brown
2012-01-24  1:30   ` [PATCH 09/10] ACPI, APEI, EINJ, cleanup 0 vs NULL confusion Len Brown
2012-01-24  1:30   ` [PATCH 10/10] Use acpi_os_map_memory() instead of ioremap() in einj driver Len Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e615bf5b5519862ab66172f4dec7455d6543a578.1327368464.git.len.brown@intel.com \
    --to=lenb@kernel.org \
    --cc=len.brown@intel.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=mstowe@redhat.com \
    --cc=myron.stowe@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).