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