Home | History | Annotate | Line # | Download | only in hardware
hwregs.c revision 1.11
      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 - 2022, 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 MERCHANTABILITY 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 = ACPI_ACCESS_BIT_WIDTH (Reg->AccessWidth);
    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 64-bit max
    251  *              version of AcpiRead.
    252  *
    253  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
    254  *      SpaceID must be SystemMemory or SystemIO.
    255  *
    256  ******************************************************************************/
    257 
    258 ACPI_STATUS
    259 AcpiHwRead (
    260     UINT64                  *Value,
    261     ACPI_GENERIC_ADDRESS    *Reg)
    262 {
    263     UINT64                  Address;
    264     UINT8                   AccessWidth;
    265     UINT32                  BitWidth;
    266     UINT8                   BitOffset;
    267     UINT64                  Value64;
    268     UINT32                  Value32;
    269     UINT8                   Index;
    270     ACPI_STATUS             Status;
    271 
    272 
    273     ACPI_FUNCTION_NAME (HwRead);
    274 
    275 
    276     /* Validate contents of the GAS register */
    277 
    278     Status = AcpiHwValidateRegister (Reg, 64, &Address);
    279     if (ACPI_FAILURE (Status))
    280     {
    281         return (Status);
    282     }
    283 
    284     /*
    285      * Initialize entire 64-bit return value to zero, convert AccessWidth
    286      * into number of bits based
    287      */
    288     *Value = 0;
    289     AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);
    290     BitWidth = Reg->BitOffset + Reg->BitWidth;
    291     BitOffset = Reg->BitOffset;
    292 
    293     /*
    294      * Two address spaces supported: Memory or IO. PCI_Config is
    295      * not supported here because the GAS structure is insufficient
    296      */
    297     Index = 0;
    298     while (BitWidth)
    299     {
    300         if (BitOffset >= AccessWidth)
    301         {
    302             Value64 = 0;
    303             BitOffset -= AccessWidth;
    304         }
    305         else
    306         {
    307             if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
    308             {
    309                 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
    310                     Address + Index * ACPI_DIV_8 (AccessWidth),
    311                     &Value64, AccessWidth);
    312             }
    313             else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    314             {
    315                 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
    316                     Address + Index * ACPI_DIV_8 (AccessWidth),
    317                     &Value32, AccessWidth);
    318                 Value64 = (UINT64) Value32;
    319             }
    320         }
    321 
    322         /*
    323          * Use offset style bit writes because "Index * AccessWidth" is
    324          * ensured to be less than 64-bits by AcpiHwValidateRegister().
    325          */
    326         ACPI_SET_BITS (Value, Index * AccessWidth,
    327             ACPI_MASK_BITS_ABOVE_64 (AccessWidth), Value64);
    328 
    329         BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
    330         Index++;
    331     }
    332 
    333     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
    334         "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
    335         ACPI_FORMAT_UINT64 (*Value), AccessWidth,
    336         ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));
    337 
    338     return (Status);
    339 }
    340 
    341 
    342 /******************************************************************************
    343  *
    344  * FUNCTION:    AcpiHwWrite
    345  *
    346  * PARAMETERS:  Value               - Value to be written
    347  *              Reg                 - GAS register structure
    348  *
    349  * RETURN:      Status
    350  *
    351  * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
    352  *              version of AcpiWrite.
    353  *
    354  ******************************************************************************/
    355 
    356 ACPI_STATUS
    357 AcpiHwWrite (
    358     UINT64                  Value,
    359     ACPI_GENERIC_ADDRESS    *Reg)
    360 {
    361     UINT64                  Address;
    362     UINT8                   AccessWidth;
    363     UINT32                  BitWidth;
    364     UINT8                   BitOffset;
    365     UINT64                  Value64;
    366     UINT8                   Index;
    367     ACPI_STATUS             Status;
    368 
    369 
    370     ACPI_FUNCTION_NAME (HwWrite);
    371 
    372 
    373     /* Validate contents of the GAS register */
    374 
    375     Status = AcpiHwValidateRegister (Reg, 64, &Address);
    376     if (ACPI_FAILURE (Status))
    377     {
    378         return (Status);
    379     }
    380 
    381     /* Convert AccessWidth into number of bits based */
    382 
    383     AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64);
    384     BitWidth = Reg->BitOffset + Reg->BitWidth;
    385     BitOffset = Reg->BitOffset;
    386 
    387     /*
    388      * Two address spaces supported: Memory or IO. PCI_Config is
    389      * not supported here because the GAS structure is insufficient
    390      */
    391     Index = 0;
    392     while (BitWidth)
    393     {
    394         /*
    395          * Use offset style bit reads because "Index * AccessWidth" is
    396          * ensured to be less than 64-bits by AcpiHwValidateRegister().
    397          */
    398         Value64 = ACPI_GET_BITS (&Value, Index * AccessWidth,
    399             ACPI_MASK_BITS_ABOVE_64 (AccessWidth));
    400 
    401         if (BitOffset >= AccessWidth)
    402         {
    403             BitOffset -= AccessWidth;
    404         }
    405         else
    406         {
    407             if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
    408             {
    409                 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
    410                     Address + Index * ACPI_DIV_8 (AccessWidth),
    411                     Value64, AccessWidth);
    412             }
    413             else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    414             {
    415                 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
    416                     Address + Index * ACPI_DIV_8 (AccessWidth),
    417                     (UINT32) Value64, AccessWidth);
    418             }
    419         }
    420 
    421         /*
    422          * Index * AccessWidth is ensured to be less than 32-bits by
    423          * AcpiHwValidateRegister().
    424          */
    425         BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
    426         Index++;
    427     }
    428 
    429     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
    430         "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
    431         ACPI_FORMAT_UINT64 (Value), AccessWidth,
    432         ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId)));
    433 
    434     return (Status);
    435 }
    436 
    437 
    438 #if (!ACPI_REDUCED_HARDWARE)
    439 /*******************************************************************************
    440  *
    441  * FUNCTION:    AcpiHwClearAcpiStatus
    442  *
    443  * PARAMETERS:  None
    444  *
    445  * RETURN:      Status
    446  *
    447  * DESCRIPTION: Clears all fixed and general purpose status bits
    448  *
    449  ******************************************************************************/
    450 
    451 ACPI_STATUS
    452 AcpiHwClearAcpiStatus (
    453     void)
    454 {
    455     ACPI_STATUS             Status;
    456     ACPI_CPU_FLAGS          LockFlags = 0;
    457 
    458 
    459     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
    460 
    461 
    462     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
    463         ACPI_BITMASK_ALL_FIXED_STATUS,
    464         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
    465 
    466     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
    467 
    468     /* Clear the fixed events in PM1 A/B */
    469 
    470     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
    471         ACPI_BITMASK_ALL_FIXED_STATUS);
    472 
    473     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
    474 
    475     if (ACPI_FAILURE (Status))
    476     {
    477         goto Exit;
    478     }
    479 
    480     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
    481 
    482     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
    483 
    484 Exit:
    485     return_ACPI_STATUS (Status);
    486 }
    487 
    488 
    489 /*******************************************************************************
    490  *
    491  * FUNCTION:    AcpiHwGetBitRegisterInfo
    492  *
    493  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
    494  *
    495  * RETURN:      The bitmask to be used when accessing the register
    496  *
    497  * DESCRIPTION: Map RegisterId into a register bitmask.
    498  *
    499  ******************************************************************************/
    500 
    501 ACPI_BIT_REGISTER_INFO *
    502 AcpiHwGetBitRegisterInfo (
    503     UINT32                  RegisterId)
    504 {
    505     ACPI_FUNCTION_ENTRY ();
    506 
    507 
    508     if (RegisterId > ACPI_BITREG_MAX)
    509     {
    510         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
    511         return (NULL);
    512     }
    513 
    514     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
    515 }
    516 
    517 
    518 /******************************************************************************
    519  *
    520  * FUNCTION:    AcpiHwWritePm1Control
    521  *
    522  * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
    523  *              Pm1bControl         - Value to be written to PM1B control
    524  *
    525  * RETURN:      Status
    526  *
    527  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
    528  *              different than the PM1 A/B status and enable registers
    529  *              in that different values can be written to the A/B registers.
    530  *              Most notably, the SLP_TYP bits can be different, as per the
    531  *              values returned from the _Sx predefined methods.
    532  *
    533  ******************************************************************************/
    534 
    535 ACPI_STATUS
    536 AcpiHwWritePm1Control (
    537     UINT32                  Pm1aControl,
    538     UINT32                  Pm1bControl)
    539 {
    540     ACPI_STATUS             Status;
    541 
    542 
    543     ACPI_FUNCTION_TRACE (HwWritePm1Control);
    544 
    545 
    546     Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
    547     if (ACPI_FAILURE (Status))
    548     {
    549         return_ACPI_STATUS (Status);
    550     }
    551 
    552     if (AcpiGbl_FADT.XPm1bControlBlock.Address)
    553     {
    554         Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
    555     }
    556     return_ACPI_STATUS (Status);
    557 }
    558 
    559 
    560 /******************************************************************************
    561  *
    562  * FUNCTION:    AcpiHwRegisterRead
    563  *
    564  * PARAMETERS:  RegisterId          - ACPI Register ID
    565  *              ReturnValue         - Where the register value is returned
    566  *
    567  * RETURN:      Status and the value read.
    568  *
    569  * DESCRIPTION: Read from the specified ACPI register
    570  *
    571  ******************************************************************************/
    572 
    573 ACPI_STATUS
    574 AcpiHwRegisterRead (
    575     UINT32                  RegisterId,
    576     UINT32                  *ReturnValue)
    577 {
    578     UINT32                  Value = 0;
    579     UINT64                  Value64;
    580     ACPI_STATUS             Status;
    581 
    582 
    583     ACPI_FUNCTION_TRACE (HwRegisterRead);
    584 
    585 
    586     switch (RegisterId)
    587     {
    588     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
    589 
    590         Status = AcpiHwReadMultiple (&Value,
    591             &AcpiGbl_XPm1aStatus,
    592             &AcpiGbl_XPm1bStatus);
    593         break;
    594 
    595     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
    596 
    597         Status = AcpiHwReadMultiple (&Value,
    598             &AcpiGbl_XPm1aEnable,
    599             &AcpiGbl_XPm1bEnable);
    600         break;
    601 
    602     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
    603 
    604         Status = AcpiHwReadMultiple (&Value,
    605             &AcpiGbl_FADT.XPm1aControlBlock,
    606             &AcpiGbl_FADT.XPm1bControlBlock);
    607 
    608         /*
    609          * Zero the write-only bits. From the ACPI specification, "Hardware
    610          * Write-Only Bits": "Upon reads to registers with write-only bits,
    611          * software masks out all write-only bits."
    612          */
    613         Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
    614         break;
    615 
    616     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
    617 
    618         Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPm2ControlBlock);
    619         if (ACPI_SUCCESS (Status))
    620         {
    621             Value = (UINT32) Value64;
    622         }
    623         break;
    624 
    625     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
    626 
    627         Status = AcpiHwRead (&Value64, &AcpiGbl_FADT.XPmTimerBlock);
    628         if (ACPI_SUCCESS (Status))
    629         {
    630             Value = (UINT32) Value64;
    631         }
    632 
    633         break;
    634 
    635     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
    636 
    637         Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
    638         break;
    639 
    640     default:
    641 
    642         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
    643             RegisterId));
    644         Status = AE_BAD_PARAMETER;
    645         break;
    646     }
    647 
    648     if (ACPI_SUCCESS (Status))
    649     {
    650         *ReturnValue = (UINT32) Value;
    651     }
    652 
    653     return_ACPI_STATUS (Status);
    654 }
    655 
    656 
    657 /******************************************************************************
    658  *
    659  * FUNCTION:    AcpiHwRegisterWrite
    660  *
    661  * PARAMETERS:  RegisterId          - ACPI Register ID
    662  *              Value               - The value to write
    663  *
    664  * RETURN:      Status
    665  *
    666  * DESCRIPTION: Write to the specified ACPI register
    667  *
    668  * NOTE: In accordance with the ACPI specification, this function automatically
    669  * preserves the value of the following bits, meaning that these bits cannot be
    670  * changed via this interface:
    671  *
    672  * PM1_CONTROL[0] = SCI_EN
    673  * PM1_CONTROL[9]
    674  * PM1_STATUS[11]
    675  *
    676  * ACPI References:
    677  * 1) Hardware Ignored Bits: When software writes to a register with ignored
    678  *      bit fields, it preserves the ignored bit fields
    679  * 2) SCI_EN: OSPM always preserves this bit position
    680  *
    681  ******************************************************************************/
    682 
    683 ACPI_STATUS
    684 AcpiHwRegisterWrite (
    685     UINT32                  RegisterId,
    686     UINT32                  Value)
    687 {
    688     ACPI_STATUS             Status;
    689     UINT32                  ReadValue;
    690     UINT64                  ReadValue64;
    691 
    692 
    693     ACPI_FUNCTION_TRACE (HwRegisterWrite);
    694 
    695 
    696     switch (RegisterId)
    697     {
    698     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
    699         /*
    700          * Handle the "ignored" bit in PM1 Status. According to the ACPI
    701          * specification, ignored bits are to be preserved when writing.
    702          * Normally, this would mean a read/modify/write sequence. However,
    703          * preserving a bit in the status register is different. Writing a
    704          * one clears the status, and writing a zero preserves the status.
    705          * Therefore, we must always write zero to the ignored bit.
    706          *
    707          * This behavior is clarified in the ACPI 4.0 specification.
    708          */
    709         Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
    710 
    711         Status = AcpiHwWriteMultiple (Value,
    712             &AcpiGbl_XPm1aStatus,
    713             &AcpiGbl_XPm1bStatus);
    714         break;
    715 
    716     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
    717 
    718         Status = AcpiHwWriteMultiple (Value,
    719             &AcpiGbl_XPm1aEnable,
    720             &AcpiGbl_XPm1bEnable);
    721         break;
    722 
    723     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
    724         /*
    725          * Perform a read first to preserve certain bits (per ACPI spec)
    726          * Note: This includes SCI_EN, we never want to change this bit
    727          */
    728         Status = AcpiHwReadMultiple (&ReadValue,
    729             &AcpiGbl_FADT.XPm1aControlBlock,
    730             &AcpiGbl_FADT.XPm1bControlBlock);
    731         if (ACPI_FAILURE (Status))
    732         {
    733             goto Exit;
    734         }
    735 
    736         /* Insert the bits to be preserved */
    737 
    738         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
    739 
    740         /* Now we can write the data */
    741 
    742         Status = AcpiHwWriteMultiple (Value,
    743             &AcpiGbl_FADT.XPm1aControlBlock,
    744             &AcpiGbl_FADT.XPm1bControlBlock);
    745         break;
    746 
    747     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
    748         /*
    749          * For control registers, all reserved bits must be preserved,
    750          * as per the ACPI spec.
    751          */
    752         Status = AcpiHwRead (&ReadValue64, &AcpiGbl_FADT.XPm2ControlBlock);
    753         if (ACPI_FAILURE (Status))
    754         {
    755             goto Exit;
    756         }
    757         ReadValue = (UINT32) ReadValue64;
    758 
    759         /* Insert the bits to be preserved */
    760 
    761         ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
    762 
    763         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
    764         break;
    765 
    766     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
    767 
    768         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
    769         break;
    770 
    771     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
    772 
    773         /* SMI_CMD is currently always in IO space */
    774 
    775         Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
    776         break;
    777 
    778     default:
    779 
    780         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
    781             RegisterId));
    782         Status = AE_BAD_PARAMETER;
    783         break;
    784     }
    785 
    786 Exit:
    787     return_ACPI_STATUS (Status);
    788 }
    789 
    790 
    791 /******************************************************************************
    792  *
    793  * FUNCTION:    AcpiHwReadMultiple
    794  *
    795  * PARAMETERS:  Value               - Where the register value is returned
    796  *              RegisterA           - First ACPI register (required)
    797  *              RegisterB           - Second ACPI register (optional)
    798  *
    799  * RETURN:      Status
    800  *
    801  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
    802  *
    803  ******************************************************************************/
    804 
    805 static ACPI_STATUS
    806 AcpiHwReadMultiple (
    807     UINT32                  *Value,
    808     ACPI_GENERIC_ADDRESS    *RegisterA,
    809     ACPI_GENERIC_ADDRESS    *RegisterB)
    810 {
    811     UINT32                  ValueA = 0;
    812     UINT32                  ValueB = 0;
    813     UINT64                  Value64;
    814     ACPI_STATUS             Status;
    815 
    816 
    817     /* The first register is always required */
    818 
    819     Status = AcpiHwRead (&Value64, RegisterA);
    820     if (ACPI_FAILURE (Status))
    821     {
    822         return (Status);
    823     }
    824     ValueA = (UINT32) Value64;
    825 
    826     /* Second register is optional */
    827 
    828     if (RegisterB->Address)
    829     {
    830         Status = AcpiHwRead (&Value64, RegisterB);
    831         if (ACPI_FAILURE (Status))
    832         {
    833             return (Status);
    834         }
    835         ValueB = (UINT32) Value64;
    836     }
    837 
    838     /*
    839      * OR the two return values together. No shifting or masking is necessary,
    840      * because of how the PM1 registers are defined in the ACPI specification:
    841      *
    842      * "Although the bits can be split between the two register blocks (each
    843      * register block has a unique pointer within the FADT), the bit positions
    844      * are maintained. The register block with unimplemented bits (that is,
    845      * those implemented in the other register block) always returns zeros,
    846      * and writes have no side effects"
    847      */
    848     *Value = (ValueA | ValueB);
    849     return (AE_OK);
    850 }
    851 
    852 
    853 /******************************************************************************
    854  *
    855  * FUNCTION:    AcpiHwWriteMultiple
    856  *
    857  * PARAMETERS:  Value               - The value to write
    858  *              RegisterA           - First ACPI register (required)
    859  *              RegisterB           - Second ACPI register (optional)
    860  *
    861  * RETURN:      Status
    862  *
    863  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
    864  *
    865  ******************************************************************************/
    866 
    867 static ACPI_STATUS
    868 AcpiHwWriteMultiple (
    869     UINT32                  Value,
    870     ACPI_GENERIC_ADDRESS    *RegisterA,
    871     ACPI_GENERIC_ADDRESS    *RegisterB)
    872 {
    873     ACPI_STATUS             Status;
    874 
    875 
    876     /* The first register is always required */
    877 
    878     Status = AcpiHwWrite (Value, RegisterA);
    879     if (ACPI_FAILURE (Status))
    880     {
    881         return (Status);
    882     }
    883 
    884     /*
    885      * Second register is optional
    886      *
    887      * No bit shifting or clearing is necessary, because of how the PM1
    888      * registers are defined in the ACPI specification:
    889      *
    890      * "Although the bits can be split between the two register blocks (each
    891      * register block has a unique pointer within the FADT), the bit positions
    892      * are maintained. The register block with unimplemented bits (that is,
    893      * those implemented in the other register block) always returns zeros,
    894      * and writes have no side effects"
    895      */
    896     if (RegisterB->Address)
    897     {
    898         Status = AcpiHwWrite (Value, RegisterB);
    899     }
    900 
    901     return (Status);
    902 }
    903 
    904 #endif /* !ACPI_REDUCED_HARDWARE */
    905