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