Home | History | Annotate | Line # | Download | only in hardware
hwregs.c revision 1.4
      1 /*******************************************************************************
      2  *
      3  * Module Name: hwregs - Read/write access functions for the various ACPI
      4  *                       control and status registers.
      5  *
      6  ******************************************************************************/
      7 
      8 /*
      9  * Copyright (C) 2000 - 2017, Intel Corp.
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions, and the following disclaimer,
     17  *    without modification.
     18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     19  *    substantially similar to the "NO WARRANTY" disclaimer below
     20  *    ("Disclaimer") and any redistribution must be conditioned upon
     21  *    including a substantially similar Disclaimer requirement for further
     22  *    binary redistribution.
     23  * 3. Neither the names of the above-listed copyright holders nor the names
     24  *    of any contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * Alternatively, this software may be distributed under the terms of the
     28  * GNU General Public License ("GPL") version 2 as published by the Free
     29  * Software Foundation.
     30  *
     31  * NO WARRANTY
     32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     42  * POSSIBILITY OF SUCH DAMAGES.
     43  */
     44 
     45 #include "acpi.h"
     46 #include "accommon.h"
     47 #include "acevents.h"
     48 
     49 #define _COMPONENT          ACPI_HARDWARE
     50         ACPI_MODULE_NAME    ("hwregs")
     51 
     52 
     53 #if (!ACPI_REDUCED_HARDWARE)
     54 
     55 /* Local Prototypes */
     56 
     57 static UINT8
     58 AcpiHwGetAccessBitWidth (
     59     UINT64                  Address,
     60     ACPI_GENERIC_ADDRESS    *Reg,
     61     UINT8                   MaxBitWidth);
     62 
     63 static ACPI_STATUS
     64 AcpiHwReadMultiple (
     65     UINT32                  *Value,
     66     ACPI_GENERIC_ADDRESS    *RegisterA,
     67     ACPI_GENERIC_ADDRESS    *RegisterB);
     68 
     69 static ACPI_STATUS
     70 AcpiHwWriteMultiple (
     71     UINT32                  Value,
     72     ACPI_GENERIC_ADDRESS    *RegisterA,
     73     ACPI_GENERIC_ADDRESS    *RegisterB);
     74 
     75 #endif /* !ACPI_REDUCED_HARDWARE */
     76 
     77 
     78 /******************************************************************************
     79  *
     80  * FUNCTION:    AcpiHwGetAccessBitWidth
     81  *
     82  * PARAMETERS:  Address             - GAS register address
     83  *              Reg                 - GAS register structure
     84  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
     85  *
     86  * RETURN:      Status
     87  *
     88  * DESCRIPTION: Obtain optimal access bit width
     89  *
     90  ******************************************************************************/
     91 
     92 static UINT8
     93 AcpiHwGetAccessBitWidth (
     94     UINT64                  Address,
     95     ACPI_GENERIC_ADDRESS    *Reg,
     96     UINT8                   MaxBitWidth)
     97 {
     98     UINT8                   AccessBitWidth;
     99 
    100 
    101     /*
    102      * GAS format "register", used by FADT:
    103      *  1. Detected if BitOffset is 0 and BitWidth is 8/16/32/64;
    104      *  2. AccessSize field is ignored and BitWidth field is used for
    105      *     determining the boundary of the IO accesses.
    106      * GAS format "region", used by APEI registers:
    107      *  1. Detected if BitOffset is not 0 or BitWidth is not 8/16/32/64;
    108      *  2. AccessSize field is used for determining the boundary of the
    109      *     IO accesses;
    110      *  3. BitOffset/BitWidth fields are used to describe the "region".
    111      *
    112      * Note: This algorithm assumes that the "Address" fields should always
    113      *       contain aligned values.
    114      */
    115     if (!Reg->BitOffset && Reg->BitWidth &&
    116         ACPI_IS_POWER_OF_TWO (Reg->BitWidth) &&
    117         ACPI_IS_ALIGNED (Reg->BitWidth, 8))
    118     {
    119         AccessBitWidth = Reg->BitWidth;
    120     }
    121     else if (Reg->AccessWidth)
    122     {
    123         AccessBitWidth = (1 << (Reg->AccessWidth + 2));
    124     }
    125     else
    126     {
    127         AccessBitWidth = ACPI_ROUND_UP_POWER_OF_TWO_8 (
    128             Reg->BitOffset + Reg->BitWidth);
    129         if (AccessBitWidth <= 8)
    130         {
    131             AccessBitWidth = 8;
    132         }
    133         else
    134         {
    135             while (!ACPI_IS_ALIGNED (Address, AccessBitWidth >> 3))
    136             {
    137                 AccessBitWidth >>= 1;
    138             }
    139         }
    140     }
    141 
    142     /* Maximum IO port access bit width is 32 */
    143 
    144     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
    145     {
    146         MaxBitWidth = 32;
    147     }
    148 
    149     /*
    150      * Return access width according to the requested maximum access bit width,
    151      * as the caller should know the format of the register and may enforce
    152      * a 32-bit accesses.
    153      */
    154     if (AccessBitWidth < MaxBitWidth)
    155     {
    156         return (AccessBitWidth);
    157     }
    158     return (MaxBitWidth);
    159 }
    160 
    161 
    162 /******************************************************************************
    163  *
    164  * FUNCTION:    AcpiHwValidateRegister
    165  *
    166  * PARAMETERS:  Reg                 - GAS register structure
    167  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
    168  *              Address             - Pointer to where the gas->address
    169  *                                    is returned
    170  *
    171  * RETURN:      Status
    172  *
    173  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
    174  *              pointer, Address, SpaceId, BitWidth, and BitOffset.
    175  *
    176  ******************************************************************************/
    177 
    178 ACPI_STATUS
    179 AcpiHwValidateRegister (
    180     ACPI_GENERIC_ADDRESS    *Reg,
    181     UINT8                   MaxBitWidth,
    182     UINT64                  *Address)
    183 {
    184     UINT8                   BitWidth;
    185     UINT8                   AccessWidth;
    186 
    187 
    188     /* Must have a valid pointer to a GAS structure */
    189 
    190     if (!Reg)
    191     {
    192         return (AE_BAD_PARAMETER);
    193     }
    194 
    195     /*
    196      * Copy the target address. This handles possible alignment issues.
    197      * Address must not be null. A null address also indicates an optional
    198      * ACPI register that is not supported, so no error message.
    199      */
    200     ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
    201     if (!(*Address))
    202     {
    203         return (AE_BAD_ADDRESS);
    204     }
    205 
    206     /* Validate the SpaceID */
    207 
    208     if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
    209         (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
    210     {
    211         ACPI_ERROR ((AE_INFO,
    212             "Unsupported address space: 0x%X", Reg->SpaceId));
    213         return (AE_SUPPORT);
    214     }
    215 
    216     /* Validate the AccessWidth */
    217 
    218     if (Reg->AccessWidth > 4)
    219     {
    220         ACPI_ERROR ((AE_INFO,
    221             "Unsupported register access width: 0x%X", Reg->AccessWidth));
    222         return (AE_SUPPORT);
    223     }
    224 
    225     /* Validate the BitWidth, convert AccessWidth into number of bits */
    226 
    227     AccessWidth = AcpiHwGetAccessBitWidth (*Address, Reg, MaxBitWidth);
    228     BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);
    229     if (MaxBitWidth < BitWidth)
    230     {
    231         ACPI_WARNING ((AE_INFO,
    232             "Requested bit width 0x%X is smaller than register bit width 0x%X",
    233             MaxBitWidth, BitWidth));
    234         return (AE_SUPPORT);
    235     }
    236 
    237     return (AE_OK);
    238 }
    239 
    240 
    241 /******************************************************************************
    242  *
    243  * FUNCTION:    AcpiHwRead
    244  *
    245  * PARAMETERS:  Value               - Where the value is returned
    246  *              Reg                 - GAS register structure
    247  *
    248  * RETURN:      Status
    249  *
    250  * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
    251  *              version of AcpiRead, used internally since the overhead of
    252  *              64-bit values is not needed.
    253  *
    254  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
    255  *      SpaceID must be SystemMemory or SystemIO.
    256  *
    257  ******************************************************************************/
    258 
    259 ACPI_STATUS
    260 AcpiHwRead (
    261     UINT32                  *Value,
    262     ACPI_GENERIC_ADDRESS    *Reg)
    263 {
    264     UINT64                  Address;
    265     UINT8                   AccessWidth;
    266     UINT32                  BitWidth;
    267     UINT8                   BitOffset;
    268     UINT64                  Value64;
    269     UINT32                  Value32;
    270     UINT8                   Index;
    271     ACPI_STATUS             Status;
    272 
    273 
    274     ACPI_FUNCTION_NAME (HwRead);
    275 
    276 
    277     /* Validate contents of the GAS register */
    278 
    279     Status = AcpiHwValidateRegister (Reg, 32, &Address);
    280     if (ACPI_FAILURE (Status))
    281     {
    282         return (Status);
    283     }
    284 
    285     /*
    286      * Initialize entire 32-bit return value to zero, convert AccessWidth
    287      * into number of bits based
    288      */
    289     *Value = 0;
    290     AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32);
    291     BitWidth = Reg->BitOffset + Reg->BitWidth;
    292     BitOffset = Reg->BitOffset;
    293 
    294     /*
    295      * Two address spaces supported: Memory or IO. PCI_Config is
    296      * not supported here because the GAS structure is insufficient
    297      */
    298     Index = 0;
    299     while (BitWidth)
    300     {
    301         if (BitOffset >= AccessWidth)
    302         {
    303             Value32 = 0;
    304             BitOffset -= AccessWidth;
    305         }
    306         else
    307         {
    308             if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
    309             {
    310                 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
    311                     Address + Index * ACPI_DIV_8 (AccessWidth),
    312                     &Value64, AccessWidth);
    313                 Value32 = (UINT32) Value64;
    314             }
    315             else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    316             {
    317                 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
    318                     Address + Index * ACPI_DIV_8 (AccessWidth),
    319                     &Value32, AccessWidth);
    320             }
    321         }
    322 
    323         /*
    324          * Use offset style bit writes because "Index * AccessWidth" is
    325          * ensured to be less than 32-bits by AcpiHwValidateRegister().
    326          */
    327         ACPI_SET_BITS (Value, Index * AccessWidth,
    328             ACPI_MASK_BITS_ABOVE_32 (AccessWidth), Value32);
    329 
    330         BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
    331         Index++;
    332     }
    333 
    334     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
    335         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
    336         *Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
    337         AcpiUtGetRegionName (Reg->SpaceId)));
    338 
    339     return (Status);
    340 }
    341 
    342 
    343 /******************************************************************************
    344  *
    345  * FUNCTION:    AcpiHwWrite
    346  *
    347  * PARAMETERS:  Value               - Value to be written
    348  *              Reg                 - GAS register structure
    349  *
    350  * RETURN:      Status
    351  *
    352  * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
    353  *              version of AcpiWrite, used internally since the overhead of
    354  *              64-bit values is not needed.
    355  *
    356  ******************************************************************************/
    357 
    358 ACPI_STATUS
    359 AcpiHwWrite (
    360     UINT32                  Value,
    361     ACPI_GENERIC_ADDRESS    *Reg)
    362 {
    363     UINT64                  Address;
    364     UINT8                   AccessWidth;
    365     UINT32                  BitWidth;
    366     UINT8                   BitOffset;
    367     UINT64                  Value64;
    368     UINT32                  Value32;
    369     UINT8                   Index;
    370     ACPI_STATUS             Status;
    371 
    372 
    373     ACPI_FUNCTION_NAME (HwWrite);
    374 
    375 
    376     /* Validate contents of the GAS register */
    377 
    378     Status = AcpiHwValidateRegister (Reg, 32, &Address);
    379     if (ACPI_FAILURE (Status))
    380     {
    381         return (Status);
    382     }
    383 
    384     /* Convert AccessWidth into number of bits based */
    385 
    386     AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 32);
    387     BitWidth = Reg->BitOffset + Reg->BitWidth;
    388     BitOffset = Reg->BitOffset;
    389 
    390     /*
    391      * Two address spaces supported: Memory or IO. PCI_Config is
    392      * not supported here because the GAS structure is insufficient
    393      */
    394     Index = 0;
    395     while (BitWidth)
    396     {
    397         /*
    398          * Use offset style bit reads because "Index * AccessWidth" is
    399          * ensured to be less than 32-bits by AcpiHwValidateRegister().
    400          */
    401         Value32 = ACPI_GET_BITS (&Value, Index * AccessWidth,
    402             ACPI_MASK_BITS_ABOVE_32 (AccessWidth));
    403 
    404         if (BitOffset >= AccessWidth)
    405         {
    406             BitOffset -= AccessWidth;
    407         }
    408         else
    409         {
    410             if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
    411             {
    412                 Value64 = (UINT64) Value32;
    413                 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
    414                     Address + Index * ACPI_DIV_8 (AccessWidth),
    415                     Value64, AccessWidth);
    416             }
    417             else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    418             {
    419                 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
    420                     Address + Index * ACPI_DIV_8 (AccessWidth),
    421                     Value32, AccessWidth);
    422             }
    423         }
    424 
    425         /*
    426          * Index * AccessWidth is ensured to be less than 32-bits by
    427          * AcpiHwValidateRegister().
    428          */
    429         BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
    430         Index++;
    431     }
    432 
    433     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
    434         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
    435         Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
    436         AcpiUtGetRegionName (Reg->SpaceId)));
    437 
    438     return (Status);
    439 }
    440 
    441 
    442 #if (!ACPI_REDUCED_HARDWARE)
    443 /*******************************************************************************
    444  *
    445  * FUNCTION:    AcpiHwClearAcpiStatus
    446  *
    447  * PARAMETERS:  None
    448  *
    449  * RETURN:      Status
    450  *
    451  * DESCRIPTION: Clears all fixed and general purpose status bits
    452  *
    453  ******************************************************************************/
    454 
    455 ACPI_STATUS
    456 AcpiHwClearAcpiStatus (
    457     void)
    458 {
    459     ACPI_STATUS             Status;
    460     ACPI_CPU_FLAGS          LockFlags = 0;
    461 
    462 
    463     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
    464 
    465 
    466     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
    467         ACPI_BITMASK_ALL_FIXED_STATUS,
    468         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
    469 
    470     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
    471 
    472     /* Clear the fixed events in PM1 A/B */
    473 
    474     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
    475         ACPI_BITMASK_ALL_FIXED_STATUS);
    476 
    477     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
    478 
    479     if (ACPI_FAILURE (Status))
    480     {
    481         goto Exit;
    482     }
    483 
    484     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
    485 
    486     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
    487 
    488 Exit:
    489     return_ACPI_STATUS (Status);
    490 }
    491 
    492 
    493 /*******************************************************************************
    494  *
    495  * FUNCTION:    AcpiHwGetBitRegisterInfo
    496  *
    497  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
    498  *
    499  * RETURN:      The bitmask to be used when accessing the register
    500  *
    501  * DESCRIPTION: Map RegisterId into a register bitmask.
    502  *
    503  ******************************************************************************/
    504 
    505 ACPI_BIT_REGISTER_INFO *
    506 AcpiHwGetBitRegisterInfo (
    507     UINT32                  RegisterId)
    508 {
    509     ACPI_FUNCTION_ENTRY ();
    510 
    511 
    512     if (RegisterId > ACPI_BITREG_MAX)
    513     {
    514         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
    515         return (NULL);
    516     }
    517 
    518     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
    519 }
    520 
    521 
    522 /******************************************************************************
    523  *
    524  * FUNCTION:    AcpiHwWritePm1Control
    525  *
    526  * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
    527  *              Pm1bControl         - Value to be written to PM1B control
    528  *
    529  * RETURN:      Status
    530  *
    531  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
    532  *              different than than the PM1 A/B status and enable registers
    533  *              in that different values can be written to the A/B registers.
    534  *              Most notably, the SLP_TYP bits can be different, as per the
    535  *              values returned from the _Sx predefined methods.
    536  *
    537  ******************************************************************************/
    538 
    539 ACPI_STATUS
    540 AcpiHwWritePm1Control (
    541     UINT32                  Pm1aControl,
    542     UINT32                  Pm1bControl)
    543 {
    544     ACPI_STATUS             Status;
    545 
    546 
    547     ACPI_FUNCTION_TRACE (HwWritePm1Control);
    548 
    549 
    550     Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
    551     if (ACPI_FAILURE (Status))
    552     {
    553         return_ACPI_STATUS (Status);
    554     }
    555 
    556     if (AcpiGbl_FADT.XPm1bControlBlock.Address)
    557     {
    558         Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
    559     }
    560     return_ACPI_STATUS (Status);
    561 }
    562 
    563 
    564 /******************************************************************************
    565  *
    566  * FUNCTION:    AcpiHwRegisterRead
    567  *
    568  * PARAMETERS:  RegisterId          - ACPI Register ID
    569  *              ReturnValue         - Where the register value is returned
    570  *
    571  * RETURN:      Status and the value read.
    572  *
    573  * DESCRIPTION: Read from the specified ACPI register
    574  *
    575  ******************************************************************************/
    576 
    577 ACPI_STATUS
    578 AcpiHwRegisterRead (
    579     UINT32                  RegisterId,
    580     UINT32                  *ReturnValue)
    581 {
    582     UINT32                  Value = 0;
    583     ACPI_STATUS             Status;
    584 
    585 
    586     ACPI_FUNCTION_TRACE (HwRegisterRead);
    587 
    588 
    589     switch (RegisterId)
    590     {
    591     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
    592 
    593         Status = AcpiHwReadMultiple (&Value,
    594             &AcpiGbl_XPm1aStatus,
    595             &AcpiGbl_XPm1bStatus);
    596         break;
    597 
    598     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
    599 
    600         Status = AcpiHwReadMultiple (&Value,
    601             &AcpiGbl_XPm1aEnable,
    602             &AcpiGbl_XPm1bEnable);
    603         break;
    604 
    605     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
    606 
    607         Status = AcpiHwReadMultiple (&Value,
    608             &AcpiGbl_FADT.XPm1aControlBlock,
    609             &AcpiGbl_FADT.XPm1bControlBlock);
    610 
    611         /*
    612          * Zero the write-only bits. From the ACPI specification, "Hardware
    613          * Write-Only Bits": "Upon reads to registers with write-only bits,
    614          * software masks out all write-only bits."
    615          */
    616         Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
    617         break;
    618 
    619     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
    620 
    621         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
    622         break;
    623 
    624     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
    625 
    626         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
    627         break;
    628 
    629     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
    630 
    631         Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
    632         break;
    633 
    634     default:
    635 
    636         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
    637             RegisterId));
    638         Status = AE_BAD_PARAMETER;
    639         break;
    640     }
    641 
    642     if (ACPI_SUCCESS (Status))
    643     {
    644         *ReturnValue = Value;
    645     }
    646 
    647     return_ACPI_STATUS (Status);
    648 }
    649 
    650 
    651 /******************************************************************************
    652  *
    653  * FUNCTION:    AcpiHwRegisterWrite
    654  *
    655  * PARAMETERS:  RegisterId          - ACPI Register ID
    656  *              Value               - The value to write
    657  *
    658  * RETURN:      Status
    659  *
    660  * DESCRIPTION: Write to the specified ACPI register
    661  *
    662  * NOTE: In accordance with the ACPI specification, this function automatically
    663  * preserves the value of the following bits, meaning that these bits cannot be
    664  * changed via this interface:
    665  *
    666  * PM1_CONTROL[0] = SCI_EN
    667  * PM1_CONTROL[9]
    668  * PM1_STATUS[11]
    669  *
    670  * ACPI References:
    671  * 1) Hardware Ignored Bits: When software writes to a register with ignored
    672  *      bit fields, it preserves the ignored bit fields
    673  * 2) SCI_EN: OSPM always preserves this bit position
    674  *
    675  ******************************************************************************/
    676 
    677 ACPI_STATUS
    678 AcpiHwRegisterWrite (
    679     UINT32                  RegisterId,
    680     UINT32                  Value)
    681 {
    682     ACPI_STATUS             Status;
    683     UINT32                  ReadValue;
    684 
    685 
    686     ACPI_FUNCTION_TRACE (HwRegisterWrite);
    687 
    688 
    689     switch (RegisterId)
    690     {
    691     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
    692         /*
    693          * Handle the "ignored" bit in PM1 Status. According to the ACPI
    694          * specification, ignored bits are to be preserved when writing.
    695          * Normally, this would mean a read/modify/write sequence. However,
    696          * preserving a bit in the status register is different. Writing a
    697          * one clears the status, and writing a zero preserves the status.
    698          * Therefore, we must always write zero to the ignored bit.
    699          *
    700          * This behavior is clarified in the ACPI 4.0 specification.
    701          */
    702         Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
    703 
    704         Status = AcpiHwWriteMultiple (Value,
    705             &AcpiGbl_XPm1aStatus,
    706             &AcpiGbl_XPm1bStatus);
    707         break;
    708 
    709     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
    710 
    711         Status = AcpiHwWriteMultiple (Value,
    712             &AcpiGbl_XPm1aEnable,
    713             &AcpiGbl_XPm1bEnable);
    714         break;
    715 
    716     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
    717         /*
    718          * Perform a read first to preserve certain bits (per ACPI spec)
    719          * Note: This includes SCI_EN, we never want to change this bit
    720          */
    721         Status = AcpiHwReadMultiple (&ReadValue,
    722             &AcpiGbl_FADT.XPm1aControlBlock,
    723             &AcpiGbl_FADT.XPm1bControlBlock);
    724         if (ACPI_FAILURE (Status))
    725         {
    726             goto Exit;
    727         }
    728 
    729         /* Insert the bits to be preserved */
    730 
    731         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
    732 
    733         /* Now we can write the data */
    734 
    735         Status = AcpiHwWriteMultiple (Value,
    736             &AcpiGbl_FADT.XPm1aControlBlock,
    737             &AcpiGbl_FADT.XPm1bControlBlock);
    738         break;
    739 
    740     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
    741         /*
    742          * For control registers, all reserved bits must be preserved,
    743          * as per the ACPI spec.
    744          */
    745         Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
    746         if (ACPI_FAILURE (Status))
    747         {
    748             goto Exit;
    749         }
    750 
    751         /* Insert the bits to be preserved */
    752 
    753         ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
    754 
    755         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
    756         break;
    757 
    758     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
    759 
    760         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
    761         break;
    762 
    763     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
    764 
    765         /* SMI_CMD is currently always in IO space */
    766 
    767         Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
    768         break;
    769 
    770     default:
    771 
    772         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
    773             RegisterId));
    774         Status = AE_BAD_PARAMETER;
    775         break;
    776     }
    777 
    778 Exit:
    779     return_ACPI_STATUS (Status);
    780 }
    781 
    782 
    783 /******************************************************************************
    784  *
    785  * FUNCTION:    AcpiHwReadMultiple
    786  *
    787  * PARAMETERS:  Value               - Where the register value is returned
    788  *              RegisterA           - First ACPI register (required)
    789  *              RegisterB           - Second ACPI register (optional)
    790  *
    791  * RETURN:      Status
    792  *
    793  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
    794  *
    795  ******************************************************************************/
    796 
    797 static ACPI_STATUS
    798 AcpiHwReadMultiple (
    799     UINT32                  *Value,
    800     ACPI_GENERIC_ADDRESS    *RegisterA,
    801     ACPI_GENERIC_ADDRESS    *RegisterB)
    802 {
    803     UINT32                  ValueA = 0;
    804     UINT32                  ValueB = 0;
    805     ACPI_STATUS             Status;
    806 
    807 
    808     /* The first register is always required */
    809 
    810     Status = AcpiHwRead (&ValueA, RegisterA);
    811     if (ACPI_FAILURE (Status))
    812     {
    813         return (Status);
    814     }
    815 
    816     /* Second register is optional */
    817 
    818     if (RegisterB->Address)
    819     {
    820         Status = AcpiHwRead (&ValueB, RegisterB);
    821         if (ACPI_FAILURE (Status))
    822         {
    823             return (Status);
    824         }
    825     }
    826 
    827     /*
    828      * OR the two return values together. No shifting or masking is necessary,
    829      * because of how the PM1 registers are defined in the ACPI specification:
    830      *
    831      * "Although the bits can be split between the two register blocks (each
    832      * register block has a unique pointer within the FADT), the bit positions
    833      * are maintained. The register block with unimplemented bits (that is,
    834      * those implemented in the other register block) always returns zeros,
    835      * and writes have no side effects"
    836      */
    837     *Value = (ValueA | ValueB);
    838     return (AE_OK);
    839 }
    840 
    841 
    842 /******************************************************************************
    843  *
    844  * FUNCTION:    AcpiHwWriteMultiple
    845  *
    846  * PARAMETERS:  Value               - The value to write
    847  *              RegisterA           - First ACPI register (required)
    848  *              RegisterB           - Second ACPI register (optional)
    849  *
    850  * RETURN:      Status
    851  *
    852  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
    853  *
    854  ******************************************************************************/
    855 
    856 static ACPI_STATUS
    857 AcpiHwWriteMultiple (
    858     UINT32                  Value,
    859     ACPI_GENERIC_ADDRESS    *RegisterA,
    860     ACPI_GENERIC_ADDRESS    *RegisterB)
    861 {
    862     ACPI_STATUS             Status;
    863 
    864 
    865     /* The first register is always required */
    866 
    867     Status = AcpiHwWrite (Value, RegisterA);
    868     if (ACPI_FAILURE (Status))
    869     {
    870         return (Status);
    871     }
    872 
    873     /*
    874      * Second register is optional
    875      *
    876      * No bit shifting or clearing is necessary, because of how the PM1
    877      * registers are defined in the ACPI specification:
    878      *
    879      * "Although the bits can be split between the two register blocks (each
    880      * register block has a unique pointer within the FADT), the bit positions
    881      * are maintained. The register block with unimplemented bits (that is,
    882      * those implemented in the other register block) always returns zeros,
    883      * and writes have no side effects"
    884      */
    885     if (RegisterB->Address)
    886     {
    887         Status = AcpiHwWrite (Value, RegisterB);
    888     }
    889 
    890     return (Status);
    891 }
    892 
    893 #endif /* !ACPI_REDUCED_HARDWARE */
    894