xref: /titanic_41/usr/src/uts/intel/io/acpica/hardware/hwxface.c (revision de5d74c22760a6d2cefd94d0e7f0fd87214fb71f)
1 /******************************************************************************
2  *
3  * Module Name: hwxface - Public ACPICA hardware interfaces
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #define EXPORT_ACPI_INTERFACES
45 
46 #include "acpi.h"
47 #include "accommon.h"
48 #include "acnamesp.h"
49 
50 #define _COMPONENT          ACPI_HARDWARE
51         ACPI_MODULE_NAME    ("hwxface")
52 
53 
54 /******************************************************************************
55  *
56  * FUNCTION:    AcpiReset
57  *
58  * PARAMETERS:  None
59  *
60  * RETURN:      Status
61  *
62  * DESCRIPTION: Set reset register in memory or IO space. Note: Does not
63  *              support reset register in PCI config space, this must be
64  *              handled separately.
65  *
66  ******************************************************************************/
67 
68 ACPI_STATUS
AcpiReset(void)69 AcpiReset (
70     void)
71 {
72     ACPI_GENERIC_ADDRESS    *ResetReg;
73     ACPI_STATUS             Status;
74 
75 
76     ACPI_FUNCTION_TRACE (AcpiReset);
77 
78 
79     ResetReg = &AcpiGbl_FADT.ResetRegister;
80 
81     /* Check if the reset register is supported */
82 
83     if (!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) ||
84         !ResetReg->Address)
85     {
86         return_ACPI_STATUS (AE_NOT_EXIST);
87     }
88 
89     if (ResetReg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
90     {
91         /*
92          * For I/O space, write directly to the OSL. This bypasses the port
93          * validation mechanism, which may block a valid write to the reset
94          * register.
95          *
96          * NOTE:
97          * The ACPI spec requires the reset register width to be 8, so we
98          * hardcode it here and ignore the FADT value. This maintains
99          * compatibility with other ACPI implementations that have allowed
100          * BIOS code with bad register width values to go unnoticed.
101          */
102         Status = AcpiOsWritePort ((ACPI_IO_ADDRESS) ResetReg->Address,
103             AcpiGbl_FADT.ResetValue, ACPI_RESET_REGISTER_WIDTH);
104     }
105     else
106     {
107         /* Write the reset value to the reset register */
108 
109         Status = AcpiHwWrite (AcpiGbl_FADT.ResetValue, ResetReg);
110     }
111 
112     return_ACPI_STATUS (Status);
113 }
114 
ACPI_EXPORT_SYMBOL(AcpiReset)115 ACPI_EXPORT_SYMBOL (AcpiReset)
116 
117 
118 /******************************************************************************
119  *
120  * FUNCTION:    AcpiRead
121  *
122  * PARAMETERS:  Value               - Where the value is returned
123  *              Reg                 - GAS register structure
124  *
125  * RETURN:      Status
126  *
127  * DESCRIPTION: Read from either memory or IO space.
128  *
129  * LIMITATIONS: <These limitations also apply to AcpiWrite>
130  *      BitWidth must be exactly 8, 16, 32, or 64.
131  *      SpaceID must be SystemMemory or SystemIO.
132  *      BitOffset and AccessWidth are currently ignored, as there has
133  *          not been a need to implement these.
134  *
135  ******************************************************************************/
136 
137 ACPI_STATUS
138 AcpiRead (
139     UINT64                  *ReturnValue,
140     ACPI_GENERIC_ADDRESS    *Reg)
141 {
142     UINT32                  ValueLo;
143     UINT32                  ValueHi;
144     UINT32                  Width;
145     UINT64                  Address;
146     ACPI_STATUS             Status;
147 
148 
149     ACPI_FUNCTION_NAME (AcpiRead);
150 
151 
152     if (!ReturnValue)
153     {
154         return (AE_BAD_PARAMETER);
155     }
156 
157     /* Validate contents of the GAS register. Allow 64-bit transfers */
158 
159     Status = AcpiHwValidateRegister (Reg, 64, &Address);
160     if (ACPI_FAILURE (Status))
161     {
162         return (Status);
163     }
164 
165     /*
166      * Two address spaces supported: Memory or I/O. PCI_Config is
167      * not supported here because the GAS structure is insufficient
168      */
169     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
170     {
171         Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
172             Address, ReturnValue, Reg->BitWidth);
173         if (ACPI_FAILURE (Status))
174         {
175             return (Status);
176         }
177     }
178     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
179     {
180         ValueLo = 0;
181         ValueHi = 0;
182 
183         Width = Reg->BitWidth;
184         if (Width == 64)
185         {
186             Width = 32; /* Break into two 32-bit transfers */
187         }
188 
189         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
190             Address, &ValueLo, Width);
191         if (ACPI_FAILURE (Status))
192         {
193             return (Status);
194         }
195 
196         if (Reg->BitWidth == 64)
197         {
198             /* Read the top 32 bits */
199 
200             Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
201                 (Address + 4), &ValueHi, 32);
202             if (ACPI_FAILURE (Status))
203             {
204                 return (Status);
205             }
206         }
207 
208         /* Set the return value only if status is AE_OK */
209 
210         *ReturnValue = (ValueLo | ((UINT64) ValueHi << 32));
211     }
212 
213     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
214         "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
215         ACPI_FORMAT_UINT64 (*ReturnValue), Reg->BitWidth,
216         ACPI_FORMAT_UINT64 (Address),
217         AcpiUtGetRegionName (Reg->SpaceId)));
218 
219     return (AE_OK);
220 }
221 
ACPI_EXPORT_SYMBOL(AcpiRead)222 ACPI_EXPORT_SYMBOL (AcpiRead)
223 
224 
225 /******************************************************************************
226  *
227  * FUNCTION:    AcpiWrite
228  *
229  * PARAMETERS:  Value               - Value to be written
230  *              Reg                 - GAS register structure
231  *
232  * RETURN:      Status
233  *
234  * DESCRIPTION: Write to either memory or IO space.
235  *
236  ******************************************************************************/
237 
238 ACPI_STATUS
239 AcpiWrite (
240     UINT64                  Value,
241     ACPI_GENERIC_ADDRESS    *Reg)
242 {
243     UINT32                  Width;
244     UINT64                  Address;
245     ACPI_STATUS             Status;
246 
247 
248     ACPI_FUNCTION_NAME (AcpiWrite);
249 
250 
251     /* Validate contents of the GAS register. Allow 64-bit transfers */
252 
253     Status = AcpiHwValidateRegister (Reg, 64, &Address);
254     if (ACPI_FAILURE (Status))
255     {
256         return (Status);
257     }
258 
259     /*
260      * Two address spaces supported: Memory or IO. PCI_Config is
261      * not supported here because the GAS structure is insufficient
262      */
263     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
264     {
265         Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
266             Address, Value, Reg->BitWidth);
267         if (ACPI_FAILURE (Status))
268         {
269             return (Status);
270         }
271     }
272     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
273     {
274         Width = Reg->BitWidth;
275         if (Width == 64)
276         {
277             Width = 32; /* Break into two 32-bit transfers */
278         }
279 
280         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
281             Address, ACPI_LODWORD (Value), Width);
282         if (ACPI_FAILURE (Status))
283         {
284             return (Status);
285         }
286 
287         if (Reg->BitWidth == 64)
288         {
289             Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
290                 (Address + 4), ACPI_HIDWORD (Value), 32);
291             if (ACPI_FAILURE (Status))
292             {
293                 return (Status);
294             }
295         }
296     }
297 
298     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
299         "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
300         ACPI_FORMAT_UINT64 (Value), Reg->BitWidth,
301         ACPI_FORMAT_UINT64 (Address),
302         AcpiUtGetRegionName (Reg->SpaceId)));
303 
304     return (Status);
305 }
306 
ACPI_EXPORT_SYMBOL(AcpiWrite)307 ACPI_EXPORT_SYMBOL (AcpiWrite)
308 
309 
310 #if (!ACPI_REDUCED_HARDWARE)
311 /*******************************************************************************
312  *
313  * FUNCTION:    AcpiReadBitRegister
314  *
315  * PARAMETERS:  RegisterId      - ID of ACPI Bit Register to access
316  *              ReturnValue     - Value that was read from the register,
317  *                                normalized to bit position zero.
318  *
319  * RETURN:      Status and the value read from the specified Register. Value
320  *              returned is normalized to bit0 (is shifted all the way right)
321  *
322  * DESCRIPTION: ACPI BitRegister read function. Does not acquire the HW lock.
323  *
324  * SUPPORTS:    Bit fields in PM1 Status, PM1 Enable, PM1 Control, and
325  *              PM2 Control.
326  *
327  * Note: The hardware lock is not required when reading the ACPI bit registers
328  *       since almost all of them are single bit and it does not matter that
329  *       the parent hardware register can be split across two physical
330  *       registers. The only multi-bit field is SLP_TYP in the PM1 control
331  *       register, but this field does not cross an 8-bit boundary (nor does
332  *       it make much sense to actually read this field.)
333  *
334  ******************************************************************************/
335 
336 ACPI_STATUS
337 AcpiReadBitRegister (
338     UINT32                  RegisterId,
339     UINT32                  *ReturnValue)
340 {
341     ACPI_BIT_REGISTER_INFO  *BitRegInfo;
342     UINT32                  RegisterValue;
343     UINT32                  Value;
344     ACPI_STATUS             Status;
345 
346 
347     ACPI_FUNCTION_TRACE_U32 (AcpiReadBitRegister, RegisterId);
348 
349 
350     /* Get the info structure corresponding to the requested ACPI Register */
351 
352     BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId);
353     if (!BitRegInfo)
354     {
355         return_ACPI_STATUS (AE_BAD_PARAMETER);
356     }
357 
358     /* Read the entire parent register */
359 
360     Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister,
361         &RegisterValue);
362     if (ACPI_FAILURE (Status))
363     {
364         return_ACPI_STATUS (Status);
365     }
366 
367     /* Normalize the value that was read, mask off other bits */
368 
369     Value = ((RegisterValue & BitRegInfo->AccessBitMask)
370         >> BitRegInfo->BitPosition);
371 
372     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
373         "BitReg %X, ParentReg %X, Actual %8.8X, ReturnValue %8.8X\n",
374         RegisterId, BitRegInfo->ParentRegister, RegisterValue, Value));
375 
376     *ReturnValue = Value;
377     return_ACPI_STATUS (AE_OK);
378 }
379 
ACPI_EXPORT_SYMBOL(AcpiReadBitRegister)380 ACPI_EXPORT_SYMBOL (AcpiReadBitRegister)
381 
382 
383 /*******************************************************************************
384  *
385  * FUNCTION:    AcpiWriteBitRegister
386  *
387  * PARAMETERS:  RegisterId      - ID of ACPI Bit Register to access
388  *              Value           - Value to write to the register, in bit
389  *                                position zero. The bit is automatically
390  *                                shifted to the correct position.
391  *
392  * RETURN:      Status
393  *
394  * DESCRIPTION: ACPI Bit Register write function. Acquires the hardware lock
395  *              since most operations require a read/modify/write sequence.
396  *
397  * SUPPORTS:    Bit fields in PM1 Status, PM1 Enable, PM1 Control, and
398  *              PM2 Control.
399  *
400  * Note that at this level, the fact that there may be actually two
401  * hardware registers (A and B - and B may not exist) is abstracted.
402  *
403  ******************************************************************************/
404 
405 ACPI_STATUS
406 AcpiWriteBitRegister (
407     UINT32                  RegisterId,
408     UINT32                  Value)
409 {
410     ACPI_BIT_REGISTER_INFO  *BitRegInfo;
411     ACPI_CPU_FLAGS          LockFlags;
412     UINT32                  RegisterValue;
413     ACPI_STATUS             Status = AE_OK;
414 
415 
416     ACPI_FUNCTION_TRACE_U32 (AcpiWriteBitRegister, RegisterId);
417 
418 
419     /* Get the info structure corresponding to the requested ACPI Register */
420 
421     BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId);
422     if (!BitRegInfo)
423     {
424         return_ACPI_STATUS (AE_BAD_PARAMETER);
425     }
426 
427     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
428 
429     /*
430      * At this point, we know that the parent register is one of the
431      * following: PM1 Status, PM1 Enable, PM1 Control, or PM2 Control
432      */
433     if (BitRegInfo->ParentRegister != ACPI_REGISTER_PM1_STATUS)
434     {
435         /*
436          * 1) Case for PM1 Enable, PM1 Control, and PM2 Control
437          *
438          * Perform a register read to preserve the bits that we are not
439          * interested in
440          */
441         Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister,
442             &RegisterValue);
443         if (ACPI_FAILURE (Status))
444         {
445             goto UnlockAndExit;
446         }
447 
448         /*
449          * Insert the input bit into the value that was just read
450          * and write the register
451          */
452         ACPI_REGISTER_INSERT_VALUE (RegisterValue, BitRegInfo->BitPosition,
453             BitRegInfo->AccessBitMask, Value);
454 
455         Status = AcpiHwRegisterWrite (BitRegInfo->ParentRegister,
456             RegisterValue);
457     }
458     else
459     {
460         /*
461          * 2) Case for PM1 Status
462          *
463          * The Status register is different from the rest. Clear an event
464          * by writing 1, writing 0 has no effect. So, the only relevant
465          * information is the single bit we're interested in, all others
466          * should be written as 0 so they will be left unchanged.
467          */
468         RegisterValue = ACPI_REGISTER_PREPARE_BITS (Value,
469             BitRegInfo->BitPosition, BitRegInfo->AccessBitMask);
470 
471         /* No need to write the register if value is all zeros */
472 
473         if (RegisterValue)
474         {
475             Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
476                 RegisterValue);
477         }
478     }
479 
480     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
481         "BitReg %X, ParentReg %X, Value %8.8X, Actual %8.8X\n",
482         RegisterId, BitRegInfo->ParentRegister, Value, RegisterValue));
483 
484 
485 UnlockAndExit:
486 
487     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
488     return_ACPI_STATUS (Status);
489 }
490 
ACPI_EXPORT_SYMBOL(AcpiWriteBitRegister)491 ACPI_EXPORT_SYMBOL (AcpiWriteBitRegister)
492 
493 #endif /* !ACPI_REDUCED_HARDWARE */
494 
495 
496 /*******************************************************************************
497  *
498  * FUNCTION:    AcpiGetSleepTypeData
499  *
500  * PARAMETERS:  SleepState          - Numeric sleep state
501  *              *SleepTypeA         - Where SLP_TYPa is returned
502  *              *SleepTypeB         - Where SLP_TYPb is returned
503  *
504  * RETURN:      Status
505  *
506  * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested
507  *              sleep state via the appropriate \_Sx object.
508  *
509  *  The sleep state package returned from the corresponding \_Sx_ object
510  *  must contain at least one integer.
511  *
512  *  March 2005:
513  *  Added support for a package that contains two integers. This
514  *  goes against the ACPI specification which defines this object as a
515  *  package with one encoded DWORD integer. However, existing practice
516  *  by many BIOS vendors is to return a package with 2 or more integer
517  *  elements, at least one per sleep type (A/B).
518  *
519  *  January 2013:
520  *  Therefore, we must be prepared to accept a package with either a
521  *  single integer or multiple integers.
522  *
523  *  The single integer DWORD format is as follows:
524  *      BYTE 0 - Value for the PM1A SLP_TYP register
525  *      BYTE 1 - Value for the PM1B SLP_TYP register
526  *      BYTE 2-3 - Reserved
527  *
528  *  The dual integer format is as follows:
529  *      Integer 0 - Value for the PM1A SLP_TYP register
530  *      Integer 1 - Value for the PM1A SLP_TYP register
531  *
532  ******************************************************************************/
533 
534 ACPI_STATUS
535 AcpiGetSleepTypeData (
536     UINT8                   SleepState,
537     UINT8                   *SleepTypeA,
538     UINT8                   *SleepTypeB)
539 {
540     ACPI_STATUS             Status;
541     ACPI_EVALUATE_INFO      *Info;
542     ACPI_OPERAND_OBJECT     **Elements;
543 
544 
545     ACPI_FUNCTION_TRACE (AcpiGetSleepTypeData);
546 
547 
548     /* Validate parameters */
549 
550     if ((SleepState > ACPI_S_STATES_MAX) ||
551         !SleepTypeA || !SleepTypeB)
552     {
553         return_ACPI_STATUS (AE_BAD_PARAMETER);
554     }
555 
556     /* Allocate the evaluation information block */
557 
558     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
559     if (!Info)
560     {
561         return_ACPI_STATUS (AE_NO_MEMORY);
562     }
563 
564     /*
565      * Evaluate the \_Sx namespace object containing the register values
566      * for this state
567      */
568     Info->RelativePathname = AcpiGbl_SleepStateNames[SleepState];
569 
570     Status = AcpiNsEvaluate (Info);
571     if (ACPI_FAILURE (Status))
572     {
573         if (Status == AE_NOT_FOUND)
574         {
575             /* The _Sx states are optional, ignore NOT_FOUND */
576 
577             goto FinalCleanup;
578         }
579 
580         goto WarningCleanup;
581     }
582 
583     /* Must have a return object */
584 
585     if (!Info->ReturnObject)
586     {
587         ACPI_ERROR ((AE_INFO, "No Sleep State object returned from [%s]",
588             Info->RelativePathname));
589         Status = AE_AML_NO_RETURN_VALUE;
590         goto WarningCleanup;
591     }
592 
593     /* Return object must be of type Package */
594 
595     if (Info->ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
596     {
597         ACPI_ERROR ((AE_INFO, "Sleep State return object is not a Package"));
598         Status = AE_AML_OPERAND_TYPE;
599         goto ReturnValueCleanup;
600     }
601 
602     /*
603      * Any warnings about the package length or the object types have
604      * already been issued by the predefined name module -- there is no
605      * need to repeat them here.
606      */
607     Elements = Info->ReturnObject->Package.Elements;
608     switch (Info->ReturnObject->Package.Count)
609     {
610     case 0:
611 
612         Status = AE_AML_PACKAGE_LIMIT;
613         break;
614 
615     case 1:
616 
617         if (Elements[0]->Common.Type != ACPI_TYPE_INTEGER)
618         {
619             Status = AE_AML_OPERAND_TYPE;
620             break;
621         }
622 
623         /* A valid _Sx_ package with one integer */
624 
625         *SleepTypeA = (UINT8) Elements[0]->Integer.Value;
626         *SleepTypeB = (UINT8) (Elements[0]->Integer.Value >> 8);
627         break;
628 
629     case 2:
630     default:
631 
632         if ((Elements[0]->Common.Type != ACPI_TYPE_INTEGER) ||
633             (Elements[1]->Common.Type != ACPI_TYPE_INTEGER))
634         {
635             Status = AE_AML_OPERAND_TYPE;
636             break;
637         }
638 
639         /* A valid _Sx_ package with two integers */
640 
641         *SleepTypeA = (UINT8) Elements[0]->Integer.Value;
642         *SleepTypeB = (UINT8) Elements[1]->Integer.Value;
643         break;
644     }
645 
646 ReturnValueCleanup:
647     AcpiUtRemoveReference (Info->ReturnObject);
648 
649 WarningCleanup:
650     if (ACPI_FAILURE (Status))
651     {
652         ACPI_EXCEPTION ((AE_INFO, Status,
653             "While evaluating Sleep State [%s]",
654             Info->RelativePathname));
655     }
656 
657 FinalCleanup:
658     ACPI_FREE (Info);
659     return_ACPI_STATUS (Status);
660 }
661 
662 ACPI_EXPORT_SYMBOL (AcpiGetSleepTypeData)
663