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