exfield.c revision 228110
167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8217365Sjkim * Copyright (C) 2000 - 2011, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
4467754Smsmith
4577424Smsmith#define __EXFIELD_C__
4667754Smsmith
47193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
48193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
49193341Sjkim#include <contrib/dev/acpica/include/acdispat.h>
50193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
5167754Smsmith
5267754Smsmith
5377424Smsmith#define _COMPONENT          ACPI_EXECUTER
5491116Smsmith        ACPI_MODULE_NAME    ("exfield")
5567754Smsmith
5667754Smsmith
5767754Smsmith/*******************************************************************************
5867754Smsmith *
5977424Smsmith * FUNCTION:    AcpiExReadDataFromField
6067754Smsmith *
6199146Siwasaki * PARAMETERS:  WalkState           - Current execution state
6299146Siwasaki *              ObjDesc             - The named field
6387031Smsmith *              RetBufferDesc       - Where the return data object is stored
6467754Smsmith *
6587031Smsmith * RETURN:      Status
6667754Smsmith *
6787031Smsmith * DESCRIPTION: Read from a named field.  Returns either an Integer or a
6887031Smsmith *              Buffer, depending on the size of the field.
6967754Smsmith *
7067754Smsmith ******************************************************************************/
7167754Smsmith
7267754SmsmithACPI_STATUS
7377424SmsmithAcpiExReadDataFromField (
7499146Siwasaki    ACPI_WALK_STATE         *WalkState,
7567754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
7677424Smsmith    ACPI_OPERAND_OBJECT     **RetBufferDesc)
7767754Smsmith{
7877424Smsmith    ACPI_STATUS             Status;
7977424Smsmith    ACPI_OPERAND_OBJECT     *BufferDesc;
80114237Snjl    ACPI_SIZE               Length;
8177424Smsmith    void                    *Buffer;
82197104Sjkim    UINT32                  Function;
8367754Smsmith
8467754Smsmith
85167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
8667754Smsmith
8767754Smsmith
8867754Smsmith    /* Parameter validation */
8967754Smsmith
9077424Smsmith    if (!ObjDesc)
9167754Smsmith    {
9267754Smsmith        return_ACPI_STATUS (AE_AML_NO_OPERAND);
9367754Smsmith    }
94151937Sjkim    if (!RetBufferDesc)
95151937Sjkim    {
96151937Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
97151937Sjkim    }
9867754Smsmith
99193267Sjkim    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
10087031Smsmith    {
10187031Smsmith        /*
10287031Smsmith         * If the BufferField arguments have not been previously evaluated,
10387031Smsmith         * evaluate them now and save the results.
10487031Smsmith         */
10587031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
10687031Smsmith        {
10787031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
10887031Smsmith            if (ACPI_FAILURE (Status))
10987031Smsmith            {
11087031Smsmith                return_ACPI_STATUS (Status);
11187031Smsmith            }
11287031Smsmith        }
11387031Smsmith    }
114193267Sjkim    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
115197104Sjkim             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
116228110Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
117197104Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
118107325Siwasaki    {
119107325Siwasaki        /*
120228110Sjkim         * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
121197104Sjkim         * the data and then directly access the region handler.
122197104Sjkim         *
123228110Sjkim         * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
124107325Siwasaki         */
125197104Sjkim        if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
126197104Sjkim        {
127197104Sjkim            Length = ACPI_SMBUS_BUFFER_SIZE;
128197104Sjkim            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
129197104Sjkim        }
130228110Sjkim        else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
131228110Sjkim        {
132228110Sjkim            Length = ACPI_GSBUS_BUFFER_SIZE;
133228110Sjkim            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
134228110Sjkim        }
135197104Sjkim        else /* IPMI */
136197104Sjkim        {
137197104Sjkim            Length = ACPI_IPMI_BUFFER_SIZE;
138197104Sjkim            Function = ACPI_READ;
139197104Sjkim        }
140197104Sjkim
141197104Sjkim        BufferDesc = AcpiUtCreateBufferObject (Length);
142107325Siwasaki        if (!BufferDesc)
143107325Siwasaki        {
144107325Siwasaki            return_ACPI_STATUS (AE_NO_MEMORY);
145107325Siwasaki        }
14687031Smsmith
147107325Siwasaki        /* Lock entire transaction if requested */
148107325Siwasaki
149167802Sjkim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
150107325Siwasaki
151197104Sjkim        /* Call the region handler for the read */
152197104Sjkim
153114237Snjl        Status = AcpiExAccessRegion (ObjDesc, 0,
154202771Sjkim                    ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
155197104Sjkim                    Function);
156167802Sjkim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
157107325Siwasaki        goto Exit;
158107325Siwasaki    }
159107325Siwasaki
16067754Smsmith    /*
16177424Smsmith     * Allocate a buffer for the contents of the field.
16267754Smsmith     *
163202771Sjkim     * If the field is larger than the current integer width, create
16477424Smsmith     * a BUFFER to hold it.  Otherwise, use an INTEGER.  This allows
16577424Smsmith     * the use of arithmetic operators on the returned value if the
16677424Smsmith     * field size is equal or smaller than an Integer.
16777424Smsmith     *
16877424Smsmith     * Note: Field.length is in bits.
16967754Smsmith     */
170114237Snjl    Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
17199679Siwasaki    if (Length > AcpiGbl_IntegerByteWidth)
17267754Smsmith    {
17377424Smsmith        /* Field is too large for an Integer, create a Buffer instead */
17467754Smsmith
175107325Siwasaki        BufferDesc = AcpiUtCreateBufferObject (Length);
17677424Smsmith        if (!BufferDesc)
17777424Smsmith        {
17877424Smsmith            return_ACPI_STATUS (AE_NO_MEMORY);
17977424Smsmith        }
18077424Smsmith        Buffer = BufferDesc->Buffer.Pointer;
18167754Smsmith    }
18277424Smsmith    else
18377424Smsmith    {
18477424Smsmith        /* Field will fit within an Integer (normal case) */
18567754Smsmith
186199337Sjkim        BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
18777424Smsmith        if (!BufferDesc)
18877424Smsmith        {
18977424Smsmith            return_ACPI_STATUS (AE_NO_MEMORY);
19077424Smsmith        }
19177424Smsmith
19299679Siwasaki        Length = AcpiGbl_IntegerByteWidth;
19377424Smsmith        Buffer = &BufferDesc->Integer.Value;
19467754Smsmith    }
19567754Smsmith
19699146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
197123315Snjl        "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
198193267Sjkim        ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
19999146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
200123315Snjl        "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
20187031Smsmith        ObjDesc->CommonField.BitLength,
20287031Smsmith        ObjDesc->CommonField.StartFieldBitOffset,
20387031Smsmith        ObjDesc->CommonField.BaseByteOffset));
20477424Smsmith
205107325Siwasaki    /* Lock entire transaction if requested */
206107325Siwasaki
207167802Sjkim    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
20877424Smsmith
20987031Smsmith    /* Read from the field */
21067754Smsmith
211114237Snjl    Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
212167802Sjkim    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
21367754Smsmith
214107325Siwasaki
215107325SiwasakiExit:
21677424Smsmith    if (ACPI_FAILURE (Status))
21777424Smsmith    {
21877424Smsmith        AcpiUtRemoveReference (BufferDesc);
21977424Smsmith    }
220151937Sjkim    else
22177424Smsmith    {
22277424Smsmith        *RetBufferDesc = BufferDesc;
22377424Smsmith    }
22477424Smsmith
22577424Smsmith    return_ACPI_STATUS (Status);
22667754Smsmith}
22767754Smsmith
22867754Smsmith
22967754Smsmith/*******************************************************************************
23067754Smsmith *
23177424Smsmith * FUNCTION:    AcpiExWriteDataToField
23267754Smsmith *
23387031Smsmith * PARAMETERS:  SourceDesc          - Contains data to write
23487031Smsmith *              ObjDesc             - The named field
235151937Sjkim *              ResultDesc          - Where the return value is returned, if any
23667754Smsmith *
23767754Smsmith * RETURN:      Status
23867754Smsmith *
23987031Smsmith * DESCRIPTION: Write to a named field
24067754Smsmith *
24167754Smsmith ******************************************************************************/
24267754Smsmith
24367754SmsmithACPI_STATUS
24477424SmsmithAcpiExWriteDataToField (
24577424Smsmith    ACPI_OPERAND_OBJECT     *SourceDesc,
246107325Siwasaki    ACPI_OPERAND_OBJECT     *ObjDesc,
247107325Siwasaki    ACPI_OPERAND_OBJECT     **ResultDesc)
24867754Smsmith{
24977424Smsmith    ACPI_STATUS             Status;
25077424Smsmith    UINT32                  Length;
25177424Smsmith    void                    *Buffer;
252107325Siwasaki    ACPI_OPERAND_OBJECT     *BufferDesc;
253197104Sjkim    UINT32                  Function;
25467754Smsmith
25567754Smsmith
256167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
25767754Smsmith
25867754Smsmith
25971867Smsmith    /* Parameter validation */
26071867Smsmith
26177424Smsmith    if (!SourceDesc || !ObjDesc)
26267754Smsmith    {
26377424Smsmith        return_ACPI_STATUS (AE_AML_NO_OPERAND);
26467754Smsmith    }
26567754Smsmith
266193267Sjkim    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
26787031Smsmith    {
26887031Smsmith        /*
26987031Smsmith         * If the BufferField arguments have not been previously evaluated,
27087031Smsmith         * evaluate them now and save the results.
27187031Smsmith         */
27287031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
27387031Smsmith        {
27487031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
27587031Smsmith            if (ACPI_FAILURE (Status))
27687031Smsmith            {
27787031Smsmith                return_ACPI_STATUS (Status);
27887031Smsmith            }
27987031Smsmith        }
28087031Smsmith    }
281193267Sjkim    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
282197104Sjkim             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
283228110Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
284197104Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
285107325Siwasaki    {
286107325Siwasaki        /*
287228110Sjkim         * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
288197104Sjkim         * mechanism and handoff the buffer directly to the handler. For
289197104Sjkim         * these address spaces, the buffer is bi-directional; on a write,
290197104Sjkim         * return data is returned in the same buffer.
291107325Siwasaki         *
292197104Sjkim         * Source must be a buffer of sufficient size:
293228110Sjkim         * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
294197104Sjkim         *
295228110Sjkim         * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
296107325Siwasaki         */
297193267Sjkim        if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
298107325Siwasaki        {
299197104Sjkim            ACPI_ERROR ((AE_INFO,
300228110Sjkim                "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
301107325Siwasaki                AcpiUtGetObjectTypeName (SourceDesc)));
302151937Sjkim
303107325Siwasaki            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
304107325Siwasaki        }
30567754Smsmith
306197104Sjkim        if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
307107325Siwasaki        {
308197104Sjkim            Length = ACPI_SMBUS_BUFFER_SIZE;
309197104Sjkim            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
310197104Sjkim        }
311228110Sjkim        else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
312228110Sjkim        {
313228110Sjkim            Length = ACPI_GSBUS_BUFFER_SIZE;
314228110Sjkim            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
315228110Sjkim        }
316197104Sjkim        else /* IPMI */
317197104Sjkim        {
318197104Sjkim            Length = ACPI_IPMI_BUFFER_SIZE;
319197104Sjkim            Function = ACPI_WRITE;
320197104Sjkim        }
321197104Sjkim
322197104Sjkim        if (SourceDesc->Buffer.Length < Length)
323197104Sjkim        {
324167802Sjkim            ACPI_ERROR ((AE_INFO,
325228110Sjkim                "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
326197104Sjkim                Length, SourceDesc->Buffer.Length));
327151937Sjkim
328107325Siwasaki            return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
329107325Siwasaki        }
330107325Siwasaki
331197104Sjkim        /* Create the bi-directional buffer */
332197104Sjkim
333197104Sjkim        BufferDesc = AcpiUtCreateBufferObject (Length);
334107325Siwasaki        if (!BufferDesc)
335107325Siwasaki        {
336107325Siwasaki            return_ACPI_STATUS (AE_NO_MEMORY);
337107325Siwasaki        }
338107325Siwasaki
339107325Siwasaki        Buffer = BufferDesc->Buffer.Pointer;
340197104Sjkim        ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);
341107325Siwasaki
342107325Siwasaki        /* Lock entire transaction if requested */
343107325Siwasaki
344167802Sjkim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
345107325Siwasaki
346114237Snjl        /*
347151937Sjkim         * Perform the write (returns status and perhaps data in the
348151937Sjkim         * same buffer)
349107325Siwasaki         */
350114237Snjl        Status = AcpiExAccessRegion (ObjDesc, 0,
351202771Sjkim                    (UINT64 *) Buffer, Function);
352167802Sjkim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
353107325Siwasaki
354107325Siwasaki        *ResultDesc = BufferDesc;
355107325Siwasaki        return_ACPI_STATUS (Status);
356107325Siwasaki    }
357107325Siwasaki
358151937Sjkim    /* Get a pointer to the data to be written */
359151937Sjkim
360193267Sjkim    switch (SourceDesc->Common.Type)
36167754Smsmith    {
36277424Smsmith    case ACPI_TYPE_INTEGER:
36377424Smsmith        Buffer = &SourceDesc->Integer.Value;
36477424Smsmith        Length = sizeof (SourceDesc->Integer.Value);
36577424Smsmith        break;
36677424Smsmith
36777424Smsmith    case ACPI_TYPE_BUFFER:
36877424Smsmith        Buffer = SourceDesc->Buffer.Pointer;
36977424Smsmith        Length = SourceDesc->Buffer.Length;
37077424Smsmith        break;
37177424Smsmith
37277424Smsmith    case ACPI_TYPE_STRING:
37377424Smsmith        Buffer = SourceDesc->String.Pointer;
37477424Smsmith        Length = SourceDesc->String.Length;
37577424Smsmith        break;
37677424Smsmith
37777424Smsmith    default:
37877424Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
37967754Smsmith    }
38067754Smsmith
38199146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
382123315Snjl        "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
383193267Sjkim        SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
384193267Sjkim        SourceDesc->Common.Type, Buffer, Length));
385151937Sjkim
38699146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
387123315Snjl        "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
388193267Sjkim        ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
389193267Sjkim        ObjDesc->Common.Type,
39087031Smsmith        ObjDesc->CommonField.BitLength,
39187031Smsmith        ObjDesc->CommonField.StartFieldBitOffset,
39287031Smsmith        ObjDesc->CommonField.BaseByteOffset));
39367754Smsmith
394107325Siwasaki    /* Lock entire transaction if requested */
395107325Siwasaki
396167802Sjkim    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
39777424Smsmith
398107325Siwasaki    /* Write to the field */
399107325Siwasaki
40087031Smsmith    Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
401167802Sjkim    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
40267754Smsmith
40377424Smsmith    return_ACPI_STATUS (Status);
40477424Smsmith}
40577424Smsmith
40677424Smsmith
407