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