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