Home | History | Annotate | Line # | Download | only in hardware
hwregs.c revision 1.1
      1 
      2 /*******************************************************************************
      3  *
      4  * Module Name: hwregs - Read/write access functions for the various ACPI
      5  *                       control and status registers.
      6  *
      7  ******************************************************************************/
      8 
      9 /******************************************************************************
     10  *
     11  * 1. Copyright Notice
     12  *
     13  * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp.
     14  * All rights reserved.
     15  *
     16  * 2. License
     17  *
     18  * 2.1. This is your license from Intel Corp. under its intellectual property
     19  * rights.  You may have additional license terms from the party that provided
     20  * you this software, covering your right to use that party's intellectual
     21  * property rights.
     22  *
     23  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
     24  * copy of the source code appearing in this file ("Covered Code") an
     25  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
     26  * base code distributed originally by Intel ("Original Intel Code") to copy,
     27  * make derivatives, distribute, use and display any portion of the Covered
     28  * Code in any form, with the right to sublicense such rights; and
     29  *
     30  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
     31  * license (with the right to sublicense), under only those claims of Intel
     32  * patents that are infringed by the Original Intel Code, to make, use, sell,
     33  * offer to sell, and import the Covered Code and derivative works thereof
     34  * solely to the minimum extent necessary to exercise the above copyright
     35  * license, and in no event shall the patent license extend to any additions
     36  * to or modifications of the Original Intel Code.  No other license or right
     37  * is granted directly or by implication, estoppel or otherwise;
     38  *
     39  * The above copyright and patent license is granted only if the following
     40  * conditions are met:
     41  *
     42  * 3. Conditions
     43  *
     44  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
     45  * Redistribution of source code of any substantial portion of the Covered
     46  * Code or modification with rights to further distribute source must include
     47  * the above Copyright Notice, the above License, this list of Conditions,
     48  * and the following Disclaimer and Export Compliance provision.  In addition,
     49  * Licensee must cause all Covered Code to which Licensee contributes to
     50  * contain a file documenting the changes Licensee made to create that Covered
     51  * Code and the date of any change.  Licensee must include in that file the
     52  * documentation of any changes made by any predecessor Licensee.  Licensee
     53  * must include a prominent statement that the modification is derived,
     54  * directly or indirectly, from Original Intel Code.
     55  *
     56  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
     57  * Redistribution of source code of any substantial portion of the Covered
     58  * Code or modification without rights to further distribute source must
     59  * include the following Disclaimer and Export Compliance provision in the
     60  * documentation and/or other materials provided with distribution.  In
     61  * addition, Licensee may not authorize further sublicense of source of any
     62  * portion of the Covered Code, and must include terms to the effect that the
     63  * license from Licensee to its licensee is limited to the intellectual
     64  * property embodied in the software Licensee provides to its licensee, and
     65  * not to intellectual property embodied in modifications its licensee may
     66  * make.
     67  *
     68  * 3.3. Redistribution of Executable. Redistribution in executable form of any
     69  * substantial portion of the Covered Code or modification must reproduce the
     70  * above Copyright Notice, and the following Disclaimer and Export Compliance
     71  * provision in the documentation and/or other materials provided with the
     72  * distribution.
     73  *
     74  * 3.4. Intel retains all right, title, and interest in and to the Original
     75  * Intel Code.
     76  *
     77  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
     78  * Intel shall be used in advertising or otherwise to promote the sale, use or
     79  * other dealings in products derived from or relating to the Covered Code
     80  * without prior written authorization from Intel.
     81  *
     82  * 4. Disclaimer and Export Compliance
     83  *
     84  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
     85  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
     86  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
     87  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
     88  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
     89  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
     90  * PARTICULAR PURPOSE.
     91  *
     92  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
     93  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
     94  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
     95  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
     96  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
     97  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
     98  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
     99  * LIMITED REMEDY.
    100  *
    101  * 4.3. Licensee shall not export, either directly or indirectly, any of this
    102  * software or system incorporating such software without first obtaining any
    103  * required license or other approval from the U. S. Department of Commerce or
    104  * any other agency or department of the United States Government.  In the
    105  * event Licensee exports any such software from the United States or
    106  * re-exports any such software from a foreign destination, Licensee shall
    107  * ensure that the distribution and export/re-export of the software is in
    108  * compliance with all laws, regulations, orders, or other restrictions of the
    109  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
    110  * any of its subsidiaries will export/re-export any technical data, process,
    111  * software, or service, directly or indirectly, to any country for which the
    112  * United States government or any agency thereof requires an export license,
    113  * other governmental approval, or letter of assurance, without first obtaining
    114  * such license, approval or letter.
    115  *
    116  *****************************************************************************/
    117 
    118 #define __HWREGS_C__
    119 
    120 #include "acpi.h"
    121 #include "accommon.h"
    122 #include "acevents.h"
    123 
    124 #define _COMPONENT          ACPI_HARDWARE
    125         ACPI_MODULE_NAME    ("hwregs")
    126 
    127 
    128 /* Local Prototypes */
    129 
    130 static ACPI_STATUS
    131 AcpiHwReadMultiple (
    132     UINT32                  *Value,
    133     ACPI_GENERIC_ADDRESS    *RegisterA,
    134     ACPI_GENERIC_ADDRESS    *RegisterB);
    135 
    136 static ACPI_STATUS
    137 AcpiHwWriteMultiple (
    138     UINT32                  Value,
    139     ACPI_GENERIC_ADDRESS    *RegisterA,
    140     ACPI_GENERIC_ADDRESS    *RegisterB);
    141 
    142 
    143 /******************************************************************************
    144  *
    145  * FUNCTION:    AcpiHwValidateRegister
    146  *
    147  * PARAMETERS:  Reg                 - GAS register structure
    148  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
    149  *              Address             - Pointer to where the gas->address
    150  *                                    is returned
    151  *
    152  * RETURN:      Status
    153  *
    154  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
    155  *              pointer, Address, SpaceId, BitWidth, and BitOffset.
    156  *
    157  ******************************************************************************/
    158 
    159 ACPI_STATUS
    160 AcpiHwValidateRegister (
    161     ACPI_GENERIC_ADDRESS    *Reg,
    162     UINT8                   MaxBitWidth,
    163     UINT64                  *Address)
    164 {
    165 
    166     /* Must have a valid pointer to a GAS structure */
    167 
    168     if (!Reg)
    169     {
    170         return (AE_BAD_PARAMETER);
    171     }
    172 
    173     /*
    174      * Copy the target address. This handles possible alignment issues.
    175      * Address must not be null. A null address also indicates an optional
    176      * ACPI register that is not supported, so no error message.
    177      */
    178     ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
    179     if (!(*Address))
    180     {
    181         return (AE_BAD_ADDRESS);
    182     }
    183 
    184     /* Validate the SpaceID */
    185 
    186     if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
    187         (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
    188     {
    189         ACPI_ERROR ((AE_INFO,
    190             "Unsupported address space: 0x%X", Reg->SpaceId));
    191         return (AE_SUPPORT);
    192     }
    193 
    194     /* Validate the BitWidth */
    195 
    196     if ((Reg->BitWidth != 8) &&
    197         (Reg->BitWidth != 16) &&
    198         (Reg->BitWidth != 32) &&
    199         (Reg->BitWidth != MaxBitWidth))
    200     {
    201         ACPI_ERROR ((AE_INFO,
    202             "Unsupported register bit width: 0x%X", Reg->BitWidth));
    203         return (AE_SUPPORT);
    204     }
    205 
    206     /* Validate the BitOffset. Just a warning for now. */
    207 
    208     if (Reg->BitOffset != 0)
    209     {
    210         ACPI_WARNING ((AE_INFO,
    211             "Unsupported register bit offset: 0x%X", Reg->BitOffset));
    212     }
    213 
    214     return (AE_OK);
    215 }
    216 
    217 
    218 /******************************************************************************
    219  *
    220  * FUNCTION:    AcpiHwRead
    221  *
    222  * PARAMETERS:  Value               - Where the value is returned
    223  *              Reg                 - GAS register structure
    224  *
    225  * RETURN:      Status
    226  *
    227  * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
    228  *              version of AcpiRead, used internally since the overhead of
    229  *              64-bit values is not needed.
    230  *
    231  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
    232  *      BitWidth must be exactly 8, 16, or 32.
    233  *      SpaceID must be SystemMemory or SystemIO.
    234  *      BitOffset and AccessWidth are currently ignored, as there has
    235  *          not been a need to implement these.
    236  *
    237  ******************************************************************************/
    238 
    239 ACPI_STATUS
    240 AcpiHwRead (
    241     UINT32                  *Value,
    242     ACPI_GENERIC_ADDRESS    *Reg)
    243 {
    244     UINT64                  Address;
    245     ACPI_STATUS             Status;
    246 
    247 
    248     ACPI_FUNCTION_NAME (HwRead);
    249 
    250 
    251     /* Validate contents of the GAS register */
    252 
    253     Status = AcpiHwValidateRegister (Reg, 32, &Address);
    254     if (ACPI_FAILURE (Status))
    255     {
    256         return (Status);
    257     }
    258 
    259     /* Initialize entire 32-bit return value to zero */
    260 
    261     *Value = 0;
    262 
    263     /*
    264      * Two address spaces supported: Memory or IO. PCI_Config is
    265      * not supported here because the GAS structure is insufficient
    266      */
    267     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
    268     {
    269         Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
    270                     Address, Value, Reg->BitWidth);
    271     }
    272     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    273     {
    274         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
    275                     Address, Value, Reg->BitWidth);
    276     }
    277 
    278     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
    279         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
    280         *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
    281         AcpiUtGetRegionName (Reg->SpaceId)));
    282 
    283     return (Status);
    284 }
    285 
    286 
    287 /******************************************************************************
    288  *
    289  * FUNCTION:    AcpiHwWrite
    290  *
    291  * PARAMETERS:  Value               - Value to be written
    292  *              Reg                 - GAS register structure
    293  *
    294  * RETURN:      Status
    295  *
    296  * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
    297  *              version of AcpiWrite, used internally since the overhead of
    298  *              64-bit values is not needed.
    299  *
    300  ******************************************************************************/
    301 
    302 ACPI_STATUS
    303 AcpiHwWrite (
    304     UINT32                  Value,
    305     ACPI_GENERIC_ADDRESS    *Reg)
    306 {
    307     UINT64                  Address;
    308     ACPI_STATUS             Status;
    309 
    310 
    311     ACPI_FUNCTION_NAME (HwWrite);
    312 
    313 
    314     /* Validate contents of the GAS register */
    315 
    316     Status = AcpiHwValidateRegister (Reg, 32, &Address);
    317     if (ACPI_FAILURE (Status))
    318     {
    319         return (Status);
    320     }
    321 
    322     /*
    323      * Two address spaces supported: Memory or IO. PCI_Config is
    324      * not supported here because the GAS structure is insufficient
    325      */
    326     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
    327     {
    328         Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
    329                     Address, Value, Reg->BitWidth);
    330     }
    331     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
    332     {
    333         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
    334                     Address, Value, Reg->BitWidth);
    335     }
    336 
    337     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
    338         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
    339         Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
    340         AcpiUtGetRegionName (Reg->SpaceId)));
    341 
    342     return (Status);
    343 }
    344 
    345 
    346 /*******************************************************************************
    347  *
    348  * FUNCTION:    AcpiHwClearAcpiStatus
    349  *
    350  * PARAMETERS:  None
    351  *
    352  * RETURN:      Status
    353  *
    354  * DESCRIPTION: Clears all fixed and general purpose status bits
    355  *
    356  ******************************************************************************/
    357 
    358 ACPI_STATUS
    359 AcpiHwClearAcpiStatus (
    360     void)
    361 {
    362     ACPI_STATUS             Status;
    363     ACPI_CPU_FLAGS          LockFlags = 0;
    364 
    365 
    366     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
    367 
    368 
    369     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
    370         ACPI_BITMASK_ALL_FIXED_STATUS,
    371         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
    372 
    373     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
    374 
    375     /* Clear the fixed events in PM1 A/B */
    376 
    377     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
    378                 ACPI_BITMASK_ALL_FIXED_STATUS);
    379     if (ACPI_FAILURE (Status))
    380     {
    381         goto UnlockAndExit;
    382     }
    383 
    384     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
    385 
    386     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
    387 
    388 UnlockAndExit:
    389     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
    390     return_ACPI_STATUS (Status);
    391 }
    392 
    393 
    394 /*******************************************************************************
    395  *
    396  * FUNCTION:    AcpiHwGetRegisterBitMask
    397  *
    398  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
    399  *
    400  * RETURN:      The bitmask to be used when accessing the register
    401  *
    402  * DESCRIPTION: Map RegisterId into a register bitmask.
    403  *
    404  ******************************************************************************/
    405 
    406 ACPI_BIT_REGISTER_INFO *
    407 AcpiHwGetBitRegisterInfo (
    408     UINT32                  RegisterId)
    409 {
    410     ACPI_FUNCTION_ENTRY ();
    411 
    412 
    413     if (RegisterId > ACPI_BITREG_MAX)
    414     {
    415         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId));
    416         return (NULL);
    417     }
    418 
    419     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
    420 }
    421 
    422 
    423 /******************************************************************************
    424  *
    425  * FUNCTION:    AcpiHwWritePm1Control
    426  *
    427  * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
    428  *              Pm1bControl         - Value to be written to PM1B control
    429  *
    430  * RETURN:      Status
    431  *
    432  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
    433  *              different than than the PM1 A/B status and enable registers
    434  *              in that different values can be written to the A/B registers.
    435  *              Most notably, the SLP_TYP bits can be different, as per the
    436  *              values returned from the _Sx predefined methods.
    437  *
    438  ******************************************************************************/
    439 
    440 ACPI_STATUS
    441 AcpiHwWritePm1Control (
    442     UINT32                  Pm1aControl,
    443     UINT32                  Pm1bControl)
    444 {
    445     ACPI_STATUS             Status;
    446 
    447 
    448     ACPI_FUNCTION_TRACE (HwWritePm1Control);
    449 
    450 
    451     Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
    452     if (ACPI_FAILURE (Status))
    453     {
    454         return_ACPI_STATUS (Status);
    455     }
    456 
    457     if (AcpiGbl_FADT.XPm1bControlBlock.Address)
    458     {
    459         Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
    460     }
    461     return_ACPI_STATUS (Status);
    462 }
    463 
    464 
    465 /******************************************************************************
    466  *
    467  * FUNCTION:    AcpiHwRegisterRead
    468  *
    469  * PARAMETERS:  RegisterId          - ACPI Register ID
    470  *              ReturnValue         - Where the register value is returned
    471  *
    472  * RETURN:      Status and the value read.
    473  *
    474  * DESCRIPTION: Read from the specified ACPI register
    475  *
    476  ******************************************************************************/
    477 
    478 ACPI_STATUS
    479 AcpiHwRegisterRead (
    480     UINT32                  RegisterId,
    481     UINT32                  *ReturnValue)
    482 {
    483     UINT32                  Value = 0;
    484     ACPI_STATUS             Status;
    485 
    486 
    487     ACPI_FUNCTION_TRACE (HwRegisterRead);
    488 
    489 
    490     switch (RegisterId)
    491     {
    492     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
    493 
    494         Status = AcpiHwReadMultiple (&Value,
    495                     &AcpiGbl_XPm1aStatus,
    496                     &AcpiGbl_XPm1bStatus);
    497         break;
    498 
    499 
    500     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
    501 
    502         Status = AcpiHwReadMultiple (&Value,
    503                     &AcpiGbl_XPm1aEnable,
    504                     &AcpiGbl_XPm1bEnable);
    505         break;
    506 
    507 
    508     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
    509 
    510         Status = AcpiHwReadMultiple (&Value,
    511                     &AcpiGbl_FADT.XPm1aControlBlock,
    512                     &AcpiGbl_FADT.XPm1bControlBlock);
    513 
    514         /*
    515          * Zero the write-only bits. From the ACPI specification, "Hardware
    516          * Write-Only Bits": "Upon reads to registers with write-only bits,
    517          * software masks out all write-only bits."
    518          */
    519         Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
    520         break;
    521 
    522 
    523     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
    524 
    525         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
    526         break;
    527 
    528 
    529     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
    530 
    531         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
    532         break;
    533 
    534 
    535     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
    536 
    537         Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
    538         break;
    539 
    540 
    541     default:
    542         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
    543             RegisterId));
    544         Status = AE_BAD_PARAMETER;
    545         break;
    546     }
    547 
    548     if (ACPI_SUCCESS (Status))
    549     {
    550         *ReturnValue = Value;
    551     }
    552 
    553     return_ACPI_STATUS (Status);
    554 }
    555 
    556 
    557 /******************************************************************************
    558  *
    559  * FUNCTION:    AcpiHwRegisterWrite
    560  *
    561  * PARAMETERS:  RegisterId          - ACPI Register ID
    562  *              Value               - The value to write
    563  *
    564  * RETURN:      Status
    565  *
    566  * DESCRIPTION: Write to the specified ACPI register
    567  *
    568  * NOTE: In accordance with the ACPI specification, this function automatically
    569  * preserves the value of the following bits, meaning that these bits cannot be
    570  * changed via this interface:
    571  *
    572  * PM1_CONTROL[0] = SCI_EN
    573  * PM1_CONTROL[9]
    574  * PM1_STATUS[11]
    575  *
    576  * ACPI References:
    577  * 1) Hardware Ignored Bits: When software writes to a register with ignored
    578  *      bit fields, it preserves the ignored bit fields
    579  * 2) SCI_EN: OSPM always preserves this bit position
    580  *
    581  ******************************************************************************/
    582 
    583 ACPI_STATUS
    584 AcpiHwRegisterWrite (
    585     UINT32                  RegisterId,
    586     UINT32                  Value)
    587 {
    588     ACPI_STATUS             Status;
    589     UINT32                  ReadValue;
    590 
    591 
    592     ACPI_FUNCTION_TRACE (HwRegisterWrite);
    593 
    594 
    595     switch (RegisterId)
    596     {
    597     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
    598         /*
    599          * Handle the "ignored" bit in PM1 Status. According to the ACPI
    600          * specification, ignored bits are to be preserved when writing.
    601          * Normally, this would mean a read/modify/write sequence. However,
    602          * preserving a bit in the status register is different. Writing a
    603          * one clears the status, and writing a zero preserves the status.
    604          * Therefore, we must always write zero to the ignored bit.
    605          *
    606          * This behavior is clarified in the ACPI 4.0 specification.
    607          */
    608         Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
    609 
    610         Status = AcpiHwWriteMultiple (Value,
    611                     &AcpiGbl_XPm1aStatus,
    612                     &AcpiGbl_XPm1bStatus);
    613         break;
    614 
    615 
    616     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
    617 
    618         Status = AcpiHwWriteMultiple (Value,
    619                     &AcpiGbl_XPm1aEnable,
    620                     &AcpiGbl_XPm1bEnable);
    621         break;
    622 
    623 
    624     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
    625 
    626         /*
    627          * Perform a read first to preserve certain bits (per ACPI spec)
    628          * Note: This includes SCI_EN, we never want to change this bit
    629          */
    630         Status = AcpiHwReadMultiple (&ReadValue,
    631                     &AcpiGbl_FADT.XPm1aControlBlock,
    632                     &AcpiGbl_FADT.XPm1bControlBlock);
    633         if (ACPI_FAILURE (Status))
    634         {
    635             goto Exit;
    636         }
    637 
    638         /* Insert the bits to be preserved */
    639 
    640         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
    641 
    642         /* Now we can write the data */
    643 
    644         Status = AcpiHwWriteMultiple (Value,
    645                     &AcpiGbl_FADT.XPm1aControlBlock,
    646                     &AcpiGbl_FADT.XPm1bControlBlock);
    647         break;
    648 
    649 
    650     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
    651 
    652         /*
    653          * For control registers, all reserved bits must be preserved,
    654          * as per the ACPI spec.
    655          */
    656         Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
    657         if (ACPI_FAILURE (Status))
    658         {
    659             goto Exit;
    660         }
    661 
    662         /* Insert the bits to be preserved */
    663 
    664         ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
    665 
    666         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
    667         break;
    668 
    669 
    670     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
    671 
    672         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
    673         break;
    674 
    675 
    676     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
    677 
    678         /* SMI_CMD is currently always in IO space */
    679 
    680         Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
    681         break;
    682 
    683 
    684     default:
    685         ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X",
    686             RegisterId));
    687         Status = AE_BAD_PARAMETER;
    688         break;
    689     }
    690 
    691 Exit:
    692     return_ACPI_STATUS (Status);
    693 }
    694 
    695 
    696 /******************************************************************************
    697  *
    698  * FUNCTION:    AcpiHwReadMultiple
    699  *
    700  * PARAMETERS:  Value               - Where the register value is returned
    701  *              RegisterA           - First ACPI register (required)
    702  *              RegisterB           - Second ACPI register (optional)
    703  *
    704  * RETURN:      Status
    705  *
    706  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
    707  *
    708  ******************************************************************************/
    709 
    710 static ACPI_STATUS
    711 AcpiHwReadMultiple (
    712     UINT32                  *Value,
    713     ACPI_GENERIC_ADDRESS    *RegisterA,
    714     ACPI_GENERIC_ADDRESS    *RegisterB)
    715 {
    716     UINT32                  ValueA = 0;
    717     UINT32                  ValueB = 0;
    718     ACPI_STATUS             Status;
    719 
    720 
    721     /* The first register is always required */
    722 
    723     Status = AcpiHwRead (&ValueA, RegisterA);
    724     if (ACPI_FAILURE (Status))
    725     {
    726         return (Status);
    727     }
    728 
    729     /* Second register is optional */
    730 
    731     if (RegisterB->Address)
    732     {
    733         Status = AcpiHwRead (&ValueB, RegisterB);
    734         if (ACPI_FAILURE (Status))
    735         {
    736             return (Status);
    737         }
    738     }
    739 
    740     /*
    741      * OR the two return values together. No shifting or masking is necessary,
    742      * because of how the PM1 registers are defined in the ACPI specification:
    743      *
    744      * "Although the bits can be split between the two register blocks (each
    745      * register block has a unique pointer within the FADT), the bit positions
    746      * are maintained. The register block with unimplemented bits (that is,
    747      * those implemented in the other register block) always returns zeros,
    748      * and writes have no side effects"
    749      */
    750     *Value = (ValueA | ValueB);
    751     return (AE_OK);
    752 }
    753 
    754 
    755 /******************************************************************************
    756  *
    757  * FUNCTION:    AcpiHwWriteMultiple
    758  *
    759  * PARAMETERS:  Value               - The value to write
    760  *              RegisterA           - First ACPI register (required)
    761  *              RegisterB           - Second ACPI register (optional)
    762  *
    763  * RETURN:      Status
    764  *
    765  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
    766  *
    767  ******************************************************************************/
    768 
    769 static ACPI_STATUS
    770 AcpiHwWriteMultiple (
    771     UINT32                  Value,
    772     ACPI_GENERIC_ADDRESS    *RegisterA,
    773     ACPI_GENERIC_ADDRESS    *RegisterB)
    774 {
    775     ACPI_STATUS             Status;
    776 
    777 
    778     /* The first register is always required */
    779 
    780     Status = AcpiHwWrite (Value, RegisterA);
    781     if (ACPI_FAILURE (Status))
    782     {
    783         return (Status);
    784     }
    785 
    786     /*
    787      * Second register is optional
    788      *
    789      * No bit shifting or clearing is necessary, because of how the PM1
    790      * registers are defined in the ACPI specification:
    791      *
    792      * "Although the bits can be split between the two register blocks (each
    793      * register block has a unique pointer within the FADT), the bit positions
    794      * are maintained. The register block with unimplemented bits (that is,
    795      * those implemented in the other register block) always returns zeros,
    796      * and writes have no side effects"
    797      */
    798     if (RegisterB->Address)
    799     {
    800         Status = AcpiHwWrite (Value, RegisterB);
    801     }
    802 
    803     return (Status);
    804 }
    805 
    806