summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2016-11-09 04:05:05 +0800
committerLv Zheng <lv.zheng@intel.com>2016-11-09 04:05:05 +0800
commit365b321a31cb701957c055cae2d2161577147252 (patch)
tree0d8ccb7079521caeef7afeb7ef8d962c72fa01c0
parentcbb0294649cbd7e8bd6107e4329461a6a7a0d967 (diff)
downloadacpica-365b321a31cb701957c055cae2d2161577147252.tar.gz
Hardware: Sort access bit width algorithm
GAS can be in register or register region format, so we need to improve our "register" format detection code in order not to regress. Such detection may be still experimental, and is generated according to the current known facts. Lv Zheng. Link: https://bugzilla.kernel.org/show_bug.cgi?id=151501 Reported-and-tested-by: Andrey Skvortsov <andrej.skvortzov@gmail.com> Signed-off-by: Lv Zheng <lv.zheng@intel.com>
-rw-r--r--source/components/hardware/hwregs.c79
1 files changed, 59 insertions, 20 deletions
diff --git a/source/components/hardware/hwregs.c b/source/components/hardware/hwregs.c
index d53ab8c72..1f9e4c245 100644
--- a/source/components/hardware/hwregs.c
+++ b/source/components/hardware/hwregs.c
@@ -128,6 +128,7 @@
static UINT8
AcpiHwGetAccessBitWidth (
+ UINT64 Address,
ACPI_GENERIC_ADDRESS *Reg,
UINT8 MaxBitWidth);
@@ -150,7 +151,8 @@ AcpiHwWriteMultiple (
*
* FUNCTION: AcpiHwGetAccessBitWidth
*
- * PARAMETERS: Reg - GAS register structure
+ * PARAMETERS: Address - GAS register address
+ * Reg - GAS register structure
* MaxBitWidth - Max BitWidth supported (32 or 64)
*
* RETURN: Status
@@ -161,34 +163,71 @@ AcpiHwWriteMultiple (
static UINT8
AcpiHwGetAccessBitWidth (
+ UINT64 Address,
ACPI_GENERIC_ADDRESS *Reg,
UINT8 MaxBitWidth)
{
+ UINT8 AccessBitWidth;
- if (!Reg->AccessWidth)
+
+ /*
+ * GAS format "register", used by FADT:
+ * 1. Detected if BitOffset is 0 and BitWidth is 8/16/32/64;
+ * 2. AccessSize field is ignored and BitWidth field is used for
+ * determining the boundary of the IO accesses.
+ * GAS format "region", used by APEI registers:
+ * 1. Detected if BitOffset is not 0 or BitWidth is not 8/16/32/64;
+ * 2. AccessSize field is used for determining the boundary of the
+ * IO accesses;
+ * 3. BitOffset/BitWidth fields are used to describe the "region".
+ *
+ * Note: This algorithm assumes that the "Address" fields should always
+ * contain aligned values.
+ */
+ if (!Reg->BitOffset && Reg->BitWidth &&
+ ACPI_IS_POWER_OF_TWO (Reg->BitWidth) &&
+ ACPI_IS_ALIGNED (Reg->BitWidth, 8))
{
- if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
+ AccessBitWidth = Reg->BitWidth;
+ }
+ else if (Reg->AccessWidth)
+ {
+ AccessBitWidth = (1 << (Reg->AccessWidth + 2));
+ }
+ else
+ {
+ AccessBitWidth = ACPI_ROUND_UP_POWER_OF_TWO_8 (
+ Reg->BitOffset + Reg->BitWidth);
+ if (AccessBitWidth <= 8)
{
- MaxBitWidth = 32;
+ AccessBitWidth = 8;
}
-
- /*
- * Detect old register descriptors where only the BitWidth field
- * makes senses.
- */
- if (Reg->BitWidth < MaxBitWidth &&
- !Reg->BitOffset && Reg->BitWidth &&
- ACPI_IS_POWER_OF_TWO (Reg->BitWidth) &&
- ACPI_IS_ALIGNED (Reg->BitWidth, 8))
+ else
{
- return (Reg->BitWidth);
+ while (!ACPI_IS_ALIGNED (Address, AccessBitWidth >> 3))
+ {
+ AccessBitWidth >>= 1;
+ }
}
- return (MaxBitWidth);
}
- else
+
+ /* Maximum IO port access bit width is 32 */
+
+ if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
+ {
+ MaxBitWidth = 32;
+ }
+
+ /*
+ * Return access width according to the requested maximum access bit width,
+ * as the caller should know the format of the register and may enforce
+ * a 32-bit accesses.
+ */
+ if (AccessBitWidth < MaxBitWidth)
{
- return (1 << (Reg->AccessWidth + 2));
+ return (AccessBitWidth);
}
+ return (MaxBitWidth);
}
@@ -257,7 +296,7 @@ AcpiHwValidateRegister (
/* Validate the BitWidth, convert AccessWidth into number of bits */
- AccessWidth = AcpiHwGetAccessBitWidth (Reg, MaxBitWidth);
+ AccessWidth = AcpiHwGetAccessBitWidth (*Address, Reg, MaxBitWidth);
BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);
if (MaxBitWidth < BitWidth)
{
@@ -320,7 +359,7 @@ AcpiHwRead (
* into number of bits based
*/
*Value = 0;
- AccessWidth = AcpiHwGetAccessBitWidth (Reg, 32);
+ AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32);
BitWidth = Reg->BitOffset + Reg->BitWidth;
BitOffset = Reg->BitOffset;
@@ -416,7 +455,7 @@ AcpiHwWrite (
/* Convert AccessWidth into number of bits based */
- AccessWidth = AcpiHwGetAccessBitWidth (Reg, 32);
+ AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32);
BitWidth = Reg->BitOffset + Reg->BitWidth;
BitOffset = Reg->BitOffset;