LCOV - code coverage report
Current view: top level - drivers/acpi/acpica - exfield.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 63 115 54.8 %
Date: 2022-04-01 14:35:51 Functions: 2 3 66.7 %
Branches: 32 72 44.4 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
       2                 :            : /******************************************************************************
       3                 :            :  *
       4                 :            :  * Module Name: exfield - AML execution - field_unit read/write
       5                 :            :  *
       6                 :            :  * Copyright (C) 2000 - 2020, Intel Corp.
       7                 :            :  *
       8                 :            :  *****************************************************************************/
       9                 :            : 
      10                 :            : #include <acpi/acpi.h>
      11                 :            : #include "accommon.h"
      12                 :            : #include "acdispat.h"
      13                 :            : #include "acinterp.h"
      14                 :            : #include "amlcode.h"
      15                 :            : 
      16                 :            : #define _COMPONENT          ACPI_EXECUTER
      17                 :            : ACPI_MODULE_NAME("exfield")
      18                 :            : 
      19                 :            : /*
      20                 :            :  * This table maps the various Attrib protocols to the byte transfer
      21                 :            :  * length. Used for the generic serial bus.
      22                 :            :  */
      23                 :            : #define ACPI_INVALID_PROTOCOL_ID        0x80
      24                 :            : #define ACPI_MAX_PROTOCOL_ID            0x0F
      25                 :            : const u8 acpi_protocol_lengths[] = {
      26                 :            :         ACPI_INVALID_PROTOCOL_ID,       /* 0 - reserved */
      27                 :            :         ACPI_INVALID_PROTOCOL_ID,       /* 1 - reserved */
      28                 :            :         0x00,                   /* 2 - ATTRIB_QUICK */
      29                 :            :         ACPI_INVALID_PROTOCOL_ID,       /* 3 - reserved */
      30                 :            :         0x01,                   /* 4 - ATTRIB_SEND_RECEIVE */
      31                 :            :         ACPI_INVALID_PROTOCOL_ID,       /* 5 - reserved */
      32                 :            :         0x01,                   /* 6 - ATTRIB_BYTE */
      33                 :            :         ACPI_INVALID_PROTOCOL_ID,       /* 7 - reserved */
      34                 :            :         0x02,                   /* 8 - ATTRIB_WORD */
      35                 :            :         ACPI_INVALID_PROTOCOL_ID,       /* 9 - reserved */
      36                 :            :         0xFF,                   /* A - ATTRIB_BLOCK  */
      37                 :            :         0xFF,                   /* B - ATTRIB_BYTES */
      38                 :            :         0x02,                   /* C - ATTRIB_PROCESS_CALL */
      39                 :            :         0xFF,                   /* D - ATTRIB_BLOCK_PROCESS_CALL */
      40                 :            :         0xFF,                   /* E - ATTRIB_RAW_BYTES */
      41                 :            :         0xFF                    /* F - ATTRIB_RAW_PROCESS_BYTES */
      42                 :            : };
      43                 :            : 
      44                 :            : #define PCC_MASTER_SUBSPACE     3
      45                 :            : 
      46                 :            : /*
      47                 :            :  * The following macros determine a given offset is a COMD field.
      48                 :            :  * According to the specification, generic subspaces (types 0-2) contains a
      49                 :            :  * 2-byte COMD field at offset 4 and master subspaces (type 3) contains a 4-byte
      50                 :            :  * COMD field starting at offset 12.
      51                 :            :  */
      52                 :            : #define GENERIC_SUBSPACE_COMMAND(a)     (4 == a || a == 5)
      53                 :            : #define MASTER_SUBSPACE_COMMAND(a)      (12 <= a && a <= 15)
      54                 :            : 
      55                 :            : /*******************************************************************************
      56                 :            :  *
      57                 :            :  * FUNCTION:    acpi_ex_get_protocol_buffer_length
      58                 :            :  *
      59                 :            :  * PARAMETERS:  protocol_id     - The type of the protocol indicated by region
      60                 :            :  *                                field access attributes
      61                 :            :  *              return_length   - Where the protocol byte transfer length is
      62                 :            :  *                                returned
      63                 :            :  *
      64                 :            :  * RETURN:      Status and decoded byte transfer length
      65                 :            :  *
      66                 :            :  * DESCRIPTION: This routine returns the length of the generic_serial_bus
      67                 :            :  *              protocol bytes
      68                 :            :  *
      69                 :            :  ******************************************************************************/
      70                 :            : 
      71                 :            : acpi_status
      72                 :          0 : acpi_ex_get_protocol_buffer_length(u32 protocol_id, u32 *return_length)
      73                 :            : {
      74                 :            : 
      75         [ #  # ]:          0 :         if ((protocol_id > ACPI_MAX_PROTOCOL_ID) ||
      76         [ #  # ]:          0 :             (acpi_protocol_lengths[protocol_id] == ACPI_INVALID_PROTOCOL_ID)) {
      77                 :          0 :                 ACPI_ERROR((AE_INFO,
      78                 :            :                             "Invalid Field/AccessAs protocol ID: 0x%4.4X",
      79                 :            :                             protocol_id));
      80                 :            : 
      81                 :          0 :                 return (AE_AML_PROTOCOL);
      82                 :            :         }
      83                 :            : 
      84                 :          0 :         *return_length = acpi_protocol_lengths[protocol_id];
      85                 :          0 :         return (AE_OK);
      86                 :            : }
      87                 :            : 
      88                 :            : /*******************************************************************************
      89                 :            :  *
      90                 :            :  * FUNCTION:    acpi_ex_read_data_from_field
      91                 :            :  *
      92                 :            :  * PARAMETERS:  walk_state          - Current execution state
      93                 :            :  *              obj_desc            - The named field
      94                 :            :  *              ret_buffer_desc     - Where the return data object is stored
      95                 :            :  *
      96                 :            :  * RETURN:      Status
      97                 :            :  *
      98                 :            :  * DESCRIPTION: Read from a named field. Returns either an Integer or a
      99                 :            :  *              Buffer, depending on the size of the field and whether if a
     100                 :            :  *              field is created by the create_field() operator.
     101                 :            :  *
     102                 :            :  ******************************************************************************/
     103                 :            : 
     104                 :            : acpi_status
     105                 :       1113 : acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
     106                 :            :                              union acpi_operand_object *obj_desc,
     107                 :            :                              union acpi_operand_object **ret_buffer_desc)
     108                 :            : {
     109                 :       1113 :         acpi_status status;
     110                 :       1113 :         union acpi_operand_object *buffer_desc;
     111                 :       1113 :         void *buffer;
     112                 :       1113 :         u32 buffer_length;
     113                 :            : 
     114                 :       1113 :         ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
     115                 :            : 
     116                 :            :         /* Parameter validation */
     117                 :            : 
     118         [ +  - ]:       1113 :         if (!obj_desc) {
     119                 :            :                 return_ACPI_STATUS(AE_AML_NO_OPERAND);
     120                 :            :         }
     121         [ +  - ]:       1113 :         if (!ret_buffer_desc) {
     122                 :            :                 return_ACPI_STATUS(AE_BAD_PARAMETER);
     123                 :            :         }
     124                 :            : 
     125         [ +  + ]:       1113 :         if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
     126                 :            :                 /*
     127                 :            :                  * If the buffer_field arguments have not been previously evaluated,
     128                 :            :                  * evaluate them now and save the results.
     129                 :            :                  */
     130         [ -  + ]:         21 :                 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
     131                 :          0 :                         status = acpi_ds_get_buffer_field_arguments(obj_desc);
     132         [ #  # ]:          0 :                         if (ACPI_FAILURE(status)) {
     133                 :            :                                 return_ACPI_STATUS(status);
     134                 :            :                         }
     135                 :            :                 }
     136         [ +  - ]:       1092 :         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
     137                 :       1092 :                    (obj_desc->field.region_obj->region.space_id ==
     138                 :            :                     ACPI_ADR_SPACE_SMBUS
     139         [ +  - ]:       1092 :                     || obj_desc->field.region_obj->region.space_id ==
     140                 :            :                     ACPI_ADR_SPACE_GSBUS
     141         [ -  + ]:       1092 :                     || obj_desc->field.region_obj->region.space_id ==
     142                 :            :                     ACPI_ADR_SPACE_IPMI)) {
     143                 :            : 
     144                 :            :                 /* SMBus, GSBus, IPMI serial */
     145                 :            : 
     146                 :          0 :                 status = acpi_ex_read_serial_bus(obj_desc, ret_buffer_desc);
     147                 :          0 :                 return_ACPI_STATUS(status);
     148                 :            :         }
     149                 :            : 
     150                 :            :         /*
     151                 :            :          * Allocate a buffer for the contents of the field.
     152                 :            :          *
     153                 :            :          * If the field is larger than the current integer width, create
     154                 :            :          * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
     155                 :            :          * the use of arithmetic operators on the returned value if the
     156                 :            :          * field size is equal or smaller than an Integer.
     157                 :            :          *
     158                 :            :          * However, all buffer fields created by create_field operator needs to
     159                 :            :          * remain as a buffer to match other AML interpreter implementations.
     160                 :            :          *
     161                 :            :          * Note: Field.length is in bits.
     162                 :            :          */
     163                 :       1113 :         buffer_length =
     164                 :       1113 :             (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
     165                 :            : 
     166         [ +  - ]:       1113 :         if (buffer_length > acpi_gbl_integer_byte_width ||
     167         [ +  + ]:       1113 :             (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD &&
     168         [ -  + ]:         21 :              obj_desc->buffer_field.is_create_field)) {
     169                 :            : 
     170                 :            :                 /* Field is too large for an Integer, create a Buffer instead */
     171                 :            : 
     172                 :          0 :                 buffer_desc = acpi_ut_create_buffer_object(buffer_length);
     173         [ #  # ]:          0 :                 if (!buffer_desc) {
     174                 :            :                         return_ACPI_STATUS(AE_NO_MEMORY);
     175                 :            :                 }
     176                 :          0 :                 buffer = buffer_desc->buffer.pointer;
     177                 :            :         } else {
     178                 :            :                 /* Field will fit within an Integer (normal case) */
     179                 :            : 
     180                 :       1113 :                 buffer_desc = acpi_ut_create_integer_object((u64) 0);
     181         [ +  - ]:       1113 :                 if (!buffer_desc) {
     182                 :            :                         return_ACPI_STATUS(AE_NO_MEMORY);
     183                 :            :                 }
     184                 :            : 
     185                 :       1113 :                 buffer_length = acpi_gbl_integer_byte_width;
     186                 :       1113 :                 buffer = &buffer_desc->integer.value;
     187                 :            :         }
     188                 :            : 
     189         [ +  + ]:       1113 :         if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
     190         [ -  + ]:       1092 :             (obj_desc->field.region_obj->region.space_id ==
     191                 :            :              ACPI_ADR_SPACE_GPIO)) {
     192                 :            : 
     193                 :            :                 /* General Purpose I/O */
     194                 :            : 
     195                 :          0 :                 status = acpi_ex_read_gpio(obj_desc, buffer);
     196                 :          0 :                 goto exit;
     197         [ +  + ]:       1113 :         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
     198         [ -  + ]:       1092 :                    (obj_desc->field.region_obj->region.space_id ==
     199                 :            :                     ACPI_ADR_SPACE_PLATFORM_COMM)) {
     200                 :            :                 /*
     201                 :            :                  * Reading from a PCC field unit does not require the handler because
     202                 :            :                  * it only requires reading from the internal_pcc_buffer.
     203                 :            :                  */
     204                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
     205                 :            :                                   "PCC FieldRead bits %u\n",
     206                 :          0 :                                   obj_desc->field.bit_length));
     207                 :            : 
     208                 :          0 :                 memcpy(buffer,
     209                 :          0 :                        obj_desc->field.region_obj->field.internal_pcc_buffer +
     210                 :          0 :                        obj_desc->field.base_byte_offset,
     211                 :          0 :                        (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.
     212                 :            :                                                               bit_length));
     213                 :            : 
     214                 :          0 :                 *ret_buffer_desc = buffer_desc;
     215                 :          0 :                 return AE_OK;
     216                 :            :         }
     217                 :            : 
     218                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
     219                 :            :                           "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
     220                 :            :                           obj_desc, obj_desc->common.type, buffer,
     221                 :       1113 :                           buffer_length));
     222                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
     223                 :            :                           "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
     224                 :            :                           obj_desc->common_field.bit_length,
     225                 :            :                           obj_desc->common_field.start_field_bit_offset,
     226                 :       1113 :                           obj_desc->common_field.base_byte_offset));
     227                 :            : 
     228                 :            :         /* Lock entire transaction if requested */
     229                 :            : 
     230                 :       1113 :         acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
     231                 :            : 
     232                 :            :         /* Read from the field */
     233                 :            : 
     234                 :       1113 :         status = acpi_ex_extract_from_field(obj_desc, buffer, buffer_length);
     235                 :       1113 :         acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
     236                 :            : 
     237                 :       1113 : exit:
     238         [ -  + ]:       1113 :         if (ACPI_FAILURE(status)) {
     239                 :          0 :                 acpi_ut_remove_reference(buffer_desc);
     240                 :            :         } else {
     241                 :       1113 :                 *ret_buffer_desc = buffer_desc;
     242                 :            :         }
     243                 :            : 
     244                 :            :         return_ACPI_STATUS(status);
     245                 :            : }
     246                 :            : 
     247                 :            : /*******************************************************************************
     248                 :            :  *
     249                 :            :  * FUNCTION:    acpi_ex_write_data_to_field
     250                 :            :  *
     251                 :            :  * PARAMETERS:  source_desc         - Contains data to write
     252                 :            :  *              obj_desc            - The named field
     253                 :            :  *              result_desc         - Where the return value is returned, if any
     254                 :            :  *
     255                 :            :  * RETURN:      Status
     256                 :            :  *
     257                 :            :  * DESCRIPTION: Write to a named field
     258                 :            :  *
     259                 :            :  ******************************************************************************/
     260                 :            : 
     261                 :            : acpi_status
     262                 :        357 : acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
     263                 :            :                             union acpi_operand_object *obj_desc,
     264                 :            :                             union acpi_operand_object **result_desc)
     265                 :            : {
     266                 :        357 :         acpi_status status;
     267                 :        357 :         u32 buffer_length;
     268                 :        357 :         u32 data_length;
     269                 :        357 :         void *buffer;
     270                 :            : 
     271                 :        357 :         ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
     272                 :            : 
     273                 :            :         /* Parameter validation */
     274                 :            : 
     275         [ +  - ]:        357 :         if (!source_desc || !obj_desc) {
     276                 :            :                 return_ACPI_STATUS(AE_AML_NO_OPERAND);
     277                 :            :         }
     278                 :            : 
     279         [ +  + ]:        357 :         if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
     280                 :            :                 /*
     281                 :            :                  * If the buffer_field arguments have not been previously evaluated,
     282                 :            :                  * evaluate them now and save the results.
     283                 :            :                  */
     284         [ -  + ]:        189 :                 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
     285                 :          0 :                         status = acpi_ds_get_buffer_field_arguments(obj_desc);
     286         [ #  # ]:          0 :                         if (ACPI_FAILURE(status)) {
     287                 :            :                                 return_ACPI_STATUS(status);
     288                 :            :                         }
     289                 :            :                 }
     290         [ +  - ]:        168 :         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
     291         [ -  + ]:        168 :                    (obj_desc->field.region_obj->region.space_id ==
     292                 :            :                     ACPI_ADR_SPACE_GPIO)) {
     293                 :            : 
     294                 :            :                 /* General Purpose I/O */
     295                 :            : 
     296                 :          0 :                 status = acpi_ex_write_gpio(source_desc, obj_desc, result_desc);
     297                 :          0 :                 return_ACPI_STATUS(status);
     298         [ +  - ]:        168 :         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
     299                 :        168 :                    (obj_desc->field.region_obj->region.space_id ==
     300                 :            :                     ACPI_ADR_SPACE_SMBUS
     301         [ +  - ]:        168 :                     || obj_desc->field.region_obj->region.space_id ==
     302                 :            :                     ACPI_ADR_SPACE_GSBUS
     303         [ -  + ]:        168 :                     || obj_desc->field.region_obj->region.space_id ==
     304                 :            :                     ACPI_ADR_SPACE_IPMI)) {
     305                 :            : 
     306                 :            :                 /* SMBus, GSBus, IPMI serial */
     307                 :            : 
     308                 :          0 :                 status =
     309                 :          0 :                     acpi_ex_write_serial_bus(source_desc, obj_desc,
     310                 :            :                                              result_desc);
     311                 :          0 :                 return_ACPI_STATUS(status);
     312         [ +  - ]:        168 :         } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
     313         [ -  + ]:        168 :                    (obj_desc->field.region_obj->region.space_id ==
     314                 :            :                     ACPI_ADR_SPACE_PLATFORM_COMM)) {
     315                 :            :                 /*
     316                 :            :                  * According to the spec a write to the COMD field will invoke the
     317                 :            :                  * region handler. Otherwise, write to the pcc_internal buffer. This
     318                 :            :                  * implementation will use the offsets specified rather than the name
     319                 :            :                  * of the field. This is considered safer because some firmware tools
     320                 :            :                  * are known to obfiscate named objects.
     321                 :            :                  */
     322                 :          0 :                 data_length =
     323                 :          0 :                     (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.
     324                 :            :                                                            bit_length);
     325                 :          0 :                 memcpy(obj_desc->field.region_obj->field.internal_pcc_buffer +
     326                 :          0 :                        obj_desc->field.base_byte_offset,
     327                 :          0 :                        source_desc->buffer.pointer, data_length);
     328                 :            : 
     329         [ #  # ]:          0 :                 if ((obj_desc->field.region_obj->region.address ==
     330                 :            :                      PCC_MASTER_SUBSPACE
     331         [ #  # ]:          0 :                      && MASTER_SUBSPACE_COMMAND(obj_desc->field.
     332                 :            :                                                 base_byte_offset))
     333         [ #  # ]:          0 :                     || GENERIC_SUBSPACE_COMMAND(obj_desc->field.
     334                 :            :                                                 base_byte_offset)) {
     335                 :            : 
     336                 :            :                         /* Perform the write */
     337                 :            : 
     338                 :            :                         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
     339                 :          0 :                                           "PCC COMD field has been written. Invoking PCC handler now.\n"));
     340                 :            : 
     341                 :          0 :                         status =
     342                 :          0 :                             acpi_ex_access_region(obj_desc, 0,
     343                 :            :                                                   (u64 *)obj_desc->field.
     344                 :          0 :                                                   region_obj->field.
     345                 :            :                                                   internal_pcc_buffer,
     346                 :            :                                                   ACPI_WRITE);
     347                 :          0 :                         return_ACPI_STATUS(status);
     348                 :            :                 }
     349                 :            :                 return (AE_OK);
     350                 :            :         }
     351                 :            : 
     352                 :            :         /* Get a pointer to the data to be written */
     353                 :            : 
     354   [ +  -  -  - ]:        357 :         switch (source_desc->common.type) {
     355                 :        357 :         case ACPI_TYPE_INTEGER:
     356                 :            : 
     357                 :        357 :                 buffer = &source_desc->integer.value;
     358                 :        357 :                 buffer_length = sizeof(source_desc->integer.value);
     359                 :        357 :                 break;
     360                 :            : 
     361                 :          0 :         case ACPI_TYPE_BUFFER:
     362                 :            : 
     363                 :          0 :                 buffer = source_desc->buffer.pointer;
     364                 :          0 :                 buffer_length = source_desc->buffer.length;
     365                 :          0 :                 break;
     366                 :            : 
     367                 :          0 :         case ACPI_TYPE_STRING:
     368                 :            : 
     369                 :          0 :                 buffer = source_desc->string.pointer;
     370                 :          0 :                 buffer_length = source_desc->string.length;
     371                 :          0 :                 break;
     372                 :            : 
     373                 :            :         default:
     374                 :            :                 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
     375                 :            :         }
     376                 :            : 
     377                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
     378                 :            :                           "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
     379                 :            :                           source_desc,
     380                 :            :                           acpi_ut_get_type_name(source_desc->common.type),
     381                 :        357 :                           source_desc->common.type, buffer, buffer_length));
     382                 :            : 
     383                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
     384                 :            :                           "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
     385                 :            :                           obj_desc,
     386                 :            :                           acpi_ut_get_type_name(obj_desc->common.type),
     387                 :            :                           obj_desc->common.type,
     388                 :            :                           obj_desc->common_field.bit_length,
     389                 :            :                           obj_desc->common_field.start_field_bit_offset,
     390                 :        357 :                           obj_desc->common_field.base_byte_offset));
     391                 :            : 
     392                 :            :         /* Lock entire transaction if requested */
     393                 :            : 
     394                 :        357 :         acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
     395                 :            : 
     396                 :            :         /* Write to the field */
     397                 :            : 
     398                 :        357 :         status = acpi_ex_insert_into_field(obj_desc, buffer, buffer_length);
     399                 :        357 :         acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
     400                 :        357 :         return_ACPI_STATUS(status);
     401                 :            : }

Generated by: LCOV version 1.14