Home | History | Annotate | Line # | Download | only in executer
exserial.c revision 1.1.1.4
      1 /******************************************************************************
      2  *
      3  * Module Name: exserial - FieldUnit support for serial address spaces
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 #include "acpi.h"
     45 #include "accommon.h"
     46 #include "acdispat.h"
     47 #include "acinterp.h"
     48 #include "amlcode.h"
     49 
     50 
     51 #define _COMPONENT          ACPI_EXECUTER
     52         ACPI_MODULE_NAME    ("exserial")
     53 
     54 
     55 /*******************************************************************************
     56  *
     57  * FUNCTION:    AcpiExReadGpio
     58  *
     59  * PARAMETERS:  ObjDesc             - The named field to read
     60  *              Buffer              - Where the return data is returned
     61  *
     62  * RETURN:      Status
     63  *
     64  * DESCRIPTION: Read from a named field that references a Generic Serial Bus
     65  *              field
     66  *
     67  ******************************************************************************/
     68 
     69 ACPI_STATUS
     70 AcpiExReadGpio (
     71     ACPI_OPERAND_OBJECT     *ObjDesc,
     72     void                    *Buffer)
     73 {
     74     ACPI_STATUS             Status;
     75 
     76 
     77     ACPI_FUNCTION_TRACE_PTR (ExReadGpio, ObjDesc);
     78 
     79 
     80     /*
     81      * For GPIO (GeneralPurposeIo), the Address will be the bit offset
     82      * from the previous Connection() operator, making it effectively a
     83      * pin number index. The BitLength is the length of the field, which
     84      * is thus the number of pins.
     85      */
     86     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
     87         "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
     88         ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
     89 
     90     /* Lock entire transaction if requested */
     91 
     92     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
     93 
     94     /* Perform the read */
     95 
     96     Status = AcpiExAccessRegion (
     97         ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ);
     98 
     99     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    100     return_ACPI_STATUS (Status);
    101 }
    102 
    103 
    104 /*******************************************************************************
    105  *
    106  * FUNCTION:    AcpiExWriteGpio
    107  *
    108  * PARAMETERS:  SourceDesc          - Contains data to write. Expect to be
    109  *                                    an Integer object.
    110  *              ObjDesc             - The named field
    111  *              ResultDesc          - Where the return value is returned, if any
    112  *
    113  * RETURN:      Status
    114  *
    115  * DESCRIPTION: Write to a named field that references a General Purpose I/O
    116  *              field.
    117  *
    118  ******************************************************************************/
    119 
    120 ACPI_STATUS
    121 AcpiExWriteGpio (
    122     ACPI_OPERAND_OBJECT     *SourceDesc,
    123     ACPI_OPERAND_OBJECT     *ObjDesc,
    124     ACPI_OPERAND_OBJECT     **ReturnBuffer)
    125 {
    126     ACPI_STATUS             Status;
    127     void                    *Buffer;
    128 
    129 
    130     ACPI_FUNCTION_TRACE_PTR (ExWriteGpio, ObjDesc);
    131 
    132 
    133     /*
    134      * For GPIO (GeneralPurposeIo), we will bypass the entire field
    135      * mechanism and handoff the bit address and bit width directly to
    136      * the handler. The Address will be the bit offset
    137      * from the previous Connection() operator, making it effectively a
    138      * pin number index. The BitLength is the length of the field, which
    139      * is thus the number of pins.
    140      */
    141     if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
    142     {
    143         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    144     }
    145 
    146     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    147         "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X  [TO]: Pin %u Bits %u\n",
    148         AcpiUtGetTypeName (SourceDesc->Common.Type),
    149         SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
    150         ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
    151 
    152     Buffer = &SourceDesc->Integer.Value;
    153 
    154     /* Lock entire transaction if requested */
    155 
    156     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
    157 
    158     /* Perform the write */
    159 
    160     Status = AcpiExAccessRegion (
    161         ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
    162     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    163     return_ACPI_STATUS (Status);
    164 }
    165 
    166 
    167 /*******************************************************************************
    168  *
    169  * FUNCTION:    AcpiExReadSerialBus
    170  *
    171  * PARAMETERS:  ObjDesc             - The named field to read
    172  *              ReturnBuffer        - Where the return value is returned, if any
    173  *
    174  * RETURN:      Status
    175  *
    176  * DESCRIPTION: Read from a named field that references a serial bus
    177  *              (SMBus, IPMI, or GSBus).
    178  *
    179  ******************************************************************************/
    180 
    181 ACPI_STATUS
    182 AcpiExReadSerialBus (
    183     ACPI_OPERAND_OBJECT     *ObjDesc,
    184     ACPI_OPERAND_OBJECT     **ReturnBuffer)
    185 {
    186     ACPI_STATUS             Status;
    187     UINT32                  BufferLength;
    188     ACPI_OPERAND_OBJECT     *BufferDesc;
    189     UINT32                  Function;
    190     UINT16                  AccessorType;
    191 
    192 
    193     ACPI_FUNCTION_TRACE_PTR (ExReadSerialBus, ObjDesc);
    194 
    195 
    196     /*
    197      * This is an SMBus, GSBus or IPMI read. We must create a buffer to
    198      * hold the data and then directly access the region handler.
    199      *
    200      * Note: SMBus and GSBus protocol value is passed in upper 16-bits
    201      * of Function
    202      *
    203      * Common buffer format:
    204      *     Status;    (Byte 0 of the data buffer)
    205      *     Length;    (Byte 1 of the data buffer)
    206      *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
    207      */
    208     switch (ObjDesc->Field.RegionObj->Region.SpaceId)
    209     {
    210     case ACPI_ADR_SPACE_SMBUS:
    211 
    212         BufferLength = ACPI_SMBUS_BUFFER_SIZE;
    213         Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
    214         break;
    215 
    216     case ACPI_ADR_SPACE_IPMI:
    217 
    218         BufferLength = ACPI_IPMI_BUFFER_SIZE;
    219         Function = ACPI_READ;
    220         break;
    221 
    222     case ACPI_ADR_SPACE_GSBUS:
    223 
    224         AccessorType = ObjDesc->Field.Attribute;
    225         if (AccessorType == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES)
    226         {
    227             ACPI_ERROR ((AE_INFO,
    228                 "Invalid direct read using bidirectional write-then-read protocol"));
    229 
    230             return_ACPI_STATUS (AE_AML_PROTOCOL);
    231         }
    232 
    233         Status = AcpiExGetProtocolBufferLength (AccessorType, &BufferLength);
    234         if (ACPI_FAILURE (Status))
    235         {
    236             ACPI_ERROR ((AE_INFO,
    237                 "Invalid protocol ID for GSBus: 0x%4.4X", AccessorType));
    238 
    239             return_ACPI_STATUS (Status);
    240         }
    241 
    242         /* Add header length to get the full size of the buffer */
    243 
    244         BufferLength += ACPI_SERIAL_HEADER_SIZE;
    245         Function = ACPI_READ | (AccessorType << 16);
    246         break;
    247 
    248     default:
    249         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    250     }
    251 
    252     /* Create the local transfer buffer that is returned to the caller */
    253 
    254     BufferDesc = AcpiUtCreateBufferObject (BufferLength);
    255     if (!BufferDesc)
    256     {
    257         return_ACPI_STATUS (AE_NO_MEMORY);
    258     }
    259 
    260     /* Lock entire transaction if requested */
    261 
    262     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
    263 
    264     /* Call the region handler for the write-then-read */
    265 
    266     Status = AcpiExAccessRegion (ObjDesc, 0,
    267         ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
    268     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    269 
    270     *ReturnBuffer = BufferDesc;
    271     return_ACPI_STATUS (Status);
    272 }
    273 
    274 
    275 /*******************************************************************************
    276  *
    277  * FUNCTION:    AcpiExWriteSerialBus
    278  *
    279  * PARAMETERS:  SourceDesc          - Contains data to write
    280  *              ObjDesc             - The named field
    281  *              ReturnBuffer        - Where the return value is returned, if any
    282  *
    283  * RETURN:      Status
    284  *
    285  * DESCRIPTION: Write to a named field that references a serial bus
    286  *              (SMBus, IPMI, GSBus).
    287  *
    288  ******************************************************************************/
    289 
    290 ACPI_STATUS
    291 AcpiExWriteSerialBus (
    292     ACPI_OPERAND_OBJECT     *SourceDesc,
    293     ACPI_OPERAND_OBJECT     *ObjDesc,
    294     ACPI_OPERAND_OBJECT     **ReturnBuffer)
    295 {
    296     ACPI_STATUS             Status;
    297     UINT32                  BufferLength;
    298     UINT32                  DataLength;
    299     void                    *Buffer;
    300     ACPI_OPERAND_OBJECT     *BufferDesc;
    301     UINT32                  Function;
    302     UINT16                  AccessorType;
    303 
    304 
    305     ACPI_FUNCTION_TRACE_PTR (ExWriteSerialBus, ObjDesc);
    306 
    307 
    308     /*
    309      * This is an SMBus, GSBus or IPMI write. We will bypass the entire
    310      * field mechanism and handoff the buffer directly to the handler.
    311      * For these address spaces, the buffer is bidirectional; on a
    312      * write, return data is returned in the same buffer.
    313      *
    314      * Source must be a buffer of sufficient size, these are fixed size:
    315      * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
    316      *
    317      * Note: SMBus and GSBus protocol type is passed in upper 16-bits
    318      * of Function
    319      *
    320      * Common buffer format:
    321      *     Status;    (Byte 0 of the data buffer)
    322      *     Length;    (Byte 1 of the data buffer)
    323      *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
    324      */
    325     if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
    326     {
    327         ACPI_ERROR ((AE_INFO,
    328             "SMBus/IPMI/GenericSerialBus write requires "
    329             "Buffer, found type %s",
    330             AcpiUtGetObjectTypeName (SourceDesc)));
    331 
    332         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    333     }
    334 
    335     switch (ObjDesc->Field.RegionObj->Region.SpaceId)
    336     {
    337     case ACPI_ADR_SPACE_SMBUS:
    338 
    339         BufferLength = ACPI_SMBUS_BUFFER_SIZE;
    340         Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
    341         break;
    342 
    343     case ACPI_ADR_SPACE_IPMI:
    344 
    345         BufferLength = ACPI_IPMI_BUFFER_SIZE;
    346         Function = ACPI_WRITE;
    347         break;
    348 
    349     case ACPI_ADR_SPACE_GSBUS:
    350 
    351         AccessorType = ObjDesc->Field.Attribute;
    352         Status = AcpiExGetProtocolBufferLength (AccessorType, &BufferLength);
    353         if (ACPI_FAILURE (Status))
    354         {
    355             ACPI_ERROR ((AE_INFO,
    356                 "Invalid protocol ID for GSBus: 0x%4.4X", AccessorType));
    357 
    358             return_ACPI_STATUS (Status);
    359         }
    360 
    361         /* Add header length to get the full size of the buffer */
    362 
    363         BufferLength += ACPI_SERIAL_HEADER_SIZE;
    364         Function = ACPI_WRITE | (AccessorType << 16);
    365         break;
    366 
    367     default:
    368         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    369     }
    370 
    371     /* Create the transfer/bidirectional/return buffer */
    372 
    373     BufferDesc = AcpiUtCreateBufferObject (BufferLength);
    374     if (!BufferDesc)
    375     {
    376         return_ACPI_STATUS (AE_NO_MEMORY);
    377     }
    378 
    379     /* Copy the input buffer data to the transfer buffer */
    380 
    381     Buffer = BufferDesc->Buffer.Pointer;
    382     DataLength = (BufferLength < SourceDesc->Buffer.Length ?
    383         BufferLength : SourceDesc->Buffer.Length);
    384     memcpy (Buffer, SourceDesc->Buffer.Pointer, DataLength);
    385 
    386     /* Lock entire transaction if requested */
    387 
    388     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
    389 
    390     /*
    391      * Perform the write (returns status and perhaps data in the
    392      * same buffer)
    393      */
    394     Status = AcpiExAccessRegion (
    395         ObjDesc, 0, (UINT64 *) Buffer, Function);
    396     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    397 
    398     *ReturnBuffer = BufferDesc;
    399     return_ACPI_STATUS (Status);
    400 }
    401