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