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