xref: /titanic_44/usr/src/uts/intel/io/acpica/hardware/hwxface.c (revision 70f9559bd0c02885d84a425eaafc8c280df10efb)
1 
2 /******************************************************************************
3  *
4  * Module Name: hwxface - Public ACPICA hardware interfaces
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2011, 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 "acnamesp.h"
48 
49 #define _COMPONENT          ACPI_HARDWARE
50         ACPI_MODULE_NAME    ("hwxface")
51 
52 
53 /******************************************************************************
54  *
55  * FUNCTION:    AcpiReset
56  *
57  * PARAMETERS:  None
58  *
59  * RETURN:      Status
60  *
61  * DESCRIPTION: Set reset register in memory or IO space. Note: Does not
62  *              support reset register in PCI config space, this must be
63  *              handled separately.
64  *
65  ******************************************************************************/
66 
67 ACPI_STATUS
68 AcpiReset (
69     void)
70 {
71     ACPI_GENERIC_ADDRESS    *ResetReg;
72     ACPI_STATUS             Status;
73 
74 
75     ACPI_FUNCTION_TRACE (AcpiReset);
76 
77 
78     ResetReg = &AcpiGbl_FADT.ResetRegister;
79 
80     /* Check if the reset register is supported */
81 
82     if (!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) ||
83         !ResetReg->Address)
84     {
85         return_ACPI_STATUS (AE_NOT_EXIST);
86     }
87 
88     if (ResetReg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
89     {
90         /*
91          * For I/O space, write directly to the OSL. This bypasses the port
92          * validation mechanism, which may block a valid write to the reset
93          * register.
94          */
95         Status = AcpiOsWritePort ((ACPI_IO_ADDRESS) ResetReg->Address,
96                     AcpiGbl_FADT.ResetValue, ResetReg->BitWidth);
97     }
98     else
99     {
100         /* Write the reset value to the reset register */
101 
102         Status = AcpiHwWrite (AcpiGbl_FADT.ResetValue, ResetReg);
103     }
104 
105     return_ACPI_STATUS (Status);
106 }
107 
108 ACPI_EXPORT_SYMBOL (AcpiReset)
109 
110 
111 /******************************************************************************
112  *
113  * FUNCTION:    AcpiRead
114  *
115  * PARAMETERS:  Value               - Where the value is returned
116  *              Reg                 - GAS register structure
117  *
118  * RETURN:      Status
119  *
120  * DESCRIPTION: Read from either memory or IO space.
121  *
122  * LIMITATIONS: <These limitations also apply to AcpiWrite>
123  *      BitWidth must be exactly 8, 16, 32, or 64.
124  *      SpaceID must be SystemMemory or SystemIO.
125  *      BitOffset and AccessWidth are currently ignored, as there has
126  *          not been a need to implement these.
127  *
128  ******************************************************************************/
129 
130 ACPI_STATUS
131 AcpiRead (
132     UINT64                  *ReturnValue,
133     ACPI_GENERIC_ADDRESS    *Reg)
134 {
135     UINT32                  Value;
136     UINT32                  Width;
137     UINT64                  Address;
138     ACPI_STATUS             Status;
139 
140 
141     ACPI_FUNCTION_NAME (AcpiRead);
142 
143 
144     if (!ReturnValue)
145     {
146         return (AE_BAD_PARAMETER);
147     }
148 
149     /* Validate contents of the GAS register. Allow 64-bit transfers */
150 
151     Status = AcpiHwValidateRegister (Reg, 64, &Address);
152     if (ACPI_FAILURE (Status))
153     {
154         return (Status);
155     }
156 
157     Width = Reg->BitWidth;
158     if (Width == 64)
159     {
160         Width = 32; /* Break into two 32-bit transfers */
161     }
162 
163     /* Initialize entire 64-bit return value to zero */
164 
165     *ReturnValue = 0;
166     Value = 0;
167 
168     /*
169      * Two address spaces supported: Memory or IO. PCI_Config is
170      * not supported here because the GAS structure is insufficient
171      */
172     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
173     {
174         Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
175                     Address, &Value, Width);
176         if (ACPI_FAILURE (Status))
177         {
178             return (Status);
179         }
180         *ReturnValue = Value;
181 
182         if (Reg->BitWidth == 64)
183         {
184             /* Read the top 32 bits */
185 
186             Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
187                         (Address + 4), &Value, 32);
188             if (ACPI_FAILURE (Status))
189             {
190                 return (Status);
191             }
192             *ReturnValue |= ((UINT64) Value << 32);
193         }
194     }
195     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
196     {
197         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
198                     Address, &Value, Width);
199         if (ACPI_FAILURE (Status))
200         {
201             return (Status);
202         }
203         *ReturnValue = Value;
204 
205         if (Reg->BitWidth == 64)
206         {
207             /* Read the top 32 bits */
208 
209             Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
210                         (Address + 4), &Value, 32);
211             if (ACPI_FAILURE (Status))
212             {
213                 return (Status);
214             }
215             *ReturnValue |= ((UINT64) Value << 32);
216         }
217     }
218 
219     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
220         "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
221         ACPI_FORMAT_UINT64 (*ReturnValue), Reg->BitWidth,
222         ACPI_FORMAT_UINT64 (Address),
223         AcpiUtGetRegionName (Reg->SpaceId)));
224 
225     return (Status);
226 }
227 
228 ACPI_EXPORT_SYMBOL (AcpiRead)
229 
230 
231 /******************************************************************************
232  *
233  * FUNCTION:    AcpiWrite
234  *
235  * PARAMETERS:  Value               - Value to be written
236  *              Reg                 - GAS register structure
237  *
238  * RETURN:      Status
239  *
240  * DESCRIPTION: Write to either memory or IO space.
241  *
242  ******************************************************************************/
243 
244 ACPI_STATUS
245 AcpiWrite (
246     UINT64                  Value,
247     ACPI_GENERIC_ADDRESS    *Reg)
248 {
249     UINT32                  Width;
250     UINT64                  Address;
251     ACPI_STATUS             Status;
252 
253 
254     ACPI_FUNCTION_NAME (AcpiWrite);
255 
256 
257     /* Validate contents of the GAS register. Allow 64-bit transfers */
258 
259     Status = AcpiHwValidateRegister (Reg, 64, &Address);
260     if (ACPI_FAILURE (Status))
261     {
262         return (Status);
263     }
264 
265     Width = Reg->BitWidth;
266     if (Width == 64)
267     {
268         Width = 32; /* Break into two 32-bit transfers */
269     }
270 
271     /*
272      * Two address spaces supported: Memory or IO. PCI_Config is
273      * not supported here because the GAS structure is insufficient
274      */
275     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
276     {
277         Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
278                     Address, ACPI_LODWORD (Value), Width);
279         if (ACPI_FAILURE (Status))
280         {
281             return (Status);
282         }
283 
284         if (Reg->BitWidth == 64)
285         {
286             Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
287                         (Address + 4), ACPI_HIDWORD (Value), 32);
288             if (ACPI_FAILURE (Status))
289             {
290                 return (Status);
291             }
292         }
293     }
294     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
295     {
296         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
297                     Address, ACPI_LODWORD (Value), Width);
298         if (ACPI_FAILURE (Status))
299         {
300             return (Status);
301         }
302 
303         if (Reg->BitWidth == 64)
304         {
305             Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
306                         (Address + 4), ACPI_HIDWORD (Value), 32);
307             if (ACPI_FAILURE (Status))
308             {
309                 return (Status);
310             }
311         }
312     }
313 
314     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
315         "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
316         ACPI_FORMAT_UINT64 (Value), Reg->BitWidth,
317         ACPI_FORMAT_UINT64 (Address),
318         AcpiUtGetRegionName (Reg->SpaceId)));
319 
320     return (Status);
321 }
322 
323 ACPI_EXPORT_SYMBOL (AcpiWrite)
324 
325 
326 /*******************************************************************************
327  *
328  * FUNCTION:    AcpiReadBitRegister
329  *
330  * PARAMETERS:  RegisterId      - ID of ACPI Bit Register to access
331  *              ReturnValue     - Value that was read from the register,
332  *                                normalized to bit position zero.
333  *
334  * RETURN:      Status and the value read from the specified Register. Value
335  *              returned is normalized to bit0 (is shifted all the way right)
336  *
337  * DESCRIPTION: ACPI BitRegister read function. Does not acquire the HW lock.
338  *
339  * SUPPORTS:    Bit fields in PM1 Status, PM1 Enable, PM1 Control, and
340  *              PM2 Control.
341  *
342  * Note: The hardware lock is not required when reading the ACPI bit registers
343  *       since almost all of them are single bit and it does not matter that
344  *       the parent hardware register can be split across two physical
345  *       registers. The only multi-bit field is SLP_TYP in the PM1 control
346  *       register, but this field does not cross an 8-bit boundary (nor does
347  *       it make much sense to actually read this field.)
348  *
349  ******************************************************************************/
350 
351 ACPI_STATUS
352 AcpiReadBitRegister (
353     UINT32                  RegisterId,
354     UINT32                  *ReturnValue)
355 {
356     ACPI_BIT_REGISTER_INFO  *BitRegInfo;
357     UINT32                  RegisterValue;
358     UINT32                  Value;
359     ACPI_STATUS             Status;
360 
361 
362     ACPI_FUNCTION_TRACE_U32 (AcpiReadBitRegister, RegisterId);
363 
364 
365     /* Get the info structure corresponding to the requested ACPI Register */
366 
367     BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId);
368     if (!BitRegInfo)
369     {
370         return_ACPI_STATUS (AE_BAD_PARAMETER);
371     }
372 
373     /* Read the entire parent register */
374 
375     Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister,
376                 &RegisterValue);
377     if (ACPI_FAILURE (Status))
378     {
379         return_ACPI_STATUS (Status);
380     }
381 
382     /* Normalize the value that was read, mask off other bits */
383 
384     Value = ((RegisterValue & BitRegInfo->AccessBitMask)
385                 >> BitRegInfo->BitPosition);
386 
387     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
388         "BitReg %X, ParentReg %X, Actual %8.8X, ReturnValue %8.8X\n",
389         RegisterId, BitRegInfo->ParentRegister, RegisterValue, Value));
390 
391     *ReturnValue = Value;
392     return_ACPI_STATUS (AE_OK);
393 }
394 
395 ACPI_EXPORT_SYMBOL (AcpiReadBitRegister)
396 
397 
398 /*******************************************************************************
399  *
400  * FUNCTION:    AcpiWriteBitRegister
401  *
402  * PARAMETERS:  RegisterId      - ID of ACPI Bit Register to access
403  *              Value           - Value to write to the register, in bit
404  *                                position zero. The bit is automaticallly
405  *                                shifted to the correct position.
406  *
407  * RETURN:      Status
408  *
409  * DESCRIPTION: ACPI Bit Register write function. Acquires the hardware lock
410  *              since most operations require a read/modify/write sequence.
411  *
412  * SUPPORTS:    Bit fields in PM1 Status, PM1 Enable, PM1 Control, and
413  *              PM2 Control.
414  *
415  * Note that at this level, the fact that there may be actually two
416  * hardware registers (A and B - and B may not exist) is abstracted.
417  *
418  ******************************************************************************/
419 
420 ACPI_STATUS
421 AcpiWriteBitRegister (
422     UINT32                  RegisterId,
423     UINT32                  Value)
424 {
425     ACPI_BIT_REGISTER_INFO  *BitRegInfo;
426     ACPI_CPU_FLAGS          LockFlags;
427     UINT32                  RegisterValue;
428     ACPI_STATUS             Status = AE_OK;
429 
430 
431     ACPI_FUNCTION_TRACE_U32 (AcpiWriteBitRegister, RegisterId);
432 
433 
434     /* Get the info structure corresponding to the requested ACPI Register */
435 
436     BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId);
437     if (!BitRegInfo)
438     {
439         return_ACPI_STATUS (AE_BAD_PARAMETER);
440     }
441 
442     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
443 
444     /*
445      * At this point, we know that the parent register is one of the
446      * following: PM1 Status, PM1 Enable, PM1 Control, or PM2 Control
447      */
448     if (BitRegInfo->ParentRegister != ACPI_REGISTER_PM1_STATUS)
449     {
450         /*
451          * 1) Case for PM1 Enable, PM1 Control, and PM2 Control
452          *
453          * Perform a register read to preserve the bits that we are not
454          * interested in
455          */
456         Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister,
457                     &RegisterValue);
458         if (ACPI_FAILURE (Status))
459         {
460             goto UnlockAndExit;
461         }
462 
463         /*
464          * Insert the input bit into the value that was just read
465          * and write the register
466          */
467         ACPI_REGISTER_INSERT_VALUE (RegisterValue, BitRegInfo->BitPosition,
468             BitRegInfo->AccessBitMask, Value);
469 
470         Status = AcpiHwRegisterWrite (BitRegInfo->ParentRegister,
471                     RegisterValue);
472     }
473     else
474     {
475         /*
476          * 2) Case for PM1 Status
477          *
478          * The Status register is different from the rest. Clear an event
479          * by writing 1, writing 0 has no effect. So, the only relevant
480          * information is the single bit we're interested in, all others
481          * should be written as 0 so they will be left unchanged.
482          */
483         RegisterValue = ACPI_REGISTER_PREPARE_BITS (Value,
484             BitRegInfo->BitPosition, BitRegInfo->AccessBitMask);
485 
486         /* No need to write the register if value is all zeros */
487 
488         if (RegisterValue)
489         {
490             Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
491                         RegisterValue);
492         }
493     }
494 
495     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
496         "BitReg %X, ParentReg %X, Value %8.8X, Actual %8.8X\n",
497         RegisterId, BitRegInfo->ParentRegister, Value, RegisterValue));
498 
499 
500 UnlockAndExit:
501 
502     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
503     return_ACPI_STATUS (Status);
504 }
505 
506 ACPI_EXPORT_SYMBOL (AcpiWriteBitRegister)
507 
508 
509 /*******************************************************************************
510  *
511  * FUNCTION:    AcpiGetSleepTypeData
512  *
513  * PARAMETERS:  SleepState          - Numeric sleep state
514  *              *SleepTypeA         - Where SLP_TYPa is returned
515  *              *SleepTypeB         - Where SLP_TYPb is returned
516  *
517  * RETURN:      Status - ACPI status
518  *
519  * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
520  *              state.
521  *
522  ******************************************************************************/
523 
524 ACPI_STATUS
525 AcpiGetSleepTypeData (
526     UINT8                   SleepState,
527     UINT8                   *SleepTypeA,
528     UINT8                   *SleepTypeB)
529 {
530     ACPI_STATUS             Status = AE_OK;
531     ACPI_EVALUATE_INFO      *Info;
532 
533 
534     ACPI_FUNCTION_TRACE (AcpiGetSleepTypeData);
535 
536 
537     /* Validate parameters */
538 
539     if ((SleepState > ACPI_S_STATES_MAX) ||
540         !SleepTypeA ||
541         !SleepTypeB)
542     {
543         return_ACPI_STATUS (AE_BAD_PARAMETER);
544     }
545 
546     /* Allocate the evaluation information block */
547 
548     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
549     if (!Info)
550     {
551         return_ACPI_STATUS (AE_NO_MEMORY);
552     }
553 
554     Info->Pathname = ACPI_CAST_PTR (char, AcpiGbl_SleepStateNames[SleepState]);
555 
556     /* Evaluate the namespace object containing the values for this state */
557 
558     Status = AcpiNsEvaluate (Info);
559     if (ACPI_FAILURE (Status))
560     {
561         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
562             "%s while evaluating SleepState [%s]\n",
563             AcpiFormatException (Status), Info->Pathname));
564 
565         goto Cleanup;
566     }
567 
568     /* Must have a return object */
569 
570     if (!Info->ReturnObject)
571     {
572         ACPI_ERROR ((AE_INFO, "No Sleep State object returned from [%s]",
573             Info->Pathname));
574         Status = AE_NOT_EXIST;
575     }
576 
577     /* It must be of type Package */
578 
579     else if (Info->ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
580     {
581         ACPI_ERROR ((AE_INFO, "Sleep State return object is not a Package"));
582         Status = AE_AML_OPERAND_TYPE;
583     }
584 
585     /*
586      * The package must have at least two elements. NOTE (March 2005): This
587      * goes against the current ACPI spec which defines this object as a
588      * package with one encoded DWORD element. However, existing practice
589      * by BIOS vendors seems to be to have 2 or more elements, at least
590      * one per sleep type (A/B).
591      */
592     else if (Info->ReturnObject->Package.Count < 2)
593     {
594         ACPI_ERROR ((AE_INFO,
595             "Sleep State return package does not have at least two elements"));
596         Status = AE_AML_NO_OPERAND;
597     }
598 
599     /* The first two elements must both be of type Integer */
600 
601     else if (((Info->ReturnObject->Package.Elements[0])->Common.Type
602                 != ACPI_TYPE_INTEGER) ||
603              ((Info->ReturnObject->Package.Elements[1])->Common.Type
604                 != ACPI_TYPE_INTEGER))
605     {
606         ACPI_ERROR ((AE_INFO,
607             "Sleep State return package elements are not both Integers "
608             "(%s, %s)",
609             AcpiUtGetObjectTypeName (Info->ReturnObject->Package.Elements[0]),
610             AcpiUtGetObjectTypeName (Info->ReturnObject->Package.Elements[1])));
611         Status = AE_AML_OPERAND_TYPE;
612     }
613     else
614     {
615         /* Valid _Sx_ package size, type, and value */
616 
617         *SleepTypeA = (UINT8)
618             (Info->ReturnObject->Package.Elements[0])->Integer.Value;
619         *SleepTypeB = (UINT8)
620             (Info->ReturnObject->Package.Elements[1])->Integer.Value;
621     }
622 
623     if (ACPI_FAILURE (Status))
624     {
625         ACPI_EXCEPTION ((AE_INFO, Status,
626             "While evaluating SleepState [%s], bad Sleep object %p type %s",
627             Info->Pathname, Info->ReturnObject,
628             AcpiUtGetObjectTypeName (Info->ReturnObject)));
629     }
630 
631     AcpiUtRemoveReference (Info->ReturnObject);
632 
633 Cleanup:
634     ACPI_FREE (Info);
635     return_ACPI_STATUS (Status);
636 }
637 
638 ACPI_EXPORT_SYMBOL (AcpiGetSleepTypeData)
639