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