diff options
author | Lv Zheng <lv.zheng@intel.com> | 2016-11-09 04:05:05 +0800 |
---|---|---|
committer | Lv Zheng <lv.zheng@intel.com> | 2016-11-09 04:05:05 +0800 |
commit | 365b321a31cb701957c055cae2d2161577147252 (patch) | |
tree | 0d8ccb7079521caeef7afeb7ef8d962c72fa01c0 | |
parent | cbb0294649cbd7e8bd6107e4329461a6a7a0d967 (diff) | |
download | acpica-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.c | 79 |
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; |