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