Home | History | Annotate | Line # | Download | only in executer
      1 /******************************************************************************
      2  *
      3  * Module Name: exserial - FieldUnit support for serial address spaces
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2025, 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     case ACPI_ADR_SPACE_PLATFORM_RT:
    249 
    250         BufferLength = ACPI_PRM_INPUT_BUFFER_SIZE;
    251         Function = ACPI_READ;
    252         break;
    253 
    254     case ACPI_ADR_SPACE_FIXED_HARDWARE:
    255 
    256         BufferLength = ACPI_FFH_INPUT_BUFFER_SIZE;
    257         Function = ACPI_READ;
    258         break;
    259 
    260     default:
    261         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    262     }
    263 
    264     /* Create the local transfer buffer that is returned to the caller */
    265 
    266     BufferDesc = AcpiUtCreateBufferObject (BufferLength);
    267     if (!BufferDesc)
    268     {
    269         return_ACPI_STATUS (AE_NO_MEMORY);
    270     }
    271 
    272     /* Lock entire transaction if requested */
    273 
    274     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
    275 
    276     /* Call the region handler for the write-then-read */
    277 
    278     Status = AcpiExAccessRegion (ObjDesc, 0,
    279         ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
    280     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    281 
    282     *ReturnBuffer = BufferDesc;
    283     return_ACPI_STATUS (Status);
    284 }
    285 
    286 
    287 /*******************************************************************************
    288  *
    289  * FUNCTION:    AcpiExWriteSerialBus
    290  *
    291  * PARAMETERS:  SourceDesc          - Contains data to write
    292  *              ObjDesc             - The named field
    293  *              ReturnBuffer        - Where the return value is returned, if any
    294  *
    295  * RETURN:      Status
    296  *
    297  * DESCRIPTION: Write to a named field that references a serial bus
    298  *              (SMBus, IPMI, GSBus).
    299  *
    300  ******************************************************************************/
    301 
    302 ACPI_STATUS
    303 AcpiExWriteSerialBus (
    304     ACPI_OPERAND_OBJECT     *SourceDesc,
    305     ACPI_OPERAND_OBJECT     *ObjDesc,
    306     ACPI_OPERAND_OBJECT     **ReturnBuffer)
    307 {
    308     ACPI_STATUS             Status;
    309     UINT32                  BufferLength;
    310     UINT32                  DataLength;
    311     void                    *Buffer;
    312     ACPI_OPERAND_OBJECT     *BufferDesc;
    313     UINT32                  Function;
    314     UINT16                  AccessorType;
    315 
    316 
    317     ACPI_FUNCTION_TRACE_PTR (ExWriteSerialBus, ObjDesc);
    318 
    319 
    320     /*
    321      * This is an SMBus, GSBus or IPMI write. We will bypass the entire
    322      * field mechanism and handoff the buffer directly to the handler.
    323      * For these address spaces, the buffer is bidirectional; on a
    324      * write, return data is returned in the same buffer.
    325      *
    326      * Source must be a buffer of sufficient size, these are fixed size:
    327      * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
    328      *
    329      * Note: SMBus and GSBus protocol type is passed in upper 16-bits
    330      * of Function
    331      *
    332      * Common buffer format:
    333      *     Status;    (Byte 0 of the data buffer)
    334      *     Length;    (Byte 1 of the data buffer)
    335      *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
    336      */
    337     if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
    338     {
    339         ACPI_ERROR ((AE_INFO,
    340             "SMBus/IPMI/GenericSerialBus write requires "
    341             "Buffer, found type %s",
    342             AcpiUtGetObjectTypeName (SourceDesc)));
    343 
    344         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    345     }
    346 
    347     switch (ObjDesc->Field.RegionObj->Region.SpaceId)
    348     {
    349     case ACPI_ADR_SPACE_SMBUS:
    350 
    351         BufferLength = ACPI_SMBUS_BUFFER_SIZE;
    352         Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
    353         break;
    354 
    355     case ACPI_ADR_SPACE_IPMI:
    356 
    357         BufferLength = ACPI_IPMI_BUFFER_SIZE;
    358         Function = ACPI_WRITE;
    359         break;
    360 
    361     case ACPI_ADR_SPACE_GSBUS:
    362 
    363         AccessorType = ObjDesc->Field.Attribute;
    364         Status = AcpiExGetProtocolBufferLength (AccessorType, &BufferLength);
    365         if (ACPI_FAILURE (Status))
    366         {
    367             ACPI_ERROR ((AE_INFO,
    368                 "Invalid protocol ID for GSBus: 0x%4.4X", AccessorType));
    369 
    370             return_ACPI_STATUS (Status);
    371         }
    372 
    373         /* Add header length to get the full size of the buffer */
    374 
    375         BufferLength += ACPI_SERIAL_HEADER_SIZE;
    376         Function = ACPI_WRITE | (AccessorType << 16);
    377         break;
    378 
    379     case ACPI_ADR_SPACE_PLATFORM_RT:
    380 
    381         BufferLength = ACPI_PRM_INPUT_BUFFER_SIZE;
    382         Function = ACPI_WRITE;
    383         break;
    384 
    385     case ACPI_ADR_SPACE_FIXED_HARDWARE:
    386 
    387         BufferLength = ACPI_FFH_INPUT_BUFFER_SIZE;
    388         Function = ACPI_WRITE;
    389         break;
    390 
    391     default:
    392         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    393     }
    394 
    395     /* Create the transfer/bidirectional/return buffer */
    396 
    397     BufferDesc = AcpiUtCreateBufferObject (BufferLength);
    398     if (!BufferDesc)
    399     {
    400         return_ACPI_STATUS (AE_NO_MEMORY);
    401     }
    402 
    403     /* Copy the input buffer data to the transfer buffer */
    404 
    405     Buffer = BufferDesc->Buffer.Pointer;
    406     DataLength = ACPI_MIN (BufferLength, SourceDesc->Buffer.Length);
    407     memcpy (Buffer, SourceDesc->Buffer.Pointer, DataLength);
    408 
    409     /* Lock entire transaction if requested */
    410 
    411     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
    412 
    413     /*
    414      * Perform the write (returns status and perhaps data in the
    415      * same buffer)
    416      */
    417     Status = AcpiExAccessRegion (
    418         ObjDesc, 0, (UINT64 *) Buffer, Function);
    419     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    420 
    421     *ReturnBuffer = BufferDesc;
    422     return_ACPI_STATUS (Status);
    423 }
    424