xref: /titanic_52/usr/src/uts/intel/io/acpica/executer/exfield.c (revision 385cc6b4ad1792caef3f84eb61eed3f27085801f)
1db2bae30SDana Myers /******************************************************************************
2db2bae30SDana Myers  *
3db2bae30SDana Myers  * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
4db2bae30SDana Myers  *
5db2bae30SDana Myers  *****************************************************************************/
6db2bae30SDana Myers 
726f3cdf0SGordon Ross /*
8*385cc6b4SJerry Jelinek  * Copyright (C) 2000 - 2016, Intel Corp.
9db2bae30SDana Myers  * All rights reserved.
10db2bae30SDana Myers  *
1126f3cdf0SGordon Ross  * Redistribution and use in source and binary forms, with or without
1226f3cdf0SGordon Ross  * modification, are permitted provided that the following conditions
1326f3cdf0SGordon Ross  * are met:
1426f3cdf0SGordon Ross  * 1. Redistributions of source code must retain the above copyright
1526f3cdf0SGordon Ross  *    notice, this list of conditions, and the following disclaimer,
1626f3cdf0SGordon Ross  *    without modification.
1726f3cdf0SGordon Ross  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1826f3cdf0SGordon Ross  *    substantially similar to the "NO WARRANTY" disclaimer below
1926f3cdf0SGordon Ross  *    ("Disclaimer") and any redistribution must be conditioned upon
2026f3cdf0SGordon Ross  *    including a substantially similar Disclaimer requirement for further
2126f3cdf0SGordon Ross  *    binary redistribution.
2226f3cdf0SGordon Ross  * 3. Neither the names of the above-listed copyright holders nor the names
2326f3cdf0SGordon Ross  *    of any contributors may be used to endorse or promote products derived
2426f3cdf0SGordon Ross  *    from this software without specific prior written permission.
25db2bae30SDana Myers  *
2626f3cdf0SGordon Ross  * Alternatively, this software may be distributed under the terms of the
2726f3cdf0SGordon Ross  * GNU General Public License ("GPL") version 2 as published by the Free
2826f3cdf0SGordon Ross  * Software Foundation.
29db2bae30SDana Myers  *
3026f3cdf0SGordon Ross  * NO WARRANTY
3126f3cdf0SGordon Ross  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3226f3cdf0SGordon Ross  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3326f3cdf0SGordon Ross  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3426f3cdf0SGordon Ross  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3526f3cdf0SGordon Ross  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3626f3cdf0SGordon Ross  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3726f3cdf0SGordon Ross  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3826f3cdf0SGordon Ross  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3926f3cdf0SGordon Ross  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4026f3cdf0SGordon Ross  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4126f3cdf0SGordon Ross  * POSSIBILITY OF SUCH DAMAGES.
4226f3cdf0SGordon Ross  */
43db2bae30SDana Myers 
44db2bae30SDana Myers #include "acpi.h"
45aa2aa9a6SDana Myers #include "accommon.h"
46db2bae30SDana Myers #include "acdispat.h"
47db2bae30SDana Myers #include "acinterp.h"
48*385cc6b4SJerry Jelinek #include "amlcode.h"
49db2bae30SDana Myers 
50db2bae30SDana Myers 
51db2bae30SDana Myers #define _COMPONENT          ACPI_EXECUTER
52db2bae30SDana Myers         ACPI_MODULE_NAME    ("exfield")
53db2bae30SDana Myers 
54*385cc6b4SJerry Jelinek /* Local prototypes */
55*385cc6b4SJerry Jelinek 
56*385cc6b4SJerry Jelinek static UINT32
57*385cc6b4SJerry Jelinek AcpiExGetSerialAccessLength (
58*385cc6b4SJerry Jelinek     UINT32                  AccessorType,
59*385cc6b4SJerry Jelinek     UINT32                  AccessLength);
60*385cc6b4SJerry Jelinek 
61*385cc6b4SJerry Jelinek 
62*385cc6b4SJerry Jelinek /*******************************************************************************
63*385cc6b4SJerry Jelinek  *
64*385cc6b4SJerry Jelinek  * FUNCTION:    AcpiExGetSerialAccessLength
65*385cc6b4SJerry Jelinek  *
66*385cc6b4SJerry Jelinek  * PARAMETERS:  AccessorType    - The type of the protocol indicated by region
67*385cc6b4SJerry Jelinek  *                                field access attributes
68*385cc6b4SJerry Jelinek  *              AccessLength    - The access length of the region field
69*385cc6b4SJerry Jelinek  *
70*385cc6b4SJerry Jelinek  * RETURN:      Decoded access length
71*385cc6b4SJerry Jelinek  *
72*385cc6b4SJerry Jelinek  * DESCRIPTION: This routine returns the length of the GenericSerialBus
73*385cc6b4SJerry Jelinek  *              protocol bytes
74*385cc6b4SJerry Jelinek  *
75*385cc6b4SJerry Jelinek  ******************************************************************************/
76*385cc6b4SJerry Jelinek 
77*385cc6b4SJerry Jelinek static UINT32
78*385cc6b4SJerry Jelinek AcpiExGetSerialAccessLength (
79*385cc6b4SJerry Jelinek     UINT32                  AccessorType,
80*385cc6b4SJerry Jelinek     UINT32                  AccessLength)
81*385cc6b4SJerry Jelinek {
82*385cc6b4SJerry Jelinek     UINT32                  Length;
83*385cc6b4SJerry Jelinek 
84*385cc6b4SJerry Jelinek 
85*385cc6b4SJerry Jelinek     switch (AccessorType)
86*385cc6b4SJerry Jelinek     {
87*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_QUICK:
88*385cc6b4SJerry Jelinek 
89*385cc6b4SJerry Jelinek         Length = 0;
90*385cc6b4SJerry Jelinek         break;
91*385cc6b4SJerry Jelinek 
92*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_SEND_RCV:
93*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_BYTE:
94*385cc6b4SJerry Jelinek 
95*385cc6b4SJerry Jelinek         Length = 1;
96*385cc6b4SJerry Jelinek         break;
97*385cc6b4SJerry Jelinek 
98*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_WORD:
99*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_WORD_CALL:
100*385cc6b4SJerry Jelinek 
101*385cc6b4SJerry Jelinek         Length = 2;
102*385cc6b4SJerry Jelinek         break;
103*385cc6b4SJerry Jelinek 
104*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_MULTIBYTE:
105*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_RAW_BYTES:
106*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_RAW_PROCESS:
107*385cc6b4SJerry Jelinek 
108*385cc6b4SJerry Jelinek         Length = AccessLength;
109*385cc6b4SJerry Jelinek         break;
110*385cc6b4SJerry Jelinek 
111*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_BLOCK:
112*385cc6b4SJerry Jelinek     case AML_FIELD_ATTRIB_BLOCK_CALL:
113*385cc6b4SJerry Jelinek     default:
114*385cc6b4SJerry Jelinek 
115*385cc6b4SJerry Jelinek         Length = ACPI_GSBUS_BUFFER_SIZE - 2;
116*385cc6b4SJerry Jelinek         break;
117*385cc6b4SJerry Jelinek     }
118*385cc6b4SJerry Jelinek 
119*385cc6b4SJerry Jelinek     return (Length);
120*385cc6b4SJerry Jelinek }
121*385cc6b4SJerry Jelinek 
122db2bae30SDana Myers 
123db2bae30SDana Myers /*******************************************************************************
124db2bae30SDana Myers  *
125db2bae30SDana Myers  * FUNCTION:    AcpiExReadDataFromField
126db2bae30SDana Myers  *
127db2bae30SDana Myers  * PARAMETERS:  WalkState           - Current execution state
128db2bae30SDana Myers  *              ObjDesc             - The named field
129db2bae30SDana Myers  *              RetBufferDesc       - Where the return data object is stored
130db2bae30SDana Myers  *
131db2bae30SDana Myers  * RETURN:      Status
132db2bae30SDana Myers  *
133db2bae30SDana Myers  * DESCRIPTION: Read from a named field. Returns either an Integer or a
134db2bae30SDana Myers  *              Buffer, depending on the size of the field.
135db2bae30SDana Myers  *
136db2bae30SDana Myers  ******************************************************************************/
137db2bae30SDana Myers 
138db2bae30SDana Myers ACPI_STATUS
139db2bae30SDana Myers AcpiExReadDataFromField (
140db2bae30SDana Myers     ACPI_WALK_STATE         *WalkState,
141db2bae30SDana Myers     ACPI_OPERAND_OBJECT     *ObjDesc,
142db2bae30SDana Myers     ACPI_OPERAND_OBJECT     **RetBufferDesc)
143db2bae30SDana Myers {
144db2bae30SDana Myers     ACPI_STATUS             Status;
145db2bae30SDana Myers     ACPI_OPERAND_OBJECT     *BufferDesc;
146db2bae30SDana Myers     ACPI_SIZE               Length;
147db2bae30SDana Myers     void                    *Buffer;
14857190917SDana Myers     UINT32                  Function;
149*385cc6b4SJerry Jelinek     UINT16                  AccessorType;
150db2bae30SDana Myers 
151db2bae30SDana Myers 
152db2bae30SDana Myers     ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
153db2bae30SDana Myers 
154db2bae30SDana Myers 
155db2bae30SDana Myers     /* Parameter validation */
156db2bae30SDana Myers 
157db2bae30SDana Myers     if (!ObjDesc)
158db2bae30SDana Myers     {
159db2bae30SDana Myers         return_ACPI_STATUS (AE_AML_NO_OPERAND);
160db2bae30SDana Myers     }
161db2bae30SDana Myers     if (!RetBufferDesc)
162db2bae30SDana Myers     {
163db2bae30SDana Myers         return_ACPI_STATUS (AE_BAD_PARAMETER);
164db2bae30SDana Myers     }
165db2bae30SDana Myers 
166aa2aa9a6SDana Myers     if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
167db2bae30SDana Myers     {
168db2bae30SDana Myers         /*
169db2bae30SDana Myers          * If the BufferField arguments have not been previously evaluated,
170db2bae30SDana Myers          * evaluate them now and save the results.
171db2bae30SDana Myers          */
172db2bae30SDana Myers         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
173db2bae30SDana Myers         {
174db2bae30SDana Myers             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
175db2bae30SDana Myers             if (ACPI_FAILURE (Status))
176db2bae30SDana Myers             {
177db2bae30SDana Myers                 return_ACPI_STATUS (Status);
178db2bae30SDana Myers             }
179db2bae30SDana Myers         }
180db2bae30SDana Myers     }
181aa2aa9a6SDana Myers     else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
18257190917SDana Myers              (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
183*385cc6b4SJerry Jelinek               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
18457190917SDana Myers               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
185db2bae30SDana Myers     {
186db2bae30SDana Myers         /*
187*385cc6b4SJerry Jelinek          * This is an SMBus, GSBus or IPMI read. We must create a buffer to
188*385cc6b4SJerry Jelinek          * hold the data and then directly access the region handler.
18957190917SDana Myers          *
190*385cc6b4SJerry Jelinek          * Note: SMBus and GSBus protocol value is passed in upper 16-bits
191*385cc6b4SJerry Jelinek          * of Function
192db2bae30SDana Myers          */
193*385cc6b4SJerry Jelinek         if (ObjDesc->Field.RegionObj->Region.SpaceId ==
194*385cc6b4SJerry Jelinek             ACPI_ADR_SPACE_SMBUS)
19557190917SDana Myers         {
19657190917SDana Myers             Length = ACPI_SMBUS_BUFFER_SIZE;
19757190917SDana Myers             Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
19857190917SDana Myers         }
199*385cc6b4SJerry Jelinek         else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
200*385cc6b4SJerry Jelinek             ACPI_ADR_SPACE_GSBUS)
201*385cc6b4SJerry Jelinek         {
202*385cc6b4SJerry Jelinek             AccessorType = ObjDesc->Field.Attribute;
203*385cc6b4SJerry Jelinek             Length = AcpiExGetSerialAccessLength (
204*385cc6b4SJerry Jelinek                 AccessorType, ObjDesc->Field.AccessLength);
205*385cc6b4SJerry Jelinek 
206*385cc6b4SJerry Jelinek             /*
207*385cc6b4SJerry Jelinek              * Add additional 2 bytes for the GenericSerialBus data buffer:
208*385cc6b4SJerry Jelinek              *
209*385cc6b4SJerry Jelinek              *     Status;    (Byte 0 of the data buffer)
210*385cc6b4SJerry Jelinek              *     Length;    (Byte 1 of the data buffer)
211*385cc6b4SJerry Jelinek              *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
212*385cc6b4SJerry Jelinek              */
213*385cc6b4SJerry Jelinek             Length += 2;
214*385cc6b4SJerry Jelinek             Function = ACPI_READ | (AccessorType << 16);
215*385cc6b4SJerry Jelinek         }
21657190917SDana Myers         else /* IPMI */
21757190917SDana Myers         {
21857190917SDana Myers             Length = ACPI_IPMI_BUFFER_SIZE;
21957190917SDana Myers             Function = ACPI_READ;
22057190917SDana Myers         }
22157190917SDana Myers 
22257190917SDana Myers         BufferDesc = AcpiUtCreateBufferObject (Length);
223db2bae30SDana Myers         if (!BufferDesc)
224db2bae30SDana Myers         {
225db2bae30SDana Myers             return_ACPI_STATUS (AE_NO_MEMORY);
226db2bae30SDana Myers         }
227db2bae30SDana Myers 
228db2bae30SDana Myers         /* Lock entire transaction if requested */
229db2bae30SDana Myers 
230db2bae30SDana Myers         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
231db2bae30SDana Myers 
23257190917SDana Myers         /* Call the region handler for the read */
23357190917SDana Myers 
234db2bae30SDana Myers         Status = AcpiExAccessRegion (ObjDesc, 0,
235*385cc6b4SJerry Jelinek             ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
236*385cc6b4SJerry Jelinek 
237db2bae30SDana Myers         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
238db2bae30SDana Myers         goto Exit;
239db2bae30SDana Myers     }
240db2bae30SDana Myers 
241db2bae30SDana Myers     /*
242db2bae30SDana Myers      * Allocate a buffer for the contents of the field.
243db2bae30SDana Myers      *
24426f3cdf0SGordon Ross      * If the field is larger than the current integer width, create
245db2bae30SDana Myers      * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
246db2bae30SDana Myers      * the use of arithmetic operators on the returned value if the
247db2bae30SDana Myers      * field size is equal or smaller than an Integer.
248db2bae30SDana Myers      *
249db2bae30SDana Myers      * Note: Field.length is in bits.
250db2bae30SDana Myers      */
251*385cc6b4SJerry Jelinek     Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (
252*385cc6b4SJerry Jelinek         ObjDesc->Field.BitLength);
253*385cc6b4SJerry Jelinek 
254db2bae30SDana Myers     if (Length > AcpiGbl_IntegerByteWidth)
255db2bae30SDana Myers     {
256db2bae30SDana Myers         /* Field is too large for an Integer, create a Buffer instead */
257db2bae30SDana Myers 
258db2bae30SDana Myers         BufferDesc = AcpiUtCreateBufferObject (Length);
259db2bae30SDana Myers         if (!BufferDesc)
260db2bae30SDana Myers         {
261db2bae30SDana Myers             return_ACPI_STATUS (AE_NO_MEMORY);
262db2bae30SDana Myers         }
263db2bae30SDana Myers         Buffer = BufferDesc->Buffer.Pointer;
264db2bae30SDana Myers     }
265db2bae30SDana Myers     else
266db2bae30SDana Myers     {
267db2bae30SDana Myers         /* Field will fit within an Integer (normal case) */
268db2bae30SDana Myers 
26957190917SDana Myers         BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
270db2bae30SDana Myers         if (!BufferDesc)
271db2bae30SDana Myers         {
272db2bae30SDana Myers             return_ACPI_STATUS (AE_NO_MEMORY);
273db2bae30SDana Myers         }
274db2bae30SDana Myers 
275db2bae30SDana Myers         Length = AcpiGbl_IntegerByteWidth;
276db2bae30SDana Myers         Buffer = &BufferDesc->Integer.Value;
277db2bae30SDana Myers     }
278db2bae30SDana Myers 
279*385cc6b4SJerry Jelinek     if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
280*385cc6b4SJerry Jelinek         (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
281*385cc6b4SJerry Jelinek     {
282*385cc6b4SJerry Jelinek         /*
283*385cc6b4SJerry Jelinek          * For GPIO (GeneralPurposeIo), the Address will be the bit offset
284*385cc6b4SJerry Jelinek          * from the previous Connection() operator, making it effectively a
285*385cc6b4SJerry Jelinek          * pin number index. The BitLength is the length of the field, which
286*385cc6b4SJerry Jelinek          * is thus the number of pins.
287*385cc6b4SJerry Jelinek          */
288*385cc6b4SJerry Jelinek         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
289*385cc6b4SJerry Jelinek             "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
290*385cc6b4SJerry Jelinek             ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
291*385cc6b4SJerry Jelinek 
292*385cc6b4SJerry Jelinek         /* Lock entire transaction if requested */
293*385cc6b4SJerry Jelinek 
294*385cc6b4SJerry Jelinek         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
295*385cc6b4SJerry Jelinek 
296*385cc6b4SJerry Jelinek         /* Perform the write */
297*385cc6b4SJerry Jelinek 
298*385cc6b4SJerry Jelinek         Status = AcpiExAccessRegion (
299*385cc6b4SJerry Jelinek             ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ);
300*385cc6b4SJerry Jelinek 
301*385cc6b4SJerry Jelinek         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
302*385cc6b4SJerry Jelinek         if (ACPI_FAILURE (Status))
303*385cc6b4SJerry Jelinek         {
304*385cc6b4SJerry Jelinek             AcpiUtRemoveReference (BufferDesc);
305*385cc6b4SJerry Jelinek         }
306*385cc6b4SJerry Jelinek         else
307*385cc6b4SJerry Jelinek         {
308*385cc6b4SJerry Jelinek             *RetBufferDesc = BufferDesc;
309*385cc6b4SJerry Jelinek         }
310*385cc6b4SJerry Jelinek         return_ACPI_STATUS (Status);
311*385cc6b4SJerry Jelinek     }
312*385cc6b4SJerry Jelinek 
313db2bae30SDana Myers     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
314db2bae30SDana Myers         "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
315aa2aa9a6SDana Myers         ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
316db2bae30SDana Myers     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
317db2bae30SDana Myers         "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
318db2bae30SDana Myers         ObjDesc->CommonField.BitLength,
319db2bae30SDana Myers         ObjDesc->CommonField.StartFieldBitOffset,
320db2bae30SDana Myers         ObjDesc->CommonField.BaseByteOffset));
321db2bae30SDana Myers 
322db2bae30SDana Myers     /* Lock entire transaction if requested */
323db2bae30SDana Myers 
324db2bae30SDana Myers     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
325db2bae30SDana Myers 
326db2bae30SDana Myers     /* Read from the field */
327db2bae30SDana Myers 
328db2bae30SDana Myers     Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
329db2bae30SDana Myers     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
330db2bae30SDana Myers 
331db2bae30SDana Myers 
332db2bae30SDana Myers Exit:
333db2bae30SDana Myers     if (ACPI_FAILURE (Status))
334db2bae30SDana Myers     {
335db2bae30SDana Myers         AcpiUtRemoveReference (BufferDesc);
336db2bae30SDana Myers     }
337db2bae30SDana Myers     else
338db2bae30SDana Myers     {
339db2bae30SDana Myers         *RetBufferDesc = BufferDesc;
340db2bae30SDana Myers     }
341db2bae30SDana Myers 
342db2bae30SDana Myers     return_ACPI_STATUS (Status);
343db2bae30SDana Myers }
344db2bae30SDana Myers 
345db2bae30SDana Myers 
346db2bae30SDana Myers /*******************************************************************************
347db2bae30SDana Myers  *
348db2bae30SDana Myers  * FUNCTION:    AcpiExWriteDataToField
349db2bae30SDana Myers  *
350db2bae30SDana Myers  * PARAMETERS:  SourceDesc          - Contains data to write
351db2bae30SDana Myers  *              ObjDesc             - The named field
352db2bae30SDana Myers  *              ResultDesc          - Where the return value is returned, if any
353db2bae30SDana Myers  *
354db2bae30SDana Myers  * RETURN:      Status
355db2bae30SDana Myers  *
356db2bae30SDana Myers  * DESCRIPTION: Write to a named field
357db2bae30SDana Myers  *
358db2bae30SDana Myers  ******************************************************************************/
359db2bae30SDana Myers 
360db2bae30SDana Myers ACPI_STATUS
361db2bae30SDana Myers AcpiExWriteDataToField (
362db2bae30SDana Myers     ACPI_OPERAND_OBJECT     *SourceDesc,
363db2bae30SDana Myers     ACPI_OPERAND_OBJECT     *ObjDesc,
364db2bae30SDana Myers     ACPI_OPERAND_OBJECT     **ResultDesc)
365db2bae30SDana Myers {
366db2bae30SDana Myers     ACPI_STATUS             Status;
367db2bae30SDana Myers     UINT32                  Length;
368db2bae30SDana Myers     void                    *Buffer;
369db2bae30SDana Myers     ACPI_OPERAND_OBJECT     *BufferDesc;
37057190917SDana Myers     UINT32                  Function;
371*385cc6b4SJerry Jelinek     UINT16                  AccessorType;
372db2bae30SDana Myers 
373db2bae30SDana Myers 
374db2bae30SDana Myers     ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
375db2bae30SDana Myers 
376db2bae30SDana Myers 
377db2bae30SDana Myers     /* Parameter validation */
378db2bae30SDana Myers 
379db2bae30SDana Myers     if (!SourceDesc || !ObjDesc)
380db2bae30SDana Myers     {
381db2bae30SDana Myers         return_ACPI_STATUS (AE_AML_NO_OPERAND);
382db2bae30SDana Myers     }
383db2bae30SDana Myers 
384aa2aa9a6SDana Myers     if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
385db2bae30SDana Myers     {
386db2bae30SDana Myers         /*
387db2bae30SDana Myers          * If the BufferField arguments have not been previously evaluated,
388db2bae30SDana Myers          * evaluate them now and save the results.
389db2bae30SDana Myers          */
390db2bae30SDana Myers         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
391db2bae30SDana Myers         {
392db2bae30SDana Myers             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
393db2bae30SDana Myers             if (ACPI_FAILURE (Status))
394db2bae30SDana Myers             {
395db2bae30SDana Myers                 return_ACPI_STATUS (Status);
396db2bae30SDana Myers             }
397db2bae30SDana Myers         }
398db2bae30SDana Myers     }
399aa2aa9a6SDana Myers     else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
40057190917SDana Myers              (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
401*385cc6b4SJerry Jelinek               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
40257190917SDana Myers               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
403db2bae30SDana Myers     {
404db2bae30SDana Myers         /*
405*385cc6b4SJerry Jelinek          * This is an SMBus, GSBus or IPMI write. We will bypass the entire
406*385cc6b4SJerry Jelinek          * field mechanism and handoff the buffer directly to the handler.
407*385cc6b4SJerry Jelinek          * For these address spaces, the buffer is bi-directional; on a
408*385cc6b4SJerry Jelinek          * write, return data is returned in the same buffer.
409db2bae30SDana Myers          *
41057190917SDana Myers          * Source must be a buffer of sufficient size:
411*385cc6b4SJerry Jelinek          * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
412*385cc6b4SJerry Jelinek          * ACPI_IPMI_BUFFER_SIZE.
41357190917SDana Myers          *
414*385cc6b4SJerry Jelinek          * Note: SMBus and GSBus protocol type is passed in upper 16-bits
415*385cc6b4SJerry Jelinek          * of Function
416db2bae30SDana Myers          */
417aa2aa9a6SDana Myers         if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
418db2bae30SDana Myers         {
41957190917SDana Myers             ACPI_ERROR ((AE_INFO,
420*385cc6b4SJerry Jelinek                 "SMBus/IPMI/GenericSerialBus write requires "
421*385cc6b4SJerry Jelinek                 "Buffer, found type %s",
422db2bae30SDana Myers                 AcpiUtGetObjectTypeName (SourceDesc)));
423db2bae30SDana Myers 
424db2bae30SDana Myers             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
425db2bae30SDana Myers         }
426db2bae30SDana Myers 
427*385cc6b4SJerry Jelinek         if (ObjDesc->Field.RegionObj->Region.SpaceId ==
428*385cc6b4SJerry Jelinek             ACPI_ADR_SPACE_SMBUS)
42957190917SDana Myers         {
43057190917SDana Myers             Length = ACPI_SMBUS_BUFFER_SIZE;
43157190917SDana Myers             Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
43257190917SDana Myers         }
433*385cc6b4SJerry Jelinek         else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
434*385cc6b4SJerry Jelinek             ACPI_ADR_SPACE_GSBUS)
435*385cc6b4SJerry Jelinek         {
436*385cc6b4SJerry Jelinek             AccessorType = ObjDesc->Field.Attribute;
437*385cc6b4SJerry Jelinek             Length = AcpiExGetSerialAccessLength (
438*385cc6b4SJerry Jelinek                 AccessorType, ObjDesc->Field.AccessLength);
439*385cc6b4SJerry Jelinek 
440*385cc6b4SJerry Jelinek             /*
441*385cc6b4SJerry Jelinek              * Add additional 2 bytes for the GenericSerialBus data buffer:
442*385cc6b4SJerry Jelinek              *
443*385cc6b4SJerry Jelinek              *     Status;    (Byte 0 of the data buffer)
444*385cc6b4SJerry Jelinek              *     Length;    (Byte 1 of the data buffer)
445*385cc6b4SJerry Jelinek              *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
446*385cc6b4SJerry Jelinek              */
447*385cc6b4SJerry Jelinek             Length += 2;
448*385cc6b4SJerry Jelinek             Function = ACPI_WRITE | (AccessorType << 16);
449*385cc6b4SJerry Jelinek         }
45057190917SDana Myers         else /* IPMI */
45157190917SDana Myers         {
45257190917SDana Myers             Length = ACPI_IPMI_BUFFER_SIZE;
45357190917SDana Myers             Function = ACPI_WRITE;
45457190917SDana Myers         }
45557190917SDana Myers 
45657190917SDana Myers         if (SourceDesc->Buffer.Length < Length)
457db2bae30SDana Myers         {
458db2bae30SDana Myers             ACPI_ERROR ((AE_INFO,
459*385cc6b4SJerry Jelinek                 "SMBus/IPMI/GenericSerialBus write requires "
460*385cc6b4SJerry Jelinek                 "Buffer of length %u, found length %u",
46157190917SDana Myers                 Length, SourceDesc->Buffer.Length));
462db2bae30SDana Myers 
463db2bae30SDana Myers             return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
464db2bae30SDana Myers         }
465db2bae30SDana Myers 
46657190917SDana Myers         /* Create the bi-directional buffer */
46757190917SDana Myers 
46857190917SDana Myers         BufferDesc = AcpiUtCreateBufferObject (Length);
469db2bae30SDana Myers         if (!BufferDesc)
470db2bae30SDana Myers         {
471db2bae30SDana Myers             return_ACPI_STATUS (AE_NO_MEMORY);
472db2bae30SDana Myers         }
473db2bae30SDana Myers 
474db2bae30SDana Myers         Buffer = BufferDesc->Buffer.Pointer;
475*385cc6b4SJerry Jelinek         memcpy (Buffer, SourceDesc->Buffer.Pointer, Length);
476db2bae30SDana Myers 
477db2bae30SDana Myers         /* Lock entire transaction if requested */
478db2bae30SDana Myers 
479db2bae30SDana Myers         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
480db2bae30SDana Myers 
481db2bae30SDana Myers         /*
482db2bae30SDana Myers          * Perform the write (returns status and perhaps data in the
483db2bae30SDana Myers          * same buffer)
484db2bae30SDana Myers          */
485*385cc6b4SJerry Jelinek         Status = AcpiExAccessRegion (
486*385cc6b4SJerry Jelinek             ObjDesc, 0, (UINT64 *) Buffer, Function);
487db2bae30SDana Myers         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
488db2bae30SDana Myers 
489db2bae30SDana Myers         *ResultDesc = BufferDesc;
490db2bae30SDana Myers         return_ACPI_STATUS (Status);
491db2bae30SDana Myers     }
492*385cc6b4SJerry Jelinek     else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
493*385cc6b4SJerry Jelinek              (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
494*385cc6b4SJerry Jelinek     {
495*385cc6b4SJerry Jelinek         /*
496*385cc6b4SJerry Jelinek          * For GPIO (GeneralPurposeIo), we will bypass the entire field
497*385cc6b4SJerry Jelinek          * mechanism and handoff the bit address and bit width directly to
498*385cc6b4SJerry Jelinek          * the handler. The Address will be the bit offset
499*385cc6b4SJerry Jelinek          * from the previous Connection() operator, making it effectively a
500*385cc6b4SJerry Jelinek          * pin number index. The BitLength is the length of the field, which
501*385cc6b4SJerry Jelinek          * is thus the number of pins.
502*385cc6b4SJerry Jelinek          */
503*385cc6b4SJerry Jelinek         if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
504*385cc6b4SJerry Jelinek         {
505*385cc6b4SJerry Jelinek             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
506*385cc6b4SJerry Jelinek         }
507*385cc6b4SJerry Jelinek 
508*385cc6b4SJerry Jelinek         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
509*385cc6b4SJerry Jelinek             "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]: Pin %u Bits %u\n",
510*385cc6b4SJerry Jelinek             AcpiUtGetTypeName (SourceDesc->Common.Type),
511*385cc6b4SJerry Jelinek             SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
512*385cc6b4SJerry Jelinek             ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
513*385cc6b4SJerry Jelinek 
514*385cc6b4SJerry Jelinek         Buffer = &SourceDesc->Integer.Value;
515*385cc6b4SJerry Jelinek 
516*385cc6b4SJerry Jelinek         /* Lock entire transaction if requested */
517*385cc6b4SJerry Jelinek 
518*385cc6b4SJerry Jelinek         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
519*385cc6b4SJerry Jelinek 
520*385cc6b4SJerry Jelinek         /* Perform the write */
521*385cc6b4SJerry Jelinek 
522*385cc6b4SJerry Jelinek         Status = AcpiExAccessRegion (
523*385cc6b4SJerry Jelinek             ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
524*385cc6b4SJerry Jelinek         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
525*385cc6b4SJerry Jelinek         return_ACPI_STATUS (Status);
526*385cc6b4SJerry Jelinek     }
527db2bae30SDana Myers 
528db2bae30SDana Myers     /* Get a pointer to the data to be written */
529db2bae30SDana Myers 
530aa2aa9a6SDana Myers     switch (SourceDesc->Common.Type)
531db2bae30SDana Myers     {
532db2bae30SDana Myers     case ACPI_TYPE_INTEGER:
533*385cc6b4SJerry Jelinek 
534db2bae30SDana Myers         Buffer = &SourceDesc->Integer.Value;
535db2bae30SDana Myers         Length = sizeof (SourceDesc->Integer.Value);
536db2bae30SDana Myers         break;
537db2bae30SDana Myers 
538db2bae30SDana Myers     case ACPI_TYPE_BUFFER:
539*385cc6b4SJerry Jelinek 
540db2bae30SDana Myers         Buffer = SourceDesc->Buffer.Pointer;
541db2bae30SDana Myers         Length = SourceDesc->Buffer.Length;
542db2bae30SDana Myers         break;
543db2bae30SDana Myers 
544db2bae30SDana Myers     case ACPI_TYPE_STRING:
545*385cc6b4SJerry Jelinek 
546db2bae30SDana Myers         Buffer = SourceDesc->String.Pointer;
547db2bae30SDana Myers         Length = SourceDesc->String.Length;
548db2bae30SDana Myers         break;
549db2bae30SDana Myers 
550db2bae30SDana Myers     default:
551*385cc6b4SJerry Jelinek 
552db2bae30SDana Myers         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
553db2bae30SDana Myers     }
554db2bae30SDana Myers 
555db2bae30SDana Myers     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
556db2bae30SDana Myers         "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
557aa2aa9a6SDana Myers         SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
558aa2aa9a6SDana Myers         SourceDesc->Common.Type, Buffer, Length));
559db2bae30SDana Myers 
560db2bae30SDana Myers     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
561db2bae30SDana Myers         "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
562aa2aa9a6SDana Myers         ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
563aa2aa9a6SDana Myers         ObjDesc->Common.Type,
564db2bae30SDana Myers         ObjDesc->CommonField.BitLength,
565db2bae30SDana Myers         ObjDesc->CommonField.StartFieldBitOffset,
566db2bae30SDana Myers         ObjDesc->CommonField.BaseByteOffset));
567db2bae30SDana Myers 
568db2bae30SDana Myers     /* Lock entire transaction if requested */
569db2bae30SDana Myers 
570db2bae30SDana Myers     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
571db2bae30SDana Myers 
572db2bae30SDana Myers     /* Write to the field */
573db2bae30SDana Myers 
574db2bae30SDana Myers     Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
575db2bae30SDana Myers     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
576db2bae30SDana Myers 
577db2bae30SDana Myers     return_ACPI_STATUS (Status);
578db2bae30SDana Myers }
579