Revert "ACPICA: ACPI 2.0, Hardware: Add access_width/bit_offset support for acpi_hw_w...
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 15 Jun 2016 00:16:13 +0000 (02:16 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 15 Jun 2016 00:16:13 +0000 (02:16 +0200)
Revert commit 66b1ed5aa8dd "ACPICA: ACPI 2.0, Hardware: Add
access_width/bit_offset support for acpi_hw_write()" that is reported
to break suspend-to-RAM (ACPI S3) on one system.

The root cause of the failure is a wrong access width value for one of
the involved registers provided by the ACPI tables, but before commit
66b1ed5aa8dd that value was not taken into account at all and things
worked.

Fixes: 66b1ed5aa8dd "ACPICA: ACPI 2.0, Hardware: Add access_width/bit_offset support for acpi_hw_write()"
Reported-by: Andrey Skvortsov <andrej.skvortzov@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/hwregs.c

index daceb80022b023da04354bb36300caf13cc40a2a..3b7fb99362b6945ecc5ebe3f192405718ecd33fb 100644 (file)
@@ -306,12 +306,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
 acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
 {
        u64 address;
-       u8 access_width;
-       u32 bit_width;
-       u8 bit_offset;
-       u64 value64;
-       u32 new_value32, old_value32;
-       u8 index;
        acpi_status status;
 
        ACPI_FUNCTION_NAME(hw_write);
@@ -323,145 +317,23 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
                return (status);
        }
 
-       /* Convert access_width into number of bits based */
-
-       access_width = acpi_hw_get_access_bit_width(reg, 32);
-       bit_width = reg->bit_offset + reg->bit_width;
-       bit_offset = reg->bit_offset;
-
        /*
         * Two address spaces supported: Memory or IO. PCI_Config is
         * not supported here because the GAS structure is insufficient
         */
-       index = 0;
-       while (bit_width) {
-               /*
-                * Use offset style bit reads because "Index * AccessWidth" is
-                * ensured to be less than 32-bits by acpi_hw_validate_register().
-                */
-               new_value32 = ACPI_GET_BITS(&value, index * access_width,
-                                           ACPI_MASK_BITS_ABOVE_32
-                                           (access_width));
-
-               if (bit_offset >= access_width) {
-                       bit_offset -= access_width;
-               } else {
-                       /*
-                        * Use offset style bit masks because access_width is ensured
-                        * to be less than 32-bits by acpi_hw_validate_register() and
-                        * bit_offset/bit_width is less than access_width here.
-                        */
-                       if (bit_offset) {
-                               new_value32 &= ACPI_MASK_BITS_BELOW(bit_offset);
-                       }
-                       if (bit_width < access_width) {
-                               new_value32 &= ACPI_MASK_BITS_ABOVE(bit_width);
-                       }
-
-                       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-                               if (bit_offset || bit_width < access_width) {
-                                       /*
-                                        * Read old values in order not to modify the bits that
-                                        * are beyond the register bit_width/bit_offset setting.
-                                        */
-                                       status =
-                                           acpi_os_read_memory((acpi_physical_address)
-                                                               address +
-                                                               index *
-                                                               ACPI_DIV_8
-                                                               (access_width),
-                                                               &value64,
-                                                               access_width);
-                                       old_value32 = (u32)value64;
-
-                                       /*
-                                        * Use offset style bit masks because access_width is
-                                        * ensured to be less than 32-bits by
-                                        * acpi_hw_validate_register() and bit_offset/bit_width is
-                                        * less than access_width here.
-                                        */
-                                       if (bit_offset) {
-                                               old_value32 &=
-                                                   ACPI_MASK_BITS_ABOVE
-                                                   (bit_offset);
-                                               bit_offset = 0;
-                                       }
-                                       if (bit_width < access_width) {
-                                               old_value32 &=
-                                                   ACPI_MASK_BITS_BELOW
-                                                   (bit_width);
-                                       }
-
-                                       new_value32 |= old_value32;
-                               }
-
-                               value64 = (u64)new_value32;
-                               status =
-                                   acpi_os_write_memory((acpi_physical_address)
-                                                        address +
-                                                        index *
-                                                        ACPI_DIV_8
-                                                        (access_width),
-                                                        value64, access_width);
-                       } else {        /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
-
-                               if (bit_offset || bit_width < access_width) {
-                                       /*
-                                        * Read old values in order not to modify the bits that
-                                        * are beyond the register bit_width/bit_offset setting.
-                                        */
-                                       status =
-                                           acpi_hw_read_port((acpi_io_address)
-                                                             address +
-                                                             index *
-                                                             ACPI_DIV_8
-                                                             (access_width),
-                                                             &old_value32,
-                                                             access_width);
-
-                                       /*
-                                        * Use offset style bit masks because access_width is
-                                        * ensured to be less than 32-bits by
-                                        * acpi_hw_validate_register() and bit_offset/bit_width is
-                                        * less than access_width here.
-                                        */
-                                       if (bit_offset) {
-                                               old_value32 &=
-                                                   ACPI_MASK_BITS_ABOVE
-                                                   (bit_offset);
-                                               bit_offset = 0;
-                                       }
-                                       if (bit_width < access_width) {
-                                               old_value32 &=
-                                                   ACPI_MASK_BITS_BELOW
-                                                   (bit_width);
-                                       }
-
-                                       new_value32 |= old_value32;
-                               }
-
-                               status = acpi_hw_write_port((acpi_io_address)
-                                                           address +
-                                                           index *
-                                                           ACPI_DIV_8
-                                                           (access_width),
-                                                           new_value32,
-                                                           access_width);
-                       }
-               }
-
-               /*
-                * Index * access_width is ensured to be less than 32-bits by
-                * acpi_hw_validate_register().
-                */
-               bit_width -=
-                   bit_width > access_width ? access_width : bit_width;
-               index++;
+       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+               status = acpi_os_write_memory((acpi_physical_address)
+                                             address, (u64)value,
+                                             reg->bit_width);
+       } else {                /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
+
+               status = acpi_hw_write_port((acpi_io_address)
+                                           address, value, reg->bit_width);
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
                          "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
-                         value, access_width, ACPI_FORMAT_UINT64(address),
+                         value, reg->bit_width, ACPI_FORMAT_UINT64(address),
                          acpi_ut_get_region_name(reg->space_id)));
 
        return (status);