Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: exserial - field_unit support for serial address spaces
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acdispat.h"
0013 #include "acinterp.h"
0014 #include "amlcode.h"
0015 
0016 #define _COMPONENT          ACPI_EXECUTER
0017 ACPI_MODULE_NAME("exserial")
0018 
0019 /*******************************************************************************
0020  *
0021  * FUNCTION:    acpi_ex_read_gpio
0022  *
0023  * PARAMETERS:  obj_desc            - The named field to read
0024  *              buffer              - Where the return data is returned
0025  *
0026  * RETURN:      Status
0027  *
0028  * DESCRIPTION: Read from a named field that references a Generic Serial Bus
0029  *              field
0030  *
0031  ******************************************************************************/
0032 acpi_status acpi_ex_read_gpio(union acpi_operand_object *obj_desc, void *buffer)
0033 {
0034     acpi_status status;
0035 
0036     ACPI_FUNCTION_TRACE_PTR(ex_read_gpio, obj_desc);
0037 
0038     /*
0039      * For GPIO (general_purpose_io), the Address will be the bit offset
0040      * from the previous Connection() operator, making it effectively a
0041      * pin number index. The bit_length is the length of the field, which
0042      * is thus the number of pins.
0043      */
0044     ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0045               "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
0046               obj_desc->field.pin_number_index,
0047               obj_desc->field.bit_length));
0048 
0049     /* Lock entire transaction if requested */
0050 
0051     acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
0052 
0053     /* Perform the read */
0054 
0055     status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ);
0056 
0057     acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
0058     return_ACPI_STATUS(status);
0059 }
0060 
0061 /*******************************************************************************
0062  *
0063  * FUNCTION:    acpi_ex_write_gpio
0064  *
0065  * PARAMETERS:  source_desc         - Contains data to write. Expect to be
0066  *                                    an Integer object.
0067  *              obj_desc            - The named field
0068  *              result_desc         - Where the return value is returned, if any
0069  *
0070  * RETURN:      Status
0071  *
0072  * DESCRIPTION: Write to a named field that references a General Purpose I/O
0073  *              field.
0074  *
0075  ******************************************************************************/
0076 
0077 acpi_status
0078 acpi_ex_write_gpio(union acpi_operand_object *source_desc,
0079            union acpi_operand_object *obj_desc,
0080            union acpi_operand_object **return_buffer)
0081 {
0082     acpi_status status;
0083     void *buffer;
0084 
0085     ACPI_FUNCTION_TRACE_PTR(ex_write_gpio, obj_desc);
0086 
0087     /*
0088      * For GPIO (general_purpose_io), we will bypass the entire field
0089      * mechanism and handoff the bit address and bit width directly to
0090      * the handler. The Address will be the bit offset
0091      * from the previous Connection() operator, making it effectively a
0092      * pin number index. The bit_length is the length of the field, which
0093      * is thus the number of pins.
0094      */
0095     if (source_desc->common.type != ACPI_TYPE_INTEGER) {
0096         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0097     }
0098 
0099     ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0100               "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X  [TO]: Pin %u Bits %u\n",
0101               acpi_ut_get_type_name(source_desc->common.type),
0102               source_desc->common.type,
0103               (u32)source_desc->integer.value,
0104               obj_desc->field.pin_number_index,
0105               obj_desc->field.bit_length));
0106 
0107     buffer = &source_desc->integer.value;
0108 
0109     /* Lock entire transaction if requested */
0110 
0111     acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
0112 
0113     /* Perform the write */
0114 
0115     status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_WRITE);
0116     acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
0117     return_ACPI_STATUS(status);
0118 }
0119 
0120 /*******************************************************************************
0121  *
0122  * FUNCTION:    acpi_ex_read_serial_bus
0123  *
0124  * PARAMETERS:  obj_desc            - The named field to read
0125  *              return_buffer       - Where the return value is returned, if any
0126  *
0127  * RETURN:      Status
0128  *
0129  * DESCRIPTION: Read from a named field that references a serial bus
0130  *              (SMBus, IPMI, or GSBus).
0131  *
0132  ******************************************************************************/
0133 
0134 acpi_status
0135 acpi_ex_read_serial_bus(union acpi_operand_object *obj_desc,
0136             union acpi_operand_object **return_buffer)
0137 {
0138     acpi_status status;
0139     u32 buffer_length;
0140     union acpi_operand_object *buffer_desc;
0141     u32 function;
0142     u16 accessor_type;
0143 
0144     ACPI_FUNCTION_TRACE_PTR(ex_read_serial_bus, obj_desc);
0145 
0146     /*
0147      * This is an SMBus, GSBus or IPMI read. We must create a buffer to
0148      * hold the data and then directly access the region handler.
0149      *
0150      * Note: SMBus and GSBus protocol value is passed in upper 16-bits
0151      * of Function
0152      *
0153      * Common buffer format:
0154      *     Status;    (Byte 0 of the data buffer)
0155      *     Length;    (Byte 1 of the data buffer)
0156      *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
0157      */
0158     switch (obj_desc->field.region_obj->region.space_id) {
0159     case ACPI_ADR_SPACE_SMBUS:
0160 
0161         buffer_length = ACPI_SMBUS_BUFFER_SIZE;
0162         function = ACPI_READ | (obj_desc->field.attribute << 16);
0163         break;
0164 
0165     case ACPI_ADR_SPACE_IPMI:
0166 
0167         buffer_length = ACPI_IPMI_BUFFER_SIZE;
0168         function = ACPI_READ;
0169         break;
0170 
0171     case ACPI_ADR_SPACE_GSBUS:
0172 
0173         accessor_type = obj_desc->field.attribute;
0174         if (accessor_type == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES) {
0175             ACPI_ERROR((AE_INFO,
0176                     "Invalid direct read using bidirectional write-then-read protocol"));
0177 
0178             return_ACPI_STATUS(AE_AML_PROTOCOL);
0179         }
0180 
0181         status =
0182             acpi_ex_get_protocol_buffer_length(accessor_type,
0183                                &buffer_length);
0184         if (ACPI_FAILURE(status)) {
0185             ACPI_ERROR((AE_INFO,
0186                     "Invalid protocol ID for GSBus: 0x%4.4X",
0187                     accessor_type));
0188 
0189             return_ACPI_STATUS(status);
0190         }
0191 
0192         /* Add header length to get the full size of the buffer */
0193 
0194         buffer_length += ACPI_SERIAL_HEADER_SIZE;
0195         function = ACPI_READ | (accessor_type << 16);
0196         break;
0197 
0198     case ACPI_ADR_SPACE_PLATFORM_RT:
0199 
0200         buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
0201         function = ACPI_READ;
0202         break;
0203 
0204     default:
0205         return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
0206     }
0207 
0208     /* Create the local transfer buffer that is returned to the caller */
0209 
0210     buffer_desc = acpi_ut_create_buffer_object(buffer_length);
0211     if (!buffer_desc) {
0212         return_ACPI_STATUS(AE_NO_MEMORY);
0213     }
0214 
0215     /* Lock entire transaction if requested */
0216 
0217     acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
0218 
0219     /* Call the region handler for the write-then-read */
0220 
0221     status = acpi_ex_access_region(obj_desc, 0,
0222                        ACPI_CAST_PTR(u64,
0223                              buffer_desc->buffer.
0224                              pointer), function);
0225     acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
0226 
0227     *return_buffer = buffer_desc;
0228     return_ACPI_STATUS(status);
0229 }
0230 
0231 /*******************************************************************************
0232  *
0233  * FUNCTION:    acpi_ex_write_serial_bus
0234  *
0235  * PARAMETERS:  source_desc         - Contains data to write
0236  *              obj_desc            - The named field
0237  *              return_buffer       - Where the return value is returned, if any
0238  *
0239  * RETURN:      Status
0240  *
0241  * DESCRIPTION: Write to a named field that references a serial bus
0242  *              (SMBus, IPMI, GSBus).
0243  *
0244  ******************************************************************************/
0245 
0246 acpi_status
0247 acpi_ex_write_serial_bus(union acpi_operand_object *source_desc,
0248              union acpi_operand_object *obj_desc,
0249              union acpi_operand_object **return_buffer)
0250 {
0251     acpi_status status;
0252     u32 buffer_length;
0253     u32 data_length;
0254     void *buffer;
0255     union acpi_operand_object *buffer_desc;
0256     u32 function;
0257     u16 accessor_type;
0258 
0259     ACPI_FUNCTION_TRACE_PTR(ex_write_serial_bus, obj_desc);
0260 
0261     /*
0262      * This is an SMBus, GSBus or IPMI write. We will bypass the entire
0263      * field mechanism and handoff the buffer directly to the handler.
0264      * For these address spaces, the buffer is bidirectional; on a
0265      * write, return data is returned in the same buffer.
0266      *
0267      * Source must be a buffer of sufficient size, these are fixed size:
0268      * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
0269      *
0270      * Note: SMBus and GSBus protocol type is passed in upper 16-bits
0271      * of Function
0272      *
0273      * Common buffer format:
0274      *     Status;    (Byte 0 of the data buffer)
0275      *     Length;    (Byte 1 of the data buffer)
0276      *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
0277      */
0278     if (source_desc->common.type != ACPI_TYPE_BUFFER) {
0279         ACPI_ERROR((AE_INFO,
0280                 "SMBus/IPMI/GenericSerialBus write requires "
0281                 "Buffer, found type %s",
0282                 acpi_ut_get_object_type_name(source_desc)));
0283 
0284         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0285     }
0286 
0287     switch (obj_desc->field.region_obj->region.space_id) {
0288     case ACPI_ADR_SPACE_SMBUS:
0289 
0290         buffer_length = ACPI_SMBUS_BUFFER_SIZE;
0291         function = ACPI_WRITE | (obj_desc->field.attribute << 16);
0292         break;
0293 
0294     case ACPI_ADR_SPACE_IPMI:
0295 
0296         buffer_length = ACPI_IPMI_BUFFER_SIZE;
0297         function = ACPI_WRITE;
0298         break;
0299 
0300     case ACPI_ADR_SPACE_GSBUS:
0301 
0302         accessor_type = obj_desc->field.attribute;
0303         status =
0304             acpi_ex_get_protocol_buffer_length(accessor_type,
0305                                &buffer_length);
0306         if (ACPI_FAILURE(status)) {
0307             ACPI_ERROR((AE_INFO,
0308                     "Invalid protocol ID for GSBus: 0x%4.4X",
0309                     accessor_type));
0310 
0311             return_ACPI_STATUS(status);
0312         }
0313 
0314         /* Add header length to get the full size of the buffer */
0315 
0316         buffer_length += ACPI_SERIAL_HEADER_SIZE;
0317         function = ACPI_WRITE | (accessor_type << 16);
0318         break;
0319 
0320     case ACPI_ADR_SPACE_PLATFORM_RT:
0321 
0322         buffer_length = ACPI_PRM_INPUT_BUFFER_SIZE;
0323         function = ACPI_WRITE;
0324         break;
0325 
0326     default:
0327         return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
0328     }
0329 
0330     /* Create the transfer/bidirectional/return buffer */
0331 
0332     buffer_desc = acpi_ut_create_buffer_object(buffer_length);
0333     if (!buffer_desc) {
0334         return_ACPI_STATUS(AE_NO_MEMORY);
0335     }
0336 
0337     /* Copy the input buffer data to the transfer buffer */
0338 
0339     buffer = buffer_desc->buffer.pointer;
0340     data_length = (buffer_length < source_desc->buffer.length ?
0341                buffer_length : source_desc->buffer.length);
0342     memcpy(buffer, source_desc->buffer.pointer, data_length);
0343 
0344     /* Lock entire transaction if requested */
0345 
0346     acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
0347 
0348     /*
0349      * Perform the write (returns status and perhaps data in the
0350      * same buffer)
0351      */
0352     status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
0353     acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
0354 
0355     *return_buffer = buffer_desc;
0356     return_ACPI_STATUS(status);
0357 }