Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: exfldio - Aml Field I/O
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acinterp.h"
0013 #include "amlcode.h"
0014 #include "acevents.h"
0015 #include "acdispat.h"
0016 
0017 #define _COMPONENT          ACPI_EXECUTER
0018 ACPI_MODULE_NAME("exfldio")
0019 
0020 /* Local prototypes */
0021 static acpi_status
0022 acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
0023                u32 field_datum_byte_offset, u64 *value, u32 read_write);
0024 
0025 static u8
0026 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value);
0027 
0028 static acpi_status
0029 acpi_ex_setup_region(union acpi_operand_object *obj_desc,
0030              u32 field_datum_byte_offset);
0031 
0032 /*******************************************************************************
0033  *
0034  * FUNCTION:    acpi_ex_setup_region
0035  *
0036  * PARAMETERS:  obj_desc                - Field to be read or written
0037  *              field_datum_byte_offset - Byte offset of this datum within the
0038  *                                        parent field
0039  *
0040  * RETURN:      Status
0041  *
0042  * DESCRIPTION: Common processing for acpi_ex_extract_from_field and
0043  *              acpi_ex_insert_into_field. Initialize the Region if necessary and
0044  *              validate the request.
0045  *
0046  ******************************************************************************/
0047 
0048 static acpi_status
0049 acpi_ex_setup_region(union acpi_operand_object *obj_desc,
0050              u32 field_datum_byte_offset)
0051 {
0052     acpi_status status = AE_OK;
0053     union acpi_operand_object *rgn_desc;
0054     u8 space_id;
0055 
0056     ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset);
0057 
0058     rgn_desc = obj_desc->common_field.region_obj;
0059 
0060     /* We must have a valid region */
0061 
0062     if (rgn_desc->common.type != ACPI_TYPE_REGION) {
0063         ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)",
0064                 rgn_desc->common.type,
0065                 acpi_ut_get_object_type_name(rgn_desc)));
0066 
0067         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0068     }
0069 
0070     space_id = rgn_desc->region.space_id;
0071 
0072     /* Validate the Space ID */
0073 
0074     if (!acpi_is_valid_space_id(space_id)) {
0075         ACPI_ERROR((AE_INFO,
0076                 "Invalid/unknown Address Space ID: 0x%2.2X",
0077                 space_id));
0078         return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID);
0079     }
0080 
0081     /*
0082      * If the Region Address and Length have not been previously evaluated,
0083      * evaluate them now and save the results.
0084      */
0085     if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) {
0086         status = acpi_ds_get_region_arguments(rgn_desc);
0087         if (ACPI_FAILURE(status)) {
0088             return_ACPI_STATUS(status);
0089         }
0090     }
0091 
0092     /*
0093      * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
0094      * address space and the request cannot be directly validated
0095      */
0096     if (space_id == ACPI_ADR_SPACE_SMBUS ||
0097         space_id == ACPI_ADR_SPACE_GSBUS ||
0098         space_id == ACPI_ADR_SPACE_IPMI) {
0099 
0100         /* SMBus or IPMI has a non-linear address space */
0101 
0102         return_ACPI_STATUS(AE_OK);
0103     }
0104 #ifdef ACPI_UNDER_DEVELOPMENT
0105     /*
0106      * If the Field access is any_acc, we can now compute the optimal
0107      * access (because we know the length of the parent region)
0108      */
0109     if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
0110         if (ACPI_FAILURE(status)) {
0111             return_ACPI_STATUS(status);
0112         }
0113     }
0114 #endif
0115 
0116     /*
0117      * Validate the request. The entire request from the byte offset for a
0118      * length of one field datum (access width) must fit within the region.
0119      * (Region length is specified in bytes)
0120      */
0121     if (rgn_desc->region.length <
0122         (obj_desc->common_field.base_byte_offset + field_datum_byte_offset +
0123          obj_desc->common_field.access_byte_width)) {
0124         if (acpi_gbl_enable_interpreter_slack) {
0125             /*
0126              * Slack mode only:  We will go ahead and allow access to this
0127              * field if it is within the region length rounded up to the next
0128              * access width boundary. acpi_size cast for 64-bit compile.
0129              */
0130             if (ACPI_ROUND_UP(rgn_desc->region.length,
0131                       obj_desc->common_field.
0132                       access_byte_width) >=
0133                 ((acpi_size)obj_desc->common_field.
0134                  base_byte_offset +
0135                  obj_desc->common_field.access_byte_width +
0136                  field_datum_byte_offset)) {
0137                 return_ACPI_STATUS(AE_OK);
0138             }
0139         }
0140 
0141         if (rgn_desc->region.length <
0142             obj_desc->common_field.access_byte_width) {
0143             /*
0144              * This is the case where the access_type (acc_word, etc.) is wider
0145              * than the region itself. For example, a region of length one
0146              * byte, and a field with Dword access specified.
0147              */
0148             ACPI_ERROR((AE_INFO,
0149                     "Field [%4.4s] access width (%u bytes) "
0150                     "too large for region [%4.4s] (length %u)",
0151                     acpi_ut_get_node_name(obj_desc->
0152                               common_field.node),
0153                     obj_desc->common_field.access_byte_width,
0154                     acpi_ut_get_node_name(rgn_desc->region.
0155                               node),
0156                     rgn_desc->region.length));
0157         }
0158 
0159         /*
0160          * Offset rounded up to next multiple of field width
0161          * exceeds region length, indicate an error
0162          */
0163         ACPI_ERROR((AE_INFO,
0164                 "Field [%4.4s] Base+Offset+Width %u+%u+%u "
0165                 "is beyond end of region [%4.4s] (length %u)",
0166                 acpi_ut_get_node_name(obj_desc->common_field.node),
0167                 obj_desc->common_field.base_byte_offset,
0168                 field_datum_byte_offset,
0169                 obj_desc->common_field.access_byte_width,
0170                 acpi_ut_get_node_name(rgn_desc->region.node),
0171                 rgn_desc->region.length));
0172 
0173         return_ACPI_STATUS(AE_AML_REGION_LIMIT);
0174     }
0175 
0176     return_ACPI_STATUS(AE_OK);
0177 }
0178 
0179 /*******************************************************************************
0180  *
0181  * FUNCTION:    acpi_ex_access_region
0182  *
0183  * PARAMETERS:  obj_desc                - Field to be read
0184  *              field_datum_byte_offset - Byte offset of this datum within the
0185  *                                        parent field
0186  *              value                   - Where to store value (must at least
0187  *                                        64 bits)
0188  *              function                - Read or Write flag plus other region-
0189  *                                        dependent flags
0190  *
0191  * RETURN:      Status
0192  *
0193  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
0194  *
0195  ******************************************************************************/
0196 
0197 acpi_status
0198 acpi_ex_access_region(union acpi_operand_object *obj_desc,
0199               u32 field_datum_byte_offset, u64 *value, u32 function)
0200 {
0201     acpi_status status;
0202     union acpi_operand_object *rgn_desc;
0203     u32 region_offset;
0204 
0205     ACPI_FUNCTION_TRACE(ex_access_region);
0206 
0207     /*
0208      * Ensure that the region operands are fully evaluated and verify
0209      * the validity of the request
0210      */
0211     status = acpi_ex_setup_region(obj_desc, field_datum_byte_offset);
0212     if (ACPI_FAILURE(status)) {
0213         return_ACPI_STATUS(status);
0214     }
0215 
0216     /*
0217      * The physical address of this field datum is:
0218      *
0219      * 1) The base of the region, plus
0220      * 2) The base offset of the field, plus
0221      * 3) The current offset into the field
0222      */
0223     rgn_desc = obj_desc->common_field.region_obj;
0224     region_offset =
0225         obj_desc->common_field.base_byte_offset + field_datum_byte_offset;
0226 
0227     if ((function & ACPI_IO_MASK) == ACPI_READ) {
0228         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[READ]"));
0229     } else {
0230         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[WRITE]"));
0231     }
0232 
0233     ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
0234                   " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
0235                   acpi_ut_get_region_name(rgn_desc->region.
0236                               space_id),
0237                   rgn_desc->region.space_id,
0238                   obj_desc->common_field.access_byte_width,
0239                   obj_desc->common_field.base_byte_offset,
0240                   field_datum_byte_offset,
0241                   ACPI_FORMAT_UINT64(rgn_desc->region.address +
0242                          region_offset)));
0243 
0244     /* Invoke the appropriate address_space/op_region handler */
0245 
0246     status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc,
0247                         function, region_offset,
0248                         ACPI_MUL_8(obj_desc->
0249                                common_field.
0250                                access_byte_width),
0251                         value);
0252 
0253     if (ACPI_FAILURE(status)) {
0254         if (status == AE_NOT_IMPLEMENTED) {
0255             ACPI_ERROR((AE_INFO,
0256                     "Region %s (ID=%u) not implemented",
0257                     acpi_ut_get_region_name(rgn_desc->region.
0258                                 space_id),
0259                     rgn_desc->region.space_id));
0260         } else if (status == AE_NOT_EXIST) {
0261             ACPI_ERROR((AE_INFO,
0262                     "Region %s (ID=%u) has no handler",
0263                     acpi_ut_get_region_name(rgn_desc->region.
0264                                 space_id),
0265                     rgn_desc->region.space_id));
0266         }
0267     }
0268 
0269     return_ACPI_STATUS(status);
0270 }
0271 
0272 /*******************************************************************************
0273  *
0274  * FUNCTION:    acpi_ex_register_overflow
0275  *
0276  * PARAMETERS:  obj_desc                - Register(Field) to be written
0277  *              value                   - Value to be stored
0278  *
0279  * RETURN:      TRUE if value overflows the field, FALSE otherwise
0280  *
0281  * DESCRIPTION: Check if a value is out of range of the field being written.
0282  *              Used to check if the values written to Index and Bank registers
0283  *              are out of range. Normally, the value is simply truncated
0284  *              to fit the field, but this case is most likely a serious
0285  *              coding error in the ASL.
0286  *
0287  ******************************************************************************/
0288 
0289 static u8
0290 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value)
0291 {
0292 
0293     if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
0294         /*
0295          * The field is large enough to hold the maximum integer, so we can
0296          * never overflow it.
0297          */
0298         return (FALSE);
0299     }
0300 
0301     if (value >= ((u64) 1 << obj_desc->common_field.bit_length)) {
0302         /*
0303          * The Value is larger than the maximum value that can fit into
0304          * the register.
0305          */
0306         ACPI_ERROR((AE_INFO,
0307                 "Index value 0x%8.8X%8.8X overflows field width 0x%X",
0308                 ACPI_FORMAT_UINT64(value),
0309                 obj_desc->common_field.bit_length));
0310 
0311         return (TRUE);
0312     }
0313 
0314     /* The Value will fit into the field with no truncation */
0315 
0316     return (FALSE);
0317 }
0318 
0319 /*******************************************************************************
0320  *
0321  * FUNCTION:    acpi_ex_field_datum_io
0322  *
0323  * PARAMETERS:  obj_desc                - Field to be read
0324  *              field_datum_byte_offset - Byte offset of this datum within the
0325  *                                        parent field
0326  *              value                   - Where to store value (must be 64 bits)
0327  *              read_write              - Read or Write flag
0328  *
0329  * RETURN:      Status
0330  *
0331  * DESCRIPTION: Read or Write a single datum of a field. The field_type is
0332  *              demultiplexed here to handle the different types of fields
0333  *              (buffer_field, region_field, index_field, bank_field)
0334  *
0335  ******************************************************************************/
0336 
0337 static acpi_status
0338 acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
0339                u32 field_datum_byte_offset, u64 *value, u32 read_write)
0340 {
0341     acpi_status status;
0342     u64 local_value;
0343 
0344     ACPI_FUNCTION_TRACE_U32(ex_field_datum_io, field_datum_byte_offset);
0345 
0346     if (read_write == ACPI_READ) {
0347         if (!value) {
0348             local_value = 0;
0349 
0350             /* To support reads without saving return value */
0351             value = &local_value;
0352         }
0353 
0354         /* Clear the entire return buffer first, [Very Important!] */
0355 
0356         *value = 0;
0357     }
0358 
0359     /*
0360      * The four types of fields are:
0361      *
0362      * buffer_field - Read/write from/to a Buffer
0363      * region_field - Read/write from/to a Operation Region.
0364      * bank_field  - Write to a Bank Register, then read/write from/to an
0365      *               operation_region
0366      * index_field - Write to an Index Register, then read/write from/to a
0367      *               Data Register
0368      */
0369     switch (obj_desc->common.type) {
0370     case ACPI_TYPE_BUFFER_FIELD:
0371         /*
0372          * If the buffer_field arguments have not been previously evaluated,
0373          * evaluate them now and save the results.
0374          */
0375         if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
0376             status = acpi_ds_get_buffer_field_arguments(obj_desc);
0377             if (ACPI_FAILURE(status)) {
0378                 return_ACPI_STATUS(status);
0379             }
0380         }
0381 
0382         if (read_write == ACPI_READ) {
0383             /*
0384              * Copy the data from the source buffer.
0385              * Length is the field width in bytes.
0386              */
0387             memcpy(value,
0388                    (obj_desc->buffer_field.buffer_obj)->buffer.
0389                    pointer +
0390                    obj_desc->buffer_field.base_byte_offset +
0391                    field_datum_byte_offset,
0392                    obj_desc->common_field.access_byte_width);
0393         } else {
0394             /*
0395              * Copy the data to the target buffer.
0396              * Length is the field width in bytes.
0397              */
0398             memcpy((obj_desc->buffer_field.buffer_obj)->buffer.
0399                    pointer +
0400                    obj_desc->buffer_field.base_byte_offset +
0401                    field_datum_byte_offset, value,
0402                    obj_desc->common_field.access_byte_width);
0403         }
0404 
0405         status = AE_OK;
0406         break;
0407 
0408     case ACPI_TYPE_LOCAL_BANK_FIELD:
0409         /*
0410          * Ensure that the bank_value is not beyond the capacity of
0411          * the register
0412          */
0413         if (acpi_ex_register_overflow(obj_desc->bank_field.bank_obj,
0414                           (u64) obj_desc->bank_field.
0415                           value)) {
0416             return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
0417         }
0418 
0419         /*
0420          * For bank_fields, we must write the bank_value to the bank_register
0421          * (itself a region_field) before we can access the data.
0422          */
0423         status =
0424             acpi_ex_insert_into_field(obj_desc->bank_field.bank_obj,
0425                           &obj_desc->bank_field.value,
0426                           sizeof(obj_desc->bank_field.
0427                              value));
0428         if (ACPI_FAILURE(status)) {
0429             return_ACPI_STATUS(status);
0430         }
0431 
0432         /*
0433          * Now that the Bank has been selected, fall through to the
0434          * region_field case and write the datum to the Operation Region
0435          */
0436 
0437         ACPI_FALLTHROUGH;
0438 
0439     case ACPI_TYPE_LOCAL_REGION_FIELD:
0440         /*
0441          * For simple region_fields, we just directly access the owning
0442          * Operation Region.
0443          */
0444         status =
0445             acpi_ex_access_region(obj_desc, field_datum_byte_offset,
0446                       value, read_write);
0447         break;
0448 
0449     case ACPI_TYPE_LOCAL_INDEX_FIELD:
0450         /*
0451          * Ensure that the index_value is not beyond the capacity of
0452          * the register
0453          */
0454         if (acpi_ex_register_overflow(obj_desc->index_field.index_obj,
0455                           (u64) obj_desc->index_field.
0456                           value)) {
0457             return_ACPI_STATUS(AE_AML_REGISTER_LIMIT);
0458         }
0459 
0460         /* Write the index value to the index_register (itself a region_field) */
0461 
0462         field_datum_byte_offset += obj_desc->index_field.value;
0463 
0464         ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0465                   "Write to Index Register: Value %8.8X\n",
0466                   field_datum_byte_offset));
0467 
0468         status =
0469             acpi_ex_insert_into_field(obj_desc->index_field.index_obj,
0470                           &field_datum_byte_offset,
0471                           sizeof(field_datum_byte_offset));
0472         if (ACPI_FAILURE(status)) {
0473             return_ACPI_STATUS(status);
0474         }
0475 
0476         if (read_write == ACPI_READ) {
0477 
0478             /* Read the datum from the data_register */
0479 
0480             ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0481                       "Read from Data Register\n"));
0482 
0483             status =
0484                 acpi_ex_extract_from_field(obj_desc->index_field.
0485                                data_obj, value,
0486                                sizeof(u64));
0487         } else {
0488             /* Write the datum to the data_register */
0489 
0490             ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0491                       "Write to Data Register: Value %8.8X%8.8X\n",
0492                       ACPI_FORMAT_UINT64(*value)));
0493 
0494             status =
0495                 acpi_ex_insert_into_field(obj_desc->index_field.
0496                               data_obj, value,
0497                               sizeof(u64));
0498         }
0499         break;
0500 
0501     default:
0502 
0503         ACPI_ERROR((AE_INFO, "Wrong object type in field I/O %u",
0504                 obj_desc->common.type));
0505         status = AE_AML_INTERNAL;
0506         break;
0507     }
0508 
0509     if (ACPI_SUCCESS(status)) {
0510         if (read_write == ACPI_READ) {
0511             ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0512                       "Value Read %8.8X%8.8X, Width %u\n",
0513                       ACPI_FORMAT_UINT64(*value),
0514                       obj_desc->common_field.
0515                       access_byte_width));
0516         } else {
0517             ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0518                       "Value Written %8.8X%8.8X, Width %u\n",
0519                       ACPI_FORMAT_UINT64(*value),
0520                       obj_desc->common_field.
0521                       access_byte_width));
0522         }
0523     }
0524 
0525     return_ACPI_STATUS(status);
0526 }
0527 
0528 /*******************************************************************************
0529  *
0530  * FUNCTION:    acpi_ex_write_with_update_rule
0531  *
0532  * PARAMETERS:  obj_desc                - Field to be written
0533  *              mask                    - bitmask within field datum
0534  *              field_value             - Value to write
0535  *              field_datum_byte_offset - Offset of datum within field
0536  *
0537  * RETURN:      Status
0538  *
0539  * DESCRIPTION: Apply the field update rule to a field write
0540  *
0541  ******************************************************************************/
0542 
0543 acpi_status
0544 acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
0545                    u64 mask,
0546                    u64 field_value, u32 field_datum_byte_offset)
0547 {
0548     acpi_status status = AE_OK;
0549     u64 merged_value;
0550     u64 current_value;
0551 
0552     ACPI_FUNCTION_TRACE_U32(ex_write_with_update_rule, mask);
0553 
0554     /* Start with the new bits  */
0555 
0556     merged_value = field_value;
0557 
0558     /* If the mask is all ones, we don't need to worry about the update rule */
0559 
0560     if (mask != ACPI_UINT64_MAX) {
0561 
0562         /* Decode the update rule */
0563 
0564         switch (obj_desc->common_field.
0565             field_flags & AML_FIELD_UPDATE_RULE_MASK) {
0566         case AML_FIELD_UPDATE_PRESERVE:
0567             /*
0568              * Check if update rule needs to be applied (not if mask is all
0569              * ones)  The left shift drops the bits we want to ignore.
0570              */
0571             if ((~mask << (ACPI_MUL_8(sizeof(mask)) -
0572                        ACPI_MUL_8(obj_desc->common_field.
0573                           access_byte_width))) != 0) {
0574                 /*
0575                  * Read the current contents of the byte/word/dword containing
0576                  * the field, and merge with the new field value.
0577                  */
0578                 status =
0579                     acpi_ex_field_datum_io(obj_desc,
0580                                field_datum_byte_offset,
0581                                &current_value,
0582                                ACPI_READ);
0583                 if (ACPI_FAILURE(status)) {
0584                     return_ACPI_STATUS(status);
0585                 }
0586 
0587                 merged_value |= (current_value & ~mask);
0588             }
0589             break;
0590 
0591         case AML_FIELD_UPDATE_WRITE_AS_ONES:
0592 
0593             /* Set positions outside the field to all ones */
0594 
0595             merged_value |= ~mask;
0596             break;
0597 
0598         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
0599 
0600             /* Set positions outside the field to all zeros */
0601 
0602             merged_value &= mask;
0603             break;
0604 
0605         default:
0606 
0607             ACPI_ERROR((AE_INFO,
0608                     "Unknown UpdateRule value: 0x%X",
0609                     (obj_desc->common_field.field_flags &
0610                      AML_FIELD_UPDATE_RULE_MASK)));
0611             return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
0612         }
0613     }
0614 
0615     ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
0616               "Mask %8.8X%8.8X, DatumOffset %X, Width %X, "
0617               "Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
0618               ACPI_FORMAT_UINT64(mask),
0619               field_datum_byte_offset,
0620               obj_desc->common_field.access_byte_width,
0621               ACPI_FORMAT_UINT64(field_value),
0622               ACPI_FORMAT_UINT64(merged_value)));
0623 
0624     /* Write the merged value */
0625 
0626     status =
0627         acpi_ex_field_datum_io(obj_desc, field_datum_byte_offset,
0628                    &merged_value, ACPI_WRITE);
0629 
0630     return_ACPI_STATUS(status);
0631 }
0632 
0633 /*******************************************************************************
0634  *
0635  * FUNCTION:    acpi_ex_extract_from_field
0636  *
0637  * PARAMETERS:  obj_desc            - Field to be read
0638  *              buffer              - Where to store the field data
0639  *              buffer_length       - Length of Buffer
0640  *
0641  * RETURN:      Status
0642  *
0643  * DESCRIPTION: Retrieve the current value of the given field
0644  *
0645  ******************************************************************************/
0646 
0647 acpi_status
0648 acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
0649                void *buffer, u32 buffer_length)
0650 {
0651     acpi_status status;
0652     u64 raw_datum;
0653     u64 merged_datum;
0654     u32 field_offset = 0;
0655     u32 buffer_offset = 0;
0656     u32 buffer_tail_bits;
0657     u32 datum_count;
0658     u32 field_datum_count;
0659     u32 access_bit_width;
0660     u32 i;
0661 
0662     ACPI_FUNCTION_TRACE(ex_extract_from_field);
0663 
0664     /* Validate target buffer and clear it */
0665 
0666     if (buffer_length <
0667         ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
0668         ACPI_ERROR((AE_INFO,
0669                 "Field size %u (bits) is too large for buffer (%u)",
0670                 obj_desc->common_field.bit_length, buffer_length));
0671 
0672         return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
0673     }
0674 
0675     memset(buffer, 0, buffer_length);
0676     access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
0677 
0678     /* Handle the simple case here */
0679 
0680     if ((obj_desc->common_field.start_field_bit_offset == 0) &&
0681         (obj_desc->common_field.bit_length == access_bit_width)) {
0682         if (buffer_length >= sizeof(u64)) {
0683             status =
0684                 acpi_ex_field_datum_io(obj_desc, 0, buffer,
0685                            ACPI_READ);
0686         } else {
0687             /* Use raw_datum (u64) to handle buffers < 64 bits */
0688 
0689             status =
0690                 acpi_ex_field_datum_io(obj_desc, 0, &raw_datum,
0691                            ACPI_READ);
0692             memcpy(buffer, &raw_datum, buffer_length);
0693         }
0694 
0695         return_ACPI_STATUS(status);
0696     }
0697 
0698 /* TBD: Move to common setup code */
0699 
0700     /* Field algorithm is limited to sizeof(u64), truncate if needed */
0701 
0702     if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
0703         obj_desc->common_field.access_byte_width = sizeof(u64);
0704         access_bit_width = sizeof(u64) * 8;
0705     }
0706 
0707     /* Compute the number of datums (access width data items) */
0708 
0709     datum_count =
0710         ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
0711                  access_bit_width);
0712 
0713     field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
0714                          obj_desc->common_field.
0715                          start_field_bit_offset,
0716                          access_bit_width);
0717 
0718     /* Priming read from the field */
0719 
0720     status =
0721         acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
0722                    ACPI_READ);
0723     if (ACPI_FAILURE(status)) {
0724         return_ACPI_STATUS(status);
0725     }
0726     merged_datum =
0727         raw_datum >> obj_desc->common_field.start_field_bit_offset;
0728 
0729     /* Read the rest of the field */
0730 
0731     for (i = 1; i < field_datum_count; i++) {
0732 
0733         /* Get next input datum from the field */
0734 
0735         field_offset += obj_desc->common_field.access_byte_width;
0736         status =
0737             acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
0738                        ACPI_READ);
0739         if (ACPI_FAILURE(status)) {
0740             return_ACPI_STATUS(status);
0741         }
0742 
0743         /*
0744          * Merge with previous datum if necessary.
0745          *
0746          * Note: Before the shift, check if the shift value will be larger than
0747          * the integer size. If so, there is no need to perform the operation.
0748          * This avoids the differences in behavior between different compilers
0749          * concerning shift values larger than the target data width.
0750          */
0751         if (access_bit_width -
0752             obj_desc->common_field.start_field_bit_offset <
0753             ACPI_INTEGER_BIT_SIZE) {
0754             merged_datum |=
0755                 raw_datum << (access_bit_width -
0756                       obj_desc->common_field.
0757                       start_field_bit_offset);
0758         }
0759 
0760         if (i == datum_count) {
0761             break;
0762         }
0763 
0764         /* Write merged datum to target buffer */
0765 
0766         memcpy(((char *)buffer) + buffer_offset, &merged_datum,
0767                ACPI_MIN(obj_desc->common_field.access_byte_width,
0768                 buffer_length - buffer_offset));
0769 
0770         buffer_offset += obj_desc->common_field.access_byte_width;
0771         merged_datum =
0772             raw_datum >> obj_desc->common_field.start_field_bit_offset;
0773     }
0774 
0775     /* Mask off any extra bits in the last datum */
0776 
0777     buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
0778     if (buffer_tail_bits) {
0779         merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
0780     }
0781 
0782     /* Write the last datum to the buffer */
0783 
0784     memcpy(((char *)buffer) + buffer_offset, &merged_datum,
0785            ACPI_MIN(obj_desc->common_field.access_byte_width,
0786             buffer_length - buffer_offset));
0787 
0788     return_ACPI_STATUS(AE_OK);
0789 }
0790 
0791 /*******************************************************************************
0792  *
0793  * FUNCTION:    acpi_ex_insert_into_field
0794  *
0795  * PARAMETERS:  obj_desc            - Field to be written
0796  *              buffer              - Data to be written
0797  *              buffer_length       - Length of Buffer
0798  *
0799  * RETURN:      Status
0800  *
0801  * DESCRIPTION: Store the Buffer contents into the given field
0802  *
0803  ******************************************************************************/
0804 
0805 acpi_status
0806 acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
0807               void *buffer, u32 buffer_length)
0808 {
0809     void *new_buffer;
0810     acpi_status status;
0811     u64 mask;
0812     u64 width_mask;
0813     u64 merged_datum;
0814     u64 raw_datum = 0;
0815     u32 field_offset = 0;
0816     u32 buffer_offset = 0;
0817     u32 buffer_tail_bits;
0818     u32 datum_count;
0819     u32 field_datum_count;
0820     u32 access_bit_width;
0821     u32 required_length;
0822     u32 i;
0823 
0824     ACPI_FUNCTION_TRACE(ex_insert_into_field);
0825 
0826     /* Validate input buffer */
0827 
0828     new_buffer = NULL;
0829     required_length =
0830         ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
0831 
0832     /*
0833      * We must have a buffer that is at least as long as the field
0834      * we are writing to. This is because individual fields are
0835      * indivisible and partial writes are not supported -- as per
0836      * the ACPI specification.
0837      */
0838     if (buffer_length < required_length) {
0839 
0840         /* We need to create a new buffer */
0841 
0842         new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
0843         if (!new_buffer) {
0844             return_ACPI_STATUS(AE_NO_MEMORY);
0845         }
0846 
0847         /*
0848          * Copy the original data to the new buffer, starting
0849          * at Byte zero. All unused (upper) bytes of the
0850          * buffer will be 0.
0851          */
0852         memcpy((char *)new_buffer, (char *)buffer, buffer_length);
0853         buffer = new_buffer;
0854         buffer_length = required_length;
0855     }
0856 
0857 /* TBD: Move to common setup code */
0858 
0859     /* Algo is limited to sizeof(u64), so cut the access_byte_width */
0860     if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
0861         obj_desc->common_field.access_byte_width = sizeof(u64);
0862     }
0863 
0864     access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
0865 
0866     /* Create the bitmasks used for bit insertion */
0867 
0868     width_mask = ACPI_MASK_BITS_ABOVE_64(access_bit_width);
0869     mask = width_mask &
0870         ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);
0871 
0872     /* Compute the number of datums (access width data items) */
0873 
0874     datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
0875                        access_bit_width);
0876 
0877     field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
0878                          obj_desc->common_field.
0879                          start_field_bit_offset,
0880                          access_bit_width);
0881 
0882     /* Get initial Datum from the input buffer */
0883 
0884     memcpy(&raw_datum, buffer,
0885            ACPI_MIN(obj_desc->common_field.access_byte_width,
0886             buffer_length - buffer_offset));
0887 
0888     merged_datum =
0889         raw_datum << obj_desc->common_field.start_field_bit_offset;
0890 
0891     /* Write the entire field */
0892 
0893     for (i = 1; i < field_datum_count; i++) {
0894 
0895         /* Write merged datum to the target field */
0896 
0897         merged_datum &= mask;
0898         status =
0899             acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum,
0900                            field_offset);
0901         if (ACPI_FAILURE(status)) {
0902             goto exit;
0903         }
0904 
0905         field_offset += obj_desc->common_field.access_byte_width;
0906 
0907         /*
0908          * Start new output datum by merging with previous input datum
0909          * if necessary.
0910          *
0911          * Note: Before the shift, check if the shift value will be larger than
0912          * the integer size. If so, there is no need to perform the operation.
0913          * This avoids the differences in behavior between different compilers
0914          * concerning shift values larger than the target data width.
0915          */
0916         if ((access_bit_width -
0917              obj_desc->common_field.start_field_bit_offset) <
0918             ACPI_INTEGER_BIT_SIZE) {
0919             merged_datum =
0920                 raw_datum >> (access_bit_width -
0921                       obj_desc->common_field.
0922                       start_field_bit_offset);
0923         } else {
0924             merged_datum = 0;
0925         }
0926 
0927         mask = width_mask;
0928 
0929         if (i == datum_count) {
0930             break;
0931         }
0932 
0933         /* Get the next input datum from the buffer */
0934 
0935         buffer_offset += obj_desc->common_field.access_byte_width;
0936         memcpy(&raw_datum, ((char *)buffer) + buffer_offset,
0937                ACPI_MIN(obj_desc->common_field.access_byte_width,
0938                 buffer_length - buffer_offset));
0939 
0940         merged_datum |=
0941             raw_datum << obj_desc->common_field.start_field_bit_offset;
0942     }
0943 
0944     /* Mask off any extra bits in the last datum */
0945 
0946     buffer_tail_bits = (obj_desc->common_field.bit_length +
0947                 obj_desc->common_field.start_field_bit_offset) %
0948         access_bit_width;
0949     if (buffer_tail_bits) {
0950         mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
0951     }
0952 
0953     /* Write the last datum to the field */
0954 
0955     merged_datum &= mask;
0956     status =
0957         acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum,
0958                        field_offset);
0959 
0960 exit:
0961     /* Free temporary buffer if we used one */
0962 
0963     if (new_buffer) {
0964         ACPI_FREE(new_buffer);
0965     }
0966     return_ACPI_STATUS(status);
0967 }