xref: /minix3/minix/drivers/power/acpi/executer/exprep.c (revision 29492bb71c7148a089a5afafa0c99409161218df)
1433d6423SLionel Sambuc /******************************************************************************
2433d6423SLionel Sambuc  *
3433d6423SLionel Sambuc  * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities
4433d6423SLionel Sambuc  *
5433d6423SLionel Sambuc  *****************************************************************************/
6433d6423SLionel Sambuc 
7*29492bb7SDavid van Moolenbroek /*
8*29492bb7SDavid van Moolenbroek  * Copyright (C) 2000 - 2014, Intel Corp.
9433d6423SLionel Sambuc  * All rights reserved.
10433d6423SLionel Sambuc  *
11*29492bb7SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
12*29492bb7SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
13*29492bb7SDavid van Moolenbroek  * are met:
14*29492bb7SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
15*29492bb7SDavid van Moolenbroek  *    notice, this list of conditions, and the following disclaimer,
16*29492bb7SDavid van Moolenbroek  *    without modification.
17*29492bb7SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18*29492bb7SDavid van Moolenbroek  *    substantially similar to the "NO WARRANTY" disclaimer below
19*29492bb7SDavid van Moolenbroek  *    ("Disclaimer") and any redistribution must be conditioned upon
20*29492bb7SDavid van Moolenbroek  *    including a substantially similar Disclaimer requirement for further
21*29492bb7SDavid van Moolenbroek  *    binary redistribution.
22*29492bb7SDavid van Moolenbroek  * 3. Neither the names of the above-listed copyright holders nor the names
23*29492bb7SDavid van Moolenbroek  *    of any contributors may be used to endorse or promote products derived
24*29492bb7SDavid van Moolenbroek  *    from this software without specific prior written permission.
25433d6423SLionel Sambuc  *
26*29492bb7SDavid van Moolenbroek  * Alternatively, this software may be distributed under the terms of the
27*29492bb7SDavid van Moolenbroek  * GNU General Public License ("GPL") version 2 as published by the Free
28*29492bb7SDavid van Moolenbroek  * Software Foundation.
29433d6423SLionel Sambuc  *
30*29492bb7SDavid van Moolenbroek  * NO WARRANTY
31*29492bb7SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32*29492bb7SDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33*29492bb7SDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34*29492bb7SDavid van Moolenbroek  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35*29492bb7SDavid van Moolenbroek  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*29492bb7SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*29492bb7SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*29492bb7SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39*29492bb7SDavid van Moolenbroek  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40*29492bb7SDavid van Moolenbroek  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41*29492bb7SDavid van Moolenbroek  * POSSIBILITY OF SUCH DAMAGES.
42*29492bb7SDavid van Moolenbroek  */
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc #include "acpi.h"
45433d6423SLionel Sambuc #include "accommon.h"
46433d6423SLionel Sambuc #include "acinterp.h"
47433d6423SLionel Sambuc #include "amlcode.h"
48433d6423SLionel Sambuc #include "acnamesp.h"
49*29492bb7SDavid van Moolenbroek #include "acdispat.h"
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc #define _COMPONENT          ACPI_EXECUTER
53433d6423SLionel Sambuc         ACPI_MODULE_NAME    ("exprep")
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc /* Local prototypes */
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc static UINT32
58433d6423SLionel Sambuc AcpiExDecodeFieldAccess (
59433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *ObjDesc,
60433d6423SLionel Sambuc     UINT8                   FieldFlags,
61433d6423SLionel Sambuc     UINT32                  *ReturnByteAlignment);
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc #ifdef ACPI_UNDER_DEVELOPMENT
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc static UINT32
67433d6423SLionel Sambuc AcpiExGenerateAccess (
68433d6423SLionel Sambuc     UINT32                  FieldBitOffset,
69433d6423SLionel Sambuc     UINT32                  FieldBitLength,
70433d6423SLionel Sambuc     UINT32                  RegionLength);
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc /*******************************************************************************
73433d6423SLionel Sambuc  *
74433d6423SLionel Sambuc  * FUNCTION:    AcpiExGenerateAccess
75433d6423SLionel Sambuc  *
76433d6423SLionel Sambuc  * PARAMETERS:  FieldBitOffset      - Start of field within parent region/buffer
77433d6423SLionel Sambuc  *              FieldBitLength      - Length of field in bits
78433d6423SLionel Sambuc  *              RegionLength        - Length of parent in bytes
79433d6423SLionel Sambuc  *
80433d6423SLionel Sambuc  * RETURN:      Field granularity (8, 16, 32 or 64) and
81433d6423SLionel Sambuc  *              ByteAlignment (1, 2, 3, or 4)
82433d6423SLionel Sambuc  *
83433d6423SLionel Sambuc  * DESCRIPTION: Generate an optimal access width for fields defined with the
84433d6423SLionel Sambuc  *              AnyAcc keyword.
85433d6423SLionel Sambuc  *
86433d6423SLionel Sambuc  * NOTE: Need to have the RegionLength in order to check for boundary
87433d6423SLionel Sambuc  *       conditions (end-of-region). However, the RegionLength is a deferred
88433d6423SLionel Sambuc  *       operation. Therefore, to complete this implementation, the generation
89433d6423SLionel Sambuc  *       of this access width must be deferred until the region length has
90433d6423SLionel Sambuc  *       been evaluated.
91433d6423SLionel Sambuc  *
92433d6423SLionel Sambuc  ******************************************************************************/
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc static UINT32
AcpiExGenerateAccess(UINT32 FieldBitOffset,UINT32 FieldBitLength,UINT32 RegionLength)95433d6423SLionel Sambuc AcpiExGenerateAccess (
96433d6423SLionel Sambuc     UINT32                  FieldBitOffset,
97433d6423SLionel Sambuc     UINT32                  FieldBitLength,
98433d6423SLionel Sambuc     UINT32                  RegionLength)
99433d6423SLionel Sambuc {
100433d6423SLionel Sambuc     UINT32                  FieldByteLength;
101433d6423SLionel Sambuc     UINT32                  FieldByteOffset;
102433d6423SLionel Sambuc     UINT32                  FieldByteEndOffset;
103433d6423SLionel Sambuc     UINT32                  AccessByteWidth;
104433d6423SLionel Sambuc     UINT32                  FieldStartOffset;
105433d6423SLionel Sambuc     UINT32                  FieldEndOffset;
106433d6423SLionel Sambuc     UINT32                  MinimumAccessWidth = 0xFFFFFFFF;
107433d6423SLionel Sambuc     UINT32                  MinimumAccesses = 0xFFFFFFFF;
108433d6423SLionel Sambuc     UINT32                  Accesses;
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (ExGenerateAccess);
112433d6423SLionel Sambuc 
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc     /* Round Field start offset and length to "minimal" byte boundaries */
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc     FieldByteOffset    = ACPI_DIV_8 (ACPI_ROUND_DOWN (FieldBitOffset, 8));
117433d6423SLionel Sambuc     FieldByteEndOffset = ACPI_DIV_8 (ACPI_ROUND_UP   (FieldBitLength +
118433d6423SLionel Sambuc                                                       FieldBitOffset, 8));
119433d6423SLionel Sambuc     FieldByteLength    = FieldByteEndOffset - FieldByteOffset;
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
122433d6423SLionel Sambuc         "Bit length %u, Bit offset %u\n",
123433d6423SLionel Sambuc         FieldBitLength, FieldBitOffset));
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
126433d6423SLionel Sambuc         "Byte Length %u, Byte Offset %u, End Offset %u\n",
127433d6423SLionel Sambuc         FieldByteLength, FieldByteOffset, FieldByteEndOffset));
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc     /*
130433d6423SLionel Sambuc      * Iterative search for the maximum access width that is both aligned
131433d6423SLionel Sambuc      * and does not go beyond the end of the region
132433d6423SLionel Sambuc      *
133433d6423SLionel Sambuc      * Start at ByteAcc and work upwards to QwordAcc max. (1,2,4,8 bytes)
134433d6423SLionel Sambuc      */
135433d6423SLionel Sambuc     for (AccessByteWidth = 1; AccessByteWidth <= 8; AccessByteWidth <<= 1)
136433d6423SLionel Sambuc     {
137433d6423SLionel Sambuc         /*
138433d6423SLionel Sambuc          * 1) Round end offset up to next access boundary and make sure that
139433d6423SLionel Sambuc          *    this does not go beyond the end of the parent region.
140433d6423SLionel Sambuc          * 2) When the Access width is greater than the FieldByteLength, we
141433d6423SLionel Sambuc          *    are done. (This does not optimize for the perfectly aligned
142433d6423SLionel Sambuc          *    case yet).
143433d6423SLionel Sambuc          */
144433d6423SLionel Sambuc         if (ACPI_ROUND_UP (FieldByteEndOffset, AccessByteWidth) <= RegionLength)
145433d6423SLionel Sambuc         {
146433d6423SLionel Sambuc             FieldStartOffset =
147433d6423SLionel Sambuc                 ACPI_ROUND_DOWN (FieldByteOffset, AccessByteWidth) /
148433d6423SLionel Sambuc                 AccessByteWidth;
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc             FieldEndOffset =
151433d6423SLionel Sambuc                 ACPI_ROUND_UP ((FieldByteLength + FieldByteOffset),
152433d6423SLionel Sambuc                     AccessByteWidth) / AccessByteWidth;
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc             Accesses = FieldEndOffset - FieldStartOffset;
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
157433d6423SLionel Sambuc                 "AccessWidth %u end is within region\n", AccessByteWidth));
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
160433d6423SLionel Sambuc                 "Field Start %u, Field End %u -- requires %u accesses\n",
161433d6423SLionel Sambuc                 FieldStartOffset, FieldEndOffset, Accesses));
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc             /* Single access is optimal */
164433d6423SLionel Sambuc 
165433d6423SLionel Sambuc             if (Accesses <= 1)
166433d6423SLionel Sambuc             {
167433d6423SLionel Sambuc                 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
168433d6423SLionel Sambuc                     "Entire field can be accessed with one operation of size %u\n",
169433d6423SLionel Sambuc                     AccessByteWidth));
170433d6423SLionel Sambuc                 return_VALUE (AccessByteWidth);
171433d6423SLionel Sambuc             }
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc             /*
174433d6423SLionel Sambuc              * Fits in the region, but requires more than one read/write.
175433d6423SLionel Sambuc              * try the next wider access on next iteration
176433d6423SLionel Sambuc              */
177433d6423SLionel Sambuc             if (Accesses < MinimumAccesses)
178433d6423SLionel Sambuc             {
179433d6423SLionel Sambuc                 MinimumAccesses    = Accesses;
180433d6423SLionel Sambuc                 MinimumAccessWidth = AccessByteWidth;
181433d6423SLionel Sambuc             }
182433d6423SLionel Sambuc         }
183433d6423SLionel Sambuc         else
184433d6423SLionel Sambuc         {
185433d6423SLionel Sambuc             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
186433d6423SLionel Sambuc                 "AccessWidth %u end is NOT within region\n", AccessByteWidth));
187433d6423SLionel Sambuc             if (AccessByteWidth == 1)
188433d6423SLionel Sambuc             {
189433d6423SLionel Sambuc                 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
190433d6423SLionel Sambuc                     "Field goes beyond end-of-region!\n"));
191433d6423SLionel Sambuc 
192433d6423SLionel Sambuc                 /* Field does not fit in the region at all */
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc                 return_VALUE (0);
195433d6423SLionel Sambuc             }
196433d6423SLionel Sambuc 
197433d6423SLionel Sambuc             /*
198433d6423SLionel Sambuc              * This width goes beyond the end-of-region, back off to
199433d6423SLionel Sambuc              * previous access
200433d6423SLionel Sambuc              */
201433d6423SLionel Sambuc             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
202433d6423SLionel Sambuc                 "Backing off to previous optimal access width of %u\n",
203433d6423SLionel Sambuc                 MinimumAccessWidth));
204433d6423SLionel Sambuc             return_VALUE (MinimumAccessWidth);
205433d6423SLionel Sambuc         }
206433d6423SLionel Sambuc     }
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc     /*
209433d6423SLionel Sambuc      * Could not read/write field with one operation,
210433d6423SLionel Sambuc      * just use max access width
211433d6423SLionel Sambuc      */
212433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
213433d6423SLionel Sambuc         "Cannot access field in one operation, using width 8\n"));
214433d6423SLionel Sambuc     return_VALUE (8);
215433d6423SLionel Sambuc }
216433d6423SLionel Sambuc #endif /* ACPI_UNDER_DEVELOPMENT */
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc 
219433d6423SLionel Sambuc /*******************************************************************************
220433d6423SLionel Sambuc  *
221433d6423SLionel Sambuc  * FUNCTION:    AcpiExDecodeFieldAccess
222433d6423SLionel Sambuc  *
223433d6423SLionel Sambuc  * PARAMETERS:  ObjDesc             - Field object
224433d6423SLionel Sambuc  *              FieldFlags          - Encoded fieldflags (contains access bits)
225433d6423SLionel Sambuc  *              ReturnByteAlignment - Where the byte alignment is returned
226433d6423SLionel Sambuc  *
227433d6423SLionel Sambuc  * RETURN:      Field granularity (8, 16, 32 or 64) and
228433d6423SLionel Sambuc  *              ByteAlignment (1, 2, 3, or 4)
229433d6423SLionel Sambuc  *
230433d6423SLionel Sambuc  * DESCRIPTION: Decode the AccessType bits of a field definition.
231433d6423SLionel Sambuc  *
232433d6423SLionel Sambuc  ******************************************************************************/
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc static UINT32
AcpiExDecodeFieldAccess(ACPI_OPERAND_OBJECT * ObjDesc,UINT8 FieldFlags,UINT32 * ReturnByteAlignment)235433d6423SLionel Sambuc AcpiExDecodeFieldAccess (
236433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *ObjDesc,
237433d6423SLionel Sambuc     UINT8                   FieldFlags,
238433d6423SLionel Sambuc     UINT32                  *ReturnByteAlignment)
239433d6423SLionel Sambuc {
240433d6423SLionel Sambuc     UINT32                  Access;
241433d6423SLionel Sambuc     UINT32                  ByteAlignment;
242433d6423SLionel Sambuc     UINT32                  BitLength;
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (ExDecodeFieldAccess);
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc     Access = (FieldFlags & AML_FIELD_ACCESS_TYPE_MASK);
249433d6423SLionel Sambuc 
250433d6423SLionel Sambuc     switch (Access)
251433d6423SLionel Sambuc     {
252433d6423SLionel Sambuc     case AML_FIELD_ACCESS_ANY:
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc #ifdef ACPI_UNDER_DEVELOPMENT
255433d6423SLionel Sambuc         ByteAlignment =
256433d6423SLionel Sambuc             AcpiExGenerateAccess (ObjDesc->CommonField.StartFieldBitOffset,
257433d6423SLionel Sambuc                 ObjDesc->CommonField.BitLength,
258433d6423SLionel Sambuc                 0xFFFFFFFF /* Temp until we pass RegionLength as parameter */);
259433d6423SLionel Sambuc         BitLength = ByteAlignment * 8;
260433d6423SLionel Sambuc #endif
261433d6423SLionel Sambuc 
262433d6423SLionel Sambuc         ByteAlignment = 1;
263433d6423SLionel Sambuc         BitLength = 8;
264433d6423SLionel Sambuc         break;
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc     case AML_FIELD_ACCESS_BYTE:
267433d6423SLionel Sambuc     case AML_FIELD_ACCESS_BUFFER:   /* ACPI 2.0 (SMBus Buffer) */
268*29492bb7SDavid van Moolenbroek 
269433d6423SLionel Sambuc         ByteAlignment = 1;
270433d6423SLionel Sambuc         BitLength     = 8;
271433d6423SLionel Sambuc         break;
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc     case AML_FIELD_ACCESS_WORD:
274*29492bb7SDavid van Moolenbroek 
275433d6423SLionel Sambuc         ByteAlignment = 2;
276433d6423SLionel Sambuc         BitLength     = 16;
277433d6423SLionel Sambuc         break;
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc     case AML_FIELD_ACCESS_DWORD:
280*29492bb7SDavid van Moolenbroek 
281433d6423SLionel Sambuc         ByteAlignment = 4;
282433d6423SLionel Sambuc         BitLength     = 32;
283433d6423SLionel Sambuc         break;
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc     case AML_FIELD_ACCESS_QWORD:    /* ACPI 2.0 */
286*29492bb7SDavid van Moolenbroek 
287433d6423SLionel Sambuc         ByteAlignment = 8;
288433d6423SLionel Sambuc         BitLength     = 64;
289433d6423SLionel Sambuc         break;
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc     default:
292*29492bb7SDavid van Moolenbroek 
293433d6423SLionel Sambuc         /* Invalid field access type */
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc         ACPI_ERROR ((AE_INFO,
296433d6423SLionel Sambuc             "Unknown field access type 0x%X",
297433d6423SLionel Sambuc             Access));
298433d6423SLionel Sambuc         return_UINT32 (0);
299433d6423SLionel Sambuc     }
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc     if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
302433d6423SLionel Sambuc     {
303433d6423SLionel Sambuc         /*
304433d6423SLionel Sambuc          * BufferField access can be on any byte boundary, so the
305433d6423SLionel Sambuc          * ByteAlignment is always 1 byte -- regardless of any ByteAlignment
306433d6423SLionel Sambuc          * implied by the field access type.
307433d6423SLionel Sambuc          */
308433d6423SLionel Sambuc         ByteAlignment = 1;
309433d6423SLionel Sambuc     }
310433d6423SLionel Sambuc 
311433d6423SLionel Sambuc     *ReturnByteAlignment = ByteAlignment;
312433d6423SLionel Sambuc     return_UINT32 (BitLength);
313433d6423SLionel Sambuc }
314433d6423SLionel Sambuc 
315433d6423SLionel Sambuc 
316433d6423SLionel Sambuc /*******************************************************************************
317433d6423SLionel Sambuc  *
318433d6423SLionel Sambuc  * FUNCTION:    AcpiExPrepCommonFieldObject
319433d6423SLionel Sambuc  *
320433d6423SLionel Sambuc  * PARAMETERS:  ObjDesc             - The field object
321433d6423SLionel Sambuc  *              FieldFlags          - Access, LockRule, and UpdateRule.
322433d6423SLionel Sambuc  *                                    The format of a FieldFlag is described
323433d6423SLionel Sambuc  *                                    in the ACPI specification
324433d6423SLionel Sambuc  *              FieldAttribute      - Special attributes (not used)
325433d6423SLionel Sambuc  *              FieldBitPosition    - Field start position
326433d6423SLionel Sambuc  *              FieldBitLength      - Field length in number of bits
327433d6423SLionel Sambuc  *
328433d6423SLionel Sambuc  * RETURN:      Status
329433d6423SLionel Sambuc  *
330433d6423SLionel Sambuc  * DESCRIPTION: Initialize the areas of the field object that are common
331433d6423SLionel Sambuc  *              to the various types of fields. Note: This is very "sensitive"
332433d6423SLionel Sambuc  *              code because we are solving the general case for field
333433d6423SLionel Sambuc  *              alignment.
334433d6423SLionel Sambuc  *
335433d6423SLionel Sambuc  ******************************************************************************/
336433d6423SLionel Sambuc 
337433d6423SLionel Sambuc ACPI_STATUS
AcpiExPrepCommonFieldObject(ACPI_OPERAND_OBJECT * ObjDesc,UINT8 FieldFlags,UINT8 FieldAttribute,UINT32 FieldBitPosition,UINT32 FieldBitLength)338433d6423SLionel Sambuc AcpiExPrepCommonFieldObject (
339433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *ObjDesc,
340433d6423SLionel Sambuc     UINT8                   FieldFlags,
341433d6423SLionel Sambuc     UINT8                   FieldAttribute,
342433d6423SLionel Sambuc     UINT32                  FieldBitPosition,
343433d6423SLionel Sambuc     UINT32                  FieldBitLength)
344433d6423SLionel Sambuc {
345433d6423SLionel Sambuc     UINT32                  AccessBitWidth;
346433d6423SLionel Sambuc     UINT32                  ByteAlignment;
347433d6423SLionel Sambuc     UINT32                  NearestByteAddress;
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (ExPrepCommonFieldObject);
351433d6423SLionel Sambuc 
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc     /*
354433d6423SLionel Sambuc      * Note: the structure being initialized is the
355433d6423SLionel Sambuc      * ACPI_COMMON_FIELD_INFO;  No structure fields outside of the common
356433d6423SLionel Sambuc      * area are initialized by this procedure.
357433d6423SLionel Sambuc      */
358433d6423SLionel Sambuc     ObjDesc->CommonField.FieldFlags = FieldFlags;
359433d6423SLionel Sambuc     ObjDesc->CommonField.Attribute  = FieldAttribute;
360433d6423SLionel Sambuc     ObjDesc->CommonField.BitLength  = FieldBitLength;
361433d6423SLionel Sambuc 
362433d6423SLionel Sambuc     /*
363433d6423SLionel Sambuc      * Decode the access type so we can compute offsets. The access type gives
364433d6423SLionel Sambuc      * two pieces of information - the width of each field access and the
365433d6423SLionel Sambuc      * necessary ByteAlignment (address granularity) of the access.
366433d6423SLionel Sambuc      *
367433d6423SLionel Sambuc      * For AnyAcc, the AccessBitWidth is the largest width that is both
368433d6423SLionel Sambuc      * necessary and possible in an attempt to access the whole field in one
369433d6423SLionel Sambuc      * I/O operation. However, for AnyAcc, the ByteAlignment is always one
370433d6423SLionel Sambuc      * byte.
371433d6423SLionel Sambuc      *
372433d6423SLionel Sambuc      * For all Buffer Fields, the ByteAlignment is always one byte.
373433d6423SLionel Sambuc      *
374433d6423SLionel Sambuc      * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is
375433d6423SLionel Sambuc      * the same (equivalent) as the ByteAlignment.
376433d6423SLionel Sambuc      */
377433d6423SLionel Sambuc     AccessBitWidth = AcpiExDecodeFieldAccess (ObjDesc, FieldFlags,
378433d6423SLionel Sambuc                         &ByteAlignment);
379433d6423SLionel Sambuc     if (!AccessBitWidth)
380433d6423SLionel Sambuc     {
381433d6423SLionel Sambuc         return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
382433d6423SLionel Sambuc     }
383433d6423SLionel Sambuc 
384*29492bb7SDavid van Moolenbroek     /* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */
385433d6423SLionel Sambuc 
386433d6423SLionel Sambuc     ObjDesc->CommonField.AccessByteWidth = (UINT8)
387*29492bb7SDavid van Moolenbroek         ACPI_DIV_8 (AccessBitWidth);
388433d6423SLionel Sambuc 
389433d6423SLionel Sambuc     /*
390433d6423SLionel Sambuc      * BaseByteOffset is the address of the start of the field within the
391433d6423SLionel Sambuc      * region. It is the byte address of the first *datum* (field-width data
392433d6423SLionel Sambuc      * unit) of the field. (i.e., the first datum that contains at least the
393433d6423SLionel Sambuc      * first *bit* of the field.)
394433d6423SLionel Sambuc      *
395433d6423SLionel Sambuc      * Note: ByteAlignment is always either equal to the AccessBitWidth or 8
396433d6423SLionel Sambuc      * (Byte access), and it defines the addressing granularity of the parent
397433d6423SLionel Sambuc      * region or buffer.
398433d6423SLionel Sambuc      */
399433d6423SLionel Sambuc     NearestByteAddress =
400433d6423SLionel Sambuc         ACPI_ROUND_BITS_DOWN_TO_BYTES (FieldBitPosition);
401433d6423SLionel Sambuc     ObjDesc->CommonField.BaseByteOffset = (UINT32)
402433d6423SLionel Sambuc         ACPI_ROUND_DOWN (NearestByteAddress, ByteAlignment);
403433d6423SLionel Sambuc 
404433d6423SLionel Sambuc     /*
405433d6423SLionel Sambuc      * StartFieldBitOffset is the offset of the first bit of the field within
406433d6423SLionel Sambuc      * a field datum.
407433d6423SLionel Sambuc      */
408433d6423SLionel Sambuc     ObjDesc->CommonField.StartFieldBitOffset = (UINT8)
409433d6423SLionel Sambuc         (FieldBitPosition - ACPI_MUL_8 (ObjDesc->CommonField.BaseByteOffset));
410433d6423SLionel Sambuc 
411433d6423SLionel Sambuc     return_ACPI_STATUS (AE_OK);
412433d6423SLionel Sambuc }
413433d6423SLionel Sambuc 
414433d6423SLionel Sambuc 
415433d6423SLionel Sambuc /*******************************************************************************
416433d6423SLionel Sambuc  *
417433d6423SLionel Sambuc  * FUNCTION:    AcpiExPrepFieldValue
418433d6423SLionel Sambuc  *
419433d6423SLionel Sambuc  * PARAMETERS:  Info    - Contains all field creation info
420433d6423SLionel Sambuc  *
421433d6423SLionel Sambuc  * RETURN:      Status
422433d6423SLionel Sambuc  *
423*29492bb7SDavid van Moolenbroek  * DESCRIPTION: Construct an object of type ACPI_OPERAND_OBJECT with a
424*29492bb7SDavid van Moolenbroek  *              subtype of DefField and connect it to the parent Node.
425433d6423SLionel Sambuc  *
426433d6423SLionel Sambuc  ******************************************************************************/
427433d6423SLionel Sambuc 
428433d6423SLionel Sambuc ACPI_STATUS
AcpiExPrepFieldValue(ACPI_CREATE_FIELD_INFO * Info)429433d6423SLionel Sambuc AcpiExPrepFieldValue (
430433d6423SLionel Sambuc     ACPI_CREATE_FIELD_INFO  *Info)
431433d6423SLionel Sambuc {
432433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *ObjDesc;
433433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *SecondDesc = NULL;
434433d6423SLionel Sambuc     ACPI_STATUS             Status;
435*29492bb7SDavid van Moolenbroek     UINT32                  AccessByteWidth;
436*29492bb7SDavid van Moolenbroek     UINT32                  Type;
437433d6423SLionel Sambuc 
438433d6423SLionel Sambuc 
439433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (ExPrepFieldValue);
440433d6423SLionel Sambuc 
441433d6423SLionel Sambuc 
442433d6423SLionel Sambuc     /* Parameter validation */
443433d6423SLionel Sambuc 
444433d6423SLionel Sambuc     if (Info->FieldType != ACPI_TYPE_LOCAL_INDEX_FIELD)
445433d6423SLionel Sambuc     {
446433d6423SLionel Sambuc         if (!Info->RegionNode)
447433d6423SLionel Sambuc         {
448433d6423SLionel Sambuc             ACPI_ERROR ((AE_INFO, "Null RegionNode"));
449433d6423SLionel Sambuc             return_ACPI_STATUS (AE_AML_NO_OPERAND);
450433d6423SLionel Sambuc         }
451433d6423SLionel Sambuc 
452433d6423SLionel Sambuc         Type = AcpiNsGetType (Info->RegionNode);
453433d6423SLionel Sambuc         if (Type != ACPI_TYPE_REGION)
454433d6423SLionel Sambuc         {
455*29492bb7SDavid van Moolenbroek             ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
456433d6423SLionel Sambuc                 Type, AcpiUtGetTypeName (Type)));
457433d6423SLionel Sambuc 
458433d6423SLionel Sambuc             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
459433d6423SLionel Sambuc         }
460433d6423SLionel Sambuc     }
461433d6423SLionel Sambuc 
462433d6423SLionel Sambuc     /* Allocate a new field object */
463433d6423SLionel Sambuc 
464433d6423SLionel Sambuc     ObjDesc = AcpiUtCreateInternalObject (Info->FieldType);
465433d6423SLionel Sambuc     if (!ObjDesc)
466433d6423SLionel Sambuc     {
467433d6423SLionel Sambuc         return_ACPI_STATUS (AE_NO_MEMORY);
468433d6423SLionel Sambuc     }
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc     /* Initialize areas of the object that are common to all fields */
471433d6423SLionel Sambuc 
472433d6423SLionel Sambuc     ObjDesc->CommonField.Node = Info->FieldNode;
473*29492bb7SDavid van Moolenbroek     Status = AcpiExPrepCommonFieldObject (ObjDesc,
474*29492bb7SDavid van Moolenbroek                 Info->FieldFlags, Info->Attribute,
475*29492bb7SDavid van Moolenbroek                 Info->FieldBitPosition, Info->FieldBitLength);
476433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
477433d6423SLionel Sambuc     {
478433d6423SLionel Sambuc         AcpiUtDeleteObjectDesc (ObjDesc);
479433d6423SLionel Sambuc         return_ACPI_STATUS (Status);
480433d6423SLionel Sambuc     }
481433d6423SLionel Sambuc 
482433d6423SLionel Sambuc     /* Initialize areas of the object that are specific to the field type */
483433d6423SLionel Sambuc 
484433d6423SLionel Sambuc     switch (Info->FieldType)
485433d6423SLionel Sambuc     {
486433d6423SLionel Sambuc     case ACPI_TYPE_LOCAL_REGION_FIELD:
487433d6423SLionel Sambuc 
488433d6423SLionel Sambuc         ObjDesc->Field.RegionObj = AcpiNsGetAttachedObject (Info->RegionNode);
489433d6423SLionel Sambuc 
490*29492bb7SDavid van Moolenbroek         /* Fields specific to GenericSerialBus fields */
491*29492bb7SDavid van Moolenbroek 
492*29492bb7SDavid van Moolenbroek         ObjDesc->Field.AccessLength = Info->AccessLength;
493*29492bb7SDavid van Moolenbroek 
494*29492bb7SDavid van Moolenbroek         if (Info->ConnectionNode)
495*29492bb7SDavid van Moolenbroek         {
496*29492bb7SDavid van Moolenbroek             SecondDesc = Info->ConnectionNode->Object;
497*29492bb7SDavid van Moolenbroek             if (!(SecondDesc->Common.Flags & AOPOBJ_DATA_VALID))
498*29492bb7SDavid van Moolenbroek             {
499*29492bb7SDavid van Moolenbroek                 Status = AcpiDsGetBufferArguments (SecondDesc);
500*29492bb7SDavid van Moolenbroek                 if (ACPI_FAILURE (Status))
501*29492bb7SDavid van Moolenbroek                 {
502*29492bb7SDavid van Moolenbroek                     AcpiUtDeleteObjectDesc (ObjDesc);
503*29492bb7SDavid van Moolenbroek                     return_ACPI_STATUS (Status);
504*29492bb7SDavid van Moolenbroek                 }
505*29492bb7SDavid van Moolenbroek             }
506*29492bb7SDavid van Moolenbroek 
507*29492bb7SDavid van Moolenbroek             ObjDesc->Field.ResourceBuffer = SecondDesc->Buffer.Pointer;
508*29492bb7SDavid van Moolenbroek             ObjDesc->Field.ResourceLength = (UINT16) SecondDesc->Buffer.Length;
509*29492bb7SDavid van Moolenbroek         }
510*29492bb7SDavid van Moolenbroek         else if (Info->ResourceBuffer)
511*29492bb7SDavid van Moolenbroek         {
512*29492bb7SDavid van Moolenbroek             ObjDesc->Field.ResourceBuffer = Info->ResourceBuffer;
513*29492bb7SDavid van Moolenbroek             ObjDesc->Field.ResourceLength = Info->ResourceLength;
514*29492bb7SDavid van Moolenbroek         }
515*29492bb7SDavid van Moolenbroek 
516*29492bb7SDavid van Moolenbroek         ObjDesc->Field.PinNumberIndex = Info->PinNumberIndex;
517*29492bb7SDavid van Moolenbroek 
518*29492bb7SDavid van Moolenbroek         /* Allow full data read from EC address space */
519*29492bb7SDavid van Moolenbroek 
520*29492bb7SDavid van Moolenbroek         if ((ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_EC) &&
521*29492bb7SDavid van Moolenbroek             (ObjDesc->CommonField.BitLength > 8))
522*29492bb7SDavid van Moolenbroek         {
523*29492bb7SDavid van Moolenbroek             AccessByteWidth = ACPI_ROUND_BITS_UP_TO_BYTES (
524*29492bb7SDavid van Moolenbroek                 ObjDesc->CommonField.BitLength);
525*29492bb7SDavid van Moolenbroek 
526*29492bb7SDavid van Moolenbroek             /* Maximum byte width supported is 255 */
527*29492bb7SDavid van Moolenbroek 
528*29492bb7SDavid van Moolenbroek             if (AccessByteWidth < 256)
529*29492bb7SDavid van Moolenbroek             {
530*29492bb7SDavid van Moolenbroek                 ObjDesc->CommonField.AccessByteWidth = (UINT8) AccessByteWidth;
531*29492bb7SDavid van Moolenbroek             }
532*29492bb7SDavid van Moolenbroek         }
533*29492bb7SDavid van Moolenbroek 
534433d6423SLionel Sambuc         /* An additional reference for the container */
535433d6423SLionel Sambuc 
536433d6423SLionel Sambuc         AcpiUtAddReference (ObjDesc->Field.RegionObj);
537433d6423SLionel Sambuc 
538433d6423SLionel Sambuc         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
539433d6423SLionel Sambuc             "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
540433d6423SLionel Sambuc             ObjDesc->Field.StartFieldBitOffset, ObjDesc->Field.BaseByteOffset,
541433d6423SLionel Sambuc             ObjDesc->Field.AccessByteWidth, ObjDesc->Field.RegionObj));
542433d6423SLionel Sambuc         break;
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc     case ACPI_TYPE_LOCAL_BANK_FIELD:
545433d6423SLionel Sambuc 
546433d6423SLionel Sambuc         ObjDesc->BankField.Value = Info->BankValue;
547*29492bb7SDavid van Moolenbroek         ObjDesc->BankField.RegionObj =
548*29492bb7SDavid van Moolenbroek             AcpiNsGetAttachedObject (Info->RegionNode);
549*29492bb7SDavid van Moolenbroek         ObjDesc->BankField.BankObj =
550*29492bb7SDavid van Moolenbroek             AcpiNsGetAttachedObject (Info->RegisterNode);
551433d6423SLionel Sambuc 
552433d6423SLionel Sambuc         /* An additional reference for the attached objects */
553433d6423SLionel Sambuc 
554433d6423SLionel Sambuc         AcpiUtAddReference (ObjDesc->BankField.RegionObj);
555433d6423SLionel Sambuc         AcpiUtAddReference (ObjDesc->BankField.BankObj);
556433d6423SLionel Sambuc 
557433d6423SLionel Sambuc         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
558433d6423SLionel Sambuc             "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
559433d6423SLionel Sambuc             ObjDesc->BankField.StartFieldBitOffset,
560433d6423SLionel Sambuc             ObjDesc->BankField.BaseByteOffset,
561433d6423SLionel Sambuc             ObjDesc->Field.AccessByteWidth,
562433d6423SLionel Sambuc             ObjDesc->BankField.RegionObj,
563433d6423SLionel Sambuc             ObjDesc->BankField.BankObj));
564433d6423SLionel Sambuc 
565433d6423SLionel Sambuc         /*
566433d6423SLionel Sambuc          * Remember location in AML stream of the field unit
567433d6423SLionel Sambuc          * opcode and operands -- since the BankValue
568433d6423SLionel Sambuc          * operands must be evaluated.
569433d6423SLionel Sambuc          */
570433d6423SLionel Sambuc         SecondDesc = ObjDesc->Common.NextObject;
571*29492bb7SDavid van Moolenbroek         SecondDesc->Extra.AmlStart = ACPI_CAST_PTR (ACPI_PARSE_OBJECT,
572*29492bb7SDavid van Moolenbroek             Info->DataRegisterNode)->Named.Data;
573*29492bb7SDavid van Moolenbroek         SecondDesc->Extra.AmlLength = ACPI_CAST_PTR (ACPI_PARSE_OBJECT,
574*29492bb7SDavid van Moolenbroek             Info->DataRegisterNode)->Named.Length;
575433d6423SLionel Sambuc 
576433d6423SLionel Sambuc         break;
577433d6423SLionel Sambuc 
578433d6423SLionel Sambuc     case ACPI_TYPE_LOCAL_INDEX_FIELD:
579433d6423SLionel Sambuc 
580433d6423SLionel Sambuc         /* Get the Index and Data registers */
581433d6423SLionel Sambuc 
582*29492bb7SDavid van Moolenbroek         ObjDesc->IndexField.IndexObj =
583*29492bb7SDavid van Moolenbroek             AcpiNsGetAttachedObject (Info->RegisterNode);
584*29492bb7SDavid van Moolenbroek         ObjDesc->IndexField.DataObj =
585*29492bb7SDavid van Moolenbroek             AcpiNsGetAttachedObject (Info->DataRegisterNode);
586433d6423SLionel Sambuc 
587433d6423SLionel Sambuc         if (!ObjDesc->IndexField.DataObj || !ObjDesc->IndexField.IndexObj)
588433d6423SLionel Sambuc         {
589433d6423SLionel Sambuc             ACPI_ERROR ((AE_INFO, "Null Index Object during field prep"));
590433d6423SLionel Sambuc             AcpiUtDeleteObjectDesc (ObjDesc);
591433d6423SLionel Sambuc             return_ACPI_STATUS (AE_AML_INTERNAL);
592433d6423SLionel Sambuc         }
593433d6423SLionel Sambuc 
594433d6423SLionel Sambuc         /* An additional reference for the attached objects */
595433d6423SLionel Sambuc 
596433d6423SLionel Sambuc         AcpiUtAddReference (ObjDesc->IndexField.DataObj);
597433d6423SLionel Sambuc         AcpiUtAddReference (ObjDesc->IndexField.IndexObj);
598433d6423SLionel Sambuc 
599433d6423SLionel Sambuc         /*
600433d6423SLionel Sambuc          * April 2006: Changed to match MS behavior
601433d6423SLionel Sambuc          *
602433d6423SLionel Sambuc          * The value written to the Index register is the byte offset of the
603433d6423SLionel Sambuc          * target field in units of the granularity of the IndexField
604433d6423SLionel Sambuc          *
605433d6423SLionel Sambuc          * Previously, the value was calculated as an index in terms of the
606433d6423SLionel Sambuc          * width of the Data register, as below:
607433d6423SLionel Sambuc          *
608433d6423SLionel Sambuc          *      ObjDesc->IndexField.Value = (UINT32)
609433d6423SLionel Sambuc          *          (Info->FieldBitPosition / ACPI_MUL_8 (
610433d6423SLionel Sambuc          *              ObjDesc->Field.AccessByteWidth));
611433d6423SLionel Sambuc          *
612433d6423SLionel Sambuc          * February 2006: Tried value as a byte offset:
613433d6423SLionel Sambuc          *      ObjDesc->IndexField.Value = (UINT32)
614433d6423SLionel Sambuc          *          ACPI_DIV_8 (Info->FieldBitPosition);
615433d6423SLionel Sambuc          */
616433d6423SLionel Sambuc         ObjDesc->IndexField.Value = (UINT32) ACPI_ROUND_DOWN (
617433d6423SLionel Sambuc             ACPI_DIV_8 (Info->FieldBitPosition),
618433d6423SLionel Sambuc             ObjDesc->IndexField.AccessByteWidth);
619433d6423SLionel Sambuc 
620433d6423SLionel Sambuc         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
621433d6423SLionel Sambuc             "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
622433d6423SLionel Sambuc             ObjDesc->IndexField.StartFieldBitOffset,
623433d6423SLionel Sambuc             ObjDesc->IndexField.BaseByteOffset,
624433d6423SLionel Sambuc             ObjDesc->IndexField.Value,
625433d6423SLionel Sambuc             ObjDesc->Field.AccessByteWidth,
626433d6423SLionel Sambuc             ObjDesc->IndexField.IndexObj,
627433d6423SLionel Sambuc             ObjDesc->IndexField.DataObj));
628433d6423SLionel Sambuc         break;
629433d6423SLionel Sambuc 
630433d6423SLionel Sambuc     default:
631*29492bb7SDavid van Moolenbroek 
632433d6423SLionel Sambuc         /* No other types should get here */
633*29492bb7SDavid van Moolenbroek 
634433d6423SLionel Sambuc         break;
635433d6423SLionel Sambuc     }
636433d6423SLionel Sambuc 
637433d6423SLionel Sambuc     /*
638433d6423SLionel Sambuc      * Store the constructed descriptor (ObjDesc) into the parent Node,
639433d6423SLionel Sambuc      * preserving the current type of that NamedObj.
640433d6423SLionel Sambuc      */
641433d6423SLionel Sambuc     Status = AcpiNsAttachObject (Info->FieldNode, ObjDesc,
642433d6423SLionel Sambuc                 AcpiNsGetType (Info->FieldNode));
643433d6423SLionel Sambuc 
644433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n",
645433d6423SLionel Sambuc         Info->FieldNode, AcpiUtGetNodeName (Info->FieldNode), ObjDesc));
646433d6423SLionel Sambuc 
647433d6423SLionel Sambuc     /* Remove local reference to the object */
648433d6423SLionel Sambuc 
649433d6423SLionel Sambuc     AcpiUtRemoveReference (ObjDesc);
650433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
651433d6423SLionel Sambuc }
652