xref: /titanic_52/usr/src/uts/intel/io/acpica/hardware/hwregs.c (revision eaacacc0c33d7b79a8156d9b3e07dbb4354eb2d6)
1 
2 /*******************************************************************************
3  *
4  * Module Name: hwregs - Read/write access functions for the various ACPI
5  *                       control and status registers.
6  *              $Revision: 1.183 $
7  *
8  ******************************************************************************/
9 
10 /******************************************************************************
11  *
12  * 1. Copyright Notice
13  *
14  * Some or all of this work - Copyright (c) 1999 - 2006, Intel Corp.
15  * All rights reserved.
16  *
17  * 2. License
18  *
19  * 2.1. This is your license from Intel Corp. under its intellectual property
20  * rights.  You may have additional license terms from the party that provided
21  * you this software, covering your right to use that party's intellectual
22  * property rights.
23  *
24  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
25  * copy of the source code appearing in this file ("Covered Code") an
26  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
27  * base code distributed originally by Intel ("Original Intel Code") to copy,
28  * make derivatives, distribute, use and display any portion of the Covered
29  * Code in any form, with the right to sublicense such rights; and
30  *
31  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
32  * license (with the right to sublicense), under only those claims of Intel
33  * patents that are infringed by the Original Intel Code, to make, use, sell,
34  * offer to sell, and import the Covered Code and derivative works thereof
35  * solely to the minimum extent necessary to exercise the above copyright
36  * license, and in no event shall the patent license extend to any additions
37  * to or modifications of the Original Intel Code.  No other license or right
38  * is granted directly or by implication, estoppel or otherwise;
39  *
40  * The above copyright and patent license is granted only if the following
41  * conditions are met:
42  *
43  * 3. Conditions
44  *
45  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
46  * Redistribution of source code of any substantial portion of the Covered
47  * Code or modification with rights to further distribute source must include
48  * the above Copyright Notice, the above License, this list of Conditions,
49  * and the following Disclaimer and Export Compliance provision.  In addition,
50  * Licensee must cause all Covered Code to which Licensee contributes to
51  * contain a file documenting the changes Licensee made to create that Covered
52  * Code and the date of any change.  Licensee must include in that file the
53  * documentation of any changes made by any predecessor Licensee.  Licensee
54  * must include a prominent statement that the modification is derived,
55  * directly or indirectly, from Original Intel Code.
56  *
57  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
58  * Redistribution of source code of any substantial portion of the Covered
59  * Code or modification without rights to further distribute source must
60  * include the following Disclaimer and Export Compliance provision in the
61  * documentation and/or other materials provided with distribution.  In
62  * addition, Licensee may not authorize further sublicense of source of any
63  * portion of the Covered Code, and must include terms to the effect that the
64  * license from Licensee to its licensee is limited to the intellectual
65  * property embodied in the software Licensee provides to its licensee, and
66  * not to intellectual property embodied in modifications its licensee may
67  * make.
68  *
69  * 3.3. Redistribution of Executable. Redistribution in executable form of any
70  * substantial portion of the Covered Code or modification must reproduce the
71  * above Copyright Notice, and the following Disclaimer and Export Compliance
72  * provision in the documentation and/or other materials provided with the
73  * distribution.
74  *
75  * 3.4. Intel retains all right, title, and interest in and to the Original
76  * Intel Code.
77  *
78  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
79  * Intel shall be used in advertising or otherwise to promote the sale, use or
80  * other dealings in products derived from or relating to the Covered Code
81  * without prior written authorization from Intel.
82  *
83  * 4. Disclaimer and Export Compliance
84  *
85  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
86  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
87  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
88  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
89  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
90  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
91  * PARTICULAR PURPOSE.
92  *
93  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
94  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
95  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
96  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
97  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
98  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
99  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
100  * LIMITED REMEDY.
101  *
102  * 4.3. Licensee shall not export, either directly or indirectly, any of this
103  * software or system incorporating such software without first obtaining any
104  * required license or other approval from the U. S. Department of Commerce or
105  * any other agency or department of the United States Government.  In the
106  * event Licensee exports any such software from the United States or
107  * re-exports any such software from a foreign destination, Licensee shall
108  * ensure that the distribution and export/re-export of the software is in
109  * compliance with all laws, regulations, orders, or other restrictions of the
110  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
111  * any of its subsidiaries will export/re-export any technical data, process,
112  * software, or service, directly or indirectly, to any country for which the
113  * United States government or any agency thereof requires an export license,
114  * other governmental approval, or letter of assurance, without first obtaining
115  * such license, approval or letter.
116  *
117  *****************************************************************************/
118 
119 #define __HWREGS_C__
120 
121 #include "acpi.h"
122 #include "acnamesp.h"
123 #include "acevents.h"
124 
125 #define _COMPONENT          ACPI_HARDWARE
126         ACPI_MODULE_NAME    ("hwregs")
127 
128 
129 /*******************************************************************************
130  *
131  * FUNCTION:    AcpiHwClearAcpiStatus
132  *
133  * PARAMETERS:  Flags           - Lock the hardware or not
134  *
135  * RETURN:      none
136  *
137  * DESCRIPTION: Clears all fixed and general purpose status bits
138  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
139  *
140  * NOTE: TBD: Flags parameter is obsolete, to be removed
141  *
142  ******************************************************************************/
143 
144 ACPI_STATUS
145 AcpiHwClearAcpiStatus (
146     UINT32                  Flags)
147 {
148     ACPI_STATUS             Status;
149     ACPI_CPU_FLAGS          LockFlags = 0;
150 
151 
152     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
153 
154 
155     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %04X\n",
156         ACPI_BITMASK_ALL_FIXED_STATUS,
157         (UINT16) ACPI_GET_ADDRESS (AcpiGbl_FADT->XPm1aEvtBlk.Address)));
158 
159     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
160 
161     Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
162                 ACPI_REGISTER_PM1_STATUS,
163                 ACPI_BITMASK_ALL_FIXED_STATUS);
164     if (ACPI_FAILURE (Status))
165     {
166         goto UnlockAndExit;
167     }
168 
169     /* Clear the fixed events */
170 
171     if (ACPI_VALID_ADDRESS (AcpiGbl_FADT->XPm1bEvtBlk.Address))
172     {
173         Status = AcpiHwLowLevelWrite (16, ACPI_BITMASK_ALL_FIXED_STATUS,
174                     &AcpiGbl_FADT->XPm1bEvtBlk);
175         if (ACPI_FAILURE (Status))
176         {
177             goto UnlockAndExit;
178         }
179     }
180 
181     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
182 
183     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock);
184 
185 UnlockAndExit:
186     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
187     return_ACPI_STATUS (Status);
188 }
189 
190 
191 /*******************************************************************************
192  *
193  * FUNCTION:    AcpiGetSleepTypeData
194  *
195  * PARAMETERS:  SleepState          - Numeric sleep state
196  *              *SleepTypeA         - Where SLP_TYPa is returned
197  *              *SleepTypeB         - Where SLP_TYPb is returned
198  *
199  * RETURN:      Status - ACPI status
200  *
201  * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
202  *              state.
203  *
204  ******************************************************************************/
205 
206 ACPI_STATUS
207 AcpiGetSleepTypeData (
208     UINT8                   SleepState,
209     UINT8                   *SleepTypeA,
210     UINT8                   *SleepTypeB)
211 {
212     ACPI_STATUS             Status = AE_OK;
213     ACPI_EVALUATE_INFO      *Info;
214 
215 
216     ACPI_FUNCTION_TRACE (AcpiGetSleepTypeData);
217 
218 
219     /* Validate parameters */
220 
221     if ((SleepState > ACPI_S_STATES_MAX) ||
222         !SleepTypeA || !SleepTypeB)
223     {
224         return_ACPI_STATUS (AE_BAD_PARAMETER);
225     }
226 
227     /* Allocate the evaluation information block */
228 
229     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
230     if (!Info)
231     {
232         return_ACPI_STATUS (AE_NO_MEMORY);
233     }
234 
235     Info->Pathname = ACPI_CAST_PTR (char, AcpiGbl_SleepStateNames[SleepState]);
236 
237     /* Evaluate the namespace object containing the values for this state */
238 
239     Status = AcpiNsEvaluate (Info);
240     if (ACPI_FAILURE (Status))
241     {
242         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
243             "%s while evaluating SleepState [%s]\n",
244             AcpiFormatException (Status), Info->Pathname));
245 
246         goto Cleanup;
247     }
248 
249     /* Must have a return object */
250 
251     if (!Info->ReturnObject)
252     {
253         ACPI_ERROR ((AE_INFO, "No Sleep State object returned from [%s]",
254             Info->Pathname));
255         Status = AE_NOT_EXIST;
256     }
257 
258     /* It must be of type Package */
259 
260     else if (ACPI_GET_OBJECT_TYPE (Info->ReturnObject) != ACPI_TYPE_PACKAGE)
261     {
262         ACPI_ERROR ((AE_INFO, "Sleep State return object is not a Package"));
263         Status = AE_AML_OPERAND_TYPE;
264     }
265 
266     /*
267      * The package must have at least two elements. NOTE (March 2005): This
268      * goes against the current ACPI spec which defines this object as a
269      * package with one encoded DWORD element. However, existing practice
270      * by BIOS vendors seems to be to have 2 or more elements, at least
271      * one per sleep type (A/B).
272      */
273     else if (Info->ReturnObject->Package.Count < 2)
274     {
275         ACPI_ERROR ((AE_INFO,
276             "Sleep State return package does not have at least two elements"));
277         Status = AE_AML_NO_OPERAND;
278     }
279 
280     /* The first two elements must both be of type Integer */
281 
282     else if ((ACPI_GET_OBJECT_TYPE (Info->ReturnObject->Package.Elements[0])
283                 != ACPI_TYPE_INTEGER) ||
284              (ACPI_GET_OBJECT_TYPE (Info->ReturnObject->Package.Elements[1])
285                 != ACPI_TYPE_INTEGER))
286     {
287         ACPI_ERROR ((AE_INFO,
288             "Sleep State return package elements are not both Integers (%s, %s)",
289             AcpiUtGetObjectTypeName (Info->ReturnObject->Package.Elements[0]),
290             AcpiUtGetObjectTypeName (Info->ReturnObject->Package.Elements[1])));
291         Status = AE_AML_OPERAND_TYPE;
292     }
293     else
294     {
295         /* Valid _Sx_ package size, type, and value */
296 
297         *SleepTypeA = (UINT8)
298             (Info->ReturnObject->Package.Elements[0])->Integer.Value;
299         *SleepTypeB = (UINT8)
300             (Info->ReturnObject->Package.Elements[1])->Integer.Value;
301     }
302 
303     if (ACPI_FAILURE (Status))
304     {
305         ACPI_EXCEPTION ((AE_INFO, Status,
306             "While evaluating SleepState [%s], bad Sleep object %p type %s",
307             Info->Pathname, Info->ReturnObject,
308             AcpiUtGetObjectTypeName (Info->ReturnObject)));
309     }
310 
311     AcpiUtRemoveReference (Info->ReturnObject);
312 
313 Cleanup:
314     ACPI_FREE (Info);
315     return_ACPI_STATUS (Status);
316 }
317 
318 ACPI_EXPORT_SYMBOL (AcpiGetSleepTypeData)
319 
320 
321 /*******************************************************************************
322  *
323  * FUNCTION:    AcpiHwGetRegisterBitMask
324  *
325  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
326  *
327  * RETURN:      The bitmask to be used when accessing the register
328  *
329  * DESCRIPTION: Map RegisterId into a register bitmask.
330  *
331  ******************************************************************************/
332 
333 ACPI_BIT_REGISTER_INFO *
334 AcpiHwGetBitRegisterInfo (
335     UINT32                  RegisterId)
336 {
337     ACPI_FUNCTION_ENTRY ();
338 
339 
340     if (RegisterId > ACPI_BITREG_MAX)
341     {
342         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: %X", RegisterId));
343         return (NULL);
344     }
345 
346     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
347 }
348 
349 
350 /*******************************************************************************
351  *
352  * FUNCTION:    AcpiGetRegister
353  *
354  * PARAMETERS:  RegisterId      - ID of ACPI BitRegister to access
355  *              ReturnValue     - Value that was read from the register
356  *              Flags           - Lock the hardware or not
357  *
358  * RETURN:      Status and the value read from specified Register. Value
359  *              returned is normalized to bit0 (is shifted all the way right)
360  *
361  * DESCRIPTION: ACPI BitRegister read function.
362  *
363  * NOTE: TBD: Flags parameter is obsolete, to be removed
364  *
365  ******************************************************************************/
366 
367 ACPI_STATUS
368 AcpiGetRegister (
369     UINT32                  RegisterId,
370     UINT32                  *ReturnValue,
371     UINT32                  Flags)
372 {
373     UINT32                  RegisterValue = 0;
374     ACPI_BIT_REGISTER_INFO  *BitRegInfo;
375     ACPI_STATUS             Status;
376 
377 
378     ACPI_FUNCTION_TRACE (AcpiGetRegister);
379 
380 
381     /* Get the info structure corresponding to the requested ACPI Register */
382 
383     BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId);
384     if (!BitRegInfo)
385     {
386         return_ACPI_STATUS (AE_BAD_PARAMETER);
387     }
388 
389     /* Read from the register */
390 
391     Status = AcpiHwRegisterRead (ACPI_MTX_LOCK,
392                 BitRegInfo->ParentRegister, &RegisterValue);
393 
394     if (ACPI_SUCCESS (Status))
395     {
396         /* Normalize the value that was read */
397 
398         RegisterValue = ((RegisterValue & BitRegInfo->AccessBitMask)
399                             >> BitRegInfo->BitPosition);
400 
401         *ReturnValue = RegisterValue;
402 
403         ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %8.8X register %X\n",
404             RegisterValue, BitRegInfo->ParentRegister));
405     }
406 
407     return_ACPI_STATUS (Status);
408 }
409 
410 ACPI_EXPORT_SYMBOL (AcpiGetRegister)
411 
412 
413 /*******************************************************************************
414  *
415  * FUNCTION:    AcpiSetRegister
416  *
417  * PARAMETERS:  RegisterId      - ID of ACPI BitRegister to access
418  *              Value           - (only used on write) value to write to the
419  *                                Register, NOT pre-normalized to the bit pos
420  *              Flags           - Lock the hardware or not
421  *
422  * RETURN:      Status
423  *
424  * DESCRIPTION: ACPI Bit Register write function.
425  *
426  * NOTE: TBD: Flags parameter is obsolete, to be removed
427  *
428  ******************************************************************************/
429 
430 ACPI_STATUS
431 AcpiSetRegister (
432     UINT32                  RegisterId,
433     UINT32                  Value,
434     UINT32                  Flags)
435 {
436     UINT32                  RegisterValue = 0;
437     ACPI_BIT_REGISTER_INFO  *BitRegInfo;
438     ACPI_STATUS             Status;
439     ACPI_CPU_FLAGS          LockFlags;
440 
441 
442     ACPI_FUNCTION_TRACE_U32 (AcpiSetRegister, RegisterId);
443 
444 
445     /* Get the info structure corresponding to the requested ACPI Register */
446 
447     BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId);
448     if (!BitRegInfo)
449     {
450         ACPI_ERROR ((AE_INFO, "Bad ACPI HW RegisterId: %X", RegisterId));
451         return_ACPI_STATUS (AE_BAD_PARAMETER);
452     }
453 
454     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
455 
456     /* Always do a register read first so we can insert the new bits  */
457 
458     Status = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK,
459                 BitRegInfo->ParentRegister, &RegisterValue);
460     if (ACPI_FAILURE (Status))
461     {
462         goto UnlockAndExit;
463     }
464 
465     /*
466      * Decode the Register ID
467      * Register ID = [Register block ID] | [bit ID]
468      *
469      * Check bit ID to fine locate Register offset.
470      * Check Mask to determine Register offset, and then read-write.
471      */
472     switch (BitRegInfo->ParentRegister)
473     {
474     case ACPI_REGISTER_PM1_STATUS:
475 
476         /*
477          * Status Registers are different from the rest. Clear by
478          * writing 1, and writing 0 has no effect. So, the only relevant
479          * information is the single bit we're interested in, all others should
480          * be written as 0 so they will be left unchanged.
481          */
482         Value = ACPI_REGISTER_PREPARE_BITS (Value,
483                     BitRegInfo->BitPosition, BitRegInfo->AccessBitMask);
484         if (Value)
485         {
486             Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
487                         ACPI_REGISTER_PM1_STATUS, (UINT16) Value);
488             RegisterValue = 0;
489         }
490         break;
491 
492 
493     case ACPI_REGISTER_PM1_ENABLE:
494 
495         ACPI_REGISTER_INSERT_VALUE (RegisterValue, BitRegInfo->BitPosition,
496             BitRegInfo->AccessBitMask, Value);
497 
498         Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
499                     ACPI_REGISTER_PM1_ENABLE, (UINT16) RegisterValue);
500         break;
501 
502 
503     case ACPI_REGISTER_PM1_CONTROL:
504 
505         /*
506          * Write the PM1 Control register.
507          * Note that at this level, the fact that there are actually TWO
508          * registers (A and B - and B may not exist) is abstracted.
509          */
510         ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM1 control: Read %X\n",
511             RegisterValue));
512 
513         ACPI_REGISTER_INSERT_VALUE (RegisterValue, BitRegInfo->BitPosition,
514             BitRegInfo->AccessBitMask, Value);
515 
516         Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
517                     ACPI_REGISTER_PM1_CONTROL, (UINT16) RegisterValue);
518         break;
519 
520 
521     case ACPI_REGISTER_PM2_CONTROL:
522 
523         Status = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK,
524                     ACPI_REGISTER_PM2_CONTROL, &RegisterValue);
525         if (ACPI_FAILURE (Status))
526         {
527             goto UnlockAndExit;
528         }
529 
530         ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n",
531             RegisterValue,
532             ACPI_FORMAT_UINT64 (ACPI_GET_ADDRESS (
533                 AcpiGbl_FADT->XPm2CntBlk.Address))));
534 
535         ACPI_REGISTER_INSERT_VALUE (RegisterValue, BitRegInfo->BitPosition,
536                 BitRegInfo->AccessBitMask, Value);
537 
538         ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n",
539             RegisterValue,
540             ACPI_FORMAT_UINT64 (ACPI_GET_ADDRESS (
541                 AcpiGbl_FADT->XPm2CntBlk.Address))));
542 
543         Status = AcpiHwRegisterWrite (ACPI_MTX_DO_NOT_LOCK,
544                     ACPI_REGISTER_PM2_CONTROL, (UINT8) (RegisterValue));
545         break;
546 
547 
548     default:
549         break;
550     }
551 
552 
553 UnlockAndExit:
554 
555     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
556 
557     /* Normalize the value that was read */
558 
559     ACPI_DEBUG_EXEC (RegisterValue =
560         ((RegisterValue & BitRegInfo->AccessBitMask) >>
561             BitRegInfo->BitPosition));
562 
563     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n",
564         Value, RegisterValue, BitRegInfo->ParentRegister));
565     return_ACPI_STATUS (Status);
566 }
567 
568 ACPI_EXPORT_SYMBOL (AcpiSetRegister)
569 
570 
571 /******************************************************************************
572  *
573  * FUNCTION:    AcpiHwRegisterRead
574  *
575  * PARAMETERS:  UseLock             - Lock hardware? True/False
576  *              RegisterId          - ACPI Register ID
577  *              ReturnValue         - Where the register value is returned
578  *
579  * RETURN:      Status and the value read.
580  *
581  * DESCRIPTION: Read from the specified ACPI register
582  *
583  ******************************************************************************/
584 
585 ACPI_STATUS
586 AcpiHwRegisterRead (
587     BOOLEAN                 UseLock,
588     UINT32                  RegisterId,
589     UINT32                  *ReturnValue)
590 {
591     UINT32                  Value1 = 0;
592     UINT32                  Value2 = 0;
593     ACPI_STATUS             Status;
594     ACPI_CPU_FLAGS          LockFlags = 0;
595 
596 
597     ACPI_FUNCTION_TRACE (HwRegisterRead);
598 
599 
600     if (ACPI_MTX_LOCK == UseLock)
601     {
602         LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
603     }
604 
605     switch (RegisterId)
606     {
607     case ACPI_REGISTER_PM1_STATUS:           /* 16-bit access */
608 
609         Status = AcpiHwLowLevelRead (16, &Value1, &AcpiGbl_FADT->XPm1aEvtBlk);
610         if (ACPI_FAILURE (Status))
611         {
612             goto UnlockAndExit;
613         }
614 
615         /* PM1B is optional */
616 
617         Status = AcpiHwLowLevelRead (16, &Value2, &AcpiGbl_FADT->XPm1bEvtBlk);
618         Value1 |= Value2;
619         break;
620 
621 
622     case ACPI_REGISTER_PM1_ENABLE:           /* 16-bit access */
623 
624         Status = AcpiHwLowLevelRead (16, &Value1, &AcpiGbl_XPm1aEnable);
625         if (ACPI_FAILURE (Status))
626         {
627             goto UnlockAndExit;
628         }
629 
630         /* PM1B is optional */
631 
632         Status = AcpiHwLowLevelRead (16, &Value2, &AcpiGbl_XPm1bEnable);
633         Value1 |= Value2;
634         break;
635 
636 
637     case ACPI_REGISTER_PM1_CONTROL:          /* 16-bit access */
638 
639         Status = AcpiHwLowLevelRead (16, &Value1, &AcpiGbl_FADT->XPm1aCntBlk);
640         if (ACPI_FAILURE (Status))
641         {
642             goto UnlockAndExit;
643         }
644 
645         Status = AcpiHwLowLevelRead (16, &Value2, &AcpiGbl_FADT->XPm1bCntBlk);
646         Value1 |= Value2;
647         break;
648 
649 
650     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
651 
652         Status = AcpiHwLowLevelRead (8, &Value1, &AcpiGbl_FADT->XPm2CntBlk);
653         break;
654 
655 
656     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
657 
658         Status = AcpiHwLowLevelRead (32, &Value1, &AcpiGbl_FADT->XPmTmrBlk);
659         break;
660 
661     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
662 
663         Status = AcpiOsReadPort (AcpiGbl_FADT->SmiCmd, &Value1, 8);
664         break;
665 
666     default:
667         ACPI_ERROR ((AE_INFO, "Unknown Register ID: %X",
668             RegisterId));
669         Status = AE_BAD_PARAMETER;
670         break;
671     }
672 
673 UnlockAndExit:
674     if (ACPI_MTX_LOCK == UseLock)
675     {
676         AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
677     }
678 
679     if (ACPI_SUCCESS (Status))
680     {
681         *ReturnValue = Value1;
682     }
683 
684     return_ACPI_STATUS (Status);
685 }
686 
687 
688 /******************************************************************************
689  *
690  * FUNCTION:    AcpiHwRegisterWrite
691  *
692  * PARAMETERS:  UseLock             - Lock hardware? True/False
693  *              RegisterId          - ACPI Register ID
694  *              Value               - The value to write
695  *
696  * RETURN:      Status
697  *
698  * DESCRIPTION: Write to the specified ACPI register
699  *
700  * NOTE: In accordance with the ACPI specification, this function automatically
701  * preserves the value of the following bits, meaning that these bits cannot be
702  * changed via this interface:
703  *
704  * PM1_CONTROL[0] = SCI_EN
705  * PM1_CONTROL[9]
706  * PM1_STATUS[11]
707  *
708  * ACPI References:
709  * 1) Hardware Ignored Bits: When software writes to a register with ignored
710  *      bit fields, it preserves the ignored bit fields
711  * 2) SCI_EN: OSPM always preserves this bit position
712  *
713  ******************************************************************************/
714 
715 ACPI_STATUS
716 AcpiHwRegisterWrite (
717     BOOLEAN                 UseLock,
718     UINT32                  RegisterId,
719     UINT32                  Value)
720 {
721     ACPI_STATUS             Status;
722     ACPI_CPU_FLAGS          LockFlags = 0;
723     UINT32                  ReadValue;
724 
725 
726     ACPI_FUNCTION_TRACE (HwRegisterWrite);
727 
728 
729     if (ACPI_MTX_LOCK == UseLock)
730     {
731         LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
732     }
733 
734     switch (RegisterId)
735     {
736     case ACPI_REGISTER_PM1_STATUS:           /* 16-bit access */
737 
738         /* Perform a read first to preserve certain bits (per ACPI spec) */
739 
740         Status = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK,
741                     ACPI_REGISTER_PM1_STATUS, &ReadValue);
742         if (ACPI_FAILURE (Status))
743         {
744             goto UnlockAndExit;
745         }
746 
747         /* Insert the bits to be preserved */
748 
749         ACPI_INSERT_BITS (Value, ACPI_PM1_STATUS_PRESERVED_BITS, ReadValue);
750 
751         /* Now we can write the data */
752 
753         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_FADT->XPm1aEvtBlk);
754         if (ACPI_FAILURE (Status))
755         {
756             goto UnlockAndExit;
757         }
758 
759         /* PM1B is optional */
760 
761         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_FADT->XPm1bEvtBlk);
762         break;
763 
764 
765     case ACPI_REGISTER_PM1_ENABLE:           /* 16-bit access */
766 
767         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_XPm1aEnable);
768         if (ACPI_FAILURE (Status))
769         {
770             goto UnlockAndExit;
771         }
772 
773         /* PM1B is optional */
774 
775         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_XPm1bEnable);
776         break;
777 
778 
779     case ACPI_REGISTER_PM1_CONTROL:          /* 16-bit access */
780 
781         /*
782          * Perform a read first to preserve certain bits (per ACPI spec)
783          *
784          * Note: This includes SCI_EN, we never want to change this bit
785          */
786         Status = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK,
787                     ACPI_REGISTER_PM1_CONTROL, &ReadValue);
788         if (ACPI_FAILURE (Status))
789         {
790             goto UnlockAndExit;
791         }
792 
793         /* Insert the bits to be preserved */
794 
795         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
796 
797         /* Now we can write the data */
798 
799         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_FADT->XPm1aCntBlk);
800         if (ACPI_FAILURE (Status))
801         {
802             goto UnlockAndExit;
803         }
804 
805         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_FADT->XPm1bCntBlk);
806         break;
807 
808 
809     case ACPI_REGISTER_PM1A_CONTROL:         /* 16-bit access */
810 
811         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_FADT->XPm1aCntBlk);
812         break;
813 
814 
815     case ACPI_REGISTER_PM1B_CONTROL:         /* 16-bit access */
816 
817         Status = AcpiHwLowLevelWrite (16, Value, &AcpiGbl_FADT->XPm1bCntBlk);
818         break;
819 
820 
821     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
822 
823         Status = AcpiHwLowLevelWrite (8, Value, &AcpiGbl_FADT->XPm2CntBlk);
824         break;
825 
826 
827     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
828 
829         Status = AcpiHwLowLevelWrite (32, Value, &AcpiGbl_FADT->XPmTmrBlk);
830         break;
831 
832 
833     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
834 
835         /* SMI_CMD is currently always in IO space */
836 
837         Status = AcpiOsWritePort (AcpiGbl_FADT->SmiCmd, Value, 8);
838         break;
839 
840 
841     default:
842         Status = AE_BAD_PARAMETER;
843         break;
844     }
845 
846 UnlockAndExit:
847     if (ACPI_MTX_LOCK == UseLock)
848     {
849         AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
850     }
851 
852     return_ACPI_STATUS (Status);
853 }
854 
855 
856 /******************************************************************************
857  *
858  * FUNCTION:    AcpiHwLowLevelRead
859  *
860  * PARAMETERS:  Width               - 8, 16, or 32
861  *              Value               - Where the value is returned
862  *              Reg                 - GAS register structure
863  *
864  * RETURN:      Status
865  *
866  * DESCRIPTION: Read from either memory or IO space.
867  *
868  ******************************************************************************/
869 
870 ACPI_STATUS
871 AcpiHwLowLevelRead (
872     UINT32                  Width,
873     UINT32                  *Value,
874     ACPI_GENERIC_ADDRESS    *Reg)
875 {
876     UINT64                  Address;
877     ACPI_STATUS             Status;
878 
879 
880     ACPI_FUNCTION_NAME (HwLowLevelRead);
881 
882 
883     /*
884      * Must have a valid pointer to a GAS structure, and
885      * a non-zero address within. However, don't return an error
886      * because the PM1A/B code must not fail if B isn't present.
887      */
888     if (!Reg)
889     {
890         return (AE_OK);
891     }
892 
893     /* Get a local copy of the address. Handles possible alignment issues */
894 
895     ACPI_MOVE_64_TO_64 (&Address, &Reg->Address);
896     if (!ACPI_VALID_ADDRESS (Address))
897     {
898         return (AE_OK);
899     }
900     *Value = 0;
901 
902     /*
903      * Two address spaces supported: Memory or IO.
904      * PCI_Config is not supported here because the GAS struct is insufficient
905      */
906     switch (Reg->AddressSpaceId)
907     {
908     case ACPI_ADR_SPACE_SYSTEM_MEMORY:
909 
910         Status = AcpiOsReadMemory (
911                     (ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (Address),
912                     Value, Width);
913         break;
914 
915 
916     case ACPI_ADR_SPACE_SYSTEM_IO:
917 
918         Status = AcpiOsReadPort ((ACPI_IO_ADDRESS) ACPI_GET_ADDRESS (Address),
919                     Value, Width);
920         break;
921 
922 
923     default:
924         ACPI_ERROR ((AE_INFO,
925             "Unsupported address space: %X", Reg->AddressSpaceId));
926         return (AE_BAD_PARAMETER);
927     }
928 
929     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
930         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
931         *Value, Width,
932         ACPI_FORMAT_UINT64 (ACPI_GET_ADDRESS (Address)),
933         AcpiUtGetRegionName (Reg->AddressSpaceId)));
934 
935     return (Status);
936 }
937 
938 
939 /******************************************************************************
940  *
941  * FUNCTION:    AcpiHwLowLevelWrite
942  *
943  * PARAMETERS:  Width               - 8, 16, or 32
944  *              Value               - To be written
945  *              Reg                 - GAS register structure
946  *
947  * RETURN:      Status
948  *
949  * DESCRIPTION: Write to either memory or IO space.
950  *
951  ******************************************************************************/
952 
953 ACPI_STATUS
954 AcpiHwLowLevelWrite (
955     UINT32                  Width,
956     UINT32                  Value,
957     ACPI_GENERIC_ADDRESS    *Reg)
958 {
959     UINT64                  Address;
960     ACPI_STATUS             Status;
961 
962 
963     ACPI_FUNCTION_NAME (HwLowLevelWrite);
964 
965 
966     /*
967      * Must have a valid pointer to a GAS structure, and
968      * a non-zero address within. However, don't return an error
969      * because the PM1A/B code must not fail if B isn't present.
970      */
971     if (!Reg)
972     {
973         return (AE_OK);
974     }
975 
976     /* Get a local copy of the address. Handles possible alignment issues */
977 
978     ACPI_MOVE_64_TO_64 (&Address, &Reg->Address);
979     if (!ACPI_VALID_ADDRESS (Address))
980     {
981         return (AE_OK);
982     }
983 
984     /*
985      * Two address spaces supported: Memory or IO.
986      * PCI_Config is not supported here because the GAS struct is insufficient
987      */
988     switch (Reg->AddressSpaceId)
989     {
990     case ACPI_ADR_SPACE_SYSTEM_MEMORY:
991 
992         Status = AcpiOsWriteMemory (
993                     (ACPI_PHYSICAL_ADDRESS) ACPI_GET_ADDRESS (Address),
994                     Value, Width);
995         break;
996 
997 
998     case ACPI_ADR_SPACE_SYSTEM_IO:
999 
1000         Status = AcpiOsWritePort ((ACPI_IO_ADDRESS) ACPI_GET_ADDRESS (Address),
1001                     Value, Width);
1002         break;
1003 
1004 
1005     default:
1006         ACPI_ERROR ((AE_INFO,
1007             "Unsupported address space: %X", Reg->AddressSpaceId));
1008         return (AE_BAD_PARAMETER);
1009     }
1010 
1011     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
1012         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
1013         Value, Width,
1014         ACPI_FORMAT_UINT64 (ACPI_GET_ADDRESS (Address)),
1015         AcpiUtGetRegionName (Reg->AddressSpaceId)));
1016 
1017     return (Status);
1018 }
1019