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