linux/drivers/acpi/acpica/exfldio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: exfldio - Aml Field I/O
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acinterp.h"
  13#include "amlcode.h"
  14#include "acevents.h"
  15#include "acdispat.h"
  16
  17#define _COMPONENT          ACPI_EXECUTER
  18ACPI_MODULE_NAME("exfldio")
  19
  20/* Local prototypes */
  21static acpi_status
  22acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
  23                       u32 field_datum_byte_offset, u64 *value, u32 read_write);
  24
  25static u8
  26acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value);
  27
  28static acpi_status
  29acpi_ex_setup_region(union acpi_operand_object *obj_desc,
  30                     u32 field_datum_byte_offset);
  31
  32/*******************************************************************************
  33 *
  34 * FUNCTION:    acpi_ex_setup_region
  35 *
  36 * PARAMETERS:  obj_desc                - Field to be read or written
  37 *              field_datum_byte_offset - Byte offset of this datum within the
  38 *                                        parent field
  39 *
  40 * RETURN:      Status
  41 *
  42 * DESCRIPTION: Common processing for acpi_ex_extract_from_field and
  43 *              acpi_ex_insert_into_field. Initialize the Region if necessary and
  44 *              validate the request.
  45 *
  46 ******************************************************************************/
  47
  48static acpi_status
  49acpi_ex_setup_region(union acpi_operand_object *obj_desc,
  50                     u32 field_datum_byte_offset)
  51{
  52        acpi_status status = AE_OK;
  53        union acpi_operand_object *rgn_desc;
  54        u8 space_id;
  55
  56        ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset);
  57
  58        rgn_desc = obj_desc->common_field.region_obj;
  59
  60        /* We must have a valid region */
  61
  62        if (rgn_desc->common.type != ACPI_TYPE_REGION) {
  63                ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)",
  64                            rgn_desc->common.type,
  65                            acpi_ut_get_object_type_name(rgn_desc)));
  66
  67                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  68        }
  69
  70        space_id = rgn_desc->region.space_id;
  71
  72        /* Validate the Space ID */
  73
  74        if (!acpi_is_valid_space_id(space_id)) {
  75                ACPI_ERROR((AE_INFO,
  76                            "Invalid/unknown Address Space ID: 0x%2.2X",
  77                            space_id));
  78                return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
  79        }
  80
  81        /*
  82         * If the Region Address and Length have not been previously evaluated,
  83         * evaluate them now and save the results.
  84         */
  85        if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) {
  86                status = acpi_ds_get_region_arguments(rgn_desc);
  87                if (ACPI_FAILURE(status)) {
  88                        return_ACPI_STATUS(status);
  89                }
  90        }
  91
  92        /*
  93         * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
  94         * address space and the request cannot be directly validated
  95         */
  96        if (space_id == ACPI_ADR_SPACE_SMBUS ||
  97            space_id == ACPI_ADR_SPACE_GSBUS ||
  98            space_id == ACPI_ADR_SPACE_IPMI) {
  99
 100                /* SMBus or IPMI has a non-linear address space */
 101
 102                return_ACPI_STATUS(AE_OK);
 103        }
 104#ifdef ACPI_UNDER_DEVELOPMENT
 105        /*
 106         * If the Field access is any_acc, we can now compute the optimal
 107         * access (because we know know the length of the parent region)
 108         */
 109        if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
 110                if (ACPI_FAILURE(status)) {
 111                        return_ACPI_STATUS(status);
 112                }
 113        }
 114#endif
 115
 116        /*
 117         * Validate the request. The entire request from the byte offset for a
 118         * length of one field datum (access width) must fit within the region.
 119         * (Region length is specified in bytes)
 120         */
 121        if (rgn_desc->region.length <
 122            (obj_desc->common_field.base_byte_offset + field_datum_byte_offset +
 123             obj_desc->common_field.access_byte_width)) {
 124                if (acpi_gbl_enable_interpreter_slack) {
 125                        /*
 126                         * Slack mode only:  We will go ahead and allow access to this
 127                         * field if it is within the region length rounded up to the next
 128                         * access width boundary. acpi_size cast for 64-bit compile.
 129                         */
 130                        if (ACPI_ROUND_UP(rgn_desc->region.length,
 131                                          obj_desc->common_field.
 132                                          access_byte_width) >=
 133                            ((acpi_size)obj_desc->common_field.
 134                             base_byte_offset +
 135                             obj_desc->common_field.access_byte_width +
 136                             field_datum_byte_offset)) {
 137                                return_ACPI_STATUS(AE_OK);
 138                        }
 139                }
 140
 141                if (rgn_desc->region.length <
 142                    obj_desc->common_field.access_byte_width) {
 143                        /*
 144                         * This is the case where the access_type (acc_word, etc.) is wider
 145                         * than the region itself. For example, a region of length one
 146                         * byte, and a field with Dword access specified.
 147                         */
 148                        ACPI_ERROR((AE_INFO,
 149                                    "Field [%4.4s] access width (%u bytes) "
 150                                    "too large for region [%4.4s] (length %u)",
 151                                    acpi_ut_get_node_name(obj_desc->
 152                                                          common_field.node),
 153                                    obj_desc->common_field.access_byte_width,
 154                                    acpi_ut_get_node_name(rgn_desc->region.
 155                                                          node),
 156                                    rgn_desc->region.length));
 157                }
 158
 159                /*
 160                 * Offset rounded up to next multiple of field width
 161                 * exceeds region length, indicate an error
 162                 */
 163                ACPI_ERROR((AE_INFO,
 164                            "Field [%4.4s] Base+Offset+Width %u+%u+%u "
 165                            "is beyond end of region [%4.4s] (length %u)",
 166                            acpi_ut_get_node_name(obj_desc->common_field.node),
 167                            obj_desc->common_field.base_byte_offset,
 168                            field_datum_byte_offset,
 169                            obj_desc->common_field.access_byte_width,
 170                            acpi_ut_get_node_name(rgn_desc->region.node),
 171                            rgn_desc->region.length));
 172
 173                return_ACPI_STATUS(AE_AML_REGION_LIMIT);
 174        }
 175
 176        return_ACPI_STATUS(AE_OK);
 177}
 178
 179/*******************************************************************************
 180 *
 181 * FUNCTION:    acpi_ex_access_region
 182 *
 183 * PARAMETERS:  obj_desc                - Field to be read
 184 *              field_datum_byte_offset - Byte offset of this datum within the
 185 *                                        parent field
 186 *              value                   - Where to store value (must at least
 187 *                                        64 bits)
 188 *              function                - Read or Write flag plus other region-
 189 *                                        dependent flags
 190 *
 191 * RETURN:      Status
 192 *
 193 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
 194 *
 195 ******************************************************************************/
 196
 197acpi_status
 198acpi_ex_access_region(union acpi_operand_object *obj_desc,
 199                      u32 field_datum_byte_offset, u64 *value, u32 function)
 200{
 201        acpi_status status;
 202        union acpi_operand_object *rgn_desc;
 203        u32 region_offset;
 204
 205        ACPI_FUNCTION_TRACE(ex_access_region);
 206
 207        /*
 208         * Ensure that the region operands are fully evaluated and verify
 209         * the validity of the request
 210         */
 211        status = acpi_ex_setup_region(obj_desc, field_datum_byte_offset);
 212        if (ACPI_FAILURE(status)) {
 213                return_ACPI_STATUS(status);
 214        }
 215
 216        /*
 217         * The physical address of this field datum is:
 218         *
 219         * 1) The base of the region, plus
 220         * 2) The base offset of the field, plus
 221         * 3) The current offset into the field
 222         */
 223        rgn_desc = obj_desc->common_field.region_obj;
 224        region_offset =
 225            obj_desc->common_field.base_byte_offset + field_datum_byte_offset;
 226
 227        if ((function & ACPI_IO_MASK) == ACPI_READ) {
 228                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[READ]"));
 229        } else {
 230                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[WRITE]"));
 231        }
 232
 233        ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
 234                              " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
 235                              acpi_ut_get_region_name(rgn_desc->region.
 236                                                      space_id),
 237                              rgn_desc->region.space_id,
 238                              obj_desc->common_field.access_byte_width,
 239                              obj_desc->common_field.base_byte_offset,
 240                              field_datum_byte_offset,
 241                              ACPI_FORMAT_UINT64(rgn_desc->region.address +
 242                                                 region_offset)));
 243
 244        /* Invoke the appropriate address_space/op_region handler */
 245
 246        status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc,
 247                                                function, region_offset,
 248                                                ACPI_MUL_8(obj_desc->
 249                                                           common_field.
 250                                                           access_byte_width),
 251                                                value);
 252
 253        if (ACPI_FAILURE(status)) {
 254                if (status == AE_NOT_IMPLEMENTED) {
 255                        ACPI_ERROR((AE_INFO,
 256                                    "Region %s (ID=%u) not implemented",
 257                                    acpi_ut_get_region_name(rgn_desc->region.
 258                                                            space_id),
 259                                    rgn_desc->region.space_id));
 260                } else if (status == AE_NOT_EXIST) {
 261                        ACPI_ERROR((AE_INFO,
 262                                    "Region %s (ID=%u) has no handler",
 263                                    acpi_ut_get_region_name(rgn_desc->region.
 264                                                            space_id),
 265                                    rgn_desc->region.space_id));
 266                }
 267        }
 268
 269        return_ACPI_STATUS(status);
 270}
 271
 272/*******************************************************************************
 273 *
 274 * FUNCTION:    acpi_ex_register_overflow
 275 *
 276 * PARAMETERS:  obj_desc                - Register(Field) to be written
 277 *              value                   - Value to be stored
 278 *
 279 * RETURN:      TRUE if value overflows the field, FALSE otherwise
 280 *
 281 * DESCRIPTION: Check if a value is out of range of the field being written.
 282 *              Used to check if the values written to Index and Bank registers
 283 *              are out of range. Normally, the value is simply truncated
 284 *              to fit the field, but this case is most likely a serious
 285 *              coding error in the ASL.
 286 *
 287 ******************************************************************************/
 288
 289static u8
 290acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
 291{
 292
 293        if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
 294                /*
 295                 * The field is large enough to hold the maximum integer, so we can
 296                 * never overflow it.
 297                 */
 298                return (FALSE);
 299        }
 300
 301        if (value >= ((u64) 1 << obj_desc->common_field.bit_length)) {
 302                /*
 303                 * The Value is larger than the maximum value that can fit into
 304                 * the register.
 305                 */
 306                ACPI_ERROR((AE_INFO,
 307                            "Index value 0x%8.8X%8.8X overflows field width 0x%X",
 308                            ACPI_FORMAT_UINT64(value),
 309                            obj_desc->common_field.bit_length));
 310
 311                return (TRUE);
 312        }
 313
 314        /* The Value will fit into the field with no truncation */
 315
 316        return (FALSE);
 317}
 318
 319/*******************************************************************************
 320 *
 321 * FUNCTION:    acpi_ex_field_datum_io
 322 *
 323 * PARAMETERS:  obj_desc                - Field to be read
 324 *              field_datum_byte_offset - Byte offset of this datum within the
 325 *                                        parent field
 326 *              value                   - Where to store value (must be 64 bits)
 327 *              read_write              - Read or Write flag
 328 *
 329 * RETURN:      Status
 330 *
 331 * DESCRIPTION: Read or Write a single datum of a field. The field_type is
 332 *              demultiplexed here to handle the different types of fields
 333 *              (buffer_field, region_field, index_field, bank_field)
 334 *
 335 ******************************************************************************/
 336
 337static acpi_status
 338acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
 339                       u32 field_datum_byte_offset, u64 *value, u32 read_write)
 340{
 341        acpi_status status;
 342        u64 local_value;
 343
 344        ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset);
 345
 346        if (read_write == ACPI_READ) {
 347                if (!value) {
 348                        local_value = 0;
 349
 350                        /* To support reads without saving return value */
 351                        value = &local_value;
 352                }
 353
 354                /* Clear the entire return buffer first, [Very Important!] */
 355
 356                *value = 0;
 357        }
 358
 359        /*
 360         * The four types of fields are:
 361         *
 362         * buffer_field - Read/write from/to a Buffer
 363         * region_field - Read/write from/to a Operation Region.
 364         * bank_field  - Write to a Bank Register, then read/write from/to an
 365         *               operation_region
 366         * index_field - Write to an Index Register, then read/write from/to a
 367         *               Data Register
 368         */
 369        switch (obj_desc->common.type) {
 370        case ACPI_TYPE_BUFFER_FIELD:
 371                /*
 372                 * If the buffer_field arguments have not been previously evaluated,
 373                 * evaluate them now and save the results.
 374                 */
 375                if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
 376                        status = acpi_ds_get_buffer_field_arguments(obj_desc);
 377                        if (ACPI_FAILURE(status)) {
 378                                return_ACPI_STATUS(status);
 379                        }
 380                }
 381
 382                if (read_write == ACPI_READ) {
 383                        /*
 384                         * Copy the data from the source buffer.
 385                         * Length is the field width in bytes.
 386                         */
 387                        memcpy(value,
 388                               (obj_desc->buffer_field.buffer_obj)->buffer.
 389                               pointer +
 390                               obj_desc->buffer_field.base_byte_offset +
 391                               field_datum_byte_offset,
 392                               obj_desc->common_field.access_byte_width);
 393                } else {
 394                        /*
 395                         * Copy the data to the target buffer.
 396                         * Length is the field width in bytes.
 397                         */
 398                        memcpy((obj_desc->buffer_field.buffer_obj)->buffer.
 399                               pointer +
 400                               obj_desc->buffer_field.base_byte_offset +
 401                               field_datum_byte_offset, value,
 402                               obj_desc->common_field.access_byte_width);
 403                }
 404
 405                status = AE_OK;
 406                break;
 407
 408        case ACPI_TYPE_LOCAL_BANK_FIELD:
 409                /*
 410                 * Ensure that the bank_value is not beyond the capacity of
 411                 * the register
 412                 */
 413                if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj,
 414                                              (u64) obj_desc->bank_field.
 415                                              value)) {
 416                        return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
 417                }
 418
 419                /*
 420                 * For bank_fields, we must write the bank_value to the bank_register
 421                 * (itself a region_field) before we can access the data.
 422                 */
 423                status =
 424                    acpi_ex_insert_into_field(obj_desc->bank_field.bank_obj,
 425                                              &obj_desc->bank_field.value,
 426                                              sizeof(obj_desc->bank_field.
 427                                                     value));
 428                if (ACPI_FAILURE(status)) {
 429                        return_ACPI_STATUS(status);
 430                }
 431
 432                /*
 433                 * Now that the Bank has been selected, fall through to the
 434                 * region_field case and write the datum to the Operation Region
 435                 */
 436
 437                ACPI_FALLTHROUGH;
 438
 439        case ACPI_TYPE_LOCAL_REGION_FIELD:
 440                /*
 441                 * For simple region_fields, we just directly access the owning
 442                 * Operation Region.
 443                 */
 444                status =
 445                    acpi_ex_access_region(obj_desc, field_datum_byte_offset,
 446                                          value, read_write);
 447                break;
 448
 449        case ACPI_TYPE_LOCAL_INDEX_FIELD:
 450                /*
 451                 * Ensure that the index_value is not beyond the capacity of
 452                 * the register
 453                 */
 454                if (acpi_ex_register_overflow(obj_desc->index_field.index_obj,
 455                                              (u64) obj_desc->index_field.
 456                                              value)) {
 457                        return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
 458                }
 459
 460                /* Write the index value to the index_register (itself a region_field) */
 461
 462                field_datum_byte_offset += obj_desc->index_field.value;
 463
 464                ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 465                                  "Write to Index Register: Value %8.8X\n",
 466                                  field_datum_byte_offset));
 467
 468                status =
 469                    acpi_ex_insert_into_field(obj_desc->index_field.index_obj,
 470                                              &field_datum_byte_offset,
 471                                              sizeof(field_datum_byte_offset));
 472                if (ACPI_FAILURE(status)) {
 473                        return_ACPI_STATUS(status);
 474                }
 475
 476                if (read_write == ACPI_READ) {
 477
 478                        /* Read the datum from the data_register */
 479
 480                        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 481                                          "Read from Data Register\n"));
 482
 483                        status =
 484                            acpi_ex_extract_from_field(obj_desc->index_field.
 485                                                       data_obj, value,
 486                                                       sizeof(u64));
 487                } else {
 488                        /* Write the datum to the data_register */
 489
 490                        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 491                                          "Write to Data Register: Value %8.8X%8.8X\n",
 492                                          ACPI_FORMAT_UINT64(*value)));
 493
 494                        status =
 495                            acpi_ex_insert_into_field(obj_desc->index_field.
 496                                                      data_obj, value,
 497                                                      sizeof(u64));
 498                }
 499                break;
 500
 501        default:
 502
 503                ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %u",
 504                            obj_desc->common.type));
 505                status = AE_AML_INTERNAL;
 506                break;
 507        }
 508
 509        if (ACPI_SUCCESS(status)) {
 510                if (read_write == ACPI_READ) {
 511                        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 512                                          "Value Read %8.8X%8.8X, Width %u\n",
 513                                          ACPI_FORMAT_UINT64(*value),
 514                                          obj_desc->common_field.
 515                                          access_byte_width));
 516                } else {
 517                        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 518                                          "Value Written %8.8X%8.8X, Width %u\n",
 519                                          ACPI_FORMAT_UINT64(*value),
 520                                          obj_desc->common_field.
 521                                          access_byte_width));
 522                }
 523        }
 524
 525        return_ACPI_STATUS(status);
 526}
 527
 528/*******************************************************************************
 529 *
 530 * FUNCTION:    acpi_ex_write_with_update_rule
 531 *
 532 * PARAMETERS:  obj_desc                - Field to be written
 533 *              mask                    - bitmask within field datum
 534 *              field_value             - Value to write
 535 *              field_datum_byte_offset - Offset of datum within field
 536 *
 537 * RETURN:      Status
 538 *
 539 * DESCRIPTION: Apply the field update rule to a field write
 540 *
 541 ******************************************************************************/
 542
 543acpi_status
 544acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
 545                               u64 mask,
 546                               u64 field_value, u32 field_datum_byte_offset)
 547{
 548        acpi_status status = AE_OK;
 549        u64 merged_value;
 550        u64 current_value;
 551
 552        ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);
 553
 554        /* Start with the new bits  */
 555
 556        merged_value = field_value;
 557
 558        /* If the mask is all ones, we don't need to worry about the update rule */
 559
 560        if (mask != ACPI_UINT64_MAX) {
 561
 562                /* Decode the update rule */
 563
 564                switch (obj_desc->common_field.
 565                        field_flags & AML_FIELD_UPDATE_RULE_MASK) {
 566                case AML_FIELD_UPDATE_PRESERVE:
 567                        /*
 568                         * Check if update rule needs to be applied (not if mask is all
 569                         * ones)  The left shift drops the bits we want to ignore.
 570                         */
 571                        if ((~mask << (ACPI_MUL_8(sizeof(mask)) -
 572                                       ACPI_MUL_8(obj_desc->common_field.
 573                                                  access_byte_width))) != 0) {
 574                                /*
 575                                 * Read the current contents of the byte/word/dword containing
 576                                 * the field, and merge with the new field value.
 577                                 */
 578                                status =
 579                                    acpi_ex_field_datum_io(obj_desc,
 580                                                           field_datum_byte_offset,
 581                                                           &current_value,
 582                                                           ACPI_READ);
 583                                if (ACPI_FAILURE(status)) {
 584                                        return_ACPI_STATUS(status);
 585                                }
 586
 587                                merged_value |= (current_value & ~mask);
 588                        }
 589                        break;
 590
 591                case AML_FIELD_UPDATE_WRITE_AS_ONES:
 592
 593                        /* Set positions outside the field to all ones */
 594
 595                        merged_value |= ~mask;
 596                        break;
 597
 598                case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
 599
 600                        /* Set positions outside the field to all zeros */
 601
 602                        merged_value &= mask;
 603                        break;
 604
 605                default:
 606
 607                        ACPI_ERROR((AE_INFO,
 608                                    "Unknown UpdateRule value: 0x%X",
 609                                    (obj_desc->common_field.field_flags &
 610                                     AML_FIELD_UPDATE_RULE_MASK)));
 611                        return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
 612                }
 613        }
 614
 615        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 616                          "Mask %8.8X%8.8X, DatumOffset %X, Width %X, "
 617                          "Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
 618                          ACPI_FORMAT_UINT64(mask),
 619                          field_datum_byte_offset,
 620                          obj_desc->common_field.access_byte_width,
 621                          ACPI_FORMAT_UINT64(field_value),
 622                          ACPI_FORMAT_UINT64(merged_value)));
 623
 624        /* Write the merged value */
 625
 626        status =
 627            acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset,
 628                                   &merged_value, ACPI_WRITE);
 629
 630        return_ACPI_STATUS(status);
 631}
 632
 633/*******************************************************************************
 634 *
 635 * FUNCTION:    acpi_ex_extract_from_field
 636 *
 637 * PARAMETERS:  obj_desc            - Field to be read
 638 *              buffer              - Where to store the field data
 639 *              buffer_length       - Length of Buffer
 640 *
 641 * RETURN:      Status
 642 *
 643 * DESCRIPTION: Retrieve the current value of the given field
 644 *
 645 ******************************************************************************/
 646
 647acpi_status
 648acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
 649                           void *buffer, u32 buffer_length)
 650{
 651        acpi_status status;
 652        u64 raw_datum;
 653        u64 merged_datum;
 654        u32 field_offset = 0;
 655        u32 buffer_offset = 0;
 656        u32 buffer_tail_bits;
 657        u32 datum_count;
 658        u32 field_datum_count;
 659        u32 access_bit_width;
 660        u32 i;
 661
 662        ACPI_FUNCTION_TRACE(ex_extract_from_field);
 663
 664        /* Validate target buffer and clear it */
 665
 666        if (buffer_length <
 667            ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
 668                ACPI_ERROR((AE_INFO,
 669                            "Field size %u (bits) is too large for buffer (%u)",
 670                            obj_desc->common_field.bit_length, buffer_length));
 671
 672                return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
 673        }
 674
 675        memset(buffer, 0, buffer_length);
 676        access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
 677
 678        /* Handle the simple case here */
 679
 680        if ((obj_desc->common_field.start_field_bit_offset == 0) &&
 681            (obj_desc->common_field.bit_length == access_bit_width)) {
 682                if (buffer_length >= sizeof(u64)) {
 683                        status =
 684                            acpi_ex_field_datum_io(obj_desc, 0, buffer,
 685                                                   ACPI_READ);
 686                } else {
 687                        /* Use raw_datum (u64) to handle buffers < 64 bits */
 688
 689                        status =
 690                            acpi_ex_field_datum_io(obj_desc, 0, &raw_datum,
 691                                                   ACPI_READ);
 692                        memcpy(buffer, &raw_datum, buffer_length);
 693                }
 694
 695                return_ACPI_STATUS(status);
 696        }
 697
 698/* TBD: Move to common setup code */
 699
 700        /* Field algorithm is limited to sizeof(u64), truncate if needed */
 701
 702        if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
 703                obj_desc->common_field.access_byte_width = sizeof(u64);
 704                access_bit_width = sizeof(u64) * 8;
 705        }
 706
 707        /* Compute the number of datums (access width data items) */
 708
 709        datum_count =
 710            ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
 711                             access_bit_width);
 712
 713        field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
 714                                             obj_desc->common_field.
 715                                             start_field_bit_offset,
 716                                             access_bit_width);
 717
 718        /* Priming read from the field */
 719
 720        status =
 721            acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
 722                                   ACPI_READ);
 723        if (ACPI_FAILURE(status)) {
 724                return_ACPI_STATUS(status);
 725        }
 726        merged_datum =
 727            raw_datum >> obj_desc->common_field.start_field_bit_offset;
 728
 729        /* Read the rest of the field */
 730
 731        for (i = 1; i < field_datum_count; i++) {
 732
 733                /* Get next input datum from the field */
 734
 735                field_offset += obj_desc->common_field.access_byte_width;
 736                status =
 737                    acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
 738                                           ACPI_READ);
 739                if (ACPI_FAILURE(status)) {
 740                        return_ACPI_STATUS(status);
 741                }
 742
 743                /*
 744                 * Merge with previous datum if necessary.
 745                 *
 746                 * Note: Before the shift, check if the shift value will be larger than
 747                 * the integer size. If so, there is no need to perform the operation.
 748                 * This avoids the differences in behavior between different compilers
 749                 * concerning shift values larger than the target data width.
 750                 */
 751                if (access_bit_width -
 752                    obj_desc->common_field.start_field_bit_offset <
 753                    ACPI_INTEGER_BIT_SIZE) {
 754                        merged_datum |=
 755                            raw_datum << (access_bit_width -
 756                                          obj_desc->common_field.
 757                                          start_field_bit_offset);
 758                }
 759
 760                if (i == datum_count) {
 761                        break;
 762                }
 763
 764                /* Write merged datum to target buffer */
 765
 766                memcpy(((char *)buffer) + buffer_offset, &merged_datum,
 767                       ACPI_MIN(obj_desc->common_field.access_byte_width,
 768                                buffer_length - buffer_offset));
 769
 770                buffer_offset += obj_desc->common_field.access_byte_width;
 771                merged_datum =
 772                    raw_datum >> obj_desc->common_field.start_field_bit_offset;
 773        }
 774
 775        /* Mask off any extra bits in the last datum */
 776
 777        buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
 778        if (buffer_tail_bits) {
 779                merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
 780        }
 781
 782        /* Write the last datum to the buffer */
 783
 784        memcpy(((char *)buffer) + buffer_offset, &merged_datum,
 785               ACPI_MIN(obj_desc->common_field.access_byte_width,
 786                        buffer_length - buffer_offset));
 787
 788        return_ACPI_STATUS(AE_OK);
 789}
 790
 791/*******************************************************************************
 792 *
 793 * FUNCTION:    acpi_ex_insert_into_field
 794 *
 795 * PARAMETERS:  obj_desc            - Field to be written
 796 *              buffer              - Data to be written
 797 *              buffer_length       - Length of Buffer
 798 *
 799 * RETURN:      Status
 800 *
 801 * DESCRIPTION: Store the Buffer contents into the given field
 802 *
 803 ******************************************************************************/
 804
 805acpi_status
 806acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
 807                          void *buffer, u32 buffer_length)
 808{
 809        void *new_buffer;
 810        acpi_status status;
 811        u64 mask;
 812        u64 width_mask;
 813        u64 merged_datum;
 814        u64 raw_datum = 0;
 815        u32 field_offset = 0;
 816        u32 buffer_offset = 0;
 817        u32 buffer_tail_bits;
 818        u32 datum_count;
 819        u32 field_datum_count;
 820        u32 access_bit_width;
 821        u32 required_length;
 822        u32 i;
 823
 824        ACPI_FUNCTION_TRACE(ex_insert_into_field);
 825
 826        /* Validate input buffer */
 827
 828        new_buffer = NULL;
 829        required_length =
 830            ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
 831
 832        /*
 833         * We must have a buffer that is at least as long as the field
 834         * we are writing to. This is because individual fields are
 835         * indivisible and partial writes are not supported -- as per
 836         * the ACPI specification.
 837         */
 838        if (buffer_length < required_length) {
 839
 840                /* We need to create a new buffer */
 841
 842                new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
 843                if (!new_buffer) {
 844                        return_ACPI_STATUS(AE_NO_MEMORY);
 845                }
 846
 847                /*
 848                 * Copy the original data to the new buffer, starting
 849                 * at Byte zero. All unused (upper) bytes of the
 850                 * buffer will be 0.
 851                 */
 852                memcpy((char *)new_buffer, (char *)buffer, buffer_length);
 853                buffer = new_buffer;
 854                buffer_length = required_length;
 855        }
 856
 857/* TBD: Move to common setup code */
 858
 859        /* Algo is limited to sizeof(u64), so cut the access_byte_width */
 860        if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
 861                obj_desc->common_field.access_byte_width = sizeof(u64);
 862        }
 863
 864        access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
 865
 866        /* Create the bitmasks used for bit insertion */
 867
 868        width_mask = ACPI_MASK_BITS_ABOVE_64(access_bit_width);
 869        mask = width_mask &
 870            ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);
 871
 872        /* Compute the number of datums (access width data items) */
 873
 874        datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
 875                                       access_bit_width);
 876
 877        field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
 878                                             obj_desc->common_field.
 879                                             start_field_bit_offset,
 880                                             access_bit_width);
 881
 882        /* Get initial Datum from the input buffer */
 883
 884        memcpy(&raw_datum, buffer,
 885               ACPI_MIN(obj_desc->common_field.access_byte_width,
 886                        buffer_length - buffer_offset));
 887
 888        merged_datum =
 889            raw_datum << obj_desc->common_field.start_field_bit_offset;
 890
 891        /* Write the entire field */
 892
 893        for (i = 1; i < field_datum_count; i++) {
 894
 895                /* Write merged datum to the target field */
 896
 897                merged_datum &= mask;
 898                status =
 899                    acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum,
 900                                                   field_offset);
 901                if (ACPI_FAILURE(status)) {
 902                        goto exit;
 903                }
 904
 905                field_offset += obj_desc->common_field.access_byte_width;
 906
 907                /*
 908                 * Start new output datum by merging with previous input datum
 909                 * if necessary.
 910                 *
 911                 * Note: Before the shift, check if the shift value will be larger than
 912                 * the integer size. If so, there is no need to perform the operation.
 913                 * This avoids the differences in behavior between different compilers
 914                 * concerning shift values larger than the target data width.
 915                 */
 916                if ((access_bit_width -
 917                     obj_desc->common_field.start_field_bit_offset) <
 918                    ACPI_INTEGER_BIT_SIZE) {
 919                        merged_datum =
 920                            raw_datum >> (access_bit_width -
 921                                          obj_desc->common_field.
 922                                          start_field_bit_offset);
 923                } else {
 924                        merged_datum = 0;
 925                }
 926
 927                mask = width_mask;
 928
 929                if (i == datum_count) {
 930                        break;
 931                }
 932
 933                /* Get the next input datum from the buffer */
 934
 935                buffer_offset += obj_desc->common_field.access_byte_width;
 936                memcpy(&raw_datum, ((char *)buffer) + buffer_offset,
 937                       ACPI_MIN(obj_desc->common_field.access_byte_width,
 938                                buffer_length - buffer_offset));
 939
 940                merged_datum |=
 941                    raw_datum << obj_desc->common_field.start_field_bit_offset;
 942        }
 943
 944        /* Mask off any extra bits in the last datum */
 945
 946        buffer_tail_bits = (obj_desc->common_field.bit_length +
 947                            obj_desc->common_field.start_field_bit_offset) %
 948            access_bit_width;
 949        if (buffer_tail_bits) {
 950                mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
 951        }
 952
 953        /* Write the last datum to the field */
 954
 955        merged_datum &= mask;
 956        status =
 957            acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum,
 958                                           field_offset);
 959
 960exit:
 961        /* Free temporary buffer if we used one */
 962
 963        if (new_buffer) {
 964                ACPI_FREE(new_buffer);
 965        }
 966        return_ACPI_STATUS(status);
 967}
 968