[PATCH 2/2] ACPICA: support Generic Address Structure bit_offset in acpi_read/write

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



acpi_read(), acpi_write(), acpi_hw_read(), and acpi_hw_write() currently
ignore the GAS bit_offset field (but they do warn if it is non-zero).

APEI tables are starting to use non-zero bit_offsets.  APEI uses
special-purpose apei_exec_read_register() and apei_exec_write_register()
interfaces that apply the bit_offset.

This patch adds bit_offset support to the generic interfaces, which is
one small step toward using them instead of the special-purpose APEI ones.

Signed-off-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
---
 drivers/acpi/acpica/hwregs.c  |   32 ++++++++++++++++++++------------
 drivers/acpi/acpica/hwxface.c |    8 +++++---
 2 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index cc70f3f..2b50800 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -82,6 +82,7 @@ acpi_status
 acpi_hw_validate_register(struct acpi_generic_address *reg,
 			  u8 max_bit_width, u64 *address)
 {
+	static u8 width[] = {64, 8, 16, 32, 64};
 
 	/* Must have a valid pointer to a GAS structure */
 
@@ -119,12 +120,14 @@ acpi_hw_validate_register(struct acpi_generic_address *reg,
 		return (AE_SUPPORT);
 	}
 
-	/* Validate the bit_offset. Just a warning for now. */
+	/* Validate the bit_offset */
 
-	if (reg->bit_offset != 0) {
-		ACPI_WARNING((AE_INFO,
-			      "Unsupported register bit offset: 0x%X",
-			      reg->bit_offset));
+	if (reg->bit_offset > width[reg->access_width] - 1) {
+		ACPI_ERROR((AE_INFO,
+			   "Unsupported register bit offset: 0x%X access size: 0x%X (%d bits)",
+			   reg->bit_offset, reg->access_width,
+			   width[reg->access_width]));
+		return (AE_BAD_ADDRESS);
 	}
 
 	return (AE_OK);
@@ -146,14 +149,15 @@ acpi_hw_validate_register(struct acpi_generic_address *reg,
  * LIMITATIONS: <These limitations also apply to acpi_hw_write>
  *      bit_width must be exactly 8, 16, or 32.
  *      space_iD must be system_memory or system_iO.
- *      bit_offset and access_width are currently ignored, as there has
- *          not been a need to implement these.
+ *      access_width is currently ignored, as there has
+ *          not been a need to implement it.
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
+acpi_status acpi_hw_read(u32 *return_value, struct acpi_generic_address *reg)
 {
 	u64 address;
+	u32 value;
 	acpi_status status;
 
 	ACPI_FUNCTION_NAME(hw_read);
@@ -167,7 +171,7 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
 
 	/* Initialize entire 32-bit return value to zero */
 
-	*value = 0;
+	*return_value = 0;
 
 	/*
 	 * Two address spaces supported: Memory or IO. PCI_Config is
@@ -175,16 +179,18 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
 	 */
 	if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
 		status = acpi_os_read_memory((acpi_physical_address)
-					     address, value, reg->bit_width);
+					     address, &value, reg->bit_width);
 	} else {		/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
 
 		status = acpi_hw_read_port((acpi_io_address)
-					   address, value, reg->bit_width);
+					   address, &value, reg->bit_width);
 	}
 
+	*return_value = value >> reg->bit_offset;
 	ACPI_DEBUG_PRINT((ACPI_DB_IO,
 			  "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
-			  *value, reg->bit_width, ACPI_FORMAT_UINT64(address),
+			  *return_value, reg->bit_width,
+			  ACPI_FORMAT_UINT64(address),
 			  acpi_ut_get_region_name(reg->space_id)));
 
 	return (status);
@@ -219,6 +225,8 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
 		return (status);
 	}
 
+	value = value << reg->bit_offset;
+
 	/*
 	 * Two address spaces supported: Memory or IO. PCI_Config is
 	 * not supported here because the GAS structure is insufficient
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 12b5c57..a0526fe 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -114,8 +114,8 @@ ACPI_EXPORT_SYMBOL(acpi_reset)
  * LIMITATIONS: <These limitations also apply to acpi_write>
  *      bit_width must be exactly 8, 16, 32, or 64.
  *      space_iD must be system_memory or system_iO.
- *      bit_offset and access_width are currently ignored, as there has
- *          not been a need to implement these.
+ *      access_width is currently ignored, as there has
+ *          not been a need to implement it.
  *
  ******************************************************************************/
 acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg)
@@ -195,7 +195,7 @@ acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg)
 		}
 	}
 
-	*return_value = complete_value;
+	*return_value = complete_value >> reg->bit_offset;
 	ACPI_DEBUG_PRINT((ACPI_DB_IO,
 			  "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
 			  ACPI_FORMAT_UINT64(*return_value), reg->bit_width,
@@ -239,6 +239,8 @@ acpi_status acpi_write(u64 value, struct acpi_generic_address *reg)
 		width = 32;	/* Break into two 32-bit transfers */
 	}
 
+	value = value << reg->bit_offset;
+
 	/*
 	 * Two address spaces supported: Memory or IO. PCI_Config is
 	 * not supported here because the GAS structure is insufficient

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux