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