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
04c25997c9, 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>
This commit is contained in:
Myron Stowe
2012-01-20 19:13:24 -07:00
committed by Len Brown
parent dcd6c92267
commit e615bf5b55
3 changed files with 124 additions and 31 deletions

View File

@@ -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);