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:
parent
dcd6c92267
commit
e615bf5b55
|
@ -596,33 +596,19 @@ int apei_read(u64 *val, struct acpi_generic_address *reg)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u64 address;
|
u64 address;
|
||||||
u32 tmp, width = reg->bit_width;
|
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
|
||||||
rc = apei_check_gar(reg, &address);
|
rc = apei_check_gar(reg, &address);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (width == 64)
|
|
||||||
width = 32; /* Break into two 32-bit transfers */
|
|
||||||
|
|
||||||
*val = 0;
|
*val = 0;
|
||||||
switch(reg->space_id) {
|
switch(reg->space_id) {
|
||||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||||
status = acpi_os_read_memory((acpi_physical_address)
|
status = acpi_os_read_memory64((acpi_physical_address)
|
||||||
address, &tmp, width);
|
address, val, reg->bit_width);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return -EIO;
|
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;
|
break;
|
||||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||||
status = acpi_os_read_port(address, (u32 *)val, reg->bit_width);
|
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;
|
int rc;
|
||||||
u64 address;
|
u64 address;
|
||||||
u32 width = reg->bit_width;
|
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
|
||||||
rc = apei_check_gar(reg, &address);
|
rc = apei_check_gar(reg, &address);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (width == 64)
|
|
||||||
width = 32; /* Break into two 32-bit transfers */
|
|
||||||
|
|
||||||
switch (reg->space_id) {
|
switch (reg->space_id) {
|
||||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||||
status = acpi_os_write_memory((acpi_physical_address)
|
status = acpi_os_write_memory64((acpi_physical_address)
|
||||||
address, ACPI_LODWORD(val),
|
address, val, reg->bit_width);
|
||||||
width);
|
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return -EIO;
|
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;
|
break;
|
||||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||||
status = acpi_os_write_port(address, val, reg->bit_width);
|
status = acpi_os_write_port(address, val, reg->bit_width);
|
||||||
|
|
|
@ -710,6 +710,67 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
|
||||||
return AE_OK;
|
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_status
|
||||||
acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
|
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;
|
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_status
|
||||||
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
|
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
|
||||||
u64 *value, u32 width)
|
u64 *value, u32 width)
|
||||||
|
|
|
@ -218,9 +218,13 @@ acpi_status acpi_os_write_port(acpi_io_address address, u32 value, u32 width);
|
||||||
*/
|
*/
|
||||||
acpi_status
|
acpi_status
|
||||||
acpi_os_read_memory(acpi_physical_address address, u32 * value, u32 width);
|
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_status
|
||||||
acpi_os_write_memory(acpi_physical_address address, u32 value, u32 width);
|
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
|
* Platform and hardware-independent PCI configuration space access
|
||||||
|
|
Loading…
Reference in New Issue