linux/drivers/acpi/acpica/exfield.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
   5 *
   6 * Copyright (C) 2000 - 2018, 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
  17ACPI_MODULE_NAME("exfield")
  18
  19/* Local prototypes */
  20static u32
  21acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length);
  22
  23/*******************************************************************************
  24 *
  25 * FUNCTION:    acpi_ex_get_serial_access_length
  26 *
  27 * PARAMETERS:  accessor_type   - The type of the protocol indicated by region
  28 *                                field access attributes
  29 *              access_length   - The access length of the region field
  30 *
  31 * RETURN:      Decoded access length
  32 *
  33 * DESCRIPTION: This routine returns the length of the generic_serial_bus
  34 *              protocol bytes
  35 *
  36 ******************************************************************************/
  37
  38static u32
  39acpi_ex_get_serial_access_length(u32 accessor_type, u32 access_length)
  40{
  41        u32 length;
  42
  43        switch (accessor_type) {
  44        case AML_FIELD_ATTRIB_QUICK:
  45
  46                length = 0;
  47                break;
  48
  49        case AML_FIELD_ATTRIB_SEND_RCV:
  50        case AML_FIELD_ATTRIB_BYTE:
  51
  52                length = 1;
  53                break;
  54
  55        case AML_FIELD_ATTRIB_WORD:
  56        case AML_FIELD_ATTRIB_WORD_CALL:
  57
  58                length = 2;
  59                break;
  60
  61        case AML_FIELD_ATTRIB_MULTIBYTE:
  62        case AML_FIELD_ATTRIB_RAW_BYTES:
  63        case AML_FIELD_ATTRIB_RAW_PROCESS:
  64
  65                length = access_length;
  66                break;
  67
  68        case AML_FIELD_ATTRIB_BLOCK:
  69        case AML_FIELD_ATTRIB_BLOCK_CALL:
  70        default:
  71
  72                length = ACPI_GSBUS_BUFFER_SIZE - 2;
  73                break;
  74        }
  75
  76        return (length);
  77}
  78
  79/*******************************************************************************
  80 *
  81 * FUNCTION:    acpi_ex_read_data_from_field
  82 *
  83 * PARAMETERS:  walk_state          - Current execution state
  84 *              obj_desc            - The named field
  85 *              ret_buffer_desc     - Where the return data object is stored
  86 *
  87 * RETURN:      Status
  88 *
  89 * DESCRIPTION: Read from a named field. Returns either an Integer or a
  90 *              Buffer, depending on the size of the field.
  91 *
  92 ******************************************************************************/
  93
  94acpi_status
  95acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
  96                             union acpi_operand_object *obj_desc,
  97                             union acpi_operand_object **ret_buffer_desc)
  98{
  99        acpi_status status;
 100        union acpi_operand_object *buffer_desc;
 101        acpi_size length;
 102        void *buffer;
 103        u32 function;
 104        u16 accessor_type;
 105
 106        ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
 107
 108        /* Parameter validation */
 109
 110        if (!obj_desc) {
 111                return_ACPI_STATUS(AE_AML_NO_OPERAND);
 112        }
 113        if (!ret_buffer_desc) {
 114                return_ACPI_STATUS(AE_BAD_PARAMETER);
 115        }
 116
 117        if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
 118                /*
 119                 * If the buffer_field arguments have not been previously evaluated,
 120                 * evaluate them now and save the results.
 121                 */
 122                if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
 123                        status = acpi_ds_get_buffer_field_arguments(obj_desc);
 124                        if (ACPI_FAILURE(status)) {
 125                                return_ACPI_STATUS(status);
 126                        }
 127                }
 128        } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
 129                   (obj_desc->field.region_obj->region.space_id ==
 130                    ACPI_ADR_SPACE_SMBUS
 131                    || obj_desc->field.region_obj->region.space_id ==
 132                    ACPI_ADR_SPACE_GSBUS
 133                    || obj_desc->field.region_obj->region.space_id ==
 134                    ACPI_ADR_SPACE_IPMI)) {
 135                /*
 136                 * This is an SMBus, GSBus or IPMI read. We must create a buffer to
 137                 * hold the data and then directly access the region handler.
 138                 *
 139                 * Note: SMBus and GSBus protocol value is passed in upper 16-bits
 140                 * of Function
 141                 */
 142                if (obj_desc->field.region_obj->region.space_id ==
 143                    ACPI_ADR_SPACE_SMBUS) {
 144                        length = ACPI_SMBUS_BUFFER_SIZE;
 145                        function =
 146                            ACPI_READ | (obj_desc->field.attribute << 16);
 147                } else if (obj_desc->field.region_obj->region.space_id ==
 148                           ACPI_ADR_SPACE_GSBUS) {
 149                        accessor_type = obj_desc->field.attribute;
 150                        length =
 151                            acpi_ex_get_serial_access_length(accessor_type,
 152                                                             obj_desc->field.
 153                                                             access_length);
 154
 155                        /*
 156                         * Add additional 2 bytes for the generic_serial_bus data buffer:
 157                         *
 158                         *     Status;    (Byte 0 of the data buffer)
 159                         *     Length;    (Byte 1 of the data buffer)
 160                         *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
 161                         */
 162                        length += 2;
 163                        function = ACPI_READ | (accessor_type << 16);
 164                } else {        /* IPMI */
 165
 166                        length = ACPI_IPMI_BUFFER_SIZE;
 167                        function = ACPI_READ;
 168                }
 169
 170                buffer_desc = acpi_ut_create_buffer_object(length);
 171                if (!buffer_desc) {
 172                        return_ACPI_STATUS(AE_NO_MEMORY);
 173                }
 174
 175                /* Lock entire transaction if requested */
 176
 177                acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
 178
 179                /* Call the region handler for the read */
 180
 181                status = acpi_ex_access_region(obj_desc, 0,
 182                                               ACPI_CAST_PTR(u64,
 183                                                             buffer_desc->
 184                                                             buffer.pointer),
 185                                               function);
 186
 187                acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
 188                goto exit;
 189        }
 190
 191        /*
 192         * Allocate a buffer for the contents of the field.
 193         *
 194         * If the field is larger than the current integer width, create
 195         * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
 196         * the use of arithmetic operators on the returned value if the
 197         * field size is equal or smaller than an Integer.
 198         *
 199         * Note: Field.length is in bits.
 200         */
 201        length =
 202            (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
 203
 204        if (length > acpi_gbl_integer_byte_width) {
 205
 206                /* Field is too large for an Integer, create a Buffer instead */
 207
 208                buffer_desc = acpi_ut_create_buffer_object(length);
 209                if (!buffer_desc) {
 210                        return_ACPI_STATUS(AE_NO_MEMORY);
 211                }
 212                buffer = buffer_desc->buffer.pointer;
 213        } else {
 214                /* Field will fit within an Integer (normal case) */
 215
 216                buffer_desc = acpi_ut_create_integer_object((u64) 0);
 217                if (!buffer_desc) {
 218                        return_ACPI_STATUS(AE_NO_MEMORY);
 219                }
 220
 221                length = acpi_gbl_integer_byte_width;
 222                buffer = &buffer_desc->integer.value;
 223        }
 224
 225        if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
 226            (obj_desc->field.region_obj->region.space_id ==
 227             ACPI_ADR_SPACE_GPIO)) {
 228                /*
 229                 * For GPIO (general_purpose_io), the Address will be the bit offset
 230                 * from the previous Connection() operator, making it effectively a
 231                 * pin number index. The bit_length is the length of the field, which
 232                 * is thus the number of pins.
 233                 */
 234                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 235                                  "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
 236                                  obj_desc->field.pin_number_index,
 237                                  obj_desc->field.bit_length));
 238
 239                /* Lock entire transaction if requested */
 240
 241                acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
 242
 243                /* Perform the write */
 244
 245                status =
 246                    acpi_ex_access_region(obj_desc, 0, (u64 *)buffer,
 247                                          ACPI_READ);
 248
 249                acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
 250                if (ACPI_FAILURE(status)) {
 251                        acpi_ut_remove_reference(buffer_desc);
 252                } else {
 253                        *ret_buffer_desc = buffer_desc;
 254                }
 255                return_ACPI_STATUS(status);
 256        }
 257
 258        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 259                          "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
 260                          obj_desc, obj_desc->common.type, buffer,
 261                          (u32) length));
 262        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 263                          "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
 264                          obj_desc->common_field.bit_length,
 265                          obj_desc->common_field.start_field_bit_offset,
 266                          obj_desc->common_field.base_byte_offset));
 267
 268        /* Lock entire transaction if requested */
 269
 270        acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
 271
 272        /* Read from the field */
 273
 274        status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
 275        acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
 276
 277exit:
 278        if (ACPI_FAILURE(status)) {
 279                acpi_ut_remove_reference(buffer_desc);
 280        } else {
 281                *ret_buffer_desc = buffer_desc;
 282        }
 283
 284        return_ACPI_STATUS(status);
 285}
 286
 287/*******************************************************************************
 288 *
 289 * FUNCTION:    acpi_ex_write_data_to_field
 290 *
 291 * PARAMETERS:  source_desc         - Contains data to write
 292 *              obj_desc            - The named field
 293 *              result_desc         - Where the return value is returned, if any
 294 *
 295 * RETURN:      Status
 296 *
 297 * DESCRIPTION: Write to a named field
 298 *
 299 ******************************************************************************/
 300
 301acpi_status
 302acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
 303                            union acpi_operand_object *obj_desc,
 304                            union acpi_operand_object **result_desc)
 305{
 306        acpi_status status;
 307        u32 length;
 308        void *buffer;
 309        union acpi_operand_object *buffer_desc;
 310        u32 function;
 311        u16 accessor_type;
 312
 313        ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
 314
 315        /* Parameter validation */
 316
 317        if (!source_desc || !obj_desc) {
 318                return_ACPI_STATUS(AE_AML_NO_OPERAND);
 319        }
 320
 321        if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
 322                /*
 323                 * If the buffer_field arguments have not been previously evaluated,
 324                 * evaluate them now and save the results.
 325                 */
 326                if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
 327                        status = acpi_ds_get_buffer_field_arguments(obj_desc);
 328                        if (ACPI_FAILURE(status)) {
 329                                return_ACPI_STATUS(status);
 330                        }
 331                }
 332        } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
 333                   (obj_desc->field.region_obj->region.space_id ==
 334                    ACPI_ADR_SPACE_SMBUS
 335                    || obj_desc->field.region_obj->region.space_id ==
 336                    ACPI_ADR_SPACE_GSBUS
 337                    || obj_desc->field.region_obj->region.space_id ==
 338                    ACPI_ADR_SPACE_IPMI)) {
 339                /*
 340                 * This is an SMBus, GSBus or IPMI write. We will bypass the entire
 341                 * field mechanism and handoff the buffer directly to the handler.
 342                 * For these address spaces, the buffer is bi-directional; on a
 343                 * write, return data is returned in the same buffer.
 344                 *
 345                 * Source must be a buffer of sufficient size:
 346                 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
 347                 * ACPI_IPMI_BUFFER_SIZE.
 348                 *
 349                 * Note: SMBus and GSBus protocol type is passed in upper 16-bits
 350                 * of Function
 351                 */
 352                if (source_desc->common.type != ACPI_TYPE_BUFFER) {
 353                        ACPI_ERROR((AE_INFO,
 354                                    "SMBus/IPMI/GenericSerialBus write requires "
 355                                    "Buffer, found type %s",
 356                                    acpi_ut_get_object_type_name(source_desc)));
 357
 358                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 359                }
 360
 361                if (obj_desc->field.region_obj->region.space_id ==
 362                    ACPI_ADR_SPACE_SMBUS) {
 363                        length = ACPI_SMBUS_BUFFER_SIZE;
 364                        function =
 365                            ACPI_WRITE | (obj_desc->field.attribute << 16);
 366                } else if (obj_desc->field.region_obj->region.space_id ==
 367                           ACPI_ADR_SPACE_GSBUS) {
 368                        accessor_type = obj_desc->field.attribute;
 369                        length =
 370                            acpi_ex_get_serial_access_length(accessor_type,
 371                                                             obj_desc->field.
 372                                                             access_length);
 373
 374                        /*
 375                         * Add additional 2 bytes for the generic_serial_bus data buffer:
 376                         *
 377                         *     Status;    (Byte 0 of the data buffer)
 378                         *     Length;    (Byte 1 of the data buffer)
 379                         *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
 380                         */
 381                        length += 2;
 382                        function = ACPI_WRITE | (accessor_type << 16);
 383                } else {        /* IPMI */
 384
 385                        length = ACPI_IPMI_BUFFER_SIZE;
 386                        function = ACPI_WRITE;
 387                }
 388
 389                if (source_desc->buffer.length < length) {
 390                        ACPI_ERROR((AE_INFO,
 391                                    "SMBus/IPMI/GenericSerialBus write requires "
 392                                    "Buffer of length %u, found length %u",
 393                                    length, source_desc->buffer.length));
 394
 395                        return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
 396                }
 397
 398                /* Create the bi-directional buffer */
 399
 400                buffer_desc = acpi_ut_create_buffer_object(length);
 401                if (!buffer_desc) {
 402                        return_ACPI_STATUS(AE_NO_MEMORY);
 403                }
 404
 405                buffer = buffer_desc->buffer.pointer;
 406                memcpy(buffer, source_desc->buffer.pointer, length);
 407
 408                /* Lock entire transaction if requested */
 409
 410                acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
 411
 412                /*
 413                 * Perform the write (returns status and perhaps data in the
 414                 * same buffer)
 415                 */
 416                status =
 417                    acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, function);
 418                acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
 419
 420                *result_desc = buffer_desc;
 421                return_ACPI_STATUS(status);
 422        } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
 423                   (obj_desc->field.region_obj->region.space_id ==
 424                    ACPI_ADR_SPACE_GPIO)) {
 425                /*
 426                 * For GPIO (general_purpose_io), we will bypass the entire field
 427                 * mechanism and handoff the bit address and bit width directly to
 428                 * the handler. The Address will be the bit offset
 429                 * from the previous Connection() operator, making it effectively a
 430                 * pin number index. The bit_length is the length of the field, which
 431                 * is thus the number of pins.
 432                 */
 433                if (source_desc->common.type != ACPI_TYPE_INTEGER) {
 434                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 435                }
 436
 437                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 438                                  "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]: Pin %u Bits %u\n",
 439                                  acpi_ut_get_type_name(source_desc->common.
 440                                                        type),
 441                                  source_desc->common.type,
 442                                  (u32)source_desc->integer.value,
 443                                  obj_desc->field.pin_number_index,
 444                                  obj_desc->field.bit_length));
 445
 446                buffer = &source_desc->integer.value;
 447
 448                /* Lock entire transaction if requested */
 449
 450                acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
 451
 452                /* Perform the write */
 453
 454                status =
 455                    acpi_ex_access_region(obj_desc, 0, (u64 *)buffer,
 456                                          ACPI_WRITE);
 457                acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
 458                return_ACPI_STATUS(status);
 459        }
 460
 461        /* Get a pointer to the data to be written */
 462
 463        switch (source_desc->common.type) {
 464        case ACPI_TYPE_INTEGER:
 465
 466                buffer = &source_desc->integer.value;
 467                length = sizeof(source_desc->integer.value);
 468                break;
 469
 470        case ACPI_TYPE_BUFFER:
 471
 472                buffer = source_desc->buffer.pointer;
 473                length = source_desc->buffer.length;
 474                break;
 475
 476        case ACPI_TYPE_STRING:
 477
 478                buffer = source_desc->string.pointer;
 479                length = source_desc->string.length;
 480                break;
 481
 482        default:
 483
 484                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 485        }
 486
 487        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 488                          "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
 489                          source_desc,
 490                          acpi_ut_get_type_name(source_desc->common.type),
 491                          source_desc->common.type, buffer, length));
 492
 493        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 494                          "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
 495                          obj_desc,
 496                          acpi_ut_get_type_name(obj_desc->common.type),
 497                          obj_desc->common.type,
 498                          obj_desc->common_field.bit_length,
 499                          obj_desc->common_field.start_field_bit_offset,
 500                          obj_desc->common_field.base_byte_offset));
 501
 502        /* Lock entire transaction if requested */
 503
 504        acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
 505
 506        /* Write to the field */
 507
 508        status = acpi_ex_insert_into_field(obj_desc, buffer, length);
 509        acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
 510
 511        return_ACPI_STATUS(status);
 512}
 513